gitee.com/mirrors/Hugo-Go@v0.47.1/hugolib/resource_chain_test.go (about) 1 // Copyright 2018 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package hugolib 15 16 import ( 17 "os" 18 "path/filepath" 19 "testing" 20 21 "github.com/spf13/viper" 22 23 "github.com/stretchr/testify/require" 24 25 "github.com/gohugoio/hugo/hugofs" 26 27 "github.com/gohugoio/hugo/common/loggers" 28 "github.com/gohugoio/hugo/resource/tocss/scss" 29 ) 30 31 func TestSCSSWithIncludePaths(t *testing.T) { 32 if !scss.Supports() { 33 t.Skip("Skip SCSS") 34 } 35 assert := require.New(t) 36 workDir, clean, err := createTempDir("hugo-scss-include") 37 assert.NoError(err) 38 defer clean() 39 40 v := viper.New() 41 v.Set("workingDir", workDir) 42 b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger()) 43 b.WithViper(v) 44 b.WithWorkingDir(workDir) 45 // Need to use OS fs for this. 46 b.Fs = hugofs.NewDefault(v) 47 48 fooDir := filepath.Join(workDir, "node_modules", "foo") 49 scssDir := filepath.Join(workDir, "assets", "scss") 50 assert.NoError(os.MkdirAll(fooDir, 0777)) 51 assert.NoError(os.MkdirAll(filepath.Join(workDir, "content", "sect"), 0777)) 52 assert.NoError(os.MkdirAll(filepath.Join(workDir, "data"), 0777)) 53 assert.NoError(os.MkdirAll(filepath.Join(workDir, "i18n"), 0777)) 54 assert.NoError(os.MkdirAll(filepath.Join(workDir, "layouts", "shortcodes"), 0777)) 55 assert.NoError(os.MkdirAll(filepath.Join(workDir, "layouts", "_default"), 0777)) 56 assert.NoError(os.MkdirAll(filepath.Join(scssDir), 0777)) 57 58 b.WithSourceFile(filepath.Join(fooDir, "_moo.scss"), ` 59 $moolor: #fff; 60 61 moo { 62 color: $moolor; 63 } 64 `) 65 66 b.WithSourceFile(filepath.Join(scssDir, "main.scss"), ` 67 @import "moo"; 68 69 `) 70 71 b.WithTemplatesAdded("index.html", ` 72 {{ $cssOpts := (dict "includePaths" (slice "node_modules/foo" ) ) }} 73 {{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts | minify }} 74 T1: {{ $r.Content }} 75 `) 76 b.Build(BuildCfg{}) 77 78 b.AssertFileContent(filepath.Join(workDir, "public/index.html"), `T1: moo{color:#fff}`) 79 80 } 81 82 func TestSCSSWithThemeOverrides(t *testing.T) { 83 if !scss.Supports() { 84 t.Skip("Skip SCSS") 85 } 86 assert := require.New(t) 87 workDir, clean, err := createTempDir("hugo-scss-include") 88 assert.NoError(err) 89 defer clean() 90 91 theme := "mytheme" 92 themesDir := filepath.Join(workDir, "themes") 93 themeDirs := filepath.Join(themesDir, theme) 94 v := viper.New() 95 v.Set("workingDir", workDir) 96 v.Set("theme", theme) 97 b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger()) 98 b.WithViper(v) 99 b.WithWorkingDir(workDir) 100 // Need to use OS fs for this. 101 b.Fs = hugofs.NewDefault(v) 102 103 fooDir := filepath.Join(workDir, "node_modules", "foo") 104 scssDir := filepath.Join(workDir, "assets", "scss") 105 scssThemeDir := filepath.Join(themeDirs, "assets", "scss") 106 assert.NoError(os.MkdirAll(fooDir, 0777)) 107 assert.NoError(os.MkdirAll(filepath.Join(workDir, "content", "sect"), 0777)) 108 assert.NoError(os.MkdirAll(filepath.Join(workDir, "data"), 0777)) 109 assert.NoError(os.MkdirAll(filepath.Join(workDir, "i18n"), 0777)) 110 assert.NoError(os.MkdirAll(filepath.Join(workDir, "layouts", "shortcodes"), 0777)) 111 assert.NoError(os.MkdirAll(filepath.Join(workDir, "layouts", "_default"), 0777)) 112 assert.NoError(os.MkdirAll(filepath.Join(scssDir, "components"), 0777)) 113 assert.NoError(os.MkdirAll(filepath.Join(scssThemeDir, "components"), 0777)) 114 115 b.WithSourceFile(filepath.Join(scssThemeDir, "components", "_imports.scss"), ` 116 @import "moo"; 117 @import "_boo"; 118 `) 119 120 b.WithSourceFile(filepath.Join(scssThemeDir, "components", "_moo.scss"), ` 121 $moolor: #fff; 122 123 moo { 124 color: $moolor; 125 } 126 `) 127 128 b.WithSourceFile(filepath.Join(scssThemeDir, "components", "_boo.scss"), ` 129 $boolor: orange; 130 131 boo { 132 color: $boolor; 133 } 134 `) 135 136 b.WithSourceFile(filepath.Join(scssThemeDir, "main.scss"), ` 137 @import "components/imports"; 138 139 `) 140 141 b.WithSourceFile(filepath.Join(scssDir, "components", "_moo.scss"), ` 142 $moolor: #ccc; 143 144 moo { 145 color: $moolor; 146 } 147 `) 148 149 b.WithSourceFile(filepath.Join(scssDir, "components", "_boo.scss"), ` 150 $boolor: green; 151 152 boo { 153 color: $boolor; 154 } 155 `) 156 157 b.WithTemplatesAdded("index.html", ` 158 {{ $cssOpts := (dict "includePaths" (slice "node_modules/foo" ) ) }} 159 {{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts | minify }} 160 T1: {{ $r.Content }} 161 `) 162 b.Build(BuildCfg{}) 163 164 b.AssertFileContent(filepath.Join(workDir, "public/index.html"), `T1: moo{color:#ccc}boo{color:green}`) 165 166 } 167 168 func TestResourceChain(t *testing.T) { 169 t.Parallel() 170 171 tests := []struct { 172 name string 173 shouldRun func() bool 174 prepare func(b *sitesBuilder) 175 verify func(b *sitesBuilder) 176 }{ 177 {"tocss", func() bool { return scss.Supports() }, func(b *sitesBuilder) { 178 b.WithTemplates("home.html", ` 179 {{ $scss := resources.Get "scss/styles2.scss" | toCSS }} 180 {{ $sass := resources.Get "sass/styles3.sass" | toCSS }} 181 {{ $scssCustomTarget := resources.Get "scss/styles2.scss" | toCSS (dict "targetPath" "styles/main.css") }} 182 {{ $scssCustomTargetString := resources.Get "scss/styles2.scss" | toCSS "styles/main.css" }} 183 {{ $scssMin := resources.Get "scss/styles2.scss" | toCSS | minify }} 184 {{ $scssFromTempl := ".{{ .Kind }} { color: blue; }" | resources.FromString "kindofblue.templ" | resources.ExecuteAsTemplate "kindofblue.scss" . | toCSS (dict "targetPath" "styles/templ.css") | minify }} 185 {{ $bundle1 := slice $scssFromTempl $scssMin | resources.Concat "styles/bundle1.css" }} 186 T1: Len Content: {{ len $scss.Content }}|RelPermalink: {{ $scss.RelPermalink }}|Permalink: {{ $scss.Permalink }}|MediaType: {{ $scss.MediaType.Type }} 187 T2: Content: {{ $scssMin.Content }}|RelPermalink: {{ $scssMin.RelPermalink }} 188 T3: Content: {{ len $scssCustomTarget.Content }}|RelPermalink: {{ $scssCustomTarget.RelPermalink }}|MediaType: {{ $scssCustomTarget.MediaType.Type }} 189 T4: Content: {{ len $scssCustomTargetString.Content }}|RelPermalink: {{ $scssCustomTargetString.RelPermalink }}|MediaType: {{ $scssCustomTargetString.MediaType.Type }} 190 T5: Content: {{ $sass.Content }}|T5 RelPermalink: {{ $sass.RelPermalink }}| 191 T6: {{ $bundle1.Permalink }} 192 `) 193 }, func(b *sitesBuilder) { 194 b.AssertFileContent("public/index.html", `T1: Len Content: 24|RelPermalink: /scss/styles2.css|Permalink: http://example.com/scss/styles2.css|MediaType: text/css`) 195 b.AssertFileContent("public/index.html", `T2: Content: body{color:#333}|RelPermalink: /scss/styles2.min.css`) 196 b.AssertFileContent("public/index.html", `T3: Content: 24|RelPermalink: /styles/main.css|MediaType: text/css`) 197 b.AssertFileContent("public/index.html", `T4: Content: 24|RelPermalink: /styles/main.css|MediaType: text/css`) 198 b.AssertFileContent("public/index.html", `T5: Content: .content-navigation {`) 199 b.AssertFileContent("public/index.html", `T5 RelPermalink: /sass/styles3.css|`) 200 b.AssertFileContent("public/index.html", `T6: http://example.com/styles/bundle1.css`) 201 202 b.AssertFileContent("public/styles/templ.min.css", `.home{color:blue}`) 203 b.AssertFileContent("public/styles/bundle1.css", `.home{color:blue}body{color:#333}`) 204 205 }}, 206 207 {"minify", func() bool { return true }, func(b *sitesBuilder) { 208 b.WithTemplates("home.html", ` 209 Min CSS: {{ ( resources.Get "css/styles1.css" | minify ).Content }} 210 Min JS: {{ ( resources.Get "js/script1.js" | resources.Minify ).Content | safeJS }} 211 Min JSON: {{ ( resources.Get "mydata/json1.json" | resources.Minify ).Content | safeHTML }} 212 Min XML: {{ ( resources.Get "mydata/xml1.xml" | resources.Minify ).Content | safeHTML }} 213 Min SVG: {{ ( resources.Get "mydata/svg1.svg" | resources.Minify ).Content | safeHTML }} 214 Min SVG again: {{ ( resources.Get "mydata/svg1.svg" | resources.Minify ).Content | safeHTML }} 215 Min HTML: {{ ( resources.Get "mydata/html1.html" | resources.Minify ).Content | safeHTML }} 216 217 218 `) 219 }, func(b *sitesBuilder) { 220 b.AssertFileContent("public/index.html", `Min CSS: h1{font-style:bold}`) 221 b.AssertFileContent("public/index.html", `Min JS: var x;x=5;document.getElementById("demo").innerHTML=x*10;`) 222 b.AssertFileContent("public/index.html", `Min JSON: {"employees":[{"firstName":"John","lastName":"Doe"},{"firstName":"Anna","lastName":"Smith"},{"firstName":"Peter","lastName":"Jones"}]}`) 223 b.AssertFileContent("public/index.html", `Min XML: <hello><world>Hugo Rocks!</<world></hello>`) 224 b.AssertFileContent("public/index.html", `Min SVG: <svg height="100" width="100"><path d="M5 10 20 40z"/></svg>`) 225 b.AssertFileContent("public/index.html", `Min SVG again: <svg height="100" width="100"><path d="M5 10 20 40z"/></svg>`) 226 b.AssertFileContent("public/index.html", `Min HTML: <html><a href=#>Cool</a></html>`) 227 }}, 228 229 {"concat", func() bool { return true }, func(b *sitesBuilder) { 230 b.WithTemplates("home.html", ` 231 {{ $a := "A" | resources.FromString "a.txt"}} 232 {{ $b := "B" | resources.FromString "b.txt"}} 233 {{ $c := "C" | resources.FromString "c.txt"}} 234 {{ $textResources := .Resources.Match "*.txt" }} 235 {{ $combined := slice $a $b $c | resources.Concat "bundle/concat.txt" }} 236 T1: Content: {{ $combined.Content }}|RelPermalink: {{ $combined.RelPermalink }}|Permalink: {{ $combined.Permalink }}|MediaType: {{ $combined.MediaType.Type }} 237 {{ with $textResources }} 238 {{ $combinedText := . | resources.Concat "bundle/concattxt.txt" }} 239 T2: Content: {{ $combinedText.Content }}|{{ $combinedText.RelPermalink }} 240 {{ end }} 241 `) 242 }, func(b *sitesBuilder) { 243 b.AssertFileContent("public/index.html", `T1: Content: ABC|RelPermalink: /bundle/concat.txt|Permalink: http://example.com/bundle/concat.txt|MediaType: text/plain`) 244 b.AssertFileContent("public/bundle/concat.txt", "ABC") 245 246 b.AssertFileContent("public/index.html", `T2: Content: t1t|t2t|`) 247 b.AssertFileContent("public/bundle/concattxt.txt", "t1t|t2t|") 248 }}, 249 {"fromstring", func() bool { return true }, func(b *sitesBuilder) { 250 b.WithTemplates("home.html", ` 251 {{ $r := "Hugo Rocks!" | resources.FromString "rocks/hugo.txt" }} 252 {{ $r.Content }}|{{ $r.RelPermalink }}|{{ $r.Permalink }}|{{ $r.MediaType.Type }} 253 `) 254 255 }, func(b *sitesBuilder) { 256 b.AssertFileContent("public/index.html", `Hugo Rocks!|/rocks/hugo.txt|http://example.com/rocks/hugo.txt|text/plain`) 257 b.AssertFileContent("public/rocks/hugo.txt", "Hugo Rocks!") 258 259 }}, 260 {"execute-as-template", func() bool { return true }, func(b *sitesBuilder) { 261 b.WithTemplates("home.html", ` 262 263 {{ $result := "{{ .Kind | upper }}" | resources.FromString "mytpl.txt" | resources.ExecuteAsTemplate "result.txt" . }} 264 T1: {{ $result.Content }}|{{ $result.RelPermalink}}|{{$result.MediaType.Type }} 265 `) 266 267 }, func(b *sitesBuilder) { 268 b.AssertFileContent("public/index.html", `T1: HOME|/result.txt|text/plain`) 269 270 }}, 271 {"fingerprint", func() bool { return true }, func(b *sitesBuilder) { 272 b.WithTemplates("home.html", ` 273 {{ $r := "ab" | resources.FromString "rocks/hugo.txt" }} 274 {{ $result := $r | fingerprint }} 275 {{ $result512 := $r | fingerprint "sha512" }} 276 {{ $resultMD5 := $r | fingerprint "md5" }} 277 T1: {{ $result.Content }}|{{ $result.RelPermalink}}|{{$result.MediaType.Type }}|{{ $result.Data.Integrity }}| 278 T2: {{ $result512.Content }}|{{ $result512.RelPermalink}}|{{$result512.MediaType.Type }}|{{ $result512.Data.Integrity }}| 279 T3: {{ $resultMD5.Content }}|{{ $resultMD5.RelPermalink}}|{{$resultMD5.MediaType.Type }}|{{ $resultMD5.Data.Integrity }}| 280 `) 281 }, func(b *sitesBuilder) { 282 b.AssertFileContent("public/index.html", `T1: ab|/rocks/hugo.fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603.txt|text/plain|sha256-+44g/C5MPySMYMOb1lLzwTRymLuXe4tNWQO4UFViBgM=|`) 283 b.AssertFileContent("public/index.html", `T2: ab|/rocks/hugo.2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d.txt|text/plain|sha512-LUCKBxfsGIFYJ4p5bGiQRDYdxv3eKNbwSXO4CJbhgjl1zb8S62P54FkTKO4jXYDptb8apqRPRhf/PK9kAOsXLQ==|`) 284 b.AssertFileContent("public/index.html", `T3: ab|/rocks/hugo.187ef4436122d1cc2f40dc2b92f0eba0.txt|text/plain|md5-GH70Q2Ei0cwvQNwrkvDroA==|`) 285 }}, 286 {"template", func() bool { return true }, func(b *sitesBuilder) {}, func(b *sitesBuilder) { 287 }}, 288 } 289 290 for _, test := range tests { 291 if !test.shouldRun() { 292 t.Log("Skip", test.name) 293 continue 294 } 295 296 b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger()) 297 b.WithSimpleConfigFile() 298 b.WithContent("_index.md", ` 299 --- 300 title: Home 301 --- 302 303 Home. 304 305 `, 306 "page1.md", ` 307 --- 308 title: Hello1 309 --- 310 311 Hello1 312 `, 313 "page2.md", ` 314 --- 315 title: Hello2 316 --- 317 318 Hello2 319 `, 320 "t1.txt", "t1t|", 321 "t2.txt", "t2t|", 322 ) 323 324 b.WithSourceFile(filepath.Join("assets", "css", "styles1.css"), ` 325 h1 { 326 font-style: bold; 327 } 328 `) 329 330 b.WithSourceFile(filepath.Join("assets", "js", "script1.js"), ` 331 var x; 332 x = 5; 333 document.getElementById("demo").innerHTML = x * 10; 334 `) 335 336 b.WithSourceFile(filepath.Join("assets", "mydata", "json1.json"), ` 337 { 338 "employees":[ 339 {"firstName":"John", "lastName":"Doe"}, 340 {"firstName":"Anna", "lastName":"Smith"}, 341 {"firstName":"Peter", "lastName":"Jones"} 342 ] 343 } 344 `) 345 346 b.WithSourceFile(filepath.Join("assets", "mydata", "svg1.svg"), ` 347 <svg height="100" width="100"> 348 <line x1="5" y1="10" x2="20" y2="40"/> 349 </svg> 350 `) 351 352 b.WithSourceFile(filepath.Join("assets", "mydata", "xml1.xml"), ` 353 <hello> 354 <world>Hugo Rocks!</<world> 355 </hello> 356 `) 357 358 b.WithSourceFile(filepath.Join("assets", "mydata", "html1.html"), ` 359 <html> 360 <a href="#"> 361 Cool 362 </a > 363 </html> 364 `) 365 366 b.WithSourceFile(filepath.Join("assets", "scss", "styles2.scss"), ` 367 $color: #333; 368 369 body { 370 color: $color; 371 } 372 `) 373 374 b.WithSourceFile(filepath.Join("assets", "sass", "styles3.sass"), ` 375 $color: #333; 376 377 .content-navigation 378 border-color: $color 379 380 `) 381 382 t.Log("Test", test.name) 383 test.prepare(b) 384 b.Build(BuildCfg{}) 385 test.verify(b) 386 } 387 } 388 389 func TestMultiSiteResource(t *testing.T) { 390 t.Parallel() 391 assert := require.New(t) 392 393 b := newMultiSiteTestDefaultBuilder(t) 394 395 b.CreateSites().Build(BuildCfg{}) 396 397 // This build is multilingual, but not multihost. There should be only one pipes.txt 398 b.AssertFileContent("public/fr/index.html", "French Home Page", "String Resource: /blog/text/pipes.txt") 399 assert.False(b.CheckExists("public/fr/text/pipes.txt")) 400 assert.False(b.CheckExists("public/en/text/pipes.txt")) 401 b.AssertFileContent("public/en/index.html", "Default Home Page", "String Resource: /blog/text/pipes.txt") 402 b.AssertFileContent("public/text/pipes.txt", "Hugo Pipes") 403 404 }