summaryrefslogtreecommitdiffstats
path: root/parser
diff options
context:
space:
mode:
authorCameron Moore <moorereason@gmail.com>2016-12-26 15:23:20 -0600
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-03-11 17:52:25 +0100
commitf039e3be9e4a11808508c8cd3043b340deea040f (patch)
treedf3e709fc6321fd2a3e1d23efa2c3512d8ed4a94 /parser
parentddc8cc0082965143a650052a9aa538bac9133481 (diff)
parser: Refactor frontmatter parser and add tests
Lots of cleanups here: - Refactor InterfaceToConfig and InterfaceToFrontMatter to use io.Writer. - Simplify InterfaceToFrontMatter by wrapping InterfaceToConfig. - Export FrontmatterType since we return it in DetectFrontMatter. - Refactor removeTOMLIdentifier to avoid blindly replacing "+++". - Update HandleJSONMetaData to return an empty map on nil input. - Updates vendored goorgeous package and test for org-mode frontmatter. - Add tests and godoc comments. Coverage for parser package increased from 45.2% to 85.2%.
Diffstat (limited to 'parser')
-rw-r--r--parser/frontmatter.go161
-rw-r--r--parser/frontmatter_test.go281
-rw-r--r--parser/page.go18
-rw-r--r--parser/page_test.go130
4 files changed, 527 insertions, 63 deletions
diff --git a/parser/frontmatter.go b/parser/frontmatter.go
index e57a593ab..797c6fcf0 100644
--- a/parser/frontmatter.go
+++ b/parser/frontmatter.go
@@ -17,6 +17,7 @@ import (
"bytes"
"encoding/json"
"errors"
+ "io"
"strings"
"github.com/chaseadamsio/goorgeous"
@@ -25,113 +26,116 @@ import (
"gopkg.in/yaml.v2"
)
-type frontmatterType struct {
- markstart, markend []byte
- Parse func([]byte) (interface{}, error)
- includeMark bool
+// FrontmatterType represents a type of frontmatter.
+type FrontmatterType struct {
+ // Parse decodes content into a Go interface.
+ Parse func([]byte) (interface{}, error)
+
+ markstart, markend []byte // starting and ending delimiters
+ includeMark bool // include start and end mark in output
}
-func InterfaceToConfig(in interface{}, mark rune) ([]byte, error) {
+// InterfaceToConfig encodes a given input based upon the mark and writes to w.
+func InterfaceToConfig(in interface{}, mark rune, w io.Writer) error {
if in == nil {
- return []byte{}, errors.New("input was nil")
+ return errors.New("input was nil")
}
- b := new(bytes.Buffer)
-
switch mark {
case rune(YAMLLead[0]):
- by, err := yaml.Marshal(in)
- if err != nil {
- return nil, err
- }
- b.Write(by)
- _, err = b.Write([]byte("..."))
+ b, err := yaml.Marshal(in)
if err != nil {
- return nil, err
+ return err
}
- return b.Bytes(), nil
+
+ _, err = w.Write(b)
+ return err
+
case rune(TOMLLead[0]):
tree := toml.TreeFromMap(in.(map[string]interface{}))
- return []byte(tree.String()), nil
+ b := []byte(tree.String())
+
+ _, err := w.Write(b)
+ return err
+
case rune(JSONLead[0]):
- by, err := json.MarshalIndent(in, "", " ")
+ b, err := json.MarshalIndent(in, "", " ")
if err != nil {
- return nil, err
+ return err
}
- b.Write(by)
- _, err = b.Write([]byte("\n"))
+
+ _, err = w.Write(b)
if err != nil {
- return nil, err
+ return err
}
- return b.Bytes(), nil
+
+ _, err = w.Write([]byte{'\n'})
+ return err
+
default:
- return nil, errors.New("Unsupported Format provided")
+ return errors.New("Unsupported Format provided")
}
}
-func InterfaceToFrontMatter(in interface{}, mark rune) ([]byte, error) {
+// InterfaceToFrontMatter encodes a given input into a frontmatter
+// representation based upon the mark with the appropriate front matter delimiters
+// surrounding the output, which is written to w.
+func InterfaceToFrontMatter(in interface{}, mark rune, w io.Writer) error {
if in == nil {
- return []byte{}, errors.New("input was nil")
+ return errors.New("input was nil")
}
- b := new(bytes.Buffer)
-
switch mark {
case rune(YAMLLead[0]):
- _, err := b.Write([]byte(YAMLDelimUnix))
+ _, err := w.Write([]byte(YAMLDelimUnix))
if err != nil {
- return nil, err
+ return err
}
- by, err := yaml.Marshal(in)
- if err != nil {
- return nil, err
- }
- b.Write(by)
- _, err = b.Write([]byte(YAMLDelimUnix))
+
+ err = InterfaceToConfig(in, mark, w)
if err != nil {
- return nil, err
+ return err
}
- return b.Bytes(), nil
+
+ _, err = w.Write([]byte(YAMLDelimUnix))
+ return err
+
case rune(TOMLLead[0]):
- _, err := b.Write([]byte(TOMLDelimUnix))
+ _, err := w.Write([]byte(TOMLDelimUnix))
if err != nil {
- return nil, err
+ return err
}
- tree := toml.TreeFromMap(in.(map[string]interface{}))
- b.Write([]byte(tree.String()))
- _, err = b.Write([]byte("\n" + TOMLDelimUnix))
- if err != nil {
- return nil, err
- }
- return b.Bytes(), nil
- case rune(JSONLead[0]):
- by, err := json.MarshalIndent(in, "", " ")
- if err != nil {
- return nil, err
- }
- b.Write(by)
- _, err = b.Write([]byte("\n"))
+ err = InterfaceToConfig(in, mark, w)
if err != nil {
- return nil, err
+ return err
}
- return b.Bytes(), nil
+
+ _, err = w.Write([]byte("\n" + TOMLDelimUnix))
+ return err
+
default:
- return nil, errors.New("Unsupported Format provided")
+ return InterfaceToConfig(in, mark, w)
}
}
+// FormatToLeadRune takes a given format kind and return the leading front
+// matter delimiter.
func FormatToLeadRune(kind string) rune {
switch FormatSanitize(kind) {
case "yaml":
return rune([]byte(YAMLLead)[0])
case "json":
return rune([]byte(JSONLead)[0])
+ case "org":
+ return '#'
default:
return rune([]byte(TOMLLead)[0])
}
}
+// FormatSanitize returns the canonical format name for a given kind.
+//
// TODO(bep) move to helpers
func FormatSanitize(kind string) string {
switch strings.ToLower(kind) {
@@ -141,27 +145,31 @@ func FormatSanitize(kind string) string {
return "toml"
case "json", "js":
return "json"
+ case "org":
+ return kind
default:
return "toml"
}
}
// DetectFrontMatter detects the type of frontmatter analysing its first character.
-func DetectFrontMatter(mark rune) (f *frontmatterType) {
+func DetectFrontMatter(mark rune) (f *FrontmatterType) {
switch mark {
case '-':
- return &frontmatterType{[]byte(YAMLDelim), []byte(YAMLDelim), HandleYAMLMetaData, false}
+ return &FrontmatterType{HandleYAMLMetaData, []byte(YAMLDelim), []byte(YAMLDelim), false}
case '+':
- return &frontmatterType{[]byte(TOMLDelim), []byte(TOMLDelim), HandleTOMLMetaData, false}
+ return &FrontmatterType{HandleTOMLMetaData, []byte(TOMLDelim), []byte(TOMLDelim), false}
case '{':
- return &frontmatterType{[]byte{'{'}, []byte{'}'}, HandleJSONMetaData, true}
+ return &FrontmatterType{HandleJSONMetaData, []byte{'{'}, []byte{'}'}, true}
case '#':
- return &frontmatterType{[]byte("#+"), []byte("\n"), HandleOrgMetaData, false}
+ return &FrontmatterType{HandleOrgMetaData, []byte("#+"), []byte("\n"), false}
default:
return nil
}
}
+// HandleTOMLMetaData unmarshals TOML-encoded datum and returns a Go interface
+// representing the encoded data structure.
func HandleTOMLMetaData(datum []byte) (interface{}, error) {
m := map[string]interface{}{}
datum = removeTOMLIdentifier(datum)
@@ -177,22 +185,49 @@ func HandleTOMLMetaData(datum []byte) (interface{}, error) {
return m, nil
}
+// removeTOMLIdentifier removes, if necessary, beginning and ending TOML
+// frontmatter delimiters from a byte slice.
func removeTOMLIdentifier(datum []byte) []byte {
- return bytes.Replace(datum, []byte(TOMLDelim), []byte(""), -1)
+ ld := len(datum)
+ if ld < 8 {
+ return datum
+ }
+
+ b := bytes.TrimPrefix(datum, []byte(TOMLDelim))
+ if ld-len(b) != 3 {
+ // No TOML prefix trimmed, so bail out
+ return datum
+ }
+
+ b = bytes.Trim(b, "\r\n")
+ return bytes.TrimSuffix(b, []byte(TOMLDelim))
}
+// HandleYAMLMetaData unmarshals YAML-encoded datum and returns a Go interface
+// representing the encoded data structure.
func HandleYAMLMetaData(datum []byte) (interface{}, error) {
m := map[string]interface{}{}
err := yaml.Unmarshal(datum, &m)
return m, err
}
+// HandleJSONMetaData unmarshals JSON-encoded datum and returns a Go interface
+// representing the encoded data structure.
func HandleJSONMetaData(datum []byte) (interface{}, error) {
+ if datum == nil {
+ // Package json returns on error on nil input.
+ // Return an empty map to be consistent with our other supported
+ // formats.
+ return make(map[string]interface{}), nil
+ }
+
var f interface{}
err := json.Unmarshal(datum, &f)
return f, err
}
+// HandleOrgMetaData unmarshals org-mode encoded datum and returns a Go
+// interface representing the encoded data structure.
func HandleOrgMetaData(datum []byte) (interface{}, error) {
return goorgeous.OrgHeaders(datum)
}
diff --git a/parser/frontmatter_test.go b/parser/frontmatter_test.go
index 081910094..5aef3562f 100644
--- a/parser/frontmatter_test.go
+++ b/parser/frontmatter_test.go
@@ -14,9 +14,231 @@
package parser
import (
+ "bytes"
+ "reflect"
"testing"
)
+func TestInterfaceToConfig(t *testing.T) {
+ cases := []struct {
+ input interface{}
+ mark byte
+ want []byte
+ isErr bool
+ }{
+ // TOML
+ {map[string]interface{}{}, TOMLLead[0], nil, false},
+ {
+ map[string]interface{}{"title": "test 1"},
+ TOMLLead[0],
+ []byte("title = \"test 1\"\n"),
+ false,
+ },
+
+ // YAML
+ {map[string]interface{}{}, YAMLLead[0], []byte("{}\n"), false},
+ {
+ map[string]interface{}{"title": "test 1"},
+ YAMLLead[0],
+ []byte("title: test 1\n"),
+ false,
+ },
+
+ // JSON
+ {map[string]interface{}{}, JSONLead[0], []byte("{}\n"), false},
+ {
+ map[string]interface{}{"title": "test 1"},
+ JSONLead[0],
+ []byte("{\n \"title\": \"test 1\"\n}\n"),
+ false,
+ },
+
+ // Errors
+ {nil, TOMLLead[0], nil, true},
+ {map[string]interface{}{}, '$', nil, true},
+ }
+
+ for i, c := range cases {
+ var buf bytes.Buffer
+
+ err := InterfaceToConfig(c.input, rune(c.mark), &buf)
+ if err != nil {
+ if c.isErr {
+ continue
+ }
+ t.Fatalf("[%d] unexpected error value: %v", i, err)
+ }
+
+ if !reflect.DeepEqual(buf.Bytes(), c.want) {
+ t.Errorf("[%d] not equal:\nwant %q,\n got %q", i, c.want, buf.Bytes())
+ }
+ }
+}
+
+func TestInterfaceToFrontMatter(t *testing.T) {
+ cases := []struct {
+ input interface{}
+ mark rune
+ want []byte
+ isErr bool
+ }{
+ // TOML
+ {map[string]interface{}{}, '+', []byte("+++\n\n+++\n"), false},
+ {
+ map[string]interface{}{"title": "test 1"},
+ '+',
+ []byte("+++\ntitle = \"test 1\"\n\n+++\n"),
+ false,
+ },
+
+ // YAML
+ {map[string]interface{}{}, '-', []byte("---\n{}\n---\n"), false}, //
+ {
+ map[string]interface{}{"title": "test 1"},
+ '-',
+ []byte("---\ntitle: test 1\n---\n"),
+ false,
+ },
+
+ // JSON
+ {map[string]interface{}{}, '{', []byte("{}\n"), false},
+ {
+ map[string]interface{}{"title": "test 1"},
+ '{',
+ []byte("{\n \"title\": \"test 1\"\n}\n"),
+ false,
+ },
+
+ // Errors
+ {nil, '+', nil, true},
+ {map[string]interface{}{}, '$', nil, true},
+ }
+
+ for i, c := range cases {
+ var buf bytes.Buffer
+ err := InterfaceToFrontMatter(c.input, c.mark, &buf)
+ if err != nil {
+ if c.isErr {
+ continue
+ }
+ t.Fatalf("[%d] unexpected error value: %v", i, err)
+ }
+
+ if !reflect.DeepEqual(buf.Bytes(), c.want) {
+ t.Errorf("[%d] not equal:\nwant %q,\n got %q", i, c.want, buf.Bytes())
+ }
+ }
+}
+
+func TestHandleTOMLMetaData(t *testing.T) {
+ cases := []struct {
+ input []byte
+ want interface{}
+ isErr bool
+ }{
+ {nil, map[string]interface{}{}, false},
+ {[]byte("title = \"test 1\""), map[string]interface{}{"title": "test 1"}, false},
+ {[]byte("a = [1, 2, 3]"), map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}, false},
+ {[]byte("b = [\n[1, 2],\n[3, 4]\n]"), map[string]interface{}{"b": []interface{}{[]interface{}{int64(1), int64(2)}, []interface{}{int64(3), int64(4)}}}, false},
+ // errors
+ {[]byte("z = [\n[1, 2]\n[3, 4]\n]"), nil, true},
+ }
+
+ for i, c := range cases {
+ res, err := HandleTOMLMetaData(c.input)
+ if err != nil {
+ if c.isErr {
+ continue
+ }
+ t.Fatalf("[%d] unexpected error value: %v", i, err)
+ }
+
+ if !reflect.DeepEqual(res, c.want) {
+ t.Errorf("[%d] not equal: given %q\nwant %#v,\n got %#v", i, c.input, c.want, res)
+ }
+ }
+}
+
+func TestHandleYAMLMetaData(t *testing.T) {
+ cases := []struct {
+ input []byte
+ want interface{}
+ isErr bool
+ }{
+ {nil, map[string]interface{}{}, false},
+ {[]byte("title: test 1"), map[string]interface{}{"title": "test 1"}, false},
+ {[]byte("a: Easy!\nb:\n c: 2\n d: [3, 4]"), map[string]interface{}{"a": "Easy!", "b": map[interface{}]interface{}{"c": 2, "d": []interface{}{3, 4}}}, false},
+ // errors
+ {[]byte("z = not toml"), nil, true},
+ }
+
+ for i, c := range cases {
+ res, err := HandleYAMLMetaData(c.input)
+ if err != nil {
+ if c.isErr {
+ continue
+ }
+ t.Fatalf("[%d] unexpected error value: %v", i, err)
+ }
+
+ if !reflect.DeepEqual(res, c.want) {
+ t.Errorf("[%d] not equal: given %q\nwant %#v,\n got %#v", i, c.input, c.want, res)
+ }
+ }
+}
+
+func TestHandleJSONMetaData(t *testing.T) {
+ cases := []struct {
+ input []byte
+ want interface{}
+ isErr bool
+ }{
+ {nil, map[string]interface{}{}, false},
+ {[]byte("{\"title\": \"test 1\"}"), map[string]interface{}{"title": "test 1"}, false},
+ // errors
+ {[]byte("{noquotes}"), nil, true},
+ }
+
+ for i, c := range cases {
+ res, err := HandleJSONMetaData(c.input)
+ if err != nil {
+ if c.isErr {
+ continue
+ }
+ t.Fatalf("[%d] unexpected error value: %v", i, err)
+ }
+
+ if !reflect.DeepEqual(res, c.want) {
+ t.Errorf("[%d] not equal: given %q\nwant %#v,\n got %#v", i, c.input, c.want, res)
+ }
+ }
+}
+
+func TestHandleOrgMetaData(t *testing.T) {
+ cases := []struct {
+ input []byte
+ want interface{}
+ isErr bool
+ }{
+ {nil, map[string]interface{}{}, false},
+ {[]byte("#+title: test 1\n"), map[string]interface{}{"title": "test 1"}, false},
+ }
+
+ for i, c := range cases {
+ res, err := HandleOrgMetaData(c.input)
+ if err != nil {
+ if c.isErr {
+ continue
+ }
+ t.Fatalf("[%d] unexpected error value: %v", i, err)
+ }
+
+ if !reflect.DeepEqual(res, c.want) {
+ t.Errorf("[%d] not equal: given %q\nwant %#v,\n got %#v", i, c.input, c.want, res)
+ }
+ }
+}
+
func TestFormatToLeadRune(t *testing.T) {
for i, this := range []struct {
kind string
@@ -25,8 +247,10 @@ func TestFormatToLeadRune(t *testing.T) {
{"yaml", '-'},
{"yml", '-'},
{"toml", '+'},
+ {"tml", '+'},
{"json", '{'},
{"js", '{'},
+ {"org", '#'},
{"unknown", '+'},
} {
result := FormatToLeadRune(this.kind)
@@ -36,3 +260,60 @@ func TestFormatToLeadRune(t *testing.T) {
}
}
}
+
+func TestDetectFrontMatter(t *testing.T) {
+ cases := []struct {
+ mark rune
+ want *FrontmatterType
+ }{
+ // funcs are uncomparable, so we ignore FrontmatterType.Parse in these tests
+ {'-', &FrontmatterType{nil, []byte(YAMLDelim), []byte(YAMLDelim), false}},
+ {'+', &FrontmatterType{nil, []byte(TOMLDelim), []byte(TOMLDelim), false}},
+ {'{', &FrontmatterType{nil, []byte("{"), []byte("}"), true}},
+ {'#', &FrontmatterType{nil, []byte("#+"), []byte("\n"), false}},
+ {'$', nil},
+ }
+
+ for _, c := range cases {
+ res := DetectFrontMatter(c.mark)
+ if res == nil {
+ if c.want == nil {
+ continue
+ }
+
+ t.Fatalf("want %v, got %v", *c.want, res)
+ }
+
+ if !reflect.DeepEqual(res.markstart, c.want.markstart) {
+ t.Errorf("markstart mismatch: want %v, got %v", c.want.markstart, res.markstart)
+ }
+ if !reflect.DeepEqual(res.markend, c.want.markend) {
+ t.Errorf("markend mismatch: want %v, got %v", c.want.markend, res.markend)
+ }
+ if !reflect.DeepEqual(res.includeMark, c.want.includeMark) {
+ t.Errorf("includeMark mismatch: want %v, got %v", c.want.includeMark, res.includeMark)
+ }
+ }
+}
+
+func TestRemoveTOMLIdentifier(t *testing.T) {
+ cases := []struct {
+ input string
+ want string
+ }{
+ {"a = 1", "a = 1"},
+ {"a = 1\r\n", "a = 1\r\n"},
+ {"+++\r\na = 1\r\n+++\r\n", "a = 1\r\n"},
+ {"+++\na = 1\n+++\n", "a = 1\n"},
+ {"+++\nb = \"+++ oops +++\"\n+++\n", "b = \"+++ oops +++\"\n"},
+ {"+++\nc = \"\"\"+++\noops\n+++\n\"\"\"\"\n+++\n", "c = \"\"\"+++\noops\n+++\n\"\"\"\"\n"},
+ {"+++\nd = 1\n+++", "d = 1\n"},
+ }
+
+ for i, c := range cases {
+ res := removeTOMLIdentifier([]byte(c.input))
+ if string(res) != c.want {
+ t.Errorf("[%d] given %q\nwant: %q\n got: %q", i, c.input, c.want, res)
+ }
+ }
+}
diff --git a/parser/page.go b/parser/page.go
index 3347380d7..a0679289c 100644
--- a/parser/page.go
+++ b/parser/page.go
@@ -64,30 +64,42 @@ var (
// Page represents a parsed content page.
type Page interface {
+ // FrontMatter contains the raw frontmatter with relevant delimiters.
FrontMatter() []byte
+
+ // Content contains the raw page content.
Content() []byte
+
+ // IsRenderable denotes that the page should be rendered.
IsRenderable() bool
+
+ // Metadata returns the unmarshalled frontmatter data.
Metadata() (interface{}, error)
}
+// page implements the Page interface.
type page struct {
render bool
frontmatter []byte
content []byte
}
+// Content returns the raw page content.
func (p *page) Content() []byte {
return p.content
}
+// FrontMatter contains the raw frontmatter with relevant delimiters.
func (p *page) FrontMatter() []byte {
return p.frontmatter
}
+// IsRenderable denotes that the page should be rendered.
func (p *page) IsRenderable() bool {
return p.render
}
+// Metadata returns the unmarshalled frontmatter data.
func (p *page) Metadata() (meta interface{}, err error) {
frontmatter := p.FrontMatter()
@@ -151,6 +163,7 @@ func ReadFrom(r io.Reader) (p Page, err error) {
return newp, nil
}
+// chompBOM scans any leading Unicode Byte Order Markers from r.
func chompBOM(r io.RuneScanner) (err error) {
for {
c, _, err := r.ReadRune()
@@ -164,6 +177,7 @@ func chompBOM(r io.RuneScanner) (err error) {
}
}
+// chompWhitespace scans any leading Unicode whitespace from r.
func chompWhitespace(r io.RuneScanner) (err error) {
for {
c, _, err := r.ReadRune()
@@ -177,6 +191,9 @@ func chompWhitespace(r io.RuneScanner) (err error) {
}
}
+// chompFrontmatterStartComment checks r for a leading HTML comment. If a
+// comment is found, it is read from r and then whitespace is trimmed from the
+// beginning of r.
func chompFrontmatterStartComment(r *bufio.Reader) (err error) {
candidate, err := r.Peek(32)
if err != nil {
@@ -206,6 +223,7 @@ func chompFrontmatterStartComment(r *bufio.Reader) (err error) {
return nil
}
+// chompFrontmatterEndComment checks r for a trailing HTML comment.
func chompFrontmatterEndComment(r *bufio.Reader) (err error) {
candidate, err := r.Peek(32)
if err != nil {
diff --git a/parser/page_test.go b/parser/page_test.go
new file mode 100644
index 000000000..07d7660d4
--- /dev/null
+++ b/parser/page_test.go
@@ -0,0 +1,130 @@
+package parser
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestPage(t *testing.T) {
+ cases := []struct {
+ raw string
+
+ content string
+ frontmatter string
+ renderable bool
+ metadata map[string]interface{}
+ }{
+ {
+ testPageLeader + jsonPageFrontMatter + "\n" + testPageTrailer + jsonPageContent,
+ jsonPageContent,
+ jsonPageFrontMatter,
+ true,
+ map[string]interface{}{
+ "title": "JSON Test 1",
+ "social": []interface{}{
+ []interface{}{"a", "#"},
+ []interface{}{"b", "#"},
+ },
+ },
+ },
+ {
+ testPageLeader + tomlPageFrontMatter + testPageTrailer + tomlPageContent,
+ tomlPageContent,
+ tomlPageFrontMatter,
+ true,
+ map[string]interface{}{
+ "title": "TOML Test 1",
+ "social": []interface{}{
+ []interface{}{"a", "#"},
+ []interface{}{"b", "#"},
+ },
+ },
+ },
+ {
+ testPageLeader + yamlPageFrontMatter + testPageTrailer + yamlPageContent,
+ yamlPageContent,
+ yamlPageFrontMatter,
+ true,
+ map[string]interface{}{
+ "title": "YAML Test 1",
+ "social": []interface{}{
+ []interface{}{"a", "#"},
+ []interface{}{"b", "#"},
+ },
+ },
+ },
+ {
+ testPageLeader + orgPageFrontMatter + orgPageContent,
+ orgPageContent,
+ orgPageFrontMatter,
+ true,
+ map[string]interface{}{
+ "TITLE": "Org Test 1",
+ "categories": []string{"a", "b"},
+ },
+ },
+ }
+
+ for i, c := range cases {
+ p := pageMust(ReadFrom(strings.NewReader(c.raw)))
+ meta, err := p.Metadata()
+
+ mesg := fmt.Sprintf("[%d]", i)
+
+ require.Nil(t, err, mesg)
+ assert.Equal(t, c.content, string(p.Content()), mesg+" content")
+ assert.Equal(t, c.frontmatter, string(p.FrontMatter()), mesg+" frontmatter")
+ assert.Equal(t, c.renderable, p.IsRenderable(), mesg+" renderable")
+ assert.Equal(t, c.metadata, meta, mesg+" metadata")
+ }
+}
+
+var (
+ testWhitespace = "\t\t\n\n"
+ testPageLeader = "\ufeff" + testWhitespace + "<!--[metadata]>\n"
+ testPageTrailer = "\n<![end-metadata]-->\n"
+
+ jsonPageContent = "# JSON Test\n"
+ jsonPageFrontMatter = `{
+ "title": "JSON Test 1",
+ "social": [
+ ["a", "#"],
+ ["b", "#"]
+ ]
+}`
+
+ tomlPageContent = "# TOML Test\n"
+ tomlPageFrontMatter = `+++
+title = "TOML Test 1"
+social = [
+ ["a", "#"],
+ ["b", "#"],
+]
++++
+`
+
+ yamlPageContent = "# YAML Test\n"
+ yamlPageFrontMatter = `---
+title: YAML Test 1
+social:
+ - - "a"
+ - "#"
+ - - "b"
+ - "#"
+---
+`
+
+ orgPageContent = "* Org Test\n"
+ orgPageFrontMatter = `#+TITLE: Org Test 1
+#+categories: a b
+`
+
+ pageHTMLComment = `<!--
+ This is a sample comment.
+-->
+`
+)