def test_disabled_code():
    source, indent_corrections = undo_amendments(
        "# Some code\n"
        "a = b + c\n"
        "### with disabled_code()\n"
        "###     a += 1\n"
        "### \n"
        "###\n"
        "    ### \n"
        "    ###\n"
        "    ### a -= 1\n"
        "a += 1\n"
    )

    assert source == (
        "# Some code\n"
        "a = b + c\n"
        "with disabled_code()\n"
        "    a += 1\n"
        "\n"
        "\n"
        "    \n"
        "    \n"
        "    a -= 1\n"
        "a += 1\n"
    )
    assert indent_corrections == {
        3: 4,
        4: 4,
        5: 4,
        6: 3,
        7: 4,
        8: 3,
        9: 4,
    }
def test_not_in_spec_line():
    source, indent_corrections = undo_amendments(
        "# Some code\n"
        "a = 1\n"
        "with foo():  ## Not in spec\n"
        "    foobar()  ##not  in SPEC  at all!\n"
        "b = 2\n"
    )

    assert source == (
        "# Some code\n"
        "a = 1\n"
        "# with foo():  ## Not in spec\n"
        "#     foobar()  ##not  in SPEC  at all!\n"
        "b = 2\n"
    )
    assert indent_corrections == {}
def test_not_in_spec_block():
    source, indent_corrections = undo_amendments(
        "# Some code\n"
        "a = 1\n"
        "## Begin not in spec\n"
        "with foo():\n"
        "    foobar()\n"
        "    ##  end  NOT  in  spec at all either!\n"
        "b = 2\n"
    )

    assert source == (
        "# Some code\n"
        "a = 1\n"
        "# ## Begin not in spec\n"
        "# with foo():\n"
        "#     foobar()\n"
        "#     ##  end  NOT  in  spec at all either!\n"
        "b = 2\n"
    )
    assert indent_corrections == {}
def test_single_hashes_dont_cause_changes():
    source, indent_corrections = undo_amendments(
        "# Some code\n"
        "a = 1  # Not in spec\n"
        "# Begin not in spec\n"
        "with foo():\n"
        "    foobar()\n"
        "# End not in spec\n"
        "b = 2\n"
    )

    assert source == (
        "# Some code\n"
        "a = 1  # Not in spec\n"
        "# Begin not in spec\n"
        "with foo():\n"
        "    foobar()\n"
        "# End not in spec\n"
        "b = 2\n"
    )
    assert indent_corrections == {}
Example #5
0
def compare_sources(ref_source, imp_source, comparator):
    """
    Compare two Python sources, one containing a reference VC-2 pseudocode
    function and the other containing an implementation.

    Parameters
    ==========
    ref_source : str
        The reference VC-2 pseudocode implementation of a function.
    imp_source : str
        The implementation of the same function used in
        :py:mod:`vc2_conformance`. Will be pre-processed using
        :py:func:`verification.amendment_comments.undo_amendments` prior to
        comparison.
    comparator : :py:class:`verification.node_comparator.NodeComparator`
        The comparator instance to use to test for equivalence.

    Returns
    =======
    True or :py:class:`Difference`
        True is returned if the implementations are equal (according to the
        supplied comparator). Otherwise a :py:class:`Difference` is returned
        enumerating the differences.

    Raises
    =======
    :py:exc:`ComparisonError`
    """
    try:
        imp_source, implementation_indent_offsets = undo_amendments(imp_source)
    except TokenError as e:
        raise ComparisonError(e.args[0],
                              imp_row=e.args[1][0],
                              imp_col=e.args[1][1])
    except BadAmendmentCommentError as e:
        raise ComparisonError(
            "Unrecognised amendment comment {!r}".format(e.comment),
            imp_row=e.row,
            imp_col=e.col,
        )
    except UnmatchedNotInSpecBlockError as e:
        raise ComparisonError(
            "No matching '## Begin not in spec'",
            imp_row=e.row,
        )
    except UnclosedNotInSpecBlockError as e:
        raise ComparisonError(
            "'## Begin not in spec' block not closed",
            imp_row=e.row,
        )

    try:
        ref_ast = ast.parse(ref_source)
    except SyntaxError as e:
        raise ComparisonError(e.msg, ref_row=e.lineno, ref_col=e.offset)

    try:
        imp_ast = ast.parse(imp_source)
    except SyntaxError as e:
        raise ComparisonError(
            e.msg,
            imp_row=e.lineno,
            imp_col=e.offset + implementation_indent_offsets.get(e.lineno, 0),
        )

    match = comparator.compare(ref_ast, imp_ast)
    if match is True:
        return match

    message = str(match)
    ref_row = None
    ref_col = None
    imp_row = None
    imp_col = None
    if isinstance(match, NodeTypesDiffer):
        message = "Mismatched {} vs. {}".format(
            type(match.n1).__name__,
            type(match.n2).__name__,
        )
        ref_row, ref_col = match.n1_row_col
        imp_row, imp_col = match.n2_row_col
    elif isinstance(match, NodeFieldsDiffer):
        message = "Different {} values".format(match.field)
        ref_row, ref_col = match.n1_row_col
        imp_row, imp_col = match.n2_row_col
    elif isinstance(match, NodeFieldLengthsDiffer):
        if len(match.v1) > len(match.v2):
            num = len(match.v1) - len(match.v2)
            message = "{} extra value{} in reference's {}".format(
                num,
                "s" if num != 1 else "",
                match.field,
            )
        else:
            num = len(match.v2) - len(match.v1)
            message = "{} extra value{} in implementation's {}".format(
                num,
                "s" if num != 1 else "",
                match.field,
            )
        ref_row, ref_col = match.n1_row_col
        imp_row, imp_col = match.n2_row_col
    elif isinstance(match, NodeListFieldsDiffer):
        message = "Different {} at index {} ({!r} and {!r})".format(
            match.field,
            match.index,
            match.v1[match.index],
            match.v2[match.index],
        )
        ref_row, ref_col = match.n1_row_col
        imp_row, imp_col = match.n2_row_col

    return Difference(
        message=message,
        ref_row=ref_row,
        ref_col=ref_col,
        imp_row=imp_row,
        imp_col=(imp_col + implementation_indent_offsets.get(imp_row, 0)
                 if imp_row is not None and imp_col is not None else imp_col),
    )
def test_no_amendment_comments():
    source, indent_corrections = undo_amendments("# Some code\n" "a = b + c\n")

    assert source == ("# Some code\n" "a = b + c\n")
    assert indent_corrections == {}
def test_unclosed_not_in_spec_block():
    with pytest.raises(UnclosedNotInSpecBlockError):
        undo_amendments("## Begin not in spec")
def test_unmatched_not_in_spec_block():
    with pytest.raises(UnmatchedNotInSpecBlockError):
        undo_amendments("## End not in spec")
def test_bad_amendment_comment():
    with pytest.raises(BadAmendmentCommentError):
        undo_amendments("## Not a valid one...")

    with pytest.raises(BadAmendmentCommentError):
        undo_amendments("###Space after hashes is required")
def test_bad_tokenization():
    with pytest.raises(tokenize.TokenError):
        undo_amendments("'''")
def test_empty():
    assert undo_amendments("") == ("", {})