]> git.giacomolli.uk - onechat/blobdiff - log_test.go
Reflow comments over the reflow width
[onechat] / log_test.go
index 89b87b337a7240709934057742938fd2f5b39f59..5b3042661359eb903ec61745261a51e532dc5825 100644 (file)
@@ -16,6 +16,7 @@ func TestLogReopenLoadsTheSameMessages(t *testing.T) {
        require.NoError(t, err)
 
        var written []Message
+
        for _, kind := range []string{"user", "reply", "tool", "echo", "work", "note"} {
                message, err := log.Append(kind, kind+" text ✓")
                require.NoError(t, err)
@@ -35,6 +36,7 @@ func TestLogReopenLoadsTheSameMessages(t *testing.T) {
        }()
 
        require.Equal(t, len(written), log.Len())
+
        for _, message := range written {
                read, err := log.Message(message.ID)
                require.NoError(t, err)
@@ -62,7 +64,7 @@ func TestLogBuildsAMissingIndexAgain(t *testing.T) {
        require.NoError(t, log.Close())
 
        // A missing index, and an index that a crash cut in a record.
-       for _, cut := range []func(string) error{os.Remove, truncateToOneAndAHalf} {
+       for _, cut := range []func(string) error{os.Remove, logTruncateToOneAndAHalf} {
                require.NoError(t, cut(filepath.Join(root, "index", "main.idx")))
 
                log, err = openLog(t.Context(), root, clock.Now)
@@ -95,11 +97,11 @@ func TestLogWritesOneFilePerDay(t *testing.T) {
 
        first, err := os.ReadFile(filepath.Join(root, "main", "2026-01-01.jsonl"))
        require.NoError(t, err)
-       require.Equal(t, `{"i":0,"kind":"user","text":"first day","size":9,"date":"2026-01-01T12:00:00Z"}`+"\n", string(first))
+       require.JSONEq(t, `{"i":0,"kind":"user","text":"first day","size":9,"date":"2026-01-01T12:00:00Z"}`+"\n", string(first))
 
        second, err := os.ReadFile(filepath.Join(root, "main", "2026-01-02.jsonl"))
        require.NoError(t, err)
-       require.Equal(t, `{"i":1,"kind":"user","text":"second day","size":10,"date":"2026-01-02T12:00:00Z"}`+"\n", string(second))
+       require.JSONEq(t, `{"i":1,"kind":"user","text":"second day","size":10,"date":"2026-01-02T12:00:00Z"}`+"\n", string(second))
 }
 
 func TestLogAllowsOneWriter(t *testing.T) {
@@ -141,7 +143,60 @@ func TestLogRejectsAGapInTheIDs(t *testing.T) {
        require.ErrorContains(t, err, "expected message 0, found 1")
 }
 
-// truncateToOneAndAHalf cuts the index at path in its second record.
-func truncateToOneAndAHalf(path string) error {
+func TestLogCutsAnIncompleteLastLine(t *testing.T) {
+       root := t.TempDir()
+       clock := newTestClock()
+       log, err := openLog(t.Context(), root, clock.Now)
+       require.NoError(t, err)
+
+       _, err = log.Append("user", "whole")
+       require.NoError(t, err)
+       require.NoError(t, log.Close())
+
+       path := filepath.Join(root, "main", "2026-01-01.jsonl")
+       file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0)
+       require.NoError(t, err)
+
+       _, err = file.WriteString(`{"i":1,"kind":"user","te`)
+       require.NoError(t, err)
+       require.NoError(t, file.Close())
+
+       log, err = openLog(t.Context(), root, clock.Now)
+       require.NoError(t, err)
+       require.Equal(t, 1, log.Len())
+
+       message, err := log.Append("user", "after the cut")
+       require.NoError(t, err)
+       require.Equal(t, 1, message.ID)
+       require.NoError(t, log.Close())
+
+       log, err = openLog(t.Context(), root, clock.Now)
+       require.NoError(t, err)
+
+       defer func() {
+               require.NoError(t, log.Close())
+       }()
+
+       message, err = log.Message(1)
+       require.NoError(t, err)
+       require.Equal(t, "after the cut", message.Text)
+}
+
+func TestLogRejectsAnIncompleteLineBeforeTheLastDay(t *testing.T) {
+       root := t.TempDir()
+       require.NoError(t, os.MkdirAll(filepath.Join(root, "main"), 0o700))
+
+       first := `{"i":0,"kind":"user","text":"x","size":1,"date":"2026-01-01T12:00:00Z"}` + "\n" + `{"i":1,"kin`
+       second := `{"i":1,"kind":"user","text":"y","size":1,"date":"2026-01-02T12:00:00Z"}` + "\n"
+
+       require.NoError(t, os.WriteFile(filepath.Join(root, "main", "2026-01-01.jsonl"), []byte(first), 0o600))
+       require.NoError(t, os.WriteFile(filepath.Join(root, "main", "2026-01-02.jsonl"), []byte(second), 0o600))
+
+       _, err := openLog(t.Context(), root, newTestClock().Now)
+       require.ErrorContains(t, err, "ends in an incomplete line")
+}
+
+// logTruncateToOneAndAHalf cuts the index at path in its second record.
+func logTruncateToOneAndAHalf(path string) error {
        return os.Truncate(path, positionBytes+positionBytes/2)
 }