all repos — grayfriday @ master

blackfriday fork with a few changes

helpers_test.go (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
//
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
// Distributed under the Simplified BSD License.
// See README.md for details.
//

//
// Helper functions for unit testing
//

package blackfriday

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"regexp"
	"strings"
	"testing"
)

type TestParams struct {
	extensions        Extensions
	referenceOverride ReferenceOverrideFunc
	HTMLFlags
	HTMLRendererParameters
}

func execRecoverableTestSuite(t *testing.T, tests []string, params TestParams, suite func(candidate *string)) {
	// Catch and report panics. This is useful when running 'go test -v' on
	// the integration server. When developing, though, crash dump is often
	// preferable, so recovery can be easily turned off with doRecover = false.
	var candidate string
	const doRecover = true
	if doRecover {
		defer func() {
			if err := recover(); err != nil {
				t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err)
			}
		}()
	}
	suite(&candidate)
}

func runMarkdown(input string, params TestParams) string {
	params.HTMLRendererParameters.Flags = params.HTMLFlags
	renderer := NewHTMLRenderer(params.HTMLRendererParameters)
	return string(Run([]byte(input), WithRenderer(renderer),
		WithExtensions(params.extensions),
		WithRefOverride(params.referenceOverride)))
}

// doTests runs full document tests using MarkdownCommon configuration.
func doTests(t *testing.T, tests []string) {
	doTestsParam(t, tests, TestParams{
		extensions: CommonExtensions,
		HTMLRendererParameters: HTMLRendererParameters{
			Flags: CommonHTMLFlags,
		},
	})
}

func doTestsBlock(t *testing.T, tests []string, extensions Extensions) {
	doTestsParam(t, tests, TestParams{
		extensions: extensions,
		HTMLFlags:  UseXHTML,
	})
}

func doTestsParam(t *testing.T, tests []string, params TestParams) {
	execRecoverableTestSuite(t, tests, params, func(candidate *string) {
		for i := 0; i+1 < len(tests); i += 2 {
			input := tests[i]
			*candidate = input
			expected := tests[i+1]
			actual := runMarkdown(*candidate, params)
			if actual != expected {
				t.Errorf("\nInput   [%#v]\nExpected[%#v]\nActual  [%#v]",
					*candidate, expected, actual)
			}

			// now test every substring to stress test bounds checking
			if !testing.Short() {
				for start := 0; start < len(input); start++ {
					for end := start + 1; end <= len(input); end++ {
						*candidate = input[start:end]
						runMarkdown(*candidate, params)
					}
				}
			}
		}
	})
}

func doTestsInline(t *testing.T, tests []string) {
	doTestsInlineParam(t, tests, TestParams{})
}

func doLinkTestsInline(t *testing.T, tests []string) {
	doTestsInline(t, tests)

	prefix := "http://localhost"
	params := HTMLRendererParameters{AbsolutePrefix: prefix}
	transformTests := transformLinks(tests, prefix)
	doTestsInlineParam(t, transformTests, TestParams{
		HTMLRendererParameters: params,
	})
	doTestsInlineParam(t, transformTests, TestParams{
		HTMLFlags:              UseXHTML,
		HTMLRendererParameters: params,
	})
}

func doSafeTestsInline(t *testing.T, tests []string) {
	doTestsInlineParam(t, tests, TestParams{HTMLFlags: Safelink})

	// All the links in this test should not have the prefix appended, so
	// just rerun it with different parameters and the same expectations.
	prefix := "http://localhost"
	params := HTMLRendererParameters{AbsolutePrefix: prefix}
	transformTests := transformLinks(tests, prefix)
	doTestsInlineParam(t, transformTests, TestParams{
		HTMLFlags:              Safelink,
		HTMLRendererParameters: params,
	})
}

func doTestsInlineParam(t *testing.T, tests []string, params TestParams) {
	params.extensions |= Autolink | Strikethrough
	params.HTMLFlags |= UseXHTML
	doTestsParam(t, tests, params)
}

func transformLinks(tests []string, prefix string) []string {
	newTests := make([]string, len(tests))
	anchorRe := regexp.MustCompile(`<a href="/(.*?)"`)
	imgRe := regexp.MustCompile(`<img src="/(.*?)"`)
	for i, test := range tests {
		if i%2 == 1 {
			test = anchorRe.ReplaceAllString(test, `<a href="`+prefix+`/$1"`)
			test = imgRe.ReplaceAllString(test, `<img src="`+prefix+`/$1"`)
		}
		newTests[i] = test
	}
	return newTests
}

func doTestsReference(t *testing.T, files []string, flag Extensions) {
	params := TestParams{extensions: flag}
	execRecoverableTestSuite(t, files, params, func(candidate *string) {
		for _, basename := range files {
			filename := filepath.Join("testdata", basename+".text")
			inputBytes, err := ioutil.ReadFile(filename)
			if err != nil {
				t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
				continue
			}
			input := string(inputBytes)

			filename = filepath.Join("testdata", basename+".html")
			expectedBytes, err := ioutil.ReadFile(filename)
			if err != nil {
				t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
				continue
			}
			expected := string(expectedBytes)

			actual := string(runMarkdown(input, params))
			if actual != expected {
				t.Errorf("\n" + doTestDiff(basename, expected, actual))
			}

			// now test every prefix of every input to check for
			// bounds checking
			if !testing.Short() {
				start, max := 0, len(input)
				for end := start + 1; end <= max; end++ {
					*candidate = input[start:end]
					runMarkdown(*candidate, params)
				}
			}
		}
	})
}

func doTestDiff(name, expected, actual string) string {
	expectedLines := strings.Split(expected, "\n")
	actualLines := strings.Split(actual, "\n")
	d := "file: " + name + "\n"
	for i, line := range expectedLines {
		// Allow the actualLines indexing to panic because we're in tests where
		// that's okay and we probably want to know about it if this input is wrong
		// somehow.
		if line != actualLines[i] {
			d += fmt.Sprintf(`
line: %d

-%s
+%s
`, i, line, actualLines[i])
		}
	}

	return d
}