NumericalOS

tests/test_archtable.py

back to source

import os
import subprocess
import unittest
from numos.archtable import render_arch_table
from numos import seed

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ARCH_TABLE = os.path.join(ROOT, "boot", "lib", "arch_table.sh")


class TestSeed(unittest.TestCase):
    def test_nine_arch_targets_seeded(self):
        self.assertEqual(len(seed.ARCH_TARGETS), 9)

    def test_every_canonical_is_in_its_own_aliases(self):
        for target in seed.ARCH_TARGETS:
            self.assertIn(target["canonical"], target["aliases"])

    def test_aliases_are_globally_unique(self):
        seen = []
        for target in seed.ARCH_TARGETS:
            seen.extend(target["aliases"])
        self.assertEqual(len(seen), len(set(seen)))

    def test_riscv64_is_present(self):
        self.assertIn("riscv64", [t["canonical"] for t in seed.ARCH_TARGETS])

    def test_every_target_has_a_busybox_fallback(self):
        for target in seed.ARCH_TARGETS:
            self.assertTrue(target["busybox_variant"])


class TestRenderArchTable(unittest.TestCase):
    def setUp(self):
        self.sh = render_arch_table(seed.ARCH_TARGETS)

    def test_marked_generated(self):
        self.assertIn("GENERATED", self.sh)
        self.assertIn("DO NOT EDIT", self.sh)

    def test_defines_both_functions(self):
        self.assertIn("numos_canonical_arch()", self.sh)
        self.assertIn("numos_arch_has_static()", self.sh)

    def test_every_alias_of_every_record_has_an_arm(self):
        # A single spot-check ("x86_64|amd64)") would pass while any other
        # arch's aliases were missing or attached to the wrong canonical.
        for target in seed.ARCH_TARGETS:
            arm = "    %s) echo %s ;;" % ("|".join(target["aliases"]),
                                          target["canonical"])
            self.assertIn(arm, self.sh.split("\n"))

    def test_unknown_arch_returns_nonzero(self):
        self.assertIn("*) return 1 ;;", self.sh)

    def test_contains_no_bashisms(self):
        for bashism in ("[[", "declare ", "local ", "${!"):
            self.assertNotIn(bashism, self.sh)

    def test_is_ascii(self):
        self.assertTrue(all(ord(c) < 128 for c in self.sh),
                        "arch_table.sh contains a non-ASCII character")

    def test_deterministic(self):
        self.assertEqual(self.sh, render_arch_table(seed.ARCH_TARGETS))


class TestCommittedTableIsInSync(unittest.TestCase):
    """boot/lib/arch_table.sh is generated and marked DO NOT EDIT.

    It is the one artifact carrying the design's central claim -- that
    adding an architecture is a node insert, not a code edit. Edit
    numos/seed.py and forget `py -m numos.archtable` and the bootstrap
    resolves architectures from stale data with every other test still
    green, which would quietly falsify the claim.
    """

    def test_committed_file_is_byte_identical_to_its_generator_output(self):
        with open(ARCH_TABLE, "r", newline="") as handle:
            committed = handle.read()
        self.assertEqual(
            committed, render_arch_table(seed.ARCH_TARGETS),
            "boot/lib/arch_table.sh has drifted from numos/seed.py: "
            "regenerate with `py -m numos.archtable`")

    def test_committed_file_is_ascii_with_lf_endings(self):
        with open(ARCH_TABLE, "rb") as handle:
            raw = handle.read()
        self.assertNotIn(b"\r", raw)
        self.assertTrue(all(byte < 128 for byte in raw))


class TestCommittedTableResolvesEveryAlias(unittest.TestCase):
    """Run the committed table through a real shell, not just grep it.

    Every alias of every record is resolved in one bash invocation, so a
    wrong arm, a shadowed pattern or a broken `case` shows up as a wrong
    answer rather than a passing substring match.
    """

    @classmethod
    def setUpClass(cls):
        aliases = []
        for target in seed.ARCH_TARGETS:
            aliases.extend(target["aliases"])
        script = (
            '. "%s"\n'
            'for a in %s notanarch; do\n'
            '  c="$(numos_canonical_arch "$a")" || c=UNRESOLVED\n'
            '  if numos_arch_has_static "$c"; then s=static; else s=fallback; fi\n'
            '  echo "$a=$c/$s"\n'
            'done\n' % (ARCH_TABLE.replace("\\", "/"), " ".join(aliases)))
        proc = subprocess.run(["bash", "-c", script], capture_output=True, text=True)
        cls.rc = proc.returncode
        cls.answers = dict(
            line.split("=", 1) for line in proc.stdout.strip().split("\n") if "=" in line)
        cls.stderr = proc.stderr

    def test_shell_ran_cleanly(self):
        self.assertEqual(self.rc, 0, self.stderr)

    def test_every_alias_resolves_to_its_own_canonical(self):
        for target in seed.ARCH_TARGETS:
            expected = "%s/%s" % (target["canonical"],
                                  "static" if target["zig_triple"] else "fallback")
            for alias in target["aliases"]:
                self.assertEqual(self.answers.get(alias), expected,
                                 "alias %s resolved wrong" % alias)

    def test_an_unlisted_arch_stays_unresolved(self):
        self.assertEqual(self.answers.get("notanarch"), "UNRESOLVED/fallback")


if __name__ == "__main__":
    unittest.main()