Skip to content

Commit c21d606

Browse files
committed
test(helpers): close coverage gaps for every tag/color form in issue #83
Adds a TestParseSwgohStringIssue83Coverage class that exercises every tag and every color literal length called out in the issue across the output formats where they are renderable but were previously untested: - [t]/[/t] sprite, [y=X]/[/y] scale, [sub], [sub=X], [sup], [sup=X] in terminal/discord (must strip cleanly, no markup leakage) - 4-digit [RGBA] in bare and terminal (RGB channel emitted, alpha dropped) - 8-digit [RRGGBBAA] in bare, terminal, and web (web uses rgba() with the alpha channel converted to the 0-1 CSS float) - 1-digit [A] alpha-only literal in terminal (re-emits the prior RGB) - Standalone color literal in web with no enclosing [c] wrapper Adding the web standalone-color test surfaced a latent bug: the web finalizer never closed dangling spans/tags. _finalize_output now balances any open color span and unclosed bold/italic/underline/strike depth so strings that omit closing tags still produce well-formed HTML. Total localization tests: 89 (was 77).
1 parent 1536853 commit c21d606

2 files changed

Lines changed: 106 additions & 1 deletion

File tree

src/swgoh_comlink/helpers/_localization.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,9 +570,22 @@ def _reapply_terminal_styles(state: _FormattingState, result: list[str]) -> None
570570

571571

572572
def _finalize_output(output: OutputFormat, state: _FormattingState, result: list[str]) -> str:
573-
"""Finalize and return the formatted output."""
573+
"""Finalize and return the formatted output, balancing any unclosed markup."""
574574
if output == "terminal" and (state.active_color or state.any_style_active()):
575575
result.append(ANSI_RESET)
576+
elif output == "web":
577+
# Close any tags the source string left dangling so the HTML stays well-formed.
578+
# Inner-most first: styles, then color span.
579+
for _ in range(state.strike_depth):
580+
result.append("</s>")
581+
for _ in range(state.underline_depth):
582+
result.append("</u>")
583+
for _ in range(state.italic_depth):
584+
result.append("</em>")
585+
for _ in range(state.bold_depth):
586+
result.append("</b>")
587+
if state.active_color is not None:
588+
result.append("</span>")
576589

577590
formatted = "".join(result)
578591

tests/unit/test_helpers.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,98 @@ def test_issue_83_golden_string(self):
14461446
assert parse_swgoh_string(s, output="discord") == "**Boss** deals __2x__ damage"
14471447

14481448

1449+
class TestParseSwgohStringIssue83Coverage:
1450+
"""Round-trip coverage for every tag and color format named in issue #83.
1451+
1452+
For text-only outputs (bare/terminal/discord) the visual-only tags
1453+
([t], [y=X], [sub], [sup]) are expected to be stripped without leaking
1454+
any markup characters into the rendered string.
1455+
"""
1456+
1457+
# --- [t] / [/t] sprite color forcing ---------------------------------------
1458+
def test_sprite_terminal_strips(self):
1459+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1460+
1461+
assert parse_swgoh_string("[t]icon[/t]", output="terminal") == "icon"
1462+
1463+
def test_sprite_discord_strips(self):
1464+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1465+
1466+
assert parse_swgoh_string("[t]icon[/t]", output="discord") == "icon"
1467+
1468+
# --- [y=FLOAT] / [/y] font scaling -----------------------------------------
1469+
def test_scale_terminal_strips(self):
1470+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1471+
1472+
assert parse_swgoh_string("[y=1.5]big[/y]", output="terminal") == "big"
1473+
1474+
# --- [sub] / [sub=FLOAT] / [/sub] subscript --------------------------------
1475+
def test_sub_terminal_strips(self):
1476+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1477+
1478+
assert parse_swgoh_string("[sub]x[/sub]", output="terminal") == "x"
1479+
assert parse_swgoh_string("[sub=0.8]x[/sub]", output="terminal") == "x"
1480+
1481+
# --- [sup] / [sup=FLOAT] / [/sup] superscript ------------------------------
1482+
def test_sup_terminal_strips(self):
1483+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1484+
1485+
assert parse_swgoh_string("[sup]x[/sup]", output="terminal") == "x"
1486+
assert parse_swgoh_string("[sup=1.25]x[/sup]", output="terminal") == "x"
1487+
1488+
# --- 4-digit [RGBA] color --------------------------------------------------
1489+
def test_four_digit_rgba_bare(self):
1490+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1491+
1492+
assert parse_swgoh_string("[F0A8]x[/c]", output="bare") == "x"
1493+
1494+
def test_four_digit_rgba_terminal_uses_rgb_channel(self):
1495+
"""Terminal can't render alpha, but it must still emit the RGB channel."""
1496+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1497+
1498+
result = parse_swgoh_string("[F0A8]x[/c]", output="terminal")
1499+
# F0A8 -> RGB FF00AA, alpha 88 -> ignored by ANSI but RGB still shown.
1500+
assert "\033[38;2;255;0;170m" in result
1501+
assert "x" in result
1502+
1503+
# --- 8-digit [RRGGBBAA] color ----------------------------------------------
1504+
def test_eight_digit_rgba_bare(self):
1505+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1506+
1507+
assert parse_swgoh_string("[12345678]x[/c]", output="bare") == "x"
1508+
1509+
def test_eight_digit_rgba_terminal(self):
1510+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1511+
1512+
result = parse_swgoh_string("[12345678]x[/c]", output="terminal")
1513+
# 0x12=18, 0x34=52, 0x56=86 (alpha 0x78 dropped by ANSI)
1514+
assert "\033[38;2;18;52;86m" in result
1515+
assert "x" in result
1516+
1517+
def test_eight_digit_rgba_web(self):
1518+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1519+
1520+
result = parse_swgoh_string("[12345678]x[/c]", output="web")
1521+
# alpha 0x78 = 120 -> 120/255 = 0.471
1522+
assert "rgba(18,52,86,0.471)" in result
1523+
1524+
# --- 1-digit [A] alpha-only ------------------------------------------------
1525+
def test_alpha_only_terminal_no_rgb_change(self):
1526+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1527+
1528+
result = parse_swgoh_string("[FF0000]r[8]still_red[/c]", output="terminal")
1529+
# The alpha tag re-emits the same RGB sequence in terminal output.
1530+
assert result.count("\033[38;2;255;0;0m") == 2
1531+
assert "still_red" in result
1532+
1533+
# --- [c] is optional: standalone color without wrapper ---------------------
1534+
def test_standalone_color_web_without_c_wrapper(self):
1535+
from swgoh_comlink.helpers._localization import parse_swgoh_string
1536+
1537+
result = parse_swgoh_string("[00FF00]green", output="web")
1538+
assert '<span style="color:#00FF00">green</span>' in result
1539+
1540+
14491541
# ── Additional quick-win helper tests ──────────────────────────────────
14501542

14511543

0 commit comments

Comments
 (0)