Files
pynamics/diagnostics/os_diagnostics.py
2026-03-17 17:40:53 +00:00

873 lines
34 KiB
Python

from pybricks.parameters import Port
from uerrno import EAGAIN, EBUSY, ECANCELED, EINVAL, EIO, ENODEV, EOPNOTSUPP, EPERM, ETIMEDOUT
import uio
import ujson
import urandom
from urandom import random
from pybricks.iodevices import UARTDevice as _UARTDevice
from pybricks.tools import wait, multitask, run_task
class FakeUART:
def __init__(self, port, baudrate, timeout):
self.timeout = timeout
self._force_error = None
print("Warning: No physical UART detected. Using simulator.")
def set_error(self, errno):
self._force_error = errno
def read(self, length=1):
if self._force_error is not None:
err = self._force_error
self._force_error = None
raise OSError(err)
if self.timeout is not None:
wait(self.timeout)
raise OSError(ETIMEDOUT)
else:
while True:
wait(1000)
def write(self, data):
if self._force_error is not None:
err = self._force_error
self._force_error = None
raise OSError(err)
def UARTDevice(port, baudrate=9600, timeout=None):
try:
return _UARTDevice(port, baudrate, timeout)
except OSError:
return FakeUART(port, baudrate, timeout)
class OSDiagnostics:
def __init__(self, hub, motorclass):
self.hub = hub
self.motorclass = motorclass
self.successfultests = 0
self.failedtests = {}
def testUErrno(self):
uerrnotestobject = UerrnoTest(self.hub, self.motorclass)
uerrnotestobject.testeagain()
uerrnotestobject.testebusy()
uerrnotestobject.testecanceled()
uerrnotestobject.testeinval()
uerrnotestobject.testeio()
uerrnotestobject.testenodev()
uerrnotestobject.testeopnotsupp()
uerrnotestobject.testeperm()
uerrnotestobject.testetimedout()
uerrnotestobject.print_results()
self.successfultests += uerrnotestobject.successfultests
self.failedtests.update(uerrnotestobject.failedtests)
def testUIO(self):
uiotestobject = UIOTest(self.hub, self.motorclass)
uiotestobject.print_results()
self.successfultests += uiotestobject.successfultests
self.failedtests.update(uiotestobject.failedtests)
def testUJSON(self):
ujsontestobject = UJSONTest(self.hub, self.motorclass)
ujsontestobject.print_results()
self.successfultests += ujsontestobject.successfultests
self.failedtests.update(ujsontestobject.failedtests)
def testUMath(self):
umathtestobject = UMathTest(self.hub, self.motorclass)
umathtestobject.print_results()
self.successfultests += umathtestobject.successfultests
self.failedtests.update(umathtestobject.failedtests)
def testURandom(self):
urandtestobject = URandomTest(self.hub, self.motorclass)
urandtestobject.print_results()
self.successfultests += urandtestobject.successfultests
self.failedtests.update(urandtestobject.failedtests)
def testUSelect(self):
uselecttestobject = USelectTest(self.hub, self.motorclass)
uselecttestobject.print_results()
self.successfultests += uselecttestobject.successfultests
self.failedtests.update(uselecttestobject.failedtests)
def testUStruct(self):
ustructtestobject = UStructTest(self.hub, self.motorclass)
ustructtestobject.print_results()
self.successfultests += ustructtestobject.successfultests
self.failedtests.update(ustructtestobject.failedtests)
def testUSys(self):
usystestobject = USysTest(self.hub, self.motorclass)
usystestobject.print_results()
self.successfultests += usystestobject.successfultests
self.failedtests.update(usystestobject.failedtests)
class UerrnoTest:
def __init__(self, hub, motorclass):
self.hub = hub
self.motorclass = motorclass
self.successfultests = 0
self.failedtests = {}
def testeagain(self):
# Triggered by calling multitask() nested inside another multitask()
print("Starting Test 1/9: EAGAIN - Try Again Error")
try:
async def inner():
await multitask(wait(100)) # nested multitask raises EAGAIN
async def outer():
await multitask(inner())
run_task(outer())
print("No error raised.\nCompleted Test 1/9: EAGAIN - FAILED")
self.failedtests["EAGAIN"] = "No error raised"
except OSError as ex:
if ex.errno == EAGAIN:
print("EAGAIN can be thrown and caught.\nCompleted Test 1/9: EAGAIN - SUCCESSFUL")
self.successfultests += 1
elif ex.errno == EIO:
print("An unspecified error occurred (EIO).\nCompleted Test 1/9: EAGAIN - FAILED")
self.failedtests["EAGAIN"] = "EIO - Unspecified Error"
else:
print(f"Another error occurred with code: {ex.errno}.\nCompleted Test 1/9: EAGAIN - FAILED")
self.failedtests["EAGAIN"] = ex.errno
def testebusy(self):
# No reliable hardware trigger; use FakeUART
print("Starting Test 2/9: EBUSY - Device Busy Error")
uart = UARTDevice(Port.A, baudrate=9600, timeout=1000)
uart.set_error(EBUSY)
try:
uart.read(1)
print("No error raised.\nCompleted Test 2/9: EBUSY - FAILED")
self.failedtests["EBUSY"] = "No error raised"
except OSError as ex:
if ex.errno == EBUSY:
print("EBUSY can be thrown and caught.\nCompleted Test 2/9: EBUSY - SUCCESSFUL")
self.successfultests += 1
elif ex.errno == EIO:
print("An unspecified error occurred (EIO).\nCompleted Test 2/9: EBUSY - FAILED")
self.failedtests["EBUSY"] = "EIO - Unspecified Error"
else:
print(f"Another error occurred with code: {ex.errno}.\nCompleted Test 2/9: EBUSY - FAILED")
self.failedtests["EBUSY"] = ex.errno
def testecanceled(self):
# No reliable hardware trigger; use FakeUART
print("Starting Test 3/9: ECANCELED - Operation Canceled Error")
uart = UARTDevice(Port.A, baudrate=9600, timeout=1000)
uart.set_error(ECANCELED)
try:
uart.read(1)
print("No error raised.\nCompleted Test 3/9: ECANCELED - FAILED")
self.failedtests["ECANCELED"] = "No error raised"
except OSError as ex:
if ex.errno == ECANCELED:
print("ECANCELED can be thrown and caught.\nCompleted Test 3/9: ECANCELED - SUCCESSFUL")
self.successfultests += 1
elif ex.errno == EIO:
print("An unspecified error occurred (EIO).\nCompleted Test 3/9: ECANCELED - FAILED")
self.failedtests["ECANCELED"] = "EIO - Unspecified Error"
else:
print(f"Another error occurred with code: {ex.errno}.\nCompleted Test 3/9: ECANCELED - FAILED")
self.failedtests["ECANCELED"] = ex.errno
def testeinval(self):
# Triggered by passing an out-of-range value to motor.control.limits()
print("Starting Test 4/9: EINVAL - Invalid Argument Error")
input("Plug a motor into Port A, then press Enter.")
try:
motor = self.motorclass(Port.A)
motor.control.limits(speed=9999999, acceleration=9999999)
print("No error raised.\nCompleted Test 4/9: EINVAL - FAILED")
self.failedtests["EINVAL"] = "No error raised"
except OSError as ex:
if ex.errno == EINVAL:
print("EINVAL can be thrown and caught.\nCompleted Test 4/9: EINVAL - SUCCESSFUL")
self.successfultests += 1
elif ex.errno == EIO:
print("An unspecified error occurred (EIO).\nCompleted Test 4/9: EINVAL - FAILED")
self.failedtests["EINVAL"] = "EIO - Unspecified Error"
else:
print(f"Another error occurred with code: {ex.errno}.\nCompleted Test 4/9: EINVAL - FAILED")
self.failedtests["EINVAL"] = ex.errno
def testeio(self):
# No reliable scriptable trigger (requires physical unplug); use FakeUART
print("Starting Test 5/9: EIO - I/O Error")
uart = UARTDevice(Port.A, baudrate=9600, timeout=1000)
uart.set_error(EIO)
try:
uart.read(1)
print("No error raised.\nCompleted Test 5/9: EIO - FAILED")
self.failedtests["EIO"] = "No error raised"
except OSError as ex:
if ex.errno == EIO:
print("EIO can be thrown and caught.\nCompleted Test 5/9: EIO - SUCCESSFUL")
self.successfultests += 1
else:
print(f"Another error occurred with code: {ex.errno}.\nCompleted Test 5/9: EIO - FAILED")
self.failedtests["EIO"] = ex.errno
def testenodev(self):
# Triggered by initializing a motor on an empty port
print("Starting Test 6/9: ENODEV - Device Not Found Error")
input("Make sure Port A doesn't have anything plugged in, then press Enter.")
try:
my_motor = self.motorclass(Port.A)
print("OS detected a motor when there was nothing. You may have allowed missing motors. This is useful for debugging, but not recommended for production as it can cause issues with device control.")
self.failedtests["ENODEV"] = "No error raised"
except OSError as ex:
if ex.errno == ENODEV:
print("There is no motor on this port. ENODEV can be thrown and caught.\nCompleted Test 6/9: ENODEV - SUCCESSFUL")
self.successfultests += 1
elif ex.errno == EIO:
print("An unspecified error occurred (EIO).\nCompleted Test 6/9: ENODEV - FAILED")
self.failedtests["ENODEV"] = "EIO - Unspecified Error"
else:
print(f"Another error occurred with code: {ex.errno}.\nCompleted Test 6/9: ENODEV - FAILED")
self.failedtests["ENODEV"] = ex.errno
def testeopnotsupp(self):
# No reliable scriptable trigger without specific hardware; use FakeUART
print("Starting Test 7/9: EOPNOTSUPP - Operation Not Supported Error")
uart = UARTDevice(Port.A, baudrate=9600, timeout=1000)
uart.set_error(EOPNOTSUPP)
try:
uart.read(1)
print("No error raised.\nCompleted Test 7/9: EOPNOTSUPP - FAILED")
self.failedtests["EOPNOTSUPP"] = "No error raised"
except OSError as ex:
if ex.errno == EOPNOTSUPP:
print("EOPNOTSUPP can be thrown and caught.\nCompleted Test 7/9: EOPNOTSUPP - SUCCESSFUL")
self.successfultests += 1
elif ex.errno == EIO:
print("An unspecified error occurred (EIO).\nCompleted Test 7/9: EOPNOTSUPP - FAILED")
self.failedtests["EOPNOTSUPP"] = "EIO - Unspecified Error"
else:
print(f"Another error occurred with code: {ex.errno}.\nCompleted Test 7/9: EOPNOTSUPP - FAILED")
self.failedtests["EOPNOTSUPP"] = ex.errno
def testeperm(self):
# Triggered by calling motor.control.limits() while a motor is actively running
print("Starting Test 8/9: EPERM - Operation Not Permitted Error")
input("Plug a motor into Port A, then press Enter.")
try:
motor = self.motorclass(Port.A)
motor.run(500)
wait(50)
motor.control.limits(speed=500, acceleration=1000)
print("No error raised.\nCompleted Test 8/9: EPERM - FAILED")
self.failedtests["EPERM"] = "No error raised"
except OSError as ex:
if ex.errno == EPERM:
print("EPERM can be thrown and caught.\nCompleted Test 8/9: EPERM - SUCCESSFUL")
self.successfultests += 1
elif ex.errno == EIO:
print("An unspecified error occurred (EIO).\nCompleted Test 8/9: EPERM - FAILED")
self.failedtests["EPERM"] = "EIO - Unspecified Error"
else:
print(f"Another error occurred with code: {ex.errno}.\nCompleted Test 8/9: EPERM - FAILED")
self.failedtests["EPERM"] = ex.errno
finally:
try:
motor.stop()
except Exception:
pass
def testetimedout(self):
# Triggered by FakeUART (or real UART) timing out on read
print("Starting Test 9/9: ETIMEDOUT - Timed Out Error")
uart = UARTDevice(Port.A, baudrate=9600, timeout=1000)
try:
data = uart.read(10)
print("No error raised.\nCompleted Test 9/9: ETIMEDOUT - FAILED")
self.failedtests["ETIMEDOUT"] = "No error raised"
except OSError as ex:
if ex.errno == ETIMEDOUT:
print("Timed out with synthetic UART device. ETIMEDOUT can be thrown and caught.\nCompleted Test 9/9: ETIMEDOUT - SUCCESSFUL")
self.successfultests += 1
elif ex.errno == EIO:
print("An unspecified error occurred (EIO).\nCompleted Test 9/9: ETIMEDOUT - FAILED")
self.failedtests["ETIMEDOUT"] = "EIO - Unspecified Error"
else:
print(f"Another error occurred with code: {ex.errno}.\nCompleted Test 9/9: ETIMEDOUT - FAILED")
self.failedtests["ETIMEDOUT"] = ex.errno
def print_results(self):
print(f"\n=== Results: {self.successfultests}/9 tests passed ===")
if self.failedtests:
print("Failed tests:")
for key, value in self.failedtests.items():
print(f" {key}: {value}")
class UIOTest(OSDiagnostics):
def __init__(self, hub, motorclass):
self.hub = hub
self.motorclass = motorclass
self.successfultests = 0
self.failedtests = {}
# uio contains BytesIO, StringIO, and FileIO, but due to SPIKE Prime's lack of a filesystem, the test will omit FileIO and only include BytesIO and StringIO
def testbytesio(self):
try:
buffer = io.BytesIO()
buffer.write(b'Hello, ')
buffer.write(b'Pybricks byte stream!')
current_content = buffer.getvalue()
print(f"Buffer content (via getvalue()): {current_content}")
print(f"Current cursor position: {buffer.tell()}")
# TODO: After testing that BytesIO actually works on this system, add checks to make sure that the outputs match what they should.
buffer.seek(0)
read_data = buffer.read()
print(f"Read data (via read()): {read_data}")
print(f"Current cursor position after reading: {buffer.tell()}")
buffer.close()
print("Buffer was closed successfully.")
print("Completed Test 1/2: BytesIO - SUCCESSFUL")
self.successfultests += 1
except Exception as ex:
print("An unexpected error occured.")
print("Completed Test 1/2: BytesIO - FAILED")
self.failedtests["BytesIO"] = ex.errno
def teststringio(self):
try:
buffer = io.StringIO()
buffer.write('Hello, ')
buffer.write('Pybricks string stream!')
current_content = buffer.getvalue()
print(f"Buffer content (via getvalue()): {current_content}")
print(f"Current cursor position: {buffer.tell()}")
# TODO: After testing that StringIO actually works on this system, add checks to make sure that the outputs match what they should.
buffer.seek(0)
read_data = buffer.read()
print(f"Read data (via read()): {read_data}")
print(f"Current cursor position after reading: {buffer.tell()}")
buffer.close()
print("Buffer was closed successfully.")
print("Completed Test 2/2: StringIO - SUCCESSFUL")
self.successfultests += 1
except Exception as ex:
print("An unexpected error occured.")
print("Completed Test 2/2: StringIO - FAILED")
self.failedtests["StringIO"] = ex.errno
def print_results(self):
self.testbytesio()
self.teststringio()
print(f"\n=== Results: {self.successfultests}/2 tests passed ===")
if self.failedtests:
print("Failed tests:")
for key, value in self.failedtests.items():
print(f" {key}: {value}")
class UJSONTest:
def __init__(self, hub, motorclass):
self.hub = hub
self.motorclass = motorclass
self.successfultests = 0
self.failedtests = {}
# Tests ujson.dumps() and ujson.loads()
def testdumpsloads(self):
try:
original = {"robot": "Pybricks", "speed": 500, "active": True}
json_str = ujson.dumps(original)
print(f"Serialized (via dumps()): {json_str}")
restored = ujson.loads(json_str)
print(f"Deserialized (via loads()): {restored}")
# TODO: After confirming dumps/loads works on this system, add equality tests
print("Completed Test 1/3: dumps/loads - SUCCESSFUL")
self.successfultests += 1
except Exception as ex:
print("An unexpected error occurred.")
print("Completed Test 1/3: dumps/loads - FAILED")
self.failedtests["dumps/loads"] = getattr(ex, "errno", str(ex))
# Tests ujson.loads() raising ValueError on malformed input
def testloadsinvalid(self):
try:
ujson.loads("{not valid json}")
print("No error raised.")
print("Completed Test 2/3: loads invalid - FAILED")
self.failedtests["loads_invalid"] = "No error raised"
except ValueError:
print("ValueError raised on malformed JSON, as expected.")
print("Completed Test 2/3: loads invalid - SUCCESSFUL")
self.successfultests += 1
except Exception as ex:
print("An unexpected error occurred.")
print("Completed Test 2/3: loads invalid - FAILED")
self.failedtests["loads_invalid"] = getattr(ex, "errno", str(ex))
# Tests ujson.dump() and ujson.load() using a uio.StringIO stream
def testdumpload(self):
try:
original = {"hub": "SPIKE Prime", "port": "A", "value": 42}
stream = uio.StringIO()
ujson.dump(original, stream)
print(f"Serialized to stream (via dump()): {stream.getvalue()}")
stream.seek(0)
restored = ujson.load(stream)
print(f"Deserialized from stream (via load()): {restored}")
stream.close()
# TODO: After confirming dump/load works on this system, add
# equality assertions to verify round-trip fidelity.
print("Completed Test 3/3: dump/load (stream) - SUCCESSFUL")
self.successfultests += 1
except Exception as ex:
print("An unexpected error occurred.")
print("Completed Test 3/3: dump/load (stream) - FAILED")
self.failedtests["dump/load"] = getattr(ex, "errno", str(ex))
def print_results(self):
self.testdumpsloads()
self.testloadsinvalid()
self.testdumpload()
print(f"\n=== Results: {self.successfultests}/3 tests passed ===")
if self.failedtests:
print("Failed tests:")
for key, value in self.failedtests.items():
print(f" {key}: {value}")
class UMathTest:
def __init__(self, hub, motorclass):
self.hub = hub
self.motorclass = motorclass
self.successfultests = 0
self.failedtests = {}
def test_math(self):
if(umath.ceil(87.21) == 88):
self.successfultests += 1
else:
self.failedtests["ceilpos"] = "Failed"
if(umath.floor(14.61) == 14):
self.successfultests += 1
else:
self.failedtests["floorpos"] = "Failed"
if(umath.ceil(-87.21) == -87):
self.successfultests += 1
else:
self.failedtests["ceilneg"] = "Failed"
if(umath.floor(-14.61) == -15):
self.successfultests += 1
else:
self.failedtests["floorneg"] = "Failed"
if(umath.trunc(33.22) == 33):
self.successfultests += 1
else:
self.failedtests["truncpos"] = "Failed"
if(umath.trunc(-33.22) == -33):
self.successfultests += 1
else:
self.failedtests["truncneg"] = "Failed"
if(umath.fmod(6040, 3) == 1):
self.successfultests += 1
else:
self.failedtests["fmod"] = "Failed"
if(umath.fabs(88273) == 88273):
self.successfultests += 1
else:
self.failedtests["fabspos"] = "Failed"
if(umath.fabs(-27482) == 27482):
self.successfultests += 1
else:
self.failedtests["fabsneg"] = "Failed"
if(umath.fabs(-2742.233) == 2742.233):
self.successfultests += 1
else:
self.failedtests["fabsflt"] = "Failed"
if(umath.copysign(3928, -182) == -3928):
self.successfultests += 1
else:
self.failedtests["copysign"] = "Failed"
if(umath.exp(umath.log(1)) == 1):
self.successfultests += 2
else:
self.failedtests["eexp"] = "Failed"
self.failedtests["ln"] = "Failed"
print(umath.e)
print("\n")
if(input("Press Y and press enter if the value displayed above is around 2.718282. Type N and press Enter if it is not:") == "Y"):
self.successfultests += 1
else:
self.failedtests["e"] = "Failed"
if(umath.pow(19, 7) == 893871739):
self.successfultests += 1
else:
self.failedtests["pow"] = "Failed"
if(umath.sqrt(242064) == 492):
self.successfultests += 1
else:
self.failedtests["sqrt"] = "Failed"
print(umath.pi)
print("\n")
if(input("Press Y and press enter if the value displayed above is around 3.14159265. Type N and press Enter if it is not:") == "Y"):
self.successfultests += 1
else:
self.failedtests["pi"] = "Failed"
EPSILON = 1e-9
if abs(umath.degrees(umath.pi * 3) - 540) < EPSILON:
self.successfultests += 1
else:
self.failedtests["degrees"] = "Failed"
if abs(umath.radians(270) - umath.pi * 1.5) < EPSILON:
self.successfultests += 1
else:
self.failedtests["radians"] = "Failed"
if(abs(umath.sin(umath.pi)) < EPSILON):
self.successfultests += 1
else:
self.failedtests["sin"] = "Failed"
if(abs(umath.asin(1) - umath.pi * 0.5) < EPSILON):
self.successfultests += 1
else:
self.failedtests["asin"] = "Failed"
if(abs(umath.cos(umath.pi) + 1) < EPSILON):
self.successfultests += 1
else:
self.failedtests["cos"] = "Failed"
if(abs(umath.acos(1)) < EPSILON):
self.successfultests += 1
else:
self.failedtests["acos"] = "Failed"
if(abs(umath.tan(umath.pi)) < EPSILON):
self.successfultests += 1
else:
self.failedtests["tan"] = "Failed"
if(abs(umath.atan(1) - umath.pi * 0.25) < EPSILON):
self.successfultests += 1
else:
self.failedtests["atan"] = "Failed"
if(abs(umath.atan2(1, -1) - umath.pi * 0.75) < EPSILON):
self.successfultests += 1
else:
self.failedtests["atan2"] = "Failed"
infinitenum = float('inf')
finitenum = 123456
if(umath.isfinite(finitenum) == True):
self.successfultests += 1
else:
self.failedtests["isfinitefinite"] = "Failed"
if(umath.isfinite(infinitenum) == False):
self.successfultests += 1
else:
self.failedtests["isfiniteinfinite"] = "Failed"
if(umath.isinfinite(finitenum) == False):
self.successfultests += 1
else:
self.failedtests["isinfinitefinite"] = "Failed"
if(umath.isinfinite(infinitenum) == True):
self.successfultests += 1
else:
self.failedtests["isinfiniteinfinite"] = "Failed"
nannum = float("nan")
if(umath.isnan(nannum) == True):
self.successfultests += 1
else:
self.failedtests["isnannan"] = "Failed"
if(umath.isnan(finitenum) == False):
self.successfultests += 1
else:
self.failedtests["isnannotnan"] = "Failed"
frac, integer = umath.modf(87.21)
if integer == 87.0 and abs(frac - 0.21) < EPSILON:
self.successfultests += 1
else:
self.failedtests["modf"] = "Failed"
mantissa, exponent = umath.frexp(64)
if mantissa == 0.5 and exponent == 7:
self.successfultests += 1
else:
self.failedtests["frexp"] = "Failed"
result = umath.ldexp(0.5, 7)
if result == 64:
self.successfultests += 1
else:
self.failedtests["ldexp"] = "Failed"
def print_results(self):
self.test_math()
print(f"\n=== Results: {self.successfultests}/34 tests passed ===")
if self.failedtests:
print("Failed tests:")
for key, value in self.failedtests.items():
print(f" {key}: {value}")
class URandomTest:
def __init__(self, hub, motorclass):
self.hub = hub
self.motorclass = motorclass
self.successfultests = 0
self.failedtests = {}
def testrandom(self):
NUM_SAMPLES = 1000000
NUM_BUCKETS = 10
CHART_WIDTH = 50
SAMPLE_PEEK = 20
samples = [random() for _ in range(NUM_SAMPLES)]
bucket_counts = [0] * NUM_BUCKETS
for x in samples:
i = int(x * NUM_BUCKETS)
if i == NUM_BUCKETS:
i -= 1
bucket_counts[i] += 1
mean = sum(samples) / NUM_SAMPLES
ideal = NUM_SAMPLES / NUM_BUCKETS
max_count = max(bucket_counts)
print("=" * 66)
print(" random() distribution test n=" + str(NUM_SAMPLES))
print("=" * 66)
print("")
print(" Range Count Bar")
print(" -------------- ----- " + "-" * CHART_WIDTH)
for i in range(NUM_BUCKETS):
lo = i / NUM_BUCKETS
hi = (i + 1) / NUM_BUCKETS
count = bucket_counts[i]
bar = round(count / max_count * CHART_WIDTH)
dev = abs(count - ideal) / ideal
if dev <= 0.10:
marker = "#"
elif dev <= 0.20:
marker = "+"
else:
marker = "."
lo_str = "{:.2f}".format(lo)
hi_str = "{:.2f}".format(hi)
count_str = str(count).rjust(10)
print(" " + lo_str + " - " + hi_str + " " + count_str + " " + marker * bar)
print("")
print(" Samples : " + str(NUM_SAMPLES))
print(" Mean : " + "{:.6f}".format(mean) + " (ideal 0.500000)")
print(" Min : " + "{:.6f}".format(min(samples)))
print(" Max : " + "{:.6f}".format(max(samples)))
print(" Legend : # within 10% + within 20% . beyond 20%")
print("")
print(" First " + str(SAMPLE_PEEK) + " raw values:")
row = " "
for idx, val in enumerate(samples[:SAMPLE_PEEK], 1):
row += "{:.4f} ".format(val)
if idx % 5 == 0:
print(row)
row = " "
if row.strip():
print(row)
print("")
if(abs(0.5 - mean) < 0.02):
print("Random Distribution Test: SUCCESSFUL")
self.successfultests += 1
else:
print("Random Distribution Test: FAILED")
self.failedtests["randomdistribution"] = "Too much error"
def test_other_rands(self):
N = 1000
choicelist = ["apple", "banana", "grape", "orange"]
randint_vals = [urandom.randint(1, 100) for _ in range(N)]
randint_mean = sum(randint_vals) / N
print("Randint mean (ideally 50.5): {:.4f}".format(randint_mean))
if abs(50.5 - randint_mean) < 1.0:
print("Randint Test: SUCCESSFUL")
self.successfultests += 1
else:
print("Randint Test: FAILED")
self.failedtests["randint"] = "Too much error"
getrandbits_vals = [urandom.getrandbits(7) for _ in range(N)]
getrandbits_mean = sum(getrandbits_vals) / N
print("Getrandbits(7) mean (ideally 63.5): {:.4f}".format(getrandbits_mean))
if abs(63.5 - getrandbits_mean) < 1.3:
print("Getrandbits Test: SUCCESSFUL")
self.successfultests += 1
else:
print("Getrandbits Test: FAILED")
self.failedtests["getrandbits"] = "Too much error"
randrange_vals = [urandom.randrange(1, 1001, 4) for _ in range(N)]
randrange_mean = sum(randrange_vals) / N
print("Randrange(1,1001,4) mean (ideally 501.0): {:.4f}".format(randrange_mean))
if abs(501.0 - randrange_mean) < 10.0:
print("Randrange Test: SUCCESSFUL")
self.successfultests += 1
else:
print("Randrange Test: FAILED")
self.failedtests["randrange"] = "Too much error"
uniform_vals = [urandom.uniform(1, 10) for _ in range(N)]
uniform_mean = sum(uniform_vals) / N
print("Uniform(1,10) mean (ideally 5.5): {:.4f}".format(uniform_mean))
if abs(5.5 - uniform_mean) < 0.09:
print("Uniform Test: SUCCESSFUL")
self.successfultests += 1
else:
print("Uniform Test: FAILED")
self.failedtests["uniform"] = "Too much error"
choice_counts = {}
for item in choicelist:
choice_counts[item] = 0
for _ in range(N):
choice_counts[urandom.choice(choicelist)] += 1
ideal_pct = 100.0 / len(choicelist)
print("Choice distribution (ideally {:.1f}% each):".format(ideal_pct))
choice_ok = True
for item in choicelist:
pct = choice_counts[item] / N * 100
print(" " + item + ": {:.1f}%".format(pct))
if abs(pct - ideal_pct) > 5.0:
choice_ok = False
if choice_ok:
print("Choice Test: SUCCESSFUL")
self.successfultests += 1
else:
print("Choice Test: FAILED")
self.failedtests["choice"] = "Too much error"
def print_results(self):
self.testrandom()
self.test_other_rands()
print(f"\n=== Results: {self.successfultests}/6 tests passed ===")
if self.failedtests:
print("Failed tests:")
for key, value in self.failedtests.items():
print(f" {key}: {value}")
class USelectTest:
def __init__(self, hub, motorclass):
self.hub = hub
self.motorclass = motorclass
self.successfultests = 0
self.failedtests = {}
def print_results(self):
# Register the standard input so we can read keyboard presses.
keyboard = poll()
keyboard.register(stdin)
print("Type a few keys, make sure you get back what characteryou typed, then press Escape.")
while True:
# Check if a key has been pressed.
if keyboard.poll(0):
# Read the key and print it.
key = stdin.read(1)
if key == '\x1b':
print("Escape key pressed. Exiting...")
break
else:
print("Pressed:", key)
if(input("Input Y if the results were accurate:") == "Y"):
print(f"\n=== Results: 1/1 tests passed ===")
self.successfultests += 1
else:
self.failedtests["input"] = "Unsatisfied"
if self.failedtests:
print("Failed tests:")
for key, value in self.failedtests.items():
print(f" {key}: {value}")
class UStructTest:
def __init__(self, hub, motorclass):
self.hub = hub
self.motorclass = motorclass
self.successfultests = 0
self.failedtests = {}
def print_results(self):
packed = struct.pack('ii', 42, 100)
print(f'Packed bytes using pack(): {packed}')
unpacked = struct.unpack('ii', packed)
print(f'Unpacked values using unpack(): {unpacked}')
print(unpacked == (42, 100))
format_string = 'hhl'
size = struct.calcsize(format_string)
buffer = bytearray(size)
struct.pack_into(format_string, buffer, 0, 5, 10, 15)
print("Packed buffer using pack_into():", buffer)
unpackedfrom = struct.unpack_from(format_string, buffer, 0)
print("Unpacked buffer using unpack_from():", unpackedfrom)
if(unpackedfrom == (5, 10, 15)):
print("Completed Test 2/2: pack_into - SUCCESSFUL")
else:
print("Completed Test 2/2: pack_into - FAILED")
print(f"\n=== Results: {self.successfultests}/0 tests passed ===")
if self.failedtests:
print("Failed tests:")
for key, value in self.failedtests.items():
print(f" {key}: {value}")
class USysTest:
def __init__(self, hub, motorclass):
self.hub = hub
self.motorclass = motorclass
self.successfultests = 0
self.failedtests = {}
def print_results(self):
print(f"\n=== Results: {self.successfultests}/0 tests passed ===")
if self.failedtests:
print("Failed tests:")
for key, value in self.failedtests.items():
print(f" {key}: {value}")