package system import ( "context" "encoding/json" "os" "path/filepath" "runtime" "testing" ) func TestWriteJSONRoundtrip(t *testing.T) { path := filepath.Join(t.TempDir(), "out.json") value := map[string]any{"name": "banger", "n": 42.0} if err := WriteJSON(path, value); err != nil { t.Fatalf("WriteJSON: %v", err) } data, err := os.ReadFile(path) if err != nil { t.Fatalf("ReadFile: %v", err) } var got map[string]any if err := json.Unmarshal(data, &got); err != nil { t.Fatalf("Unmarshal: %v", err) } if got["name"] != "banger" || got["n"].(float64) != 42.0 { t.Fatalf("decoded = %v", got) } } func TestWriteJSONErrorsForUnmarshalable(t *testing.T) { path := filepath.Join(t.TempDir(), "out.json") if err := WriteJSON(path, make(chan int)); err == nil { t.Fatal("expected marshal error for channel value") } if _, err := os.Stat(path); !os.IsNotExist(err) { t.Fatalf("expected no file when marshal fails, got %v", err) } } func TestTailCommand(t *testing.T) { cmd := TailCommand("/tmp/log.txt", false) if cmd == nil || cmd.Path == "" { t.Fatal("TailCommand(false) returned nil/empty") } // follow=false → cat, follow=true → tail -f. if !hasArg(cmd.Args, "/tmp/log.txt") { t.Fatalf("cat args missing path: %v", cmd.Args) } followCmd := TailCommand("/tmp/log.txt", true) if !hasArg(followCmd.Args, "-f") { t.Fatalf("follow cmd missing -f: %v", followCmd.Args) } if !hasArg(followCmd.Args, "/tmp/log.txt") { t.Fatalf("follow cmd missing path: %v", followCmd.Args) } } func hasArg(args []string, want string) bool { for _, a := range args { if a == want { return true } } return false } func TestReportAddWarnAndHasFailures(t *testing.T) { var r Report r.AddPass("a") r.AddWarn("b", "detail-1", "detail-2") if r.HasFailures() { t.Fatal("HasFailures should be false with only pass+warn") } if len(r.Checks) != 2 { t.Fatalf("len(Checks) = %d, want 2", len(r.Checks)) } if r.Checks[1].Status != CheckStatusWarn { t.Fatalf("check[1].Status = %v, want warn", r.Checks[1].Status) } if len(r.Checks[1].Details) != 2 { t.Fatalf("warn details lost: %v", r.Checks[1].Details) } r.AddFail("c") if !r.HasFailures() { t.Fatal("HasFailures should be true after AddFail") } } func TestRequireCommandsMissing(t *testing.T) { err := RequireCommands(context.Background(), "this-command-cannot-possibly-exist-xyz-123") if err == nil { t.Fatal("expected error for missing command") } } func TestRequireCommandsPresent(t *testing.T) { // `go` is guaranteed on PATH during test runs. if err := RequireCommands(context.Background(), "go"); err != nil { t.Fatalf("RequireCommands(go): %v", err) } } func TestReadHostResources(t *testing.T) { if runtime.GOOS != "linux" { t.Skip("ReadHostResources reads /proc/meminfo; Linux-only") } res, err := ReadHostResources() if err != nil { t.Fatalf("ReadHostResources: %v", err) } if res.CPUCount <= 0 { t.Errorf("CPUCount = %d, want > 0", res.CPUCount) } if res.TotalMemoryBytes <= 0 { t.Errorf("TotalMemoryBytes = %d, want > 0", res.TotalMemoryBytes) } } func TestShortIDEdgeCases(t *testing.T) { if got := ShortID(""); got != "" { t.Errorf("ShortID('') = %q, want ''", got) } if got := ShortID("short"); got != "short" { t.Errorf("ShortID('short') = %q, want 'short'", got) } long := "0123456789abcdef" if got := ShortID(long); got != "01234567" { t.Errorf("ShortID(long) = %q, want 01234567", got) } }