diff options
| author | Paul Oliver <contact@pauloliver.dev> | 2026-06-18 00:08:54 +0200 |
|---|---|---|
| committer | Paul Oliver <contact@pauloliver.dev> | 2026-06-25 00:15:17 +0200 |
| commit | 0f5581f53f73a92d33826c4771553a9683376e67 (patch) | |
| tree | eab8172d21dc4a0b36714af541d22a82cec858f3 /salis.py | |
| parent | 00a0cb3821ce2bd0fc589ae64ed9cbb791ce44bb (diff) | |
Adds unit testing scaffold and build tests
Diffstat (limited to 'salis.py')
| -rwxr-xr-x | salis.py | 51 |
1 files changed, 33 insertions, 18 deletions
@@ -2,6 +2,7 @@ # index # [section] argument parser +# [section] run unit tests # [section] build class # [section] logging # [section] options dict formatter @@ -20,6 +21,7 @@ import shutil import socket import subprocess import sys +import unittest from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, ArgumentTypeError, RawTextHelpFormatter from tempfile import TemporaryDirectory @@ -39,9 +41,7 @@ new = sub_parsers.add_parser("new", formatter_class=formatter_class, help="creat load = sub_parsers.add_parser("load", formatter_class=formatter_class, help="load saved simulation") server = sub_parsers.add_parser("server", formatter_class=formatter_class, help="run data server") client = sub_parsers.add_parser("client", formatter_class=formatter_class, help="run data client") - -architectures = os.listdir("./arch") -uis = os.listdir("./ui") +test = sub_parsers.add_parser("test", formatter_class=formatter_class, help="run unit tests") def seed(i): ival = int(i, 0) @@ -67,14 +67,14 @@ fmt_id = lambda val: val fmt_hex = lambda val: hex(int(val, 0)) if type(val) == str else hex(val) options = { - (("A", "anc"), (new,), fmt_id): {"metavar": "ANC", "help": "ancestor file name without extension; to be compiled on all cores; ANC points to 'anc/{arch}/{ANC}.asm'", "required": True, "type": str}, - (("a", "arch"), (new,), fmt_id): {"choices": architectures, "help": "VM architecture", "default": "dummy", "required": False, "type": str}, + (("a", "anc"), (new,), fmt_id): {"metavar": "ANC", "help": "ancestor file name without extension; to be compiled on all cores; ANC points to '{anc-path}/{arch}/{ANC}.asm'", "required": True, "type": str}, + (("A", "anc-path"), (new,), fmt_id): {"metavar": "PATH", "help": "path to search for ancestor files", "default": "anc", "required": False, "type": str}, + (("b", "build-only"), (new, load, server, client), fmt_id): {"action": "store_true", "help": "only build (do not run) executable", "required": False}, (("C", "clones"), (new,), fmt_id): {"metavar": "N", "help": "number of ancestor clones on each core", "default": 1, "required": False, "type": nat}, (("c", "cores"), (new,), fmt_id): {"metavar": "N", "help": "number of simulator cores", "default": 2, "required": False, "type": nat}, (("d", "data-push-pow"), (new,), fmt_id): {"metavar": "POW", "help": "data aggregation interval exponent; interval = 2^{POW} >= {sync-pow}", "default": 28, "required": False, "type": nat}, - (("F", "font"), (client,), fmt_id): {"metavar": "FILE", "help": "font face to use", "default": "/usr/share/fonts/droid/DroidSansMono.ttf", "required": False}, + (("f", "font"), (client,), fmt_id): {"metavar": "FILE", "help": "font face to use", "default": "/usr/share/fonts/droid/DroidSansMono.ttf", "required": False}, (("f", "force"), (new,), fmt_id): {"action": "store_true", "help": "overwrite existing simulation of given name", "required": False}, - (("F", "muta-flip"), (new,), fmt_id): {"action": "store_true", "help": "cosmic rays flip bits instead of randomizing whole bytes", "required": False}, (("g", "c-compiler"), (new, load, server, client), fmt_id): {"metavar": "CC", "help": "C compiler to use", "default": "gcc", "required": False, "type": str}, (("G", "c-compiler-flags"), (new, load, server, client), fmt_id): {"metavar": "FLAGS", "help": "base set of flags to pass to C compiler", "default": "-Wall -Wextra -Werror -Wno-overlength-strings -pedantic", "required": False, "type": str}, (("H", "home"), (new, load, server), fmt_id): {"metavar": "PATH", "help": "salis home directory", "default": os.path.join(os.environ["HOME"], ".salis"), "required": False, "type": str}, @@ -83,13 +83,16 @@ options = { (("m", "mvec-pow"), (new,), fmt_id): {"metavar": "POW", "help": "memory core size exponent; size = 2^{POW}", "default": 20, "required": False, "type": pos}, (("n", "name"), (new, load, server), fmt_id): {"metavar": "NAME", "help": "name of new or loaded simulation", "default": "def.sim", "required": False, "type": str}, (("o", "optimized"), (new, load, server, client), fmt_id): {"action": "store_true", "help": "build with optimizations", "required": False}, + (("p", "pattern"), (test,), fmt_id): {"metavar": "PATTERN", "help": "pattern for unit test discovery", "default": "*", "required": False, "type": str}, (("P", "port"), (server, client), fmt_id): {"metavar": "PORT", "help": "port number for data server", "default": 8080, "required": False, "type": port}, (("p", "pre-cmd"), (new, load, server, client), fmt_id): {"metavar": "CMD", "help": "shell command with which to wrap call to executable; e.g. gdb, time, valgrind, etc.", "required": False, "type": str}, (("s", "seed"), (new,), fmt_hex): {"metavar": "SEED", "help": "seed value for new simulation; a value of 0 disables cosmic rays; a value of -1 creates a random seed", "default": 0, "required": False, "type": seed}, (("T", "keep-temp-dir"), (new, load, server, client), fmt_id): {"action": "store_true", "help": "keep temporary directory on exit", "required": False}, (("t", "thread-gap"), (new, load), fmt_hex): {"metavar": "N", "help": "memory gap between core elements in bytes; may help reduce cache misses", "default": 0x100, "required": False, "type": nat}, - (("u", "ui"), (new, load), fmt_id): {"choices": uis, "help": "user interface", "default": "curses", "required": False, "type": str}, + (("u", "ui"), (new, load), fmt_id): {"metavar": "UI", "help": "user interface", "default": "curses", "required": False, "type": str}, + (("U", "ui-path"), (new, load), fmt_id): {"metavar": "PATH", "help": "path to search for UIs", "default": "ui", "required": False, "type": str}, (("v", "no-vsync"), (client,), fmt_id): {"action": "store_true", "help": "disable vsync", "required": False}, + (("v", "vm-arch"), (new,), fmt_id): {"metavar": "ARCH", "help": "VM architecture", "default": "dummy", "required": False, "type": str}, (("x", "cpp-compiler"), (client,), fmt_id): {"metavar": "CXX", "help": "C++ compiler to use", "default": "g++", "required": False, "type": str}, (("X", "cpp-compiler-flags"), (client,), fmt_id): {"metavar": "FLAGS", "help": "base set of flags to pass to C++ compiler", "default": "-Wall -Wextra -Werror -pedantic -std=c++20 -lstdc++", "required": False, "type": str}, (("y", "sync-pow"), (new,), fmt_id): {"metavar": "POW", "help": "core sync interval exponent; sync events occur every N steps, where N = 2^{POW}", "default": 20, "required": False, "type": pos}, @@ -103,6 +106,16 @@ for (name, sub_parsers, _), kwargs in options.items(): args = parser.parse_args() # ------------------------------------------------------------------------------ +# [section] run unit tests +# ------------------------------------------------------------------------------ +if args.command == "test": + test_runner = unittest.TextTestRunner(verbosity=2) + test_loader = unittest.TestLoader() + test_loader.testNamePatterns = [args.pattern] + test_runner.run(test_loader.discover("test")) + sys.exit(0) + +# ------------------------------------------------------------------------------ # [section] build class # ------------------------------------------------------------------------------ class Build: @@ -296,14 +309,14 @@ if args.command == "client": # ------------------------------------------------------------------------------ # [section] source architecture variables # ------------------------------------------------------------------------------ -arch_path = os.path.join("arch", args.arch, "vars.py") +arch_path = os.path.join("arch", args.vm_arch, "vars.py") log.info(f"Loading architecture variables from: {arch_path}") arch_vars = runpy.run_path(arch_path, init_globals=globals()) # ------------------------------------------------------------------------------ # [section] ancestor assembler # ------------------------------------------------------------------------------ -anc_path = os.path.join("anc", args.arch, f"{args.anc}.asm") +anc_path = os.path.join(args.anc_path, args.vm_arch, f"{args.anc}.asm") if not os.path.isfile(anc_path): raise RuntimeError(f"Could not find ancestor file: {anc_path}") @@ -337,11 +350,11 @@ log.info(f"Compiled ancestor file '{anc_path}' into byte array: {anc_repr}") # [section] compiler flags # ------------------------------------------------------------------------------ def pop_ui_vars(): - ns.ui_path = os.path.join("ui", args.ui, "vars.py") - ns.ui_vars = runpy.run_path(ns.ui_path, init_globals=globals()) - log.info(f"Sourced UI variables from: {ns.ui_path}") + ns.ui_vars_path = os.path.join(args.ui_path, args.ui, "vars.py") + ns.ui_vars = runpy.run_path(ns.ui_vars_path, init_globals=globals()) + log.info(f"Sourced UI variables from: {ns.ui_vars_path}") - ns.b.flags.add(f"-Iui/{args.ui}") + ns.b.flags.add(f"-I{args.ui_path}/{args.ui}") ns.b.flags.update({*ns.ui_vars["flags"]}) ns.b.defines.update({*ns.ui_vars["defines"]}) ns.b.links.update({*ns.ui_vars["links"]}) @@ -362,10 +375,10 @@ def pop_net_vars(): ns.b.links.add("-ljson-c") def pop_general(): - ns.b.flags.add(f"-Iarch/{args.arch}") + ns.b.flags.add(f"-Iarch/{args.vm_arch}") ns.b.flags.add("-Icore") - if args.muta_flip: + if arch_vars["muta_flip"]: ns.b.defines.add("-DMUTA_FLIP") if arch_vars["mvec_loop"]: @@ -374,7 +387,7 @@ def pop_general(): ns.b.defines.add(f"-DANC=\"{args.anc}\"") ns.b.defines.add(f"-DANC_BYTES={anc_repr}") ns.b.defines.add(f"-DANC_SIZE={len(anc_bytes)}") - ns.b.defines.add(f"-DARCH=\"{args.arch}\"") + ns.b.defines.add(f"-DARCH=\"{args.vm_arch}\"") ns.b.defines.add(f"-DAUTOSAVE_INTERVAL={2 ** args.auto_save_pow}ul") ns.b.defines.add(f"-DCLONES={args.clones}") ns.b.defines.add(f"-DCOMMAND_{args.command.upper()}") @@ -445,4 +458,6 @@ if args.command == "client": # [section] build and launch # ------------------------------------------------------------------------------ ns.b.build() -ns.b.exec() + +if not args.build_only: + ns.b.exec() |
