package check import ( "strings" "testing" "amadan.net/rastrillo/fiesta" "amadan.net/rastrillo/fiesta/internal/markup" ) // The seeded spelling fixture, held to the class spelling as text. The // browser drive (markup_v3_browser_test.go) compares the fixture // against markup.Respell of it; a fixture that already carried the // attribute spelling in places would compare those elements against // themselves and prove nothing about them, which is what rastrillo's own // fixture did before it was translated back to classes. // mappedAttributes is every rst- attribute name the grammar writes for // a class tokens.css styles: the set a class-spelled page must not // carry. func mappedAttributes(t *testing.T) map[string]bool { t.Helper() out := map[string]bool{} for class := range styledClasses(t, string(fiesta.TokensCSS())) { if name, _, ok := markup.Attribute(class); ok { out[name] = true } } if len(out) < 20 { t.Fatalf("the grammar maps %d attribute names from tokens.css's classes; the reader is broken", len(out)) } return out } // rstAttributesIn lists every rst- attribute in the open tags of html // whose name the grammar maps, each with the tag it sits in. The class // attribute comes out of the tag before the scan: its tokens follow // whitespace exactly as an attribute does, and rst-btn in class="rst-btn" // is a class, not an attribute. func rstAttributesIn(html string, mapped map[string]bool) []string { var found []string for _, tag := range openTagInFixture.FindAllString(html, -1) { for _, m := range rstAttrInFixture.FindAllStringSubmatch(classInMarkup.ReplaceAllString(tag, ""), -1) { if mapped[m[1]] { found = append(found, m[1]+" in "+tag) } } } return found } // mappedClassesIn lists every rst- class token in html that the // grammar maps to an attribute, each with the class attribute it sits // in. Only rst- tokens: the grammar is defined on the vocabulary, and // Attribute answers for any name handed to it (.icon, an app's own // class), which are not the stylesheet's to respell. func mappedClassesIn(html string) []string { var found []string for _, m := range classInMarkup.FindAllStringSubmatch(html, -1) { for _, token := range strings.Fields(m[1]) { if !strings.HasPrefix(token, "rst-") { continue } if _, _, ok := markup.Attribute(token); ok { found = append(found, token+" in "+m[0]) } } } return found } // TestTheClassFixtureIsGenuinelyClassSpelled: the seeded class page // holds no rst- attribute the grammar maps, its markup.Respell twin // holds no class="rst-…" token the grammar maps, and the two differ. // rastrillo's fixture was the partials and the styleguide, which write // attributes, behind a hand-written block in classes; the seed is that // fixture translated back whole, and this is what says the translation // reached all of it. func TestTheClassFixtureIsGenuinelyClassSpelled(t *testing.T) { class := fixture(t, "markup_v3_browser_test.go", "classFixture", "") mapped := mappedAttributes(t) if found := rstAttributesIn(class, mapped); len(found) > 0 { t.Errorf("the class page carries %d rst- attributes the grammar maps; it is not in the class spelling. The first: %s", len(found), found[0]) } attr, notes := markup.Respell([]byte(class)) for _, n := range notes { t.Errorf("respelling the class page: %s", n) } if found := mappedClassesIn(string(attr)); len(found) > 0 { t.Errorf("the attribute twin still carries %d classes the grammar maps; the translation did not reach them. The first: %s", len(found), found[0]) } if string(attr) == class { t.Error("the attribute twin is identical to the class page; the translation did nothing") } }