fixed processFrontmatter and added test

This commit is contained in:
Daniel Fichtinger 2025-01-01 23:55:16 -05:00
parent 35c14f09c0
commit af81617db5
No known key found for this signature in database
GPG key ID: D1B0947B25420214
7 changed files with 162 additions and 183 deletions

View file

@ -51,8 +51,8 @@ func processWithYaml(f []byte) (Metadata, []byte, error) {
}
func processFrontmatter(p string) (Metadata, error) {
// read only the first three lines
f, err := util.ReadNLines(p, 3)
// TODO: Also save index of the line where the actual document starts?
f, err := util.ReadFile(p)
if err != nil {
return nil, err
}
@ -60,11 +60,13 @@ func processFrontmatter(p string) (Metadata, error) {
trimmed := bytes.TrimSpace(f)
normalized := strings.ReplaceAll(string(trimmed), "\r\n", "\n")
if !strings.HasPrefix(normalized, ("---\n")) {
// No valid yaml, so return the entire content
// No frontmatter, return nil -- handled by caller
return nil, nil
}
// Separate YAML from rest of document
split := strings.SplitN(normalized, "---\n", 3)
// __AUTO_GENERATED_PRINT_VAR_START__
fmt.Println(fmt.Sprintf("processFrontmatter split: %v", split)) // __AUTO_GENERATED_PRINT_VAR_END__
if len(split) < 3 {
return nil, fmt.Errorf("Invalid frontmatter format.")
}
@ -127,7 +129,7 @@ func buildPageData(m Metadata, in string, out string, settings *Settings) *PageD
return p
}
func ConvertFile(in string, out string, settings *Settings) error {
func BuildHtmlFile(in string, out string, settings *Settings) error {
mdPre, err := util.ReadFile(in)
if err != nil {
return err

View file

@ -1,37 +1,64 @@
// FILE: internal/builder/build_page_test.go
package builder
import "testing"
import (
"os"
"testing"
)
func Test_processWithYaml(t *testing.T) {
tests := []struct {
name string // description of this test case
// Named input parameters for target function.
f []byte
want Metadata
want2 []byte
wantErr bool
}{
// TODO: Add test cases.
func TestProcessFrontmatter(t *testing.T) {
// Create a temporary file with valid frontmatter
validContent := `---
title: "Test Title"
description: "Test Description"
---
This is the body of the document.`
tmpfile, err := os.CreateTemp("", "testfile")
if err != nil {
t.Fatal(err)
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got2, gotErr := processWithYaml(tt.f)
if gotErr != nil {
if !tt.wantErr {
t.Errorf("processWithYaml() failed: %v", gotErr)
}
return
}
if tt.wantErr {
t.Fatal("processWithYaml() succeeded unexpectedly")
}
// TODO: update the condition below to compare got with tt.want.
if true {
t.Errorf("processWithYaml() = %v, want %v", got, tt.want)
}
if true {
t.Errorf("processWithYaml() = %v, want %v", got2, tt.want2)
}
})
defer os.Remove(tmpfile.Name()) // clean up
if _, err := tmpfile.Write([]byte(validContent)); err != nil {
t.Fatal(err)
}
if err := tmpfile.Close(); err != nil {
t.Fatal(err)
}
// Test the processFrontmatter function with valid frontmatter
meta, err := processFrontmatter(tmpfile.Name())
if err != nil {
t.Fatalf("processFrontmatter failed: %v", err)
}
if meta["title"] != "Test Title" || meta["description"] != "Test Description" {
t.Errorf("Expected title 'Test Title' and description 'Test Description', got title '%s' and description '%s'", meta["title"], meta["description"])
}
// Create a temporary file with invalid frontmatter
invalidContent := `---
title: "Test Title"
description: "Test Description"
This is the body of the document.`
tmpfile, err = os.CreateTemp("", "testfile")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tmpfile.Name()) // clean up
if _, err := tmpfile.Write([]byte(invalidContent)); err != nil {
t.Fatal(err)
}
if err := tmpfile.Close(); err != nil {
t.Fatal(err)
}
// Test the processFrontmatter function with invalid frontmatter
_, err = processFrontmatter(tmpfile.Name())
if err == nil {
t.Fatalf("Expected error for invalid frontmatter, got nil")
}
}

View file

@ -1,122 +0,0 @@
package builder_test
import (
"os"
"path/filepath"
"testing"
"github.com/ficcdaf/zona/internal/builder"
"github.com/ficcdaf/zona/internal/util"
)
func TestMdToHTML(t *testing.T) {
md := []byte("# Hello World\n\nThis is a test.")
expectedHTML := "<h1 id=\"hello-world\">Hello World</h1>\n<p>This is a test.</p>\n"
nExpectedHTML := util.NormalizeContent(expectedHTML)
html, err := builder.MdToHTML(md)
nHtml := util.NormalizeContent(string(html))
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if nHtml != nExpectedHTML {
t.Errorf("Expected:\n%s\nGot:\n%s", expectedHTML, html)
}
}
func TestWriteFile(t *testing.T) {
path := filepath.Join(t.TempDir(), "test.txt")
content := []byte("Hello, World!")
err := builder.WriteFile(content, path)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
// Verify file content
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("Error reading file: %v", err)
}
if string(data) != string(content) {
t.Errorf("Expected:\n%s\nGot:\n%s", content, data)
}
}
func TestReadFile(t *testing.T) {
path := filepath.Join(t.TempDir(), "test.txt")
content := []byte("Hello, World!")
err := os.WriteFile(path, content, 0644)
if err != nil {
t.Fatalf("Error writing file: %v", err)
}
data, err := builder.ReadFile(path)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if string(data) != string(content) {
t.Errorf("Expected:\n%s\nGot:\n%s", content, data)
}
}
func TestCopyFile(t *testing.T) {
src := filepath.Join(t.TempDir(), "source.txt")
dst := filepath.Join(t.TempDir(), "dest.txt")
content := []byte("File content for testing.")
err := os.WriteFile(src, content, 0644)
if err != nil {
t.Fatalf("Error writing source file: %v", err)
}
err = builder.CopyFile(src, dst)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
// Verify destination file content
data, err := os.ReadFile(dst)
if err != nil {
t.Fatalf("Error reading destination file: %v", err)
}
if string(data) != string(content) {
t.Errorf("Expected:\n%s\nGot:\n%s", content, data)
}
}
func TestConvertFile(t *testing.T) {
src := filepath.Join(t.TempDir(), "test.md")
dst := filepath.Join(t.TempDir(), "test.html")
mdContent := []byte("# Test Title\n\nThis is Markdown content.")
nExpectedHTML := util.NormalizeContent("<h1 id=\"test-title\">Test Title</h1>\n<p>This is Markdown content.</p>\n")
err := os.WriteFile(src, mdContent, 0644)
if err != nil {
t.Fatalf("Error writing source Markdown file: %v", err)
}
err = builder.ConvertFile(src, dst)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
// Verify destination HTML content
data, err := os.ReadFile(dst)
if err != nil {
t.Fatalf("Error reading HTML file: %v", err)
}
if util.NormalizeContent(string(data)) != nExpectedHTML {
t.Errorf("Expected:\n%s\nGot:\n%s", nExpectedHTML, data)
}
}
func TestChangeExtension(t *testing.T) {
input := "test.md"
output := builder.ChangeExtension(input, ".html")
expected := "test.html"
if output != expected {
t.Errorf("Expected %s, got %s", expected, output)
}
}

View file

@ -8,22 +8,39 @@ import (
)
type ProcessMemory struct {
// Pages holds all page data that may be
// Files holds all page data that may be
// needed while building *other* pages.
Pages []*Page
Files []*File
// Queue is a FIFO queue of Pages indexes to be built.
// queue should be constructed after all the Pages have been parsed
Queue []int
// Posts is an array of pointers to post pages
Posts []*Page
// This list is ONLY referenced for generating
// the archive, NOT by the build process!
Posts []*File
}
type Page struct {
Data *PageData
Ext string
InPath string
OutPath string
Copy bool
type File struct {
Data *PageData
Ext string
InPath string
OutPath string
ShouldCopy bool
HasFrontmatter bool
}
// NewProcessMemory initializes an empty
// process memory structure
func NewProcessMemory() *ProcessMemory {
f := make([]*File, 0)
q := make([]int, 0)
p := make([]*File, 0)
pm := &ProcessMemory{
f,
q,
p,
}
return pm
}
// processFile processes the metadata only
@ -38,36 +55,44 @@ func processFile(inPath string, entry fs.DirEntry, err error, outRoot string, se
if !entry.IsDir() {
ext = filepath.Ext(inPath)
outPath = util.ReplaceRoot(inPath, outRoot)
// NOTE: This could be an if statement, but keeping
// the switch makes it easy to extend the logic here later
switch ext {
case ".md":
// fmt.Println("Processing markdown...")
toProcess = true
outPath = util.ChangeExtension(outPath, ".html")
// If it's not a file we need to process,
// we simply copy it to the destination path.
default:
toProcess = false
}
}
page := &Page{
nil,
ext,
inPath,
outPath,
!toProcess,
}
var pd *PageData
hasFrontmatter := false
if toProcess {
// process its frontmatter here
m, err := processFrontmatter(inPath)
if err != nil {
return err
}
pd := buildPageData(m, inPath, outPath, settings)
if pd.Type == "post" {
pm.Posts = append(pm.Posts, page)
if m != nil {
hasFrontmatter = true
}
page.Data = pd
pd = buildPageData(m, inPath, outPath, settings)
} else {
pd = nil
}
pm.Pages = append(pm.Pages, page)
file := &File{
pd,
ext,
inPath,
outPath,
!toProcess,
hasFrontmatter,
}
if pd != nil && pd.Type == "post" {
pm.Posts = append(pm.Posts, file)
}
pm.Files = append(pm.Files, file)
return nil
}

View file

@ -23,7 +23,7 @@ func buildFile(inPath string, entry fs.DirEntry, err error, outRoot string, sett
if err := util.CreateParents(outPath); err != nil {
return err
}
if err := ConvertFile(inPath, outPath, settings); err != nil {
if err := BuildHtmlFile(inPath, outPath, settings); err != nil {
return errors.Join(errors.New("Error processing file "+inPath), err)
} else {
return nil
@ -52,3 +52,12 @@ func Traverse(root string, outRoot string, settings *Settings) error {
err := filepath.WalkDir(root, walkFunc)
return err
}
func ProcessTraverse(root string, outRoot string, settings *Settings) error {
pm := NewProcessMemory()
walkFunc := func(path string, entry fs.DirEntry, err error) error {
return processFile(path, entry, err, outRoot, settings, pm)
}
err := filepath.WalkDir(root, walkFunc)
return err
}