1*5a6e8488SAndroid Build Coastguard Worker#! /usr/bin/python3 -B 2*5a6e8488SAndroid Build Coastguard Worker# 3*5a6e8488SAndroid Build Coastguard Worker# SPDX-License-Identifier: BSD-2-Clause 4*5a6e8488SAndroid Build Coastguard Worker# 5*5a6e8488SAndroid Build Coastguard Worker# Copyright (c) 2018-2024 Gavin D. Howard and contributors. 6*5a6e8488SAndroid Build Coastguard Worker# 7*5a6e8488SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without 8*5a6e8488SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are met: 9*5a6e8488SAndroid Build Coastguard Worker# 10*5a6e8488SAndroid Build Coastguard Worker# * Redistributions of source code must retain the above copyright notice, this 11*5a6e8488SAndroid Build Coastguard Worker# list of conditions and the following disclaimer. 12*5a6e8488SAndroid Build Coastguard Worker# 13*5a6e8488SAndroid Build Coastguard Worker# * Redistributions in binary form must reproduce the above copyright notice, 14*5a6e8488SAndroid Build Coastguard Worker# this list of conditions and the following disclaimer in the documentation 15*5a6e8488SAndroid Build Coastguard Worker# and/or other materials provided with the distribution. 16*5a6e8488SAndroid Build Coastguard Worker# 17*5a6e8488SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18*5a6e8488SAndroid Build Coastguard Worker# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*5a6e8488SAndroid Build Coastguard Worker# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*5a6e8488SAndroid Build Coastguard Worker# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21*5a6e8488SAndroid Build Coastguard Worker# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22*5a6e8488SAndroid Build Coastguard Worker# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*5a6e8488SAndroid Build Coastguard Worker# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*5a6e8488SAndroid Build Coastguard Worker# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25*5a6e8488SAndroid Build Coastguard Worker# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*5a6e8488SAndroid Build Coastguard Worker# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27*5a6e8488SAndroid Build Coastguard Worker# POSSIBILITY OF SUCH DAMAGE. 28*5a6e8488SAndroid Build Coastguard Worker# 29*5a6e8488SAndroid Build Coastguard Worker 30*5a6e8488SAndroid Build Coastguard Workerimport os, errno 31*5a6e8488SAndroid Build Coastguard Workerimport random 32*5a6e8488SAndroid Build Coastguard Workerimport sys 33*5a6e8488SAndroid Build Coastguard Workerimport subprocess 34*5a6e8488SAndroid Build Coastguard Worker 35*5a6e8488SAndroid Build Coastguard Worker# I want line length to *not* affect differences between the two, so I set it 36*5a6e8488SAndroid Build Coastguard Worker# as high as possible. 37*5a6e8488SAndroid Build Coastguard Workerenv = { 38*5a6e8488SAndroid Build Coastguard Worker "BC_LINE_LENGTH": "65535", 39*5a6e8488SAndroid Build Coastguard Worker "DC_LINE_LENGTH": "65535" 40*5a6e8488SAndroid Build Coastguard Worker} 41*5a6e8488SAndroid Build Coastguard Worker 42*5a6e8488SAndroid Build Coastguard Worker 43*5a6e8488SAndroid Build Coastguard Worker# Generate a random integer between 0 and 2^limit. 44*5a6e8488SAndroid Build Coastguard Worker# @param limit The power of two for the upper limit. 45*5a6e8488SAndroid Build Coastguard Workerdef gen(limit=4): 46*5a6e8488SAndroid Build Coastguard Worker return random.randint(0, 2 ** (8 * limit)) 47*5a6e8488SAndroid Build Coastguard Worker 48*5a6e8488SAndroid Build Coastguard Worker 49*5a6e8488SAndroid Build Coastguard Worker# Returns a random boolean for whether a number should be negative or not. 50*5a6e8488SAndroid Build Coastguard Workerdef negative(): 51*5a6e8488SAndroid Build Coastguard Worker return random.randint(0, 1) == 1 52*5a6e8488SAndroid Build Coastguard Worker 53*5a6e8488SAndroid Build Coastguard Worker 54*5a6e8488SAndroid Build Coastguard Worker# Returns a random boolean for whether a number should be 0 or not. I decided to 55*5a6e8488SAndroid Build Coastguard Worker# have it be 0 every 2^4 times since sometimes it is used to make a number less 56*5a6e8488SAndroid Build Coastguard Worker# than 1. 57*5a6e8488SAndroid Build Coastguard Workerdef zero(): 58*5a6e8488SAndroid Build Coastguard Worker return random.randint(0, 2 ** (4) - 1) == 0 59*5a6e8488SAndroid Build Coastguard Worker 60*5a6e8488SAndroid Build Coastguard Worker 61*5a6e8488SAndroid Build Coastguard Worker# Generate a real portion of a number. 62*5a6e8488SAndroid Build Coastguard Workerdef gen_real(): 63*5a6e8488SAndroid Build Coastguard Worker 64*5a6e8488SAndroid Build Coastguard Worker # Figure out if we should have a real portion. If so generate it. 65*5a6e8488SAndroid Build Coastguard Worker if negative(): 66*5a6e8488SAndroid Build Coastguard Worker n = str(gen(25)) 67*5a6e8488SAndroid Build Coastguard Worker length = gen(7 / 8) 68*5a6e8488SAndroid Build Coastguard Worker if len(n) < length: 69*5a6e8488SAndroid Build Coastguard Worker n = ("0" * (length - len(n))) + n 70*5a6e8488SAndroid Build Coastguard Worker else: 71*5a6e8488SAndroid Build Coastguard Worker n = "0" 72*5a6e8488SAndroid Build Coastguard Worker 73*5a6e8488SAndroid Build Coastguard Worker return n 74*5a6e8488SAndroid Build Coastguard Worker 75*5a6e8488SAndroid Build Coastguard Worker 76*5a6e8488SAndroid Build Coastguard Worker# Generates a number (as a string) based on the parameters. 77*5a6e8488SAndroid Build Coastguard Worker# @param op The operation under test. 78*5a6e8488SAndroid Build Coastguard Worker# @param neg Whether the number can be negative. 79*5a6e8488SAndroid Build Coastguard Worker# @param real Whether the number can be a non-integer. 80*5a6e8488SAndroid Build Coastguard Worker# @param z Whether the number can be zero. 81*5a6e8488SAndroid Build Coastguard Worker# @param limit The power of 2 upper limit for the number. 82*5a6e8488SAndroid Build Coastguard Workerdef num(op, neg, real, z, limit=4): 83*5a6e8488SAndroid Build Coastguard Worker 84*5a6e8488SAndroid Build Coastguard Worker # Handle zero first. 85*5a6e8488SAndroid Build Coastguard Worker if z: 86*5a6e8488SAndroid Build Coastguard Worker z = zero() 87*5a6e8488SAndroid Build Coastguard Worker else: 88*5a6e8488SAndroid Build Coastguard Worker z = False 89*5a6e8488SAndroid Build Coastguard Worker 90*5a6e8488SAndroid Build Coastguard Worker if z: 91*5a6e8488SAndroid Build Coastguard Worker # Generate a real portion maybe 92*5a6e8488SAndroid Build Coastguard Worker if real: 93*5a6e8488SAndroid Build Coastguard Worker n = gen_real() 94*5a6e8488SAndroid Build Coastguard Worker if n != "0": 95*5a6e8488SAndroid Build Coastguard Worker return "0." + n 96*5a6e8488SAndroid Build Coastguard Worker return "0" 97*5a6e8488SAndroid Build Coastguard Worker 98*5a6e8488SAndroid Build Coastguard Worker # Figure out if we should be negative. 99*5a6e8488SAndroid Build Coastguard Worker if neg: 100*5a6e8488SAndroid Build Coastguard Worker neg = negative() 101*5a6e8488SAndroid Build Coastguard Worker 102*5a6e8488SAndroid Build Coastguard Worker # Generate the integer portion. 103*5a6e8488SAndroid Build Coastguard Worker g = gen(limit) 104*5a6e8488SAndroid Build Coastguard Worker 105*5a6e8488SAndroid Build Coastguard Worker # Figure out if we should have a real number. negative() is used to give a 106*5a6e8488SAndroid Build Coastguard Worker # 50/50 chance of getting a negative number. 107*5a6e8488SAndroid Build Coastguard Worker if real: 108*5a6e8488SAndroid Build Coastguard Worker n = gen_real() 109*5a6e8488SAndroid Build Coastguard Worker else: 110*5a6e8488SAndroid Build Coastguard Worker n = "0" 111*5a6e8488SAndroid Build Coastguard Worker 112*5a6e8488SAndroid Build Coastguard Worker # Generate the string. 113*5a6e8488SAndroid Build Coastguard Worker g = str(g) 114*5a6e8488SAndroid Build Coastguard Worker if n != "0": 115*5a6e8488SAndroid Build Coastguard Worker g = g + "." + n 116*5a6e8488SAndroid Build Coastguard Worker 117*5a6e8488SAndroid Build Coastguard Worker # Make sure to use the right negative sign. 118*5a6e8488SAndroid Build Coastguard Worker if neg and g != "0": 119*5a6e8488SAndroid Build Coastguard Worker if op != modexp: 120*5a6e8488SAndroid Build Coastguard Worker g = "-" + g 121*5a6e8488SAndroid Build Coastguard Worker else: 122*5a6e8488SAndroid Build Coastguard Worker g = "_" + g 123*5a6e8488SAndroid Build Coastguard Worker 124*5a6e8488SAndroid Build Coastguard Worker return g 125*5a6e8488SAndroid Build Coastguard Worker 126*5a6e8488SAndroid Build Coastguard Worker 127*5a6e8488SAndroid Build Coastguard Worker# Add a failed test to the list. 128*5a6e8488SAndroid Build Coastguard Worker# @param test The test that failed. 129*5a6e8488SAndroid Build Coastguard Worker# @param op The operation for the test. 130*5a6e8488SAndroid Build Coastguard Workerdef add(test, op): 131*5a6e8488SAndroid Build Coastguard Worker tests.append(test) 132*5a6e8488SAndroid Build Coastguard Worker gen_ops.append(op) 133*5a6e8488SAndroid Build Coastguard Worker 134*5a6e8488SAndroid Build Coastguard Worker 135*5a6e8488SAndroid Build Coastguard Worker# Compare the output between the two. 136*5a6e8488SAndroid Build Coastguard Worker# @param exe The executable under test. 137*5a6e8488SAndroid Build Coastguard Worker# @param options The command-line options. 138*5a6e8488SAndroid Build Coastguard Worker# @param p The object returned from subprocess.run() for the calculator 139*5a6e8488SAndroid Build Coastguard Worker# under test. 140*5a6e8488SAndroid Build Coastguard Worker# @param test The test. 141*5a6e8488SAndroid Build Coastguard Worker# @param halt The halt string for the calculator under test. 142*5a6e8488SAndroid Build Coastguard Worker# @param expected The expected result. 143*5a6e8488SAndroid Build Coastguard Worker# @param op The operation under test. 144*5a6e8488SAndroid Build Coastguard Worker# @param do_add If true, add a failing test to the list, otherwise, don't. 145*5a6e8488SAndroid Build Coastguard Workerdef compare(exe, options, p, test, halt, expected, op, do_add=True): 146*5a6e8488SAndroid Build Coastguard Worker 147*5a6e8488SAndroid Build Coastguard Worker # Check for error from the calculator under test. 148*5a6e8488SAndroid Build Coastguard Worker if p.returncode != 0: 149*5a6e8488SAndroid Build Coastguard Worker 150*5a6e8488SAndroid Build Coastguard Worker print(" {} returned an error ({})".format(exe, p.returncode)) 151*5a6e8488SAndroid Build Coastguard Worker 152*5a6e8488SAndroid Build Coastguard Worker if do_add: 153*5a6e8488SAndroid Build Coastguard Worker print(" adding to checklist...") 154*5a6e8488SAndroid Build Coastguard Worker add(test, op) 155*5a6e8488SAndroid Build Coastguard Worker 156*5a6e8488SAndroid Build Coastguard Worker return 157*5a6e8488SAndroid Build Coastguard Worker 158*5a6e8488SAndroid Build Coastguard Worker actual = p.stdout.decode() 159*5a6e8488SAndroid Build Coastguard Worker 160*5a6e8488SAndroid Build Coastguard Worker # Check for a difference in output. 161*5a6e8488SAndroid Build Coastguard Worker if actual != expected: 162*5a6e8488SAndroid Build Coastguard Worker 163*5a6e8488SAndroid Build Coastguard Worker if op >= exponent: 164*5a6e8488SAndroid Build Coastguard Worker 165*5a6e8488SAndroid Build Coastguard Worker # This is here because GNU bc, like mine can be flaky on the 166*5a6e8488SAndroid Build Coastguard Worker # functions in the math library. This is basically testing if adding 167*5a6e8488SAndroid Build Coastguard Worker # 10 to the scale works to make them match. If so, the difference is 168*5a6e8488SAndroid Build Coastguard Worker # only because of that. 169*5a6e8488SAndroid Build Coastguard Worker indata = "scale += 10; {}; {}".format(test, halt) 170*5a6e8488SAndroid Build Coastguard Worker args = [ exe, options ] 171*5a6e8488SAndroid Build Coastguard Worker p2 = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) 172*5a6e8488SAndroid Build Coastguard Worker expected = p2.stdout[:-10].decode() 173*5a6e8488SAndroid Build Coastguard Worker 174*5a6e8488SAndroid Build Coastguard Worker if actual == expected: 175*5a6e8488SAndroid Build Coastguard Worker print(" failed because of bug in other {}".format(exe)) 176*5a6e8488SAndroid Build Coastguard Worker print(" continuing...") 177*5a6e8488SAndroid Build Coastguard Worker return 178*5a6e8488SAndroid Build Coastguard Worker 179*5a6e8488SAndroid Build Coastguard Worker # Do the correct output for the situation. 180*5a6e8488SAndroid Build Coastguard Worker if do_add: 181*5a6e8488SAndroid Build Coastguard Worker print(" failed; adding to checklist...") 182*5a6e8488SAndroid Build Coastguard Worker add(test, op) 183*5a6e8488SAndroid Build Coastguard Worker else: 184*5a6e8488SAndroid Build Coastguard Worker print(" failed {}".format(test)) 185*5a6e8488SAndroid Build Coastguard Worker print(" expected:") 186*5a6e8488SAndroid Build Coastguard Worker print(" {}".format(expected)) 187*5a6e8488SAndroid Build Coastguard Worker print(" actual:") 188*5a6e8488SAndroid Build Coastguard Worker print(" {}".format(actual)) 189*5a6e8488SAndroid Build Coastguard Worker 190*5a6e8488SAndroid Build Coastguard Worker 191*5a6e8488SAndroid Build Coastguard Worker# Generates a test for op. I made sure that there was no clashing between 192*5a6e8488SAndroid Build Coastguard Worker# calculators. Each calculator is responsible for certain ops. 193*5a6e8488SAndroid Build Coastguard Worker# @param op The operation to test. 194*5a6e8488SAndroid Build Coastguard Workerdef gen_test(op): 195*5a6e8488SAndroid Build Coastguard Worker 196*5a6e8488SAndroid Build Coastguard Worker # First, figure out how big the scale should be. 197*5a6e8488SAndroid Build Coastguard Worker scale = num(op, False, False, True, 5 / 8) 198*5a6e8488SAndroid Build Coastguard Worker 199*5a6e8488SAndroid Build Coastguard Worker # Do the right thing for each op. Generate the test based on the format 200*5a6e8488SAndroid Build Coastguard Worker # string and the constraints of each op. For example, some ops can't accept 201*5a6e8488SAndroid Build Coastguard Worker # 0 in some arguments, and some must have integers in some arguments. 202*5a6e8488SAndroid Build Coastguard Worker if op < div: 203*5a6e8488SAndroid Build Coastguard Worker s = fmts[op].format(scale, num(op, True, True, True), num(op, True, True, True)) 204*5a6e8488SAndroid Build Coastguard Worker elif op == div or op == mod: 205*5a6e8488SAndroid Build Coastguard Worker s = fmts[op].format(scale, num(op, True, True, True), num(op, True, True, False)) 206*5a6e8488SAndroid Build Coastguard Worker elif op == power: 207*5a6e8488SAndroid Build Coastguard Worker s = fmts[op].format(scale, num(op, True, True, True, 7 / 8), num(op, True, False, True, 6 / 8)) 208*5a6e8488SAndroid Build Coastguard Worker elif op == modexp: 209*5a6e8488SAndroid Build Coastguard Worker s = fmts[op].format(scale, num(op, True, False, True), num(op, True, False, True), 210*5a6e8488SAndroid Build Coastguard Worker num(op, True, False, False)) 211*5a6e8488SAndroid Build Coastguard Worker elif op == sqrt: 212*5a6e8488SAndroid Build Coastguard Worker s = "1" 213*5a6e8488SAndroid Build Coastguard Worker while s == "1": 214*5a6e8488SAndroid Build Coastguard Worker s = num(op, False, True, True, 1) 215*5a6e8488SAndroid Build Coastguard Worker s = fmts[op].format(scale, s) 216*5a6e8488SAndroid Build Coastguard Worker else: 217*5a6e8488SAndroid Build Coastguard Worker 218*5a6e8488SAndroid Build Coastguard Worker if op == exponent: 219*5a6e8488SAndroid Build Coastguard Worker first = num(op, True, True, True, 6 / 8) 220*5a6e8488SAndroid Build Coastguard Worker elif op == bessel: 221*5a6e8488SAndroid Build Coastguard Worker first = num(op, False, True, True, 6 / 8) 222*5a6e8488SAndroid Build Coastguard Worker else: 223*5a6e8488SAndroid Build Coastguard Worker first = num(op, True, True, True) 224*5a6e8488SAndroid Build Coastguard Worker 225*5a6e8488SAndroid Build Coastguard Worker if op != bessel: 226*5a6e8488SAndroid Build Coastguard Worker s = fmts[op].format(scale, first) 227*5a6e8488SAndroid Build Coastguard Worker else: 228*5a6e8488SAndroid Build Coastguard Worker s = fmts[op].format(scale, first, 6 / 8) 229*5a6e8488SAndroid Build Coastguard Worker 230*5a6e8488SAndroid Build Coastguard Worker return s 231*5a6e8488SAndroid Build Coastguard Worker 232*5a6e8488SAndroid Build Coastguard Worker 233*5a6e8488SAndroid Build Coastguard Worker# Runs a test with number t. 234*5a6e8488SAndroid Build Coastguard Worker# @param t The number of the test. 235*5a6e8488SAndroid Build Coastguard Workerdef run_test(t): 236*5a6e8488SAndroid Build Coastguard Worker 237*5a6e8488SAndroid Build Coastguard Worker # Randomly select the operation. 238*5a6e8488SAndroid Build Coastguard Worker op = random.randrange(bessel + 1) 239*5a6e8488SAndroid Build Coastguard Worker 240*5a6e8488SAndroid Build Coastguard Worker # Select the right calculator. 241*5a6e8488SAndroid Build Coastguard Worker if op != modexp: 242*5a6e8488SAndroid Build Coastguard Worker exe = "bc" 243*5a6e8488SAndroid Build Coastguard Worker halt = "halt" 244*5a6e8488SAndroid Build Coastguard Worker options = "-lq" 245*5a6e8488SAndroid Build Coastguard Worker else: 246*5a6e8488SAndroid Build Coastguard Worker exe = "dc" 247*5a6e8488SAndroid Build Coastguard Worker halt = "q" 248*5a6e8488SAndroid Build Coastguard Worker options = "" 249*5a6e8488SAndroid Build Coastguard Worker 250*5a6e8488SAndroid Build Coastguard Worker # Generate the test. 251*5a6e8488SAndroid Build Coastguard Worker test = gen_test(op) 252*5a6e8488SAndroid Build Coastguard Worker 253*5a6e8488SAndroid Build Coastguard Worker # These don't work very well for some reason. 254*5a6e8488SAndroid Build Coastguard Worker if "c(0)" in test or "scale = 4; j(4" in test: 255*5a6e8488SAndroid Build Coastguard Worker return 256*5a6e8488SAndroid Build Coastguard Worker 257*5a6e8488SAndroid Build Coastguard Worker # Make sure the calculator will halt. 258*5a6e8488SAndroid Build Coastguard Worker bcexe = exedir + "/" + exe 259*5a6e8488SAndroid Build Coastguard Worker indata = test + "\n" + halt 260*5a6e8488SAndroid Build Coastguard Worker 261*5a6e8488SAndroid Build Coastguard Worker print("Test {}: {}".format(t, test)) 262*5a6e8488SAndroid Build Coastguard Worker 263*5a6e8488SAndroid Build Coastguard Worker # Only bc has options. 264*5a6e8488SAndroid Build Coastguard Worker if exe == "bc": 265*5a6e8488SAndroid Build Coastguard Worker args = [ exe, options ] 266*5a6e8488SAndroid Build Coastguard Worker else: 267*5a6e8488SAndroid Build Coastguard Worker args = [ exe ] 268*5a6e8488SAndroid Build Coastguard Worker 269*5a6e8488SAndroid Build Coastguard Worker # Run the GNU bc. 270*5a6e8488SAndroid Build Coastguard Worker p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) 271*5a6e8488SAndroid Build Coastguard Worker 272*5a6e8488SAndroid Build Coastguard Worker output1 = p.stdout.decode() 273*5a6e8488SAndroid Build Coastguard Worker 274*5a6e8488SAndroid Build Coastguard Worker # Error checking for GNU. 275*5a6e8488SAndroid Build Coastguard Worker if p.returncode != 0 or output1 == "": 276*5a6e8488SAndroid Build Coastguard Worker print(" other {} returned an error ({}); continuing...".format(exe, p.returncode)) 277*5a6e8488SAndroid Build Coastguard Worker return 278*5a6e8488SAndroid Build Coastguard Worker 279*5a6e8488SAndroid Build Coastguard Worker if output1 == "\n": 280*5a6e8488SAndroid Build Coastguard Worker print(" other {} has a bug; continuing...".format(exe)) 281*5a6e8488SAndroid Build Coastguard Worker return 282*5a6e8488SAndroid Build Coastguard Worker 283*5a6e8488SAndroid Build Coastguard Worker # Don't know why GNU has this problem... 284*5a6e8488SAndroid Build Coastguard Worker if output1 == "-0\n": 285*5a6e8488SAndroid Build Coastguard Worker output1 = "0\n" 286*5a6e8488SAndroid Build Coastguard Worker elif output1 == "-0": 287*5a6e8488SAndroid Build Coastguard Worker output1 = "0" 288*5a6e8488SAndroid Build Coastguard Worker 289*5a6e8488SAndroid Build Coastguard Worker args = [ bcexe, options ] 290*5a6e8488SAndroid Build Coastguard Worker 291*5a6e8488SAndroid Build Coastguard Worker # Run this bc/dc and compare. 292*5a6e8488SAndroid Build Coastguard Worker p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) 293*5a6e8488SAndroid Build Coastguard Worker compare(exe, options, p, test, halt, output1, op) 294*5a6e8488SAndroid Build Coastguard Worker 295*5a6e8488SAndroid Build Coastguard Worker 296*5a6e8488SAndroid Build Coastguard Worker# This script must be run by itself. 297*5a6e8488SAndroid Build Coastguard Workerif __name__ != "__main__": 298*5a6e8488SAndroid Build Coastguard Worker sys.exit(1) 299*5a6e8488SAndroid Build Coastguard Worker 300*5a6e8488SAndroid Build Coastguard Workerscript = sys.argv[0] 301*5a6e8488SAndroid Build Coastguard Workertestdir = os.path.dirname(script) 302*5a6e8488SAndroid Build Coastguard Worker 303*5a6e8488SAndroid Build Coastguard Workerexedir = testdir + "/../bin" 304*5a6e8488SAndroid Build Coastguard Worker 305*5a6e8488SAndroid Build Coastguard Worker# The following are tables used to generate numbers. 306*5a6e8488SAndroid Build Coastguard Worker 307*5a6e8488SAndroid Build Coastguard Worker# The operations to test. 308*5a6e8488SAndroid Build Coastguard Workerops = [ '+', '-', '*', '/', '%', '^', '|' ] 309*5a6e8488SAndroid Build Coastguard Worker 310*5a6e8488SAndroid Build Coastguard Worker# The functions that can be tested. 311*5a6e8488SAndroid Build Coastguard Workerfuncs = [ "sqrt", "e", "l", "a", "s", "c", "j" ] 312*5a6e8488SAndroid Build Coastguard Worker 313*5a6e8488SAndroid Build Coastguard Worker# The files (corresponding to the operations with the functions appended) to add 314*5a6e8488SAndroid Build Coastguard Worker# tests to if they fail. 315*5a6e8488SAndroid Build Coastguard Workerfiles = [ "add", "subtract", "multiply", "divide", "modulus", "power", "modexp", 316*5a6e8488SAndroid Build Coastguard Worker "sqrt", "exponent", "log", "arctangent", "sine", "cosine", "bessel" ] 317*5a6e8488SAndroid Build Coastguard Worker 318*5a6e8488SAndroid Build Coastguard Worker# The format strings corresponding to each operation and then each function. 319*5a6e8488SAndroid Build Coastguard Workerfmts = [ "scale = {}; {} + {}", "scale = {}; {} - {}", "scale = {}; {} * {}", 320*5a6e8488SAndroid Build Coastguard Worker "scale = {}; {} / {}", "scale = {}; {} % {}", "scale = {}; {} ^ {}", 321*5a6e8488SAndroid Build Coastguard Worker "{}k {} {} {}|pR", "scale = {}; sqrt({})", "scale = {}; e({})", 322*5a6e8488SAndroid Build Coastguard Worker "scale = {}; l({})", "scale = {}; a({})", "scale = {}; s({})", 323*5a6e8488SAndroid Build Coastguard Worker "scale = {}; c({})", "scale = {}; j({}, {})" ] 324*5a6e8488SAndroid Build Coastguard Worker 325*5a6e8488SAndroid Build Coastguard Worker# Constants to make some code easier later. 326*5a6e8488SAndroid Build Coastguard Workerdiv = 3 327*5a6e8488SAndroid Build Coastguard Workermod = 4 328*5a6e8488SAndroid Build Coastguard Workerpower = 5 329*5a6e8488SAndroid Build Coastguard Workermodexp = 6 330*5a6e8488SAndroid Build Coastguard Workersqrt = 7 331*5a6e8488SAndroid Build Coastguard Workerexponent = 8 332*5a6e8488SAndroid Build Coastguard Workerbessel = 13 333*5a6e8488SAndroid Build Coastguard Worker 334*5a6e8488SAndroid Build Coastguard Workergen_ops = [] 335*5a6e8488SAndroid Build Coastguard Workertests = [] 336*5a6e8488SAndroid Build Coastguard Worker 337*5a6e8488SAndroid Build Coastguard Worker# Infinite loop until the user sends SIGINT. 338*5a6e8488SAndroid Build Coastguard Workertry: 339*5a6e8488SAndroid Build Coastguard Worker i = 0 340*5a6e8488SAndroid Build Coastguard Worker while True: 341*5a6e8488SAndroid Build Coastguard Worker run_test(i) 342*5a6e8488SAndroid Build Coastguard Worker i = i + 1 343*5a6e8488SAndroid Build Coastguard Workerexcept KeyboardInterrupt: 344*5a6e8488SAndroid Build Coastguard Worker pass 345*5a6e8488SAndroid Build Coastguard Worker 346*5a6e8488SAndroid Build Coastguard Worker# This is where we start processing the checklist of possible failures. Why only 347*5a6e8488SAndroid Build Coastguard Worker# possible failures? Because some operations, specifically the functions in the 348*5a6e8488SAndroid Build Coastguard Worker# math library, are not guaranteed to be exactly correct. Because of that, we 349*5a6e8488SAndroid Build Coastguard Worker# need to present every failed test to the user for a final check before we 350*5a6e8488SAndroid Build Coastguard Worker# add them as test cases. 351*5a6e8488SAndroid Build Coastguard Worker 352*5a6e8488SAndroid Build Coastguard Worker# No items, just exit. 353*5a6e8488SAndroid Build Coastguard Workerif len(tests) == 0: 354*5a6e8488SAndroid Build Coastguard Worker print("\nNo items in checklist.") 355*5a6e8488SAndroid Build Coastguard Worker print("Exiting") 356*5a6e8488SAndroid Build Coastguard Worker sys.exit(0) 357*5a6e8488SAndroid Build Coastguard Worker 358*5a6e8488SAndroid Build Coastguard Workerprint("\nGoing through the checklist...\n") 359*5a6e8488SAndroid Build Coastguard Worker 360*5a6e8488SAndroid Build Coastguard Worker# Just do some error checking. If this fails here, it's a bug in this script. 361*5a6e8488SAndroid Build Coastguard Workerif len(tests) != len(gen_ops): 362*5a6e8488SAndroid Build Coastguard Worker print("Corrupted checklist!") 363*5a6e8488SAndroid Build Coastguard Worker print("Exiting...") 364*5a6e8488SAndroid Build Coastguard Worker sys.exit(1) 365*5a6e8488SAndroid Build Coastguard Worker 366*5a6e8488SAndroid Build Coastguard Worker# Go through each item in the checklist. 367*5a6e8488SAndroid Build Coastguard Workerfor i in range(0, len(tests)): 368*5a6e8488SAndroid Build Coastguard Worker 369*5a6e8488SAndroid Build Coastguard Worker # Yes, there's some code duplication. Sue me. 370*5a6e8488SAndroid Build Coastguard Worker 371*5a6e8488SAndroid Build Coastguard Worker print("\n{}".format(tests[i])) 372*5a6e8488SAndroid Build Coastguard Worker 373*5a6e8488SAndroid Build Coastguard Worker op = int(gen_ops[i]) 374*5a6e8488SAndroid Build Coastguard Worker 375*5a6e8488SAndroid Build Coastguard Worker if op != modexp: 376*5a6e8488SAndroid Build Coastguard Worker exe = "bc" 377*5a6e8488SAndroid Build Coastguard Worker halt = "halt" 378*5a6e8488SAndroid Build Coastguard Worker options = "-lq" 379*5a6e8488SAndroid Build Coastguard Worker else: 380*5a6e8488SAndroid Build Coastguard Worker exe = "dc" 381*5a6e8488SAndroid Build Coastguard Worker halt = "q" 382*5a6e8488SAndroid Build Coastguard Worker options = "" 383*5a6e8488SAndroid Build Coastguard Worker 384*5a6e8488SAndroid Build Coastguard Worker # We want to run the test again to show the user the difference. 385*5a6e8488SAndroid Build Coastguard Worker indata = tests[i] + "\n" + halt 386*5a6e8488SAndroid Build Coastguard Worker 387*5a6e8488SAndroid Build Coastguard Worker args = [ exe, options ] 388*5a6e8488SAndroid Build Coastguard Worker 389*5a6e8488SAndroid Build Coastguard Worker p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) 390*5a6e8488SAndroid Build Coastguard Worker 391*5a6e8488SAndroid Build Coastguard Worker expected = p.stdout.decode() 392*5a6e8488SAndroid Build Coastguard Worker 393*5a6e8488SAndroid Build Coastguard Worker bcexe = exedir + "/" + exe 394*5a6e8488SAndroid Build Coastguard Worker args = [ bcexe, options ] 395*5a6e8488SAndroid Build Coastguard Worker 396*5a6e8488SAndroid Build Coastguard Worker p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) 397*5a6e8488SAndroid Build Coastguard Worker 398*5a6e8488SAndroid Build Coastguard Worker compare(exe, options, p, tests[i], halt, expected, op, False) 399*5a6e8488SAndroid Build Coastguard Worker 400*5a6e8488SAndroid Build Coastguard Worker # Ask the user to make a decision on the failed test. 401*5a6e8488SAndroid Build Coastguard Worker answer = input("\nAdd test ({}/{}) to test suite? [y/N]: ".format(i + 1, len(tests))) 402*5a6e8488SAndroid Build Coastguard Worker 403*5a6e8488SAndroid Build Coastguard Worker # Quick and dirty answer parsing. 404*5a6e8488SAndroid Build Coastguard Worker if 'Y' in answer or 'y' in answer: 405*5a6e8488SAndroid Build Coastguard Worker 406*5a6e8488SAndroid Build Coastguard Worker print("Yes") 407*5a6e8488SAndroid Build Coastguard Worker 408*5a6e8488SAndroid Build Coastguard Worker name = testdir + "/" + exe + "/" + files[op] 409*5a6e8488SAndroid Build Coastguard Worker 410*5a6e8488SAndroid Build Coastguard Worker # Write the test to the test file and the expected result to the 411*5a6e8488SAndroid Build Coastguard Worker # results file. 412*5a6e8488SAndroid Build Coastguard Worker with open(name + ".txt", "a") as f: 413*5a6e8488SAndroid Build Coastguard Worker f.write(tests[i] + "\n") 414*5a6e8488SAndroid Build Coastguard Worker 415*5a6e8488SAndroid Build Coastguard Worker with open(name + "_results.txt", "a") as f: 416*5a6e8488SAndroid Build Coastguard Worker f.write(expected) 417*5a6e8488SAndroid Build Coastguard Worker 418*5a6e8488SAndroid Build Coastguard Worker else: 419*5a6e8488SAndroid Build Coastguard Worker print("No") 420*5a6e8488SAndroid Build Coastguard Worker 421*5a6e8488SAndroid Build Coastguard Workerprint("Done!") 422