diff --git a/hatmill_test.go b/hatmill_test.go index 4a0b82e..be5098f 100644 --- a/hatmill_test.go +++ b/hatmill_test.go @@ -2,11 +2,16 @@ package hatmill_test import ( "bytes" + "fmt" + "io" + "reflect" + "strings" + "testing" + "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" "gitlab.codemonkeysoftware.com/b/hatmill" - "testing" ) type NopWriter struct{} @@ -15,33 +20,156 @@ 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("writing to string is identity", prop.ForAll( + properties.Property("WriteTo is correct", prop.ForAll( func(s string) bool { - var buf bytes.Buffer - hatmill.Text(s).WriteTo(&buf) - return buf.String() == s - }, - gen.AnyString(), - )) - - properties.Property("WriteTo returns correct n", prop.ForAll( - func(s string) bool { - n, _ := hatmill.Text(s).WriteTo(NopWriter{}) - return n == int64(len(s)) - }, - gen.AnyString(), - )) - - properties.Property("WriteTo does not generate error", prop.ForAll( - func(s string) bool { - _, err := hatmill.Text(s).WriteTo(NopWriter{}) - return err == nil + 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.EmptyElement{ + 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.EmptyElement{ + 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.Html { + 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 { + EmptyElement: hatmill.EmptyElement{ + TagName: tagName, + Attribs: attribs, + }, + } + + openTag := writeToString(elem.EmptyElement) + expected := openTag + "" + 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.Html) bool { + elem := &hatmill.ParentElement { + EmptyElement: hatmill.EmptyElement{ + TagName: tagName, + Attribs: attribs, + }, + Children: children, + } + + openTag := writeToString(elem.EmptyElement) + + var childStrings []string + for _, child := range children { + childStrings = append(childStrings, writeToString(child)) + } + + expected := openTag + strings.Join(childStrings, "") + "" + return checkWrite(elem, expected) + }, + gen.AnyString(), + gen.SliceOf(attribGen), + gen.SliceOf(htmlTextGen), + )) + + properties.TestingRun(t) +}