arnaucube
arnaucube/mirror-to-giteaPublic Self-hosted repository
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}