-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_fixtures.py
101 lines (76 loc) · 3.53 KB
/
test_fixtures.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
import os
import warnings
import pytest
from jsonschema.validators import Draft4Validator as Validator
def custom_warning_formatter(message, category, filename, lineno, line=None):
return str(message).replace(os.getcwd() + os.sep, "")
warnings.formatwarning = custom_warning_formatter
def get_test_cases():
excluded_files = {"test_fixtures.py", "test_converter.py"}
for root, dirs, files in os.walk("tests"):
for directory in list(dirs):
# Field-level tests use sub-schema, not the release schema.
if directory.startswith("__") or directory == "field": # __pycache__
dirs.remove(directory)
for file in files:
if not file.startswith("test_") or not file.endswith(".py") or file in excluded_files:
continue
filename = os.path.join(root, file)
# https://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path
import importlib.util
spec = importlib.util.spec_from_file_location("dummy", filename)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
for key, value in module.__dict__.items():
if key.startswith("__"):
continue
if isinstance(value, dict | list):
yield filename, key, value
def add_id(value, *keys):
for key in keys:
if key in value:
for i, item in enumerate(value[key]):
item.setdefault("id", str(i))
@pytest.mark.parametrize(("filename", "key", "values"), list(get_test_cases()))
def test_valid(filename, key, values, schema, format_checker):
errors = 0
invalid = key.endswith("__invalid_schema")
if not isinstance(values, list):
values = [values]
length = len(values)
if length > 500:
pytest.skip(f"{filename}:{key} has too many items ({length}) - validate manually")
for value in values:
if not isinstance(value, dict):
continue
# Add required fields.
value.setdefault("ocid", "ocid")
value.setdefault("id", "id")
value.setdefault("date", "2000-01-01T00:00:00Z")
value.setdefault("tag", ["tender"])
value.setdefault("initiationType", "tender")
if "planning" in value:
add_id(value["planning"], "documents", "milestones")
if "tender" in value:
value["tender"].setdefault("id", "id")
add_id(value["tender"], "documents", "items", "milestones")
if "awards" in value:
for i, item in enumerate(value["awards"]):
item.setdefault("id", str(i))
add_id(item, "documents")
if "contracts" in value:
for i, item in enumerate(value["contracts"]):
item.setdefault("id", str(i))
item.setdefault("awardID", str(i))
add_id(item, "documents", "milestones")
if "implementation" in item:
add_id(item["implementation"], "documents", "milestones", "transactions")
# Validate the item.
for error in Validator(schema, format_checker=format_checker).iter_errors(value):
errors += 1
if not invalid:
warnings.warn(f"{key} {error.message} ({'/'.join(error.absolute_schema_path)})\n", stacklevel=2)
if invalid:
assert errors, f"{filename}:{key} is valid, but is expected to be invalid"
else:
assert errors == 0, f"{filename}:{key} is invalid. See warnings below."