github.com/elves/elvish@v0.15.0/pkg/cli/histutil/hybrid_store_test.go (about) 1 package histutil 2 3 import ( 4 "errors" 5 "reflect" 6 "testing" 7 8 "github.com/elves/elvish/pkg/store" 9 ) 10 11 var errMock = errors.New("mock error") 12 13 func TestNewHybridStore_ReturnsMemStoreIfDBIsNil(t *testing.T) { 14 store, err := NewHybridStore(nil) 15 if _, ok := store.(*memStore); !ok { 16 t.Errorf("NewHybridStore -> %v, want memStore", store) 17 } 18 if err != nil { 19 t.Errorf("NewHybridStore -> error %v, want nil", err) 20 } 21 } 22 23 func TestNewHybridStore_ReturnsMemStoreOnDBError(t *testing.T) { 24 db := NewFaultyInMemoryDB() 25 db.SetOneOffError(errMock) 26 store, err := NewHybridStore(db) 27 if _, ok := store.(*memStore); !ok { 28 t.Errorf("NewHybridStore -> %v, want memStore", store) 29 } 30 if err != errMock { 31 t.Errorf("NewHybridStore -> error %v, want %v", err, errMock) 32 } 33 } 34 35 func TestFusuer_AddCmd_AddsBothToDBAndSession(t *testing.T) { 36 db := NewFaultyInMemoryDB("shared 1") 37 f := mustNewHybridStore(db) 38 39 f.AddCmd(store.Cmd{Text: "session 1"}) 40 41 wantDBCmds := []store.Cmd{ 42 {Text: "shared 1", Seq: 0}, {Text: "session 1", Seq: 1}} 43 if dbCmds, _ := db.CmdsWithSeq(-1, -1); !reflect.DeepEqual(dbCmds, wantDBCmds) { 44 t.Errorf("DB commands = %v, want %v", dbCmds, wantDBCmds) 45 } 46 47 allCmds, err := f.AllCmds() 48 if err != nil { 49 panic(err) 50 } 51 wantAllCmds := []store.Cmd{ 52 {Text: "shared 1", Seq: 0}, 53 {Text: "session 1", Seq: 1}} 54 if !reflect.DeepEqual(allCmds, wantAllCmds) { 55 t.Errorf("AllCmd -> %v, want %v", allCmds, wantAllCmds) 56 } 57 } 58 59 func TestHybridStore_AddCmd_AddsToSessionEvenIfDBErrors(t *testing.T) { 60 db := NewFaultyInMemoryDB() 61 f := mustNewHybridStore(db) 62 db.SetOneOffError(errMock) 63 64 _, err := f.AddCmd(store.Cmd{Text: "haha"}) 65 if err != errMock { 66 t.Errorf("AddCmd -> error %v, want %v", err, errMock) 67 } 68 69 allCmds, err := f.AllCmds() 70 if err != nil { 71 panic(err) 72 } 73 wantAllCmds := []store.Cmd{{Text: "haha", Seq: 1}} 74 if !reflect.DeepEqual(allCmds, wantAllCmds) { 75 t.Errorf("AllCmd -> %v, want %v", allCmds, wantAllCmds) 76 } 77 } 78 79 func TestHybridStore_AllCmds_IncludesFrozenSharedAndNewlyAdded(t *testing.T) { 80 db := NewFaultyInMemoryDB("shared 1") 81 f := mustNewHybridStore(db) 82 83 // Simulate adding commands from both the current session and other sessions. 84 f.AddCmd(store.Cmd{Text: "session 1"}) 85 db.AddCmd("other session 1") 86 db.AddCmd("other session 2") 87 f.AddCmd(store.Cmd{Text: "session 2"}) 88 db.AddCmd("other session 3") 89 90 // AllCmds should return all commands from the storage when the HybridStore 91 // was created, plus session commands. The session commands should have 92 // sequence numbers consistent with the DB. 93 allCmds, err := f.AllCmds() 94 if err != nil { 95 t.Errorf("AllCmds -> error %v, want nil", err) 96 } 97 wantAllCmds := []store.Cmd{ 98 {Text: "shared 1", Seq: 0}, 99 {Text: "session 1", Seq: 1}, 100 {Text: "session 2", Seq: 4}} 101 if !reflect.DeepEqual(allCmds, wantAllCmds) { 102 t.Errorf("AllCmds -> %v, want %v", allCmds, wantAllCmds) 103 } 104 } 105 106 func TestHybridStore_AllCmds_ReturnsSessionIfDBErrors(t *testing.T) { 107 db := NewFaultyInMemoryDB("shared 1") 108 f := mustNewHybridStore(db) 109 f.AddCmd(store.Cmd{Text: "session 1"}) 110 db.SetOneOffError(errMock) 111 112 allCmds, err := f.AllCmds() 113 if err != errMock { 114 t.Errorf("AllCmds -> error %v, want %v", err, errMock) 115 } 116 wantAllCmds := []store.Cmd{{Text: "session 1", Seq: 1}} 117 if !reflect.DeepEqual(allCmds, wantAllCmds) { 118 t.Errorf("AllCmd -> %v, want %v", allCmds, wantAllCmds) 119 } 120 } 121 122 func TestHybridStore_Cursor_OnlySession(t *testing.T) { 123 db := NewFaultyInMemoryDB() 124 f := mustNewHybridStore(db) 125 db.AddCmd("+ other session") 126 f.AddCmd(store.Cmd{Text: "+ session 1"}) 127 f.AddCmd(store.Cmd{Text: "- no match"}) 128 129 testCursorIteration(t, f.Cursor("+"), []store.Cmd{{Text: "+ session 1", Seq: 1}}) 130 } 131 132 func TestHybridStore_Cursor_OnlyShared(t *testing.T) { 133 db := NewFaultyInMemoryDB("- no match", "+ shared 1") 134 f := mustNewHybridStore(db) 135 db.AddCmd("+ other session") 136 f.AddCmd(store.Cmd{Text: "- no match"}) 137 138 testCursorIteration(t, f.Cursor("+"), []store.Cmd{{Text: "+ shared 1", Seq: 1}}) 139 } 140 141 func TestHybridStore_Cursor_SharedAndSession(t *testing.T) { 142 db := NewFaultyInMemoryDB("- no match", "+ shared 1") 143 f := mustNewHybridStore(db) 144 db.AddCmd("+ other session") 145 db.AddCmd("- no match") 146 f.AddCmd(store.Cmd{Text: "+ session 1"}) 147 f.AddCmd(store.Cmd{Text: "- no match"}) 148 149 testCursorIteration(t, f.Cursor("+"), []store.Cmd{ 150 {Text: "+ shared 1", Seq: 1}, 151 {Text: "+ session 1", Seq: 4}}) 152 } 153 154 func testCursorIteration(t *testing.T, cursor Cursor, wantCmds []store.Cmd) { 155 expectEndOfHistory := func() { 156 t.Helper() 157 if _, err := cursor.Get(); err != ErrEndOfHistory { 158 t.Errorf("Get -> error %v, want ErrEndOfHistory", err) 159 } 160 } 161 expectCmd := func(i int) { 162 t.Helper() 163 wantCmd := wantCmds[i] 164 cmd, err := cursor.Get() 165 if cmd != wantCmd { 166 t.Errorf("Get -> %v, want %v", cmd, wantCmd) 167 } 168 if err != nil { 169 t.Errorf("Get -> error %v, want nil", err) 170 } 171 } 172 173 expectEndOfHistory() 174 175 for i := len(wantCmds) - 1; i >= 0; i-- { 176 cursor.Prev() 177 expectCmd(i) 178 } 179 180 cursor.Prev() 181 expectEndOfHistory() 182 cursor.Prev() 183 expectEndOfHistory() 184 185 for i := range wantCmds { 186 cursor.Next() 187 expectCmd(i) 188 } 189 190 cursor.Next() 191 expectEndOfHistory() 192 cursor.Next() 193 expectEndOfHistory() 194 } 195 196 func mustNewHybridStore(db DB) Store { 197 f, err := NewHybridStore(db) 198 if err != nil { 199 panic(err) 200 } 201 return f 202 }