From cd9772387a0113ae8eee3ee48810fb926db0a8e2 Mon Sep 17 00:00:00 2001 From: Christof Laenzlinger <6319634+laenzlinger@users.noreply.github.com> Date: Sun, 26 Apr 2026 21:58:00 +0200 Subject: [PATCH 1/3] Add unit tests for nodetext, song, convert, gig.Section, setlist - nodetext.Extract: heading, paragraph, list item - song.New, song.RemoveCols - convert.PageCount: single page, two pages, empty - gig.Section.HeaderText: heading, empty, no heading - setlist.Render: table output with songs --- internal/gig/section_test.go | 37 +++++++++++++++++++ internal/html/pdf/convert_test.go | 42 ++++++++++++++++++++++ internal/nodetext/nodetext_test.go | 58 ++++++++++++++++++++++++++++++ internal/setlist/setlist_test.go | 50 ++++++++++++++++++++++++++ internal/song/song_test.go | 56 +++++++++++++++++++++++++++++ 5 files changed, 243 insertions(+) create mode 100644 internal/gig/section_test.go create mode 100644 internal/html/pdf/convert_test.go create mode 100644 internal/nodetext/nodetext_test.go create mode 100644 internal/setlist/setlist_test.go create mode 100644 internal/song/song_test.go diff --git a/internal/gig/section_test.go b/internal/gig/section_test.go new file mode 100644 index 0000000..3361bfe --- /dev/null +++ b/internal/gig/section_test.go @@ -0,0 +1,37 @@ +package gig + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSectionHeaderText(t *testing.T) { + tests := []struct { + name string + header string + want string + }{ + { + name: "heading", + header: "# Set 1\n", + want: "Set 1", + }, + { + name: "empty", + header: "", + want: "", + }, + { + name: "no heading", + header: "just text\n", + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Section{Header: []byte(tt.header)} + assert.Equal(t, tt.want, s.HeaderText()) + }) + } +} diff --git a/internal/html/pdf/convert_test.go b/internal/html/pdf/convert_test.go new file mode 100644 index 0000000..a6c5183 --- /dev/null +++ b/internal/html/pdf/convert_test.go @@ -0,0 +1,42 @@ +package convert_test + +import ( + "testing" + + convert "github.com/laenzlinger/setlist/internal/html/pdf" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPageCount(t *testing.T) { + tests := []struct { + name string + pdf string + want int + }{ + { + name: "single page", + pdf: "%PDF-1.4\n1 0 obj<>endobj\n2 0 obj<>endobj\n", + want: 1, + }, + { + name: "two pages", + pdf: "%PDF-1.4\n1 0 obj<>endobj\n" + + "2 0 obj<>endobj\n" + + "3 0 obj<>endobj\n", + want: 2, + }, + { + name: "empty", + pdf: "%PDF-1.4\n", + want: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := convert.PageCount([]byte(tt.pdf)) + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/nodetext/nodetext_test.go b/internal/nodetext/nodetext_test.go new file mode 100644 index 0000000..39a3c07 --- /dev/null +++ b/internal/nodetext/nodetext_test.go @@ -0,0 +1,58 @@ +package nodetext_test + +import ( + "testing" + + "github.com/laenzlinger/setlist/internal/nodetext" + "github.com/stretchr/testify/assert" + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/text" +) + +func firstChild(source []byte, kind ast.NodeKind) ast.Node { + doc := goldmark.New().Parser().Parse(text.NewReader(source)) + for n := doc.FirstChild(); n != nil; n = n.NextSibling() { + if n.Kind() == kind { + return n + } + } + return nil +} + +func TestExtract(t *testing.T) { + tests := []struct { + name string + source string + want string + kind ast.NodeKind + }{ + { + name: "heading", + source: "# Hello World", + kind: ast.KindHeading, + want: "Hello World", + }, + { + name: "paragraph", + source: "some text", + kind: ast.KindParagraph, + want: "some text", + }, + { + name: "list item", + source: "* item one", + kind: ast.KindList, + want: "item one", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + source := []byte(tt.source) + n := firstChild(source, tt.kind) + assert.NotNil(t, n) + got := nodetext.Extract(n, source) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/setlist/setlist_test.go b/internal/setlist/setlist_test.go new file mode 100644 index 0000000..4995fcd --- /dev/null +++ b/internal/setlist/setlist_test.go @@ -0,0 +1,50 @@ +package setlist_test + +import ( + "testing" + + "github.com/laenzlinger/setlist/internal/setlist" + "github.com/laenzlinger/setlist/internal/song" + "github.com/stretchr/testify/assert" + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/extension" + east "github.com/yuin/goldmark/extension/ast" + "github.com/yuin/goldmark/text" +) + +func songsFromTable(source []byte) (song.Header, []song.Song) { + md := goldmark.New(goldmark.WithExtensions(extension.GFM)) + doc := md.Parser().Parse(text.NewReader(source)) + table := doc.FirstChild() + var header song.Header + var songs []song.Song + for r := table.FirstChild(); r != nil; r = r.NextSibling() { + if r.Kind() == east.KindTableRow { + songs = append(songs, song.New(r, source)) + } + if r.Kind() == east.KindTableHeader { + header = song.NewHeader(&r) + } + } + return header, songs +} + +func TestRender(t *testing.T) { + source := []byte("| Title | Year |\n|---|---|\n| Song A | 2020 |\n| Song B | 2021 |\n") + md := goldmark.New(goldmark.WithExtensions(extension.GFM)) + header, songs := songsFromTable(source) + + sl := setlist.Setlist{ + TableHeader: header, + Markdown: md, + Source: source, + Sections: []setlist.Section{ + {Songs: songs}, + }, + } + + result := sl.Render() + assert.Contains(t, result, "Song A") + assert.Contains(t, result, "Song B") + assert.Contains(t, result, " Date: Fri, 15 May 2026 12:02:07 +0200 Subject: [PATCH 2/3] Center song title in cheat sheet --- internal/html/template/songsheet.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/html/template/songsheet.html b/internal/html/template/songsheet.html index 78b0e2f..b26c101 100644 --- a/internal/html/template/songsheet.html +++ b/internal/html/template/songsheet.html @@ -26,7 +26,7 @@ } h1 { font-size: 14px; - text-align: right; + text-align: center; } article { From 33a6025952b6e432bff34eb96a9631b3cd907e08 Mon Sep 17 00:00:00 2001 From: Christof Laenzlinger <6319634+laenzlinger@users.noreply.github.com> Date: Fri, 15 May 2026 12:24:11 +0200 Subject: [PATCH 3/3] Reduce PDF margins and increase font size to 36px --- internal/html/pdf/convert.go | 4 ++++ internal/html/template/songsheet.html | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/internal/html/pdf/convert.go b/internal/html/pdf/convert.go index 58aa54c..c00efdf 100644 --- a/internal/html/pdf/convert.go +++ b/internal/html/pdf/convert.go @@ -83,6 +83,10 @@ func printToPDF(urlstr string, res *[]byte) chromedp.Tasks { WithPrintBackground(true). WithPaperHeight(A4Height). WithPaperWidth(A4Width). + WithMarginTop(0.2). + WithMarginBottom(0.2). + WithMarginLeft(0.2). + WithMarginRight(0.2). WithLandscape(config.Landscape()). Do(ctx) if err != nil { diff --git a/internal/html/template/songsheet.html b/internal/html/template/songsheet.html index b26c101..301be37 100644 --- a/internal/html/template/songsheet.html +++ b/internal/html/template/songsheet.html @@ -9,7 +9,7 @@ padding: 0; } body { - font-size: 28px; + font-size: 36px; font-family: Tahoma, Geneva, sans-serif; font-weight: bold; } @@ -17,7 +17,7 @@ border: 1px solid; border-color: DarkGray; border-collapse: collapse; - font-size: 28px; + font-size: 36px; font-family: Tahoma, Geneva, sans-serif; font-weight: bold; } @@ -28,6 +28,9 @@ font-size: 14px; text-align: center; } +pre { + margin: 0.2em 0; +} article { }