package cms import ( "os" "path/filepath" "strings" "testing" ) func TestCreateSiteArticleAndBuild(t *testing.T) { tmp := t.TempDir() root, err := CreateSite(tmp, SiteOptions{Name: "my-capsule", Title: "My Capsule", Host: "gemini.example.org", Language: "en"}) if err != nil { t.Fatalf("CreateSite: %v", err) } if _, err := CreateArticle(root, ArticleOptions{Title: "Hello Gemini", Section: "journal", Tags: []string{"gemini"}}); err != nil { t.Fatalf("CreateArticle: %v", err) } if _, err := CreateSection(root, SectionOptions{Name: "journal", Title: "Journal"}); err != nil { t.Fatalf("CreateSection: %v", err) } report, err := Build(root) if err != nil { t.Fatalf("Build: %v", err) } if report.FilesWritten < 3 { t.Fatalf("expected at least 3 files written, got %d", report.FilesWritten) } assertFileContains(t, filepath.Join(root, "public/index.gmi"), "My Capsule") assertFileContains(t, filepath.Join(root, "public/journal/hello-gemini.gmi"), "# Hello Gemini") assertFileContains(t, filepath.Join(root, "public/journal/index.gmi"), "=> /journal/hello-gemini.gmi") } func TestMenuAndWidgetShortcodes(t *testing.T) { tmp := t.TempDir() root, err := CreateSite(tmp, SiteOptions{Name: "capsule", Title: "Capsule"}) if err != nil { t.Fatalf("CreateSite: %v", err) } if _, err := CreatePage(root, PageOptions{Slug: "about", Title: "About"}); err != nil { t.Fatalf("CreatePage: %v", err) } if err := AddMenuItem(root, MenuItemOptions{Menu: "top", Kind: "page", Target: "about", Label: "About"}); err != nil { t.Fatalf("AddMenuItem: %v", err) } if _, err := CreateArticle(root, ArticleOptions{Title: "First Post"}); err != nil { t.Fatalf("CreateArticle: %v", err) } if _, err := Build(root); err != nil { t.Fatalf("Build: %v", err) } assertFileContains(t, filepath.Join(root, "public/index.gmi"), "=> /about.gmi About") assertFileContains(t, filepath.Join(root, "public/index.gmi"), "=> /articles/first-post.gmi") } func TestAddMarkdownArticle(t *testing.T) { tmp := t.TempDir() root, err := CreateSite(tmp, SiteOptions{Name: "capsule", Title: "Capsule"}) if err != nil { t.Fatalf("CreateSite: %v", err) } source := filepath.Join(tmp, "article.md") if err := os.WriteFile(source, []byte("# Imported Article\n\n- one\n\n[Gemini](gemini://example.org)\n"), 0o644); err != nil { t.Fatalf("write source: %v", err) } doc, err := AddFile(root, AddOptions{ Path: source, Section: "journal", Tags: []string{"gemini"}, Draft: true, Menu: "top", }) if err != nil { t.Fatalf("AddFile: %v", err) } if doc.Type != "article" { t.Fatalf("expected article, got %q", doc.Type) } assertFileContains(t, doc.SourcePath, "section = \"journal\"") assertFileContains(t, doc.SourcePath, "tags = [\"gemini\"]") assertFileContains(t, doc.SourcePath, "draft = true") assertFileContains(t, doc.SourcePath, "* one") assertFileContains(t, doc.SourcePath, "=> gemini://example.org Gemini") } func TestAddDirectoryImportsContentFiles(t *testing.T) { tmp := t.TempDir() root, err := CreateSite(tmp, SiteOptions{Name: "capsule", Title: "Capsule"}) if err != nil { t.Fatalf("CreateSite: %v", err) } sourceDir := filepath.Join(tmp, "source") if err := os.MkdirAll(filepath.Join(sourceDir, "pages"), 0o755); err != nil { t.Fatalf("mkdir source: %v", err) } if err := os.WriteFile(filepath.Join(sourceDir, "post.md"), []byte("---\ntitle: YAML Title\ntags: gemini, cms\n---\n\nBody\n"), 0o644); err != nil { t.Fatalf("write post: %v", err) } if err := os.WriteFile(filepath.Join(sourceDir, "pages/about.gmi"), []byte("+++\ntitle = \"About\"\ntype = \"page\"\nslug = \"about\"\n+++\n\n# About\n"), 0o644); err != nil { t.Fatalf("write page: %v", err) } if err := os.WriteFile(filepath.Join(sourceDir, "ignore.txt"), []byte("ignore"), 0o644); err != nil { t.Fatalf("write ignored file: %v", err) } report, err := AddPath(root, AddOptions{Path: sourceDir, Section: "journal"}) if err != nil { t.Fatalf("AddPath: %v", err) } if len(report.Documents) != 2 { t.Fatalf("expected 2 imported documents, got %d", len(report.Documents)) } article := findDocument(t, report.Documents, "YAML Title") assertFileContains(t, article.SourcePath, "title = \"YAML Title\"") assertFileContains(t, article.SourcePath, "tags = [\"gemini\", \"cms\"]") assertFileContains(t, article.SourcePath, "section = \"journal\"") assertFileContains(t, filepath.Join(root, "content/pages/about.gmi"), "title = \"About\"") } func TestStatusReportCountsContentAndIssues(t *testing.T) { tmp := t.TempDir() root, err := CreateSite(tmp, SiteOptions{Name: "capsule", Title: "Capsule"}) if err != nil { t.Fatalf("CreateSite: %v", err) } if _, err := CreateArticle(root, ArticleOptions{Title: "Draft Post", Draft: true}); err != nil { t.Fatalf("CreateArticle: %v", err) } if _, err := Build(root); err != nil { t.Fatalf("Build: %v", err) } status, err := Status(root) if err != nil { t.Fatalf("Status: %v", err) } if status.Pages != 1 || status.Articles != 1 || status.Drafts != 1 { t.Fatalf("unexpected status counts: %#v", status) } if status.Health() != "OK" { t.Fatalf("expected OK health, got %s with %#v", status.Health(), status.Issues) } if status.PublicFiles == 0 { t.Fatalf("expected public files to be counted") } } func TestCheckReportsMalformedGemtextLink(t *testing.T) { tmp := t.TempDir() root, err := CreateSite(tmp, SiteOptions{Name: "capsule", Title: "Capsule"}) if err != nil { t.Fatalf("CreateSite: %v", err) } pagePath := filepath.Join(root, "content/pages/bad.gmi") if err := os.WriteFile(pagePath, []byte("+++\ntitle = \"Bad\"\ntype = \"page\"\nslug = \"bad\"\n+++\n\n=>\n"), 0o644); err != nil { t.Fatalf("write bad page: %v", err) } report, err := Check(root) if err != nil { t.Fatalf("Check: %v", err) } if !report.HasErrors() { t.Fatalf("expected check errors, got %#v", report.Issues) } } func assertFileContains(t *testing.T, path, want string) { t.Helper() data, err := os.ReadFile(path) if err != nil { t.Fatalf("read %s: %v", path, err) } if !strings.Contains(string(data), want) { t.Fatalf("%s does not contain %q\n%s", path, want, string(data)) } } func findDocument(t *testing.T, docs []Document, title string) Document { t.Helper() for _, doc := range docs { if doc.Title == title { return doc } } t.Fatalf("document %q not found in %#v", title, docs) return Document{} }