mirror of
https://github.com/danog/blackfriday.git
synced 2024-12-04 02:17:50 +01:00
Merge pull request #280 from russross/fix-279-and-refactor
Fix fenced code block rendering with content resembling references.
This commit is contained in:
commit
4e6f303e8d
70
block.go
70
block.go
@ -102,7 +102,7 @@ func (p *parser) block(out *bytes.Buffer, data []byte) {
|
|||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
if p.flags&EXTENSION_FENCED_CODE != 0 {
|
if p.flags&EXTENSION_FENCED_CODE != 0 {
|
||||||
if i := p.fencedCode(out, data, true); i > 0 {
|
if i := p.fencedCodeBlock(out, data, true); i > 0 {
|
||||||
data = data[i:]
|
data = data[i:]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -515,7 +515,7 @@ func (p *parser) htmlFindEnd(tag string, data []byte) int {
|
|||||||
return i + skip
|
return i + skip
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) isEmpty(data []byte) int {
|
func (*parser) isEmpty(data []byte) int {
|
||||||
// it is okay to call isEmpty on an empty buffer
|
// it is okay to call isEmpty on an empty buffer
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return 0
|
return 0
|
||||||
@ -530,7 +530,7 @@ func (p *parser) isEmpty(data []byte) int {
|
|||||||
return i + 1
|
return i + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) isHRule(data []byte) bool {
|
func (*parser) isHRule(data []byte) bool {
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
// skip up to three spaces
|
// skip up to three spaces
|
||||||
@ -559,21 +559,24 @@ func (p *parser) isHRule(data []byte) bool {
|
|||||||
return n >= 3
|
return n >= 3
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) isFencedCode(data []byte, syntax **string, oldmarker string) (skip int, marker string) {
|
// isFenceLine checks if there's a fence line (e.g., ``` or ``` go) at the beginning of data,
|
||||||
|
// and returns the end index if so, or 0 otherwise. It also returns the marker found.
|
||||||
|
// If syntax is not nil, it gets set to the syntax specified in the fence line.
|
||||||
|
// A final newline is mandatory to recognize the fence line, unless newlineOptional is true.
|
||||||
|
func isFenceLine(data []byte, syntax *string, oldmarker string, newlineOptional bool) (end int, marker string) {
|
||||||
i, size := 0, 0
|
i, size := 0, 0
|
||||||
skip = 0
|
|
||||||
|
|
||||||
// skip up to three spaces
|
// skip up to three spaces
|
||||||
for i < len(data) && i < 3 && data[i] == ' ' {
|
for i < len(data) && i < 3 && data[i] == ' ' {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
if i >= len(data) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for the marker characters: ~ or `
|
// check for the marker characters: ~ or `
|
||||||
|
if i >= len(data) {
|
||||||
|
return 0, ""
|
||||||
|
}
|
||||||
if data[i] != '~' && data[i] != '`' {
|
if data[i] != '~' && data[i] != '`' {
|
||||||
return
|
return 0, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
c := data[i]
|
c := data[i]
|
||||||
@ -584,27 +587,28 @@ func (p *parser) isFencedCode(data []byte, syntax **string, oldmarker string) (s
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
if i >= len(data) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// the marker char must occur at least 3 times
|
// the marker char must occur at least 3 times
|
||||||
if size < 3 {
|
if size < 3 {
|
||||||
return
|
return 0, ""
|
||||||
}
|
}
|
||||||
marker = string(data[i-size : i])
|
marker = string(data[i-size : i])
|
||||||
|
|
||||||
// if this is the end marker, it must match the beginning marker
|
// if this is the end marker, it must match the beginning marker
|
||||||
if oldmarker != "" && marker != oldmarker {
|
if oldmarker != "" && marker != oldmarker {
|
||||||
return
|
return 0, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(shurcooL): It's probably a good idea to simplify the 2 code paths here
|
||||||
|
// into one, always get the syntax, and discard it if the caller doesn't care.
|
||||||
if syntax != nil {
|
if syntax != nil {
|
||||||
syn := 0
|
syn := 0
|
||||||
i = skipChar(data, i, ' ')
|
i = skipChar(data, i, ' ')
|
||||||
|
|
||||||
if i >= len(data) {
|
if i >= len(data) {
|
||||||
return
|
if newlineOptional && i == len(data) {
|
||||||
|
return i, marker
|
||||||
|
}
|
||||||
|
return 0, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
syntaxStart := i
|
syntaxStart := i
|
||||||
@ -619,7 +623,7 @@ func (p *parser) isFencedCode(data []byte, syntax **string, oldmarker string) (s
|
|||||||
}
|
}
|
||||||
|
|
||||||
if i >= len(data) || data[i] != '}' {
|
if i >= len(data) || data[i] != '}' {
|
||||||
return
|
return 0, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// strip all whitespace at the beginning and the end
|
// strip all whitespace at the beginning and the end
|
||||||
@ -641,22 +645,26 @@ func (p *parser) isFencedCode(data []byte, syntax **string, oldmarker string) (s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
language := string(data[syntaxStart : syntaxStart+syn])
|
*syntax = string(data[syntaxStart : syntaxStart+syn])
|
||||||
*syntax = &language
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i = skipChar(data, i, ' ')
|
i = skipChar(data, i, ' ')
|
||||||
if i >= len(data) || data[i] != '\n' {
|
if i >= len(data) || data[i] != '\n' {
|
||||||
return
|
if newlineOptional && i == len(data) {
|
||||||
|
return i, marker
|
||||||
|
}
|
||||||
|
return 0, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
skip = i + 1
|
return i + 1, marker // Take newline into account.
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) fencedCode(out *bytes.Buffer, data []byte, doRender bool) int {
|
// fencedCodeBlock returns the end index if data contains a fenced code block at the beginning,
|
||||||
var lang *string
|
// or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects.
|
||||||
beg, marker := p.isFencedCode(data, &lang, "")
|
// If doRender is true, a final newline is mandatory to recognize the fenced code block.
|
||||||
|
func (p *parser) fencedCodeBlock(out *bytes.Buffer, data []byte, doRender bool) int {
|
||||||
|
var syntax string
|
||||||
|
beg, marker := isFenceLine(data, &syntax, "", true)
|
||||||
if beg == 0 || beg >= len(data) {
|
if beg == 0 || beg >= len(data) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -667,7 +675,8 @@ func (p *parser) fencedCode(out *bytes.Buffer, data []byte, doRender bool) int {
|
|||||||
// safe to assume beg < len(data)
|
// safe to assume beg < len(data)
|
||||||
|
|
||||||
// check for the end of the code block
|
// check for the end of the code block
|
||||||
fenceEnd, _ := p.isFencedCode(data[beg:], nil, marker)
|
newlineOptional := !doRender
|
||||||
|
fenceEnd, _ := isFenceLine(data[beg:], nil, marker, newlineOptional)
|
||||||
if fenceEnd != 0 {
|
if fenceEnd != 0 {
|
||||||
beg += fenceEnd
|
beg += fenceEnd
|
||||||
break
|
break
|
||||||
@ -688,11 +697,6 @@ func (p *parser) fencedCode(out *bytes.Buffer, data []byte, doRender bool) int {
|
|||||||
beg = end
|
beg = end
|
||||||
}
|
}
|
||||||
|
|
||||||
syntax := ""
|
|
||||||
if lang != nil {
|
|
||||||
syntax = *lang
|
|
||||||
}
|
|
||||||
|
|
||||||
if doRender {
|
if doRender {
|
||||||
p.r.BlockCode(out, work.Bytes(), syntax)
|
p.r.BlockCode(out, work.Bytes(), syntax)
|
||||||
}
|
}
|
||||||
@ -934,7 +938,7 @@ func (p *parser) quote(out *bytes.Buffer, data []byte) int {
|
|||||||
// irregardless of any contents inside it
|
// irregardless of any contents inside it
|
||||||
for data[end] != '\n' {
|
for data[end] != '\n' {
|
||||||
if p.flags&EXTENSION_FENCED_CODE != 0 {
|
if p.flags&EXTENSION_FENCED_CODE != 0 {
|
||||||
if i := p.fencedCode(out, data[end:], false); i > 0 {
|
if i := p.fencedCodeBlock(out, data[end:], false); i > 0 {
|
||||||
// -1 to compensate for the extra end++ after the loop:
|
// -1 to compensate for the extra end++ after the loop:
|
||||||
end += i - 1
|
end += i - 1
|
||||||
break
|
break
|
||||||
@ -1384,7 +1388,7 @@ func (p *parser) paragraph(out *bytes.Buffer, data []byte) int {
|
|||||||
|
|
||||||
// if there's a fenced code block, paragraph is over
|
// if there's a fenced code block, paragraph is over
|
||||||
if p.flags&EXTENSION_FENCED_CODE != 0 {
|
if p.flags&EXTENSION_FENCED_CODE != 0 {
|
||||||
if p.fencedCode(out, current, false) > 0 {
|
if p.fencedCodeBlock(out, current, false) > 0 {
|
||||||
p.renderParagraph(out, data[:i])
|
p.renderParagraph(out, data[:i])
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
@ -1130,6 +1130,12 @@ func TestFencedCodeBlock(t *testing.T) {
|
|||||||
|
|
||||||
"Some text before a fenced code block\n``` oz\ncode blocks breakup paragraphs\n```\nSome text in between\n``` oz\nmultiple code blocks work okay\n```\nAnd some text after a fenced code block",
|
"Some text before a fenced code block\n``` oz\ncode blocks breakup paragraphs\n```\nSome text in between\n``` oz\nmultiple code blocks work okay\n```\nAnd some text after a fenced code block",
|
||||||
"<p>Some text before a fenced code block</p>\n\n<pre><code class=\"language-oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>Some text in between</p>\n\n<pre><code class=\"language-oz\">multiple code blocks work okay\n</code></pre>\n\n<p>And some text after a fenced code block</p>\n",
|
"<p>Some text before a fenced code block</p>\n\n<pre><code class=\"language-oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>Some text in between</p>\n\n<pre><code class=\"language-oz\">multiple code blocks work okay\n</code></pre>\n\n<p>And some text after a fenced code block</p>\n",
|
||||||
|
|
||||||
|
"```\n[]:()\n```\n",
|
||||||
|
"<pre><code>[]:()\n</code></pre>\n",
|
||||||
|
|
||||||
|
"```\n[]:()\n[]:)\n[]:(\n[]:x\n[]:testing\n[:testing\n\n[]:\nlinebreak\n[]()\n\n[]:\n[]()\n```",
|
||||||
|
"<pre><code>[]:()\n[]:)\n[]:(\n[]:x\n[]:testing\n[:testing\n\n[]:\nlinebreak\n[]()\n\n[]:\n[]()\n</code></pre>\n",
|
||||||
}
|
}
|
||||||
doTestsBlock(t, tests, EXTENSION_FENCED_CODE)
|
doTestsBlock(t, tests, EXTENSION_FENCED_CODE)
|
||||||
}
|
}
|
||||||
@ -1636,3 +1642,68 @@ func TestCDATA(t *testing.T) {
|
|||||||
`,
|
`,
|
||||||
}, EXTENSION_FENCED_CODE)
|
}, EXTENSION_FENCED_CODE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsFenceLine(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
data []byte
|
||||||
|
syntaxRequested bool
|
||||||
|
newlineOptional bool
|
||||||
|
wantEnd int
|
||||||
|
wantMarker string
|
||||||
|
wantSyntax string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
data: []byte("```"),
|
||||||
|
wantEnd: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte("```\nstuff here\n"),
|
||||||
|
wantEnd: 4,
|
||||||
|
wantMarker: "```",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte("stuff here\n```\n"),
|
||||||
|
wantEnd: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte("```"),
|
||||||
|
newlineOptional: true,
|
||||||
|
wantEnd: 3,
|
||||||
|
wantMarker: "```",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte("```"),
|
||||||
|
syntaxRequested: true,
|
||||||
|
newlineOptional: true,
|
||||||
|
wantEnd: 3,
|
||||||
|
wantMarker: "```",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte("``` go"),
|
||||||
|
syntaxRequested: true,
|
||||||
|
newlineOptional: true,
|
||||||
|
wantEnd: 6,
|
||||||
|
wantMarker: "```",
|
||||||
|
wantSyntax: "go",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
var syntax *string
|
||||||
|
if test.syntaxRequested {
|
||||||
|
syntax = new(string)
|
||||||
|
}
|
||||||
|
end, marker := isFenceLine(test.data, syntax, "```", test.newlineOptional)
|
||||||
|
if got, want := end, test.wantEnd; got != want {
|
||||||
|
t.Errorf("got end %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := marker, test.wantMarker; got != want {
|
||||||
|
t.Errorf("got marker %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
if test.syntaxRequested {
|
||||||
|
if got, want := *syntax, test.wantSyntax; got != want {
|
||||||
|
t.Errorf("got syntax %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -59,13 +59,11 @@ func doTestsInlineParam(t *testing.T, tests []string, opts Options, htmlFlags in
|
|||||||
params HtmlRendererParameters) {
|
params HtmlRendererParameters) {
|
||||||
// catch and report panics
|
// catch and report panics
|
||||||
var candidate string
|
var candidate string
|
||||||
/*
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
t.Errorf("\npanic while processing [%#v] (%v)\n", candidate, err)
|
t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
*/
|
|
||||||
|
|
||||||
for i := 0; i+1 < len(tests); i += 2 {
|
for i := 0; i+1 < len(tests); i += 2 {
|
||||||
input := tests[i]
|
input := tests[i]
|
||||||
@ -722,10 +720,6 @@ func TestReferenceLink(t *testing.T) {
|
|||||||
|
|
||||||
"[link][ref]\n [ref]: /url/",
|
"[link][ref]\n [ref]: /url/",
|
||||||
"<p><a href=\"/url/\">link</a></p>\n",
|
"<p><a href=\"/url/\">link</a></p>\n",
|
||||||
|
|
||||||
// Issue 172 in blackfriday
|
|
||||||
"[]:<",
|
|
||||||
"<p>[]:<</p>\n",
|
|
||||||
}
|
}
|
||||||
doLinkTestsInline(t, tests)
|
doLinkTestsInline(t, tests)
|
||||||
}
|
}
|
||||||
|
24
markdown.go
24
markdown.go
@ -386,9 +386,9 @@ func MarkdownOptions(input []byte, renderer Renderer, opts Options) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// first pass:
|
// first pass:
|
||||||
// - extract references
|
|
||||||
// - expand tabs
|
|
||||||
// - normalize newlines
|
// - normalize newlines
|
||||||
|
// - extract references (outside of fenced code blocks)
|
||||||
|
// - expand tabs (outside of fenced code blocks)
|
||||||
// - copy everything else
|
// - copy everything else
|
||||||
func firstPass(p *parser, input []byte) []byte {
|
func firstPass(p *parser, input []byte) []byte {
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
@ -396,22 +396,20 @@ func firstPass(p *parser, input []byte) []byte {
|
|||||||
if p.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
|
if p.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
|
||||||
tabSize = TAB_SIZE_EIGHT
|
tabSize = TAB_SIZE_EIGHT
|
||||||
}
|
}
|
||||||
beg, end := 0, 0
|
beg := 0
|
||||||
lastFencedCodeBlockEnd := 0
|
lastFencedCodeBlockEnd := 0
|
||||||
for beg < len(input) { // iterate over lines
|
for beg < len(input) {
|
||||||
if end = isReference(p, input[beg:], tabSize); end > 0 {
|
// Find end of this line, then process the line.
|
||||||
beg += end
|
end := beg
|
||||||
} else { // skip to the next line
|
|
||||||
end = beg
|
|
||||||
for end < len(input) && input[end] != '\n' && input[end] != '\r' {
|
for end < len(input) && input[end] != '\n' && input[end] != '\r' {
|
||||||
end++
|
end++
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.flags&EXTENSION_FENCED_CODE != 0 {
|
if p.flags&EXTENSION_FENCED_CODE != 0 {
|
||||||
// track fenced code block boundaries to suppress tab expansion
|
// track fenced code block boundaries to suppress tab expansion
|
||||||
// inside them:
|
// and reference extraction inside them:
|
||||||
if beg >= lastFencedCodeBlockEnd {
|
if beg >= lastFencedCodeBlockEnd {
|
||||||
if i := p.fencedCode(&out, input[beg:], false); i > 0 {
|
if i := p.fencedCodeBlock(&out, input[beg:], false); i > 0 {
|
||||||
lastFencedCodeBlockEnd = beg + i
|
lastFencedCodeBlockEnd = beg + i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -421,11 +419,13 @@ func firstPass(p *parser, input []byte) []byte {
|
|||||||
if end > beg {
|
if end > beg {
|
||||||
if end < lastFencedCodeBlockEnd { // Do not expand tabs while inside fenced code blocks.
|
if end < lastFencedCodeBlockEnd { // Do not expand tabs while inside fenced code blocks.
|
||||||
out.Write(input[beg:end])
|
out.Write(input[beg:end])
|
||||||
|
} else if refEnd := isReference(p, input[beg:], tabSize); refEnd > 0 {
|
||||||
|
beg += refEnd
|
||||||
|
continue
|
||||||
} else {
|
} else {
|
||||||
expandTabs(&out, input[beg:end], tabSize)
|
expandTabs(&out, input[beg:end], tabSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.WriteByte('\n')
|
|
||||||
|
|
||||||
if end < len(input) && input[end] == '\r' {
|
if end < len(input) && input[end] == '\r' {
|
||||||
end++
|
end++
|
||||||
@ -433,10 +433,10 @@ func firstPass(p *parser, input []byte) []byte {
|
|||||||
if end < len(input) && input[end] == '\n' {
|
if end < len(input) && input[end] == '\n' {
|
||||||
end++
|
end++
|
||||||
}
|
}
|
||||||
|
out.WriteByte('\n')
|
||||||
|
|
||||||
beg = end
|
beg = end
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// empty input?
|
// empty input?
|
||||||
if out.Len() == 0 {
|
if out.Len() == 0 {
|
||||||
|
75
markdown_test.go
Normal file
75
markdown_test.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Unit tests for full document parsing and rendering
|
||||||
|
//
|
||||||
|
|
||||||
|
package blackfriday
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runMarkdown(input string) string {
|
||||||
|
return string(MarkdownCommon([]byte(input)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func doTests(t *testing.T, tests []string) {
|
||||||
|
// catch and report panics
|
||||||
|
var candidate string
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for i := 0; i+1 < len(tests); i += 2 {
|
||||||
|
input := tests[i]
|
||||||
|
candidate = input
|
||||||
|
expected := tests[i+1]
|
||||||
|
actual := runMarkdown(candidate)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDocument(t *testing.T) {
|
||||||
|
var tests = []string{
|
||||||
|
// Empty document.
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
|
||||||
|
" ",
|
||||||
|
"",
|
||||||
|
|
||||||
|
// This shouldn't panic.
|
||||||
|
// https://github.com/russross/blackfriday/issues/172
|
||||||
|
"[]:<",
|
||||||
|
"<p>[]:<</p>\n",
|
||||||
|
|
||||||
|
// This shouldn't panic.
|
||||||
|
// https://github.com/russross/blackfriday/issues/173
|
||||||
|
" [",
|
||||||
|
"<p>[</p>\n",
|
||||||
|
}
|
||||||
|
doTests(t, tests)
|
||||||
|
}
|
@ -29,7 +29,7 @@ func doTestsReference(t *testing.T, files []string, flag int) {
|
|||||||
var candidate string
|
var candidate string
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
t.Errorf("\npanic while processing [%#v]\n", candidate)
|
t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user