A fast and simple blog backend.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
mediocre-blog/src/post/post_test.go

270 lines
5.5 KiB

package post
import (
"sort"
"strconv"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/tilinna/clock"
)
func TestNewID(t *testing.T) {
tests := [][2]string{
{
"Why Do We Have WiFi Passwords?",
"why-do-we-have-wifi-passwords",
},
{
"Ginger: A Small VM Update",
"ginger-a-small-vm-update",
},
{
"Something-Weird.... woah!",
"somethingweird-woah",
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
assert.Equal(t, test[1], NewID(test[0]))
})
}
}
func testPost(i int) Post {
istr := strconv.Itoa(i)
return Post{
ID: istr,
Title: istr,
Body: istr,
Format: FormatMarkdown,
}
}
type storeTestHarness struct {
clock *clock.Mock
store Store
}
func newStoreTestHarness(t *testing.T) storeTestHarness {
clock := clock.NewMock(time.Now().UTC().Truncate(1 * time.Hour))
db := NewInMemSQLDB()
t.Cleanup(func() { db.Close() })
store := NewStore(db)
return storeTestHarness{
clock: clock,
store: store,
}
}
func (h *storeTestHarness) testStoredPost(i int) StoredPost {
post := testPost(i)
return StoredPost{
Post: post,
PublishedAt: h.clock.Now(),
}
}
func TestStore(t *testing.T) {
assertPostEqual := func(t *testing.T, exp, got StoredPost) {
t.Helper()
sort.Strings(exp.Tags)
sort.Strings(got.Tags)
assert.Equal(t, exp, got)
}
assertPostsEqual := func(t *testing.T, exp, got []StoredPost) {
t.Helper()
if !assert.Len(t, got, len(exp), "exp:%+v\ngot: %+v", exp, got) {
return
}
for i := range exp {
assertPostEqual(t, exp[i], got[i])
}
}
t.Run("not_found", func(t *testing.T) {
h := newStoreTestHarness(t)
_, err := h.store.GetByID("foo")
assert.ErrorIs(t, err, ErrPostNotFound)
})
t.Run("set_get_delete", func(t *testing.T) {
h := newStoreTestHarness(t)
now := h.clock.Now().UTC()
post := testPost(0)
post.Tags = []string{"foo", "bar"}
first, err := h.store.Set(post, now)
assert.NoError(t, err, "post:%+v", post)
assert.True(t, first)
gotPost, err := h.store.GetByID(post.ID)
assert.NoError(t, err)
assertPostEqual(t, StoredPost{
Post: post,
PublishedAt: now,
}, gotPost)
// we will now try updating the post on a different day, and ensure it
// updates properly
h.clock.Add(24 * time.Hour)
newNow := h.clock.Now().UTC()
post.Title = "something else"
post.Description = "some description"
post.Series = "whatever"
post.Body = "anything"
post.Tags = []string{"bar", "baz"}
post.Format = FormatGemtext
first, err = h.store.Set(post, newNow)
assert.NoError(t, err)
assert.False(t, first)
gotPost, err = h.store.GetByID(post.ID)
assert.NoError(t, err)
assertPostEqual(t, StoredPost{
Post: post,
PublishedAt: now,
LastUpdatedAt: newNow,
}, gotPost)
// delete the post, it should go away
assert.NoError(t, h.store.Delete(post.ID))
_, err = h.store.GetByID(post.ID)
assert.ErrorIs(t, err, ErrPostNotFound)
})
t.Run("get", func(t *testing.T) {
h := newStoreTestHarness(t)
now := h.clock.Now().UTC()
posts := []StoredPost{
h.testStoredPost(3),
h.testStoredPost(2),
h.testStoredPost(1),
h.testStoredPost(0),
}
for _, post := range posts {
_, err := h.store.Set(post.Post, now)
assert.NoError(t, err)
}
gotPosts, hasMore, err := h.store.Get(0, 2)
assert.NoError(t, err)
assert.True(t, hasMore)
assertPostsEqual(t, posts[:2], gotPosts)
gotPosts, hasMore, err = h.store.Get(1, 2)
assert.NoError(t, err)
assert.False(t, hasMore)
assertPostsEqual(t, posts[2:4], gotPosts)
posts = append([]StoredPost{h.testStoredPost(4)}, posts...)
_, err = h.store.Set(posts[0].Post, now)
assert.NoError(t, err)
gotPosts, hasMore, err = h.store.Get(1, 2)
assert.NoError(t, err)
assert.True(t, hasMore)
assertPostsEqual(t, posts[2:4], gotPosts)
gotPosts, hasMore, err = h.store.Get(2, 2)
assert.NoError(t, err)
assert.False(t, hasMore)
assertPostsEqual(t, posts[4:], gotPosts)
})
t.Run("get_by_series", func(t *testing.T) {
h := newStoreTestHarness(t)
now := h.clock.Now().UTC()
posts := []StoredPost{
h.testStoredPost(3),
h.testStoredPost(2),
h.testStoredPost(1),
h.testStoredPost(0),
}
posts[0].Series = "foo"
posts[1].Series = "bar"
posts[2].Series = "bar"
for _, post := range posts {
_, err := h.store.Set(post.Post, now)
assert.NoError(t, err)
}
fooPosts, err := h.store.GetBySeries("foo")
assert.NoError(t, err)
assertPostsEqual(t, posts[:1], fooPosts)
barPosts, err := h.store.GetBySeries("bar")
assert.NoError(t, err)
assertPostsEqual(t, posts[1:3], barPosts)
bazPosts, err := h.store.GetBySeries("baz")
assert.NoError(t, err)
assert.Empty(t, bazPosts)
})
t.Run("get_by_tag", func(t *testing.T) {
h := newStoreTestHarness(t)
now := h.clock.Now().UTC()
posts := []StoredPost{
h.testStoredPost(3),
h.testStoredPost(2),
h.testStoredPost(1),
h.testStoredPost(0),
}
posts[0].Tags = []string{"foo"}
posts[1].Tags = []string{"foo", "bar"}
posts[2].Tags = []string{"bar"}
for _, post := range posts {
_, err := h.store.Set(post.Post, now)
assert.NoError(t, err)
}
fooPosts, err := h.store.GetByTag("foo")
assert.NoError(t, err)
assertPostsEqual(t, posts[:2], fooPosts)
barPosts, err := h.store.GetByTag("bar")
assert.NoError(t, err)
assertPostsEqual(t, posts[1:3], barPosts)
bazPosts, err := h.store.GetByTag("baz")
assert.NoError(t, err)
assert.Empty(t, bazPosts)
tags, err := h.store.GetTags()
assert.NoError(t, err)
assert.ElementsMatch(t, []string{"foo", "bar"}, tags)
})
}