Example #1
0
    def _compile_grammar(self):
        # type: () -> ParserElement
        """
        Takes the individual grammars from each registered directive and compiles them into a full test fixture grammar
        whose callback methods are the bound methods on this class instance.

        :return: The full PyParsing grammar for test fixture files.
        """
        grammars = [
            (LineEnd().suppress()).setParseAction(
                functools.partial(self._finalize_test_case)
            )
        ]

        # directives
        for directive_class in get_all_directives():
            grammars.append(
                LineStart() +
                directive_class.get_full_grammar().setParseAction(
                    functools.partial(self._ingest_directive, directive_class)
                ) +
                LineEnd()
            )

        return StringStart() + OneOrMore(MatchFirst(grammars)) + StringEnd()
Example #2
0
    def _ingest_directive(self, directive_class, active_string, location,
                          parse_result):
        """
        A callback that ingests a particular matched directive. Called by PyParsing when processing the grammar.

        :param directive_class: The matched directive class (not an instance)
        :type directive_class: type
        :param active_string: The contents of the fixture file
        :type active_string: union[str, unicode]
        :param location: The file location of the current parsing activity
        :param parse_result: The resulting PyParsing parsing object
        """
        self._line_number = get_parse_line_number(location, active_string)
        source = get_parse_line(location, active_string)
        self._fixture_source.append(source)

        if self._working_test_case and not self._working_test_case_line_number:
            self._working_test_case_line_number = self._line_number - 1

        test_case_target = self._working_test_case
        if parse_result.is_global:
            # This is actually a global directive, so we're working on those, not on a test case
            test_case_target = self._global_directives
        else:
            self._working_test_case_source.append(source)

        if parse_result.action:
            action_path = '{}.{}'.format(parse_result.action,
                                         parse_result.action_index or '0')
            if 'actions' not in test_case_target:
                test_case_target['actions'] = []

            if action_path not in test_case_target:
                if not parse_result.is_global:
                    # Global directives don't need a list of actions to run; only test cases do
                    test_case_target['actions'].append(action_path)

                if self._working_action_case:
                    # We're done parsing the previous action case and starting a new one
                    for dc in get_all_directives():
                        dc().post_parse_test_case_action(
                            self._working_action_case, test_case_target)

                test_case_target[action_path] = {}

            action_case_target = test_case_target[action_path]
            self._working_action_case = action_case_target
        else:
            # This branch handles non-action directives, such as comments, test names, test descriptions, non-action
            # time-freezing, non-action mocking, etc.
            action_case_target = test_case_target

        directive_class().ingest_from_parsed_test_fixture(
            action_case_target,
            test_case_target,
            parse_result,
            self._fixture_file_name,
            self._line_number,
        )
Example #3
0
    def setUpClass(cls):
        """
        This method is invoked one time before the test plan (all the fixtures defined in ``fixture_path``) or any of
        the normal tests in your test case are run.
        """
        cls._all_directives = get_all_directives()

        super(ServicePlanTestCase, cls).setUpClass()
Example #4
0
    def setup_class(cls):
        # type: () -> None
        """
        This method is invoked one time before the test plan (all the fixtures defined in ``fixture_path``) or any of
        the normal tests in your test case are run.
        """
        cls._all_directives = get_all_directives()

        super(ServicePlanTestCase, cls).setup_class()

        if not hasattr(cls, '_test_fixture_setup_called'):
            setattr(cls, '_test_fixture_setup_called', {})
        if not hasattr(cls, '_test_fixture_setup_succeeded'):
            setattr(cls, '_test_fixture_setup_succeeded', {})
Example #5
0
    'action': 'NAME',
    'action_index': 'NUM',
    'comment': 'PLAIN_LANGUAGE',
    'data_type': "'{}'".format("' | '".join(get_all_data_type_names())),
    'description': 'PLAIN_LANGUAGE',
    'error_code': 'NAME',
    'error_message': 'PLAIN_LANGUAGE',
    'field_name': "HYPHENATED_NAME (HYPHENATED_NAME | '.')*",
    'job_slot': "'context' | 'control'",
    'name': 'NAME',
    'reason': 'PLAIN_LANGUAGE',
    'value': 'PLAIN_LANGUAGE',
    'variable_name': 'ALPHANUM (ALPHANUM | [-_.{}])*',
}

for __directive_class in get_all_directives():
    for k, v in six.iteritems(
            __directive_class.supplies_additional_grammar_types()):
        if k not in __base_types:
            __base_types[k] = v

for k in sorted(__base_types.keys()):
    __doc__ += __wrap_documentation_line('{}: {}'.format(
        k, __base_types[k])) + '\n'
__doc__ += '\n'

for __directive_class in get_all_directives():
    __doc__ += __wrap_documentation_line(
        __directive_class.name() + ': ' +
        repr(__directive_class()).strip()) + '\n'
Example #6
0
    def _finalize_test_case(self, active_string, location, _):
        # type: (six.text_type, int, Optional[ParseResults]) -> None
        """
        Called by PyParsing at the end of each test case.

        :param active_string: The contents of the fixture file
        :param location: The file location of the current parsing activity
        """
        self._fixture_source.append('')

        if self._working_action_case:
            # We're done parsing the test case and still need to wrap up the last action in the test case
            for dc in get_all_directives():
                dc().post_parse_test_case_action(
                    self._working_action_case,
                    self._working_test_case or self._global_directives,
                )
            self._working_action_case = {}

        if not self._working_test_case:
            # just a blank line before any test cases, probably after globals or an extra blank line between tests
            return

        self._working_test_case['line_number'] = self._working_test_case_line_number
        self._working_test_case_line_number = 0

        self._working_test_case['fixture_name'] = self._fixture_name
        self._working_test_case['fixture_file_name'] = self._fixture_file_name
        self._working_test_case['source'] = self._working_test_case_source

        line_number = get_parse_line_number(location, active_string)
        if not self._working_test_case.get('name'):

            raise FixtureSyntaxError(
                '{}:{}: Test case without name'.format(self._fixture_file_name, line_number),
                file_name=self._fixture_file_name,
                line_number=line_number - 1,
            )

        if not self._working_test_case.get('description'):
            raise FixtureSyntaxError(
                '{}:{}: Test case without description'.format(self._fixture_file_name, line_number),
                file_name=self._fixture_file_name,
                line_number=line_number - 1,
            )

        if not self._working_test_case.get('actions') and not self._global_directives:
            raise FixtureSyntaxError(
                '{}:{}: Empty test case'.format(self._fixture_file_name, line_number),
                file_name=self._fixture_file_name,
                line_number=line_number - 1,
            )

        if self._global_directives:
            # merge, but make sure current overlays global where there is conflict
            test_case = {}  # type: TestCase

            for path in get_all_paths(self._global_directives, allow_blank=True):
                try:
                    value = path_get(self._global_directives, path)
                    path_put(test_case, path, copy.copy(value))
                except (KeyError, IndexError):
                    raise FixtureSyntaxError(
                        'Invalid path: `{}`'.format(path),
                        file_name=self._fixture_file_name,
                        line_number=line_number,
                    )
            for path in get_all_paths(self._working_test_case, allow_blank=True):
                try:
                    path_put(test_case, path, path_get(self._working_test_case, path))
                except (KeyError, IndexError):
                    raise FixtureSyntaxError(
                        'Invalid path: `{}`'.format(path),
                        file_name=self._fixture_file_name,
                        line_number=line_number,
                    )

            for directive_class in get_all_directives():
                directive_class().post_parse_test_case(test_case)
        else:
            for directive_class in get_all_directives():
                directive_class().post_parse_test_case(self._working_test_case)

            test_case = copy.deepcopy(self._working_test_case)

        test_case['fixture_source'] = self._fixture_source
        self.test_cases.append(test_case)

        self._working_test_case.clear()
        self._working_test_case_source = []