helpers_test.go (view raw)
1//
2// Blackfriday Markdown Processor
3// Available at http://github.com/russross/blackfriday
4//
5// Copyright © 2011 Russ Ross <russ@russross.com>.
6// Distributed under the Simplified BSD License.
7// See README.md for details.
8//
9
10//
11// Helper functions for unit testing
12//
13
14package blackfriday
15
16import (
17 "io/ioutil"
18 "path/filepath"
19 "regexp"
20 "testing"
21)
22
23type TestParams struct {
24 Options
25 HTMLFlags
26 HTMLRendererParameters
27}
28
29func execRecoverableTestSuite(t *testing.T, tests []string, params TestParams, suite func(candidate *string)) {
30 // Catch and report panics. This is useful when running 'go test -v' on
31 // the integration server. When developing, though, crash dump is often
32 // preferable, so recovery can be easily turned off with doRecover = false.
33 var candidate string
34 const doRecover = true
35 if doRecover {
36 defer func() {
37 if err := recover(); err != nil {
38 t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err)
39 }
40 }()
41 }
42 suite(&candidate)
43}
44
45func runMarkdown(input string, params TestParams) string {
46 params.HTMLRendererParameters.Flags = params.HTMLFlags
47 params.HTMLRendererParameters.Extensions = params.Options.Extensions
48 renderer := NewHTMLRenderer(params.HTMLRendererParameters)
49 return string(Markdown([]byte(input), renderer, params.Options))
50}
51
52// doTests runs full document tests using MarkdownCommon configuration.
53func doTests(t *testing.T, tests []string) {
54 doTestsParam(t, tests, TestParams{
55 Options: DefaultOptions,
56 HTMLRendererParameters: HTMLRendererParameters{
57 Flags: CommonHTMLFlags,
58 Extensions: CommonExtensions,
59 },
60 })
61}
62
63func doTestsBlock(t *testing.T, tests []string, extensions Extensions) {
64 doTestsParam(t, tests, TestParams{
65 Options: Options{Extensions: extensions},
66 HTMLFlags: UseXHTML,
67 })
68}
69
70func doTestsParam(t *testing.T, tests []string, params TestParams) {
71 execRecoverableTestSuite(t, tests, params, func(candidate *string) {
72 for i := 0; i+1 < len(tests); i += 2 {
73 input := tests[i]
74 *candidate = input
75 expected := tests[i+1]
76 actual := runMarkdown(*candidate, params)
77 if actual != expected {
78 t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]",
79 *candidate, expected, actual)
80 }
81
82 // now test every substring to stress test bounds checking
83 if !testing.Short() {
84 for start := 0; start < len(input); start++ {
85 for end := start + 1; end <= len(input); end++ {
86 *candidate = input[start:end]
87 runMarkdown(*candidate, params)
88 }
89 }
90 }
91 }
92 })
93}
94
95func doTestsInline(t *testing.T, tests []string) {
96 doTestsInlineParam(t, tests, TestParams{})
97}
98
99func doLinkTestsInline(t *testing.T, tests []string) {
100 doTestsInline(t, tests)
101
102 prefix := "http://localhost"
103 params := HTMLRendererParameters{AbsolutePrefix: prefix}
104 transformTests := transformLinks(tests, prefix)
105 doTestsInlineParam(t, transformTests, TestParams{
106 HTMLRendererParameters: params,
107 })
108 doTestsInlineParam(t, transformTests, TestParams{
109 HTMLFlags: UseXHTML,
110 HTMLRendererParameters: params,
111 })
112}
113
114func doSafeTestsInline(t *testing.T, tests []string) {
115 doTestsInlineParam(t, tests, TestParams{HTMLFlags: Safelink})
116
117 // All the links in this test should not have the prefix appended, so
118 // just rerun it with different parameters and the same expectations.
119 prefix := "http://localhost"
120 params := HTMLRendererParameters{AbsolutePrefix: prefix}
121 transformTests := transformLinks(tests, prefix)
122 doTestsInlineParam(t, transformTests, TestParams{
123 HTMLFlags: Safelink,
124 HTMLRendererParameters: params,
125 })
126}
127
128func doTestsInlineParam(t *testing.T, tests []string, params TestParams) {
129 params.Options.Extensions |= Autolink
130 params.Options.Extensions |= Strikethrough
131 params.HTMLFlags |= UseXHTML
132 doTestsParam(t, tests, params)
133}
134
135func transformLinks(tests []string, prefix string) []string {
136 newTests := make([]string, len(tests))
137 anchorRe := regexp.MustCompile(`<a href="/(.*?)"`)
138 imgRe := regexp.MustCompile(`<img src="/(.*?)"`)
139 for i, test := range tests {
140 if i%2 == 1 {
141 test = anchorRe.ReplaceAllString(test, `<a href="`+prefix+`/$1"`)
142 test = imgRe.ReplaceAllString(test, `<img src="`+prefix+`/$1"`)
143 }
144 newTests[i] = test
145 }
146 return newTests
147}
148
149func doTestsReference(t *testing.T, files []string, flag Extensions) {
150 params := TestParams{Options: Options{Extensions: flag}}
151 execRecoverableTestSuite(t, files, params, func(candidate *string) {
152 for _, basename := range files {
153 filename := filepath.Join("testdata", basename+".text")
154 inputBytes, err := ioutil.ReadFile(filename)
155 if err != nil {
156 t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
157 continue
158 }
159 input := string(inputBytes)
160
161 filename = filepath.Join("testdata", basename+".html")
162 expectedBytes, err := ioutil.ReadFile(filename)
163 if err != nil {
164 t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
165 continue
166 }
167 expected := string(expectedBytes)
168
169 actual := string(runMarkdown(input, params))
170 if actual != expected {
171 t.Errorf("\n [%#v]\nExpected[%#v]\nActual [%#v]",
172 basename+".text", expected, actual)
173 }
174
175 // now test every prefix of every input to check for
176 // bounds checking
177 if !testing.Short() {
178 start, max := 0, len(input)
179 for end := start + 1; end <= max; end++ {
180 *candidate = input[start:end]
181 runMarkdown(*candidate, params)
182 }
183 }
184 }
185 })
186}