-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimporter_test.py
executable file
·160 lines (138 loc) · 5.64 KB
/
importer_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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__version__ = "0.1"
import argparse
import json
import os
import sys
def get_args(argv=None) -> argparse.Namespace:
parser = argparse.ArgumentParser(
add_help=True,
description="Json test importer. A script to import Codesignal json tests into a working pytest file.",
formatter_class=argparse.RawDescriptionHelpFormatter,
prog="importer-test",
)
parser.add_argument(
"-v",
"--version",
action="version",
version=f"{parser.prog} v{__version__}",
)
parser.add_argument(
"code_file",
# nargs=1,
help="File with the code to test.",
metavar="SOURCE_FILE",
type=str,
)
parser.add_argument(
"filename",
nargs="+", # one or more files
help="Json filename with the test case variables and expected output.",
metavar="JSON_FILE",
type=str,
)
parser.add_argument(
"-o",
"--output",
default="",
help="The filename of the output python test file.",
metavar="FILE",
type=str,
)
parser.add_argument(
"-i",
"--insert",
action="store_true",
default=False,
help="Append the tests into a the test file without removing its content.",
)
return parser.parse_args(argv)
class JsonTest:
def __init__(
self, name: str, case_variables: dict[str, any], expected: any
) -> None:
self.name: str = name
self.variables: dict[str, any] = case_variables
self.expected: any = expected
def generate_test(self, source_filename: str) -> str:
test_str = "# @pytest.mark.skip()\n"
test_str += f"def {self.name}():\n"
indent = " "
assert self.name != ""
assert self.variables is not None and self.variables != {}
assert self.expected is not None
for var_name, var_value in self.variables.items():
test_str += f"{indent}{var_name} = {var_value}\n"
test_str += f"{indent}expected = {self.expected}\n"
variables = ", ".join(self.variables.keys())
test_str += f"{indent}output = solution({variables})\n"
test_str += f"{indent}assert output == expected\n\n\n"
return test_str
class JsonTestImporter:
def __init__(
self, source_code_name: str, test_files: list[str], insert_mode: bool
) -> None:
self.source_code_file: str = source_code_name
self.json_test_files: list[str] = test_files
self.raw_data: dict[str, json] = {}
self.test_collection: dict[str, JsonTest] = {}
self.insert_mode: bool = insert_mode
self.output_data: str = ""
def read_file(self, filename):
try:
with open(os.path.abspath(filename), "r", encoding="utf-8") as stream:
raw_data = json.load(stream)
except Exception as err:
raise IOError(f"Error reading json file {filename}", err)
return raw_data
def read_files(self) -> None:
self.json_test_files.sort(key=lambda c: int("".join(filter(str.isdigit, c))))
for file in self.json_test_files:
self.raw_data[file] = self.read_file(file)
def write_output_data_to_file(self, target_file: str) -> None:
write_mode = "a" if self.insert_mode else "w"
try:
with open(target_file, write_mode, encoding="utf-8") as file:
file.write(self.output_data)
except Exception as err:
IOError("Error writing to the output file", err)
def get_header(self) -> str:
header = "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nimport pytest\n\n"
source_code_file = self.source_code_file
if source_code_file.endswith(".py"):
source_code_file = source_code_file[:-3]
source_import = f"from {source_code_file} import solution\n\n\n"
return header + source_import
def generate_test_file_data(self) -> None:
self.test_collection = self.populate_test_collection(self.raw_data)
output_file: str = "\n\n" if self.insert_mode else self.get_header()
for name, test in self.test_collection.items():
output_file += test.generate_test(self.source_code_file)
self.output_data = output_file
def populate_test_collection(self, raw_data: dict) -> dict[str, JsonTest]:
assert raw_data is not None or len(raw_data) != 0
test_collection = {}
for test_filename, test_data in raw_data.items():
# Good enough. Maybe provide a more robust way.
test_number = int("".join(filter(str.isdigit, test_filename)))
name = f"test_case{test_number}"
expected_output = test_data.get("output")
variables: dict[str, any] = test_data.get("input")
assert expected_output is not None, "Missing output data"
assert variables is not None, "Missing input data"
test_collection[test_filename] = JsonTest(name, variables, expected_output)
return test_collection
def export_test_file(self, output_file: str) -> None:
assert self.output_data != "", "Error: empty output_data."
if output_file == "":
output_file = f"test_{self.source_code_file}"
self.write_output_data_to_file(output_file)
def main(argv: argparse.Namespace) -> None:
importer = JsonTestImporter(argv.code_file, argv.filename, argv.insert)
importer.read_files()
importer.generate_test_file_data()
importer.export_test_file(argv.output)
if __name__ == "__main__":
# sys.exit(main(get_args(["roadsBuilding.py", "test-5.json"])))
sys.exit(main(get_args(sys.argv[1:])))