package main import ( "os" "path/filepath" "strings" "testing" ) func TestListMarkdownFiles(t *testing.T) { dir := t.TempDir() // Create test files os.WriteFile(filepath.Join(dir, "README.md"), []byte("# Hello"), 0644) os.WriteFile(filepath.Join(dir, "SPEC.md"), []byte("# Spec"), 0644) os.WriteFile(filepath.Join(dir, "main.go"), []byte("package main"), 0644) // Create docs subdirectory os.MkdirAll(filepath.Join(dir, "docs"), 0755) os.WriteFile(filepath.Join(dir, "docs", "ARCHITECTURE.md"), []byte("# Arch"), 0644) os.WriteFile(filepath.Join(dir, "docs", "notes.txt"), []byte("not md"), 0644) t.Run("lists only .md files", func(t *testing.T) { files, err := ListMarkdownFiles(dir) if err != nil { t.Fatalf("ListMarkdownFiles: %v", err) } if len(files) != 3 { t.Fatalf("got %d files, want 3", len(files)) } }) t.Run("includes docs subdir", func(t *testing.T) { files, err := ListMarkdownFiles(dir) if err != nil { t.Fatalf("ListMarkdownFiles: %v", err) } found := false for _, f := range files { if f.Name == "docs/ARCHITECTURE.md" { found = true break } } if !found { t.Error("should include docs/ARCHITECTURE.md") } }) t.Run("sorted", func(t *testing.T) { files, err := ListMarkdownFiles(dir) if err != nil { t.Fatalf("ListMarkdownFiles: %v", err) } for i := 1; i < len(files); i++ { if files[i].Name < files[i-1].Name { t.Errorf("not sorted: %q before %q", files[i-1].Name, files[i].Name) } } }) t.Run("nonexistent dir", func(t *testing.T) { _, err := ListMarkdownFiles("/nonexistent") if err == nil { t.Fatal("expected error") } }) } func TestReadFileContent(t *testing.T) { dir := t.TempDir() os.WriteFile(filepath.Join(dir, "test.md"), []byte("hello world"), 0644) t.Run("reads file", func(t *testing.T) { content, err := ReadFileContent(dir, "test.md") if err != nil { t.Fatalf("ReadFileContent: %v", err) } if content != "hello world" { t.Errorf("content = %q", content) } }) t.Run("path traversal blocked", func(t *testing.T) { _, err := ReadFileContent(dir, "../../etc/passwd") if err == nil { t.Fatal("expected error for path traversal") } if !strings.Contains(err.Error(), "path traversal") { t.Errorf("error = %v, want path traversal error", err) } }) t.Run("file not found", func(t *testing.T) { _, err := ReadFileContent(dir, "nonexistent.md") if err == nil { t.Fatal("expected error for nonexistent file") } }) } func TestRenderMarkdownFile(t *testing.T) { dir := t.TempDir() os.WriteFile(filepath.Join(dir, "test.md"), []byte("# Hello\n\nWorld"), 0644) t.Run("renders markdown", func(t *testing.T) { html, err := RenderMarkdownFile(dir, "test.md") if err != nil { t.Fatalf("RenderMarkdownFile: %v", err) } if !strings.Contains(html, "

Hello

") { t.Errorf("missing h1, got: %s", html) } if !strings.Contains(html, "

World

") { t.Errorf("missing p, got: %s", html) } }) t.Run("path traversal blocked", func(t *testing.T) { _, err := RenderMarkdownFile(dir, "../../../etc/passwd") if err == nil { t.Fatal("expected error for path traversal") } }) }