service_test.go

  1package filetracker
  2
  3import (
  4	"context"
  5	"testing"
  6	"testing/synctest"
  7	"time"
  8
  9	"github.com/charmbracelet/crush/internal/db"
 10	"github.com/stretchr/testify/require"
 11)
 12
 13type testEnv struct {
 14	ctx context.Context
 15	q   *db.Queries
 16	svc Service
 17}
 18
 19func setupTest(t *testing.T) *testEnv {
 20	t.Helper()
 21
 22	conn, err := db.Connect(t.Context(), t.TempDir())
 23	require.NoError(t, err)
 24	t.Cleanup(func() { conn.Close() })
 25
 26	q := db.New(conn)
 27	return &testEnv{
 28		ctx: t.Context(),
 29		q:   q,
 30		svc: NewService(q),
 31	}
 32}
 33
 34func (e *testEnv) createSession(t *testing.T, sessionID string) {
 35	t.Helper()
 36	_, err := e.q.CreateSession(e.ctx, db.CreateSessionParams{
 37		ID:    sessionID,
 38		Title: "Test Session",
 39	})
 40	require.NoError(t, err)
 41}
 42
 43func TestService_RecordRead(t *testing.T) {
 44	env := setupTest(t)
 45
 46	sessionID := "test-session-1"
 47	path := "/path/to/file.go"
 48	env.createSession(t, sessionID)
 49
 50	env.svc.RecordRead(env.ctx, sessionID, path)
 51
 52	lastRead := env.svc.LastReadTime(env.ctx, sessionID, path)
 53	require.False(t, lastRead.IsZero(), "expected non-zero time after recording read")
 54	require.WithinDuration(t, time.Now(), lastRead, 2*time.Second)
 55}
 56
 57func TestService_LastReadTime_NotFound(t *testing.T) {
 58	env := setupTest(t)
 59
 60	lastRead := env.svc.LastReadTime(env.ctx, "nonexistent-session", "/nonexistent/path")
 61	require.True(t, lastRead.IsZero(), "expected zero time for unread file")
 62}
 63
 64func TestService_RecordRead_UpdatesTimestamp(t *testing.T) {
 65	env := setupTest(t)
 66
 67	sessionID := "test-session-2"
 68	path := "/path/to/file.go"
 69	env.createSession(t, sessionID)
 70
 71	env.svc.RecordRead(env.ctx, sessionID, path)
 72	firstRead := env.svc.LastReadTime(env.ctx, sessionID, path)
 73	require.False(t, firstRead.IsZero())
 74
 75	synctest.Test(t, func(t *testing.T) {
 76		time.Sleep(100 * time.Millisecond)
 77		synctest.Wait()
 78		env.svc.RecordRead(env.ctx, sessionID, path)
 79		secondRead := env.svc.LastReadTime(env.ctx, sessionID, path)
 80
 81		require.False(t, secondRead.Before(firstRead), "second read time should not be before first")
 82	})
 83}
 84
 85func TestService_RecordRead_DifferentSessions(t *testing.T) {
 86	env := setupTest(t)
 87
 88	path := "/shared/file.go"
 89	session1, session2 := "session-1", "session-2"
 90	env.createSession(t, session1)
 91	env.createSession(t, session2)
 92
 93	env.svc.RecordRead(env.ctx, session1, path)
 94
 95	lastRead1 := env.svc.LastReadTime(env.ctx, session1, path)
 96	require.False(t, lastRead1.IsZero())
 97
 98	lastRead2 := env.svc.LastReadTime(env.ctx, session2, path)
 99	require.True(t, lastRead2.IsZero(), "session 2 should not see session 1's read")
100}
101
102func TestService_RecordRead_DifferentPaths(t *testing.T) {
103	env := setupTest(t)
104
105	sessionID := "test-session-3"
106	path1, path2 := "/path/to/file1.go", "/path/to/file2.go"
107	env.createSession(t, sessionID)
108
109	env.svc.RecordRead(env.ctx, sessionID, path1)
110
111	lastRead1 := env.svc.LastReadTime(env.ctx, sessionID, path1)
112	require.False(t, lastRead1.IsZero())
113
114	lastRead2 := env.svc.LastReadTime(env.ctx, sessionID, path2)
115	require.True(t, lastRead2.IsZero(), "path2 should not be recorded")
116}