1package spec_test
2
3import (
4	"math/rand"
5
6	. "github.com/onsi/ginkgo"
7	. "github.com/onsi/ginkgo/internal/spec"
8	. "github.com/onsi/gomega"
9
10	"github.com/onsi/ginkgo/internal/codelocation"
11	"github.com/onsi/ginkgo/internal/containernode"
12	"github.com/onsi/ginkgo/internal/leafnodes"
13	"github.com/onsi/ginkgo/types"
14)
15
16var _ = Describe("Specs", func() {
17	var specs *Specs
18
19	newSpec := func(text string, flag types.FlagType) *Spec {
20		subject := leafnodes.NewItNode(text, func() {}, flag, codelocation.New(0), 0, nil, 0)
21		return New(subject, []*containernode.ContainerNode{}, false)
22	}
23
24	newMeasureSpec := func(text string, flag types.FlagType) *Spec {
25		subject := leafnodes.NewMeasureNode(text, func(Benchmarker) {}, flag, codelocation.New(0), 0, nil, 0)
26		return New(subject, []*containernode.ContainerNode{}, false)
27	}
28
29	newSpecs := func(args ...interface{}) *Specs {
30		specs := []*Spec{}
31		for index := 0; index < len(args)-1; index += 2 {
32			specs = append(specs, newSpec(args[index].(string), args[index+1].(types.FlagType)))
33		}
34		return NewSpecs(specs)
35	}
36
37	specTexts := func(specs *Specs) []string {
38		texts := []string{}
39		for _, spec := range specs.Specs() {
40			texts = append(texts, spec.ConcatenatedString())
41		}
42		return texts
43	}
44
45	willRunTexts := func(specs *Specs) []string {
46		texts := []string{}
47		for _, spec := range specs.Specs() {
48			if !(spec.Skipped() || spec.Pending()) {
49				texts = append(texts, spec.ConcatenatedString())
50			}
51		}
52		return texts
53	}
54
55	skippedTexts := func(specs *Specs) []string {
56		texts := []string{}
57		for _, spec := range specs.Specs() {
58			if spec.Skipped() {
59				texts = append(texts, spec.ConcatenatedString())
60			}
61		}
62		return texts
63	}
64
65	pendingTexts := func(specs *Specs) []string {
66		texts := []string{}
67		for _, spec := range specs.Specs() {
68			if spec.Pending() {
69				texts = append(texts, spec.ConcatenatedString())
70			}
71		}
72		return texts
73	}
74
75	Describe("Shuffling specs", func() {
76		It("should shuffle the specs using the passed in randomizer", func() {
77			specs17 := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag)
78			specs17.Shuffle(rand.New(rand.NewSource(17)))
79			texts17 := specTexts(specs17)
80
81			specs17Again := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag)
82			specs17Again.Shuffle(rand.New(rand.NewSource(17)))
83			texts17Again := specTexts(specs17Again)
84
85			specs15 := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag)
86			specs15.Shuffle(rand.New(rand.NewSource(15)))
87			texts15 := specTexts(specs15)
88
89			specsUnshuffled := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag)
90			textsUnshuffled := specTexts(specsUnshuffled)
91
92			Ω(textsUnshuffled).Should(Equal([]string{"C", "A", "B"}))
93
94			Ω(texts17).Should(Equal(texts17Again))
95			Ω(texts17).ShouldNot(Equal(texts15))
96			Ω(texts17).ShouldNot(Equal(textsUnshuffled))
97			Ω(texts15).ShouldNot(Equal(textsUnshuffled))
98
99			Ω(texts17).Should(HaveLen(3))
100			Ω(texts17).Should(ContainElement("A"))
101			Ω(texts17).Should(ContainElement("B"))
102			Ω(texts17).Should(ContainElement("C"))
103
104			Ω(texts15).Should(HaveLen(3))
105			Ω(texts15).Should(ContainElement("A"))
106			Ω(texts15).Should(ContainElement("B"))
107			Ω(texts15).Should(ContainElement("C"))
108		})
109	})
110
111	Describe("with no programmatic focus", func() {
112		BeforeEach(func() {
113			specs = newSpecs("A1", noneFlag, "A2", noneFlag, "B1", noneFlag, "B2", pendingFlag)
114			specs.ApplyFocus("", "", "")
115		})
116
117		It("should not report as having programmatic specs", func() {
118			Ω(specs.HasProgrammaticFocus()).Should(BeFalse())
119		})
120	})
121
122	Describe("Applying focus/skip", func() {
123		var description, focusString, skipString string
124
125		BeforeEach(func() {
126			description, focusString, skipString = "", "", ""
127		})
128
129		JustBeforeEach(func() {
130			specs = newSpecs("A1", focusedFlag, "A2", noneFlag, "B1", focusedFlag, "B2", pendingFlag)
131			specs.ApplyFocus(description, focusString, skipString)
132		})
133
134		Context("with neither a focus string nor a skip string", func() {
135			It("should apply the programmatic focus", func() {
136				Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "B1"}))
137				Ω(skippedTexts(specs)).Should(Equal([]string{"A2", "B2"}))
138				Ω(pendingTexts(specs)).Should(BeEmpty())
139			})
140
141			It("should report as having programmatic specs", func() {
142				Ω(specs.HasProgrammaticFocus()).Should(BeTrue())
143			})
144		})
145
146		Context("with a focus regexp", func() {
147			BeforeEach(func() {
148				focusString = "A"
149			})
150
151			It("should override the programmatic focus", func() {
152				Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "A2"}))
153				Ω(skippedTexts(specs)).Should(Equal([]string{"B1", "B2"}))
154				Ω(pendingTexts(specs)).Should(BeEmpty())
155			})
156
157			It("should not report as having programmatic specs", func() {
158				Ω(specs.HasProgrammaticFocus()).Should(BeFalse())
159			})
160		})
161
162		Context("with a focus regexp", func() {
163			BeforeEach(func() {
164				focusString = "B"
165			})
166
167			It("should not override any pendings", func() {
168				Ω(willRunTexts(specs)).Should(Equal([]string{"B1"}))
169				Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2"}))
170				Ω(pendingTexts(specs)).Should(Equal([]string{"B2"}))
171			})
172		})
173
174		Context("with a description", func() {
175			BeforeEach(func() {
176				description = "C"
177				focusString = "C"
178			})
179
180			It("should include the description in the focus determination", func() {
181				Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "A2", "B1"}))
182				Ω(skippedTexts(specs)).Should(BeEmpty())
183				Ω(pendingTexts(specs)).Should(Equal([]string{"B2"}))
184			})
185		})
186
187		Context("with a description", func() {
188			BeforeEach(func() {
189				description = "C"
190				skipString = "C"
191			})
192
193			It("should include the description in the focus determination", func() {
194				Ω(willRunTexts(specs)).Should(BeEmpty())
195				Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2", "B1", "B2"}))
196				Ω(pendingTexts(specs)).Should(BeEmpty())
197			})
198		})
199
200		Context("with a skip regexp", func() {
201			BeforeEach(func() {
202				skipString = "A"
203			})
204
205			It("should override the programmatic focus", func() {
206				Ω(willRunTexts(specs)).Should(Equal([]string{"B1"}))
207				Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2"}))
208				Ω(pendingTexts(specs)).Should(Equal([]string{"B2"}))
209			})
210
211			It("should not report as having programmatic specs", func() {
212				Ω(specs.HasProgrammaticFocus()).Should(BeFalse())
213			})
214		})
215
216		Context("with both a focus and a skip regexp", func() {
217			BeforeEach(func() {
218				focusString = "1"
219				skipString = "B"
220			})
221
222			It("should AND the two", func() {
223				Ω(willRunTexts(specs)).Should(Equal([]string{"A1"}))
224				Ω(skippedTexts(specs)).Should(Equal([]string{"A2", "B1", "B2"}))
225				Ω(pendingTexts(specs)).Should(BeEmpty())
226			})
227
228			It("should not report as having programmatic specs", func() {
229				Ω(specs.HasProgrammaticFocus()).Should(BeFalse())
230			})
231		})
232	})
233
234	Describe("With a focused spec within a pending context and a pending spec within a focused context", func() {
235		BeforeEach(func() {
236			pendingInFocused := New(
237				leafnodes.NewItNode("PendingInFocused", func() {}, pendingFlag, codelocation.New(0), 0, nil, 0),
238				[]*containernode.ContainerNode{
239					containernode.New("", focusedFlag, codelocation.New(0)),
240				}, false)
241
242			focusedInPending := New(
243				leafnodes.NewItNode("FocusedInPending", func() {}, focusedFlag, codelocation.New(0), 0, nil, 0),
244				[]*containernode.ContainerNode{
245					containernode.New("", pendingFlag, codelocation.New(0)),
246				}, false)
247
248			specs = NewSpecs([]*Spec{
249				newSpec("A", noneFlag),
250				newSpec("B", noneFlag),
251				pendingInFocused,
252				focusedInPending,
253			})
254			specs.ApplyFocus("", "", "")
255		})
256
257		It("should not have a programmatic focus and should run all tests", func() {
258			Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B"}))
259			Ω(skippedTexts(specs)).Should(BeEmpty())
260			Ω(pendingTexts(specs)).Should(ConsistOf(ContainSubstring("PendingInFocused"), ContainSubstring("FocusedInPending")))
261		})
262	})
263
264	Describe("skipping measurements", func() {
265		BeforeEach(func() {
266			specs = NewSpecs([]*Spec{
267				newSpec("A", noneFlag),
268				newSpec("B", noneFlag),
269				newSpec("C", pendingFlag),
270				newMeasureSpec("measurementA", noneFlag),
271				newMeasureSpec("measurementB", pendingFlag),
272			})
273		})
274
275		It("should skip measurements", func() {
276			Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B", "measurementA"}))
277			Ω(skippedTexts(specs)).Should(BeEmpty())
278			Ω(pendingTexts(specs)).Should(Equal([]string{"C", "measurementB"}))
279
280			specs.SkipMeasurements()
281
282			Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B"}))
283			Ω(skippedTexts(specs)).Should(Equal([]string{"measurementA", "measurementB"}))
284			Ω(pendingTexts(specs)).Should(Equal([]string{"C"}))
285		})
286	})
287})
288