package domain import ( "encoding/json" "strings" "testing" "time" ) func TestNewManualRejectsEmptyNextAction(t *testing.T) { _, err := NewManual("", "tests pass", 25*time.Minute) if err != ErrMissingNextAction { t.Fatalf("want ErrMissingNextAction, got %v", err) } } func TestNewManualRejectsEmptySuccessCondition(t *testing.T) { _, err := NewManual("Refactor state", " ", 25*time.Minute) if err != ErrMissingSuccessCondition { t.Fatalf("want ErrMissingSuccessCondition, got %v", err) } } func TestNewManualRejectsZeroTimebox(t *testing.T) { _, err := NewManual("Refactor state", "tests pass", 0) if err != ErrMissingTimebox { t.Fatalf("want ErrMissingTimebox, got %v", err) } } func TestNewManualPopulatesDraftCommitment(t *testing.T) { c, err := NewManual(" Port domain ", "domain tests pass", 25*time.Minute) if err != nil { t.Fatalf("unexpected error: %v", err) } if c.NextAction != "Port domain" { t.Errorf("next action not trimmed: %q", c.NextAction) } if c.SuccessCondition != "domain tests pass" { t.Errorf("success condition wrong: %q", c.SuccessCondition) } if c.TimeboxSecs != 1500 { t.Errorf("timebox secs wrong: %d", c.TimeboxSecs) } if c.State != CommitmentDraft { t.Errorf("state should be draft, got %s", c.State) } if c.Source != SourceManual { t.Errorf("source should be manual, got %s", c.Source) } if !strings.HasPrefix(c.ID, "commitment-") { t.Errorf("id should be prefixed, got %s", c.ID) } } func TestNewManualRejectsSubSecondTimebox(t *testing.T) { _, err := NewManual("Refactor state", "tests pass", 500*time.Millisecond) if err != ErrMissingTimebox { t.Fatalf("want ErrMissingTimebox, got %v", err) } } func TestForRuntimePopulatesPolicySnapshot(t *testing.T) { p := ForRuntime("commitment-123", RuntimeActive, EnforcementObserve) if !strings.HasPrefix(p.ID, "policy-") { t.Errorf("id should be prefixed, got %s", p.ID) } if p.CommitmentID != "commitment-123" { t.Errorf("commitment id wrong: %s", p.CommitmentID) } if p.SchemaVersion != PolicySchemaVersion { t.Errorf("schema version wrong: %d", p.SchemaVersion) } if p.RuntimeState != RuntimeActive { t.Errorf("runtime state wrong: %s", p.RuntimeState) } if p.EnforcementLevel != EnforcementObserve { t.Errorf("enforcement level wrong: %s", p.EnforcementLevel) } } func TestCommitmentSerializesSnakeCaseEnums(t *testing.T) { c, _ := NewManual("Port domain", "domain tests pass", 25*time.Minute) data, err := json.Marshal(c) if err != nil { t.Fatalf("marshal failed: %v", err) } s := string(data) if !strings.Contains(s, `"source":"manual"`) { t.Errorf("missing snake_case source in %s", s) } if !strings.Contains(s, `"state":"draft"`) { t.Errorf("missing snake_case state in %s", s) } }