1package histutil 2 3import ( 4 "strings" 5 6 "src.elv.sh/pkg/store/storedefs" 7) 8 9// DB is the interface of the storage database. 10type DB interface { 11 NextCmdSeq() (int, error) 12 AddCmd(cmd string) (int, error) 13 CmdsWithSeq(from, upto int) ([]storedefs.Cmd, error) 14 PrevCmd(upto int, prefix string) (storedefs.Cmd, error) 15 NextCmd(from int, prefix string) (storedefs.Cmd, error) 16} 17 18// FaultyInMemoryDB is an in-memory DB implementation that can be injected 19// one-off errors. It is useful in tests. 20type FaultyInMemoryDB interface { 21 DB 22 // SetOneOffError causes the next operation on the database to return the 23 // given error. 24 SetOneOffError(err error) 25} 26 27// NewFaultyInMemoryDB creates a new FaultyInMemoryDB with the given commands. 28func NewFaultyInMemoryDB(cmds ...string) FaultyInMemoryDB { 29 return &testDB{cmds: cmds} 30} 31 32// Implementation of FaultyInMemoryDB. 33type testDB struct { 34 cmds []string 35 oneOffError error 36} 37 38func (s *testDB) SetOneOffError(err error) { 39 s.oneOffError = err 40} 41 42func (s *testDB) error() error { 43 err := s.oneOffError 44 s.oneOffError = nil 45 return err 46} 47 48func (s *testDB) NextCmdSeq() (int, error) { 49 return len(s.cmds), s.error() 50} 51 52func (s *testDB) AddCmd(cmd string) (int, error) { 53 if s.oneOffError != nil { 54 return -1, s.error() 55 } 56 s.cmds = append(s.cmds, cmd) 57 return len(s.cmds) - 1, nil 58} 59 60func (s *testDB) CmdsWithSeq(from, upto int) ([]storedefs.Cmd, error) { 61 if err := s.error(); err != nil { 62 return nil, err 63 } 64 if from < 0 { 65 from = 0 66 } 67 if upto < 0 || upto > len(s.cmds) { 68 upto = len(s.cmds) 69 } 70 var cmds []storedefs.Cmd 71 for i := from; i < upto; i++ { 72 cmds = append(cmds, storedefs.Cmd{Text: s.cmds[i], Seq: i}) 73 } 74 return cmds, nil 75} 76 77func (s *testDB) PrevCmd(upto int, prefix string) (storedefs.Cmd, error) { 78 if s.oneOffError != nil { 79 return storedefs.Cmd{}, s.error() 80 } 81 if upto < 0 || upto > len(s.cmds) { 82 upto = len(s.cmds) 83 } 84 for i := upto - 1; i >= 0; i-- { 85 if strings.HasPrefix(s.cmds[i], prefix) { 86 return storedefs.Cmd{Text: s.cmds[i], Seq: i}, nil 87 } 88 } 89 return storedefs.Cmd{}, storedefs.ErrNoMatchingCmd 90} 91 92func (s *testDB) NextCmd(from int, prefix string) (storedefs.Cmd, error) { 93 if s.oneOffError != nil { 94 return storedefs.Cmd{}, s.error() 95 } 96 if from < 0 { 97 from = 0 98 } 99 for i := from; i < len(s.cmds); i++ { 100 if strings.HasPrefix(s.cmds[i], prefix) { 101 return storedefs.Cmd{Text: s.cmds[i], Seq: i}, nil 102 } 103 } 104 return storedefs.Cmd{}, storedefs.ErrNoMatchingCmd 105} 106