1f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#!/usr/bin/env python
2f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Copyright (c) 2014 The Chromium Authors. All rights reserved.
3f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Use of this source code is governed by a BSD-style license that can be
4f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# found in the LICENSE file.
5f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
6f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch"""Test for TranslationUnitGenerator tool."""
7f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
8f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport difflib
9f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport glob
10f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport json
11f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport ntpath
12f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport os
13f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport os.path
14f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport subprocess
15f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport sys
16f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
17f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
18f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef _GenerateCompileCommands(template_path, test_files_dir):
19f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  """Returns a JSON string containing a compilation database for the input."""
20f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  with open(template_path) as fh:
21f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    return fh.read().replace('$test_files_dir', test_files_dir)
22f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
23f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
24f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef _NumberOfTestsToString(tests):
25f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  """Returns an English sentence describing the number of tests."""
26f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  return "%d test%s" % (tests, 's' if tests != 1 else '')
27f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
28f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
29f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Before running this test script, please build the translation_unit clang tool
30f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# first. This is explained here:
31f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# https://chromium.googlesource.com/chromium/src/+/master/docs/clang_tool_refactoring.md
32f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef main():
33f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  tools_clang_directory = os.path.dirname(os.path.dirname(
34f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      os.path.realpath(__file__)))
35f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  tools_clang_scripts_directory = os.path.join(tools_clang_directory, 'scripts')
36f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  test_directory_for_tool = os.path.join(
37f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      tools_clang_directory, 'translation_unit', 'test_files')
38f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  compile_database = os.path.join(test_directory_for_tool,
39f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                  'compile_commands.json')
40f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  compile_database_template = compile_database + '.template'
41f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  source_files = glob.glob(os.path.join(test_directory_for_tool, '*.cc'))
42f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
43f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # Generate a temporary compilation database to run the tool over.
44f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  with open(compile_database, 'w') as f:
45f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    f.write(_GenerateCompileCommands(compile_database_template,
46f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                     test_directory_for_tool))
47f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
48f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  args = ['python',
49f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          os.path.join(tools_clang_scripts_directory, 'run_tool.py'),
50f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          'translation_unit',
51f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          test_directory_for_tool]
52f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  args.extend(source_files)
53f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  run_tool = subprocess.Popen(args, stdout=subprocess.PIPE)
54f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  stdout, _ = run_tool.communicate()
55f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if run_tool.returncode != 0:
56f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    print 'run_tool failed:\n%s' % stdout
57f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    sys.exit(1)
58f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
59f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  passed = 0
60f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  failed = 0
61f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  for actual in source_files:
62f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    actual += '.filepaths'
63f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    expected = actual + '.expected'
64f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    print '[ RUN      ] %s' % os.path.relpath(actual)
65f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    expected_output = actual_output = None
66f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    with open(expected, 'r') as f:
67f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      expected_output = f.readlines()
68f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    with open(actual, 'r') as f:
69f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      actual_output = f.readlines()
70f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    has_same_filepaths = True
71f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    for expected_line, actual_line in zip(expected_output, actual_output):
72f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      if '//' in actual_line:
73f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        actual_line = '//' + actual_line.split('//')[1]
74f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
75f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      if ntpath.basename(expected_line) != ntpath.basename(actual_line):
76f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        sys.stdout.write('expected: %s' % ntpath.basename(expected_line))
77f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        sys.stdout.write('actual: %s' % ntpath.basename(actual_line))
78f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        has_same_filepaths = False
79f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        break
80f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    if not has_same_filepaths:
81f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      failed += 1
82f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      for line in difflib.unified_diff(expected_output, actual_output,
83f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                       fromfile=os.path.relpath(expected),
84f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                       tofile=os.path.relpath(actual)):
85f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        sys.stdout.write(line)
86f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      print '[  FAILED  ] %s' % os.path.relpath(actual)
87f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      # Don't clean up the file on failure, so the results can be referenced
88f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      # more easily.
89f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      continue
90f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    print '[       OK ] %s' % os.path.relpath(actual)
91f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    passed += 1
92f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    os.remove(actual)
93f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
94f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if failed == 0:
95f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    os.remove(compile_database)
96f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
97f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  print '[==========] %s ran.' % _NumberOfTestsToString(len(source_files))
98f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if passed > 0:
99f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    print '[  PASSED  ] %s.' % _NumberOfTestsToString(passed)
100f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  if failed > 0:
101f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    print '[  FAILED  ] %s.' % _NumberOfTestsToString(failed)
102f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
103f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
104f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochif __name__ == '__main__':
105f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  sys.exit(main())
106