src/boost-bars.test.lua
1-- Tests for boost-bars.lua. These guard the boost frame against the drift that
2-- mangled it in three independent copies: misaligned walls (body ║ at col 0 but
3-- top ╦ at col 2), the wrong bottom-bar junction columns (71 copied from the
4-- golden layout instead of 67), and ▢ replacement chars from byte-slicing the
5-- multibyte ═ in the [BOOST] bar.
6--
7-- The frame is ASYMMETRIC: left edge always double, right edge a FILL FRONTIER
8-- (single ┐│┤┴ until the bar fills the far-right column, then double ╗║╣╩).
9-- Run: luajit src/boost-bars.test.lua
10package.path = "./src/?.lua;./libs/?.lua;" .. package.path
11local B = require("boost-bars")
12B.configure({ arrow = "#dc3c3c", outer_frame = "#74C0FC", inner_box = "#38D9A9" })
13
14local passed, failed = 0, 0
15local function check(name, cond)
16 if cond then passed = passed + 1 else failed = failed + 1; print(" FAIL: " .. name) end
17end
18
19-- Strip HTML, then count UTF-8 codepoints (box chars are 3 bytes each).
20local function visible(s)
21 local txt = s:gsub("<[^>]+>", "")
22 local _, n = txt:gsub("[^\128-\191]", "") -- non-continuation bytes = codepoints
23 return n, txt
24end
25-- Count how many times a (literal) substring char appears.
26local function count(s, ch)
27 local _, n = s:gsub(ch, "")
28 return n
29end
30-- Walk codepoints, return 0-indexed column of the Nth occurrence of any char in set.
31local function columns_of(txt, set)
32 local col, cols = 0, {}
33 for cp in txt:gmatch("[\1-\127\194-\244][\128-\191]*") do
34 if set[cp] then cols[#cols + 1] = col end
35 col = col + 1
36 end
37 return cols
38end
39
40local SIM = "<a href='s'>similar</a>"
41local DIF = "<a href='d'>different</a>"
42local CHR = "<a href='c'>chronological</a>"
43
44-- The body lines (cols 2..81 framed) are 82 wide; the top arrow ◀═ replaces the
45-- 2-space indent (also 82); the bottom adds a trailing ─▶ (84).
46for _, pct in ipairs({0, 0.01, 0.37, 0.5, 0.99, 1.0}) do
47 local pc = math.floor(pct * 78)
48 check("top_border 82 wide @ " .. pct, visible(B.top_border(pct)) == 82)
49 check("inner_top 82 wide @ " .. pct, visible(B.inner_top(pc)) == 82)
50 check("inner_bottom 82 wide @ " .. pct, visible(B.inner_bottom(pc)) == 82)
51 check("content_line 82 wide @ " .. pct, visible(B.content_line("hello world", pc)) == 82)
52 check("nav_separator 82 wide @ " .. pct, visible(B.nav_separator(pc)) == 82)
53 check("nav_line(with chrono) 82 wide @ " .. pct, visible(B.nav_line(SIM, DIF, CHR, pc)) == 82)
54 check("nav_line(no chrono) 82 wide @ " .. pct, visible(B.nav_line(SIM, DIF, nil, pc)) == 82)
55 check("bottom_border 84 wide @ " .. pct, visible(B.bottom_border(pct)) == 84)
56end
57
58-- No U+FFFD / ▢ anywhere (the byte-slice corruption produced these).
59for _, line in ipairs({
60 B.top_border(0.4), B.inner_top(30), B.content_line("x", 30),
61 B.nav_separator(30), B.nav_line(SIM, DIF, CHR, 30), B.bottom_border(0.4),
62}) do
63 check("no replacement char in line", not line:find("\239\191\189", 1, true) and not line:find("▢", 1, true))
64end
65
66-- Left edge is ALWAYS double (╦ top, ║ body/nav, ╠ sep, ╚ bottom).
67do
68 local _, top = visible(B.top_border(0.1))
69 local _, sep = visible(B.nav_separator(5))
70 local _, bot = visible(B.bottom_border(0.1))
71 check("top-left is ╦", top:find("╦", 1, true) ~= nil)
72 check("nav-sep-left is ╠", sep:find("╠", 1, true) ~= nil)
73 check("bottom-left is ╚", bot:find("╚", 1, true) ~= nil)
74end
75
76-- Fill frontier: at LOW progress the right edge is single; at FULL it doubles.
77do
78 local _, top_lo = visible(B.top_border(0.1))
79 local _, top_hi = visible(B.top_border(1.0))
80 check("low progress: top-right single ┐ (no ╗)",
81 top_lo:find("┐", 1, true) ~= nil and top_lo:find("╗", 1, true) == nil)
82 check("full progress: top-right double ╗", top_hi:find("╗", 1, true) ~= nil)
83
84 local _, body_lo = visible(B.content_line("x", 5))
85 local _, body_hi = visible(B.content_line("x", 78))
86 check("low progress: body-right single │ (no ║ on right)", body_lo:sub(-#"│") == "│")
87 check("full progress: body-right double ║", body_hi:sub(-#"║") == "║")
88
89 local _, sep_hi = visible(B.nav_separator(78))
90 check("full progress: nav-sep-right double ╣", sep_hi:find("╣", 1, true) ~= nil)
91 local _, bot_lo = visible(B.bottom_border(0.1))
92 local _, bot_hi = visible(B.bottom_border(1.0))
93 check("low progress: bottom-right single ┴ before arrow", bot_lo:find("┴─▶", 1, true) ~= nil)
94 check("full progress: bottom-right double ╩ before arrow", bot_hi:find("╩─▶", 1, true) ~= nil)
95end
96
97-- Bottom-bar junctions sit at columns 12 and 69 (under the nav-box walls),
98-- i.e. bar-index 10 and 67 -- NOT the golden layout's 71.
99do
100 local _, bot = visible(B.bottom_border(1.0)) -- fully filled -> junctions are ╧
101 local cols = columns_of(bot, { ["╧"] = true, ["┴"] = true })
102 -- cols[1..2] are the two junctions; the trailing ╩ corner is also ┴-family
103 -- so filter to the two that fall at 12 and 69.
104 local has12, has69 = false, false
105 for _, c in ipairs(cols) do
106 if c == 12 then has12 = true end
107 if c == 69 then has69 = true end
108 end
109 check("bottom junctions at columns 12 and 69", has12 and has69)
110end
111
112-- Nav line: similar/different walls align with the separator corners (col 12/69).
113do
114 local _, sep = visible(B.nav_separator(5))
115 local _, nav = visible(B.nav_line(SIM, DIF, CHR, 5))
116 local sep_cols = columns_of(sep, { ["┐"] = true }) -- similar box right corner
117 local nav_cols = columns_of(nav, { ["│"] = true }) -- green box walls
118 check("separator similar-box corner at col 12", sep_cols[1] == 12)
119 check("nav-line green walls at cols 12 and 69", nav_cols[1] == 12 and nav_cols[2] == 69)
120end
121
122-- format_boost assembles top + inner + content* + inner + nav + bottom.
123do
124 local frame = B.format_boost({ "line one", "line two" }, 0.5, SIM, DIF, CHR, true)
125 local lines = {}
126 for l in (frame .. "\n"):gmatch("(.-)\n") do lines[#lines + 1] = l end
127 check("assembled frame has 8 lines (top+itop+2content+ibot+sep+nav+bottom)", #lines == 8)
128 check("assembled first line is the top border", lines[1]:find("╦", 1, true) ~= nil)
129 check("assembled last line is the bottom border", lines[#lines]:find("─▶", 1, true) ~= nil)
130end
131
132print(string.format("\nboost-bars: %d passed, %d failed", passed, failed))
133os.exit(failed == 0 and 0 or 1)
134