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