Last active
December 9, 2021 07:56
-
-
Save Samyak2/20eaef27510506fc74408f59cdcb3a2c to your computer and use it in GitHub Desktop.
Random test case generator and tester for intal in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this is a testing file for intal (integer of arbitrary length) in C, to be used with the python file | |
# Steps to use | |
# 1. Compile with the main file (which is here - https://gist.github.com/Samyak2/d0c2552b11581f59091f9f377bbc65f0) | |
# 1.1 Make sure the executable is named `intal` (using `-o intal` during compiling) | |
# 2. Make sure python version is >=3.6 and scipy is installed | |
# 3. Run this script | |
# excuse the bad code, it was only intended to work | |
# Here is another version to test the time complexity - https://gist.github.com/Samyak2/a2975ec738e76dd7ead1147db3c0ef93 | |
# Author: Samyak S Sarnayak | |
import sys | |
import subprocess | |
import random | |
import operator | |
import math | |
import scipy.special | |
def fibonacci(n): | |
a = 0 | |
b = 1 | |
if n == 0: | |
return a | |
if n == 1: | |
return b | |
for _ in range(2, n+1): | |
c = a + b | |
a = b | |
b = c | |
return b | |
def coin_row_problem(arr, s): | |
n = len(arr) | |
if n == 0: | |
return 0 | |
prev = 0 | |
cur = arr[0] | |
for i in range(1, n): | |
next_ = max(prev+arr[i], cur) | |
prev = cur | |
cur = next_ | |
return cur | |
max_ = 10**1000 | |
def test_intal_outs_binary(operation, name, cases=100, max1=max_//2, max2=max_//2): | |
passed = 0 | |
skipped = 0 | |
total_time = 0.0 | |
max_time = 0.0 | |
for _ in range(cases): | |
a = random.randrange(0, max1) | |
b = random.randrange(0, max2) | |
try: | |
expected_res = operation(a, b) | |
if expected_res > max_: | |
# print(f"Skipped a test case due to result being huge. {a} {name} {b} = {expected_res}") | |
skipped += 1 | |
continue | |
p = subprocess.run(["./intal", name], check=True, | |
input=f"{a}\n{b}\n", | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
encoding="ascii") | |
# res = int(p.stdout.strip()) | |
res, time = p.stdout.strip().split() | |
res = res.strip() # int(res) | |
expected_res = str(expected_res) | |
time = float(time) | |
if time > max_time: | |
max_time = time | |
total_time += time | |
if res == expected_res: | |
passed += 1 | |
else: | |
print(f"Test failed: {a} {name} {b} = {expected_res} != {res}", file=sys.stderr) | |
except subprocess.CalledProcessError as e: | |
print(f"Test failed: for a = {a}, b = {b}. Error: {e}", file=sys.stderr) | |
except OverflowError as e: | |
print(f"Test failed due to overflow {a} {name} {b}", file=sys.stderr) | |
except ValueError as e: | |
print(f"Test failed due to invalid output: {a} {name} {b} = {expected_res}. Error: {e}", file=sys.stderr) | |
avg_time = (total_time*1000)/passed if passed > 0 else "N/A" | |
print(f"{passed} tests passed, {skipped} tests skipped out of {cases} for {name}. Average time taken: {avg_time}ms. Maximum time: {max_time*1000}ms") | |
def test_intal_outs_unary(operation, name, cases=100, max1=100): | |
passed = 0 | |
skipped = 0 | |
total_time = 0.0 | |
max_time = 0.0 | |
for _ in range(cases): | |
a = random.randrange(0, max1) | |
try: | |
expected_res = operation(a) | |
if expected_res > max_: | |
# print(f"Skipped a test case due to result being huge. {name} {a} = {expected_res}") | |
skipped += 1 | |
continue | |
p = subprocess.run(["./intal", name], check=True, | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
input=f"{a}\n", | |
encoding="ascii") | |
# res = int(p.stdout.strip()) | |
res, time = p.stdout.strip().split() | |
res = res.strip() # int(res) | |
expected_res = str(expected_res) | |
time = float(time) | |
if time > max_time: | |
max_time = time | |
total_time += time | |
if res == expected_res: | |
passed += 1 | |
else: | |
print(f"Test failed: {name} {a} = {expected_res} != {res}", file=sys.stderr) | |
except subprocess.CalledProcessError as e: | |
print(f"Test failed: for a = {a}. Error: {e}", file=sys.stderr) | |
except OverflowError as e: | |
print(f"Test failed due to overflow {name} {a}", file=sys.stderr) | |
except ValueError as e: | |
print(f"Test failed due to invalid output: {name} {a} = {expected_res}. Error: {e}", file=sys.stderr) | |
avg_time = (total_time*1000)/passed if passed > 0 else "N/A" | |
print(f"{passed} tests passed, {skipped} tests skipped out of {cases} for {name}. Average time taken: {avg_time}ms. Maximum time: {max_time*1000}ms") | |
def test_intal_outs_array(operation, name, extra_inp=False, extra_inp_from_arr=False, cases=100, arraylength=50, max1=max_, sort=False, | |
check_sort=False): | |
passed = 0 | |
skipped = 0 | |
total_time = 0.0 | |
max_time = 0.0 | |
for __ in range(cases): | |
arr = [random.randrange(0, max1) for _ in range(arraylength)] | |
if sort: | |
arr.sort() | |
if extra_inp: | |
if extra_inp_from_arr: | |
s = random.choice(arr) | |
else: | |
s = random.randrange(0, max1) | |
else: | |
s = None | |
try: | |
expected_res = operation(arr, s) | |
if not check_sort: | |
if expected_res > max_: | |
skipped += 1 | |
continue | |
p = subprocess.run(["./intal", "array", name], check=True, | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
input="{}\n{}\n".format(arraylength, '\n'.join(map(str, arr if s is None else arr+[s]))), | |
encoding="ascii") | |
# res = int(p.stdout.strip()) | |
if not check_sort: | |
res, time = p.stdout.strip().split() | |
res = res.strip() # int(res) | |
expected_res = str(expected_res) | |
else: | |
res = p.stdout.strip().split() | |
time = res[-1] | |
res = res[:-1] | |
res = [str(res_).strip() for res_ in res] | |
expected_res = [str(res_) for res_ in expected_res] | |
time = float(time) | |
if time > max_time: | |
max_time = time | |
total_time += time | |
if res == expected_res: | |
passed += 1 | |
else: | |
print(f"Test failed: {name} {[len(str(a)) for a in arr]} = {expected_res} != {res}", file=sys.stderr) | |
except subprocess.CalledProcessError as e: | |
print(f"Test failed: for a = {[len(str(a)) for a in arr]}. Error: {e}", file=sys.stderr) | |
except OverflowError as e: | |
print(f"Test failed due to overflow {name} {[len(str(a)) for a in arr]}", file=sys.stderr) | |
except ValueError as e: | |
print(f"Test failed due to invalid output: {name} {[len(str(a)) for a in arr]} = {expected_res}. Error: {e}", file=sys.stderr) | |
avg_time = (total_time*1000)/passed if passed > 0 else "N/A" | |
print(f"{passed} tests passed, {skipped} tests skipped out of {cases} for {name}. Average time taken: {avg_time}ms. Maximum time: {max_time*1000}ms") | |
# this feature was implemented by Rehan in his fork. Source: https://gist.github.com/rehanvipin/2bcbe40fb9e25b44c3439f9855df98fb | |
all_tests = ["add", "diff", "multiply", "mod", "bincoeff", "gcd", "pow", "fibo", "fact", "min", "max", "search", "binsearch", "sort", "coinrow"] | |
print("Which functions do you want to test?") | |
for index, _test in enumerate(all_tests): | |
print(index, _test) | |
print("Enter your choices, index numbers, separated by a comma, enter 12345 to test them all") | |
choices = list(map(int, input().split(","))) | |
use_all = False | |
if 12345 in choices: | |
use_all = True | |
if 0 in choices or use_all: | |
test_intal_outs_binary(operator.add, "add") | |
if 1 in choices or use_all: | |
test_intal_outs_binary(lambda a, b: operator.abs(operator.sub(a, b)), "diff") | |
if 2 in choices or use_all: | |
test_intal_outs_binary(operator.mul, "multiply", max1=10**100, max2=10**10) | |
if 3 in choices or use_all: | |
test_intal_outs_binary(operator.mod, "mod") | |
if 4 in choices or use_all: | |
test_intal_outs_binary(lambda n, k: scipy.special.comb(n, k, exact=True), "bincoeff", | |
max1=1000, | |
max2=1000) | |
if 5 in choices or use_all: | |
test_intal_outs_binary(math.gcd, "gcd") | |
if 6 in choices or use_all: | |
test_intal_outs_binary(operator.pow, "pow", max1=10**3, max2=10**2) | |
if 7 in choices or use_all: | |
test_intal_outs_unary(fibonacci, "fibo") | |
if 8 in choices or use_all: | |
test_intal_outs_unary(math.factorial, "fact") | |
if 9 in choices or use_all: | |
test_intal_outs_array(lambda arr, s: min(enumerate(arr), key=lambda p: p[1])[0], "min") | |
if 10 in choices or use_all: | |
test_intal_outs_array(lambda arr, s: max(enumerate(arr), key=lambda p: p[1])[0], "max") | |
if 11 in choices or use_all: | |
test_intal_outs_array(lambda arr, s: arr.index(s) if s in arr else -1, "search", extra_inp=True) | |
test_intal_outs_array(lambda arr, s: arr.index(s) if s in arr else -1, "search", extra_inp=True, extra_inp_from_arr=True) | |
if 12 in choices or use_all: | |
test_intal_outs_array(lambda arr, s: arr.index(s) if s in arr else -1, "binsearch", extra_inp=True, sort=True) | |
test_intal_outs_array(lambda arr, s: arr.index(s) if s in arr else -1, "binsearch", extra_inp=True, extra_inp_from_arr=True, sort=True) | |
if 13 in choices or use_all: | |
test_intal_outs_array(lambda arr, s: sorted(arr), "sort", check_sort=True) | |
test_intal_outs_array(lambda arr, s: sorted(arr), "sort", check_sort=True, sort=True) | |
if 14 in choices or use_all: | |
test_intal_outs_array(coin_row_problem, "coinrow", max1=10*100) | |
test_intal_outs_array(coin_row_problem, "coinrow", max1=10*100, sort=True) |
Hello,
Awesome work! Thank you very much!
I've added this feature for testing functions individually, would you please look at it and merge if possible?
I just forked and added some if conditions : https://gist.github.com/rehanvipin/2bcbe40fb9e25b44c3439f9855df98fb
, couldn't find anything here for making pull requests though.
Thanks! I'll merge it.
Try
chmod u+x intal
, this will make sure that the executable you generated using themain.c
file can be executed.
The error was because I had not downloaded main.c. The tests worked fine after that 👍.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello,
Awesome work! Thank you very much!
I've added this feature for testing functions individually, would you please look at it and merge if possible?
I just forked and added some if conditions : https://gist.github.com/rehanvipin/2bcbe40fb9e25b44c3439f9855df98fb
, couldn't find anything here for making pull requests though.