github.com/neohugo/neohugo@v0.123.8/hugolib/cascade_test.go (about) 1 // Copyright 2019 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 "bytes" 18 "fmt" 19 "path" 20 "strings" 21 "testing" 22 23 "github.com/neohugo/neohugo/common/maps" 24 25 qt "github.com/frankban/quicktest" 26 "github.com/neohugo/neohugo/parser" 27 "github.com/neohugo/neohugo/parser/metadecoders" 28 ) 29 30 func BenchmarkCascade(b *testing.B) { 31 allLangs := []string{"en", "nn", "nb", "sv", "ab", "aa", "af", "sq", "kw", "da"} 32 33 for i := 1; i <= len(allLangs); i += 2 { 34 langs := allLangs[0:i] 35 b.Run(fmt.Sprintf("langs-%d", len(langs)), func(b *testing.B) { 36 c := qt.New(b) 37 b.StopTimer() 38 builders := make([]*sitesBuilder, b.N) 39 for i := 0; i < b.N; i++ { 40 builders[i] = newCascadeTestBuilder(b, langs) 41 } 42 b.StartTimer() 43 44 for i := 0; i < b.N; i++ { 45 builder := builders[i] 46 err := builder.BuildE(BuildCfg{}) 47 c.Assert(err, qt.IsNil) 48 first := builder.H.Sites[0] 49 c.Assert(first, qt.Not(qt.IsNil)) 50 } 51 }) 52 } 53 } 54 55 func BenchmarkCascadeTarget(b *testing.B) { 56 files := ` 57 -- content/_index.md -- 58 background = 'yosemite.jpg' 59 [cascade._target] 60 kind = '{section,term}' 61 -- content/posts/_index.md -- 62 -- content/posts/funny/_index.md -- 63 ` 64 65 for i := 1; i < 100; i++ { 66 files += fmt.Sprintf("\n-- content/posts/p%d.md --\n", i+1) 67 } 68 69 for i := 1; i < 100; i++ { 70 files += fmt.Sprintf("\n-- content/posts/funny/pf%d.md --\n", i+1) 71 } 72 73 b.Run("Kind", func(b *testing.B) { 74 cfg := IntegrationTestConfig{ 75 T: b, 76 TxtarString: files, 77 } 78 builders := make([]*IntegrationTestBuilder, b.N) 79 80 for i := range builders { 81 builders[i] = NewIntegrationTestBuilder(cfg) 82 } 83 84 b.ResetTimer() 85 86 for i := 0; i < b.N; i++ { 87 builders[i].Build() 88 } 89 }) 90 } 91 92 func TestCascadeConfig(t *testing.T) { 93 c := qt.New(t) 94 95 // Make sure the cascade from config gets applied even if we're not 96 // having a content file for the home page. 97 for _, withHomeContent := range []bool{true, false} { 98 testName := "Home content file" 99 if !withHomeContent { 100 testName = "No home content file" 101 } 102 c.Run(testName, func(c *qt.C) { 103 b := newTestSitesBuilder(c) 104 105 b.WithConfigFile("toml", ` 106 baseURL="https://example.org" 107 108 [cascade] 109 img1 = "img1-config.jpg" 110 imgconfig = "img-config.jpg" 111 112 `) 113 114 if withHomeContent { 115 b.WithContent("_index.md", ` 116 --- 117 title: "Home" 118 cascade: 119 img1: "img1-home.jpg" 120 img2: "img2-home.jpg" 121 --- 122 `) 123 } 124 125 b.WithContent("p1.md", ``) 126 127 b.Build(BuildCfg{}) 128 129 p1 := b.H.Sites[0].getPageOldVersion("p1") 130 131 if withHomeContent { 132 b.Assert(p1.Params(), qt.DeepEquals, maps.Params{ 133 "imgconfig": "img-config.jpg", 134 "draft": bool(false), 135 "iscjklanguage": bool(false), 136 "img1": "img1-home.jpg", 137 "img2": "img2-home.jpg", 138 }) 139 } else { 140 b.Assert(p1.Params(), qt.DeepEquals, maps.Params{ 141 "img1": "img1-config.jpg", 142 "imgconfig": "img-config.jpg", 143 "draft": bool(false), 144 "iscjklanguage": bool(false), 145 }) 146 } 147 }) 148 149 } 150 } 151 152 func TestCascade(t *testing.T) { 153 allLangs := []string{"en", "nn", "nb", "sv"} 154 155 langs := allLangs[:3] 156 157 t.Run(fmt.Sprintf("langs-%d", len(langs)), func(t *testing.T) { 158 b := newCascadeTestBuilder(t, langs) 159 b.Build(BuildCfg{}) 160 161 // b.H.Sites[0].pageMap.debugPrint("", 999, os.Stdout) 162 163 // 12|term|/categories/cool|Cascade Category|cat.png|page|html-|\ 164 165 b.AssertFileContent("public/index.html", ` 166 12|term|/categories/cool|Cascade Category|cat.png|categories|html-| 167 12|term|/categories/catsect1|Cascade Category|cat.png|categories|html-| 168 12|term|/categories/funny|Cascade Category|cat.png|categories|html-| 169 12|taxonomy|/categories|My Categories|cat.png|categories|html-| 170 32|term|/categories/sad|Cascade Category|sad.png|categories|html-| 171 42|term|/tags/blue|Cascade Home|home.png|tags|html-| 172 42|taxonomy|/tags|Cascade Home|home.png|tags|html-| 173 42|section|/sectnocontent|Cascade Home|home.png|sectnocontent|html-| 174 42|section|/sect3|Cascade Home|home.png|sect3|html-| 175 42|page|/bundle1|Cascade Home|home.png|page|html-| 176 42|page|/p2|Cascade Home|home.png|page|html-| 177 42|page|/sect2/p2|Cascade Home|home.png|sect2|html-| 178 42|page|/sect3/nofrontmatter|Cascade Home|home.png|sect3|html-| 179 42|page|/sect3/p1|Cascade Home|home.png|sect3|html-| 180 42|page|/sectnocontent/p1|Cascade Home|home.png|sectnocontent|html-| 181 42|section|/sectnofrontmatter|Cascade Home|home.png|sectnofrontmatter|html-| 182 42|term|/tags/green|Cascade Home|home.png|tags|html-| 183 42|home|/|Home|home.png|page|html-| 184 42|page|/p1|p1|home.png|page|html-| 185 42|section|/sect1|Sect1|sect1.png|stype|html-| 186 42|section|/sect1/s1_2|Sect1_2|sect1.png|stype|html-| 187 42|page|/sect1/s1_2/p1|Sect1_2_p1|sect1.png|stype|html-| 188 42|page|/sect1/s1_2/p2|Sect1_2_p2|sect1.png|stype|html-| 189 42|section|/sect2|Sect2|home.png|sect2|html-| 190 42|page|/sect2/p1|Sect2_p1|home.png|sect2|html-| 191 52|page|/sect4/p1|Cascade Home|home.png|sect4|rss-| 192 52|section|/sect4|Sect4|home.png|sect4|rss-| 193 `) 194 195 // Check that type set in cascade gets the correct layout. 196 b.AssertFileContent("public/sect1/index.html", `stype list: Sect1`) 197 b.AssertFileContent("public/sect1/s1_2/p2/index.html", `stype single: Sect1_2_p2`) 198 199 // Check output formats set in cascade 200 b.AssertFileContent("public/sect4/index.xml", `<link>https://example.org/sect4/index.xml</link>`) 201 b.AssertFileContent("public/sect4/p1/index.xml", `<link>https://example.org/sect4/p1/index.xml</link>`) 202 b.C.Assert(b.CheckExists("public/sect2/index.xml"), qt.Equals, false) 203 204 // Check cascade into bundled page 205 b.AssertFileContent("public/bundle1/index.html", `Resources: bp1.md|home.png|`) 206 }) 207 } 208 209 func TestCascadeEdit(t *testing.T) { 210 p1Content := `--- 211 title: P1 212 --- 213 ` 214 215 indexContentNoCascade := ` 216 --- 217 title: Home 218 --- 219 ` 220 221 indexContentCascade := ` 222 --- 223 title: Section 224 cascade: 225 banner: post.jpg 226 layout: postlayout 227 type: posttype 228 --- 229 ` 230 231 layout := `Banner: {{ .Params.banner }}|Layout: {{ .Layout }}|Type: {{ .Type }}|Content: {{ .Content }}` 232 233 newSite := func(t *testing.T, cascade bool) *sitesBuilder { 234 b := newTestSitesBuilder(t).Running() 235 b.WithTemplates("_default/single.html", layout) 236 b.WithTemplates("_default/list.html", layout) 237 if cascade { 238 b.WithContent("post/_index.md", indexContentCascade) 239 } else { 240 b.WithContent("post/_index.md", indexContentNoCascade) 241 } 242 b.WithContent("post/dir/p1.md", p1Content) 243 244 return b 245 } 246 247 t.Run("Edit descendant", func(t *testing.T) { 248 t.Parallel() 249 250 b := newSite(t, true) 251 b.Build(BuildCfg{}) 252 253 assert := func() { 254 b.Helper() 255 b.AssertFileContent("public/post/dir/p1/index.html", 256 `Banner: post.jpg|`, 257 `Layout: postlayout`, 258 `Type: posttype`, 259 ) 260 } 261 262 assert() 263 264 b.EditFiles("content/post/dir/p1.md", p1Content+"\ncontent edit") 265 b.Build(BuildCfg{}) 266 267 assert() 268 b.AssertFileContent("public/post/dir/p1/index.html", 269 `content edit 270 Banner: post.jpg`, 271 ) 272 }) 273 274 t.Run("Edit ancestor", func(t *testing.T) { 275 t.Parallel() 276 277 b := newSite(t, true) 278 b.Build(BuildCfg{}) 279 280 b.AssertFileContent("public/post/dir/p1/index.html", `Banner: post.jpg|Layout: postlayout|Type: posttype|Content:`) 281 282 b.EditFiles("content/post/_index.md", strings.Replace(indexContentCascade, "post.jpg", "edit.jpg", 1)) 283 284 b.Build(BuildCfg{}) 285 286 b.AssertFileContent("public/post/index.html", `Banner: edit.jpg|Layout: postlayout|Type: posttype|`) 287 b.AssertFileContent("public/post/dir/p1/index.html", `Banner: edit.jpg|Layout: postlayout|Type: posttype|`) 288 }) 289 290 t.Run("Edit ancestor, add cascade", func(t *testing.T) { 291 t.Parallel() 292 293 b := newSite(t, true) 294 b.Build(BuildCfg{}) 295 296 b.AssertFileContent("public/post/dir/p1/index.html", `Banner: post.jpg`) 297 298 b.EditFiles("content/post/_index.md", indexContentCascade) 299 300 b.Build(BuildCfg{}) 301 302 b.AssertFileContent("public/post/index.html", `Banner: post.jpg|Layout: postlayout|Type: posttype|`) 303 b.AssertFileContent("public/post/dir/p1/index.html", `Banner: post.jpg|Layout: postlayout|`) 304 }) 305 306 t.Run("Edit ancestor, remove cascade", func(t *testing.T) { 307 t.Parallel() 308 309 b := newSite(t, false) 310 b.Build(BuildCfg{}) 311 312 b.AssertFileContent("public/post/dir/p1/index.html", `Banner: |Layout: |`) 313 314 b.EditFiles("content/post/_index.md", indexContentNoCascade) 315 316 b.Build(BuildCfg{}) 317 318 b.AssertFileContent("public/post/index.html", `Banner: |Layout: |Type: post|`) 319 b.AssertFileContent("public/post/dir/p1/index.html", `Banner: |Layout: |`) 320 }) 321 322 t.Run("Edit ancestor, content only", func(t *testing.T) { 323 t.Parallel() 324 325 b := newSite(t, true) 326 b.Build(BuildCfg{}) 327 328 b.EditFiles("content/post/_index.md", indexContentCascade+"\ncontent edit") 329 330 counters := &buildCounters{} 331 b.Build(BuildCfg{testCounters: counters}) 332 b.Assert(int(counters.contentRenderCounter.Load()), qt.Equals, 2) 333 334 b.AssertFileContent("public/post/index.html", `Banner: post.jpg|Layout: postlayout|Type: posttype|Content: <p>content edit</p>`) 335 b.AssertFileContent("public/post/dir/p1/index.html", `Banner: post.jpg|Layout: postlayout|`) 336 }) 337 } 338 339 func TestCascadeBuildOptionsTaxonomies(t *testing.T) { 340 t.Parallel() 341 342 files := ` 343 -- hugo.toml -- 344 baseURL="https://example.org" 345 [taxonomies] 346 tag = "tags" 347 348 [[cascade]] 349 350 [cascade._build] 351 render = "never" 352 list = "never" 353 publishResources = false 354 355 [cascade._target] 356 path = '/hidden/**' 357 -- content/p1.md -- 358 --- 359 title: P1 360 --- 361 -- content/hidden/p2.md -- 362 --- 363 title: P2 364 tags: [t1, t2] 365 --- 366 -- layouts/_default/list.html -- 367 List: {{ len .Pages }}| 368 -- layouts/_default/single.html -- 369 Single: Tags: {{ site.Taxonomies.tags }}| 370 ` 371 372 b := Test(t, files) 373 374 b.AssertFileContent("public/p1/index.html", "Single: Tags: map[]|") 375 b.AssertFileContent("public/tags/index.html", "List: 0|") 376 b.AssertFileExists("public/hidden/p2/index.html", false) 377 b.AssertFileExists("public/tags/t2/index.html", false) 378 } 379 380 func newCascadeTestBuilder(t testing.TB, langs []string) *sitesBuilder { 381 c := qt.New(t) 382 p := func(m map[string]any) string { 383 var yamlStr string 384 385 if len(m) > 0 { 386 var b bytes.Buffer 387 388 c.Assert(parser.InterfaceToConfig(m, metadecoders.YAML, &b), qt.IsNil) 389 yamlStr = b.String() 390 } 391 392 metaStr := "---\n" + yamlStr + "\n---" 393 394 return metaStr 395 } 396 397 createLangConfig := func(lang string) string { 398 const langEntry = ` 399 [languages.%s] 400 ` 401 return fmt.Sprintf(langEntry, lang) 402 } 403 404 createMount := func(lang string) string { 405 const mountsTempl = ` 406 [[module.mounts]] 407 source="content/%s" 408 target="content" 409 lang="%s" 410 ` 411 return fmt.Sprintf(mountsTempl, lang, lang) 412 } 413 414 config := ` 415 baseURL = "https://example.org" 416 defaultContentLanguage = "en" 417 defaultContentLanguageInSubDir = false 418 419 [languages]` 420 for _, lang := range langs { 421 config += createLangConfig(lang) 422 } 423 424 config += "\n\n[module]\n" 425 for _, lang := range langs { 426 config += createMount(lang) 427 } 428 429 b := newTestSitesBuilder(t).WithConfigFile("toml", config) 430 431 createContentFiles := func(lang string) { 432 withContent := func(filenameContent ...string) { 433 for i := 0; i < len(filenameContent); i += 2 { 434 b.WithContent(path.Join(lang, filenameContent[i]), filenameContent[i+1]) 435 } 436 } 437 438 withContent( 439 "_index.md", p(map[string]any{ 440 "title": "Home", 441 "cascade": map[string]any{ 442 "title": "Cascade Home", 443 "ICoN": "home.png", 444 "outputs": []string{"HTML"}, 445 "weight": 42, 446 }, 447 }), 448 "p1.md", p(map[string]any{ 449 "title": "p1", 450 }), 451 "p2.md", p(map[string]any{}), 452 "sect1/_index.md", p(map[string]any{ 453 "title": "Sect1", 454 "type": "stype", 455 "cascade": map[string]any{ 456 "title": "Cascade Sect1", 457 "icon": "sect1.png", 458 "type": "stype", 459 "categories": []string{"catsect1"}, 460 }, 461 }), 462 "sect1/s1_2/_index.md", p(map[string]any{ 463 "title": "Sect1_2", 464 }), 465 "sect1/s1_2/p1.md", p(map[string]any{ 466 "title": "Sect1_2_p1", 467 }), 468 "sect1/s1_2/p2.md", p(map[string]any{ 469 "title": "Sect1_2_p2", 470 }), 471 "sect2/_index.md", p(map[string]any{ 472 "title": "Sect2", 473 }), 474 "sect2/p1.md", p(map[string]any{ 475 "title": "Sect2_p1", 476 "categories": []string{"cool", "funny", "sad"}, 477 "tags": []string{"blue", "green"}, 478 }), 479 "sect2/p2.md", p(map[string]any{}), 480 "sect3/p1.md", p(map[string]any{}), 481 482 // No front matter, see #6855 483 "sect3/nofrontmatter.md", `**Hello**`, 484 "sectnocontent/p1.md", `**Hello**`, 485 "sectnofrontmatter/_index.md", `**Hello**`, 486 487 "sect4/_index.md", p(map[string]any{ 488 "title": "Sect4", 489 "cascade": map[string]any{ 490 "weight": 52, 491 "outputs": []string{"RSS"}, 492 }, 493 }), 494 "sect4/p1.md", p(map[string]any{}), 495 "p2.md", p(map[string]any{}), 496 "bundle1/index.md", p(map[string]any{}), 497 "bundle1/bp1.md", p(map[string]any{}), 498 "categories/_index.md", p(map[string]any{ 499 "title": "My Categories", 500 "cascade": map[string]any{ 501 "title": "Cascade Category", 502 "icoN": "cat.png", 503 "weight": 12, 504 }, 505 }), 506 "categories/cool/_index.md", p(map[string]any{}), 507 "categories/sad/_index.md", p(map[string]any{ 508 "cascade": map[string]any{ 509 "icon": "sad.png", 510 "weight": 32, 511 }, 512 }), 513 ) 514 } 515 516 createContentFiles("en") 517 518 b.WithTemplates("index.html", ` 519 520 {{ range .Site.Pages }} 521 {{- .Weight }}|{{ .Kind }}|{{ .Path }}|{{ .Title }}|{{ .Params.icon }}|{{ .Type }}|{{ range .OutputFormats }}{{ .Name }}-{{ end }}| 522 {{ end }} 523 `, 524 525 "_default/single.html", "default single: {{ .Title }}|{{ .RelPermalink }}|{{ .Content }}|Resources: {{ range .Resources }}{{ .Name }}|{{ .Params.icon }}|{{ .Content }}{{ end }}", 526 "_default/list.html", "default list: {{ .Title }}", 527 "stype/single.html", "stype single: {{ .Title }}|{{ .RelPermalink }}|{{ .Content }}", 528 "stype/list.html", "stype list: {{ .Title }}", 529 ) 530 531 return b 532 } 533 534 func TestCascadeTarget(t *testing.T) { 535 t.Parallel() 536 537 c := qt.New(t) 538 539 newBuilder := func(c *qt.C) *sitesBuilder { 540 b := newTestSitesBuilder(c) 541 542 b.WithTemplates("index.html", ` 543 {{ $p1 := site.GetPage "s1/p1" }} 544 {{ $s1 := site.GetPage "s1" }} 545 546 P1|p1:{{ $p1.Params.p1 }}|p2:{{ $p1.Params.p2 }}| 547 S1|p1:{{ $s1.Params.p1 }}|p2:{{ $s1.Params.p2 }}| 548 `) 549 b.WithContent("s1/_index.md", "---\ntitle: s1 section\n---") 550 b.WithContent("s1/p1/index.md", "---\ntitle: p1\n---") 551 b.WithContent("s1/p2/index.md", "---\ntitle: p2\n---") 552 b.WithContent("s2/p1/index.md", "---\ntitle: p1_2\n---") 553 554 return b 555 } 556 557 c.Run("slice", func(c *qt.C) { 558 b := newBuilder(c) 559 b.WithContent("_index.md", `+++ 560 title = "Home" 561 [[cascade]] 562 p1 = "p1" 563 [[cascade]] 564 p2 = "p2" 565 +++ 566 `) 567 568 b.Build(BuildCfg{}) 569 570 b.AssertFileContent("public/index.html", "P1|p1:p1|p2:p2") 571 }) 572 573 c.Run("slice with _target", func(c *qt.C) { 574 b := newBuilder(c) 575 576 b.WithContent("_index.md", `+++ 577 title = "Home" 578 [[cascade]] 579 p1 = "p1" 580 [cascade._target] 581 path="**p1**" 582 [[cascade]] 583 p2 = "p2" 584 [cascade._target] 585 kind="section" 586 +++ 587 `) 588 589 b.Build(BuildCfg{}) 590 591 b.AssertFileContent("public/index.html", ` 592 P1|p1:p1|p2:| 593 S1|p1:|p2:p2| 594 `) 595 }) 596 597 c.Run("slice with environment _target", func(c *qt.C) { 598 b := newBuilder(c) 599 600 b.WithContent("_index.md", `+++ 601 title = "Home" 602 [[cascade]] 603 p1 = "p1" 604 [cascade._target] 605 path="**p1**" 606 environment="testing" 607 [[cascade]] 608 p2 = "p2" 609 [cascade._target] 610 kind="section" 611 environment="production" 612 +++ 613 `) 614 615 b.Build(BuildCfg{}) 616 617 b.AssertFileContent("public/index.html", ` 618 P1|p1:|p2:| 619 S1|p1:|p2:p2| 620 `) 621 }) 622 623 c.Run("slice with yaml _target", func(c *qt.C) { 624 b := newBuilder(c) 625 626 b.WithContent("_index.md", `--- 627 title: "Home" 628 cascade: 629 - p1: p1 630 _target: 631 path: "**p1**" 632 - p2: p2 633 _target: 634 kind: "section" 635 --- 636 `) 637 638 b.Build(BuildCfg{}) 639 640 b.AssertFileContent("public/index.html", ` 641 P1|p1:p1|p2:| 642 S1|p1:|p2:p2| 643 `) 644 }) 645 646 c.Run("slice with json _target", func(c *qt.C) { 647 b := newBuilder(c) 648 649 b.WithContent("_index.md", `{ 650 "title": "Home", 651 "cascade": [ 652 { 653 "p1": "p1", 654 "_target": { 655 "path": "**p1**" 656 } 657 },{ 658 "p2": "p2", 659 "_target": { 660 "kind": "section" 661 } 662 } 663 ] 664 } 665 `) 666 667 b.Build(BuildCfg{}) 668 669 b.AssertFileContent("public/index.html", ` 670 P1|p1:p1|p2:| 671 S1|p1:|p2:p2| 672 `) 673 }) 674 } 675 676 // Issue 11977. 677 func TestCascadeExtensionInPath(t *testing.T) { 678 t.Parallel() 679 680 files := ` 681 -- hugo.toml -- 682 baseURL = "https://example.org" 683 [languages] 684 [languages.en] 685 weight = 1 686 [languages.de] 687 -- content/_index.de.md -- 688 +++ 689 [[cascade]] 690 [cascade.params] 691 foo = 'bar' 692 [cascade._target] 693 path = '/posts/post-1.de.md' 694 +++ 695 -- content/posts/post-1.de.md -- 696 --- 697 title: "Post 1" 698 --- 699 -- layouts/_default/single.html -- 700 {{ .Title }}|{{ .Params.foo }}$ 701 ` 702 b, err := TestE(t, files) 703 b.Assert(err, qt.IsNotNil) 704 b.AssertLogContains(`cascade target path "/posts/post-1.de.md" looks like a path with an extension; since Hugo v0.123.0 this will not match anything, see https://gohugo.io/methods/page/path/`) 705 } 706 707 func TestCascadeExtensionInPathIgnore(t *testing.T) { 708 t.Parallel() 709 710 files := ` 711 -- hugo.toml -- 712 baseURL = "https://example.org" 713 ignoreLogs = ['cascade-pattern-with-extension'] 714 [languages] 715 [languages.en] 716 weight = 1 717 [languages.de] 718 -- content/_index.de.md -- 719 +++ 720 [[cascade]] 721 [cascade.params] 722 foo = 'bar' 723 [cascade._target] 724 path = '/posts/post-1.de.md' 725 +++ 726 -- content/posts/post-1.de.md -- 727 --- 728 title: "Post 1" 729 --- 730 -- layouts/_default/single.html -- 731 {{ .Title }}|{{ .Params.foo }}$ 732 ` 733 b := Test(t, files) 734 b.AssertLogNotContains(`looks like a path with an extension`) 735 } 736 737 func TestCascadConfigExtensionInPath(t *testing.T) { 738 t.Parallel() 739 740 files := ` 741 -- hugo.toml -- 742 baseURL = "https://example.org" 743 [[cascade]] 744 [cascade.params] 745 foo = 'bar' 746 [cascade._target] 747 path = '/p1.md' 748 ` 749 b, err := TestE(t, files) 750 b.Assert(err, qt.IsNotNil) 751 b.AssertLogContains(`looks like a path with an extension`) 752 } 753 754 func TestCascadConfigExtensionInPathIgnore(t *testing.T) { 755 t.Parallel() 756 757 files := ` 758 -- hugo.toml -- 759 baseURL = "https://example.org" 760 ignoreLogs = ['cascade-pattern-with-extension'] 761 [[cascade]] 762 [cascade.params] 763 foo = 'bar' 764 [cascade._target] 765 path = '/p1.md' 766 ` 767 b := Test(t, files) 768 b.AssertLogNotContains(`looks like a path with an extension`) 769 } 770 771 func TestCascadeIssue12172(t *testing.T) { 772 t.Parallel() 773 774 files := ` 775 -- hugo.toml -- 776 disableKinds = ['rss','sitemap','taxonomy','term'] 777 [[cascade]] 778 headless = true 779 [cascade._target] 780 path = '/s1**' 781 -- content/s1/p1.md -- 782 --- 783 title: p1 784 --- 785 -- layouts/_default/single.html -- 786 {{ .Title }}| 787 -- layouts/_default/list.html -- 788 {{ .Title }}| 789 ` 790 b := Test(t, files) 791 792 b.AssertFileExists("public/index.html", true) 793 b.AssertFileExists("public/s1/index.html", false) 794 b.AssertFileExists("public/s1/p1/index.html", false) 795 }