Exemple #1
0
    def __call__(self, end_coord, buf, toks):
        """
        Called once processing of the directive is complete.

        :param end_coord: The coordinates at which the directive
                          processing completed.
        :type end_coord: ``hypocrite.location.Coordinate``
        :param list buf: A list of lines, including trailing newlines,
                         enclosed within the directive.
        :param list toks: A list of tokens.  Will be ``None`` if the
                          directive was closed by the end of file.

        :returns: A ``None`` value to indicate no further processing
                  is necessary.

        :raises hypocrite.perfile.ParseException:
            An error occurred while parsing the directive.
        """

        # Check for errors
        if toks is None:
            raise perfile.ParseException(
                'Unclosed %%preamble directive at end of file; '
                'starts at %s' % self.start_coord)
        elif len(toks) != 0:
            raise perfile.ParseException(
                'Invalid end of %%preamble directive at %s' % end_coord)

        # Update the preamble data
        self.values['preamble'].append(
            Preamble(self.start_coord - end_coord, buf))

        return None
Exemple #2
0
    def teardown(self, end_coord, buf, toks):
        """
        Called once processing of the teardown directive is complete.

        :param end_coord: The coordinates at which the directive
                          processing completed.
        :type end_coord: ``hypocrite.location.Coordinate``
        :param list buf: A list of lines, including trailing newlines,
                         enclosed within the directive.
        :param list toks: A list of tokens.  Will be ``None`` if the
                          directive was closed by the end of file.

        :returns: A ``None`` value to indicate no further processing
                  is necessary.

        :raises hypocrite.perfile.ParseException:
            An error occurred while parsing the directive.
        """

        # Check for errors
        if toks is None:
            raise perfile.ParseException(
                'Unclosed %%teardown directive at end of file; starts at %s' %
                self.block_start)
        elif len(toks) != 0:
            raise perfile.ParseException(
                'Invalid end of %%teardown directive at %s' % end_coord)

        # Create the fixture
        self.values['fixtures'][self.name] = Fixture(
            self.start_coord - end_coord, self.name, self.type_, self.code,
            buf)

        return None
Exemple #3
0
    def __init__(self, values, start_coord, toks):
        """
        Initialize a ``TestDirective`` instance.

        :param dict values: The values dictionary that the directive's
                            return value may be placed in.
        :param start_coord: The coordinates the directive started at.
        :type start_coord: ``hypocrite.location.Coordinate``
        :param list toks: A list of tokens.

        :raises hypocrite.perfile.ParseException:
            An error occurred while parsing the directive.
        """

        # Make sure the token list is correct
        if (len(toks) < 2 or toks[0].type_ != perfile.TOK_WORD
                or not toks[0].value or toks[-1] != (perfile.TOK_CHAR, '{')):
            raise perfile.ParseException('Invalid %%test directive at %s' %
                                         start_coord)

        # Save the gunk we need for __call__()
        self.name = toks[0].value
        self.fixtures = []
        self.values = values
        self.start_coord = start_coord

        # Extract the optional fixtures
        if len(toks) > 2:
            if (toks[1] != (perfile.TOK_CHAR, '(') or toks[-2] !=
                (perfile.TOK_CHAR, ')')):
                raise perfile.ParseException('Invalid %%test directive at %s' %
                                             start_coord)

            for fix_toks in perfile.split_toks(toks[2:-2],
                                               {(perfile.TOK_CHAR, ',')}):
                # Sanity-check the tokens
                if len(fix_toks) < 1 or len(fix_toks) > 2:
                    raise perfile.ParseException(
                        'Invalid fixture specification in %%test directive '
                        'at %s' % start_coord)

                # Determine if it's an injectable
                inject = True
                if fix_toks[0] == (perfile.TOK_CHAR, '!'):
                    inject = False
                    fix_toks.pop(0)

                # Determine the fixture name
                if (len(fix_toks) != 1 or fix_toks[0].type_ != perfile.TOK_WORD
                        or not fix_toks[0].value):
                    raise perfile.ParseException(
                        'Invalid fixture specification in %%test directive '
                        'at %s' % start_coord)

                # Add the fixture injection
                self.fixtures.append(
                    HypoFixtureInjection(fix_toks[0].value, inject))
Exemple #4
0
    def __init__(self, values, start_coord, toks):
        """
        Initialize a ``FixtureDirective`` instance.

        :param dict values: The values dictionary that the directive's
                            return value may be placed in.
        :param start_coord: The coordinates the directive started at.
        :type start_coord: ``hypocrite.location.Coordinate``
        :param list toks: A list of tokens.

        :raises hypocrite.perfile.ParseException:
            An error occurred while parsing the directive.
        """

        # Parse the directive
        end_expected = False
        for type_, name, delim in _extract_type(toks,
                                                {(perfile.TOK_CHAR, '{')}):
            # Were we expecting the end of the directive?
            if end_expected:
                if type_ or name or delim:
                    raise perfile.ParseException(
                        'Unexpected tokens after %%fixture directive at %s' %
                        start_coord)

                # Just here to exhaust the iterator for coverage
                continue  # pragma: no cover

            # OK, was it the end of the directive?
            elif not delim:
                raise perfile.ParseException(
                    'Premature end of arguments in %%fixture directive at %s' %
                    start_coord)

            # Found the open brace
            end_expected = True

            # Sanity-check the name token
            if not name or name.type_ != perfile.TOK_WORD or not name.value:
                raise perfile.ParseException(
                    'Invalid %%fixture directive at %s' % start_coord)

            # Save the fixture's type and name
            self.name = name.value
            self.type_ = (None
                          if not type_ or type_ == [(perfile.TOK_WORD, 'void')]
                          else _make_type(type_, 'fixture', start_coord))
            self.values = values
            self.start_coord = start_coord
            self.block_start = start_coord
Exemple #5
0
def target_directive(values, start_coord, toks):
    """
    The ``%target`` directive.  Should contain a single TOK_STR token
    giving the name of the source file being tested.

    :param dict values: The values dictionary that the directive's
                        return value may be placed in.
    :param start_coord: The coordinates the directive started at.
    :type start_coord: ``hypocrite.location.Coordinate``
    :param list toks: A list of tokens.

    :returns: A ``None`` value to indicate no further processing is
              necessary.

    :raises hypocrite.perfile.ParseException:
        An error occurred while parsing the directive.
    """

    # Make sure the token list is correct
    if len(toks) != 1 or toks[0].type_ != perfile.TOK_STR or not toks[0].value:
        raise perfile.ParseException('Invalid %%file directive at %s' %
                                     start_coord)

    # Save the target file
    values['target'] = toks[0].value

    return None
Exemple #6
0
def insert(values, start_coord, toks):
    """
    The ``%insert`` directive.  Should contain a single TOK_WORD token
    giving the name of the section to insert into the file's
    structure.

    :param dict values: The values dictionary that the directive's
                        return value may be placed in.
    :param start_coord: The coordinates the directive started at.
    :type start_coord: ``hypocrite.location.Coordinate``
    :param list toks: A list of tokens.

    :returns: A ``None`` value to indicate no further processing is
              necessary.

    :raises hypocrite.perfile.ParseException:
        An error occurred while parsing the directive.
    """

    # Make sure the token list is correct
    if (len(toks) != 1 or toks[0].type_ != perfile.TOK_WORD
            or not toks[0].value):
        raise perfile.ParseException('Invalid %%insert directive at %s' %
                                     start_coord)

    # Add an insert-section directive
    values['structure'].append(
        InsertSection(start_coord - start_coord, toks[0].value))

    return None
Exemple #7
0
    def __init__(self, values, start_coord, toks):
        """
        Initialize a ``SectionDirective`` instance.

        :param dict values: The values dictionary that the directive's
                            return value may be placed in.
        :param start_coord: The coordinates the directive started at.
        :type start_coord: ``hypocrite.location.Coordinate``
        :param list toks: A list of tokens.

        :raises hypocrite.perfile.ParseException:
            An error occurred while parsing the directive.
        """

        # Make sure the token list is correct
        if (len(toks) < 2 or toks[0].type_ != perfile.TOK_WORD
                or not toks[0].value or toks[-1] != (perfile.TOK_CHAR, '{')):
            raise perfile.ParseException('Invalid %%section directive at %s' %
                                         start_coord)

        # Check for requirements
        requires = set()
        if len(toks) > 2:
            if (len(toks) < 4 or toks[1] != (perfile.TOK_CHAR, '(')
                    or toks[-2] != (perfile.TOK_CHAR, ')')):
                raise perfile.ParseException(
                    'Invalid %%section directive at %s' % start_coord)

            for requirement in perfile.split_toks(toks[2:-2],
                                                  {(perfile.TOK_CHAR, ',')}):
                if (len(requirement) != 1
                        or requirement[0].type_ != perfile.TOK_WORD
                        or not requirement[0].value):
                    raise perfile.ParseException(
                        'Invalid %%section directive at %s' % start_coord)

                requires.add(requirement[0].value)

        # Save the gunk we need for __call__()
        self.name = toks[0].value
        self.requires = requires
        self.values = values
        self.start_coord = start_coord
Exemple #8
0
    def __call__(self, end_coord, buf, toks):
        """
        Called once processing of the directive is complete.

        :param end_coord: The coordinates at which the directive
                          processing completed.
        :type end_coord: ``hypocrite.location.Coordinate``
        :param list buf: A list of lines, including trailing newlines,
                         enclosed within the directive.
        :param list toks: A list of tokens.  Will be ``None`` if the
                          directive was closed by the end of file.

        :returns: A ``None`` value to indicate no further processing
                  is necessary, or a callable to collect the remaining
                  lines.

        :raises hypocrite.perfile.ParseException:
            An error occurred while parsing the directive.
        """

        # Check for errors
        if toks is None:
            raise perfile.ParseException(
                'Unclosed %%fixture directive at end of file; starts at %s' %
                self.block_start)
        elif (len(toks) != 0 and toks != [(perfile.TOK_WORD, 'teardown'),
                                          (perfile.TOK_CHAR, '{')]):
            raise perfile.ParseException('Invalid %%teardown directive at %s' %
                                         end_coord)

        # If we have a teardown clause, save the code clause and chain
        if toks:
            self.code = buf
            self.block_start = end_coord  # update to start of teardown
            return self.teardown

        # Create the fixture
        self.values['fixtures'][self.name] = Fixture(
            self.start_coord - end_coord, self.name, self.type_, buf)

        return None
Exemple #9
0
    def __init__(self, values, start_coord, toks):
        """
        Initialize a ``PreambleDirective`` instance.

        :param dict values: The values dictionary that the directive's
                            return value may be placed in.
        :param start_coord: The coordinates the directive started at.
        :type start_coord: ``hypocrite.location.Coordinate``
        :param list toks: A list of tokens.

        :raises hypocrite.perfile.ParseException:
            An error occurred while parsing the directive.
        """

        # Make sure the token list is correct
        if len(toks) != 1 or toks[0] != (perfile.TOK_CHAR, '{'):
            raise perfile.ParseException('Invalid %%preamble directive at %s' %
                                         start_coord)

        # Save the gunk we need for __call__()
        self.values = values
        self.start_coord = start_coord
Exemple #10
0
def _make_type(toks, directive, coord):
    """
    Construct a type string from a sequence of tokens.

    :param list toks: The list of tokens to form the type string from.
    :param str directive: The name of the directive.  This is used for
                          error reporting.
    :param coord: The coordinates the tokens are from.  This is used
                  for error reporting.
    :type coord: ``Coordinates``

    :returns: A type string.

    :raises HypocriteException:
        An error occurred while parsing the directive.
    """

    type_ = []

    last_tok = None
    for tok in toks:
        # Watch out for bogus token types
        if tok.type_ != perfile.TOK_WORD and tok != (perfile.TOK_CHAR, '*'):
            raise perfile.ParseException('Invalid %%%s directive at %s' %
                                         (directive, coord))

        if (last_tok and tok.type_ == perfile.TOK_CHAR
                and last_tok.type_ == perfile.TOK_CHAR):
            # Avoid spaces between subsequent '*' tokens
            type_[-1] += tok.value
        else:
            type_.append(tok.value)

        last_tok = tok

    # Create and return the type string
    return ' '.join(type_)
Exemple #11
0
def mock(values, start_coord, toks):
    """
    The ``%mock`` directive.  Should contain a sequence of tokens
    declaring a function to be mocked, excluding any trailing
    semicolon (';').

    :param dict values: The values dictionary that the directive's
                        return value may be placed in.
    :param start_coord: The coordinates the directive started at.
    :type start_coord: ``hypocrite.location.Coordinate``
    :param list toks: A list of tokens.

    :returns: A ``None`` value to indicate no further processing is
              necessary.

    :raises hypocrite.perfile.ParseException:
        An error occurred while parsing the directive.
    """

    # Initialize the type iterator
    type_iter = _extract_type(toks, _mock_type_delims)

    # First, have to collect the return type and function name
    try:
        type_, name, delim = six.next(type_iter)
    except StopIteration:  # pragma: no cover
        # Shouldn't ever actually happen
        raise perfile.ParseException('Invalid %%mock directive at %s' %
                                     start_coord)

    # Make sure the tokens make sense
    if (not type_ or name.type_ != perfile.TOK_WORD or not name.value
            or delim != (perfile.TOK_CHAR, '(')):
        raise perfile.ParseException('Invalid %%mock directive at %s' %
                                     start_coord)

    # Initialize the mock information
    func_name = name.value
    return_type = _make_type(type_, 'mock', start_coord)
    args = []

    # Extract argument information
    end_expected = False
    for type_, name, delim in type_iter:
        # Were we expecting the end of the directive?
        if end_expected:
            if type_ or name or delim:
                raise perfile.ParseException(
                    'Unexpected tokens after %%mock directive at %s' %
                    start_coord)

            # Just here to exhaust the iterator for coverage
            continue  # pragma: no cover

        # OK, was it the end of the directive?
        elif not delim:
            raise perfile.ParseException(
                'Premature end of arguments in %%mock directive at %s' %
                start_coord)

        # Found the closing parenthesis
        elif delim == (perfile.TOK_CHAR, ')'):
            end_expected = True

            # Handles the case of 'void foo()' and 'void foo(void)'
            if not args and (
                (not type_ and not name) or
                (not type_ and name == (perfile.TOK_WORD, 'void'))):
                continue

        # Sanity-check the argument
        if (not type_ or not name or name.type_ != perfile.TOK_WORD
                or not name.value or delim == (perfile.TOK_CHAR, '(')):
            raise perfile.ParseException('Invalid %%mock directive at %s' %
                                         start_coord)

        # Save the argument
        args.append(
            HypoMockArg(_make_type(type_, 'mock', start_coord), name.value))

    # Construct and save the mock
    values['mocks'][func_name] = HypocriteMock(start_coord - start_coord,
                                               func_name, return_type, args)