mirror-to-gitea/vendor/github.com/onsi/ginkgo/internal/spec/spec.go
vendor/github.com/onsi/ginkgo/internal/spec/spec.goRaw
1package spec
2
3import (
4 "fmt"
5 "io"
6 "time"
7
8 "sync"
9
10 "github.com/onsi/ginkgo/internal/containernode"
11 "github.com/onsi/ginkgo/internal/leafnodes"
12 "github.com/onsi/ginkgo/types"
13)
14
15type Spec struct {
16 subject leafnodes.SubjectNode
17 focused bool
18 announceProgress bool
19
20 containers []*containernode.ContainerNode
21
22 state types.SpecState
23 runTime time.Duration
24 startTime time.Time
25 failure types.SpecFailure
26 previousFailures bool
27
28 stateMutex *sync.Mutex
29}
30
31func New(subject leafnodes.SubjectNode, containers []*containernode.ContainerNode, announceProgress bool) *Spec {
32 spec := &Spec{
33 subject: subject,
34 containers: containers,
35 focused: subject.Flag() == types.FlagTypeFocused,
36 announceProgress: announceProgress,
37 stateMutex: &sync.Mutex{},
38 }
39
40 spec.processFlag(subject.Flag())
41 for i := len(containers) - 1; i >= 0; i-- {
42 spec.processFlag(containers[i].Flag())
43 }
44
45 return spec
46}
47
48func (spec *Spec) processFlag(flag types.FlagType) {
49 if flag == types.FlagTypeFocused {
50 spec.focused = true
51 } else if flag == types.FlagTypePending {
52 spec.setState(types.SpecStatePending)
53 }
54}
55
56func (spec *Spec) Skip() {
57 spec.setState(types.SpecStateSkipped)
58}
59
60func (spec *Spec) Failed() bool {
61 return spec.getState() == types.SpecStateFailed || spec.getState() == types.SpecStatePanicked || spec.getState() == types.SpecStateTimedOut
62}
63
64func (spec *Spec) Passed() bool {
65 return spec.getState() == types.SpecStatePassed
66}
67
68func (spec *Spec) Flaked() bool {
69 return spec.getState() == types.SpecStatePassed && spec.previousFailures
70}
71
72func (spec *Spec) Pending() bool {
73 return spec.getState() == types.SpecStatePending
74}
75
76func (spec *Spec) Skipped() bool {
77 return spec.getState() == types.SpecStateSkipped
78}
79
80func (spec *Spec) Focused() bool {
81 return spec.focused
82}
83
84func (spec *Spec) IsMeasurement() bool {
85 return spec.subject.Type() == types.SpecComponentTypeMeasure
86}
87
88func (spec *Spec) Summary(suiteID string) *types.SpecSummary {
89 componentTexts := make([]string, len(spec.containers)+1)
90 componentCodeLocations := make([]types.CodeLocation, len(spec.containers)+1)
91
92 for i, container := range spec.containers {
93 componentTexts[i] = container.Text()
94 componentCodeLocations[i] = container.CodeLocation()
95 }
96
97 componentTexts[len(spec.containers)] = spec.subject.Text()
98 componentCodeLocations[len(spec.containers)] = spec.subject.CodeLocation()
99
100 runTime := spec.runTime
101 if runTime == 0 && !spec.startTime.IsZero() {
102 runTime = time.Since(spec.startTime)
103 }
104
105 return &types.SpecSummary{
106 IsMeasurement: spec.IsMeasurement(),
107 NumberOfSamples: spec.subject.Samples(),
108 ComponentTexts: componentTexts,
109 ComponentCodeLocations: componentCodeLocations,
110 State: spec.getState(),
111 RunTime: runTime,
112 Failure: spec.failure,
113 Measurements: spec.measurementsReport(),
114 SuiteID: suiteID,
115 }
116}
117
118func (spec *Spec) ConcatenatedString() string {
119 s := ""
120 for _, container := range spec.containers {
121 s += container.Text() + " "
122 }
123
124 return s + spec.subject.Text()
125}
126
127func (spec *Spec) Run(writer io.Writer) {
128 if spec.getState() == types.SpecStateFailed {
129 spec.previousFailures = true
130 }
131
132 spec.startTime = time.Now()
133 defer func() {
134 spec.runTime = time.Since(spec.startTime)
135 }()
136
137 for sample := 0; sample < spec.subject.Samples(); sample++ {
138 spec.runSample(sample, writer)
139
140 if spec.getState() != types.SpecStatePassed {
141 return
142 }
143 }
144}
145
146func (spec *Spec) getState() types.SpecState {
147 spec.stateMutex.Lock()
148 defer spec.stateMutex.Unlock()
149 return spec.state
150}
151
152func (spec *Spec) setState(state types.SpecState) {
153 spec.stateMutex.Lock()
154 defer spec.stateMutex.Unlock()
155 spec.state = state
156}
157
158func (spec *Spec) runSample(sample int, writer io.Writer) {
159 spec.setState(types.SpecStatePassed)
160 spec.failure = types.SpecFailure{}
161 innerMostContainerIndexToUnwind := -1
162
163 defer func() {
164 for i := innerMostContainerIndexToUnwind; i >= 0; i-- {
165 container := spec.containers[i]
166 for _, justAfterEach := range container.SetupNodesOfType(types.SpecComponentTypeJustAfterEach) {
167 spec.announceSetupNode(writer, "JustAfterEach", container, justAfterEach)
168 justAfterEachState, justAfterEachFailure := justAfterEach.Run()
169 if justAfterEachState != types.SpecStatePassed && spec.state == types.SpecStatePassed {
170 spec.state = justAfterEachState
171 spec.failure = justAfterEachFailure
172 }
173 }
174 }
175
176 for i := innerMostContainerIndexToUnwind; i >= 0; i-- {
177 container := spec.containers[i]
178 for _, afterEach := range container.SetupNodesOfType(types.SpecComponentTypeAfterEach) {
179 spec.announceSetupNode(writer, "AfterEach", container, afterEach)
180 afterEachState, afterEachFailure := afterEach.Run()
181 if afterEachState != types.SpecStatePassed && spec.getState() == types.SpecStatePassed {
182 spec.setState(afterEachState)
183 spec.failure = afterEachFailure
184 }
185 }
186 }
187 }()
188
189 for i, container := range spec.containers {
190 innerMostContainerIndexToUnwind = i
191 for _, beforeEach := range container.SetupNodesOfType(types.SpecComponentTypeBeforeEach) {
192 spec.announceSetupNode(writer, "BeforeEach", container, beforeEach)
193 s, f := beforeEach.Run()
194 spec.failure = f
195 spec.setState(s)
196 if spec.getState() != types.SpecStatePassed {
197 return
198 }
199 }
200 }
201
202 for _, container := range spec.containers {
203 for _, justBeforeEach := range container.SetupNodesOfType(types.SpecComponentTypeJustBeforeEach) {
204 spec.announceSetupNode(writer, "JustBeforeEach", container, justBeforeEach)
205 s, f := justBeforeEach.Run()
206 spec.failure = f
207 spec.setState(s)
208 if spec.getState() != types.SpecStatePassed {
209 return
210 }
211 }
212 }
213
214 spec.announceSubject(writer, spec.subject)
215 s, f := spec.subject.Run()
216 spec.failure = f
217 spec.setState(s)
218}
219
220func (spec *Spec) announceSetupNode(writer io.Writer, nodeType string, container *containernode.ContainerNode, setupNode leafnodes.BasicNode) {
221 if spec.announceProgress {
222 s := fmt.Sprintf("[%s] %s\n %s\n", nodeType, container.Text(), setupNode.CodeLocation().String())
223 writer.Write([]byte(s))
224 }
225}
226
227func (spec *Spec) announceSubject(writer io.Writer, subject leafnodes.SubjectNode) {
228 if spec.announceProgress {
229 nodeType := ""
230 switch subject.Type() {
231 case types.SpecComponentTypeIt:
232 nodeType = "It"
233 case types.SpecComponentTypeMeasure:
234 nodeType = "Measure"
235 }
236 s := fmt.Sprintf("[%s] %s\n %s\n", nodeType, subject.Text(), subject.CodeLocation().String())
237 writer.Write([]byte(s))
238 }
239}
240
241func (spec *Spec) measurementsReport() map[string]*types.SpecMeasurement {
242 if !spec.IsMeasurement() || spec.Failed() {
243 return map[string]*types.SpecMeasurement{}
244 }
245
246 return spec.subject.(*leafnodes.MeasureNode).MeasurementsReport()
247}