def runTest(self): # ARRANGE # expected_file_name = 'quoted file name.src' act_phase_instructions = [instr([str(surrounded_by_hard_quotes(expected_file_name))]), instr([''])] executor_that_records_arguments = CommandExecutorThatRecordsArguments() arrangement = integration_check.arrangement_w_tcds( hds_contents=contents_in(RelHdsOptionType.REL_HDS_ACT, DirContents([ File.empty(expected_file_name)])), process_execution=ProcessExecutionArrangement( os_services=os_services_access.new_for_cmd_exe(executor_that_records_arguments) ) ) expectation = integration_check.Expectation() # ACT # integration_check.check_execution(self, ACTOR_THAT_RUNS_PYTHON_PROGRAM_FILE, act_phase_instructions, arrangement, expectation) # ASSERT # expected_command = asrt_command.matches_command( driver=asrt_command.matches_executable_file_command_driver(asrt.anything_goes()), arguments=asrt.matches_sequence([ asrt_path.str_as_path(asrt_path.name_equals(expected_file_name)) ]) ) expected_command.apply_with_message( self, executor_that_records_arguments.command, 'command', )
def test_fail__must_be_on_current_line(self): cases = [ NameAndValue( 'token is not the name of a primitive expression', [ast.NOT_A_PRIMITIVE_EXPR_NAME_AND_NOT_A_VALID_SYMBOL_NAME], ), NameAndValue( 'token is the name of a primitive expression, but it is quoted/soft', [str(surrounded_by_soft_quotes(ast.PRIMITIVE_SANS_ARG))], ), NameAndValue( 'token is the name of a primitive expression, but it is quoted/hard', [str(surrounded_by_hard_quotes(ast.PRIMITIVE_SANS_ARG))], ), NameAndValue( 'token is the name of a primitive expression, but it is on the next line', [ast.PRIMITIVE_SANS_ARG], ), ] # ACT & ASSERT # parse_check.check_fail__must_be_on_current_line( self, self.parser_maker, GRAMMARS, cases, )
def test_fail(self): for grammar_description, grammar in self.grammars: cases = [ ( 'token is not the name of a simple expression', remaining_source(ast.NOT_A_SIMPLE_EXPR_NAME_AND_NOT_A_VALID_SYMBOL_NAME), ), ( 'token is the name of a simple expression, but it is quoted/soft', remaining_source(str(surrounded_by_soft_quotes(ast.SIMPLE_SANS_ARG))), ), ( 'token is the name of a simple expression, but it is quoted/hard', remaining_source(str(surrounded_by_hard_quotes(ast.SIMPLE_SANS_ARG))), ), ( 'token is the name of a simple expression, but it is on the next line', remaining_source('', [ast.SIMPLE_SANS_ARG]), ), ] for case_name, source in cases: with self.subTest(grammar=grammar_description, case_name=case_name): with self.assertRaises(SingleInstructionInvalidArgumentException): sut.parse_from_parse_source(grammar, source)
def test_fail(self): symbol_name = 'the_symbol_name' for grammar_description, grammar in GRAMMARS: cases = [ NameAndValue( 'symbol name is quoted', remaining_source( str(surrounded_by_hard_quotes(symbol_name))), ), NameAndValue( 'symbol reference syntax with invalid symbol name character: space', remaining_source( symbol_reference_syntax_for_name('the symbol')), ), NameAndValue( 'symbol reference syntax with invalid symbol name character: &', remaining_source( symbol_reference_syntax_for_name('the&symbol')), ), ] for case in cases: with self.subTest(grammar=grammar_description, case_name=case.name): parser = self.parser_maker.make( grammar, must_be_on_current_line=True) with self.assertRaises( SingleInstructionInvalidArgumentException): parser.parse(case.value)
def test(self): for must_be_on_current_line in [False, True]: for grammar in GRAMMARS: parser = self.parser_maker.make(grammar.value, must_be_on_current_line) cases = [ NameAndValue( 'source is just space', remaining_source(' '), ), NameAndValue( 'first token quoted/soft', remaining_source( str(surrounded_by_soft_quotes('token'))), ), NameAndValue( 'first token quoted/hard', remaining_source( str(surrounded_by_hard_quotes('token'))), ), NameAndValue( 'missing )', remaining_source('( {primitive} '.format( primitive=ast.PRIMITIVE_SANS_ARG)), ), ] for case in cases: with self.subTest( grammar=grammar.name, must_be_on_current_line=must_be_on_current_line, case_name=case.name): with self.assertRaises( SingleInstructionInvalidArgumentException): parser.parse(case.value)
def test_failing_parse(self): cases = [ NameAndValue( 'missing argument', '', ), NameAndValue( 'single quoted argument', str(surrounded_by_hard_quotes(arg_syntax.arbitrary_single_line_value_that_must_not_be_quoted())), ), NameAndValue( 'non-transformer name that is not a valid symbol name', NOT_A_VALID_SYMBOL_NAME, ), ] # ARRANGE # defined_name = 'defined_name' parser = sut.EmbryoParser() for case in cases: with self.subTest(case.name): source = single_line_source( src('{string_matcher_type} {defined_name} = {matcher_argument}', defined_name=defined_name, matcher_argument=case.value), ) with self.assertRaises(SingleInstructionInvalidArgumentException): # ACT & ASSERT # parser.parse(ARBITRARY_FS_LOCATION_INFO, source)
def test_failing_parse(self): cases = [ NameAndValue( 'missing argument', '', ), NameAndValue( 'single quoted argument', str( surrounded_by_hard_quotes( arg_syntax. arbitrary_single_line_value_that_must_not_be_quoted()) ), ), NameAndValue( 'non-transformer name that is not a valid symbol name', NOT_A_VALID_SYMBOL_NAME, ), ] # ARRANGE # defined_name = 'defined_name' parser = sut.EmbryoParser() for case in cases: with self.subTest(case.name): source = single_line_source( src2(ValueType.STRING_MATCHER, defined_name, case.value), ) with self.assertRaises( SingleInstructionInvalidArgumentException): # ACT & ASSERT # parser.parse(ARBITRARY_FS_LOCATION_INFO, source)
def test_failing_parse(self): cases = [ NameAndValue( 'missing argument', '', ), NameAndValue( 'single quoted argument', str(surrounded_by_hard_quotes(arg_syntax.FilesCondition.empty())), ), NameAndValue( 'non-transformer name that is not a valid symbol name', NOT_A_VALID_SYMBOL_NAME, ), ] # ARRANGE # defined_name = 'defined_name' parser = sut.EmbryoParser() for case in cases: with self.subTest(case.name): source = remaining_source( src__const(ValueType.FILES_CONDITION, defined_name, case.value), ) with self.assertRaises(SingleInstructionInvalidArgumentException): # ACT & ASSERT # parser.parse(ARBITRARY_FS_LOCATION_INFO, source)
def test_failing_parse(self): cases = [ NameAndValue( 'single quoted argument', str(surrounded_by_hard_quotes(NAME_MATCHER_NAME)), ), NameAndValue( 'non-selector name that is not a valid symbol name', NOT_A_VALID_SYMBOL_NAME, ), NameAndValue( 'missing matcher', '', ), ] # ARRANGE # defined_name = 'defined_name' parser = sut.EmbryoParser() for case in cases: with self.subTest(name=case.name): source = single_line_source( src2(ValueType.FILE_MATCHER, defined_name, case.value), ) with self.assertRaises( SingleInstructionInvalidArgumentException): # ACT & ASSERT # parser.parse(ARBITRARY_FS_LOCATION_INFO, source)
def test_quoted_tokens(self): # ARRANGE # regex_str = '.* regex' matches_for_case_sensitive = [' regex', 'before regex after'] option_cases = [ option_case_for_no_option( _AssertPattern(regex_str, matching_strings=matches_for_case_sensitive, non_matching_string=' REGEX') ), option_case_for_ignore_case( _AssertPattern(regex_str, matching_strings=matches_for_case_insensitive(matches_for_case_sensitive), non_matching_string='regex') ), ] text_on_following_line = 'text on following line' source_cases = [ SourceCase( 'soft quotes', source= Arguments('{regex}'.format( regex=surrounded_by_soft_quotes(regex_str), )), source_assertion= assert_token_stream(is_null=asrt.is_true), ), SourceCase( 'hard quotes, and text on following line', source= Arguments('{regex}'.format( regex=surrounded_by_hard_quotes(regex_str), ), following_lines=[text_on_following_line]), source_assertion= assert_token_stream( remaining_source=asrt.equals('\n' + text_on_following_line)), ), ] # ACT & ASSERT # check_many(self, Arrangement(), source_cases, ExpectationExceptPattern( validation=all_validations_passes() ), option_cases, )
def test_quoted_tokens(self): # ARRANGE # regex_str = '.* regex' matches_for_case_sensitive = [' regex', 'before regex after'] option_cases = [ option_case_for_no_option( _AssertPattern(regex_str, matching_strings=matches_for_case_sensitive, non_matching_string=' REGEX') ), option_case_for_ignore_case( _AssertPattern(regex_str, matching_strings=matches_for_case_insensitive(matches_for_case_sensitive), non_matching_string='regex') ), ] text_on_following_line = 'text on following line' source_cases = [ SourceCase( 'soft quotes', source= Arguments('{regex}'.format( regex=surrounded_by_soft_quotes(regex_str), )), source_assertion= assert_token_stream(is_null=asrt.is_true), ), SourceCase( 'hard quotes, and text on following line', source= Arguments('{regex}'.format( regex=surrounded_by_hard_quotes(regex_str), ), following_lines=[text_on_following_line]), source_assertion= assert_token_stream( remaining_source=asrt.equals('\n' + text_on_following_line)), ), ] # ACT & ASSERT # check_many(self, Arrangement(), source_cases, ExpectationExceptPattern( validation=ValidationAssertions.all_passes() ), option_cases, )
def test_successful_parse_of_expr_sans_argument(self): space_after = ' ' token_after = str(surrounded_by_hard_quotes('not an expression')) format_map = { 'primitive_expr': ast.PRIMITIVE_SANS_ARG, 'space_after': space_after, 'token_after': token_after, } def source(s: str) -> str: return s.format_map(format_map) cases = [ SourceCase('first line is only primitive expr', source('{primitive_expr}'), SourceExpectation.is_at_end_of_line(1)), SourceCase( 'first line is primitive expr with space around', source(' {primitive_expr}{space_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=space_after[1:])), SourceCase( 'expression is followed by non-expression', source('{primitive_expr} {token_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=token_after)), SourceCase( '( primitive )', source('( {primitive_expr} )'), SourceExpectation.is_at_end_of_line(1), ), SourceCase( '( primitive ) followed by non-expression', source('( {primitive_expr} ) {token_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=token_after), ), SourceCase( '( ( primitive ) )', source('( ( {primitive_expr} ) )'), SourceExpectation.is_at_end_of_line(1), ), ] # ACT & ASSERT # parse_check.check_with_must_be_on_current_line_variants( self, self.parser_maker, ast.PrimitiveSansArg(), GRAMMARS, cases, )
def test_successful_parse_of_quoted_tokens(self): # ARRANGE # regex_str = 'the regex' replacement_str = 'the replacement' text_on_following_line = 'text on following line' expected_resolver = resolved_value_is_replace_transformer(regex_str, replacement_str) cases = [ SourceCase( 'soft quotes', source= remaining_source('{regex} {replacement}'.format( regex=surrounded_by_soft_quotes(regex_str), replacement=surrounded_by_soft_quotes(replacement_str), )), source_assertion= assert_token_stream(is_null=asrt.is_true), ), SourceCase( 'hard quotes, and text on following line', source= remaining_source('{regex} {replacement}'.format( regex=surrounded_by_hard_quotes(regex_str), replacement=surrounded_by_hard_quotes(replacement_str), ), following_lines=[text_on_following_line]), source_assertion= assert_token_stream( remaining_source=asrt.equals('\n' + text_on_following_line)), ), ] for case in cases: with self.subTest(case_name=case.name): self._check(case.source, Expectation(expected_resolver, case.source_assertion))
def test_successful_parse(self): symbol_name = 'the_symbol_name' space_after = ' ' token_after = str(surrounded_by_hard_quotes('not an expression')) for grammar_description, grammar in self.grammars: cases = [ SourceCase( 'first line is only simple expr', source= remaining_source('{symbol_name}'.format( symbol_name=symbol_name, )), source_assertion= asrt_source.is_at_end_of_line(1) ), SourceCase( 'first line is simple expr with space around', source= remaining_source(' {symbol_name}{space_after}'.format( symbol_name=symbol_name, space_after=space_after)), source_assertion= asrt_source.source_is_not_at_end(current_line_number=asrt.equals(1), remaining_part_of_current_line=asrt.equals(space_after[1:])) ), SourceCase( 'expression is followed by non-expression', source= remaining_source('{symbol_name} {token_after}'.format( symbol_name=symbol_name, token_after=token_after)), source_assertion= asrt_source.source_is_not_at_end(current_line_number=asrt.equals(1), remaining_part_of_current_line=asrt.equals(token_after)) ), ] for case in cases: with self.subTest(grammar=grammar_description, name=case.name): self._check( Arrangement( grammar=grammar, source=case.source), Expectation( expression=ast.RefExpr(symbol_name), source=case.source_assertion, ) )
def test_fail(self): symbol_name = 'the_symbol_name' for grammar_description, grammar in self.grammars: cases = [ ( 'symbol name is quoted', remaining_source(str(surrounded_by_hard_quotes(symbol_name))), ), ] for case_name, source in cases: with self.subTest(grammar=grammar_description, case_name=case_name): with self.assertRaises(SingleInstructionInvalidArgumentException): sut.parse_from_parse_source(grammar, source)
def test_successful_parse(self): symbol_name = 'the_symbol_name' space_after = ' ' token_after = str(surrounded_by_hard_quotes('not an expression')) symbol_ref_syntax_cases = [ NameAndValue( 'plain', symbol_name, ), NameAndValue( 'reference syntax', symbol_reference_syntax_for_name(symbol_name), ), ] def cases_for_symbol_syntax( symbol_reference: NameAndValue[str]) -> List[SourceCase]: sf = StringFormatter({ 'symbol_name': symbol_reference.value, 'space_after': space_after, 'token_after': token_after, }) def source(template: str) -> str: return sf.format(template) def name(case: str) -> str: return 'symbol_syntax={} / {}'.format(symbol_reference.name, case) return [ SourceCase(name('first line is only primitive expr'), source('{symbol_name}'), SourceExpectation.is_at_end_of_line(1)), SourceCase( name('first line is primitive expr with space around'), source(' {symbol_name}{space_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=space_after[1:])), SourceCase( name('expression is followed by non-expression'), source('{symbol_name} {token_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=token_after)), ]
def test_back_slash_should_not_separate_parts(self): # ARRANGE # file_name_with_back_slash = '\\'.join(FILE_NAME_PARTS) expected_file_names = { PurePosixPath(file_name_with_back_slash): asrt.is_none } source = args.FilesCondition([ args.FileCondition( surrounded_by_hard_quotes(file_name_with_back_slash)), ]) # ACT & ASSERT # CHECKER.check__w_source_variants( self, source.as_arguments, None, arrangement_wo_tcds(), Expectation( ParseExpectation(), ExecutionExpectation(), primitive=prim_asrt__constant( asrt_primitive.files_matches(expected_file_names))))
def runTest(self): # ARRANGE # atc_file_name = 'existing-file.py' arg_1 = 'un-quoted' arg_2 = 'single quoted' arg_3 = 'double quoted' act_line_1 = '{} {} {} {}'.format( atc_file_name, arg_1, surrounded_by_hard_quotes(arg_2), surrounded_by_soft_quotes(arg_3), ) atc_line_2 = '' act_phase_instructions = [instr([act_line_1]), instr([atc_line_2])] executor_that_records_arguments = CommandExecutorThatRecordsArguments() arrangement = integration_check.arrangement_w_tcds( hds_contents=contents_in(RelHdsOptionType.REL_HDS_ACT, DirContents([ File.empty(atc_file_name)])), process_execution=ProcessExecutionArrangement( os_services=os_services_access.new_for_cmd_exe(executor_that_records_arguments) ) ) expected_command = asrt_command.matches_command( driver=asrt_command.matches_executable_file_command_driver(asrt.anything_goes()), arguments=asrt.matches_sequence([ asrt_path.str_as_path(asrt_path.name_equals(atc_file_name)), asrt.equals(arg_1), asrt.equals(arg_2), asrt.equals(arg_3), ]) ) expectation = integration_check.Expectation( after_execution=ExecutedCommandAssertion(executor_that_records_arguments, lambda tcds: expected_command) ) # ACT & ASSERT # integration_check.check_execution(self, ACTOR_THAT_RUNS_PYTHON_PROGRAM_FILE, act_phase_instructions, arrangement, expectation)
def test_fail__expr_on_following_line_is_accepted(self): cases = [ NameAndValue( 'token is not the name of a primitive expression', ast.NOT_A_PRIMITIVE_EXPR_NAME_AND_NOT_A_VALID_SYMBOL_NAME, ), NameAndValue( 'token is the name of a primitive expression, but it is quoted/soft', str(surrounded_by_soft_quotes(ast.PRIMITIVE_SANS_ARG)), ), NameAndValue( 'token is the name of a primitive expression, but it is quoted/hard', str(surrounded_by_hard_quotes(ast.PRIMITIVE_SANS_ARG)), ), ] parse_check.check_fail__expr_on_following_line_is_accepted( self, self.parser_maker, GRAMMARS, cases, )
def test_failing_parse(self): cases = [ ( 'single quoted argument', str(surrounded_by_hard_quotes(REPLACE_TRANSFORMER_NAME)), ), ( 'non-transformer name that is not a valid symbol name', NOT_A_VALID_SYMBOL_NAME, ), ] # ARRANGE # defined_name = 'defined_name' parser = sut.EmbryoParser() for name, rhs_source in cases: with self.subTest(name=name): source = single_line_source( src('{lines_trans_type} {defined_name} = {transformer_argument}', defined_name=defined_name, transformer_argument=rhs_source), ) with self.assertRaises(SingleInstructionInvalidArgumentException): # ACT & ASSERT # parser.parse(ARBITRARY_FS_LOCATION_INFO, source)
def test(self): grammars = [ ( 'sans complex expressions', ast.GRAMMAR_SANS_COMPLEX_EXPRESSIONS, ), ( 'with complex expressions', ast.GRAMMAR_WITH_ALL_COMPONENTS, ), ] for grammar_description, grammar in grammars: cases = [ ( 'source is just space', remaining_source(' '), ), ( 'first token quoted/soft', remaining_source(str(surrounded_by_soft_quotes('token'))), ), ( 'first token quoted/hard', remaining_source(str(surrounded_by_hard_quotes('token'))), ), ( 'missing )', remaining_source('( {simple} '.format(simple=ast.SIMPLE_SANS_ARG)), ), ] for case_name, source in cases: with self.subTest(grammar=grammar_description, case_name=case_name): with self.assertRaises(SingleInstructionInvalidArgumentException): sut.parse_from_parse_source(grammar, source)
def test_success_of_single_operator(self): space_after = ' ' quoted_string = str(surrounded_by_hard_quotes('quoted string')) valid_simple_expressions = [ ( '{simple_expression}'.format(simple_expression=ast.SIMPLE_SANS_ARG), ast.SimpleSansArg() ), ( '{simple_expression_name} {argument}'.format( simple_expression_name=ast.SIMPLE_WITH_ARG, argument='simple-expr-argument'), ast.SimpleWithArg('simple-expr-argument') ), ] operators = [ ( ast.COMPLEX_A, ast.ComplexA, ), ( ast.COMPLEX_B_THAT_IS_NOT_A_VALID_SYMBOL_NAME, ast.ComplexB, ), ] for valid_simple_expr_source, expected_simple_expr in valid_simple_expressions: for operator_source, operator_constructor in operators: expected_expression = operator_constructor([expected_simple_expr, expected_simple_expr]) cases = [ SourceCase( 'first line is just complex expr', source= remaining_source('{simple_expr} {operator} {simple_expr}'.format( simple_expr=valid_simple_expr_source, operator=operator_source, )), source_assertion= asrt_source.is_at_end_of_line(1) ), SourceCase( 'first line is complex expr, followed by space', source= remaining_source('{simple_expr} {operator} {simple_expr}{space_after}'.format( simple_expr=valid_simple_expr_source, operator=operator_source, space_after=space_after, )), source_assertion= asrt_source.source_is_not_at_end( current_line_number=asrt.equals(1), remaining_part_of_current_line=asrt.equals(space_after[1:])) ), SourceCase( 'complex expr followed by non-operator', source= remaining_source('{simple_expr} {operator} {simple_expr} {quoted_string}'.format( simple_expr=valid_simple_expr_source, operator=operator_source, quoted_string=quoted_string, )), source_assertion= asrt_source.source_is_not_at_end( current_line_number=asrt.equals(1), remaining_part_of_current_line=asrt.equals(quoted_string)) ), SourceCase( 'complex expr followed by simple expression', source= remaining_source('{simple_expr} {operator} {simple_expr} {simple_expr}'.format( simple_expr=valid_simple_expr_source, operator=operator_source, )), source_assertion= asrt_source.source_is_not_at_end( current_line_number=asrt.equals(1), remaining_part_of_current_line=asrt.equals(valid_simple_expr_source)) ), SourceCase( 'complex expr followed by quoted operator', source= remaining_source('{simple_expr} {operator} {simple_expr} {quoted_operator}'.format( simple_expr=valid_simple_expr_source, operator=operator_source, quoted_operator=surrounded_by_soft_quotes(operator_source), )), source_assertion= asrt_source.source_is_not_at_end( current_line_number=asrt.equals(1), remaining_part_of_current_line=asrt.equals(str(surrounded_by_soft_quotes(operator_source)))) ), SourceCase( 'first line is just complex expr: inside ()', source= remaining_source('( {simple_expr} {operator} {simple_expr} )'.format( simple_expr=valid_simple_expr_source, operator=operator_source, )), source_assertion= asrt_source.is_at_end_of_line(1) ), SourceCase( 'first simple expr inside ()', source= remaining_source('( {simple_expr} ) {operator} {simple_expr}'.format( simple_expr=valid_simple_expr_source, operator=operator_source, )), source_assertion= asrt_source.is_at_end_of_line(1) ), SourceCase( 'second simple expr inside ()', source= remaining_source('{simple_expr} {operator} ( {simple_expr} )'.format( simple_expr=valid_simple_expr_source, operator=operator_source, )), source_assertion= asrt_source.is_at_end_of_line(1) ), SourceCase( 'second expr on following line', source= remaining_source(valid_simple_expr_source + ' ' + operator_source, [valid_simple_expr_source]), source_assertion= asrt_source.is_at_end_of_line(2) ), ] for case in cases: with self.subTest(name=case.name, operator_source=operator_source, valid_simple_expr_source=valid_simple_expr_source): _check(self, Arrangement( grammar= ast.GRAMMAR_WITH_ALL_COMPONENTS, source= case.source), Expectation( expression= expected_expression, source= case.source_assertion, ) )
from exactly_lib.util.str_.formatter import StringFormatter from exactly_lib_test.test_resources.test_utils import NIE from exactly_lib_test.util.test_resources.quoting import surrounded_by_hard_quotes SINGLE_TOKEN_NAME = 'single_token_dir_name' MULTI_LINE_NAME = 'a\nname\nthat\nspans\nmultiple\nlines\n' SF = StringFormatter({ 'single_token_name': SINGLE_TOKEN_NAME, 'quoted_multi_line_name': surrounded_by_hard_quotes(MULTI_LINE_NAME), }) SOURCE_LAYOUT_CASES = [ NIE( 'all arguments on first line', input_value=SF.format('{single_token_name}'), expected_value=SINGLE_TOKEN_NAME, ), NIE( 'path argument on following line', input_value=SF.format('\n {single_token_name}'), expected_value=SINGLE_TOKEN_NAME, ), NIE( 'multi line path argument on following line', input_value=SF.format('\n {quoted_multi_line_name}'), expected_value=MULTI_LINE_NAME, ), ]
def source_cases_for_expressions(primitive_expr: str, operator: str) -> List[SourceCase]: sf = StringFormatter({ 'primitive_expr': primitive_expr, 'operator': operator, 'quoted_operator': surrounded_by_soft_quotes(operator_source), 'space_after': ' ', 'quoted_string': surrounded_by_hard_quotes('quoted string'), }) def source(template: str) -> str: return sf.format(template) return [ SourceCase( 'first line is just infix op expr', source('{primitive_expr} {operator} {primitive_expr}'), SourceExpectation.is_at_end_of_line(1) ), SourceCase( 'first line is infix op expr, followed by space', source('{primitive_expr} {operator} {primitive_expr}{space_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=sf.format('{space_after}')[1:]) ), SourceCase( 'infix op expr followed by non-operator', source('{primitive_expr} {operator} {primitive_expr} {quoted_string}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=sf.format('{quoted_string}')) ), SourceCase( 'infix op expr followed by primitive expression', source('{primitive_expr} {operator} {primitive_expr} {primitive_expr}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=sf.format('{primitive_expr}')) ), SourceCase( 'infix op expr followed by quoted operator', source('{primitive_expr} {operator} {primitive_expr} {quoted_operator}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=sf.format('{quoted_operator}')) ), SourceCase( 'first line is just infix op expr: inside ()', source('( {primitive_expr} {operator} {primitive_expr} )'), SourceExpectation.is_at_end_of_line(1) ), SourceCase( 'first primitive expr inside ()', source('( {primitive_expr} ) {operator} {primitive_expr}'), SourceExpectation.is_at_end_of_line(1) ), SourceCase( 'second primitive expr inside ()', source('{primitive_expr} {operator} ( {primitive_expr} )'), SourceExpectation.is_at_end_of_line(1) ), SourceCase( 'second expr on following line', source('{primitive_expr} {operator}\n{primitive_expr}'), SourceExpectation.is_at_end_of_line(2) ), ]
def test_successful_parse_with_primitive_expr(self): space_after = ' ' token_after = str(surrounded_by_hard_quotes('not an expression')) primitive_expr = ast.PrimitiveSansArg() primitive_expr_src = ast.PRIMITIVE_SANS_ARG def cases_for_operator(the_prefix_operator: str) -> List[SourceCase]: sf = StringFormatter({ 'op': the_prefix_operator, 'primitive_expr': primitive_expr_src, 'space_after': space_after, 'token_after': token_after, }) return [ SourceCase('first line is only primitive expr', sf.format('{op} {primitive_expr}'), SourceExpectation.is_at_end_of_line(1)), SourceCase( 'first line is primitive expr with space around', sf.format(' {op} {primitive_expr}{space_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=space_after[1:])), SourceCase( 'expression is followed by non-expression', sf.format('{op} {primitive_expr} {token_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=token_after)), SourceCase( '( op primitive )', sf.format('( {op} {primitive_expr} )'), SourceExpectation.is_at_end_of_line(1), ), SourceCase( 'op ( primitive )', sf.format('{op} ( {primitive_expr} )'), SourceExpectation.is_at_end_of_line(1), ), SourceCase( 'no source after operator, but expr on following line', sf.format('{op}\n{primitive_expr}'), SourceExpectation.is_at_end_of_line(2), ), ] operator_cases = [ (prefix_operator, mk_prefix_expr(primitive_expr), cases_for_operator(prefix_operator)) for prefix_operator, mk_prefix_expr in self.PREFIX_OPERATORS ] for grammar in GRAMMARS: for operator_case in operator_cases: cases = current_line_case_variants_for_grammar( operator_case[1], grammar.value, operator_case[2]) for case in cases: with self.subTest(grammar=grammar.name, prefix_operator=operator_case[0], name=case.name): parse_check.check( self, self.parser_maker, case.arrangement, case.expectation, )
def test_successful_parse_of_expr_with_argument(self): the_argument = 'the-argument' space_after = ' ' token_after = str(surrounded_by_hard_quotes('not an expression')) for grammar_description, grammar in self.grammars: cases = [ SourceCase( 'first line is only simple expr', source= remaining_source('{simple_with_arg} {argument}'.format( simple_with_arg=ast.SIMPLE_WITH_ARG, argument=the_argument)), source_assertion= asrt_source.is_at_end_of_line(1) ), SourceCase( 'first line is simple expr with space around', source= remaining_source(' {simple_with_arg} {argument}{space_after}'.format( simple_with_arg=ast.SIMPLE_WITH_ARG, argument=the_argument, space_after=space_after)), source_assertion= asrt_source.source_is_not_at_end(current_line_number=asrt.equals(1), remaining_part_of_current_line=asrt.equals(space_after[1:])) ), SourceCase( 'expression is followed by non-expression', source= remaining_source(' {simple_with_arg} {argument} {token_after}'.format( simple_with_arg=ast.SIMPLE_WITH_ARG, argument=the_argument, token_after=token_after)), source_assertion= asrt_source.source_is_not_at_end(current_line_number=asrt.equals(1), remaining_part_of_current_line=asrt.equals(token_after)) ), SourceCase( '( simple )', source= remaining_source('( {simple_with_arg} {argument} )'.format( simple_with_arg=ast.SIMPLE_WITH_ARG, argument=the_argument, )), source_assertion= asrt_source.is_at_end_of_line(1), ), SourceCase( '( ( simple ) )', source= remaining_source('( ( {simple_with_arg} {argument} ) )'.format( simple_with_arg=ast.SIMPLE_WITH_ARG, argument=the_argument, )), source_assertion= asrt_source.is_at_end_of_line(1), ), ] for case in cases: with self.subTest(grammar=grammar_description, name=case.name): self._check( Arrangement( grammar=grammar, source=case.source), Expectation( expression=ast.SimpleWithArg(the_argument), source=case.source_assertion, ) )
def test_successful_parse_of_expr_with_argument(self): # ARRANGE # the_argument = 'the-argument' space_after = ' ' token_after = str(surrounded_by_hard_quotes('not an expression')) format_map = { 'primitive_with_arg': ast.PRIMITIVE_WITH_ARG, 'argument': the_argument, 'space_after': space_after, 'token_after': token_after, } def source(s: str) -> str: return s.format_map(format_map) cases = [ SourceCase('first line is only primitive expr', source('{primitive_with_arg} {argument}'), SourceExpectation.is_at_end_of_line(1)), SourceCase( 'first line is primitive expr with space around', source(' {primitive_with_arg} {argument}{space_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=space_after[1:])), SourceCase( 'expression is followed by non-expression', source(' {primitive_with_arg} {argument} {token_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=token_after)), SourceCase( '( primitive )', source('( {primitive_with_arg} {argument} )'), SourceExpectation.is_at_end_of_line(1), ), SourceCase( 'primitive, within parentheses, with tokens on separate lines', source('( \n {primitive_with_arg} \n {argument} \n )'), SourceExpectation.is_at_end_of_line(4), ), SourceCase( 'primitive, within parentheses, with expression tokens on separate lines, followed by non-expression', source( '( \n {primitive_with_arg} \n {argument} \n ) {token_after}' ), SourceExpectation.source_is_not_at_end( current_line_number=4, remaining_part_of_current_line=token_after), ), SourceCase( '( ( primitive ) )', source('( ( {primitive_with_arg} {argument} ) )'), SourceExpectation.is_at_end_of_line(1), ), ] # ACT & ASSERT # parse_check.check_with_must_be_on_current_line_variants( self, self.parser_maker, ast.PrimitiveWithArg(the_argument), GRAMMARS, cases, )
def test_successful_parse_with_simple_expr(self): space_after = ' ' token_after = str(surrounded_by_hard_quotes('not an expression')) simple_expr = ast.SimpleSansArg() simple_expr_src = ast.SIMPLE_SANS_ARG for grammar_description, grammar in self.grammars: for prefix_operator, mk_prefix_expr in self.prefix_operators: cases = [ SourceCase( 'first line is only simple expr', source= remaining_source('{op} {simple_expr}'.format( op=prefix_operator, simple_expr=simple_expr_src, )), source_assertion= asrt_source.is_at_end_of_line(1) ), SourceCase( 'first line is simple expr with space around', source= remaining_source(' {op} {simple_expr}{space_after}'.format( op=prefix_operator, simple_expr=simple_expr_src, space_after=space_after)), source_assertion= asrt_source.source_is_not_at_end(current_line_number=asrt.equals(1), remaining_part_of_current_line=asrt.equals(space_after[1:])) ), SourceCase( 'expression is followed by non-expression', source= remaining_source('{op} {simple_expr} {token_after}'.format( op=prefix_operator, simple_expr=simple_expr_src, token_after=token_after)), source_assertion= asrt_source.source_is_not_at_end(current_line_number=asrt.equals(1), remaining_part_of_current_line=asrt.equals(token_after)) ), SourceCase( '( op simple )', source= remaining_source('( {op} {simple_expr} )'.format( op=prefix_operator, simple_expr=simple_expr_src, token_after=token_after)), source_assertion= asrt_source.is_at_end_of_line(1), ), SourceCase( 'op ( simple )', source= remaining_source('{op} ( {simple_expr} )'.format( op=prefix_operator, simple_expr=simple_expr_src, token_after=token_after)), source_assertion= asrt_source.is_at_end_of_line(1), ), ] for case in cases: with self.subTest(grammar=grammar_description, prefix_operator=prefix_operator, name=case.name): self._check( Arrangement( grammar=grammar, source=case.source), Expectation( expression=mk_prefix_expr(simple_expr), source=case.source_assertion, ) )