Fix class collector when running with --minify
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 21 Apr 2020 10:57:45 +0000 (12:57 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 21 Apr 2020 19:00:52 +0000 (21:00 +0200)
Also add a related stresstest.

Fixes #7161

hugolib/site_test.go
publisher/htmlElementsCollector.go
publisher/htmlElementsCollector_test.go

index e404d80a4f5e0679ad22671c4cefb741949a897a..3116113c0fe241349b5382c1de03984f386f656e 100644 (file)
 package hugolib
 
 import (
+       "encoding/json"
        "fmt"
+       "io/ioutil"
+       "os"
        "path/filepath"
        "strings"
        "testing"
 
+       "github.com/gohugoio/hugo/publisher"
+
        "github.com/spf13/viper"
 
        "github.com/markbates/inflect"
@@ -982,39 +987,64 @@ func TestRefIssues(t *testing.T) {
 }
 
 func TestClassCollector(t *testing.T) {
-       b := newTestSitesBuilder(t)
-       b.WithConfigFile("toml", `
+
+       for _, minify := range []bool{false, true} {
+               t.Run(fmt.Sprintf("minify-%t", minify), func(t *testing.T) {
+                       statsFilename := "hugo_stats.json"
+                       defer os.Remove(statsFilename)
+
+                       b := newTestSitesBuilder(t)
+                       b.WithConfigFile("toml", fmt.Sprintf(`
+                       
+                       
+minify = %t
 
 [build]
   writeStats = true
 
-`)
+`, minify))
 
-       b.WithTemplates("index.html", `
+                       b.WithTemplates("index.html", `
        
 <div id="el1" class="a b c">Foo</div>
 
 Some text.
 
 <div class="c d e" id="el2">Foo</div>
+
+<span class=z>FOO</span>
+
+ <a class="text-base hover:text-gradient inline-block px-3 pb-1 rounded lowercase" href="{{ .RelPermalink }}">{{ .Title }}</a>
+
+
 `)
 
-       b.WithContent("p1.md", "")
+                       b.WithContent("p1.md", "")
 
-       b.Build(BuildCfg{})
+                       b.Build(BuildCfg{})
 
-       b.AssertFileContent("hugo_stats.json", `
-{
+                       b.AssertFileContent("hugo_stats.json", `
+ {
           "htmlElements": {
             "tags": [
-              "div"
+              "a",
+              "div",
+              "span"
             ],
             "classes": [
               "a",
               "b",
               "c",
               "d",
-              "e"
+              "e",
+              "hover:text-gradient",
+              "inline-block",
+              "lowercase",
+              "pb-1",
+              "px-3",
+              "rounded",
+              "text-base",
+              "z"
             ],
             "ids": [
               "el1",
@@ -1023,4 +1053,78 @@ Some text.
           }
         }
 `)
+
+               })
+
+       }
+}
+
+func TestClassCollectorStress(t *testing.T) {
+       statsFilename := "hugo_stats.json"
+       defer os.Remove(statsFilename)
+
+       b := newTestSitesBuilder(t)
+       b.WithConfigFile("toml", `
+       
+disableKinds = ["home", "section", "taxonomy", "taxonomyTerm" ]
+
+[languages]
+[languages.en]
+[languages.nb]
+[languages.no]
+[languages.sv]
+
+
+[build]
+  writeStats = true
+
+`)
+
+       b.WithTemplates("_default/single.html", `
+<div class="c d e" id="el2">Foo</div>
+
+Some text.
+
+{{ $n := index (shuffle (seq 1 20)) 0 }}
+
+{{ "<span class=_a>Foo</span>" | strings.Repeat $n | safeHTML }}
+
+<div class="{{ .Title }}">
+ABC.
+</div>
+
+<div class="f"></div>
+
+{{ $n := index (shuffle (seq 1 5)) 0 }}
+
+{{ "<hr class=p-3>" | safeHTML }}
+
+`)
+
+       for _, lang := range []string{"en", "nb", "no", "sv"} {
+
+               for i := 100; i <= 999; i++ {
+                       b.WithContent(fmt.Sprintf("p%d.%s.md", i, lang), fmt.Sprintf("---\ntitle: p%s%d\n---", lang, i))
+               }
+       }
+
+       b.Build(BuildCfg{})
+
+       contentMem := b.FileContent(statsFilename)
+       cb, err := ioutil.ReadFile(statsFilename)
+       b.Assert(err, qt.IsNil)
+       contentFile := string(cb)
+
+       for _, content := range []string{contentMem, contentFile} {
+
+               stats := &publisher.PublishStats{}
+               b.Assert(json.Unmarshal([]byte(content), stats), qt.IsNil)
+
+               els := stats.HTMLElements
+
+               b.Assert(els.Classes, qt.HasLen, 3606) // (4 * 900) + 4 +2
+               b.Assert(els.Tags, qt.HasLen, 8)
+               b.Assert(els.IDs, qt.HasLen, 1)
+       }
+
 }
index c6e0d3f0f97f14deb712591f6d2ab4bc22292d6d..6166c49adbb536857b9289cc57350e9c10d5d754 100644 (file)
@@ -87,11 +87,6 @@ func (w *cssClassCollectorWriter) Write(p []byte) (n int, err error) {
                if w.isCollecting {
                        for ; i < len(p); i++ {
                                b := p[i]
-                               if !w.inQuote && b == '/' {
-                                       // End element, we don't care about those.
-                                       w.endCollecting(true)
-                                       break
-                               }
                                w.toggleIfQuote(b)
                                if !w.inQuote && b == '>' {
                                        w.endCollecting(false)
index 3ef159d8be86b76471b2818c21bfbceac0c07e21..fe3876ae62507e2e4aa1162d798e86fe74da04c2 100644 (file)
@@ -51,6 +51,8 @@ func TestClassCollector(t *testing.T) {
                {"duplicates", `<div class="b a b"></div>`, f("div", "a b", "")},
                {"single quote", `<body class='b a'></body>`, f("body", "a b", "")},
                {"no quote", `<body class=b id=myelement></body>`, f("body", "b", "myelement")},
+               // https://github.com/gohugoio/hugo/issues/7161
+               {"minified a href", `<a class="b a" href=/></a>`, f("a", "a b", "")},
 
                {"AlpineJS bind 1", `<body>
                        <div x-bind:class="{