history: add history module

This commit is contained in:
Chris Sexton 2021-10-05 18:46:11 -04:00 committed by Chris Sexton
parent 6a11ddc98a
commit fc0c6ccd46
2 changed files with 166 additions and 0 deletions

84
bot/history/history.go Normal file
View File

@ -0,0 +1,84 @@
package history
import (
"container/ring"
"fmt"
"github.com/velour/catbase/bot/msg"
)
// History is a ring buffer of messages
type History struct {
r *ring.Ring
}
// New returns a history of sz size
func New(sz int) *History {
return &History{ring.New(sz)}
}
// Edit looks for an entry and ammends it
// returns error if the id is not found
func (h *History) Edit(id string, update *msg.Message) error {
r := h.r
for i := 0; i < r.Len(); i++ {
m := r.Value.(*msg.Message)
if m != nil && m.ID == id {
r.Value = update
return nil
}
r = r.Next()
}
return fmt.Errorf("entry not found")
}
// Append adds a message to the history
func (h *History) Append(m *msg.Message) {
h.r.Value = m
h.r = h.r.Next()
}
// Find looks for an entry by id and returns an error if not found
func (h *History) Find(id string) (*msg.Message, error) {
r := h.r
for i := 0; i < r.Len(); i++ {
m := r.Value.(*msg.Message)
if m != nil && m.ID == id {
return m, nil
}
r = r.Next()
}
return nil, fmt.Errorf("entry not found")
}
// Last gets the last known message
func (h *History) Last() *msg.Message {
return h.r.Prev().Value.(*msg.Message)
}
// LastInChannel searches backwards for the last message matching channel ch
func (h *History) LastInChannel(ch string) (*msg.Message, error) {
r := h.r
for i := 0; i < r.Len(); i++ {
m := r.Value.(*msg.Message)
if m != nil && m.Channel == ch {
return m, nil
}
r = r.Prev()
}
return nil, fmt.Errorf("entry not found")
}
// InChannel returns all knows messages from channel ch in reverse order
func (h *History) InChannel(ch string) []*msg.Message {
out := []*msg.Message{}
r := h.r
for i := 0; i < r.Len(); i++ {
m := r.Value.(*msg.Message)
if m != nil && m.Channel == ch {
out = append(out, m)
}
r = r.Prev()
}
return out
}

View File

@ -0,0 +1,82 @@
package history
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/velour/catbase/bot/msg"
)
var sampleMessages []*msg.Message
func init() {
sampleMessages = []*msg.Message{}
for i := 0; i < 100; i++ {
txt := fmt.Sprintf("Message #%d", i)
m := &msg.Message{
ID: txt,
Body: txt,
}
sampleMessages = append(sampleMessages, m)
}
}
func TestAppend(t *testing.T) {
h := New(10)
for i := 0; i < 10; i++ {
h.Append(sampleMessages[i])
}
previous := h.r.Prev().Value.(*msg.Message)
assert.Equal(t, sampleMessages[9].ID, previous.ID)
}
func TestFindExists(t *testing.T) {
h := New(10)
for i := 0; i < 10; i++ {
h.Append(sampleMessages[i])
}
id := sampleMessages[5].ID
elt, err := h.Find(id)
assert.Nil(t, err)
assert.Equal(t, id, elt.ID)
}
func TestFindMissing(t *testing.T) {
h := New(10)
for i := 0; i < 10; i++ {
h.Append(sampleMessages[i])
}
id := sampleMessages[15].ID
elt, err := h.Find(id)
assert.NotNil(t, err)
assert.Nil(t, elt)
}
func TestEditExists(t *testing.T) {
h := New(10)
for i := 0; i < 10; i++ {
h.Append(sampleMessages[i])
}
id := sampleMessages[5].ID
m := sampleMessages[15]
m.ID = id
err := h.Edit(id, m)
assert.Nil(t, err)
actual, err := h.Find(id)
assert.Nil(t, err)
assert.Equal(t, m.Body, actual.Body)
}
func TestEditMissing(t *testing.T) {
h := New(10)
for i := 0; i < 10; i++ {
h.Append(sampleMessages[i])
}
id := sampleMessages[10].ID
m := sampleMessages[6]
t.Logf("id: %s, editID: %s", id, m.ID)
err := h.Edit(id, m)
assert.NotNil(t, err)
}