package state import ( "os" "path/filepath" "strings" "testing" "time" ) // TestReadIntentHandlesMissingAndEmpty runs one orchestration or CLI step. // Signature: TestReadIntentHandlesMissingAndEmpty(t *testing.T). // Why: covers nil-state branches for missing and empty intent files. func TestReadIntentHandlesMissingAndEmpty(t *testing.T) { path := filepath.Join(t.TempDir(), "intent.json") in, err := ReadIntent(path) if err != nil { t.Fatalf("read missing intent: %v", err) } if in.State != "" { t.Fatalf("expected empty state for missing file, got %q", in.State) } if err := os.WriteFile(path, nil, 0o640); err != nil { t.Fatalf("write empty intent file: %v", err) } in, err = ReadIntent(path) if err != nil { t.Fatalf("read empty intent file: %v", err) } if in.State != "" { t.Fatalf("expected empty state for empty file, got %q", in.State) } } // TestWriteIntentSetsUpdatedAtWhenZero runs one orchestration or CLI step. // Signature: TestWriteIntentSetsUpdatedAtWhenZero(t *testing.T). // Why: verifies write helper auto-populates timestamp for callers. func TestWriteIntentSetsUpdatedAtWhenZero(t *testing.T) { path := filepath.Join(t.TempDir(), "intent.json") if err := WriteIntent(path, Intent{State: IntentNormal, Reason: "unit", Source: "test"}); err != nil { t.Fatalf("write intent: %v", err) } in, err := ReadIntent(path) if err != nil { t.Fatalf("read intent: %v", err) } if in.UpdatedAt.IsZero() { t.Fatalf("expected non-zero updated_at") } } // TestParseIntentOutputErrorsOnBadUpdatedAt runs one orchestration or CLI step. // Signature: TestParseIntentOutputErrorsOnBadUpdatedAt(t *testing.T). // Why: covers parser error branch for malformed timestamp values. func TestParseIntentOutputErrorsOnBadUpdatedAt(t *testing.T) { raw := `intent=normal reason="x" source=y updated_at=not-a-time` if _, err := ParseIntentOutput(raw); err == nil { t.Fatalf("expected updated_at parse error") } } // TestParseIntentOutputErrorsWhenMissingToken runs one orchestration or CLI step. // Signature: TestParseIntentOutputErrorsWhenMissingToken(t *testing.T). // Why: covers parser terminal error when intent token is absent. func TestParseIntentOutputErrorsWhenMissingToken(t *testing.T) { if _, err := ParseIntentOutput("no intent line here"); err == nil { t.Fatalf("expected parse failure without intent token") } } // TestParseIntentOutputWithoutReasonOrSource runs one orchestration or CLI step. // Signature: TestParseIntentOutputWithoutReasonOrSource(t *testing.T). // Why: covers parser branch where optional fields are omitted. func TestParseIntentOutputWithoutReasonOrSource(t *testing.T) { in, err := ParseIntentOutput("intent=shutdown_complete") if err != nil { t.Fatalf("parse intent output: %v", err) } if in.State != IntentShutdownComplete { t.Fatalf("expected shutdown_complete, got %q", in.State) } } // TestMustWriteIntentPersistsProvidedTimestampType runs one orchestration or CLI step. // Signature: TestMustWriteIntentPersistsProvidedTimestampType(t *testing.T). // Why: sanity check that written timestamps round-trip RFC3339 parsing. func TestMustWriteIntentPersistsProvidedTimestampType(t *testing.T) { path := filepath.Join(t.TempDir(), "intent.json") if err := MustWriteIntent(path, IntentNormal, "ok", "test"); err != nil { t.Fatalf("must write intent: %v", err) } in, err := ReadIntent(path) if err != nil { t.Fatalf("read intent: %v", err) } if time.Since(in.UpdatedAt) > time.Minute { t.Fatalf("expected recent timestamp, got %s", in.UpdatedAt) } } // TestWriteIntentFailsWhenParentIsFile runs one orchestration or CLI step. // Signature: TestWriteIntentFailsWhenParentIsFile(t *testing.T). // Why: covers mkdir failure branch when parent path is not a directory. func TestWriteIntentFailsWhenParentIsFile(t *testing.T) { tmp := t.TempDir() parent := filepath.Join(tmp, "not-a-dir") if err := os.WriteFile(parent, []byte("x"), 0o600); err != nil { t.Fatalf("write parent file: %v", err) } err := WriteIntent(filepath.Join(parent, "intent.json"), Intent{State: IntentNormal}) if err == nil { t.Fatalf("expected write failure for non-directory parent") } } // TestReadIntentFailsOnPermissionError runs one orchestration or CLI step. // Signature: TestReadIntentFailsOnPermissionError(t *testing.T). // Why: covers read error branch distinct from not-exist and empty-file handling. func TestReadIntentFailsOnPermissionError(t *testing.T) { path := filepath.Join(t.TempDir(), "intent.json") if err := os.WriteFile(path, []byte(`{"state":"normal"}`), 0o640); err != nil { t.Fatalf("write intent file: %v", err) } if err := os.Chmod(path, 0o000); err != nil { t.Fatalf("chmod intent file: %v", err) } defer os.Chmod(path, 0o640) _, err := ReadIntent(path) if err == nil { t.Fatalf("expected permission error") } if strings.Contains(strings.ToLower(err.Error()), "not exist") { t.Fatalf("expected permission-related error, got: %v", err) } }