github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/parser/pageparser/pageparser_intro_test.go (about) 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 "strings" 19 "testing" 20 21 qt "github.com/frankban/quicktest" 22 ) 23 24 type lexerTest struct { 25 name string 26 input string 27 items []typeText 28 } 29 30 type typeText struct { 31 typ ItemType 32 text string 33 } 34 35 func nti(tp ItemType, val string) typeText { 36 return typeText{typ: tp, text: val} 37 } 38 39 var ( 40 tstJSON = `{ "a": { "b": "\"Hugo\"}" } }` 41 tstFrontMatterTOML = nti(TypeFrontMatterTOML, "foo = \"bar\"\n") 42 tstFrontMatterYAML = nti(TypeFrontMatterYAML, "foo: \"bar\"\n") 43 tstFrontMatterYAMLCRLF = nti(TypeFrontMatterYAML, "foo: \"bar\"\r\n") 44 tstFrontMatterJSON = nti(TypeFrontMatterJSON, tstJSON+"\r\n") 45 tstSomeText = nti(tText, "\nSome text.\n") 46 tstSummaryDivider = nti(TypeLeadSummaryDivider, "<!--more-->\n") 47 tstNewline = nti(tText, "\n") 48 49 tstORG = ` 50 #+TITLE: T1 51 #+AUTHOR: A1 52 #+DESCRIPTION: D1 53 ` 54 tstFrontMatterORG = nti(TypeFrontMatterORG, tstORG) 55 ) 56 57 var crLfReplacer = strings.NewReplacer("\r", "#", "\n", "$") 58 59 // TODO(bep) a way to toggle ORG mode vs the rest. 60 var frontMatterTests = []lexerTest{ 61 {"empty", "", []typeText{tstEOF}}, 62 {"Byte order mark", "\ufeff\nSome text.\n", []typeText{nti(TypeIgnore, "\ufeff"), tstSomeText, tstEOF}}, 63 {"HTML Document", ` <html> `, []typeText{nti(tError, "plain HTML documents not supported")}}, 64 {"HTML Document with shortcode", `<html>{{< sc1 >}}</html>`, []typeText{nti(tError, "plain HTML documents not supported")}}, 65 {"No front matter", "\nSome text.\n", []typeText{tstSomeText, tstEOF}}, 66 {"YAML front matter", "---\nfoo: \"bar\"\n---\n\nSome text.\n", []typeText{tstFrontMatterYAML, tstSomeText, tstEOF}}, 67 {"YAML empty front matter", "---\n---\n\nSome text.\n", []typeText{nti(TypeFrontMatterYAML, ""), tstSomeText, tstEOF}}, 68 {"YAML commented out front matter", "<!--\n---\nfoo: \"bar\"\n---\n-->\nSome text.\n", []typeText{nti(TypeIgnore, "<!--\n"), tstFrontMatterYAML, nti(TypeIgnore, "-->"), tstSomeText, tstEOF}}, 69 {"YAML commented out front matter, no end", "<!--\n---\nfoo: \"bar\"\n---\nSome text.\n", []typeText{nti(TypeIgnore, "<!--\n"), tstFrontMatterYAML, nti(tError, "starting HTML comment with no end")}}, 70 // Note that we keep all bytes as they are, but we need to handle CRLF 71 {"YAML front matter CRLF", "---\r\nfoo: \"bar\"\r\n---\n\nSome text.\n", []typeText{tstFrontMatterYAMLCRLF, tstSomeText, tstEOF}}, 72 {"TOML front matter", "+++\nfoo = \"bar\"\n+++\n\nSome text.\n", []typeText{tstFrontMatterTOML, tstSomeText, tstEOF}}, 73 {"JSON front matter", tstJSON + "\r\n\nSome text.\n", []typeText{tstFrontMatterJSON, tstSomeText, tstEOF}}, 74 {"ORG front matter", tstORG + "\nSome text.\n", []typeText{tstFrontMatterORG, tstSomeText, tstEOF}}, 75 {"Summary divider ORG", tstORG + "\nSome text.\n# more\nSome text.\n", []typeText{tstFrontMatterORG, tstSomeText, nti(TypeLeadSummaryDivider, "# more\n"), nti(tText, "Some text.\n"), tstEOF}}, 76 {"Summary divider", "+++\nfoo = \"bar\"\n+++\n\nSome text.\n<!--more-->\nSome text.\n", []typeText{tstFrontMatterTOML, tstSomeText, tstSummaryDivider, nti(tText, "Some text.\n"), tstEOF}}, 77 {"Summary divider same line", "+++\nfoo = \"bar\"\n+++\n\nSome text.<!--more-->Some text.\n", []typeText{tstFrontMatterTOML, nti(tText, "\nSome text."), nti(TypeLeadSummaryDivider, "<!--more-->"), nti(tText, "Some text.\n"), tstEOF}}, 78 // https://github.com/gohugoio/hugo/issues/5402 79 {"Summary and shortcode, no space", "+++\nfoo = \"bar\"\n+++\n\nSome text.\n<!--more-->{{< sc1 >}}\nSome text.\n", []typeText{tstFrontMatterTOML, tstSomeText, nti(TypeLeadSummaryDivider, "<!--more-->"), tstLeftNoMD, tstSC1, tstRightNoMD, tstSomeText, tstEOF}}, 80 // https://github.com/gohugoio/hugo/issues/5464 81 {"Summary and shortcode only", "+++\nfoo = \"bar\"\n+++\n{{< sc1 >}}\n<!--more-->\n{{< sc2 >}}", []typeText{tstFrontMatterTOML, tstLeftNoMD, tstSC1, tstRightNoMD, tstNewline, tstSummaryDivider, tstLeftNoMD, tstSC2, tstRightNoMD, tstEOF}}, 82 } 83 84 func TestFrontMatter(t *testing.T) { 85 t.Parallel() 86 c := qt.New(t) 87 for i, test := range frontMatterTests { 88 items := collect([]byte(test.input), false, lexIntroSection) 89 if !equal(test.input, items, test.items) { 90 got := itemsToString(items, []byte(test.input)) 91 expected := testItemsToString(test.items) 92 c.Assert(got, qt.Equals, expected, qt.Commentf("Test %d: %s", i, test.name)) 93 } 94 } 95 } 96 97 func itemsToString(items []Item, source []byte) string { 98 var sb strings.Builder 99 for i, item := range items { 100 var s string 101 if item.Err != nil { 102 s = item.Err.Error() 103 } else { 104 s = string(item.Val(source)) 105 } 106 sb.WriteString(fmt.Sprintf("%s: %s\n", item.Type, s)) 107 108 if i < len(items)-1 { 109 sb.WriteString("\n") 110 } 111 } 112 return crLfReplacer.Replace(sb.String()) 113 } 114 115 func testItemsToString(items []typeText) string { 116 var sb strings.Builder 117 for i, item := range items { 118 sb.WriteString(fmt.Sprintf("%s: %s\n", item.typ, item.text)) 119 120 if i < len(items)-1 { 121 sb.WriteString("\n") 122 } 123 } 124 return crLfReplacer.Replace(sb.String()) 125 } 126 127 func collectWithConfig(input []byte, skipFrontMatter bool, stateStart stateFunc, cfg Config) (items []Item) { 128 l := newPageLexer(input, stateStart, cfg) 129 l.run() 130 iter := NewIterator(l.items) 131 132 for { 133 item := iter.Next() 134 items = append(items, item) 135 if item.Type == tEOF || item.Type == tError { 136 break 137 } 138 } 139 return 140 } 141 142 func collect(input []byte, skipFrontMatter bool, stateStart stateFunc) (items []Item) { 143 var cfg Config 144 145 return collectWithConfig(input, skipFrontMatter, stateStart, cfg) 146 } 147 148 func collectStringMain(input string) []Item { 149 return collect([]byte(input), true, lexMainSection) 150 } 151 152 // no positional checking, for now ... 153 func equal(source string, got []Item, expect []typeText) bool { 154 if len(got) != len(expect) { 155 return false 156 } 157 sourceb := []byte(source) 158 for k := range got { 159 g := got[k] 160 e := expect[k] 161 if g.Type != e.typ { 162 return false 163 } 164 165 var s string 166 if g.Err != nil { 167 s = g.Err.Error() 168 } else { 169 s = string(g.Val(sourceb)) 170 } 171 172 if s != e.text { 173 return false 174 } 175 176 } 177 return true 178 }