2018-10-17 07:48:55 -04:00
// Copyright 2018 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pageparser
import (
"fmt"
2018-10-18 03:04:48 -04:00
"reflect"
2018-10-17 07:48:55 -04:00
"strings"
"testing"
)
type lexerTest struct {
name string
input string
items [ ] Item
}
2018-10-18 04:21:23 -04:00
func nti ( tp ItemType , val string ) Item {
2018-10-18 03:04:48 -04:00
return Item { tp , 0 , [ ] byte ( val ) }
}
2018-10-17 07:48:55 -04:00
var (
tstJSON = ` { "a": { "b": "\"Hugo\"}" } } `
2018-10-18 04:21:23 -04:00
tstFrontMatterTOML = nti ( TypeFrontMatterTOML , "\nfoo = \"bar\"\n" )
tstFrontMatterYAML = nti ( TypeFrontMatterYAML , "\nfoo: \"bar\"\n" )
tstFrontMatterYAMLCRLF = nti ( TypeFrontMatterYAML , "\r\nfoo: \"bar\"\r\n" )
tstFrontMatterJSON = nti ( TypeFrontMatterJSON , tstJSON + "\r\n" )
2018-10-18 03:04:48 -04:00
tstSomeText = nti ( tText , "\nSome text.\n" )
2018-10-18 04:21:23 -04:00
tstSummaryDivider = nti ( TypeLeadSummaryDivider , "<!--more-->" )
tstSummaryDividerOrg = nti ( TypeSummaryDividerOrg , "# more" )
2018-10-17 07:48:55 -04:00
tstORG = `
# + TITLE : T1
# + AUTHOR : A1
# + DESCRIPTION : D1
`
2018-10-18 04:21:23 -04:00
tstFrontMatterORG = nti ( TypeFrontMatterORG , tstORG )
2018-10-17 07:48:55 -04:00
)
var crLfReplacer = strings . NewReplacer ( "\r" , "#" , "\n" , "$" )
// TODO(bep) a way to toggle ORG mode vs the rest.
var frontMatterTests = [ ] lexerTest {
{ "empty" , "" , [ ] Item { tstEOF } } ,
2018-10-18 04:21:23 -04:00
{ "Byte order mark" , "\ufeff\nSome text.\n" , [ ] Item { nti ( TypeIgnore , "\ufeff" ) , tstSomeText , tstEOF } } ,
{ "HTML Document" , ` <html> ` , [ ] Item { nti ( TypeHTMLDocument , " <html> " ) , tstEOF } } ,
{ "HTML Document 2" , ` <html><h1>Hugo Rocks</h1></html> ` , [ ] Item { nti ( TypeHTMLDocument , "<html><h1>Hugo Rocks</h1></html>" ) , tstEOF } } ,
{ "No front matter" , "\nSome text.\n" , [ ] Item { tstSomeText , tstEOF } } ,
2018-10-17 07:48:55 -04:00
{ "YAML front matter" , "---\nfoo: \"bar\"\n---\n\nSome text.\n" , [ ] Item { tstFrontMatterYAML , tstSomeText , tstEOF } } ,
2018-10-18 04:21:23 -04:00
{ "YAML empty front matter" , "---\n---\n\nSome text.\n" , [ ] Item { nti ( TypeFrontMatterYAML , "\n" ) , tstSomeText , tstEOF } } ,
{ "YAML commented out front matter" , "<!--\n---\nfoo: \"bar\"\n---\n-->\nSome text.\n" , [ ] Item { nti ( TypeHTMLComment , "<!--\n---\nfoo: \"bar\"\n---\n-->" ) , tstSomeText , tstEOF } } ,
2018-10-17 07:48:55 -04:00
// Note that we keep all bytes as they are, but we need to handle CRLF
{ "YAML front matter CRLF" , "---\r\nfoo: \"bar\"\r\n---\n\nSome text.\n" , [ ] Item { tstFrontMatterYAMLCRLF , tstSomeText , tstEOF } } ,
{ "TOML front matter" , "+++\nfoo = \"bar\"\n+++\n\nSome text.\n" , [ ] Item { tstFrontMatterTOML , tstSomeText , tstEOF } } ,
{ "JSON front matter" , tstJSON + "\r\n\nSome text.\n" , [ ] Item { tstFrontMatterJSON , tstSomeText , tstEOF } } ,
{ "ORG front matter" , tstORG + "\nSome text.\n" , [ ] Item { tstFrontMatterORG , tstSomeText , tstEOF } } ,
{ "Summary divider ORG" , tstORG + "\nSome text.\n# more\nSome text.\n" , [ ] Item { tstFrontMatterORG , tstSomeText , tstSummaryDividerOrg , tstSomeText , tstEOF } } ,
{ "Summary divider" , "+++\nfoo = \"bar\"\n+++\n\nSome text.\n<!--more-->\nSome text.\n" , [ ] Item { tstFrontMatterTOML , tstSomeText , tstSummaryDivider , tstSomeText , tstEOF } } ,
}
func TestFrontMatter ( t * testing . T ) {
t . Parallel ( )
for i , test := range frontMatterTests {
2018-10-18 03:04:48 -04:00
items := collect ( [ ] byte ( test . input ) , false , lexIntroSection )
2018-10-17 07:48:55 -04:00
if ! equal ( items , test . items ) {
got := crLfReplacer . Replace ( fmt . Sprint ( items ) )
expected := crLfReplacer . Replace ( fmt . Sprint ( test . items ) )
t . Errorf ( "[%d] %s: got\n\t%v\nexpected\n\t%v" , i , test . name , got , expected )
}
}
}
2018-10-18 03:04:48 -04:00
func collect ( input [ ] byte , skipFrontMatter bool , stateStart stateFunc ) ( items [ ] Item ) {
2018-10-17 07:48:55 -04:00
l := newPageLexer ( input , 0 , stateStart )
l . run ( )
2018-10-18 04:21:23 -04:00
t := l . newIterator ( )
2018-10-17 07:48:55 -04:00
for {
2018-10-18 04:21:23 -04:00
item := t . Next ( )
2018-10-17 07:48:55 -04:00
items = append ( items , item )
2018-10-18 04:21:23 -04:00
if item . Typ == tEOF || item . Typ == tError {
2018-10-17 07:48:55 -04:00
break
}
}
return
}
// no positional checking, for now ...
func equal ( i1 , i2 [ ] Item ) bool {
if len ( i1 ) != len ( i2 ) {
return false
}
for k := range i1 {
2018-10-18 04:21:23 -04:00
if i1 [ k ] . Typ != i2 [ k ] . Typ {
2018-10-17 07:48:55 -04:00
return false
}
2018-10-18 03:04:48 -04:00
if ! reflect . DeepEqual ( i1 [ k ] . Val , i2 [ k ] . Val ) {
2018-10-17 07:48:55 -04:00
return false
}
}
return true
}