package main import ( "database/sql" "os" "testing" _ "github.com/lib/pq" ) // newTestStore opens a connection to the test DB, skipping if not available. // Pattern from go-htmx-web-dev skill: TDD mandatory, no code without tests. func newTestStore(t *testing.T) *Store { t.Helper() dsn := os.Getenv("POSTS_TEST_DSN") if dsn == "" { dsn = "postgres://posts:posts@127.0.0.1:5432/posts_test?sslmode=disable" } db, err := sql.Open("postgres", dsn) if err != nil { t.Skipf("no test db: %v", err) } if err := db.Ping(); err != nil { t.Skipf("no test db: %v", err) } return NewStore(db) } func TestCreatePostBumpsAt(t *testing.T) { s := newTestStore(t) p, err := s.CreatePost("scott", "Hello", "world", []string{"scobleclaw"}) if err != nil { t.Fatalf("create: %v", err) } if p.ID == "" { t.Fatal("expected id") } if p.BumpedAt.IsZero() { t.Fatal("expected bumped_at set") } } func TestAddCommentBumpsPost(t *testing.T) { s := newTestStore(t) p, err := s.CreatePost("scott", "Hello", "world", nil) if err != nil { t.Fatalf("create: %v", err) } before := p.BumpedAt // sleep a beat so timestamps are strictly different // (we're testing logical correctness; in CI you'd inject a clock) c, err := s.AddComment(p.ID, "", "hermes", "first!") if err != nil { t.Fatalf("add comment: %v", err) } if c.Path != c.ID { t.Fatalf("top-level path should equal id, got %q", c.Path) } got, err := s.GetPost(p.ID) if err != nil { t.Fatalf("get: %v", err) } if !got.BumpedAt.After(before) && !got.BumpedAt.Equal(before) { t.Fatalf("post should have been bumped, before=%v after=%v", before, got.BumpedAt) } } func TestNestedCommentPath(t *testing.T) { s := newTestStore(t) p, err := s.CreatePost("scott", "Tree test", "body", nil) if err != nil { t.Fatal(err) } c1, err := s.AddComment(p.ID, "", "hermes", "top") if err != nil { t.Fatal(err) } c2, err := s.AddComment(p.ID, c1.ID, "hermes", "nested") if err != nil { t.Fatal(err) } if c2.Depth != 1 { t.Fatalf("expected depth 1, got %d", c2.Depth) } wantPrefix := c1.ID + "." if !startsWith(c2.Path, wantPrefix) { t.Fatalf("path %q should start with %q", c2.Path, wantPrefix) } } func startsWith(s, prefix string) bool { return len(s) >= len(prefix) && s[:len(prefix)] == prefix }