github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/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  	"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  }