#!/usr/bin/env python from __future__ import print_function import argparse import os import subprocess import sys from test_util import TestFailedError, prepareForIncrParse, run_command, \ serializeIncrParseMarkupFile def testWithParserLib(test_file, test_case, pre_edit_file, post_edit_file, after_roundtrip_file, swiftsyntax_lit_test_helper): # ========================================================================= # First generate the pre-edit and post-edit Swift file and gather the edits # and expected reparse regions. This is the parser for the special edit # markup for testing incremental parsing # ========================================================================= # Gather command line arguments for swift-syntax-test specifiying the # performed edits in this list incremental_edit_args = [] reparse_args = [] try: prepareForIncrParse(test_file=test_file, test_case=test_case, pre_edit_file=pre_edit_file, post_edit_file=post_edit_file, incremental_edit_args=incremental_edit_args, reparse_args=reparse_args) except TestFailedError as e: print('Test case "%s" of %s FAILed' % (test_case, test_file), file=sys.stderr) print(e.message, file=sys.stderr) sys.exit(1) try: run_command([swiftsyntax_lit_test_helper, '-parse-incremental'] + ['-old-source-file', pre_edit_file] + ['-source-file', post_edit_file] + incremental_edit_args + reparse_args + ['-out', after_roundtrip_file]) except subprocess.CalledProcessError as e: print('Test case "%s" of %s FAILed' % (test_case, test_file), file=sys.stderr) print('Parsing the swift file failed:\n', file=sys.stderr) print(e.output, file=sys.stderr) sys.exit(1) # Check if the two syntax trees are the same try: run_command( [ 'diff', '-u', post_edit_file, after_roundtrip_file ]) except subprocess.CalledProcessError as e: print('Test case "%s" of %s FAILed' % (test_case, test_file), file=sys.stderr) print('Source file after incrementally parsing ' 'does not match post-edit source file:\n\n', file=sys.stderr) print(e.output, file=sys.stderr) sys.exit(1) def main(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description='Utility for testing incremental syntax parsing', epilog=''' Based of a single template the utility generates a pre-edit and a post-edit file. It then verifies that incrementally parsing the post-edit file base on the pre-edit file results in the same syntax tree as reparsing the post-edit file from scratch. To generate the pre-edit and the post-edit file from the template, it operates on markers of the form: <>> These placeholders are replaced by: - 'pre' if a different test case than 'test_case' is run - 'pre' for the pre-edit version of 'test_case' - 'post' for the post-edit version of 'test_case' ''') parser.add_argument( 'file', type=argparse.FileType(), help='The template file to test') parser.add_argument( '--test-case', default='', help='The test case to execute. If no test case is specified all \ unnamed substitutions are applied') parser.add_argument( '--temp-dir', required=True, help='A temporary directory where pre-edit and post-edit files can be \ saved') parser.add_argument( '--swift-syntax-test', required=False, help='The path to swift-syntax-test') parser.add_argument( '--swiftsyntax-lit-test-helper', required=True, help='The path to the lit-test-helper binary of SwiftSyntax') parser.add_argument( '--serialization-format', choices=['json', 'byteTree'], default='json', help=''' The format that shall be used to transfer the syntax tree ''') args = parser.parse_args(sys.argv[1:]) test_file = args.file.name test_file_name = os.path.basename(test_file) test_case = args.test_case temp_dir = args.temp_dir swift_syntax_test = args.swift_syntax_test swiftsyntax_lit_test_helper = args.swiftsyntax_lit_test_helper serialization_format = args.serialization_format if not os.path.exists(temp_dir): os.makedirs(temp_dir) # FIXME: This check is transitional, once SwiftSyntax starts using the # parser library it will become self-contained and not need # swift-syntax-test for its lit tests. Contents of testWithParserLib() # function will move here and replace what comes below. if not swift_syntax_test: pre_edit_file = temp_dir + '/' + test_file_name + '.' + test_case + \ '.pre.swift' post_edit_file = temp_dir + '/' + test_file_name + '.' + test_case + \ '.post.swift' after_roundtrip_file = temp_dir + '/' + test_file_name + '.' \ + test_case + '.post_after_roundtrip.swift' return testWithParserLib( test_file=test_file, test_case=test_case, pre_edit_file=pre_edit_file, post_edit_file=post_edit_file, after_roundtrip_file=after_roundtrip_file, swiftsyntax_lit_test_helper=swiftsyntax_lit_test_helper) treeFileExtension = serialization_format pre_edit_tree_file = temp_dir + '/' + test_file_name + '.' \ + test_case + '.pre.' + treeFileExtension incremental_tree_file = temp_dir + '/' + test_file_name + '.' \ + test_case + '.incr.' + treeFileExtension post_edit_source_file = temp_dir + '/' + test_file_name + '.' \ + test_case + '.post.swift' after_roundtrip_source_file = temp_dir + '/' + test_file_name + '.' \ + test_case + '.post_after_roundtrip.swift' # Generate the syntax tree once incrementally and once from scratch try: serializeIncrParseMarkupFile(test_file=test_file, test_case=test_case, mode='pre-edit', serialization_mode='full', serialization_format=serialization_format, omit_node_ids=False, output_file=pre_edit_tree_file, diags_output_file=None, temp_dir=temp_dir, swift_syntax_test=swift_syntax_test, print_visual_reuse_info=False) serializeIncrParseMarkupFile(test_file=test_file, test_case=test_case, mode='incremental', serialization_mode='incremental', serialization_format=serialization_format, omit_node_ids=False, output_file=incremental_tree_file, diags_output_file=None, temp_dir=temp_dir, swift_syntax_test=swift_syntax_test, print_visual_reuse_info=False) except TestFailedError as e: print('Test case "%s" of %s FAILed' % (test_case, test_file), file=sys.stderr) print(e.message, file=sys.stderr) sys.exit(1) try: run_command([swiftsyntax_lit_test_helper, '-deserialize-incremental'] + ['-serialization-format', serialization_format] + ['-pre-edit-tree', pre_edit_tree_file] + ['-incr-tree', incremental_tree_file] + ['-out', after_roundtrip_source_file]) except subprocess.CalledProcessError as e: print('Test case "%s" of %s FAILed' % (test_case, test_file), file=sys.stderr) print('Deserializing the swift file failed:\n', file=sys.stderr) print(e.output, file=sys.stderr) sys.exit(1) # Check if the two syntax trees are the same try: run_command( [ 'diff', '-u', post_edit_source_file, after_roundtrip_source_file ]) except subprocess.CalledProcessError as e: print('Test case "%s" of %s FAILed' % (test_case, test_file), file=sys.stderr) print('Source file after incrementally transferring the syntax tree ' 'to swiftSyntax does not match post-edit source file:\n\n', file=sys.stderr) print(e.output, file=sys.stderr) sys.exit(1) if __name__ == '__main__': main()