All checks were successful
Tests / unit-tests (push) Successful in 51s
- Login sa session cookie autentifikacijom - Lista projekata iz filesystem-a - Chat sa Claude CLI preko WebSocket-a - Streaming NDJSON parsiranje iz CLI stdout-a - Sesija zivi nezavisno od browsera (reconnect replay) - Sidebar sa .md fajlovima i markdown renderovanjem - Dark tema, htmx + Go templates - 47 unit testova Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
126 lines
3.1 KiB
Go
126 lines
3.1 KiB
Go
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, "<h1>Hello</h1>") {
|
|
t.Errorf("missing h1, got: %s", html)
|
|
}
|
|
if !strings.Contains(html, "<p>World</p>") {
|
|
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")
|
|
}
|
|
})
|
|
}
|