denotesrv/pkg/encoding/frontmatter/frontmatter_test.go

389 lines
9.0 KiB
Go

package frontmatter
import (
"denotesrv/pkg/metadata"
"slices"
"strings"
"testing"
)
// TestFormatTags validates tag formatting for different file types
// Maps to dt-denote--format-front-matter from original tests
func TestFormatTags(t *testing.T) {
tests := []struct {
name string
tags []string
fileType metadata.FileType
want string
}{
{
name: "org with multiple tags",
tags: []string{"tag1", "tag2"},
fileType: metadata.FileTypeOrg,
want: ":tag1:tag2:",
},
{
name: "org with single tag",
tags: []string{"single"},
fileType: metadata.FileTypeOrg,
want: ":single:",
},
{
name: "org with empty tags",
tags: []string{},
fileType: metadata.FileTypeOrg,
want: "",
},
{
name: "md-yaml with multiple tags",
tags: []string{"tag1", "tag2"},
fileType: metadata.FileTypeMdYaml,
want: "[tag1, tag2]",
},
{
name: "md-yaml with single tag",
tags: []string{"single"},
fileType: metadata.FileTypeMdYaml,
want: "[single]",
},
{
name: "md-yaml with empty tags",
tags: []string{},
fileType: metadata.FileTypeMdYaml,
want: "",
},
{
name: "md-toml with multiple tags",
tags: []string{"tag1", "tag2"},
fileType: metadata.FileTypeMdToml,
want: "[tag1, tag2]",
},
{
name: "md-toml with empty tags",
tags: []string{},
fileType: metadata.FileTypeMdToml,
want: "",
},
{
name: "txt with multiple tags",
tags: []string{"tag1", "tag2"},
fileType: metadata.FileTypeTxt,
want: "tag1 tag2",
},
{
name: "txt with single tag",
tags: []string{"single"},
fileType: metadata.FileTypeTxt,
want: "single",
},
{
name: "txt with empty tags",
tags: []string{},
fileType: metadata.FileTypeTxt,
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := formatTags(tt.tags, tt.fileType)
if got != tt.want {
t.Errorf("formatTags(%v, %q) = %q, want %q", tt.tags, tt.fileType, got, tt.want)
}
})
}
}
// TestFrontMatterBytes validates front matter formatting for all file types
// Maps to dt-denote--format-front-matter from original tests
func TestFrontMatterBytes(t *testing.T) {
identifier := "20240101T120000"
title := "Test Note"
tags := []string{"tag1", "tag2"}
tests := []struct {
name string
fileType metadata.FileType
wantContains []string
wantNotContains []string
}{
{
name: "org format",
fileType: metadata.FileTypeOrg,
wantContains: []string{
"#+title: Test Note",
"#+filetags: :tag1:tag2:",
"#+identifier: 20240101T120000",
"#+date:",
},
},
{
name: "md-yaml format",
fileType: metadata.FileTypeMdYaml,
wantContains: []string{
"---",
"title: Test Note",
"tags: [tag1, tag2]",
"identifier: 20240101T120000",
"date:",
},
},
{
name: "md-toml format",
fileType: metadata.FileTypeMdToml,
wantContains: []string{
"+++",
"title = Test Note",
"tags = [tag1, tag2]",
"identifier = 20240101T120000",
"date =",
},
},
{
name: "txt format",
fileType: metadata.FileTypeTxt,
wantContains: []string{
"title: Test Note",
"tags: tag1 tag2",
"identifier: 20240101T120000",
"date:",
"---------------------------",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fm := metadata.NewFrontMatter(title, "", tags, identifier)
got := string(Marshal(fm, tt.fileType))
for _, want := range tt.wantContains {
if !strings.Contains(got, want) {
t.Errorf("FrontMatter.Bytes() missing %q\nGot:\n%s", want, got)
}
}
for _, notWant := range tt.wantNotContains {
if strings.Contains(got, notWant) {
t.Errorf("FrontMatter.Bytes() should not contain %q\nGot:\n%s", notWant, got)
}
}
})
}
}
// TestFrontMatterBytesEmptyTags validates front matter formatting with no tags
func TestFrontMatterBytesEmptyTags(t *testing.T) {
identifier := "20240101T120000"
title := "Test Note"
tags := []string{}
tests := []struct {
name string
fileType metadata.FileType
wantTags string
}{
{
name: "org with empty tags",
fileType: metadata.FileTypeOrg,
wantTags: "#+filetags:",
},
{
name: "md-yaml with empty tags",
fileType: metadata.FileTypeMdYaml,
wantTags: "tags:",
},
{
name: "md-toml with empty tags",
fileType: metadata.FileTypeMdToml,
wantTags: "tags =",
},
{
name: "txt with empty tags",
fileType: metadata.FileTypeTxt,
wantTags: "tags:",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fm := metadata.NewFrontMatter(title, "", tags, identifier)
got := string(Marshal(fm, tt.fileType))
if !strings.Contains(got, tt.wantTags) {
t.Errorf("FrontMatter.Bytes() with empty tags should contain %q\nGot:\n%s",
tt.wantTags, got)
}
})
}
}
// TestUnmarshal validates front matter parsing from content
func TestUnmarshal(t *testing.T) {
tests := []struct {
name string
content string
ext string
wantTitle string
wantTags []string
wantIdentifier string
wantFileType metadata.FileType
}{
{
name: "org format",
content: `#+title: Org Note
#+date: [2024-01-01 Mon 12:00]
#+filetags: :work:emacs:
#+identifier: 20240101T120000
* First Heading`,
ext: ".org",
wantTitle: "Org Note",
wantTags: []string{"work", "emacs"},
wantIdentifier: "20240101T120000",
wantFileType: metadata.FileTypeOrg,
},
{
name: "org with single tag",
content: `#+title: Single Tag
#+filetags: :single:
#+identifier: 20240101T120000`,
ext: ".org",
wantTitle: "Single Tag",
wantTags: []string{"single"},
wantIdentifier: "20240101T120000",
wantFileType: metadata.FileTypeOrg,
},
{
name: "org without tags",
content: `#+title: No Tags
#+identifier: 20240101T120000`,
ext: ".org",
wantTitle: "No Tags",
wantTags: nil,
wantIdentifier: "20240101T120000",
wantFileType: metadata.FileTypeOrg,
},
{
name: "markdown yaml",
content: `---
title: Markdown Note
date: 2024-01-01
tags: [work, personal]
identifier: 20240101T120000
---
# Content`,
ext: ".md",
wantTitle: "Markdown Note",
wantTags: []string{"work", "personal"},
wantIdentifier: "20240101T120000",
wantFileType: metadata.FileTypeMdYaml,
},
{
name: "markdown yaml with quoted title",
content: `---
title: "Quoted Title"
tags: [test]
identifier: 20240101T120000
---`,
ext: ".md",
wantTitle: "Quoted Title",
wantTags: []string{"test"},
wantIdentifier: "20240101T120000",
wantFileType: metadata.FileTypeMdYaml,
},
{
name: "markdown toml",
content: `+++
title = TOML Note
date = 2024-01-01
tags = [rust, go]
identifier = 20240101T120000
+++
Content`,
ext: ".md",
wantTitle: "TOML Note",
wantTags: []string{"rust", "go"},
wantIdentifier: "20240101T120000",
wantFileType: metadata.FileTypeMdToml,
},
{
name: "txt format",
content: `title: Plain Text
date: 2024-01-01
tags: simple plain
identifier: 20240101T120000
---------------------------
Content here`,
ext: ".txt",
wantTitle: "Plain Text",
wantTags: []string{"simple", "plain"},
wantIdentifier: "20240101T120000",
wantFileType: metadata.FileTypeTxt,
},
{
name: "txt without tags",
content: `title: No Tags Text
identifier: 20240101T120000
---------------------------`,
ext: ".txt",
wantTitle: "No Tags Text",
wantTags: nil,
wantIdentifier: "20240101T120000",
wantFileType: metadata.FileTypeTxt,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, fileType, err := Unmarshal([]byte(tt.content), tt.ext)
if err != nil {
t.Fatalf("Unmarshal() error = %v", err)
}
if got.Title != tt.wantTitle {
t.Errorf("Unmarshal().Title = %q, want %q", got.Title, tt.wantTitle)
}
if !slices.Equal(got.Tags, tt.wantTags) {
t.Errorf("Unmarshal().Tags = %v, want %v", got.Tags, tt.wantTags)
}
if got.Identifier != tt.wantIdentifier {
t.Errorf("Unmarshal().Identifier = %q, want %q", got.Identifier, tt.wantIdentifier)
}
if fileType != tt.wantFileType {
t.Errorf("Unmarshal() fileType = %q, want %q", fileType, tt.wantFileType)
}
})
}
}
// TestUnmarshalMissingFields validates handling of missing fields
func TestUnmarshalMissingFields(t *testing.T) {
content := `---
date: 2024-01-01
---`
got, _, err := Unmarshal([]byte(content), ".md")
if err != nil {
t.Fatalf("Unmarshal() error = %v", err)
}
// Should have empty values, not error
if got.Title != "" {
t.Errorf("Unmarshal().Title = %q, want empty", got.Title)
}
if got.Identifier != "" {
t.Errorf("Unmarshal().Identifier = %q, want empty", got.Identifier)
}
if got.Tags != nil {
t.Errorf("Unmarshal().Tags = %v, want nil", got.Tags)
}
}