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("", []string{}, []string{})
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 (
124			description string
125			focus, skip []string
126		)
127
128		BeforeEach(func() {
129			description = ""
130			focus = []string{}
131			skip = []string{}
132		})
133
134		JustBeforeEach(func() {
135			specs = newSpecs("A1", focusedFlag, "A2", noneFlag, "B1", focusedFlag, "B2", pendingFlag)
136			specs.ApplyFocus(description, focus, skip)
137		})
138
139		Context("with neither a focus string nor a skip string", func() {
140			It("should apply the programmatic focus", func() {
141				Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "B1"}))
142				Ω(skippedTexts(specs)).Should(Equal([]string{"A2", "B2"}))
143				Ω(pendingTexts(specs)).Should(BeEmpty())
144			})
145
146			It("should report as having programmatic specs", func() {
147				Ω(specs.HasProgrammaticFocus()).Should(BeTrue())
148			})
149		})
150
151		Context("with a focus regexp", func() {
152			BeforeEach(func() {
153				focus = []string{"A"}
154			})
155
156			It("should override the programmatic focus", func() {
157				Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "A2"}))
158				Ω(skippedTexts(specs)).Should(Equal([]string{"B1", "B2"}))
159				Ω(pendingTexts(specs)).Should(BeEmpty())
160			})
161
162			It("should not report as having programmatic specs", func() {
163				Ω(specs.HasProgrammaticFocus()).Should(BeFalse())
164			})
165		})
166
167		Context("with a focus regexp", func() {
168			BeforeEach(func() {
169				focus = []string{"B"}
170			})
171
172			It("should not override any pendings", func() {
173				Ω(willRunTexts(specs)).Should(Equal([]string{"B1"}))
174				Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2"}))
175				Ω(pendingTexts(specs)).Should(Equal([]string{"B2"}))
176			})
177		})
178
179		Context("with a description", func() {
180			BeforeEach(func() {
181				description = "C"
182				focus = []string{"C"}
183			})
184
185			It("should include the description in the focus determination", func() {
186				Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "A2", "B1"}))
187				Ω(skippedTexts(specs)).Should(BeEmpty())
188				Ω(pendingTexts(specs)).Should(Equal([]string{"B2"}))
189			})
190		})
191
192		Context("with a description", func() {
193			BeforeEach(func() {
194				description = "C"
195				skip = []string{"C"}
196			})
197
198			It("should include the description in the focus determination", func() {
199				Ω(willRunTexts(specs)).Should(BeEmpty())
200				Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2", "B1", "B2"}))
201				Ω(pendingTexts(specs)).Should(BeEmpty())
202			})
203		})
204
205		Context("with a skip regexp", func() {
206			BeforeEach(func() {
207				skip = []string{"A"}
208			})
209
210			It("should override the programmatic focus", func() {
211				Ω(willRunTexts(specs)).Should(Equal([]string{"B1"}))
212				Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2"}))
213				Ω(pendingTexts(specs)).Should(Equal([]string{"B2"}))
214			})
215
216			It("should not report as having programmatic specs", func() {
217				Ω(specs.HasProgrammaticFocus()).Should(BeFalse())
218			})
219		})
220
221		Context("with both a focus and a skip regexp", func() {
222			BeforeEach(func() {
223				focus = []string{"1"}
224				skip = []string{"B"}
225			})
226
227			It("should AND the two", func() {
228				Ω(willRunTexts(specs)).Should(Equal([]string{"A1"}))
229				Ω(skippedTexts(specs)).Should(Equal([]string{"A2", "B1", "B2"}))
230				Ω(pendingTexts(specs)).Should(BeEmpty())
231			})
232
233			It("should not report as having programmatic specs", func() {
234				Ω(specs.HasProgrammaticFocus()).Should(BeFalse())
235			})
236		})
237	})
238
239	Describe("With a focused spec within a pending context and a pending spec within a focused context", func() {
240		BeforeEach(func() {
241			pendingInFocused := New(
242				leafnodes.NewItNode("PendingInFocused", func() {}, pendingFlag, codelocation.New(0), 0, nil, 0),
243				[]*containernode.ContainerNode{
244					containernode.New("", focusedFlag, codelocation.New(0)),
245				}, false)
246
247			focusedInPending := New(
248				leafnodes.NewItNode("FocusedInPending", func() {}, focusedFlag, codelocation.New(0), 0, nil, 0),
249				[]*containernode.ContainerNode{
250					containernode.New("", pendingFlag, codelocation.New(0)),
251				}, false)
252
253			specs = NewSpecs([]*Spec{
254				newSpec("A", noneFlag),
255				newSpec("B", noneFlag),
256				pendingInFocused,
257				focusedInPending,
258			})
259			specs.ApplyFocus("", []string{}, []string{})
260		})
261
262		It("should not have a programmatic focus and should run all tests", func() {
263			Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B"}))
264			Ω(skippedTexts(specs)).Should(BeEmpty())
265			Ω(pendingTexts(specs)).Should(ConsistOf(ContainSubstring("PendingInFocused"), ContainSubstring("FocusedInPending")))
266		})
267	})
268
269	Describe("skipping measurements", func() {
270		BeforeEach(func() {
271			specs = NewSpecs([]*Spec{
272				newSpec("A", noneFlag),
273				newSpec("B", noneFlag),
274				newSpec("C", pendingFlag),
275				newMeasureSpec("measurementA", noneFlag),
276				newMeasureSpec("measurementB", pendingFlag),
277			})
278		})
279
280		It("should skip measurements", func() {
281			Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B", "measurementA"}))
282			Ω(skippedTexts(specs)).Should(BeEmpty())
283			Ω(pendingTexts(specs)).Should(Equal([]string{"C", "measurementB"}))
284
285			specs.SkipMeasurements()
286
287			Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B"}))
288			Ω(skippedTexts(specs)).Should(Equal([]string{"measurementA", "measurementB"}))
289			Ω(pendingTexts(specs)).Should(Equal([]string{"C"}))
290		})
291	})
292})
293