def test_element_parser_SHOULD_be_able_to_report_syntax_error_by_returning_None(self): # ARRANGE # section_name = 'section-name' unknown_section_name = 'unknown-section-name' parser = new_parser_for( SectionsConfiguration([SectionConfiguration(section_name, SectionElementParserThatReturnsNone())], default_section_name=section_name)) unrecognized_line = 'unrecognized' cases = [ NEA('unrecognized source inside declared section', actual=[section_header(section_name), unrecognized_line, 'following line'], expected=matches_file_source_error( maybe_section_name=asrt.equals(section_name), location_path=[ SourceLocation(single_line_sequence(2, unrecognized_line), EXPECTED_SOURCE_FILE_PATH) ]) ), NEA('unrecognized source in default section', actual=[unrecognized_line, 'following line'], expected=matches_file_source_error( maybe_section_name=asrt.equals(section_name), location_path=[ SourceLocation(single_line_sequence(1, unrecognized_line), EXPECTED_SOURCE_FILE_PATH) ]) ), NEA('unrecognized section name', actual=[section_header(unknown_section_name), 'following line'], expected=matches_file_source_error( maybe_section_name=asrt.is_none, location_path=[ SourceLocation(single_line_sequence(1, section_header(unknown_section_name)), EXPECTED_SOURCE_FILE_PATH) ]) ), ] for nea in cases: with self.subTest(nea.name): with self.assertRaises(FileSourceError) as cm: # ACT & ASSERT # self._parse_lines(parser, nea.actual) nea.expected.apply_without_message(self, cm.exception)
def test_fail_when_end_marker_not_found(self): first_line = '<<MARKER' following_lines_cases = [ [ 'not marker', syntax.section_header('section-name'), ], [ 'not marker', ], [], [ ' MARKER', ], [ 'MARKER ', ], [ 'NOT_MARKER', ], ] for following_lines in following_lines_cases: for is_mandatory in [False, True]: parser = sut.HereDocParser(is_mandatory) with self.subTest(msg=repr((is_mandatory, following_lines))): with self.assertRaises( sut.HereDocumentContentsParsingException): parser.parse( remaining_source(first_line, following_lines))
def __init__(self, name: str): self._name = name self._formats = { self.SYNTAX: section_header(name), self.PLAIN: name, self.EMPHASIS: emphasis(name), self.DEFAULT: emphasis(name), }
def _check_failing_line(self, configuration: sut.Configuration, phases: Sequence[Phase], invalid_line_cases: Sequence[NameAndValue[SourceAndStatus]]): proc_cases = [ NameAndValue('not allowed to pollute current process', sut.new_processor_that_should_not_pollute_current_process(configuration)), NameAndValue('allowed to pollute current process', sut.new_processor_that_is_allowed_to_pollute_current_process(configuration)), ] for phase in phases: for invalid_line_case in invalid_line_cases: source_and_status = invalid_line_case.value assert isinstance(source_and_status, SourceAndStatus) # Type info for IDE file_with_error = fs.file_with_lines('file-with-error.src', [ source_and_status.failing_source_line, ]) erroneous_line = single_line_sequence(1, source_and_status.failing_source_line) test_case_file = fs.file_with_lines('test.case', [ section_header(phase.section_name), directive_for_inclusion_of_file(file_with_error.name), ]) line_that_includes_erroneous_file = single_line_sequence(2, directive_for_inclusion_of_file( file_with_error.name)) cwd_contents = fs.DirContents([test_case_file, file_with_error]) expected_source_location_path = SourceLocationPath( location=SourceLocation(erroneous_line, pathlib.Path(file_with_error.name)), file_inclusion_chain=[SourceLocation(line_that_includes_erroneous_file, pathlib.Path(test_case_file.name))]) for proc_case in proc_cases: with self.subTest(phase=phase.section_name, proc=proc_case.name, line=erroneous_line.first_line): processor = proc_case.value assert isinstance(processor, Processor) with tmp_dir_as_cwd(cwd_contents): test_case_reference = test_case_reference_of_source_file(pathlib.Path(test_case_file.name)) # ACT # result = processor.apply(test_case_reference) # ASSERT # assert isinstance(result, Result) # Type info for IDE source_and_status.expected_result_statuses.apply_with_message(self, result, 'result statuses') source_location_path_expectation = equals_source_location_path( expected_source_location_path) source_location_path_expectation.apply_with_message(self, result.source_location_path, 'source location path')
def _text_parser() -> TextParser: return TextParser({ 'phase_declaration_for_NAME': section_header('NAME'), 'instr': AnyInstructionNameDictionary(), 'instruction': concepts.INSTRUCTION_CONCEPT_INFO.name, 'instruction_description': defs.INSTRUCTION_DESCRIPTION, 'description_delimiter': defs.DESCRIPTION_DELIMITER, 'description_delimiter_char_name': defs.DESCRIPTION_DELIMITER_CHAR_NAME, 'default_phase': phase_names.PHASE_NAME_DICTIONARY[DEFAULT_PHASE.identifier].syntax, 'phase': phase_names.PHASE_NAME_DICTIONARY, 'actor': formatting.concept_(ACTOR_CONCEPT_INFO), 'CONTENTS_EQUALS_ARGUMENT': contents_opts.EQUALS_ARGUMENT, 'CONTENTS_EMPTY_ARGUMENT': contents_opts.EMPTY_ARGUMENT, 'line_comment_char': LINE_COMMENT_MARKER, 'file_inclusion_directive_in_text': formatting.keyword(directives.INCLUDING_DIRECTIVE_INFO.singular_name), 'file_inclusion_directive': directives.INCLUDING_DIRECTIVE_INFO.singular_name, 'shell_command': formatting.misc_name_with_formatting(misc_texts.SHELL_COMMAND), 'plain_string': misc_texts.PLAIN_STRING, 'instruction__shell_cmd_line': instruction_names.SHELL_INSTRUCTION_NAME, 'instruction__stdout': instruction_names.CONTENTS_OF_STDOUT_INSTRUCTION_NAME, 'instruction__stderr': instruction_names.CONTENTS_OF_STDERR_INSTRUCTION_NAME, 'instruction__exit_code': instruction_names.EXIT_CODE_INSTRUCTION_NAME, 'INT_EQUALS_OPERATOR': comparators.EQ.name, 'HERE_DOCUMENT_MARKER_PREFIX': string.HERE_DOCUMENT_MARKER_PREFIX, 'MARKER': 'EOF', 'sds_result_dir': sds.SUB_DIRECTORY__RESULT, 'sds_stdout_file': sds.RESULT_FILE__STDOUT, })
def test_failing_parse(self): # ARRANGE # test_case_definition = test_case_definition_for(instruction_set()) actor = ActorThatRunsConstantActions() test_case_source = lines_content([ section_header(phase_identifier.SETUP.identifier), 'not_the_name_of_an_instruction', ]) expectation = Expectation(NO_EXECUTION__SYNTAX_ERROR, output_is_empty) # ACT & ASSERT # _check(self, test_case_definition, actor, test_case_source, self.sandbox_dir_resolver_that_should_not_be_called, expectation)
def test_inclusion_of_non_exiting_file_SHOULD_cause_file_access_error( self): # ARRANGE # name_of_non_existing_file = 'non-existing.src' configuration = configuration_with_no_instructions_and_no_preprocessor( ) proc_cases = [ NameAndValue( 'not allowed to pollute current process', sut.new_processor_that_should_not_pollute_current_process( configuration)), NameAndValue( 'allowed to pollute current process', sut.new_processor_that_is_allowed_to_pollute_current_process( configuration)), ] for phase in phase_identifier.ALL_WITH_INSTRUCTIONS: for proc_case in proc_cases: with self.subTest(phase.section_name, proc=proc_case.name): test_case_file = fs.file_with_lines( 'test.case', [ section_header(phase.section_name), directive_for_inclusion_of_file( name_of_non_existing_file), ]) cwd_contents = fs.DirContents([test_case_file]) processor = proc_case.value assert isinstance(processor, Processor) with tmp_dir_as_cwd(cwd_contents): test_case_reference = test_case_reference_of_source_file( pathlib.Path(test_case_file.name)) # ACT # result = processor.apply(test_case_reference) # ASSERT # assert isinstance(result, Result) # Type info for IDE self.assertEqual(Status.ACCESS_ERROR, result.status) self.assertEqual(AccessErrorType.FILE_ACCESS_ERROR, result.access_error_type) source_location_path_expectation = equals_source_location_path( source_location_path_of( pathlib.Path(test_case_file.name), Line( 2, directive_for_inclusion_of_file( name_of_non_existing_file)))) source_location_path_expectation.apply_with_message( self, result.error_info.source_location_path, 'source location path')
def test_inclusion_of_file_SHOULD_be_possible_in_all_phases_except_act( self): # ARRANGE # name_of_recording_instruction = 'recording-instruction' file_to_include = fs.file_with_lines('included-file.src', [ name_of_recording_instruction, ]) proc_cases = [ NameAndValue( 'not allowed to pollute current process', sut.new_processor_that_should_not_pollute_current_process), NameAndValue( 'allowed to pollute current process', sut.new_processor_that_is_allowed_to_pollute_current_process), ] for phase in phase_identifier.ALL_WITH_INSTRUCTIONS: for proc_case in proc_cases: with self.subTest(phase.section_name, proc=proc_case.name): test_case_file = fs.file_with_lines( 'test.case', [ section_header(phase.section_name), directive_for_inclusion_of_file( file_to_include.name), ]) cwd_contents = fs.DirContents( [test_case_file, file_to_include]) recording_output = [] configuration = configuration_with_instruction_in_each_phase_that_records_phase_name( name_of_recording_instruction, recording_output) processor = proc_case.value(configuration) with tmp_dir_as_cwd(cwd_contents): test_case_reference = test_case_reference_of_source_file( pathlib.Path(test_case_file.name)) # ACT # result = processor.apply(test_case_reference) # ASSERT # assert isinstance(result, Result) # Type info for IDE self.assertEqual(Status.EXECUTED, result.status) self.assertFalse(result.execution_result.is_failure) self.assertEqual(FullExeResultStatus.PASS, result.execution_result.status) self.assertEqual([phase.section_name], recording_output)
def test_inclusion_of_file_SHOULD_be_possible_in_all_phases_except_act(self): # ARRANGE # name_of_recording_instruction = 'recording-instruction' file_to_include = fs.file_with_lines('included-file.src', [ name_of_recording_instruction, ]) proc_cases = [ NameAndValue('not allowed to pollute current process', sut.new_processor_that_should_not_pollute_current_process), NameAndValue('allowed to pollute current process', sut.new_processor_that_is_allowed_to_pollute_current_process), ] for phase in phase_identifier.ALL_WITH_INSTRUCTIONS: for proc_case in proc_cases: with self.subTest(phase.section_name, proc=proc_case.name): test_case_file = fs.file_with_lines('test.case', [ section_header(phase.section_name), directive_for_inclusion_of_file(file_to_include.name), ]) cwd_contents = fs.DirContents([test_case_file, file_to_include]) recording_output = [] configuration = configuration_with_instruction_in_each_phase_that_records_phase_name( name_of_recording_instruction, recording_output) processor = proc_case.value(configuration) with tmp_dir_as_cwd(cwd_contents): test_case_reference = test_case_reference_of_source_file(pathlib.Path(test_case_file.name)) # ACT # result = processor.apply(test_case_reference) # ASSERT # assert isinstance(result, Result) # Type info for IDE self.assertEqual(Status.EXECUTED, result.status) self.assertFalse(result.execution_result.is_failure) self.assertEqual(FullExeResultStatus.PASS, result.execution_result.status) self.assertEqual([phase.section_name], recording_output)
def _check_instruction(put: unittest.TestCase, mk_sds_resolver: Callable[[str], SandboxRootDirNameResolver], case: Case): # ARRANGE # instruction_name = 'the_instruction' test_case_definition = test_case_definition_for( case.arrangement.instruction_setup_with_the_instruction(instruction_name)) test_case_source = lines_content([ section_header(case.arrangement.phase.identifier), instruction_name, ]) _check(put, test_case_definition, ActorThatRunsConstantActions(), test_case_source, mk_sds_resolver, case.expectation)
def test_inclusion_of_non_exiting_file_SHOULD_cause_file_access_error(self): # ARRANGE # name_of_non_existing_file = 'non-existing.src' configuration = configuration_with_no_instructions_and_no_preprocessor() proc_cases = [ NameAndValue('not allowed to pollute current process', sut.new_processor_that_should_not_pollute_current_process(configuration)), NameAndValue('allowed to pollute current process', sut.new_processor_that_is_allowed_to_pollute_current_process(configuration)), ] for phase in phase_identifier.ALL_WITH_INSTRUCTIONS: for proc_case in proc_cases: with self.subTest(phase.section_name, proc=proc_case.name): test_case_file = fs.file_with_lines('test.case', [ section_header(phase.section_name), directive_for_inclusion_of_file(name_of_non_existing_file), ]) cwd_contents = fs.DirContents([test_case_file]) processor = proc_case.value assert isinstance(processor, Processor) with tmp_dir_as_cwd(cwd_contents): test_case_reference = test_case_reference_of_source_file(pathlib.Path(test_case_file.name)) # ACT # result = processor.apply(test_case_reference) # ASSERT # assert isinstance(result, Result) # Type info for IDE self.assertEqual(Status.ACCESS_ERROR, result.status) self.assertEqual(AccessErrorType.FILE_ACCESS_ERROR, result.access_error_type) source_location_path_expectation = equals_source_location_path( source_location_path_of(pathlib.Path(test_case_file.name), Line(2, directive_for_inclusion_of_file(name_of_non_existing_file)))) source_location_path_expectation.apply_with_message(self, result.error_info.source_location_path, 'source location path')
def test_case(self) -> str: return lines_content([ section_header(phase_identifier.SETUP.section_name), 'invalid test case that will would PARSE-ERROR, if it was not preprocessed' ])
from exactly_lib_test.test_resources.main_program import main_program_check_for_test_case from exactly_lib_test.test_resources.process import SubProcessResultInfo from exactly_lib_test.test_resources.value_assertions import process_result_info_assertions from exactly_lib_test.test_resources.value_assertions.value_assertion import Assertion IF_BASENAME_IS_PASS_THEN_EMPTY_TC_ELSE_TC_THAT_WILL_CAUSE_PARSER_ERROR = """ import sys import os.path import os basename = os.path.basename(sys.argv[1]) if basename == 'pass': print('{section_header_for_phase_with_instructions}' + os.linesep + '# valid empty test case that PASS') else: print('{section_header_for_phase_with_instructions}' + os.linesep + 'invalid test case that will cause PARSER-ERROR') """.format(section_header_for_phase_with_instructions=section_header( phase_identifier.SETUP.section_name)) class TransformationIntoTestCaseThatPass( main_program_check_for_test_case.SetupWithPreprocessorAndTestActor): def file_argument_base_name(self) -> str: return 'pass' def test_case(self) -> str: return lines_content([ section_header(phase_identifier.SETUP.section_name), 'invalid test case that will would PARSE-ERROR, if it was not preprocessed' ]) def preprocessor_source(self) -> str: return IF_BASENAME_IS_PASS_THEN_EMPTY_TC_ELSE_TC_THAT_WILL_CAUSE_PARSER_ERROR
def test_case(self) -> str: test_case_lines = [ section_header('invalid phase name'), ] return lines_content(test_case_lines)
def test_valid_special_characters(self): name = 'begin -_.0123456789' actual = syntax.extract_section_name_from_section_line( syntax.section_header(name)) self.assertEqual(name, actual)
def test_valid_phase_line_without_initial_space(self): name = 'name' actual = syntax.extract_section_name_from_section_line( syntax.section_header(name)) self.assertEqual(name, actual)
def test_case(self) -> str: return lines_content([ section_header(phase_identifier.SETUP.section_name), '# valid empty test case that would PASS, if it was not preprocessed' ])
def phase_header_line(phase: phase_identifier.Phase) -> str: return section_header(phase.section_name)
def test_valid_special_characters(self): name = 'begin -_.0123456789' actual = syntax.extract_section_name_from_section_line(syntax.section_header(name)) self.assertEqual(name, actual)
def _check_failing_line( self, configuration: sut.Configuration, phases: Sequence[Phase], invalid_line_cases: Sequence[NameAndValue[SourceAndStatus]]): proc_cases = [ NameAndValue( 'not allowed to pollute current process', sut.new_processor_that_should_not_pollute_current_process( configuration)), NameAndValue( 'allowed to pollute current process', sut.new_processor_that_is_allowed_to_pollute_current_process( configuration)), ] for phase in phases: for invalid_line_case in invalid_line_cases: source_and_status = invalid_line_case.value assert isinstance(source_and_status, SourceAndStatus) # Type info for IDE file_with_error = fs.file_with_lines('file-with-error.src', [ source_and_status.failing_source_line, ]) erroneous_line = single_line_sequence( 1, source_and_status.failing_source_line) test_case_file = fs.file_with_lines('test.case', [ section_header(phase.section_name), directive_for_inclusion_of_file(file_with_error.name), ]) line_that_includes_erroneous_file = single_line_sequence( 2, directive_for_inclusion_of_file(file_with_error.name)) cwd_contents = fs.DirContents( [test_case_file, file_with_error]) expected_source_location_path = SourceLocationPath( location=SourceLocation(erroneous_line, pathlib.Path( file_with_error.name)), file_inclusion_chain=[ SourceLocation(line_that_includes_erroneous_file, pathlib.Path(test_case_file.name)) ]) for proc_case in proc_cases: with self.subTest(phase=phase.section_name, proc=proc_case.name, line=erroneous_line.first_line): processor = proc_case.value assert isinstance(processor, Processor) with tmp_dir_as_cwd(cwd_contents): test_case_reference = test_case_reference_of_source_file( pathlib.Path(test_case_file.name)) # ACT # result = processor.apply(test_case_reference) # ASSERT # assert isinstance(result, Result) # Type info for IDE source_and_status.expected_result_statuses.apply_with_message( self, result, 'result statuses') source_location_path_expectation = equals_source_location_path( expected_source_location_path) source_location_path_expectation.apply_with_message( self, result.source_location_path, 'source location path')
from exactly_lib_test.test_resources.main_program import main_program_check_for_test_case from exactly_lib_test.test_resources.process import SubProcessResultInfo from exactly_lib_test.test_resources.value_assertions import process_result_info_assertions from exactly_lib_test.test_resources.value_assertions.value_assertion import ValueAssertion IF_BASENAME_IS_PASS_THEN_EMPTY_TC_ELSE_TC_THAT_WILL_CAUSE_PARSER_ERROR = """ import sys import os.path import os basename = os.path.basename(sys.argv[1]) if basename == 'pass': print('{section_header_for_phase_with_instructions}' + os.linesep + '# valid empty test case that PASS') else: print('{section_header_for_phase_with_instructions}' + os.linesep + 'invalid test case that will cause PARSER-ERROR') """.format(section_header_for_phase_with_instructions=section_header(phase_identifier.SETUP.section_name)) class TransformationIntoTestCaseThatPass(main_program_check_for_test_case.SetupWithPreprocessorAndTestActor): def file_argument_base_name(self) -> str: return 'pass' def test_case(self) -> str: return lines_content([ section_header(phase_identifier.SETUP.section_name), 'invalid test case that will would PARSE-ERROR, if it was not preprocessed' ]) def preprocessor_source(self) -> str: return IF_BASENAME_IS_PASS_THEN_EMPTY_TC_ELSE_TC_THAT_WILL_CAUSE_PARSER_ERROR
class PreprocessorIsAppliedWithTestCaseFileAsArgument( main_program_check_for_test_suite.SetupWithPreprocessor): if_basename_is_pass_then_empty_tc_else_tc_that_will_cause_parser_error = """ import sys import os.path import os basename = os.path.basename(sys.argv[1]) if basename == 'pass': print('{section_header_for_phase_with_instructions}' + os.linesep + '# valid empty test case that PASS') else: print('{section_header_for_phase_with_instructions}' + os.linesep + 'invalid test case that will cause PARSER-ERROR') """.format(section_header_for_phase_with_instructions=section_header( phase_identifier.SETUP.section_name)) def root_suite_file_based_at(self, root_path: pathlib.Path) -> pathlib.Path: return root_path / 'main.suite' def preprocessor_source(self) -> str: return self.if_basename_is_pass_then_empty_tc_else_tc_that_will_cause_parser_error def file_structure(self, root_path: pathlib.Path, python_executable_file_name: str, preprocessor_source_file_name: str) -> DirContents: preprocessor = '%s %s' % ( string_formatting.file_name(python_executable_file_name), string_formatting.file_name(preprocessor_source_file_name)) return DirContents([ File( 'main.suite', lines_content([ '[conf]', 'preprocessor = ' + preprocessor, '[cases]', 'pass', 'syntax-error' ])), File( 'pass', 'original content that would PARSE-ERROR, if it was not preprocessed' ), File( 'syntax-error', '# empty content that would PASS, if it was not preprocessed'), ]) def expected_stdout_run_lines(self, root_path: pathlib.Path) -> list: expected_line = simple_progress_reporter_output.ExpectedLine(root_path) return [ expected_line.suite_begin(root_path / 'main.suite'), expected_line.case(root_path / 'pass', EXECUTION__PASS.exit_identifier), expected_line.case(root_path / 'syntax-error', NO_EXECUTION__SYNTAX_ERROR.exit_identifier), expected_line.suite_end(root_path / 'main.suite'), ] def expected_stdout_reporting_lines(self, root_path: pathlib.Path) -> list: expected_line = simple_progress_reporter_output.ExpectedLine(root_path) return expected_line.summary_for_valid_suite(root_path, exit_values.FAILED_TESTS) def expected_exit_code(self) -> int: return exit_values.FAILED_TESTS.exit_code def _translate_actual_stdout_before_assertion( self, output_on_stdout: str) -> str: return simple_progress_reporter_output.replace_variable_output_with_placeholders( output_on_stdout)
def section_line(section_name: str) -> str: return 'In ' + section_header(section_name)
def test_valid_phase_line_without_initial_space(self): name = 'name' actual = syntax.extract_section_name_from_section_line(syntax.section_header(name)) self.assertEqual(name, actual)