From 740cf8979ac025aa94f0daf7ee8ddf7184e405f2 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Wed, 18 Mar 2026 22:19:26 +1100 Subject: [PATCH] fix: unit tests --- handlers/posts.go | 3 +- models/ids_test.go | 4 +- providers/db/provider_test.go | 19 +++-- providers/sitereader/provider.go | 94 ----------------------- providers/sitereader/provider_test.go | 106 -------------------------- services/import/service.go | 54 ------------- 6 files changed, 16 insertions(+), 264 deletions(-) delete mode 100644 providers/sitereader/provider.go delete mode 100644 providers/sitereader/provider_test.go delete mode 100644 services/import/service.go diff --git a/handlers/posts.go b/handlers/posts.go index e0234fc..a339685 100644 --- a/handlers/posts.go +++ b/handlers/posts.go @@ -145,8 +145,7 @@ func (ph PostsHandler) Patch(c fiber.Ctx) error { return accepts(c, json(func() any { return struct{}{} }), html(func(c fiber.Ctx) error { - - return c.Redirect().To(fmt.Sprintf("/sites/%v/posts")) + return c.Redirect().To(fmt.Sprintf("/sites/%v/posts", models.MustGetSite(c.Context()).ID)) })) } diff --git a/models/ids_test.go b/models/ids_test.go index e57daf0..8d933fc 100644 --- a/models/ids_test.go +++ b/models/ids_test.go @@ -7,8 +7,8 @@ import ( func TestNewNanoID(t *testing.T) { id := NewNanoID() - if len(id) != 12 { - t.Errorf("Expected ID length of 12, got %d", len(id)) + if len(id) != 16 { + t.Errorf("Expected ID length of 16, got %d", len(id)) } if id == "" { diff --git a/providers/db/provider_test.go b/providers/db/provider_test.go index caf83d1..06f03c0 100644 --- a/providers/db/provider_test.go +++ b/providers/db/provider_test.go @@ -98,6 +98,7 @@ func TestProvider_Sites(t *testing.T) { t.Run("select site by id", func(t *testing.T) { site := &models.Site{ OwnerID: user.ID, + GUID: models.NewNanoID(), Title: "Lookup Blog", Tagline: "Find me by ID", } @@ -143,10 +144,11 @@ func TestProvider_Posts(t *testing.T) { require.NoError(t, p.SaveSite(ctx, site)) t.Run("save and select posts", func(t *testing.T) { + guid := models.NewNanoID() now := time.Date(2026, 2, 19, 12, 0, 0, 0, time.UTC) post := &models.Post{ SiteID: site.ID, - GUID: "post-001", + GUID: guid, Title: "First Post", Body: "Hello world", Slug: "/2026/02/19/first-post", @@ -158,12 +160,12 @@ func TestProvider_Posts(t *testing.T) { require.NoError(t, err) assert.NotZero(t, post.ID) - posts, err := p.SelectPostsOfSite(ctx, site.ID, false, db.PagingParams{}) + posts, err := p.SelectPostsOfSite(ctx, site.ID, false, db.PagingParams{Limit: 10, Offset: 0}) require.NoError(t, err) require.Len(t, posts, 1) assert.Equal(t, post.ID, posts[0].ID) assert.Equal(t, site.ID, posts[0].SiteID) - assert.Equal(t, "post-001", posts[0].GUID) + assert.Equal(t, guid, posts[0].GUID) assert.Equal(t, "First Post", posts[0].Title) assert.Equal(t, "Hello world", posts[0].Body) assert.Equal(t, "/2026/02/19/first-post", posts[0].Slug) @@ -173,8 +175,10 @@ func TestProvider_Posts(t *testing.T) { t.Run("posts ordered by created_at desc", func(t *testing.T) { // Create a second site to isolate this test + guid := models.NewNanoID() site2 := &models.Site{ OwnerID: user.ID, + GUID: models.NewNanoID(), Title: "Second Blog", Tagline: "", } @@ -185,7 +189,7 @@ func TestProvider_Posts(t *testing.T) { post1 := &models.Post{ SiteID: site2.ID, - GUID: "old-post", + GUID: guid, Title: "Old Post", Body: "old", Slug: "/old", @@ -194,7 +198,7 @@ func TestProvider_Posts(t *testing.T) { } post2 := &models.Post{ SiteID: site2.ID, - GUID: "new-post", + GUID: models.NewNanoID(), Title: "New Post", Body: "new", Slug: "/new", @@ -205,7 +209,7 @@ func TestProvider_Posts(t *testing.T) { require.NoError(t, p.SavePost(ctx, post1)) require.NoError(t, p.SavePost(ctx, post2)) - posts, err := p.SelectPostsOfSite(ctx, site2.ID, false, db.PagingParams{}) + posts, err := p.SelectPostsOfSite(ctx, site2.ID, false, db.PagingParams{Limit: 10, Offset: 0}) require.NoError(t, err) require.Len(t, posts, 2) assert.Equal(t, "New Post", posts[0].Title) @@ -215,6 +219,7 @@ func TestProvider_Posts(t *testing.T) { t.Run("select posts for site with no posts", func(t *testing.T) { emptySite := &models.Site{ OwnerID: user.ID, + GUID: models.NewNanoID(), Title: "Empty Blog", Tagline: "", } @@ -239,6 +244,7 @@ func TestProvider_PublishTargets(t *testing.T) { site := &models.Site{ OwnerID: user.ID, + GUID: models.NewNanoID(), Title: "My Blog", Tagline: "A test blog", } @@ -272,6 +278,7 @@ func TestProvider_PublishTargets(t *testing.T) { t.Run("select targets for site with no targets", func(t *testing.T) { emptySite := &models.Site{ OwnerID: user.ID, + GUID: models.NewNanoID(), Title: "No Targets", Tagline: "", } diff --git a/providers/sitereader/provider.go b/providers/sitereader/provider.go deleted file mode 100644 index 1365d4b..0000000 --- a/providers/sitereader/provider.go +++ /dev/null @@ -1,94 +0,0 @@ -package sitereader - -import ( - "bytes" - "io" - "io/fs" - "time" - - "gopkg.in/yaml.v3" - "lmika.dev/lmika/weiro/models" -) - -type Provider struct { - fs fs.FS -} - -func New(fs fs.FS) *Provider { - return &Provider{ - fs: fs, - } -} - -func (p *Provider) ReadSite() (ReadSiteModels, error) { - posts, err := p.ListPosts() - if err != nil { - return ReadSiteModels{}, err - } - - meta := siteMeta{} - metaBytes, err := fs.ReadFile(p.fs, "site.yaml") - if err != nil { - return ReadSiteModels{}, err - } - if err := yaml.Unmarshal(metaBytes, &meta); err != nil { - return ReadSiteModels{}, err - } - - site := models.Site{ - Title: meta.Title, - Tagline: meta.Tagline, - } - - return ReadSiteModels{ - Site: site, - Posts: posts, - }, nil -} - -func (p *Provider) ListPosts() (posts []*models.Post, err error) { - err = fs.WalkDir(p.fs, "posts", func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } else if d.IsDir() { - return nil - } - - post, err := p.ReadPost(path) - if err != nil { - return err - } - posts = append(posts, post) - return nil - }) - return posts, err -} - -func (p *Provider) ReadPost(path string) (*models.Post, error) { - data, err := fs.ReadFile(p.fs, path) - if err != nil { - return nil, err - } - - // Split front matter and content - parts := bytes.SplitN(data, []byte("---"), 3) - if len(parts) < 3 { - return nil, io.ErrUnexpectedEOF - } - - var meta postMeta - if err := yaml.Unmarshal(parts[1], &meta); err != nil { - return nil, err - } - - post := models.Post{ - Slug: meta.Slug, - Title: meta.Title, - GUID: meta.ID, - PublishedAt: meta.Date, - CreatedAt: time.Now(), - } - - post.Body = string(bytes.TrimPrefix(parts[2], []byte("\n"))) - return &post, nil -} diff --git a/providers/sitereader/provider_test.go b/providers/sitereader/provider_test.go deleted file mode 100644 index 0b012eb..0000000 --- a/providers/sitereader/provider_test.go +++ /dev/null @@ -1,106 +0,0 @@ -package sitereader_test - -import ( - "testing" - "testing/fstest" - "time" - - "github.com/stretchr/testify/assert" - "lmika.dev/lmika/weiro/providers/sitereader" -) - -func TestProvider_ReadPost(t *testing.T) { - t.Run("with meta", func(t *testing.T) { - testFS := fstest.MapFS{ - "site.yaml": {Data: []byte(`base_url: https://example.com`)}, - "posts/test.md": {Data: []byte(`--- -date: 2026-02-18T19:59:00Z -title: Test Post Here -tags: [test, example] ---- -This is just a test post. -`)}, - } - - pr := sitereader.New(testFS) - - post, err := pr.ReadPost("posts/test.md") - assert.NoError(t, err) - assert.Equal(t, "Test Post Here", post.Title) - assert.Equal(t, time.Date(2026, 2, 18, 19, 59, 0, 0, time.UTC), post.PublishedAt) - assert.Equal(t, "This is just a test post.\n", post.Body) - }) - - t.Run("without meta", func(t *testing.T) { - testFS := fstest.MapFS{ - "posts/test.md": {Data: []byte(`--- ---- -This is just a test post. -`)}, - } - - pr := sitereader.New(testFS) - - post, err := pr.ReadPost("posts/test.md") - assert.NoError(t, err) - assert.Equal(t, "", post.Title) - assert.Equal(t, "This is just a test post.\n", post.Body) - }) -} - -func TestProvider_ListPosts(t *testing.T) { - testFS := fstest.MapFS{ - "posts/01-post1.md": {Data: []byte(`--- -id: 111 -date: 2026-02-18T19:59:00Z -title: Test Post Here -tags: [test, example] ---- -This is just a test post. -`)}, - "posts/02-post2.md": {Data: []byte(`--- -id: 222 ---- -This is just a test post. -`)}, - } - - pr := sitereader.New(testFS) - - posts, err := pr.ListPosts() - assert.NoError(t, err) - - assert.Equal(t, 2, len(posts)) - - assert.Equal(t, "111", posts[0].GUID) - assert.Equal(t, "222", posts[1].GUID) -} - -func TestProvider_ReadSite(t *testing.T) { - testFS := fstest.MapFS{ - "site.yaml": {Data: []byte(`base_url: https://example.com`)}, - "posts/01-post1.md": {Data: []byte(`--- -id: 111 -date: 2026-02-18T19:59:00Z -title: Test Post Here -tags: [test, example] ---- -This is just a test post. -`)}, - "posts/02-post2.md": {Data: []byte(`--- -id: 222 ---- -This is just a test post. -`)}, - } - - pr := sitereader.New(testFS) - - sites, err := pr.ReadSite() - assert.NoError(t, err) - - assert.Equal(t, 2, len(sites.Posts)) - - assert.Equal(t, "111", sites.Posts[0].GUID) - assert.Equal(t, "222", sites.Posts[1].GUID) -} diff --git a/services/import/service.go b/services/import/service.go deleted file mode 100644 index e4aee94..0000000 --- a/services/import/service.go +++ /dev/null @@ -1,54 +0,0 @@ -package _import - -import ( - "context" - "os" - - "emperror.dev/errors" - "lmika.dev/lmika/weiro/models" - "lmika.dev/lmika/weiro/providers/db" - "lmika.dev/lmika/weiro/providers/sitereader" -) - -type Service struct { - db *db.Provider -} - -func New(db *db.Provider) *Service { - return &Service{ - db: db, - } -} - -func (s *Service) Import(ctx context.Context, sitePath string) (models.Site, error) { - user, ok := models.GetUser(ctx) - if !ok { - return models.Site{}, models.UserRequiredError - } - - sr := sitereader.New(os.DirFS(sitePath)) - - readSite, err := sr.ReadSite() - if err != nil { - return models.Site{}, errors.Wrap(err, "failed to read site") - } - - site := readSite.Site - site.OwnerID = user.ID - - if err := s.db.SaveSite(ctx, &site); err != nil { - return models.Site{}, errors.Wrap(err, "failed to save site") - } - - for _, post := range readSite.Posts { - post.SiteID = site.ID - if post.GUID == "" { - post.GUID = models.NewNanoID() - } - if err := s.db.SavePost(ctx, post); err != nil { - return models.Site{}, errors.Wrap(err, "failed to save post") - } - } - - return site, nil -}