From 4f01edb9230f58ff84b0dd892c931ec8ac9aad55 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Tue, 13 Sep 2022 12:56:08 +0200 Subject: move src out of srv, clean up default.nix and Makefile --- src/post/post_test.go | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 src/post/post_test.go (limited to 'src/post/post_test.go') diff --git a/src/post/post_test.go b/src/post/post_test.go new file mode 100644 index 0000000..c7f9cdc --- /dev/null +++ b/src/post/post_test.go @@ -0,0 +1,268 @@ +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, + Description: istr, + Body: istr, + } +} + +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) + 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.Series = "whatever" + post.Body = "anything" + post.Tags = []string{"bar", "baz"} + + 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) + }) +} -- cgit v1.2.3