package html_test
import (
"bytes"
"code.squareroundforest.org/arpio/html"
. "code.squareroundforest.org/arpio/html/tag"
"strings"
"testing"
)
func TestRender(t *testing.T) {
t.Run("merge render guides", func(t *testing.T) {
foo := html.Inline(html.Verbatim(Define("foo")))
foo = foo("")
var b bytes.Buffer
if err := html.Write(&b, foo); err != nil {
t.Fatal(err)
}
if b.String() != "\n\t\n" {
t.Fatal(b.String())
}
})
t.Run("attributes", func(t *testing.T) {
t.Run("escaping", func(t *testing.T) {
span := Span(Attr("foo", "bar=\"&\""))
var b bytes.Buffer
if err := html.WriteRaw(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("true form", func(t *testing.T) {
span := Span(Attr("foo", true))
var b bytes.Buffer
if err := html.WriteRaw(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("declaration", func(t *testing.T) {
comment := Comment("foo & bar & baz", "qux")
var b bytes.Buffer
if err := html.WriteRaw(&b, comment); 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.WriteRaw(&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.WriteRaw(&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 := &errorWriter{}
if err := html.WriteRaw(w, div); err == nil || !strings.Contains(err.Error(), "test write error") {
t.Fatal()
}
})
t.Run("fail in tag", func(t *testing.T) {
div := Div(Span("foo"))
w := &errorWriter{failAfter: 6}
if err := html.WriteRaw(w, div); err == nil || !strings.Contains(err.Error(), "test write error") {
t.Fatal()
}
})
t.Run("partial text children", func(t *testing.T) {
div := Div("foo", Div("bar"), "baz")
w := &errorWriter{failAfter: 5}
if err := html.Write(w, div); err == nil || !strings.Contains(err.Error(), "test write error") {
t.Fatal()
}
})
t.Run("text children", func(t *testing.T) {
div := Div("foo", "bar", "baz")
w := &errorWriter{failAfter: 5}
if err := html.Write(w, div); err == nil || !strings.Contains(err.Error(), "test write 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.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "
\n\tfoo\n
" {
t.Fatal(b.String())
}
})
t.Run("empty tag", func(t *testing.T) {
div := Div(Br)
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\t
\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.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo bar baz\n\t
\n\t\tqux quux\n\t
\n\tcorge\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.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\t
foo bar baz\n\t\t\n\t\t\tqux quux\n\t\t
\n\tcorge\n
" {
t.Fatal(b.String())
}
})
t.Run("verbatim", func(t *testing.T) {
foo := html.Verbatim(Define("foo"))
foo = foo("bar\nbaz\nqux")
var b bytes.Buffer
if err := html.Write(&b, foo); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tbar\n\tbaz\n\tqux\n" {
t.Fatal(b.String())
}
})
t.Run("script not indented", func(t *testing.T) {
script := Div(Script("foo()\nbar()\nbaz()"))
var b bytes.Buffer
if err := html.Write(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "\n\t\n
" {
t.Fatal(b.String())
}
})
})
t.Run("simple", func(t *testing.T) {
t.Run("unindented", func(t *testing.T) {
div := Div("foo")
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "foo
" {
t.Fatal(b.String())
}
})
t.Run("unindented number", func(t *testing.T) {
div := Div(42)
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "42
" {
t.Fatal(b.String())
}
})
t.Run("unindented after block", func(t *testing.T) {
div := Div(Div, "foo")
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("unindented after inline", func(t *testing.T) {
div := Div(Span, "foo")
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "foo
" {
t.Fatal(b.String())
}
})
t.Run("inline", func(t *testing.T) {
span := Span("foo")
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "foo" {
t.Fatal(b.String())
}
})
t.Run("inline number", func(t *testing.T) {
span := Span(42)
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "42" {
t.Fatal(b.String())
}
})
t.Run("inline after block", func(t *testing.T) {
span := Span(Div, "foo")
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "\n\t\nfoo" {
t.Fatal(b.String())
}
})
t.Run("inline after inline", func(t *testing.T) {
span := Span(Span, "foo")
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "foo" {
t.Fatal(b.String())
}
})
t.Run("inline tag after block", func(t *testing.T) {
span := Span(Div, Span("foo"))
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "\n\t\nfoo" {
t.Fatal(b.String())
}
})
t.Run("inline children", func(t *testing.T) {
p := P("foo")
var b bytes.Buffer
if err := html.Write(&b, p); err != nil {
t.Fatal(err)
}
if b.String() != "foo
" {
t.Fatal(b.String())
}
})
t.Run("inline children number", func(t *testing.T) {
p := P(42)
var b bytes.Buffer
if err := html.Write(&b, p); err != nil {
t.Fatal(err)
}
if b.String() != "42
" {
t.Fatal(b.String())
}
})
t.Run("inline children after inline children", func(t *testing.T) {
p := P(P, "foo")
var b bytes.Buffer
if err := html.Write(&b, p); err != nil {
t.Fatal(err)
}
if b.String() != "\n\t
\nfoo" {
t.Fatal(b.String())
}
})
t.Run("block", func(t *testing.T) {
div := Div("foo")
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo\n
" {
t.Fatal(b.String())
}
})
t.Run("block number", func(t *testing.T) {
div := Div(42)
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\t42\n
" {
t.Fatal(b.String())
}
})
t.Run("block after block", func(t *testing.T) {
div := Div(Div, 42)
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("block after inline", func(t *testing.T) {
div := Div(Span, 42)
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\t42\n
" {
t.Fatal(b.String())
}
})
})
t.Run("nil child", func(t *testing.T) {
t.Run("unindented", func(t *testing.T) {
div := Div("foo", nil, "bar")
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "foobar
" {
t.Fatal(b.String())
}
})
t.Run("unindented verbatim", func(t *testing.T) {
div := html.Verbatim(Div("foo &", nil, " bar"))
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "foo & bar
" {
t.Fatal(b.String())
}
})
t.Run("unindented script", func(t *testing.T) {
script := Script("let foo =", nil, " bar && baz")
var b bytes.Buffer
if err := html.WriteRaw(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("inline", func(t *testing.T) {
span := Span("foo", nil, "bar")
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "foobar" {
t.Fatal(b.String())
}
})
t.Run("inline verbatim", func(t *testing.T) {
span := html.Verbatim(Span("foo &", nil, " bar"))
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo &\n\t bar\n" {
t.Fatal(b.String())
}
})
t.Run("inline script", func(t *testing.T) {
script := html.Inline(Script("let foo =", nil, " bar && baz"))
var b bytes.Buffer
if err := html.Write(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("block", func(t *testing.T) {
div := Div("foo", nil, "bar")
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoobar\n
" {
t.Fatal(b.String())
}
})
t.Run("block verbatim", func(t *testing.T) {
div := html.Verbatim(Div("foo &", nil, " bar"))
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo &\n\t bar\n
" {
t.Fatal(b.String())
}
})
t.Run("block script", func(t *testing.T) {
script := Script("let foo =", nil, " bar && baz")
var b bytes.Buffer
if err := html.Write(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
})
t.Run("empty child", func(t *testing.T) {
t.Run("unindented", func(t *testing.T) {
div := Div("foo", "", "bar")
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "foobar
" {
t.Fatal(b.String())
}
})
t.Run("unindented verbatim", func(t *testing.T) {
div := html.Verbatim(Div("foo &", "", " bar"))
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "foo & bar
" {
t.Fatal(b.String())
}
})
t.Run("unindented script", func(t *testing.T) {
script := Script("let foo =", "", " bar && baz")
var b bytes.Buffer
if err := html.WriteRaw(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("inline", func(t *testing.T) {
span := Span("foo", "", "bar")
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "foobar" {
t.Fatal(b.String())
}
})
t.Run("inline verbatim", func(t *testing.T) {
span := html.Verbatim(Span("foo &", "", " bar"))
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo &\n\t bar\n" {
t.Fatal(b.String())
}
})
t.Run("inline script", func(t *testing.T) {
script := html.Inline(Script("let foo =", "", " bar && baz"))
var b bytes.Buffer
if err := html.Write(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("block", func(t *testing.T) {
div := Div("foo", "", "bar")
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoobar\n
" {
t.Fatal(b.String())
}
})
t.Run("block verbatim", func(t *testing.T) {
div := html.Verbatim(Div("foo &", "", " bar"))
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo &\n\t bar\n
" {
t.Fatal(b.String())
}
})
t.Run("block script", func(t *testing.T) {
script := Script("let foo =", "", " bar && baz")
var b bytes.Buffer
if err := html.Write(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
})
t.Run("reader child", func(t *testing.T) {
t.Run("unindented", func(t *testing.T) {
rd := bytes.NewBufferString("foo & bar & baz")
div := Div(rd)
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "foo & bar & baz
" {
t.Fatal(b.String())
}
})
t.Run("unindented verbatim", func(t *testing.T) {
rd := bytes.NewBufferString("foo & bar & baz")
div := html.Verbatim(Div(rd))
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "foo & bar & baz
" {
t.Fatal(b.String())
}
})
t.Run("unindented script", func(t *testing.T) {
rd := bytes.NewBufferString("let foo = bar() && baz()")
script := Script(rd)
var b bytes.Buffer
if err := html.WriteRaw(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("inline", func(t *testing.T) {
rd := bytes.NewBufferString("foo & bar & baz")
span := Span(rd)
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "foo & bar & baz" {
t.Fatal(b.String())
}
})
t.Run("inline verbatim", func(t *testing.T) {
rd := bytes.NewBufferString("foo & bar & baz")
span := html.Verbatim(Span(rd))
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo & bar & baz\n" {
t.Fatal(b.String())
}
})
t.Run("inline script", func(t *testing.T) {
rd := bytes.NewBufferString("let foo = bar() && baz()")
script := html.Inline(Script(rd))
var b bytes.Buffer
if err := html.Write(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("inline after block", func(t *testing.T) {
rd := bytes.NewBufferString("foo & bar & baz")
span := Span(Div, rd)
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "\n\t\nfoo & bar & baz" {
t.Fatal(b.String())
}
})
t.Run("block", func(t *testing.T) {
rd := bytes.NewBufferString("foo & bar & baz")
div := Div(rd)
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo & bar & baz\n
" {
t.Fatal(b.String())
}
})
t.Run("block verbatim", func(t *testing.T) {
rd := bytes.NewBufferString("foo & bar & baz")
div := html.Verbatim(Div(rd))
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo & bar & baz\n
" {
t.Fatal(b.String())
}
})
t.Run("block script", func(t *testing.T) {
rd := bytes.NewBufferString("let foo = bar() && baz()")
script := Script(rd)
var b bytes.Buffer
if err := html.Write(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
})
t.Run("void", func(t *testing.T) {
t.Run("unindented", func(t *testing.T) {
var b bytes.Buffer
if err := html.WriteRaw(&b, Br); err != nil {
t.Fatal(err)
}
if b.String() != "
" {
t.Fatal(b.String())
}
})
t.Run("inline", func(t *testing.T) {
var b bytes.Buffer
if err := html.Write(&b, Br); err != nil {
t.Fatal(err)
}
if b.String() != "
" {
t.Fatal(b.String())
}
})
t.Run("block", func(t *testing.T) {
var b bytes.Buffer
if err := html.Write(&b, Hr); err != nil {
t.Fatal(err)
}
if b.String() != "
" {
t.Fatal(b.String())
}
})
})
t.Run("no children", func(t *testing.T) {
t.Run("unindented", func(t *testing.T) {
var b bytes.Buffer
if err := html.WriteRaw(&b, Div); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("inline", func(t *testing.T) {
var b bytes.Buffer
if err := html.Write(&b, Span); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("block", func(t *testing.T) {
var b bytes.Buffer
if err := html.Write(&b, Div); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
})
t.Run("verbatim", func(t *testing.T) {
t.Run("unindented", func(t *testing.T) {
div := html.Verbatim(Div("foo & bar"))
var b bytes.Buffer
if err := html.WriteRaw(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "foo & bar
" {
t.Fatal(b.String())
}
})
t.Run("inline", func(t *testing.T) {
span := html.Verbatim(Span("foo & bar"))
var b bytes.Buffer
if err := html.Write(&b, span); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo & bar\n" {
t.Fatal(b.String())
}
})
t.Run("block", func(t *testing.T) {
div := html.Verbatim(Div("foo & bar"))
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "\n\tfoo & bar\n
" {
t.Fatal(b.String())
}
})
})
t.Run("preformatted", func(t *testing.T) {
t.Run("simple", func(t *testing.T) {
pre := Pre("foo\nbar")
var b bytes.Buffer
if err := html.Write(&b, pre); err != nil {
t.Fatal(err)
}
if b.String() != "\nfoo\nbar\n
" {
t.Fatal(b.String())
}
})
t.Run("indented", func(t *testing.T) {
div := Div(Pre("foo\nbar"))
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("child elements", func(t *testing.T) {
div := Div(Pre("foo", Div("bar\n\t", Span("baz\n"), " "), "\t"))
var b bytes.Buffer
if err := html.Write(&b, div); err != nil {
t.Fatal(err)
}
const expect = "\n\t
\nfoobar\n\tbaz\n
\t\n\t
\n
"
if b.String() != expect {
t.Fatal(b.String())
}
})
t.Run("escaping", func(t *testing.T) {
pre := Pre("foo & ", Span("baz & "), "qux")
var b bytes.Buffer
if err := html.Write(&b, pre); err != nil {
t.Fatal(err)
}
if b.String() != "\nfoo & baz & qux\n
" {
t.Fatal(b.String())
}
})
t.Run("verbatim child element", func(t *testing.T) {
div := html.Verbatim(Div)
pre := Pre("foo", div("\n\tbar\t\n"), "baz")
var b bytes.Buffer
if err := html.Write(&b, pre); err != nil {
t.Fatal(err)
}
if b.String() != "\nfoo\n\tbar\t\n
baz\n
" {
t.Fatal(b.String())
}
})
t.Run("verbatim", func(t *testing.T) {
pre := html.Verbatim(Pre)
pre = pre("\n foo\n
")
var b bytes.Buffer
if err := html.Write(&b, pre); err != nil {
t.Fatal(err)
}
if b.String() != "\n\n foo\n
\n
" {
t.Fatal(b.String())
}
})
t.Run("reader child", func(t *testing.T) {
pre := Pre(bytes.NewBufferString("foo &\nbar &\nbaz"))
var b bytes.Buffer
if err := html.Write(&b, pre); err != nil {
t.Fatal(err)
}
if b.String() != "\nfoo &\nbar &\nbaz\n
" {
t.Fatal(b.String())
}
})
})
t.Run("script", func(t *testing.T) {
t.Run("unindented", func(t *testing.T) {
script := Script("let foo = bar && baz")
var b bytes.Buffer
if err := html.WriteRaw(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("inline", func(t *testing.T) {
script := html.Inline(Script("let foo = bar && baz"))
var b bytes.Buffer
if err := html.Write(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
t.Run("block", func(t *testing.T) {
script := Script("let foo = bar && baz")
var b bytes.Buffer
if err := html.Write(&b, script); err != nil {
t.Fatal(err)
}
if b.String() != "" {
t.Fatal(b.String())
}
})
})
t.Run("wrap", func(t *testing.T) {
t.Run("simple", func(t *testing.T) {
p := P("foo bar baz qux quux corge")
var b bytes.Buffer
if err := html.WriteIndent(&b, html.Indentation{Indent: "\t", PWidth: 15}, p); err != nil {
t.Error(err)
}
if b.String() != "foo bar baz\nqux quux corge\n
" {
t.Error(b.String())
}
})
t.Run("min width", func(t *testing.T) {
div := Div(P("foo bar baz qux quux corge"))
var b bytes.Buffer
if err := html.WriteIndent(&b, html.Indentation{Indent: "\t", PWidth: 21, MinPWidth: 18}, div); err != nil {
t.Error(err)
}
if b.String() != "\n\t
foo bar baz qux\n\tquux corge
\n
" {
t.Error(b.String())
}
})
t.Run("min width inline", func(t *testing.T) {
span := Span(P("foo bar baz qux quux corge"))
var b bytes.Buffer
if err := html.WriteIndent(&b, html.Indentation{Indent: "\t", PWidth: 21, MinPWidth: 18}, span); err != nil {
t.Error(err)
}
if b.String() != "\n\tfoo bar baz qux\n\tquux corge
\n" {
t.Error(b.String())
}
})
})
}