-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtest.py
130 lines (104 loc) · 4.42 KB
/
test.py
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
import filecmp
import os
import sys
from pathlib import Path
from subprocess import STDOUT, CalledProcessError, check_call, check_output
import pytest
from marshalparser.magic import get_pyc_python_version
PYTHON_VERSION = "{}.{}".format(*sys.version_info[:2])
CMD = ["python" + PYTHON_VERSION, "-m", "marshalparser", "-f"]
def fixed_filename(original_filename):
original_filename = Path(original_filename)
return original_filename.with_suffix(".fixed" + original_filename.suffix)
def param(p, *, skip_reason=None):
"""Return a pytest.param with stringified id, for nicer verbose output
When skip_reson is set, the pytest.param will be marked as skipped."""
if skip_reason is None:
return pytest.param(p, id=str(p))
return pytest.param(
p, id=str(p), marks=[pytest.mark.skip(reason=skip_reason)]
)
def generate_test_data():
for python_version_dir in (Path("test") / "python_stdlib").glob("*"):
python_version = python_version_dir.name
try:
check_call(("python" + python_version, "-c", "pass"))
except FileNotFoundError:
skip_reason = f"python{python_version} not found"
else:
skip_reason = None
yield from (
param(p, skip_reason=skip_reason)
for p in python_version_dir.glob("*.pyc")
)
yield from (param(p) for p in (Path("test") / "pure_marshal").glob("*"))
yield from (param(p) for p in (Path("test") / "renamed_pycs").glob("*"))
@pytest.mark.parametrize("original_filename", generate_test_data())
def test_complete(original_filename, tmp_path):
# To be able to run tests in parallel, we create
# a symlink for each test file so the fixed file appears
# next to the symlink in the temp dir instead of the
# test folder next to the original files.
filename = tmp_path / original_filename.name
filename.symlink_to(original_filename.absolute())
# This command uses the Python we are testing with
# because for example we can run marshalparser with
# Python 3.9 and fix pyc file for Python 3.6
output = check_output(CMD + [filename], encoding="utf-8")
assert os.path.isfile(fixed_filename(filename))
if filecmp.cmp(filename, fixed_filename(filename), shallow=False):
pytest.skip("Fixed file is the same as original, nothing to check")
assert output.endswith(
f" unused FLAG_REFs from {fixed_filename(filename)}\n"
)
assert output[:8] == "Removed "
# To compare two pyc files, we need to use Python
# they were compiled by
python_version = get_pyc_python_version(filename=filename)
if python_version:
python_version_str = "{}.{}".format(*python_version)
# pass this to marshal_content_check.py so we don't have to
# check the header there again
check_pyc = True
else:
# For non-pyc files, we use the current Python for content check
python_version_str = PYTHON_VERSION
check_pyc = False
CHECK_CMD = [
"python" + python_version_str,
"marshal_content_check.py",
str(int(check_pyc)),
filename,
fixed_filename(filename),
]
try:
check_call(CHECK_CMD)
except FileNotFoundError:
# this could still happen with test/renamed_pycs
pytest.skip(
f"python{python_version_str} not found! Cannot check the result."
)
# Fixing the already fixed file should make no changes
again_output = check_output(
CMD + ["-o", fixed_filename(filename)], encoding="utf-8"
)
assert (
again_output == f"No unused FLAG_REFs in {fixed_filename(filename)}\n"
)
test_files = sorted((Path("test") / "renamed_pycs").glob("*"))
three_doubles = [(test_files[n], test_files[n + 1]) for n in range(0, 6, 2)]
@pytest.mark.parametrize("original_filenames", three_doubles)
def test_run_with_more_than_one_file(original_filenames, tmp_path):
filenames = []
for original_filename in original_filenames:
filename = tmp_path / original_filename.name
filename.symlink_to(original_filename.absolute())
filenames.append(filename)
check_call(CMD + [*filenames])
def test_empty_file(tmp_path):
filename = tmp_path / "empty_file.pyc"
filename.touch()
with pytest.raises(CalledProcessError) as e:
check_output(CMD + [filename], encoding="utf-8", stderr=STDOUT)
assert e.value.returncode == 1
assert f"File {filename} is empty!" in e.value.output