rastrillo / fiesta Public

Clone
git clone https://amadan.net/rastrillo/fiesta

Plain git — no account needed to clone.

Download

Download this file

1package rowrule
2
3import (
4 "slices"
5 "strings"
6 "testing"
7
8 xhtml "golang.org/x/net/html"
9
10 "amadan.net/rastrillo/fiesta/internal/markup"
11)
12
13// read is markup as Breaches wants it: respelled, then parsed.
14func read(t *testing.T, src string) *xhtml.Node {
15 t.Helper()
16 respelled, _ := markup.Respell([]byte(src))
17 doc, err := xhtml.Parse(strings.NewReader(string(respelled)))
18 if err != nil {
19 t.Fatalf("parsing %q: %v", src, err)
20 }
21 return doc
22}
23
24// TestTheRowCheckNamesEachBreach: each way a dropdown can break the
25// rule is named by its own message, in both spellings, and each shape
26// the rule allows passes. A checker that only counted breaches would
27// pass a page that broke the rule one way and was fixed another.
28func TestTheRowCheckNamesEachBreach(t *testing.T) {
29 const header = `<header rst-page-header><h1>T</h1></header>`
30 cases := []struct {
31 name, markup string
32 want []string
33 }{
34 {"alone at the top of the page, above its title",
35 `<main rst-page><details rst-dropdown></details>` + header + `</main>`,
36 []string{"a dropdown sits in main[rst-page], not in a row", "a dropdown comes before the page header"}},
37 {"in a bare div",
38 `<div><details rst-dropdown></details></div>`,
39 []string{"a dropdown sits in div, not in a row"}},
40 {"in a toolbar above the page's title",
41 `<main rst-page><div rst-lbar><details rst-dropdown></details></div>` + header + `</main>`,
42 []string{"a dropdown comes before the page header"}},
43 {"a page header with no title",
44 `<header rst-page-header><details rst-dropdown></details></header>`,
45 []string{"a page header holds a dropdown and no h1"}},
46 {"a section head with no heading",
47 `<div rst-box-head><details rst-dropdown></details></div>`,
48 []string{"a section head holds a dropdown and no heading"}},
49 {"class-spelled, alone in the body",
50 `<body><details class="rst-dropdown"></details></body>`,
51 []string{"a dropdown sits in body, not in a row"}},
52 {"in a form that lays itself out",
53 `<div rst-lbar><form rst-search><details rst-dropdown></details></form></div>`,
54 []string{"a dropdown sits in form[rst-search], not in a row"}},
55 {"a heading inside the menu is not the section's",
56 `<div rst-box-head><details rst-dropdown><summary>S</summary><div rst-dropdown-menu><h2>P</h2></div></details></div>`,
57 []string{"a section head holds a dropdown and no heading"}},
58
59 {"in a toolbar inside a page header with no title",
60 `<header rst-page-header><div rst-lbar><details rst-dropdown><summary>Menu</summary></details></div></header>`,
61 []string{"a page header holds a dropdown and no h1"}},
62 {"class-spelled, in a toolbar inside a page header with no title",
63 `<header class="rst-page-header"><div class="rst-lbar"><details class="rst-dropdown"><summary>Menu</summary></details></div></header>`,
64 []string{"a page header holds a dropdown and no h1"}},
65 {"in a toolbar inside a section head with no heading",
66 `<div rst-box-head><div rst-lbar><details rst-dropdown><summary>Menu</summary></details></div></div>`,
67 []string{"a section head holds a dropdown and no heading"}},
68 {"class-spelled, in a toolbar inside a section head with no heading",
69 `<div class="rst-box-head"><div class="rst-lbar"><details class="rst-dropdown"><summary>Menu</summary></details></div></div>`,
70 []string{"a section head holds a dropdown and no heading"}},
71 {"a class list the respeller cannot read",
72 `<main rst-page><details class=rst-dropdown{{.Open}}></details></main>`,
73 []string{`a class list could not be respelled, so the check cannot read it: <details class="rst-dropdown{{.Open}}">`}},
74
75 {"escaped markup in a code sample",
76 `<p><code>class=&quot;rst-box&quot;</code></p>`, nil},
77 {"in a toolbar inside a page header with its title",
78 `<header rst-page-header><h1>T</h1><div rst-lbar><details rst-dropdown><summary>Menu</summary></details></div></header>`, nil},
79 {"class-spelled, in a toolbar inside a section head with its heading",
80 `<div class="rst-box-head"><h2>P</h2><div class="rst-lbar"><details class="rst-dropdown"><summary>Menu</summary></details></div></div>`, nil},
81 {"class-spelled, in a section head with its heading",
82 `<div class="rst-box-head"><h2>P</h2><details rst-dropdown></details></div>`, nil},
83 {"in a toolbar, inside a form, after the toolbar's search",
84 `<div rst-lbar><search><form rst-search method="get" action="/posts"><input type="search" name="q"></form></search>` +
85 `<form method="get" action="/posts"><details rst-dropdown><summary>S</summary></details></form></div>`, nil},
86 {"in a toolbar, inside a search's form",
87 `<div rst-lbar><search><form method="get"><details rst-dropdown></details></form></search></div>`, nil},
88 {"in the shell's bar, before the page header",
89 `<div rst-shell-tail><details rst-dropdown></details></div><main rst-page>` + header + `</main>`, nil},
90 {"in a menu in the rail's foot, before the page header",
91 `<div rst-shell-rail-foot><details rst-dropdown><summary>S</summary><div rst-dropdown-menu><details rst-dropdown></details></div></details></div><main rst-page>` + header + `</main>`, nil},
92 {"inside another dropdown's menu",
93 `<div rst-box-head><h2>P</h2><details rst-dropdown><summary>S</summary><div rst-dropdown-menu><details rst-dropdown></details></div></details></div>`, nil},
94 {"in the page header beside its title",
95 `<main rst-page><header rst-page-header><div><h1>T</h1></div><details rst-dropdown></details></header></main>`, nil},
96 {"in the footer row, after the page header",
97 `<main rst-page>` + header + `<footer rst-page-foot><details rst-dropdown></details></footer></main>`, nil},
98 }
99 for _, c := range cases {
100 if got := Breaches(read(t, c.markup), nil); !slices.Equal(got, c.want) {
101 t.Errorf("%s:\n got %q\n want %q", c.name, got, c.want)
102 }
103 }
104}
105
106// TestAPageNamesItsOwnRows: a page that lays out its own bars names
107// them by class, and a menu in one of them is in a row. A name a menu's
108// row does not carry, or one written as an attribute, is no row: the
109// page's names extend Fiesta's rows, they do not loosen the rule for
110// the rest of the page.
111func TestAPageNamesItsOwnRows(t *testing.T) {
112 bar := map[string]string{"site-bar": "the site's theme bar"}
113 cases := []struct {
114 name, markup string
115 rows map[string]string
116 want []string
117 }{
118 {"in a row the page names",
119 `<div class="site-stage site-bar"><span>Theme</span><details rst-dropdown></details></div>`, bar, nil},
120 {"in a form inside a row the page names",
121 `<nav class="site-bar"><form method="post"><details rst-dropdown></details></form></nav>`, bar, nil},
122 {"in a div the page does not name",
123 `<div class="site-stage"><details rst-dropdown></details></div>`, bar,
124 []string{"a dropdown sits in div, not in a row"}},
125 {"the name written as an attribute",
126 `<div site-bar><details rst-dropdown></details></div>`, bar,
127 []string{"a dropdown sits in div, not in a row"}},
128 {"a row the page names, with no names passed",
129 `<div class="site-bar"><details rst-dropdown></details></div>`, nil,
130 []string{"a dropdown sits in div, not in a row"}},
131 {"a Fiesta row, beside the page's names",
132 `<div rst-lbar><details rst-dropdown></details></div>`, bar, nil},
133 }
134 for _, c := range cases {
135 if got := Breaches(read(t, c.markup), c.rows); !slices.Equal(got, c.want) {
136 t.Errorf("%s:\n got %q\n want %q", c.name, got, c.want)
137 }
138 }
139}
140