176 lines
6.9 KiB
Python
176 lines
6.9 KiB
Python
""" debug_lib
|
|
A bunch of helpful debuging functions
|
|
Cal.W 2025
|
|
"""
|
|
|
|
import numpy as np
|
|
|
|
# Consts
|
|
IS_CLOSE_VAR = 0.001
|
|
|
|
# Horriable ENUM types
|
|
class NO_EVAL(type): pass # Whats an enum?
|
|
class TUPLE_EVAL(type): pass
|
|
|
|
def compair_outputs(tasks):
|
|
"""
|
|
|
|
callable, args, expected, force comp type
|
|
|
|
tasks: Tuple[Tuple[callable, Tuple[...], Expacted, [TYPE]], ...]
|
|
|
|
tasks = (
|
|
(determine_power_used, (5e6, 250, 8, 85), 500.9191176470588),
|
|
(determine_water_released, (300, 250, 8, 85), 2994495.4128440367),
|
|
(determine_cost_to_pump, (300, 8, 0.02), 48),
|
|
(calc_speed_at_outlet, (30,), 24.261079942986875),
|
|
(calc_new_water_height, (20, 40000, 1, 30), (19.985143183382704, 592567.1021442247)),
|
|
(calc_heights_water_out, (40, 5, 40000, 1, 30), ((39.97898928844613, 39.95798409574207, 39.93698442188801), (838016.4324684857, 837796.3120398963, 837576.1916037091), TUPLE_EVAL)),
|
|
)
|
|
|
|
"""
|
|
for i, (task, args, expected) in enumerate(tasks):
|
|
print(f'Task {i+1}')
|
|
result = task(*args)
|
|
|
|
# Number comparison
|
|
if isinstance(expected, (float, int)):
|
|
foo = np.isclose(result, expected, IS_CLOSE_VAR)
|
|
print(f'{task.__qualname__}{args}')
|
|
print(f' -> {result} {"~=" if foo else "!="} {expected}')
|
|
print(f'Task is{"" if foo else " NOT"} close enough to expected result.')
|
|
|
|
# Run the task and print out what is is expected on a new line
|
|
elif isinstance(expected, (list, tuple)) and expected[-1] is NO_EVAL:
|
|
print(f'{task.__qualname__}{args} -> {result}')
|
|
print(f'Expected: {expected[:-1]}')
|
|
|
|
# Do a tuple eval
|
|
# [TODO] Do this, not complete
|
|
elif isinstance(expected, (list, tuple)) and expected[-1] is TUPLE_EVAL:
|
|
expected_result = expected[:-1]
|
|
comp_lenths = tuple(len(z) for z in expected_result)
|
|
|
|
flag = False
|
|
for ii, comp_res in enumerate(comp_lenths):
|
|
for iii in range(comp_res):
|
|
bar = isinstance(expected[ii][iii], (float, int)) and isinstance(result[ii][iii], (float, int))
|
|
baz = np.isclose(result[ii][iii], expected[ii][iii], IS_CLOSE_VAR) if bar else (result[ii][iii] == expected[ii][iii])
|
|
if not baz:
|
|
flag = True
|
|
break
|
|
if flag: break
|
|
|
|
print(f'{task.__qualname__}{args} -> {tuple(result[z][:comp_lenths[z]] for z in range(len(result)))}')
|
|
print(f'Expected: {expected[:-1]}')
|
|
|
|
if flag:
|
|
print(f"First Mismatch; result[{ii}][{iii}] -> {result[ii][iii]} != {expected[ii][iii]}")
|
|
|
|
print(f'Task is{" NOT" if flag else ""} close enough to expected result.')
|
|
|
|
# Literal Comparison
|
|
elif expected is not None:
|
|
print(f'{task.__qualname__}{args} -> {result} {"==" if result == expected else "!="} {expected}')
|
|
print(f'Task is{"" if result == expected else " NOT"} equal to expected result.')
|
|
|
|
# Just run the task
|
|
else:
|
|
print(f'{task.__qualname__}{args} -> {result}')
|
|
|
|
# Newline
|
|
print()
|
|
|
|
class auto_input:
|
|
"""Given a list automagicly enter a value."""
|
|
def __init__(self, input_list):
|
|
#Just setup some internal stuff
|
|
self.input_index = 0
|
|
self.input_list = input_list
|
|
|
|
def __call__(self, input_text):
|
|
#TLDR: Get the next value from the array and return that
|
|
# If there was an error then ask the user for input
|
|
try:
|
|
out = self.input_list[self.input_index]
|
|
except:
|
|
out = None
|
|
|
|
self.input_index += 1
|
|
|
|
if out is None:
|
|
out = __builtins__['input']('#Input#: '+input_text)
|
|
else:
|
|
print(str(input_text)+str(out))
|
|
|
|
return str(out)
|
|
|
|
def stringCompairTests(test_function, tests, doPrint=True, logFile=None):
|
|
"""Run a bunch of tests on a function and check the outputs via comparing them to wanted outputs as strings.
|
|
Prams:
|
|
test_function: function - This needs to be the function to test
|
|
tests: list - The list of tests to run. Each test is a list in the form: [(arg1, arg2, ...), expected_output]
|
|
Note: The number of arguments in the tuple *must* equal the number required for the function
|
|
doPrint: bool - Print the test results - Default: True
|
|
logFile: str - The path to write the output as a log if it is NoneType(None) then it won't make a logfile - Default: None
|
|
|
|
Returns:
|
|
list - A list containing each test result as a tuple in the form: (returned_result, Bool(test_succeeded), test)
|
|
|
|
|
|
Example:
|
|
def doThing(arg1, arg2):
|
|
return arg1 + arg2
|
|
|
|
tests = [
|
|
[(1, 2), 3],
|
|
[("Hello", "World"), "HelloWorld"],
|
|
[(1, 3), 2]
|
|
]
|
|
|
|
test_results = stringCompairTests(doThing, tests)
|
|
|
|
>>>test_results => [
|
|
(3, True, [(1, 2), 3]),
|
|
("HelloWorld", True, [("Hello", "World"), "HelloWorld"]),
|
|
(4, False, [(1, 3), 2])
|
|
]
|
|
"""
|
|
test_results = []
|
|
logString = ""
|
|
|
|
for i, test in enumerate(tests):
|
|
result = test_function(**test[0]) if type(test[0]) is dict else test_function(*test[0])
|
|
test_results.append((result, str(test[1]) == str(result), test))
|
|
|
|
logStringL = "-"*50
|
|
logStringL += "\n"+ "Test: " + str(i) + (" - Success" if result else " - Failure")
|
|
logStringL += "\n"+ "Given Arguments: \"" + '", "'.join(test[0]) + '"'
|
|
logStringL += "\n"+ "Expected Output: " + str(test[1])
|
|
logStringL += "\n"+ "Returned Output: " + str(result)
|
|
logStringL += "\n"+ "Returned Values " + ("don't" if not result else "") + "match."
|
|
|
|
logString += '\n' + logStringL
|
|
|
|
if doPrint: print(logStringL)
|
|
|
|
|
|
successfull_tests = sum([1 for x in test_results if x[1]])
|
|
logStringL = "\n" + str(successfull_tests) + " test" + ("s" if len(test_results)-successfull_tests == 1 else '')
|
|
logStringL += " succeeded with " + str(len(test_results)-successfull_tests) + " test"
|
|
logStringL += ("s" if len(test_results)-successfull_tests == 1 else "") + " failing."
|
|
logString += '\n' + logStringL
|
|
|
|
if doPrint: print(logStringL,"\n")
|
|
|
|
if logFile not in (None, ""):
|
|
if type(logFile) is bool and logFile: logFile = __file__.rsplit('\\', 1)[1]
|
|
if logString[0] == "\n": logString = logString[1:]
|
|
|
|
with open(str(logFile)+".log", 'w') as writeFile:
|
|
writeFile.write(logString)
|
|
writeFile.close()
|
|
|
|
if doPrint: print("The logfile:", '\''+str(logFile)+".log'", "has been written to.", "\n")
|
|
|
|
return test_results |