package contracts import ( "errors" "reflect" "testing" ) func TestOldResultRejectedBeforeNewDebounce(t *testing.T) { var s searchState a := s.change("a") if !s.begin(a) { t.Fatal("first request not admitted") } b := s.change("b") before := s if s.finish(a, []string{"old"}, nil) { t.Fatal("old result accepted during new debounce") } if !reflect.DeepEqual(before, s) { t.Fatal("rejected result mutated state") } if !s.begin(b) || !s.finish(b, []string{"new"}, nil) { t.Fatal("new request failed") } if s.phase != ready || !reflect.DeepEqual(s.rows, []string{"new"}) { t.Fatalf("unexpected final state: %+v", s) } } func TestStaleFailureCannotOverwriteSuccess(t *testing.T) { var s searchState a := s.change("a") s.begin(a) b := s.change("b") s.begin(b) s.finish(b, []string{"new"}, nil) before := s if s.finish(a, nil, errors.New("old failure")) || !reflect.DeepEqual(before, s) { t.Fatal("stale failure changed successful state") } } func TestStaleCompletionCannotStopNewLoading(t *testing.T) { var s searchState a := s.change("a") s.begin(a) b := s.change("b") s.begin(b) if s.finish(a, nil, nil) || s.phase != loading { t.Fatal("stale completion stopped the new loading state") } } func TestOldDebounceRejected(t *testing.T) { var s searchState a := s.change("a") b := s.change("b") if s.begin(a) || !s.begin(b) { t.Fatal("incorrect debounce ownership") } } func TestDuplicateBeginAndCompletionRejected(t *testing.T) { var s searchState g := s.change("query") if !s.begin(g) || s.begin(g) { t.Fatal("request admission is not single-use") } if !s.finish(g, []string{"first"}, nil) || s.finish(g, []string{"duplicate"}, nil) { t.Fatal("request completion is not single-use") } } func TestSameQueryRetryGetsNewIdentity(t *testing.T) { var s searchState a := s.change("query") s.begin(a) s.finish(a, nil, errors.New("transient")) b := s.change("query") if b == a || s.err != nil || !s.begin(b) || !s.finish(b, []string{"ok"}, nil) { t.Fatalf("retry failed: %+v", s) } } func TestEmptyResultIsReadyNotFailure(t *testing.T) { var s searchState g := s.change("no matches") s.begin(g) if !s.finish(g, nil, nil) || s.phase != ready || s.err != nil || len(s.rows) != 0 { t.Fatalf("empty successful result misclassified: %+v", s) } } func TestStopRejectsCompletions(t *testing.T) { var s searchState g := s.change("query") s.begin(g) s.stop() if s.finish(g, []string{"late"}, nil) || s.phase != stopped { t.Fatal("stopped owner accepted completion") } } func TestAcceptedRowsDoNotAliasCallerSlice(t *testing.T) { var s searchState g := s.change("query") s.begin(g) rows := []string{"before"} s.finish(g, rows, nil) rows[0] = "after" // Sequential mutation, not a concurrent ownership test. if s.rows[0] != "before" { t.Fatal("stored rows alias caller slice") } } func TestResultBeforeBeginRejected(t *testing.T) { var s searchState g := s.change("query") if s.finish(g, []string{"unexpected"}, nil) || s.phase != debouncing { t.Fatal("accepted a result before admitting its request") } } func TestBodyRows(t *testing.T) { cases := []struct { name string total, header, footer int want int compact bool }{ {"normal", 24, 3, 2, 19, false}, {"exact", 5, 3, 2, 0, false}, {"header-too-tall", 2, 3, 1, 0, true}, {"footer-too-tall", 5, 3, 3, 0, true}, {"zero-with-chrome", 0, 1, 1, 0, true}, {"zero-empty", 0, 0, 0, 0, false}, {"negative-size", -1, 1, 1, 0, true}, {"negative-chrome", 5, -2, -3, 5, false}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got, compact := bodyRows(tc.total, tc.header, tc.footer) if got != tc.want || compact != tc.compact { t.Fatalf("got (%d, %v), want (%d, %v)", got, compact, tc.want, tc.compact) } }) } }