1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
# SPDX-FileCopyrightText: David Fritzsche
# SPDX-License-Identifier: CC0-1.0
import ast
import sys
import typing as _typing
from tokenize import COMMENT, ENDMARKER, NAME, NEWLINE, NL, TokenInfo
from unittest.mock import Mock
import pytest
from _pytest.config import Config
from pytest_mypy_testing.parser import (
MypyTestItem,
generate_per_line_token_lists,
parse_file,
)
from pytest_mypy_testing.strutil import dedent
@pytest.mark.parametrize("node", [None, 123, "abc"])
def test_cannot_create_mypy_test_case_from_ast_node_without_valid_node(node):
with pytest.raises(ValueError):
MypyTestItem.from_ast_node(node)
def test_create_mypy_test_case():
func = dedent(
r"""
@pytest.mark.mypy_testing
@pytest.mark.skip()
@foo.bar
def mypy_foo():
pass
"""
)
tree = ast.parse(func, "func.py")
func_nodes = [
node for node in ast.iter_child_nodes(tree) if isinstance(node, ast.FunctionDef)
]
assert func_nodes
tc = MypyTestItem.from_ast_node(func_nodes[0])
assert tc.lineno == 1
def test_iter_comments():
source = "\n".join(["# foo", "assert True # E: bar"])
actual = list(generate_per_line_token_lists(source))
# fmt: off
expected:_typing.List[_typing.List[TokenInfo]] = [
[], # line 0
[
TokenInfo(type=COMMENT, string="# foo", start=(1, 0), end=(1, 5), line="# foo\n",),
TokenInfo(type=NL, string="\n", start=(1, 5), end=(1, 6), line="# foo\n"),
],
[
TokenInfo(type=NAME, string="assert", start=(2, 0), end=(2, 6), line="assert True # E: bar",),
TokenInfo(type=NAME, string="True", start=(2, 7), end=(2, 11), line="assert True # E: bar",),
TokenInfo(type=COMMENT, string="# E: bar", start=(2, 12), end=(2, 20), line="assert True # E: bar",),
TokenInfo(type=NEWLINE, string="", start=(2, 20), end=(2, 21), line=""),
],
[
TokenInfo(type=ENDMARKER, string="", start=(3, 0), end=(3, 0), line="")
],
]
# fmt: on
# some patching due to differences between Python versions...
for lineno, line_toks in enumerate(actual):
for i, tok in enumerate(line_toks):
if tok.type == NEWLINE:
try:
expected_tok = expected[lineno][i]
if expected_tok.type == NEWLINE:
expected[lineno][i] = TokenInfo(
type=expected_tok.type,
string=expected_tok.string,
start=expected_tok.start,
end=expected_tok.end,
line=tok.line,
)
except IndexError:
pass
assert actual == expected
def test_parse_file_basic_call_works_with_py37(monkeypatch, tmp_path):
path = tmp_path / "parse_file_test.py"
path.write_text(
dedent(
r"""
# foo
def test_mypy_foo():
pass
@pytest.mark.mypy_testing
def test_mypy_bar():
pass
"""
)
)
monkeypatch.setattr(sys, "version_info", (3, 7, 5))
config = Mock(spec=Config)
parse_file(str(path), config)
def test_parse_async(tmp_path):
path = tmp_path / "test_async.mypy-testing"
path.write_text(
dedent(
r"""
import pytest
@pytest.mark.mypy_testing
async def mypy_test_invalid_assginment():
foo = "abc"
foo = 123 # E: Incompatible types in assignment (expression has type "int", variable has type "str")
"""
)
)
config = Mock(spec=Config)
result = parse_file(str(path), config)
assert len(result.items) == 1
item = result.items[0]
assert item.name == "mypy_test_invalid_assginment"
|