Example #1
0
    def _get_inline_overrides(
            self, testplan: TestPlanUnit
    ) -> "List[Tuple[str, List[Tuple[str, str]]]]":
        """
        Look at the include field of a test plan and collect all of the in-line
        overrides. For an include statement that has any overrides they are
        collected into a list of tuples ``(field, value)`` and this list is
        subsequently packed into a tuple ``(pattern, field_value_list)``.
        """
        override_list = []
        if testplan.include is not None:

            class V(Visitor):

                def visit_IncludeStmt_node(self, node: IncludeStmt):
                    if not node.overrides:
                        return
                    pattern = r"^{}$".format(
                        testplan.qualify_id(node.pattern.text))
                    field_value_list = [
                        (override_exp.field.text.replace('-', '_'),
                         override_exp.value.text)
                        for override_exp in node.overrides]
                    override_list.append((pattern, field_value_list))

            V().visit(IncludeStmtList.parse(testplan.include))
        for tp_unit in testplan.get_nested_part():
            override_list.extend(self._get_inline_overrides(tp_unit))
        return override_list
Example #2
0
    def _get_matchers(self, testplan, text):
        """
        Parse the specified text and create a list of matchers

        :param text:
            string of text, including newlines and comments, to parse
        :returns:
            A generator returning quads (lineno_offset, field, matcher, error)
            where ``lineno_offset`` is the offset of a line number from the
            start of the text, ``field`` is the name of the field in a job
            definition unit that the matcher should be applied,
            ``matcher`` can be None (then ``error`` is relevant) or one of
            the ``IMatcher`` subclasses discussed below.

        Supported matcher objects include:

        PatternMatcher:
            This matcher is created for lines of text that **are** regular
            expressions. The pattern is automatically expanded to include
            ^...$ (if missing) so that it cannot silently match a portion of
            a job definition

        OperatorMatcher:
            This matcher is created for lines of text that **are not** regular
            expressions. The matcher uses the operator.eq operator (equality)
            and stores the expected job identifier as the right-hand-side value
        """
        results = []

        class V(Visitor):

            def visit_IncludeStmt_node(self, node: IncludeStmt):
                if isinstance(node.pattern, ReFixed):
                    target_id = testplan.qualify_id(node.pattern.text)
                    matcher = OperatorMatcher(operator.eq, target_id)
                elif isinstance(node.pattern, RePattern):
                    pattern = testplan.qualify_pattern(node.pattern.text)
                    matcher = PatternMatcher(pattern)
                result = (node.lineno, 'id', matcher)
                results.append(result)

        V().visit(IncludeStmtList.parse(text, 0))
        return results
Example #3
0
    def parse_matchers(self, text):
        """
        Parse the specified text and create a list of matchers

        :param text:
            string of text, including newlines and comments, to parse
        :returns:
            A generator returning quads (lineno_offset, field, matcher, error)
            where ``lineno_offset`` is the offset of a line number from the
            start of the text, ``field`` is the name of the field in a job
            definition unit that the matcher should be applied,
            ``matcher`` can be None (then ``error`` is relevant) or one of
            the ``IMatcher`` subclasses discussed below.

        Supported matcher objects include:

        PatternMatcher:
            This matcher is created for lines of text that **are** regular
            expressions. The pattern is automatically expanded to include
            ^...$ (if missing) so that it cannot silently match a portion of
            a job definition

        OperatorMatcher:
            This matcher is created for lines of text that **are not** regular
            expressions. The matcher uses the operator.eq operator (equality)
            and stores the expected job identifier as the right-hand-side value
        """
        from plainbox.impl.xparsers import Error
        from plainbox.impl.xparsers import ReErr, ReFixed, RePattern
        from plainbox.impl.xparsers import IncludeStmt
        from plainbox.impl.xparsers import IncludeStmtList
        from plainbox.impl.xparsers import Visitor

        outer_self = self

        class IncludeStmtVisitor(Visitor):

            def __init__(self):
                self.results = []  # (lineno_offset, field, matcher, error)

            def visit_IncludeStmt_node(self, node: IncludeStmt):
                if isinstance(node.pattern, ReErr):
                    matcher = None
                    error = node.pattern.exc
                elif isinstance(node.pattern, ReFixed):
                    target_id = outer_self.qualify_id(node.pattern.text)
                    matcher = OperatorMatcher(operator.eq, target_id)
                    error = None
                elif isinstance(node.pattern, RePattern):
                    text = node.pattern.text
                    # Ensure that pattern is surrounded by ^ and $
                    if text.startswith('^') and text.endswith('$'):
                        target_id_pattern = '^{}$'.format(
                            outer_self.qualify_id(text[1:-1]))
                    elif text.startswith('^'):
                        target_id_pattern = '^{}$'.format(
                            outer_self.qualify_id(text[1:]))
                    elif text.endswith('$'):
                        target_id_pattern = '^{}$'.format(
                            outer_self.qualify_id(text[:-1]))
                    else:
                        target_id_pattern = '^{}$'.format(
                            outer_self.qualify_id(text))
                    matcher = PatternMatcher(target_id_pattern)
                    error = None
                result = (node.lineno, 'id', matcher, error)
                self.results.append(result)

            def visit_Error_node(self, node: Error):
                # we're just faking an exception object here
                error = ValueError(node.msg)
                result = (node.lineno, 'id', None, error)
                self.results.append(result)

        visitor = IncludeStmtVisitor()
        visitor.visit(IncludeStmtList.parse(text, 0, 0))
        return visitor.results