mirror of https://github.com/mickael-menu/zk
Test the note formatter
parent
5759896fd4
commit
5c59d7946b
@ -0,0 +1,164 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mickael-menu/zk/util/opt"
|
||||
"github.com/mickael-menu/zk/util/test/assert"
|
||||
)
|
||||
|
||||
func TestEmptyFormat(t *testing.T) {
|
||||
f, _ := newFormatter(t, opt.NewString(""))
|
||||
res, err := f.Format(Match{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, res, "")
|
||||
}
|
||||
|
||||
func TestDefaultFormat(t *testing.T) {
|
||||
f, _ := newFormatter(t, opt.NullString)
|
||||
res, err := f.Format(Match{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, res, `{{style "title" title}} {{style "path" path}} ({{date created "elapsed"}})
|
||||
|
||||
{{prepend " " snippet}}`)
|
||||
}
|
||||
|
||||
func TestFormats(t *testing.T) {
|
||||
test := func(format string, expected string) {
|
||||
f, _ := newFormatter(t, opt.NewString(format))
|
||||
actual, err := f.Format(Match{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, actual, expected)
|
||||
}
|
||||
|
||||
// Known formats
|
||||
test("path", `{{path}}`)
|
||||
|
||||
test("oneline", `{{style "title" title}} {{style "path" path}} ({{date created "elapsed"}})`)
|
||||
|
||||
test("short", `{{style "title" title}} {{style "path" path}} ({{date created "elapsed"}})
|
||||
|
||||
{{prepend " " snippet}}`)
|
||||
|
||||
test("medium", `{{style "title" title}} {{style "path" path}}
|
||||
Created: {{date created "short"}}
|
||||
|
||||
{{prepend " " snippet}}`)
|
||||
|
||||
test("long", `{{style "title" title}} {{style "path" path}}
|
||||
Created: {{date created "short"}}
|
||||
Modified: {{date created "short"}}
|
||||
|
||||
{{prepend " " snippet}}`)
|
||||
|
||||
test("full", `{{style "title" title}} {{style "path" path}}
|
||||
Created: {{date created "short"}}
|
||||
Modified: {{date created "short"}}
|
||||
|
||||
{{prepend " " body}}`)
|
||||
|
||||
// Known formats are case sensitive.
|
||||
test("Path", "Path")
|
||||
|
||||
// Custom formats are used literally.
|
||||
test("{{title}}", "{{title}}")
|
||||
|
||||
// \n and \t in custom formats are expanded.
|
||||
test(`{{title}}\t{{path}}\n{{snippet}}`, "{{title}}\t{{path}}\n{{snippet}}")
|
||||
}
|
||||
|
||||
func TestFormatRenderContext(t *testing.T) {
|
||||
f, templs := newFormatter(t, opt.NewString("path"))
|
||||
|
||||
_, err := f.Format(Match{
|
||||
Snippet: "Note snippet",
|
||||
Metadata: Metadata{
|
||||
Path: "dir/note.md",
|
||||
Title: "Note title",
|
||||
Lead: "Lead paragraph",
|
||||
Body: "Note body",
|
||||
RawContent: "Raw content",
|
||||
WordCount: 42,
|
||||
Created: Now,
|
||||
Modified: Now.Add(48 * time.Hour),
|
||||
Checksum: "Note checksum",
|
||||
},
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Check that the template was provided with the proper information in the
|
||||
// render context.
|
||||
assert.Equal(t, templs.Contexts, []interface{}{
|
||||
formatRenderContext{
|
||||
Path: "dir/note.md",
|
||||
Title: "Note title",
|
||||
Lead: "Lead paragraph",
|
||||
Body: "Note body",
|
||||
Snippet: "Note snippet",
|
||||
RawContent: "Raw content",
|
||||
WordCount: 42,
|
||||
Created: Now,
|
||||
Modified: Now.Add(48 * time.Hour),
|
||||
Checksum: "Note checksum",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestFormatPath(t *testing.T) {
|
||||
test := func(basePath, currentPath, path string, expected string) {
|
||||
f, templs := newFormatterWithPaths(t, basePath, currentPath, opt.NullString)
|
||||
_, err := f.Format(Match{
|
||||
Metadata: Metadata{Path: path},
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, templs.Contexts, []interface{}{
|
||||
formatRenderContext{
|
||||
Path: expected,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Check that the path is relative to the current directory.
|
||||
test("", "", "note.md", "note.md")
|
||||
test("", "", "dir/note.md", "dir/note.md")
|
||||
test("/abs/zk", "/abs/zk", "note.md", "note.md")
|
||||
test("/abs/zk", "/abs/zk", "dir/note.md", "dir/note.md")
|
||||
test("/abs/zk", "/abs/zk/dir", "note.md", "../note.md")
|
||||
test("/abs/zk", "/abs/zk/dir", "dir/note.md", "note.md")
|
||||
test("/abs/zk", "/abs", "note.md", "zk/note.md")
|
||||
test("/abs/zk", "/abs", "dir/note.md", "zk/dir/note.md")
|
||||
}
|
||||
|
||||
func TestFormatStylesSnippetTerm(t *testing.T) {
|
||||
test := func(snippet string, expected string) {
|
||||
f, templs := newFormatter(t, opt.NullString)
|
||||
_, err := f.Format(Match{
|
||||
Snippet: snippet,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, templs.Contexts, []interface{}{
|
||||
formatRenderContext{
|
||||
Path: ".",
|
||||
Snippet: expected,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
test("Hello world!", "Hello world!")
|
||||
test("Hello <zk:match>world</zk:match>!", "Hello term(world)!")
|
||||
test("Hello <zk:match>world</zk:match> with <zk:match>several matches</zk:match>!", "Hello term(world) with term(several matches)!")
|
||||
test("Hello <zk:match>world</zk:match> with <zk:match>several<zk:match> matches</zk:match>!", "Hello term(world) with term(several<zk:match> matches)!")
|
||||
}
|
||||
|
||||
func newFormatter(t *testing.T, format opt.String) (*Formatter, *TemplLoaderSpy) {
|
||||
return newFormatterWithPaths(t, "", "", format)
|
||||
}
|
||||
|
||||
func newFormatterWithPaths(t *testing.T, basePath, currentPath string, format opt.String) (*Formatter, *TemplLoaderSpy) {
|
||||
loader := NewTemplLoaderSpy()
|
||||
styler := &StylerMock{}
|
||||
formatter, err := NewFormatter(basePath, currentPath, format, loader, styler)
|
||||
assert.Nil(t, err)
|
||||
return formatter, loader
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package note
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/mickael-menu/zk/core/style"
|
||||
"github.com/mickael-menu/zk/core/templ"
|
||||
)
|
||||
|
||||
var Now = time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
|
||||
|
||||
// TemplLoaderSpy implements templ.Loader and saves the render contexts
|
||||
// provided to the templates it creates.
|
||||
//
|
||||
// The generated Renderer returns the template used to create them without
|
||||
// modification.
|
||||
type TemplLoaderSpy struct {
|
||||
Contexts []interface{}
|
||||
}
|
||||
|
||||
func NewTemplLoaderSpy() *TemplLoaderSpy {
|
||||
return &TemplLoaderSpy{
|
||||
Contexts: make([]interface{}, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *TemplLoaderSpy) Load(template string) (templ.Renderer, error) {
|
||||
return NewRendererSpy(func(context interface{}) string {
|
||||
l.Contexts = append(l.Contexts, context)
|
||||
return template
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (l *TemplLoaderSpy) LoadFile(path string) (templ.Renderer, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// RendererSpy implements templ.Renderer and saves the provided render contexts.
|
||||
type RendererSpy struct {
|
||||
Result func(interface{}) string
|
||||
Contexts []interface{}
|
||||
}
|
||||
|
||||
func NewRendererSpy(result func(interface{}) string) *RendererSpy {
|
||||
return &RendererSpy{
|
||||
Contexts: make([]interface{}, 0),
|
||||
Result: result,
|
||||
}
|
||||
}
|
||||
|
||||
func NewRendererSpyString(result string) *RendererSpy {
|
||||
return &RendererSpy{
|
||||
Contexts: make([]interface{}, 0),
|
||||
Result: func(_ interface{}) string { return result },
|
||||
}
|
||||
}
|
||||
|
||||
func (m *RendererSpy) Render(context interface{}) (string, error) {
|
||||
m.Contexts = append(m.Contexts, context)
|
||||
return m.Result(context), nil
|
||||
}
|
||||
|
||||
// StylerMock implements core.Styler by doing the transformation:
|
||||
// "hello", "red" -> "red(hello)"
|
||||
type StylerMock struct{}
|
||||
|
||||
func (s *StylerMock) Style(text string, rules ...style.Rule) (string, error) {
|
||||
for _, rule := range rules {
|
||||
text = fmt.Sprintf("%s(%s)", rule, text)
|
||||
}
|
||||
return text, nil
|
||||
}
|
Loading…
Reference in New Issue