blob: ca226324a8dc3fe5df0b3820846801fc8d4cde9b [file] [log] [blame]
Gavin Howardfd06ac22018-10-10 16:48:32 -06001#! /usr/bin/python3 -B
2#
Gavin Howard29e00ba2020-06-30 09:25:21 -06003# SPDX-License-Identifier: BSD-2-Clause
4#
Gavin Howard4feb7082021-01-26 01:19:25 -07005# Copyright (c) 2018-2021 Gavin D. Howard and contributors.
Gavin Howardfd06ac22018-10-10 16:48:32 -06006#
Gavin Howard7345cb92019-04-08 14:13:43 -06007# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions are met:
9#
10# * Redistributions of source code must retain the above copyright notice, this
11# list of conditions and the following disclaimer.
12#
13# * Redistributions in binary form must reproduce the above copyright notice,
14# this list of conditions and the following disclaimer in the documentation
15# and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27# POSSIBILITY OF SUCH DAMAGE.
Gavin Howardfd06ac22018-10-10 16:48:32 -060028#
29
30import os, errno
31import random
32import sys
33import subprocess
34
Gavin Howardfd06ac22018-10-10 16:48:32 -060035def gen(limit=4):
36 return random.randint(0, 2 ** (8 * limit))
37
38def negative():
39 return random.randint(0, 1) == 1
40
41def zero():
42 return random.randint(0, 2 ** (8) - 1) == 0
43
Gavin Howardefa4d742018-10-11 11:59:59 -060044def num(op, neg, real, z, limit=4):
Gavin Howardfd06ac22018-10-10 16:48:32 -060045
46 if z:
47 z = zero()
48 else:
49 z = False
50
51 if z:
52 return 0
53
54 if neg:
55 neg = negative()
56
57 g = gen(limit)
58
59 if real and negative():
Gavin Howardc9ba1ee2018-10-12 08:43:10 -060060 n = str(gen(25))
Gavin Howard4f07e6e2018-10-13 20:29:52 -060061 length = gen(7 / 8)
Gavin Howardc9ba1ee2018-10-12 08:43:10 -060062 if len(n) < length:
63 n = ("0" * (length - len(n))) + n
Gavin Howardfd06ac22018-10-10 16:48:32 -060064 else:
Gavin Howardc9ba1ee2018-10-12 08:43:10 -060065 n = "0"
Gavin Howardfd06ac22018-10-10 16:48:32 -060066
67 g = str(g)
Gavin Howardc9ba1ee2018-10-12 08:43:10 -060068 if n != "0":
69 g = g + "." + n
Gavin Howardfd06ac22018-10-10 16:48:32 -060070
71 if neg and g != "0":
Gavin Howardefa4d742018-10-11 11:59:59 -060072 if op != modexp:
73 g = "-" + g
74 else:
75 g = "_" + g
Gavin Howardfd06ac22018-10-10 16:48:32 -060076
77 return g
78
79
Gavin Howarda8f61ed2018-10-10 17:03:42 -060080def add(test, op):
Gavin Howardfd06ac22018-10-10 16:48:32 -060081
Gavin Howard31a22752018-10-12 08:45:03 -060082 tests.append(test)
83 gen_ops.append(op)
Gavin Howardfd06ac22018-10-10 16:48:32 -060084
85def compare(exe, options, p, test, halt, expected, op, do_add=True):
86
87 if p.returncode != 0:
88
89 print(" {} returned an error ({})".format(exe, p.returncode))
90
91 if do_add:
Gavin Howard4d00e1e2018-10-13 20:35:53 -060092 print(" adding to checklist...")
Gavin Howarda8f61ed2018-10-10 17:03:42 -060093 add(test, op)
Gavin Howardfd06ac22018-10-10 16:48:32 -060094
95 return
96
97 actual = p.stdout.decode()
98
99 if actual != expected:
100
101 if op >= exponent:
102
103 indata = "scale += 10; {}; {}".format(test, halt)
104 args = [ exe, options ]
105 p2 = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
106 expected = p2.stdout[:-10].decode()
107
108 if actual == expected:
109 print(" failed because of bug in other {}".format(exe))
110 print(" continuing...")
111 return
112
Gavin Howardfd06ac22018-10-10 16:48:32 -0600113 if do_add:
Gavin Howard4d00e1e2018-10-13 20:35:53 -0600114 print(" failed; adding to checklist...")
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600115 add(test, op)
Gavin Howard4d00e1e2018-10-13 20:35:53 -0600116 else:
117 print(" failed {}".format(test))
118 print(" expected:")
119 print(" {}".format(expected))
120 print(" actual:")
121 print(" {}".format(actual))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600122
123
124def gen_test(op):
125
Gavin Howardefa4d742018-10-11 11:59:59 -0600126 scale = num(op, False, False, True, 5 / 8)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600127
128 if op < div:
Gavin Howardefa4d742018-10-11 11:59:59 -0600129 s = fmts[op].format(scale, num(op, True, True, True), num(op, True, True, True))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600130 elif op == div or op == mod:
Gavin Howardefa4d742018-10-11 11:59:59 -0600131 s = fmts[op].format(scale, num(op, True, True, True), num(op, True, True, False))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600132 elif op == power:
Gavin Howardefa4d742018-10-11 11:59:59 -0600133 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 -0600134 elif op == modexp:
Gavin Howardefa4d742018-10-11 11:59:59 -0600135 s = fmts[op].format(scale, num(op, True, False, True), num(op, True, False, True),
136 num(op, True, False, False))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600137 elif op == sqrt:
138 s = "1"
139 while s == "1":
Gavin Howardefa4d742018-10-11 11:59:59 -0600140 s = num(op, False, True, True, 1)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600141 s = fmts[op].format(scale, s)
142 else:
143
144 if op == exponent:
Gavin Howardefa4d742018-10-11 11:59:59 -0600145 first = num(op, True, True, True, 6 / 8)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600146 elif op == bessel:
Gavin Howardefa4d742018-10-11 11:59:59 -0600147 first = num(op, False, True, True, 6 / 8)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600148 else:
Gavin Howardefa4d742018-10-11 11:59:59 -0600149 first = num(op, True, True, True)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600150
151 if op != bessel:
152 s = fmts[op].format(scale, first)
153 else:
154 s = fmts[op].format(scale, first, 6 / 8)
155
156 return s
157
158def run_test(t):
159
160 op = random.randrange(bessel + 1)
161
162 if op != modexp:
163 exe = "bc"
164 halt = "halt"
165 options = "-lq"
166 else:
167 exe = "dc"
168 halt = "q"
Gavin Howard96f3e2e2019-06-23 09:18:07 -0600169 options = ""
Gavin Howardfd06ac22018-10-10 16:48:32 -0600170
171 test = gen_test(op)
172
Gavin Howardddc16962018-10-12 08:46:01 -0600173 if "c(0)" in test or "scale = 4; j(4" in test:
174 return
175
Gavin Howardfd06ac22018-10-10 16:48:32 -0600176 bcexe = exedir + "/" + exe
177 indata = test + "\n" + halt
178
Gavin Howardfd06ac22018-10-10 16:48:32 -0600179 print("Test {}: {}".format(t, test))
180
Gavin Howarde2b88b52019-06-23 12:29:36 -0600181 if exe == "bc":
182 args = [ exe, options ]
183 else:
184 args = [ exe ]
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600185
Gavin Howardfd06ac22018-10-10 16:48:32 -0600186 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
187
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600188 output1 = p.stdout.decode()
189
190 if p.returncode != 0 or output1 == "":
Gavin Howardfd06ac22018-10-10 16:48:32 -0600191 print(" other {} returned an error ({}); continuing...".format(exe, p.returncode))
192 return
193
Gavin Howard3e4ce692018-10-13 18:29:24 -0600194 if output1 == "\n":
195 print(" other {} has a bug; continuing...".format(exe))
196 return
197
198 if output1 == "-0\n":
199 output1 = "0\n"
Gavin Howard1fe84c42018-10-13 20:00:28 -0600200 elif output1 == "-0":
201 output1 = "0"
Gavin Howard3e4ce692018-10-13 18:29:24 -0600202
Gavin Howardfd06ac22018-10-10 16:48:32 -0600203 args = [ bcexe, options ]
204
205 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
206 compare(exe, options, p, test, halt, output1, op)
207
208
209if __name__ != "__main__":
210 sys.exit(1)
211
212script = sys.argv[0]
213testdir = os.path.dirname(script)
214
Gavin Howard5f361b42018-10-12 18:06:59 -0600215exedir = testdir + "/../bin"
Gavin Howardfd06ac22018-10-10 16:48:32 -0600216
217ops = [ '+', '-', '*', '/', '%', '^', '|' ]
218files = [ "add", "subtract", "multiply", "divide", "modulus", "power", "modexp",
219 "sqrt", "exponent", "log", "arctangent", "sine", "cosine", "bessel" ]
220funcs = [ "sqrt", "e", "l", "a", "s", "c", "j" ]
221
222fmts = [ "scale = {}; {} + {}", "scale = {}; {} - {}", "scale = {}; {} * {}",
223 "scale = {}; {} / {}", "scale = {}; {} % {}", "scale = {}; {} ^ {}",
224 "{}k {} {} {}|pR", "scale = {}; sqrt({})", "scale = {}; e({})",
225 "scale = {}; l({})", "scale = {}; a({})", "scale = {}; s({})",
226 "scale = {}; c({})", "scale = {}; j({}, {})" ]
227
228div = 3
229mod = 4
230power = 5
231modexp = 6
232sqrt = 7
233exponent = 8
234bessel = 13
235
Gavin Howard31a22752018-10-12 08:45:03 -0600236gen_ops = []
237tests = []
Gavin Howardfd06ac22018-10-10 16:48:32 -0600238
239try:
240 i = 0
241 while True:
242 run_test(i)
243 i = i + 1
244except KeyboardInterrupt:
245 pass
246
Gavin Howard89722402018-10-12 10:43:20 -0600247if len(tests) == 0:
Gavin Howardfd06ac22018-10-10 16:48:32 -0600248 print("\nNo items in checklist.")
249 print("Exiting")
250 sys.exit(0)
251
252print("\nGoing through the checklist...\n")
253
Gavin Howard31a22752018-10-12 08:45:03 -0600254if len(tests) != len(gen_ops):
Gavin Howardfd06ac22018-10-10 16:48:32 -0600255 print("Corrupted checklist!")
256 print("Exiting...")
257 sys.exit(1)
258
259for i in range(0, len(tests)):
260
Gavin Howardfd06ac22018-10-10 16:48:32 -0600261 print("\n{}".format(tests[i]))
262
Gavin Howard31a22752018-10-12 08:45:03 -0600263 op = int(gen_ops[i])
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600264
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600265 if op != modexp:
Gavin Howardfd06ac22018-10-10 16:48:32 -0600266 exe = "bc"
267 halt = "halt"
268 options = "-lq"
269 else:
270 exe = "dc"
271 halt = "q"
272 options = ""
273
Gavin Howardfd06ac22018-10-10 16:48:32 -0600274 indata = tests[i] + "\n" + halt
275
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600276 args = [ exe, options ]
277
Gavin Howardfd06ac22018-10-10 16:48:32 -0600278 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
279
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600280 expected = p.stdout.decode()
281
282 bcexe = exedir + "/" + exe
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600283 args = [ bcexe, options ]
284
285 p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
286
287 compare(exe, options, p, tests[i], halt, expected, op, False)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600288
Gavin Howard06e02432018-10-12 08:46:28 -0600289 answer = input("\nAdd test ({}/{}) to test suite? [y/N]: ".format(i + 1, len(tests)))
Gavin Howardfd06ac22018-10-10 16:48:32 -0600290
291 if 'Y' in answer or 'y' in answer:
Gavin Howard0f46afc2018-10-26 10:25:08 -0600292
Gavin Howardfd06ac22018-10-10 16:48:32 -0600293 print("Yes")
Gavin Howardfd06ac22018-10-10 16:48:32 -0600294
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600295 name = testdir + "/" + exe + "/" + files[op]
Gavin Howardfd06ac22018-10-10 16:48:32 -0600296
297 with open(name + ".txt", "a") as f:
Gavin Howarde9238d22019-05-14 12:40:29 -0600298 f.write(tests[i] + "\n")
Gavin Howardfd06ac22018-10-10 16:48:32 -0600299
300 with open(name + "_results.txt", "a") as f:
Gavin Howarda8f61ed2018-10-10 17:03:42 -0600301 f.write(expected)
Gavin Howardfd06ac22018-10-10 16:48:32 -0600302
303 else:
304 print("No")
305
Gavin Howard31a22752018-10-12 08:45:03 -0600306print("Done!")