libs/hope-card-formatter-test.lua

214 lines

1#!/usr/bin/env luajit
2-- Test suite for hope-card-formatter.lua
3-- Tests the conversion of poems to words-pdf format
4
5local DIR = "/mnt/mtwo/programming/ai-stuff/neocities-modernization"
6package.path = DIR .. "/libs/?.lua;" .. package.path
7
8local formatter = require("hope-card-formatter")
9
10-- Test counter
11local tests_run = 0
12local tests_passed = 0
13local tests_failed = 0
14
15-- {{{ test helper functions
16local function assert_equal(actual, expected, test_name)
17 tests_run = tests_run + 1
18 if actual == expected then
19 tests_passed = tests_passed + 1
20 print(string.format("✅ PASS: %s", test_name))
21 return true
22 else
23 tests_failed = tests_failed + 1
24 print(string.format("❌ FAIL: %s", test_name))
25 print(string.format(" Expected: %q", expected))
26 print(string.format(" Got: %q", actual))
27 return false
28 end
29end
30
31local function assert_true(condition, test_name)
32 tests_run = tests_run + 1
33 if condition then
34 tests_passed = tests_passed + 1
35 print(string.format("✅ PASS: %s", test_name))
36 return true
37 else
38 tests_failed = tests_failed + 1
39 print(string.format("❌ FAIL: %s", test_name))
40 return false
41 end
42end
43
44local function assert_contains(haystack, needle, test_name)
45 tests_run = tests_run + 1
46 if type(haystack) == "string" and haystack:find(needle, 1, true) then
47 tests_passed = tests_passed + 1
48 print(string.format("✅ PASS: %s", test_name))
49 return true
50 else
51 tests_failed = tests_failed + 1
52 print(string.format("❌ FAIL: %s", test_name))
53 print(string.format(" Expected to find: %q", needle))
54 print(string.format(" In: %q", tostring(haystack)))
55 return false
56 end
57end
58-- }}}
59
60print("═══════════════════════════════════════════")
61print(" Hope Card Formatter Test Suite")
62print("═══════════════════════════════════════════")
63print("")
64
65-- Test 1: DASH_SEPARATOR constant
66print("Test Group: Constants")
67assert_equal(formatter.DASH_SEPARATOR, string.rep("-", 80),
68 "DASH_SEPARATOR is exactly 80 dashes")
69print("")
70
71-- Test 2: wrap_line with short line
72print("Test Group: Line Wrapping")
73local short_line = "This is a short line"
74local wrapped_short = formatter.wrap_line(short_line, 80)
75assert_equal(#wrapped_short, 1, "Short line returns single element")
76assert_equal(wrapped_short[1], short_line, "Short line unchanged")
77
78-- Test 3: wrap_line with long line
79local long_line = "This is a very long line that definitely exceeds eighty characters and needs to be wrapped properly at word boundaries"
80local wrapped_long = formatter.wrap_line(long_line, 80)
81assert_true(#wrapped_long > 1, "Long line gets wrapped into multiple lines")
82for i, line in ipairs(wrapped_long) do
83 assert_true(#line <= 80, string.format("Wrapped line %d is <= 80 chars", i))
84end
85
86-- Test 4: wrap_line with exact 80 characters
87local exact_line = string.rep("x", 80)
88local wrapped_exact = formatter.wrap_line(exact_line, 80)
89assert_equal(#wrapped_exact, 1, "Exactly 80 chars stays on one line")
90
91-- Test 5: wrap_line with 81 characters (single word)
92local over_line = string.rep("x", 81)
93local wrapped_over = formatter.wrap_line(over_line, 80)
94assert_true(#wrapped_over >= 2, "81 char word gets hard-broken")
95print("")
96
97-- Test 6: format_poem_for_wordspdf with simple poem
98print("Test Group: Poem Formatting")
99local simple_poem = {
100 id = 1,
101 content = "Line one\nLine two\nLine three"
102}
103local formatted_simple = formatter.format_poem_for_wordspdf(simple_poem)
104assert_contains(formatted_simple, "Line one", "Contains first line")
105assert_contains(formatted_simple, "Line two", "Contains second line")
106assert_contains(formatted_simple, "Line three", "Contains third line")
107
108-- Test 7: format_poem_for_wordspdf with lines array
109local array_poem = {
110 id = 2,
111 lines = {"First", "Second", "Third"}
112}
113local formatted_array = formatter.format_poem_for_wordspdf(array_poem)
114assert_contains(formatted_array, "First", "Array poem contains first line")
115assert_contains(formatted_array, "Second", "Array poem contains second line")
116
117-- Test 8: format_poem_for_wordspdf with long line
118local long_poem = {
119 id = 3,
120 content = "This is a line that definitely exceeds eighty characters in length and should be wrapped automatically"
121}
122local formatted_long = formatter.format_poem_for_wordspdf(long_poem)
123for line in formatted_long:gmatch("[^\n]+") do
124 assert_true(#line <= 80, "Long line poem wraps all lines to <= 80 chars")
125end
126print("")
127
128-- Test 9: format_poems_to_string with multiple poems
129print("Test Group: Multiple Poem Formatting")
130local test_poems = {
131 {id = 1, content = "Poem one\nFirst poem content"},
132 {id = 2, content = "Poem two\nSecond poem content"},
133 {id = 3, content = "Poem three\nThird poem content"}
134}
135local formatted_multiple = formatter.format_poems_to_string(test_poems)
136
137assert_contains(formatted_multiple, "Poem one", "Contains first poem")
138assert_contains(formatted_multiple, "Poem two", "Contains second poem")
139assert_contains(formatted_multiple, "Poem three", "Contains third poem")
140
141-- Count separator occurrences (should be 3 - one after each poem)
142local separator_count = 0
143for line in formatted_multiple:gmatch("[^\n]+") do
144 if line == formatter.DASH_SEPARATOR then
145 separator_count = separator_count + 1
146 end
147end
148assert_equal(separator_count, 3, "Has correct number of separators (3)")
149print("")
150
151-- Test 10: format_poems_to_string with empty array
152print("Test Group: Edge Cases")
153local empty_formatted = formatter.format_poems_to_string({})
154assert_equal(empty_formatted, "", "Empty poem array returns empty string")
155
156-- Test 11: format_poem_for_wordspdf with nil
157local nil_formatted = formatter.format_poem_for_wordspdf(nil)
158assert_equal(nil_formatted, "", "Nil poem returns empty string")
159
160-- Test 12: generate_hope_card_filename
161local filename = formatter.generate_hope_card_filename(123, 200)
162assert_equal(filename, "hope-card-0123-200poems.txt", "Generates correct filename")
163print("")
164
165-- Test 13: write_to_file and verify content
166print("Test Group: File Operations")
167local temp_file = DIR .. "/tmp/hope-card-formatter-test.txt"
168local test_write_poems = {
169 {id = 1, content = "Test poem for file writing"},
170 {id = 2, content = "Second test poem"}
171}
172
173local success, err = formatter.write_to_file(test_write_poems, temp_file)
174assert_true(success, "File write succeeds")
175assert_equal(err, nil, "No error message on success")
176
177-- Verify file contents
178if success then
179 local file = io.open(temp_file, "r")
180 if file then
181 local content = file:read("*all")
182 file:close()
183
184 assert_contains(content, "Test poem for file writing", "File contains first poem")
185 assert_contains(content, "Second test poem", "File contains second poem")
186 assert_contains(content, formatter.DASH_SEPARATOR, "File contains separator")
187
188 -- Clean up
189 os.remove(temp_file)
190 end
191end
192print("")
193
194-- Test 14: write_to_file with invalid path
195local fail_success, fail_err = formatter.write_to_file(test_write_poems, "/invalid/path/that/does/not/exist.txt")
196assert_true(not fail_success, "Write to invalid path fails")
197assert_true(fail_err ~= nil, "Error message provided on failure")
198print("")
199
200-- Summary
201print("═══════════════════════════════════════════")
202print(string.format(" Tests run: %d", tests_run))
203print(string.format(" Tests passed: %d", tests_passed))
204print(string.format(" Tests failed: %d", tests_failed))
205print("═══════════════════════════════════════════")
206
207if tests_failed == 0 then
208 print("✅ All tests passed!")
209 os.exit(0)
210else
211 print("❌ Some tests failed")
212 os.exit(1)
213end
214