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