template_test.go (21201B)
1 // Copyright 2016 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 "fmt" 18 "path/filepath" 19 "strings" 20 "testing" 21 22 "github.com/gohugoio/hugo/config" 23 "github.com/gohugoio/hugo/identity" 24 25 qt "github.com/frankban/quicktest" 26 "github.com/gohugoio/hugo/deps" 27 "github.com/gohugoio/hugo/hugofs" 28 "github.com/gohugoio/hugo/tpl" 29 ) 30 31 func TestTemplateLookupOrder(t *testing.T) { 32 var ( 33 fs *hugofs.Fs 34 cfg config.Provider 35 th testHelper 36 ) 37 38 // Variants base templates: 39 // 1. <current-path>/<template-name>-baseof.<suffix>, e.g. list-baseof.<suffix>. 40 // 2. <current-path>/baseof.<suffix> 41 // 3. _default/<template-name>-baseof.<suffix>, e.g. list-baseof.<suffix>. 42 // 4. _default/baseof.<suffix> 43 for _, this := range []struct { 44 name string 45 setup func(t *testing.T) 46 assert func(t *testing.T) 47 }{ 48 { 49 "Variant 1", 50 func(t *testing.T) { 51 writeSource(t, fs, filepath.Join("layouts", "section", "sect1-baseof.html"), `Base: {{block "main" .}}block{{end}}`) 52 writeSource(t, fs, filepath.Join("layouts", "section", "sect1.html"), `{{define "main"}}sect{{ end }}`) 53 }, 54 func(t *testing.T) { 55 th.assertFileContent(filepath.Join("public", "sect1", "index.html"), "Base: sect") 56 }, 57 }, 58 { 59 "Variant 2", 60 func(t *testing.T) { 61 writeSource(t, fs, filepath.Join("layouts", "baseof.html"), `Base: {{block "main" .}}block{{end}}`) 62 writeSource(t, fs, filepath.Join("layouts", "index.html"), `{{define "main"}}index{{ end }}`) 63 }, 64 func(t *testing.T) { 65 th.assertFileContent(filepath.Join("public", "index.html"), "Base: index") 66 }, 67 }, 68 { 69 "Variant 3", 70 func(t *testing.T) { 71 writeSource(t, fs, filepath.Join("layouts", "_default", "list-baseof.html"), `Base: {{block "main" .}}block{{end}}`) 72 writeSource(t, fs, filepath.Join("layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`) 73 }, 74 func(t *testing.T) { 75 th.assertFileContent(filepath.Join("public", "sect1", "index.html"), "Base: list") 76 }, 77 }, 78 { 79 "Variant 4", 80 func(t *testing.T) { 81 writeSource(t, fs, filepath.Join("layouts", "_default", "baseof.html"), `Base: {{block "main" .}}block{{end}}`) 82 writeSource(t, fs, filepath.Join("layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`) 83 }, 84 func(t *testing.T) { 85 th.assertFileContent(filepath.Join("public", "sect1", "index.html"), "Base: list") 86 }, 87 }, 88 { 89 "Variant 1, theme, use site base", 90 func(t *testing.T) { 91 cfg.Set("theme", "mytheme") 92 writeSource(t, fs, filepath.Join("layouts", "section", "sect1-baseof.html"), `Base: {{block "main" .}}block{{end}}`) 93 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "section", "sect-baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`) 94 writeSource(t, fs, filepath.Join("layouts", "section", "sect1.html"), `{{define "main"}}sect{{ end }}`) 95 }, 96 func(t *testing.T) { 97 th.assertFileContent(filepath.Join("public", "sect1", "index.html"), "Base: sect") 98 }, 99 }, 100 { 101 "Variant 1, theme, use theme base", 102 func(t *testing.T) { 103 cfg.Set("theme", "mytheme") 104 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "section", "sect1-baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`) 105 writeSource(t, fs, filepath.Join("layouts", "section", "sect1.html"), `{{define "main"}}sect{{ end }}`) 106 }, 107 func(t *testing.T) { 108 th.assertFileContent(filepath.Join("public", "sect1", "index.html"), "Base Theme: sect") 109 }, 110 }, 111 { 112 "Variant 4, theme, use site base", 113 func(t *testing.T) { 114 cfg.Set("theme", "mytheme") 115 writeSource(t, fs, filepath.Join("layouts", "_default", "baseof.html"), `Base: {{block "main" .}}block{{end}}`) 116 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "_default", "baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`) 117 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`) 118 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "index.html"), `{{define "main"}}index{{ end }}`) 119 }, 120 func(t *testing.T) { 121 th.assertFileContent(filepath.Join("public", "sect1", "index.html"), "Base: list") 122 th.assertFileContent(filepath.Join("public", "index.html"), "Base: index") // Issue #3505 123 }, 124 }, 125 { 126 "Variant 4, theme, use themes base", 127 func(t *testing.T) { 128 cfg.Set("theme", "mytheme") 129 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "_default", "baseof.html"), `Base Theme: {{block "main" .}}block{{end}}`) 130 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "_default", "list.html"), `{{define "main"}}list{{ end }}`) 131 }, 132 func(t *testing.T) { 133 th.assertFileContent(filepath.Join("public", "sect1", "index.html"), "Base Theme: list") 134 }, 135 }, 136 { 137 // Issue #3116 138 "Test section list and single template selection", 139 func(t *testing.T) { 140 cfg.Set("theme", "mytheme") 141 142 writeSource(t, fs, filepath.Join("layouts", "_default", "baseof.html"), `Base: {{block "main" .}}block{{end}}`) 143 144 // Both single and list template in /SECTION/ 145 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "sect1", "list.html"), `sect list`) 146 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "_default", "list.html"), `default list`) 147 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "sect1", "single.html"), `sect single`) 148 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "_default", "single.html"), `default single`) 149 150 // sect2 with list template in /section 151 writeSource(t, fs, filepath.Join("themes", "mytheme", "layouts", "section", "sect2.html"), `sect2 list`) 152 }, 153 func(t *testing.T) { 154 th.assertFileContent(filepath.Join("public", "sect1", "index.html"), "sect list") 155 th.assertFileContent(filepath.Join("public", "sect1", "page1", "index.html"), "sect single") 156 th.assertFileContent(filepath.Join("public", "sect2", "index.html"), "sect2 list") 157 }, 158 }, 159 { 160 // Issue #2995 161 "Test section list and single template selection with base template", 162 func(t *testing.T) { 163 writeSource(t, fs, filepath.Join("layouts", "_default", "baseof.html"), `Base Default: {{block "main" .}}block{{end}}`) 164 writeSource(t, fs, filepath.Join("layouts", "sect1", "baseof.html"), `Base Sect1: {{block "main" .}}block{{end}}`) 165 writeSource(t, fs, filepath.Join("layouts", "section", "sect2-baseof.html"), `Base Sect2: {{block "main" .}}block{{end}}`) 166 167 // Both single and list + base template in /SECTION/ 168 writeSource(t, fs, filepath.Join("layouts", "sect1", "list.html"), `{{define "main"}}sect1 list{{ end }}`) 169 writeSource(t, fs, filepath.Join("layouts", "_default", "list.html"), `{{define "main"}}default list{{ end }}`) 170 writeSource(t, fs, filepath.Join("layouts", "sect1", "single.html"), `{{define "main"}}sect single{{ end }}`) 171 writeSource(t, fs, filepath.Join("layouts", "_default", "single.html"), `{{define "main"}}default single{{ end }}`) 172 173 // sect2 with list template in /section 174 writeSource(t, fs, filepath.Join("layouts", "section", "sect2.html"), `{{define "main"}}sect2 list{{ end }}`) 175 }, 176 func(t *testing.T) { 177 th.assertFileContent(filepath.Join("public", "sect1", "index.html"), "Base Sect1", "sect1 list") 178 th.assertFileContent(filepath.Join("public", "sect1", "page1", "index.html"), "Base Sect1", "sect single") 179 th.assertFileContent(filepath.Join("public", "sect2", "index.html"), "Base Sect2", "sect2 list") 180 181 // Note that this will get the default base template and not the one in /sect2 -- because there are no 182 // single template defined in /sect2. 183 th.assertFileContent(filepath.Join("public", "sect2", "page2", "index.html"), "Base Default", "default single") 184 }, 185 }, 186 } { 187 188 this := this 189 t.Run(this.name, func(t *testing.T) { 190 // TODO(bep) there are some function vars need to pull down here to enable => t.Parallel() 191 cfg, fs = newTestCfg() 192 th = newTestHelper(cfg, fs, t) 193 194 for i := 1; i <= 3; i++ { 195 writeSource(t, fs, filepath.Join("content", fmt.Sprintf("sect%d", i), fmt.Sprintf("page%d.md", i)), `--- 196 title: Template test 197 --- 198 Some content 199 `) 200 } 201 202 this.setup(t) 203 204 buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{}) 205 // helpers.PrintFs(s.BaseFs.Layouts.Fs, "", os.Stdout) 206 this.assert(t) 207 }) 208 209 } 210 } 211 212 // https://github.com/gohugoio/hugo/issues/4895 213 func TestTemplateBOM(t *testing.T) { 214 b := newTestSitesBuilder(t).WithSimpleConfigFile() 215 bom := "\ufeff" 216 217 b.WithTemplatesAdded( 218 "_default/baseof.html", bom+` 219 Base: {{ block "main" . }}base main{{ end }}`, 220 "_default/single.html", bom+`{{ define "main" }}Hi!?{{ end }}`) 221 222 b.WithContent("page.md", `--- 223 title: "Page" 224 --- 225 226 Page Content 227 `) 228 229 b.CreateSites().Build(BuildCfg{}) 230 231 b.AssertFileContent("public/page/index.html", "Base: Hi!?") 232 } 233 234 func TestTemplateManyBaseTemplates(t *testing.T) { 235 t.Parallel() 236 b := newTestSitesBuilder(t).WithSimpleConfigFile() 237 238 numPages := 100 // To get some parallelism 239 240 pageTemplate := `--- 241 title: "Page %d" 242 layout: "layout%d" 243 --- 244 245 Content. 246 ` 247 248 singleTemplate := ` 249 {{ define "main" }}%d{{ end }} 250 ` 251 baseTemplate := ` 252 Base %d: {{ block "main" . }}FOO{{ end }} 253 ` 254 255 for i := 0; i < numPages; i++ { 256 id := i + 1 257 b.WithContent(fmt.Sprintf("page%d.md", id), fmt.Sprintf(pageTemplate, id, id)) 258 b.WithTemplates(fmt.Sprintf("_default/layout%d.html", id), fmt.Sprintf(singleTemplate, id)) 259 b.WithTemplates(fmt.Sprintf("_default/layout%d-baseof.html", id), fmt.Sprintf(baseTemplate, id)) 260 } 261 262 b.Build(BuildCfg{}) 263 for i := 0; i < numPages; i++ { 264 id := i + 1 265 b.AssertFileContent(fmt.Sprintf("public/page%d/index.html", id), fmt.Sprintf(`Base %d: %d`, id, id)) 266 } 267 } 268 269 // https://github.com/gohugoio/hugo/issues/6790 270 func TestTemplateNoBasePlease(t *testing.T) { 271 t.Parallel() 272 b := newTestSitesBuilder(t).WithSimpleConfigFile() 273 274 b.WithTemplates("_default/list.html", ` 275 {{ define "main" }} 276 Bonjour 277 {{ end }} 278 279 {{ printf "list" }} 280 281 282 `) 283 284 b.WithTemplates( 285 "_default/single.html", ` 286 {{ printf "single" }} 287 {{ define "main" }} 288 Bonjour 289 {{ end }} 290 291 292 `) 293 294 b.WithContent("blog/p1.md", `--- 295 title: The Page 296 --- 297 `) 298 299 b.Build(BuildCfg{}) 300 301 b.AssertFileContent("public/blog/p1/index.html", `single`) 302 b.AssertFileContent("public/blog/index.html", `list`) 303 } 304 305 // https://github.com/gohugoio/hugo/issues/6816 306 func TestTemplateBaseWithComment(t *testing.T) { 307 t.Parallel() 308 b := newTestSitesBuilder(t).WithSimpleConfigFile() 309 b.WithTemplatesAdded( 310 "baseof.html", `Base: {{ block "main" . }}{{ end }}`, 311 "index.html", ` 312 {{/* A comment */}} 313 {{ define "main" }} 314 Bonjour 315 {{ end }} 316 317 318 `) 319 320 b.Build(BuildCfg{}) 321 b.AssertFileContent("public/index.html", `Base: 322 Bonjour`) 323 } 324 325 func TestTemplateLookupSite(t *testing.T) { 326 t.Run("basic", func(t *testing.T) { 327 t.Parallel() 328 b := newTestSitesBuilder(t).WithSimpleConfigFile() 329 b.WithTemplates( 330 "_default/single.html", `Single: {{ .Title }}`, 331 "_default/list.html", `List: {{ .Title }}`, 332 ) 333 334 createContent := func(title string) string { 335 return fmt.Sprintf(`--- 336 title: %s 337 ---`, title) 338 } 339 340 b.WithContent( 341 "_index.md", createContent("Home Sweet Home"), 342 "p1.md", createContent("P1")) 343 344 b.CreateSites().Build(BuildCfg{}) 345 b.AssertFileContent("public/index.html", `List: Home Sweet Home`) 346 b.AssertFileContent("public/p1/index.html", `Single: P1`) 347 }) 348 349 t.Run("baseof", func(t *testing.T) { 350 t.Parallel() 351 b := newTestSitesBuilder(t).WithDefaultMultiSiteConfig() 352 353 b.WithTemplatesAdded( 354 "index.html", `{{ define "main" }}Main Home En{{ end }}`, 355 "index.fr.html", `{{ define "main" }}Main Home Fr{{ end }}`, 356 "baseof.html", `Baseof en: {{ block "main" . }}main block{{ end }}`, 357 "baseof.fr.html", `Baseof fr: {{ block "main" . }}main block{{ end }}`, 358 "mysection/baseof.html", `Baseof mysection: {{ block "main" . }}mysection block{{ end }}`, 359 "_default/single.html", `{{ define "main" }}Main Default Single{{ end }}`, 360 "_default/list.html", `{{ define "main" }}Main Default List{{ end }}`, 361 ) 362 363 b.WithContent("mysection/p1.md", `--- 364 title: My Page 365 --- 366 367 `) 368 369 b.CreateSites().Build(BuildCfg{}) 370 371 b.AssertFileContent("public/en/index.html", `Baseof en: Main Home En`) 372 b.AssertFileContent("public/fr/index.html", `Baseof fr: Main Home Fr`) 373 b.AssertFileContent("public/en/mysection/index.html", `Baseof mysection: Main Default List`) 374 b.AssertFileContent("public/en/mysection/p1/index.html", `Baseof mysection: Main Default Single`) 375 }) 376 } 377 378 func TestTemplateFuncs(t *testing.T) { 379 b := newTestSitesBuilder(t).WithDefaultMultiSiteConfig() 380 381 homeTpl := `Site: {{ site.Language.Lang }} / {{ .Site.Language.Lang }} / {{ site.BaseURL }} 382 Sites: {{ site.Sites.First.Home.Language.Lang }} 383 Hugo: {{ hugo.Generator }} 384 ` 385 386 b.WithTemplatesAdded( 387 "index.html", homeTpl, 388 "index.fr.html", homeTpl, 389 ) 390 391 b.CreateSites().Build(BuildCfg{}) 392 393 b.AssertFileContent("public/en/index.html", 394 "Site: en / en / http://example.com/blog", 395 "Sites: en", 396 "Hugo: <meta name=\"generator\" content=\"Hugo") 397 b.AssertFileContent("public/fr/index.html", 398 "Site: fr / fr / http://example.com/blog", 399 "Sites: en", 400 "Hugo: <meta name=\"generator\" content=\"Hugo", 401 ) 402 } 403 404 func TestPartialWithReturn(t *testing.T) { 405 c := qt.New(t) 406 407 newBuilder := func(t testing.TB) *sitesBuilder { 408 b := newTestSitesBuilder(t).WithSimpleConfigFile() 409 b.WithTemplatesAdded( 410 "partials/add42.tpl", ` 411 {{ $v := add . 42 }} 412 {{ return $v }} 413 `, 414 "partials/dollarContext.tpl", ` 415 {{ $v := add $ 42 }} 416 {{ return $v }} 417 `, 418 "partials/dict.tpl", ` 419 {{ $v := add $.adder 42 }} 420 {{ return $v }} 421 `, 422 "partials/complex.tpl", ` 423 {{ return add . 42 }} 424 `, "partials/hello.tpl", ` 425 {{ $v := printf "hello %s" . }} 426 {{ return $v }} 427 `, 428 ) 429 430 return b 431 } 432 433 c.Run("Return", func(c *qt.C) { 434 b := newBuilder(c) 435 436 b.WithTemplatesAdded( 437 "index.html", ` 438 Test Partials With Return Values: 439 440 add42: 50: {{ partial "add42.tpl" 8 }} 441 hello world: {{ partial "hello.tpl" "world" }} 442 dollarContext: 60: {{ partial "dollarContext.tpl" 18 }} 443 adder: 70: {{ partial "dict.tpl" (dict "adder" 28) }} 444 complex: 80: {{ partial "complex.tpl" 38 }} 445 `, 446 ) 447 448 b.CreateSites().Build(BuildCfg{}) 449 450 b.AssertFileContent("public/index.html", ` 451 add42: 50: 50 452 hello world: hello world 453 dollarContext: 60: 60 454 adder: 70: 70 455 complex: 80: 80 456 `, 457 ) 458 }) 459 } 460 461 // Issue 7528 462 func TestPartialWithZeroedArgs(t *testing.T) { 463 b := newTestSitesBuilder(t) 464 b.WithTemplatesAdded("index.html", 465 ` 466 X{{ partial "retval" dict }}X 467 X{{ partial "retval" slice }}X 468 X{{ partial "retval" "" }}X 469 X{{ partial "retval" false }}X 470 X{{ partial "retval" 0 }}X 471 {{ define "partials/retval" }} 472 {{ return 123 }} 473 {{ end }}`) 474 475 b.WithContentAdded("p.md", ``) 476 b.Build(BuildCfg{}) 477 b.AssertFileContent("public/index.html", 478 ` 479 X123X 480 X123X 481 X123X 482 X123X 483 X123X 484 `) 485 } 486 487 func TestPartialCached(t *testing.T) { 488 b := newTestSitesBuilder(t) 489 490 b.WithTemplatesAdded( 491 "index.html", ` 492 {{ $key1 := (dict "a" "av" ) }} 493 {{ $key2 := (dict "a" "av2" ) }} 494 Partial cached1: {{ partialCached "p1" "input1" $key1 }} 495 Partial cached2: {{ partialCached "p1" "input2" $key1 }} 496 Partial cached3: {{ partialCached "p1" "input3" $key2 }} 497 `, 498 499 "partials/p1.html", `partial: {{ . }}`, 500 ) 501 502 b.Build(BuildCfg{}) 503 504 b.AssertFileContent("public/index.html", ` 505 Partial cached1: partial: input1 506 Partial cached2: partial: input1 507 Partial cached3: partial: input3 508 `) 509 } 510 511 // https://github.com/gohugoio/hugo/issues/6615 512 func TestTemplateTruth(t *testing.T) { 513 b := newTestSitesBuilder(t) 514 b.WithTemplatesAdded("index.html", ` 515 {{ $p := index site.RegularPages 0 }} 516 {{ $zero := $p.ExpiryDate }} 517 {{ $notZero := time.Now }} 518 519 if: Zero: {{ if $zero }}FAIL{{ else }}OK{{ end }} 520 if: Not Zero: {{ if $notZero }}OK{{ else }}Fail{{ end }} 521 not: Zero: {{ if not $zero }}OK{{ else }}FAIL{{ end }} 522 not: Not Zero: {{ if not $notZero }}FAIL{{ else }}OK{{ end }} 523 524 with: Zero {{ with $zero }}FAIL{{ else }}OK{{ end }} 525 526 `) 527 528 b.Build(BuildCfg{}) 529 530 b.AssertFileContent("public/index.html", ` 531 if: Zero: OK 532 if: Not Zero: OK 533 not: Zero: OK 534 not: Not Zero: OK 535 with: Zero OK 536 `) 537 } 538 539 func TestTemplateDependencies(t *testing.T) { 540 b := newTestSitesBuilder(t).Running() 541 542 b.WithTemplates("index.html", ` 543 {{ $p := site.GetPage "p1" }} 544 {{ partial "p1.html" $p }} 545 {{ partialCached "p2.html" "foo" }} 546 {{ partials.Include "p3.html" "data" }} 547 {{ partials.IncludeCached "p4.html" "foo" }} 548 {{ $p := partial "p5" }} 549 {{ partial "sub/p6.html" }} 550 {{ partial "P7.html" }} 551 {{ template "_default/foo.html" }} 552 Partial nested: {{ partial "p10" }} 553 554 `, 555 "partials/p1.html", `ps: {{ .Render "li" }}`, 556 "partials/p2.html", `p2`, 557 "partials/p3.html", `p3`, 558 "partials/p4.html", `p4`, 559 "partials/p5.html", `p5`, 560 "partials/sub/p6.html", `p6`, 561 "partials/P7.html", `p7`, 562 "partials/p8.html", `p8 {{ partial "p9.html" }}`, 563 "partials/p9.html", `p9`, 564 "partials/p10.html", `p10 {{ partial "p11.html" }}`, 565 "partials/p11.html", `p11`, 566 "_default/foo.html", `foo`, 567 "_default/li.html", `li {{ partial "p8.html" }}`, 568 ) 569 570 b.WithContent("p1.md", `--- 571 title: P1 572 --- 573 574 575 `) 576 577 b.Build(BuildCfg{}) 578 579 s := b.H.Sites[0] 580 581 templ, found := s.lookupTemplate("index.html") 582 b.Assert(found, qt.Equals, true) 583 584 idset := make(map[identity.Identity]bool) 585 collectIdentities(idset, templ.(tpl.Info)) 586 b.Assert(idset, qt.HasLen, 11) 587 } 588 589 func TestTemplateGoIssues(t *testing.T) { 590 b := newTestSitesBuilder(t) 591 592 b.WithTemplatesAdded( 593 "index.html", ` 594 {{ $title := "a & b" }} 595 <script type="application/ld+json">{"@type":"WebPage","headline":"{{$title}}"}</script> 596 597 {{/* Action/commands newlines, from Go 1.16, see https://github.com/golang/go/issues/29770 */}} 598 {{ $norway := dict 599 "country" "Norway" 600 "population" "5 millions" 601 "language" "Norwegian" 602 "language_code" "nb" 603 "weather" "freezing cold" 604 "capitol" "Oslo" 605 "largest_city" "Oslo" 606 "currency" "Norwegian krone" 607 "dialing_code" "+47" 608 }} 609 610 Population in Norway is {{ 611 $norway.population 612 | lower 613 | upper 614 }} 615 616 `, 617 ) 618 619 b.Build(BuildCfg{}) 620 621 b.AssertFileContent("public/index.html", ` 622 <script type="application/ld+json">{"@type":"WebPage","headline":"a \u0026 b"}</script> 623 Population in Norway is 5 MILLIONS 624 625 `) 626 } 627 628 func collectIdentities(set map[identity.Identity]bool, provider identity.Provider) { 629 if ids, ok := provider.(identity.IdentitiesProvider); ok { 630 for _, id := range ids.GetIdentities() { 631 collectIdentities(set, id) 632 } 633 } else { 634 set[provider.GetIdentity()] = true 635 } 636 } 637 638 func ident(level int) string { 639 return strings.Repeat(" ", level) 640 } 641 642 func TestPartialInline(t *testing.T) { 643 b := newTestSitesBuilder(t) 644 645 b.WithContent("p1.md", "") 646 647 b.WithTemplates( 648 "index.html", ` 649 650 {{ $p1 := partial "p1" . }} 651 {{ $p2 := partial "p2" . }} 652 653 P1: {{ $p1 }} 654 P2: {{ $p2 }} 655 656 {{ define "partials/p1" }}Inline: p1{{ end }} 657 658 {{ define "partials/p2" }} 659 {{ $value := 32 }} 660 {{ return $value }} 661 {{ end }} 662 663 664 `, 665 ) 666 667 b.CreateSites().Build(BuildCfg{}) 668 669 b.AssertFileContent("public/index.html", 670 ` 671 P1: Inline: p1 672 P2: 32`, 673 ) 674 } 675 676 func TestPartialInlineBase(t *testing.T) { 677 b := newTestSitesBuilder(t) 678 679 b.WithContent("p1.md", "") 680 681 b.WithTemplates( 682 "baseof.html", `{{ $p3 := partial "p3" . }}P3: {{ $p3 }} 683 {{ block "main" . }}{{ end }}{{ define "partials/p3" }}Inline: p3{{ end }}`, 684 "index.html", ` 685 {{ define "main" }} 686 687 {{ $p1 := partial "p1" . }} 688 {{ $p2 := partial "p2" . }} 689 690 P1: {{ $p1 }} 691 P2: {{ $p2 }} 692 693 {{ end }} 694 695 696 {{ define "partials/p1" }}Inline: p1{{ end }} 697 698 {{ define "partials/p2" }} 699 {{ $value := 32 }} 700 {{ return $value }} 701 {{ end }} 702 703 704 `, 705 ) 706 707 b.CreateSites().Build(BuildCfg{}) 708 709 b.AssertFileContent("public/index.html", 710 ` 711 P1: Inline: p1 712 P2: 32 713 P3: Inline: p3 714 `, 715 ) 716 } 717 718 // https://github.com/gohugoio/hugo/issues/7478 719 func TestBaseWithAndWithoutDefine(t *testing.T) { 720 b := newTestSitesBuilder(t) 721 722 b.WithContent("p1.md", "---\ntitle: P\n---\nContent") 723 724 b.WithTemplates( 725 "_default/baseof.html", ` 726 ::Header Start:{{ block "header" . }}{{ end }}:Header End: 727 ::{{ block "main" . }}Main{{ end }}:: 728 `, "index.html", ` 729 {{ define "header" }} 730 Home Header 731 {{ end }} 732 {{ define "main" }} 733 This is home main 734 {{ end }} 735 `, 736 737 "_default/single.html", ` 738 {{ define "main" }} 739 This is single main 740 {{ end }} 741 `, 742 ) 743 744 b.CreateSites().Build(BuildCfg{}) 745 746 b.AssertFileContent("public/index.html", ` 747 Home Header 748 This is home main 749 `, 750 ) 751 752 b.AssertFileContent("public/p1/index.html", ` 753 ::Header Start::Header End: 754 This is single main 755 `, 756 ) 757 } 758 759 // Issue 9393. 760 func TestApplyWithNamespace(t *testing.T) { 761 b := newTestSitesBuilder(t) 762 763 b.WithTemplates( 764 "index.html", ` 765 {{ $b := slice " a " " b " " c" }} 766 {{ $a := apply $b "strings.Trim" "." " " }} 767 a: {{ $a }} 768 `, 769 ).WithContent("p1.md", "") 770 771 b.Build(BuildCfg{}) 772 773 b.AssertFileContent("public/index.html", `a: [a b c]`) 774 }