okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
f7fcae1
main
1package contracts 2 3import ( 4"errors" 5"reflect" 6"testing" 7) 8 9func TestOldResultRejectedBeforeNewDebounce (t * testing.T ) { 10var s searchState 11a := s .change ("a" ) 12if ! s .begin (a ) { 13t .Fatal ("first request not admitted" ) 14 } 15b := s .change ("b" ) 16before := s 17if s .finish (a , []string {"old" },nil ) { 18t .Fatal ("old result accepted during new debounce" ) 19 } 20if ! reflect .DeepEqual (before ,s ) { 21t .Fatal ("rejected result mutated state" ) 22 } 23if ! s .begin (b )|| ! s .finish (b , []string {"new" },nil ) { 24t .Fatal ("new request failed" ) 25 } 26if s .phase != ready || ! reflect .DeepEqual (s .rows , []string {"new" }) { 27t .Fatalf ("unexpected final state: %+v" ,s ) 28 } 29} 30 31func TestStaleFailureCannotOverwriteSuccess (t * testing.T ) { 32var s searchState 33a := s .change ("a" ) 34s .begin (a ) 35b := s .change ("b" ) 36s .begin (b ) 37s .finish (b , []string {"new" },nil ) 38before := s 39if s .finish (a ,nil ,errors .New ("old failure" ))|| ! reflect .DeepEqual (before ,s ) { 40t .Fatal ("stale failure changed successful state" ) 41 } 42} 43 44func TestStaleCompletionCannotStopNewLoading (t * testing.T ) { 45var s searchState 46a := s .change ("a" ) 47s .begin (a ) 48b := s .change ("b" ) 49s .begin (b ) 50if s .finish (a ,nil ,nil )|| s .phase != loading { 51t .Fatal ("stale completion stopped the new loading state" ) 52 } 53} 54 55func TestOldDebounceRejected (t * testing.T ) { 56var s searchState 57a := s .change ("a" ) 58b := s .change ("b" ) 59if s .begin (a )|| ! s .begin (b ) { 60t .Fatal ("incorrect debounce ownership" ) 61 } 62} 63 64func TestDuplicateBeginAndCompletionRejected (t * testing.T ) { 65var s searchState 66g := s .change ("query" ) 67if ! s .begin (g )|| s .begin (g ) { 68t .Fatal ("request admission is not single-use" ) 69 } 70if ! s .finish (g , []string {"first" },nil )|| s .finish (g , []string {"duplicate" },nil ) { 71t .Fatal ("request completion is not single-use" ) 72 } 73} 74 75func TestSameQueryRetryGetsNewIdentity (t * testing.T ) { 76var s searchState 77a := s .change ("query" ) 78s .begin (a ) 79s .finish (a ,nil ,errors .New ("transient" )) 80b := s .change ("query" ) 81if b == a || s .err != nil || ! s .begin (b )|| ! s .finish (b , []string {"ok" },nil ) { 82t .Fatalf ("retry failed: %+v" ,s ) 83 } 84} 85 86func TestEmptyResultIsReadyNotFailure (t * testing.T ) { 87var s searchState 88g := s .change ("no matches" ) 89s .begin (g ) 90if ! s .finish (g ,nil ,nil )|| s .phase != ready || s .err != nil || len (s .rows )!= 0 { 91t .Fatalf ("empty successful result misclassified: %+v" ,s ) 92 } 93} 94 95func TestStopRejectsCompletions (t * testing.T ) { 96var s searchState 97g := s .change ("query" ) 98s .begin (g ) 99s .stop () 100if s .finish (g , []string {"late" },nil )|| s .phase != stopped { 101t .Fatal ("stopped owner accepted completion" ) 102 } 103} 104 105func TestAcceptedRowsDoNotAliasCallerSlice (t * testing.T ) { 106var s searchState 107g := s .change ("query" ) 108s .begin (g ) 109rows := []string {"before" } 110s .finish (g ,rows ,nil ) 111rows [0 ]= "after" // Sequential mutation, not a concurrent ownership test. 112if s .rows [0 ]!= "before" { 113t .Fatal ("stored rows alias caller slice" ) 114 } 115} 116 117func TestResultBeforeBeginRejected (t * testing.T ) { 118var s searchState 119g := s .change ("query" ) 120if s .finish (g , []string {"unexpected" },nil )|| s .phase != debouncing { 121t .Fatal ("accepted a result before admitting its request" ) 122 } 123} 124 125func TestBodyRows (t * testing.T ) { 126cases := []struct { 127name string 128total ,header ,footer int 129want int 130compact bool 131 }{ 132 {"normal" ,24 ,3 ,2 ,19 ,false }, 133 {"exact" ,5 ,3 ,2 ,0 ,false }, 134 {"header-too-tall" ,2 ,3 ,1 ,0 ,true }, 135 {"footer-too-tall" ,5 ,3 ,3 ,0 ,true }, 136 {"zero-with-chrome" ,0 ,1 ,1 ,0 ,true }, 137 {"zero-empty" ,0 ,0 ,0 ,0 ,false }, 138 {"negative-size" ,- 1 ,1 ,1 ,0 ,true }, 139 {"negative-chrome" ,5 ,- 2 ,- 3 ,5 ,false }, 140 } 141for _ ,tc := range cases { 142t .Run (tc .name ,func (t * testing.T ) { 143got ,compact := bodyRows (tc .total ,tc .header ,tc .footer ) 144if got != tc .want || compact != tc .compact { 145t .Fatalf ("got (%d, %v), want (%d, %v)" ,got ,compact ,tc .want ,tc .compact ) 146 } 147 }) 148 } 149}