test_helpers.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 renderer := HTMLRendererWithParameters(params.HTMLFlags,
47 params.Options.Extensions, "", "", params.HTMLRendererParameters)
48 return string(MarkdownOptions([]byte(input), renderer, params.Options))
49}
50
51func doTestsBlock(t *testing.T, tests []string, extensions Extensions) {
52 doTestsParam(t, tests, TestParams{
53 Options: Options{Extensions: extensions},
54 HTMLFlags: UseXHTML,
55 })
56}
57
58func doTestsParam(t *testing.T, tests []string, params TestParams) {
59 execRecoverableTestSuite(t, tests, params, func(candidate *string) {
60 for i := 0; i+1 < len(tests); i += 2 {
61 input := tests[i]
62 *candidate = input
63 expected := tests[i+1]
64 actual := runMarkdown(*candidate, params)
65 if actual != expected {
66 t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]",
67 *candidate, expected, actual)
68 }
69
70 // now test every substring to stress test bounds checking
71 if !testing.Short() {
72 for start := 0; start < len(input); start++ {
73 for end := start + 1; end <= len(input); end++ {
74 *candidate = input[start:end]
75 runMarkdown(*candidate, params)
76 }
77 }
78 }
79 }
80 })
81}
82
83func doTestsInline(t *testing.T, tests []string) {
84 doTestsInlineParam(t, tests, TestParams{})
85}
86
87func doLinkTestsInline(t *testing.T, tests []string) {
88 doTestsInline(t, tests)
89
90 prefix := "http://localhost"
91 params := HTMLRendererParameters{AbsolutePrefix: prefix}
92 transformTests := transformLinks(tests, prefix)
93 doTestsInlineParam(t, transformTests, TestParams{
94 HTMLRendererParameters: params,
95 })
96 doTestsInlineParam(t, transformTests, TestParams{
97 HTMLFlags: CommonHtmlFlags,
98 HTMLRendererParameters: params,
99 })
100}
101
102func doSafeTestsInline(t *testing.T, tests []string) {
103 doTestsInlineParam(t, tests, TestParams{HTMLFlags: Safelink})
104
105 // All the links in this test should not have the prefix appended, so
106 // just rerun it with different parameters and the same expectations.
107 prefix := "http://localhost"
108 params := HTMLRendererParameters{AbsolutePrefix: prefix}
109 transformTests := transformLinks(tests, prefix)
110 doTestsInlineParam(t, transformTests, TestParams{
111 HTMLFlags: Safelink,
112 HTMLRendererParameters: params,
113 })
114}
115
116func doTestsInlineParam(t *testing.T, tests []string, params TestParams) {
117 params.Options.Extensions |= Autolink
118 params.Options.Extensions |= Strikethrough
119 params.HTMLFlags |= UseXHTML
120 doTestsParam(t, tests, params)
121}
122
123func transformLinks(tests []string, prefix string) []string {
124 newTests := make([]string, len(tests))
125 anchorRe := regexp.MustCompile(`<a href="/(.*?)"`)
126 imgRe := regexp.MustCompile(`<img src="/(.*?)"`)
127 for i, test := range tests {
128 if i%2 == 1 {
129 test = anchorRe.ReplaceAllString(test, `<a href="`+prefix+`/$1"`)
130 test = imgRe.ReplaceAllString(test, `<img src="`+prefix+`/$1"`)
131 }
132 newTests[i] = test
133 }
134 return newTests
135}
136
137func doTestsReference(t *testing.T, files []string, flag Extensions) {
138 params := TestParams{Options: Options{Extensions: flag}}
139 execRecoverableTestSuite(t, files, params, func(candidate *string) {
140 for _, basename := range files {
141 filename := filepath.Join("testdata", basename+".text")
142 inputBytes, err := ioutil.ReadFile(filename)
143 if err != nil {
144 t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
145 continue
146 }
147 input := string(inputBytes)
148
149 filename = filepath.Join("testdata", basename+".html")
150 expectedBytes, err := ioutil.ReadFile(filename)
151 if err != nil {
152 t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
153 continue
154 }
155 expected := string(expectedBytes)
156
157 actual := string(runMarkdown(input, params))
158 if actual != expected {
159 t.Errorf("\n [%#v]\nExpected[%#v]\nActual [%#v]",
160 basename+".text", expected, actual)
161 }
162
163 // now test every prefix of every input to check for
164 // bounds checking
165 if !testing.Short() {
166 start, max := 0, len(input)
167 for end := start + 1; end <= max; end++ {
168 *candidate = input[start:end]
169 runMarkdown(*candidate, params)
170 }
171 }
172 }
173 })
174}