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 extensions Extensions
25 referenceOverride ReferenceOverrideFunc
26 HTMLFlags
27 HTMLRendererParameters
28}
29
30func execRecoverableTestSuite(t *testing.T, tests []string, params TestParams, suite func(candidate *string)) {
31 // Catch and report panics. This is useful when running 'go test -v' on
32 // the integration server. When developing, though, crash dump is often
33 // preferable, so recovery can be easily turned off with doRecover = false.
34 var candidate string
35 const doRecover = true
36 if doRecover {
37 defer func() {
38 if err := recover(); err != nil {
39 t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err)
40 }
41 }()
42 }
43 suite(&candidate)
44}
45
46func runMarkdown(input string, params TestParams) string {
47 params.HTMLRendererParameters.Flags = params.HTMLFlags
48 renderer := NewHTMLRenderer(params.HTMLRendererParameters)
49 return string(Markdown([]byte(input), WithRenderer(renderer),
50 WithExtensions(params.extensions),
51 WithRefOverride(params.referenceOverride)))
52}
53
54// doTests runs full document tests using MarkdownCommon configuration.
55func doTests(t *testing.T, tests []string) {
56 doTestsParam(t, tests, TestParams{
57 extensions: CommonExtensions,
58 HTMLRendererParameters: HTMLRendererParameters{
59 Flags: CommonHTMLFlags,
60 },
61 })
62}
63
64func doTestsBlock(t *testing.T, tests []string, extensions Extensions) {
65 doTestsParam(t, tests, TestParams{
66 extensions: extensions,
67 HTMLFlags: UseXHTML,
68 })
69}
70
71func doTestsParam(t *testing.T, tests []string, params TestParams) {
72 execRecoverableTestSuite(t, tests, params, func(candidate *string) {
73 for i := 0; i+1 < len(tests); i += 2 {
74 input := tests[i]
75 *candidate = input
76 expected := tests[i+1]
77 actual := runMarkdown(*candidate, params)
78 if actual != expected {
79 t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]",
80 *candidate, expected, actual)
81 }
82
83 // now test every substring to stress test bounds checking
84 if !testing.Short() {
85 for start := 0; start < len(input); start++ {
86 for end := start + 1; end <= len(input); end++ {
87 *candidate = input[start:end]
88 runMarkdown(*candidate, params)
89 }
90 }
91 }
92 }
93 })
94}
95
96func doTestsInline(t *testing.T, tests []string) {
97 doTestsInlineParam(t, tests, TestParams{})
98}
99
100func doLinkTestsInline(t *testing.T, tests []string) {
101 doTestsInline(t, tests)
102
103 prefix := "http://localhost"
104 params := HTMLRendererParameters{AbsolutePrefix: prefix}
105 transformTests := transformLinks(tests, prefix)
106 doTestsInlineParam(t, transformTests, TestParams{
107 HTMLRendererParameters: params,
108 })
109 doTestsInlineParam(t, transformTests, TestParams{
110 HTMLFlags: UseXHTML,
111 HTMLRendererParameters: params,
112 })
113}
114
115func doSafeTestsInline(t *testing.T, tests []string) {
116 doTestsInlineParam(t, tests, TestParams{HTMLFlags: Safelink})
117
118 // All the links in this test should not have the prefix appended, so
119 // just rerun it with different parameters and the same expectations.
120 prefix := "http://localhost"
121 params := HTMLRendererParameters{AbsolutePrefix: prefix}
122 transformTests := transformLinks(tests, prefix)
123 doTestsInlineParam(t, transformTests, TestParams{
124 HTMLFlags: Safelink,
125 HTMLRendererParameters: params,
126 })
127}
128
129func doTestsInlineParam(t *testing.T, tests []string, params TestParams) {
130 params.extensions |= Autolink | 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{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}