github.com/oneingfw/hugo@v0.47.1/hugolib/page_bundler_test.go (about) 1 // Copyright 2017-present 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 "github.com/gohugoio/hugo/common/loggers" 18 19 "os" 20 "runtime" 21 "testing" 22 23 "github.com/gohugoio/hugo/helpers" 24 25 "io" 26 27 "github.com/spf13/afero" 28 29 "github.com/gohugoio/hugo/media" 30 31 "path/filepath" 32 33 "fmt" 34 35 "github.com/gohugoio/hugo/deps" 36 "github.com/gohugoio/hugo/hugofs" 37 "github.com/spf13/viper" 38 39 "github.com/stretchr/testify/require" 40 ) 41 42 func TestPageBundlerSiteRegular(t *testing.T) { 43 t.Parallel() 44 45 for _, ugly := range []bool{false, true} { 46 t.Run(fmt.Sprintf("ugly=%t", ugly), 47 func(t *testing.T) { 48 49 assert := require.New(t) 50 fs, cfg := newTestBundleSources(t) 51 assert.NoError(loadDefaultSettingsFor(cfg)) 52 assert.NoError(loadLanguageSettings(cfg, nil)) 53 54 cfg.Set("permalinks", map[string]string{ 55 "a": ":sections/:filename", 56 "b": ":year/:slug/", 57 "c": ":sections/:slug", 58 "": ":filename/", 59 }) 60 61 cfg.Set("outputFormats", map[string]interface{}{ 62 "CUSTOMO": map[string]interface{}{ 63 "mediaType": media.HTMLType, 64 "baseName": "cindex", 65 "path": "cpath", 66 }, 67 }) 68 69 cfg.Set("outputs", map[string]interface{}{ 70 "home": []string{"HTML", "CUSTOMO"}, 71 "page": []string{"HTML", "CUSTOMO"}, 72 "section": []string{"HTML", "CUSTOMO"}, 73 }) 74 75 cfg.Set("uglyURLs", ugly) 76 77 s := buildSingleSite(t, deps.DepsCfg{Logger: loggers.NewWarningLogger(), Fs: fs, Cfg: cfg}, BuildCfg{}) 78 79 th := testHelper{s.Cfg, s.Fs, t} 80 81 assert.Len(s.RegularPages, 8) 82 83 singlePage := s.getPage(KindPage, "a/1.md") 84 assert.Equal("", singlePage.BundleType()) 85 86 assert.NotNil(singlePage) 87 assert.Equal(singlePage, s.getPage("page", "a/1")) 88 assert.Equal(singlePage, s.getPage("page", "1")) 89 90 assert.Contains(singlePage.content(), "TheContent") 91 92 if ugly { 93 assert.Equal("/a/1.html", singlePage.RelPermalink()) 94 th.assertFileContent(filepath.FromSlash("/work/public/a/1.html"), "TheContent") 95 96 } else { 97 assert.Equal("/a/1/", singlePage.RelPermalink()) 98 th.assertFileContent(filepath.FromSlash("/work/public/a/1/index.html"), "TheContent") 99 } 100 101 th.assertFileContent(filepath.FromSlash("/work/public/images/hugo-logo.png"), "content") 102 103 // This should be just copied to destination. 104 th.assertFileContent(filepath.FromSlash("/work/public/assets/pic1.png"), "content") 105 106 leafBundle1 := s.getPage(KindPage, "b/my-bundle/index.md") 107 assert.NotNil(leafBundle1) 108 assert.Equal("leaf", leafBundle1.BundleType()) 109 assert.Equal("b", leafBundle1.Section()) 110 sectionB := s.getPage(KindSection, "b") 111 assert.NotNil(sectionB) 112 home, _ := s.Info.Home() 113 assert.Equal("branch", home.BundleType()) 114 115 // This is a root bundle and should live in the "home section" 116 // See https://github.com/gohugoio/hugo/issues/4332 117 rootBundle := s.getPage(KindPage, "root") 118 assert.NotNil(rootBundle) 119 assert.True(rootBundle.Parent().IsHome()) 120 if ugly { 121 assert.Equal("/root.html", rootBundle.RelPermalink()) 122 } else { 123 assert.Equal("/root/", rootBundle.RelPermalink()) 124 } 125 126 leafBundle2 := s.getPage(KindPage, "a/b/index.md") 127 assert.NotNil(leafBundle2) 128 unicodeBundle := s.getPage(KindPage, "c/bundle/index.md") 129 assert.NotNil(unicodeBundle) 130 131 pageResources := leafBundle1.Resources.ByType(pageResourceType) 132 assert.Len(pageResources, 2) 133 firstPage := pageResources[0].(*Page) 134 secondPage := pageResources[1].(*Page) 135 assert.Equal(filepath.FromSlash("b/my-bundle/1.md"), firstPage.pathOrTitle(), secondPage.pathOrTitle()) 136 assert.Contains(firstPage.content(), "TheContent") 137 assert.Equal(6, len(leafBundle1.Resources)) 138 139 // Verify shortcode in bundled page 140 assert.Contains(secondPage.content(), filepath.FromSlash("MyShort in b/my-bundle/2.md")) 141 142 // https://github.com/gohugoio/hugo/issues/4582 143 assert.Equal(leafBundle1, firstPage.Parent()) 144 assert.Equal(leafBundle1, secondPage.Parent()) 145 146 assert.Equal(firstPage, pageResources.GetMatch("1*")) 147 assert.Equal(secondPage, pageResources.GetMatch("2*")) 148 assert.Nil(pageResources.GetMatch("doesnotexist*")) 149 150 imageResources := leafBundle1.Resources.ByType("image") 151 assert.Equal(3, len(imageResources)) 152 image := imageResources[0] 153 154 altFormat := leafBundle1.OutputFormats().Get("CUSTOMO") 155 assert.NotNil(altFormat) 156 157 assert.Equal("https://example.com/2017/pageslug/c/logo.png", image.Permalink()) 158 159 th.assertFileContent(filepath.FromSlash("/work/public/2017/pageslug/c/logo.png"), "content") 160 th.assertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug/c/logo.png"), "content") 161 162 // Custom media type defined in site config. 163 assert.Len(leafBundle1.Resources.ByType("bepsays"), 1) 164 165 if ugly { 166 assert.Equal("/2017/pageslug.html", leafBundle1.RelPermalink()) 167 th.assertFileContent(filepath.FromSlash("/work/public/2017/pageslug.html"), 168 "TheContent", 169 "Sunset RelPermalink: /2017/pageslug/sunset1.jpg", 170 "Thumb Width: 123", 171 "Thumb Name: my-sunset-1", 172 "Short Sunset RelPermalink: /2017/pageslug/sunset2.jpg", 173 "Short Thumb Width: 56", 174 "1: Image Title: Sunset Galore 1", 175 "1: Image Params: map[myparam:My Sunny Param]", 176 "2: Image Title: Sunset Galore 2", 177 "2: Image Params: map[myparam:My Sunny Param]", 178 "1: Image myParam: Lower: My Sunny Param Caps: My Sunny Param", 179 ) 180 th.assertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug.html"), "TheContent") 181 182 assert.Equal("/a/b.html", leafBundle2.RelPermalink()) 183 184 // 은행 185 assert.Equal("/c/%EC%9D%80%ED%96%89.html", unicodeBundle.RelPermalink()) 186 th.assertFileContent(filepath.FromSlash("/work/public/c/은행.html"), "Content for 은행") 187 th.assertFileContent(filepath.FromSlash("/work/public/c/은행/logo-은행.png"), "은행 PNG") 188 189 } else { 190 assert.Equal("/2017/pageslug/", leafBundle1.RelPermalink()) 191 th.assertFileContent(filepath.FromSlash("/work/public/2017/pageslug/index.html"), "TheContent") 192 th.assertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug/cindex.html"), "TheContent") 193 th.assertFileContent(filepath.FromSlash("/work/public/2017/pageslug/index.html"), "Single Title") 194 th.assertFileContent(filepath.FromSlash("/work/public/root/index.html"), "Single Title") 195 196 assert.Equal("/a/b/", leafBundle2.RelPermalink()) 197 198 } 199 200 }) 201 } 202 203 } 204 205 func TestPageBundlerSiteMultilingual(t *testing.T) { 206 t.Parallel() 207 208 for _, ugly := range []bool{false, true} { 209 t.Run(fmt.Sprintf("ugly=%t", ugly), 210 func(t *testing.T) { 211 212 assert := require.New(t) 213 fs, cfg := newTestBundleSourcesMultilingual(t) 214 cfg.Set("uglyURLs", ugly) 215 216 assert.NoError(loadDefaultSettingsFor(cfg)) 217 assert.NoError(loadLanguageSettings(cfg, nil)) 218 sites, err := NewHugoSites(deps.DepsCfg{Fs: fs, Cfg: cfg}) 219 assert.NoError(err) 220 assert.Equal(2, len(sites.Sites)) 221 222 assert.NoError(sites.Build(BuildCfg{})) 223 224 s := sites.Sites[0] 225 226 assert.Equal(8, len(s.RegularPages)) 227 assert.Equal(16, len(s.Pages)) 228 assert.Equal(31, len(s.AllPages)) 229 230 bundleWithSubPath := s.getPage(KindPage, "lb/index") 231 assert.NotNil(bundleWithSubPath) 232 233 // See https://github.com/gohugoio/hugo/issues/4312 234 // Before that issue: 235 // A bundle in a/b/index.en.md 236 // a/b/index.en.md => OK 237 // a/b/index => OK 238 // index.en.md => ambigous, but OK. 239 // With bundles, the file name has little meaning, the folder it lives in does. So this should also work: 240 // a/b 241 // and probably also just b (aka "my-bundle") 242 // These may also be translated, so we also need to test that. 243 // "bf", "my-bf-bundle", "index.md + nn 244 bfBundle := s.getPage(KindPage, "bf/my-bf-bundle/index") 245 assert.NotNil(bfBundle) 246 assert.Equal("en", bfBundle.Lang()) 247 assert.Equal(bfBundle, s.getPage(KindPage, "bf/my-bf-bundle/index.md")) 248 assert.Equal(bfBundle, s.getPage(KindPage, "bf/my-bf-bundle")) 249 assert.Equal(bfBundle, s.getPage(KindPage, "my-bf-bundle")) 250 251 nnSite := sites.Sites[1] 252 assert.Equal(7, len(nnSite.RegularPages)) 253 254 bfBundleNN := nnSite.getPage(KindPage, "bf/my-bf-bundle/index") 255 assert.NotNil(bfBundleNN) 256 assert.Equal("nn", bfBundleNN.Lang()) 257 assert.Equal(bfBundleNN, nnSite.getPage(KindPage, "bf/my-bf-bundle/index.nn.md")) 258 assert.Equal(bfBundleNN, nnSite.getPage(KindPage, "bf/my-bf-bundle")) 259 assert.Equal(bfBundleNN, nnSite.getPage(KindPage, "my-bf-bundle")) 260 261 // See https://github.com/gohugoio/hugo/issues/4295 262 // Every resource should have its Name prefixed with its base folder. 263 cBundleResources := bundleWithSubPath.Resources.Match("c/**") 264 assert.Equal(4, len(cBundleResources)) 265 bundlePage := bundleWithSubPath.Resources.GetMatch("c/page*") 266 assert.NotNil(bundlePage) 267 assert.IsType(&Page{}, bundlePage) 268 269 }) 270 } 271 } 272 273 func TestMultilingualDisableDefaultLanguage(t *testing.T) { 274 t.Parallel() 275 276 assert := require.New(t) 277 _, cfg := newTestBundleSourcesMultilingual(t) 278 279 cfg.Set("disableLanguages", []string{"en"}) 280 281 err := loadDefaultSettingsFor(cfg) 282 assert.NoError(err) 283 err = loadLanguageSettings(cfg, nil) 284 assert.Error(err) 285 assert.Contains(err.Error(), "cannot disable default language") 286 } 287 288 func TestMultilingualDisableLanguage(t *testing.T) { 289 t.Parallel() 290 291 assert := require.New(t) 292 fs, cfg := newTestBundleSourcesMultilingual(t) 293 cfg.Set("disableLanguages", []string{"nn"}) 294 295 assert.NoError(loadDefaultSettingsFor(cfg)) 296 assert.NoError(loadLanguageSettings(cfg, nil)) 297 298 sites, err := NewHugoSites(deps.DepsCfg{Fs: fs, Cfg: cfg}) 299 assert.NoError(err) 300 assert.Equal(1, len(sites.Sites)) 301 302 assert.NoError(sites.Build(BuildCfg{})) 303 304 s := sites.Sites[0] 305 306 assert.Equal(8, len(s.RegularPages)) 307 assert.Equal(16, len(s.Pages)) 308 // No nn pages 309 assert.Equal(16, len(s.AllPages)) 310 for _, p := range s.rawAllPages { 311 assert.True(p.Lang() != "nn") 312 } 313 for _, p := range s.AllPages { 314 assert.True(p.Lang() != "nn") 315 } 316 317 } 318 319 func TestPageBundlerSiteWitSymbolicLinksInContent(t *testing.T) { 320 if runtime.GOOS == "windows" && os.Getenv("CI") == "" { 321 t.Skip("Skip TestPageBundlerSiteWitSymbolicLinksInContent as os.Symlink needs administrator rights on Windows") 322 } 323 324 assert := require.New(t) 325 ps, clean, workDir := newTestBundleSymbolicSources(t) 326 defer clean() 327 328 cfg := ps.Cfg 329 fs := ps.Fs 330 331 s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg, Logger: loggers.NewErrorLogger()}, BuildCfg{}) 332 333 th := testHelper{s.Cfg, s.Fs, t} 334 335 assert.Equal(7, len(s.RegularPages)) 336 a1Bundle := s.getPage(KindPage, "symbolic2/a1/index.md") 337 assert.NotNil(a1Bundle) 338 assert.Equal(2, len(a1Bundle.Resources)) 339 assert.Equal(1, len(a1Bundle.Resources.ByType(pageResourceType))) 340 341 th.assertFileContent(filepath.FromSlash(workDir+"/public/a/page/index.html"), "TheContent") 342 th.assertFileContent(filepath.FromSlash(workDir+"/public/symbolic1/s1/index.html"), "TheContent") 343 th.assertFileContent(filepath.FromSlash(workDir+"/public/symbolic2/a1/index.html"), "TheContent") 344 345 } 346 347 func TestPageBundlerHeadless(t *testing.T) { 348 t.Parallel() 349 350 cfg, fs := newTestCfg() 351 assert := require.New(t) 352 353 workDir := "/work" 354 cfg.Set("workingDir", workDir) 355 cfg.Set("contentDir", "base") 356 cfg.Set("baseURL", "https://example.com") 357 358 pageContent := `--- 359 title: "Bundle Galore" 360 slug: s1 361 date: 2017-01-23 362 --- 363 364 TheContent. 365 366 {{< myShort >}} 367 ` 368 369 writeSource(t, fs, filepath.Join(workDir, "layouts", "_default", "single.html"), "single {{ .Content }}") 370 writeSource(t, fs, filepath.Join(workDir, "layouts", "_default", "list.html"), "list") 371 writeSource(t, fs, filepath.Join(workDir, "layouts", "shortcodes", "myShort.html"), "SHORTCODE") 372 373 writeSource(t, fs, filepath.Join(workDir, "base", "a", "index.md"), pageContent) 374 writeSource(t, fs, filepath.Join(workDir, "base", "a", "l1.png"), "PNG image") 375 writeSource(t, fs, filepath.Join(workDir, "base", "a", "l2.png"), "PNG image") 376 377 writeSource(t, fs, filepath.Join(workDir, "base", "b", "index.md"), `--- 378 title: "Headless Bundle in Topless Bar" 379 slug: s2 380 headless: true 381 date: 2017-01-23 382 --- 383 384 TheContent. 385 HEADLESS {{< myShort >}} 386 `) 387 writeSource(t, fs, filepath.Join(workDir, "base", "b", "l1.png"), "PNG image") 388 writeSource(t, fs, filepath.Join(workDir, "base", "b", "l2.png"), "PNG image") 389 writeSource(t, fs, filepath.Join(workDir, "base", "b", "p1.md"), pageContent) 390 391 s := buildSingleSite(t, deps.DepsCfg{Fs: fs, Cfg: cfg}, BuildCfg{}) 392 393 assert.Equal(1, len(s.RegularPages)) 394 assert.Equal(1, len(s.headlessPages)) 395 396 regular := s.getPage(KindPage, "a/index") 397 assert.Equal("/a/s1/", regular.RelPermalink()) 398 399 headless := s.getPage(KindPage, "b/index") 400 assert.NotNil(headless) 401 assert.True(headless.headless) 402 assert.Equal("Headless Bundle in Topless Bar", headless.Title()) 403 assert.Equal("", headless.RelPermalink()) 404 assert.Equal("", headless.Permalink()) 405 assert.Contains(headless.content(), "HEADLESS SHORTCODE") 406 407 headlessResources := headless.Resources 408 assert.Equal(3, len(headlessResources)) 409 assert.Equal(2, len(headlessResources.Match("l*"))) 410 pageResource := headlessResources.GetMatch("p*") 411 assert.NotNil(pageResource) 412 assert.IsType(&Page{}, pageResource) 413 p := pageResource.(*Page) 414 assert.Contains(p.content(), "SHORTCODE") 415 assert.Equal("p1.md", p.Name()) 416 417 th := testHelper{s.Cfg, s.Fs, t} 418 419 th.assertFileContent(filepath.FromSlash(workDir+"/public/a/s1/index.html"), "TheContent") 420 th.assertFileContent(filepath.FromSlash(workDir+"/public/a/s1/l1.png"), "PNG") 421 422 th.assertFileNotExist(workDir + "/public/b/s2/index.html") 423 // But the bundled resources needs to be published 424 th.assertFileContent(filepath.FromSlash(workDir+"/public/b/s2/l1.png"), "PNG") 425 426 } 427 428 func newTestBundleSources(t *testing.T) (*hugofs.Fs, *viper.Viper) { 429 cfg, fs := newTestCfg() 430 assert := require.New(t) 431 432 workDir := "/work" 433 cfg.Set("workingDir", workDir) 434 cfg.Set("contentDir", "base") 435 cfg.Set("baseURL", "https://example.com") 436 cfg.Set("mediaTypes", map[string]interface{}{ 437 "text/bepsays": map[string]interface{}{ 438 "suffix": "bep", 439 }, 440 }) 441 442 pageContent := `--- 443 title: "Bundle Galore" 444 slug: pageslug 445 date: 2017-10-09 446 --- 447 448 TheContent. 449 ` 450 451 pageContentShortcode := `--- 452 title: "Bundle Galore" 453 slug: pageslug 454 date: 2017-10-09 455 --- 456 457 TheContent. 458 459 {{< myShort >}} 460 ` 461 462 pageWithImageShortcodeAndResourceMetadataContent := `--- 463 title: "Bundle Galore" 464 slug: pageslug 465 date: 2017-10-09 466 resources: 467 - src: "*.jpg" 468 name: "my-sunset-:counter" 469 title: "Sunset Galore :counter" 470 params: 471 myParam: "My Sunny Param" 472 --- 473 474 TheContent. 475 476 {{< myShort >}} 477 ` 478 479 pageContentNoSlug := `--- 480 title: "Bundle Galore #2" 481 date: 2017-10-09 482 --- 483 484 TheContent. 485 ` 486 487 singleLayout := ` 488 Single Title: {{ .Title }} 489 Content: {{ .Content }} 490 {{ $sunset := .Resources.GetMatch "my-sunset-1*" }} 491 {{ with $sunset }} 492 Sunset RelPermalink: {{ .RelPermalink }} 493 {{ $thumb := .Fill "123x123" }} 494 Thumb Width: {{ $thumb.Width }} 495 Thumb Name: {{ $thumb.Name }} 496 Thumb Title: {{ $thumb.Title }} 497 Thumb RelPermalink: {{ $thumb.RelPermalink }} 498 {{ end }} 499 {{ range $i, $e := .Resources.ByType "image" }} 500 {{ $i }}: Image Title: {{ .Title }} 501 {{ $i }}: Image Name: {{ .Name }} 502 {{ $i }}: Image Params: {{ printf "%v" .Params }} 503 {{ $i }}: Image myParam: Lower: {{ .Params.myparam }} Caps: {{ .Params.MYPARAM }} 504 {{ end }} 505 ` 506 507 myShort := ` 508 MyShort in {{ .Page.Path }}: 509 {{ $sunset := .Page.Resources.GetMatch "my-sunset-2*" }} 510 {{ with $sunset }} 511 Short Sunset RelPermalink: {{ .RelPermalink }} 512 {{ $thumb := .Fill "56x56" }} 513 Short Thumb Width: {{ $thumb.Width }} 514 {{ end }} 515 ` 516 517 listLayout := `{{ .Title }}|{{ .Content }}` 518 519 writeSource(t, fs, filepath.Join(workDir, "layouts", "_default", "single.html"), singleLayout) 520 writeSource(t, fs, filepath.Join(workDir, "layouts", "_default", "list.html"), listLayout) 521 writeSource(t, fs, filepath.Join(workDir, "layouts", "shortcodes", "myShort.html"), myShort) 522 523 writeSource(t, fs, filepath.Join(workDir, "base", "_index.md"), pageContent) 524 writeSource(t, fs, filepath.Join(workDir, "base", "_1.md"), pageContent) 525 writeSource(t, fs, filepath.Join(workDir, "base", "_1.png"), pageContent) 526 527 writeSource(t, fs, filepath.Join(workDir, "base", "images", "hugo-logo.png"), "content") 528 writeSource(t, fs, filepath.Join(workDir, "base", "a", "2.md"), pageContent) 529 writeSource(t, fs, filepath.Join(workDir, "base", "a", "1.md"), pageContent) 530 531 writeSource(t, fs, filepath.Join(workDir, "base", "a", "b", "index.md"), pageContentNoSlug) 532 writeSource(t, fs, filepath.Join(workDir, "base", "a", "b", "ab1.md"), pageContentNoSlug) 533 534 // Mostly plain static assets in a folder with a page in a sub folder thrown in. 535 writeSource(t, fs, filepath.Join(workDir, "base", "assets", "pic1.png"), "content") 536 writeSource(t, fs, filepath.Join(workDir, "base", "assets", "pic2.png"), "content") 537 writeSource(t, fs, filepath.Join(workDir, "base", "assets", "pages", "mypage.md"), pageContent) 538 539 // Bundle 540 writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "index.md"), pageWithImageShortcodeAndResourceMetadataContent) 541 writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "1.md"), pageContent) 542 writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "2.md"), pageContentShortcode) 543 writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "custom-mime.bep"), "bepsays") 544 writeSource(t, fs, filepath.Join(workDir, "base", "b", "my-bundle", "c", "logo.png"), "content") 545 546 // Bundle with 은행 slug 547 // See https://github.com/gohugoio/hugo/issues/4241 548 writeSource(t, fs, filepath.Join(workDir, "base", "c", "bundle", "index.md"), `--- 549 title: "은행 은행" 550 slug: 은행 551 date: 2017-10-09 552 --- 553 554 Content for 은행. 555 `) 556 557 // Bundle in root 558 writeSource(t, fs, filepath.Join(workDir, "base", "root", "index.md"), pageWithImageShortcodeAndResourceMetadataContent) 559 writeSource(t, fs, filepath.Join(workDir, "base", "root", "1.md"), pageContent) 560 writeSource(t, fs, filepath.Join(workDir, "base", "root", "c", "logo.png"), "content") 561 562 writeSource(t, fs, filepath.Join(workDir, "base", "c", "bundle", "logo-은행.png"), "은행 PNG") 563 564 // Write a real image into one of the bundle above. 565 src, err := os.Open("testdata/sunset.jpg") 566 assert.NoError(err) 567 568 // We need 2 to test https://github.com/gohugoio/hugo/issues/4202 569 out, err := fs.Source.Create(filepath.Join(workDir, "base", "b", "my-bundle", "sunset1.jpg")) 570 assert.NoError(err) 571 out2, err := fs.Source.Create(filepath.Join(workDir, "base", "b", "my-bundle", "sunset2.jpg")) 572 assert.NoError(err) 573 574 _, err = io.Copy(out, src) 575 out.Close() 576 src.Seek(0, 0) 577 _, err = io.Copy(out2, src) 578 out2.Close() 579 src.Close() 580 assert.NoError(err) 581 582 return fs, cfg 583 584 } 585 586 func newTestBundleSourcesMultilingual(t *testing.T) (*hugofs.Fs, *viper.Viper) { 587 cfg, fs := newTestCfg() 588 589 workDir := "/work" 590 cfg.Set("workingDir", workDir) 591 cfg.Set("contentDir", "base") 592 cfg.Set("baseURL", "https://example.com") 593 cfg.Set("defaultContentLanguage", "en") 594 595 langConfig := map[string]interface{}{ 596 "en": map[string]interface{}{ 597 "weight": 1, 598 "languageName": "English", 599 }, 600 "nn": map[string]interface{}{ 601 "weight": 2, 602 "languageName": "Nynorsk", 603 }, 604 } 605 606 cfg.Set("languages", langConfig) 607 608 pageContent := `--- 609 slug: pageslug 610 date: 2017-10-09 611 --- 612 613 TheContent. 614 ` 615 616 layout := `{{ .Title }}|{{ .Content }}|Lang: {{ .Site.Language.Lang }}` 617 618 writeSource(t, fs, filepath.Join(workDir, "layouts", "_default", "single.html"), layout) 619 writeSource(t, fs, filepath.Join(workDir, "layouts", "_default", "list.html"), layout) 620 621 writeSource(t, fs, filepath.Join(workDir, "base", "1s", "mypage.md"), pageContent) 622 writeSource(t, fs, filepath.Join(workDir, "base", "1s", "mypage.nn.md"), pageContent) 623 writeSource(t, fs, filepath.Join(workDir, "base", "1s", "mylogo.png"), "content") 624 625 writeSource(t, fs, filepath.Join(workDir, "base", "bb", "_index.md"), pageContent) 626 writeSource(t, fs, filepath.Join(workDir, "base", "bb", "_index.nn.md"), pageContent) 627 writeSource(t, fs, filepath.Join(workDir, "base", "bb", "en.md"), pageContent) 628 writeSource(t, fs, filepath.Join(workDir, "base", "bb", "_1.md"), pageContent) 629 writeSource(t, fs, filepath.Join(workDir, "base", "bb", "_1.nn.md"), pageContent) 630 writeSource(t, fs, filepath.Join(workDir, "base", "bb", "a.png"), "content") 631 writeSource(t, fs, filepath.Join(workDir, "base", "bb", "b.png"), "content") 632 writeSource(t, fs, filepath.Join(workDir, "base", "bb", "b.nn.png"), "content") 633 writeSource(t, fs, filepath.Join(workDir, "base", "bb", "c.nn.png"), "content") 634 writeSource(t, fs, filepath.Join(workDir, "base", "bb", "b", "d.nn.png"), "content") 635 636 writeSource(t, fs, filepath.Join(workDir, "base", "bc", "_index.md"), pageContent) 637 writeSource(t, fs, filepath.Join(workDir, "base", "bc", "page.md"), pageContent) 638 writeSource(t, fs, filepath.Join(workDir, "base", "bc", "logo-bc.png"), pageContent) 639 writeSource(t, fs, filepath.Join(workDir, "base", "bc", "page.nn.md"), pageContent) 640 641 writeSource(t, fs, filepath.Join(workDir, "base", "bd", "index.md"), pageContent) 642 writeSource(t, fs, filepath.Join(workDir, "base", "bd", "page.md"), pageContent) 643 writeSource(t, fs, filepath.Join(workDir, "base", "bd", "page.nn.md"), pageContent) 644 645 writeSource(t, fs, filepath.Join(workDir, "base", "be", "_index.md"), pageContent) 646 writeSource(t, fs, filepath.Join(workDir, "base", "be", "page.md"), pageContent) 647 writeSource(t, fs, filepath.Join(workDir, "base", "be", "page.nn.md"), pageContent) 648 649 // Bundle leaf, multilingual 650 writeSource(t, fs, filepath.Join(workDir, "base", "lb", "index.md"), pageContent) 651 writeSource(t, fs, filepath.Join(workDir, "base", "lb", "index.nn.md"), pageContent) 652 writeSource(t, fs, filepath.Join(workDir, "base", "lb", "1.md"), pageContent) 653 writeSource(t, fs, filepath.Join(workDir, "base", "lb", "2.md"), pageContent) 654 writeSource(t, fs, filepath.Join(workDir, "base", "lb", "2.nn.md"), pageContent) 655 writeSource(t, fs, filepath.Join(workDir, "base", "lb", "c", "page.md"), pageContent) 656 writeSource(t, fs, filepath.Join(workDir, "base", "lb", "c", "logo.png"), "content") 657 writeSource(t, fs, filepath.Join(workDir, "base", "lb", "c", "logo.nn.png"), "content") 658 writeSource(t, fs, filepath.Join(workDir, "base", "lb", "c", "one.png"), "content") 659 writeSource(t, fs, filepath.Join(workDir, "base", "lb", "c", "d", "deep.png"), "content") 660 661 //Translated bundle in some sensible sub path. 662 writeSource(t, fs, filepath.Join(workDir, "base", "bf", "my-bf-bundle", "index.md"), pageContent) 663 writeSource(t, fs, filepath.Join(workDir, "base", "bf", "my-bf-bundle", "index.nn.md"), pageContent) 664 writeSource(t, fs, filepath.Join(workDir, "base", "bf", "my-bf-bundle", "page.md"), pageContent) 665 666 return fs, cfg 667 } 668 669 func newTestBundleSymbolicSources(t *testing.T) (*helpers.PathSpec, func(), string) { 670 assert := require.New(t) 671 // We need to use the OS fs for this. 672 cfg := viper.New() 673 fs := hugofs.NewFrom(hugofs.Os, cfg) 674 fs.Destination = &afero.MemMapFs{} 675 loadDefaultSettingsFor(cfg) 676 677 workDir, clean, err := createTempDir("hugosym") 678 assert.NoError(err) 679 680 contentDir := "base" 681 cfg.Set("workingDir", workDir) 682 cfg.Set("contentDir", contentDir) 683 cfg.Set("baseURL", "https://example.com") 684 685 if err := loadLanguageSettings(cfg, nil); err != nil { 686 t.Fatal(err) 687 } 688 689 layout := `{{ .Title }}|{{ .Content }}` 690 pageContent := `--- 691 slug: %s 692 date: 2017-10-09 693 --- 694 695 TheContent. 696 ` 697 698 fs.Source.MkdirAll(filepath.Join(workDir, "layouts", "_default"), 0777) 699 fs.Source.MkdirAll(filepath.Join(workDir, contentDir), 0777) 700 fs.Source.MkdirAll(filepath.Join(workDir, contentDir, "a"), 0777) 701 for i := 1; i <= 3; i++ { 702 fs.Source.MkdirAll(filepath.Join(workDir, fmt.Sprintf("symcontent%d", i)), 0777) 703 704 } 705 fs.Source.MkdirAll(filepath.Join(workDir, "symcontent2", "a1"), 0777) 706 707 writeSource(t, fs, filepath.Join(workDir, "layouts", "_default", "single.html"), layout) 708 writeSource(t, fs, filepath.Join(workDir, "layouts", "_default", "list.html"), layout) 709 710 writeSource(t, fs, filepath.Join(workDir, contentDir, "a", "regular.md"), fmt.Sprintf(pageContent, "a1")) 711 712 // Regular files inside symlinked folder. 713 writeSource(t, fs, filepath.Join(workDir, "symcontent1", "s1.md"), fmt.Sprintf(pageContent, "s1")) 714 writeSource(t, fs, filepath.Join(workDir, "symcontent1", "s2.md"), fmt.Sprintf(pageContent, "s2")) 715 716 // A bundle 717 writeSource(t, fs, filepath.Join(workDir, "symcontent2", "a1", "index.md"), fmt.Sprintf(pageContent, "")) 718 writeSource(t, fs, filepath.Join(workDir, "symcontent2", "a1", "page.md"), fmt.Sprintf(pageContent, "page")) 719 writeSource(t, fs, filepath.Join(workDir, "symcontent2", "a1", "logo.png"), "image") 720 721 // Assets 722 writeSource(t, fs, filepath.Join(workDir, "symcontent3", "s1.png"), "image") 723 writeSource(t, fs, filepath.Join(workDir, "symcontent3", "s2.png"), "image") 724 725 wd, _ := os.Getwd() 726 defer func() { 727 os.Chdir(wd) 728 }() 729 // Symlinked sections inside content. 730 os.Chdir(filepath.Join(workDir, contentDir)) 731 for i := 1; i <= 3; i++ { 732 assert.NoError(os.Symlink(filepath.FromSlash(fmt.Sprintf(("../symcontent%d"), i)), fmt.Sprintf("symbolic%d", i))) 733 } 734 735 os.Chdir(filepath.Join(workDir, contentDir, "a")) 736 737 // Create a symlink to one single content file 738 assert.NoError(os.Symlink(filepath.FromSlash("../../symcontent2/a1/page.md"), "page_s.md")) 739 740 os.Chdir(filepath.FromSlash("../../symcontent3")) 741 742 // Create a circular symlink. Will print some warnings. 743 assert.NoError(os.Symlink(filepath.Join("..", contentDir), filepath.FromSlash("circus"))) 744 745 os.Chdir(workDir) 746 assert.NoError(err) 747 748 ps, _ := helpers.NewPathSpec(fs, cfg) 749 750 return ps, clean, workDir 751 }