Skip to content

Commit 9aab30f

Browse files
Tony Ricciardijhunsaker
authored andcommitted
generalize python test generation logic; add --inplace option to regen result files
1 parent 17de8d7 commit 9aab30f

File tree

3 files changed

+125
-64
lines changed

3 files changed

+125
-64
lines changed

pyth/tests/conftest.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import argparse
2+
import glob
3+
import inspect
4+
import os
5+
import subprocess
6+
7+
8+
__all__ = [
9+
'BaseTest',
10+
]
11+
12+
13+
class BaseTest:
14+
15+
def __init_subclass__(cls, **kwargs):
16+
super().__init_subclass__(**kwargs)
17+
funcs = cls.gen_test_funcs()
18+
for func in funcs:
19+
setattr(cls, func.__name__, func)
20+
21+
@classmethod
22+
def gen_test_funcs(cls):
23+
paths = cls.get_input_paths()
24+
return [cls.get_test_method(path) for path in paths]
25+
26+
@classmethod
27+
def get_subdir(cls) -> str:
28+
raise NotImplementedError()
29+
30+
@classmethod
31+
def get_absdir(cls) -> str:
32+
path = os.path.abspath(inspect.getfile(cls))
33+
return os.path.join(os.path.dirname(path), cls.get_subdir())
34+
35+
@classmethod
36+
def get_input_pattern(cls) -> str:
37+
raise NotImplementedError()
38+
39+
@classmethod
40+
def get_input_paths(cls):
41+
pattern = os.path.join(cls.get_absdir(), cls.get_input_pattern())
42+
return glob.glob(pattern)
43+
44+
@classmethod
45+
def get_output_path(cls, input_path: str) -> str:
46+
base, _ = os.path.splitext(input_path)
47+
return base + '.result'
48+
49+
@classmethod
50+
def get_test_id(cls, path: str) -> str:
51+
test_id, _ = os.path.splitext(os.path.basename(path))
52+
return test_id
53+
54+
@classmethod
55+
def get_test_method(cls, input_path: str):
56+
57+
def test_func(self: BaseTest, *, inplace: bool = False):
58+
output_path = self.get_output_path(input_path)
59+
self.run_test(input_path, output_path, inplace=inplace)
60+
61+
test_id = cls.get_test_id(input_path)
62+
test_func.__name__ = 'test_' + test_id
63+
return test_func
64+
65+
@classmethod
66+
def get_arg_parser(cls):
67+
parser = argparse.ArgumentParser()
68+
parser.add_argument('--inplace', action='store_true')
69+
return parser
70+
71+
@classmethod
72+
def main(cls):
73+
parser = cls.get_arg_parser()
74+
args = parser.parse_args()
75+
inst = cls()
76+
funcs = inst.gen_test_funcs()
77+
for func in funcs:
78+
func(inst, inplace=args.inplace)
79+
80+
def get_subprocess_args(self, input_path: str):
81+
cmd = 'test_' + self.get_subdir()
82+
return [cmd, input_path]
83+
84+
def gen_output(self, input_path: str) -> str:
85+
args = self.get_subprocess_args(input_path)
86+
output = subprocess.check_output(args)
87+
return output.decode()
88+
89+
def run_test(self, input_path: str, output_path: str, *, inplace: bool):
90+
with open(output_path, 'r') as f:
91+
expected = f.read()
92+
actual = self.gen_output(input_path)
93+
94+
if inplace:
95+
if actual != expected:
96+
with open(output_path, 'w') as f:
97+
f.write(actual)
98+
else:
99+
assert actual == expected

pyth/tests/test_qset.py

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,21 @@
1-
from __future__ import absolute_import
1+
from pyth.tests.conftest import BaseTest
22

3-
import os
4-
from glob import glob
5-
from subprocess import check_output
63

7-
_this_path = os.path.abspath(__file__)
8-
_this_dir = os.path.dirname(_this_path)
4+
__all__ = [
5+
'TestQset',
6+
]
97

108

11-
def _get_test_class():
9+
class TestQset(BaseTest):
1210

13-
test_folder = os.path.join(_this_dir, 'qset')
11+
@classmethod
12+
def get_subdir(cls) -> str:
13+
return 'qset'
1414

15-
class TestQset(object):
15+
@classmethod
16+
def get_input_pattern(cls) -> str:
17+
return '*.json'
1618

17-
def run_test(self, test_id):
18-
test_file = os.path.join(test_folder, '%s.json' % (test_id,))
19-
output = check_output(['test_qset', test_file])
20-
output = output.decode()
21-
reg_file = os.path.join(test_folder, '%s.result' % (test_id,))
22-
with open(reg_file, 'r') as f:
23-
reg_output = f.read()
24-
assert output == reg_output
2519

26-
test_files = os.path.join(test_folder, '*.json')
27-
for test_file in glob(test_files):
28-
test_id = os.path.basename(test_file).rsplit('.')[0]
29-
30-
def get_test_func(test_id):
31-
def test_func(self):
32-
self.run_test(test_id)
33-
return test_func
34-
35-
setattr(TestQset, 'test_%s' % (test_id,), get_test_func(test_id))
36-
37-
return TestQset
38-
39-
40-
TestQset = _get_test_class()
20+
if __name__ == '__main__':
21+
TestQset.main()

pyth/tests/test_twap.py

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,21 @@
1-
from __future__ import absolute_import
1+
from pyth.tests.conftest import BaseTest
22

3-
import os
4-
from glob import glob
5-
from subprocess import check_output
63

7-
_this_path = os.path.abspath(__file__)
8-
_this_dir = os.path.dirname(_this_path)
4+
__all__ = [
5+
'TestTwap',
6+
]
97

108

11-
def _get_test_class():
9+
class TestTwap(BaseTest):
1210

13-
test_folder = os.path.join(_this_dir, 'twap')
11+
@classmethod
12+
def get_subdir(cls) -> str:
13+
return 'twap'
1414

15-
class TestTwap(object):
15+
@classmethod
16+
def get_input_pattern(cls) -> str:
17+
return '*.csv'
1618

17-
def run_test(self, test_id):
18-
test_file = os.path.join(test_folder, '%s.csv' % (test_id,))
19-
output = check_output(['test_twap', test_file])
20-
output = output.decode()
21-
reg_file = os.path.join(test_folder, '%s.result' % (test_id,))
22-
with open(reg_file, 'r') as f:
23-
reg_output = f.read()
24-
assert output == reg_output
2519

26-
test_files = os.path.join(test_folder, '*.csv')
27-
for test_file in glob(test_files):
28-
test_id = os.path.basename(test_file).rsplit('.')[0]
29-
30-
def get_test_func(test_id):
31-
def test_func(self):
32-
self.run_test(test_id)
33-
return test_func
34-
35-
setattr(TestTwap, 'test_%s' % (test_id,), get_test_func(test_id))
36-
37-
return TestTwap
38-
39-
40-
TestTwap = _get_test_class()
20+
if __name__ == '__main__':
21+
TestTwap.main()

0 commit comments

Comments
 (0)