blob: b4383b0521743e68b5bdf6829954c00eeedd93d4 [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))
Gavin Howard4f07e6e2018-10-13 20:29:52 -060048 length = gen(7 / 8)
Gavin Howardc9ba1ee2018-10-12 08:43:10 -060049 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:
Gavin Howard4d00e1e2018-10-13 20:35:53 -060079 print(" adding to checklist...")
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 Howardfd06ac22018-10-10 16:48:32 -0600100 if do_add:
Gavin Howard4d00e1e2018-10-13 20:35:53 -0600101 print(" failed; adding to checklist...")
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600102 add(test, op)
Gavin Howard4d00e1e2018-10-13 20:35:53 -0600103 else:
104 print(" failed {}".format(test))
105 print(" expected:")
106 print(" {}".format(expected))
107 print(" actual:")
108 print(" {}".format(actual))
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 Howard3e4ce692018-10-13 18:29:24 -0600178 if output1 == "\n":
179 print(" other {} has a bug; continuing...".format(exe))
180 return
181
182 if output1 == "-0\n":
183 output1 = "0\n"
Gavin Howard1fe84c42018-10-13 20:00:28 -0600184 elif output1 == "-0":
185 output1 = "0"
Gavin Howard3e4ce692018-10-13 18:29:24 -0600186
Gavin Howardfd06ac22018-10-10 16:48:32 -0600187 args = [ bcexe, options ]
188
189 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
190 compare(exe, options, p, test, halt, output1, op)
191
192
193if __name__ != "__main__":
194 sys.exit(1)
195
196script = sys.argv[0]
197testdir = os.path.dirname(script)
198
Gavin Howard5f361b42018-10-12 18:06:59 -0600199exedir = testdir + "/../bin"
Gavin Howardfd06ac22018-10-10 16:48:32 -0600200
201ops = [ '+', '-', '*', '/', '%', '^', '|' ]
202files = [ "add", "subtract", "multiply", "divide", "modulus", "power", "modexp",
203 "sqrt", "exponent", "log", "arctangent", "sine", "cosine", "bessel" ]
204funcs = [ "sqrt", "e", "l", "a", "s", "c", "j" ]
205
206fmts = [ "scale = {}; {} + {}", "scale = {}; {} - {}", "scale = {}; {} * {}",
207 "scale = {}; {} / {}", "scale = {}; {} % {}", "scale = {}; {} ^ {}",
208 "{}k {} {} {}|pR", "scale = {}; sqrt({})", "scale = {}; e({})",
209 "scale = {}; l({})", "scale = {}; a({})", "scale = {}; s({})",
210 "scale = {}; c({})", "scale = {}; j({}, {})" ]
211
212div = 3
213mod = 4
214power = 5
215modexp = 6
216sqrt = 7
217exponent = 8
218bessel = 13
219
Gavin Howard31a22752018-10-12 08:45:03 -0600220gen_ops = []
221tests = []
Gavin Howardfd06ac22018-10-10 16:48:32 -0600222
223try:
224 i = 0
225 while True:
226 run_test(i)
227 i = i + 1
228except KeyboardInterrupt:
229 pass
230
Gavin Howard89722402018-10-12 10:43:20 -0600231if len(tests) == 0:
Gavin Howardfd06ac22018-10-10 16:48:32 -0600232 print("\nNo items in checklist.")
233 print("Exiting")
234 sys.exit(0)
235
236print("\nGoing through the checklist...\n")
237
Gavin Howard31a22752018-10-12 08:45:03 -0600238if len(tests) != len(gen_ops):
Gavin Howardfd06ac22018-10-10 16:48:32 -0600239 print("Corrupted checklist!")
240 print("Exiting...")
241 sys.exit(1)
242
243for i in range(0, len(tests)):
244
Gavin Howardfd06ac22018-10-10 16:48:32 -0600245 print("\n{}".format(tests[i]))
246
Gavin Howard31a22752018-10-12 08:45:03 -0600247 op = int(gen_ops[i])
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600248
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600249 if op != modexp:
Gavin Howardfd06ac22018-10-10 16:48:32 -0600250 exe = "bc"
251 halt = "halt"
252 options = "-lq"
253 else:
254 exe = "dc"
255 halt = "q"
256 options = ""
257
Gavin Howardfd06ac22018-10-10 16:48:32 -0600258 indata = tests[i] + "\n" + halt
259
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600260 args = [ exe, options ]
261
Gavin Howardfd06ac22018-10-10 16:48:32 -0600262 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
263
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600264 expected = p.stdout.decode()
265
266 bcexe = exedir + "/" + exe
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600267 args = [ bcexe, options ]
268
269 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
270
271 compare(exe, options, p, tests[i], halt, expected, op, False)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600272
Gavin Howard06e02432018-10-12 08:46:28 -0600273 answer = input("\nAdd test ({}/{}) to test suite? [y/N]: ".format(i + 1, len(tests)))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600274
275 if 'Y' in answer or 'y' in answer:
276 print("Yes")
277 continue
278
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600279 name = testdir + "/" + exe + "/" + files[op]
Gavin Howardfd06ac22018-10-10 16:48:32 -0600280
281 with open(name + ".txt", "a") as f:
282 f.write(tests[i])
283
284 with open(name + "_results.txt", "a") as f:
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600285 f.write(expected)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600286
287 else:
288 print("No")
289
Gavin Howard31a22752018-10-12 08:45:03 -0600290print("Done!")