Skip to content

Commit cd7cd5c

Browse files
author
Jianchun Xu
committed
[MERGE #983] xplat: enhance test/runtests.py to use rlexe.xml
Merge pull request #983 from jianchun:pyrl Use `argparse` module to handle command line arguments. (Now this also works on Windows -- needs **python 2.7**.) Read `rlexe.xml` to load test metadata and honor `compile-flags`. Run all loaded tests and print summary at the end. Note this is only one step towards current rl test harness. There are lots of test harness features not implemented yet.
2 parents 4cbd900 + c7a21d7 commit cd7cd5c

File tree

1 file changed

+182
-88
lines changed

1 file changed

+182
-88
lines changed

test/runtests.py

Lines changed: 182 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -7,114 +7,208 @@
77
import sys
88
import os
99
import subprocess as SP
10+
import argparse
11+
import xml.etree.ElementTree as ET
1012

11-
test_all = True
12-
test_root = os.path.dirname(os.path.realpath(__file__))
13+
# handle command line args
14+
parser = argparse.ArgumentParser(
15+
description='ChakraCore *nix Test Script',
16+
formatter_class=argparse.RawDescriptionHelpFormatter,
17+
epilog='''\
18+
Samples:
19+
20+
test all folders:
21+
{0}
22+
23+
test only Array:
24+
{0} Array
25+
26+
test a single file:
27+
{0} Basics/hello.js
28+
'''.format(sys.argv[0]))
29+
30+
parser.add_argument('folders', metavar='folder', nargs='*',
31+
help='folder subset to run tests')
32+
parser.add_argument('-b', '--binary', metavar='bin', help='ch full path')
33+
parser.add_argument('-d', '--debug', action='store_true',
34+
help='use debug build');
35+
parser.add_argument('-t', '--test', action='store_true', help='use test build')
36+
parser.add_argument('--x86', action='store_true', help='use x86 build')
37+
parser.add_argument('--x64', action='store_true', help='use x64 build')
38+
args = parser.parse_args()
1339

14-
# ugly trick
15-
ch_path = os.path.join(os.path.dirname(test_root), "BuildLinux/ch")
1640

17-
if not os.path.isfile(ch_path):
18-
print "BuildLinux/ch not found. Did you run ./build.sh already?"
41+
test_root = os.path.dirname(os.path.realpath(__file__))
42+
repo_root = os.path.dirname(test_root)
43+
44+
# arch: x86, x64
45+
arch = 'x86' if args.x86 else ('x64' if args.x64 else None)
46+
if arch == None:
47+
arch = os.environ.get('_BuildArch', 'x86')
48+
49+
# flavor: debug, test, release
50+
type_flavor = {'chk':'debug', 'test':'test', 'fre':'release'}
51+
flavor = 'debug' if args.debug else ('test' if args.test else None)
52+
if flavor == None:
53+
flavor = type_flavor[os.environ.get('_BuildType', 'fre')]
54+
55+
# binary: full ch path
56+
binary = args.binary
57+
if binary == None:
58+
if sys.platform == 'win32':
59+
binary = 'Build/VcBuild/bin/{}_{}/ch.exe'.format(arch, flavor)
60+
else:
61+
binary = 'BuildLinux/ch'
62+
binary = os.path.join(repo_root, binary)
63+
if not os.path.isfile(binary):
64+
print('{} not found. Did you run ./build.sh already?'.format(binary))
1965
sys.exit(1)
2066

21-
if len(sys.argv) > 1:
22-
if sys.argv[1] in ['-?', '--help']:
23-
print "ChakraCore *nix Test Script\n"
2467

25-
print "Usage:"
26-
print "test.py <optional test path>\n"
68+
# records pass_count/fail_count
69+
class PassFailCount(object):
70+
def __init__(self):
71+
self.pass_count = 0
72+
self.fail_count = 0
73+
74+
def __str__(self):
75+
return 'passed {}, failed {}'.format(self.pass_count, self.fail_count)
76+
77+
# records total and individual folder's pass_count/fail_count
78+
class TestResult(PassFailCount):
79+
def __init__(self):
80+
super(self.__class__, self).__init__()
81+
self.folders = {}
2782

28-
print "-?, --help : Show help\n"
83+
def _get_folder_result(self, folder):
84+
r = self.folders.get(folder)
85+
if not r:
86+
r = PassFailCount()
87+
self.folders[folder] = r
88+
return r
2989

30-
print "Samples:"
31-
print "test only Array:"
32-
print "\t./test.py Array\n"
33-
34-
print "test a single file:"
35-
print "\t./test.py Basics/hello.js\n"
90+
def log(self, filename=None, folder=None, fail=False):
91+
if not folder:
92+
folder = os.path.basename(os.path.dirname(filename))
93+
r = self._get_folder_result(folder)
94+
if fail:
95+
r.fail_count += 1
96+
self.fail_count += 1
97+
else:
98+
r.pass_count += 1
99+
self.pass_count += 1
36100

37-
print "test all folders:"
38-
print "\t./test.py"
39-
sys.exit(0)
40-
test_all = None
101+
test_result = TestResult()
41102

42-
test_dirs=['']
43-
if test_all:
44-
test_dirs = os.listdir(test_root)
45-
else:
46-
test_dirs[0] = sys.argv[1]
47103

48104
def show_failed(filename, output, exit_code, expected_output):
49-
print "\nFailed ->", filename
105+
print("\nFailed -> {}".format(filename))
50106
if expected_output == None:
51-
print "\nOutput:"
52-
print "----------------------------"
53-
print output
54-
print "----------------------------"
107+
print("\nOutput:")
108+
print("----------------------------")
109+
print(output)
110+
print("----------------------------")
55111
else:
56112
lst_output = output.split('\n')
57113
lst_expected = expected_output.split('\n')
58114
ln = min(len(lst_output), len(lst_expected))
59115
for i in range(0, ln):
60116
if lst_output[i] != lst_expected[i]:
61-
print "Output: (at line " + str(i) + ")"
62-
print "----------------------------"
63-
print lst_output[i]
64-
print "----------------------------"
65-
print "Expected Output:"
66-
print "----------------------------"
67-
print lst_expected[i]
68-
print "----------------------------"
117+
print("Output: (at line " + str(i) + ")")
118+
print("----------------------------")
119+
print(lst_output[i])
120+
print("----------------------------")
121+
print("Expected Output:")
122+
print("----------------------------")
123+
print(lst_expected[i])
124+
print("----------------------------")
69125
break
70126

71-
print "exit code:", exit_code
72-
print "\nFailed!"
73-
sys.exit(exit_code)
127+
print("exit code: {}".format(exit_code))
128+
test_result.log(filename, fail=True)
74129

75-
def test_path(folder, is_file):
76-
files=['']
77-
if is_file == False:
78-
print "Testing ->", os.path.basename(folder)
79-
files = os.listdir(folder)
130+
def test_path(path):
131+
if os.path.isfile(path):
132+
folder, file = os.path.dirname(path), os.path.basename(path)
80133
else:
81-
files[0] = folder
82-
83-
for js_file in files:
84-
if is_file or os.path.splitext(js_file)[1] == '.js':
85-
js_file = os.path.join(folder, js_file)
86-
js_output = ""
87-
88-
if not os.path.isfile(js_file):
89-
print "Javascript file doesn't exist (" + js_file + ")"
90-
sys.exit(1)
91-
92-
p = SP.Popen([ch_path, js_file], stdout=SP.PIPE, stderr=SP.STDOUT, close_fds=True)
93-
js_output = p.communicate()[0].replace('\r','')
94-
exit_code = p.wait()
95-
96-
if exit_code != 0:
97-
show_failed(js_file, js_output, exit_code, None)
98-
else: #compare outputs
99-
baseline = os.path.splitext(js_file)[0] + '.baseline'
100-
baseline = os.path.join(folder, baseline)
101-
if os.path.isfile(baseline):
102-
expected_output = None
103-
with open(baseline, 'r') as bs_file:
104-
expected_output = bs_file.read().replace('\r', '')
105-
# todo: compare line by line and use/implement wild cards support
106-
# todo: by default we discard line endings (xplat), make this optional
107-
if expected_output.replace('\n', '') != js_output.replace('\n', ''):
108-
show_failed(js_file, js_output, exit_code, expected_output)
109-
110-
if not is_file:
111-
print "\tPassed ->", os.path.basename(js_file)
112-
113-
is_file = len(test_dirs) == 1 and os.path.splitext(test_dirs[0])[1] == '.js'
114-
115-
for folder in test_dirs:
116-
full_path = os.path.join(test_root, folder)
117-
if os.path.isdir(full_path) or is_file:
118-
test_path(full_path, is_file)
119-
120-
print 'Success!'
134+
folder, file = path, None
135+
136+
tests = load_tests(folder, file)
137+
if len(tests) == 0:
138+
return
139+
140+
print("Testing -> " + os.path.basename(folder))
141+
for test in tests:
142+
test_one(folder, test)
143+
144+
def test_one(folder, test):
145+
js_file = os.path.join(folder, test['files'])
146+
js_output = ""
147+
148+
flags = test.get('compile-flags')
149+
cmd = [binary, '-WERExceptionSupport', '-ExtendedErrorStackForTestHost'] \
150+
+ (flags.split() if flags else []) \
151+
+ [js_file]
152+
p = SP.Popen(cmd, stdout=SP.PIPE, stderr=SP.STDOUT)
153+
js_output = p.communicate()[0].replace('\r','')
154+
exit_code = p.wait()
155+
156+
if exit_code != 0:
157+
return show_failed(js_file, js_output, exit_code, None)
158+
else: #compare outputs
159+
baseline = os.path.splitext(js_file)[0] + '.baseline'
160+
if os.path.isfile(baseline):
161+
expected_output = None
162+
with open(baseline, 'r') as bs_file:
163+
expected_output = bs_file.read().replace('\r', '')
164+
# todo: compare line by line and use/implement wild cards support
165+
# todo: by default we discard line endings (xplat), make this optional
166+
if expected_output.replace('\n', '') != js_output.replace('\n', ''):
167+
return show_failed(js_file, js_output, exit_code, expected_output)
168+
169+
print("\tPassed -> " + os.path.basename(js_file))
170+
test_result.log(folder=folder)
171+
172+
def load_tests(folder, file):
173+
try:
174+
xmlpath = os.path.join(folder, 'rlexe.xml')
175+
xml = ET.parse(xmlpath).getroot()
176+
except IOError:
177+
return []
178+
179+
tests = [load_test(x) for x in xml]
180+
if file != None:
181+
tests = [x for x in tests if x['files'] == file]
182+
if len(tests) == 0 and is_jsfile(file):
183+
tests = [{'files':file}]
184+
return tests
185+
186+
def load_test(testXml):
187+
test = dict()
188+
for c in testXml.find('default'):
189+
test[c.tag] = c.text
190+
return test
191+
192+
def is_jsfile(path):
193+
return os.path.splitext(path)[1] == '.js'
194+
195+
def main():
196+
# By default run all tests
197+
if len(args.folders) == 0:
198+
args.folders = [os.path.join(test_root, x)
199+
for x in sorted(os.listdir(test_root))]
200+
201+
for folder in args.folders:
202+
test_path(folder)
203+
204+
print('\n')
205+
print('============================')
206+
for folder, result in sorted(test_result.folders.items()):
207+
print('{}: {}'.format(folder, result))
208+
print('============================')
209+
print('Total: {}'.format(test_result))
210+
print('Success!' if test_result.fail_count == 0 else 'Failed!')
211+
return 0
212+
213+
if __name__ == '__main__':
214+
sys.exit(main())

0 commit comments

Comments
 (0)