package memoriatest import ( "strings" "testing" "golang.org/x/net/html" ) // The helpers in this file read a page the way a browser does, through // an HTML parser, so a check cannot be passed by spelling the same markup // differently: rst-refresh='x', RST-REFRESH="x" and rst-refresh=x are one // attribute to a browser and three strings to a regex. func parsePage(t *testing.T, body string) *html.Node { t.Helper() doc, err := html.Parse(strings.NewReader(body)) if err != nil { t.Fatalf("parsing the page: %v", err) } return doc } func attrOf(n *html.Node, key string) (string, bool) { for _, a := range n.Attr { if a.Key == key { return a.Val, true } } return "", false } func findAll(root *html.Node, match func(*html.Node) bool) []*html.Node { var out []*html.Node var walk func(*html.Node) walk = func(n *html.Node) { if n.Type == html.ElementNode && match(n) { out = append(out, n) } for c := n.FirstChild; c != nil; c = c.NextSibling { walk(c) } } walk(root) return out } func hasAttr(key string) func(*html.Node) bool { return func(n *html.Node) bool { _, ok := attrOf(n, key); return ok } } func elementWith(tag, key, val string) func(*html.Node) bool { return func(n *html.Node) bool { v, ok := attrOf(n, key) return n.Data == tag && ok && v == val } } // within reports whether n is inside ancestor, or is it. func within(n, ancestor *html.Node) bool { for ; n != nil; n = n.Parent { if n == ancestor { return true } } return false } func textOf(n *html.Node) string { var b strings.Builder var walk func(*html.Node) walk = func(n *html.Node) { if n.Type == html.TextNode { b.WriteString(n.Data) } for c := n.FirstChild; c != nil; c = c.NextSibling { walk(c) } } walk(n) return strings.Join(strings.Fields(b.String()), " ") } // region returns the one element carrying rst-refresh=name. func region(t *testing.T, doc *html.Node, name string) *html.Node { t.Helper() found := findAll(doc, func(n *html.Node) bool { v, ok := attrOf(n, "rst-refresh"); return ok && v == name }) if len(found) != 1 { t.Fatalf("%d regions named %q on the page, want 1", len(found), name) } return found[0] }