hugo_smoke_test.go - hugo - [fork] hugo port for 9front
 (HTM) git clone https://git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       hugo_smoke_test.go (15315B)
       ---
            1 // Copyright 2024 The Hugo Authors. All rights reserved.
            2 //
            3 // Licensed under the Apache License, Version 2.0 (the "License");
            4 // you may not use this file except in compliance with the License.
            5 // You may obtain a copy of the License at
            6 // http://www.apache.org/licenses/LICENSE-2.0
            7 //
            8 // Unless required by applicable law or agreed to in writing, software
            9 // distributed under the License is distributed on an "AS IS" BASIS,
           10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           11 // See the License for the specific language governing permissions and
           12 // limitations under the License.
           13 
           14 package hugolib
           15 
           16 import (
           17         "fmt"
           18         "math/rand"
           19         "testing"
           20 
           21         "github.com/bep/logg"
           22         qt "github.com/frankban/quicktest"
           23 )
           24 
           25 // The most basic build test.
           26 func TestHello(t *testing.T) {
           27         files := `
           28 -- hugo.toml --
           29 title = "Hello"
           30 baseURL="https://example.org"
           31 disableKinds = ["term", "taxonomy", "section", "page"]
           32 -- content/p1.md --
           33 ---
           34 title: Page
           35 ---
           36 -- layouts/index.html --
           37 Home: {{ .Title }}
           38 `
           39 
           40         b := NewIntegrationTestBuilder(
           41                 IntegrationTestConfig{
           42                         T:           t,
           43                         TxtarString: files,
           44                         // LogLevel:    logg.LevelTrace,
           45                 },
           46         ).Build()
           47 
           48         b.Assert(b.H.Log.LoggCount(logg.LevelWarn), qt.Equals, 0)
           49         b.AssertFileContent("public/index.html", `Hello`)
           50 }
           51 
           52 func TestSmokeOutputFormats(t *testing.T) {
           53         t.Parallel()
           54 
           55         files := `
           56 -- hugo.toml --
           57 baseURL = "https://example.com/"
           58 defaultContentLanguage = "en"
           59 disableKinds = ["term", "taxonomy", "robotsTXT", "sitemap"]
           60 [outputs]
           61 home = ["html",  "rss"]
           62 section = ["html", "rss"]
           63 page = ["html"]
           64 -- content/p1.md --
           65 ---
           66 title: Page
           67 ---
           68 Page.
           69 
           70 -- layouts/_default/list.html --
           71 List: {{ .Title }}|{{ .RelPermalink}}|{{ range .OutputFormats }}{{ .Name }}: {{ .RelPermalink }}|{{ end }}$
           72 -- layouts/_default/list.xml --
           73 List xml: {{ .Title }}|{{ .RelPermalink}}|{{ range .OutputFormats }}{{ .Name }}: {{ .RelPermalink }}|{{ end }}$
           74 -- layouts/_default/single.html --
           75 Single: {{ .Title }}|{{ .RelPermalink}}|{{ range .OutputFormats }}{{ .Name }}: {{ .RelPermalink }}|{{ end }}$
           76 
           77 `
           78 
           79         for i := 0; i < 2; i++ {
           80                 b := Test(t, files)
           81                 b.AssertFileContent("public/index.html", `List: |/|html: /|rss: /index.xml|$`)
           82                 b.AssertFileContent("public/index.xml", `List xml: |/|html: /|rss: /index.xml|$`)
           83                 b.AssertFileContent("public/p1/index.html", `Single: Page|/p1/|html: /p1/|$`)
           84                 b.AssertFileExists("public/p1/index.xml", false)
           85         }
           86 }
           87 
           88 func TestSmoke(t *testing.T) {
           89         t.Parallel()
           90 
           91         // Basic test cases.
           92         // OK translations
           93         // OK page collections
           94         // OK next, prev in section
           95         // OK GetPage
           96         // OK Pagination
           97         // OK RenderString with shortcode
           98         // OK cascade
           99         // OK site last mod, section last mod.
          100         // OK main sections
          101         // OK taxonomies
          102         // OK GetTerms
          103         // OK Resource page
          104         // OK Resource txt
          105 
          106         const files = `
          107 -- hugo.toml --
          108 baseURL = "https://example.com"
          109 title = "Smoke Site"
          110 rssLimit = 3
          111 defaultContentLanguage = "en"
          112 defaultContentLanguageInSubdir = true
          113 enableRobotsTXT = true
          114 
          115 [pagination]
          116 pagerSize = 1
          117 
          118 [taxonomies]
          119 category = 'categories'
          120 tag = 'tags'
          121 
          122 [languages]
          123 [languages.en]
          124 weight = 1
          125 title = "In English"
          126 [languages.no]
          127 weight = 2
          128 title = "På norsk"
          129 
          130 [params]
          131 hugo = "Rules!"
          132 
          133 [outputs]
          134   home = ["html", "json", "rss"]
          135 -- layouts/index.html --
          136 Home: {{ .Lang}}|{{ .Kind }}|{{ .RelPermalink }}|{{ .Title }}|{{ .Content }}|Len Resources: {{ len .Resources }}|HTML
          137 Resources: {{ range .Resources }}{{ .ResourceType }}|{{ .RelPermalink }}|{{ .MediaType }} - {{ end }}|
          138 Site last mod: {{ site.Lastmod.Format "2006-02-01" }}|
          139 Home last mod: {{ .Lastmod.Format "2006-02-01" }}|
          140 Len Translations: {{ len .Translations }}|
          141 Len home.RegularPagesRecursive: {{ len .RegularPagesRecursive }}|
          142 RegularPagesRecursive: {{ range .RegularPagesRecursive }}{{ .RelPermalink }}|{{ end }}@
          143 Len site.RegularPages: {{ len site.RegularPages }}|
          144 Len site.Pages: {{ len site.Pages }}|
          145 Len site.AllPages: {{ len site.AllPages }}|
          146 GetPage: {{ with .Site.GetPage "posts/p1" }}{{ .RelPermalink }}|{{ .Title }}{{ end }}|
          147 RenderString with shortcode: {{ .RenderString "{{% hello %}}" }}|
          148 Paginate: {{ .Paginator.PageNumber }}/{{ .Paginator.TotalPages }}|
          149 -- layouts/index.json --
          150 Home:{{ .Lang}}|{{ .Kind }}|{{ .RelPermalink }}|{{ .Title }}|{{ .Content }}|Len Resources: {{ len .Resources }}|JSON
          151 -- layouts/_default/list.html --
          152 List: {{ .Lang}}|{{ .Kind }}|{{ .RelPermalink }}|{{ .Title }}|{{ .Content }}|Len Resources: {{ len .Resources }}|
          153 Resources: {{ range .Resources }}{{ .ResourceType }}|{{ .RelPermalink }}|{{ .MediaType }} - {{ end }}
          154 Pages Length: {{ len .Pages }}
          155 RegularPages Length: {{ len .RegularPages }}
          156 RegularPagesRecursive Length: {{ len .RegularPagesRecursive }}
          157 List last mod: {{ .Lastmod.Format "2006-02-01" }}
          158 Background: {{ .Params.background }}|
          159 Kind: {{ .Kind }}
          160 Type: {{ .Type }}
          161 Paginate: {{ .Paginator.PageNumber }}/{{ .Paginator.TotalPages }}|
          162 -- layouts/_default/single.html --
          163 Single: {{ .Lang}}|{{ .Kind }}|{{ .RelPermalink }}|{{ .Title }}|{{ .Content }}|Len Resources: {{ len .Resources }}|Background: {{ .Params.background }}|
          164 Resources: {{ range .Resources }}{{ .ResourceType }}|{{ .RelPermalink }}|{{ .MediaType }}|{{ .Params }} - {{ end }}
          165 {{ $textResource := .Resources.GetMatch "**.txt" }}
          166 {{ with $textResource }}
          167 Icon: {{ .Params.icon }}|
          168 {{ $textResourceFingerprinted :=  . | fingerprint }}
          169 Icon fingerprinted: {{ with $textResourceFingerprinted }}{{ .Params.icon }}|{{ .RelPermalink }}{{ end }}|
          170 {{ end }}
          171 NextInSection: {{ with .NextInSection }}{{ .RelPermalink }}|{{ .Title }}{{ end }}|
          172 PrevInSection: {{ with .PrevInSection }}{{ .RelPermalink }}|{{ .Title }}{{ end }}|
          173 GetTerms: {{ range .GetTerms "tags" }}name: {{ .Name }}, title: {{ .Title }}|{{ end }}
          174 -- layouts/shortcodes/hello.html --
          175 Hello.
          176 -- content/_index.md --
          177 ---
          178 title: Home in English
          179 ---
          180 Home Content.
          181 -- content/_index.no.md --
          182 ---
          183 title: Hjem
          184 cascade:
          185   - _target:
          186       kind: page
          187       path: /posts/**
          188     background: post.jpg
          189   - _target:
          190       kind: term
          191     background: term.jpg
          192 ---
          193 Hjem Innhold.
          194 -- content/posts/f1.txt --
          195 posts f1 text.
          196 -- content/posts/sub/f1.txt --
          197 posts sub f1 text.
          198 -- content/posts/p1/index.md --
          199 +++
          200 title = "Post 1"
          201 lastMod = "2001-01-01"
          202 tags = ["tag1"]
          203 [[resources]]
          204 src = '**'
          205 [resources.params]
          206 icon = 'enicon'
          207 +++
          208 Content 1.
          209 -- content/posts/p1/index.no.md --
          210 +++
          211 title = "Post 1 no"
          212 lastMod = "2002-02-02"
          213 tags = ["tag1", "tag2"]
          214 [[resources]]
          215 src = '**'
          216 [resources.params]
          217 icon = 'noicon'
          218 +++
          219 Content 1 no.
          220 -- content/posts/_index.md --
          221 ---
          222 title: Posts
          223 ---
          224 -- content/posts/p1/f1.txt --
          225 posts p1 f1 text.
          226 -- content/posts/p1/sub/ps1.md --
          227 ---
          228 title: Post Sub 1
          229 ---
          230 Content Sub 1.
          231 -- content/posts/p2.md --
          232 ---
          233 title: Post 2
          234 tags: ["tag1", "tag3"]
          235 ---
          236 Content 2.
          237 -- content/posts/p2.no.md --
          238 ---
          239 title: Post 2 No
          240 ---
          241 Content 2 No.
          242 -- content/tags/_index.md --
          243 ---
          244 title: Tags
          245 ---
          246 Content Tags.
          247 -- content/tags/tag1/_index.md --
          248 ---
          249 title: Tag 1
          250 ---
          251 Content Tag 1.
          252 
          253 
          254 `
          255 
          256         b := NewIntegrationTestBuilder(IntegrationTestConfig{
          257                 T:           t,
          258                 TxtarString: files,
          259                 NeedsOsFS:   true,
          260                 // Verbose:     true,
          261                 // LogLevel:    logg.LevelTrace,
          262         }).Build()
          263 
          264         b.AssertFileContent("public/en/index.html",
          265                 "Home: en|home|/en/|Home in English|<p>Home Content.</p>\n|HTML",
          266                 "Site last mod: 2001-01-01",
          267                 "Home last mod: 2001-01-01",
          268                 "Translations: 1|",
          269                 "Len home.RegularPagesRecursive: 2|",
          270                 "Len site.RegularPages: 2|",
          271                 "Len site.Pages: 8|",
          272                 "Len site.AllPages: 16|",
          273                 "GetPage: /en/posts/p1/|Post 1|",
          274                 "RenderString with shortcode: Hello.|",
          275                 "Paginate: 1/2|",
          276         )
          277         b.AssertFileContent("public/en/page/2/index.html", "Paginate: 2/2|")
          278 
          279         b.AssertFileContent("public/no/index.html",
          280                 "Home: no|home|/no/|Hjem|<p>Hjem Innhold.</p>\n|HTML",
          281                 "Site last mod: 2002-02-02",
          282                 "Home last mod: 2002-02-02",
          283                 "Translations: 1",
          284                 "GetPage: /no/posts/p1/|Post 1 no|",
          285         )
          286 
          287         b.AssertFileContent("public/en/index.json", "Home:en|home|/en/|Home in English|<p>Home Content.</p>\n|JSON")
          288         b.AssertFileContent("public/no/index.json", "Home:no|home|/no/|Hjem|<p>Hjem Innhold.</p>\n|JSON")
          289 
          290         b.AssertFileContent("public/en/posts/p1/index.html",
          291                 "Single: en|page|/en/posts/p1/|Post 1|<p>Content 1.</p>\n|Len Resources: 2|",
          292                 "Resources: text|/en/posts/p1/f1.txt|text/plain|map[icon:enicon] - page||application/octet-stream|map[draft:false iscjklanguage:false title:Post Sub 1] -",
          293                 "Icon: enicon",
          294                 "Icon fingerprinted: enicon|/en/posts/p1/f1.e5746577af5cbfc4f34c558051b7955a9a5a795a84f1c6ab0609cb3473a924cb.txt|",
          295                 "NextInSection: |\nPrevInSection: /en/posts/p2/|Post 2|",
          296                 "GetTerms: name: tag1, title: Tag 1|",
          297         )
          298 
          299         b.AssertFileContent("public/no/posts/p1/index.html",
          300                 "Resources: 1",
          301                 "Resources: text|/en/posts/p1/f1.txt|text/plain|map[icon:noicon] -",
          302                 "Icon: noicon",
          303                 "Icon fingerprinted: noicon|/en/posts/p1/f1.e5746577af5cbfc4f34c558051b7955a9a5a795a84f1c6ab0609cb3473a924cb.txt|",
          304                 "Background: post.jpg",
          305                 "NextInSection: |\nPrevInSection: /no/posts/p2/|Post 2 No|",
          306         )
          307 
          308         b.AssertFileContent("public/en/posts/index.html",
          309                 "List: en|section|/en/posts/|Posts||Len Resources: 2|",
          310                 "Resources: text|/en/posts/f1.txt|text/plain - text|/en/posts/sub/f1.txt|text/plain -",
          311                 "List last mod: 2001-01-01",
          312         )
          313 
          314         b.AssertFileContent("public/no/posts/index.html",
          315                 "List last mod: 2002-02-02",
          316         )
          317 
          318         b.AssertFileContent("public/en/posts/p2/index.html", "Single: en|page|/en/posts/p2/|Post 2|<p>Content 2.</p>\n|",
          319                 "|Len Resources: 0",
          320                 "GetTerms: name: tag1, title: Tag 1|name: tag3, title: Tag3|",
          321         )
          322         b.AssertFileContent("public/no/posts/p2/index.html", "Single: no|page|/no/posts/p2/|Post 2 No|<p>Content 2 No.</p>\n|")
          323 
          324         b.AssertFileContent("public/no/categories/index.html",
          325                 "Kind: taxonomy",
          326                 "Type: categories",
          327         )
          328         b.AssertFileContent("public/no/tags/index.html",
          329                 "Kind: taxonomy",
          330                 "Type: tags",
          331         )
          332 
          333         b.AssertFileContent("public/no/tags/tag1/index.html",
          334                 "Background: term.jpg",
          335                 "Kind: term",
          336                 "Type: tags",
          337                 "Paginate: 1/1|",
          338         )
          339 
          340         b.AssertFileContent("public/en/tags/tag1/index.html",
          341                 "Kind: term",
          342                 "Type: tags",
          343                 "Paginate: 1/2|",
          344         )
          345 }
          346 
          347 // Basic tests that verifies that the different file systems work as expected.
          348 func TestSmokeFilesystems(t *testing.T) {
          349         t.Parallel()
          350 
          351         files := `
          352 -- hugo.toml --
          353 baseURL = "https://example.com"
          354 defaultContentLanguage = "en"
          355 defaultContentLanguageInSubdir = true
          356 [languages]
          357 [languages.en]
          358 title = "In English"
          359 [languages.nn]
          360 title = "På nynorsk"
          361 [module]
          362 [[module.mounts]]
          363 source = "i18n"
          364 target = "i18n"
          365 [[module.mounts]]
          366 source = "data"
          367 target = "data"
          368 [[module.mounts]]
          369 source = "content/en"
          370 target = "content"
          371 lang = "en"
          372 [[module.mounts]]
          373 source = "content/nn"
          374 target = "content"
          375 lang = "nn"
          376 [[module.imports]]
          377 path = "mytheme"
          378 -- layouts/index.html --
          379 i18n s1: {{ i18n "s1" }}|
          380 i18n s2: {{ i18n "s2" }}|
          381 data s1: {{ site.Data.d1.s1 }}|
          382 data s2: {{ site.Data.d1.s2 }}|
          383 title: {{ .Title }}|
          384 -- themes/mytheme/hugo.toml --
          385 [[module.mounts]]
          386 source = "i18n"
          387 target = "i18n"
          388 [[module.mounts]]
          389 source = "data"
          390 target = "data"
          391 # i18n files both project and theme.
          392 -- i18n/en.toml --
          393 [s1]
          394 other = 's1project'
          395 -- i18n/nn.toml --
          396 [s1]
          397 other = 's1prosjekt'
          398 -- themes/mytheme/i18n/en.toml --
          399 [s1]
          400 other = 's1theme'
          401 [s2]
          402 other = 's2theme'
          403 # data files both project and theme.
          404 -- data/d1.yaml --
          405 s1: s1project
          406 -- themes/mytheme/data/d1.yaml --
          407 s1: s1theme
          408 s2: s2theme
          409 # Content
          410 -- content/en/_index.md --
          411 ---
          412 title: "Home"
          413 ---
          414 -- content/nn/_index.md --
          415 ---
          416 title: "Heim"
          417 ---
          418 
          419 `
          420         b := Test(t, files)
          421 
          422         b.AssertFileContent("public/en/index.html",
          423                 "i18n s1: s1project", "i18n s2: s2theme",
          424                 "data s1: s1project", "data s2: s2theme",
          425                 "title: Home",
          426         )
          427 
          428         b.AssertFileContent("public/nn/index.html",
          429                 "i18n s1: s1prosjekt", "i18n s2: s2theme",
          430                 "data s1: s1project", "data s2: s2theme",
          431                 "title: Heim",
          432         )
          433 }
          434 
          435 // https://github.com/golang/go/issues/30286
          436 func TestDataRace(t *testing.T) {
          437         const page = `
          438 ---
          439 title: "The Page"
          440 outputs: ["HTML", "JSON"]
          441 ---
          442 
          443 The content.
          444 
          445 
          446         `
          447 
          448         b := newTestSitesBuilder(t).WithSimpleConfigFile()
          449         for i := 1; i <= 50; i++ {
          450                 b.WithContent(fmt.Sprintf("blog/page%d.md", i), page)
          451         }
          452 
          453         b.WithContent("_index.md", `
          454 ---
          455 title: "The Home"
          456 outputs: ["HTML", "JSON", "CSV", "RSS"]
          457 ---
          458 
          459 The content.
          460 
          461 
          462 `)
          463 
          464         commonTemplate := `{{ .Data.Pages }}`
          465 
          466         b.WithTemplatesAdded("_default/single.html", "HTML Single: "+commonTemplate)
          467         b.WithTemplatesAdded("_default/list.html", "HTML List: "+commonTemplate)
          468 
          469         b.CreateSites().Build(BuildCfg{})
          470 }
          471 
          472 // This is just a test to verify that BenchmarkBaseline is working as intended.
          473 func TestBenchmarkBaseline(t *testing.T) {
          474         cfg := IntegrationTestConfig{
          475                 T:           t,
          476                 TxtarString: benchmarkBaselineFiles(true),
          477         }
          478         b := NewIntegrationTestBuilder(cfg).Build()
          479 
          480         b.Assert(len(b.H.Sites), qt.Equals, 4)
          481         b.Assert(len(b.H.Sites[0].RegularPages()), qt.Equals, 161)
          482         b.Assert(len(b.H.Sites[0].Pages()), qt.Equals, 197)
          483         b.Assert(len(b.H.Sites[2].RegularPages()), qt.Equals, 158)
          484         b.Assert(len(b.H.Sites[2].Pages()), qt.Equals, 194)
          485 }
          486 
          487 func BenchmarkBaseline(b *testing.B) {
          488         cfg := IntegrationTestConfig{
          489                 T:           b,
          490                 TxtarString: benchmarkBaselineFiles(false),
          491         }
          492         builders := make([]*IntegrationTestBuilder, b.N)
          493 
          494         for i := range builders {
          495                 builders[i] = NewIntegrationTestBuilder(cfg)
          496         }
          497 
          498         b.ResetTimer()
          499         for i := 0; i < b.N; i++ {
          500                 builders[i].Build()
          501         }
          502 }
          503 
          504 func benchmarkBaselineFiles(leafBundles bool) string {
          505         rnd := rand.New(rand.NewSource(32))
          506 
          507         files := `
          508 -- config.toml --
          509 baseURL = "https://example.com"
          510 defaultContentLanguage = 'en'
          511 
          512 [module]
          513 [[module.mounts]]
          514 source = 'content/en'
          515 target = 'content/en'
          516 lang = 'en'
          517 [[module.mounts]]
          518 source = 'content/nn'
          519 target = 'content/nn'
          520 lang = 'nn'
          521 [[module.mounts]]
          522 source = 'content/no'
          523 target = 'content/no'
          524 lang = 'no'
          525 [[module.mounts]]
          526 source = 'content/sv'
          527 target = 'content/sv'
          528 lang = 'sv'
          529 [[module.mounts]]
          530 source = 'layouts'
          531 target = 'layouts'
          532 
          533 [languages]
          534 [languages.en]
          535 title = "English"
          536 weight = 1
          537 [languages.nn]
          538 title = "Nynorsk"
          539 weight = 2
          540 [languages.no]
          541 title = "Norsk"
          542 weight = 3
          543 [languages.sv]
          544 title = "Svenska"
          545 weight = 4
          546 -- layouts/_default/list.html --
          547 {{ .Title }}
          548 {{ .Content }}
          549 -- layouts/_default/single.html --
          550 {{ .Title }}
          551 {{ .Content }}
          552 -- layouts/shortcodes/myshort.html --
          553 {{ .Inner }}
          554 `
          555 
          556         contentTemplate := `
          557 ---
          558 title: "Page %d"
          559 date: "2018-01-01"
          560 weight: %d
          561 ---
          562 
          563 ## Heading 1
          564 
          565 Duis nisi reprehenderit nisi cupidatat cillum aliquip ea id eu esse commodo et.
          566 
          567 ## Heading 2
          568 
          569 Aliqua labore enim et sint anim amet excepteur ea dolore.
          570 
          571 {{< myshort >}}
          572 Hello, World!
          573 {{< /myshort >}}
          574 
          575 Aliqua labore enim et sint anim amet excepteur ea dolore.
          576 
          577 
          578 `
          579 
          580         for _, lang := range []string{"en", "nn", "no", "sv"} {
          581                 files += fmt.Sprintf("\n-- content/%s/_index.md --\n"+contentTemplate, lang, 1, 1, 1)
          582                 for i, root := range []string{"", "foo", "bar", "baz"} {
          583                         for j, section := range []string{"posts", "posts/funny", "posts/science", "posts/politics", "posts/world", "posts/technology", "posts/world/news", "posts/world/news/europe"} {
          584                                 n := i + j + 1
          585                                 files += fmt.Sprintf("\n-- content/%s/%s/%s/_index.md --\n"+contentTemplate, lang, root, section, n, n, n)
          586                                 for k := 1; k < rnd.Intn(30)+1; k++ {
          587                                         n := n + k
          588                                         ns := fmt.Sprintf("%d", n)
          589                                         if leafBundles {
          590                                                 ns = fmt.Sprintf("%d/index", n)
          591                                         }
          592                                         file := fmt.Sprintf("\n-- content/%s/%s/%s/p%s.md --\n"+contentTemplate, lang, root, section, ns, n, n)
          593                                         files += file
          594                                 }
          595                         }
          596                 }
          597         }
          598 
          599         return files
          600 }