all repos — grayfriday @ 4c9bf9512682b995722660a4196c0013228e2049

blackfriday fork with a few changes

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	"fmt"
 18	"io/ioutil"
 19	"path/filepath"
 20	"regexp"
 21	"strings"
 22	"testing"
 23)
 24
 25type TestParams struct {
 26	extensions        Extensions
 27	referenceOverride ReferenceOverrideFunc
 28	HTMLFlags
 29	HTMLRendererParameters
 30}
 31
 32func execRecoverableTestSuite(t *testing.T, tests []string, params TestParams, suite func(candidate *string)) {
 33	// Catch and report panics. This is useful when running 'go test -v' on
 34	// the integration server. When developing, though, crash dump is often
 35	// preferable, so recovery can be easily turned off with doRecover = false.
 36	var candidate string
 37	const doRecover = true
 38	if doRecover {
 39		defer func() {
 40			if err := recover(); err != nil {
 41				t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err)
 42			}
 43		}()
 44	}
 45	suite(&candidate)
 46}
 47
 48func runMarkdown(input string, params TestParams) string {
 49	params.HTMLRendererParameters.Flags = params.HTMLFlags
 50	renderer := NewHTMLRenderer(params.HTMLRendererParameters)
 51	return string(Run([]byte(input), WithRenderer(renderer),
 52		WithExtensions(params.extensions),
 53		WithRefOverride(params.referenceOverride)))
 54}
 55
 56// doTests runs full document tests using MarkdownCommon configuration.
 57func doTests(t *testing.T, tests []string) {
 58	doTestsParam(t, tests, TestParams{
 59		extensions: CommonExtensions,
 60		HTMLRendererParameters: HTMLRendererParameters{
 61			Flags: CommonHTMLFlags,
 62		},
 63	})
 64}
 65
 66func doTestsBlock(t *testing.T, tests []string, extensions Extensions) {
 67	doTestsParam(t, tests, TestParams{
 68		extensions: extensions,
 69		HTMLFlags:  UseXHTML,
 70	})
 71}
 72
 73func doTestsParam(t *testing.T, tests []string, params TestParams) {
 74	execRecoverableTestSuite(t, tests, params, func(candidate *string) {
 75		for i := 0; i+1 < len(tests); i += 2 {
 76			input := tests[i]
 77			*candidate = input
 78			expected := tests[i+1]
 79			actual := runMarkdown(*candidate, params)
 80			if actual != expected {
 81				t.Errorf("\nInput   [%#v]\nExpected[%#v]\nActual  [%#v]",
 82					*candidate, expected, actual)
 83			}
 84
 85			// now test every substring to stress test bounds checking
 86			if !testing.Short() {
 87				for start := 0; start < len(input); start++ {
 88					for end := start + 1; end <= len(input); end++ {
 89						*candidate = input[start:end]
 90						runMarkdown(*candidate, params)
 91					}
 92				}
 93			}
 94		}
 95	})
 96}
 97
 98func doTestsInline(t *testing.T, tests []string) {
 99	doTestsInlineParam(t, tests, TestParams{})
100}
101
102func doLinkTestsInline(t *testing.T, tests []string) {
103	doTestsInline(t, tests)
104
105	prefix := "http://localhost"
106	params := HTMLRendererParameters{AbsolutePrefix: prefix}
107	transformTests := transformLinks(tests, prefix)
108	doTestsInlineParam(t, transformTests, TestParams{
109		HTMLRendererParameters: params,
110	})
111	doTestsInlineParam(t, transformTests, TestParams{
112		HTMLFlags:              UseXHTML,
113		HTMLRendererParameters: params,
114	})
115}
116
117func doSafeTestsInline(t *testing.T, tests []string) {
118	doTestsInlineParam(t, tests, TestParams{HTMLFlags: Safelink})
119
120	// All the links in this test should not have the prefix appended, so
121	// just rerun it with different parameters and the same expectations.
122	prefix := "http://localhost"
123	params := HTMLRendererParameters{AbsolutePrefix: prefix}
124	transformTests := transformLinks(tests, prefix)
125	doTestsInlineParam(t, transformTests, TestParams{
126		HTMLFlags:              Safelink,
127		HTMLRendererParameters: params,
128	})
129}
130
131func doTestsInlineParam(t *testing.T, tests []string, params TestParams) {
132	params.extensions |= Autolink | Strikethrough
133	params.HTMLFlags |= UseXHTML
134	doTestsParam(t, tests, params)
135}
136
137func transformLinks(tests []string, prefix string) []string {
138	newTests := make([]string, len(tests))
139	anchorRe := regexp.MustCompile(`<a href="/(.*?)"`)
140	imgRe := regexp.MustCompile(`<img src="/(.*?)"`)
141	for i, test := range tests {
142		if i%2 == 1 {
143			test = anchorRe.ReplaceAllString(test, `<a href="`+prefix+`/$1"`)
144			test = imgRe.ReplaceAllString(test, `<img src="`+prefix+`/$1"`)
145		}
146		newTests[i] = test
147	}
148	return newTests
149}
150
151func doTestsReference(t *testing.T, files []string, flag Extensions) {
152	params := TestParams{extensions: flag}
153	execRecoverableTestSuite(t, files, params, func(candidate *string) {
154		for _, basename := range files {
155			filename := filepath.Join("testdata", basename+".text")
156			inputBytes, err := ioutil.ReadFile(filename)
157			if err != nil {
158				t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
159				continue
160			}
161			input := string(inputBytes)
162
163			filename = filepath.Join("testdata", basename+".html")
164			expectedBytes, err := ioutil.ReadFile(filename)
165			if err != nil {
166				t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
167				continue
168			}
169			expected := string(expectedBytes)
170
171			actual := string(runMarkdown(input, params))
172			if actual != expected {
173				t.Errorf("\n" + doTestDiff(basename, expected, actual))
174			}
175
176			// now test every prefix of every input to check for
177			// bounds checking
178			if !testing.Short() {
179				start, max := 0, len(input)
180				for end := start + 1; end <= max; end++ {
181					*candidate = input[start:end]
182					runMarkdown(*candidate, params)
183				}
184			}
185		}
186	})
187}
188
189func doTestDiff(name, expected, actual string) string {
190	expectedLines := strings.Split(expected, "\n")
191	actualLines := strings.Split(actual, "\n")
192	d := "file: " + name + "\n"
193	for i, line := range expectedLines {
194		// Allow the actualLines indexing to panic because we're in tests where
195		// that's okay and we probably want to know about it if this input is wrong
196		// somehow.
197		if line != actualLines[i] {
198			d += fmt.Sprintf(`
199line: %d
200
201-%s
202+%s
203`, i, line, actualLines[i])
204		}
205	}
206
207	return d
208}