Commit 42b7d574 authored by Tobias Weingartner's avatar Tobias Weingartner

Fix more tests, and fix template parsing.

parent 027f697f
...@@ -36,7 +36,7 @@ func markdownParse(c *Controller) ([]*markdown.Config, error) { ...@@ -36,7 +36,7 @@ func markdownParse(c *Controller) ([]*markdown.Config, error) {
md := &markdown.Config{ md := &markdown.Config{
Renderer: blackfriday.HtmlRenderer(0, "", ""), Renderer: blackfriday.HtmlRenderer(0, "", ""),
Extensions: make(map[string]struct{}), Extensions: make(map[string]struct{}),
Templates: make(map[string]string), Template: markdown.GetDefaultTemplate(),
} }
// Get the path scope // Get the path scope
...@@ -95,17 +95,32 @@ func loadParams(c *Controller, mdc *markdown.Config) error { ...@@ -95,17 +95,32 @@ func loadParams(c *Controller, mdc *markdown.Config) error {
default: default:
return c.ArgErr() return c.ArgErr()
case 1: case 1:
if _, ok := mdc.Templates[markdown.DefaultTemplate]; ok {
return c.Err("only one default template is allowed, use alias.")
}
fpath := filepath.ToSlash(filepath.Clean(c.Root + string(filepath.Separator) + tArgs[0])) fpath := filepath.ToSlash(filepath.Clean(c.Root + string(filepath.Separator) + tArgs[0]))
mdc.Templates[markdown.DefaultTemplate] = fpath
if err := markdown.SetTemplate(mdc.Template, "", fpath); err != nil {
c.Errf("default template parse error: %v", err)
}
return nil return nil
case 2: case 2:
fpath := filepath.ToSlash(filepath.Clean(c.Root + string(filepath.Separator) + tArgs[1])) fpath := filepath.ToSlash(filepath.Clean(c.Root + string(filepath.Separator) + tArgs[1]))
mdc.Templates[tArgs[0]] = fpath
if err := markdown.SetTemplate(mdc.Template, tArgs[0], fpath); err != nil {
c.Errf("template parse error: %v", err)
}
return nil return nil
} }
case "templatedir":
if !c.NextArg() {
return c.ArgErr()
}
_, err := mdc.Template.ParseGlob(c.Val())
if err != nil {
c.Errf("template load error: %v", err)
}
if c.NextArg() {
return c.ArgErr()
}
return nil
default: default:
return c.Err("Expected valid markdown configuration property") return c.Err("Expected valid markdown configuration property")
} }
......
package setup package setup
import ( import (
"bytes"
"fmt" "fmt"
"net/http"
"testing" "testing"
"text/template"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/markdown" "github.com/mholt/caddy/middleware/markdown"
) )
...@@ -58,8 +62,9 @@ func TestMarkdownParse(t *testing.T) { ...@@ -58,8 +62,9 @@ func TestMarkdownParse(t *testing.T) {
".md": struct{}{}, ".md": struct{}{},
".txt": struct{}{}, ".txt": struct{}{},
}, },
Styles: []string{"/resources/css/blog.css"}, Styles: []string{"/resources/css/blog.css"},
Scripts: []string{"/resources/js/blog.js"}, Scripts: []string{"/resources/js/blog.js"},
Template: markdown.GetDefaultTemplate(),
}}}, }}},
{`markdown /blog { {`markdown /blog {
ext .md ext .md
...@@ -69,9 +74,13 @@ func TestMarkdownParse(t *testing.T) { ...@@ -69,9 +74,13 @@ func TestMarkdownParse(t *testing.T) {
Extensions: map[string]struct{}{ Extensions: map[string]struct{}{
".md": struct{}{}, ".md": struct{}{},
}, },
Templates: map[string]string{markdown.DefaultTemplate: "testdata/tpl_with_include.html"}, Template: markdown.GetDefaultTemplate(),
}}}, }}},
} }
// Setup the extra template
tmpl := tests[1].expectedMarkdownConfig[0].Template
markdown.SetTemplate(tmpl, "", "./testdata/tpl_with_include.html")
for i, test := range tests { for i, test := range tests {
c := NewTestController(test.inputMarkdownConfig) c := NewTestController(test.inputMarkdownConfig)
c.Root = "./testdata" c.Root = "./testdata"
...@@ -101,11 +110,47 @@ func TestMarkdownParse(t *testing.T) { ...@@ -101,11 +110,47 @@ func TestMarkdownParse(t *testing.T) {
t.Errorf("Test %d expected %dth Markdown Config Scripts to be %s , but got %s", t.Errorf("Test %d expected %dth Markdown Config Scripts to be %s , but got %s",
i, j, fmt.Sprint(test.expectedMarkdownConfig[j].Scripts), fmt.Sprint(actualMarkdownConfig.Scripts)) i, j, fmt.Sprint(test.expectedMarkdownConfig[j].Scripts), fmt.Sprint(actualMarkdownConfig.Scripts))
} }
if fmt.Sprint(actualMarkdownConfig.Templates) != fmt.Sprint(test.expectedMarkdownConfig[j].Templates) { if ok, tx, ty := equalTemplates(actualMarkdownConfig.Template, test.expectedMarkdownConfig[j].Template); !ok {
t.Errorf("Test %d expected %dth Markdown Config Templates to be %s , but got %s", t.Errorf("Test %d the %dth Markdown Config Templates did not match, expected %s to be %s", i, j, tx, ty)
i, j, fmt.Sprint(test.expectedMarkdownConfig[j].Templates), fmt.Sprint(actualMarkdownConfig.Templates))
} }
} }
} }
}
func equalTemplates(i, j *template.Template) (bool, string, string) {
// Just in case :)
if i == j {
return true, "", ""
}
// We can't do much here, templates can't really be compared. However,
// we can execute the templates and compare their outputs to be reasonably
// sure that they're the same.
// This is exceedingly ugly.
ctx := middleware.Context{
Root: http.Dir("./testdata"),
}
md := markdown.Data{
Context: ctx,
Doc: make(map[string]string),
DocFlags: make(map[string]bool),
Styles: []string{"style1"},
Scripts: []string{"js1"},
}
md.Doc["title"] = "some title"
md.Doc["body"] = "some body"
bufi := new(bytes.Buffer)
bufj := new(bytes.Buffer)
if err := i.Execute(bufi, md); err != nil {
return false, fmt.Sprintf("%v", err), ""
}
if err := j.Execute(bufj, md); err != nil {
return false, "", fmt.Sprintf("%v", err)
}
return bytes.Equal(bufi.Bytes(), bufj.Bytes()), string(bufi.Bytes()), string(bufj.Bytes())
} }
...@@ -4,10 +4,10 @@ package markdown ...@@ -4,10 +4,10 @@ package markdown
import ( import (
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"os" "os"
"path" "path"
"text/template"
"github.com/mholt/caddy/middleware" "github.com/mholt/caddy/middleware"
"github.com/russross/blackfriday" "github.com/russross/blackfriday"
...@@ -59,8 +59,8 @@ type Config struct { ...@@ -59,8 +59,8 @@ type Config struct {
// List of JavaScript files to load for each markdown file // List of JavaScript files to load for each markdown file
Scripts []string Scripts []string
// Map of registered templates // Template(s) to render with
Templates map[string]string Template *template.Template
} }
// ServeHTTP implements the http.Handler interface. // ServeHTTP implements the http.Handler interface.
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
"path/filepath"
"strings" "strings"
"testing" "testing"
"time" "time"
...@@ -14,11 +15,15 @@ import ( ...@@ -14,11 +15,15 @@ import (
) )
func TestMarkdown(t *testing.T) { func TestMarkdown(t *testing.T) {
templates := make(map[string]string) rootDir := "./testdata"
templates[DefaultTemplate] = "testdata/markdown_tpl.html"
f := func(filename string) string {
return filepath.ToSlash(rootDir + string(filepath.Separator) + filename)
}
md := Markdown{ md := Markdown{
Root: "./testdata", Root: rootDir,
FileSys: http.Dir("./testdata"), FileSys: http.Dir(rootDir),
Configs: []*Config{ Configs: []*Config{
{ {
Renderer: blackfriday.HtmlRenderer(0, "", ""), Renderer: blackfriday.HtmlRenderer(0, "", ""),
...@@ -26,9 +31,9 @@ func TestMarkdown(t *testing.T) { ...@@ -26,9 +31,9 @@ func TestMarkdown(t *testing.T) {
Extensions: map[string]struct{}{ Extensions: map[string]struct{}{
".md": struct{}{}, ".md": struct{}{},
}, },
Styles: []string{}, Styles: []string{},
Scripts: []string{}, Scripts: []string{},
Templates: templates, Template: setDefaultTemplate(f("markdown_tpl.html")),
}, },
{ {
Renderer: blackfriday.HtmlRenderer(0, "", ""), Renderer: blackfriday.HtmlRenderer(0, "", ""),
...@@ -36,11 +41,9 @@ func TestMarkdown(t *testing.T) { ...@@ -36,11 +41,9 @@ func TestMarkdown(t *testing.T) {
Extensions: map[string]struct{}{ Extensions: map[string]struct{}{
".md": struct{}{}, ".md": struct{}{},
}, },
Styles: []string{}, Styles: []string{},
Scripts: []string{}, Scripts: []string{},
Templates: map[string]string{ Template: setDefaultTemplate(f("docflags/template.txt")),
DefaultTemplate: "testdata/docflags/template.txt",
},
}, },
{ {
Renderer: blackfriday.HtmlRenderer(0, "", ""), Renderer: blackfriday.HtmlRenderer(0, "", ""),
...@@ -48,9 +51,9 @@ func TestMarkdown(t *testing.T) { ...@@ -48,9 +51,9 @@ func TestMarkdown(t *testing.T) {
Extensions: map[string]struct{}{ Extensions: map[string]struct{}{
".md": struct{}{}, ".md": struct{}{},
}, },
Styles: []string{"/resources/css/log.css", "/resources/css/default.css"}, Styles: []string{"/resources/css/log.css", "/resources/css/default.css"},
Scripts: []string{"/resources/js/log.js", "/resources/js/default.js"}, Scripts: []string{"/resources/js/log.js", "/resources/js/default.js"},
Templates: make(map[string]string), Template: GetDefaultTemplate(),
}, },
{ {
Renderer: blackfriday.HtmlRenderer(0, "", ""), Renderer: blackfriday.HtmlRenderer(0, "", ""),
...@@ -58,9 +61,9 @@ func TestMarkdown(t *testing.T) { ...@@ -58,9 +61,9 @@ func TestMarkdown(t *testing.T) {
Extensions: map[string]struct{}{ Extensions: map[string]struct{}{
".md": struct{}{}, ".md": struct{}{},
}, },
Styles: []string{}, Styles: []string{},
Scripts: []string{}, Scripts: []string{},
Templates: templates, Template: setDefaultTemplate(f("markdown_tpl.html")),
}, },
}, },
IndexFiles: []string{"index.html"}, IndexFiles: []string{"index.html"},
...@@ -145,12 +148,10 @@ DocFlags.var_bool true` ...@@ -145,12 +148,10 @@ DocFlags.var_bool true`
<title>Markdown test 2</title> <title>Markdown test 2</title>
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="stylesheet" href="/resources/css/log.css"> <link rel="stylesheet" href="/resources/css/log.css">
<link rel="stylesheet" href="/resources/css/default.css"> <link rel="stylesheet" href="/resources/css/default.css">
<script src="/resources/js/log.js"></script> <script src="/resources/js/log.js"></script>
<script src="/resources/js/default.js"></script> <script src="/resources/js/default.js"></script>
</head>
</head>
<body> <body>
<h2>Welcome on the blog</h2> <h2>Welcome on the blog</h2>
......
...@@ -2,19 +2,12 @@ package markdown ...@@ -2,19 +2,12 @@ package markdown
import ( import (
"bytes" "bytes"
"io/ioutil"
"path/filepath" "path/filepath"
"text/template"
"github.com/mholt/caddy/middleware" "github.com/mholt/caddy/middleware"
"github.com/russross/blackfriday" "github.com/russross/blackfriday"
) )
const (
// DefaultTemplate is the default template.
DefaultTemplate = "defaultTemplate"
)
// Data represents a markdown document. // Data represents a markdown document.
type Data struct { type Data struct {
middleware.Context middleware.Context
...@@ -52,24 +45,6 @@ func (md Markdown) Process(c *Config, requestPath string, b []byte, ctx middlewa ...@@ -52,24 +45,6 @@ func (md Markdown) Process(c *Config, requestPath string, b []byte, ctx middlewa
metadata = parser.Metadata() metadata = parser.Metadata()
} }
// if template is not specified, check if Default template is set
if metadata.Template == "" {
if _, ok := c.Templates[DefaultTemplate]; ok {
metadata.Template = DefaultTemplate
}
}
// if template is set, load it
var tmpl []byte
if metadata.Template != "" {
if t, ok := c.Templates[metadata.Template]; ok {
tmpl, err = ioutil.ReadFile(t)
}
if err != nil {
return nil, err
}
}
// process markdown // process markdown
extns := 0 extns := 0
extns |= blackfriday.EXTENSION_TABLES extns |= blackfriday.EXTENSION_TABLES
...@@ -88,27 +63,12 @@ func (md Markdown) Process(c *Config, requestPath string, b []byte, ctx middlewa ...@@ -88,27 +63,12 @@ func (md Markdown) Process(c *Config, requestPath string, b []byte, ctx middlewa
} }
metadata.Variables["title"] = title metadata.Variables["title"] = title
return md.processTemplate(c, requestPath, tmpl, metadata, ctx) // return md.processTemplate(c, requestPath, metadata, ctx)
return md.doTemplate(c, requestPath, metadata, ctx)
} }
// processTemplate processes a template given a requestPath, // doTemplate executes a template given a requestPath, template, and metadata
// template (tmpl) and metadata func (md Markdown) doTemplate(c *Config, reqPath string, metadata Metadata, ctx middleware.Context) ([]byte, error) {
func (md Markdown) processTemplate(c *Config, requestPath string, tmpl []byte, metadata Metadata, ctx middleware.Context) ([]byte, error) {
var t *template.Template
var err error
// if template is not specified,
// use the default template
if tmpl == nil {
t = template.Must(template.New("").Parse(htmlTemplate))
} else {
t, err = template.New("").Parse(string(tmpl))
if err != nil {
return nil, err
}
}
// process the template
mdData := Data{ mdData := Data{
Context: ctx, Context: ctx,
Doc: metadata.Variables, Doc: metadata.Variables,
...@@ -118,27 +78,9 @@ func (md Markdown) processTemplate(c *Config, requestPath string, tmpl []byte, m ...@@ -118,27 +78,9 @@ func (md Markdown) processTemplate(c *Config, requestPath string, tmpl []byte, m
} }
b := new(bytes.Buffer) b := new(bytes.Buffer)
err = t.Execute(b, mdData) if err := c.Template.ExecuteTemplate(b, metadata.Template, mdData); err != nil {
if err != nil {
return nil, err return nil, err
} }
return b.Bytes(), nil return b.Bytes(), nil
} }
const (
htmlTemplate = `<!DOCTYPE html>
<html>
<head>
<title>{{.Doc.title}}</title>
<meta charset="utf-8">
{{range .Styles}}<link rel="stylesheet" href="{{.}}">
{{end -}}
{{range .Scripts}}<script src="{{.}}"></script>
{{end -}}
</head>
<body>
{{.Doc.body}}
</body>
</html>`
)
package markdown
import (
"io/ioutil"
"text/template"
)
func setDefaultTemplate(filename string) *template.Template {
buf, err := ioutil.ReadFile(filename)
if err != nil {
return nil
}
return template.Must(GetDefaultTemplate().Parse(string(buf)))
}
func SetTemplate(t *template.Template, name, filename string) error {
// Read template
buf, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
// Update if exists
if tt := t.Lookup(name); tt != nil {
_, err = tt.Parse(string(buf))
return err
}
// Allocate new name if not
_, err = t.New(name).Parse(string(buf))
return err
}
func GetDefaultTemplate() *template.Template {
return template.Must(template.New("").Parse(defaultTemplate))
}
const (
defaultTemplate = `<!DOCTYPE html>
<html>
<head>
<title>{{.Doc.title}}</title>
<meta charset="utf-8">
{{range .Styles}}<link rel="stylesheet" href="{{.}}">
{{end -}}
{{range .Scripts}}<script src="{{.}}"></script>
{{end -}}
</head>
<body>
{{.Doc.body}}
</body>
</html>`
)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment