github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/cli/histutil/db.go (about)

     1  package histutil
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/markusbkk/elvish/pkg/store/storedefs"
     7  )
     8  
     9  // DB is the interface of the storage database.
    10  type 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.
    20  type 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.
    28  func NewFaultyInMemoryDB(cmds ...string) FaultyInMemoryDB {
    29  	return &testDB{cmds: cmds}
    30  }
    31  
    32  // Implementation of FaultyInMemoryDB.
    33  type testDB struct {
    34  	cmds        []string
    35  	oneOffError error
    36  }
    37  
    38  func (s *testDB) SetOneOffError(err error) {
    39  	s.oneOffError = err
    40  }
    41  
    42  func (s *testDB) error() error {
    43  	err := s.oneOffError
    44  	s.oneOffError = nil
    45  	return err
    46  }
    47  
    48  func (s *testDB) NextCmdSeq() (int, error) {
    49  	return len(s.cmds), s.error()
    50  }
    51  
    52  func (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  
    60  func (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  
    77  func (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  
    92  func (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  }