check-safety/main_test.go
Alex Dunmow cd88c808b0 initial: standalone check-safety module hoisted from CMS
Static safety/lint runner for the BlockNinja codebase. ~25 invariant
checks across Go and frontend sources. Was at git.dev.alexdunmow.com:block/ninja
in backend/cmd/check-safety/ until the 2026-06-06 consolidation moved
the BlockNinja repos under a shared ~/src/blockninja/ parent.

This repo is the standalone extraction:
- Own go.mod (git.dev.alexdunmow.com/block/check-safety, go 1.26.4)
- Vendored internal/{helpers,theme} from CMS (Go's internal/ rule
  blocks cross-module imports; vendoring is the workaround)
- CLI contract unchanged: `check-safety <target-dir> [--flags]`
- CMS Makefile shells into ../check-safety for safety-check /
  install-safety-checker targets

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 13:04:02 +08:00

192 lines
6.4 KiB
Go

package main
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestDefaultScanTargetDirUsesCWDPlugin(t *testing.T) {
cwd := t.TempDir()
pluginMod := filepath.Join(cwd, "plugin.mod")
if err := os.WriteFile(pluginMod, []byte("[plugin]\nname = \"example\"\nversion = \"1.0.0\"\n"), 0644); err != nil {
t.Fatalf("write plugin.mod: %v", err)
}
got := defaultScanTargetDir(".", nil, cwd)
if got != cwd {
t.Fatalf("defaultScanTargetDir() = %q, want %q", got, cwd)
}
}
func TestDefaultScanTargetDirFallsBackToCoreBackend(t *testing.T) {
cwd := t.TempDir()
got := defaultScanTargetDir(".", nil, cwd)
want := filepath.Join(blockNinjaRepoRoot(), "backend")
if got != want {
t.Fatalf("defaultScanTargetDir() = %q, want %q", got, want)
}
}
func TestShouldIncludeCoreTargetsUsesBackendPathAsToolHostForPluginScans(t *testing.T) {
targetDir := filepath.Join(blockNinjaRepoRoot(), "backend")
if !shouldIncludeCoreTargets(targetDir, targetDir, nil, nil) {
t.Fatalf("expected core targets to be included when no plugin flags are present")
}
if shouldIncludeCoreTargets(targetDir, targetDir, []string{"/tmp/plugin"}, nil) {
t.Fatalf("expected core targets to be skipped when plugin roots are passed with the checker backend path")
}
if shouldIncludeCoreTargets(targetDir, targetDir, nil, []string{"/tmp/plugin/web/src"}) {
t.Fatalf("expected core targets to be skipped when plugin pages are passed with the checker backend path")
}
}
func TestCollectTargetsSkipsCoreWhenIncludeCoreTargetsFalse(t *testing.T) {
repoRoot := t.TempDir()
backendDir := filepath.Join(repoRoot, "backend")
pluginFrontendDir := filepath.Join(repoRoot, "plugins", "example", "web", "src")
for _, dir := range []string{backendDir, pluginFrontendDir} {
if err := os.MkdirAll(dir, 0755); err != nil {
t.Fatalf("mkdir %s: %v", dir, err)
}
}
if targets := collectBackendScanTargets(repoRoot, backendDir, false); len(targets) != 0 {
t.Fatalf("collectBackendScanTargets(..., false) returned %d targets, want 0", len(targets))
}
frontendTargets := collectFrontendScanTargets(repoRoot, backendDir, []pluginScanTarget{{
root: filepath.Join(repoRoot, "plugins", "example"),
frontendDir: pluginFrontendDir,
display: "plugins/example",
frontendLabel: "plugins/example/web/src",
}}, false)
if len(frontendTargets) != 1 {
t.Fatalf("collectFrontendScanTargets(..., false) returned %d targets, want 1", len(frontendTargets))
}
if frontendTargets[0].dir != pluginFrontendDir {
t.Fatalf("frontend target dir = %q, want %q", frontendTargets[0].dir, pluginFrontendDir)
}
if !frontendTargets[0].pluginRules {
t.Fatalf("frontend target pluginRules = false, want true")
}
if !frontendTargets[0].managedConfigs {
t.Fatalf("frontend target managedConfigs = false, want true")
}
}
func TestDiscoverOrchestratorTestTargetsRequiresCoreScan(t *testing.T) {
repoRoot := blockNinjaRepoRoot()
backendDir := filepath.Join(repoRoot, "backend")
if targets := discoverOrchestratorTestTargets(repoRoot, backendDir, false); len(targets) != 0 {
t.Fatalf("discoverOrchestratorTestTargets(..., false) returned %d targets, want 0", len(targets))
}
pluginRoot := filepath.Join(t.TempDir(), "plugin")
if targets := discoverOrchestratorTestTargets(pluginRoot, pluginRoot, true); len(targets) != 0 {
t.Fatalf("discoverOrchestratorTestTargets(plugin root) returned %d targets, want 0", len(targets))
}
}
func TestDiscoverOrchestratorTestTargetsFromRoot(t *testing.T) {
root := t.TempDir()
backendDir := filepath.Join(root, "backend")
if err := os.MkdirAll(backendDir, 0755); err != nil {
t.Fatalf("mkdir backend: %v", err)
}
if targets := discoverOrchestratorTestTargetsFromRoot(root); len(targets) != 0 {
t.Fatalf("targets without go.mod = %d, want 0", len(targets))
}
if err := os.WriteFile(filepath.Join(backendDir, "go.mod"), []byte("module example.com/orchestrator\n"), 0644); err != nil {
t.Fatalf("write go.mod: %v", err)
}
targets := discoverOrchestratorTestTargetsFromRoot(root)
if len(targets) != 1 {
t.Fatalf("targets = %d, want 1", len(targets))
}
if targets[0].label != "orchestrator/backend" {
t.Fatalf("label = %q, want orchestrator/backend", targets[0].label)
}
if targets[0].moduleRoot != backendDir {
t.Fatalf("moduleRoot = %q, want %q", targets[0].moduleRoot, backendDir)
}
if got := strings.Join(targets[0].args, " "); got != "test ./..." {
t.Fatalf("args = %q, want test ./...", got)
}
}
func TestResolvePluginTargetsUsesRootFolderNameForDisplay(t *testing.T) {
repoRoot := t.TempDir()
pluginRoot := filepath.Join(t.TempDir(), "messenger")
pluginFrontend := filepath.Join(pluginRoot, "web")
for _, dir := range []string{pluginRoot, pluginFrontend} {
if err := os.MkdirAll(dir, 0755); err != nil {
t.Fatalf("mkdir %s: %v", dir, err)
}
}
if err := os.WriteFile(filepath.Join(pluginFrontend, "index.tsx"), []byte("export const x = 1\n"), 0644); err != nil {
t.Fatalf("write frontend file: %v", err)
}
targets, unresolved := resolvePluginTargets(repoRoot, []string{pluginRoot})
if len(unresolved) != 0 {
t.Fatalf("unresolved = %v, want none", unresolved)
}
if len(targets) != 1 {
t.Fatalf("targets = %d, want 1", len(targets))
}
if targets[0].display != "messenger" {
t.Fatalf("display = %q, want messenger", targets[0].display)
}
if targets[0].frontendLabel != "messenger" {
t.Fatalf("frontendLabel = %q, want messenger", targets[0].frontendLabel)
}
}
func TestExtractRBACMethodRolesParsesRoleValues(t *testing.T) {
dir := t.TempDir()
file := filepath.Join(dir, "interceptor.go")
if err := os.WriteFile(file, []byte(`package rbac
type Role string
const (
RoleViewer Role = "viewer"
RoleAdmin Role = "admin"
)
var MethodRoles = map[string]Role{
"/example.v1.Service/Public": "",
"/example.v1.Service/View": RoleViewer,
"/example.v1.Service/Admin": RoleAdmin,
}
`), 0644); err != nil {
t.Fatalf("write interceptor.go: %v", err)
}
methods, err := extractRBACMethodRoles(file)
if err != nil {
t.Fatalf("extractRBACMethodRoles() error = %v", err)
}
if methods["/example.v1.Service/Public"] != "public" {
t.Fatalf("public role = %q, want public", methods["/example.v1.Service/Public"])
}
if methods["/example.v1.Service/View"] != "viewer" {
t.Fatalf("viewer role = %q, want viewer", methods["/example.v1.Service/View"])
}
if methods["/example.v1.Service/Admin"] != "admin" {
t.Fatalf("admin role = %q, want admin", methods["/example.v1.Service/Admin"])
}
}