blob: 52f17c97eb7370c5d807be22d3873332937f2c8f [file] [log] [blame]
Gavin Howardfd06ac22018-10-10 16:48:32 -06001#! /usr/bin/python3 -B
2#
3# Copyright 2018 Gavin D. Howard
4#
5# Permission to use, copy, modify, and/or distribute this software for any
6# purpose with or without fee is hereby granted.
7#
8# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14# PERFORMANCE OF THIS SOFTWARE.
15#
16
17import os, errno
18import random
19import sys
20import subprocess
21
Gavin Howardfd06ac22018-10-10 16:48:32 -060022def gen(limit=4):
23 return random.randint(0, 2 ** (8 * limit))
24
25def negative():
26 return random.randint(0, 1) == 1
27
28def zero():
29 return random.randint(0, 2 ** (8) - 1) == 0
30
Gavin Howardefa4d742018-10-11 11:59:59 -060031def num(op, neg, real, z, limit=4):
Gavin Howardfd06ac22018-10-10 16:48:32 -060032
33 if z:
34 z = zero()
35 else:
36 z = False
37
38 if z:
39 return 0
40
41 if neg:
42 neg = negative()
43
44 g = gen(limit)
45
46 if real and negative():
Gavin Howardc9ba1ee2018-10-12 08:43:10 -060047 n = str(gen(25))
48 length = gen(1)
49 if len(n) < length:
50 n = ("0" * (length - len(n))) + n
Gavin Howardfd06ac22018-10-10 16:48:32 -060051 else:
Gavin Howardc9ba1ee2018-10-12 08:43:10 -060052 n = "0"
Gavin Howardfd06ac22018-10-10 16:48:32 -060053
54 g = str(g)
Gavin Howardc9ba1ee2018-10-12 08:43:10 -060055 if n != "0":
56 g = g + "." + n
Gavin Howardfd06ac22018-10-10 16:48:32 -060057
58 if neg and g != "0":
Gavin Howardefa4d742018-10-11 11:59:59 -060059 if op != modexp:
60 g = "-" + g
61 else:
62 g = "_" + g
Gavin Howardfd06ac22018-10-10 16:48:32 -060063
64 return g
65
66
Gavin Howarda8f61ed2018-10-10 17:03:42 -060067def add(test, op):
Gavin Howardfd06ac22018-10-10 16:48:32 -060068
Gavin Howard31a22752018-10-12 08:45:03 -060069 tests.append(test)
70 gen_ops.append(op)
Gavin Howardfd06ac22018-10-10 16:48:32 -060071
72def compare(exe, options, p, test, halt, expected, op, do_add=True):
73
74 if p.returncode != 0:
75
76 print(" {} returned an error ({})".format(exe, p.returncode))
77
78 if do_add:
79 print(" adding {} to checklist...".format(test))
Gavin Howarda8f61ed2018-10-10 17:03:42 -060080 add(test, op)
Gavin Howardfd06ac22018-10-10 16:48:32 -060081
82 return
83
84 actual = p.stdout.decode()
85
86 if actual != expected:
87
88 if op >= exponent:
89
90 indata = "scale += 10; {}; {}".format(test, halt)
91 args = [ exe, options ]
92 p2 = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
93 expected = p2.stdout[:-10].decode()
94
95 if actual == expected:
96 print(" failed because of bug in other {}".format(exe))
97 print(" continuing...")
98 return
99
Gavin Howard34b5c682018-10-11 17:30:09 -0600100 print(" failed {}".format(test))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600101 print(" expected:")
102 print(" {}".format(expected))
103 print(" actual:")
104 print(" {}".format(actual))
105
106 if do_add:
107 print(" adding to checklist...")
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600108 add(test, op)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600109
110
111def gen_test(op):
112
Gavin Howardefa4d742018-10-11 11:59:59 -0600113 scale = num(op, False, False, True, 5 / 8)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600114
115 if op < div:
Gavin Howardefa4d742018-10-11 11:59:59 -0600116 s = fmts[op].format(scale, num(op, True, True, True), num(op, True, True, True))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600117 elif op == div or op == mod:
Gavin Howardefa4d742018-10-11 11:59:59 -0600118 s = fmts[op].format(scale, num(op, True, True, True), num(op, True, True, False))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600119 elif op == power:
Gavin Howardefa4d742018-10-11 11:59:59 -0600120 s = fmts[op].format(scale, num(op, True, True, True, 7 / 8), num(op, True, False, True, 6 / 8))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600121 elif op == modexp:
Gavin Howardefa4d742018-10-11 11:59:59 -0600122 s = fmts[op].format(scale, num(op, True, False, True), num(op, True, False, True),
123 num(op, True, False, False))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600124 elif op == sqrt:
125 s = "1"
126 while s == "1":
Gavin Howardefa4d742018-10-11 11:59:59 -0600127 s = num(op, False, True, True, 1)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600128 s = fmts[op].format(scale, s)
129 else:
130
131 if op == exponent:
Gavin Howardefa4d742018-10-11 11:59:59 -0600132 first = num(op, True, True, True, 6 / 8)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600133 elif op == bessel:
Gavin Howardefa4d742018-10-11 11:59:59 -0600134 first = num(op, False, True, True, 6 / 8)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600135 else:
Gavin Howardefa4d742018-10-11 11:59:59 -0600136 first = num(op, True, True, True)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600137
138 if op != bessel:
139 s = fmts[op].format(scale, first)
140 else:
141 s = fmts[op].format(scale, first, 6 / 8)
142
143 return s
144
145def run_test(t):
146
147 op = random.randrange(bessel + 1)
148
149 if op != modexp:
150 exe = "bc"
151 halt = "halt"
152 options = "-lq"
153 else:
154 exe = "dc"
155 halt = "q"
156 options = ""
157
158 test = gen_test(op)
159
Gavin Howardddc16962018-10-12 08:46:01 -0600160 if "c(0)" in test or "scale = 4; j(4" in test:
161 return
162
Gavin Howardfd06ac22018-10-10 16:48:32 -0600163 bcexe = exedir + "/" + exe
164 indata = test + "\n" + halt
165
Gavin Howardfd06ac22018-10-10 16:48:32 -0600166 print("Test {}: {}".format(t, test))
167
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600168 args = [ exe, options ]
169
Gavin Howardfd06ac22018-10-10 16:48:32 -0600170 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
171
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600172 output1 = p.stdout.decode()
173
174 if p.returncode != 0 or output1 == "":
Gavin Howardfd06ac22018-10-10 16:48:32 -0600175 print(" other {} returned an error ({}); continuing...".format(exe, p.returncode))
176 return
177
Gavin Howardfd06ac22018-10-10 16:48:32 -0600178 args = [ bcexe, options ]
179
180 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
181 compare(exe, options, p, test, halt, output1, op)
182
183
184if __name__ != "__main__":
185 sys.exit(1)
186
187script = sys.argv[0]
188testdir = os.path.dirname(script)
189
190exedir = testdir + "/.."
Gavin Howardfd06ac22018-10-10 16:48:32 -0600191
192ops = [ '+', '-', '*', '/', '%', '^', '|' ]
193files = [ "add", "subtract", "multiply", "divide", "modulus", "power", "modexp",
194 "sqrt", "exponent", "log", "arctangent", "sine", "cosine", "bessel" ]
195funcs = [ "sqrt", "e", "l", "a", "s", "c", "j" ]
196
197fmts = [ "scale = {}; {} + {}", "scale = {}; {} - {}", "scale = {}; {} * {}",
198 "scale = {}; {} / {}", "scale = {}; {} % {}", "scale = {}; {} ^ {}",
199 "{}k {} {} {}|pR", "scale = {}; sqrt({})", "scale = {}; e({})",
200 "scale = {}; l({})", "scale = {}; a({})", "scale = {}; s({})",
201 "scale = {}; c({})", "scale = {}; j({}, {})" ]
202
203div = 3
204mod = 4
205power = 5
206modexp = 6
207sqrt = 7
208exponent = 8
209bessel = 13
210
Gavin Howard31a22752018-10-12 08:45:03 -0600211gen_ops = []
212tests = []
Gavin Howardfd06ac22018-10-10 16:48:32 -0600213
214try:
215 i = 0
216 while True:
217 run_test(i)
218 i = i + 1
219except KeyboardInterrupt:
220 pass
221
Gavin Howard89722402018-10-12 10:43:20 -0600222if len(tests) == 0:
Gavin Howardfd06ac22018-10-10 16:48:32 -0600223 print("\nNo items in checklist.")
224 print("Exiting")
225 sys.exit(0)
226
227print("\nGoing through the checklist...\n")
228
Gavin Howard31a22752018-10-12 08:45:03 -0600229if len(tests) != len(gen_ops):
Gavin Howardfd06ac22018-10-10 16:48:32 -0600230 print("Corrupted checklist!")
231 print("Exiting...")
232 sys.exit(1)
233
234for i in range(0, len(tests)):
235
Gavin Howardfd06ac22018-10-10 16:48:32 -0600236 print("\n{}".format(tests[i]))
237
Gavin Howard31a22752018-10-12 08:45:03 -0600238 op = int(gen_ops[i])
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600239
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600240 if op != modexp:
Gavin Howardfd06ac22018-10-10 16:48:32 -0600241 exe = "bc"
242 halt = "halt"
243 options = "-lq"
244 else:
245 exe = "dc"
246 halt = "q"
247 options = ""
248
Gavin Howardfd06ac22018-10-10 16:48:32 -0600249 indata = tests[i] + "\n" + halt
250
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600251 args = [ exe, options ]
252
Gavin Howardfd06ac22018-10-10 16:48:32 -0600253 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
254
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600255 expected = p.stdout.decode()
256
257 bcexe = exedir + "/" + exe
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600258 args = [ bcexe, options ]
259
260 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
261
262 compare(exe, options, p, tests[i], halt, expected, op, False)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600263
Gavin Howard06e02432018-10-12 08:46:28 -0600264 answer = input("\nAdd test ({}/{}) to test suite? [y/N]: ".format(i + 1, len(tests)))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600265
266 if 'Y' in answer or 'y' in answer:
267 print("Yes")
268 continue
269
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600270 name = testdir + "/" + exe + "/" + files[op]
Gavin Howardfd06ac22018-10-10 16:48:32 -0600271
272 with open(name + ".txt", "a") as f:
273 f.write(tests[i])
274
275 with open(name + "_results.txt", "a") as f:
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600276 f.write(expected)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600277
278 else:
279 print("No")
280
Gavin Howard31a22752018-10-12 08:45:03 -0600281print("Done!")