package html_test import ( "bytes" "code.squareroundforest.org/arpio/html" . "code.squareroundforest.org/arpio/html/tags" "errors" "strings" "testing" ) type failingWriter struct { after int } func failWriteAfter(n int) *failingWriter { return &failingWriter{n} } func (w *failingWriter) Write(p []byte) (int, error) { w.after -= len(p) if w.after < 0 { return len(p) + w.after, errors.New("test error") } return len(p), nil } func TestRender(t *testing.T) { t.Run("merge render guides", func(t *testing.T) { foo := html.Inline(html.Verbatim(NewTag("foo"))) foo = foo("") var b bytes.Buffer if err := html.RenderIndent(&b, "\t", 0, foo); err != nil { t.Fatal(err) } if b.String() != "" { t.Fatal(b.String()) } }) t.Run("attribute escaping", func(t *testing.T) { span := Span(Attr("foo", "bar=\"&\"")) var b bytes.Buffer if err := html.Render(&b, span); err != nil { t.Fatal(err) } if b.String() != "" { t.Fatal(b.String()) } }) t.Run("html escape", func(t *testing.T) { t.Run("basic escape", func(t *testing.T) { span := Span("bar&baz") var b bytes.Buffer if err := html.Render(&b, span); err != nil { t.Fatal(err) } if b.String() != "<foo>bar&baz</foo>" { t.Fatal(b.String()) } }) t.Run("consecutive spaces", func(t *testing.T) { span := Span("consecutive spaces: \" \"") var b bytes.Buffer if err := html.Render(&b, span); err != nil { t.Fatal(err) } if b.String() != "consecutive spaces: \"   \"" { t.Fatal(b.String()) } }) }) t.Run("write error", func(t *testing.T) { t.Run("fail immediately", func(t *testing.T) { div := Div(Span("foo")) w := failWriteAfter(0) if err := html.Render(w, div); err == nil || !strings.Contains(err.Error(), "test error") { t.Fatal() } }) t.Run("fail in tag", func(t *testing.T) { div := Div(Span("foo")) w := failWriteAfter(6) if err := html.Render(w, div); err == nil || !strings.Contains(err.Error(), "test error") { t.Fatal() } }) t.Run("partial text children", func(t *testing.T) { div := Div("foo", Div("bar"), "baz") w := failWriteAfter(5) if err := html.RenderIndent(w, "\t", 0, div); err == nil || !strings.Contains(err.Error(), "test error") { t.Fatal() } }) t.Run("text children", func(t *testing.T) { div := Div("foo", "bar", "baz") w := failWriteAfter(5) if err := html.RenderIndent(w, "\t", 0, div); err == nil || !strings.Contains(err.Error(), "test error") { t.Fatal() } }) }) t.Run("indent", func(t *testing.T) { t.Run("simple tag", func(t *testing.T) { div := Div(Span("foo")) var b bytes.Buffer if err := html.RenderIndent(&b, "\t", 0, div); err != nil { t.Fatal(err) } if b.String() != "
\n\tfoo\n
\n" { t.Fatal(b.String()) } }) t.Run("empty tag", func(t *testing.T) { div := Div(Br()) var b bytes.Buffer if err := html.RenderIndent(&b, "\t", 0, div); err != nil { t.Fatal(err) } if b.String() != "
\n\t
\n
\n" { t.Fatal(b.String()) } }) t.Run("inline fragment between blocks", func(t *testing.T) { div := Div("foo bar baz", Div("qux quux"), "corge") var b bytes.Buffer if err := html.RenderIndent(&b, "\t", 0, div); err != nil { t.Fatal(err) } if b.String() != "
\n\tfoo bar baz\n\t
\n\t\tqux quux\n\t
\n\tcorge\n
\n" { t.Fatal(b.String()) } }) t.Run("block inside inline", func(t *testing.T) { div := Div(Span("foo bar baz", Div("qux quux"), "corge")) var b bytes.Buffer if err := html.RenderIndent(&b, "XYZ", 0, div); err != nil { t.Fatal(err) } if b.String() != "" { t.Fatal(b.String()) } }) }) }