hatmill/hatmill_test.go
2019-04-08 22:10:02 -06:00

199 lines
4.9 KiB
Go

package hatmill_test
import (
"bytes"
"fmt"
"html"
"io"
"os"
"reflect"
"strings"
"testing"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/gen"
"github.com/leanovate/gopter/prop"
"gitlab.codemonkeysoftware.net/b/hatmill"
ha "gitlab.codemonkeysoftware.net/b/hatmill/attribute"
he "gitlab.codemonkeysoftware.net/b/hatmill/element"
)
type NopWriter struct{}
func (NopWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
func writeToString(wt io.WriterTo) string {
var buf bytes.Buffer
_, err := wt.WriteTo(&buf)
if err != nil {
panic(err)
}
return buf.String()
}
func checkWrite(wt io.WriterTo, expected string) bool {
var buf bytes.Buffer
n, err := wt.WriteTo(&buf)
return err == nil && n == int64(buf.Len()) && buf.String() == expected
}
func TestText(t *testing.T) {
properties := gopter.NewProperties(nil)
properties.Property("WriteTo is correct", prop.ForAll(
func(s string) bool {
return checkWrite(hatmill.Text(s), s)
},
gen.AnyString(),
))
properties.TestingRun(t)
}
var nonEmptyAlphaString = gen.AlphaString().SuchThat(func(v interface{}) bool {
return v.(string) != ""
})
var attribGen = gen.Struct(reflect.TypeOf(hatmill.Attrib{}), map[string]gopter.Gen{
"Key": nonEmptyAlphaString,
"Value": gen.AlphaString(),
})
func TestAttrib(t *testing.T) {
properties := gopter.NewProperties(nil)
properties.Property("WriteTo only writes key when value is empty", prop.ForAll(
func(key string) bool {
attrib := hatmill.Attrib{
Key: key,
}
return checkWrite(attrib, key)
},
nonEmptyAlphaString,
))
properties.Property("writes key=value when value is not empty", prop.ForAll(
func(attrib hatmill.Attrib) bool {
expected := fmt.Sprintf("%s='%s'", attrib.Key, attrib.Value)
return checkWrite(attrib, expected)
},
attribGen.SuchThat(func(attrib interface{}) bool {
return attrib.(hatmill.Attrib).Value != ""
}),
))
properties.TestingRun(t)
}
func TestEmptyElement(t *testing.T) {
properties := gopter.NewProperties(nil)
properties.Property("WriteTo writes element correctly with no attributes", prop.ForAll(
func(tagName string) bool {
elem := &hatmill.VoidElement{
TagName: tagName,
}
expected := "<" + tagName + ">"
return checkWrite(elem, expected)
},
gen.AnyString(),
))
properties.Property("WriteTo writes element correctly with attributes", prop.ForAll(
func(tagName string, attribs []hatmill.Attrib) bool {
elem := hatmill.VoidElement{
TagName: tagName,
Attribs: attribs,
}
var attribStrings []string
for _, attrib := range attribs {
attribStrings = append(attribStrings, writeToString(attrib))
}
if len(attribStrings) > 0 {
attribStrings[0] = " " + attribStrings[0]
}
expected := "<" + tagName + strings.Join(attribStrings, " ") + ">"
return checkWrite(elem, expected)
},
gen.AnyString(),
gen.SliceOf(attribGen),
))
properties.TestingRun(t)
}
var htmlTextGen = gen.AnyString().Map(func(s string) hatmill.Term {
return hatmill.Text(s)
})
func TestParentElement(t *testing.T) {
properties := gopter.NewProperties(nil)
properties.Property("WriteTo writes element correctly without children", prop.ForAll(
func(tagName string, attribs []hatmill.Attrib) bool {
elem := &hatmill.ParentElement{
VoidElement: hatmill.VoidElement{
TagName: tagName,
Attribs: attribs,
},
}
openTag := writeToString(elem.VoidElement)
expected := openTag + "</" + tagName + ">"
return checkWrite(elem, expected)
},
gen.AnyString(),
gen.SliceOf(attribGen),
))
properties.Property("WriteTo writes element correctly with children", prop.ForAll(
func(tagName string, attribs []hatmill.Attrib, children []hatmill.Term) bool {
elem := &hatmill.ParentElement{
VoidElement: hatmill.VoidElement{
TagName: tagName,
Attribs: attribs,
},
Children: children,
}
openTag := writeToString(elem.VoidElement)
var childStrings []string
for _, child := range children {
childStrings = append(childStrings, writeToString(child))
}
expected := openTag + strings.Join(childStrings, "") + "</" + tagName + ">"
return checkWrite(elem, expected)
},
gen.AnyString(),
gen.SliceOf(attribGen),
gen.SliceOf(htmlTextGen),
))
properties.TestingRun(t)
}
func Example() {
userInput := "<script>launchMissiles();</script>"
document := he.Html()(
he.Head()(
he.Meta(ha.HttpEquiv("refresh"), ha.Content("5")),
),
he.Body()(
he.Div()(
he.Img(ha.Src("./me.jpg"), ha.Id("profile-photo")),
hatmill.Text(html.EscapeString(userInput)),
he.Div(ha.Disabled(), ha.CustomData("coolness", "awesome"))(),
),
),
)
hatmill.WriteDocument(os.Stdout, document)
// Output: <!DOCTYPE html><html><head><meta http-equiv='refresh' content='5'></head><body><div><img src='./me.jpg' id='profile-photo'>&lt;script&gt;launchMissiles();&lt;/script&gt;<div disabled data-coolness='awesome'></div></div></body></html>
}