Skip to content

Commit

Permalink
- Moved outputWriter to reporter.go
Browse files Browse the repository at this point in the history
- outputWriter is now interface
- Old outputWriter implementation is now plainWriter
- Added some basic functionality to xunitWriter
  • Loading branch information
Ivan Kirichenko committed Dec 29, 2014
1 parent 6413154 commit 45ed7de
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 84 deletions.
87 changes: 3 additions & 84 deletions check.go
Expand Up @@ -509,7 +509,7 @@ type suiteRunner struct {
tracker *resultTracker
tempDir *tempDir
keepDir bool
output *outputWriter
output outputWriter
reportedProblemLast bool
benchTime time.Duration
benchMem bool
Expand Down Expand Up @@ -545,7 +545,7 @@ func newSuiteRunner(suite interface{}, runConf *RunConf) *suiteRunner {

runner := &suiteRunner{
suite: suite,
output: newOutputWriter(conf.Output, conf.Stream, conf.Verbose),
output: newPlainWriter(conf.Output, conf.Stream, conf.Verbose),
tracker: newResultTracker(),
benchTime: conf.BenchmarkTime,
benchMem: conf.BenchmarkMem,
Expand Down Expand Up @@ -632,7 +632,7 @@ func (runner *suiteRunner) run() *Result {
// goroutine with the provided dispatcher for running it.
func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C {
var logw io.Writer
if runner.output.Stream {
if runner.output.StreamEnabled() {
logw = runner.output
}
if logb == nil {
Expand Down Expand Up @@ -862,84 +862,3 @@ func (runner *suiteRunner) reportCallDone(c *C) {
runner.output.WriteCallSuccess("MISS", c)
}
}

// -----------------------------------------------------------------------
// Output writer manages atomic output writing according to settings.

type outputWriter struct {
m sync.Mutex
writer io.Writer
wroteCallProblemLast bool
Stream bool
Verbose bool
}

func newOutputWriter(writer io.Writer, stream, verbose bool) *outputWriter {
return &outputWriter{writer: writer, Stream: stream, Verbose: verbose}
}

func (ow *outputWriter) Write(content []byte) (n int, err error) {
ow.m.Lock()
n, err = ow.writer.Write(content)
ow.m.Unlock()
return
}

func (ow *outputWriter) WriteCallStarted(label string, c *C) {
if ow.Stream {
header := renderCallHeader(label, c, "", "\n")
ow.m.Lock()
ow.writer.Write([]byte(header))
ow.m.Unlock()
}
}

func (ow *outputWriter) WriteCallProblem(label string, c *C) {
var prefix string
if !ow.Stream {
prefix = "\n-----------------------------------" +
"-----------------------------------\n"
}
header := renderCallHeader(label, c, prefix, "\n\n")
ow.m.Lock()
ow.wroteCallProblemLast = true
ow.writer.Write([]byte(header))
if !ow.Stream {
c.logb.WriteTo(ow.writer)
}
ow.m.Unlock()
}

func (ow *outputWriter) WriteCallSuccess(label string, c *C) {
if ow.Stream || (ow.Verbose && c.kind == testKd) {
// TODO Use a buffer here.
var suffix string
if c.reason != "" {
suffix = " (" + c.reason + ")"
}
if c.status == succeededSt {
suffix += "\t" + c.timerString()
}
suffix += "\n"
if ow.Stream {
suffix += "\n"
}
header := renderCallHeader(label, c, "", suffix)
ow.m.Lock()
// Resist temptation of using line as prefix above due to race.
if !ow.Stream && ow.wroteCallProblemLast {
header = "\n-----------------------------------" +
"-----------------------------------\n" +
header
}
ow.wroteCallProblemLast = false
ow.writer.Write([]byte(header))
ow.m.Unlock()
}
}

func renderCallHeader(label string, c *C, prefix, suffix string) string {
pc := c.method.PC()
return fmt.Sprintf("%s%s: %s: %s%s", prefix, label, niceFuncPath(pc),
niceFuncName(pc), suffix)
}
178 changes: 178 additions & 0 deletions reporter.go
@@ -0,0 +1,178 @@
package check

import (
"bytes"
"fmt"
"io"
"sync"
"time"
)

// TODO: start test suite
type outputWriter interface {
Write(content []byte) (n int, err error)
WriteCallStarted(label string, c *C)
WriteCallProblem(label string, c *C)
WriteCallSuccess(label string, c *C)
StreamEnabled() bool
}

/*************** Plain writer *****************/

type plainWriter struct {
outputWriter
m sync.Mutex
writer io.Writer
wroteCallProblemLast bool
stream bool
verbose bool
}

func newPlainWriter(writer io.Writer, stream, verbose bool) *plainWriter {
return &plainWriter{writer: writer, stream: stream, verbose: verbose}
}

func (w *plainWriter) StreamEnabled() bool { return w.stream }

func (w *plainWriter) Write(content []byte) (n int, err error) {
w.m.Lock()
n, err = w.writer.Write(content)
w.m.Unlock()
return
}

func (w *plainWriter) WriteCallStarted(label string, c *C) {
if w.stream {
header := renderCallHeader(label, c, "", "\n")
w.m.Lock()
w.writer.Write([]byte(header))
w.m.Unlock()
}
}

func (w *plainWriter) WriteCallProblem(label string, c *C) {
var prefix string
if !w.stream {
prefix = "\n-----------------------------------" +
"-----------------------------------\n"
}
header := renderCallHeader(label, c, prefix, "\n\n")
w.m.Lock()
w.wroteCallProblemLast = true
w.writer.Write([]byte(header))
if !w.stream {
c.logb.WriteTo(w.writer)
}
w.m.Unlock()
}

func (w *plainWriter) WriteCallSuccess(label string, c *C) {
if w.stream || (w.verbose && c.kind == testKd) {
// TODO Use a buffer here.
var suffix string
if c.reason != "" {
suffix = " (" + c.reason + ")"
}
if c.status == succeededSt {
suffix += "\t" + c.timerString()
}
suffix += "\n"
if w.stream {
suffix += "\n"
}
header := renderCallHeader(label, c, "", suffix)
w.m.Lock()
// Resist temptation of using line as prefix above due to race.
if !w.stream && w.wroteCallProblemLast {
header = "\n-----------------------------------" +
"-----------------------------------\n" +
header
}
w.wroteCallProblemLast = false
w.writer.Write([]byte(header))
w.m.Unlock()
}
}

func renderCallHeader(label string, c *C, prefix, suffix string) string {
pc := c.method.PC()
return fmt.Sprintf("%s%s: %s: %s%s", prefix, label, niceFuncPath(pc),
niceFuncName(pc), suffix)
}

/*************** xUnit writer *****************/
// TODO: Write mrthod can collect data for std-out
type xunitReport struct {
suites []xunitSuite `xml:"testsuites>testsuite,omitempty"`
}

type xunitSuite struct {
Package string `xml:"package,attr,omitempty"`
Name string `xml:"name,attr,omitempty"`
Classname string `xml:"classname,attr,omitempty"`
Time float64 `xml:"time,attr"`
Timestamp time.Time `xml:"timestamp,attr"`

Tests uint64 `xml:"tests,attr"`
Failures uint64 `xml:"failures,attr"`
Errors uint64 `xml:"errors,attr"`
Skipped uint64 `xml:"skipped,attr"`

Properties []xunitSuiteProperty `xml:"properties>property"` //TODO: test
Testcases []xunitTestcase `xml:"testcase"`

SystemOut string `xml:"system-out,omitempty"`
SystemErr string `xml:"system-err,omitempty"`
}

type xunitSuiteProperty struct {
Name string `xml:"name,attr"`
Value string `xml:"value,attr"`
}

type xunitTestcase struct {
Name string `xml:"name,attr,omitempty"`
Classname string `xml:"classname,attr,omitempty"`
Time float64 `xml:"time,attr"`
Failure *xunitTestcaseResult `xml:"failure,omitempty"`
Error *xunitTestcaseResult `xml:"error,omitempty"`
}

type xunitTestcaseResult struct {
Message string `xml:"message,attr,omitempty"`
Type string `xml:"type,attr,omitempty"`
Value string `xml:",chardata"`
}

type xunitWriter struct {
outputWriter
m sync.Mutex
writer io.Writer
stream bool
verbose bool

systemOut io.Writer
}

func newXunitWriter(writer io.Writer, stream, verbose bool) *plainWriter {
return &xunitWriter{
writer: writer,
systemOut: bytes.Buffer{},
stream: stream,
verbose: verbose,
}
}

func (w *xunitWriter) GetReport() string {
}

func (w *xunitWriter) Write(content []byte) (n int, err error) {
w.m.Lock()
n, err = w.systemOut.Write(content)
w.m.Unlock()
return
}
func (w *xunitWriter) WriteCallStarted(label string, c *C) {}
func (w *xunitWriter) WriteCallProblem(label string, c *C) {}
func (w *xunitWriter) WriteCallSuccess(label string, c *C) {}
func (w *xunitWriter) StreamEnabled() bool {}

0 comments on commit 45ed7de

Please sign in to comment.