fixed processFrontmatter and added test
This commit is contained in:
parent
35c14f09c0
commit
af81617db5
7 changed files with 162 additions and 183 deletions
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue