You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
307 lines
7.0 KiB
307 lines
7.0 KiB
#! /usr/bin/python3 -B
|
|
#
|
|
# SPDX-License-Identifier: BSD-2-Clause
|
|
#
|
|
# Copyright (c) 2018-2021 Gavin D. Howard and contributors.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
#
|
|
# * Redistributions of source code must retain the above copyright notice, this
|
|
# list of conditions and the following disclaimer.
|
|
#
|
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
# this list of conditions and the following disclaimer in the documentation
|
|
# and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
|
|
import os, errno
|
|
import random
|
|
import sys
|
|
import subprocess
|
|
|
|
def gen(limit=4):
|
|
return random.randint(0, 2 ** (8 * limit))
|
|
|
|
def negative():
|
|
return random.randint(0, 1) == 1
|
|
|
|
def zero():
|
|
return random.randint(0, 2 ** (8) - 1) == 0
|
|
|
|
def num(op, neg, real, z, limit=4):
|
|
|
|
if z:
|
|
z = zero()
|
|
else:
|
|
z = False
|
|
|
|
if z:
|
|
return 0
|
|
|
|
if neg:
|
|
neg = negative()
|
|
|
|
g = gen(limit)
|
|
|
|
if real and negative():
|
|
n = str(gen(25))
|
|
length = gen(7 / 8)
|
|
if len(n) < length:
|
|
n = ("0" * (length - len(n))) + n
|
|
else:
|
|
n = "0"
|
|
|
|
g = str(g)
|
|
if n != "0":
|
|
g = g + "." + n
|
|
|
|
if neg and g != "0":
|
|
if op != modexp:
|
|
g = "-" + g
|
|
else:
|
|
g = "_" + g
|
|
|
|
return g
|
|
|
|
|
|
def add(test, op):
|
|
|
|
tests.append(test)
|
|
gen_ops.append(op)
|
|
|
|
def compare(exe, options, p, test, halt, expected, op, do_add=True):
|
|
|
|
if p.returncode != 0:
|
|
|
|
print(" {} returned an error ({})".format(exe, p.returncode))
|
|
|
|
if do_add:
|
|
print(" adding to checklist...")
|
|
add(test, op)
|
|
|
|
return
|
|
|
|
actual = p.stdout.decode()
|
|
|
|
if actual != expected:
|
|
|
|
if op >= exponent:
|
|
|
|
indata = "scale += 10; {}; {}".format(test, halt)
|
|
args = [ exe, options ]
|
|
p2 = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
expected = p2.stdout[:-10].decode()
|
|
|
|
if actual == expected:
|
|
print(" failed because of bug in other {}".format(exe))
|
|
print(" continuing...")
|
|
return
|
|
|
|
if do_add:
|
|
print(" failed; adding to checklist...")
|
|
add(test, op)
|
|
else:
|
|
print(" failed {}".format(test))
|
|
print(" expected:")
|
|
print(" {}".format(expected))
|
|
print(" actual:")
|
|
print(" {}".format(actual))
|
|
|
|
|
|
def gen_test(op):
|
|
|
|
scale = num(op, False, False, True, 5 / 8)
|
|
|
|
if op < div:
|
|
s = fmts[op].format(scale, num(op, True, True, True), num(op, True, True, True))
|
|
elif op == div or op == mod:
|
|
s = fmts[op].format(scale, num(op, True, True, True), num(op, True, True, False))
|
|
elif op == power:
|
|
s = fmts[op].format(scale, num(op, True, True, True, 7 / 8), num(op, True, False, True, 6 / 8))
|
|
elif op == modexp:
|
|
s = fmts[op].format(scale, num(op, True, False, True), num(op, True, False, True),
|
|
num(op, True, False, False))
|
|
elif op == sqrt:
|
|
s = "1"
|
|
while s == "1":
|
|
s = num(op, False, True, True, 1)
|
|
s = fmts[op].format(scale, s)
|
|
else:
|
|
|
|
if op == exponent:
|
|
first = num(op, True, True, True, 6 / 8)
|
|
elif op == bessel:
|
|
first = num(op, False, True, True, 6 / 8)
|
|
else:
|
|
first = num(op, True, True, True)
|
|
|
|
if op != bessel:
|
|
s = fmts[op].format(scale, first)
|
|
else:
|
|
s = fmts[op].format(scale, first, 6 / 8)
|
|
|
|
return s
|
|
|
|
def run_test(t):
|
|
|
|
op = random.randrange(bessel + 1)
|
|
|
|
if op != modexp:
|
|
exe = "bc"
|
|
halt = "halt"
|
|
options = "-lq"
|
|
else:
|
|
exe = "dc"
|
|
halt = "q"
|
|
options = ""
|
|
|
|
test = gen_test(op)
|
|
|
|
if "c(0)" in test or "scale = 4; j(4" in test:
|
|
return
|
|
|
|
bcexe = exedir + "/" + exe
|
|
indata = test + "\n" + halt
|
|
|
|
print("Test {}: {}".format(t, test))
|
|
|
|
if exe == "bc":
|
|
args = [ exe, options ]
|
|
else:
|
|
args = [ exe ]
|
|
|
|
p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
|
output1 = p.stdout.decode()
|
|
|
|
if p.returncode != 0 or output1 == "":
|
|
print(" other {} returned an error ({}); continuing...".format(exe, p.returncode))
|
|
return
|
|
|
|
if output1 == "\n":
|
|
print(" other {} has a bug; continuing...".format(exe))
|
|
return
|
|
|
|
if output1 == "-0\n":
|
|
output1 = "0\n"
|
|
elif output1 == "-0":
|
|
output1 = "0"
|
|
|
|
args = [ bcexe, options ]
|
|
|
|
p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
compare(exe, options, p, test, halt, output1, op)
|
|
|
|
|
|
if __name__ != "__main__":
|
|
sys.exit(1)
|
|
|
|
script = sys.argv[0]
|
|
testdir = os.path.dirname(script)
|
|
|
|
exedir = testdir + "/../bin"
|
|
|
|
ops = [ '+', '-', '*', '/', '%', '^', '|' ]
|
|
files = [ "add", "subtract", "multiply", "divide", "modulus", "power", "modexp",
|
|
"sqrt", "exponent", "log", "arctangent", "sine", "cosine", "bessel" ]
|
|
funcs = [ "sqrt", "e", "l", "a", "s", "c", "j" ]
|
|
|
|
fmts = [ "scale = {}; {} + {}", "scale = {}; {} - {}", "scale = {}; {} * {}",
|
|
"scale = {}; {} / {}", "scale = {}; {} % {}", "scale = {}; {} ^ {}",
|
|
"{}k {} {} {}|pR", "scale = {}; sqrt({})", "scale = {}; e({})",
|
|
"scale = {}; l({})", "scale = {}; a({})", "scale = {}; s({})",
|
|
"scale = {}; c({})", "scale = {}; j({}, {})" ]
|
|
|
|
div = 3
|
|
mod = 4
|
|
power = 5
|
|
modexp = 6
|
|
sqrt = 7
|
|
exponent = 8
|
|
bessel = 13
|
|
|
|
gen_ops = []
|
|
tests = []
|
|
|
|
try:
|
|
i = 0
|
|
while True:
|
|
run_test(i)
|
|
i = i + 1
|
|
except KeyboardInterrupt:
|
|
pass
|
|
|
|
if len(tests) == 0:
|
|
print("\nNo items in checklist.")
|
|
print("Exiting")
|
|
sys.exit(0)
|
|
|
|
print("\nGoing through the checklist...\n")
|
|
|
|
if len(tests) != len(gen_ops):
|
|
print("Corrupted checklist!")
|
|
print("Exiting...")
|
|
sys.exit(1)
|
|
|
|
for i in range(0, len(tests)):
|
|
|
|
print("\n{}".format(tests[i]))
|
|
|
|
op = int(gen_ops[i])
|
|
|
|
if op != modexp:
|
|
exe = "bc"
|
|
halt = "halt"
|
|
options = "-lq"
|
|
else:
|
|
exe = "dc"
|
|
halt = "q"
|
|
options = ""
|
|
|
|
indata = tests[i] + "\n" + halt
|
|
|
|
args = [ exe, options ]
|
|
|
|
p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
|
expected = p.stdout.decode()
|
|
|
|
bcexe = exedir + "/" + exe
|
|
args = [ bcexe, options ]
|
|
|
|
p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
|
compare(exe, options, p, tests[i], halt, expected, op, False)
|
|
|
|
answer = input("\nAdd test ({}/{}) to test suite? [y/N]: ".format(i + 1, len(tests)))
|
|
|
|
if 'Y' in answer or 'y' in answer:
|
|
|
|
print("Yes")
|
|
|
|
name = testdir + "/" + exe + "/" + files[op]
|
|
|
|
with open(name + ".txt", "a") as f:
|
|
f.write(tests[i] + "\n")
|
|
|
|
with open(name + "_results.txt", "a") as f:
|
|
f.write(expected)
|
|
|
|
else:
|
|
print("No")
|
|
|
|
print("Done!")
|