summaryrefslogtreecommitdiff
path: root/vendor/github.com/onsi/ginkgo/ginkgo/main.go
blob: 0741ba8c993d6c105d6db7b519851ed975d04723 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/*
The Ginkgo CLI

The Ginkgo CLI is fully documented [here](http://onsi.github.io/ginkgo/#the_ginkgo_cli)

You can also learn more by running:

	ginkgo help

Here are some of the more commonly used commands:

To install:

	go install github.com/onsi/ginkgo/ginkgo

To run tests:

	ginkgo

To run tests in all subdirectories:

	ginkgo -r

To run tests in particular packages:

	ginkgo <flags> /path/to/package /path/to/another/package

To pass arguments/flags to your tests:

	ginkgo <flags> <packages> -- <pass-throughs>

To run tests in parallel

	ginkgo -p

this will automatically detect the optimal number of nodes to use.  Alternatively, you can specify the number of nodes with:

	ginkgo -nodes=N

(note that you don't need to provide -p in this case).

By default the Ginkgo CLI will spin up a server that the individual test processes send test output to.  The CLI aggregates this output and then presents coherent test output, one test at a time, as each test completes.
An alternative is to have the parallel nodes run and stream interleaved output back.  This useful for debugging, particularly in contexts where tests hang/fail to start.  To get this interleaved output:

	ginkgo -nodes=N -stream=true

On windows, the default value for stream is true.

By default, when running multiple tests (with -r or a list of packages) Ginkgo will abort when a test fails.  To have Ginkgo run subsequent test suites instead you can:

	ginkgo -keepGoing

To fail if there are ginkgo tests in a directory but no test suite (missing `RunSpecs`)

	ginkgo -requireSuite

To monitor packages and rerun tests when changes occur:

	ginkgo watch <-r> </path/to/package>

passing `ginkgo watch` the `-r` flag will recursively detect all test suites under the current directory and monitor them.
`watch` does not detect *new* packages. Moreover, changes in package X only rerun the tests for package X, tests for packages
that depend on X are not rerun.

[OSX & Linux only] To receive (desktop) notifications when a test run completes:

	ginkgo -notify

this is particularly useful with `ginkgo watch`.  Notifications are currently only supported on OS X and require that you `brew install terminal-notifier`

Sometimes (to suss out race conditions/flakey tests, for example) you want to keep running a test suite until it fails.  You can do this with:

	ginkgo -untilItFails

To bootstrap a test suite:

	ginkgo bootstrap

To generate a test file:

	ginkgo generate <test_file_name>

To bootstrap/generate test files without using "." imports:

	ginkgo bootstrap --nodot
	ginkgo generate --nodot

this will explicitly export all the identifiers in Ginkgo and Gomega allowing you to rename them to avoid collisions.  When you pull to the latest Ginkgo/Gomega you'll want to run

	ginkgo nodot

to refresh this list and pull in any new identifiers.  In particular, this will pull in any new Gomega matchers that get added.

To convert an existing XUnit style test suite to a Ginkgo-style test suite:

	ginkgo convert .

To unfocus tests:

	ginkgo unfocus

or

	ginkgo blur

To compile a test suite:

	ginkgo build <path-to-package>

will output an executable file named `package.test`.  This can be run directly or by invoking

	ginkgo <path-to-package.test>

To print out Ginkgo's version:

	ginkgo version

To get more help:

	ginkgo help
*/
package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/onsi/ginkgo/config"
	"github.com/onsi/ginkgo/ginkgo/testsuite"
)

const greenColor = "\x1b[32m"
const redColor = "\x1b[91m"
const defaultStyle = "\x1b[0m"
const lightGrayColor = "\x1b[37m"

type Command struct {
	Name                      string
	AltName                   string
	FlagSet                   *flag.FlagSet
	Usage                     []string
	UsageCommand              string
	Command                   func(args []string, additionalArgs []string)
	SuppressFlagDocumentation bool
	FlagDocSubstitute         []string
}

func (c *Command) Matches(name string) bool {
	return c.Name == name || (c.AltName != "" && c.AltName == name)
}

func (c *Command) Run(args []string, additionalArgs []string) {
	c.FlagSet.Usage = usage
	c.FlagSet.Parse(args)
	c.Command(c.FlagSet.Args(), additionalArgs)
}

var DefaultCommand *Command
var Commands []*Command

func init() {
	DefaultCommand = BuildRunCommand()
	Commands = append(Commands, BuildWatchCommand())
	Commands = append(Commands, BuildBuildCommand())
	Commands = append(Commands, BuildBootstrapCommand())
	Commands = append(Commands, BuildGenerateCommand())
	Commands = append(Commands, BuildNodotCommand())
	Commands = append(Commands, BuildConvertCommand())
	Commands = append(Commands, BuildUnfocusCommand())
	Commands = append(Commands, BuildVersionCommand())
	Commands = append(Commands, BuildHelpCommand())
}

func main() {
	args := []string{}
	additionalArgs := []string{}

	foundDelimiter := false

	for _, arg := range os.Args[1:] {
		if !foundDelimiter {
			if arg == "--" {
				foundDelimiter = true
				continue
			}
		}

		if foundDelimiter {
			additionalArgs = append(additionalArgs, arg)
		} else {
			args = append(args, arg)
		}
	}

	if len(args) > 0 {
		commandToRun, found := commandMatching(args[0])
		if found {
			commandToRun.Run(args[1:], additionalArgs)
			return
		}
	}

	DefaultCommand.Run(args, additionalArgs)
}

func commandMatching(name string) (*Command, bool) {
	for _, command := range Commands {
		if command.Matches(name) {
			return command, true
		}
	}
	return nil, false
}

func usage() {
	fmt.Printf("Ginkgo Version %s\n\n", config.VERSION)
	usageForCommand(DefaultCommand, false)
	for _, command := range Commands {
		fmt.Printf("\n")
		usageForCommand(command, false)
	}
}

func usageForCommand(command *Command, longForm bool) {
	fmt.Printf("%s\n%s\n", command.UsageCommand, strings.Repeat("-", len(command.UsageCommand)))
	fmt.Printf("%s\n", strings.Join(command.Usage, "\n"))
	if command.SuppressFlagDocumentation && !longForm {
		fmt.Printf("%s\n", strings.Join(command.FlagDocSubstitute, "\n  "))
	} else {
		command.FlagSet.SetOutput(os.Stdout)
		command.FlagSet.PrintDefaults()
	}
}

func complainAndQuit(complaint string) {
	fmt.Fprintf(os.Stderr, "%s\nFor usage instructions:\n\tginkgo help\n", complaint)
	os.Exit(1)
}

func findSuites(args []string, recurseForAll bool, skipPackage string, allowPrecompiled bool) ([]testsuite.TestSuite, []string) {
	suites := []testsuite.TestSuite{}

	if len(args) > 0 {
		for _, arg := range args {
			if allowPrecompiled {
				suite, err := testsuite.PrecompiledTestSuite(arg)
				if err == nil {
					suites = append(suites, suite)
					continue
				}
			}
			recurseForSuite := recurseForAll
			if strings.HasSuffix(arg, "/...") && arg != "/..." {
				arg = arg[:len(arg)-4]
				recurseForSuite = true
			}
			suites = append(suites, testsuite.SuitesInDir(arg, recurseForSuite)...)
		}
	} else {
		suites = testsuite.SuitesInDir(".", recurseForAll)
	}

	skippedPackages := []string{}
	if skipPackage != "" {
		skipFilters := strings.Split(skipPackage, ",")
		filteredSuites := []testsuite.TestSuite{}
		for _, suite := range suites {
			skip := false
			for _, skipFilter := range skipFilters {
				if strings.Contains(suite.Path, skipFilter) {
					skip = true
					break
				}
			}
			if skip {
				skippedPackages = append(skippedPackages, suite.Path)
			} else {
				filteredSuites = append(filteredSuites, suite)
			}
		}
		suites = filteredSuites
	}

	return suites, skippedPackages
}

func goFmt(path string) {
	err := exec.Command("go", "fmt", path).Run()
	if err != nil {
		complainAndQuit("Could not fmt: " + err.Error())
	}
}

func pluralizedWord(singular, plural string, count int) string {
	if count == 1 {
		return singular
	}
	return plural
}