diff options
| -rw-r--r-- | core/salis.c | 18 | ||||
| -rwxr-xr-x | salis.py | 20 | ||||
| -rw-r--r-- | test/test_build.py | 56 | ||||
| -rw-r--r-- | test/test_general.py | 54 | ||||
| -rw-r--r-- | test/test_run.py | 55 | ||||
| -rw-r--r-- | test/ui/push/links.json | 1 | ||||
| -rw-r--r-- | test/ui/push/ui.c | 25 |
7 files changed, 220 insertions, 9 deletions
diff --git a/core/salis.c b/core/salis.c index 93dc842..6cc0725 100644 --- a/core/salis.c +++ b/core/salis.c @@ -360,6 +360,13 @@ static void core_save(const struct Core *core, FILE *f) { arch_core_save(core, f); } +void core_event_array_init(struct EventArray *eva) { + assert(eva); + eva->params.size = sizeof(uint64_t) * MVEC_SIZE; + eva->params.in = (Bytef *)eva->data; + eva->params.out = (Bytef *)eva->comp; +} + #if defined(COMMAND_NEW) static void core_assemble_ancestor(struct Core *core) { assert(core); @@ -381,13 +388,6 @@ static void core_assemble_ancestor(struct Core *core) { } } -void core_event_array_init(struct EventArray *eva) { - assert(eva); - eva->params.size = sizeof(uint64_t) * MVEC_SIZE; - eva->params.in = (Bytef *)eva->data; - eva->params.out = (Bytef *)eva->comp; -} - static void core_init(struct Core *core, uint64_t *seed) { assert(core); assert(seed); @@ -460,6 +460,10 @@ static void core_load(struct Core *core, FILE *f) { fread(core->eeva.data, sizeof(uint64_t), MVEC_SIZE, f); fread(core->beva.data, sizeof(uint64_t), MVEC_SIZE, f); + core_event_array_init(&core->aeva); + core_event_array_init(&core->eeva); + core_event_array_init(&core->beva); + arch_core_load(core, f); } #endif @@ -7,6 +7,7 @@ # index: # [section] imports # [section] argument parser +# [section] unit tests # [section] build class # [section] logger # [section] options dict formatter @@ -24,9 +25,9 @@ import json import os import random import shutil -import signal import subprocess import sys +import unittest from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, ArgumentTypeError, RawTextHelpFormatter from tempfile import TemporaryDirectory @@ -44,6 +45,7 @@ formatter_class = lambda prog: ArgumentDefaultsHelpFormatter(max_help_position=4 new = sub_parsers.add_parser("new", formatter_class=formatter_class, help="create new simulation") load = sub_parsers.add_parser("load", formatter_class=formatter_class, help="load saved simulation") +test = sub_parsers.add_parser("test", formatter_class=formatter_class, help="run unit tests") def seed(i): ival = int(i, 0) @@ -83,6 +85,7 @@ 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), fmt_id, {"metavar": "NAME", "help": "name of new or loaded simulation", "default": "def.sim", "required": False, "type": str}), ("o", "optimized", (new, load), 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", "pre-cmd", (new, load), 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), fmt_id, {"action": "store_true", "help": "keep temporary directory on exit", "required": False}), @@ -97,6 +100,16 @@ options = ( args = parser.parse_args() # ------------------------------------------------------------------------------ +# [section] unit tests +# ------------------------------------------------------------------------------ +if args.command == "test": + loader = unittest.TestLoader() + loader.testNamePatterns = [args.pattern] + runner = unittest.TextTestRunner(verbosity=2) + result = runner.run(loader.discover("test")) + exit(0 if not result.errors and not result.failures else 1) + +# ------------------------------------------------------------------------------ # [section] build class # ------------------------------------------------------------------------------ class Build: @@ -143,7 +156,7 @@ class Build: # When a signal is received (e.g. SIGINT), is propagates through the entire process group. # Handle signal on the interpreter and allow the simulator to shut down gracefully. try: - signal.pause() + proc.wait() except KeyboardInterrupt: proc.wait() @@ -316,6 +329,9 @@ ui_path = f"{args.ui_path}/{args.ui}" ui_flags = [f"-Iarch/{args.vm_arch}", "-Icore", f"arch/{args.vm_arch}/arch.c", arch_inst_path, "core/compress.c", "core/logger.c", "core/salis.c", "core/sql.c"] ui_defines = defines + logger_defines +if not os.path.isdir(ui_path): + raise RuntimeError(f"UI not found at '{ui_path}'") + with open(f"{ui_path}/links.json", "r") as f: ui_links = json.load(f) diff --git a/test/test_build.py b/test/test_build.py new file mode 100644 index 0000000..7c0126a --- /dev/null +++ b/test/test_build.py @@ -0,0 +1,56 @@ +# file : test/test_build.py +# project : Salis-VM +# author : Paul Oliver <contact@pauloliver.dev> + +# index: +# [section] imports +# [section] constants +# [section] command lists +# [section] tests null + +# ------------------------------------------------------------------------------ +# [section] imports +# ------------------------------------------------------------------------------ +from test_general import SalisTest + +class TestBuild(SalisTest): + # -------------------------------------------------------------------------- + # [section] constants + # -------------------------------------------------------------------------- + SIM_NAME = "test-build.sim" + + # -------------------------------------------------------------------------- + # [section] command lists + # -------------------------------------------------------------------------- + def commands_new(self, anc, arch): + return [ + f"./salis.py new -a{anc} -b -f -g{compiler} -H{self.tempdir.name} -n{self.SIM_NAME} {optimized} -s{seed} -u{ui} -v{arch}" + for compiler in ["clang", "gcc", "tcc"] + for optimized in ["", "-o"] + for seed in [-1, 0, 1234] + for ui in ["daemon"] + ] + + def commands_load(self): + return [ + f"./salis.py load -b -g{compiler} -H{self.tempdir.name} -n{self.SIM_NAME} {optimized} -u{ui}" + for compiler in ["clang", "gcc", "tcc"] + for optimized in ["", "-o"] + for ui in ["daemon"] + ] + + # -------------------------------------------------------------------------- + # [section] tests null + # -------------------------------------------------------------------------- + def test_null_new(self): + for command in self.commands_new("0123", "null"): + self.run_subprocess(command) + self.assert_files_exist([f"{self.tempdir.name}/{self.SIM_NAME}/opts.json"]) + + def test_null_load(self): + self.run_subprocess(self.commands_new("0123", "null")[0]) + self.assert_files_exist([f"{self.tempdir.name}/{self.SIM_NAME}/opts.json"]) + + for command in self.commands_load(): + self.run_subprocess(command) + self.assert_files_exist([f"{self.tempdir.name}/{self.SIM_NAME}/opts.json"]) diff --git a/test/test_general.py b/test/test_general.py new file mode 100644 index 0000000..b4e0e85 --- /dev/null +++ b/test/test_general.py @@ -0,0 +1,54 @@ +# file : test/test_general.py +# project : Salis-VM +# author : Paul Oliver <contact@pauloliver.dev> + +# index: +# [section] imports +# [section] setup/teardown +# [section] file lists +# [section] assertions +# [section] subprocess + +# ------------------------------------------------------------------------------ +# [section] imports +# ------------------------------------------------------------------------------ +import os +import subprocess +import unittest + +from tempfile import TemporaryDirectory + +class SalisTest(unittest.TestCase): + # -------------------------------------------------------------------------- + # [section] setup/teardown + # -------------------------------------------------------------------------- + def setUp(self): + self.tempdir = TemporaryDirectory(prefix="salis_test_") + + def tearDown(self): + self.tempdir.cleanup() + + # -------------------------------------------------------------------------- + # [section] file lists + # -------------------------------------------------------------------------- + def files_on_new(self, name): + return [ + f"{self.tempdir.name}/{name}/evas/evas-{0:016x}", + f"{self.tempdir.name}/{name}/opts.json", + f"{self.tempdir.name}/{name}/{name}", + f"{self.tempdir.name}/{name}/{name}-{0:016x}", + f"{self.tempdir.name}/{name}/{name}.sqlite3", + ] + + # -------------------------------------------------------------------------- + # [section] assertions + # -------------------------------------------------------------------------- + def assert_files_exist(self, files): + for file in files: + assert os.path.isfile(file), f"{file} does not exist" + + # -------------------------------------------------------------------------- + # [section] subprocess + # -------------------------------------------------------------------------- + def run_subprocess(self, command): + subprocess.run(command.split(), check=True, stdout=subprocess.DEVNULL) diff --git a/test/test_run.py b/test/test_run.py new file mode 100644 index 0000000..cab195c --- /dev/null +++ b/test/test_run.py @@ -0,0 +1,55 @@ +# file : test/test_run.py +# project : Salis-VM +# author : Paul Oliver <contact@pauloliver.dev> + +# index: +# [section] imports +# [section] constants +# [section] command lists +# [section] file lists +# [section] tests null + +# ------------------------------------------------------------------------------ +# [section] imports +# ------------------------------------------------------------------------------ +from test_general import SalisTest + +class TestRun(SalisTest): + # -------------------------------------------------------------------------- + # [section] constants + # -------------------------------------------------------------------------- + SIM_NAME = "test-run.sim" + PUSH_POW = 8 + + # -------------------------------------------------------------------------- + # [section] command lists + # -------------------------------------------------------------------------- + def commands(self, anc, arch): + return [ + ( + f"./salis.py new -a{anc} -d{self.PUSH_POW} -f -g{compiler} -H{self.tempdir.name} -n{self.SIM_NAME} {optimized} -s{seed} -upush -Utest/ui/ -v{arch} -y{self.PUSH_POW}", + f"./salis.py load -g{compiler} -H{self.tempdir.name} -n{self.SIM_NAME} {optimized} -upush -Utest/ui/", + ) + for compiler in ["clang", "gcc", "tcc"] + for optimized in ["", "-o"] + for seed in [-1, 0, 1234] + ] + + # -------------------------------------------------------------------------- + # [section] file lists + # -------------------------------------------------------------------------- + def files_on_first_push(self): + return [*self.files_on_new(self.SIM_NAME), f"{self.tempdir.name}/{self.SIM_NAME}/evas/evas-{2 ** self.PUSH_POW:016x}"] + + def files_on_second_push(self): + return [*self.files_on_first_push(), f"{self.tempdir.name}/{self.SIM_NAME}/evas/evas-{2 * (2 ** self.PUSH_POW):016x}"] + + # -------------------------------------------------------------------------- + # [section] tests null + # -------------------------------------------------------------------------- + def test_null(self): + for command in self.commands("0123", "null"): + self.run_subprocess(command[0]) + self.assert_files_exist(self.files_on_first_push()) + self.run_subprocess(command[1]) + self.assert_files_exist(self.files_on_second_push()) diff --git a/test/ui/push/links.json b/test/ui/push/links.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/test/ui/push/links.json @@ -0,0 +1 @@ +[] diff --git a/test/ui/push/ui.c b/test/ui/push/ui.c new file mode 100644 index 0000000..53baac9 --- /dev/null +++ b/test/ui/push/ui.c @@ -0,0 +1,25 @@ +// file : test/ui/push/ui.c +// project : Salis-VM +// author : Paul Oliver <contact@pauloliver.dev> + +#include <stdbool.h> +#include <stdint.h> +#include <threads.h> +#include <zlib.h> + +#include "arch_spec.h" +#include "compress.h" +#include "logger.h" +#include "salis.h" + +int main(void) { +#if defined(COMMAND_NEW) + salis_init(); +#elif defined(COMMAND_LOAD) + salis_load(); +#endif + + salis_step(DATA_PUSH_INTERVAL); + salis_free(); + return 0; +} |
