Skip to content

Commit 9a782fb

Browse files
authoredJan 11, 2021
cli: allow multiple -focus and -skip flags (#736)
As an example, now instead of ... --skip one|two|three|four ... one can specify ... \ --skip one \ --skip two \ --skip three \ --skip four \ ... which helps readability and maintainability a lot in case there are many tests to skip. Fixes #735 Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
1 parent 5207632 commit 9a782fb

File tree

6 files changed

+68
-35
lines changed

6 files changed

+68
-35
lines changed
 

‎config/config.go

+23-8
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ type GinkgoConfigType struct {
2626
RandomSeed int64
2727
RandomizeAllSpecs bool
2828
RegexScansFilePath bool
29-
FocusString string
30-
SkipString string
29+
FocusStrings []string
30+
SkipStrings []string
3131
SkipMeasurements bool
3232
FailOnPending bool
3333
FailFast bool
@@ -65,6 +65,11 @@ func processPrefix(prefix string) string {
6565
return prefix
6666
}
6767

68+
type flagFunc func(string)
69+
70+
func (f flagFunc) String() string { return "" }
71+
func (f flagFunc) Set(s string) error { f(s); return nil }
72+
6873
func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) {
6974
prefix = processPrefix(prefix)
7075
flagSet.Int64Var(&(GinkgoConfig.RandomSeed), prefix+"seed", time.Now().Unix(), "The seed used to randomize the spec suite.")
@@ -75,8 +80,8 @@ func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) {
7580

7681
flagSet.BoolVar(&(GinkgoConfig.DryRun), prefix+"dryRun", false, "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v.")
7782

78-
flagSet.StringVar(&(GinkgoConfig.FocusString), prefix+"focus", "", "If set, ginkgo will only run specs that match this regular expression.")
79-
flagSet.StringVar(&(GinkgoConfig.SkipString), prefix+"skip", "", "If set, ginkgo will only run specs that do not match this regular expression.")
83+
flagSet.Var(flagFunc(flagFocus), prefix+"focus", "If set, ginkgo will only run specs that match this regular expression. Can be specified multiple times, values are ORed.")
84+
flagSet.Var(flagFunc(flagSkip), prefix+"skip", "If set, ginkgo will only run specs that do not match this regular expression. Can be specified multiple times, values are ORed.")
8085

8186
flagSet.BoolVar(&(GinkgoConfig.RegexScansFilePath), prefix+"regexScansFilePath", false, "If set, ginkgo regex matching also will look at the file path (code location).")
8287

@@ -133,12 +138,12 @@ func BuildFlagArgs(prefix string, ginkgo GinkgoConfigType, reporter DefaultRepor
133138
result = append(result, fmt.Sprintf("--%sdryRun", prefix))
134139
}
135140

136-
if ginkgo.FocusString != "" {
137-
result = append(result, fmt.Sprintf("--%sfocus=%s", prefix, ginkgo.FocusString))
141+
for _, s := range ginkgo.FocusStrings {
142+
result = append(result, fmt.Sprintf("--%sfocus=%s", prefix, s))
138143
}
139144

140-
if ginkgo.SkipString != "" {
141-
result = append(result, fmt.Sprintf("--%sskip=%s", prefix, ginkgo.SkipString))
145+
for _, s := range ginkgo.SkipStrings {
146+
result = append(result, fmt.Sprintf("--%sskip=%s", prefix, s))
142147
}
143148

144149
if ginkgo.FlakeAttempts > 1 {
@@ -211,3 +216,13 @@ func BuildFlagArgs(prefix string, ginkgo GinkgoConfigType, reporter DefaultRepor
211216

212217
return result
213218
}
219+
220+
// flagFocus implements the -focus flag.
221+
func flagFocus(arg string) {
222+
GinkgoConfig.FocusStrings = append(GinkgoConfig.FocusStrings, arg)
223+
}
224+
225+
// flagSkip implements the -skip flag.
226+
func flagSkip(arg string) {
227+
GinkgoConfig.SkipStrings = append(GinkgoConfig.SkipStrings, arg)
228+
}

‎integration/flags_test.go

+13
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ var _ = Describe("Flags Specs", func() {
105105
Ω(output).Should(ContainSubstring("3 Skipped"))
106106
})
107107

108+
It("should override the programmatic focus when told to skip (multiple options)", func() {
109+
session := startGinkgo(pathToTest, "--noColor", "--skip=marshmallow", "--skip=failing", "--skip=flaky")
110+
Eventually(session).Should(gexec.Exit(0))
111+
output := string(session.Out.Contents())
112+
113+
Ω(output).ShouldNot(ContainSubstring("marshmallow"))
114+
Ω(output).Should(ContainSubstring("chocolate"))
115+
Ω(output).Should(ContainSubstring("smores"))
116+
Ω(output).Should(ContainSubstring("11 Passed"))
117+
Ω(output).Should(ContainSubstring("0 Failed"))
118+
Ω(output).Should(ContainSubstring("1 Pending"))
119+
Ω(output).Should(ContainSubstring("3 Skipped"))
120+
})
108121
It("should run the race detector when told to", func() {
109122
if !raceDetectorSupported() {
110123
Skip("race detection is not supported")

‎internal/spec/specs.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"math/rand"
55
"regexp"
66
"sort"
7+
"strings"
78
)
89

910
type Specs struct {
@@ -46,11 +47,11 @@ func (e *Specs) Shuffle(r *rand.Rand) {
4647
e.names = names
4748
}
4849

49-
func (e *Specs) ApplyFocus(description string, focusString string, skipString string) {
50-
if focusString == "" && skipString == "" {
50+
func (e *Specs) ApplyFocus(description string, focus, skip []string) {
51+
if len(focus)+len(skip) == 0 {
5152
e.applyProgrammaticFocus()
5253
} else {
53-
e.applyRegExpFocusAndSkip(description, focusString, skipString)
54+
e.applyRegExpFocusAndSkip(description, focus, skip)
5455
}
5556
}
5657

@@ -90,14 +91,13 @@ func (e *Specs) toMatch(description string, i int) []byte {
9091
}
9192
}
9293

93-
func (e *Specs) applyRegExpFocusAndSkip(description string, focusString string, skipString string) {
94-
var focusFilter *regexp.Regexp
95-
if focusString != "" {
96-
focusFilter = regexp.MustCompile(focusString)
94+
func (e *Specs) applyRegExpFocusAndSkip(description string, focus, skip []string) {
95+
var focusFilter, skipFilter *regexp.Regexp
96+
if len(focus) > 0 {
97+
focusFilter = regexp.MustCompile(strings.Join(focus, "|"))
9798
}
98-
var skipFilter *regexp.Regexp
99-
if skipString != "" {
100-
skipFilter = regexp.MustCompile(skipString)
99+
if len(skip) > 0 {
100+
skipFilter = regexp.MustCompile(strings.Join(skip, "|"))
101101
}
102102

103103
for i, spec := range e.specs {

‎internal/spec/specs_test.go

+17-12
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ var _ = Describe("Specs", func() {
111111
Describe("with no programmatic focus", func() {
112112
BeforeEach(func() {
113113
specs = newSpecs("A1", noneFlag, "A2", noneFlag, "B1", noneFlag, "B2", pendingFlag)
114-
specs.ApplyFocus("", "", "")
114+
specs.ApplyFocus("", []string{}, []string{})
115115
})
116116

117117
It("should not report as having programmatic specs", func() {
@@ -120,15 +120,20 @@ var _ = Describe("Specs", func() {
120120
})
121121

122122
Describe("Applying focus/skip", func() {
123-
var description, focusString, skipString string
123+
var (
124+
description string
125+
focus, skip []string
126+
)
124127

125128
BeforeEach(func() {
126-
description, focusString, skipString = "", "", ""
129+
description = ""
130+
focus = []string{}
131+
skip = []string{}
127132
})
128133

129134
JustBeforeEach(func() {
130135
specs = newSpecs("A1", focusedFlag, "A2", noneFlag, "B1", focusedFlag, "B2", pendingFlag)
131-
specs.ApplyFocus(description, focusString, skipString)
136+
specs.ApplyFocus(description, focus, skip)
132137
})
133138

134139
Context("with neither a focus string nor a skip string", func() {
@@ -145,7 +150,7 @@ var _ = Describe("Specs", func() {
145150

146151
Context("with a focus regexp", func() {
147152
BeforeEach(func() {
148-
focusString = "A"
153+
focus = []string{"A"}
149154
})
150155

151156
It("should override the programmatic focus", func() {
@@ -161,7 +166,7 @@ var _ = Describe("Specs", func() {
161166

162167
Context("with a focus regexp", func() {
163168
BeforeEach(func() {
164-
focusString = "B"
169+
focus = []string{"B"}
165170
})
166171

167172
It("should not override any pendings", func() {
@@ -174,7 +179,7 @@ var _ = Describe("Specs", func() {
174179
Context("with a description", func() {
175180
BeforeEach(func() {
176181
description = "C"
177-
focusString = "C"
182+
focus = []string{"C"}
178183
})
179184

180185
It("should include the description in the focus determination", func() {
@@ -187,7 +192,7 @@ var _ = Describe("Specs", func() {
187192
Context("with a description", func() {
188193
BeforeEach(func() {
189194
description = "C"
190-
skipString = "C"
195+
skip = []string{"C"}
191196
})
192197

193198
It("should include the description in the focus determination", func() {
@@ -199,7 +204,7 @@ var _ = Describe("Specs", func() {
199204

200205
Context("with a skip regexp", func() {
201206
BeforeEach(func() {
202-
skipString = "A"
207+
skip = []string{"A"}
203208
})
204209

205210
It("should override the programmatic focus", func() {
@@ -215,8 +220,8 @@ var _ = Describe("Specs", func() {
215220

216221
Context("with both a focus and a skip regexp", func() {
217222
BeforeEach(func() {
218-
focusString = "1"
219-
skipString = "B"
223+
focus = []string{"1"}
224+
skip = []string{"B"}
220225
})
221226

222227
It("should AND the two", func() {
@@ -251,7 +256,7 @@ var _ = Describe("Specs", func() {
251256
pendingInFocused,
252257
focusedInPending,
253258
})
254-
specs.ApplyFocus("", "", "")
259+
specs.ApplyFocus("", []string{}, []string{})
255260
})
256261

257262
It("should not have a programmatic focus and should run all tests", func() {

‎internal/suite/suite.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func (suite *Suite) generateSpecsIterator(description string, config config.Gink
9797
specs.Shuffle(rand.New(rand.NewSource(config.RandomSeed)))
9898
}
9999

100-
specs.ApplyFocus(description, config.FocusString, config.SkipString)
100+
specs.ApplyFocus(description, config.FocusStrings, config.SkipStrings)
101101

102102
if config.SkipMeasurements {
103103
specs.SkipMeasurements()

‎internal/suite/suite_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ var _ = Describe("Suite", func() {
4040
runOrder []string
4141
randomizeAllSpecs bool
4242
randomSeed int64
43-
focusString string
43+
focusStrings []string
4444
parallelNode int
4545
parallelTotal int
4646
runResult bool
@@ -58,7 +58,7 @@ var _ = Describe("Suite", func() {
5858
randomSeed = 11
5959
parallelNode = 1
6060
parallelTotal = 1
61-
focusString = ""
61+
focusStrings = []string{}
6262

6363
runOrder = make([]string, 0)
6464
specSuite.SetBeforeSuiteNode(f("BeforeSuite"), codelocation.New(0), 0)
@@ -91,7 +91,7 @@ var _ = Describe("Suite", func() {
9191
runResult, hasProgrammaticFocus = specSuite.Run(fakeT, "suite description", []reporters.Reporter{fakeR}, writer, config.GinkgoConfigType{
9292
RandomSeed: randomSeed,
9393
RandomizeAllSpecs: randomizeAllSpecs,
94-
FocusString: focusString,
94+
FocusStrings: focusStrings,
9595
ParallelNode: parallelNode,
9696
ParallelTotal: parallelTotal,
9797
})
@@ -186,7 +186,7 @@ var _ = Describe("Suite", func() {
186186

187187
Context("when provided with a filter", func() {
188188
BeforeEach(func() {
189-
focusString = `inner|\d`
189+
focusStrings = []string{`inner`, `\d`}
190190
})
191191

192192
It("converts the filter to a regular expression and uses it to filter the running specs", func() {

0 commit comments

Comments
 (0)
Please sign in to comment.