From ed0985404db4630d1b9d3ad0b7e41fb186ae0112 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?=
")
+ endMarkup = []byte(" ")
+ endMarkup = []byte("
Simple Page
\n") - checkPageSummary(t, p, "Simple Page") - checkPageType(t, p, "page") - checkPageLayout(t, p, "page/single.html", "_default/single.html", "theme/page/single.html", "theme/_default/single.html") - checkTruncation(t, p, false, "simple short page") + for _, e := range engines { + if !e.shouldExecute() { + continue + } + + filename := baseFilename + "." + e.ext + + s := newSiteFromSources(filename, pageContent) + + if err := buildSiteSkipRender(s); err != nil { + t.Fatalf("Failed to build site: %s", err) + } + + require.Len(t, s.Pages, 1) + + p := s.Pages[0] + + assertFunc(t, e.ext, p) + + } + +} + +func TestCreateNewPage(t *testing.T) { + + assertFunc := func(t *testing.T, ext string, p *Page) { + assert.False(t, p.IsHome) + checkPageTitle(t, p, "Simple") + checkPageContent(t, p, normalizeExpected(ext, "Simple Page
\n")) + checkPageSummary(t, p, "Simple Page") + checkPageType(t, p, "page") + checkPageLayout(t, p, "page/single.html", "_default/single.html", "theme/page/single.html", "theme/_default/single.html") + checkTruncation(t, p, false, "simple short page") + } + + testAllMarkdownEnginesForPage(t, assertFunc, "simple", simplePage) +} + +func TestSplitSummaryAndContent(t *testing.T) { + + for i, this := range []struct { + markup string + content string + expectedSummary string + expectedContent string + expectedContentWithoutSummary string + }{ + {"markdown", `Summary Same LineHUGOMORE42
+ +Some more text
`, "Summary Same Line
", "Summary Same Line
\n\nSome more text
", "Some more text
"}, + {"asciidoc", `sn
HUGOMORE42Some more text
sn
sn
Some more text
Some more text
Summary Next Line
HUGOMORE42Some more text
Summary Next Line
Summary Next Line
Some more text
Some more text
a
b
HUGOMORE42c
", "a
b
", "a
b
c
", "c
"}, + {"markdown", "a
b
cHUGOMORE42
", "a
b
c
", "a
b
c
", ""}, + {"markdown", "a
bHUGOMORE42
c
", "a
b
", "a
b
c
", "c
"}, + {"markdown", "aHUGOMORE42
b
c
", "a
", "a
b
c
", "b
c
"}, + } { + + sc := splitUserDefinedSummaryAndContent(this.markup, []byte(this.content)) + + require.NotNil(t, sc, fmt.Sprintf("[%d] Nil %s", i, this.markup)) + require.Equal(t, this.expectedSummary, string(sc.summary), fmt.Sprintf("[%d] Summary markup %s", i, this.markup)) + require.Equal(t, this.expectedContent, string(sc.content), fmt.Sprintf("[%d] Content markup %s", i, this.markup)) + require.Equal(t, this.expectedContentWithoutSummary, string(sc.contentWithoutSummary), fmt.Sprintf("[%d] Content without summary, markup %s", i, this.markup)) + } + + if true { + return + } + + ad := `sn
HUGOMORE42 +Some more text
+Summary Same LineHUGOMORE42
+ +Some more text
` + + sc := splitUserDefinedSummaryAndContent("markdown", []byte(md)) + + require.Equal(t, "adf", string(sc.summary)) + require.Equal(t, "asdf", string(sc.content)) + + if true { + return + } + sc = splitUserDefinedSummaryAndContent("asciidoc", []byte(ad)) + require.Equal(t, "sn
\nSome more text
\nSummary Next Line
\n\nSome more text
\n"), ext) + checkPageSummary(t, p, normalizeExpected(ext, "Summary Next Line
"), ext) + checkPageType(t, p, "page") + checkPageLayout(t, p, "page/single.html", "_default/single.html", "theme/page/single.html", "theme/_default/single.html") + checkTruncation(t, p, true, "page with summary delimiter") + } + + testAllMarkdownEnginesForPage(t, assertFunc, "simple", simplePageWithSummaryDelimiter) +} + +// Issue #1076 +func TestPageWithDelimiterForMarkdownThatCrossesBorder(t *testing.T) { + s := newSiteFromSources("simple.md", simplePageWithSummaryDelimiterAndMarkdownThatCrossesBorder) + + if err := buildSiteSkipRender(s); err != nil { + t.Fatalf("Failed to build site: %s", err) + } + + require.Len(t, s.Pages, 1) + + p := s.Pages[0] + + if p.Summary != template.HTML("The best static site generator.1\n
") { + t.Fatalf("Got summary:\n%q", p.Summary) + } + + if p.Content != template.HTML("The best static site generator.1\n
\nSummary Next Line
\n\nSome more text
\n") - checkPageSummary(t, p, "Summary Next Line
\n") - checkPageType(t, p, "page") - checkPageLayout(t, p, "page/single.html", "_default/single.html", "theme/page/single.html", "theme/_default/single.html") - checkTruncation(t, p, true, "page with summary delimiter") } func TestPageWithShortCodeInSummary(t *testing.T) { - s := new(Site) - s.prepTemplates(nil) - p, _ := NewPage("simple.md") - _, err := p.ReadFrom(strings.NewReader(simplePageWithShortcodeInSummary)) - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) - } - p.Convert() - checkPageTitle(t, p, "Simple") - checkPageContent(t, p, "Summary Next Line. \n\n \n \n
Some more text
\n") - checkPageSummary(t, p, "Summary Next Line. . More text here. Some more text") - checkPageType(t, p, "page") - checkPageLayout(t, p, "page/single.html", "_default/single.html", "theme/page/single.html", "theme/_default/single.html") + assertFunc := func(t *testing.T, ext string, p *Page) { + checkPageTitle(t, p, "Simple") + checkPageContent(t, p, normalizeExpected(ext, "Summary Next Line.
Some more text
"), ext) + checkPageSummary(t, p, "Summary Next Line. . More text here. Some more text", ext) + checkPageType(t, p, "page") + checkPageLayout(t, p, "page/single.html", "_default/single.html", "theme/page/single.html", "theme/_default/single.html") + } + + testAllMarkdownEnginesForPage(t, assertFunc, "simple", simplePageWithShortcodeInSummary) } func TestPageWithEmbeddedScriptTag(t *testing.T) { - p, _ := NewPage("simple.md") - _, err := p.ReadFrom(strings.NewReader(simplePageWithEmbeddedScript)) - p.Convert() - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) + + assertFunc := func(t *testing.T, ext string, p *Page) { + if ext == "ad" || ext == "rst" { + // TOD(bep) + return + } + checkPageContent(t, p, "\n", ext) } - checkPageContent(t, p, "\n") + + testAllMarkdownEnginesForPage(t, assertFunc, "simple", simplePageWithEmbeddedScript) } func TestPageWithAdditionalExtension(t *testing.T) { - p, _ := NewPage("simple.md") - _, err := p.ReadFrom(strings.NewReader(simplePageWithAdditionalExtension)) - p.Convert() - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) + s := newSiteFromSources("simple.md", simplePageWithAdditionalExtension) + + if err := buildSiteSkipRender(s); err != nil { + t.Fatalf("Failed to build site: %s", err) } + + require.Len(t, s.Pages, 1) + + p := s.Pages[0] + checkPageContent(t, p, "first line.
\nsecond line.
fourth line.
\n") } func TestTableOfContents(t *testing.T) { - p, _ := NewPage("tocpage.md") - _, err := p.ReadFrom(strings.NewReader(pageWithToC)) - p.Convert() - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) + s := newSiteFromSources("tocpage.md", pageWithToC) + + if err := buildSiteSkipRender(s); err != nil { + t.Fatalf("Failed to build site: %s", err) } + + require.Len(t, s.Pages, 1) + + p := s.Pages[0] + checkPageContent(t, p, "\n\nFor some moments the old man did not reply. He stood with bowed head, buried in deep thought. But at last he spoke.
\n\nI have no idea, of course, how long it took me to reach the limit of the plain,\nbut at last I entered the foothills, following a pretty little canyon upward\ntoward the mountains. Beside me frolicked a laughing brooklet, hurrying upon\nits noisy way down to the silent sea. In its quieter pools I discovered many\nsmall fish, of four-or five-pound weight I should imagine. In appearance,\nexcept as to size and color, they were not unlike the whale of our own seas. As\nI watched them playing about I discovered, not only that they suckled their\nyoung, but that at intervals they rose to the surface to breathe as well as to\nfeed upon certain grasses and a strange, scarlet lichen which grew upon the\nrocks just above the water line.
\n\nI remember I felt an extraordinary persuasion that I was being played with,\nthat presently, when I was upon the very verge of safety, this mysterious\ndeath–as swift as the passage of light–would leap after me from the pit about\nthe cylinder and strike me down. ## BB
\n\n“You’re a great Granser,” he cried delightedly, “always making believe them little marks mean something.”
\n") checkPageTOC(t, p, "") } func TestPageWithMoreTag(t *testing.T) { - p, _ := NewPage("simple.md") - _, err := p.ReadFrom(strings.NewReader(simplePageWithSummaryDelimiterSameLine)) - p.Convert() - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) + + assertFunc := func(t *testing.T, ext string, p *Page) { + checkPageTitle(t, p, "Simple") + checkPageContent(t, p, normalizeExpected(ext, "Summary Same Line
\n\nSome more text
\n")) + checkPageSummary(t, p, normalizeExpected(ext, "Summary Same Line
")) + checkPageType(t, p, "page") + checkPageLayout(t, p, "page/single.html", "_default/single.html", "theme/page/single.html", "theme/_default/single.html") } - checkPageTitle(t, p, "Simple") - checkPageContent(t, p, "Summary Same Line
\n\nSome more text
\n") - checkPageSummary(t, p, "Summary Same Line
\n") - checkPageType(t, p, "page") - checkPageLayout(t, p, "page/single.html", "_default/single.html", "theme/page/single.html", "theme/_default/single.html") + + testAllMarkdownEnginesForPage(t, assertFunc, "simple", simplePageWithSummaryDelimiterSameLine) } func TestPageWithDate(t *testing.T) { - p, _ := NewPage("simple.md") - _, err := p.ReadFrom(strings.NewReader(simplePageRFC3339Date)) - p.Convert() - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) - } - d, err := time.Parse(time.RFC3339, "2013-05-17T16:59:30Z") - if err != nil { - t.Fatalf("Unable to prase page.") + s := newSiteFromSources("simple.md", simplePageRFC3339Date) + + if err := buildSiteSkipRender(s); err != nil { + t.Fatalf("Failed to build site: %s", err) } + + require.Len(t, s.Pages, 1) + + p := s.Pages[0] + d, _ := time.Parse(time.RFC3339, "2013-05-17T16:59:30Z") + checkPageDate(t, p, d) } func TestWordCountWithAllCJKRunesWithoutHasCJKLanguage(t *testing.T) { testCommonResetState() - p, _ := NewPage("simple.md") - _, err := p.ReadFrom(strings.NewReader(simplePageWithAllCJKRunes)) - p.Convert() - p.analyzePage() - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) + assertFunc := func(t *testing.T, ext string, p *Page) { + if p.WordCount != 8 { + t.Fatalf("[%s] incorrect word count for content '%s'. expected %v, got %v", ext, p.plain, 8, p.WordCount) + } } - if p.WordCount != 8 { - t.Fatalf("incorrect word count for content '%s'. expected %v, got %v", p.plain, 8, p.WordCount) - } + testAllMarkdownEnginesForPage(t, assertFunc, "simple", simplePageWithAllCJKRunes) } func TestWordCountWithAllCJKRunesHasCJKLanguage(t *testing.T) { testCommonResetState() - viper.Set("HasCJKLanguage", true) - p, _ := NewPage("simple.md") - _, err := p.ReadFrom(strings.NewReader(simplePageWithAllCJKRunes)) - p.Convert() - p.analyzePage() - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) + assertFunc := func(t *testing.T, ext string, p *Page) { + if p.WordCount != 15 { + t.Fatalf("[%s] incorrect word count for content '%s'. expected %v, got %v", ext, p.plain, 15, p.WordCount) + } } - if p.WordCount != 15 { - t.Fatalf("incorrect word count for content '%s'. expected %v, got %v", p.plain, 15, p.WordCount) - } + testAllMarkdownEnginesForPage(t, assertFunc, "simple", simplePageWithAllCJKRunes) } func TestWordCountWithMainEnglishWithCJKRunes(t *testing.T) { @@ -682,69 +842,60 @@ func TestWordCountWithMainEnglishWithCJKRunes(t *testing.T) { viper.Set("HasCJKLanguage", true) - p, _ := NewPage("simple.md") - _, err := p.ReadFrom(strings.NewReader(simplePageWithMainEnglishWithCJKRunes)) - p.Convert() - p.analyzePage() - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) + assertFunc := func(t *testing.T, ext string, p *Page) { + if p.WordCount != 74 { + t.Fatalf("[%s] incorrect word count for content '%s'. expected %v, got %v", ext, p.plain, 74, p.WordCount) + } + + if p.Summary != simplePageWithMainEnglishWithCJKRunesSummary { + t.Fatalf("[%s] incorrect Summary for content '%s'. expected %v, got %v", ext, p.plain, + simplePageWithMainEnglishWithCJKRunesSummary, p.Summary) + } + } - if p.WordCount != 74 { - t.Fatalf("incorrect word count for content '%s'. expected %v, got %v", p.plain, 74, p.WordCount) - } - - if p.Summary != simplePageWithMainEnglishWithCJKRunesSummary { - t.Fatalf("incorrect Summary for content '%s'. expected %v, got %v", p.plain, - simplePageWithMainEnglishWithCJKRunesSummary, p.Summary) - } + testAllMarkdownEnginesForPage(t, assertFunc, "simple", simplePageWithMainEnglishWithCJKRunes) } func TestWordCountWithIsCJKLanguageFalse(t *testing.T) { testCommonResetState() - viper.Set("HasCJKLanguage", true) - p, _ := NewPage("simple.md") - _, err := p.ReadFrom(strings.NewReader(simplePageWithIsCJKLanguageFalse)) - p.Convert() - p.analyzePage() - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) + assertFunc := func(t *testing.T, ext string, p *Page) { + if p.WordCount != 75 { + t.Fatalf("[%s] incorrect word count for content '%s'. expected %v, got %v", ext, p.plain, 74, p.WordCount) + } + + if p.Summary != simplePageWithIsCJKLanguageFalseSummary { + t.Fatalf("[%s] incorrect Summary for content '%s'. expected %v, got %v", ext, p.plain, + simplePageWithIsCJKLanguageFalseSummary, p.Summary) + } + } - if p.WordCount != 75 { - t.Fatalf("incorrect word count for content '%s'. expected %v, got %v", p.plain, 75, p.WordCount) - } + testAllMarkdownEnginesForPage(t, assertFunc, "simple", simplePageWithIsCJKLanguageFalse) - if p.Summary != simplePageWithIsCJKLanguageFalseSummary { - t.Fatalf("incorrect Summary for content '%s'. expected %v, got %v", p.plain, - simplePageWithIsCJKLanguageFalseSummary, p.Summary) - } } func TestWordCount(t *testing.T) { - p, _ := NewPage("simple.md") - _, err := p.ReadFrom(strings.NewReader(simplePageWithLongContent)) - p.Convert() - p.analyzePage() - if err != nil { - t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) + + assertFunc := func(t *testing.T, ext string, p *Page) { + if p.WordCount != 483 { + t.Fatalf("[%s] incorrect word count. expected %v, got %v", ext, 483, p.WordCount) + } + + if p.FuzzyWordCount != 500 { + t.Fatalf("[%s] incorrect word count. expected %v, got %v", ext, 500, p.WordCount) + } + + if p.ReadingTime != 3 { + t.Fatalf("[%s] incorrect min read. expected %v, got %v", ext, 3, p.ReadingTime) + } + + checkTruncation(t, p, true, "long page") } - if p.WordCount != 483 { - t.Fatalf("incorrect word count. expected %v, got %v", 483, p.WordCount) - } - - if p.FuzzyWordCount != 500 { - t.Fatalf("incorrect word count. expected %v, got %v", 500, p.WordCount) - } - - if p.ReadingTime != 3 { - t.Fatalf("incorrect min read. expected %v, got %v", 3, p.ReadingTime) - } - - checkTruncation(t, p, true, "long page") + testAllMarkdownEnginesForPage(t, assertFunc, "simple", simplePageWithLongContent) } func TestCreatePage(t *testing.T) { @@ -1049,15 +1200,18 @@ func TestPageSimpleMethods(t *testing.T) { } func TestChompBOM(t *testing.T) { - p, _ := NewPage("simple.md") const utf8BOM = "\xef\xbb\xbf" - _, err := p.ReadFrom(strings.NewReader(utf8BOM + simplePage)) - p.Convert() - if err != nil { - t.Fatalf("Unable to create a page with BOM prefixed frontmatter and body content: %s", err) + s := newSiteFromSources("simple.md", utf8BOM+simplePage) + + if err := buildSiteSkipRender(s); err != nil { + t.Fatalf("Failed to build site: %s", err) } + require.Len(t, s.Pages, 1) + + p := s.Pages[0] + checkPageTitle(t, p, "Simple") } diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go index 2de00fa90..b63ba4a49 100644 --- a/hugolib/shortcode.go +++ b/hugolib/shortcode.go @@ -160,7 +160,11 @@ func HandleShortcodes(stringToParse string, page *Page, t tpl.Template) (string, } if len(tmpShortcodes) > 0 { - tmpContentWithTokensReplaced, err := replaceShortcodeTokens([]byte(tmpContent), shortcodePlaceholderPrefix, tmpShortcodes) + shortcodes, err := executeShortcodeFuncMap(tmpShortcodes) + if err != nil { + return "", err + } + tmpContentWithTokensReplaced, err := replaceShortcodeTokens([]byte(tmpContent), shortcodePlaceholderPrefix, shortcodes) if err != nil { return "", fmt.Errorf("Fail to replace short code tokens in %s:\n%s", page.BaseFileName(), err.Error()) @@ -274,7 +278,7 @@ func renderShortcode(sc shortcode, parent *ShortcodeWithPage, p *Page, t tpl.Tem return renderShortcodeWithPage(tmpl, data) } -func extractAndRenderShortcodes(stringToParse string, p *Page, t tpl.Template) (string, map[string]string, error) { +func extractAndRenderShortcodes(stringToParse string, p *Page, t tpl.Template) (string, map[string]func() (string, error), error) { if p.rendered { panic("Illegal state: Page already marked as rendered, please reuse the shortcodes") @@ -297,15 +301,32 @@ func extractAndRenderShortcodes(stringToParse string, p *Page, t tpl.Template) ( } -func renderShortcodes(shortcodes map[string]shortcode, p *Page, t tpl.Template) map[string]string { - renderedShortcodes := make(map[string]string) +var emptyShortcodeFn = func() (string, error) { return "", nil } + +func executeShortcodeFuncMap(funcs map[string]func() (string, error)) (map[string]string, error) { + result := make(map[string]string) + + for k, v := range funcs { + s, err := v() + if err != nil { + return nil, fmt.Errorf("Failed to execute shortcode with key %s: %s", k, err) + } + result[k] = s + } + + return result, nil +} + +func renderShortcodes(shortcodes map[string]shortcode, p *Page, t tpl.Template) map[string]func() (string, error) { + renderedShortcodes := make(map[string]func() (string, error)) for key, sc := range shortcodes { if sc.err != nil { // need to have something to replace with - renderedShortcodes[key] = "" + renderedShortcodes[key] = emptyShortcodeFn } else { - renderedShortcodes[key] = renderShortcode(sc, nil, p, t) + shorctode := sc + renderedShortcodes[key] = func() (string, error) { return renderShortcode(shorctode, nil, p, t), nil } } } diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go index 5069fa195..dd16bff07 100644 --- a/hugolib/shortcode_test.go +++ b/hugolib/shortcode_test.go @@ -484,9 +484,34 @@ e`, {"sect/doc8.rst", `**Shortcodes:** *b: {{< b >}} c: {{% c %}}*`, filepath.FromSlash("sect/doc8/index.html"), "Shortcodes: b: b c: c
\nShortcodes: b: b c: c
\n"}, + // Issue #1229: Menus not available in shortcode. + {"sect/doc10.md", `--- +menu: + main: + identifier: 'parent' +tags: +- Menu +--- +**Menus:** {{< menu >}}`, + filepath.FromSlash("sect/doc10/index.html"), + "Menus: 1
\n"}, + // Issue #2323: Taxonomies not available in shortcode. + {"sect/doc11.md", `--- +tags: +- Bugs +--- +**Tags:** {{< tags >}}`, + filepath.FromSlash("sect/doc11/index.html"), + "Tags: 2
\n"}, } sources := make([]source.ByteSource, len(tests)) @@ -507,6 +532,8 @@ e`, templ.AddInternalShortcode("b.html", `b`) templ.AddInternalShortcode("c.html", `c`) templ.AddInternalShortcode("d.html", `d`) + templ.AddInternalShortcode("menu.html", `{{ len (index .Page.Menus "main").Children }}`) + templ.AddInternalShortcode("tags.html", `{{ len .Page.Site.Taxonomies.tags }}`) return nil @@ -540,7 +567,7 @@ e`, content := helpers.ReaderToString(file) if content != test.expected { - t.Errorf("%s content expected:\n%q\ngot:\n%q", test.outFile, test.expected, content) + t.Fatalf("%s content expected:\n%q\ngot:\n%q", test.outFile, test.expected, content) } } diff --git a/hugolib/site.go b/hugolib/site.go index 59b8379dc..03e697130 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -113,6 +113,26 @@ func newSiteDefaultLang() *Site { return NewSite(newDefaultLanguage()) } +// Convenience func used in tests. +func newSiteFromSources(pathContentPairs ...string) *Site { + if len(pathContentPairs)%2 != 0 { + panic("pathContentPairs must come in pairs") + } + + sources := make([]source.ByteSource, 0) + + for i := 0; i < len(pathContentPairs); i += 2 { + path := pathContentPairs[i] + content := pathContentPairs[i+1] + sources = append(sources, source.ByteSource{Name: filepath.FromSlash(path), Content: []byte(content)}) + } + + return &Site{ + Source: &source.InMemorySource{ByteSource: sources}, + Language: newDefaultLanguage(), + } +} + type targetList struct { page target.Output pageUgly target.Output diff --git a/hugolib/site_test.go b/hugolib/site_test.go index b9e2d346b..f98bc6a7d 100644 --- a/hugolib/site_test.go +++ b/hugolib/site_test.go @@ -30,6 +30,7 @@ import ( "github.com/spf13/hugo/target" "github.com/spf13/viper" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const ( @@ -84,10 +85,16 @@ func pageMust(p *Page, err error) *Page { } func TestDegenerateRenderThingMissingTemplate(t *testing.T) { - p, _ := NewPageFrom(strings.NewReader(pageSimpleTitle), "content/a/file.md") - p.Convert() - s := new(Site) - s.prepTemplates(nil) + s := newSiteFromSources("content/a/file.md", pageSimpleTitle) + + if err := buildSiteSkipRender(s); err != nil { + t.Fatalf("Failed to build site: %s", err) + } + + require.Len(t, s.Pages, 1) + + p := s.Pages[0] + err := s.renderThing(p, "foobar", nil) if err == nil { t.Errorf("Expected err to be returned when missing the template.")