1// TODO: under unit test
2
3package reporting
4
5import (
6	"bytes"
7	"encoding/json"
8	"fmt"
9	"strings"
10)
11
12type JsonReporter struct {
13	out        *Printer
14	currentKey []string
15	current    *ScopeResult
16	index      map[string]*ScopeResult
17	scopes     []*ScopeResult
18}
19
20func (self *JsonReporter) depth() int { return len(self.currentKey) }
21
22func (self *JsonReporter) BeginStory(story *StoryReport) {}
23
24func (self *JsonReporter) Enter(scope *ScopeReport) {
25	self.currentKey = append(self.currentKey, scope.Title)
26	ID := strings.Join(self.currentKey, "|")
27	if _, found := self.index[ID]; !found {
28		next := newScopeResult(scope.Title, self.depth(), scope.File, scope.Line)
29		self.scopes = append(self.scopes, next)
30		self.index[ID] = next
31	}
32	self.current = self.index[ID]
33}
34
35func (self *JsonReporter) Report(report *AssertionResult) {
36	self.current.Assertions = append(self.current.Assertions, report)
37}
38
39func (self *JsonReporter) Exit() {
40	self.currentKey = self.currentKey[:len(self.currentKey)-1]
41}
42
43func (self *JsonReporter) EndStory() {
44	self.report()
45	self.reset()
46}
47func (self *JsonReporter) report() {
48	scopes := []string{}
49	for _, scope := range self.scopes {
50		serialized, err := json.Marshal(scope)
51		if err != nil {
52			self.out.Println(jsonMarshalFailure)
53			panic(err)
54		}
55		var buffer bytes.Buffer
56		json.Indent(&buffer, serialized, "", "  ")
57		scopes = append(scopes, buffer.String())
58	}
59	self.out.Print(fmt.Sprintf("%s\n%s,\n%s\n", OpenJson, strings.Join(scopes, ","), CloseJson))
60}
61func (self *JsonReporter) reset() {
62	self.scopes = []*ScopeResult{}
63	self.index = map[string]*ScopeResult{}
64	self.currentKey = nil
65}
66
67func (self *JsonReporter) Write(content []byte) (written int, err error) {
68	self.current.Output += string(content)
69	return len(content), nil
70}
71
72func NewJsonReporter(out *Printer) *JsonReporter {
73	self := new(JsonReporter)
74	self.out = out
75	self.reset()
76	return self
77}
78
79const OpenJson = ">->->OPEN-JSON->->->"   // "⌦"
80const CloseJson = "<-<-<-CLOSE-JSON<-<-<" // "⌫"
81const jsonMarshalFailure = `
82
83GOCONVEY_JSON_MARSHALL_FAILURE: There was an error when attempting to convert test results to JSON.
84Please file a bug report and reference the code that caused this failure if possible.
85
86Here's the panic:
87
88`
89