mirror of https://github.com/gogs/gogs.git
178 lines
4.5 KiB
Go
178 lines
4.5 KiB
Go
package parser
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/smartystreets/goconvey/convey/reporting"
|
|
"github.com/smartystreets/goconvey/web/server/contract"
|
|
)
|
|
|
|
type testParser struct {
|
|
test *contract.TestResult
|
|
line string
|
|
index int
|
|
inJson bool
|
|
jsonLines []string
|
|
otherLines []string
|
|
}
|
|
|
|
func parseTestOutput(test *contract.TestResult) *contract.TestResult {
|
|
parser := newTestParser(test)
|
|
parser.parseTestFunctionOutput()
|
|
return test
|
|
}
|
|
|
|
func newTestParser(test *contract.TestResult) *testParser {
|
|
self := new(testParser)
|
|
self.test = test
|
|
return self
|
|
}
|
|
|
|
func (self *testParser) parseTestFunctionOutput() {
|
|
if len(self.test.RawLines) > 0 {
|
|
self.processLines()
|
|
self.deserializeJson()
|
|
self.composeCapturedOutput()
|
|
}
|
|
}
|
|
|
|
func (self *testParser) processLines() {
|
|
for self.index, self.line = range self.test.RawLines {
|
|
if !self.processLine() {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func (self *testParser) processLine() bool {
|
|
if strings.HasSuffix(self.line, reporting.OpenJson) {
|
|
self.inJson = true
|
|
self.accountForOutputWithoutNewline()
|
|
|
|
} else if self.line == reporting.CloseJson {
|
|
self.inJson = false
|
|
|
|
} else if self.inJson {
|
|
self.jsonLines = append(self.jsonLines, self.line)
|
|
|
|
} else if isPanic(self.line) {
|
|
self.parsePanicOutput()
|
|
return false
|
|
|
|
} else if isGoTestLogOutput(self.line) {
|
|
self.parseLogLocation()
|
|
|
|
} else {
|
|
self.otherLines = append(self.otherLines, self.line)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// If fmt.Print(f) produces output with no \n and that output
|
|
// is that last output before the framework spits out json
|
|
// (which starts with ''>>>>>'') then without this code
|
|
// all of the json is counted as output, not as json to be
|
|
// parsed and displayed by the web UI.
|
|
func (self *testParser) accountForOutputWithoutNewline() {
|
|
prefix := strings.Split(self.line, reporting.OpenJson)[0]
|
|
if prefix != "" {
|
|
self.otherLines = append(self.otherLines, prefix)
|
|
}
|
|
}
|
|
|
|
func (self *testParser) deserializeJson() {
|
|
formatted := createArrayForJsonItems(self.jsonLines)
|
|
var scopes []reporting.ScopeResult
|
|
err := json.Unmarshal(formatted, &scopes)
|
|
if err != nil {
|
|
panic(fmt.Sprintf(bugReportRequest, err, formatted))
|
|
}
|
|
self.test.Stories = scopes
|
|
}
|
|
func (self *testParser) parsePanicOutput() {
|
|
for index, line := range self.test.RawLines[self.index:] {
|
|
self.parsePanicLocation(index, line)
|
|
self.preserveStackTraceIndentation(index, line)
|
|
}
|
|
self.test.Error = strings.Join(self.test.RawLines, "\n")
|
|
}
|
|
func (self *testParser) parsePanicLocation(index int, line string) {
|
|
if !panicLineHasMetadata(line) {
|
|
return
|
|
}
|
|
metaLine := self.test.RawLines[index+4]
|
|
fields := strings.Split(metaLine, " ")
|
|
fileAndLine := strings.Split(fields[0], ":")
|
|
self.test.File = fileAndLine[0]
|
|
if len(fileAndLine) >= 2 {
|
|
self.test.Line, _ = strconv.Atoi(fileAndLine[1])
|
|
}
|
|
}
|
|
func (self *testParser) preserveStackTraceIndentation(index int, line string) {
|
|
if panicLineShouldBeIndented(index, line) {
|
|
self.test.RawLines[index] = "\t" + line
|
|
}
|
|
}
|
|
func (self *testParser) parseLogLocation() {
|
|
self.otherLines = append(self.otherLines, self.line)
|
|
lineFields := strings.TrimSpace(self.line)
|
|
if strings.HasPrefix(lineFields, "Error Trace:") {
|
|
lineFields = strings.TrimPrefix(lineFields, "Error Trace:")
|
|
}
|
|
fields := strings.Split(lineFields, ":")
|
|
self.test.File = strings.TrimSpace(fields[0])
|
|
self.test.Line, _ = strconv.Atoi(fields[1])
|
|
}
|
|
|
|
func (self *testParser) composeCapturedOutput() {
|
|
self.test.Message = strings.Join(self.otherLines, "\n")
|
|
}
|
|
|
|
func createArrayForJsonItems(lines []string) []byte {
|
|
jsonArrayItems := strings.Join(lines, "")
|
|
jsonArrayItems = removeTrailingComma(jsonArrayItems)
|
|
return []byte(fmt.Sprintf("[%s]\n", jsonArrayItems))
|
|
}
|
|
func removeTrailingComma(rawJson string) string {
|
|
if trailingComma(rawJson) {
|
|
return rawJson[:len(rawJson)-1]
|
|
}
|
|
return rawJson
|
|
}
|
|
func trailingComma(value string) bool {
|
|
return strings.HasSuffix(value, ",")
|
|
}
|
|
|
|
func isGoTestLogOutput(line string) bool {
|
|
return strings.Count(line, ":") == 2
|
|
}
|
|
|
|
func isPanic(line string) bool {
|
|
return strings.HasPrefix(line, "panic: ")
|
|
}
|
|
|
|
func panicLineHasMetadata(line string) bool {
|
|
return strings.HasPrefix(line, "goroutine") && strings.Contains(line, "[running]")
|
|
}
|
|
func panicLineShouldBeIndented(index int, line string) bool {
|
|
return strings.Contains(line, "+") || (index > 0 && strings.Contains(line, "panic: "))
|
|
}
|
|
|
|
const bugReportRequest = `
|
|
Uh-oh! Looks like something went wrong. Please copy the following text and file a bug report at:
|
|
|
|
https://github.com/smartystreets/goconvey/issues?state=open
|
|
|
|
======= BEGIN BUG REPORT =======
|
|
|
|
ERROR: %v
|
|
|
|
OUTPUT: %s
|
|
|
|
======= END BUG REPORT =======
|
|
|
|
`
|