ref: f039e3be9e4a11808508c8cd3043b340deea040f
parent: ddc8cc0082965143a650052a9aa538bac9133481
author: Cameron Moore <moorereason@gmail.com>
date: Mon Dec 26 10:23:20 EST 2016
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%.
--- a/commands/import_jekyll.go
+++ b/commands/import_jekyll.go
@@ -251,17 +251,13 @@
}
kind = parser.FormatSanitize(kind)
- by, err := parser.InterfaceToConfig(in, parser.FormatToLeadRune(kind))
+ var buf bytes.Buffer
+ err = parser.InterfaceToConfig(in, parser.FormatToLeadRune(kind), &buf)
if err != nil {return err
}
- err = helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), bytes.NewReader(by), fs)
- if err != nil {- return
- }
-
- return nil
+ return helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), &buf, fs)
}
func copyFile(source string, dest string) error {--- a/commands/new.go
+++ b/commands/new.go
@@ -356,15 +356,11 @@
}
kind = parser.FormatSanitize(kind)
- by, err := parser.InterfaceToConfig(in, parser.FormatToLeadRune(kind))
+ var buf bytes.Buffer
+ err = parser.InterfaceToConfig(in, parser.FormatToLeadRune(kind), &buf)
if err != nil {return err
}
- err = helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), bytes.NewReader(by), fs.Source)
- if err != nil {- return
- }
-
- return nil
+ return helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), &buf, fs.Source)
}
--- a/commands/undraft_test.go
+++ b/commands/undraft_test.go
@@ -46,17 +46,17 @@
{yamlDraftFM, ""},}
- for _, test := range tests {+ for i, test := range tests {r := bytes.NewReader([]byte(test.fm))
p, _ := parser.ReadFrom(r)
res, err := undraftContent(p)
if test.expectedErr != "" { if err == nil {- t.Error("Expected error, got none")+ t.Error("[%d] Expected error, got none", i)continue
}
if err.Error() != test.expectedErr {- t.Errorf("Expected %q, got %q", test.expectedErr, err)+ t.Errorf("[%d] Expected %q, got %q", i, test.expectedErr, err)continue
}
} else {@@ -64,19 +64,19 @@
p, _ = parser.ReadFrom(r)
meta, err := p.Metadata()
if err != nil {- t.Errorf("unexpected error %q", err)+ t.Errorf("[%d] unexpected error %q", i, err)continue
}
for k, v := range meta.(map[string]interface{}) { if k == "draft" { if v.(bool) {- t.Errorf("Expected %q to be \"false\", got \"true\"", k)+ t.Errorf("[%d] Expected %q to be \"false\", got \"true\"", i, k)continue
}
}
if k == "date" { if !strings.HasPrefix(v.(string), time.Now().Format("2006-01-02")) {- t.Errorf("Expected %v to start with %v", v.(string), time.Now().Format("2006-01-02"))+ t.Errorf("[%d] Expected %v to start with %v", i, v.(string), time.Now().Format("2006-01-02"))}
}
}
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -1424,15 +1424,20 @@
}
}()
- var by []byte
+ buf := bp.GetBuffer()
+ defer bp.PutBuffer(buf)
- by, err = parser.InterfaceToFrontMatter(in, mark)
+ err = parser.InterfaceToFrontMatter(in, mark, buf)
if err != nil {return
}
- by = append(by, '\n')
- p.Source.Frontmatter = by
+ _, err = buf.WriteRune('\n')+ if err != nil {+ return
+ }
+
+ p.Source.Frontmatter = buf.Bytes()
return
}
--- a/parser/frontmatter.go
+++ b/parser/frontmatter.go
@@ -17,6 +17,7 @@
"bytes"
"encoding/json"
"errors"
+ "io"
"strings"
"github.com/chaseadamsio/goorgeous"
@@ -25,102 +26,101 @@
"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)
+ b, err := yaml.Marshal(in)
if err != nil {- return nil, err
+ return err
}
- b.Write(by)
- _, err = b.Write([]byte("..."))- if err != nil {- return nil, 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)
+
+ err = InterfaceToConfig(in, mark, w)
if err != nil {- return nil, err
+ return err
}
- b.Write(by)
- _, err = b.Write([]byte(YAMLDelimUnix))
- if err != nil {- return nil, 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))+ err = InterfaceToConfig(in, mark, w)
if err != nil {- return nil, err
+ return 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"))- if err != nil {- return nil, 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":
@@ -127,11 +127,15 @@
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,6 +145,8 @@
return "toml"
case "json", "js":
return "json"
+ case "org":
+ return kind
default:
return "toml"
}
@@ -147,21 +153,23 @@
}
// 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,10 +185,26 @@
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)
@@ -187,12 +211,23 @@
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)
}
--- 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 @@
{"yaml", '-'}, {"yml", '-'}, {"toml", '+'},+ {"tml", '+'}, {"json", '{'}, {"js", '{'},+ {"org", '#'}, {"unknown", '+'}, } {result := FormatToLeadRune(this.kind)
@@ -33,6 +257,63 @@
if result != this.expect { t.Errorf("[%d] got %q but expected %q", i, result, this.expect)+ }
+ }
+}
+
+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)}
}
}
--- a/parser/page.go
+++ b/parser/page.go
@@ -64,12 +64,20 @@
// 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
@@ -76,18 +84,22 @@
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 @@
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 @@
}
}
+// chompWhitespace scans any leading Unicode whitespace from r.
func chompWhitespace(r io.RuneScanner) (err error) { for {c, _, err := r.ReadRune()
@@ -177,6 +191,9 @@
}
}
+// 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 @@
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 {--- /dev/null
+++ b/parser/page_test.go
@@ -1,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.
+-->
+`
+)
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -33,10 +33,10 @@
"revisionTime": "2016-04-08T19:03:23Z"
},
{- "checksumSHA1": "RxIwAgjIuBpwde5BCZRLLK7VRG8=",
+ "checksumSHA1": "tOtpDG/zYOvYRQeSHcg8IhZnRHQ=",
"path": "github.com/chaseadamsio/goorgeous",
- "revision": "72a06e1b07db57f3931f5a9c00f3f04e636ad0a8",
- "revisionTime": "2017-02-17T13:03:04Z"
+ "revision": "054aba677f27bd60872cfe68f8145dc57bdf4746",
+ "revisionTime": "2017-02-22T05:25:03Z"
},
{"checksumSHA1": "ntacCkWfMT63DaehXLG5FeXWyNM=",
--
⑨