github.com/jmooring/hugo@v0.47.1/hugolib/hugo_sites_build_test.go (about) 1 package hugolib 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 "testing" 8 9 "html/template" 10 "os" 11 "path/filepath" 12 "time" 13 14 "github.com/gohugoio/hugo/langs" 15 16 "github.com/fortytw2/leaktest" 17 "github.com/fsnotify/fsnotify" 18 "github.com/gohugoio/hugo/helpers" 19 "github.com/gohugoio/hugo/hugofs" 20 "github.com/spf13/afero" 21 "github.com/spf13/viper" 22 "github.com/stretchr/testify/require" 23 ) 24 25 func TestMultiSitesMainLangInRoot(t *testing.T) { 26 t.Parallel() 27 for _, b := range []bool{false} { 28 doTestMultiSitesMainLangInRoot(t, b) 29 } 30 } 31 32 func doTestMultiSitesMainLangInRoot(t *testing.T, defaultInSubDir bool) { 33 assert := require.New(t) 34 35 siteConfig := map[string]interface{}{ 36 "DefaultContentLanguage": "fr", 37 "DefaultContentLanguageInSubdir": defaultInSubDir, 38 } 39 40 b := newMultiSiteTestBuilder(t, "toml", multiSiteTOMLConfigTemplate, siteConfig) 41 42 pathMod := func(s string) string { 43 return s 44 } 45 46 if !defaultInSubDir { 47 pathMod = func(s string) string { 48 return strings.Replace(s, "/fr/", "/", -1) 49 } 50 } 51 52 b.CreateSites() 53 b.Build(BuildCfg{}) 54 55 sites := b.H.Sites 56 57 require.Len(t, sites, 4) 58 59 enSite := sites[0] 60 frSite := sites[1] 61 62 assert.Equal("/en", enSite.Info.LanguagePrefix) 63 64 if defaultInSubDir { 65 assert.Equal("/fr", frSite.Info.LanguagePrefix) 66 } else { 67 assert.Equal("", frSite.Info.LanguagePrefix) 68 } 69 70 assert.Equal("/blog/en/foo", enSite.PathSpec.RelURL("foo", true)) 71 72 doc1en := enSite.RegularPages[0] 73 doc1fr := frSite.RegularPages[0] 74 75 enPerm := doc1en.Permalink() 76 enRelPerm := doc1en.RelPermalink() 77 assert.Equal("http://example.com/blog/en/sect/doc1-slug/", enPerm) 78 assert.Equal("/blog/en/sect/doc1-slug/", enRelPerm) 79 80 frPerm := doc1fr.Permalink() 81 frRelPerm := doc1fr.RelPermalink() 82 83 b.AssertFileContent(pathMod("public/fr/sect/doc1/index.html"), "Single", "Bonjour") 84 b.AssertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Hello") 85 86 if defaultInSubDir { 87 assert.Equal("http://example.com/blog/fr/sect/doc1/", frPerm) 88 assert.Equal("/blog/fr/sect/doc1/", frRelPerm) 89 90 // should have a redirect on top level. 91 b.AssertFileContent("public/index.html", `<meta http-equiv="refresh" content="0; url=http://example.com/blog/fr" />`) 92 } else { 93 // Main language in root 94 assert.Equal("http://example.com/blog/sect/doc1/", frPerm) 95 assert.Equal("/blog/sect/doc1/", frRelPerm) 96 97 // should have redirect back to root 98 b.AssertFileContent("public/fr/index.html", `<meta http-equiv="refresh" content="0; url=http://example.com/blog" />`) 99 } 100 b.AssertFileContent(pathMod("public/fr/index.html"), "Home", "Bonjour") 101 b.AssertFileContent("public/en/index.html", "Home", "Hello") 102 103 // Check list pages 104 b.AssertFileContent(pathMod("public/fr/sect/index.html"), "List", "Bonjour") 105 b.AssertFileContent("public/en/sect/index.html", "List", "Hello") 106 b.AssertFileContent(pathMod("public/fr/plaques/frtag1/index.html"), "List", "Bonjour") 107 b.AssertFileContent("public/en/tags/tag1/index.html", "List", "Hello") 108 109 // Check sitemaps 110 // Sitemaps behaves different: In a multilanguage setup there will always be a index file and 111 // one sitemap in each lang folder. 112 b.AssertFileContent("public/sitemap.xml", 113 "<loc>http://example.com/blog/en/sitemap.xml</loc>", 114 "<loc>http://example.com/blog/fr/sitemap.xml</loc>") 115 116 if defaultInSubDir { 117 b.AssertFileContent("public/fr/sitemap.xml", "<loc>http://example.com/blog/fr/</loc>") 118 } else { 119 b.AssertFileContent("public/fr/sitemap.xml", "<loc>http://example.com/blog/</loc>") 120 } 121 b.AssertFileContent("public/en/sitemap.xml", "<loc>http://example.com/blog/en/</loc>") 122 123 // Check rss 124 b.AssertFileContent(pathMod("public/fr/index.xml"), pathMod(`<atom:link href="http://example.com/blog/fr/index.xml"`), 125 `rel="self" type="application/rss+xml"`) 126 b.AssertFileContent("public/en/index.xml", `<atom:link href="http://example.com/blog/en/index.xml"`) 127 b.AssertFileContent( 128 pathMod("public/fr/sect/index.xml"), 129 pathMod(`<atom:link href="http://example.com/blog/fr/sect/index.xml"`)) 130 b.AssertFileContent("public/en/sect/index.xml", `<atom:link href="http://example.com/blog/en/sect/index.xml"`) 131 b.AssertFileContent( 132 pathMod("public/fr/plaques/frtag1/index.xml"), 133 pathMod(`<atom:link href="http://example.com/blog/fr/plaques/frtag1/index.xml"`)) 134 b.AssertFileContent("public/en/tags/tag1/index.xml", `<atom:link href="http://example.com/blog/en/tags/tag1/index.xml"`) 135 136 // Check paginators 137 b.AssertFileContent(pathMod("public/fr/page/1/index.html"), pathMod(`refresh" content="0; url=http://example.com/blog/fr/"`)) 138 b.AssertFileContent("public/en/page/1/index.html", `refresh" content="0; url=http://example.com/blog/en/"`) 139 b.AssertFileContent(pathMod("public/fr/page/2/index.html"), "Home Page 2", "Bonjour", pathMod("http://example.com/blog/fr/")) 140 b.AssertFileContent("public/en/page/2/index.html", "Home Page 2", "Hello", "http://example.com/blog/en/") 141 b.AssertFileContent(pathMod("public/fr/sect/page/1/index.html"), pathMod(`refresh" content="0; url=http://example.com/blog/fr/sect/"`)) 142 b.AssertFileContent("public/en/sect/page/1/index.html", `refresh" content="0; url=http://example.com/blog/en/sect/"`) 143 b.AssertFileContent(pathMod("public/fr/sect/page/2/index.html"), "List Page 2", "Bonjour", pathMod("http://example.com/blog/fr/sect/")) 144 b.AssertFileContent("public/en/sect/page/2/index.html", "List Page 2", "Hello", "http://example.com/blog/en/sect/") 145 b.AssertFileContent( 146 pathMod("public/fr/plaques/frtag1/page/1/index.html"), 147 pathMod(`refresh" content="0; url=http://example.com/blog/fr/plaques/frtag1/"`)) 148 b.AssertFileContent("public/en/tags/tag1/page/1/index.html", `refresh" content="0; url=http://example.com/blog/en/tags/tag1/"`) 149 b.AssertFileContent( 150 pathMod("public/fr/plaques/frtag1/page/2/index.html"), "List Page 2", "Bonjour", 151 pathMod("http://example.com/blog/fr/plaques/frtag1/")) 152 b.AssertFileContent("public/en/tags/tag1/page/2/index.html", "List Page 2", "Hello", "http://example.com/blog/en/tags/tag1/") 153 // nn (Nynorsk) and nb (Bokmål) have custom pagePath: side ("page" in Norwegian) 154 b.AssertFileContent("public/nn/side/1/index.html", `refresh" content="0; url=http://example.com/blog/nn/"`) 155 b.AssertFileContent("public/nb/side/1/index.html", `refresh" content="0; url=http://example.com/blog/nb/"`) 156 } 157 158 func TestMultiSitesWithTwoLanguages(t *testing.T) { 159 t.Parallel() 160 161 assert := require.New(t) 162 b := newTestSitesBuilder(t).WithConfigFile("toml", ` 163 164 defaultContentLanguage = "nn" 165 166 [languages] 167 [languages.nn] 168 languageName = "Nynorsk" 169 weight = 1 170 title = "Tittel på Nynorsk" 171 [languages.nn.params] 172 p1 = "p1nn" 173 174 [languages.en] 175 title = "Title in English" 176 languageName = "English" 177 weight = 2 178 [languages.en.params] 179 p1 = "p1en" 180 `) 181 182 b.CreateSites() 183 b.Build(BuildCfg{SkipRender: true}) 184 sites := b.H.Sites 185 186 assert.Len(sites, 2) 187 188 nnSite := sites[0] 189 nnHome := nnSite.getPage(KindHome) 190 assert.Len(nnHome.AllTranslations(), 2) 191 assert.Len(nnHome.Translations(), 1) 192 assert.True(nnHome.IsTranslated()) 193 194 enHome := sites[1].getPage(KindHome) 195 196 p1, err := enHome.Param("p1") 197 assert.NoError(err) 198 assert.Equal("p1en", p1) 199 200 p1, err = nnHome.Param("p1") 201 assert.NoError(err) 202 assert.Equal("p1nn", p1) 203 } 204 205 // 206 func TestMultiSitesBuild(t *testing.T) { 207 t.Parallel() 208 209 for _, config := range []struct { 210 content string 211 suffix string 212 }{ 213 {multiSiteTOMLConfigTemplate, "toml"}, 214 {multiSiteYAMLConfigTemplate, "yml"}, 215 {multiSiteJSONConfigTemplate, "json"}, 216 } { 217 doTestMultiSitesBuild(t, config.content, config.suffix) 218 } 219 } 220 221 func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) { 222 assert := require.New(t) 223 224 b := newMultiSiteTestBuilder(t, configSuffix, configTemplate, nil) 225 b.CreateSites() 226 227 sites := b.H.Sites 228 assert.Equal(4, len(sites)) 229 230 b.Build(BuildCfg{}) 231 232 // Check site config 233 for _, s := range sites { 234 require.True(t, s.Info.defaultContentLanguageInSubdir, s.Info.Title) 235 require.NotNil(t, s.disabledKinds) 236 } 237 238 gp1 := b.H.GetContentPage(filepath.FromSlash("content/sect/doc1.en.md")) 239 require.NotNil(t, gp1) 240 require.Equal(t, "doc1", gp1.title) 241 gp2 := b.H.GetContentPage(filepath.FromSlash("content/dummysect/notfound.md")) 242 require.Nil(t, gp2) 243 244 enSite := sites[0] 245 enSiteHome := enSite.getPage(KindHome) 246 require.True(t, enSiteHome.IsTranslated()) 247 248 require.Equal(t, "en", enSite.Language.Lang) 249 250 assert.Equal(5, len(enSite.RegularPages)) 251 assert.Equal(32, len(enSite.AllPages)) 252 253 doc1en := enSite.RegularPages[0] 254 permalink := doc1en.Permalink() 255 require.Equal(t, "http://example.com/blog/en/sect/doc1-slug/", permalink, "invalid doc1.en permalink") 256 require.Len(t, doc1en.Translations(), 1, "doc1-en should have one translation, excluding itself") 257 258 doc2 := enSite.RegularPages[1] 259 permalink = doc2.Permalink() 260 require.Equal(t, "http://example.com/blog/en/sect/doc2/", permalink, "invalid doc2 permalink") 261 262 doc3 := enSite.RegularPages[2] 263 permalink = doc3.Permalink() 264 // Note that /superbob is a custom URL set in frontmatter. 265 // We respect that URL literally (it can be /search.json) 266 // and do no not do any language code prefixing. 267 require.Equal(t, "http://example.com/blog/superbob/", permalink, "invalid doc3 permalink") 268 269 require.Equal(t, "/superbob", doc3.URL(), "invalid url, was specified on doc3") 270 b.AssertFileContent("public/superbob/index.html", "doc3|Hello|en") 271 require.Equal(t, doc2.Next, doc3, "doc3 should follow doc2, in .Next") 272 273 doc1fr := doc1en.Translations()[0] 274 permalink = doc1fr.Permalink() 275 require.Equal(t, "http://example.com/blog/fr/sect/doc1/", permalink, "invalid doc1fr permalink") 276 277 require.Equal(t, doc1en.Translations()[0], doc1fr, "doc1-en should have doc1-fr as translation") 278 require.Equal(t, doc1fr.Translations()[0], doc1en, "doc1-fr should have doc1-en as translation") 279 require.Equal(t, "fr", doc1fr.Language().Lang) 280 281 doc4 := enSite.AllPages[4] 282 permalink = doc4.Permalink() 283 require.Equal(t, "http://example.com/blog/fr/sect/doc4/", permalink, "invalid doc4 permalink") 284 require.Equal(t, "/blog/fr/sect/doc4/", doc4.URL()) 285 286 require.Len(t, doc4.Translations(), 0, "found translations for doc4") 287 288 doc5 := enSite.AllPages[5] 289 permalink = doc5.Permalink() 290 require.Equal(t, "http://example.com/blog/fr/somewhere/else/doc5/", permalink, "invalid doc5 permalink") 291 292 // Taxonomies and their URLs 293 require.Len(t, enSite.Taxonomies, 1, "should have 1 taxonomy") 294 tags := enSite.Taxonomies["tags"] 295 require.Len(t, tags, 2, "should have 2 different tags") 296 require.Equal(t, tags["tag1"][0].Page, doc1en, "first tag1 page should be doc1") 297 298 frSite := sites[1] 299 300 require.Equal(t, "fr", frSite.Language.Lang) 301 require.Len(t, frSite.RegularPages, 4, "should have 3 pages") 302 require.Len(t, frSite.AllPages, 32, "should have 32 total pages (including translations and nodes)") 303 304 for _, frenchPage := range frSite.RegularPages { 305 require.Equal(t, "fr", frenchPage.Lang()) 306 } 307 308 // See https://github.com/gohugoio/hugo/issues/4285 309 // Before Hugo 0.33 you had to be explicit with the content path to get the correct Page, which 310 // isn't ideal in a multilingual setup. You want a way to get the current language version if available. 311 // Now you can do lookups with translation base name to get that behaviour. 312 // Let us test all the regular page variants: 313 getPageDoc1En := enSite.getPage(KindPage, filepath.ToSlash(doc1en.Path())) 314 getPageDoc1EnBase := enSite.getPage(KindPage, "sect/doc1") 315 getPageDoc1Fr := frSite.getPage(KindPage, filepath.ToSlash(doc1fr.Path())) 316 getPageDoc1FrBase := frSite.getPage(KindPage, "sect/doc1") 317 require.Equal(t, doc1en, getPageDoc1En) 318 require.Equal(t, doc1fr, getPageDoc1Fr) 319 require.Equal(t, doc1en, getPageDoc1EnBase) 320 require.Equal(t, doc1fr, getPageDoc1FrBase) 321 322 // Check redirect to main language, French 323 b.AssertFileContent("public/index.html", "0; url=http://example.com/blog/fr") 324 325 // check home page content (including data files rendering) 326 b.AssertFileContent("public/en/index.html", "Default Home Page 1", "Hello", "Hugo Rocks!") 327 b.AssertFileContent("public/fr/index.html", "French Home Page 1", "Bonjour", "Hugo Rocks!") 328 329 // check single page content 330 b.AssertFileContent("public/fr/sect/doc1/index.html", "Single", "Shortcode: Bonjour", "LingoFrench") 331 b.AssertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Shortcode: Hello", "LingoDefault") 332 333 // Check node translations 334 homeEn := enSite.getPage(KindHome) 335 require.NotNil(t, homeEn) 336 require.Len(t, homeEn.Translations(), 3) 337 require.Equal(t, "fr", homeEn.Translations()[0].Lang()) 338 require.Equal(t, "nn", homeEn.Translations()[1].Lang()) 339 require.Equal(t, "På nynorsk", homeEn.Translations()[1].title) 340 require.Equal(t, "nb", homeEn.Translations()[2].Lang()) 341 require.Equal(t, "På bokmål", homeEn.Translations()[2].title, configSuffix) 342 require.Equal(t, "Bokmål", homeEn.Translations()[2].Language().LanguageName, configSuffix) 343 344 sectFr := frSite.getPage(KindSection, "sect") 345 require.NotNil(t, sectFr) 346 347 require.Equal(t, "fr", sectFr.Lang()) 348 require.Len(t, sectFr.Translations(), 1) 349 require.Equal(t, "en", sectFr.Translations()[0].Lang()) 350 require.Equal(t, "Sects", sectFr.Translations()[0].title) 351 352 nnSite := sites[2] 353 require.Equal(t, "nn", nnSite.Language.Lang) 354 taxNn := nnSite.getPage(KindTaxonomyTerm, "lag") 355 require.NotNil(t, taxNn) 356 require.Len(t, taxNn.Translations(), 1) 357 require.Equal(t, "nb", taxNn.Translations()[0].Lang()) 358 359 taxTermNn := nnSite.getPage(KindTaxonomy, "lag", "sogndal") 360 require.NotNil(t, taxTermNn) 361 require.Len(t, taxTermNn.Translations(), 1) 362 require.Equal(t, "nb", taxTermNn.Translations()[0].Lang()) 363 364 // Check sitemap(s) 365 b.AssertFileContent("public/sitemap.xml", 366 "<loc>http://example.com/blog/en/sitemap.xml</loc>", 367 "<loc>http://example.com/blog/fr/sitemap.xml</loc>") 368 b.AssertFileContent("public/en/sitemap.xml", "http://example.com/blog/en/sect/doc2/") 369 b.AssertFileContent("public/fr/sitemap.xml", "http://example.com/blog/fr/sect/doc1/") 370 371 // Check taxonomies 372 enTags := enSite.Taxonomies["tags"] 373 frTags := frSite.Taxonomies["plaques"] 374 require.Len(t, enTags, 2, fmt.Sprintf("Tags in en: %v", enTags)) 375 require.Len(t, frTags, 2, fmt.Sprintf("Tags in fr: %v", frTags)) 376 require.NotNil(t, enTags["tag1"]) 377 require.NotNil(t, frTags["frtag1"]) 378 b.AssertFileContent("public/fr/plaques/frtag1/index.html", "Frtag1|Bonjour|http://example.com/blog/fr/plaques/frtag1/") 379 b.AssertFileContent("public/en/tags/tag1/index.html", "Tag1|Hello|http://example.com/blog/en/tags/tag1/") 380 381 // Check Blackfriday config 382 require.True(t, strings.Contains(string(doc1fr.content()), "«"), string(doc1fr.content())) 383 require.False(t, strings.Contains(string(doc1en.content()), "«"), string(doc1en.content())) 384 require.True(t, strings.Contains(string(doc1en.content()), "“"), string(doc1en.content())) 385 386 // Check that the drafts etc. are not built/processed/rendered. 387 assertShouldNotBuild(t, b.H) 388 389 // en and nn have custom site menus 390 require.Len(t, frSite.Menus, 0, "fr: "+configSuffix) 391 require.Len(t, enSite.Menus, 1, "en: "+configSuffix) 392 require.Len(t, nnSite.Menus, 1, "nn: "+configSuffix) 393 394 require.Equal(t, "Home", enSite.Menus["main"].ByName()[0].Name) 395 require.Equal(t, "Heim", nnSite.Menus["main"].ByName()[0].Name) 396 397 // Issue #1302 398 require.Equal(t, template.URL(""), enSite.RegularPages[0].RSSLink()) 399 400 // Issue #3108 401 next := enSite.RegularPages[0].Next 402 require.NotNil(t, next) 403 require.Equal(t, KindPage, next.Kind) 404 405 for { 406 if next == nil { 407 break 408 } 409 require.Equal(t, KindPage, next.Kind) 410 next = next.Next 411 } 412 413 // Check bundles 414 bundleFr := frSite.getPage(KindPage, "bundles/b1/index.md") 415 require.NotNil(t, bundleFr) 416 require.Equal(t, "/blog/fr/bundles/b1/", bundleFr.RelPermalink()) 417 require.Equal(t, 1, len(bundleFr.Resources)) 418 logoFr := bundleFr.Resources.GetMatch("logo*") 419 require.NotNil(t, logoFr) 420 require.Equal(t, "/blog/fr/bundles/b1/logo.png", logoFr.RelPermalink()) 421 b.AssertFileContent("public/fr/bundles/b1/logo.png", "PNG Data") 422 423 bundleEn := enSite.getPage(KindPage, "bundles/b1/index.en.md") 424 require.NotNil(t, bundleEn) 425 require.Equal(t, "/blog/en/bundles/b1/", bundleEn.RelPermalink()) 426 require.Equal(t, 1, len(bundleEn.Resources)) 427 logoEn := bundleEn.Resources.GetMatch("logo*") 428 require.NotNil(t, logoEn) 429 require.Equal(t, "/blog/en/bundles/b1/logo.png", logoEn.RelPermalink()) 430 b.AssertFileContent("public/en/bundles/b1/logo.png", "PNG Data") 431 432 } 433 434 func TestMultiSitesRebuild(t *testing.T) { 435 // t.Parallel() not supported, see https://github.com/fortytw2/leaktest/issues/4 436 // This leaktest seems to be a little bit shaky on Travis. 437 if !isCI() { 438 defer leaktest.CheckTimeout(t, 10*time.Second)() 439 } 440 441 assert := require.New(t) 442 443 b := newMultiSiteTestDefaultBuilder(t).Running().CreateSites().Build(BuildCfg{}) 444 445 sites := b.H.Sites 446 fs := b.Fs 447 448 b.AssertFileContent("public/en/sect/doc2/index.html", "Single: doc2|Hello|en|\n\n<h1 id=\"doc2\">doc2</h1>\n\n<p><em>some content</em>") 449 450 enSite := sites[0] 451 frSite := sites[1] 452 453 assert.Len(enSite.RegularPages, 5) 454 assert.Len(frSite.RegularPages, 4) 455 456 // Verify translations 457 b.AssertFileContent("public/en/sect/doc1-slug/index.html", "Hello") 458 b.AssertFileContent("public/fr/sect/doc1/index.html", "Bonjour") 459 460 // check single page content 461 b.AssertFileContent("public/fr/sect/doc1/index.html", "Single", "Shortcode: Bonjour") 462 b.AssertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Shortcode: Hello") 463 464 contentFs := b.H.BaseFs.Content.Fs 465 466 for i, this := range []struct { 467 preFunc func(t *testing.T) 468 events []fsnotify.Event 469 assertFunc func(t *testing.T) 470 }{ 471 // * Remove doc 472 // * Add docs existing languages 473 // (Add doc new language: TODO(bep) we should load config.toml as part of these so we can add languages). 474 // * Rename file 475 // * Change doc 476 // * Change a template 477 // * Change language file 478 { 479 func(t *testing.T) { 480 fs.Source.Remove("content/sect/doc2.en.md") 481 }, 482 []fsnotify.Event{{Name: filepath.FromSlash("content/sect/doc2.en.md"), Op: fsnotify.Remove}}, 483 func(t *testing.T) { 484 assert.Len(enSite.RegularPages, 4, "1 en removed") 485 486 // Check build stats 487 require.Equal(t, 1, enSite.draftCount, "Draft") 488 require.Equal(t, 1, enSite.futureCount, "Future") 489 require.Equal(t, 1, enSite.expiredCount, "Expired") 490 require.Equal(t, 0, frSite.draftCount, "Draft") 491 require.Equal(t, 1, frSite.futureCount, "Future") 492 require.Equal(t, 1, frSite.expiredCount, "Expired") 493 }, 494 }, 495 { 496 func(t *testing.T) { 497 writeNewContentFile(t, contentFs, "new_en_1", "2016-07-31", "new1.en.md", -5) 498 writeNewContentFile(t, contentFs, "new_en_2", "1989-07-30", "new2.en.md", -10) 499 writeNewContentFile(t, contentFs, "new_fr_1", "2016-07-30", "new1.fr.md", 10) 500 }, 501 []fsnotify.Event{ 502 {Name: filepath.FromSlash("content/new1.en.md"), Op: fsnotify.Create}, 503 {Name: filepath.FromSlash("content/new2.en.md"), Op: fsnotify.Create}, 504 {Name: filepath.FromSlash("content/new1.fr.md"), Op: fsnotify.Create}, 505 }, 506 func(t *testing.T) { 507 assert.Len(enSite.RegularPages, 6) 508 assert.Len(enSite.AllPages, 34) 509 assert.Len(frSite.RegularPages, 5) 510 require.Equal(t, "new_fr_1", frSite.RegularPages[3].title) 511 require.Equal(t, "new_en_2", enSite.RegularPages[0].title) 512 require.Equal(t, "new_en_1", enSite.RegularPages[1].title) 513 514 rendered := readDestination(t, fs, "public/en/new1/index.html") 515 require.True(t, strings.Contains(rendered, "new_en_1"), rendered) 516 }, 517 }, 518 { 519 func(t *testing.T) { 520 p := "sect/doc1.en.md" 521 doc1 := readFileFromFs(t, contentFs, p) 522 doc1 += "CHANGED" 523 writeToFs(t, contentFs, p, doc1) 524 }, 525 []fsnotify.Event{{Name: filepath.FromSlash("content/sect/doc1.en.md"), Op: fsnotify.Write}}, 526 func(t *testing.T) { 527 assert.Len(enSite.RegularPages, 6) 528 doc1 := readDestination(t, fs, "public/en/sect/doc1-slug/index.html") 529 require.True(t, strings.Contains(doc1, "CHANGED"), doc1) 530 531 }, 532 }, 533 // Rename a file 534 { 535 func(t *testing.T) { 536 if err := contentFs.Rename("new1.en.md", "new1renamed.en.md"); err != nil { 537 t.Fatalf("Rename failed: %s", err) 538 } 539 }, 540 []fsnotify.Event{ 541 {Name: filepath.FromSlash("content/new1renamed.en.md"), Op: fsnotify.Rename}, 542 {Name: filepath.FromSlash("content/new1.en.md"), Op: fsnotify.Rename}, 543 }, 544 func(t *testing.T) { 545 assert.Len(enSite.RegularPages, 6, "Rename") 546 require.Equal(t, "new_en_1", enSite.RegularPages[1].title) 547 rendered := readDestination(t, fs, "public/en/new1renamed/index.html") 548 require.True(t, strings.Contains(rendered, "new_en_1"), rendered) 549 }}, 550 { 551 // Change a template 552 func(t *testing.T) { 553 template := "layouts/_default/single.html" 554 templateContent := readSource(t, fs, template) 555 templateContent += "{{ print \"Template Changed\"}}" 556 writeSource(t, fs, template, templateContent) 557 }, 558 []fsnotify.Event{{Name: filepath.FromSlash("layouts/_default/single.html"), Op: fsnotify.Write}}, 559 func(t *testing.T) { 560 assert.Len(enSite.RegularPages, 6) 561 assert.Len(enSite.AllPages, 34) 562 assert.Len(frSite.RegularPages, 5) 563 doc1 := readDestination(t, fs, "public/en/sect/doc1-slug/index.html") 564 require.True(t, strings.Contains(doc1, "Template Changed"), doc1) 565 }, 566 }, 567 { 568 // Change a language file 569 func(t *testing.T) { 570 languageFile := "i18n/fr.yaml" 571 langContent := readSource(t, fs, languageFile) 572 langContent = strings.Replace(langContent, "Bonjour", "Salut", 1) 573 writeSource(t, fs, languageFile, langContent) 574 }, 575 []fsnotify.Event{{Name: filepath.FromSlash("i18n/fr.yaml"), Op: fsnotify.Write}}, 576 func(t *testing.T) { 577 assert.Len(enSite.RegularPages, 6) 578 assert.Len(enSite.AllPages, 34) 579 assert.Len(frSite.RegularPages, 5) 580 docEn := readDestination(t, fs, "public/en/sect/doc1-slug/index.html") 581 require.True(t, strings.Contains(docEn, "Hello"), "No Hello") 582 docFr := readDestination(t, fs, "public/fr/sect/doc1/index.html") 583 require.True(t, strings.Contains(docFr, "Salut"), "No Salut") 584 585 homeEn := enSite.getPage(KindHome) 586 require.NotNil(t, homeEn) 587 assert.Len(homeEn.Translations(), 3) 588 require.Equal(t, "fr", homeEn.Translations()[0].Lang()) 589 590 }, 591 }, 592 // Change a shortcode 593 { 594 func(t *testing.T) { 595 writeSource(t, fs, "layouts/shortcodes/shortcode.html", "Modified Shortcode: {{ i18n \"hello\" }}") 596 }, 597 []fsnotify.Event{ 598 {Name: filepath.FromSlash("layouts/shortcodes/shortcode.html"), Op: fsnotify.Write}, 599 }, 600 func(t *testing.T) { 601 assert.Len(enSite.RegularPages, 6) 602 assert.Len(enSite.AllPages, 34) 603 assert.Len(frSite.RegularPages, 5) 604 b.AssertFileContent("public/fr/sect/doc1/index.html", "Single", "Modified Shortcode: Salut") 605 b.AssertFileContent("public/en/sect/doc1-slug/index.html", "Single", "Modified Shortcode: Hello") 606 }, 607 }, 608 } { 609 610 if this.preFunc != nil { 611 this.preFunc(t) 612 } 613 614 err := b.H.Build(BuildCfg{}, this.events...) 615 616 if err != nil { 617 t.Fatalf("[%d] Failed to rebuild sites: %s", i, err) 618 } 619 620 this.assertFunc(t) 621 } 622 623 // Check that the drafts etc. are not built/processed/rendered. 624 assertShouldNotBuild(t, b.H) 625 626 } 627 628 func assertShouldNotBuild(t *testing.T, sites *HugoSites) { 629 s := sites.Sites[0] 630 631 for _, p := range s.rawAllPages { 632 // No HTML when not processed 633 require.Equal(t, p.shouldBuild(), bytes.Contains(p.workContent, []byte("</")), p.BaseFileName()+": "+string(p.workContent)) 634 require.Equal(t, p.shouldBuild(), p.content() != "", p.BaseFileName()) 635 636 require.Equal(t, p.shouldBuild(), p.content() != "", p.BaseFileName()) 637 638 } 639 } 640 641 func TestAddNewLanguage(t *testing.T) { 642 t.Parallel() 643 assert := require.New(t) 644 645 b := newMultiSiteTestDefaultBuilder(t) 646 b.CreateSites().Build(BuildCfg{}) 647 648 fs := b.Fs 649 650 newConfig := multiSiteTOMLConfigTemplate + ` 651 652 [Languages.sv] 653 weight = 15 654 title = "Svenska" 655 ` 656 657 writeNewContentFile(t, fs.Source, "Swedish Contentfile", "2016-01-01", "content/sect/doc1.sv.md", 10) 658 // replace the config 659 b.WithNewConfig(newConfig) 660 661 sites := b.H 662 663 // Watching does not work with in-memory fs, so we trigger a reload manually 664 assert.NoError(sites.Cfg.(*langs.Language).Cfg.(*viper.Viper).ReadInConfig()) 665 err := b.H.Build(BuildCfg{CreateSitesFromConfig: true}) 666 667 if err != nil { 668 t.Fatalf("Failed to rebuild sites: %s", err) 669 } 670 671 require.Len(t, sites.Sites, 5, fmt.Sprintf("Len %d", len(sites.Sites))) 672 673 // The Swedish site should be put in the middle (language weight=15) 674 enSite := sites.Sites[0] 675 svSite := sites.Sites[1] 676 frSite := sites.Sites[2] 677 require.True(t, enSite.Language.Lang == "en", enSite.Language.Lang) 678 require.True(t, svSite.Language.Lang == "sv", svSite.Language.Lang) 679 require.True(t, frSite.Language.Lang == "fr", frSite.Language.Lang) 680 681 homeEn := enSite.getPage(KindHome) 682 require.NotNil(t, homeEn) 683 require.Len(t, homeEn.Translations(), 4) 684 require.Equal(t, "sv", homeEn.Translations()[0].Lang()) 685 686 require.Len(t, enSite.RegularPages, 5) 687 require.Len(t, frSite.RegularPages, 4) 688 689 // Veriy Swedish site 690 require.Len(t, svSite.RegularPages, 1) 691 svPage := svSite.RegularPages[0] 692 693 require.Equal(t, "Swedish Contentfile", svPage.title) 694 require.Equal(t, "sv", svPage.Lang()) 695 require.Len(t, svPage.Translations(), 2) 696 require.Len(t, svPage.AllTranslations(), 3) 697 require.Equal(t, "en", svPage.Translations()[0].Lang()) 698 699 // Regular pages have no children 700 require.Len(t, svPage.Pages, 0) 701 require.Len(t, svPage.data["Pages"], 0) 702 703 } 704 705 func TestChangeDefaultLanguage(t *testing.T) { 706 t.Parallel() 707 708 assert := require.New(t) 709 710 b := newMultiSiteTestBuilder(t, "", "", map[string]interface{}{ 711 "DefaultContentLanguage": "fr", 712 "DefaultContentLanguageInSubdir": false, 713 }) 714 b.CreateSites().Build(BuildCfg{}) 715 716 b.AssertFileContent("public/sect/doc1/index.html", "Single", "Bonjour") 717 b.AssertFileContent("public/en/sect/doc2/index.html", "Single", "Hello") 718 719 // Switch language 720 b.WithNewConfigData(map[string]interface{}{ 721 "DefaultContentLanguage": "en", 722 "DefaultContentLanguageInSubdir": false, 723 }) 724 725 // Watching does not work with in-memory fs, so we trigger a reload manually 726 // This does not look pretty, so we should think of something else. 727 assert.NoError(b.H.Cfg.(*langs.Language).Cfg.(*viper.Viper).ReadInConfig()) 728 err := b.H.Build(BuildCfg{CreateSitesFromConfig: true}) 729 if err != nil { 730 t.Fatalf("Failed to rebuild sites: %s", err) 731 } 732 733 // Default language is now en, so that should now be the "root" language 734 b.AssertFileContent("public/fr/sect/doc1/index.html", "Single", "Bonjour") 735 b.AssertFileContent("public/sect/doc2/index.html", "Single", "Hello") 736 } 737 738 // https://github.com/gohugoio/hugo/issues/4706 739 func TestContentStressTest(t *testing.T) { 740 b := newTestSitesBuilder(t) 741 742 numPages := 500 743 744 contentTempl := ` 745 --- 746 %s 747 title: %q 748 weight: %d 749 multioutput: %t 750 --- 751 752 # Header 753 754 CONTENT 755 756 The End. 757 ` 758 759 contentTempl = strings.Replace(contentTempl, "CONTENT", strings.Repeat(` 760 761 ## Another header 762 763 Some text. Some more text. 764 765 `, 100), -1) 766 767 var content []string 768 defaultOutputs := `outputs: ["html", "json", "rss" ]` 769 770 for i := 1; i <= numPages; i++ { 771 outputs := defaultOutputs 772 multioutput := true 773 if i%3 == 0 { 774 outputs = `outputs: ["json"]` 775 multioutput = false 776 } 777 section := "s1" 778 if i%10 == 0 { 779 section = "s2" 780 } 781 content = append(content, []string{fmt.Sprintf("%s/page%d.md", section, i), fmt.Sprintf(contentTempl, outputs, fmt.Sprintf("Title %d", i), i, multioutput)}...) 782 } 783 784 content = append(content, []string{"_index.md", fmt.Sprintf(contentTempl, defaultOutputs, fmt.Sprintf("Home %d", 0), 0, true)}...) 785 content = append(content, []string{"s1/_index.md", fmt.Sprintf(contentTempl, defaultOutputs, fmt.Sprintf("S %d", 1), 1, true)}...) 786 content = append(content, []string{"s2/_index.md", fmt.Sprintf(contentTempl, defaultOutputs, fmt.Sprintf("S %d", 2), 2, true)}...) 787 788 b.WithSimpleConfigFile() 789 b.WithTemplates("layouts/_default/single.html", `Single: {{ .Content }}`) 790 b.WithTemplates("layouts/_default/myview.html", `View: {{ len .Content }}`) 791 b.WithTemplates("layouts/_default/single.json", `Single JSON: {{ .Content }}`) 792 b.WithTemplates("layouts/_default/list.html", ` 793 Page: {{ .Paginator.PageNumber }} 794 P: {{ path.Join .Path }} 795 List: {{ len .Paginator.Pages }}|List Content: {{ len .Content }} 796 {{ $shuffled := where .Site.RegularPages "Params.multioutput" true | shuffle }} 797 {{ $first5 := $shuffled | first 5 }} 798 L1: {{ len .Site.RegularPages }} L2: {{ len $first5 }} 799 {{ range $i, $e := $first5 }} 800 Render {{ $i }}: {{ .Render "myview" }} 801 {{ end }} 802 END 803 `) 804 805 b.WithContent(content...) 806 807 b.CreateSites().Build(BuildCfg{}) 808 809 contentMatchers := []string{"<h2 id=\"another-header\">Another header</h2>", "<h2 id=\"another-header-99\">Another header</h2>", "<p>The End.</p>"} 810 811 for i := 1; i <= numPages; i++ { 812 if i%3 != 0 { 813 section := "s1" 814 if i%10 == 0 { 815 section = "s2" 816 } 817 checkContent(b, fmt.Sprintf("public/%s/page%d/index.html", section, i), 8343, contentMatchers...) 818 } 819 } 820 821 for i := 1; i <= numPages; i++ { 822 section := "s1" 823 if i%10 == 0 { 824 section = "s2" 825 } 826 checkContent(b, fmt.Sprintf("public/%s/page%d/index.json", section, i), 8348, contentMatchers...) 827 } 828 829 checkContent(b, "public/s1/index.html", 184, "P: s1/_index.md\nList: 10|List Content: 8335\n\n\nL1: 500 L2: 5\n\nRender 0: View: 8335\n\nRender 1: View: 8335\n\nRender 2: View: 8335\n\nRender 3: View: 8335\n\nRender 4: View: 8335\n\nEND\n") 830 checkContent(b, "public/s2/index.html", 184, "P: s2/_index.md\nList: 10|List Content: 8335", "Render 4: View: 8335\n\nEND") 831 checkContent(b, "public/index.html", 181, "P: _index.md\nList: 10|List Content: 8335", "4: View: 8335\n\nEND") 832 833 // Chek paginated pages 834 for i := 2; i <= 9; i++ { 835 checkContent(b, fmt.Sprintf("public/page/%d/index.html", i), 181, fmt.Sprintf("Page: %d", i), "Content: 8335\n\n\nL1: 500 L2: 5\n\nRender 0: View: 8335", "Render 4: View: 8335\n\nEND") 836 } 837 } 838 839 func checkContent(s *sitesBuilder, filename string, length int, matches ...string) { 840 content := readDestination(s.T, s.Fs, filename) 841 for _, match := range matches { 842 if !strings.Contains(content, match) { 843 s.Fatalf("No match for %q in content for %s\n%q", match, filename, content) 844 } 845 } 846 if len(content) != length { 847 s.Fatalf("got %d expected %d", len(content), length) 848 } 849 } 850 851 func TestTableOfContentsInShortcodes(t *testing.T) { 852 t.Parallel() 853 854 b := newMultiSiteTestDefaultBuilder(t) 855 856 b.WithTemplatesAdded("layouts/shortcodes/toc.html", tocShortcode) 857 b.WithContent("post/simple.en.md", tocPageSimple) 858 b.WithContent("post/withSCInHeading.en.md", tocPageWithShortcodesInHeadings) 859 860 b.CreateSites().Build(BuildCfg{}) 861 862 b.AssertFileContent("public/en/post/simple/index.html", tocPageSimpleExpected) 863 b.AssertFileContent("public/en/post/withSCInHeading/index.html", tocPageWithShortcodesInHeadingsExpected) 864 } 865 866 var tocShortcode = ` 867 {{ .Page.TableOfContents }} 868 ` 869 870 func TestSelfReferencedContentInShortcode(t *testing.T) { 871 t.Parallel() 872 873 b := newMultiSiteTestDefaultBuilder(t) 874 875 var ( 876 shortcode = `{{- .Page.Content -}}{{- .Page.Summary -}}{{- .Page.Plain -}}{{- .Page.PlainWords -}}{{- .Page.WordCount -}}{{- .Page.ReadingTime -}}` 877 878 page = `--- 879 title: sctest 880 --- 881 Empty:{{< mycontent >}}: 882 ` 883 ) 884 885 b.WithTemplatesAdded("layouts/shortcodes/mycontent.html", shortcode) 886 b.WithContent("post/simple.en.md", page) 887 888 b.CreateSites().Build(BuildCfg{}) 889 890 b.AssertFileContent("public/en/post/simple/index.html", "Empty:[]00:") 891 } 892 893 var tocPageSimple = `--- 894 title: tocTest 895 publishdate: "2000-01-01" 896 --- 897 {{< toc >}} 898 # Heading 1 {#1} 899 Some text. 900 ## Subheading 1.1 {#1-1} 901 Some more text. 902 # Heading 2 {#2} 903 Even more text. 904 ## Subheading 2.1 {#2-1} 905 Lorem ipsum... 906 ` 907 908 var tocPageSimpleExpected = `<nav id="TableOfContents"> 909 <ul> 910 <li><a href="#1">Heading 1</a> 911 <ul> 912 <li><a href="#1-1">Subheading 1.1</a></li> 913 </ul></li> 914 <li><a href="#2">Heading 2</a> 915 <ul> 916 <li><a href="#2-1">Subheading 2.1</a></li> 917 </ul></li> 918 </ul> 919 </nav>` 920 921 var tocPageWithShortcodesInHeadings = `--- 922 title: tocTest 923 publishdate: "2000-01-01" 924 --- 925 926 {{< toc >}} 927 928 # Heading 1 {#1} 929 930 Some text. 931 932 ## Subheading 1.1 {{< shortcode >}} {#1-1} 933 934 Some more text. 935 936 # Heading 2 {{% shortcode %}} {#2} 937 938 Even more text. 939 940 ## Subheading 2.1 {#2-1} 941 942 Lorem ipsum... 943 ` 944 945 var tocPageWithShortcodesInHeadingsExpected = `<nav id="TableOfContents"> 946 <ul> 947 <li><a href="#1">Heading 1</a> 948 <ul> 949 <li><a href="#1-1">Subheading 1.1 Shortcode: Hello</a></li> 950 </ul></li> 951 <li><a href="#2">Heading 2 Shortcode: Hello</a> 952 <ul> 953 <li><a href="#2-1">Subheading 2.1</a></li> 954 </ul></li> 955 </ul> 956 </nav>` 957 958 var multiSiteTOMLConfigTemplate = ` 959 baseURL = "http://example.com/blog" 960 rssURI = "index.xml" 961 962 paginate = 1 963 disablePathToLower = true 964 defaultContentLanguage = "{{ .DefaultContentLanguage }}" 965 defaultContentLanguageInSubdir = {{ .DefaultContentLanguageInSubdir }} 966 967 [permalinks] 968 other = "/somewhere/else/:filename" 969 970 [blackfriday] 971 angledQuotes = true 972 973 [Taxonomies] 974 tag = "tags" 975 976 [Languages] 977 [Languages.en] 978 weight = 10 979 title = "In English" 980 languageName = "English" 981 [Languages.en.blackfriday] 982 angledQuotes = false 983 [[Languages.en.menu.main]] 984 url = "/" 985 name = "Home" 986 weight = 0 987 988 [Languages.fr] 989 weight = 20 990 title = "Le Français" 991 languageName = "Français" 992 [Languages.fr.Taxonomies] 993 plaque = "plaques" 994 995 [Languages.nn] 996 weight = 30 997 title = "På nynorsk" 998 languageName = "Nynorsk" 999 paginatePath = "side" 1000 [Languages.nn.Taxonomies] 1001 lag = "lag" 1002 [[Languages.nn.menu.main]] 1003 url = "/" 1004 name = "Heim" 1005 weight = 1 1006 1007 [Languages.nb] 1008 weight = 40 1009 title = "På bokmål" 1010 languageName = "Bokmål" 1011 paginatePath = "side" 1012 [Languages.nb.Taxonomies] 1013 lag = "lag" 1014 ` 1015 1016 var multiSiteYAMLConfigTemplate = ` 1017 baseURL: "http://example.com/blog" 1018 rssURI: "index.xml" 1019 1020 disablePathToLower: true 1021 paginate: 1 1022 defaultContentLanguage: "{{ .DefaultContentLanguage }}" 1023 defaultContentLanguageInSubdir: {{ .DefaultContentLanguageInSubdir }} 1024 1025 permalinks: 1026 other: "/somewhere/else/:filename" 1027 1028 blackfriday: 1029 angledQuotes: true 1030 1031 Taxonomies: 1032 tag: "tags" 1033 1034 Languages: 1035 en: 1036 weight: 10 1037 title: "In English" 1038 languageName: "English" 1039 blackfriday: 1040 angledQuotes: false 1041 menu: 1042 main: 1043 - url: "/" 1044 name: "Home" 1045 weight: 0 1046 fr: 1047 weight: 20 1048 title: "Le Français" 1049 languageName: "Français" 1050 Taxonomies: 1051 plaque: "plaques" 1052 nn: 1053 weight: 30 1054 title: "På nynorsk" 1055 languageName: "Nynorsk" 1056 paginatePath: "side" 1057 Taxonomies: 1058 lag: "lag" 1059 menu: 1060 main: 1061 - url: "/" 1062 name: "Heim" 1063 weight: 1 1064 nb: 1065 weight: 40 1066 title: "På bokmål" 1067 languageName: "Bokmål" 1068 paginatePath: "side" 1069 Taxonomies: 1070 lag: "lag" 1071 1072 ` 1073 1074 // TODO(bep) clean move 1075 var multiSiteJSONConfigTemplate = ` 1076 { 1077 "baseURL": "http://example.com/blog", 1078 "rssURI": "index.xml", 1079 "paginate": 1, 1080 "disablePathToLower": true, 1081 "defaultContentLanguage": "{{ .DefaultContentLanguage }}", 1082 "defaultContentLanguageInSubdir": true, 1083 "permalinks": { 1084 "other": "/somewhere/else/:filename" 1085 }, 1086 "blackfriday": { 1087 "angledQuotes": true 1088 }, 1089 "Taxonomies": { 1090 "tag": "tags" 1091 }, 1092 "Languages": { 1093 "en": { 1094 "weight": 10, 1095 "title": "In English", 1096 "languageName": "English", 1097 "blackfriday": { 1098 "angledQuotes": false 1099 }, 1100 "menu": { 1101 "main": [ 1102 { 1103 "url": "/", 1104 "name": "Home", 1105 "weight": 0 1106 } 1107 ] 1108 } 1109 }, 1110 "fr": { 1111 "weight": 20, 1112 "title": "Le Français", 1113 "languageName": "Français", 1114 "Taxonomies": { 1115 "plaque": "plaques" 1116 } 1117 }, 1118 "nn": { 1119 "weight": 30, 1120 "title": "På nynorsk", 1121 "paginatePath": "side", 1122 "languageName": "Nynorsk", 1123 "Taxonomies": { 1124 "lag": "lag" 1125 }, 1126 "menu": { 1127 "main": [ 1128 { 1129 "url": "/", 1130 "name": "Heim", 1131 "weight": 1 1132 } 1133 ] 1134 } 1135 }, 1136 "nb": { 1137 "weight": 40, 1138 "title": "På bokmål", 1139 "paginatePath": "side", 1140 "languageName": "Bokmål", 1141 "Taxonomies": { 1142 "lag": "lag" 1143 } 1144 } 1145 } 1146 } 1147 ` 1148 1149 func writeSource(t testing.TB, fs *hugofs.Fs, filename, content string) { 1150 writeToFs(t, fs.Source, filename, content) 1151 } 1152 1153 func writeToFs(t testing.TB, fs afero.Fs, filename, content string) { 1154 if err := afero.WriteFile(fs, filepath.FromSlash(filename), []byte(content), 0755); err != nil { 1155 t.Fatalf("Failed to write file: %s", err) 1156 } 1157 } 1158 1159 func readDestination(t testing.TB, fs *hugofs.Fs, filename string) string { 1160 return readFileFromFs(t, fs.Destination, filename) 1161 } 1162 1163 func destinationExists(fs *hugofs.Fs, filename string) bool { 1164 b, err := helpers.Exists(filename, fs.Destination) 1165 if err != nil { 1166 panic(err) 1167 } 1168 return b 1169 } 1170 1171 func readSource(t *testing.T, fs *hugofs.Fs, filename string) string { 1172 return readFileFromFs(t, fs.Source, filename) 1173 } 1174 1175 func readFileFromFs(t testing.TB, fs afero.Fs, filename string) string { 1176 filename = filepath.Clean(filename) 1177 b, err := afero.ReadFile(fs, filename) 1178 if err != nil { 1179 // Print some debug info 1180 root := strings.Split(filename, helpers.FilePathSeparator)[0] 1181 helpers.PrintFs(fs, root, os.Stdout) 1182 Fatalf(t, "Failed to read file: %s", err) 1183 } 1184 return string(b) 1185 } 1186 1187 const testPageTemplate = `--- 1188 title: "%s" 1189 publishdate: "%s" 1190 weight: %d 1191 --- 1192 # Doc %s 1193 ` 1194 1195 func newTestPage(title, date string, weight int) string { 1196 return fmt.Sprintf(testPageTemplate, title, date, weight, title) 1197 } 1198 1199 func writeNewContentFile(t *testing.T, fs afero.Fs, title, date, filename string, weight int) { 1200 content := newTestPage(title, date, weight) 1201 writeToFs(t, fs, filename, content) 1202 } 1203 1204 type multiSiteTestBuilder struct { 1205 configData interface{} 1206 config string 1207 configFormat string 1208 1209 *sitesBuilder 1210 } 1211 1212 func newMultiSiteTestDefaultBuilder(t testing.TB) *multiSiteTestBuilder { 1213 return newMultiSiteTestBuilder(t, "", "", nil) 1214 } 1215 1216 func (b *multiSiteTestBuilder) WithNewConfig(config string) *multiSiteTestBuilder { 1217 b.WithConfigTemplate(b.configData, b.configFormat, config) 1218 return b 1219 } 1220 1221 func (b *multiSiteTestBuilder) WithNewConfigData(data interface{}) *multiSiteTestBuilder { 1222 b.WithConfigTemplate(data, b.configFormat, b.config) 1223 return b 1224 } 1225 1226 func newMultiSiteTestBuilder(t testing.TB, configFormat, config string, configData interface{}) *multiSiteTestBuilder { 1227 if configData == nil { 1228 configData = map[string]interface{}{ 1229 "DefaultContentLanguage": "fr", 1230 "DefaultContentLanguageInSubdir": true, 1231 } 1232 } 1233 1234 if config == "" { 1235 config = multiSiteTOMLConfigTemplate 1236 } 1237 1238 if configFormat == "" { 1239 configFormat = "toml" 1240 } 1241 1242 b := newTestSitesBuilder(t).WithConfigTemplate(configData, configFormat, config) 1243 b.WithContent("root.en.md", `--- 1244 title: root 1245 weight: 10000 1246 slug: root 1247 publishdate: "2000-01-01" 1248 --- 1249 # root 1250 `, 1251 "sect/doc1.en.md", `--- 1252 title: doc1 1253 weight: 1 1254 slug: doc1-slug 1255 tags: 1256 - tag1 1257 publishdate: "2000-01-01" 1258 --- 1259 # doc1 1260 *some "content"* 1261 1262 {{< shortcode >}} 1263 1264 {{< lingo >}} 1265 1266 NOTE: slug should be used as URL 1267 `, 1268 "sect/doc1.fr.md", `--- 1269 title: doc1 1270 weight: 1 1271 plaques: 1272 - frtag1 1273 - frtag2 1274 publishdate: "2000-01-04" 1275 --- 1276 # doc1 1277 *quelque "contenu"* 1278 1279 {{< shortcode >}} 1280 1281 {{< lingo >}} 1282 1283 NOTE: should be in the 'en' Page's 'Translations' field. 1284 NOTE: date is after "doc3" 1285 `, 1286 "sect/doc2.en.md", `--- 1287 title: doc2 1288 weight: 2 1289 publishdate: "2000-01-02" 1290 --- 1291 # doc2 1292 *some content* 1293 NOTE: without slug, "doc2" should be used, without ".en" as URL 1294 `, 1295 "sect/doc3.en.md", `--- 1296 title: doc3 1297 weight: 3 1298 publishdate: "2000-01-03" 1299 aliases: [/en/al/alias1,/al/alias2/] 1300 tags: 1301 - tag2 1302 - tag1 1303 url: /superbob 1304 --- 1305 # doc3 1306 *some content* 1307 NOTE: third 'en' doc, should trigger pagination on home page. 1308 `, 1309 "sect/doc4.md", `--- 1310 title: doc4 1311 weight: 4 1312 plaques: 1313 - frtag1 1314 publishdate: "2000-01-05" 1315 --- 1316 # doc4 1317 *du contenu francophone* 1318 NOTE: should use the defaultContentLanguage and mark this doc as 'fr'. 1319 NOTE: doesn't have any corresponding translation in 'en' 1320 `, 1321 "other/doc5.fr.md", `--- 1322 title: doc5 1323 weight: 5 1324 publishdate: "2000-01-06" 1325 --- 1326 # doc5 1327 *autre contenu francophone* 1328 NOTE: should use the "permalinks" configuration with :filename 1329 `, 1330 // Add some for the stats 1331 "stats/expired.fr.md", `--- 1332 title: expired 1333 publishdate: "2000-01-06" 1334 expiryDate: "2001-01-06" 1335 --- 1336 # Expired 1337 `, 1338 "stats/future.fr.md", `--- 1339 title: future 1340 weight: 6 1341 publishdate: "2100-01-06" 1342 --- 1343 # Future 1344 `, 1345 "stats/expired.en.md", `--- 1346 title: expired 1347 weight: 7 1348 publishdate: "2000-01-06" 1349 expiryDate: "2001-01-06" 1350 --- 1351 # Expired 1352 `, 1353 "stats/future.en.md", `--- 1354 title: future 1355 weight: 6 1356 publishdate: "2100-01-06" 1357 --- 1358 # Future 1359 `, 1360 "stats/draft.en.md", `--- 1361 title: expired 1362 publishdate: "2000-01-06" 1363 draft: true 1364 --- 1365 # Draft 1366 `, 1367 "stats/tax.nn.md", `--- 1368 title: Tax NN 1369 weight: 8 1370 publishdate: "2000-01-06" 1371 weight: 1001 1372 lag: 1373 - Sogndal 1374 --- 1375 # Tax NN 1376 `, 1377 "stats/tax.nb.md", `--- 1378 title: Tax NB 1379 weight: 8 1380 publishdate: "2000-01-06" 1381 weight: 1002 1382 lag: 1383 - Sogndal 1384 --- 1385 # Tax NB 1386 `, 1387 // Bundle 1388 "bundles/b1/index.en.md", `--- 1389 title: Bundle EN 1390 publishdate: "2000-01-06" 1391 weight: 2001 1392 --- 1393 # Bundle Content EN 1394 `, 1395 "bundles/b1/index.md", `--- 1396 title: Bundle Default 1397 publishdate: "2000-01-06" 1398 weight: 2002 1399 --- 1400 # Bundle Content Default 1401 `, 1402 "bundles/b1/logo.png", ` 1403 PNG Data 1404 `) 1405 1406 return &multiSiteTestBuilder{sitesBuilder: b, configFormat: configFormat, config: config, configData: configData} 1407 }