From d744588f25ada6d091e45a10d52b1edba69c0793 Mon Sep 17 00:00:00 2001 From: Thibaud Date: Fri, 27 Mar 2026 16:29:34 +0100 Subject: [PATCH] test: add HTMLDraftman direct visitor tests Add 32 tests covering each visit*() method in isolation: - visitRectangle: div+id, position, dimensions, filled/stroked/both/neither - visitCircle: div+class, border-radius prefixes, position, id consistency - visitTriangle: div+class, CSS border trick, position, fill color, regression test for hashCode mismatch (this.hashCode vs shape.hashCode) - visitText: content, id consistency, position, font attrs, color, nowrap, null color fallback - visitCollection: empty, multiple children, nested - generateHTML: DOCTYPE, structure, stylesheet ref, shape content Closes #10 --- .../ui/visitors/HTMLDraftmanTest.java | 409 ++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100644 src/test/java/ovh/gasser/newshapes/ui/visitors/HTMLDraftmanTest.java diff --git a/src/test/java/ovh/gasser/newshapes/ui/visitors/HTMLDraftmanTest.java b/src/test/java/ovh/gasser/newshapes/ui/visitors/HTMLDraftmanTest.java new file mode 100644 index 0000000..3e35e5e --- /dev/null +++ b/src/test/java/ovh/gasser/newshapes/ui/visitors/HTMLDraftmanTest.java @@ -0,0 +1,409 @@ +package ovh.gasser.newshapes.ui.visitors; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import ovh.gasser.newshapes.attributes.ColorAttributes; +import ovh.gasser.newshapes.shapes.*; + +import java.awt.*; +import java.io.PrintWriter; +import java.io.StringWriter; + +import static org.junit.jupiter.api.Assertions.*; + +class HTMLDraftmanTest { + + private StringWriter htmlBuffer; + private StringWriter cssBuffer; + private PrintWriter htmlWriter; + private PrintWriter cssWriter; + private HTMLDraftman draftman; + + @BeforeEach + void setUp() { + htmlBuffer = new StringWriter(); + cssBuffer = new StringWriter(); + htmlWriter = new PrintWriter(htmlBuffer); + cssWriter = new PrintWriter(cssBuffer); + draftman = new HTMLDraftman(htmlWriter, cssWriter); + } + + private String html() { + htmlWriter.flush(); + return htmlBuffer.toString(); + } + + private String css() { + cssWriter.flush(); + return cssBuffer.toString(); + } + + // ── visitRectangle ────────────────────────────────────────────── + + @Nested + class VisitRectangleTests { + + @Test + void testRectangleProducesDivWithId() { + SRectangle rect = SRectangle.create(10, 20, 100, 50); + draftman.visitRectangle(rect); + + assertTrue(html().contains("
Hello
"), "HTML should contain text content in div"); + } + + @Test + void testTextHtmlIdMatchesCssSelector() { + SText text = SText.create(0, 0, "Test"); + draftman.visitText(text); + + String id = "txt" + text.hashCode(); + assertTrue(html().contains("id=\"" + id + "\""), "HTML should contain text div with correct id"); + assertTrue(css().contains("#" + id), "CSS should reference same text id"); + } + + @Test + void testTextCssContainsPosition() { + SText text = SText.create(15, 25, "Pos"); + draftman.visitText(text); + + String cssOut = css(); + assertTrue(cssOut.contains("top:25px"), "CSS should contain correct top"); + assertTrue(cssOut.contains("left:15px"), "CSS should contain correct left"); + } + + @Test + void testTextCssContainsDefaultFontAttributes() { + SText text = SText.create(0, 0, "Font"); + draftman.visitText(text); + + String cssOut = css(); + assertTrue(cssOut.contains("font-family:"), "CSS should contain font-family"); + assertTrue(cssOut.contains("font-size:16px"), "CSS should contain default font size"); + assertTrue(cssOut.contains("font-style:normal"), "CSS should contain normal font style"); + assertTrue(cssOut.contains("font-weight:normal"), "CSS should contain normal font weight"); + } + + @Test + void testTextCssContainsColor() { + SText text = SText.create(0, 0, "Colored"); + text.addAttributes(new ColorAttributes(true, false, Color.RED, Color.BLACK)); + draftman.visitText(text); + + assertTrue(css().contains("color:#ff0000"), "CSS should contain fill color as text color"); + } + + @Test + void testTextCssWhiteSpaceNowrap() { + SText text = SText.create(0, 0, "NoWrap"); + draftman.visitText(text); + + assertTrue(css().contains("white-space: nowrap"), "CSS should prevent text wrapping"); + } + + @Test + void testTextWithNullColorAttributesFallsBackToBlack() { + SText text = SText.create(0, 0, "Fallback"); + text.addAttributes(new ColorAttributes(false, false, null, null)); + draftman.visitText(text); + + assertTrue(css().contains("color:#000000"), "Should fall back to black with null colors"); + } + } + + // ── visitCollection ───────────────────────────────────────────── + + @Nested + class VisitCollectionTests { + + @Test + void testEmptyCollection() { + SCollection empty = SCollection.of(); + draftman.visitCollection(empty); + + assertEquals("", html(), "Empty collection should produce no HTML"); + assertEquals("", css(), "Empty collection should produce no CSS"); + } + + @Test + void testCollectionVisitsAllChildren() { + SCollection coll = SCollection.of( + SRectangle.create(0, 0, 10, 10), + SCircle.create(20, 20, 5) + ); + draftman.visitCollection(coll); + + assertTrue(html().contains("rec"), "Should visit rectangle"); + assertTrue(html().contains("circle"), "Should visit circle"); + } + + @Test + void testNestedCollectionVisitsAllDescendants() { + SCollection inner = SCollection.of( + SRectangle.create(0, 0, 5, 5) + ); + SCollection outer = SCollection.of( + inner, + SCircle.create(10, 10, 3) + ); + draftman.visitCollection(outer); + + assertTrue(html().contains("rec"), "Should visit nested rectangle"); + assertTrue(html().contains("circle"), "Should visit circle at outer level"); + } + } + + // ── generateHTML ──────────────────────────────────────────────── + + @Nested + class GenerateHTMLTests { + + @Test + void testGenerateHTMLIncludesDoctype() { + SCollection model = SCollection.of(); + draftman.generateHTML(model); + + assertTrue(html().contains(""), "Should include DOCTYPE"); + } + + @Test + void testGenerateHTMLIncludesHtmlStructure() { + SCollection model = SCollection.of(); + draftman.generateHTML(model); + + String htmlOut = html(); + assertTrue(htmlOut.contains(""), "Should include head tag"); + assertTrue(htmlOut.contains(""), "Should include body tag"); + assertTrue(htmlOut.contains(""), "Should close body tag"); + } + + @Test + void testGenerateHTMLReferencesStylesheet() { + SCollection model = SCollection.of(); + draftman.generateHTML(model); + + assertTrue(html().contains("style.css"), "Should reference CSS stylesheet"); + } + + @Test + void testGenerateHTMLIncludesShapeContent() { + SCollection model = SCollection.of( + SRectangle.create(1, 2, 3, 4) + ); + draftman.generateHTML(model); + + assertTrue(html().contains("