ajhahn.de
← eeco
Go 135 lines
package notes

import (
	"os"
	"path/filepath"
	"testing"
	"time"
)

func TestAdd_WritesFilenameAndVerbatimBody(t *testing.T) {
	dir := t.TempDir()
	now := time.Date(2026, 5, 22, 14, 3, 0, 0, time.UTC)
	body := "check round-robin fairness in queue promotion"

	path, err := Add(dir, body, now)
	if err != nil {
		t.Fatal(err)
	}
	wantName := "2026-05-22-140300-check-round-robin-fairness-in.md"
	if got := filepath.Base(path); got != wantName {
		t.Errorf("filename = %q, want %q", got, wantName)
	}
	b, err := os.ReadFile(path)
	if err != nil {
		t.Fatal(err)
	}
	if string(b) != body {
		t.Errorf("body = %q, want verbatim %q", string(b), body)
	}
}

func TestAdd_CreatesDirIfMissing(t *testing.T) {
	dir := filepath.Join(t.TempDir(), "notes")
	if _, err := Add(dir, "scribble", time.Now()); err != nil {
		t.Fatal(err)
	}
	if info, err := os.Stat(dir); err != nil || !info.IsDir() {
		t.Errorf("notes dir not created: %v", err)
	}
}

func TestAdd_RejectsEmptyText(t *testing.T) {
	dir := t.TempDir()
	for _, in := range []string{"", "   ", "\t\n"} {
		if _, err := Add(dir, in, time.Now()); err == nil {
			t.Errorf("Add(%q) = nil error, want rejection", in)
		}
	}
}

func TestList_NewestFirst(t *testing.T) {
	dir := t.TempDir()
	older := time.Date(2026, 5, 21, 9, 11, 0, 0, time.UTC)
	newer := time.Date(2026, 5, 22, 14, 3, 0, 0, time.UTC)
	if _, err := Add(dir, "older note", older); err != nil {
		t.Fatal(err)
	}
	if _, err := Add(dir, "newer note", newer); err != nil {
		t.Fatal(err)
	}
	got, err := List(dir)
	if err != nil {
		t.Fatal(err)
	}
	if len(got) != 2 {
		t.Fatalf("len = %d, want 2", len(got))
	}
	if got[0].Summary != "newer note" || got[1].Summary != "older note" {
		t.Errorf("order = [%q, %q], want newest first", got[0].Summary, got[1].Summary)
	}
	if !got[0].When.Equal(newer) {
		t.Errorf("When = %v, want %v parsed from filename", got[0].When, newer)
	}
}

func TestList_MissingDirEmpty(t *testing.T) {
	got, err := List(filepath.Join(t.TempDir(), "absent"))
	if err != nil {
		t.Fatalf("err = %v, want nil for missing dir", err)
	}
	if len(got) != 0 {
		t.Errorf("len = %d, want 0", len(got))
	}
}

func TestList_SummaryIsFirstNonBlankLine(t *testing.T) {
	dir := t.TempDir()
	if _, err := Add(dir, "\n\n   first real line\nsecond line", time.Now()); err != nil {
		t.Fatal(err)
	}
	got, err := List(dir)
	if err != nil {
		t.Fatal(err)
	}
	if len(got) != 1 || got[0].Summary != "first real line" {
		t.Errorf("summary = %q, want %q", got[0].Summary, "first real line")
	}
}

func TestList_IgnoresNonMarkdown(t *testing.T) {
	dir := t.TempDir()
	if _, err := Add(dir, "real note", time.Now()); err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(filepath.Join(dir, "stray.txt"), []byte("x"), 0o644); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(filepath.Join(dir, "sub"), 0o755); err != nil {
		t.Fatal(err)
	}
	got, err := List(dir)
	if err != nil {
		t.Fatal(err)
	}
	if len(got) != 1 {
		t.Errorf("len = %d, want 1 (only the .md note)", len(got))
	}
}

func TestSlug(t *testing.T) {
	cases := []struct{ in, want string }{
		{"check round-robin fairness in queue promotion", "check-round-robin-fairness-in"},
		{"Hello, World!", "hello-world"},
		{"!!!", "note"},
		{"", "note"},
		{"   ", "note"},
		{"a", "a"},
	}
	for _, c := range cases {
		if got := slug(c.in); got != c.want {
			t.Errorf("slug(%q) = %q, want %q", c.in, got, c.want)
		}
	}
}