// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause package main import ( "runtime" "testing" "sourcedock.dev/petrbalvin/gasm-sdk/arch" ) func TestDerivedFamily(t *testing.T) { for _, n := range []string{"JEQ", "JLT", "JCC", "CMOVLGT", "SETNE", "SETA"} { if !derivedFamily(n) { t.Errorf("derivedFamily(%q) = false, want true", n) } } for _, n := range []string{"JMP", "ADDQ", "VPGATHERDD", "MOVBE", "PSHUFB"} { if derivedFamily(n) { t.Errorf("derivedFamily(%q) = true, want false", n) } } } func TestSanitize(t *testing.T) { if got := sanitize("VPCMP.UB"); got != "VPCMP_UB" { t.Errorf("sanitize: got %q", got) } } func TestAuditArch(t *testing.T) { for in, want := range map[string]arch.Arch{ "amd64": arch.AMD64, "arm64": arch.ARM64, "riscv64": arch.RISCV, "riscv": arch.RISCV, "loong64": arch.LOONG64, "LOONG": arch.LOONG64, } { got, err := auditArch(in) if err != nil || got != want { t.Errorf("auditArch(%q) = %v, %v; want %v", in, got, err, want) } } if _, err := auditArch("mips"); err == nil { t.Error("auditArch(mips) must fail") } } func TestGasmEncodable(t *testing.T) { cases := []struct { a arch.Arch yes string no string }{ {arch.AMD64, "ADDQ", "NOSUCHMNEMONIC"}, {arch.ARM64, "ADD", "NOSUCHMNEMONIC"}, {arch.RISCV, "ADD", "NOSUCHMNEMONIC"}, {arch.LOONG64, "ADDV", "NOSUCHMNEMONIC"}, } for _, c := range cases { if !gasmEncodable(c.a, c.yes) { t.Errorf("%s: %s should be encodable", c.a, c.yes) } if gasmEncodable(c.a, c.no) { t.Errorf("%s: %s should not be encodable", c.a, c.no) } } } // TestBuildConstraint pins the //go:build reader: the constraint governs the // leading comment block, the first non-comment line ends it (a tag below a // #include governs nothing, exactly as go/build drops it), and a file // without one admits every target. func TestBuildConstraint(t *testing.T) { admits := func(src, goarch, goos string) bool { t.Helper() e := buildConstraint(src) if e == nil { return true } return e.Eval(constraintTags(goarch, goos)) } const ret = "TEXT \xc2\xb7f(SB), NOSPLIT, $0\n\tRET\n" cases := []struct { name string src string amd64, arm64 bool }{ {"no constraint", ret, true, true}, {"x86 only", "//go:build 386 || amd64\n\n" + ret, true, false}, {"arm64 and linux", "//go:build arm64 && linux\n\n" + ret, false, true}, {"msan never", "//go:build msan\n\n" + ret, false, false}, {"experiment never", "//go:build goexperiment.runtimesecret\n\n" + ret, false, false}, {"below an include governs nothing", "#include \"textflag.h\"\n//go:build amd64\n" + ret, true, true}, {"unparsable narrows nothing", "//go:build (amd64\n" + ret, true, true}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { if got := admits(c.src, "amd64", runtime.GOOS); got != c.amd64 { t.Errorf("amd64 admission = %v, want %v", got, c.amd64) } if got := admits(c.src, "arm64", runtime.GOOS); got != c.arm64 { t.Errorf("arm64 admission = %v, want %v", got, c.arm64) } }) } } // TestConstraintTags pins the tag set a plain `go build` sets: the GOOS and // GOARCH, gc, unix on the unix-like GOOSes; nothing else is ever true. func TestConstraintTags(t *testing.T) { ok := constraintTags("amd64", "linux") for _, tag := range []string{"amd64", "linux", "gc", "unix"} { if !ok(tag) { t.Errorf("tag %q = false, want true", tag) } } for _, tag := range []string{"arm64", "freebsd", "darwin", "cgo", "race", "msan", "goexperiment.runtimesecret"} { if ok(tag) { t.Errorf("tag %q = true, want false", tag) } } fb := constraintTags("arm64", "freebsd") if !fb("unix") { t.Error("unix on freebsd = false, want true") } }