pageparser_intro_test.go (5518B)
1 // Copyright 2018 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 pageparser 15 16 import ( 17 "fmt" 18 "reflect" 19 "strings" 20 "testing" 21 ) 22 23 type lexerTest struct { 24 name string 25 input string 26 items []Item 27 } 28 29 func nti(tp ItemType, val string) Item { 30 return Item{tp, 0, []byte(val), false} 31 } 32 33 var ( 34 tstJSON = `{ "a": { "b": "\"Hugo\"}" } }` 35 tstFrontMatterTOML = nti(TypeFrontMatterTOML, "foo = \"bar\"\n") 36 tstFrontMatterYAML = nti(TypeFrontMatterYAML, "foo: \"bar\"\n") 37 tstFrontMatterYAMLCRLF = nti(TypeFrontMatterYAML, "foo: \"bar\"\r\n") 38 tstFrontMatterJSON = nti(TypeFrontMatterJSON, tstJSON+"\r\n") 39 tstSomeText = nti(tText, "\nSome text.\n") 40 tstSummaryDivider = nti(TypeLeadSummaryDivider, "<!--more-->\n") 41 tstNewline = nti(tText, "\n") 42 43 tstORG = ` 44 #+TITLE: T1 45 #+AUTHOR: A1 46 #+DESCRIPTION: D1 47 ` 48 tstFrontMatterORG = nti(TypeFrontMatterORG, tstORG) 49 ) 50 51 var crLfReplacer = strings.NewReplacer("\r", "#", "\n", "$") 52 53 // TODO(bep) a way to toggle ORG mode vs the rest. 54 var frontMatterTests = []lexerTest{ 55 {"empty", "", []Item{tstEOF}}, 56 {"Byte order mark", "\ufeff\nSome text.\n", []Item{nti(TypeIgnore, "\ufeff"), tstSomeText, tstEOF}}, 57 {"HTML Document", ` <html> `, []Item{nti(tError, "plain HTML documents not supported")}}, 58 {"HTML Document with shortcode", `<html>{{< sc1 >}}</html>`, []Item{nti(tError, "plain HTML documents not supported")}}, 59 {"No front matter", "\nSome text.\n", []Item{tstSomeText, tstEOF}}, 60 {"YAML front matter", "---\nfoo: \"bar\"\n---\n\nSome text.\n", []Item{tstFrontMatterYAML, tstSomeText, tstEOF}}, 61 {"YAML empty front matter", "---\n---\n\nSome text.\n", []Item{nti(TypeFrontMatterYAML, ""), tstSomeText, tstEOF}}, 62 {"YAML commented out front matter", "<!--\n---\nfoo: \"bar\"\n---\n-->\nSome text.\n", []Item{nti(TypeIgnore, "<!--\n"), tstFrontMatterYAML, nti(TypeIgnore, "-->"), tstSomeText, tstEOF}}, 63 {"YAML commented out front matter, no end", "<!--\n---\nfoo: \"bar\"\n---\nSome text.\n", []Item{nti(TypeIgnore, "<!--\n"), tstFrontMatterYAML, nti(tError, "starting HTML comment with no end")}}, 64 // Note that we keep all bytes as they are, but we need to handle CRLF 65 {"YAML front matter CRLF", "---\r\nfoo: \"bar\"\r\n---\n\nSome text.\n", []Item{tstFrontMatterYAMLCRLF, tstSomeText, tstEOF}}, 66 {"TOML front matter", "+++\nfoo = \"bar\"\n+++\n\nSome text.\n", []Item{tstFrontMatterTOML, tstSomeText, tstEOF}}, 67 {"JSON front matter", tstJSON + "\r\n\nSome text.\n", []Item{tstFrontMatterJSON, tstSomeText, tstEOF}}, 68 {"ORG front matter", tstORG + "\nSome text.\n", []Item{tstFrontMatterORG, tstSomeText, tstEOF}}, 69 {"Summary divider ORG", tstORG + "\nSome text.\n# more\nSome text.\n", []Item{tstFrontMatterORG, tstSomeText, nti(TypeLeadSummaryDivider, "# more\n"), nti(tText, "Some text.\n"), tstEOF}}, 70 {"Summary divider", "+++\nfoo = \"bar\"\n+++\n\nSome text.\n<!--more-->\nSome text.\n", []Item{tstFrontMatterTOML, tstSomeText, tstSummaryDivider, nti(tText, "Some text.\n"), tstEOF}}, 71 {"Summary divider same line", "+++\nfoo = \"bar\"\n+++\n\nSome text.<!--more-->Some text.\n", []Item{tstFrontMatterTOML, nti(tText, "\nSome text."), nti(TypeLeadSummaryDivider, "<!--more-->"), nti(tText, "Some text.\n"), tstEOF}}, 72 // https://github.com/gohugoio/hugo/issues/5402 73 {"Summary and shortcode, no space", "+++\nfoo = \"bar\"\n+++\n\nSome text.\n<!--more-->{{< sc1 >}}\nSome text.\n", []Item{tstFrontMatterTOML, tstSomeText, nti(TypeLeadSummaryDivider, "<!--more-->"), tstLeftNoMD, tstSC1, tstRightNoMD, tstSomeText, tstEOF}}, 74 // https://github.com/gohugoio/hugo/issues/5464 75 {"Summary and shortcode only", "+++\nfoo = \"bar\"\n+++\n{{< sc1 >}}\n<!--more-->\n{{< sc2 >}}", []Item{tstFrontMatterTOML, tstLeftNoMD, tstSC1, tstRightNoMD, tstNewline, tstSummaryDivider, tstLeftNoMD, tstSC2, tstRightNoMD, tstEOF}}, 76 } 77 78 func TestFrontMatter(t *testing.T) { 79 t.Parallel() 80 for i, test := range frontMatterTests { 81 items := collect([]byte(test.input), false, lexIntroSection) 82 if !equal(items, test.items) { 83 got := crLfReplacer.Replace(fmt.Sprint(items)) 84 expected := crLfReplacer.Replace(fmt.Sprint(test.items)) 85 t.Errorf("[%d] %s: got\n\t%v\nexpected\n\t%v", i, test.name, got, expected) 86 } 87 } 88 } 89 90 func collectWithConfig(input []byte, skipFrontMatter bool, stateStart stateFunc, cfg Config) (items []Item) { 91 l := newPageLexer(input, stateStart, cfg) 92 l.run() 93 t := l.newIterator() 94 95 for { 96 item := t.Next() 97 items = append(items, item) 98 if item.Type == tEOF || item.Type == tError { 99 break 100 } 101 } 102 return 103 } 104 105 func collect(input []byte, skipFrontMatter bool, stateStart stateFunc) (items []Item) { 106 var cfg Config 107 108 return collectWithConfig(input, skipFrontMatter, stateStart, cfg) 109 } 110 111 // no positional checking, for now ... 112 func equal(i1, i2 []Item) bool { 113 if len(i1) != len(i2) { 114 return false 115 } 116 for k := range i1 { 117 if i1[k].Type != i2[k].Type { 118 return false 119 } 120 121 if !reflect.DeepEqual(i1[k].Val, i2[k].Val) { 122 return false 123 } 124 } 125 return true 126 }