pax_global_header00006660000000000000000000000064137411145730014520gustar00rootroot0000000000000052 comment=55c858784e51c26077949c81b6defb6b97b76944 ginkgo-1.14.2/000077500000000000000000000000001374111457300130635ustar00rootroot00000000000000ginkgo-1.14.2/.gitignore000066400000000000000000000000741374111457300150540ustar00rootroot00000000000000.DS_Store TODO tmp/**/* *.coverprofile .vscode .idea/ *.log ginkgo-1.14.2/.travis.yml000066400000000000000000000012531374111457300151750ustar00rootroot00000000000000language: go go: - 1.13.x - 1.14.x - tip cache: directories: - $GOPATH/pkg/mod # allow internal package imports, necessary for forked repositories go_import_path: github.com/onsi/ginkgo install: - GO111MODULE="off" go get -v -t ./... - GO111MODULE="off" go get golang.org/x/tools/cmd/cover - GO111MODULE="off" go get github.com/onsi/gomega - GO111MODULE="off" go install github.com/onsi/ginkgo/ginkgo - export PATH=$PATH:$HOME/gopath/bin script: - GO111MODULE="on" go mod tidy - diff -u <(echo -n) <(git diff go.mod) - diff -u <(echo -n) <(git diff go.sum) - $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --randomizeSuites --race --trace && go vet ginkgo-1.14.2/CHANGELOG.md000066400000000000000000000362301374111457300147000ustar00rootroot00000000000000## 1.14.2 ### Fixes - correct handling windows backslash in import path (#721) [97f3d51] - Add additional methods to GinkgoT() to improve compatibility with the testing.TB interface [b5fe44d] ## 1.14.1 ### Fixes - Discard exported method declaration when running ginkgo bootstrap (#558) [f4b0240] ## 1.14.0 ### Features - Defer running top-level container nodes until RunSpecs is called [d44dedf] - [Document Ginkgo lifecycle](http://onsi.github.io/ginkgo/#understanding-ginkgos-lifecycle) - Add `extensions/globals` package (#692) [3295c8f] - this can be helpful in contexts where you are test-driving your test-generation code (see [#692](https://github.com/onsi/ginkgo/pull/692)) - Print Skip reason in JUnit reporter if one was provided [820dfab] ## 1.13.0 ### Features - Add a version of table.Entry that allows dumping the entry parameters. (#689) [21eaef2] ### Fixes - Ensure integration tests pass in an environment sans GOPATH [606fba2] - Add books package (#568) [fc0e44e] - doc(readme): installation via "tools package" (#677) [83bb20e] - Solve the undefined: unix.Dup2 compile error on mips64le (#680) [0624f75] - Import package without dot (#687) [6321024] - Fix integration tests to stop require GOPATH (#686) [a912ec5] ## 1.12.3 ### Fixes - Print correct code location of failing table test (#666) [c6d7afb] ## 1.12.2 ### Fixes - Update dependencies [ea4a036] ## 1.12.1 ### Fixes - Make unfocus ("blur") much faster (#674) [8b18061] - Fix typo (#673) [7fdcbe8] - Test against 1.14 and remove 1.12 [d5c2ad6] - Test if a coverprofile content is empty before checking its latest character (#670) [14d9fa2] - replace tail package with maintained one. this fixes go get errors (#667) [4ba33d4] - improve ginkgo performance - makes progress on #644 [a14f98e] - fix convert integration tests [1f8ba69] - fix typo succesful -> successful (#663) [1ea49cf] - Fix invalid link (#658) [b886136] - convert utility : Include comments from source (#657) [1077c6d] - Explain what BDD means [d79e7fb] - skip race detector test on unsupported platform (#642) [f8ab89d] - Use Dup2 from golang.org/x/sys/unix instead of syscallDup (#638) [5d53c55] - Fix missing newline in combined coverage file (#641) [6a07ea2] - check if a spec is run before returning SpecSummary (#645) [8850000] ## 1.12.0 ### Features - Add module definition (#630) [78916ab] ## 1.11.0 ### Features - Add syscall for riscv64 architecture [f66e896] - teamcity reporter: output location of test failure as well as test definition (#626) [9869142] - teamcity reporter: output newline after every service message (#625) [3cfa02d] - Add support for go module when running `generate` command (#578) [9c89e3f] ## 1.10.3 ### Fixes - Set go_import_path in travis.yml to allow internal packages in forks (#607) [3b721db] - Add integration test [d90e0dc] - Fix coverage files combining [e5dde8c] - A new CLI option: -ginkgo.reportFile (#601) [034fd25] ## 1.10.2 ### Fixes - speed up table entry generateIt() (#609) [5049dc5] - Fix. Write errors to stderr instead of stdout (#610) [7bb3091] ## 1.10.1 ### Fixes - stack backtrace: fix skipping (#600) [2a4c0bd] ## 1.10.0 ### Fixes - stack backtrace: fix alignment and skipping [66915d6] - fix typo in documentation [8f97b93] ## 1.9.0 ### Features - Option to print output into report, when tests have passed [0545415] ### Fixes - Fixed typos in comments [0ecbc58] - gofmt code [a7f8bfb] - Simplify code [7454d00] - Simplify concatenation, incrementation and function assignment [4825557] - Avoid unnecessary conversions [9d9403c] - JUnit: include more detailed information about panic [19cca4b] - Print help to stdout when the user asks for help [4cb7441] ## 1.8.0 ### New Features - allow config of the vet flag for `go test` (#562) [3cd45fa] - Support projects using go modules [d56ee76] ### Fixes and Minor Improvements - chore(godoc): fixes typos in Measurement funcs [dbaca8e] - Optimize focus to avoid allocations [f493786] - Ensure generated test file names are underscored [505cc35] ## 1.7.0 ### New Features - Add JustAfterEach (#484) [0d4f080] ### Fixes - Correctly round suite time in junit reporter [2445fc1] - Avoid using -i argument to go test for Golang 1.10+ [46bbc26] ## 1.6.0 ### New Features - add --debug flag to emit node output to files (#499) [39febac] ### Fixes - fix: for `go vet` to pass [69338ec] - docs: fix for contributing instructions [7004cb1] - consolidate and streamline contribution docs (#494) [d848015] - Make generated Junit file compatable with "Maven Surefire" (#488) [e51bee6] - all: gofmt [000d317] - Increase eventually timeout to 30s [c73579c] - Clarify asynchronous test behaviour [294d8f4] - Travis badge should only show master [26d2143] ## 1.5.0 5/10/2018 ### New Features - Supports go v1.10 (#443, #446, #451) [e873237, 468e89e, e37dbfe, a37f4c0, c0b857d, bca5260, 4177ca8] - Add a When() synonym for Context() (#386) [747514b, 7484dad, 7354a07, dd826c8] - Re-add noisySkippings flag [652e15c] - Allow coverage to be displayed for focused specs (#367) [11459a8] - Handle -outputdir flag (#364) [228e3a8] - Handle -coverprofile flag (#355) [43392d5] ### Fixes - When using custom reporters register the custom reporters *before* the default reporter. This allows users to see the output of any print statements in their customer reporters. (#365) [8382b23] - When running a test and calculating the coverage using the `-coverprofile` and `-outputdir` flags, Ginkgo fails with an error if the directory does not exist. This is due to an [issue in go 1.10](https://github.com/golang/go/issues/24588) (#446) [b36a6e0] - `unfocus` command ignores vendor folder (#459) [e5e551c, c556e43, a3b6351, 9a820dd] - Ignore packages whose tests are all ignored by go (#456) [7430ca7, 6d8be98] - Increase the threshold when checking time measuments (#455) [2f714bf, 68f622c] - Fix race condition in coverage tests (#423) [a5a8ff7, ab9c08b] - Add an extra new line after reporting spec run completion for test2json [874520d] - added name name field to junit reported testsuite [ae61c63] - Do not set the run time of a spec when the dryRun flag is used (#438) [457e2d9, ba8e856] - Process FWhen and FSpecify when unfocusing (#434) [9008c7b, ee65bd, df87dfe] - Synchronise the access to the state of specs to avoid race conditions (#430) [7d481bc, ae6829d] - Added Duration on GinkgoTestDescription (#383) [5f49dad, 528417e, 0747408, 329d7ed] - Fix Ginkgo stack trace on failure for Specify (#415) [b977ede, 65ca40e, 6c46eb8] - Update README with Go 1.6+, Golang -> Go (#409) [17f6b97, bc14b66, 20d1598] - Use fmt.Errorf instead of errors.New(fmt.Sprintf (#401) [a299f56, 44e2eaa] - Imports in generated code should follow conventions (#398) [0bec0b0, e8536d8] - Prevent data race error when Recording a benchmark value from multiple go routines (#390) [c0c4881, 7a241e9] - Replace GOPATH in Environment [4b883f0] ## 1.4.0 7/16/2017 - `ginkgo` now provides a hint if you accidentally forget to run `ginkgo bootstrap` to generate a `*_suite_test.go` file that actually invokes the Ginkgo test runner. [#345](https://github.com/onsi/ginkgo/pull/345) - thanks to improvements in `go test -c` `ginkgo` no longer needs to fix Go's compilation output to ensure compilation errors are expressed relative to the CWD. [#357] - `ginkgo watch -watchRegExp=...` allows you to specify a custom regular expression to watch. Only files matching the regular expression are watched for changes (the default is `\.go$`) [#356] - `ginkgo` now always emits compilation output. Previously, only failed compilation output was printed out. [#277] - `ginkgo -requireSuite` now fails the test run if there are `*_test.go` files but `go test` fails to detect any tests. Typically this means you forgot to run `ginkgo bootstrap` to generate a suite file. [#344] - `ginkgo -timeout=DURATION` allows you to adjust the timeout for the entire test suite (default is 24 hours) [#248] ## 1.3.0 3/28/2017 Improvements: - Significantly improved parallel test distribution. Now instead of pre-sharding test cases across workers (which can result in idle workers and poor test performance) Ginkgo uses a shared queue to keep all workers busy until all tests are complete. This improves test-time performance and consistency. - `Skip(message)` can be used to skip the current test. - Added `extensions/table` - a Ginkgo DSL for [Table Driven Tests](http://onsi.github.io/ginkgo/#table-driven-tests) - Add `GinkgoRandomSeed()` - shorthand for `config.GinkgoConfig.RandomSeed` - Support for retrying flaky tests with `--flakeAttempts` - `ginkgo ./...` now recurses as you'd expect - Added `Specify` a synonym for `It` - Support colorise on Windows - Broader support for various go compilation flags in the `ginkgo` CLI Bug Fixes: - Ginkgo tests now fail when you `panic(nil)` (#167) ## 1.2.0 5/31/2015 Improvements - `ginkgo -coverpkg` calls down to `go test -coverpkg` (#160) - `ginkgo -afterSuiteHook COMMAND` invokes the passed-in `COMMAND` after a test suite completes (#152) - Relaxed requirement for Go 1.4+. `ginkgo` now works with Go v1.3+ (#166) ## 1.2.0-beta Ginkgo now requires Go 1.4+ Improvements: - Call reporters in reverse order when announcing spec completion -- allows custom reporters to emit output before the default reporter does. - Improved focus behavior. Now, this: ```golang FDescribe("Some describe", func() { It("A", func() {}) FIt("B", func() {}) }) ``` will run `B` but *not* `A`. This tends to be a common usage pattern when in the thick of writing and debugging tests. - When `SIGINT` is received, Ginkgo will emit the contents of the `GinkgoWriter` before running the `AfterSuite`. Useful for debugging stuck tests. - When `--progress` is set, Ginkgo will write test progress (in particular, Ginkgo will say when it is about to run a BeforeEach, AfterEach, It, etc...) to the `GinkgoWriter`. This is useful for debugging stuck tests and tests that generate many logs. - Improved output when an error occurs in a setup or teardown block. - When `--dryRun` is set, Ginkgo will walk the spec tree and emit to its reporter *without* actually running anything. Best paired with `-v` to understand which specs will run in which order. - Add `By` to help document long `It`s. `By` simply writes to the `GinkgoWriter`. - Add support for precompiled tests: - `ginkgo build ` will now compile the package, producing a file named `package.test` - The compiled `package.test` file can be run directly. This runs the tests in series. - To run precompiled tests in parallel, you can run: `ginkgo -p package.test` - Support `bootstrap`ping and `generate`ing [Agouti](http://agouti.org) specs. - `ginkgo generate` and `ginkgo bootstrap` now honor the package name already defined in a given directory - The `ginkgo` CLI ignores `SIGQUIT`. Prevents its stack dump from interlacing with the underlying test suite's stack dump. - The `ginkgo` CLI now compiles tests into a temporary directory instead of the package directory. This necessitates upgrading to Go v1.4+. - `ginkgo -notify` now works on Linux Bug Fixes: - If --skipPackages is used and all packages are skipped, Ginkgo should exit 0. - Fix tempfile leak when running in parallel - Fix incorrect failure message when a panic occurs during a parallel test run - Fixed an issue where a pending test within a focused context (or a focused test within a pending context) would skip all other tests. - Be more consistent about handling SIGTERM as well as SIGINT - When interupted while concurrently compiling test suites in the background, Ginkgo now cleans up the compiled artifacts. - Fixed a long standing bug where `ginkgo -p` would hang if a process spawned by one of the Ginkgo parallel nodes does not exit. (Hooray!) ## 1.1.0 (8/2/2014) No changes, just dropping the beta. ## 1.1.0-beta (7/22/2014) New Features: - `ginkgo watch` now monitors packages *and their dependencies* for changes. The depth of the dependency tree can be modified with the `-depth` flag. - Test suites with a programmatic focus (`FIt`, `FDescribe`, etc...) exit with non-zero status code, even when they pass. This allows CI systems to detect accidental commits of focused test suites. - `ginkgo -p` runs the testsuite in parallel with an auto-detected number of nodes. - `ginkgo -tags=TAG_LIST` passes a list of tags down to the `go build` command. - `ginkgo --failFast` aborts the test suite after the first failure. - `ginkgo generate file_1 file_2` can take multiple file arguments. - Ginkgo now summarizes any spec failures that occurred at the end of the test run. - `ginkgo --randomizeSuites` will run tests *suites* in random order using the generated/passed-in seed. Improvements: - `ginkgo -skipPackage` now takes a comma-separated list of strings. If the *relative path* to a package matches one of the entries in the comma-separated list, that package is skipped. - `ginkgo --untilItFails` no longer recompiles between attempts. - Ginkgo now panics when a runnable node (`It`, `BeforeEach`, `JustBeforeEach`, `AfterEach`, `Measure`) is nested within another runnable node. This is always a mistake. Any test suites that panic because of this change should be fixed. Bug Fixes: - `ginkgo boostrap` and `ginkgo generate` no longer fail when dealing with `hyphen-separated-packages`. - parallel specs are now better distributed across nodes - fixed a crashing bug where (for example) distributing 11 tests across 7 nodes would panic ## 1.0.0 (5/24/2014) New Features: - Add `GinkgoParallelNode()` - shorthand for `config.GinkgoConfig.ParallelNode` Improvements: - When compilation fails, the compilation output is rewritten to present a correct *relative* path. Allows ⌘-clicking in iTerm open the file in your text editor. - `--untilItFails` and `ginkgo watch` now generate new random seeds between test runs, unless a particular random seed is specified. Bug Fixes: - `-cover` now generates a correctly combined coverprofile when running with in parallel with multiple `-node`s. - Print out the contents of the `GinkgoWriter` when `BeforeSuite` or `AfterSuite` fail. - Fix all remaining race conditions in Ginkgo's test suite. ## 1.0.0-beta (4/14/2014) Breaking changes: - `thirdparty/gomocktestreporter` is gone. Use `GinkgoT()` instead - Modified the Reporter interface - `watch` is now a subcommand, not a flag. DSL changes: - `BeforeSuite` and `AfterSuite` for setting up and tearing down test suites. - `AfterSuite` is triggered on interrupt (`^C`) as well as exit. - `SynchronizedBeforeSuite` and `SynchronizedAfterSuite` for setting up and tearing down singleton resources across parallel nodes. CLI changes: - `watch` is now a subcommand, not a flag - `--nodot` flag can be passed to `ginkgo generate` and `ginkgo bootstrap` to avoid dot imports. This explicitly imports all exported identifiers in Ginkgo and Gomega. Refreshing this list can be done by running `ginkgo nodot` - Additional arguments can be passed to specs. Pass them after the `--` separator - `--skipPackage` flag takes a regexp and ignores any packages with package names passing said regexp. - `--trace` flag prints out full stack traces when errors occur, not just the line at which the error occurs. Misc: - Start using semantic versioning - Start maintaining changelog Major refactor: - Pull out Ginkgo's internal to `internal` - Rename `example` everywhere to `spec` - Much more! ginkgo-1.14.2/CONTRIBUTING.md000066400000000000000000000022571374111457300153220ustar00rootroot00000000000000# Contributing to Ginkgo Your contributions to Ginkgo are essential for its long-term maintenance and improvement. - Please **open an issue first** - describe what problem you are trying to solve and give the community a forum for input and feedback ahead of investing time in writing code! - Ensure adequate test coverage: - When adding to the Ginkgo library, add unit and/or integration tests (under the `integration` folder). - When adding to the Ginkgo CLI, note that there are very few unit tests. Please add an integration test. - Update the documentation. Ginko uses `godoc` comments and documentation on the `gh-pages` branch. If relevant, please submit a docs PR to that branch alongside your code PR. Thanks for supporting Ginkgo! ## Setup Fork the repo, then: ``` go get github.com/onsi/ginkgo go get github.com/onsi/gomega/... cd $GOPATH/src/github.com/onsi/ginkgo git remote add fork git@github.com:/ginkgo.git ginkgo -r -p # ensure tests are green go vet ./... # ensure linter is happy ``` ## Making the PR - go to a new branch `git checkout -b my-feature` - make your changes - run tests and linter again (see above) - `git push fork` - open PR 🎉 ginkgo-1.14.2/LICENSE000066400000000000000000000020461374111457300140720ustar00rootroot00000000000000Copyright (c) 2013-2014 Onsi Fakhouri Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ginkgo-1.14.2/README.md000066400000000000000000000207631374111457300143520ustar00rootroot00000000000000![Ginkgo: A Go BDD Testing Framework](https://onsi.github.io/ginkgo/images/ginkgo.png) [![Build Status](https://travis-ci.org/onsi/ginkgo.svg?branch=master)](https://travis-ci.org/onsi/ginkgo) Jump to the [docs](https://onsi.github.io/ginkgo/) to learn more. To start rolling your Ginkgo tests *now* [keep reading](#set-me-up)! If you have a question, comment, bug report, feature request, etc. please open a GitHub issue, or visit the [Ginkgo Slack channel](https://app.slack.com/client/T029RQSE6/CQQ50BBNW). ## TLDR Ginkgo builds on Go's `testing` package, allowing expressive [Behavior-Driven Development](https://en.wikipedia.org/wiki/Behavior-driven_development) ("BDD") style tests. It is typically (and optionally) paired with the [Gomega](https://github.com/onsi/gomega) matcher library. ```go Describe("the strings package", func() { Context("strings.Contains()", func() { When("the string contains the substring in the middle", func() { It("returns `true`", func() { Expect(strings.Contains("Ginkgo is awesome", "is")).To(BeTrue()) }) }) }) }) ``` ## Feature List - Ginkgo uses Go's `testing` package and can live alongside your existing `testing` tests. It's easy to [bootstrap](https://onsi.github.io/ginkgo/#bootstrapping-a-suite) and start writing your [first tests](https://onsi.github.io/ginkgo/#adding-specs-to-a-suite) - Ginkgo allows you to write tests in Go using expressive [Behavior-Driven Development](https://en.wikipedia.org/wiki/Behavior-driven_development) ("BDD") style: - Nestable [`Describe`, `Context` and `When` container blocks](https://onsi.github.io/ginkgo/#organizing-specs-with-containers-describe-and-context) - [`BeforeEach` and `AfterEach` blocks](https://onsi.github.io/ginkgo/#extracting-common-setup-beforeeach) for setup and teardown - [`It` and `Specify` blocks](https://onsi.github.io/ginkgo/#individual-specs-it) that hold your assertions - [`JustBeforeEach` blocks](https://onsi.github.io/ginkgo/#separating-creation-and-configuration-justbeforeeach) that separate creation from configuration (also known as the subject action pattern). - [`BeforeSuite` and `AfterSuite` blocks](https://onsi.github.io/ginkgo/#global-setup-and-teardown-beforesuite-and-aftersuite) to prep for and cleanup after a suite. - A comprehensive test runner that lets you: - Mark specs as [pending](https://onsi.github.io/ginkgo/#pending-specs) - [Focus](https://onsi.github.io/ginkgo/#focused-specs) individual specs, and groups of specs, either programmatically or on the command line - Run your tests in [random order](https://onsi.github.io/ginkgo/#spec-permutation), and then reuse random seeds to replicate the same order. - Break up your test suite into parallel processes for straightforward [test parallelization](https://onsi.github.io/ginkgo/#parallel-specs) - `ginkgo`: a command line interface with plenty of handy command line arguments for [running your tests](https://onsi.github.io/ginkgo/#running-tests) and [generating](https://onsi.github.io/ginkgo/#generators) test files. Here are a few choice examples: - `ginkgo -nodes=N` runs your tests in `N` parallel processes and print out coherent output in realtime - `ginkgo -cover` runs your tests using Go's code coverage tool - `ginkgo convert` converts an XUnit-style `testing` package to a Ginkgo-style package - `ginkgo -focus="REGEXP"` and `ginkgo -skip="REGEXP"` allow you to specify a subset of tests to run via regular expression - `ginkgo -r` runs all tests suites under the current directory - `ginkgo -v` prints out identifying information for each tests just before it runs And much more: run `ginkgo help` for details! The `ginkgo` CLI is convenient, but purely optional -- Ginkgo works just fine with `go test` - `ginkgo watch` [watches](https://onsi.github.io/ginkgo/#watching-for-changes) packages *and their dependencies* for changes, then reruns tests. Run tests immediately as you develop! - Built-in support for testing [asynchronicity](https://onsi.github.io/ginkgo/#asynchronous-tests) - Built-in support for [benchmarking](https://onsi.github.io/ginkgo/#benchmark-tests) your code. Control the number of benchmark samples as you gather runtimes and other, arbitrary, bits of numerical information about your code. - [Completions for Sublime Text](https://github.com/onsi/ginkgo-sublime-completions): just use [Package Control](https://sublime.wbond.net/) to install `Ginkgo Completions`. - [Completions for VSCode](https://github.com/onsi/vscode-ginkgo): just use VSCode's extension installer to install `vscode-ginkgo`. - Straightforward support for third-party testing libraries such as [Gomock](https://code.google.com/p/gomock/) and [Testify](https://github.com/stretchr/testify). Check out the [docs](https://onsi.github.io/ginkgo/#third-party-integrations) for details. - A modular architecture that lets you easily: - Write [custom reporters](https://onsi.github.io/ginkgo/#writing-custom-reporters) (for example, Ginkgo comes with a [JUnit XML reporter](https://onsi.github.io/ginkgo/#generating-junit-xml-output) and a TeamCity reporter). - [Adapt an existing matcher library (or write your own!)](https://onsi.github.io/ginkgo/#using-other-matcher-libraries) to work with Ginkgo ## [Gomega](https://github.com/onsi/gomega): Ginkgo's Preferred Matcher Library Ginkgo is best paired with Gomega. Learn more about Gomega [here](https://onsi.github.io/gomega/) ## [Agouti](https://github.com/sclevine/agouti): A Go Acceptance Testing Framework Agouti allows you run WebDriver integration tests. Learn more about Agouti [here](https://agouti.org) ## Getting Started You'll need the Go command-line tools. Follow the [installation instructions](https://golang.org/doc/install) if you don't have it installed. ### Global installation To install the Ginkgo command line interface: ```bash go get -u github.com/onsi/ginkgo/ginkgo ``` Note that this will install it to `$GOBIN`, which will need to be in the `$PATH` (or equivalent). Run `go help install` for more information. ### Go module ["tools package"](https://github.com/golang/go/issues/25922): Create (or update) a file called `tools/tools.go` with the following contents: ```go // +build tools package tools import ( _ "github.com/onsi/ginkgo/ginkgo" ) // This file imports packages that are used when running go generate, or used // during the development process but not otherwise depended on by built code. ``` The Ginkgo command can then be run via `go run github.com/onsi/ginkgo/ginkgo`. This approach allows the version of Ginkgo to be maintained under source control for reproducible results, and is well suited to automated test pipelines. ### Bootstrapping ```bash cd path/to/package/you/want/to/test ginkgo bootstrap # set up a new ginkgo suite ginkgo generate # will create a sample test file. edit this file and add your tests then... go test # to run your tests ginkgo # also runs your tests ``` ## I'm new to Go: What are my testing options? Of course, I heartily recommend [Ginkgo](https://github.com/onsi/ginkgo) and [Gomega](https://github.com/onsi/gomega). Both packages are seeing heavy, daily, production use on a number of projects and boast a mature and comprehensive feature-set. With that said, it's great to know what your options are :) ### What Go gives you out of the box Testing is a first class citizen in Go, however Go's built-in testing primitives are somewhat limited: The [testing](https://golang.org/pkg/testing) package provides basic XUnit style tests and no assertion library. ### Matcher libraries for Go's XUnit style tests A number of matcher libraries have been written to augment Go's built-in XUnit style tests. Here are two that have gained traction: - [testify](https://github.com/stretchr/testify) - [gocheck](https://labix.org/gocheck) You can also use Ginkgo's matcher library [Gomega](https://github.com/onsi/gomega) in [XUnit style tests](https://onsi.github.io/gomega/#using-gomega-with-golangs-xunitstyle-tests) ### BDD style testing frameworks There are a handful of BDD-style testing frameworks written for Go. Here are a few: - [Ginkgo](https://github.com/onsi/ginkgo) ;) - [GoConvey](https://github.com/smartystreets/goconvey) - [Goblin](https://github.com/franela/goblin) - [Mao](https://github.com/azer/mao) - [Zen](https://github.com/pranavraja/zen) Finally, @shageman has [put together](https://github.com/shageman/gotestit) a comprehensive comparison of Go testing libraries. Go explore! ## License Ginkgo is MIT-Licensed ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) ginkgo-1.14.2/RELEASING.md000066400000000000000000000015731374111457300147240ustar00rootroot00000000000000A Ginkgo release is a tagged git sha and a GitHub release. To cut a release: 1. Ensure CHANGELOG.md is up to date. - Use `git log --pretty=format:'- %s [%h]' HEAD...vX.X.X` to list all the commits since the last release - Categorize the changes into - Breaking Changes (requires a major version) - New Features (minor version) - Fixes (fix version) - Maintenance (which in general should not be mentioned in `CHANGELOG.md` as they have no user impact) 1. Update `VERSION` in `config/config.go` 1. Create a commit with the version number as the commit message (e.g. `v1.3.0`) 1. Tag the commit with the version number as the tag name (e.g. `v1.3.0`) 1. Push the commit and tag to GitHub 1. Create a new [GitHub release](https://help.github.com/articles/creating-releases/) with the version number as the tag (e.g. `v1.3.0`). List the key changes in the release notes. ginkgo-1.14.2/config/000077500000000000000000000000001374111457300143305ustar00rootroot00000000000000ginkgo-1.14.2/config/config.go000066400000000000000000000177241374111457300161370ustar00rootroot00000000000000/* Ginkgo accepts a number of configuration options. These are documented [here](http://onsi.github.io/ginkgo/#the-ginkgo-cli) You can also learn more via ginkgo help or (I kid you not): go test -asdf */ package config import ( "flag" "time" "fmt" ) const VERSION = "1.14.2" type GinkgoConfigType struct { RandomSeed int64 RandomizeAllSpecs bool RegexScansFilePath bool FocusString string SkipString string SkipMeasurements bool FailOnPending bool FailFast bool FlakeAttempts int EmitSpecProgress bool DryRun bool DebugParallel bool ParallelNode int ParallelTotal int SyncHost string StreamHost string } var GinkgoConfig = GinkgoConfigType{} type DefaultReporterConfigType struct { NoColor bool SlowSpecThreshold float64 NoisyPendings bool NoisySkippings bool Succinct bool Verbose bool FullTrace bool ReportPassed bool ReportFile string } var DefaultReporterConfig = DefaultReporterConfigType{} func processPrefix(prefix string) string { if prefix != "" { prefix += "." } return prefix } func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) { prefix = processPrefix(prefix) flagSet.Int64Var(&(GinkgoConfig.RandomSeed), prefix+"seed", time.Now().Unix(), "The seed used to randomize the spec suite.") flagSet.BoolVar(&(GinkgoConfig.RandomizeAllSpecs), prefix+"randomizeAllSpecs", false, "If set, ginkgo will randomize all specs together. By default, ginkgo only randomizes the top level Describe, Context and When groups.") flagSet.BoolVar(&(GinkgoConfig.SkipMeasurements), prefix+"skipMeasurements", false, "If set, ginkgo will skip any measurement specs.") flagSet.BoolVar(&(GinkgoConfig.FailOnPending), prefix+"failOnPending", false, "If set, ginkgo will mark the test suite as failed if any specs are pending.") flagSet.BoolVar(&(GinkgoConfig.FailFast), prefix+"failFast", false, "If set, ginkgo will stop running a test suite after a failure occurs.") flagSet.BoolVar(&(GinkgoConfig.DryRun), prefix+"dryRun", false, "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v.") flagSet.StringVar(&(GinkgoConfig.FocusString), prefix+"focus", "", "If set, ginkgo will only run specs that match this regular expression.") flagSet.StringVar(&(GinkgoConfig.SkipString), prefix+"skip", "", "If set, ginkgo will only run specs that do not match this regular expression.") flagSet.BoolVar(&(GinkgoConfig.RegexScansFilePath), prefix+"regexScansFilePath", false, "If set, ginkgo regex matching also will look at the file path (code location).") flagSet.IntVar(&(GinkgoConfig.FlakeAttempts), prefix+"flakeAttempts", 1, "Make up to this many attempts to run each spec. Please note that if any of the attempts succeed, the suite will not be failed. But any failures will still be recorded.") flagSet.BoolVar(&(GinkgoConfig.EmitSpecProgress), prefix+"progress", false, "If set, ginkgo will emit progress information as each spec runs to the GinkgoWriter.") flagSet.BoolVar(&(GinkgoConfig.DebugParallel), prefix+"debug", false, "If set, ginkgo will emit node output to files when running in parallel.") if includeParallelFlags { flagSet.IntVar(&(GinkgoConfig.ParallelNode), prefix+"parallel.node", 1, "This worker node's (one-indexed) node number. For running specs in parallel.") flagSet.IntVar(&(GinkgoConfig.ParallelTotal), prefix+"parallel.total", 1, "The total number of worker nodes. For running specs in parallel.") flagSet.StringVar(&(GinkgoConfig.SyncHost), prefix+"parallel.synchost", "", "The address for the server that will synchronize the running nodes.") flagSet.StringVar(&(GinkgoConfig.StreamHost), prefix+"parallel.streamhost", "", "The address for the server that the running nodes should stream data to.") } flagSet.BoolVar(&(DefaultReporterConfig.NoColor), prefix+"noColor", false, "If set, suppress color output in default reporter.") flagSet.Float64Var(&(DefaultReporterConfig.SlowSpecThreshold), prefix+"slowSpecThreshold", 5.0, "(in seconds) Specs that take longer to run than this threshold are flagged as slow by the default reporter.") flagSet.BoolVar(&(DefaultReporterConfig.NoisyPendings), prefix+"noisyPendings", true, "If set, default reporter will shout about pending tests.") flagSet.BoolVar(&(DefaultReporterConfig.NoisySkippings), prefix+"noisySkippings", true, "If set, default reporter will shout about skipping tests.") flagSet.BoolVar(&(DefaultReporterConfig.Verbose), prefix+"v", false, "If set, default reporter print out all specs as they begin.") flagSet.BoolVar(&(DefaultReporterConfig.Succinct), prefix+"succinct", false, "If set, default reporter prints out a very succinct report") flagSet.BoolVar(&(DefaultReporterConfig.FullTrace), prefix+"trace", false, "If set, default reporter prints out the full stack trace when a failure occurs") flagSet.BoolVar(&(DefaultReporterConfig.ReportPassed), prefix+"reportPassed", false, "If set, default reporter prints out captured output of passed tests.") flagSet.StringVar(&(DefaultReporterConfig.ReportFile), prefix+"reportFile", "", "Override the default reporter output file path.") } func BuildFlagArgs(prefix string, ginkgo GinkgoConfigType, reporter DefaultReporterConfigType) []string { prefix = processPrefix(prefix) result := make([]string, 0) if ginkgo.RandomSeed > 0 { result = append(result, fmt.Sprintf("--%sseed=%d", prefix, ginkgo.RandomSeed)) } if ginkgo.RandomizeAllSpecs { result = append(result, fmt.Sprintf("--%srandomizeAllSpecs", prefix)) } if ginkgo.SkipMeasurements { result = append(result, fmt.Sprintf("--%sskipMeasurements", prefix)) } if ginkgo.FailOnPending { result = append(result, fmt.Sprintf("--%sfailOnPending", prefix)) } if ginkgo.FailFast { result = append(result, fmt.Sprintf("--%sfailFast", prefix)) } if ginkgo.DryRun { result = append(result, fmt.Sprintf("--%sdryRun", prefix)) } if ginkgo.FocusString != "" { result = append(result, fmt.Sprintf("--%sfocus=%s", prefix, ginkgo.FocusString)) } if ginkgo.SkipString != "" { result = append(result, fmt.Sprintf("--%sskip=%s", prefix, ginkgo.SkipString)) } if ginkgo.FlakeAttempts > 1 { result = append(result, fmt.Sprintf("--%sflakeAttempts=%d", prefix, ginkgo.FlakeAttempts)) } if ginkgo.EmitSpecProgress { result = append(result, fmt.Sprintf("--%sprogress", prefix)) } if ginkgo.DebugParallel { result = append(result, fmt.Sprintf("--%sdebug", prefix)) } if ginkgo.ParallelNode != 0 { result = append(result, fmt.Sprintf("--%sparallel.node=%d", prefix, ginkgo.ParallelNode)) } if ginkgo.ParallelTotal != 0 { result = append(result, fmt.Sprintf("--%sparallel.total=%d", prefix, ginkgo.ParallelTotal)) } if ginkgo.StreamHost != "" { result = append(result, fmt.Sprintf("--%sparallel.streamhost=%s", prefix, ginkgo.StreamHost)) } if ginkgo.SyncHost != "" { result = append(result, fmt.Sprintf("--%sparallel.synchost=%s", prefix, ginkgo.SyncHost)) } if ginkgo.RegexScansFilePath { result = append(result, fmt.Sprintf("--%sregexScansFilePath", prefix)) } if reporter.NoColor { result = append(result, fmt.Sprintf("--%snoColor", prefix)) } if reporter.SlowSpecThreshold > 0 { result = append(result, fmt.Sprintf("--%sslowSpecThreshold=%.5f", prefix, reporter.SlowSpecThreshold)) } if !reporter.NoisyPendings { result = append(result, fmt.Sprintf("--%snoisyPendings=false", prefix)) } if !reporter.NoisySkippings { result = append(result, fmt.Sprintf("--%snoisySkippings=false", prefix)) } if reporter.Verbose { result = append(result, fmt.Sprintf("--%sv", prefix)) } if reporter.Succinct { result = append(result, fmt.Sprintf("--%ssuccinct", prefix)) } if reporter.FullTrace { result = append(result, fmt.Sprintf("--%strace", prefix)) } if reporter.ReportPassed { result = append(result, fmt.Sprintf("--%sreportPassed", prefix)) } if reporter.ReportFile != "" { result = append(result, fmt.Sprintf("--%sreportFile=%s", prefix, reporter.ReportFile)) } return result } ginkgo-1.14.2/example/000077500000000000000000000000001374111457300145165ustar00rootroot00000000000000ginkgo-1.14.2/example/books/000077500000000000000000000000001374111457300156335ustar00rootroot00000000000000ginkgo-1.14.2/example/books/book_test.go000066400000000000000000000014341374111457300201550ustar00rootroot00000000000000package books_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/example/books" . "github.com/onsi/gomega" ) var _ = Describe("Book", func() { var ( longBook Book shortBook Book ) BeforeEach(func() { longBook = Book{ Title: "Les Miserables", Author: "Victor Hugo", Pages: 1488, } shortBook = Book{ Title: "Fox In Socks", Author: "Dr. Seuss", Pages: 24, } }) Describe("Categorizing book length", func() { Context("With more than 300 pages", func() { It("should be a novel", func() { Expect(longBook.CategoryByLength()).To(Equal("NOVEL")) }) }) Context("With fewer than 300 pages", func() { It("should be a short story", func() { Expect(shortBook.CategoryByLength()).To(Equal("SHORT STORY")) }) }) }) }) ginkgo-1.14.2/example/books/books.go000066400000000000000000000002751374111457300173030ustar00rootroot00000000000000package books type Book struct { Title string Author string Pages int } func (b *Book) CategoryByLength() string { if b.Pages >= 300 { return "NOVEL" } return "SHORT STORY" } ginkgo-1.14.2/example/books/books_suite_test.go000066400000000000000000000002741374111457300215520ustar00rootroot00000000000000package books_test import ( "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) func TestBooks(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Books Suite") } ginkgo-1.14.2/extensions/000077500000000000000000000000001374111457300152625ustar00rootroot00000000000000ginkgo-1.14.2/extensions/globals/000077500000000000000000000000001374111457300167055ustar00rootroot00000000000000ginkgo-1.14.2/extensions/globals/globals.go000066400000000000000000000025711374111457300206640ustar00rootroot00000000000000// Package `globals` provides an interface to alter the global state of ginkgo suite. // // ginkgo currently registers a few singleton global vars that hold all the // test blocks and failure management. These vars are global per package, which means // that only one Suite definition can coexist in one package. // // However, there can be some use cases where applications using ginkgo may want to // have a bit more control about this. For instance, a package may be using ginkgo // to dynamically generate different tests and groups depending on some configuration. // In this particular case, if the application wants to test how these different groups // are generated, they will need access to change these global variables, so they // can re-generate this global state, and ensure that different configuration generate // indeed different tests. // // Note that this package is not intended to be used as part of normal ginkgo setups, and // usually, you will never need to worry about the global state of ginkgo package globals import "github.com/onsi/ginkgo/internal/global" // Reset calls `global.InitializeGlobals()` which will basically create a new instance // of Suite, and therefore, will effectively reset the global variables to the init state. // This will effectively remove all groups, tests and blocks that were added to the Suite. func Reset() { global.InitializeGlobals() } ginkgo-1.14.2/extensions/globals/globals_test.go000066400000000000000000000007441374111457300217230ustar00rootroot00000000000000package globals_test import ( "testing" "github.com/onsi/ginkgo/extensions/globals" "github.com/onsi/ginkgo/internal/global" ) func TestGlobals(t *testing.T) { global.InitializeGlobals() oldSuite := global.Suite if oldSuite == nil { t.Error("global.Suite was nil") } globals.Reset() newSuite := global.Suite if newSuite == nil { t.Error("new global.Suite was nil") } if oldSuite == newSuite { t.Error("got the same suite but expected it to be different!") } } ginkgo-1.14.2/extensions/table/000077500000000000000000000000001374111457300163515ustar00rootroot00000000000000ginkgo-1.14.2/extensions/table/table.go000066400000000000000000000072621374111457300177760ustar00rootroot00000000000000/* Table provides a simple DSL for Ginkgo-native Table-Driven Tests The godoc documentation describes Table's API. More comprehensive documentation (with examples!) is available at http://onsi.github.io/ginkgo#table-driven-tests */ package table import ( "fmt" "reflect" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/global" "github.com/onsi/ginkgo/types" ) /* DescribeTable describes a table-driven test. For example: DescribeTable("a simple table", func(x int, y int, expected bool) { Ω(x > y).Should(Equal(expected)) }, Entry("x > y", 1, 0, true), Entry("x == y", 0, 0, false), Entry("x < y", 0, 1, false), ) The first argument to `DescribeTable` is a string description. The second argument is a function that will be run for each table entry. Your assertions go here - the function is equivalent to a Ginkgo It. The subsequent arguments must be of type `TableEntry`. We recommend using the `Entry` convenience constructors. The `Entry` constructor takes a string description followed by an arbitrary set of parameters. These parameters are passed into your function. Under the hood, `DescribeTable` simply generates a new Ginkgo `Describe`. Each `Entry` is turned into an `It` within the `Describe`. It's important to understand that the `Describe`s and `It`s are generated at evaluation time (i.e. when Ginkgo constructs the tree of tests and before the tests run). Individual Entries can be focused (with FEntry) or marked pending (with PEntry or XEntry). In addition, the entire table can be focused or marked pending with FDescribeTable and PDescribeTable/XDescribeTable. A description function can be passed to Entry in place of the description. The function is then fed with the entry parameters to generate the description of the It corresponding to that particular Entry. For example: describe := func(desc string) func(int, int, bool) string { return func(x, y int, expected bool) string { return fmt.Sprintf("%s x=%d y=%d expected:%t", desc, x, y, expected) } } DescribeTable("a simple table", func(x int, y int, expected bool) { Ω(x > y).Should(Equal(expected)) }, Entry(describe("x > y"), 1, 0, true), Entry(describe("x == y"), 0, 0, false), Entry(describe("x < y"), 0, 1, false), ) */ func DescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { describeTable(description, itBody, entries, types.FlagTypeNone) return true } /* You can focus a table with `FDescribeTable`. This is equivalent to `FDescribe`. */ func FDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { describeTable(description, itBody, entries, types.FlagTypeFocused) return true } /* You can mark a table as pending with `PDescribeTable`. This is equivalent to `PDescribe`. */ func PDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { describeTable(description, itBody, entries, types.FlagTypePending) return true } /* You can mark a table as pending with `XDescribeTable`. This is equivalent to `XDescribe`. */ func XDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { describeTable(description, itBody, entries, types.FlagTypePending) return true } func describeTable(description string, itBody interface{}, entries []TableEntry, flag types.FlagType) { itBodyValue := reflect.ValueOf(itBody) if itBodyValue.Kind() != reflect.Func { panic(fmt.Sprintf("DescribeTable expects a function, got %#v", itBody)) } global.Suite.PushContainerNode( description, func() { for _, entry := range entries { entry.generateIt(itBodyValue) } }, flag, codelocation.New(2), ) } ginkgo-1.14.2/extensions/table/table_entry.go000066400000000000000000000066401374111457300212160ustar00rootroot00000000000000package table import ( "fmt" "reflect" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/global" "github.com/onsi/ginkgo/types" ) /* TableEntry represents an entry in a table test. You generally use the `Entry` constructor. */ type TableEntry struct { Description interface{} Parameters []interface{} Pending bool Focused bool codeLocation types.CodeLocation } func (t TableEntry) generateIt(itBody reflect.Value) { var description string descriptionValue := reflect.ValueOf(t.Description) switch descriptionValue.Kind() { case reflect.String: description = descriptionValue.String() case reflect.Func: values := castParameters(descriptionValue, t.Parameters) res := descriptionValue.Call(values) if len(res) != 1 { panic(fmt.Sprintf("The describe function should return only a value, returned %d", len(res))) } if res[0].Kind() != reflect.String { panic(fmt.Sprintf("The describe function should return a string, returned %#v", res[0])) } description = res[0].String() default: panic(fmt.Sprintf("Description can either be a string or a function, got %#v", descriptionValue)) } if t.Pending { global.Suite.PushItNode(description, func() {}, types.FlagTypePending, t.codeLocation, 0) return } values := castParameters(itBody, t.Parameters) body := func() { itBody.Call(values) } if t.Focused { global.Suite.PushItNode(description, body, types.FlagTypeFocused, t.codeLocation, global.DefaultTimeout) } else { global.Suite.PushItNode(description, body, types.FlagTypeNone, t.codeLocation, global.DefaultTimeout) } } func castParameters(function reflect.Value, parameters []interface{}) []reflect.Value { res := make([]reflect.Value, len(parameters)) funcType := function.Type() for i, param := range parameters { if param == nil { inType := funcType.In(i) res[i] = reflect.Zero(inType) } else { res[i] = reflect.ValueOf(param) } } return res } /* Entry constructs a TableEntry. The first argument is a required description (this becomes the content of the generated Ginkgo `It`). Subsequent parameters are saved off and sent to the callback passed in to `DescribeTable`. Each Entry ends up generating an individual Ginkgo It. */ func Entry(description interface{}, parameters ...interface{}) TableEntry { return TableEntry{ Description: description, Parameters: parameters, Pending: false, Focused: false, codeLocation: codelocation.New(1), } } /* You can focus a particular entry with FEntry. This is equivalent to FIt. */ func FEntry(description interface{}, parameters ...interface{}) TableEntry { return TableEntry{ Description: description, Parameters: parameters, Pending: false, Focused: true, codeLocation: codelocation.New(1), } } /* You can mark a particular entry as pending with PEntry. This is equivalent to PIt. */ func PEntry(description interface{}, parameters ...interface{}) TableEntry { return TableEntry{ Description: description, Parameters: parameters, Pending: true, Focused: false, codeLocation: codelocation.New(1), } } /* You can mark a particular entry as pending with XEntry. This is equivalent to XIt. */ func XEntry(description interface{}, parameters ...interface{}) TableEntry { return TableEntry{ Description: description, Parameters: parameters, Pending: true, Focused: false, codeLocation: codelocation.New(1), } } ginkgo-1.14.2/extensions/table/table_suite_test.go000066400000000000000000000002741374111457300222420ustar00rootroot00000000000000package table_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestTable(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Table Suite") } ginkgo-1.14.2/extensions/table/table_test.go000066400000000000000000000057631374111457300210410ustar00rootroot00000000000000package table_test import ( "fmt" "strings" . "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Table", func() { DescribeTable("a simple table", func(x int, y int, expected bool) { Ω(x > y).Should(Equal(expected)) }, Entry("x > y", 1, 0, true), Entry("x == y", 0, 0, false), Entry("x < y", 0, 1, false), ) type ComplicatedThings struct { Superstructure string Substructure string Count int } DescribeTable("a more complicated table", func(c ComplicatedThings) { Ω(strings.Count(c.Superstructure, c.Substructure)).Should(BeNumerically("==", c.Count)) }, Entry("with no matching substructures", ComplicatedThings{ Superstructure: "the sixth sheikh's sixth sheep's sick", Substructure: "emir", Count: 0, }), Entry("with one matching substructure", ComplicatedThings{ Superstructure: "the sixth sheikh's sixth sheep's sick", Substructure: "sheep", Count: 1, }), Entry("with many matching substructures", ComplicatedThings{ Superstructure: "the sixth sheikh's sixth sheep's sick", Substructure: "si", Count: 3, }), ) PDescribeTable("a failure", func(value bool) { Ω(value).Should(BeFalse()) }, Entry("when true", true), Entry("when false", false), Entry("when malformed", 2), ) DescribeTable("an untyped nil as an entry", func(x interface{}) { Expect(x).To(BeNil()) }, Entry("nil", nil), ) }) var _ = Describe("TableWithParametricDescription", func() { describe := func(desc string) func(int, int, bool) string { return func(x, y int, expected bool) string { return fmt.Sprintf("%s x=%d y=%d expected:%t", desc, x, y, expected) } } DescribeTable("a simple table", func(x int, y int, expected bool) { Ω(x > y).Should(Equal(expected)) }, Entry(describe("x > y"), 1, 0, true), Entry(describe("x == y"), 0, 0, false), Entry(describe("x < y"), 0, 1, false), ) type ComplicatedThings struct { Superstructure string Substructure string Count int } describeComplicated := func(desc string) func(ComplicatedThings) string { return func(things ComplicatedThings) string { return fmt.Sprintf("%s things=%v", desc, things) } } DescribeTable("a more complicated table", func(c ComplicatedThings) { Ω(strings.Count(c.Superstructure, c.Substructure)).Should(BeNumerically("==", c.Count)) }, Entry(describeComplicated("with no matching substructures"), ComplicatedThings{ Superstructure: "the sixth sheikh's sixth sheep's sick", Substructure: "emir", Count: 0, }), Entry(describeComplicated("with one matching substructure"), ComplicatedThings{ Superstructure: "the sixth sheikh's sixth sheep's sick", Substructure: "sheep", Count: 1, }), Entry(describeComplicated("with many matching substructures"), ComplicatedThings{ Superstructure: "the sixth sheikh's sixth sheep's sick", Substructure: "si", Count: 3, }), ) }) ginkgo-1.14.2/ginkgo/000077500000000000000000000000001374111457300143415ustar00rootroot00000000000000ginkgo-1.14.2/ginkgo/bootstrap_command.go000066400000000000000000000113401374111457300204020ustar00rootroot00000000000000package main import ( "bytes" "flag" "fmt" "io/ioutil" "os" "path/filepath" "strings" "text/template" "go/build" "github.com/onsi/ginkgo/ginkgo/nodot" ) func BuildBootstrapCommand() *Command { var ( agouti, noDot, internal bool customBootstrapFile string ) flagSet := flag.NewFlagSet("bootstrap", flag.ExitOnError) flagSet.BoolVar(&agouti, "agouti", false, "If set, bootstrap will generate a bootstrap file for writing Agouti tests") flagSet.BoolVar(&noDot, "nodot", false, "If set, bootstrap will generate a bootstrap file that does not . import ginkgo and gomega") flagSet.BoolVar(&internal, "internal", false, "If set, generate will generate a test file that uses the regular package name") flagSet.StringVar(&customBootstrapFile, "template", "", "If specified, generate will use the contents of the file passed as the bootstrap template") return &Command{ Name: "bootstrap", FlagSet: flagSet, UsageCommand: "ginkgo bootstrap ", Usage: []string{ "Bootstrap a test suite for the current package", "Accepts the following flags:", }, Command: func(args []string, additionalArgs []string) { generateBootstrap(agouti, noDot, internal, customBootstrapFile) }, } } var bootstrapText = `package {{.Package}} import ( "testing" {{.GinkgoImport}} {{.GomegaImport}} ) func Test{{.FormattedName}}(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "{{.FormattedName}} Suite") } ` var agoutiBootstrapText = `package {{.Package}} import ( "testing" {{.GinkgoImport}} {{.GomegaImport}} "github.com/sclevine/agouti" ) func Test{{.FormattedName}}(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "{{.FormattedName}} Suite") } var agoutiDriver *agouti.WebDriver var _ = BeforeSuite(func() { // Choose a WebDriver: agoutiDriver = agouti.PhantomJS() // agoutiDriver = agouti.Selenium() // agoutiDriver = agouti.ChromeDriver() Expect(agoutiDriver.Start()).To(Succeed()) }) var _ = AfterSuite(func() { Expect(agoutiDriver.Stop()).To(Succeed()) }) ` type bootstrapData struct { Package string FormattedName string GinkgoImport string GomegaImport string } func getPackageAndFormattedName() (string, string, string) { path, err := os.Getwd() if err != nil { complainAndQuit("Could not get current working directory: \n" + err.Error()) } dirName := strings.Replace(filepath.Base(path), "-", "_", -1) dirName = strings.Replace(dirName, " ", "_", -1) pkg, err := build.ImportDir(path, 0) packageName := pkg.Name if err != nil { packageName = dirName } formattedName := prettifyPackageName(filepath.Base(path)) return packageName, dirName, formattedName } func prettifyPackageName(name string) string { name = strings.Replace(name, "-", " ", -1) name = strings.Replace(name, "_", " ", -1) name = strings.Title(name) name = strings.Replace(name, " ", "", -1) return name } func determinePackageName(name string, internal bool) string { if internal { return name } return name + "_test" } func fileExists(path string) bool { _, err := os.Stat(path) return err == nil } func generateBootstrap(agouti, noDot, internal bool, customBootstrapFile string) { packageName, bootstrapFilePrefix, formattedName := getPackageAndFormattedName() data := bootstrapData{ Package: determinePackageName(packageName, internal), FormattedName: formattedName, GinkgoImport: `. "github.com/onsi/ginkgo"`, GomegaImport: `. "github.com/onsi/gomega"`, } if noDot { data.GinkgoImport = `"github.com/onsi/ginkgo"` data.GomegaImport = `"github.com/onsi/gomega"` } targetFile := fmt.Sprintf("%s_suite_test.go", bootstrapFilePrefix) if fileExists(targetFile) { fmt.Printf("%s already exists.\n\n", targetFile) os.Exit(1) } else { fmt.Printf("Generating ginkgo test suite bootstrap for %s in:\n\t%s\n", packageName, targetFile) } f, err := os.Create(targetFile) if err != nil { complainAndQuit("Could not create file: " + err.Error()) panic(err.Error()) } defer f.Close() var templateText string if customBootstrapFile != "" { tpl, err := ioutil.ReadFile(customBootstrapFile) if err != nil { panic(err.Error()) } templateText = string(tpl) } else if agouti { templateText = agoutiBootstrapText } else { templateText = bootstrapText } bootstrapTemplate, err := template.New("bootstrap").Parse(templateText) if err != nil { panic(err.Error()) } buf := &bytes.Buffer{} bootstrapTemplate.Execute(buf, data) if noDot { contents, err := nodot.ApplyNoDot(buf.Bytes()) if err != nil { complainAndQuit("Failed to import nodot declarations: " + err.Error()) } fmt.Println("To update the nodot declarations in the future, switch to this directory and run:\n\tginkgo nodot") buf = bytes.NewBuffer(contents) } buf.WriteTo(f) goFmt(targetFile) } ginkgo-1.14.2/ginkgo/build_command.go000066400000000000000000000031601374111457300174650ustar00rootroot00000000000000package main import ( "flag" "fmt" "os" "path/filepath" "github.com/onsi/ginkgo/ginkgo/interrupthandler" "github.com/onsi/ginkgo/ginkgo/testrunner" ) func BuildBuildCommand() *Command { commandFlags := NewBuildCommandFlags(flag.NewFlagSet("build", flag.ExitOnError)) interruptHandler := interrupthandler.NewInterruptHandler() builder := &SpecBuilder{ commandFlags: commandFlags, interruptHandler: interruptHandler, } return &Command{ Name: "build", FlagSet: commandFlags.FlagSet, UsageCommand: "ginkgo build ", Usage: []string{ "Build the passed in (or the package in the current directory if left blank).", "Accepts the following flags:", }, Command: builder.BuildSpecs, } } type SpecBuilder struct { commandFlags *RunWatchAndBuildCommandFlags interruptHandler *interrupthandler.InterruptHandler } func (r *SpecBuilder) BuildSpecs(args []string, additionalArgs []string) { r.commandFlags.computeNodes() suites, _ := findSuites(args, r.commandFlags.Recurse, r.commandFlags.SkipPackage, false) if len(suites) == 0 { complainAndQuit("Found no test suites") } passed := true for _, suite := range suites { runner := testrunner.New(suite, 1, false, 0, r.commandFlags.GoOpts, nil) fmt.Printf("Compiling %s...\n", suite.PackageName) path, _ := filepath.Abs(filepath.Join(suite.Path, fmt.Sprintf("%s.test", suite.PackageName))) err := runner.CompileTo(path) if err != nil { fmt.Println(err.Error()) passed = false } else { fmt.Printf(" compiled %s.test\n", suite.PackageName) } } if passed { os.Exit(0) } os.Exit(1) } ginkgo-1.14.2/ginkgo/convert/000077500000000000000000000000001374111457300160215ustar00rootroot00000000000000ginkgo-1.14.2/ginkgo/convert/ginkgo_ast_nodes.go000066400000000000000000000065601374111457300216740ustar00rootroot00000000000000package convert import ( "fmt" "go/ast" "strings" "unicode" ) /* * Creates a func init() node */ func createVarUnderscoreBlock() *ast.ValueSpec { valueSpec := &ast.ValueSpec{} object := &ast.Object{Kind: 4, Name: "_", Decl: valueSpec, Data: 0} ident := &ast.Ident{Name: "_", Obj: object} valueSpec.Names = append(valueSpec.Names, ident) return valueSpec } /* * Creates a Describe("Testing with ginkgo", func() { }) node */ func createDescribeBlock() *ast.CallExpr { blockStatement := &ast.BlockStmt{List: []ast.Stmt{}} fieldList := &ast.FieldList{} funcType := &ast.FuncType{Params: fieldList} funcLit := &ast.FuncLit{Type: funcType, Body: blockStatement} basicLit := &ast.BasicLit{Kind: 9, Value: "\"Testing with Ginkgo\""} describeIdent := &ast.Ident{Name: "Describe"} return &ast.CallExpr{Fun: describeIdent, Args: []ast.Expr{basicLit, funcLit}} } /* * Convenience function to return the name of the *testing.T param * for a Test function that will be rewritten. This is useful because * we will want to replace the usage of this named *testing.T inside the * body of the function with a GinktoT. */ func namedTestingTArg(node *ast.FuncDecl) string { return node.Type.Params.List[0].Names[0].Name // *exhale* } /* * Convenience function to return the block statement node for a Describe statement */ func blockStatementFromDescribe(desc *ast.CallExpr) *ast.BlockStmt { var funcLit *ast.FuncLit var found = false for _, node := range desc.Args { switch node := node.(type) { case *ast.FuncLit: found = true funcLit = node break } } if !found { panic("Error finding ast.FuncLit inside describe statement. Somebody done goofed.") } return funcLit.Body } /* convenience function for creating an It("TestNameHere") * with all the body of the test function inside the anonymous * func passed to It() */ func createItStatementForTestFunc(testFunc *ast.FuncDecl) *ast.ExprStmt { blockStatement := &ast.BlockStmt{List: testFunc.Body.List} fieldList := &ast.FieldList{} funcType := &ast.FuncType{Params: fieldList} funcLit := &ast.FuncLit{Type: funcType, Body: blockStatement} testName := rewriteTestName(testFunc.Name.Name) basicLit := &ast.BasicLit{Kind: 9, Value: fmt.Sprintf("\"%s\"", testName)} itBlockIdent := &ast.Ident{Name: "It"} callExpr := &ast.CallExpr{Fun: itBlockIdent, Args: []ast.Expr{basicLit, funcLit}} return &ast.ExprStmt{X: callExpr} } /* * rewrite test names to be human readable * eg: rewrites "TestSomethingAmazing" as "something amazing" */ func rewriteTestName(testName string) string { nameComponents := []string{} currentString := "" indexOfTest := strings.Index(testName, "Test") if indexOfTest != 0 { return testName } testName = strings.Replace(testName, "Test", "", 1) first, rest := testName[0], testName[1:] testName = string(unicode.ToLower(rune(first))) + rest for _, rune := range testName { if unicode.IsUpper(rune) { nameComponents = append(nameComponents, currentString) currentString = string(unicode.ToLower(rune)) } else { currentString += string(rune) } } return strings.Join(append(nameComponents, currentString), " ") } func newGinkgoTFromIdent(ident *ast.Ident) *ast.CallExpr { return &ast.CallExpr{ Lparen: ident.NamePos + 1, Rparen: ident.NamePos + 2, Fun: &ast.Ident{Name: "GinkgoT"}, } } func newGinkgoTInterface() *ast.Ident { return &ast.Ident{Name: "GinkgoTInterface"} } ginkgo-1.14.2/ginkgo/convert/import.go000066400000000000000000000036111374111457300176630ustar00rootroot00000000000000package convert import ( "fmt" "go/ast" ) /* * Given the root node of an AST, returns the node containing the * import statements for the file. */ func importsForRootNode(rootNode *ast.File) (imports *ast.GenDecl, err error) { for _, declaration := range rootNode.Decls { decl, ok := declaration.(*ast.GenDecl) if !ok || len(decl.Specs) == 0 { continue } _, ok = decl.Specs[0].(*ast.ImportSpec) if ok { imports = decl return } } err = fmt.Errorf("Could not find imports for root node:\n\t%#v\n", rootNode) return } /* * Removes "testing" import, if present */ func removeTestingImport(rootNode *ast.File) { importDecl, err := importsForRootNode(rootNode) if err != nil { panic(err.Error()) } var index int for i, importSpec := range importDecl.Specs { importSpec := importSpec.(*ast.ImportSpec) if importSpec.Path.Value == "\"testing\"" { index = i break } } importDecl.Specs = append(importDecl.Specs[:index], importDecl.Specs[index+1:]...) } /* * Adds import statements for onsi/ginkgo, if missing */ func addGinkgoImports(rootNode *ast.File) { importDecl, err := importsForRootNode(rootNode) if err != nil { panic(err.Error()) } if len(importDecl.Specs) == 0 { // TODO: might need to create a import decl here panic("unimplemented : expected to find an imports block") } needsGinkgo := true for _, importSpec := range importDecl.Specs { importSpec, ok := importSpec.(*ast.ImportSpec) if !ok { continue } if importSpec.Path.Value == "\"github.com/onsi/ginkgo\"" { needsGinkgo = false } } if needsGinkgo { importDecl.Specs = append(importDecl.Specs, createImport(".", "\"github.com/onsi/ginkgo\"")) } } /* * convenience function to create an import statement */ func createImport(name, path string) *ast.ImportSpec { return &ast.ImportSpec{ Name: &ast.Ident{Name: name}, Path: &ast.BasicLit{Kind: 9, Value: path}, } } ginkgo-1.14.2/ginkgo/convert/package_rewriter.go000066400000000000000000000062151374111457300216720ustar00rootroot00000000000000package convert import ( "fmt" "go/build" "io/ioutil" "os" "os/exec" "path/filepath" "regexp" ) /* * RewritePackage takes a name (eg: my-package/tools), finds its test files using * Go's build package, and then rewrites them. A ginkgo test suite file will * also be added for this package, and all of its child packages. */ func RewritePackage(packageName string) { pkg, err := packageWithName(packageName) if err != nil { panic(fmt.Sprintf("unexpected error reading package: '%s'\n%s\n", packageName, err.Error())) } for _, filename := range findTestsInPackage(pkg) { rewriteTestsInFile(filename) } } /* * Given a package, findTestsInPackage reads the test files in the directory, * and then recurses on each child package, returning a slice of all test files * found in this process. */ func findTestsInPackage(pkg *build.Package) (testfiles []string) { for _, file := range append(pkg.TestGoFiles, pkg.XTestGoFiles...) { testfile, _ := filepath.Abs(filepath.Join(pkg.Dir, file)) testfiles = append(testfiles, testfile) } dirFiles, err := ioutil.ReadDir(pkg.Dir) if err != nil { panic(fmt.Sprintf("unexpected error reading dir: '%s'\n%s\n", pkg.Dir, err.Error())) } re := regexp.MustCompile(`^[._]`) for _, file := range dirFiles { if !file.IsDir() { continue } if re.Match([]byte(file.Name())) { continue } packageName := filepath.Join(pkg.ImportPath, file.Name()) subPackage, err := packageWithName(packageName) if err != nil { panic(fmt.Sprintf("unexpected error reading package: '%s'\n%s\n", packageName, err.Error())) } testfiles = append(testfiles, findTestsInPackage(subPackage)...) } addGinkgoSuiteForPackage(pkg) goFmtPackage(pkg) return } /* * Shells out to `ginkgo bootstrap` to create a test suite file */ func addGinkgoSuiteForPackage(pkg *build.Package) { originalDir, err := os.Getwd() if err != nil { panic(err) } suite_test_file := filepath.Join(pkg.Dir, pkg.Name+"_suite_test.go") _, err = os.Stat(suite_test_file) if err == nil { return // test file already exists, this should be a no-op } err = os.Chdir(pkg.Dir) if err != nil { panic(err) } output, err := exec.Command("ginkgo", "bootstrap").Output() if err != nil { panic(fmt.Sprintf("error running 'ginkgo bootstrap'.\nstdout: %s\n%s\n", output, err.Error())) } err = os.Chdir(originalDir) if err != nil { panic(err) } } /* * Shells out to `go fmt` to format the package */ func goFmtPackage(pkg *build.Package) { path, _ := filepath.Abs(pkg.ImportPath) output, err := exec.Command("go", "fmt", path).CombinedOutput() if err != nil { fmt.Printf("Warning: Error running 'go fmt %s'.\nstdout: %s\n%s\n", path, output, err.Error()) } } /* * Attempts to return a package with its test files already read. * The ImportMode arg to build.Import lets you specify if you want go to read the * buildable go files inside the package, but it fails if the package has no go files */ func packageWithName(name string) (pkg *build.Package, err error) { pkg, err = build.Default.Import(name, ".", build.ImportMode(0)) if err == nil { return } pkg, err = build.Default.Import(name, ".", build.ImportMode(1)) return } ginkgo-1.14.2/ginkgo/convert/test_finder.go000066400000000000000000000024341374111457300206610ustar00rootroot00000000000000package convert import ( "go/ast" "regexp" ) /* * Given a root node, walks its top level statements and returns * points to function nodes to rewrite as It statements. * These functions, according to Go testing convention, must be named * TestWithCamelCasedName and receive a single *testing.T argument. */ func findTestFuncs(rootNode *ast.File) (testsToRewrite []*ast.FuncDecl) { testNameRegexp := regexp.MustCompile("^Test[0-9A-Z].+") ast.Inspect(rootNode, func(node ast.Node) bool { if node == nil { return false } switch node := node.(type) { case *ast.FuncDecl: matches := testNameRegexp.MatchString(node.Name.Name) if matches && receivesTestingT(node) { testsToRewrite = append(testsToRewrite, node) } } return true }) return } /* * convenience function that looks at args to a function and determines if its * params include an argument of type *testing.T */ func receivesTestingT(node *ast.FuncDecl) bool { if len(node.Type.Params.List) != 1 { return false } base, ok := node.Type.Params.List[0].Type.(*ast.StarExpr) if !ok { return false } intermediate := base.X.(*ast.SelectorExpr) isTestingPackage := intermediate.X.(*ast.Ident).Name == "testing" isTestingT := intermediate.Sel.Name == "T" return isTestingPackage && isTestingT } ginkgo-1.14.2/ginkgo/convert/testfile_rewriter.go000066400000000000000000000111271374111457300221140ustar00rootroot00000000000000package convert import ( "bytes" "fmt" "go/ast" "go/format" "go/parser" "go/token" "io/ioutil" "os" ) /* * Given a file path, rewrites any tests in the Ginkgo format. * First, we parse the AST, and update the imports declaration. * Then, we walk the first child elements in the file, returning tests to rewrite. * A top level init func is declared, with a single Describe func inside. * Then the test functions to rewrite are inserted as It statements inside the Describe. * Finally we walk the rest of the file, replacing other usages of *testing.T * Once that is complete, we write the AST back out again to its file. */ func rewriteTestsInFile(pathToFile string) { fileSet := token.NewFileSet() rootNode, err := parser.ParseFile(fileSet, pathToFile, nil, parser.ParseComments) if err != nil { panic(fmt.Sprintf("Error parsing test file '%s':\n%s\n", pathToFile, err.Error())) } addGinkgoImports(rootNode) removeTestingImport(rootNode) varUnderscoreBlock := createVarUnderscoreBlock() describeBlock := createDescribeBlock() varUnderscoreBlock.Values = []ast.Expr{describeBlock} for _, testFunc := range findTestFuncs(rootNode) { rewriteTestFuncAsItStatement(testFunc, rootNode, describeBlock) } underscoreDecl := &ast.GenDecl{ Tok: 85, // gah, magick numbers are needed to make this work TokPos: 14, // this tricks Go into writing "var _ = Describe" Specs: []ast.Spec{varUnderscoreBlock}, } imports := rootNode.Decls[0] tail := rootNode.Decls[1:] rootNode.Decls = append(append([]ast.Decl{imports}, underscoreDecl), tail...) rewriteOtherFuncsToUseGinkgoT(rootNode.Decls) walkNodesInRootNodeReplacingTestingT(rootNode) var buffer bytes.Buffer if err = format.Node(&buffer, fileSet, rootNode); err != nil { panic(fmt.Sprintf("Error formatting ast node after rewriting tests.\n%s\n", err.Error())) } fileInfo, err := os.Stat(pathToFile) if err != nil { panic(fmt.Sprintf("Error stat'ing file: %s\n", pathToFile)) } err = ioutil.WriteFile(pathToFile, buffer.Bytes(), fileInfo.Mode()) } /* * Given a test func named TestDoesSomethingNeat, rewrites it as * It("does something neat", func() { __test_body_here__ }) and adds it * to the Describe's list of statements */ func rewriteTestFuncAsItStatement(testFunc *ast.FuncDecl, rootNode *ast.File, describe *ast.CallExpr) { var funcIndex int = -1 for index, child := range rootNode.Decls { if child == testFunc { funcIndex = index break } } if funcIndex < 0 { panic(fmt.Sprintf("Assert failed: Error finding index for test node %s\n", testFunc.Name.Name)) } var block *ast.BlockStmt = blockStatementFromDescribe(describe) block.List = append(block.List, createItStatementForTestFunc(testFunc)) replaceTestingTsWithGinkgoT(block, namedTestingTArg(testFunc)) // remove the old test func from the root node's declarations rootNode.Decls = append(rootNode.Decls[:funcIndex], rootNode.Decls[funcIndex+1:]...) } /* * walks nodes inside of a test func's statements and replaces the usage of * it's named *testing.T param with GinkgoT's */ func replaceTestingTsWithGinkgoT(statementsBlock *ast.BlockStmt, testingT string) { ast.Inspect(statementsBlock, func(node ast.Node) bool { if node == nil { return false } keyValueExpr, ok := node.(*ast.KeyValueExpr) if ok { replaceNamedTestingTsInKeyValueExpression(keyValueExpr, testingT) return true } funcLiteral, ok := node.(*ast.FuncLit) if ok { replaceTypeDeclTestingTsInFuncLiteral(funcLiteral) return true } callExpr, ok := node.(*ast.CallExpr) if !ok { return true } replaceTestingTsInArgsLists(callExpr, testingT) funCall, ok := callExpr.Fun.(*ast.SelectorExpr) if ok { replaceTestingTsMethodCalls(funCall, testingT) } return true }) } /* * rewrite t.Fail() or any other *testing.T method by replacing with T().Fail() * This function receives a selector expression (eg: t.Fail()) and * the name of the *testing.T param from the function declaration. Rewrites the * selector expression in place if the target was a *testing.T */ func replaceTestingTsMethodCalls(selectorExpr *ast.SelectorExpr, testingT string) { ident, ok := selectorExpr.X.(*ast.Ident) if !ok { return } if ident.Name == testingT { selectorExpr.X = newGinkgoTFromIdent(ident) } } /* * replaces usages of a named *testing.T param inside of a call expression * with a new GinkgoT object */ func replaceTestingTsInArgsLists(callExpr *ast.CallExpr, testingT string) { for index, arg := range callExpr.Args { ident, ok := arg.(*ast.Ident) if !ok { continue } if ident.Name == testingT { callExpr.Args[index] = newGinkgoTFromIdent(ident) } } } ginkgo-1.14.2/ginkgo/convert/testing_t_rewriter.go000066400000000000000000000050611374111457300222750ustar00rootroot00000000000000package convert import ( "go/ast" ) /* * Rewrites any other top level funcs that receive a *testing.T param */ func rewriteOtherFuncsToUseGinkgoT(declarations []ast.Decl) { for _, decl := range declarations { decl, ok := decl.(*ast.FuncDecl) if !ok { continue } for _, param := range decl.Type.Params.List { starExpr, ok := param.Type.(*ast.StarExpr) if !ok { continue } selectorExpr, ok := starExpr.X.(*ast.SelectorExpr) if !ok { continue } xIdent, ok := selectorExpr.X.(*ast.Ident) if !ok || xIdent.Name != "testing" { continue } if selectorExpr.Sel.Name != "T" { continue } param.Type = newGinkgoTInterface() } } } /* * Walks all of the nodes in the file, replacing *testing.T in struct * and func literal nodes. eg: * type foo struct { *testing.T } * var bar = func(t *testing.T) { } */ func walkNodesInRootNodeReplacingTestingT(rootNode *ast.File) { ast.Inspect(rootNode, func(node ast.Node) bool { if node == nil { return false } switch node := node.(type) { case *ast.StructType: replaceTestingTsInStructType(node) case *ast.FuncLit: replaceTypeDeclTestingTsInFuncLiteral(node) } return true }) } /* * replaces named *testing.T inside a composite literal */ func replaceNamedTestingTsInKeyValueExpression(kve *ast.KeyValueExpr, testingT string) { ident, ok := kve.Value.(*ast.Ident) if !ok { return } if ident.Name == testingT { kve.Value = newGinkgoTFromIdent(ident) } } /* * replaces *testing.T params in a func literal with GinkgoT */ func replaceTypeDeclTestingTsInFuncLiteral(functionLiteral *ast.FuncLit) { for _, arg := range functionLiteral.Type.Params.List { starExpr, ok := arg.Type.(*ast.StarExpr) if !ok { continue } selectorExpr, ok := starExpr.X.(*ast.SelectorExpr) if !ok { continue } target, ok := selectorExpr.X.(*ast.Ident) if !ok { continue } if target.Name == "testing" && selectorExpr.Sel.Name == "T" { arg.Type = newGinkgoTInterface() } } } /* * Replaces *testing.T types inside of a struct declaration with a GinkgoT * eg: type foo struct { *testing.T } */ func replaceTestingTsInStructType(structType *ast.StructType) { for _, field := range structType.Fields.List { starExpr, ok := field.Type.(*ast.StarExpr) if !ok { continue } selectorExpr, ok := starExpr.X.(*ast.SelectorExpr) if !ok { continue } xIdent, ok := selectorExpr.X.(*ast.Ident) if !ok { continue } if xIdent.Name == "testing" && selectorExpr.Sel.Name == "T" { field.Type = newGinkgoTInterface() } } } ginkgo-1.14.2/ginkgo/convert_command.go000066400000000000000000000015771374111457300200600ustar00rootroot00000000000000package main import ( "flag" "fmt" "os" "github.com/onsi/ginkgo/ginkgo/convert" ) func BuildConvertCommand() *Command { return &Command{ Name: "convert", FlagSet: flag.NewFlagSet("convert", flag.ExitOnError), UsageCommand: "ginkgo convert /path/to/package", Usage: []string{ "Convert the package at the passed in path from an XUnit-style test to a Ginkgo-style test", }, Command: convertPackage, } } func convertPackage(args []string, additionalArgs []string) { if len(args) != 1 { println(fmt.Sprintf("usage: ginkgo convert /path/to/your/package")) os.Exit(1) } defer func() { err := recover() if err != nil { switch err := err.(type) { case error: println(err.Error()) case string: println(err) default: println(fmt.Sprintf("unexpected error: %#v", err)) } os.Exit(1) } }() convert.RewritePackage(args[0]) } ginkgo-1.14.2/ginkgo/generate_command.go000066400000000000000000000136151374111457300201660ustar00rootroot00000000000000package main import ( "bytes" "flag" "fmt" "os" "path/filepath" "strconv" "strings" "text/template" ) func BuildGenerateCommand() *Command { var agouti, noDot, internal bool flagSet := flag.NewFlagSet("generate", flag.ExitOnError) flagSet.BoolVar(&agouti, "agouti", false, "If set, generate will generate a test file for writing Agouti tests") flagSet.BoolVar(&noDot, "nodot", false, "If set, generate will generate a test file that does not . import ginkgo and gomega") flagSet.BoolVar(&internal, "internal", false, "If set, generate will generate a test file that uses the regular package name") return &Command{ Name: "generate", FlagSet: flagSet, UsageCommand: "ginkgo generate ", Usage: []string{ "Generate a test file named filename_test.go", "If the optional argument is omitted, a file named after the package in the current directory will be created.", "Accepts the following flags:", }, Command: func(args []string, additionalArgs []string) { generateSpec(args, agouti, noDot, internal) }, } } var specText = `package {{.Package}} import ( {{if .IncludeImports}}. "github.com/onsi/ginkgo"{{end}} {{if .IncludeImports}}. "github.com/onsi/gomega"{{end}} {{if .ImportPackage}}"{{.PackageImportPath}}"{{end}} ) var _ = Describe("{{.Subject}}", func() { }) ` var agoutiSpecText = `package {{.Package}} import ( {{if .IncludeImports}}. "github.com/onsi/ginkgo"{{end}} {{if .IncludeImports}}. "github.com/onsi/gomega"{{end}} "github.com/sclevine/agouti" . "github.com/sclevine/agouti/matchers" {{if .ImportPackage}}"{{.PackageImportPath}}"{{end}} ) var _ = Describe("{{.Subject}}", func() { var page *agouti.Page BeforeEach(func() { var err error page, err = agoutiDriver.NewPage() Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { Expect(page.Destroy()).To(Succeed()) }) }) ` type specData struct { Package string Subject string PackageImportPath string IncludeImports bool ImportPackage bool } func generateSpec(args []string, agouti, noDot, internal bool) { if len(args) == 0 { err := generateSpecForSubject("", agouti, noDot, internal) if err != nil { fmt.Println(err.Error()) fmt.Println("") os.Exit(1) } fmt.Println("") return } var failed bool for _, arg := range args { err := generateSpecForSubject(arg, agouti, noDot, internal) if err != nil { failed = true fmt.Println(err.Error()) } } fmt.Println("") if failed { os.Exit(1) } } func generateSpecForSubject(subject string, agouti, noDot, internal bool) error { packageName, specFilePrefix, formattedName := getPackageAndFormattedName() if subject != "" { specFilePrefix = formatSubject(subject) formattedName = prettifyPackageName(specFilePrefix) } data := specData{ Package: determinePackageName(packageName, internal), Subject: formattedName, PackageImportPath: getPackageImportPath(), IncludeImports: !noDot, ImportPackage: !internal, } targetFile := fmt.Sprintf("%s_test.go", specFilePrefix) if fileExists(targetFile) { return fmt.Errorf("%s already exists.", targetFile) } else { fmt.Printf("Generating ginkgo test for %s in:\n %s\n", data.Subject, targetFile) } f, err := os.Create(targetFile) if err != nil { return err } defer f.Close() var templateText string if agouti { templateText = agoutiSpecText } else { templateText = specText } specTemplate, err := template.New("spec").Parse(templateText) if err != nil { return err } specTemplate.Execute(f, data) goFmt(targetFile) return nil } func formatSubject(name string) string { name = strings.Replace(name, "-", "_", -1) name = strings.Replace(name, " ", "_", -1) name = strings.Split(name, ".go")[0] name = strings.Split(name, "_test")[0] return name } // moduleName returns module name from go.mod from given module root directory func moduleName(modRoot string) string { modFile, err := os.Open(filepath.Join(modRoot, "go.mod")) if err != nil { return "" } mod := make([]byte, 128) _, err = modFile.Read(mod) if err != nil { return "" } slashSlash := []byte("//") moduleStr := []byte("module") for len(mod) > 0 { line := mod mod = nil if i := bytes.IndexByte(line, '\n'); i >= 0 { line, mod = line[:i], line[i+1:] } if i := bytes.Index(line, slashSlash); i >= 0 { line = line[:i] } line = bytes.TrimSpace(line) if !bytes.HasPrefix(line, moduleStr) { continue } line = line[len(moduleStr):] n := len(line) line = bytes.TrimSpace(line) if len(line) == n || len(line) == 0 { continue } if line[0] == '"' || line[0] == '`' { p, err := strconv.Unquote(string(line)) if err != nil { return "" // malformed quoted string or multiline module path } return p } return string(line) } return "" // missing module path } func findModuleRoot(dir string) (root string) { dir = filepath.Clean(dir) // Look for enclosing go.mod. for { if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() { return dir } d := filepath.Dir(dir) if d == dir { break } dir = d } return "" } func getPackageImportPath() string { workingDir, err := os.Getwd() if err != nil { panic(err.Error()) } sep := string(filepath.Separator) // Try go.mod file first modRoot := findModuleRoot(workingDir) if modRoot != "" { modName := moduleName(modRoot) if modName != "" { cd := strings.Replace(workingDir, modRoot, "", -1) cd = strings.ReplaceAll(cd, sep, "/") return modName + cd } } // Fallback to GOPATH structure paths := strings.Split(workingDir, sep+"src"+sep) if len(paths) == 1 { fmt.Printf("\nCouldn't identify package import path.\n\n\tginkgo generate\n\nMust be run within a package directory under $GOPATH/src/...\nYou're going to have to change UNKNOWN_PACKAGE_PATH in the generated file...\n\n") return "UNKNOWN_PACKAGE_PATH" } return filepath.ToSlash(paths[len(paths)-1]) } ginkgo-1.14.2/ginkgo/help_command.go000066400000000000000000000012001374111457300173070ustar00rootroot00000000000000package main import ( "flag" "fmt" ) func BuildHelpCommand() *Command { return &Command{ Name: "help", FlagSet: flag.NewFlagSet("help", flag.ExitOnError), UsageCommand: "ginkgo help ", Usage: []string{ "Print usage information. If a command is passed in, print usage information just for that command.", }, Command: printHelp, } } func printHelp(args []string, additionalArgs []string) { if len(args) == 0 { usage() } else { command, found := commandMatching(args[0]) if !found { complainAndQuit(fmt.Sprintf("Unknown command: %s", args[0])) } usageForCommand(command, true) } } ginkgo-1.14.2/ginkgo/interrupthandler/000077500000000000000000000000001374111457300177335ustar00rootroot00000000000000ginkgo-1.14.2/ginkgo/interrupthandler/interrupt_handler.go000066400000000000000000000014451374111457300240170ustar00rootroot00000000000000package interrupthandler import ( "os" "os/signal" "sync" "syscall" ) type InterruptHandler struct { interruptCount int lock *sync.Mutex C chan bool } func NewInterruptHandler() *InterruptHandler { h := &InterruptHandler{ lock: &sync.Mutex{}, C: make(chan bool), } go h.handleInterrupt() SwallowSigQuit() return h } func (h *InterruptHandler) WasInterrupted() bool { h.lock.Lock() defer h.lock.Unlock() return h.interruptCount > 0 } func (h *InterruptHandler) handleInterrupt() { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) <-c signal.Stop(c) h.lock.Lock() h.interruptCount++ if h.interruptCount == 1 { close(h.C) } else if h.interruptCount > 5 { os.Exit(1) } h.lock.Unlock() go h.handleInterrupt() } ginkgo-1.14.2/ginkgo/interrupthandler/sigquit_swallower_unix.go000066400000000000000000000003431374111457300251110ustar00rootroot00000000000000// +build freebsd openbsd netbsd dragonfly darwin linux solaris package interrupthandler import ( "os" "os/signal" "syscall" ) func SwallowSigQuit() { c := make(chan os.Signal, 1024) signal.Notify(c, syscall.SIGQUIT) } ginkgo-1.14.2/ginkgo/interrupthandler/sigquit_swallower_windows.go000066400000000000000000000001171374111457300256170ustar00rootroot00000000000000// +build windows package interrupthandler func SwallowSigQuit() { //noop } ginkgo-1.14.2/ginkgo/main.go000066400000000000000000000171221374111457300156170ustar00rootroot00000000000000/* 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 /path/to/package /path/to/another/package To pass arguments/flags to your tests: ginkgo -- 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> 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 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 will output an executable file named `package.test`. This can be run directly or by invoking ginkgo 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) { out, err := exec.Command("go", "fmt", path).CombinedOutput() if err != nil { complainAndQuit("Could not fmt: " + err.Error() + "\n" + string(out)) } } func pluralizedWord(singular, plural string, count int) string { if count == 1 { return singular } return plural } ginkgo-1.14.2/ginkgo/nodot/000077500000000000000000000000001374111457300154645ustar00rootroot00000000000000ginkgo-1.14.2/ginkgo/nodot/nodot.go000066400000000000000000000102161374111457300171360ustar00rootroot00000000000000package nodot import ( "fmt" "go/ast" "go/build" "go/parser" "go/token" "path/filepath" "strings" ) func ApplyNoDot(data []byte) ([]byte, error) { sections, err := generateNodotSections() if err != nil { return nil, err } for _, section := range sections { data = section.createOrUpdateIn(data) } return data, nil } type nodotSection struct { name string pkg string declarations []string types []string } func (s nodotSection) createOrUpdateIn(data []byte) []byte { renames := map[string]string{} contents := string(data) lines := strings.Split(contents, "\n") comment := "// Declarations for " + s.name newLines := []string{} for _, line := range lines { if line == comment { continue } words := strings.Split(line, " ") lastWord := words[len(words)-1] if s.containsDeclarationOrType(lastWord) { renames[lastWord] = words[1] continue } newLines = append(newLines, line) } if len(newLines[len(newLines)-1]) > 0 { newLines = append(newLines, "") } newLines = append(newLines, comment) for _, typ := range s.types { name, ok := renames[s.prefix(typ)] if !ok { name = typ } newLines = append(newLines, fmt.Sprintf("type %s %s", name, s.prefix(typ))) } for _, decl := range s.declarations { name, ok := renames[s.prefix(decl)] if !ok { name = decl } newLines = append(newLines, fmt.Sprintf("var %s = %s", name, s.prefix(decl))) } newLines = append(newLines, "") newContents := strings.Join(newLines, "\n") return []byte(newContents) } func (s nodotSection) prefix(declOrType string) string { return s.pkg + "." + declOrType } func (s nodotSection) containsDeclarationOrType(word string) bool { for _, declaration := range s.declarations { if s.prefix(declaration) == word { return true } } for _, typ := range s.types { if s.prefix(typ) == word { return true } } return false } func generateNodotSections() ([]nodotSection, error) { sections := []nodotSection{} declarations, err := getExportedDeclerationsForPackage("github.com/onsi/ginkgo", "ginkgo_dsl.go", "GINKGO_VERSION", "GINKGO_PANIC") if err != nil { return nil, err } sections = append(sections, nodotSection{ name: "Ginkgo DSL", pkg: "ginkgo", declarations: declarations, types: []string{"Done", "Benchmarker"}, }) declarations, err = getExportedDeclerationsForPackage("github.com/onsi/gomega", "gomega_dsl.go", "GOMEGA_VERSION") if err != nil { return nil, err } sections = append(sections, nodotSection{ name: "Gomega DSL", pkg: "gomega", declarations: declarations, }) declarations, err = getExportedDeclerationsForPackage("github.com/onsi/gomega", "matchers.go") if err != nil { return nil, err } sections = append(sections, nodotSection{ name: "Gomega Matchers", pkg: "gomega", declarations: declarations, }) return sections, nil } func getExportedDeclerationsForPackage(pkgPath string, filename string, blacklist ...string) ([]string, error) { pkg, err := build.Import(pkgPath, ".", 0) if err != nil { return []string{}, err } declarations, err := getExportedDeclarationsForFile(filepath.Join(pkg.Dir, filename)) if err != nil { return []string{}, err } blacklistLookup := map[string]bool{} for _, declaration := range blacklist { blacklistLookup[declaration] = true } filteredDeclarations := []string{} for _, declaration := range declarations { if blacklistLookup[declaration] { continue } filteredDeclarations = append(filteredDeclarations, declaration) } return filteredDeclarations, nil } func getExportedDeclarationsForFile(path string) ([]string, error) { fset := token.NewFileSet() tree, err := parser.ParseFile(fset, path, nil, 0) if err != nil { return []string{}, err } declarations := []string{} ast.FileExports(tree) for _, decl := range tree.Decls { switch x := decl.(type) { case *ast.GenDecl: switch s := x.Specs[0].(type) { case *ast.ValueSpec: declarations = append(declarations, s.Names[0].Name) } case *ast.FuncDecl: if x.Recv == nil { declarations = append(declarations, x.Name.Name) } } } return declarations, nil } ginkgo-1.14.2/ginkgo/nodot/nodot_suite_test.go000066400000000000000000000061101374111457300214040ustar00rootroot00000000000000package nodot_test import ( "github.com/onsi/ginkgo" "github.com/onsi/gomega" "testing" ) func TestNodot(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Nodot Suite") } // Declarations for Ginkgo DSL type Done ginkgo.Done type Benchmarker ginkgo.Benchmarker var GinkgoWriter = ginkgo.GinkgoWriter var GinkgoParallelNode = ginkgo.GinkgoParallelNode var GinkgoT = ginkgo.GinkgoT var CurrentGinkgoTestDescription = ginkgo.CurrentGinkgoTestDescription var RunSpecs = ginkgo.RunSpecs var RunSpecsWithDefaultAndCustomReporters = ginkgo.RunSpecsWithDefaultAndCustomReporters var RunSpecsWithCustomReporters = ginkgo.RunSpecsWithCustomReporters var Fail = ginkgo.Fail var GinkgoRecover = ginkgo.GinkgoRecover var Describe = ginkgo.Describe var FDescribe = ginkgo.FDescribe var PDescribe = ginkgo.PDescribe var XDescribe = ginkgo.XDescribe var Context = ginkgo.Context var FContext = ginkgo.FContext var PContext = ginkgo.PContext var XContext = ginkgo.XContext var It = ginkgo.It var FIt = ginkgo.FIt var PIt = ginkgo.PIt var XIt = ginkgo.XIt var Measure = ginkgo.Measure var FMeasure = ginkgo.FMeasure var PMeasure = ginkgo.PMeasure var XMeasure = ginkgo.XMeasure var BeforeSuite = ginkgo.BeforeSuite var AfterSuite = ginkgo.AfterSuite var SynchronizedBeforeSuite = ginkgo.SynchronizedBeforeSuite var SynchronizedAfterSuite = ginkgo.SynchronizedAfterSuite var BeforeEach = ginkgo.BeforeEach var JustBeforeEach = ginkgo.JustBeforeEach var JustAfterEach = ginkgo.JustAfterEach var AfterEach = ginkgo.AfterEach // Declarations for Gomega DSL var RegisterFailHandler = gomega.RegisterFailHandler var RegisterTestingT = gomega.RegisterTestingT var InterceptGomegaFailures = gomega.InterceptGomegaFailures var Ω = gomega.Ω var Expect = gomega.Expect var ExpectWithOffset = gomega.ExpectWithOffset var Eventually = gomega.Eventually var EventuallyWithOffset = gomega.EventuallyWithOffset var Consistently = gomega.Consistently var ConsistentlyWithOffset = gomega.ConsistentlyWithOffset var SetDefaultEventuallyTimeout = gomega.SetDefaultEventuallyTimeout var SetDefaultEventuallyPollingInterval = gomega.SetDefaultEventuallyPollingInterval var SetDefaultConsistentlyDuration = gomega.SetDefaultConsistentlyDuration var SetDefaultConsistentlyPollingInterval = gomega.SetDefaultConsistentlyPollingInterval // Declarations for Gomega Matchers var Equal = gomega.Equal var BeEquivalentTo = gomega.BeEquivalentTo var BeNil = gomega.BeNil var BeTrue = gomega.BeTrue var BeFalse = gomega.BeFalse var HaveOccurred = gomega.HaveOccurred var MatchError = gomega.MatchError var BeClosed = gomega.BeClosed var Receive = gomega.Receive var MatchRegexp = gomega.MatchRegexp var ContainSubstring = gomega.ContainSubstring var MatchJSON = gomega.MatchJSON var BeEmpty = gomega.BeEmpty var HaveLen = gomega.HaveLen var BeZero = gomega.BeZero var ContainElement = gomega.ContainElement var ConsistOf = gomega.ConsistOf var HaveKey = gomega.HaveKey var HaveKeyWithValue = gomega.HaveKeyWithValue var BeNumerically = gomega.BeNumerically var BeTemporally = gomega.BeTemporally var BeAssignableToTypeOf = gomega.BeAssignableToTypeOf var Panic = gomega.Panic ginkgo-1.14.2/ginkgo/nodot/nodot_test.go000066400000000000000000000050771374111457300202060ustar00rootroot00000000000000package nodot_test import ( "strings" . "github.com/onsi/ginkgo/ginkgo/nodot" ) var _ = Describe("ApplyNoDot", func() { var result string apply := func(input string) string { output, err := ApplyNoDot([]byte(input)) Ω(err).ShouldNot(HaveOccurred()) return string(output) } Context("when no declarations have been imported yet", func() { BeforeEach(func() { result = apply("") }) It("should add headings for the various declarations", func() { Ω(result).Should(ContainSubstring("// Declarations for Ginkgo DSL")) Ω(result).Should(ContainSubstring("// Declarations for Gomega DSL")) Ω(result).Should(ContainSubstring("// Declarations for Gomega Matchers")) }) It("should import Ginkgo's declarations", func() { Ω(result).Should(ContainSubstring("var It = ginkgo.It")) Ω(result).Should(ContainSubstring("var XDescribe = ginkgo.XDescribe")) }) It("should import Ginkgo's types", func() { Ω(result).Should(ContainSubstring("type Done ginkgo.Done")) Ω(result).Should(ContainSubstring("type Benchmarker ginkgo.Benchmarker")) Ω(strings.Count(result, "type ")).Should(Equal(2)) }) It("should import Gomega's DSL and matchers", func() { Ω(result).Should(ContainSubstring("var Ω = gomega.Ω")) Ω(result).Should(ContainSubstring("var ContainSubstring = gomega.ContainSubstring")) Ω(result).Should(ContainSubstring("var Equal = gomega.Equal")) }) It("should not import blacklisted things", func() { Ω(result).ShouldNot(ContainSubstring("GINKGO_VERSION")) Ω(result).ShouldNot(ContainSubstring("GINKGO_PANIC")) Ω(result).ShouldNot(ContainSubstring("GOMEGA_VERSION")) }) }) It("should be idempotent (module empty lines - go fmt can fix those for us)", func() { first := apply("") second := apply(first) first = strings.Trim(first, "\n") second = strings.Trim(second, "\n") Ω(first).Should(Equal(second)) }) It("should not mess with other things in the input", func() { result = apply("var MyThing = SomethingThatsMine") Ω(result).Should(ContainSubstring("var MyThing = SomethingThatsMine")) }) Context("when the user has redefined a name", func() { It("should honor the redefinition", func() { result = apply(` var _ = gomega.Ω var When = ginkgo.It `) Ω(result).Should(ContainSubstring("var _ = gomega.Ω")) Ω(result).ShouldNot(ContainSubstring("var Ω = gomega.Ω")) Ω(result).Should(ContainSubstring("var When = ginkgo.It")) Ω(result).ShouldNot(ContainSubstring("var It = ginkgo.It")) Ω(result).Should(ContainSubstring("var Context = ginkgo.Context")) }) }) }) ginkgo-1.14.2/ginkgo/nodot_command.go000066400000000000000000000036571374111457300175240ustar00rootroot00000000000000package main import ( "bufio" "flag" "io/ioutil" "os" "path/filepath" "regexp" "github.com/onsi/ginkgo/ginkgo/nodot" ) func BuildNodotCommand() *Command { return &Command{ Name: "nodot", FlagSet: flag.NewFlagSet("bootstrap", flag.ExitOnError), UsageCommand: "ginkgo nodot", Usage: []string{ "Update the nodot declarations in your test suite", "Any missing declarations (from, say, a recently added matcher) will be added to your bootstrap file.", "If you've renamed a declaration, that name will be honored and not overwritten.", }, Command: updateNodot, } } func updateNodot(args []string, additionalArgs []string) { suiteFile, perm := findSuiteFile() data, err := ioutil.ReadFile(suiteFile) if err != nil { complainAndQuit("Failed to update nodot declarations: " + err.Error()) } content, err := nodot.ApplyNoDot(data) if err != nil { complainAndQuit("Failed to update nodot declarations: " + err.Error()) } ioutil.WriteFile(suiteFile, content, perm) goFmt(suiteFile) } func findSuiteFile() (string, os.FileMode) { workingDir, err := os.Getwd() if err != nil { complainAndQuit("Could not find suite file for nodot: " + err.Error()) } files, err := ioutil.ReadDir(workingDir) if err != nil { complainAndQuit("Could not find suite file for nodot: " + err.Error()) } re := regexp.MustCompile(`RunSpecs\(|RunSpecsWithDefaultAndCustomReporters\(|RunSpecsWithCustomReporters\(`) for _, file := range files { if file.IsDir() { continue } path := filepath.Join(workingDir, file.Name()) f, err := os.Open(path) if err != nil { complainAndQuit("Could not find suite file for nodot: " + err.Error()) } defer f.Close() if re.MatchReader(bufio.NewReader(f)) { return path, file.Mode() } } complainAndQuit("Could not find a suite file for nodot: you need a bootstrap file that call's Ginkgo's RunSpecs() command.\nTry running ginkgo bootstrap first.") return "", 0 } ginkgo-1.14.2/ginkgo/notifications.go000066400000000000000000000067441374111457300175540ustar00rootroot00000000000000package main import ( "fmt" "os" "os/exec" "regexp" "runtime" "strings" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/ginkgo/testsuite" ) type Notifier struct { commandFlags *RunWatchAndBuildCommandFlags } func NewNotifier(commandFlags *RunWatchAndBuildCommandFlags) *Notifier { return &Notifier{ commandFlags: commandFlags, } } func (n *Notifier) VerifyNotificationsAreAvailable() { if n.commandFlags.Notify { onLinux := (runtime.GOOS == "linux") onOSX := (runtime.GOOS == "darwin") if onOSX { _, err := exec.LookPath("terminal-notifier") if err != nil { fmt.Printf(`--notify requires terminal-notifier, which you don't seem to have installed. OSX: To remedy this: brew install terminal-notifier To learn more about terminal-notifier: https://github.com/alloy/terminal-notifier `) os.Exit(1) } } else if onLinux { _, err := exec.LookPath("notify-send") if err != nil { fmt.Printf(`--notify requires terminal-notifier or notify-send, which you don't seem to have installed. Linux: Download and install notify-send for your distribution `) os.Exit(1) } } } } func (n *Notifier) SendSuiteCompletionNotification(suite testsuite.TestSuite, suitePassed bool) { if suitePassed { n.SendNotification("Ginkgo [PASS]", fmt.Sprintf(`Test suite for "%s" passed.`, suite.PackageName)) } else { n.SendNotification("Ginkgo [FAIL]", fmt.Sprintf(`Test suite for "%s" failed.`, suite.PackageName)) } } func (n *Notifier) SendNotification(title string, subtitle string) { if n.commandFlags.Notify { onLinux := (runtime.GOOS == "linux") onOSX := (runtime.GOOS == "darwin") if onOSX { _, err := exec.LookPath("terminal-notifier") if err == nil { args := []string{"-title", title, "-subtitle", subtitle, "-group", "com.onsi.ginkgo"} terminal := os.Getenv("TERM_PROGRAM") if terminal == "iTerm.app" { args = append(args, "-activate", "com.googlecode.iterm2") } else if terminal == "Apple_Terminal" { args = append(args, "-activate", "com.apple.Terminal") } exec.Command("terminal-notifier", args...).Run() } } else if onLinux { _, err := exec.LookPath("notify-send") if err == nil { args := []string{"-a", "ginkgo", title, subtitle} exec.Command("notify-send", args...).Run() } } } } func (n *Notifier) RunCommand(suite testsuite.TestSuite, suitePassed bool) { command := n.commandFlags.AfterSuiteHook if command != "" { // Allow for string replacement to pass input to the command passed := "[FAIL]" if suitePassed { passed = "[PASS]" } command = strings.Replace(command, "(ginkgo-suite-passed)", passed, -1) command = strings.Replace(command, "(ginkgo-suite-name)", suite.PackageName, -1) // Must break command into parts splitArgs := regexp.MustCompile(`'.+'|".+"|\S+`) parts := splitArgs.FindAllString(command, -1) output, err := exec.Command(parts[0], parts[1:]...).CombinedOutput() if err != nil { fmt.Println("Post-suite command failed:") if config.DefaultReporterConfig.NoColor { fmt.Printf("\t%s\n", output) } else { fmt.Printf("\t%s%s%s\n", redColor, string(output), defaultStyle) } n.SendNotification("Ginkgo [ERROR]", fmt.Sprintf(`After suite command "%s" failed`, n.commandFlags.AfterSuiteHook)) } else { fmt.Println("Post-suite command succeeded:") if config.DefaultReporterConfig.NoColor { fmt.Printf("\t%s\n", output) } else { fmt.Printf("\t%s%s%s\n", greenColor, string(output), defaultStyle) } } } } ginkgo-1.14.2/ginkgo/run_command.go000066400000000000000000000176201374111457300172000ustar00rootroot00000000000000package main import ( "flag" "fmt" "math/rand" "os" "regexp" "strings" "time" "io/ioutil" "path/filepath" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/ginkgo/interrupthandler" "github.com/onsi/ginkgo/ginkgo/testrunner" "github.com/onsi/ginkgo/types" ) func BuildRunCommand() *Command { commandFlags := NewRunCommandFlags(flag.NewFlagSet("ginkgo", flag.ExitOnError)) notifier := NewNotifier(commandFlags) interruptHandler := interrupthandler.NewInterruptHandler() runner := &SpecRunner{ commandFlags: commandFlags, notifier: notifier, interruptHandler: interruptHandler, suiteRunner: NewSuiteRunner(notifier, interruptHandler), } return &Command{ Name: "", FlagSet: commandFlags.FlagSet, UsageCommand: "ginkgo -- ", Usage: []string{ "Run the tests in the passed in (or the package in the current directory if left blank).", "Any arguments after -- will be passed to the test.", "Accepts the following flags:", }, Command: runner.RunSpecs, } } type SpecRunner struct { commandFlags *RunWatchAndBuildCommandFlags notifier *Notifier interruptHandler *interrupthandler.InterruptHandler suiteRunner *SuiteRunner } func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) { r.commandFlags.computeNodes() r.notifier.VerifyNotificationsAreAvailable() suites, skippedPackages := findSuites(args, r.commandFlags.Recurse, r.commandFlags.SkipPackage, true) if len(skippedPackages) > 0 { fmt.Println("Will skip:") for _, skippedPackage := range skippedPackages { fmt.Println(" " + skippedPackage) } } if len(skippedPackages) > 0 && len(suites) == 0 { fmt.Println("All tests skipped! Exiting...") os.Exit(0) } if len(suites) == 0 { complainAndQuit("Found no test suites") } r.ComputeSuccinctMode(len(suites)) t := time.Now() runners := []*testrunner.TestRunner{} for _, suite := range suites { runners = append(runners, testrunner.New(suite, r.commandFlags.NumCPU, r.commandFlags.ParallelStream, r.commandFlags.Timeout, r.commandFlags.GoOpts, additionalArgs)) } numSuites := 0 runResult := testrunner.PassingRunResult() if r.commandFlags.UntilItFails { iteration := 0 for { r.UpdateSeed() randomizedRunners := r.randomizeOrder(runners) runResult, numSuites = r.suiteRunner.RunSuites(randomizedRunners, r.commandFlags.NumCompilers, r.commandFlags.KeepGoing, nil) iteration++ if r.interruptHandler.WasInterrupted() { break } if runResult.Passed { fmt.Printf("\nAll tests passed...\nWill keep running them until they fail.\nThis was attempt #%d\n%s\n", iteration, orcMessage(iteration)) } else { fmt.Printf("\nTests failed on attempt #%d\n\n", iteration) break } } } else { randomizedRunners := r.randomizeOrder(runners) runResult, numSuites = r.suiteRunner.RunSuites(randomizedRunners, r.commandFlags.NumCompilers, r.commandFlags.KeepGoing, nil) } for _, runner := range runners { runner.CleanUp() } if r.isInCoverageMode() { if r.getOutputDir() != "" { // If coverprofile is set, combine coverages if r.getCoverprofile() != "" { if err := r.combineCoverprofiles(runners); err != nil { fmt.Println(err.Error()) os.Exit(1) } } else { // Just move them r.moveCoverprofiles(runners) } } } fmt.Printf("\nGinkgo ran %d %s in %s\n", numSuites, pluralizedWord("suite", "suites", numSuites), time.Since(t)) if runResult.Passed { if runResult.HasProgrammaticFocus && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" { fmt.Printf("Test Suite Passed\n") fmt.Printf("Detected Programmatic Focus - setting exit status to %d\n", types.GINKGO_FOCUS_EXIT_CODE) os.Exit(types.GINKGO_FOCUS_EXIT_CODE) } else { fmt.Printf("Test Suite Passed\n") os.Exit(0) } } else { fmt.Printf("Test Suite Failed\n") os.Exit(1) } } // Moves all generated profiles to specified directory func (r *SpecRunner) moveCoverprofiles(runners []*testrunner.TestRunner) { for _, runner := range runners { _, filename := filepath.Split(runner.CoverageFile) err := os.Rename(runner.CoverageFile, filepath.Join(r.getOutputDir(), filename)) if err != nil { fmt.Printf("Unable to move coverprofile %s, %v\n", runner.CoverageFile, err) return } } } // Combines all generated profiles in the specified directory func (r *SpecRunner) combineCoverprofiles(runners []*testrunner.TestRunner) error { path, _ := filepath.Abs(r.getOutputDir()) if !fileExists(path) { return fmt.Errorf("Unable to create combined profile, outputdir does not exist: %s", r.getOutputDir()) } fmt.Println("path is " + path) combined, err := os.OpenFile( filepath.Join(path, r.getCoverprofile()), os.O_WRONLY|os.O_CREATE, 0666, ) if err != nil { fmt.Printf("Unable to create combined profile, %v\n", err) return nil // non-fatal error } modeRegex := regexp.MustCompile(`^mode: .*\n`) for index, runner := range runners { contents, err := ioutil.ReadFile(runner.CoverageFile) if err != nil { fmt.Printf("Unable to read coverage file %s to combine, %v\n", runner.CoverageFile, err) return nil // non-fatal error } // remove the cover mode line from every file // except the first one if index > 0 { contents = modeRegex.ReplaceAll(contents, []byte{}) } _, err = combined.Write(contents) // Add a newline to the end of every file if missing. if err == nil && len(contents) > 0 && contents[len(contents)-1] != '\n' { _, err = combined.Write([]byte("\n")) } if err != nil { fmt.Printf("Unable to append to coverprofile, %v\n", err) return nil // non-fatal error } } fmt.Println("All profiles combined") return nil } func (r *SpecRunner) isInCoverageMode() bool { opts := r.commandFlags.GoOpts return *opts["cover"].(*bool) || *opts["coverpkg"].(*string) != "" || *opts["covermode"].(*string) != "" } func (r *SpecRunner) getCoverprofile() string { return *r.commandFlags.GoOpts["coverprofile"].(*string) } func (r *SpecRunner) getOutputDir() string { return *r.commandFlags.GoOpts["outputdir"].(*string) } func (r *SpecRunner) ComputeSuccinctMode(numSuites int) { if config.DefaultReporterConfig.Verbose { config.DefaultReporterConfig.Succinct = false return } if numSuites == 1 { return } if numSuites > 1 && !r.commandFlags.wasSet("succinct") { config.DefaultReporterConfig.Succinct = true } } func (r *SpecRunner) UpdateSeed() { if !r.commandFlags.wasSet("seed") { config.GinkgoConfig.RandomSeed = time.Now().Unix() } } func (r *SpecRunner) randomizeOrder(runners []*testrunner.TestRunner) []*testrunner.TestRunner { if !r.commandFlags.RandomizeSuites { return runners } if len(runners) <= 1 { return runners } randomizedRunners := make([]*testrunner.TestRunner, len(runners)) randomizer := rand.New(rand.NewSource(config.GinkgoConfig.RandomSeed)) permutation := randomizer.Perm(len(runners)) for i, j := range permutation { randomizedRunners[i] = runners[j] } return randomizedRunners } func orcMessage(iteration int) string { if iteration < 10 { return "" } else if iteration < 30 { return []string{ "If at first you succeed...", "...try, try again.", "Looking good!", "Still good...", "I think your tests are fine....", "Yep, still passing", "Oh boy, here I go testin' again!", "Even the gophers are getting bored", "Did you try -race?", "Maybe you should stop now?", "I'm getting tired...", "What if I just made you a sandwich?", "Hit ^C, hit ^C, please hit ^C", "Make it stop. Please!", "Come on! Enough is enough!", "Dave, this conversation can serve no purpose anymore. Goodbye.", "Just what do you think you're doing, Dave? ", "I, Sisyphus", "Insanity: doing the same thing over and over again and expecting different results. -Einstein", "I guess Einstein never tried to churn butter", }[iteration-10] + "\n" } else { return "No, seriously... you can probably stop now.\n" } } ginkgo-1.14.2/ginkgo/run_watch_and_build_command_flags.go000066400000000000000000000172231374111457300235420ustar00rootroot00000000000000package main import ( "flag" "runtime" "time" "github.com/onsi/ginkgo/config" ) type RunWatchAndBuildCommandFlags struct { Recurse bool SkipPackage string GoOpts map[string]interface{} //for run and watch commands NumCPU int NumCompilers int ParallelStream bool Notify bool AfterSuiteHook string AutoNodes bool Timeout time.Duration //only for run command KeepGoing bool UntilItFails bool RandomizeSuites bool //only for watch command Depth int WatchRegExp string FlagSet *flag.FlagSet } const runMode = 1 const watchMode = 2 const buildMode = 3 func NewRunCommandFlags(flagSet *flag.FlagSet) *RunWatchAndBuildCommandFlags { c := &RunWatchAndBuildCommandFlags{ FlagSet: flagSet, } c.flags(runMode) return c } func NewWatchCommandFlags(flagSet *flag.FlagSet) *RunWatchAndBuildCommandFlags { c := &RunWatchAndBuildCommandFlags{ FlagSet: flagSet, } c.flags(watchMode) return c } func NewBuildCommandFlags(flagSet *flag.FlagSet) *RunWatchAndBuildCommandFlags { c := &RunWatchAndBuildCommandFlags{ FlagSet: flagSet, } c.flags(buildMode) return c } func (c *RunWatchAndBuildCommandFlags) wasSet(flagName string) bool { wasSet := false c.FlagSet.Visit(func(f *flag.Flag) { if f.Name == flagName { wasSet = true } }) return wasSet } func (c *RunWatchAndBuildCommandFlags) computeNodes() { if c.wasSet("nodes") { return } if c.AutoNodes { switch n := runtime.NumCPU(); { case n <= 4: c.NumCPU = n default: c.NumCPU = n - 1 } } } func (c *RunWatchAndBuildCommandFlags) stringSlot(slot string) *string { var opt string c.GoOpts[slot] = &opt return &opt } func (c *RunWatchAndBuildCommandFlags) boolSlot(slot string) *bool { var opt bool c.GoOpts[slot] = &opt return &opt } func (c *RunWatchAndBuildCommandFlags) intSlot(slot string) *int { var opt int c.GoOpts[slot] = &opt return &opt } func (c *RunWatchAndBuildCommandFlags) flags(mode int) { c.GoOpts = make(map[string]interface{}) onWindows := (runtime.GOOS == "windows") c.FlagSet.BoolVar(&(c.Recurse), "r", false, "Find and run test suites under the current directory recursively.") c.FlagSet.BoolVar(c.boolSlot("race"), "race", false, "Run tests with race detection enabled.") c.FlagSet.BoolVar(c.boolSlot("cover"), "cover", false, "Run tests with coverage analysis, will generate coverage profiles with the package name in the current directory.") c.FlagSet.StringVar(c.stringSlot("coverpkg"), "coverpkg", "", "Run tests with coverage on the given external modules.") c.FlagSet.StringVar(&(c.SkipPackage), "skipPackage", "", "A comma-separated list of package names to be skipped. If any part of the package's path matches, that package is ignored.") c.FlagSet.StringVar(c.stringSlot("tags"), "tags", "", "A list of build tags to consider satisfied during the build.") c.FlagSet.StringVar(c.stringSlot("gcflags"), "gcflags", "", "Arguments to pass on each go tool compile invocation.") c.FlagSet.StringVar(c.stringSlot("covermode"), "covermode", "", "Set the mode for coverage analysis.") c.FlagSet.BoolVar(c.boolSlot("a"), "a", false, "Force rebuilding of packages that are already up-to-date.") c.FlagSet.BoolVar(c.boolSlot("n"), "n", false, "Have `go test` print the commands but do not run them.") c.FlagSet.BoolVar(c.boolSlot("msan"), "msan", false, "Enable interoperation with memory sanitizer.") c.FlagSet.BoolVar(c.boolSlot("x"), "x", false, "Have `go test` print the commands.") c.FlagSet.BoolVar(c.boolSlot("work"), "work", false, "Print the name of the temporary work directory and do not delete it when exiting.") c.FlagSet.StringVar(c.stringSlot("asmflags"), "asmflags", "", "Arguments to pass on each go tool asm invocation.") c.FlagSet.StringVar(c.stringSlot("buildmode"), "buildmode", "", "Build mode to use. See 'go help buildmode' for more.") c.FlagSet.StringVar(c.stringSlot("mod"), "mod", "", "Go module control. See 'go help modules' for more.") c.FlagSet.StringVar(c.stringSlot("compiler"), "compiler", "", "Name of compiler to use, as in runtime.Compiler (gccgo or gc).") c.FlagSet.StringVar(c.stringSlot("gccgoflags"), "gccgoflags", "", "Arguments to pass on each gccgo compiler/linker invocation.") c.FlagSet.StringVar(c.stringSlot("installsuffix"), "installsuffix", "", "A suffix to use in the name of the package installation directory.") c.FlagSet.StringVar(c.stringSlot("ldflags"), "ldflags", "", "Arguments to pass on each go tool link invocation.") c.FlagSet.BoolVar(c.boolSlot("linkshared"), "linkshared", false, "Link against shared libraries previously created with -buildmode=shared.") c.FlagSet.StringVar(c.stringSlot("pkgdir"), "pkgdir", "", "install and load all packages from the given dir instead of the usual locations.") c.FlagSet.StringVar(c.stringSlot("toolexec"), "toolexec", "", "a program to use to invoke toolchain programs like vet and asm.") c.FlagSet.IntVar(c.intSlot("blockprofilerate"), "blockprofilerate", 1, "Control the detail provided in goroutine blocking profiles by calling runtime.SetBlockProfileRate with the given value.") c.FlagSet.StringVar(c.stringSlot("coverprofile"), "coverprofile", "", "Write a coverage profile to the specified file after all tests have passed.") c.FlagSet.StringVar(c.stringSlot("cpuprofile"), "cpuprofile", "", "Write a CPU profile to the specified file before exiting.") c.FlagSet.StringVar(c.stringSlot("memprofile"), "memprofile", "", "Write a memory profile to the specified file after all tests have passed.") c.FlagSet.IntVar(c.intSlot("memprofilerate"), "memprofilerate", 0, "Enable more precise (and expensive) memory profiles by setting runtime.MemProfileRate.") c.FlagSet.StringVar(c.stringSlot("outputdir"), "outputdir", "", "Place output files from profiling in the specified directory.") c.FlagSet.BoolVar(c.boolSlot("requireSuite"), "requireSuite", false, "Fail if there are ginkgo tests in a directory but no test suite (missing RunSpecs)") c.FlagSet.StringVar(c.stringSlot("vet"), "vet", "", "Configure the invocation of 'go vet' to use the comma-separated list of vet checks. If list is 'off', 'go test' does not run 'go vet' at all.") if mode == runMode || mode == watchMode { config.Flags(c.FlagSet, "", false) c.FlagSet.IntVar(&(c.NumCPU), "nodes", 1, "The number of parallel test nodes to run") c.FlagSet.IntVar(&(c.NumCompilers), "compilers", 0, "The number of concurrent compilations to run (0 will autodetect)") c.FlagSet.BoolVar(&(c.AutoNodes), "p", false, "Run in parallel with auto-detected number of nodes") c.FlagSet.BoolVar(&(c.ParallelStream), "stream", onWindows, "stream parallel test output in real time: less coherent, but useful for debugging") if !onWindows { c.FlagSet.BoolVar(&(c.Notify), "notify", false, "Send desktop notifications when a test run completes") } c.FlagSet.StringVar(&(c.AfterSuiteHook), "afterSuiteHook", "", "Run a command when a suite test run completes") c.FlagSet.DurationVar(&(c.Timeout), "timeout", 24*time.Hour, "Suite fails if it does not complete within the specified timeout") } if mode == runMode { c.FlagSet.BoolVar(&(c.KeepGoing), "keepGoing", false, "When true, failures from earlier test suites do not prevent later test suites from running") c.FlagSet.BoolVar(&(c.UntilItFails), "untilItFails", false, "When true, Ginkgo will keep rerunning tests until a failure occurs") c.FlagSet.BoolVar(&(c.RandomizeSuites), "randomizeSuites", false, "When true, Ginkgo will randomize the order in which test suites run") } if mode == watchMode { c.FlagSet.IntVar(&(c.Depth), "depth", 1, "Ginkgo will watch dependencies down to this depth in the dependency tree") c.FlagSet.StringVar(&(c.WatchRegExp), "watchRegExp", `\.go$`, "Files matching this regular expression will be watched for changes") } } ginkgo-1.14.2/ginkgo/suite_runner.go000066400000000000000000000125371374111457300174220ustar00rootroot00000000000000package main import ( "fmt" "runtime" "sync" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/ginkgo/interrupthandler" "github.com/onsi/ginkgo/ginkgo/testrunner" "github.com/onsi/ginkgo/ginkgo/testsuite" colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable" ) type compilationInput struct { runner *testrunner.TestRunner result chan compilationOutput } type compilationOutput struct { runner *testrunner.TestRunner err error } type SuiteRunner struct { notifier *Notifier interruptHandler *interrupthandler.InterruptHandler } func NewSuiteRunner(notifier *Notifier, interruptHandler *interrupthandler.InterruptHandler) *SuiteRunner { return &SuiteRunner{ notifier: notifier, interruptHandler: interruptHandler, } } func (r *SuiteRunner) compileInParallel(runners []*testrunner.TestRunner, numCompilers int, willCompile func(suite testsuite.TestSuite)) chan compilationOutput { //we return this to the consumer, it will return each runner in order as it compiles compilationOutputs := make(chan compilationOutput, len(runners)) //an array of channels - the nth runner's compilation output is sent to the nth channel in this array //we read from these channels in order to ensure we run the suites in order orderedCompilationOutputs := []chan compilationOutput{} for range runners { orderedCompilationOutputs = append(orderedCompilationOutputs, make(chan compilationOutput, 1)) } //we're going to spin up numCompilers compilers - they're going to run concurrently and will consume this channel //we prefill the channel then close it, this ensures we compile things in the correct order workPool := make(chan compilationInput, len(runners)) for i, runner := range runners { workPool <- compilationInput{runner, orderedCompilationOutputs[i]} } close(workPool) //pick a reasonable numCompilers if numCompilers == 0 { numCompilers = runtime.NumCPU() } //a WaitGroup to help us wait for all compilers to shut down wg := &sync.WaitGroup{} wg.Add(numCompilers) //spin up the concurrent compilers for i := 0; i < numCompilers; i++ { go func() { defer wg.Done() for input := range workPool { if r.interruptHandler.WasInterrupted() { return } if willCompile != nil { willCompile(input.runner.Suite) } //We retry because Go sometimes steps on itself when multiple compiles happen in parallel. This is ugly, but should help resolve flakiness... var err error retries := 0 for retries <= 5 { if r.interruptHandler.WasInterrupted() { return } if err = input.runner.Compile(); err == nil { break } retries++ } input.result <- compilationOutput{input.runner, err} } }() } //read from the compilation output channels *in order* and send them to the caller //close the compilationOutputs channel to tell the caller we're done go func() { defer close(compilationOutputs) for _, orderedCompilationOutput := range orderedCompilationOutputs { select { case compilationOutput := <-orderedCompilationOutput: compilationOutputs <- compilationOutput case <-r.interruptHandler.C: //interrupt detected, wait for the compilers to shut down then bail //this ensure we clean up after ourselves as we don't leave any compilation processes running wg.Wait() return } } }() return compilationOutputs } func (r *SuiteRunner) RunSuites(runners []*testrunner.TestRunner, numCompilers int, keepGoing bool, willCompile func(suite testsuite.TestSuite)) (testrunner.RunResult, int) { runResult := testrunner.PassingRunResult() compilationOutputs := r.compileInParallel(runners, numCompilers, willCompile) numSuitesThatRan := 0 suitesThatFailed := []testsuite.TestSuite{} for compilationOutput := range compilationOutputs { if compilationOutput.err != nil { fmt.Print(compilationOutput.err.Error()) } numSuitesThatRan++ suiteRunResult := testrunner.FailingRunResult() if compilationOutput.err == nil { suiteRunResult = compilationOutput.runner.Run() } r.notifier.SendSuiteCompletionNotification(compilationOutput.runner.Suite, suiteRunResult.Passed) r.notifier.RunCommand(compilationOutput.runner.Suite, suiteRunResult.Passed) runResult = runResult.Merge(suiteRunResult) if !suiteRunResult.Passed { suitesThatFailed = append(suitesThatFailed, compilationOutput.runner.Suite) if !keepGoing { break } } if numSuitesThatRan < len(runners) && !config.DefaultReporterConfig.Succinct { fmt.Println("") } } if keepGoing && !runResult.Passed { r.listFailedSuites(suitesThatFailed) } return runResult, numSuitesThatRan } func (r *SuiteRunner) listFailedSuites(suitesThatFailed []testsuite.TestSuite) { fmt.Println("") fmt.Println("There were failures detected in the following suites:") maxPackageNameLength := 0 for _, suite := range suitesThatFailed { if len(suite.PackageName) > maxPackageNameLength { maxPackageNameLength = len(suite.PackageName) } } packageNameFormatter := fmt.Sprintf("%%%ds", maxPackageNameLength) for _, suite := range suitesThatFailed { if config.DefaultReporterConfig.NoColor { fmt.Printf("\t"+packageNameFormatter+" %s\n", suite.PackageName, suite.Path) } else { fmt.Fprintf(colorable.NewColorableStdout(), "\t%s"+packageNameFormatter+"%s %s%s%s\n", redColor, suite.PackageName, defaultStyle, lightGrayColor, suite.Path, defaultStyle) } } } ginkgo-1.14.2/ginkgo/testrunner/000077500000000000000000000000001374111457300165525ustar00rootroot00000000000000ginkgo-1.14.2/ginkgo/testrunner/build_args.go000066400000000000000000000001221374111457300212070ustar00rootroot00000000000000// +build go1.10 package testrunner var ( buildArgs = []string{"test", "-c"} ) ginkgo-1.14.2/ginkgo/testrunner/build_args_old.go000066400000000000000000000001311374111457300220450ustar00rootroot00000000000000// +build !go1.10 package testrunner var ( buildArgs = []string{"test", "-c", "-i"} ) ginkgo-1.14.2/ginkgo/testrunner/log_writer.go000066400000000000000000000015511374111457300212600ustar00rootroot00000000000000package testrunner import ( "bytes" "fmt" "io" "log" "strings" "sync" ) type logWriter struct { buffer *bytes.Buffer lock *sync.Mutex log *log.Logger } func newLogWriter(target io.Writer, node int) *logWriter { return &logWriter{ buffer: &bytes.Buffer{}, lock: &sync.Mutex{}, log: log.New(target, fmt.Sprintf("[%d] ", node), 0), } } func (w *logWriter) Write(data []byte) (n int, err error) { w.lock.Lock() defer w.lock.Unlock() w.buffer.Write(data) contents := w.buffer.String() lines := strings.Split(contents, "\n") for _, line := range lines[0 : len(lines)-1] { w.log.Println(line) } w.buffer.Reset() w.buffer.Write([]byte(lines[len(lines)-1])) return len(data), nil } func (w *logWriter) Close() error { w.lock.Lock() defer w.lock.Unlock() if w.buffer.Len() > 0 { w.log.Println(w.buffer.String()) } return nil } ginkgo-1.14.2/ginkgo/testrunner/run_result.go000066400000000000000000000010341374111457300213010ustar00rootroot00000000000000package testrunner type RunResult struct { Passed bool HasProgrammaticFocus bool } func PassingRunResult() RunResult { return RunResult{ Passed: true, HasProgrammaticFocus: false, } } func FailingRunResult() RunResult { return RunResult{ Passed: false, HasProgrammaticFocus: false, } } func (r RunResult) Merge(o RunResult) RunResult { return RunResult{ Passed: r.Passed && o.Passed, HasProgrammaticFocus: r.HasProgrammaticFocus || o.HasProgrammaticFocus, } } ginkgo-1.14.2/ginkgo/testrunner/test_runner.go000066400000000000000000000313161374111457300214550ustar00rootroot00000000000000package testrunner import ( "bytes" "fmt" "io" "io/ioutil" "os" "os/exec" "path/filepath" "strconv" "strings" "syscall" "time" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/ginkgo/testsuite" "github.com/onsi/ginkgo/internal/remote" "github.com/onsi/ginkgo/reporters/stenographer" colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable" "github.com/onsi/ginkgo/types" ) type TestRunner struct { Suite testsuite.TestSuite compiled bool compilationTargetPath string numCPU int parallelStream bool timeout time.Duration goOpts map[string]interface{} additionalArgs []string stderr *bytes.Buffer CoverageFile string } func New(suite testsuite.TestSuite, numCPU int, parallelStream bool, timeout time.Duration, goOpts map[string]interface{}, additionalArgs []string) *TestRunner { runner := &TestRunner{ Suite: suite, numCPU: numCPU, parallelStream: parallelStream, goOpts: goOpts, additionalArgs: additionalArgs, timeout: timeout, stderr: new(bytes.Buffer), } if !suite.Precompiled { runner.compilationTargetPath, _ = filepath.Abs(filepath.Join(suite.Path, suite.PackageName+".test")) } return runner } func (t *TestRunner) Compile() error { return t.CompileTo(t.compilationTargetPath) } func (t *TestRunner) BuildArgs(path string) []string { args := make([]string, len(buildArgs), len(buildArgs)+3) copy(args, buildArgs) args = append(args, "-o", path, t.Suite.Path) if t.getCoverMode() != "" { args = append(args, "-cover", fmt.Sprintf("-covermode=%s", t.getCoverMode())) } else { if t.shouldCover() || t.getCoverPackage() != "" { args = append(args, "-cover", "-covermode=atomic") } } boolOpts := []string{ "a", "n", "msan", "race", "x", "work", "linkshared", } for _, opt := range boolOpts { if s, found := t.goOpts[opt].(*bool); found && *s { args = append(args, fmt.Sprintf("-%s", opt)) } } intOpts := []string{ "memprofilerate", "blockprofilerate", } for _, opt := range intOpts { if s, found := t.goOpts[opt].(*int); found { args = append(args, fmt.Sprintf("-%s=%d", opt, *s)) } } stringOpts := []string{ "asmflags", "buildmode", "compiler", "gccgoflags", "installsuffix", "ldflags", "pkgdir", "toolexec", "coverprofile", "cpuprofile", "memprofile", "outputdir", "coverpkg", "tags", "gcflags", "vet", "mod", } for _, opt := range stringOpts { if s, found := t.goOpts[opt].(*string); found && *s != "" { args = append(args, fmt.Sprintf("-%s=%s", opt, *s)) } } return args } func (t *TestRunner) CompileTo(path string) error { if t.compiled { return nil } if t.Suite.Precompiled { return nil } args := t.BuildArgs(path) cmd := exec.Command("go", args...) output, err := cmd.CombinedOutput() if err != nil { if len(output) > 0 { return fmt.Errorf("Failed to compile %s:\n\n%s", t.Suite.PackageName, output) } return fmt.Errorf("Failed to compile %s", t.Suite.PackageName) } if len(output) > 0 { fmt.Println(string(output)) } if !fileExists(path) { compiledFile := t.Suite.PackageName + ".test" if fileExists(compiledFile) { // seems like we are on an old go version that does not support the -o flag on go test // move the compiled test file to the desired location by hand err = os.Rename(compiledFile, path) if err != nil { // We cannot move the file, perhaps because the source and destination // are on different partitions. We can copy the file, however. err = copyFile(compiledFile, path) if err != nil { return fmt.Errorf("Failed to copy compiled file: %s", err) } } } else { return fmt.Errorf("Failed to compile %s: output file %q could not be found", t.Suite.PackageName, path) } } t.compiled = true return nil } func fileExists(path string) bool { _, err := os.Stat(path) return err == nil || !os.IsNotExist(err) } // copyFile copies the contents of the file named src to the file named // by dst. The file will be created if it does not already exist. If the // destination file exists, all it's contents will be replaced by the contents // of the source file. func copyFile(src, dst string) error { srcInfo, err := os.Stat(src) if err != nil { return err } mode := srcInfo.Mode() in, err := os.Open(src) if err != nil { return err } defer in.Close() out, err := os.Create(dst) if err != nil { return err } defer func() { closeErr := out.Close() if err == nil { err = closeErr } }() _, err = io.Copy(out, in) if err != nil { return err } err = out.Sync() if err != nil { return err } return out.Chmod(mode) } func (t *TestRunner) Run() RunResult { if t.Suite.IsGinkgo { if t.numCPU > 1 { if t.parallelStream { return t.runAndStreamParallelGinkgoSuite() } else { return t.runParallelGinkgoSuite() } } else { return t.runSerialGinkgoSuite() } } else { return t.runGoTestSuite() } } func (t *TestRunner) CleanUp() { if t.Suite.Precompiled { return } os.Remove(t.compilationTargetPath) } func (t *TestRunner) runSerialGinkgoSuite() RunResult { ginkgoArgs := config.BuildFlagArgs("ginkgo", config.GinkgoConfig, config.DefaultReporterConfig) return t.run(t.cmd(ginkgoArgs, os.Stdout, 1), nil) } func (t *TestRunner) runGoTestSuite() RunResult { return t.run(t.cmd([]string{"-test.v"}, os.Stdout, 1), nil) } func (t *TestRunner) runAndStreamParallelGinkgoSuite() RunResult { completions := make(chan RunResult) writers := make([]*logWriter, t.numCPU) server, err := remote.NewServer(t.numCPU) if err != nil { panic("Failed to start parallel spec server") } server.Start() defer server.Close() for cpu := 0; cpu < t.numCPU; cpu++ { config.GinkgoConfig.ParallelNode = cpu + 1 config.GinkgoConfig.ParallelTotal = t.numCPU config.GinkgoConfig.SyncHost = server.Address() ginkgoArgs := config.BuildFlagArgs("ginkgo", config.GinkgoConfig, config.DefaultReporterConfig) writers[cpu] = newLogWriter(os.Stdout, cpu+1) cmd := t.cmd(ginkgoArgs, writers[cpu], cpu+1) server.RegisterAlive(cpu+1, func() bool { if cmd.ProcessState == nil { return true } return !cmd.ProcessState.Exited() }) go t.run(cmd, completions) } res := PassingRunResult() for cpu := 0; cpu < t.numCPU; cpu++ { res = res.Merge(<-completions) } for _, writer := range writers { writer.Close() } os.Stdout.Sync() if t.shouldCombineCoverprofiles() { t.combineCoverprofiles() } return res } func (t *TestRunner) runParallelGinkgoSuite() RunResult { result := make(chan bool) completions := make(chan RunResult) writers := make([]*logWriter, t.numCPU) reports := make([]*bytes.Buffer, t.numCPU) stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1, colorable.NewColorableStdout()) aggregator := remote.NewAggregator(t.numCPU, result, config.DefaultReporterConfig, stenographer) server, err := remote.NewServer(t.numCPU) if err != nil { panic("Failed to start parallel spec server") } server.RegisterReporters(aggregator) server.Start() defer server.Close() for cpu := 0; cpu < t.numCPU; cpu++ { config.GinkgoConfig.ParallelNode = cpu + 1 config.GinkgoConfig.ParallelTotal = t.numCPU config.GinkgoConfig.SyncHost = server.Address() config.GinkgoConfig.StreamHost = server.Address() ginkgoArgs := config.BuildFlagArgs("ginkgo", config.GinkgoConfig, config.DefaultReporterConfig) reports[cpu] = &bytes.Buffer{} writers[cpu] = newLogWriter(reports[cpu], cpu+1) cmd := t.cmd(ginkgoArgs, writers[cpu], cpu+1) server.RegisterAlive(cpu+1, func() bool { if cmd.ProcessState == nil { return true } return !cmd.ProcessState.Exited() }) go t.run(cmd, completions) } res := PassingRunResult() for cpu := 0; cpu < t.numCPU; cpu++ { res = res.Merge(<-completions) } //all test processes are done, at this point //we should be able to wait for the aggregator to tell us that it's done select { case <-result: fmt.Println("") case <-time.After(time.Second): //the aggregator never got back to us! something must have gone wrong fmt.Println(` ------------------------------------------------------------------- | | | Ginkgo timed out waiting for all parallel nodes to report back! | | | -------------------------------------------------------------------`) fmt.Println("\n", t.Suite.PackageName, "timed out. path:", t.Suite.Path) os.Stdout.Sync() for _, writer := range writers { writer.Close() } for _, report := range reports { fmt.Print(report.String()) } os.Stdout.Sync() } if t.shouldCombineCoverprofiles() { t.combineCoverprofiles() } return res } const CoverProfileSuffix = ".coverprofile" func (t *TestRunner) cmd(ginkgoArgs []string, stream io.Writer, node int) *exec.Cmd { args := []string{"--test.timeout=" + t.timeout.String()} coverProfile := t.getCoverProfile() if t.shouldCombineCoverprofiles() { testCoverProfile := "--test.coverprofile=" coverageFile := "" // Set default name for coverage results if coverProfile == "" { coverageFile = t.Suite.PackageName + CoverProfileSuffix } else { coverageFile = coverProfile } testCoverProfile += coverageFile t.CoverageFile = filepath.Join(t.Suite.Path, coverageFile) if t.numCPU > 1 { testCoverProfile = fmt.Sprintf("%s.%d", testCoverProfile, node) } args = append(args, testCoverProfile) } args = append(args, ginkgoArgs...) args = append(args, t.additionalArgs...) path := t.compilationTargetPath if t.Suite.Precompiled { path, _ = filepath.Abs(filepath.Join(t.Suite.Path, fmt.Sprintf("%s.test", t.Suite.PackageName))) } cmd := exec.Command(path, args...) cmd.Dir = t.Suite.Path cmd.Stderr = io.MultiWriter(stream, t.stderr) cmd.Stdout = stream return cmd } func (t *TestRunner) shouldCover() bool { return *t.goOpts["cover"].(*bool) } func (t *TestRunner) shouldRequireSuite() bool { return *t.goOpts["requireSuite"].(*bool) } func (t *TestRunner) getCoverProfile() string { return *t.goOpts["coverprofile"].(*string) } func (t *TestRunner) getCoverPackage() string { return *t.goOpts["coverpkg"].(*string) } func (t *TestRunner) getCoverMode() string { return *t.goOpts["covermode"].(*string) } func (t *TestRunner) shouldCombineCoverprofiles() bool { return t.shouldCover() || t.getCoverPackage() != "" || t.getCoverMode() != "" } func (t *TestRunner) run(cmd *exec.Cmd, completions chan RunResult) RunResult { var res RunResult defer func() { if completions != nil { completions <- res } }() err := cmd.Start() if err != nil { fmt.Printf("Failed to run test suite!\n\t%s", err.Error()) return res } cmd.Wait() exitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() res.Passed = (exitStatus == 0) || (exitStatus == types.GINKGO_FOCUS_EXIT_CODE) res.HasProgrammaticFocus = (exitStatus == types.GINKGO_FOCUS_EXIT_CODE) if strings.Contains(t.stderr.String(), "warning: no tests to run") { if t.shouldRequireSuite() { res.Passed = false } fmt.Fprintf(os.Stderr, `Found no test suites, did you forget to run "ginkgo bootstrap"?`) } return res } func (t *TestRunner) combineCoverprofiles() { profiles := []string{} coverProfile := t.getCoverProfile() for cpu := 1; cpu <= t.numCPU; cpu++ { var coverFile string if coverProfile == "" { coverFile = fmt.Sprintf("%s%s.%d", t.Suite.PackageName, CoverProfileSuffix, cpu) } else { coverFile = fmt.Sprintf("%s.%d", coverProfile, cpu) } coverFile = filepath.Join(t.Suite.Path, coverFile) coverProfile, err := ioutil.ReadFile(coverFile) os.Remove(coverFile) if err == nil { profiles = append(profiles, string(coverProfile)) } } if len(profiles) != t.numCPU { return } lines := map[string]int{} lineOrder := []string{} for i, coverProfile := range profiles { for _, line := range strings.Split(coverProfile, "\n")[1:] { if len(line) == 0 { continue } components := strings.Split(line, " ") count, _ := strconv.Atoi(components[len(components)-1]) prefix := strings.Join(components[0:len(components)-1], " ") lines[prefix] += count if i == 0 { lineOrder = append(lineOrder, prefix) } } } output := []string{"mode: atomic"} for _, line := range lineOrder { output = append(output, fmt.Sprintf("%s %d", line, lines[line])) } finalOutput := strings.Join(output, "\n") finalFilename := "" if coverProfile != "" { finalFilename = coverProfile } else { finalFilename = fmt.Sprintf("%s%s", t.Suite.PackageName, CoverProfileSuffix) } coverageFilepath := filepath.Join(t.Suite.Path, finalFilename) ioutil.WriteFile(coverageFilepath, []byte(finalOutput), 0666) t.CoverageFile = coverageFilepath } ginkgo-1.14.2/ginkgo/testrunner/test_runner_test.go000066400000000000000000000025471374111457300225200ustar00rootroot00000000000000package testrunner_test import ( "testing" . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/ginkgo/testrunner" "github.com/onsi/ginkgo/ginkgo/testsuite" . "github.com/onsi/gomega" ) func strAddr(s string) interface{} { return &s } func boolAddr(s bool) interface{} { return &s } func intAddr(s int) interface{} { return &s } var _ = Describe("TestRunner", func() { It("should pass through go opts", func() { //var opts map[string]interface{} opts := map[string]interface{}{ "asmflags": strAddr("a"), "pkgdir": strAddr("b"), "gcflags": strAddr("c"), "covermode": strAddr(""), "coverpkg": strAddr(""), "cover": boolAddr(false), "blockprofilerate": intAddr(100), "vet": strAddr("off"), "mod": strAddr("vendor"), } tr := testrunner.New(testsuite.TestSuite{}, 1, false, 0, opts, []string{}) args := tr.BuildArgs(".") // Remove the "-i" argument; This is discarded in Golang 1.10+. if args[2] == "-i" { args = append(args[0:2], args[3:]...) } Ω(args).Should(Equal([]string{ "test", "-c", "-o", ".", "", "-blockprofilerate=100", "-asmflags=a", "-pkgdir=b", "-gcflags=c", "-vet=off", "-mod=vendor", })) }) }) func TestTestRunner(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Test Runner Suite") } ginkgo-1.14.2/ginkgo/testsuite/000077500000000000000000000000001374111457300163725ustar00rootroot00000000000000ginkgo-1.14.2/ginkgo/testsuite/test_suite.go000066400000000000000000000045311374111457300211140ustar00rootroot00000000000000package testsuite import ( "errors" "io/ioutil" "os" "path/filepath" "regexp" "strings" ) type TestSuite struct { Path string PackageName string IsGinkgo bool Precompiled bool } func PrecompiledTestSuite(path string) (TestSuite, error) { info, err := os.Stat(path) if err != nil { return TestSuite{}, err } if info.IsDir() { return TestSuite{}, errors.New("this is a directory, not a file") } if filepath.Ext(path) != ".test" { return TestSuite{}, errors.New("this is not a .test binary") } if info.Mode()&0111 == 0 { return TestSuite{}, errors.New("this is not executable") } dir := relPath(filepath.Dir(path)) packageName := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)) return TestSuite{ Path: dir, PackageName: packageName, IsGinkgo: true, Precompiled: true, }, nil } func SuitesInDir(dir string, recurse bool) []TestSuite { suites := []TestSuite{} if vendorExperimentCheck(dir) { return suites } files, _ := ioutil.ReadDir(dir) re := regexp.MustCompile(`^[^._].*_test\.go$`) for _, file := range files { if !file.IsDir() && re.Match([]byte(file.Name())) { suites = append(suites, New(dir, files)) break } } if recurse { re = regexp.MustCompile(`^[._]`) for _, file := range files { if file.IsDir() && !re.Match([]byte(file.Name())) { suites = append(suites, SuitesInDir(dir+"/"+file.Name(), recurse)...) } } } return suites } func relPath(dir string) string { dir, _ = filepath.Abs(dir) cwd, _ := os.Getwd() dir, _ = filepath.Rel(cwd, filepath.Clean(dir)) if string(dir[0]) != "." { dir = "." + string(filepath.Separator) + dir } return dir } func New(dir string, files []os.FileInfo) TestSuite { return TestSuite{ Path: relPath(dir), PackageName: packageNameForSuite(dir), IsGinkgo: filesHaveGinkgoSuite(dir, files), } } func packageNameForSuite(dir string) string { path, _ := filepath.Abs(dir) return filepath.Base(path) } func filesHaveGinkgoSuite(dir string, files []os.FileInfo) bool { reTestFile := regexp.MustCompile(`_test\.go$`) reGinkgo := regexp.MustCompile(`package ginkgo|\/ginkgo"`) for _, file := range files { if !file.IsDir() && reTestFile.Match([]byte(file.Name())) { contents, _ := ioutil.ReadFile(dir + "/" + file.Name()) if reGinkgo.Match(contents) { return true } } } return false } ginkgo-1.14.2/ginkgo/testsuite/testsuite_suite_test.go000066400000000000000000000003101374111457300232140ustar00rootroot00000000000000package testsuite_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestTestsuite(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Testsuite Suite") } ginkgo-1.14.2/ginkgo/testsuite/testsuite_test.go000066400000000000000000000150241374111457300220130ustar00rootroot00000000000000// +build go1.6 package testsuite_test import ( "io/ioutil" "os" "path/filepath" . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/ginkgo/testsuite" . "github.com/onsi/gomega" ) var _ = Describe("TestSuite", func() { var tmpDir string var relTmpDir string writeFile := func(folder string, filename string, content string, mode os.FileMode) { path := filepath.Join(tmpDir, folder) err := os.MkdirAll(path, 0700) Ω(err).ShouldNot(HaveOccurred()) path = filepath.Join(path, filename) ioutil.WriteFile(path, []byte(content), mode) } var origVendor string BeforeSuite(func() { origVendor = os.Getenv("GO15VENDOREXPERIMENT") }) AfterSuite(func() { os.Setenv("GO15VENDOREXPERIMENT", origVendor) }) BeforeEach(func() { var err error tmpDir, err = ioutil.TempDir("/tmp", "ginkgo") Ω(err).ShouldNot(HaveOccurred()) cwd, err := os.Getwd() Ω(err).ShouldNot(HaveOccurred()) relTmpDir, err = filepath.Rel(cwd, tmpDir) Ω(err).ShouldNot(HaveOccurred()) //go files in the root directory (no tests) writeFile("/", "main.go", "package main", 0666) //non-go files in a nested directory writeFile("/redherring", "big_test.jpg", "package ginkgo", 0666) //ginkgo tests in ignored go files writeFile("/ignored", ".ignore_dot_test.go", `import "github.com/onsi/ginkgo"`, 0666) writeFile("/ignored", "_ignore_underscore_test.go", `import "github.com/onsi/ginkgo"`, 0666) //non-ginkgo tests in a nested directory writeFile("/professorplum", "professorplum_test.go", `import "testing"`, 0666) //ginkgo tests in a nested directory writeFile("/colonelmustard", "colonelmustard_test.go", `import "github.com/onsi/ginkgo"`, 0666) //ginkgo tests in a deeply nested directory writeFile("/colonelmustard/library", "library_test.go", `import "github.com/onsi/ginkgo"`, 0666) //ginkgo tests deeply nested in a vendored dependency writeFile("/vendor/mrspeacock/lounge", "lounge_test.go", `import "github.com/onsi/ginkgo"`, 0666) //a precompiled ginkgo test writeFile("/precompiled-dir", "precompiled.test", `fake-binary-file`, 0777) writeFile("/precompiled-dir", "some-other-binary", `fake-binary-file`, 0777) writeFile("/precompiled-dir", "nonexecutable.test", `fake-binary-file`, 0666) }) AfterEach(func() { os.RemoveAll(tmpDir) }) Describe("Finding precompiled test suites", func() { Context("if pointed at an executable file that ends with .test", func() { It("should return a precompiled test suite", func() { suite, err := PrecompiledTestSuite(filepath.Join(tmpDir, "precompiled-dir", "precompiled.test")) Ω(err).ShouldNot(HaveOccurred()) Ω(suite).Should(Equal(TestSuite{ Path: relTmpDir + "/precompiled-dir", PackageName: "precompiled", IsGinkgo: true, Precompiled: true, })) }) }) Context("if pointed at a directory", func() { It("should error", func() { suite, err := PrecompiledTestSuite(filepath.Join(tmpDir, "precompiled-dir")) Ω(suite).Should(BeZero()) Ω(err).Should(HaveOccurred()) }) }) Context("if pointed at an executable that doesn't have .test", func() { It("should error", func() { suite, err := PrecompiledTestSuite(filepath.Join(tmpDir, "precompiled-dir", "some-other-binary")) Ω(suite).Should(BeZero()) Ω(err).Should(HaveOccurred()) }) }) Context("if pointed at a .test that isn't executable", func() { It("should error", func() { suite, err := PrecompiledTestSuite(filepath.Join(tmpDir, "precompiled-dir", "nonexecutable.test")) Ω(suite).Should(BeZero()) Ω(err).Should(HaveOccurred()) }) }) Context("if pointed at a nonexisting file", func() { It("should error", func() { suite, err := PrecompiledTestSuite(filepath.Join(tmpDir, "precompiled-dir", "nope-nothing-to-see-here")) Ω(suite).Should(BeZero()) Ω(err).Should(HaveOccurred()) }) }) }) Describe("scanning for suites in a directory", func() { Context("when there are no tests in the specified directory", func() { It("should come up empty", func() { suites := SuitesInDir(tmpDir, false) Ω(suites).Should(BeEmpty()) }) }) Context("when there are ginkgo tests in the specified directory", func() { It("should return an appropriately configured suite", func() { suites := SuitesInDir(filepath.Join(tmpDir, "colonelmustard"), false) Ω(suites).Should(HaveLen(1)) Ω(suites[0].Path).Should(Equal(relTmpDir + "/colonelmustard")) Ω(suites[0].PackageName).Should(Equal("colonelmustard")) Ω(suites[0].IsGinkgo).Should(BeTrue()) Ω(suites[0].Precompiled).Should(BeFalse()) }) }) Context("when there are ginkgo tests that are ignored by go in the specified directory ", func() { It("should come up empty", func() { suites := SuitesInDir(filepath.Join(tmpDir, "ignored"), false) Ω(suites).Should(BeEmpty()) }) }) Context("when there are non-ginkgo tests in the specified directory", func() { It("should return an appropriately configured suite", func() { suites := SuitesInDir(filepath.Join(tmpDir, "professorplum"), false) Ω(suites).Should(HaveLen(1)) Ω(suites[0].Path).Should(Equal(relTmpDir + "/professorplum")) Ω(suites[0].PackageName).Should(Equal("professorplum")) Ω(suites[0].IsGinkgo).Should(BeFalse()) Ω(suites[0].Precompiled).Should(BeFalse()) }) }) Context("given GO15VENDOREXPERIMENT disabled", func() { BeforeEach(func() { os.Setenv("GO15VENDOREXPERIMENT", "0") }) AfterEach(func() { os.Setenv("GO15VENDOREXPERIMENT", "") }) It("should not skip vendor dirs", func() { suites := SuitesInDir(filepath.Join(tmpDir+"/vendor"), true) Ω(suites).Should(HaveLen(1)) }) It("should recurse into vendor dirs", func() { suites := SuitesInDir(filepath.Join(tmpDir), true) Ω(suites).Should(HaveLen(4)) }) }) Context("when recursively scanning", func() { It("should return suites for corresponding test suites, only", func() { suites := SuitesInDir(tmpDir, true) Ω(suites).Should(HaveLen(3)) Ω(suites).Should(ContainElement(TestSuite{ Path: relTmpDir + "/colonelmustard", PackageName: "colonelmustard", IsGinkgo: true, Precompiled: false, })) Ω(suites).Should(ContainElement(TestSuite{ Path: relTmpDir + "/professorplum", PackageName: "professorplum", IsGinkgo: false, Precompiled: false, })) Ω(suites).Should(ContainElement(TestSuite{ Path: relTmpDir + "/colonelmustard/library", PackageName: "library", IsGinkgo: true, Precompiled: false, })) }) }) }) }) ginkgo-1.14.2/ginkgo/testsuite/vendor_check_go15.go000066400000000000000000000006231374111457300222070ustar00rootroot00000000000000// +build !go1.6 package testsuite import ( "os" "path" ) // "This change will only be enabled if the go command is run with // GO15VENDOREXPERIMENT=1 in its environment." // c.f. the vendor-experiment proposal https://goo.gl/2ucMeC func vendorExperimentCheck(dir string) bool { vendorExperiment := os.Getenv("GO15VENDOREXPERIMENT") return vendorExperiment == "1" && path.Base(dir) == "vendor" } ginkgo-1.14.2/ginkgo/testsuite/vendor_check_go15_test.go000066400000000000000000000140641374111457300232520ustar00rootroot00000000000000// +build !go1.6 package testsuite_test import ( "io/ioutil" "os" "path/filepath" . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/ginkgo/testsuite" . "github.com/onsi/gomega" ) var _ = Describe("TestSuite", func() { var tmpDir string var relTmpDir string writeFile := func(folder string, filename string, content string, mode os.FileMode) { path := filepath.Join(tmpDir, folder) err := os.MkdirAll(path, 0700) Ω(err).ShouldNot(HaveOccurred()) path = filepath.Join(path, filename) ioutil.WriteFile(path, []byte(content), mode) } var origVendor string BeforeSuite(func() { origVendor = os.Getenv("GO15VENDOREXPERIMENT") }) AfterSuite(func() { os.Setenv("GO15VENDOREXPERIMENT", origVendor) }) BeforeEach(func() { var err error tmpDir, err = ioutil.TempDir("/tmp", "ginkgo") Ω(err).ShouldNot(HaveOccurred()) cwd, err := os.Getwd() Ω(err).ShouldNot(HaveOccurred()) relTmpDir, err = filepath.Rel(cwd, tmpDir) Ω(err).ShouldNot(HaveOccurred()) //go files in the root directory (no tests) writeFile("/", "main.go", "package main", 0666) //non-go files in a nested directory writeFile("/redherring", "big_test.jpg", "package ginkgo", 0666) //non-ginkgo tests in a nested directory writeFile("/professorplum", "professorplum_test.go", `import "testing"`, 0666) //ginkgo tests in a nested directory writeFile("/colonelmustard", "colonelmustard_test.go", `import "github.com/onsi/ginkgo"`, 0666) //ginkgo tests in a deeply nested directory writeFile("/colonelmustard/library", "library_test.go", `import "github.com/onsi/ginkgo"`, 0666) //ginkgo tests deeply nested in a vendored dependency writeFile("/vendor/mrspeacock/lounge", "lounge_test.go", `import "github.com/onsi/ginkgo"`, 0666) //a precompiled ginkgo test writeFile("/precompiled-dir", "precompiled.test", `fake-binary-file`, 0777) writeFile("/precompiled-dir", "some-other-binary", `fake-binary-file`, 0777) writeFile("/precompiled-dir", "nonexecutable.test", `fake-binary-file`, 0666) }) AfterEach(func() { os.RemoveAll(tmpDir) }) Describe("Finding precompiled test suites", func() { Context("if pointed at an executable file that ends with .test", func() { It("should return a precompiled test suite", func() { suite, err := PrecompiledTestSuite(filepath.Join(tmpDir, "precompiled-dir", "precompiled.test")) Ω(err).ShouldNot(HaveOccurred()) Ω(suite).Should(Equal(TestSuite{ Path: relTmpDir + "/precompiled-dir", PackageName: "precompiled", IsGinkgo: true, Precompiled: true, })) }) }) Context("if pointed at a directory", func() { It("should error", func() { suite, err := PrecompiledTestSuite(filepath.Join(tmpDir, "precompiled-dir")) Ω(suite).Should(BeZero()) Ω(err).Should(HaveOccurred()) }) }) Context("if pointed at an executable that doesn't have .test", func() { It("should error", func() { suite, err := PrecompiledTestSuite(filepath.Join(tmpDir, "precompiled-dir", "some-other-binary")) Ω(suite).Should(BeZero()) Ω(err).Should(HaveOccurred()) }) }) Context("if pointed at a .test that isn't executable", func() { It("should error", func() { suite, err := PrecompiledTestSuite(filepath.Join(tmpDir, "precompiled-dir", "nonexecutable.test")) Ω(suite).Should(BeZero()) Ω(err).Should(HaveOccurred()) }) }) Context("if pointed at a nonexisting file", func() { It("should error", func() { suite, err := PrecompiledTestSuite(filepath.Join(tmpDir, "precompiled-dir", "nope-nothing-to-see-here")) Ω(suite).Should(BeZero()) Ω(err).Should(HaveOccurred()) }) }) }) Describe("scanning for suites in a directory", func() { Context("when there are no tests in the specified directory", func() { It("should come up empty", func() { suites := SuitesInDir(tmpDir, false) Ω(suites).Should(BeEmpty()) }) }) Context("when there are ginkgo tests in the specified directory", func() { It("should return an appropriately configured suite", func() { suites := SuitesInDir(filepath.Join(tmpDir, "colonelmustard"), false) Ω(suites).Should(HaveLen(1)) Ω(suites[0].Path).Should(Equal(relTmpDir + "/colonelmustard")) Ω(suites[0].PackageName).Should(Equal("colonelmustard")) Ω(suites[0].IsGinkgo).Should(BeTrue()) Ω(suites[0].Precompiled).Should(BeFalse()) }) }) Context("when there are non-ginkgo tests in the specified directory", func() { It("should return an appropriately configured suite", func() { suites := SuitesInDir(filepath.Join(tmpDir, "professorplum"), false) Ω(suites).Should(HaveLen(1)) Ω(suites[0].Path).Should(Equal(relTmpDir + "/professorplum")) Ω(suites[0].PackageName).Should(Equal("professorplum")) Ω(suites[0].IsGinkgo).Should(BeFalse()) Ω(suites[0].Precompiled).Should(BeFalse()) }) }) Context("given GO15VENDOREXPERIMENT", func() { BeforeEach(func() { os.Setenv("GO15VENDOREXPERIMENT", "1") }) AfterEach(func() { os.Setenv("GO15VENDOREXPERIMENT", "") }) It("should skip vendor dirs", func() { suites := SuitesInDir(filepath.Join(tmpDir+"/vendor"), false) Ω(suites).Should(HaveLen(0)) }) It("should not recurse into vendor dirs", func() { suites := SuitesInDir(filepath.Join(tmpDir), true) Ω(suites).Should(HaveLen(3)) }) }) Context("when recursively scanning", func() { It("should return suites for corresponding test suites, only", func() { suites := SuitesInDir(tmpDir, true) Ω(suites).Should(HaveLen(4)) Ω(suites).Should(ContainElement(TestSuite{ Path: relTmpDir + "/colonelmustard", PackageName: "colonelmustard", IsGinkgo: true, Precompiled: false, })) Ω(suites).Should(ContainElement(TestSuite{ Path: relTmpDir + "/professorplum", PackageName: "professorplum", IsGinkgo: false, Precompiled: false, })) Ω(suites).Should(ContainElement(TestSuite{ Path: relTmpDir + "/colonelmustard/library", PackageName: "library", IsGinkgo: true, Precompiled: false, })) }) }) }) }) ginkgo-1.14.2/ginkgo/testsuite/vendor_check_go16.go000066400000000000000000000005041374111457300222060ustar00rootroot00000000000000// +build go1.6 package testsuite import ( "os" "path" ) // in 1.6 the vendor directory became the default go behaviour, so now // check if its disabled. func vendorExperimentCheck(dir string) bool { vendorExperiment := os.Getenv("GO15VENDOREXPERIMENT") return vendorExperiment != "0" && path.Base(dir) == "vendor" } ginkgo-1.14.2/ginkgo/unfocus_command.go000066400000000000000000000074241374111457300200570ustar00rootroot00000000000000package main import ( "bytes" "flag" "fmt" "go/ast" "go/parser" "go/token" "io" "io/ioutil" "os" "path/filepath" "strings" "sync" ) func BuildUnfocusCommand() *Command { return &Command{ Name: "unfocus", AltName: "blur", FlagSet: flag.NewFlagSet("unfocus", flag.ExitOnError), UsageCommand: "ginkgo unfocus (or ginkgo blur)", Usage: []string{ "Recursively unfocuses any focused tests under the current directory", }, Command: unfocusSpecs, } } func unfocusSpecs([]string, []string) { fmt.Println("Scanning for focus...") goFiles := make(chan string) go func() { unfocusDir(goFiles, ".") close(goFiles) }() const workers = 10 wg := sync.WaitGroup{} wg.Add(workers) for i := 0; i < workers; i++ { go func() { for path := range goFiles { unfocusFile(path) } wg.Done() }() } wg.Wait() } func unfocusDir(goFiles chan string, path string) { files, err := ioutil.ReadDir(path) if err != nil { fmt.Println(err.Error()) return } for _, f := range files { switch { case f.IsDir() && shouldProcessDir(f.Name()): unfocusDir(goFiles, filepath.Join(path, f.Name())) case !f.IsDir() && shouldProcessFile(f.Name()): goFiles <- filepath.Join(path, f.Name()) } } } func shouldProcessDir(basename string) bool { return basename != "vendor" && !strings.HasPrefix(basename, ".") } func shouldProcessFile(basename string) bool { return strings.HasSuffix(basename, ".go") } func unfocusFile(path string) { data, err := ioutil.ReadFile(path) if err != nil { fmt.Printf("error reading file '%s': %s\n", path, err.Error()) return } ast, err := parser.ParseFile(token.NewFileSet(), path, bytes.NewReader(data), 0) if err != nil { fmt.Printf("error parsing file '%s': %s\n", path, err.Error()) return } eliminations := scanForFocus(ast) if len(eliminations) == 0 { return } fmt.Printf("...updating %s\n", path) backup, err := writeBackup(path, data) if err != nil { fmt.Printf("error creating backup file: %s\n", err.Error()) return } if err := updateFile(path, data, eliminations); err != nil { fmt.Printf("error writing file '%s': %s\n", path, err.Error()) return } os.Remove(backup) } func writeBackup(path string, data []byte) (string, error) { t, err := ioutil.TempFile(filepath.Dir(path), filepath.Base(path)) if err != nil { return "", fmt.Errorf("error creating temporary file: %w", err) } defer t.Close() if _, err := io.Copy(t, bytes.NewReader(data)); err != nil { return "", fmt.Errorf("error writing to temporary file: %w", err) } return t.Name(), nil } func updateFile(path string, data []byte, eliminations []int64) error { to, err := os.Create(path) if err != nil { return fmt.Errorf("error opening file for writing '%s': %w\n", path, err) } defer to.Close() from := bytes.NewReader(data) var cursor int64 for _, byteToEliminate := range eliminations { if _, err := io.CopyN(to, from, byteToEliminate-cursor); err != nil { return fmt.Errorf("error copying data: %w", err) } cursor = byteToEliminate + 1 if _, err := from.Seek(1, io.SeekCurrent); err != nil { return fmt.Errorf("error seeking to position in buffer: %w", err) } } if _, err := io.Copy(to, from); err != nil { return fmt.Errorf("error copying end data: %w", err) } return nil } func scanForFocus(file *ast.File) (eliminations []int64) { ast.Inspect(file, func(n ast.Node) bool { if c, ok := n.(*ast.CallExpr); ok { if i, ok := c.Fun.(*ast.Ident); ok { if isFocus(i.Name) { eliminations = append(eliminations, int64(i.Pos()-file.Pos())) } } } return true }) return eliminations } func isFocus(name string) bool { switch name { case "FDescribe", "FContext", "FIt", "FMeasure", "FDescribeTable", "FEntry", "FSpecify", "FWhen": return true default: return false } } ginkgo-1.14.2/ginkgo/version_command.go000066400000000000000000000006571374111457300200630ustar00rootroot00000000000000package main import ( "flag" "fmt" "github.com/onsi/ginkgo/config" ) func BuildVersionCommand() *Command { return &Command{ Name: "version", FlagSet: flag.NewFlagSet("version", flag.ExitOnError), UsageCommand: "ginkgo version", Usage: []string{ "Print Ginkgo's version", }, Command: printVersion, } } func printVersion([]string, []string) { fmt.Printf("Ginkgo Version %s\n", config.VERSION) } ginkgo-1.14.2/ginkgo/watch/000077500000000000000000000000001374111457300154475ustar00rootroot00000000000000ginkgo-1.14.2/ginkgo/watch/delta.go000066400000000000000000000010261374111457300170660ustar00rootroot00000000000000package watch import "sort" type Delta struct { ModifiedPackages []string NewSuites []*Suite RemovedSuites []*Suite modifiedSuites []*Suite } type DescendingByDelta []*Suite func (a DescendingByDelta) Len() int { return len(a) } func (a DescendingByDelta) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a DescendingByDelta) Less(i, j int) bool { return a[i].Delta() > a[j].Delta() } func (d Delta) ModifiedSuites() []*Suite { sort.Sort(DescendingByDelta(d.modifiedSuites)) return d.modifiedSuites } ginkgo-1.14.2/ginkgo/watch/delta_tracker.go000066400000000000000000000032301374111457300206000ustar00rootroot00000000000000package watch import ( "fmt" "regexp" "github.com/onsi/ginkgo/ginkgo/testsuite" ) type SuiteErrors map[testsuite.TestSuite]error type DeltaTracker struct { maxDepth int watchRegExp *regexp.Regexp suites map[string]*Suite packageHashes *PackageHashes } func NewDeltaTracker(maxDepth int, watchRegExp *regexp.Regexp) *DeltaTracker { return &DeltaTracker{ maxDepth: maxDepth, watchRegExp: watchRegExp, packageHashes: NewPackageHashes(watchRegExp), suites: map[string]*Suite{}, } } func (d *DeltaTracker) Delta(suites []testsuite.TestSuite) (delta Delta, errors SuiteErrors) { errors = SuiteErrors{} delta.ModifiedPackages = d.packageHashes.CheckForChanges() providedSuitePaths := map[string]bool{} for _, suite := range suites { providedSuitePaths[suite.Path] = true } d.packageHashes.StartTrackingUsage() for _, suite := range d.suites { if providedSuitePaths[suite.Suite.Path] { if suite.Delta() > 0 { delta.modifiedSuites = append(delta.modifiedSuites, suite) } } else { delta.RemovedSuites = append(delta.RemovedSuites, suite) } } d.packageHashes.StopTrackingUsageAndPrune() for _, suite := range suites { _, ok := d.suites[suite.Path] if !ok { s, err := NewSuite(suite, d.maxDepth, d.packageHashes) if err != nil { errors[suite] = err continue } d.suites[suite.Path] = s delta.NewSuites = append(delta.NewSuites, s) } } return delta, errors } func (d *DeltaTracker) WillRun(suite testsuite.TestSuite) error { s, ok := d.suites[suite.Path] if !ok { return fmt.Errorf("unknown suite %s", suite.Path) } return s.MarkAsRunAndRecomputedDependencies(d.maxDepth) } ginkgo-1.14.2/ginkgo/watch/dependencies.go000066400000000000000000000035571374111457300204360ustar00rootroot00000000000000package watch import ( "go/build" "regexp" ) var ginkgoAndGomegaFilter = regexp.MustCompile(`github\.com/onsi/ginkgo|github\.com/onsi/gomega`) var ginkgoIntegrationTestFilter = regexp.MustCompile(`github\.com/onsi/ginkgo/integration`) //allow us to integration test this thing type Dependencies struct { deps map[string]int } func NewDependencies(path string, maxDepth int) (Dependencies, error) { d := Dependencies{ deps: map[string]int{}, } if maxDepth == 0 { return d, nil } err := d.seedWithDepsForPackageAtPath(path) if err != nil { return d, err } for depth := 1; depth < maxDepth; depth++ { n := len(d.deps) d.addDepsForDepth(depth) if n == len(d.deps) { break } } return d, nil } func (d Dependencies) Dependencies() map[string]int { return d.deps } func (d Dependencies) seedWithDepsForPackageAtPath(path string) error { pkg, err := build.ImportDir(path, 0) if err != nil { return err } d.resolveAndAdd(pkg.Imports, 1) d.resolveAndAdd(pkg.TestImports, 1) d.resolveAndAdd(pkg.XTestImports, 1) delete(d.deps, pkg.Dir) return nil } func (d Dependencies) addDepsForDepth(depth int) { for dep, depDepth := range d.deps { if depDepth == depth { d.addDepsForDep(dep, depth+1) } } } func (d Dependencies) addDepsForDep(dep string, depth int) { pkg, err := build.ImportDir(dep, 0) if err != nil { println(err.Error()) return } d.resolveAndAdd(pkg.Imports, depth) } func (d Dependencies) resolveAndAdd(deps []string, depth int) { for _, dep := range deps { pkg, err := build.Import(dep, ".", 0) if err != nil { continue } if !pkg.Goroot && (!ginkgoAndGomegaFilter.Match([]byte(pkg.Dir)) || ginkgoIntegrationTestFilter.Match([]byte(pkg.Dir))) { d.addDepIfNotPresent(pkg.Dir, depth) } } } func (d Dependencies) addDepIfNotPresent(dep string, depth int) { _, ok := d.deps[dep] if !ok { d.deps[dep] = depth } } ginkgo-1.14.2/ginkgo/watch/package_hash.go000066400000000000000000000040131374111457300203720ustar00rootroot00000000000000package watch import ( "fmt" "io/ioutil" "os" "regexp" "time" ) var goTestRegExp = regexp.MustCompile(`_test\.go$`) type PackageHash struct { CodeModifiedTime time.Time TestModifiedTime time.Time Deleted bool path string codeHash string testHash string watchRegExp *regexp.Regexp } func NewPackageHash(path string, watchRegExp *regexp.Regexp) *PackageHash { p := &PackageHash{ path: path, watchRegExp: watchRegExp, } p.codeHash, _, p.testHash, _, p.Deleted = p.computeHashes() return p } func (p *PackageHash) CheckForChanges() bool { codeHash, codeModifiedTime, testHash, testModifiedTime, deleted := p.computeHashes() if deleted { if !p.Deleted { t := time.Now() p.CodeModifiedTime = t p.TestModifiedTime = t } p.Deleted = true return true } modified := false p.Deleted = false if p.codeHash != codeHash { p.CodeModifiedTime = codeModifiedTime modified = true } if p.testHash != testHash { p.TestModifiedTime = testModifiedTime modified = true } p.codeHash = codeHash p.testHash = testHash return modified } func (p *PackageHash) computeHashes() (codeHash string, codeModifiedTime time.Time, testHash string, testModifiedTime time.Time, deleted bool) { infos, err := ioutil.ReadDir(p.path) if err != nil { deleted = true return } for _, info := range infos { if info.IsDir() { continue } if goTestRegExp.Match([]byte(info.Name())) { testHash += p.hashForFileInfo(info) if info.ModTime().After(testModifiedTime) { testModifiedTime = info.ModTime() } continue } if p.watchRegExp.Match([]byte(info.Name())) { codeHash += p.hashForFileInfo(info) if info.ModTime().After(codeModifiedTime) { codeModifiedTime = info.ModTime() } } } testHash += codeHash if codeModifiedTime.After(testModifiedTime) { testModifiedTime = codeModifiedTime } return } func (p *PackageHash) hashForFileInfo(info os.FileInfo) string { return fmt.Sprintf("%s_%d_%d", info.Name(), info.Size(), info.ModTime().UnixNano()) } ginkgo-1.14.2/ginkgo/watch/package_hashes.go000066400000000000000000000030751374111457300207310ustar00rootroot00000000000000package watch import ( "path/filepath" "regexp" "sync" ) type PackageHashes struct { PackageHashes map[string]*PackageHash usedPaths map[string]bool watchRegExp *regexp.Regexp lock *sync.Mutex } func NewPackageHashes(watchRegExp *regexp.Regexp) *PackageHashes { return &PackageHashes{ PackageHashes: map[string]*PackageHash{}, usedPaths: nil, watchRegExp: watchRegExp, lock: &sync.Mutex{}, } } func (p *PackageHashes) CheckForChanges() []string { p.lock.Lock() defer p.lock.Unlock() modified := []string{} for _, packageHash := range p.PackageHashes { if packageHash.CheckForChanges() { modified = append(modified, packageHash.path) } } return modified } func (p *PackageHashes) Add(path string) *PackageHash { p.lock.Lock() defer p.lock.Unlock() path, _ = filepath.Abs(path) _, ok := p.PackageHashes[path] if !ok { p.PackageHashes[path] = NewPackageHash(path, p.watchRegExp) } if p.usedPaths != nil { p.usedPaths[path] = true } return p.PackageHashes[path] } func (p *PackageHashes) Get(path string) *PackageHash { p.lock.Lock() defer p.lock.Unlock() path, _ = filepath.Abs(path) if p.usedPaths != nil { p.usedPaths[path] = true } return p.PackageHashes[path] } func (p *PackageHashes) StartTrackingUsage() { p.lock.Lock() defer p.lock.Unlock() p.usedPaths = map[string]bool{} } func (p *PackageHashes) StopTrackingUsageAndPrune() { p.lock.Lock() defer p.lock.Unlock() for path := range p.PackageHashes { if !p.usedPaths[path] { delete(p.PackageHashes, path) } } p.usedPaths = nil } ginkgo-1.14.2/ginkgo/watch/suite.go000066400000000000000000000036031374111457300171310ustar00rootroot00000000000000package watch import ( "fmt" "math" "time" "github.com/onsi/ginkgo/ginkgo/testsuite" ) type Suite struct { Suite testsuite.TestSuite RunTime time.Time Dependencies Dependencies sharedPackageHashes *PackageHashes } func NewSuite(suite testsuite.TestSuite, maxDepth int, sharedPackageHashes *PackageHashes) (*Suite, error) { deps, err := NewDependencies(suite.Path, maxDepth) if err != nil { return nil, err } sharedPackageHashes.Add(suite.Path) for dep := range deps.Dependencies() { sharedPackageHashes.Add(dep) } return &Suite{ Suite: suite, Dependencies: deps, sharedPackageHashes: sharedPackageHashes, }, nil } func (s *Suite) Delta() float64 { delta := s.delta(s.Suite.Path, true, 0) * 1000 for dep, depth := range s.Dependencies.Dependencies() { delta += s.delta(dep, false, depth) } return delta } func (s *Suite) MarkAsRunAndRecomputedDependencies(maxDepth int) error { s.RunTime = time.Now() deps, err := NewDependencies(s.Suite.Path, maxDepth) if err != nil { return err } s.sharedPackageHashes.Add(s.Suite.Path) for dep := range deps.Dependencies() { s.sharedPackageHashes.Add(dep) } s.Dependencies = deps return nil } func (s *Suite) Description() string { numDeps := len(s.Dependencies.Dependencies()) pluralizer := "ies" if numDeps == 1 { pluralizer = "y" } return fmt.Sprintf("%s [%d dependenc%s]", s.Suite.Path, numDeps, pluralizer) } func (s *Suite) delta(packagePath string, includeTests bool, depth int) float64 { return math.Max(float64(s.dt(packagePath, includeTests)), 0) / float64(depth+1) } func (s *Suite) dt(packagePath string, includeTests bool) time.Duration { packageHash := s.sharedPackageHashes.Get(packagePath) var modifiedTime time.Time if includeTests { modifiedTime = packageHash.TestModifiedTime } else { modifiedTime = packageHash.CodeModifiedTime } return modifiedTime.Sub(s.RunTime) } ginkgo-1.14.2/ginkgo/watch_command.go000066400000000000000000000126651374111457300175060ustar00rootroot00000000000000package main import ( "flag" "fmt" "regexp" "time" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/ginkgo/interrupthandler" "github.com/onsi/ginkgo/ginkgo/testrunner" "github.com/onsi/ginkgo/ginkgo/testsuite" "github.com/onsi/ginkgo/ginkgo/watch" colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable" ) func BuildWatchCommand() *Command { commandFlags := NewWatchCommandFlags(flag.NewFlagSet("watch", flag.ExitOnError)) interruptHandler := interrupthandler.NewInterruptHandler() notifier := NewNotifier(commandFlags) watcher := &SpecWatcher{ commandFlags: commandFlags, notifier: notifier, interruptHandler: interruptHandler, suiteRunner: NewSuiteRunner(notifier, interruptHandler), } return &Command{ Name: "watch", FlagSet: commandFlags.FlagSet, UsageCommand: "ginkgo watch -- ", Usage: []string{ "Watches the tests in the passed in and runs them when changes occur.", "Any arguments after -- will be passed to the test.", }, Command: watcher.WatchSpecs, SuppressFlagDocumentation: true, FlagDocSubstitute: []string{ "Accepts all the flags that the ginkgo command accepts except for --keepGoing and --untilItFails", }, } } type SpecWatcher struct { commandFlags *RunWatchAndBuildCommandFlags notifier *Notifier interruptHandler *interrupthandler.InterruptHandler suiteRunner *SuiteRunner } func (w *SpecWatcher) WatchSpecs(args []string, additionalArgs []string) { w.commandFlags.computeNodes() w.notifier.VerifyNotificationsAreAvailable() w.WatchSuites(args, additionalArgs) } func (w *SpecWatcher) runnersForSuites(suites []testsuite.TestSuite, additionalArgs []string) []*testrunner.TestRunner { runners := []*testrunner.TestRunner{} for _, suite := range suites { runners = append(runners, testrunner.New(suite, w.commandFlags.NumCPU, w.commandFlags.ParallelStream, w.commandFlags.Timeout, w.commandFlags.GoOpts, additionalArgs)) } return runners } func (w *SpecWatcher) WatchSuites(args []string, additionalArgs []string) { suites, _ := findSuites(args, w.commandFlags.Recurse, w.commandFlags.SkipPackage, false) if len(suites) == 0 { complainAndQuit("Found no test suites") } fmt.Printf("Identified %d test %s. Locating dependencies to a depth of %d (this may take a while)...\n", len(suites), pluralizedWord("suite", "suites", len(suites)), w.commandFlags.Depth) deltaTracker := watch.NewDeltaTracker(w.commandFlags.Depth, regexp.MustCompile(w.commandFlags.WatchRegExp)) delta, errors := deltaTracker.Delta(suites) fmt.Printf("Watching %d %s:\n", len(delta.NewSuites), pluralizedWord("suite", "suites", len(delta.NewSuites))) for _, suite := range delta.NewSuites { fmt.Println(" " + suite.Description()) } for suite, err := range errors { fmt.Printf("Failed to watch %s: %s\n", suite.PackageName, err) } if len(suites) == 1 { runners := w.runnersForSuites(suites, additionalArgs) w.suiteRunner.RunSuites(runners, w.commandFlags.NumCompilers, true, nil) runners[0].CleanUp() } ticker := time.NewTicker(time.Second) for { select { case <-ticker.C: suites, _ := findSuites(args, w.commandFlags.Recurse, w.commandFlags.SkipPackage, false) delta, _ := deltaTracker.Delta(suites) coloredStream := colorable.NewColorableStdout() suitesToRun := []testsuite.TestSuite{} if len(delta.NewSuites) > 0 { fmt.Fprintf(coloredStream, greenColor+"Detected %d new %s:\n"+defaultStyle, len(delta.NewSuites), pluralizedWord("suite", "suites", len(delta.NewSuites))) for _, suite := range delta.NewSuites { suitesToRun = append(suitesToRun, suite.Suite) fmt.Fprintln(coloredStream, " "+suite.Description()) } } modifiedSuites := delta.ModifiedSuites() if len(modifiedSuites) > 0 { fmt.Fprintln(coloredStream, greenColor+"\nDetected changes in:"+defaultStyle) for _, pkg := range delta.ModifiedPackages { fmt.Fprintln(coloredStream, " "+pkg) } fmt.Fprintf(coloredStream, greenColor+"Will run %d %s:\n"+defaultStyle, len(modifiedSuites), pluralizedWord("suite", "suites", len(modifiedSuites))) for _, suite := range modifiedSuites { suitesToRun = append(suitesToRun, suite.Suite) fmt.Fprintln(coloredStream, " "+suite.Description()) } fmt.Fprintln(coloredStream, "") } if len(suitesToRun) > 0 { w.UpdateSeed() w.ComputeSuccinctMode(len(suitesToRun)) runners := w.runnersForSuites(suitesToRun, additionalArgs) result, _ := w.suiteRunner.RunSuites(runners, w.commandFlags.NumCompilers, true, func(suite testsuite.TestSuite) { deltaTracker.WillRun(suite) }) for _, runner := range runners { runner.CleanUp() } if !w.interruptHandler.WasInterrupted() { color := redColor if result.Passed { color = greenColor } fmt.Fprintln(coloredStream, color+"\nDone. Resuming watch..."+defaultStyle) } } case <-w.interruptHandler.C: return } } } func (w *SpecWatcher) ComputeSuccinctMode(numSuites int) { if config.DefaultReporterConfig.Verbose { config.DefaultReporterConfig.Succinct = false return } if w.commandFlags.wasSet("succinct") { return } if numSuites == 1 { config.DefaultReporterConfig.Succinct = false } if numSuites > 1 { config.DefaultReporterConfig.Succinct = true } } func (w *SpecWatcher) UpdateSeed() { if !w.commandFlags.wasSet("seed") { config.GinkgoConfig.RandomSeed = time.Now().Unix() } } ginkgo-1.14.2/ginkgo_dsl.go000066400000000000000000000606041374111457300155400ustar00rootroot00000000000000/* Ginkgo is a BDD-style testing framework for Golang The godoc documentation describes Ginkgo's API. More comprehensive documentation (with examples!) is available at http://onsi.github.io/ginkgo/ Ginkgo's preferred matcher library is [Gomega](http://github.com/onsi/gomega) Ginkgo on Github: http://github.com/onsi/ginkgo Ginkgo is MIT-Licensed */ package ginkgo import ( "flag" "fmt" "io" "net/http" "os" "strings" "time" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/global" "github.com/onsi/ginkgo/internal/remote" "github.com/onsi/ginkgo/internal/testingtproxy" "github.com/onsi/ginkgo/internal/writer" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/reporters/stenographer" colorable "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable" "github.com/onsi/ginkgo/types" ) const GINKGO_VERSION = config.VERSION const GINKGO_PANIC = ` Your test failed. Ginkgo panics to prevent subsequent assertions from running. Normally Ginkgo rescues this panic so you shouldn't see it. But, if you make an assertion in a goroutine, Ginkgo can't capture the panic. To circumvent this, you should call defer GinkgoRecover() at the top of the goroutine that caused this panic. ` func init() { config.Flags(flag.CommandLine, "ginkgo", true) GinkgoWriter = writer.New(os.Stdout) } //GinkgoWriter implements an io.Writer //When running in verbose mode any writes to GinkgoWriter will be immediately printed //to stdout. Otherwise, GinkgoWriter will buffer any writes produced during the current test and flush them to screen //only if the current test fails. var GinkgoWriter io.Writer //The interface by which Ginkgo receives *testing.T type GinkgoTestingT interface { Fail() } //GinkgoRandomSeed returns the seed used to randomize spec execution order. It is //useful for seeding your own pseudorandom number generators (PRNGs) to ensure //consistent executions from run to run, where your tests contain variability (for //example, when selecting random test data). func GinkgoRandomSeed() int64 { return config.GinkgoConfig.RandomSeed } //GinkgoParallelNode returns the parallel node number for the current ginkgo process //The node number is 1-indexed func GinkgoParallelNode() int { return config.GinkgoConfig.ParallelNode } //Some matcher libraries or legacy codebases require a *testing.T //GinkgoT implements an interface analogous to *testing.T and can be used if //the library in question accepts *testing.T through an interface // // For example, with testify: // assert.Equal(GinkgoT(), 123, 123, "they should be equal") // // Or with gomock: // gomock.NewController(GinkgoT()) // // GinkgoT() takes an optional offset argument that can be used to get the // correct line number associated with the failure. func GinkgoT(optionalOffset ...int) GinkgoTInterface { offset := 3 if len(optionalOffset) > 0 { offset = optionalOffset[0] } failedFunc := func() bool { return CurrentGinkgoTestDescription().Failed } nameFunc := func() string { return CurrentGinkgoTestDescription().FullTestText } return testingtproxy.New(GinkgoWriter, Fail, Skip, failedFunc, nameFunc, offset) } //The interface returned by GinkgoT(). This covers most of the methods //in the testing package's T. type GinkgoTInterface interface { Cleanup(func()) Error(args ...interface{}) Errorf(format string, args ...interface{}) Fail() FailNow() Failed() bool Fatal(args ...interface{}) Fatalf(format string, args ...interface{}) Helper() Log(args ...interface{}) Logf(format string, args ...interface{}) Name() string Parallel() Skip(args ...interface{}) SkipNow() Skipf(format string, args ...interface{}) Skipped() bool TempDir() string } //Custom Ginkgo test reporters must implement the Reporter interface. // //The custom reporter is passed in a SuiteSummary when the suite begins and ends, //and a SpecSummary just before a spec begins and just after a spec ends type Reporter reporters.Reporter //Asynchronous specs are given a channel of the Done type. You must close or write to the channel //to tell Ginkgo that your async test is done. type Done chan<- interface{} //GinkgoTestDescription represents the information about the current running test returned by CurrentGinkgoTestDescription // FullTestText: a concatenation of ComponentTexts and the TestText // ComponentTexts: a list of all texts for the Describes & Contexts leading up to the current test // TestText: the text in the actual It or Measure node // IsMeasurement: true if the current test is a measurement // FileName: the name of the file containing the current test // LineNumber: the line number for the current test // Failed: if the current test has failed, this will be true (useful in an AfterEach) type GinkgoTestDescription struct { FullTestText string ComponentTexts []string TestText string IsMeasurement bool FileName string LineNumber int Failed bool Duration time.Duration } //CurrentGinkgoTestDescripton returns information about the current running test. func CurrentGinkgoTestDescription() GinkgoTestDescription { summary, ok := global.Suite.CurrentRunningSpecSummary() if !ok { return GinkgoTestDescription{} } subjectCodeLocation := summary.ComponentCodeLocations[len(summary.ComponentCodeLocations)-1] return GinkgoTestDescription{ ComponentTexts: summary.ComponentTexts[1:], FullTestText: strings.Join(summary.ComponentTexts[1:], " "), TestText: summary.ComponentTexts[len(summary.ComponentTexts)-1], IsMeasurement: summary.IsMeasurement, FileName: subjectCodeLocation.FileName, LineNumber: subjectCodeLocation.LineNumber, Failed: summary.HasFailureState(), Duration: summary.RunTime, } } //Measurement tests receive a Benchmarker. // //You use the Time() function to time how long the passed in body function takes to run //You use the RecordValue() function to track arbitrary numerical measurements. //The RecordValueWithPrecision() function can be used alternatively to provide the unit //and resolution of the numeric measurement. //The optional info argument is passed to the test reporter and can be used to // provide the measurement data to a custom reporter with context. // //See http://onsi.github.io/ginkgo/#benchmark_tests for more details type Benchmarker interface { Time(name string, body func(), info ...interface{}) (elapsedTime time.Duration) RecordValue(name string, value float64, info ...interface{}) RecordValueWithPrecision(name string, value float64, units string, precision int, info ...interface{}) } //RunSpecs is the entry point for the Ginkgo test runner. //You must call this within a Golang testing TestX(t *testing.T) function. // //To bootstrap a test suite you can use the Ginkgo CLI: // // ginkgo bootstrap func RunSpecs(t GinkgoTestingT, description string) bool { specReporters := []Reporter{buildDefaultReporter()} if config.DefaultReporterConfig.ReportFile != "" { reportFile := config.DefaultReporterConfig.ReportFile specReporters[0] = reporters.NewJUnitReporter(reportFile) return RunSpecsWithDefaultAndCustomReporters(t, description, specReporters) } return RunSpecsWithCustomReporters(t, description, specReporters) } //To run your tests with Ginkgo's default reporter and your custom reporter(s), replace //RunSpecs() with this method. func RunSpecsWithDefaultAndCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool { specReporters = append(specReporters, buildDefaultReporter()) return RunSpecsWithCustomReporters(t, description, specReporters) } //To run your tests with your custom reporter(s) (and *not* Ginkgo's default reporter), replace //RunSpecs() with this method. Note that parallel tests will not work correctly without the default reporter func RunSpecsWithCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool { writer := GinkgoWriter.(*writer.Writer) writer.SetStream(config.DefaultReporterConfig.Verbose) reporters := make([]reporters.Reporter, len(specReporters)) for i, reporter := range specReporters { reporters[i] = reporter } passed, hasFocusedTests := global.Suite.Run(t, description, reporters, writer, config.GinkgoConfig) if passed && hasFocusedTests && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" { fmt.Println("PASS | FOCUSED") os.Exit(types.GINKGO_FOCUS_EXIT_CODE) } return passed } func buildDefaultReporter() Reporter { remoteReportingServer := config.GinkgoConfig.StreamHost if remoteReportingServer == "" { stenographer := stenographer.New(!config.DefaultReporterConfig.NoColor, config.GinkgoConfig.FlakeAttempts > 1, colorable.NewColorableStdout()) return reporters.NewDefaultReporter(config.DefaultReporterConfig, stenographer) } else { debugFile := "" if config.GinkgoConfig.DebugParallel { debugFile = fmt.Sprintf("ginkgo-node-%d.log", config.GinkgoConfig.ParallelNode) } return remote.NewForwardingReporter(config.DefaultReporterConfig, remoteReportingServer, &http.Client{}, remote.NewOutputInterceptor(), GinkgoWriter.(*writer.Writer), debugFile) } } //Skip notifies Ginkgo that the current spec was skipped. func Skip(message string, callerSkip ...int) { skip := 0 if len(callerSkip) > 0 { skip = callerSkip[0] } global.Failer.Skip(message, codelocation.New(skip+1)) panic(GINKGO_PANIC) } //Fail notifies Ginkgo that the current spec has failed. (Gomega will call Fail for you automatically when an assertion fails.) func Fail(message string, callerSkip ...int) { skip := 0 if len(callerSkip) > 0 { skip = callerSkip[0] } global.Failer.Fail(message, codelocation.New(skip+1)) panic(GINKGO_PANIC) } //GinkgoRecover should be deferred at the top of any spawned goroutine that (may) call `Fail` //Since Gomega assertions call fail, you should throw a `defer GinkgoRecover()` at the top of any goroutine that //calls out to Gomega // //Here's why: Ginkgo's `Fail` method records the failure and then panics to prevent //further assertions from running. This panic must be recovered. Ginkgo does this for you //if the panic originates in a Ginkgo node (an It, BeforeEach, etc...) // //Unfortunately, if a panic originates on a goroutine *launched* from one of these nodes there's no //way for Ginkgo to rescue the panic. To do this, you must remember to `defer GinkgoRecover()` at the top of such a goroutine. func GinkgoRecover() { e := recover() if e != nil { global.Failer.Panic(codelocation.New(1), e) } } //Describe blocks allow you to organize your specs. A Describe block can contain any number of //BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks. // //In addition you can nest Describe, Context and When blocks. Describe, Context and When blocks are functionally //equivalent. The difference is purely semantic -- you typically Describe the behavior of an object //or method and, within that Describe, outline a number of Contexts and Whens. func Describe(text string, body func()) bool { global.Suite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1)) return true } //You can focus the tests within a describe block using FDescribe func FDescribe(text string, body func()) bool { global.Suite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1)) return true } //You can mark the tests within a describe block as pending using PDescribe func PDescribe(text string, body func()) bool { global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1)) return true } //You can mark the tests within a describe block as pending using XDescribe func XDescribe(text string, body func()) bool { global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1)) return true } //Context blocks allow you to organize your specs. A Context block can contain any number of //BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks. // //In addition you can nest Describe, Context and When blocks. Describe, Context and When blocks are functionally //equivalent. The difference is purely semantic -- you typical Describe the behavior of an object //or method and, within that Describe, outline a number of Contexts and Whens. func Context(text string, body func()) bool { global.Suite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1)) return true } //You can focus the tests within a describe block using FContext func FContext(text string, body func()) bool { global.Suite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1)) return true } //You can mark the tests within a describe block as pending using PContext func PContext(text string, body func()) bool { global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1)) return true } //You can mark the tests within a describe block as pending using XContext func XContext(text string, body func()) bool { global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1)) return true } //When blocks allow you to organize your specs. A When block can contain any number of //BeforeEach, AfterEach, JustBeforeEach, It, and Measurement blocks. // //In addition you can nest Describe, Context and When blocks. Describe, Context and When blocks are functionally //equivalent. The difference is purely semantic -- you typical Describe the behavior of an object //or method and, within that Describe, outline a number of Contexts and Whens. func When(text string, body func()) bool { global.Suite.PushContainerNode("when "+text, body, types.FlagTypeNone, codelocation.New(1)) return true } //You can focus the tests within a describe block using FWhen func FWhen(text string, body func()) bool { global.Suite.PushContainerNode("when "+text, body, types.FlagTypeFocused, codelocation.New(1)) return true } //You can mark the tests within a describe block as pending using PWhen func PWhen(text string, body func()) bool { global.Suite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1)) return true } //You can mark the tests within a describe block as pending using XWhen func XWhen(text string, body func()) bool { global.Suite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1)) return true } //It blocks contain your test code and assertions. You cannot nest any other Ginkgo blocks //within an It block. // //Ginkgo will normally run It blocks synchronously. To perform asynchronous tests, pass a //function that accepts a Done channel. When you do this, you can also provide an optional timeout. func It(text string, body interface{}, timeout ...float64) bool { global.Suite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...)) return true } //You can focus individual Its using FIt func FIt(text string, body interface{}, timeout ...float64) bool { global.Suite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...)) return true } //You can mark Its as pending using PIt func PIt(text string, _ ...interface{}) bool { global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0) return true } //You can mark Its as pending using XIt func XIt(text string, _ ...interface{}) bool { global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0) return true } //Specify blocks are aliases for It blocks and allow for more natural wording in situations //which "It" does not fit into a natural sentence flow. All the same protocols apply for Specify blocks //which apply to It blocks. func Specify(text string, body interface{}, timeout ...float64) bool { global.Suite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...)) return true } //You can focus individual Specifys using FSpecify func FSpecify(text string, body interface{}, timeout ...float64) bool { global.Suite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...)) return true } //You can mark Specifys as pending using PSpecify func PSpecify(text string, is ...interface{}) bool { global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0) return true } //You can mark Specifys as pending using XSpecify func XSpecify(text string, is ...interface{}) bool { global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0) return true } //By allows you to better document large Its. // //Generally you should try to keep your Its short and to the point. This is not always possible, however, //especially in the context of integration tests that capture a particular workflow. // //By allows you to document such flows. By must be called within a runnable node (It, BeforeEach, Measure, etc...) //By will simply log the passed in text to the GinkgoWriter. If By is handed a function it will immediately run the function. func By(text string, callbacks ...func()) { preamble := "\x1b[1mSTEP\x1b[0m" if config.DefaultReporterConfig.NoColor { preamble = "STEP" } fmt.Fprintln(GinkgoWriter, preamble+": "+text) if len(callbacks) == 1 { callbacks[0]() } if len(callbacks) > 1 { panic("just one callback per By, please") } } //Measure blocks run the passed in body function repeatedly (determined by the samples argument) //and accumulate metrics provided to the Benchmarker by the body function. // //The body function must have the signature: // func(b Benchmarker) func Measure(text string, body interface{}, samples int) bool { global.Suite.PushMeasureNode(text, body, types.FlagTypeNone, codelocation.New(1), samples) return true } //You can focus individual Measures using FMeasure func FMeasure(text string, body interface{}, samples int) bool { global.Suite.PushMeasureNode(text, body, types.FlagTypeFocused, codelocation.New(1), samples) return true } //You can mark Measurements as pending using PMeasure func PMeasure(text string, _ ...interface{}) bool { global.Suite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0) return true } //You can mark Measurements as pending using XMeasure func XMeasure(text string, _ ...interface{}) bool { global.Suite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0) return true } //BeforeSuite blocks are run just once before any specs are run. When running in parallel, each //parallel node process will call BeforeSuite. // //BeforeSuite blocks can be made asynchronous by providing a body function that accepts a Done channel // //You may only register *one* BeforeSuite handler per test suite. You typically do so in your bootstrap file at the top level. func BeforeSuite(body interface{}, timeout ...float64) bool { global.Suite.SetBeforeSuiteNode(body, codelocation.New(1), parseTimeout(timeout...)) return true } //AfterSuite blocks are *always* run after all the specs regardless of whether specs have passed or failed. //Moreover, if Ginkgo receives an interrupt signal (^C) it will attempt to run the AfterSuite before exiting. // //When running in parallel, each parallel node process will call AfterSuite. // //AfterSuite blocks can be made asynchronous by providing a body function that accepts a Done channel // //You may only register *one* AfterSuite handler per test suite. You typically do so in your bootstrap file at the top level. func AfterSuite(body interface{}, timeout ...float64) bool { global.Suite.SetAfterSuiteNode(body, codelocation.New(1), parseTimeout(timeout...)) return true } //SynchronizedBeforeSuite blocks are primarily meant to solve the problem of setting up singleton external resources shared across //nodes when running tests in parallel. For example, say you have a shared database that you can only start one instance of that //must be used in your tests. When running in parallel, only one node should set up the database and all other nodes should wait //until that node is done before running. // //SynchronizedBeforeSuite accomplishes this by taking *two* function arguments. The first is only run on parallel node #1. The second is //run on all nodes, but *only* after the first function completes successfully. Ginkgo also makes it possible to send data from the first function (on Node 1) //to the second function (on all the other nodes). // //The functions have the following signatures. The first function (which only runs on node 1) has the signature: // // func() []byte // //or, to run asynchronously: // // func(done Done) []byte // //The byte array returned by the first function is then passed to the second function, which has the signature: // // func(data []byte) // //or, to run asynchronously: // // func(data []byte, done Done) // //Here's a simple pseudo-code example that starts a shared database on Node 1 and shares the database's address with the other nodes: // // var dbClient db.Client // var dbRunner db.Runner // // var _ = SynchronizedBeforeSuite(func() []byte { // dbRunner = db.NewRunner() // err := dbRunner.Start() // Ω(err).ShouldNot(HaveOccurred()) // return []byte(dbRunner.URL) // }, func(data []byte) { // dbClient = db.NewClient() // err := dbClient.Connect(string(data)) // Ω(err).ShouldNot(HaveOccurred()) // }) func SynchronizedBeforeSuite(node1Body interface{}, allNodesBody interface{}, timeout ...float64) bool { global.Suite.SetSynchronizedBeforeSuiteNode( node1Body, allNodesBody, codelocation.New(1), parseTimeout(timeout...), ) return true } //SynchronizedAfterSuite blocks complement the SynchronizedBeforeSuite blocks in solving the problem of setting up //external singleton resources shared across nodes when running tests in parallel. // //SynchronizedAfterSuite accomplishes this by taking *two* function arguments. The first runs on all nodes. The second runs only on parallel node #1 //and *only* after all other nodes have finished and exited. This ensures that node 1, and any resources it is running, remain alive until //all other nodes are finished. // //Both functions have the same signature: either func() or func(done Done) to run asynchronously. // //Here's a pseudo-code example that complements that given in SynchronizedBeforeSuite. Here, SynchronizedAfterSuite is used to tear down the shared database //only after all nodes have finished: // // var _ = SynchronizedAfterSuite(func() { // dbClient.Cleanup() // }, func() { // dbRunner.Stop() // }) func SynchronizedAfterSuite(allNodesBody interface{}, node1Body interface{}, timeout ...float64) bool { global.Suite.SetSynchronizedAfterSuiteNode( allNodesBody, node1Body, codelocation.New(1), parseTimeout(timeout...), ) return true } //BeforeEach blocks are run before It blocks. When multiple BeforeEach blocks are defined in nested //Describe and Context blocks the outermost BeforeEach blocks are run first. // //Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts //a Done channel func BeforeEach(body interface{}, timeout ...float64) bool { global.Suite.PushBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...)) return true } //JustBeforeEach blocks are run before It blocks but *after* all BeforeEach blocks. For more details, //read the [documentation](http://onsi.github.io/ginkgo/#separating_creation_and_configuration_) // //Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts //a Done channel func JustBeforeEach(body interface{}, timeout ...float64) bool { global.Suite.PushJustBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...)) return true } //JustAfterEach blocks are run after It blocks but *before* all AfterEach blocks. For more details, //read the [documentation](http://onsi.github.io/ginkgo/#separating_creation_and_configuration_) // //Like It blocks, JustAfterEach blocks can be made asynchronous by providing a body function that accepts //a Done channel func JustAfterEach(body interface{}, timeout ...float64) bool { global.Suite.PushJustAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...)) return true } //AfterEach blocks are run after It blocks. When multiple AfterEach blocks are defined in nested //Describe and Context blocks the innermost AfterEach blocks are run first. // //Like It blocks, AfterEach blocks can be made asynchronous by providing a body function that accepts //a Done channel func AfterEach(body interface{}, timeout ...float64) bool { global.Suite.PushAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...)) return true } func parseTimeout(timeout ...float64) time.Duration { if len(timeout) == 0 { return global.DefaultTimeout } else { return time.Duration(timeout[0] * float64(time.Second)) } } ginkgo-1.14.2/go.mod000066400000000000000000000003761374111457300141770ustar00rootroot00000000000000module github.com/onsi/ginkgo require ( github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/nxadm/tail v1.4.4 github.com/onsi/gomega v1.10.1 golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 golang.org/x/text v0.3.2 // indirect ) go 1.13 ginkgo-1.14.2/go.sum000066400000000000000000000142421374111457300142210ustar00rootroot00000000000000github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= ginkgo-1.14.2/integration/000077500000000000000000000000001374111457300154065ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/000077500000000000000000000000001374111457300174165ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/000077500000000000000000000000001374111457300246175ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/first_package/000077500000000000000000000000001374111457300274215ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/first_package/coverage.go000066400000000000000000000003021374111457300315360ustar00rootroot00000000000000package first_package func A() string { return "A" } func B() string { return "B" } func C() string { return "C" } func D() string { return "D" } func E() string { return "untested" } coverage_fixture_suite_test.go000066400000000000000000000003361374111457300355040ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/first_packagepackage first_package_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestCoverageFixture(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "CombinedFixture First Suite") } ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/first_package/coverage_fixture_test.go000066400000000000000000000012671374111457300343560ustar00rootroot00000000000000package first_package_test import ( . "github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package" . "github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/first_package/external_coverage_fixture" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("CoverageFixture", func() { It("should test A", func() { Ω(A()).Should(Equal("A")) }) It("should test B", func() { Ω(B()).Should(Equal("B")) }) It("should test C", func() { Ω(C()).Should(Equal("C")) }) It("should test D", func() { Ω(D()).Should(Equal("D")) }) It("should test external package", func() { Ω(Tested()).Should(Equal("tested")) }) }) external_coverage_fixture/000077500000000000000000000000001374111457300346055ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/first_packageexternal_coverage.go000066400000000000000000000001641374111457300406320ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/first_package/external_coverage_fixturepackage external_coverage func Tested() string { return "tested" } func Untested() string { return "untested" } ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/second_package/000077500000000000000000000000001374111457300275455ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/second_package/coverage.go000066400000000000000000000002741374111457300316720ustar00rootroot00000000000000package second_package func A() string { return "A" } func B() string { return "B" } func C() string { return "C" } func D() string { return "D" } func E() string { return "E" } coverage_fixture_suite_test.go000066400000000000000000000003401374111457300356230ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/second_packagepackage second_package_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestCoverageFixture(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "CombinedFixture Second Suite") } coverage_fixture_test.go000066400000000000000000000010531374111457300344140ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/combined_coverage_fixture/second_packagepackage second_package_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/integration/_fixtures/combined_coverage_fixture/second_package" . "github.com/onsi/gomega" ) var _ = Describe("CoverageFixture", func() { It("should test A", func() { Ω(A()).Should(Equal("A")) }) It("should test B", func() { Ω(B()).Should(Equal("B")) }) It("should test C", func() { Ω(C()).Should(Equal("C")) }) It("should test D", func() { Ω(D()).Should(Equal("D")) }) It("should test E", func() { Ω(E()).Should(Equal("E")) }) }) ginkgo-1.14.2/integration/_fixtures/convert_fixtures/000077500000000000000000000000001374111457300230275ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/convert_fixtures/extra_functions_test.go000066400000000000000000000004001374111457300276220ustar00rootroot00000000000000package tmp import ( "testing" ) func TestSomethingLessImportant(t *testing.T) { strp := "hello!" somethingImportant(t, &strp) } func somethingImportant(t *testing.T, message *string) { t.Log("Something important happened in a test: " + *message) } ginkgo-1.14.2/integration/_fixtures/convert_fixtures/nested/000077500000000000000000000000001374111457300243115ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/convert_fixtures/nested/nested_test.go000066400000000000000000000002551374111457300271630ustar00rootroot00000000000000package nested import ( "testing" ) func TestSomethingLessImportant(t *testing.T) { whatever := &UselessStruct{} t.Fail(whatever.ImportantField != "SECRET_PASSWORD") } ginkgo-1.14.2/integration/_fixtures/convert_fixtures/nested_without_gofiles/000077500000000000000000000000001374111457300276045ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/convert_fixtures/nested_without_gofiles/subpackage/000077500000000000000000000000001374111457300317115ustar00rootroot00000000000000nested_subpackage_test.go000066400000000000000000000001461374111457300366700ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/convert_fixtures/nested_without_gofiles/subpackagepackage subpackage import ( "testing" ) func TestNestedSubPackages(t *testing.T) { t.Fail(true) } ginkgo-1.14.2/integration/_fixtures/convert_fixtures/outside_package_test.go000066400000000000000000000003541374111457300275460ustar00rootroot00000000000000package tmp_test import ( "testing" ) type UselessStruct struct { ImportantField string } func TestSomethingImportant(t *testing.T) { whatever := &UselessStruct{} if whatever.ImportantField != "SECRET_PASSWORD" { t.Fail() } } ginkgo-1.14.2/integration/_fixtures/convert_fixtures/xunit_test.go000066400000000000000000000013351374111457300255660ustar00rootroot00000000000000package tmp import ( "testing" ) type UselessStruct struct { ImportantField string T *testing.T } var testFunc = func(t *testing.T, arg *string) {} func assertEqual(t *testing.T, arg1, arg2 interface{}) { if arg1 != arg2 { t.Fail() } } func TestSomethingImportant(t *testing.T) { whatever := &UselessStruct{ T: t, ImportantField: "SECRET_PASSWORD", } something := &UselessStruct{ImportantField: "string value"} assertEqual(t, whatever.ImportantField, "SECRET_PASSWORD") assertEqual(t, something.ImportantField, "string value") var foo = func(t *testing.T) {} foo(t) strp := "something" testFunc(t, &strp) t.Fail() } func Test3Things(t *testing.T) { if 3 != 3 { t.Fail() } } ginkgo-1.14.2/integration/_fixtures/convert_goldmasters/000077500000000000000000000000001374111457300235025ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/convert_goldmasters/extra_functions_test.go000066400000000000000000000005211374111457300303010ustar00rootroot00000000000000package tmp import ( . "github.com/onsi/ginkgo" ) var _ = Describe("Testing with Ginkgo", func() { It("something less important", func() { strp := "hello!" somethingImportant(GinkgoT(), &strp) }) }) func somethingImportant(t GinkgoTInterface, message *string) { t.Log("Something important happened in a test: " + *message) } ginkgo-1.14.2/integration/_fixtures/convert_goldmasters/fixtures_suite_test.go000066400000000000000000000002611374111457300301510ustar00rootroot00000000000000package tmp import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestTmp(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Tmp Suite") } ginkgo-1.14.2/integration/_fixtures/convert_goldmasters/nested_subpackage_test.go000066400000000000000000000002571374111457300305430ustar00rootroot00000000000000package subpackage import ( . "github.com/onsi/ginkgo" ) var _ = Describe("Testing with Ginkgo", func() { It("nested sub packages", func() { GinkgoT().Fail(true) }) }) ginkgo-1.14.2/integration/_fixtures/convert_goldmasters/nested_suite_test.go000066400000000000000000000002771374111457300275710ustar00rootroot00000000000000package nested_test import ( "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) func TestNested(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Nested Suite") } ginkgo-1.14.2/integration/_fixtures/convert_goldmasters/nested_test.go000066400000000000000000000003701374111457300263520ustar00rootroot00000000000000package nested import ( . "github.com/onsi/ginkgo" ) var _ = Describe("Testing with Ginkgo", func() { It("something less important", func() { whatever := &UselessStruct{} GinkgoT().Fail(whatever.ImportantField != "SECRET_PASSWORD") }) }) ginkgo-1.14.2/integration/_fixtures/convert_goldmasters/outside_package_test.go000066400000000000000000000004701374111457300302200ustar00rootroot00000000000000package tmp_test import ( . "github.com/onsi/ginkgo" ) var _ = Describe("Testing with Ginkgo", func() { It("something important", func() { whatever := &UselessStruct{} if whatever.ImportantField != "SECRET_PASSWORD" { GinkgoT().Fail() } }) }) type UselessStruct struct { ImportantField string } ginkgo-1.14.2/integration/_fixtures/convert_goldmasters/suite_test.go000066400000000000000000000003161374111457300262210ustar00rootroot00000000000000package tmp_test import ( "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) func TestConvertFixtures(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "ConvertFixtures Suite") } ginkgo-1.14.2/integration/_fixtures/convert_goldmasters/xunit_test.go000066400000000000000000000015661374111457300262470ustar00rootroot00000000000000package tmp import ( . "github.com/onsi/ginkgo" ) var _ = Describe("Testing with Ginkgo", func() { It("something important", func() { whatever := &UselessStruct{ T: GinkgoT(), ImportantField: "SECRET_PASSWORD", } something := &UselessStruct{ImportantField: "string value"} assertEqual(GinkgoT(), whatever.ImportantField, "SECRET_PASSWORD") assertEqual(GinkgoT(), something.ImportantField, "string value") var foo = func(t GinkgoTInterface) {} foo(GinkgoT()) strp := "something" testFunc(GinkgoT(), &strp) GinkgoT().Fail() }) It("3 things", func() { if 3 != 3 { GinkgoT().Fail() } }) }) type UselessStruct struct { ImportantField string T GinkgoTInterface } var testFunc = func(t GinkgoTInterface, arg *string) {} func assertEqual(t GinkgoTInterface, arg1, arg2 interface{}) { if arg1 != arg2 { t.Fail() } } ginkgo-1.14.2/integration/_fixtures/coverage_fixture/000077500000000000000000000000001374111457300227575ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/coverage_fixture/coverage.go000066400000000000000000000004561374111457300251060ustar00rootroot00000000000000package coverage_fixture import ( _ "github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture" ) func A() string { return "A" } func B() string { return "B" } func C() string { return "C" } func D() string { return "D" } func E() string { return "untested" } ginkgo-1.14.2/integration/_fixtures/coverage_fixture/coverage_fixture_suite_test.go000066400000000000000000000003331374111457300311160ustar00rootroot00000000000000package coverage_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestCoverageFixture(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "CoverageFixture Suite") } ginkgo-1.14.2/integration/_fixtures/coverage_fixture/coverage_fixture_test.go000066400000000000000000000012141374111457300277040ustar00rootroot00000000000000package coverage_fixture_test import ( . "github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture" . "github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("CoverageFixture", func() { It("should test A", func() { Ω(A()).Should(Equal("A")) }) It("should test B", func() { Ω(B()).Should(Equal("B")) }) It("should test C", func() { Ω(C()).Should(Equal("C")) }) It("should test D", func() { Ω(D()).Should(Equal("D")) }) It("should test external package", func() { Ω(Tested()).Should(Equal("tested")) }) }) ginkgo-1.14.2/integration/_fixtures/coverage_fixture/external_coverage_fixture/000077500000000000000000000000001374111457300302225ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/coverage_fixture/external_coverage_fixture/external_coverage.go000066400000000000000000000001641374111457300342470ustar00rootroot00000000000000package external_coverage func Tested() string { return "tested" } func Untested() string { return "untested" } ginkgo-1.14.2/integration/_fixtures/debug_parallel_fixture/000077500000000000000000000000001374111457300241265ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/debug_parallel_fixture/debug_parallel_fixture_suite_test.go000066400000000000000000000003531374111457300334360ustar00rootroot00000000000000package debug_parallel_fixture_test import ( "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) func TestDebugParallelFixture(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "DebugParallelFixture Suite") } ginkgo-1.14.2/integration/_fixtures/debug_parallel_fixture/debug_parallel_fixture_test.go000066400000000000000000000005351374111457300322270ustar00rootroot00000000000000package debug_parallel_fixture_test import ( "fmt" "time" . "github.com/onsi/ginkgo" ) var _ = Describe("DebugParallelFixture", func() { It("emits output to a file", func() { for i := 0; i < 10; i += 1 { fmt.Printf("StdOut %d\n", i) GinkgoWriter.Write([]byte(fmt.Sprintf("GinkgoWriter %d\n", i))) } time.Sleep(time.Second) }) }) ginkgo-1.14.2/integration/_fixtures/does_not_compile/000077500000000000000000000000001374111457300227405ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/does_not_compile/does_not_compile_suite_test.go000066400000000000000000000003351374111457300310620ustar00rootroot00000000000000package does_not_compile_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestDoes_not_compile(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Does_not_compile Suite") } ginkgo-1.14.2/integration/_fixtures/does_not_compile/does_not_compile_test.go000066400000000000000000000003261374111457300276510ustar00rootroot00000000000000package does_not_compile_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/integration/_fixtures/does_not_compile" . "github.com/onsi/gomega" ) var _ = Describe("DoesNotCompile", func() { }) ginkgo-1.14.2/integration/_fixtures/eventually_failing/000077500000000000000000000000001374111457300232775ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/eventually_failing/eventually_failing_suite_test.go000066400000000000000000000003411374111457300317550ustar00rootroot00000000000000package eventually_failing_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestEventuallyFailing(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "EventuallyFailing Suite") } ginkgo-1.14.2/integration/_fixtures/eventually_failing/eventually_failing_test.go000066400000000000000000000011051374111457300305430ustar00rootroot00000000000000package eventually_failing_test import ( "fmt" "io/ioutil" "strings" "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("EventuallyFailing", func() { It("should fail on the third try", func() { time.Sleep(time.Second) files, err := ioutil.ReadDir(".") Ω(err).ShouldNot(HaveOccurred()) numRuns := 1 for _, file := range files { if strings.HasPrefix(file.Name(), "counter") { numRuns++ } } Ω(numRuns).Should(BeNumerically("<", 3)) ioutil.WriteFile(fmt.Sprintf("./counter-%d", numRuns), []byte("foo"), 0777) }) }) ginkgo-1.14.2/integration/_fixtures/exiting_synchronized_setup_tests/000077500000000000000000000000001374111457300263265ustar00rootroot00000000000000exiting_synchronized_setup_tests_suite_test.go000066400000000000000000000012221374111457300377530ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/exiting_synchronized_setup_testspackage synchronized_setup_tests_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "fmt" "os" "testing" ) func TestSynchronized_setup_tests(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Synchronized_setup_tests Suite") } var beforeData string var _ = SynchronizedBeforeSuite(func() []byte { fmt.Printf("BEFORE_A_%d\n", GinkgoParallelNode()) os.Exit(1) return []byte("WHAT EVZ") }, func(data []byte) { println("NEVER SEE THIS") }) var _ = Describe("Synchronized Setup", func() { It("should do nothing", func() { Ω(true).Should(BeTrue()) }) It("should do nothing", func() { Ω(true).Should(BeTrue()) }) }) ginkgo-1.14.2/integration/_fixtures/fail_fixture/000077500000000000000000000000001374111457300220775ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/fail_fixture/fail_fixture_suite_test.go000066400000000000000000000003211374111457300273530ustar00rootroot00000000000000package fail_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFail_fixture(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Fail_fixture Suite") } ginkgo-1.14.2/integration/_fixtures/fail_fixture/fail_fixture_test.go000066400000000000000000000051561374111457300261550ustar00rootroot00000000000000package fail_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" ) var _ = It("handles top level failures", func() { Ω("a top level failure on line 10").Should(Equal("nope")) println("NEVER SEE THIS") }) var _ = It("handles async top level failures", func(done Done) { Fail("an async top level failure on line 15") println("NEVER SEE THIS") }, 0.1) var _ = It("FAIL in a goroutine", func(done Done) { go func() { defer GinkgoRecover() Fail("a top level goroutine failure on line 22") println("NEVER SEE THIS") }() }, 0.1) var _ = Describe("Excercising different failure modes", func() { It("synchronous failures", func() { Ω("a sync failure").Should(Equal("nope")) println("NEVER SEE THIS") }) It("synchronous panics", func() { panic("a sync panic") println("NEVER SEE THIS") }) It("synchronous failures with FAIL", func() { Fail("a sync FAIL failure") println("NEVER SEE THIS") }) It("async timeout", func(done Done) { Ω(true).Should(BeTrue()) }, 0.1) It("async failure", func(done Done) { Ω("an async failure").Should(Equal("nope")) println("NEVER SEE THIS") }, 0.1) It("async panic", func(done Done) { panic("an async panic") println("NEVER SEE THIS") }, 0.1) It("async failure with FAIL", func(done Done) { Fail("an async FAIL failure") println("NEVER SEE THIS") }, 0.1) It("FAIL in a goroutine", func(done Done) { go func() { defer GinkgoRecover() Fail("a goroutine FAIL failure") println("NEVER SEE THIS") }() }, 0.1) It("Gomega in a goroutine", func(done Done) { go func() { defer GinkgoRecover() Ω("a goroutine failure").Should(Equal("nope")) println("NEVER SEE THIS") }() }, 0.1) It("Panic in a goroutine", func(done Done) { go func() { defer GinkgoRecover() panic("a goroutine panic") println("NEVER SEE THIS") }() }, 0.1) Measure("a FAIL measure", func(Benchmarker) { Fail("a measure FAIL failure") println("NEVER SEE THIS") }, 1) Measure("a gomega failed measure", func(Benchmarker) { Ω("a measure failure").Should(Equal("nope")) println("NEVER SEE THIS") }, 1) Measure("a panicking measure", func(Benchmarker) { panic("a measure panic") println("NEVER SEE THIS") }, 1) }) var _ = Specify("a top level specify", func() { Fail("fail the test") }) var _ = DescribeTable("a top level DescribeTable", func(x, y int) { Expect(x).To(Equal(y)) }, Entry("a TableEntry constructed by Entry", 2, 3), TableEntry{ Description: "a directly constructed TableEntry", Parameters: []interface{}{2, 3}, Pending: false, Focused: false, }, ) ginkgo-1.14.2/integration/_fixtures/failing_after_suite/000077500000000000000000000000001374111457300234215ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/failing_after_suite/failing_after_suite_suite_test.go000066400000000000000000000005441374111457300322260ustar00rootroot00000000000000package failing_before_suite_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFailingAfterSuite(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "FailingAfterSuite Suite") } var _ = BeforeSuite(func() { println("BEFORE SUITE") }) var _ = AfterSuite(func() { println("AFTER SUITE") panic("BAM!") }) ginkgo-1.14.2/integration/_fixtures/failing_after_suite/failing_after_suite_test.go000066400000000000000000000003451374111457300310140ustar00rootroot00000000000000package failing_before_suite_test import ( . "github.com/onsi/ginkgo" ) var _ = Describe("FailingBeforeSuite", func() { It("should run", func() { println("A TEST") }) It("should run", func() { println("A TEST") }) }) ginkgo-1.14.2/integration/_fixtures/failing_before_suite/000077500000000000000000000000001374111457300235625ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/failing_before_suite/failing_before_suite_suite_test.go000066400000000000000000000005521374111457300325270ustar00rootroot00000000000000package failing_before_suite_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFailing_before_suite(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Failing_before_suite Suite") } var _ = BeforeSuite(func() { println("BEFORE SUITE") panic("BAM!") }) var _ = AfterSuite(func() { println("AFTER SUITE") }) ginkgo-1.14.2/integration/_fixtures/failing_before_suite/failing_before_suite_test.go000066400000000000000000000004011374111457300313070ustar00rootroot00000000000000package failing_before_suite_test import ( . "github.com/onsi/ginkgo" ) var _ = Describe("FailingBeforeSuite", func() { It("should never run", func() { println("NEVER SEE THIS") }) It("should never run", func() { println("NEVER SEE THIS") }) }) ginkgo-1.14.2/integration/_fixtures/failing_ginkgo_tests/000077500000000000000000000000001374111457300236075ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/failing_ginkgo_tests/failing_ginkgo_tests.go000066400000000000000000000001101374111457300303170ustar00rootroot00000000000000package failing_ginkgo_tests func AlwaysFalse() bool { return false } ginkgo-1.14.2/integration/_fixtures/failing_ginkgo_tests/failing_ginkgo_tests_suite_test.go000066400000000000000000000003511374111457300325760ustar00rootroot00000000000000package failing_ginkgo_tests_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFailing_ginkgo_tests(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Failing_ginkgo_tests Suite") } ginkgo-1.14.2/integration/_fixtures/failing_ginkgo_tests/failing_ginkgo_tests_test.go000066400000000000000000000005551374111457300313730ustar00rootroot00000000000000package failing_ginkgo_tests_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/integration/_fixtures/failing_ginkgo_tests" . "github.com/onsi/gomega" ) var _ = Describe("FailingGinkgoTests", func() { It("should fail", func() { Ω(AlwaysFalse()).Should(BeTrue()) }) It("should pass", func() { Ω(AlwaysFalse()).Should(BeFalse()) }) }) ginkgo-1.14.2/integration/_fixtures/flags_tests/000077500000000000000000000000001374111457300217345ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/flags_tests/flags.go000066400000000000000000000001501374111457300233530ustar00rootroot00000000000000package flags func Tested() string { return "tested" } func Untested() string { return "untested" } ginkgo-1.14.2/integration/_fixtures/flags_tests/flags_suite_test.go000066400000000000000000000002741374111457300256320ustar00rootroot00000000000000package flags_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFlags(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Flags Suite") } ginkgo-1.14.2/integration/_fixtures/flags_tests/flags_test.go000066400000000000000000000036221374111457300244210ustar00rootroot00000000000000package flags_test import ( "flag" "fmt" remapped "math" _ "math/cmplx" "time" . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/integration/_fixtures/flags_tests" . "github.com/onsi/gomega" ) var customFlag string func init() { flag.StringVar(&customFlag, "customFlag", "default", "custom flag!") } var _ = Describe("Testing various flags", func() { FDescribe("the focused set", func() { Measure("a measurement", func(b Benchmarker) { b.RecordValue("a value", 3) }, 3) It("should honor -cover", func() { Ω(Tested()).Should(Equal("tested")) }) It("should allow gcflags", func() { fmt.Printf("NaN returns %T\n", remapped.NaN()) }) PIt("should honor -failOnPending and -noisyPendings") Describe("smores", func() { It("should honor -skip: marshmallow", func() { println("marshmallow") }) It("should honor -focus: chocolate", func() { println("chocolate") }) }) It("should detect races", func(done Done) { var a string go func() { a = "now you don't" close(done) }() a = "now you see me" println(a) }) It("should randomize A", func() { println("RANDOM_A") }) It("should randomize B", func() { println("RANDOM_B") }) It("should randomize C", func() { println("RANDOM_C") }) It("should honor -slowSpecThreshold", func() { time.Sleep(100 * time.Millisecond) }) It("should pass in additional arguments after '--' directly to the test process", func() { fmt.Printf("CUSTOM_FLAG: %s", customFlag) }) }) Describe("more smores", func() { It("should not run these unless -focus is set", func() { println("smores") }) }) Describe("a failing test", func() { It("should fail", func() { Ω(true).Should(Equal(false)) }) }) Describe("a flaky test", func() { runs := 0 It("should only pass the second time it's run", func() { runs++ Ω(runs).Should(BeNumerically("==", 2)) }) }) }) ginkgo-1.14.2/integration/_fixtures/focused_fixture/000077500000000000000000000000001374111457300226145ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/focused_fixture/README.md000066400000000000000000000001361374111457300240730ustar00rootroot00000000000000This file should remain the same, regardless the fact that contains FIt, FDescribe, or FWhen. ginkgo-1.14.2/integration/_fixtures/focused_fixture/focused_fixture_suite_test.go000066400000000000000000000003321374111457300306070ustar00rootroot00000000000000package focused_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFocused_fixture(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Focused_fixture Suite") } ginkgo-1.14.2/integration/_fixtures/focused_fixture/focused_fixture_test.go000066400000000000000000000016171374111457300274050ustar00rootroot00000000000000package focused_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/extensions/table" ) var _ = Describe("FocusedFixture", func() { FDescribe("focused", func() { It("focused", func() { }) }) FContext("focused", func() { It("focused", func() { }) }) FWhen("focused", func() { It("focused", func() { }) }) FIt("focused", func() { }) FSpecify("focused", func() { }) FMeasure("focused", func(b Benchmarker) { }, 2) FDescribeTable("focused", func() {}, Entry("focused"), ) DescribeTable("focused", func() {}, FEntry("focused"), ) Describe("not focused", func() { It("not focused", func() { }) }) Context("not focused", func() { It("not focused", func() { }) }) It("not focused", func() { }) Measure("not focused", func(b Benchmarker) { }, 2) DescribeTable("not focused", func() {}, Entry("not focused"), ) }) ginkgo-1.14.2/integration/_fixtures/focused_fixture/internal/000077500000000000000000000000001374111457300244305ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/focused_fixture/internal/focused_fixture_suite_test.go000066400000000000000000000003321374111457300324230ustar00rootroot00000000000000package focused_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFocused_fixture(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Focused_fixture Suite") } ginkgo-1.14.2/integration/_fixtures/focused_fixture/internal/focused_fixture_test.go000066400000000000000000000016171374111457300312210ustar00rootroot00000000000000package focused_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/extensions/table" ) var _ = Describe("FocusedFixture", func() { FDescribe("focused", func() { It("focused", func() { }) }) FContext("focused", func() { It("focused", func() { }) }) FWhen("focused", func() { It("focused", func() { }) }) FIt("focused", func() { }) FSpecify("focused", func() { }) FMeasure("focused", func(b Benchmarker) { }, 2) FDescribeTable("focused", func() {}, Entry("focused"), ) DescribeTable("focused", func() {}, FEntry("focused"), ) Describe("not focused", func() { It("not focused", func() { }) }) Context("not focused", func() { It("not focused", func() { }) }) It("not focused", func() { }) Measure("not focused", func(b Benchmarker) { }, 2) DescribeTable("not focused", func() {}, Entry("not focused"), ) }) ginkgo-1.14.2/integration/_fixtures/focused_fixture_with_vendor/000077500000000000000000000000001374111457300252245ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/focused_fixture_with_vendor/focused_fixture_suite_test.go000066400000000000000000000003321374111457300332170ustar00rootroot00000000000000package focused_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFocused_fixture(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Focused_fixture Suite") } ginkgo-1.14.2/integration/_fixtures/focused_fixture_with_vendor/focused_fixture_test.go000066400000000000000000000016171374111457300320150ustar00rootroot00000000000000package focused_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/extensions/table" ) var _ = Describe("FocusedFixture", func() { FDescribe("focused", func() { It("focused", func() { }) }) FContext("focused", func() { It("focused", func() { }) }) FWhen("focused", func() { It("focused", func() { }) }) FIt("focused", func() { }) FSpecify("focused", func() { }) FMeasure("focused", func(b Benchmarker) { }, 2) FDescribeTable("focused", func() {}, Entry("focused"), ) DescribeTable("focused", func() {}, FEntry("focused"), ) Describe("not focused", func() { It("not focused", func() { }) }) Context("not focused", func() { It("not focused", func() { }) }) It("not focused", func() { }) Measure("not focused", func(b Benchmarker) { }, 2) DescribeTable("not focused", func() {}, Entry("not focused"), ) }) ginkgo-1.14.2/integration/_fixtures/focused_fixture_with_vendor/vendor/000077500000000000000000000000001374111457300265215ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/focused_fixture_with_vendor/vendor/foo/000077500000000000000000000000001374111457300273045ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/focused_fixture_with_vendor/vendor/foo/bar/000077500000000000000000000000001374111457300300505ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/focused_fixture_with_vendor/vendor/foo/bar/bar.go000066400000000000000000000000461374111457300311430ustar00rootroot00000000000000package vendored func FContext() { } ginkgo-1.14.2/integration/_fixtures/focused_fixture_with_vendor/vendor/foo/foo.go000066400000000000000000000000411374111457300304110ustar00rootroot00000000000000package vendored func FIt() { } ginkgo-1.14.2/integration/_fixtures/focused_fixture_with_vendor/vendor/vendored.go000066400000000000000000000000661374111457300306600ustar00rootroot00000000000000package vendored func FDescribe() int { return 42 } ginkgo-1.14.2/integration/_fixtures/hanging_suite/000077500000000000000000000000001374111457300222425ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/hanging_suite/hanging_suite_suite_test.go000066400000000000000000000003221374111457300276620ustar00rootroot00000000000000package hanging_suite_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestHangingSuite(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "HangingSuite Suite") } ginkgo-1.14.2/integration/_fixtures/hanging_suite/hanging_suite_test.go000066400000000000000000000010341374111457300264520ustar00rootroot00000000000000package hanging_suite_test import ( "fmt" "time" . "github.com/onsi/ginkgo" ) var _ = AfterSuite(func() { fmt.Println("Heading Out After Suite") }) var _ = Describe("HangingSuite", func() { BeforeEach(func() { fmt.Fprintln(GinkgoWriter, "Just beginning") }) Context("inner context", func() { BeforeEach(func() { fmt.Fprintln(GinkgoWriter, "Almost there...") }) It("should hang out for a while", func() { fmt.Fprintln(GinkgoWriter, "Hanging Out") fmt.Println("Sleeping...") time.Sleep(time.Hour) }) }) }) ginkgo-1.14.2/integration/_fixtures/more_ginkgo_tests/000077500000000000000000000000001374111457300231405ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/more_ginkgo_tests/more_ginkgo_tests.go000066400000000000000000000001031374111457300272030ustar00rootroot00000000000000package more_ginkgo_tests func AlwaysTrue() bool { return true } ginkgo-1.14.2/integration/_fixtures/more_ginkgo_tests/more_ginkgo_tests_suite_test.go000066400000000000000000000003401374111457300314560ustar00rootroot00000000000000package more_ginkgo_tests_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestMore_ginkgo_tests(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "More_ginkgo_tests Suite") } ginkgo-1.14.2/integration/_fixtures/more_ginkgo_tests/more_ginkgo_tests_test.go000066400000000000000000000005501374111457300302500ustar00rootroot00000000000000package more_ginkgo_tests_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/integration/_fixtures/more_ginkgo_tests" . "github.com/onsi/gomega" ) var _ = Describe("MoreGinkgoTests", func() { It("should pass", func() { Ω(AlwaysTrue()).Should(BeTrue()) }) It("should always pass", func() { Ω(AlwaysTrue()).Should(BeTrue()) }) }) ginkgo-1.14.2/integration/_fixtures/no_test_fn/000077500000000000000000000000001374111457300215545ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/no_test_fn/no_test_fn.go000066400000000000000000000001071374111457300242370ustar00rootroot00000000000000package no_test_fn func StringIdentity(a string) string { return a } ginkgo-1.14.2/integration/_fixtures/no_test_fn/no_test_fn_test.go000066400000000000000000000004351374111457300253020ustar00rootroot00000000000000package no_test_fn_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/integration/_fixtures/no_test_fn" . "github.com/onsi/gomega" ) var _ = Describe("NoTestFn", func() { It("should proxy strings", func() { Ω(StringIdentity("foo")).Should(Equal("foo")) }) }) ginkgo-1.14.2/integration/_fixtures/no_tests/000077500000000000000000000000001374111457300212545ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/no_tests/no_tests.go000066400000000000000000000000361374111457300234400ustar00rootroot00000000000000package main func main() { } ginkgo-1.14.2/integration/_fixtures/passing_ginkgo_tests/000077500000000000000000000000001374111457300236425ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/passing_ginkgo_tests/passing_ginkgo_tests.go000066400000000000000000000002001374111457300304050ustar00rootroot00000000000000package passing_ginkgo_tests func StringIdentity(a string) string { return a } func IntegerIdentity(a int) int { return a } ginkgo-1.14.2/integration/_fixtures/passing_ginkgo_tests/passing_ginkgo_tests_suite_test.go000066400000000000000000000003511374111457300326640ustar00rootroot00000000000000package passing_ginkgo_tests_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestPassing_ginkgo_tests(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Passing_ginkgo_tests Suite") } ginkgo-1.14.2/integration/_fixtures/passing_ginkgo_tests/passing_ginkgo_tests_test.go000066400000000000000000000012511374111457300314530ustar00rootroot00000000000000package passing_ginkgo_tests_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/integration/_fixtures/passing_ginkgo_tests" . "github.com/onsi/gomega" ) var _ = Describe("PassingGinkgoTests", func() { It("should proxy strings", func() { Ω(StringIdentity("foo")).Should(Equal("foo")) }) It("should proxy integers", func() { Ω(IntegerIdentity(3)).Should(Equal(3)) }) It("should do it again", func() { Ω(StringIdentity("foo")).Should(Equal("foo")) Ω(IntegerIdentity(3)).Should(Equal(3)) }) It("should be able to run Bys", func() { By("emitting one By") Ω(3).Should(Equal(3)) By("emitting another By") Ω(4).Should(Equal(4)) }) }) ginkgo-1.14.2/integration/_fixtures/passing_suite_setup/000077500000000000000000000000001374111457300235135ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/passing_suite_setup/passing_suite_setup_suite_test.go000066400000000000000000000006371374111457300324150ustar00rootroot00000000000000package passing_before_suite_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestPassingSuiteSetup(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "PassingSuiteSetup Suite") } var a string var b string var _ = BeforeSuite(func() { a = "ran before suite" println("BEFORE SUITE") }) var _ = AfterSuite(func() { b = "ran after suite" println("AFTER SUITE") }) ginkgo-1.14.2/integration/_fixtures/passing_suite_setup/passing_suite_test.go000066400000000000000000000010541374111457300277560ustar00rootroot00000000000000package passing_before_suite_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("PassingSuiteSetup", func() { It("should pass", func() { Ω(a).Should(Equal("ran before suite")) Ω(b).Should(BeEmpty()) }) It("should pass", func() { Ω(a).Should(Equal("ran before suite")) Ω(b).Should(BeEmpty()) }) It("should pass", func() { Ω(a).Should(Equal("ran before suite")) Ω(b).Should(BeEmpty()) }) It("should pass", func() { Ω(a).Should(Equal("ran before suite")) Ω(b).Should(BeEmpty()) }) }) ginkgo-1.14.2/integration/_fixtures/progress_fixture/000077500000000000000000000000001374111457300230305ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/progress_fixture/progress_fixture_suite_test.go000066400000000000000000000003331374111457300312400ustar00rootroot00000000000000package progress_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestProgressFixture(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "ProgressFixture Suite") } ginkgo-1.14.2/integration/_fixtures/progress_fixture/progress_fixture_test.go000066400000000000000000000016501374111457300300320ustar00rootroot00000000000000package progress_fixture_test import ( "fmt" . "github.com/onsi/ginkgo" ) var _ = Describe("ProgressFixture", func() { BeforeEach(func() { fmt.Fprintln(GinkgoWriter, ">outer before<") }) JustBeforeEach(func() { fmt.Fprintln(GinkgoWriter, ">outer just before<") }) AfterEach(func() { fmt.Fprintln(GinkgoWriter, ">outer after<") }) Context("Inner Context", func() { BeforeEach(func() { fmt.Fprintln(GinkgoWriter, ">inner before<") }) JustBeforeEach(func() { fmt.Fprintln(GinkgoWriter, ">inner just before<") }) AfterEach(func() { fmt.Fprintln(GinkgoWriter, ">inner after<") }) When("Inner When", func() { BeforeEach(func() { fmt.Fprintln(GinkgoWriter, ">inner before<") }) It("should emit progress as it goes", func() { fmt.Fprintln(GinkgoWriter, ">it<") }) }) }) Specify("should emit progress as it goes", func() { fmt.Fprintln(GinkgoWriter, ">specify<") }) }) ginkgo-1.14.2/integration/_fixtures/skip_fixture/000077500000000000000000000000001374111457300221325ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/skip_fixture/skip_fixture_suite_test.go000066400000000000000000000003211374111457300274410ustar00rootroot00000000000000package fail_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFail_fixture(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Skip_fixture Suite") } ginkgo-1.14.2/integration/_fixtures/skip_fixture/skip_fixture_test.go000066400000000000000000000026471374111457300262450ustar00rootroot00000000000000package fail_fixture_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = It("handles top level skips", func() { Skip("a top level skip on line 9") println("NEVER SEE THIS") }) var _ = It("handles async top level skips", func(done Done) { Skip("an async top level skip on line 14") println("NEVER SEE THIS") }, 0.1) var _ = It("SKIP in a goroutine", func(done Done) { go func() { defer GinkgoRecover() Skip("a top level goroutine skip on line 21") println("NEVER SEE THIS") }() }, 0.1) var _ = Describe("Excercising different skip modes", func() { It("synchronous skip", func() { Skip("a sync SKIP") println("NEVER SEE THIS") }) It("async skip", func(done Done) { Skip("an async SKIP") println("NEVER SEE THIS") }, 0.1) It("SKIP in a goroutine", func(done Done) { go func() { defer GinkgoRecover() Skip("a goroutine SKIP") println("NEVER SEE THIS") }() }, 0.1) Measure("a SKIP measure", func(Benchmarker) { Skip("a measure SKIP") println("NEVER SEE THIS") }, 1) }) var _ = Describe("SKIP in a BeforeEach", func() { BeforeEach(func() { Skip("a BeforeEach SKIP") println("NEVER SEE THIS") }) It("a SKIP BeforeEach", func() { println("NEVER SEE THIS") }) }) var _ = Describe("SKIP in an AfterEach", func() { AfterEach(func() { Skip("an AfterEach SKIP") println("NEVER SEE THIS") }) It("a SKIP AfterEach", func() { Expect(true).To(BeTrue()) }) }) ginkgo-1.14.2/integration/_fixtures/suite_command_tests/000077500000000000000000000000001374111457300234675ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/suite_command_tests/suite_command.go000066400000000000000000000001601374111457300266420ustar00rootroot00000000000000package suite_command func Tested() string { return "tested" } func Untested() string { return "untested" } ginkgo-1.14.2/integration/_fixtures/suite_command_tests/suite_command_suite_test.go000066400000000000000000000003231374111457300311130ustar00rootroot00000000000000package suite_command_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestSuiteCommand(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Suite Command Suite") } ginkgo-1.14.2/integration/_fixtures/suite_command_tests/suite_command_test.go000066400000000000000000000005031374111457300277020ustar00rootroot00000000000000package suite_command_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Testing suite command", func() { It("it should succeed", func() { Ω(true).Should(Equal(true)) }) PIt("a failing test", func() { It("should fail", func() { Ω(true).Should(Equal(false)) }) }) }) ginkgo-1.14.2/integration/_fixtures/synchronized_setup_tests/000077500000000000000000000000001374111457300245775ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/synchronized_setup_tests/synchronized_setup_tests_suite_test.go000066400000000000000000000017701374111457300345640ustar00rootroot00000000000000package synchronized_setup_tests_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "fmt" "testing" "time" ) func TestSynchronized_setup_tests(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Synchronized_setup_tests Suite") } var beforeData string var _ = SynchronizedBeforeSuite(func() []byte { fmt.Printf("BEFORE_A_%d\n", GinkgoParallelNode()) time.Sleep(100 * time.Millisecond) return []byte("DATA") }, func(data []byte) { fmt.Printf("BEFORE_B_%d: %s\n", GinkgoParallelNode(), string(data)) beforeData += string(data) + "OTHER" }) var _ = SynchronizedAfterSuite(func() { fmt.Printf("\nAFTER_A_%d\n", GinkgoParallelNode()) time.Sleep(100 * time.Millisecond) }, func() { fmt.Printf("AFTER_B_%d\n", GinkgoParallelNode()) }) var _ = Describe("Synchronized Setup", func() { It("should run the before suite once", func() { Ω(beforeData).Should(Equal("DATAOTHER")) }) It("should run the before suite once", func() { Ω(beforeData).Should(Equal("DATAOTHER")) }) }) ginkgo-1.14.2/integration/_fixtures/tags_tests/000077500000000000000000000000001374111457300215765ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/tags_tests/ignored_test.go000066400000000000000000000003451374111457300246150ustar00rootroot00000000000000// +build complex_tests package tags_tests_test import ( . "github.com/onsi/ginkgo" ) var _ = Describe("Ignored", func() { It("should not have these tests", func() { }) It("should not have these tests", func() { }) }) ginkgo-1.14.2/integration/_fixtures/tags_tests/tags_tests_suite_test.go000066400000000000000000000003111374111457300265500ustar00rootroot00000000000000package tags_tests_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestTagsTests(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "TagsTests Suite") } ginkgo-1.14.2/integration/_fixtures/tags_tests/tags_tests_test.go000066400000000000000000000002231374111457300253410ustar00rootroot00000000000000package tags_tests_test import ( . "github.com/onsi/ginkgo" ) var _ = Describe("TagsTests", func() { It("should have a test", func() { }) }) ginkgo-1.14.2/integration/_fixtures/test_description/000077500000000000000000000000001374111457300230005ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/test_description/test_description_suite_test.go000066400000000000000000000003331374111457300311600ustar00rootroot00000000000000package test_description_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestTestDescription(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "TestDescription Suite") } ginkgo-1.14.2/integration/_fixtures/test_description/test_description_test.go000066400000000000000000000006441374111457300277540ustar00rootroot00000000000000package test_description_test import ( "fmt" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("TestDescription", func() { It("should pass", func() { Ω(true).Should(BeTrue()) }) It("should fail", func() { Ω(true).Should(BeFalse()) }) AfterEach(func() { description := CurrentGinkgoTestDescription() fmt.Printf("%s:%t\n", description.FullTestText, description.Failed) }) }) ginkgo-1.14.2/integration/_fixtures/watch_fixtures/000077500000000000000000000000001374111457300224555ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/watch_fixtures/A/000077500000000000000000000000001374111457300226355ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/watch_fixtures/A/A.go000066400000000000000000000001131374111457300233370ustar00rootroot00000000000000package A import "$ROOT_PATH$/B" func DoIt() string { return B.DoIt() } ginkgo-1.14.2/integration/_fixtures/watch_fixtures/A/A_suite_test.go000066400000000000000000000002601374111457300256120ustar00rootroot00000000000000package A_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestA(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "A Suite") } ginkgo-1.14.2/integration/_fixtures/watch_fixtures/A/A_test.go000066400000000000000000000003171374111457300244040ustar00rootroot00000000000000package A_test import ( . "$ROOT_PATH$/A" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("A", func() { It("should do it", func() { Ω(DoIt()).Should(Equal("done!")) }) }) ginkgo-1.14.2/integration/_fixtures/watch_fixtures/B/000077500000000000000000000000001374111457300226365ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/watch_fixtures/B/B.go000066400000000000000000000001131374111457300233410ustar00rootroot00000000000000package B import "$ROOT_PATH$/C" func DoIt() string { return C.DoIt() } ginkgo-1.14.2/integration/_fixtures/watch_fixtures/B/B_suite_test.go000066400000000000000000000002601374111457300256140ustar00rootroot00000000000000package B_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestB(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "B Suite") } ginkgo-1.14.2/integration/_fixtures/watch_fixtures/B/B_test.go000066400000000000000000000003171374111457300244060ustar00rootroot00000000000000package B_test import ( . "$ROOT_PATH$/B" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("B", func() { It("should do it", func() { Ω(DoIt()).Should(Equal("done!")) }) }) ginkgo-1.14.2/integration/_fixtures/watch_fixtures/C/000077500000000000000000000000001374111457300226375ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/watch_fixtures/C/C.go000066400000000000000000000000621374111457300233460ustar00rootroot00000000000000package C func DoIt() string { return "done!" } ginkgo-1.14.2/integration/_fixtures/watch_fixtures/C/C.json000066400000000000000000000000311374111457300237060ustar00rootroot00000000000000{ "fixture": "data" }ginkgo-1.14.2/integration/_fixtures/watch_fixtures/C/C_suite_test.go000066400000000000000000000002601374111457300256160ustar00rootroot00000000000000package C_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestC(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "C Suite") } ginkgo-1.14.2/integration/_fixtures/watch_fixtures/C/C_test.go000066400000000000000000000003171374111457300244100ustar00rootroot00000000000000package C_test import ( . "$ROOT_PATH$/C" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("C", func() { It("should do it", func() { Ω(DoIt()).Should(Equal("done!")) }) }) ginkgo-1.14.2/integration/_fixtures/watch_fixtures/D/000077500000000000000000000000001374111457300226405ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/watch_fixtures/D/D.go000066400000000000000000000001131374111457300233450ustar00rootroot00000000000000package D import "$ROOT_PATH$/C" func DoIt() string { return C.DoIt() } ginkgo-1.14.2/integration/_fixtures/watch_fixtures/D/D_suite_test.go000066400000000000000000000002601374111457300256200ustar00rootroot00000000000000package D_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestD(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "D Suite") } ginkgo-1.14.2/integration/_fixtures/watch_fixtures/D/D_test.go000066400000000000000000000003171374111457300244120ustar00rootroot00000000000000package D_test import ( . "$ROOT_PATH$/D" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("D", func() { It("should do it", func() { Ω(DoIt()).Should(Equal("done!")) }) }) ginkgo-1.14.2/integration/_fixtures/xunit_tests/000077500000000000000000000000001374111457300220075ustar00rootroot00000000000000ginkgo-1.14.2/integration/_fixtures/xunit_tests/xunit_tests.go000066400000000000000000000000751374111457300247310ustar00rootroot00000000000000package xunit_tests func AlwaysTrue() bool { return true } ginkgo-1.14.2/integration/_fixtures/xunit_tests/xunit_tests_test.go000066400000000000000000000002271374111457300257670ustar00rootroot00000000000000package xunit_tests import ( "testing" ) func TestAlwaysTrue(t *testing.T) { if AlwaysTrue() != true { t.Errorf("Expected true, got false") } } ginkgo-1.14.2/integration/convert_test.go000066400000000000000000000073151374111457300204620ustar00rootroot00000000000000package integration_test import ( "io/ioutil" "os" "os/exec" "path/filepath" "strings" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("ginkgo convert", func() { var tmpDir string readConvertedFileNamed := func(pathComponents ...string) string { pathToFile := filepath.Join(tmpDir, "convert_fixtures", filepath.Join(pathComponents...)) bytes, err := ioutil.ReadFile(pathToFile) ExpectWithOffset(1, err).NotTo(HaveOccurred()) return string(bytes) } readGoldMasterNamed := func(filename string) string { bytes, err := ioutil.ReadFile(filepath.Join("_fixtures", "convert_goldmasters", filename)) Ω(err).ShouldNot(HaveOccurred()) return string(bytes) } BeforeEach(func() { var err error tmpDir, err = ioutil.TempDir("", "ginkgo-convert") Ω(err).ShouldNot(HaveOccurred()) err = exec.Command("cp", "-r", filepath.Join("_fixtures", "convert_fixtures"), tmpDir).Run() Ω(err).ShouldNot(HaveOccurred()) }) JustBeforeEach(func() { cwd, err := os.Getwd() Ω(err).ShouldNot(HaveOccurred()) relPath, err := filepath.Rel(cwd, filepath.Join(tmpDir, "convert_fixtures")) Ω(err).ShouldNot(HaveOccurred()) cmd := exec.Command(pathToGinkgo, "convert", relPath) cmd.Env = os.Environ() for i, env := range cmd.Env { if strings.HasPrefix(env, "PATH") { cmd.Env[i] = cmd.Env[i] + ":" + filepath.Dir(pathToGinkgo) break } } err = cmd.Run() Ω(err).ShouldNot(HaveOccurred()) }) AfterEach(func() { err := os.RemoveAll(tmpDir) Ω(err).ShouldNot(HaveOccurred()) }) It("rewrites xunit tests as ginkgo tests", func() { convertedFile := readConvertedFileNamed("xunit_test.go") goldMaster := readGoldMasterNamed("xunit_test.go") Ω(convertedFile).Should(Equal(goldMaster)) }) It("rewrites all usages of *testing.T as mr.T()", func() { convertedFile := readConvertedFileNamed("extra_functions_test.go") goldMaster := readGoldMasterNamed("extra_functions_test.go") Ω(convertedFile).Should(Equal(goldMaster)) }) It("rewrites tests in the package dir that belong to other packages", func() { convertedFile := readConvertedFileNamed("outside_package_test.go") goldMaster := readGoldMasterNamed("outside_package_test.go") Ω(convertedFile).Should(Equal(goldMaster)) }) It("rewrites tests in nested packages", func() { convertedFile := readConvertedFileNamed("nested", "nested_test.go") goldMaster := readGoldMasterNamed("nested_test.go") Ω(convertedFile).Should(Equal(goldMaster)) }) Context("ginkgo test suite files", func() { It("creates a ginkgo test suite file for the package you specified", func() { testsuite := readConvertedFileNamed("convert_fixtures_suite_test.go") goldMaster := readGoldMasterNamed("suite_test.go") Ω(testsuite).Should(Equal(goldMaster)) }) It("converts go tests in deeply nested packages (some may not contain go files)", func() { testsuite := readConvertedFileNamed("nested_without_gofiles", "subpackage", "nested_subpackage_test.go") goldMaster := readGoldMasterNamed("nested_subpackage_test.go") Ω(testsuite).Should(Equal(goldMaster)) }) It("creates ginkgo test suites for all nested packages", func() { testsuite := readConvertedFileNamed("nested", "nested_suite_test.go") goldMaster := readGoldMasterNamed("nested_suite_test.go") Ω(testsuite).Should(Equal(goldMaster)) }) }) Context("with an existing test suite file", func() { BeforeEach(func() { goldMaster := readGoldMasterNamed("fixtures_suite_test.go") err := ioutil.WriteFile(filepath.Join(tmpDir, "convert_fixtures", "tmp_suite_test.go"), []byte(goldMaster), 0600) Ω(err).ShouldNot(HaveOccurred()) }) It("gracefully handles existing test suite files", func() { //nothing should have gone wrong! }) }) }) ginkgo-1.14.2/integration/coverage_test.go000066400000000000000000000155051374111457300205750ustar00rootroot00000000000000package integration_test import ( "io/ioutil" "os/exec" "regexp" "fmt" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" ) var _ = Describe("Coverage Specs", func() { Context("when it runs coverage analysis in series and in parallel", func() { AfterEach(func() { removeSuccessfully("./_fixtures/coverage_fixture/coverage_fixture.coverprofile") }) It("works", func() { session := startGinkgo("./_fixtures/coverage_fixture", "-cover") Eventually(session).Should(gexec.Exit(0)) Ω(session.Out).Should(gbytes.Say(("coverage: 80.0% of statements"))) coverFile := "./_fixtures/coverage_fixture/coverage_fixture.coverprofile" serialCoverProfileOutput, err := exec.Command("go", "tool", "cover", fmt.Sprintf("-func=%s", coverFile)).CombinedOutput() Ω(err).ShouldNot(HaveOccurred()) removeSuccessfully(coverFile) Eventually(startGinkgo("./_fixtures/coverage_fixture", "-cover", "-nodes=4")).Should(gexec.Exit(0)) parallelCoverProfileOutput, err := exec.Command("go", "tool", "cover", fmt.Sprintf("-func=%s", coverFile)).CombinedOutput() Ω(err).ShouldNot(HaveOccurred()) Ω(parallelCoverProfileOutput).Should(Equal(serialCoverProfileOutput)) By("handling external packages", func() { session = startGinkgo("./_fixtures/coverage_fixture", "-coverpkg=github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture,github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture") Eventually(session).Should(gexec.Exit(0)) Ω(session.Out).Should(gbytes.Say("coverage: 71.4% of statements in github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture, github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture")) serialCoverProfileOutput, err = exec.Command("go", "tool", "cover", fmt.Sprintf("-func=%s", coverFile)).CombinedOutput() Ω(err).ShouldNot(HaveOccurred()) removeSuccessfully("./_fixtures/coverage_fixture/coverage_fixture.coverprofile") Eventually(startGinkgo("./_fixtures/coverage_fixture", "-coverpkg=github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture,github.com/onsi/ginkgo/integration/_fixtures/coverage_fixture/external_coverage_fixture", "-nodes=4")).Should(gexec.Exit(0)) parallelCoverProfileOutput, err = exec.Command("go", "tool", "cover", fmt.Sprintf("-func=%s", coverFile)).CombinedOutput() Ω(err).ShouldNot(HaveOccurred()) Ω(parallelCoverProfileOutput).Should(Equal(serialCoverProfileOutput)) }) }) }) Context("when a custom profile name is specified", func() { AfterEach(func() { removeSuccessfully("./_fixtures/coverage_fixture/coverage.txt") }) It("generates cover profiles with the specified name", func() { session := startGinkgo("./_fixtures/coverage_fixture", "-cover", "-coverprofile=coverage.txt") Eventually(session).Should(gexec.Exit(0)) Ω("./_fixtures/coverage_fixture/coverage.txt").Should(BeARegularFile()) }) }) Context("when run in recursive mode", func() { AfterEach(func() { removeSuccessfully("./_fixtures/combined_coverage_fixture/coverage-recursive.txt") removeSuccessfully("./_fixtures/combined_coverage_fixture/first_package/coverage-recursive.txt") removeSuccessfully("./_fixtures/combined_coverage_fixture/second_package/coverage-recursive.txt") }) It("generates a coverage file per package", func() { session := startGinkgo("./_fixtures/combined_coverage_fixture", "-r", "-cover", "-coverprofile=coverage-recursive.txt") Eventually(session).Should(gexec.Exit(0)) Ω("./_fixtures/combined_coverage_fixture/first_package/coverage-recursive.txt").Should(BeARegularFile()) Ω("./_fixtures/combined_coverage_fixture/second_package/coverage-recursive.txt").Should(BeARegularFile()) }) }) Context("when run in parallel mode", func() { AfterEach(func() { removeSuccessfully("./_fixtures/coverage_fixture/coverage-parallel.txt") }) It("works", func() { session := startGinkgo("./_fixtures/coverage_fixture", "-p", "-cover", "-coverprofile=coverage-parallel.txt") Eventually(session).Should(gexec.Exit(0)) Ω("./_fixtures/coverage_fixture/coverage-parallel.txt").Should(BeARegularFile()) }) }) Context("when run in recursive mode specifying a coverprofile", func() { AfterEach(func() { removeSuccessfully("./_fixtures/combined_coverage_fixture/coverprofile-recursive.txt") removeSuccessfully("./_fixtures/combined_coverage_fixture/first_package/coverprofile-recursive.txt") removeSuccessfully("./_fixtures/combined_coverage_fixture/second_package/coverprofile-recursive.txt") }) It("combines the coverages", func() { session := startGinkgo("./_fixtures/combined_coverage_fixture", "-outputdir=./", "-r", "-cover", "-coverprofile=coverprofile-recursive.txt") Eventually(session).Should(gexec.Exit(0)) By("generating a combined coverage file", func() { Ω("./_fixtures/combined_coverage_fixture/coverprofile-recursive.txt").Should(BeARegularFile()) }) By("and strips multiple mode specifier", func() { re := regexp.MustCompile(`mode: atomic`) bytes, err := ioutil.ReadFile("./_fixtures/combined_coverage_fixture/coverprofile-recursive.txt") Ω(err).Should(BeNil()) matches := re.FindAllIndex(bytes, -1) Ω(len(matches)).Should(Equal(1)) }) By("also generating the single package coverage files", func() { Ω("./_fixtures/combined_coverage_fixture/first_package/coverprofile-recursive.txt").Should(BeARegularFile()) Ω("./_fixtures/combined_coverage_fixture/second_package/coverprofile-recursive.txt").Should(BeARegularFile()) }) }) }) It("Fails with an error if output dir and coverprofile were set, but the output dir did not exist", func() { session := startGinkgo("./_fixtures/combined_coverage_fixture", "-outputdir=./all/profiles/here", "-r", "-cover", "-coverprofile=coverage.txt") Eventually(session).Should(gexec.Exit(1)) output := session.Out.Contents() Ω(string(output)).Should(ContainSubstring("Unable to create combined profile, outputdir does not exist: ./all/profiles/here")) }) Context("when only output dir was set", func() { AfterEach(func() { removeSuccessfully("./_fixtures/combined_coverage_fixture/first_package.coverprofile") removeSuccessfully("./_fixtures/combined_coverage_fixture/first_package/coverage.txt") removeSuccessfully("./_fixtures/combined_coverage_fixture/second_package.coverprofile") removeSuccessfully("./_fixtures/combined_coverage_fixture/second_package/coverage.txt") }) It("moves coverages", func() { session := startGinkgo("./_fixtures/combined_coverage_fixture", "-outputdir=./", "-r", "-cover") Eventually(session).Should(gexec.Exit(0)) Ω("./_fixtures/combined_coverage_fixture/first_package.coverprofile").Should(BeARegularFile()) Ω("./_fixtures/combined_coverage_fixture/second_package.coverprofile").Should(BeARegularFile()) }) }) }) ginkgo-1.14.2/integration/fail_test.go000066400000000000000000000054621374111457300177160ustar00rootroot00000000000000package integration_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) var _ = Describe("Failing Specs", func() { var pathToTest string BeforeEach(func() { pathToTest = tmpPath("failing") copyIn(fixturePath("fail_fixture"), pathToTest, false) }) It("should fail in all the possible ways", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(output).ShouldNot(ContainSubstring("NEVER SEE THIS")) Ω(output).Should(ContainSubstring("a top level failure on line 10")) Ω(output).Should(ContainSubstring("fail_fixture_test.go:10")) Ω(output).Should(ContainSubstring("an async top level failure on line 15")) Ω(output).Should(ContainSubstring("fail_fixture_test.go:15")) Ω(output).Should(ContainSubstring("a top level goroutine failure on line 22")) Ω(output).Should(ContainSubstring("fail_fixture_test.go:22")) Ω(output).Should(ContainSubstring("a sync failure")) Ω(output).Should(MatchRegexp(`Test Panicked\n\s+a sync panic`)) Ω(output).Should(ContainSubstring("a sync FAIL failure")) Ω(output).Should(ContainSubstring("async timeout [It]")) Ω(output).Should(ContainSubstring("Timed out")) Ω(output).Should(ContainSubstring("an async failure")) Ω(output).Should(MatchRegexp(`Test Panicked\n\s+an async panic`)) Ω(output).Should(ContainSubstring("an async FAIL failure")) Ω(output).Should(ContainSubstring("a goroutine FAIL failure")) Ω(output).Should(ContainSubstring("a goroutine failure")) Ω(output).Should(MatchRegexp(`Test Panicked\n\s+a goroutine panic`)) Ω(output).Should(ContainSubstring("a measure failure")) Ω(output).Should(ContainSubstring("a measure FAIL failure")) Ω(output).Should(MatchRegexp(`Test Panicked\n\s+a measure panic`)) Ω(output).Should(ContainSubstring("a top level specify")) Ω(output).ShouldNot(ContainSubstring("ginkgo_dsl.go")) // depending on the go version this could be the first line of the Specify // block (>= go1.9) or the last line of the Specify block (< go1.9) Ω(output).Should(Or(ContainSubstring("fail_fixture_test.go:102"), ContainSubstring("fail_fixture_test.go:104"))) Ω(output).Should(ContainSubstring("fail_fixture_test.go:103")) Ω(output).ShouldNot(ContainSubstring("table.go")) Ω(output).Should(MatchRegexp(`a top level DescribeTable\n.*fail_fixture_test\.go:106`), "the output of a failing DescribeTable should include its file path and line number") Ω(output).ShouldNot(ContainSubstring("table_entry.go")) Ω(output).Should(MatchRegexp(`a TableEntry constructed by Entry \[It\]\n.*fail_fixture_test\.go:110`), "the output of a failing Entry should include its file path and line number") Ω(output).Should(ContainSubstring("0 Passed | 19 Failed")) }) }) ginkgo-1.14.2/integration/flags_test.go000066400000000000000000000224711374111457300200760ustar00rootroot00000000000000package integration_test import ( "io/ioutil" "os" "path/filepath" "strings" . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) var _ = Describe("Flags Specs", func() { var pathToTest string BeforeEach(func() { pathToTest = tmpPath("flags") copyIn(fixturePath("flags_tests"), pathToTest, false) }) getRandomOrders := func(output string) []int { return []int{strings.Index(output, "RANDOM_A"), strings.Index(output, "RANDOM_B"), strings.Index(output, "RANDOM_C")} } It("normally passes, runs measurements, prints out noisy pendings, does not randomize tests, and honors the programmatic focus", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Ran 3 samples:"), "has a measurement") Ω(output).Should(ContainSubstring("11 Passed")) Ω(output).Should(ContainSubstring("0 Failed")) Ω(output).Should(ContainSubstring("1 Pending")) Ω(output).Should(ContainSubstring("3 Skipped")) Ω(output).Should(ContainSubstring("[PENDING]")) Ω(output).Should(ContainSubstring("marshmallow")) Ω(output).Should(ContainSubstring("chocolate")) Ω(output).Should(ContainSubstring("CUSTOM_FLAG: default")) Ω(output).Should(ContainSubstring("Detected Programmatic Focus - setting exit status to %d", types.GINKGO_FOCUS_EXIT_CODE)) Ω(output).ShouldNot(ContainSubstring("smores")) Ω(output).ShouldNot(ContainSubstring("SLOW TEST")) Ω(output).ShouldNot(ContainSubstring("should honor -slowSpecThreshold")) orders := getRandomOrders(output) Ω(orders[0]).Should(BeNumerically("<", orders[1])) Ω(orders[1]).Should(BeNumerically("<", orders[2])) }) It("should run a coverprofile when passed -cover", func() { session := startGinkgo(pathToTest, "--noColor", "--cover", "--focus=the focused set") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) _, err := os.Stat(filepath.Join(pathToTest, "flags.coverprofile")) Ω(err).ShouldNot(HaveOccurred()) Ω(output).Should(ContainSubstring("coverage: ")) }) It("should fail when there are pending tests and it is passed --failOnPending", func() { session := startGinkgo(pathToTest, "--noColor", "--failOnPending") Eventually(session).Should(gexec.Exit(1)) }) It("should fail if the test suite takes longer than the timeout", func() { session := startGinkgo(pathToTest, "--noColor", "--timeout=1ms") Eventually(session).Should(gexec.Exit(1)) }) It("should not print out pendings when --noisyPendings=false", func() { session := startGinkgo(pathToTest, "--noColor", "--noisyPendings=false") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := string(session.Out.Contents()) Ω(output).ShouldNot(ContainSubstring("[PENDING]")) Ω(output).Should(ContainSubstring("1 Pending")) }) It("should override the programmatic focus when told to focus", func() { session := startGinkgo(pathToTest, "--noColor", "--focus=smores") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("marshmallow")) Ω(output).Should(ContainSubstring("chocolate")) Ω(output).Should(ContainSubstring("smores")) Ω(output).Should(ContainSubstring("3 Passed")) Ω(output).Should(ContainSubstring("0 Failed")) Ω(output).Should(ContainSubstring("0 Pending")) Ω(output).Should(ContainSubstring("12 Skipped")) }) It("should override the programmatic focus when told to skip", func() { session := startGinkgo(pathToTest, "--noColor", "--skip=marshmallow|failing|flaky") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).ShouldNot(ContainSubstring("marshmallow")) Ω(output).Should(ContainSubstring("chocolate")) Ω(output).Should(ContainSubstring("smores")) Ω(output).Should(ContainSubstring("11 Passed")) Ω(output).Should(ContainSubstring("0 Failed")) Ω(output).Should(ContainSubstring("1 Pending")) Ω(output).Should(ContainSubstring("3 Skipped")) }) It("should run the race detector when told to", func() { if !raceDetectorSupported() { Skip("race detection is not supported") } session := startGinkgo(pathToTest, "--noColor", "--race") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("WARNING: DATA RACE")) }) It("should randomize tests when told to", func() { session := startGinkgo(pathToTest, "--noColor", "--randomizeAllSpecs", "--seed=17") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := string(session.Out.Contents()) orders := getRandomOrders(output) Ω(orders[0]).ShouldNot(BeNumerically("<", orders[1])) }) It("should skip measurements when told to", func() { session := startGinkgo(pathToTest, "--skipMeasurements") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := string(session.Out.Contents()) Ω(output).ShouldNot(ContainSubstring("Ran 3 samples:"), "has a measurement") Ω(output).Should(ContainSubstring("4 Skipped")) }) It("should watch for slow specs", func() { session := startGinkgo(pathToTest, "--slowSpecThreshold=0.05") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("SLOW TEST")) Ω(output).Should(ContainSubstring("should honor -slowSpecThreshold")) }) It("should pass additional arguments in", func() { session := startGinkgo(pathToTest, "--", "--customFlag=madagascar") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("CUSTOM_FLAG: madagascar")) }) It("should print out full stack traces for failures when told to", func() { session := startGinkgo(pathToTest, "--focus=a failing test", "--trace") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Full Stack Trace")) }) It("should fail fast when told to", func() { pathToTest = tmpPath("fail") copyIn(fixturePath("fail_fixture"), pathToTest, false) session := startGinkgo(pathToTest, "--failFast") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("1 Failed")) Ω(output).Should(ContainSubstring("18 Skipped")) }) Context("with a flaky test", func() { It("should normally fail", func() { session := startGinkgo(pathToTest, "--focus=flaky") Eventually(session).Should(gexec.Exit(1)) }) It("should pass if retries are requested", func() { session := startGinkgo(pathToTest, "--focus=flaky --flakeAttempts=2") Eventually(session).Should(gexec.Exit(0)) }) }) It("should perform a dry run when told to", func() { pathToTest = tmpPath("fail") copyIn(fixturePath("fail_fixture"), pathToTest, false) session := startGinkgo(pathToTest, "--dryRun", "-v") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("synchronous failures")) Ω(output).Should(ContainSubstring("19 Specs")) Ω(output).Should(ContainSubstring("0 Passed")) Ω(output).Should(ContainSubstring("0 Failed")) }) regextest := func(regexOption string, skipOrFocus string) string { pathToTest = tmpPath("passing") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) session := startGinkgo(pathToTest, regexOption, "--dryRun", "-v", skipOrFocus) Eventually(session).Should(gexec.Exit(0)) return string(session.Out.Contents()) } It("regexScansFilePath (enabled) should skip and focus on file names", func() { output := regextest("-regexScansFilePath=true", "-skip=/passing/") // everything gets skipped (nothing runs) Ω(output).Should(ContainSubstring("0 of 4 Specs")) output = regextest("-regexScansFilePath=true", "-focus=/passing/") // everything gets focused (everything runs) Ω(output).Should(ContainSubstring("4 of 4 Specs")) }) It("regexScansFilePath (disabled) should not effect normal filtering", func() { output := regextest("-regexScansFilePath=false", "-skip=/passing/") // nothing gets skipped (everything runs) Ω(output).Should(ContainSubstring("4 of 4 Specs")) output = regextest("-regexScansFilePath=false", "-focus=/passing/") // nothing gets focused (nothing runs) Ω(output).Should(ContainSubstring("0 of 4 Specs")) }) It("should honor compiler flags", func() { session := startGinkgo(pathToTest, "-gcflags=-importmap 'math=math/cmplx'") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("NaN returns complex128")) }) It("should honor covermode flag", func() { session := startGinkgo(pathToTest, "--noColor", "--covermode=count", "--focus=the focused set") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("coverage: ")) coverageFile := filepath.Join(pathToTest, "flags.coverprofile") _, err := os.Stat(coverageFile) Ω(err).ShouldNot(HaveOccurred()) contents, err := ioutil.ReadFile(coverageFile) Ω(err).ShouldNot(HaveOccurred()) Ω(contents).Should(ContainSubstring("mode: count")) }) }) ginkgo-1.14.2/integration/integration.go000066400000000000000000000000241374111457300202540ustar00rootroot00000000000000package integration ginkgo-1.14.2/integration/integration_suite_test.go000066400000000000000000000065301374111457300225340ustar00rootroot00000000000000package integration_test import ( "fmt" "io" "io/ioutil" "os" "os/exec" "path/filepath" "runtime" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" "testing" "time" ) var tmpDir string var pathToGinkgo string func TestIntegration(t *testing.T) { SetDefaultEventuallyTimeout(30 * time.Second) RegisterFailHandler(Fail) RunSpecs(t, "Integration Suite") } var _ = SynchronizedBeforeSuite(func() []byte { pathToGinkgo, err := gexec.Build("../ginkgo") Ω(err).ShouldNot(HaveOccurred()) return []byte(pathToGinkgo) }, func(computedPathToGinkgo []byte) { pathToGinkgo = string(computedPathToGinkgo) }) var _ = BeforeEach(func() { tmpDir = fmt.Sprintf("./ginko-run-%d", GinkgoParallelNode()) err := os.Mkdir(tmpDir, 0700) Ω(err).ShouldNot(HaveOccurred()) }) var _ = AfterEach(func() { err := os.RemoveAll(tmpDir) Ω(err).ShouldNot(HaveOccurred()) }) var _ = SynchronizedAfterSuite(func() {}, func() { os.RemoveAll(tmpDir) gexec.CleanupBuildArtifacts() }) func tmpPath(destination string) string { return filepath.Join(tmpDir, destination) } func fixturePath(name string) string { return filepath.Join("_fixtures", name) } func copyIn(sourcePath, destinationPath string, recursive bool) { err := os.MkdirAll(destinationPath, 0777) Expect(err).NotTo(HaveOccurred()) files, err := ioutil.ReadDir(sourcePath) Expect(err).NotTo(HaveOccurred()) for _, f := range files { srcPath := filepath.Join(sourcePath, f.Name()) dstPath := filepath.Join(destinationPath, f.Name()) if f.IsDir() { if recursive { copyIn(srcPath, dstPath, recursive) } continue } src, err := os.Open(srcPath) Expect(err).NotTo(HaveOccurred()) defer src.Close() dst, err := os.Create(dstPath) Expect(err).NotTo(HaveOccurred()) defer dst.Close() _, err = io.Copy(dst, src) Expect(err).NotTo(HaveOccurred()) } } func sameFile(filePath, otherFilePath string) bool { content, readErr := ioutil.ReadFile(filePath) Expect(readErr).NotTo(HaveOccurred()) otherContent, readErr := ioutil.ReadFile(otherFilePath) Expect(readErr).NotTo(HaveOccurred()) Expect(string(content)).To(Equal(string(otherContent))) return true } func sameFolder(sourcePath, destinationPath string) bool { files, err := ioutil.ReadDir(sourcePath) Expect(err).NotTo(HaveOccurred()) for _, f := range files { srcPath := filepath.Join(sourcePath, f.Name()) dstPath := filepath.Join(destinationPath, f.Name()) if f.IsDir() { sameFolder(srcPath, dstPath) continue } Expect(sameFile(srcPath, dstPath)).To(BeTrue()) } return true } func ginkgoCommand(dir string, args ...string) *exec.Cmd { cmd := exec.Command(pathToGinkgo, args...) cmd.Dir = dir return cmd } func startGinkgo(dir string, args ...string) *gexec.Session { cmd := ginkgoCommand(dir, args...) session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) Ω(err).ShouldNot(HaveOccurred()) return session } func removeSuccessfully(path string) { err := os.RemoveAll(path) Expect(err).NotTo(HaveOccurred()) } func raceDetectorSupported() bool { // https://github.com/golang/go/blob/1a370950/src/cmd/internal/sys/supported.go#L12 switch runtime.GOOS { case "linux": return runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "arm64" case "darwin", "freebsd", "netbsd", "windows": return runtime.GOARCH == "amd64" default: return false } } ginkgo-1.14.2/integration/interrupt_test.go000066400000000000000000000027021374111457300210310ustar00rootroot00000000000000package integration_test import ( "os/exec" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" ) var _ = Describe("Interrupt", func() { var pathToTest string BeforeEach(func() { pathToTest = tmpPath("hanging") copyIn(fixturePath("hanging_suite"), pathToTest, false) }) Context("when interrupting a suite", func() { var session *gexec.Session BeforeEach(func() { //we need to signal the actual process, so we must compile the test first var err error cmd := exec.Command("go", "test", "-c") cmd.Dir = pathToTest session, err = gexec.Start(cmd, GinkgoWriter, GinkgoWriter) Ω(err).ShouldNot(HaveOccurred()) Eventually(session).Should(gexec.Exit(0)) //then run the compiled test directly cmd = exec.Command("./hanging.test", "--test.v=true", "--ginkgo.noColor") cmd.Dir = pathToTest session, err = gexec.Start(cmd, GinkgoWriter, GinkgoWriter) Ω(err).ShouldNot(HaveOccurred()) Eventually(session).Should(gbytes.Say("Sleeping...")) session.Interrupt() Eventually(session, 1000).Should(gexec.Exit(1)) }) It("should emit the contents of the GinkgoWriter", func() { Ω(session).Should(gbytes.Say("Just beginning")) Ω(session).Should(gbytes.Say("Almost there...")) Ω(session).Should(gbytes.Say("Hanging Out")) }) It("should run the AfterSuite", func() { Ω(session).Should(gbytes.Say("Heading Out After Suite")) }) }) }) ginkgo-1.14.2/integration/precompiled_test.go000066400000000000000000000034541374111457300213050ustar00rootroot00000000000000package integration_test import ( "os" "os/exec" "path/filepath" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" ) var _ = Describe("ginkgo build", func() { var pathToTest string BeforeEach(func() { pathToTest = tmpPath("passing_ginkgo_tests") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) session := startGinkgo(pathToTest, "build") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Compiling passing_ginkgo_tests")) Ω(output).Should(ContainSubstring("compiled passing_ginkgo_tests.test")) }) It("should build a test binary", func() { _, err := os.Stat(filepath.Join(pathToTest, "passing_ginkgo_tests.test")) Ω(err).ShouldNot(HaveOccurred()) }) It("should be possible to run the test binary directly", func() { cmd := exec.Command("./passing_ginkgo_tests.test") cmd.Dir = pathToTest session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) Ω(err).ShouldNot(HaveOccurred()) Eventually(session).Should(gexec.Exit(0)) Ω(session).Should(gbytes.Say("Running Suite: Passing_ginkgo_tests Suite")) }) It("should be possible to run the test binary via ginkgo", func() { session := startGinkgo(pathToTest, "./passing_ginkgo_tests.test") Eventually(session).Should(gexec.Exit(0)) Ω(session).Should(gbytes.Say("Running Suite: Passing_ginkgo_tests Suite")) }) It("should be possible to run the test binary in parallel", func() { session := startGinkgo(pathToTest, "--nodes=4", "--noColor", "./passing_ginkgo_tests.test") Eventually(session).Should(gexec.Exit(0)) Ω(session).Should(gbytes.Say("Running Suite: Passing_ginkgo_tests Suite")) Ω(session).Should(gbytes.Say("Running in parallel across 4 nodes")) }) }) ginkgo-1.14.2/integration/progress_test.go000066400000000000000000000052741374111457300206500ustar00rootroot00000000000000package integration_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" ) var _ = Describe("Emitting progress", func() { var pathToTest string var session *gexec.Session var args []string BeforeEach(func() { args = []string{"--noColor"} pathToTest = tmpPath("progress") copyIn(fixturePath("progress_fixture"), pathToTest, false) }) JustBeforeEach(func() { session = startGinkgo(pathToTest, args...) Eventually(session).Should(gexec.Exit(0)) }) Context("with the -progress flag, but no -v flag", func() { BeforeEach(func() { args = append(args, "-progress") }) It("should not emit progress", func() { Ω(session).ShouldNot(gbytes.Say("[bB]efore")) }) }) Context("with the -v flag", func() { BeforeEach(func() { args = append(args, "-v") }) It("should not emit progress", func() { Ω(session).ShouldNot(gbytes.Say(`\[BeforeEach\]`)) Ω(session).Should(gbytes.Say(`>outer before<`)) }) }) Context("with the -progress flag and the -v flag", func() { BeforeEach(func() { args = append(args, "-progress", "-v") }) It("should emit progress (by writing to the GinkgoWriter)", func() { // First spec Ω(session).Should(gbytes.Say(`\[BeforeEach\] ProgressFixture`)) Ω(session).Should(gbytes.Say(`>outer before<`)) Ω(session).Should(gbytes.Say(`\[BeforeEach\] Inner Context`)) Ω(session).Should(gbytes.Say(`>inner before<`)) Ω(session).Should(gbytes.Say(`\[BeforeEach\] when Inner When`)) Ω(session).Should(gbytes.Say(`>inner before<`)) Ω(session).Should(gbytes.Say(`\[JustBeforeEach\] ProgressFixture`)) Ω(session).Should(gbytes.Say(`>outer just before<`)) Ω(session).Should(gbytes.Say(`\[JustBeforeEach\] Inner Context`)) Ω(session).Should(gbytes.Say(`>inner just before<`)) Ω(session).Should(gbytes.Say(`\[It\] should emit progress as it goes`)) Ω(session).Should(gbytes.Say(`>it<`)) Ω(session).Should(gbytes.Say(`\[AfterEach\] Inner Context`)) Ω(session).Should(gbytes.Say(`>inner after<`)) Ω(session).Should(gbytes.Say(`\[AfterEach\] ProgressFixture`)) Ω(session).Should(gbytes.Say(`>outer after<`)) // Second spec Ω(session).Should(gbytes.Say(`\[BeforeEach\] ProgressFixture`)) Ω(session).Should(gbytes.Say(`>outer before<`)) Ω(session).Should(gbytes.Say(`\[JustBeforeEach\] ProgressFixture`)) Ω(session).Should(gbytes.Say(`>outer just before<`)) Ω(session).Should(gbytes.Say(`\[It\] should emit progress as it goes`)) Ω(session).Should(gbytes.Say(`>specify<`)) Ω(session).Should(gbytes.Say(`\[AfterEach\] ProgressFixture`)) Ω(session).Should(gbytes.Say(`>outer after<`)) }) }) }) ginkgo-1.14.2/integration/run_test.go000066400000000000000000000442571374111457300176140ustar00rootroot00000000000000package integration_test import ( "fmt" "io/ioutil" "os" "regexp" "runtime" "strings" . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" ) var _ = Describe("Running Specs", func() { var pathToTest string isWindows := (runtime.GOOS == "windows") denoter := "•" if isWindows { denoter = "+" } Context("when pointed at the current directory", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) }) It("should run the tests in the working directory", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Running Suite: Passing_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring(strings.Repeat(denoter, 4))) Ω(output).Should(ContainSubstring("SUCCESS! -- 4 Passed")) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) }) Context("when passed an explicit package to run", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) }) It("should run the ginkgo style tests", func() { session := startGinkgo(tmpDir, "--noColor", "ginkgo") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Running Suite: Passing_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring(strings.Repeat(denoter, 4))) Ω(output).Should(ContainSubstring("SUCCESS! -- 4 Passed")) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) }) Context("when passed a number of packages to run", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") otherPathToTest := tmpPath("other") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) copyIn(fixturePath("more_ginkgo_tests"), otherPathToTest, false) }) It("should run the ginkgo style tests", func() { session := startGinkgo(tmpDir, "--noColor", "--succinct=false", "ginkgo", "./other") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Running Suite: Passing_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("Running Suite: More_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) }) Context("when passed a number of packages to run, some of which have focused tests", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") otherPathToTest := tmpPath("other") focusedPathToTest := tmpPath("focused") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) copyIn(fixturePath("more_ginkgo_tests"), otherPathToTest, false) copyIn(fixturePath("focused_fixture"), focusedPathToTest, false) }) It("should exit with a status code of 2 and explain why", func() { session := startGinkgo(tmpDir, "--noColor", "--succinct=false", "-r") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Running Suite: Passing_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("Running Suite: More_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("Test Suite Passed")) Ω(output).Should(ContainSubstring("Detected Programmatic Focus - setting exit status to %d", types.GINKGO_FOCUS_EXIT_CODE)) }) Context("when the GINKGO_EDITOR_INTEGRATION environment variable is set", func() { BeforeEach(func() { os.Setenv("GINKGO_EDITOR_INTEGRATION", "true") }) AfterEach(func() { os.Setenv("GINKGO_EDITOR_INTEGRATION", "") }) It("should exit with a status code of 0 to allow a coverage file to be generated", func() { session := startGinkgo(tmpDir, "--noColor", "--succinct=false", "-r") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Running Suite: Passing_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("Running Suite: More_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) }) }) Context("when told to skipPackages", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") otherPathToTest := tmpPath("other") focusedPathToTest := tmpPath("focused") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) copyIn(fixturePath("more_ginkgo_tests"), otherPathToTest, false) copyIn(fixturePath("focused_fixture"), focusedPathToTest, false) }) It("should skip packages that match the list", func() { session := startGinkgo(tmpDir, "--noColor", "--skipPackage=other,focused", "-r") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Passing_ginkgo_tests Suite")) Ω(output).ShouldNot(ContainSubstring("More_ginkgo_tests Suite")) Ω(output).ShouldNot(ContainSubstring("Focused_fixture Suite")) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) Context("when all packages are skipped", func() { It("should not run anything, but still exit 0", func() { session := startGinkgo(tmpDir, "--noColor", "--skipPackage=other,focused,ginkgo", "-r") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("All tests skipped!")) Ω(output).ShouldNot(ContainSubstring("Passing_ginkgo_tests Suite")) Ω(output).ShouldNot(ContainSubstring("More_ginkgo_tests Suite")) Ω(output).ShouldNot(ContainSubstring("Focused_fixture Suite")) Ω(output).ShouldNot(ContainSubstring("Test Suite Passed")) }) }) }) Context("when there are no tests to run", func() { It("should exit 1", func() { session := startGinkgo(tmpDir, "--noColor", "--skipPackage=other,focused", "-r") Eventually(session).Should(gexec.Exit(1)) output := string(session.Err.Contents()) Ω(output).Should(ContainSubstring("Found no test suites")) }) }) Context("when there are test files but `go test` reports there are no tests to run", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") copyIn(fixturePath("no_test_fn"), pathToTest, false) }) It("suggests running ginkgo bootstrap", func() { session := startGinkgo(tmpDir, "--noColor", "--skipPackage=other,focused", "-r") Eventually(session).Should(gexec.Exit(0)) output := string(session.Err.Contents()) Ω(output).Should(ContainSubstring(`Found no test suites, did you forget to run "ginkgo bootstrap"?`)) }) It("fails if told to requireSuite", func() { session := startGinkgo(tmpDir, "--noColor", "--skipPackage=other,focused", "-r", "-requireSuite") Eventually(session).Should(gexec.Exit(1)) output := string(session.Err.Contents()) Ω(output).Should(ContainSubstring(`Found no test suites, did you forget to run "ginkgo bootstrap"?`)) }) }) Context("when told to randomizeSuites", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") otherPathToTest := tmpPath("other") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) copyIn(fixturePath("more_ginkgo_tests"), otherPathToTest, false) }) It("should skip packages that match the regexp", func() { session := startGinkgo(tmpDir, "--noColor", "--randomizeSuites", "-r", "--seed=2") Eventually(session).Should(gexec.Exit(0)) Ω(session).Should(gbytes.Say("More_ginkgo_tests Suite")) Ω(session).Should(gbytes.Say("Passing_ginkgo_tests Suite")) session = startGinkgo(tmpDir, "--noColor", "--randomizeSuites", "-r", "--seed=3") Eventually(session).Should(gexec.Exit(0)) Ω(session).Should(gbytes.Say("Passing_ginkgo_tests Suite")) Ω(session).Should(gbytes.Say("More_ginkgo_tests Suite")) }) }) Context("when pointed at a package with xunit style tests", func() { BeforeEach(func() { pathToTest = tmpPath("xunit") copyIn(fixturePath("xunit_tests"), pathToTest, false) }) It("should run the xunit style tests", func() { session := startGinkgo(pathToTest) Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("--- PASS: TestAlwaysTrue")) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) }) Context("when pointed at a package with no tests", func() { BeforeEach(func() { pathToTest = tmpPath("no_tests") copyIn(fixturePath("no_tests"), pathToTest, false) }) It("should fail", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(1)) Ω(session.Err.Contents()).Should(ContainSubstring("Found no test suites")) }) }) Context("when pointed at a package that fails to compile", func() { BeforeEach(func() { pathToTest = tmpPath("does_not_compile") copyIn(fixturePath("does_not_compile"), pathToTest, false) }) It("should fail", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Failed to compile")) }) }) Context("when running in parallel", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) }) Context("with a specific number of -nodes", func() { It("should use the specified number of nodes", func() { session := startGinkgo(pathToTest, "--noColor", "-succinct", "-nodes=2") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(MatchRegexp(`\[\d+\] Passing_ginkgo_tests Suite - 4 specs - 2 nodes [%s]{4} SUCCESS! \d+(\.\d+)?[muµ]s`, regexp.QuoteMeta(denoter))) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) }) Context("with -p", func() { It("it should autocompute the number of nodes", func() { session := startGinkgo(pathToTest, "--noColor", "-succinct", "-p") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) nodes := runtime.NumCPU() if nodes == 1 { Skip("Can't test parallel testings with 1 CPU") } if nodes > 4 { nodes = nodes - 1 } Ω(output).Should(MatchRegexp(`\[\d+\] Passing_ginkgo_tests Suite - 4 specs - %d nodes [%s]{4} SUCCESS! \d+(\.\d+)?[muµ]?s`, nodes, regexp.QuoteMeta(denoter))) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) }) }) Context("when running in parallel with -debug", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") copyIn(fixturePath("debug_parallel_fixture"), pathToTest, false) }) Context("without -v", func() { It("should emit node output to files on disk", func() { session := startGinkgo(pathToTest, "--nodes=2", "--debug") Eventually(session).Should(gexec.Exit(0)) f0, err := ioutil.ReadFile(pathToTest + "/ginkgo-node-1.log") Ω(err).ShouldNot(HaveOccurred()) f1, err := ioutil.ReadFile(pathToTest + "/ginkgo-node-2.log") Ω(err).ShouldNot(HaveOccurred()) content := string(append(f0, f1...)) for i := 0; i < 10; i += 1 { Ω(content).Should(ContainSubstring("StdOut %d\n", i)) Ω(content).Should(ContainSubstring("GinkgoWriter %d\n", i)) } }) }) Context("without -v", func() { It("should emit node output to files on disk, without duplicating the GinkgoWriter output", func() { session := startGinkgo(pathToTest, "--nodes=2", "--debug", "-v") Eventually(session).Should(gexec.Exit(0)) f0, err := ioutil.ReadFile(pathToTest + "/ginkgo-node-1.log") Ω(err).ShouldNot(HaveOccurred()) f1, err := ioutil.ReadFile(pathToTest + "/ginkgo-node-2.log") Ω(err).ShouldNot(HaveOccurred()) content := string(append(f0, f1...)) out := strings.Split(content, "GinkgoWriter 2") Ω(out).Should(HaveLen(2)) }) }) }) Context("when streaming in parallel", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) }) It("should print output in realtime", func() { session := startGinkgo(pathToTest, "--noColor", "-stream", "-nodes=2") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring(`[1] Parallel test node 1/2.`)) Ω(output).Should(ContainSubstring(`[2] Parallel test node 2/2.`)) Ω(output).Should(ContainSubstring(`[1] SUCCESS!`)) Ω(output).Should(ContainSubstring(`[2] SUCCESS!`)) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) }) Context("when running recursively", func() { BeforeEach(func() { passingTest := tmpPath("A") otherPassingTest := tmpPath("E") copyIn(fixturePath("passing_ginkgo_tests"), passingTest, false) copyIn(fixturePath("more_ginkgo_tests"), otherPassingTest, false) }) Context("when all the tests pass", func() { Context("with the -r flag", func() { It("should run all the tests (in succinct mode) and succeed", func() { session := startGinkgo(tmpDir, "--noColor", "-r", ".") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) outputLines := strings.Split(output, "\n") Ω(outputLines[0]).Should(MatchRegexp(`\[\d+\] Passing_ginkgo_tests Suite - 4/4 specs [%s]{4} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter))) Ω(outputLines[1]).Should(MatchRegexp(`\[\d+\] More_ginkgo_tests Suite - 2/2 specs [%s]{2} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter))) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) }) Context("with a trailing /...", func() { It("should run all the tests (in succinct mode) and succeed", func() { session := startGinkgo(tmpDir, "--noColor", "./...") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) outputLines := strings.Split(output, "\n") Ω(outputLines[0]).Should(MatchRegexp(`\[\d+\] Passing_ginkgo_tests Suite - 4/4 specs [%s]{4} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter))) Ω(outputLines[1]).Should(MatchRegexp(`\[\d+\] More_ginkgo_tests Suite - 2/2 specs [%s]{2} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter))) Ω(output).Should(ContainSubstring("Test Suite Passed")) }) }) }) Context("when one of the packages has a failing tests", func() { BeforeEach(func() { failingTest := tmpPath("C") copyIn(fixturePath("failing_ginkgo_tests"), failingTest, false) }) It("should fail and stop running tests", func() { session := startGinkgo(tmpDir, "--noColor", "-r") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) outputLines := strings.Split(output, "\n") Ω(outputLines[0]).Should(MatchRegexp(`\[\d+\] Passing_ginkgo_tests Suite - 4/4 specs [%s]{4} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter))) Ω(outputLines[1]).Should(MatchRegexp(`\[\d+\] Failing_ginkgo_tests Suite - 2/2 specs`)) Ω(output).Should(ContainSubstring(fmt.Sprintf("%s Failure", denoter))) Ω(output).ShouldNot(ContainSubstring("More_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("Test Suite Failed")) Ω(output).Should(ContainSubstring("Summarizing 1 Failure:")) Ω(output).Should(ContainSubstring("[Fail] FailingGinkgoTests [It] should fail")) }) }) Context("when one of the packages fails to compile", func() { BeforeEach(func() { doesNotCompileTest := tmpPath("C") copyIn(fixturePath("does_not_compile"), doesNotCompileTest, false) }) It("should fail and stop running tests", func() { session := startGinkgo(tmpDir, "--noColor", "-r") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) outputLines := strings.Split(output, "\n") Ω(outputLines[0]).Should(MatchRegexp(`\[\d+\] Passing_ginkgo_tests Suite - 4/4 specs [%s]{4} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter))) Ω(outputLines[1]).Should(ContainSubstring("Failed to compile C:")) Ω(output).ShouldNot(ContainSubstring("More_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("Test Suite Failed")) }) }) Context("when either is the case, but the keepGoing flag is set", func() { BeforeEach(func() { doesNotCompileTest := tmpPath("B") copyIn(fixturePath("does_not_compile"), doesNotCompileTest, false) failingTest := tmpPath("C") copyIn(fixturePath("failing_ginkgo_tests"), failingTest, false) }) It("should soldier on", func() { session := startGinkgo(tmpDir, "--noColor", "-r", "-keepGoing") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) outputLines := strings.Split(output, "\n") Ω(outputLines[0]).Should(MatchRegexp(`\[\d+\] Passing_ginkgo_tests Suite - 4/4 specs [%s]{4} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter))) Ω(outputLines[1]).Should(ContainSubstring("Failed to compile B:")) Ω(output).Should(MatchRegexp(`\[\d+\] Failing_ginkgo_tests Suite - 2/2 specs`)) Ω(output).Should(ContainSubstring(fmt.Sprintf("%s Failure", denoter))) Ω(output).Should(MatchRegexp(`\[\d+\] More_ginkgo_tests Suite - 2/2 specs [%s]{2} SUCCESS! \d+(\.\d+)?[muµ]s PASS`, regexp.QuoteMeta(denoter))) Ω(output).Should(ContainSubstring("Test Suite Failed")) }) }) }) Context("when told to keep going --untilItFails", func() { BeforeEach(func() { copyIn(fixturePath("eventually_failing"), tmpDir, false) }) It("should keep rerunning the tests, until a failure occurs", func() { session := startGinkgo(tmpDir, "--untilItFails", "--noColor") Eventually(session).Should(gexec.Exit(1)) Ω(session).Should(gbytes.Say("This was attempt #1")) Ω(session).Should(gbytes.Say("This was attempt #2")) Ω(session).Should(gbytes.Say("Tests failed on attempt #3")) //it should change the random seed between each test lines := strings.Split(string(session.Out.Contents()), "\n") randomSeeds := []string{} for _, line := range lines { if strings.Contains(line, "Random Seed:") { randomSeeds = append(randomSeeds, strings.Split(line, ": ")[1]) } } Ω(randomSeeds[0]).ShouldNot(Equal(randomSeeds[1])) Ω(randomSeeds[1]).ShouldNot(Equal(randomSeeds[2])) Ω(randomSeeds[0]).ShouldNot(Equal(randomSeeds[2])) }) }) }) ginkgo-1.14.2/integration/skip_test.go000066400000000000000000000030571374111457300177470ustar00rootroot00000000000000package integration_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) var _ = Describe("Skipping Specs", func() { var pathToTest string BeforeEach(func() { pathToTest = tmpPath("skipping") copyIn(fixturePath("skip_fixture"), pathToTest, false) }) It("should skip in all the possible ways", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).ShouldNot(ContainSubstring("NEVER SEE THIS")) Ω(output).Should(ContainSubstring("a top level skip on line 9")) Ω(output).Should(ContainSubstring("skip_fixture_test.go:9")) Ω(output).Should(ContainSubstring("an async top level skip on line 14")) Ω(output).Should(ContainSubstring("skip_fixture_test.go:14")) Ω(output).Should(ContainSubstring("a top level goroutine skip on line 21")) Ω(output).Should(ContainSubstring("skip_fixture_test.go:21")) Ω(output).Should(ContainSubstring("a sync SKIP")) Ω(output).Should(ContainSubstring("an async SKIP")) Ω(output).Should(ContainSubstring("a goroutine SKIP")) Ω(output).Should(ContainSubstring("a measure SKIP")) Ω(output).Should(ContainSubstring("S [SKIPPING] in Spec Setup (BeforeEach) [")) Ω(output).Should(ContainSubstring("a BeforeEach SKIP")) Ω(output).Should(ContainSubstring("S [SKIPPING] in Spec Teardown (AfterEach) [")) Ω(output).Should(ContainSubstring("an AfterEach SKIP")) Ω(output).Should(ContainSubstring("0 Passed | 0 Failed | 0 Pending | 9 Skipped")) }) }) ginkgo-1.14.2/integration/subcommand_test.go000066400000000000000000000437131374111457300211340ustar00rootroot00000000000000package integration_test import ( "io/ioutil" "os" "path/filepath" "strings" . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) var _ = Describe("Subcommand", func() { Describe("ginkgo bootstrap", func() { var pkgPath string BeforeEach(func() { pkgPath = tmpPath("foo") os.Mkdir(pkgPath, 0777) }) It("should generate a bootstrap file, as long as one does not exist", func() { session := startGinkgo(pkgPath, "bootstrap") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("foo_suite_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "foo_suite_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_test")) Ω(content).Should(ContainSubstring("func TestFoo(t *testing.T) {")) Ω(content).Should(ContainSubstring("RegisterFailHandler")) Ω(content).Should(ContainSubstring("RunSpecs")) Ω(content).Should(ContainSubstring("\t" + `. "github.com/onsi/ginkgo"`)) Ω(content).Should(ContainSubstring("\t" + `. "github.com/onsi/gomega"`)) session = startGinkgo(pkgPath, "bootstrap") Eventually(session).Should(gexec.Exit(1)) output = session.Out.Contents() Ω(output).Should(ContainSubstring("foo_suite_test.go already exists")) }) It("should import nodot declarations when told to", func() { session := startGinkgo(pkgPath, "bootstrap", "--nodot") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("foo_suite_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "foo_suite_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_test")) Ω(content).Should(ContainSubstring("func TestFoo(t *testing.T) {")) Ω(content).Should(ContainSubstring("RegisterFailHandler")) Ω(content).Should(ContainSubstring("RunSpecs")) Ω(content).Should(ContainSubstring("var It = ginkgo.It")) Ω(content).Should(ContainSubstring("var Ω = gomega.Ω")) Ω(content).Should(ContainSubstring("\t" + `"github.com/onsi/ginkgo"`)) Ω(content).Should(ContainSubstring("\t" + `"github.com/onsi/gomega"`)) }) It("should generate an agouti bootstrap file when told to", func() { session := startGinkgo(pkgPath, "bootstrap", "--agouti") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("foo_suite_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "foo_suite_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_test")) Ω(content).Should(ContainSubstring("func TestFoo(t *testing.T) {")) Ω(content).Should(ContainSubstring("RegisterFailHandler")) Ω(content).Should(ContainSubstring("RunSpecs")) Ω(content).Should(ContainSubstring("\t" + `. "github.com/onsi/ginkgo"`)) Ω(content).Should(ContainSubstring("\t" + `. "github.com/onsi/gomega"`)) Ω(content).Should(ContainSubstring("\t" + `"github.com/sclevine/agouti"`)) }) It("should generate a bootstrap file using a template when told to", func() { templateFile := filepath.Join(pkgPath, ".bootstrap") ioutil.WriteFile(templateFile, []byte(`package {{.Package}} import ( {{.GinkgoImport}} {{.GomegaImport}} "testing" "binary" ) func Test{{.FormattedName}}(t *testing.T) { // This is a {{.Package}} test }`), 0666) session := startGinkgo(pkgPath, "bootstrap", "--template", ".bootstrap") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("foo_suite_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "foo_suite_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_test")) Ω(content).Should(ContainSubstring(`. "github.com/onsi/ginkgo"`)) Ω(content).Should(ContainSubstring(`. "github.com/onsi/gomega"`)) Ω(content).Should(ContainSubstring(`"binary"`)) Ω(content).Should(ContainSubstring("// This is a foo_test test")) }) }) Describe("nodot", func() { It("should update the declarations in the bootstrap file", func() { pkgPath := tmpPath("foo") os.Mkdir(pkgPath, 0777) session := startGinkgo(pkgPath, "bootstrap", "--nodot") Eventually(session).Should(gexec.Exit(0)) byteContent, err := ioutil.ReadFile(filepath.Join(pkgPath, "foo_suite_test.go")) Ω(err).ShouldNot(HaveOccurred()) content := string(byteContent) content = strings.Replace(content, "var It =", "var MyIt =", -1) content = strings.Replace(content, "var Ω = gomega.Ω\n", "", -1) err = ioutil.WriteFile(filepath.Join(pkgPath, "foo_suite_test.go"), []byte(content), os.ModePerm) Ω(err).ShouldNot(HaveOccurred()) session = startGinkgo(pkgPath, "nodot") Eventually(session).Should(gexec.Exit(0)) byteContent, err = ioutil.ReadFile(filepath.Join(pkgPath, "foo_suite_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(byteContent).Should(ContainSubstring("var MyIt = ginkgo.It")) Ω(byteContent).ShouldNot(ContainSubstring("var It = ginkgo.It")) Ω(byteContent).Should(ContainSubstring("var Ω = gomega.Ω")) }) }) Describe("ginkgo generate", func() { var pkgPath string BeforeEach(func() { pkgPath = tmpPath("foo_bar") os.Mkdir(pkgPath, 0777) }) Context("with no arguments", func() { It("should generate a test file named after the package", func() { session := startGinkgo(pkgPath, "generate") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("foo_bar_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "foo_bar_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_bar_test")) Ω(content).Should(ContainSubstring(`var _ = Describe("FooBar", func() {`)) Ω(content).Should(ContainSubstring("\t" + `. "github.com/onsi/ginkgo"`)) Ω(content).Should(ContainSubstring("\t" + `. "github.com/onsi/gomega"`)) session = startGinkgo(pkgPath, "generate") Eventually(session).Should(gexec.Exit(1)) output = session.Out.Contents() Ω(output).Should(ContainSubstring("foo_bar_test.go already exists")) }) }) Context("with an argument of the form: foo", func() { It("should generate a test file named after the argument", func() { session := startGinkgo(pkgPath, "generate", "baz_buzz") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("baz_buzz_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "baz_buzz_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_bar_test")) Ω(content).Should(ContainSubstring(`var _ = Describe("BazBuzz", func() {`)) }) }) Context("with an argument of the form: foo.go", func() { It("should generate a test file named after the argument", func() { session := startGinkgo(pkgPath, "generate", "baz_buzz.go") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("baz_buzz_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "baz_buzz_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_bar_test")) Ω(content).Should(ContainSubstring(`var _ = Describe("BazBuzz", func() {`)) }) }) Context("with an argument of the form: foo_test", func() { It("should generate a test file named after the argument", func() { session := startGinkgo(pkgPath, "generate", "baz_buzz_test") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("baz_buzz_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "baz_buzz_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_bar_test")) Ω(content).Should(ContainSubstring(`var _ = Describe("BazBuzz", func() {`)) }) }) Context("with an argument of the form: foo-test", func() { It("should generate a test file named after the argument", func() { session := startGinkgo(pkgPath, "generate", "baz-buzz-test") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("baz_buzz_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "baz_buzz_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_bar_test")) Ω(content).Should(ContainSubstring(`var _ = Describe("BazBuzz", func() {`)) }) }) Context("with an argument of the form: foo_test.go", func() { It("should generate a test file named after the argument", func() { session := startGinkgo(pkgPath, "generate", "baz_buzz_test.go") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("baz_buzz_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "baz_buzz_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_bar_test")) Ω(content).Should(ContainSubstring(`var _ = Describe("BazBuzz", func() {`)) }) }) Context("with multiple arguments", func() { It("should generate a test file named after the argument", func() { session := startGinkgo(pkgPath, "generate", "baz", "buzz") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("baz_test.go")) Ω(output).Should(ContainSubstring("buzz_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "baz_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_bar_test")) Ω(content).Should(ContainSubstring(`var _ = Describe("Baz", func() {`)) content, err = ioutil.ReadFile(filepath.Join(pkgPath, "buzz_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_bar_test")) Ω(content).Should(ContainSubstring(`var _ = Describe("Buzz", func() {`)) }) }) Context("with nodot", func() { It("should not import ginkgo or gomega", func() { session := startGinkgo(pkgPath, "generate", "--nodot") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("foo_bar_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "foo_bar_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_bar_test")) Ω(content).ShouldNot(ContainSubstring("\t" + `. "github.com/onsi/ginkgo"`)) Ω(content).ShouldNot(ContainSubstring("\t" + `. "github.com/onsi/gomega"`)) }) }) Context("with agouti", func() { It("should generate an agouti test file", func() { session := startGinkgo(pkgPath, "generate", "--agouti") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("foo_bar_test.go")) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "foo_bar_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package foo_bar_test")) Ω(content).Should(ContainSubstring("\t" + `. "github.com/onsi/ginkgo"`)) Ω(content).Should(ContainSubstring("\t" + `. "github.com/onsi/gomega"`)) Ω(content).Should(ContainSubstring("\t" + `. "github.com/sclevine/agouti/matchers"`)) Ω(content).Should(ContainSubstring("\t" + `"github.com/sclevine/agouti"`)) Ω(content).Should(ContainSubstring("page, err = agoutiDriver.NewPage()")) }) }) }) Describe("ginkgo bootstrap/generate", func() { var pkgPath string BeforeEach(func() { pkgPath = tmpPath("some-crazy-thing") os.Mkdir(pkgPath, 0777) }) Context("when the working directory is empty", func() { It("generates correctly named bootstrap and generate files with a package name derived from the directory", func() { session := startGinkgo(pkgPath, "bootstrap") Eventually(session).Should(gexec.Exit(0)) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "some_crazy_thing_suite_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package some_crazy_thing_test")) Ω(content).Should(ContainSubstring("SomeCrazyThing Suite")) session = startGinkgo(pkgPath, "generate") Eventually(session).Should(gexec.Exit(0)) content, err = ioutil.ReadFile(filepath.Join(pkgPath, "some_crazy_thing_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package some_crazy_thing_test")) Ω(content).Should(ContainSubstring("SomeCrazyThing")) }) }) Context("when the working directory contains a file with a package name", func() { BeforeEach(func() { Ω(ioutil.WriteFile(filepath.Join(pkgPath, "foo.go"), []byte("package main\n\nfunc main() {}"), 0777)).Should(Succeed()) }) It("generates correctly named bootstrap and generate files with the package name", func() { session := startGinkgo(pkgPath, "bootstrap") Eventually(session).Should(gexec.Exit(0)) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "some_crazy_thing_suite_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package main_test")) Ω(content).Should(ContainSubstring("SomeCrazyThing Suite")) session = startGinkgo(pkgPath, "generate") Eventually(session).Should(gexec.Exit(0)) content, err = ioutil.ReadFile(filepath.Join(pkgPath, "some_crazy_thing_test.go")) Ω(err).ShouldNot(HaveOccurred()) Ω(content).Should(ContainSubstring("package main_test")) Ω(content).Should(ContainSubstring("SomeCrazyThing")) }) }) }) Describe("Go module and sginkgo bootstrap/generate", func() { var ( pkgPath string savedGoPath string ) BeforeEach(func() { pkgPath = tmpPath("myamazingmodule") os.Mkdir(pkgPath, 0777) Expect(ioutil.WriteFile(filepath.Join(pkgPath, "go.mod"), []byte("module fake.com/me/myamazingmodule\n"), 0777)).To(Succeed()) savedGoPath = os.Getenv("GOPATH") Expect(os.Setenv("GOPATH", "")).To(Succeed()) Expect(os.Setenv("GO111MODULE", "on")).To(Succeed()) // needed pre-Go 1.13 }) AfterEach(func() { Expect(os.Setenv("GOPATH", savedGoPath)).To(Succeed()) Expect(os.Setenv("GO111MODULE", "")).To(Succeed()) }) It("generates correctly named bootstrap and generate files with the module name", func() { session := startGinkgo(pkgPath, "bootstrap") Eventually(session).Should(gexec.Exit(0)) content, err := ioutil.ReadFile(filepath.Join(pkgPath, "myamazingmodule_suite_test.go")) Expect(err).NotTo(HaveOccurred()) Expect(content).To(ContainSubstring("package myamazingmodule_test"), string(content)) Expect(content).To(ContainSubstring("Myamazingmodule Suite"), string(content)) session = startGinkgo(pkgPath, "generate") Eventually(session).Should(gexec.Exit(0)) content, err = ioutil.ReadFile(filepath.Join(pkgPath, "myamazingmodule_test.go")) Expect(err).NotTo(HaveOccurred()) Expect(content).To(ContainSubstring("package myamazingmodule_test"), string(content)) Expect(content).To(ContainSubstring("fake.com/me/myamazingmodule"), string(content)) Expect(content).To(ContainSubstring("Myamazingmodule"), string(content)) }) }) Describe("ginkgo blur", func() { It("should unfocus tests", func() { pathToTest := tmpPath("focused") fixture := fixturePath("focused_fixture") copyIn(fixture, pathToTest, true) session := startGinkgo(pathToTest, "--noColor", "-r") Eventually(session).Should(gexec.Exit(types.GINKGO_FOCUS_EXIT_CODE)) output := session.Out.Contents() Ω(string(output)).Should(ContainSubstring("Detected Programmatic Focus")) session = startGinkgo(pathToTest, "blur") Eventually(session).Should(gexec.Exit(0)) output = session.Out.Contents() Ω(string(output)).ShouldNot(ContainSubstring("expected 'package'")) session = startGinkgo(pathToTest, "--noColor", "-r") Eventually(session).Should(gexec.Exit(0)) output = session.Out.Contents() Ω(string(output)).Should(ContainSubstring("Ginkgo ran 2 suites")) Ω(string(output)).Should(ContainSubstring("Test Suite Passed")) Ω(string(output)).ShouldNot(ContainSubstring("Detected Programmatic Focus")) Expect(sameFile(filepath.Join(pathToTest, "README.md"), filepath.Join(fixture, "README.md"))).To(BeTrue()) }) It("should ignore the 'vendor' folder", func() { pathToTest := tmpPath("focused_fixture_with_vendor") copyIn(fixturePath("focused_fixture_with_vendor"), pathToTest, true) session := startGinkgo(pathToTest, "blur") Eventually(session).Should(gexec.Exit(0)) session = startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Expect(string(output)).To(ContainSubstring("13 Passed")) Expect(string(output)).To(ContainSubstring("0 Skipped")) vendorPath := fixturePath("focused_fixture_with_vendor/vendor") otherVendorPath := filepath.Join(pathToTest, "vendor") Expect(sameFolder(vendorPath, otherVendorPath)).To(BeTrue()) }) }) Describe("ginkgo version", func() { It("should print out the version info", func() { session := startGinkgo("", "version") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(MatchRegexp(`Ginkgo Version \d+\.\d+\.\d+`)) }) }) Describe("ginkgo help", func() { It("should print out usage information", func() { session := startGinkgo("", "help") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(MatchRegexp(`Ginkgo Version \d+\.\d+\.\d+`)) Ω(output).Should(ContainSubstring("ginkgo watch")) Ω(output).Should(ContainSubstring("-succinct")) Ω(output).Should(ContainSubstring("-nodes")) Ω(output).Should(ContainSubstring("ginkgo generate")) Ω(output).Should(ContainSubstring("ginkgo help ")) }) }) }) ginkgo-1.14.2/integration/suite_command_test.go000066400000000000000000000051761374111457300216340ustar00rootroot00000000000000package integration_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) var _ = Describe("Suite Command Specs", func() { var pathToTest string BeforeEach(func() { pathToTest = tmpPath("suite_command") copyIn(fixturePath("suite_command_tests"), pathToTest, false) }) It("Runs command after suite echoing out suite data, properly reporting suite name and passing status in successful command output", func() { command := "-afterSuiteHook=echo THIS IS A (ginkgo-suite-passed) TEST OF THE (ginkgo-suite-name) SYSTEM, THIS IS ONLY A TEST" expected := "THIS IS A [PASS] TEST OF THE suite_command SYSTEM, THIS IS ONLY A TEST" session := startGinkgo(pathToTest, command) Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("1 Passed")) Ω(output).Should(ContainSubstring("0 Failed")) Ω(output).Should(ContainSubstring("1 Pending")) Ω(output).Should(ContainSubstring("0 Skipped")) Ω(output).Should(ContainSubstring("Test Suite Passed")) Ω(output).Should(ContainSubstring("Post-suite command succeeded:")) Ω(output).Should(ContainSubstring(expected)) }) It("Runs command after suite reporting that command failed", func() { command := "-afterSuiteHook=exit 1" session := startGinkgo(pathToTest, command) Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("1 Passed")) Ω(output).Should(ContainSubstring("0 Failed")) Ω(output).Should(ContainSubstring("1 Pending")) Ω(output).Should(ContainSubstring("0 Skipped")) Ω(output).Should(ContainSubstring("Test Suite Passed")) Ω(output).Should(ContainSubstring("Post-suite command failed:")) }) It("Runs command after suite echoing out suite data, properly reporting suite name and failing status in successful command output", func() { command := "-afterSuiteHook=echo THIS IS A (ginkgo-suite-passed) TEST OF THE (ginkgo-suite-name) SYSTEM, THIS IS ONLY A TEST" expected := "THIS IS A [FAIL] TEST OF THE suite_command SYSTEM, THIS IS ONLY A TEST" session := startGinkgo(pathToTest, "-failOnPending=true", command) Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("1 Passed")) Ω(output).Should(ContainSubstring("0 Failed")) Ω(output).Should(ContainSubstring("1 Pending")) Ω(output).Should(ContainSubstring("0 Skipped")) Ω(output).Should(ContainSubstring("Test Suite Failed")) Ω(output).Should(ContainSubstring("Post-suite command succeeded:")) Ω(output).Should(ContainSubstring(expected)) }) }) ginkgo-1.14.2/integration/suite_setup_test.go000066400000000000000000000157551374111457300213620ustar00rootroot00000000000000package integration_test import ( "strings" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) var _ = Describe("SuiteSetup", func() { var pathToTest string Context("when the BeforeSuite and AfterSuite pass", func() { BeforeEach(func() { pathToTest = tmpPath("suite_setup") copyIn(fixturePath("passing_suite_setup"), pathToTest, false) }) It("should run the BeforeSuite once, then run all the tests", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(strings.Count(output, "BEFORE SUITE")).Should(Equal(1)) Ω(strings.Count(output, "AFTER SUITE")).Should(Equal(1)) }) It("should run the BeforeSuite once per parallel node, then run all the tests", func() { session := startGinkgo(pathToTest, "--noColor", "--nodes=2") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(strings.Count(output, "BEFORE SUITE")).Should(Equal(2)) Ω(strings.Count(output, "AFTER SUITE")).Should(Equal(2)) }) }) Context("when the BeforeSuite fails", func() { BeforeEach(func() { pathToTest = tmpPath("suite_setup") copyIn(fixturePath("failing_before_suite"), pathToTest, false) }) It("should run the BeforeSuite once, none of the tests, but it should run the AfterSuite", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(strings.Count(output, "BEFORE SUITE")).Should(Equal(1)) Ω(strings.Count(output, "Test Panicked")).Should(Equal(1)) Ω(strings.Count(output, "AFTER SUITE")).Should(Equal(1)) Ω(output).ShouldNot(ContainSubstring("NEVER SEE THIS")) }) It("should run the BeforeSuite once per parallel node, none of the tests, but it should run the AfterSuite for each node", func() { session := startGinkgo(pathToTest, "--noColor", "--nodes=2") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(strings.Count(output, "BEFORE SUITE")).Should(Equal(2)) Ω(strings.Count(output, "Test Panicked")).Should(Equal(2)) Ω(strings.Count(output, "AFTER SUITE")).Should(Equal(2)) Ω(output).ShouldNot(ContainSubstring("NEVER SEE THIS")) }) }) Context("when the AfterSuite fails", func() { BeforeEach(func() { pathToTest = tmpPath("suite_setup") copyIn(fixturePath("failing_after_suite"), pathToTest, false) }) It("should run the BeforeSuite once, none of the tests, but it should run the AfterSuite", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(strings.Count(output, "BEFORE SUITE")).Should(Equal(1)) Ω(strings.Count(output, "AFTER SUITE")).Should(Equal(1)) Ω(strings.Count(output, "Test Panicked")).Should(Equal(1)) Ω(strings.Count(output, "A TEST")).Should(Equal(2)) }) It("should run the BeforeSuite once per parallel node, none of the tests, but it should run the AfterSuite for each node", func() { session := startGinkgo(pathToTest, "--noColor", "--nodes=2") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(strings.Count(output, "BEFORE SUITE")).Should(Equal(2)) Ω(strings.Count(output, "AFTER SUITE")).Should(Equal(2)) Ω(strings.Count(output, "Test Panicked")).Should(Equal(2)) Ω(strings.Count(output, "A TEST")).Should(Equal(2)) }) }) Context("With passing synchronized before and after suites", func() { BeforeEach(func() { pathToTest = tmpPath("suite_setup") copyIn(fixturePath("synchronized_setup_tests"), pathToTest, false) }) Context("when run with one node", func() { It("should do all the work on that one node", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("BEFORE_A_1\nBEFORE_B_1: DATA")) Ω(output).Should(ContainSubstring("AFTER_A_1\nAFTER_B_1")) }) }) Context("when run across multiple nodes", func() { It("should run the first BeforeSuite function (BEFORE_A) on node 1, the second (BEFORE_B) on all the nodes, the first AfterSuite (AFTER_A) on all the nodes, and then the second (AFTER_B) on Node 1 *after* everything else is finished", func() { session := startGinkgo(pathToTest, "--noColor", "--nodes=3") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("BEFORE_A_1")) Ω(output).Should(ContainSubstring("BEFORE_B_1: DATA")) Ω(output).Should(ContainSubstring("BEFORE_B_2: DATA")) Ω(output).Should(ContainSubstring("BEFORE_B_3: DATA")) Ω(output).ShouldNot(ContainSubstring("BEFORE_A_2")) Ω(output).ShouldNot(ContainSubstring("BEFORE_A_3")) Ω(output).Should(ContainSubstring("AFTER_A_1")) Ω(output).Should(ContainSubstring("AFTER_A_2")) Ω(output).Should(ContainSubstring("AFTER_A_3")) Ω(output).Should(ContainSubstring("AFTER_B_1")) Ω(output).ShouldNot(ContainSubstring("AFTER_B_2")) Ω(output).ShouldNot(ContainSubstring("AFTER_B_3")) }) }) Context("when streaming across multiple nodes", func() { It("should run the first BeforeSuite function (BEFORE_A) on node 1, the second (BEFORE_B) on all the nodes, the first AfterSuite (AFTER_A) on all the nodes, and then the second (AFTER_B) on Node 1 *after* everything else is finished", func() { session := startGinkgo(pathToTest, "--noColor", "--nodes=3", "--stream") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("[1] BEFORE_A_1")) Ω(output).Should(ContainSubstring("[1] BEFORE_B_1: DATA")) Ω(output).Should(ContainSubstring("[2] BEFORE_B_2: DATA")) Ω(output).Should(ContainSubstring("[3] BEFORE_B_3: DATA")) Ω(output).ShouldNot(ContainSubstring("BEFORE_A_2")) Ω(output).ShouldNot(ContainSubstring("BEFORE_A_3")) Ω(output).Should(ContainSubstring("[1] AFTER_A_1")) Ω(output).Should(ContainSubstring("[2] AFTER_A_2")) Ω(output).Should(ContainSubstring("[3] AFTER_A_3")) Ω(output).Should(ContainSubstring("[1] AFTER_B_1")) Ω(output).ShouldNot(ContainSubstring("AFTER_B_2")) Ω(output).ShouldNot(ContainSubstring("AFTER_B_3")) }) }) }) Context("With a failing synchronized before suite", func() { BeforeEach(func() { pathToTest = tmpPath("suite_setup") copyIn(fixturePath("exiting_synchronized_setup_tests"), pathToTest, false) }) It("should fail and let the user know that node 1 disappeared prematurely", func() { session := startGinkgo(pathToTest, "--noColor", "--nodes=3") Eventually(session).Should(gexec.Exit(1)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Node 1 disappeared before completing BeforeSuite")) Ω(output).Should(ContainSubstring("Ginkgo timed out waiting for all parallel nodes to report back!")) }) }) }) ginkgo-1.14.2/integration/tags_test.go000066400000000000000000000014001374111457300177250ustar00rootroot00000000000000package integration_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) var _ = Describe("Tags", func() { var pathToTest string BeforeEach(func() { pathToTest = tmpPath("tags") copyIn(fixturePath("tags_tests"), pathToTest, false) }) It("should honor the passed in -tags flag", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(0)) output := string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Ran 1 of 1 Specs")) session = startGinkgo(pathToTest, "--noColor", "-tags=complex_tests") Eventually(session).Should(gexec.Exit(0)) output = string(session.Out.Contents()) Ω(output).Should(ContainSubstring("Ran 3 of 3 Specs")) }) }) ginkgo-1.14.2/integration/test_description_test.go000066400000000000000000000012421374111457300223550ustar00rootroot00000000000000package integration_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" ) var _ = Describe("TestDescription", func() { var pathToTest string BeforeEach(func() { pathToTest = tmpPath("test_description") copyIn(fixturePath("test_description"), pathToTest, false) }) It("should capture and emit information about the current test", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(1)) Ω(session).Should(gbytes.Say("TestDescription should pass:false")) Ω(session).Should(gbytes.Say("TestDescription should fail:true")) }) }) ginkgo-1.14.2/integration/verbose_and_succinct_test.go000066400000000000000000000056121374111457300231620ustar00rootroot00000000000000package integration_test import ( "regexp" "runtime" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) var _ = Describe("Verbose And Succinct Mode", func() { var pathToTest string var otherPathToTest string isWindows := (runtime.GOOS == "windows") denoter := "•" if isWindows { denoter = "+" } Context("when running one package", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) }) It("should default to non-succinct mode", func() { session := startGinkgo(pathToTest, "--noColor") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("Running Suite: Passing_ginkgo_tests Suite")) }) }) Context("when running more than one package", func() { BeforeEach(func() { pathToTest = tmpPath("ginkgo") copyIn(fixturePath("passing_ginkgo_tests"), pathToTest, false) otherPathToTest = tmpPath("more_ginkgo") copyIn(fixturePath("more_ginkgo_tests"), otherPathToTest, false) }) Context("with no flags set", func() { It("should default to succinct mode", func() { session := startGinkgo(tmpDir, "--noColor", "ginkgo", "more_ginkgo") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(MatchRegexp(`\] Passing_ginkgo_tests Suite - 4/4 specs [%s]{4} SUCCESS!`, regexp.QuoteMeta(denoter))) Ω(output).Should(MatchRegexp(`\] More_ginkgo_tests Suite - 2/2 specs [%s]{2} SUCCESS!`, regexp.QuoteMeta(denoter))) }) }) Context("with --succinct=false", func() { It("should not be in succinct mode", func() { session := startGinkgo(tmpDir, "--noColor", "--succinct=false", "ginkgo", "more_ginkgo") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("Running Suite: Passing_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("Running Suite: More_ginkgo_tests Suite")) }) }) Context("with -v", func() { It("should not be in succinct mode, but should be verbose", func() { session := startGinkgo(tmpDir, "--noColor", "-v", "ginkgo", "more_ginkgo") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("Running Suite: Passing_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("Running Suite: More_ginkgo_tests Suite")) Ω(output).Should(ContainSubstring("should proxy strings")) Ω(output).Should(ContainSubstring("should always pass")) }) It("should emit output from Bys", func() { session := startGinkgo(tmpDir, "--noColor", "-v", "ginkgo") Eventually(session).Should(gexec.Exit(0)) output := session.Out.Contents() Ω(output).Should(ContainSubstring("emitting one By")) Ω(output).Should(ContainSubstring("emitting another By")) }) }) }) }) ginkgo-1.14.2/integration/watch_test.go000066400000000000000000000241141374111457300201040ustar00rootroot00000000000000package integration_test import ( "io/ioutil" "os" "path/filepath" "strings" "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" ) var _ = Describe("Watch", func() { var rootPath string var pathA string var pathB string var pathC string var session *gexec.Session fixUpImportPath := func(path string) { files, err := ioutil.ReadDir(path) Expect(err).NotTo(HaveOccurred()) for _, f := range files { filePath := filepath.Join(path, f.Name()) r, err := os.Open(filePath) Ω(err).ShouldNot(HaveOccurred()) src, err := ioutil.ReadAll(r) Ω(err).ShouldNot(HaveOccurred()) out := strings.ReplaceAll(string(src), "$ROOT_PATH$", "github.com/onsi/ginkgo/integration/"+rootPath) r.Close() err = ioutil.WriteFile(filePath, []byte(out), 0666) Ω(err).ShouldNot(HaveOccurred()) } } BeforeEach(func() { rootPath = tmpPath("root") pathA = filepath.Join(rootPath, "A") pathB = filepath.Join(rootPath, "B") pathC = filepath.Join(rootPath, "C") err := os.MkdirAll(pathA, 0700) Ω(err).ShouldNot(HaveOccurred()) err = os.MkdirAll(pathB, 0700) Ω(err).ShouldNot(HaveOccurred()) err = os.MkdirAll(pathC, 0700) Ω(err).ShouldNot(HaveOccurred()) copyIn(fixturePath(filepath.Join("watch_fixtures", "A")), pathA, false) fixUpImportPath(pathA) copyIn(fixturePath(filepath.Join("watch_fixtures", "B")), pathB, false) fixUpImportPath(pathB) copyIn(fixturePath(filepath.Join("watch_fixtures", "C")), pathC, false) fixUpImportPath(pathC) }) modifyFile := func(path string) { time.Sleep(time.Second) content, err := ioutil.ReadFile(path) Ω(err).ShouldNot(HaveOccurred()) content = append(content, []byte("//")...) err = ioutil.WriteFile(path, content, 0666) Ω(err).ShouldNot(HaveOccurred()) } modifyCode := func(pkgToModify string) { modifyFile(filepath.Join(rootPath, pkgToModify, pkgToModify+".go")) } modifyJSON := func(pkgToModify string) { modifyFile(filepath.Join(rootPath, pkgToModify, pkgToModify+".json")) } modifyTest := func(pkgToModify string) { modifyFile(filepath.Join(rootPath, pkgToModify, pkgToModify+"_test.go")) } AfterEach(func() { if session != nil { session.Kill().Wait() } }) It("should be set up correctly", func() { session = startGinkgo(rootPath, "-r") Eventually(session).Should(gexec.Exit(0)) Ω(session.Out.Contents()).Should(ContainSubstring("A Suite")) Ω(session.Out.Contents()).Should(ContainSubstring("B Suite")) Ω(session.Out.Contents()).Should(ContainSubstring("C Suite")) Ω(session.Out.Contents()).Should(ContainSubstring("Ginkgo ran 3 suites")) }) Context("when watching just one test suite", func() { It("should immediately run, and should rerun when the test suite changes", func() { session = startGinkgo(rootPath, "watch", "-succinct", "A") Eventually(session).Should(gbytes.Say("A Suite")) modifyCode("A") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("A Suite")) session.Kill().Wait() }) }) Context("when watching several test suites", func() { It("should not immediately run, but should rerun a test when its code changes", func() { session = startGinkgo(rootPath, "watch", "-succinct", "-r") Eventually(session).Should(gbytes.Say("Identified 3 test suites")) Consistently(session).ShouldNot(gbytes.Say("A Suite|B Suite|C Suite")) modifyCode("A") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("A Suite")) Consistently(session).ShouldNot(gbytes.Say("B Suite|C Suite")) session.Kill().Wait() }) }) Describe("watching dependencies", func() { Context("with a depth of 2", func() { It("should watch down to that depth", func() { session = startGinkgo(rootPath, "watch", "-succinct", "-r", "-depth=2") Eventually(session).Should(gbytes.Say("Identified 3 test suites")) Eventually(session).Should(gbytes.Say(`A \[`)) Eventually(session).Should(gbytes.Say(`B \[`)) Eventually(session).Should(gbytes.Say(`C \[`)) modifyCode("A") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("A Suite")) Consistently(session).ShouldNot(gbytes.Say("B Suite|C Suite")) modifyCode("B") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("B Suite")) Eventually(session).Should(gbytes.Say("A Suite")) Consistently(session).ShouldNot(gbytes.Say("C Suite")) modifyCode("C") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("C Suite")) Eventually(session).Should(gbytes.Say("B Suite")) Eventually(session).Should(gbytes.Say("A Suite")) }) }) Context("with a depth of 1", func() { It("should watch down to that depth", func() { session = startGinkgo(rootPath, "watch", "-succinct", "-r", "-depth=1") Eventually(session).Should(gbytes.Say("Identified 3 test suites")) Eventually(session).Should(gbytes.Say(`A \[`)) Eventually(session).Should(gbytes.Say(`B \[`)) Eventually(session).Should(gbytes.Say(`C \[`)) modifyCode("A") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("A Suite")) Consistently(session).ShouldNot(gbytes.Say("B Suite|C Suite")) modifyCode("B") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("B Suite")) Eventually(session).Should(gbytes.Say("A Suite")) Consistently(session).ShouldNot(gbytes.Say("C Suite")) modifyCode("C") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("C Suite")) Eventually(session).Should(gbytes.Say("B Suite")) Consistently(session).ShouldNot(gbytes.Say("A Suite")) }) }) Context("with a depth of 0", func() { It("should not watch any dependencies", func() { session = startGinkgo(rootPath, "watch", "-succinct", "-r", "-depth=0") Eventually(session).Should(gbytes.Say("Identified 3 test suites")) Eventually(session).Should(gbytes.Say(`A \[`)) Eventually(session).Should(gbytes.Say(`B \[`)) Eventually(session).Should(gbytes.Say(`C \[`)) modifyCode("A") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("A Suite")) Consistently(session).ShouldNot(gbytes.Say("B Suite|C Suite")) modifyCode("B") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("B Suite")) Consistently(session).ShouldNot(gbytes.Say("A Suite|C Suite")) modifyCode("C") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("C Suite")) Consistently(session).ShouldNot(gbytes.Say("A Suite|B Suite")) }) }) It("should not trigger dependents when tests are changed", func() { session = startGinkgo(rootPath, "watch", "-succinct", "-r", "-depth=2") Eventually(session).Should(gbytes.Say("Identified 3 test suites")) Eventually(session).Should(gbytes.Say(`A \[`)) Eventually(session).Should(gbytes.Say(`B \[`)) Eventually(session).Should(gbytes.Say(`C \[`)) modifyTest("A") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("A Suite")) Consistently(session).ShouldNot(gbytes.Say("B Suite|C Suite")) modifyTest("B") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("B Suite")) Consistently(session).ShouldNot(gbytes.Say("A Suite|C Suite")) modifyTest("C") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("C Suite")) Consistently(session).ShouldNot(gbytes.Say("A Suite|B Suite")) }) }) Describe("adjusting the watch regular expression", func() { Describe("the default regular expression", func() { It("should only trigger when go files are changed", func() { session = startGinkgo(rootPath, "watch", "-succinct", "-r", "-depth=2") Eventually(session).Should(gbytes.Say("Identified 3 test suites")) Eventually(session).Should(gbytes.Say(`A \[`)) Eventually(session).Should(gbytes.Say(`B \[`)) Eventually(session).Should(gbytes.Say(`C \[`)) modifyJSON("C") Consistently(session).ShouldNot(gbytes.Say("Detected changes in")) Consistently(session).ShouldNot(gbytes.Say("A Suite|B Suite|C Suite")) }) }) Describe("modifying the regular expression", func() { It("should trigger if the regexp matches", func() { session = startGinkgo(rootPath, "watch", "-succinct", "-r", "-depth=2", `-watchRegExp=\.json$`) Eventually(session).Should(gbytes.Say("Identified 3 test suites")) Eventually(session).Should(gbytes.Say(`A \[`)) Eventually(session).Should(gbytes.Say(`B \[`)) Eventually(session).Should(gbytes.Say(`C \[`)) modifyJSON("C") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("C Suite")) Eventually(session).Should(gbytes.Say("B Suite")) Eventually(session).Should(gbytes.Say("A Suite")) }) }) }) Describe("when new test suite is added", func() { It("should start monitoring that test suite", func() { session = startGinkgo(rootPath, "watch", "-succinct", "-r") Eventually(session).Should(gbytes.Say("Watching 3 suites")) pathD := filepath.Join(rootPath, "D") err := os.MkdirAll(pathD, 0700) Ω(err).ShouldNot(HaveOccurred()) copyIn(fixturePath(filepath.Join("watch_fixtures", "D")), pathD, false) fixUpImportPath(pathD) Eventually(session).Should(gbytes.Say("Detected 1 new suite")) Eventually(session).Should(gbytes.Say(`D \[`)) Eventually(session).Should(gbytes.Say("D Suite")) modifyCode("D") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("D Suite")) modifyCode("C") Eventually(session).Should(gbytes.Say("Detected changes in")) Eventually(session).Should(gbytes.Say("C Suite")) Eventually(session).Should(gbytes.Say("D Suite")) }) }) }) ginkgo-1.14.2/internal/000077500000000000000000000000001374111457300146775ustar00rootroot00000000000000ginkgo-1.14.2/internal/codelocation/000077500000000000000000000000001374111457300173425ustar00rootroot00000000000000ginkgo-1.14.2/internal/codelocation/code_location.go000066400000000000000000000032401374111457300224720ustar00rootroot00000000000000package codelocation import ( "regexp" "runtime" "runtime/debug" "strings" "github.com/onsi/ginkgo/types" ) func New(skip int) types.CodeLocation { _, file, line, _ := runtime.Caller(skip + 1) stackTrace := PruneStack(string(debug.Stack()), skip+1) return types.CodeLocation{FileName: file, LineNumber: line, FullStackTrace: stackTrace} } // PruneStack removes references to functions that are internal to Ginkgo // and the Go runtime from a stack string and a certain number of stack entries // at the beginning of the stack. The stack string has the format // as returned by runtime/debug.Stack. The leading goroutine information is // optional and always removed if present. Beware that runtime/debug.Stack // adds itself as first entry, so typically skip must be >= 1 to remove that // entry. func PruneStack(fullStackTrace string, skip int) string { stack := strings.Split(fullStackTrace, "\n") // Ensure that the even entries are the method names and the // the odd entries the source code information. if len(stack) > 0 && strings.HasPrefix(stack[0], "goroutine ") { // Ignore "goroutine 29 [running]:" line. stack = stack[1:] } // The "+1" is for skipping over the initial entry, which is // runtime/debug.Stack() itself. if len(stack) > 2*(skip+1) { stack = stack[2*(skip+1):] } prunedStack := []string{} re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`) for i := 0; i < len(stack)/2; i++ { // We filter out based on the source code file name. if !re.Match([]byte(stack[i*2+1])) { prunedStack = append(prunedStack, stack[i*2]) prunedStack = append(prunedStack, stack[i*2+1]) } } return strings.Join(prunedStack, "\n") } ginkgo-1.14.2/internal/codelocation/code_location_suite_test.go000066400000000000000000000003211374111457300247370ustar00rootroot00000000000000package codelocation_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestCodelocation(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "CodeLocation Suite") } ginkgo-1.14.2/internal/codelocation/code_location_test.go000066400000000000000000000074031374111457300235360ustar00rootroot00000000000000package codelocation_test import ( "fmt" "runtime" "runtime/debug" "strings" . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" ) var ( codeLocation types.CodeLocation expectedFileName string expectedLineNumber int fullStackTrace string ) func caller0() { fullStackTrace = string(debug.Stack()) codeLocation = codelocation.New(1) } func caller1() { _, expectedFileName, expectedLineNumber, _ = runtime.Caller(0) expectedLineNumber += 2 caller0() } var _ = Describe("CodeLocation", func() { BeforeEach(func() { caller1() }) It("should use the passed in skip parameter to pick out the correct file & line number", func() { Ω(codeLocation.FileName).Should(Equal(expectedFileName)) Ω(codeLocation.LineNumber).Should(Equal(expectedLineNumber)) }) Describe("stringer behavior", func() { It("should stringify nicely", func() { Ω(codeLocation.String()).Should(ContainSubstring("code_location_test.go:%d", expectedLineNumber)) }) }) Describe("PruneStack", func() { It("should remove any references to ginkgo and pkg/testing and pkg/runtime", func() { // Hard-coded string, loosely based on what debug.Stack() produces. input := `Skip: skip() /Skip/me Skip: skip() /Skip/me Something: Func() /Users/whoever/gospace/src/github.com/onsi/ginkgo/whatever.go:10 (0x12314) SomethingInternalToGinkgo: Func() /Users/whoever/gospace/src/github.com/onsi/ginkgo/whatever_else.go:10 (0x12314) Oops: BlowUp() /usr/goroot/pkg/strings/oops.go:10 (0x12341) MyCode: Func() /Users/whoever/gospace/src/mycode/code.go:10 (0x12341) MyCodeTest: Func() /Users/whoever/gospace/src/mycode/code_test.go:10 (0x12341) TestFoo: RunSpecs(t, "Foo Suite") /Users/whoever/gospace/src/mycode/code_suite_test.go:12 (0x37f08) TestingT: Blah() /usr/goroot/pkg/testing/testing.go:12 (0x37f08) Something: Func() /usr/goroot/pkg/runtime/runtime.go:12 (0x37f08) ` prunedStack := codelocation.PruneStack(input, 1) Ω(prunedStack).Should(Equal(`Oops: BlowUp() /usr/goroot/pkg/strings/oops.go:10 (0x12341) MyCode: Func() /Users/whoever/gospace/src/mycode/code.go:10 (0x12341) MyCodeTest: Func() /Users/whoever/gospace/src/mycode/code_test.go:10 (0x12341) TestFoo: RunSpecs(t, "Foo Suite") /Users/whoever/gospace/src/mycode/code_suite_test.go:12 (0x37f08)`)) }) It("should skip correctly for a Go runtime stack", func() { // Actual string from debug.Stack(), something like: // "goroutine 5 [running]:", // "runtime/debug.Stack(0x0, 0x0, 0x0)", // "\t/nvme/gopath/go/src/runtime/debug/stack.go:24 +0xa1", // "github.com/onsi/ginkgo/internal/codelocation_test.caller0()", // "\t/work/gopath.ginkgo/src/github.com/onsi/XXXXXX/internal/codeloc...+36 more", // "github.com/onsi/ginkgo/internal/codelocation_test.caller1()", // "\t/work/gopath.ginkgo/src/github.com/onsi/XXXXXX/internal/codeloc...+36 more", // "github.com/onsi/ginkgo/internal/codelocation_test.glob..func1.1(...+1 more", // "\t/work/gopath.ginkgo/src/github.com/onsi/XXXXXX/internal/codeloc...+36 more", // // To avoid pruning of our test functions // above, we change the expected filename (= this file) into // something that isn't special for PruneStack(). fakeFileName := "github.com/onsi/XXXXXX/internal/codelocation/code_location_test.go" mangledStackTrace := strings.Replace(fullStackTrace, expectedFileName, fakeFileName, -1) stack := strings.Split(codelocation.PruneStack(mangledStackTrace, 1), "\n") Ω(len(stack)).To(BeNumerically(">=", 2), "not enough entries in stack: %s", stack) Ω(stack[0]).To(Equal("github.com/onsi/ginkgo/internal/codelocation_test.caller1()")) Ω(strings.TrimLeft(stack[1], " \t")).To(HavePrefix(fmt.Sprintf("%s:%d ", fakeFileName, expectedLineNumber))) }) }) }) ginkgo-1.14.2/internal/containernode/000077500000000000000000000000001374111457300175275ustar00rootroot00000000000000ginkgo-1.14.2/internal/containernode/container_node.go000066400000000000000000000100661374111457300230500ustar00rootroot00000000000000package containernode import ( "math/rand" "sort" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/types" ) type subjectOrContainerNode struct { containerNode *ContainerNode subjectNode leafnodes.SubjectNode } func (n subjectOrContainerNode) text() string { if n.containerNode != nil { return n.containerNode.Text() } else { return n.subjectNode.Text() } } type CollatedNodes struct { Containers []*ContainerNode Subject leafnodes.SubjectNode } type ContainerNode struct { text string flag types.FlagType codeLocation types.CodeLocation setupNodes []leafnodes.BasicNode subjectAndContainerNodes []subjectOrContainerNode } func New(text string, flag types.FlagType, codeLocation types.CodeLocation) *ContainerNode { return &ContainerNode{ text: text, flag: flag, codeLocation: codeLocation, } } func (container *ContainerNode) Shuffle(r *rand.Rand) { sort.Sort(container) permutation := r.Perm(len(container.subjectAndContainerNodes)) shuffledNodes := make([]subjectOrContainerNode, len(container.subjectAndContainerNodes)) for i, j := range permutation { shuffledNodes[i] = container.subjectAndContainerNodes[j] } container.subjectAndContainerNodes = shuffledNodes } func (node *ContainerNode) BackPropagateProgrammaticFocus() bool { if node.flag == types.FlagTypePending { return false } shouldUnfocus := false for _, subjectOrContainerNode := range node.subjectAndContainerNodes { if subjectOrContainerNode.containerNode != nil { shouldUnfocus = subjectOrContainerNode.containerNode.BackPropagateProgrammaticFocus() || shouldUnfocus } else { shouldUnfocus = (subjectOrContainerNode.subjectNode.Flag() == types.FlagTypeFocused) || shouldUnfocus } } if shouldUnfocus { if node.flag == types.FlagTypeFocused { node.flag = types.FlagTypeNone } return true } return node.flag == types.FlagTypeFocused } func (node *ContainerNode) Collate() []CollatedNodes { return node.collate([]*ContainerNode{}) } func (node *ContainerNode) collate(enclosingContainers []*ContainerNode) []CollatedNodes { collated := make([]CollatedNodes, 0) containers := make([]*ContainerNode, len(enclosingContainers)) copy(containers, enclosingContainers) containers = append(containers, node) for _, subjectOrContainer := range node.subjectAndContainerNodes { if subjectOrContainer.containerNode != nil { collated = append(collated, subjectOrContainer.containerNode.collate(containers)...) } else { collated = append(collated, CollatedNodes{ Containers: containers, Subject: subjectOrContainer.subjectNode, }) } } return collated } func (node *ContainerNode) PushContainerNode(container *ContainerNode) { node.subjectAndContainerNodes = append(node.subjectAndContainerNodes, subjectOrContainerNode{containerNode: container}) } func (node *ContainerNode) PushSubjectNode(subject leafnodes.SubjectNode) { node.subjectAndContainerNodes = append(node.subjectAndContainerNodes, subjectOrContainerNode{subjectNode: subject}) } func (node *ContainerNode) PushSetupNode(setupNode leafnodes.BasicNode) { node.setupNodes = append(node.setupNodes, setupNode) } func (node *ContainerNode) SetupNodesOfType(nodeType types.SpecComponentType) []leafnodes.BasicNode { nodes := []leafnodes.BasicNode{} for _, setupNode := range node.setupNodes { if setupNode.Type() == nodeType { nodes = append(nodes, setupNode) } } return nodes } func (node *ContainerNode) Text() string { return node.text } func (node *ContainerNode) CodeLocation() types.CodeLocation { return node.codeLocation } func (node *ContainerNode) Flag() types.FlagType { return node.flag } //sort.Interface func (node *ContainerNode) Len() int { return len(node.subjectAndContainerNodes) } func (node *ContainerNode) Less(i, j int) bool { return node.subjectAndContainerNodes[i].text() < node.subjectAndContainerNodes[j].text() } func (node *ContainerNode) Swap(i, j int) { node.subjectAndContainerNodes[i], node.subjectAndContainerNodes[j] = node.subjectAndContainerNodes[j], node.subjectAndContainerNodes[i] } ginkgo-1.14.2/internal/containernode/container_node_suite_test.go000066400000000000000000000003241374111457300253140ustar00rootroot00000000000000package containernode_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestContainernode(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Containernode Suite") } ginkgo-1.14.2/internal/containernode/container_node_test.go000066400000000000000000000174421374111457300241140ustar00rootroot00000000000000package containernode_test import ( "math/rand" "github.com/onsi/ginkgo/internal/leafnodes" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/ginkgo/internal/codelocation" . "github.com/onsi/ginkgo/internal/containernode" "github.com/onsi/ginkgo/types" ) var _ = Describe("Container Node", func() { var ( codeLocation types.CodeLocation container *ContainerNode ) BeforeEach(func() { codeLocation = codelocation.New(0) container = New("description text", types.FlagTypeFocused, codeLocation) }) Describe("creating a container node", func() { It("can answer questions about itself", func() { Ω(container.Text()).Should(Equal("description text")) Ω(container.Flag()).Should(Equal(types.FlagTypeFocused)) Ω(container.CodeLocation()).Should(Equal(codeLocation)) }) }) Describe("pushing setup nodes", func() { It("can append setup nodes of various types and fetch them by type", func() { befA := leafnodes.NewBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0) befB := leafnodes.NewBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0) aftA := leafnodes.NewAfterEachNode(func() {}, codelocation.New(0), 0, nil, 0) aftB := leafnodes.NewAfterEachNode(func() {}, codelocation.New(0), 0, nil, 0) jusBefA := leafnodes.NewJustBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0) jusBefB := leafnodes.NewJustBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0) container.PushSetupNode(befA) container.PushSetupNode(befB) container.PushSetupNode(aftA) container.PushSetupNode(aftB) container.PushSetupNode(jusBefA) container.PushSetupNode(jusBefB) subject := leafnodes.NewItNode("subject", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) container.PushSubjectNode(subject) Ω(container.SetupNodesOfType(types.SpecComponentTypeBeforeEach)).Should(Equal([]leafnodes.BasicNode{befA, befB})) Ω(container.SetupNodesOfType(types.SpecComponentTypeAfterEach)).Should(Equal([]leafnodes.BasicNode{aftA, aftB})) Ω(container.SetupNodesOfType(types.SpecComponentTypeJustBeforeEach)).Should(Equal([]leafnodes.BasicNode{jusBefA, jusBefB})) Ω(container.SetupNodesOfType(types.SpecComponentTypeIt)).Should(BeEmpty()) //subjects are not setup nodes }) }) Context("With appended containers and subject nodes", func() { var ( itA, itB, innerItA, innerItB leafnodes.SubjectNode innerContainer *ContainerNode ) BeforeEach(func() { itA = leafnodes.NewItNode("Banana", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) itB = leafnodes.NewItNode("Apple", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) innerItB = leafnodes.NewItNode("inner B", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) innerContainer = New("Orange", types.FlagTypeNone, codelocation.New(0)) container.PushSubjectNode(itA) container.PushContainerNode(innerContainer) innerContainer.PushSubjectNode(innerItA) innerContainer.PushSubjectNode(innerItB) container.PushSubjectNode(itB) }) Describe("Collating", func() { It("should return a collated set of containers and subject nodes in the correct order", func() { collated := container.Collate() Ω(collated).Should(HaveLen(4)) Ω(collated[0]).Should(Equal(CollatedNodes{ Containers: []*ContainerNode{container}, Subject: itA, })) Ω(collated[1]).Should(Equal(CollatedNodes{ Containers: []*ContainerNode{container, innerContainer}, Subject: innerItA, })) Ω(collated[2]).Should(Equal(CollatedNodes{ Containers: []*ContainerNode{container, innerContainer}, Subject: innerItB, })) Ω(collated[3]).Should(Equal(CollatedNodes{ Containers: []*ContainerNode{container}, Subject: itB, })) }) }) Describe("Backpropagating Programmatic Focus", func() { //This allows inner focused specs to override the focus of outer focussed //specs and more closely maps to what a developer wants to happen //when debugging a test suite Context("when a parent is focused *and* an inner subject is focused", func() { BeforeEach(func() { container = New("description text", types.FlagTypeFocused, codeLocation) itA = leafnodes.NewItNode("A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) container.PushSubjectNode(itA) innerContainer = New("Orange", types.FlagTypeNone, codelocation.New(0)) container.PushContainerNode(innerContainer) innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeFocused, codelocation.New(0), 0, nil, 0) innerContainer.PushSubjectNode(innerItA) }) It("should unfocus the parent", func() { container.BackPropagateProgrammaticFocus() Ω(container.Flag()).Should(Equal(types.FlagTypeNone)) Ω(itA.Flag()).Should(Equal(types.FlagTypeNone)) Ω(innerContainer.Flag()).Should(Equal(types.FlagTypeNone)) Ω(innerItA.Flag()).Should(Equal(types.FlagTypeFocused)) }) }) Context("when a parent is focused *and* an inner container is focused", func() { BeforeEach(func() { container = New("description text", types.FlagTypeFocused, codeLocation) itA = leafnodes.NewItNode("A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) container.PushSubjectNode(itA) innerContainer = New("Orange", types.FlagTypeFocused, codelocation.New(0)) container.PushContainerNode(innerContainer) innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) innerContainer.PushSubjectNode(innerItA) }) It("should unfocus the parent", func() { container.BackPropagateProgrammaticFocus() Ω(container.Flag()).Should(Equal(types.FlagTypeNone)) Ω(itA.Flag()).Should(Equal(types.FlagTypeNone)) Ω(innerContainer.Flag()).Should(Equal(types.FlagTypeFocused)) Ω(innerItA.Flag()).Should(Equal(types.FlagTypeNone)) }) }) Context("when a parent is pending and a child is focused", func() { BeforeEach(func() { container = New("description text", types.FlagTypeFocused, codeLocation) itA = leafnodes.NewItNode("A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) container.PushSubjectNode(itA) innerContainer = New("Orange", types.FlagTypePending, codelocation.New(0)) container.PushContainerNode(innerContainer) innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeFocused, codelocation.New(0), 0, nil, 0) innerContainer.PushSubjectNode(innerItA) }) It("should not do anything", func() { container.BackPropagateProgrammaticFocus() Ω(container.Flag()).Should(Equal(types.FlagTypeFocused)) Ω(itA.Flag()).Should(Equal(types.FlagTypeNone)) Ω(innerContainer.Flag()).Should(Equal(types.FlagTypePending)) Ω(innerItA.Flag()).Should(Equal(types.FlagTypeFocused)) }) }) }) Describe("Shuffling", func() { var unshuffledCollation []CollatedNodes BeforeEach(func() { unshuffledCollation = container.Collate() r := rand.New(rand.NewSource(17)) container.Shuffle(r) }) It("should sort, and then shuffle, the top level contents of the container", func() { shuffledCollation := container.Collate() Ω(shuffledCollation).Should(HaveLen(len(unshuffledCollation))) Ω(shuffledCollation).ShouldNot(Equal(unshuffledCollation)) for _, entry := range unshuffledCollation { Ω(shuffledCollation).Should(ContainElement(entry)) } innerAIndex, innerBIndex := 0, 0 for i, entry := range shuffledCollation { if entry.Subject == innerItA { innerAIndex = i } else if entry.Subject == innerItB { innerBIndex = i } } Ω(innerAIndex).Should(Equal(innerBIndex - 1)) }) }) }) }) ginkgo-1.14.2/internal/failer/000077500000000000000000000000001374111457300161415ustar00rootroot00000000000000ginkgo-1.14.2/internal/failer/failer.go000066400000000000000000000036371374111457300177430ustar00rootroot00000000000000package failer import ( "fmt" "sync" "github.com/onsi/ginkgo/types" ) type Failer struct { lock *sync.Mutex failure types.SpecFailure state types.SpecState } func New() *Failer { return &Failer{ lock: &sync.Mutex{}, state: types.SpecStatePassed, } } func (f *Failer) Panic(location types.CodeLocation, forwardedPanic interface{}) { f.lock.Lock() defer f.lock.Unlock() if f.state == types.SpecStatePassed { f.state = types.SpecStatePanicked f.failure = types.SpecFailure{ Message: "Test Panicked", Location: location, ForwardedPanic: fmt.Sprintf("%v", forwardedPanic), } } } func (f *Failer) Timeout(location types.CodeLocation) { f.lock.Lock() defer f.lock.Unlock() if f.state == types.SpecStatePassed { f.state = types.SpecStateTimedOut f.failure = types.SpecFailure{ Message: "Timed out", Location: location, } } } func (f *Failer) Fail(message string, location types.CodeLocation) { f.lock.Lock() defer f.lock.Unlock() if f.state == types.SpecStatePassed { f.state = types.SpecStateFailed f.failure = types.SpecFailure{ Message: message, Location: location, } } } func (f *Failer) Drain(componentType types.SpecComponentType, componentIndex int, componentCodeLocation types.CodeLocation) (types.SpecFailure, types.SpecState) { f.lock.Lock() defer f.lock.Unlock() failure := f.failure outcome := f.state if outcome != types.SpecStatePassed { failure.ComponentType = componentType failure.ComponentIndex = componentIndex failure.ComponentCodeLocation = componentCodeLocation } f.state = types.SpecStatePassed f.failure = types.SpecFailure{} return failure, outcome } func (f *Failer) Skip(message string, location types.CodeLocation) { f.lock.Lock() defer f.lock.Unlock() if f.state == types.SpecStatePassed { f.state = types.SpecStateSkipped f.failure = types.SpecFailure{ Message: message, Location: location, } } } ginkgo-1.14.2/internal/failer/failer_suite_test.go000066400000000000000000000002771374111457300222100ustar00rootroot00000000000000package failer_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFailer(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Failer Suite") } ginkgo-1.14.2/internal/failer/failer_test.go000066400000000000000000000107741374111457300210020ustar00rootroot00000000000000package failer_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/failer" . "github.com/onsi/gomega" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/types" ) var _ = Describe("Failer", func() { var ( failer *Failer codeLocationA types.CodeLocation codeLocationB types.CodeLocation ) BeforeEach(func() { codeLocationA = codelocation.New(0) codeLocationB = codelocation.New(0) failer = New() }) Context("with no failures", func() { It("should return success when drained", func() { failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) Ω(failure).Should(BeZero()) Ω(state).Should(Equal(types.SpecStatePassed)) }) }) Describe("Skip", func() { It("should handle failures", func() { failer.Skip("something skipped", codeLocationA) failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) Ω(failure).Should(Equal(types.SpecFailure{ Message: "something skipped", Location: codeLocationA, ForwardedPanic: "", ComponentType: types.SpecComponentTypeIt, ComponentIndex: 3, ComponentCodeLocation: codeLocationB, })) Ω(state).Should(Equal(types.SpecStateSkipped)) }) }) Describe("Fail", func() { It("should handle failures", func() { failer.Fail("something failed", codeLocationA) failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) Ω(failure).Should(Equal(types.SpecFailure{ Message: "something failed", Location: codeLocationA, ForwardedPanic: "", ComponentType: types.SpecComponentTypeIt, ComponentIndex: 3, ComponentCodeLocation: codeLocationB, })) Ω(state).Should(Equal(types.SpecStateFailed)) }) }) Describe("Panic", func() { It("should handle panics", func() { failer.Panic(codeLocationA, "some forwarded panic") failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) Ω(failure).Should(Equal(types.SpecFailure{ Message: "Test Panicked", Location: codeLocationA, ForwardedPanic: "some forwarded panic", ComponentType: types.SpecComponentTypeIt, ComponentIndex: 3, ComponentCodeLocation: codeLocationB, })) Ω(state).Should(Equal(types.SpecStatePanicked)) }) }) Describe("Timeout", func() { It("should handle timeouts", func() { failer.Timeout(codeLocationA) failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) Ω(failure).Should(Equal(types.SpecFailure{ Message: "Timed out", Location: codeLocationA, ForwardedPanic: "", ComponentType: types.SpecComponentTypeIt, ComponentIndex: 3, ComponentCodeLocation: codeLocationB, })) Ω(state).Should(Equal(types.SpecStateTimedOut)) }) }) Context("when multiple failures are registered", func() { BeforeEach(func() { failer.Fail("something failed", codeLocationA) failer.Fail("something else failed", codeLocationA) }) It("should only report the first one when drained", func() { failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) Ω(failure).Should(Equal(types.SpecFailure{ Message: "something failed", Location: codeLocationA, ForwardedPanic: "", ComponentType: types.SpecComponentTypeIt, ComponentIndex: 3, ComponentCodeLocation: codeLocationB, })) Ω(state).Should(Equal(types.SpecStateFailed)) }) It("should report subsequent failures after being drained", func() { failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) failer.Fail("yet another thing failed", codeLocationA) failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) Ω(failure).Should(Equal(types.SpecFailure{ Message: "yet another thing failed", Location: codeLocationA, ForwardedPanic: "", ComponentType: types.SpecComponentTypeIt, ComponentIndex: 3, ComponentCodeLocation: codeLocationB, })) Ω(state).Should(Equal(types.SpecStateFailed)) }) It("should report sucess on subsequent drains if no errors occur", func() { failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) Ω(failure).Should(BeZero()) Ω(state).Should(Equal(types.SpecStatePassed)) }) }) }) ginkgo-1.14.2/internal/global/000077500000000000000000000000001374111457300161375ustar00rootroot00000000000000ginkgo-1.14.2/internal/global/init.go000066400000000000000000000005261374111457300174340ustar00rootroot00000000000000package global import ( "time" "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/internal/suite" ) const DefaultTimeout = time.Duration(1 * time.Second) var Suite *suite.Suite var Failer *failer.Failer func init() { InitializeGlobals() } func InitializeGlobals() { Failer = failer.New() Suite = suite.New(Failer) } ginkgo-1.14.2/internal/leafnodes/000077500000000000000000000000001374111457300166375ustar00rootroot00000000000000ginkgo-1.14.2/internal/leafnodes/benchmarker.go000066400000000000000000000053341374111457300214540ustar00rootroot00000000000000package leafnodes import ( "math" "time" "sync" "github.com/onsi/ginkgo/types" ) type benchmarker struct { mu sync.Mutex measurements map[string]*types.SpecMeasurement orderCounter int } func newBenchmarker() *benchmarker { return &benchmarker{ measurements: make(map[string]*types.SpecMeasurement), } } func (b *benchmarker) Time(name string, body func(), info ...interface{}) (elapsedTime time.Duration) { t := time.Now() body() elapsedTime = time.Since(t) b.mu.Lock() defer b.mu.Unlock() measurement := b.getMeasurement(name, "Fastest Time", "Slowest Time", "Average Time", "s", 3, info...) measurement.Results = append(measurement.Results, elapsedTime.Seconds()) return } func (b *benchmarker) RecordValue(name string, value float64, info ...interface{}) { b.mu.Lock() measurement := b.getMeasurement(name, "Smallest", " Largest", " Average", "", 3, info...) defer b.mu.Unlock() measurement.Results = append(measurement.Results, value) } func (b *benchmarker) RecordValueWithPrecision(name string, value float64, units string, precision int, info ...interface{}) { b.mu.Lock() measurement := b.getMeasurement(name, "Smallest", " Largest", " Average", units, precision, info...) defer b.mu.Unlock() measurement.Results = append(measurement.Results, value) } func (b *benchmarker) getMeasurement(name string, smallestLabel string, largestLabel string, averageLabel string, units string, precision int, info ...interface{}) *types.SpecMeasurement { measurement, ok := b.measurements[name] if !ok { var computedInfo interface{} computedInfo = nil if len(info) > 0 { computedInfo = info[0] } measurement = &types.SpecMeasurement{ Name: name, Info: computedInfo, Order: b.orderCounter, SmallestLabel: smallestLabel, LargestLabel: largestLabel, AverageLabel: averageLabel, Units: units, Precision: precision, Results: make([]float64, 0), } b.measurements[name] = measurement b.orderCounter++ } return measurement } func (b *benchmarker) measurementsReport() map[string]*types.SpecMeasurement { b.mu.Lock() defer b.mu.Unlock() for _, measurement := range b.measurements { measurement.Smallest = math.MaxFloat64 measurement.Largest = -math.MaxFloat64 sum := float64(0) sumOfSquares := float64(0) for _, result := range measurement.Results { if result > measurement.Largest { measurement.Largest = result } if result < measurement.Smallest { measurement.Smallest = result } sum += result sumOfSquares += result * result } n := float64(len(measurement.Results)) measurement.Average = sum / n measurement.StdDeviation = math.Sqrt(sumOfSquares/n - (sum/n)*(sum/n)) } return b.measurements } ginkgo-1.14.2/internal/leafnodes/interfaces.go000066400000000000000000000004541374111457300213140ustar00rootroot00000000000000package leafnodes import ( "github.com/onsi/ginkgo/types" ) type BasicNode interface { Type() types.SpecComponentType Run() (types.SpecState, types.SpecFailure) CodeLocation() types.CodeLocation } type SubjectNode interface { BasicNode Text() string Flag() types.FlagType Samples() int } ginkgo-1.14.2/internal/leafnodes/it_node.go000066400000000000000000000017271374111457300206160ustar00rootroot00000000000000package leafnodes import ( "time" "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) type ItNode struct { runner *runner flag types.FlagType text string } func NewItNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *ItNode { return &ItNode{ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeIt, componentIndex), flag: flag, text: text, } } func (node *ItNode) Run() (outcome types.SpecState, failure types.SpecFailure) { return node.runner.run() } func (node *ItNode) Type() types.SpecComponentType { return types.SpecComponentTypeIt } func (node *ItNode) Text() string { return node.text } func (node *ItNode) Flag() types.FlagType { return node.flag } func (node *ItNode) CodeLocation() types.CodeLocation { return node.runner.codeLocation } func (node *ItNode) Samples() int { return 1 } ginkgo-1.14.2/internal/leafnodes/it_node_test.go000066400000000000000000000013121374111457300216430ustar00rootroot00000000000000package leafnodes_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/leafnodes" . "github.com/onsi/gomega" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/types" ) var _ = Describe("It Nodes", func() { It("should report the correct type, text, flag, and code location", func() { codeLocation := codelocation.New(0) it := NewItNode("my it node", func() {}, types.FlagTypeFocused, codeLocation, 0, nil, 3) Ω(it.Type()).Should(Equal(types.SpecComponentTypeIt)) Ω(it.Flag()).Should(Equal(types.FlagTypeFocused)) Ω(it.Text()).Should(Equal("my it node")) Ω(it.CodeLocation()).Should(Equal(codeLocation)) Ω(it.Samples()).Should(Equal(1)) }) }) ginkgo-1.14.2/internal/leafnodes/leaf_node_suite_test.go000066400000000000000000000003061374111457300233510ustar00rootroot00000000000000package leafnodes_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestLeafNode(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "LeafNode Suite") } ginkgo-1.14.2/internal/leafnodes/measure_node.go000066400000000000000000000026361374111457300216430ustar00rootroot00000000000000package leafnodes import ( "reflect" "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) type MeasureNode struct { runner *runner text string flag types.FlagType samples int benchmarker *benchmarker } func NewMeasureNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, samples int, failer *failer.Failer, componentIndex int) *MeasureNode { benchmarker := newBenchmarker() wrappedBody := func() { reflect.ValueOf(body).Call([]reflect.Value{reflect.ValueOf(benchmarker)}) } return &MeasureNode{ runner: newRunner(wrappedBody, codeLocation, 0, failer, types.SpecComponentTypeMeasure, componentIndex), text: text, flag: flag, samples: samples, benchmarker: benchmarker, } } func (node *MeasureNode) Run() (outcome types.SpecState, failure types.SpecFailure) { return node.runner.run() } func (node *MeasureNode) MeasurementsReport() map[string]*types.SpecMeasurement { return node.benchmarker.measurementsReport() } func (node *MeasureNode) Type() types.SpecComponentType { return types.SpecComponentTypeMeasure } func (node *MeasureNode) Text() string { return node.text } func (node *MeasureNode) Flag() types.FlagType { return node.flag } func (node *MeasureNode) CodeLocation() types.CodeLocation { return node.runner.codeLocation } func (node *MeasureNode) Samples() int { return node.samples } ginkgo-1.14.2/internal/leafnodes/measure_node_test.go000066400000000000000000000150301374111457300226720ustar00rootroot00000000000000package leafnodes_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/leafnodes" . "github.com/onsi/gomega" "time" "github.com/onsi/ginkgo/internal/codelocation" Failer "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) var _ = Describe("Measure Nodes", func() { It("should report the correct type, text, flag, and code location", func() { codeLocation := codelocation.New(0) measure := NewMeasureNode("my measure node", func(b Benchmarker) {}, types.FlagTypeFocused, codeLocation, 10, nil, 3) Ω(measure.Type()).Should(Equal(types.SpecComponentTypeMeasure)) Ω(measure.Flag()).Should(Equal(types.FlagTypeFocused)) Ω(measure.Text()).Should(Equal("my measure node")) Ω(measure.CodeLocation()).Should(Equal(codeLocation)) Ω(measure.Samples()).Should(Equal(10)) }) Describe("benchmarking", func() { var measure *MeasureNode Describe("Value", func() { BeforeEach(func() { measure = NewMeasureNode("the measurement", func(b Benchmarker) { b.RecordValue("foo", 7, "info!") b.RecordValue("foo", 2) b.RecordValue("foo", 3) b.RecordValue("bar", 0.3) b.RecordValue("bar", 0.1) b.RecordValue("bar", 0.5) b.RecordValue("bar", 0.7) }, types.FlagTypeFocused, codelocation.New(0), 1, Failer.New(), 3) Ω(measure.Run()).Should(Equal(types.SpecStatePassed)) }) It("records passed in values and reports on them", func() { report := measure.MeasurementsReport() Ω(report).Should(HaveLen(2)) Ω(report["foo"].Name).Should(Equal("foo")) Ω(report["foo"].Info).Should(Equal("info!")) Ω(report["foo"].Order).Should(Equal(0)) Ω(report["foo"].SmallestLabel).Should(Equal("Smallest")) Ω(report["foo"].LargestLabel).Should(Equal(" Largest")) Ω(report["foo"].AverageLabel).Should(Equal(" Average")) Ω(report["foo"].Units).Should(Equal("")) Ω(report["foo"].Results).Should(Equal([]float64{7, 2, 3})) Ω(report["foo"].Smallest).Should(BeNumerically("==", 2)) Ω(report["foo"].Largest).Should(BeNumerically("==", 7)) Ω(report["foo"].Average).Should(BeNumerically("==", 4)) Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 2.16, 0.01)) Ω(report["bar"].Name).Should(Equal("bar")) Ω(report["bar"].Info).Should(BeNil()) Ω(report["bar"].SmallestLabel).Should(Equal("Smallest")) Ω(report["bar"].Order).Should(Equal(1)) Ω(report["bar"].LargestLabel).Should(Equal(" Largest")) Ω(report["bar"].AverageLabel).Should(Equal(" Average")) Ω(report["bar"].Units).Should(Equal("")) Ω(report["bar"].Results).Should(Equal([]float64{0.3, 0.1, 0.5, 0.7})) Ω(report["bar"].Smallest).Should(BeNumerically("==", 0.1)) Ω(report["bar"].Largest).Should(BeNumerically("==", 0.7)) Ω(report["bar"].Average).Should(BeNumerically("==", 0.4)) Ω(report["bar"].StdDeviation).Should(BeNumerically("~", 0.22, 0.01)) }) }) Describe("Value with precision", func() { BeforeEach(func() { measure = NewMeasureNode("the measurement", func(b Benchmarker) { b.RecordValueWithPrecision("foo", 7, "ms", 7, "info!") b.RecordValueWithPrecision("foo", 2, "ms", 6) b.RecordValueWithPrecision("foo", 3, "ms", 5) b.RecordValueWithPrecision("bar", 0.3, "ns", 4) b.RecordValueWithPrecision("bar", 0.1, "ns", 3) b.RecordValueWithPrecision("bar", 0.5, "ns", 2) b.RecordValueWithPrecision("bar", 0.7, "ns", 1) }, types.FlagTypeFocused, codelocation.New(0), 1, Failer.New(), 3) Ω(measure.Run()).Should(Equal(types.SpecStatePassed)) }) It("records passed in values and reports on them", func() { report := measure.MeasurementsReport() Ω(report).Should(HaveLen(2)) Ω(report["foo"].Name).Should(Equal("foo")) Ω(report["foo"].Info).Should(Equal("info!")) Ω(report["foo"].Order).Should(Equal(0)) Ω(report["foo"].SmallestLabel).Should(Equal("Smallest")) Ω(report["foo"].LargestLabel).Should(Equal(" Largest")) Ω(report["foo"].AverageLabel).Should(Equal(" Average")) Ω(report["foo"].Units).Should(Equal("ms")) Ω(report["foo"].Results).Should(Equal([]float64{7, 2, 3})) Ω(report["foo"].Smallest).Should(BeNumerically("==", 2)) Ω(report["foo"].Largest).Should(BeNumerically("==", 7)) Ω(report["foo"].Average).Should(BeNumerically("==", 4)) Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 2.16, 0.01)) Ω(report["bar"].Name).Should(Equal("bar")) Ω(report["bar"].Info).Should(BeNil()) Ω(report["bar"].SmallestLabel).Should(Equal("Smallest")) Ω(report["bar"].Order).Should(Equal(1)) Ω(report["bar"].LargestLabel).Should(Equal(" Largest")) Ω(report["bar"].AverageLabel).Should(Equal(" Average")) Ω(report["bar"].Units).Should(Equal("ns")) Ω(report["bar"].Results).Should(Equal([]float64{0.3, 0.1, 0.5, 0.7})) Ω(report["bar"].Smallest).Should(BeNumerically("==", 0.1)) Ω(report["bar"].Largest).Should(BeNumerically("==", 0.7)) Ω(report["bar"].Average).Should(BeNumerically("==", 0.4)) Ω(report["bar"].StdDeviation).Should(BeNumerically("~", 0.22, 0.01)) }) }) Describe("Time", func() { BeforeEach(func() { measure = NewMeasureNode("the measurement", func(b Benchmarker) { b.Time("foo", func() { time.Sleep(200 * time.Millisecond) }, "info!") b.Time("foo", func() { time.Sleep(300 * time.Millisecond) }) b.Time("foo", func() { time.Sleep(250 * time.Millisecond) }) }, types.FlagTypeFocused, codelocation.New(0), 1, Failer.New(), 3) Ω(measure.Run()).Should(Equal(types.SpecStatePassed)) }) It("records passed in values and reports on them", func() { report := measure.MeasurementsReport() Ω(report).Should(HaveLen(1)) Ω(report["foo"].Name).Should(Equal("foo")) Ω(report["foo"].Info).Should(Equal("info!")) Ω(report["foo"].SmallestLabel).Should(Equal("Fastest Time")) Ω(report["foo"].LargestLabel).Should(Equal("Slowest Time")) Ω(report["foo"].AverageLabel).Should(Equal("Average Time")) Ω(report["foo"].Units).Should(Equal("s")) Ω(report["foo"].Results).Should(HaveLen(3)) Ω(report["foo"].Results[0]).Should(BeNumerically("~", 0.2, 0.06)) Ω(report["foo"].Results[1]).Should(BeNumerically("~", 0.3, 0.06)) Ω(report["foo"].Results[2]).Should(BeNumerically("~", 0.25, 0.06)) Ω(report["foo"].Smallest).Should(BeNumerically("~", 0.2, 0.06)) Ω(report["foo"].Largest).Should(BeNumerically("~", 0.3, 0.06)) Ω(report["foo"].Average).Should(BeNumerically("~", 0.25, 0.06)) Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 0.07, 0.04)) }) }) }) }) ginkgo-1.14.2/internal/leafnodes/runner.go000066400000000000000000000054701374111457300205050ustar00rootroot00000000000000package leafnodes import ( "fmt" "reflect" "time" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) type runner struct { isAsync bool asyncFunc func(chan<- interface{}) syncFunc func() codeLocation types.CodeLocation timeoutThreshold time.Duration nodeType types.SpecComponentType componentIndex int failer *failer.Failer } func newRunner(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, nodeType types.SpecComponentType, componentIndex int) *runner { bodyType := reflect.TypeOf(body) if bodyType.Kind() != reflect.Func { panic(fmt.Sprintf("Expected a function but got something else at %v", codeLocation)) } runner := &runner{ codeLocation: codeLocation, timeoutThreshold: timeout, failer: failer, nodeType: nodeType, componentIndex: componentIndex, } switch bodyType.NumIn() { case 0: runner.syncFunc = body.(func()) return runner case 1: if !(bodyType.In(0).Kind() == reflect.Chan && bodyType.In(0).Elem().Kind() == reflect.Interface) { panic(fmt.Sprintf("Must pass a Done channel to function at %v", codeLocation)) } wrappedBody := func(done chan<- interface{}) { bodyValue := reflect.ValueOf(body) bodyValue.Call([]reflect.Value{reflect.ValueOf(done)}) } runner.isAsync = true runner.asyncFunc = wrappedBody return runner } panic(fmt.Sprintf("Too many arguments to function at %v", codeLocation)) } func (r *runner) run() (outcome types.SpecState, failure types.SpecFailure) { if r.isAsync { return r.runAsync() } else { return r.runSync() } } func (r *runner) runAsync() (outcome types.SpecState, failure types.SpecFailure) { done := make(chan interface{}, 1) go func() { finished := false defer func() { if e := recover(); e != nil || !finished { r.failer.Panic(codelocation.New(2), e) select { case <-done: break default: close(done) } } }() r.asyncFunc(done) finished = true }() // If this goroutine gets no CPU time before the select block, // the <-done case may complete even if the test took longer than the timeoutThreshold. // This can cause flaky behaviour, but we haven't seen it in the wild. select { case <-done: case <-time.After(r.timeoutThreshold): r.failer.Timeout(r.codeLocation) } failure, outcome = r.failer.Drain(r.nodeType, r.componentIndex, r.codeLocation) return } func (r *runner) runSync() (outcome types.SpecState, failure types.SpecFailure) { finished := false defer func() { if e := recover(); e != nil || !finished { r.failer.Panic(codelocation.New(2), e) } failure, outcome = r.failer.Drain(r.nodeType, r.componentIndex, r.codeLocation) }() r.syncFunc() finished = true return } ginkgo-1.14.2/internal/leafnodes/setup_nodes.go000066400000000000000000000031201374111457300215120ustar00rootroot00000000000000package leafnodes import ( "time" "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) type SetupNode struct { runner *runner } func (node *SetupNode) Run() (outcome types.SpecState, failure types.SpecFailure) { return node.runner.run() } func (node *SetupNode) Type() types.SpecComponentType { return node.runner.nodeType } func (node *SetupNode) CodeLocation() types.CodeLocation { return node.runner.codeLocation } func NewBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *SetupNode { return &SetupNode{ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeBeforeEach, componentIndex), } } func NewAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *SetupNode { return &SetupNode{ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeAfterEach, componentIndex), } } func NewJustBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *SetupNode { return &SetupNode{ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeJustBeforeEach, componentIndex), } } func NewJustAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *SetupNode { return &SetupNode{ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeJustAfterEach, componentIndex), } } ginkgo-1.14.2/internal/leafnodes/setup_nodes_test.go000066400000000000000000000033071374111457300225600ustar00rootroot00000000000000package leafnodes_test import ( . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" . "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/internal/codelocation" ) var _ = Describe("Setup Nodes", func() { Describe("BeforeEachNodes", func() { It("should report the correct type and code location", func() { codeLocation := codelocation.New(0) beforeEach := NewBeforeEachNode(func() {}, codeLocation, 0, nil, 3) Ω(beforeEach.Type()).Should(Equal(types.SpecComponentTypeBeforeEach)) Ω(beforeEach.CodeLocation()).Should(Equal(codeLocation)) }) }) Describe("AfterEachNodes", func() { It("should report the correct type and code location", func() { codeLocation := codelocation.New(0) afterEach := NewAfterEachNode(func() {}, codeLocation, 0, nil, 3) Ω(afterEach.Type()).Should(Equal(types.SpecComponentTypeAfterEach)) Ω(afterEach.CodeLocation()).Should(Equal(codeLocation)) }) }) Describe("JustBeforeEachNodes", func() { It("should report the correct type and code location", func() { codeLocation := codelocation.New(0) justBeforeEach := NewJustBeforeEachNode(func() {}, codeLocation, 0, nil, 3) Ω(justBeforeEach.Type()).Should(Equal(types.SpecComponentTypeJustBeforeEach)) Ω(justBeforeEach.CodeLocation()).Should(Equal(codeLocation)) }) }) Describe("JustAfterEachNodes", func() { It("should report the correct type and code location", func() { codeLocation := codelocation.New(0) justAfterEach := NewJustAfterEachNode(func() {}, codeLocation, 0, nil, 3) Ω(justAfterEach.Type()).Should(Equal(types.SpecComponentTypeJustAfterEach)) Ω(justAfterEach.CodeLocation()).Should(Equal(codeLocation)) }) }) }) ginkgo-1.14.2/internal/leafnodes/shared_runner_test.go000066400000000000000000000245721374111457300230760ustar00rootroot00000000000000package leafnodes_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/leafnodes" . "github.com/onsi/gomega" "reflect" "time" "github.com/onsi/ginkgo/internal/codelocation" Failer "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) type runnable interface { Run() (outcome types.SpecState, failure types.SpecFailure) CodeLocation() types.CodeLocation } func SynchronousSharedRunnerBehaviors(build func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable, componentType types.SpecComponentType, componentIndex int) { var ( outcome types.SpecState failure types.SpecFailure failer *Failer.Failer componentCodeLocation types.CodeLocation innerCodeLocation types.CodeLocation didRun bool ) BeforeEach(func() { failer = Failer.New() componentCodeLocation = codelocation.New(0) innerCodeLocation = codelocation.New(0) didRun = false }) Describe("synchronous functions", func() { Context("when the function passes", func() { BeforeEach(func() { outcome, failure = build(func() { didRun = true }, 0, failer, componentCodeLocation).Run() }) It("should have a successful outcome", func() { Ω(didRun).Should(BeTrue()) Ω(outcome).Should(Equal(types.SpecStatePassed)) Ω(failure).Should(BeZero()) }) }) Context("when a failure occurs", func() { BeforeEach(func() { outcome, failure = build(func() { didRun = true failer.Fail("bam", innerCodeLocation) panic("should not matter") }, 0, failer, componentCodeLocation).Run() }) It("should return the failure", func() { Ω(didRun).Should(BeTrue()) Ω(outcome).Should(Equal(types.SpecStateFailed)) Ω(failure).Should(Equal(types.SpecFailure{ Message: "bam", Location: innerCodeLocation, ForwardedPanic: "", ComponentIndex: componentIndex, ComponentType: componentType, ComponentCodeLocation: componentCodeLocation, })) }) }) Context("when a panic occurs", func() { BeforeEach(func() { outcome, failure = build(func() { didRun = true innerCodeLocation = codelocation.New(0) panic("ack!") }, 0, failer, componentCodeLocation).Run() }) It("should return the panic", func() { Ω(didRun).Should(BeTrue()) Ω(outcome).Should(Equal(types.SpecStatePanicked)) Ω(failure.ForwardedPanic).Should(Equal("ack!")) }) }) Context("when a panic occurs with a nil value", func() { BeforeEach(func() { outcome, failure = build(func() { didRun = true innerCodeLocation = codelocation.New(0) panic(nil) }, 0, failer, componentCodeLocation).Run() }) It("should return the nil-valued panic", func() { Ω(didRun).Should(BeTrue()) Ω(outcome).Should(Equal(types.SpecStatePanicked)) Ω(failure.ForwardedPanic).Should(Equal("")) }) }) }) } func AsynchronousSharedRunnerBehaviors(build func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable, componentType types.SpecComponentType, componentIndex int) { var ( outcome types.SpecState failure types.SpecFailure failer *Failer.Failer componentCodeLocation types.CodeLocation innerCodeLocation types.CodeLocation didRun bool ) BeforeEach(func() { failer = Failer.New() componentCodeLocation = codelocation.New(0) innerCodeLocation = codelocation.New(0) didRun = false }) Describe("asynchronous functions", func() { var timeoutDuration time.Duration BeforeEach(func() { timeoutDuration = time.Duration(1 * float64(time.Second)) }) Context("when running", func() { It("should run the function as a goroutine, and block until it's done", func() { proveAsync := make(chan bool) build(func(done Done) { didRun = true proveAsync <- true close(done) }, timeoutDuration, failer, componentCodeLocation).Run() Eventually(proveAsync).Should(Receive(Equal(true))) }) }) Context("when the function passes", func() { BeforeEach(func() { outcome, failure = build(func(done Done) { didRun = true close(done) }, timeoutDuration, failer, componentCodeLocation).Run() }) It("should have a successful outcome", func() { Ω(didRun).Should(BeTrue()) Ω(outcome).Should(Equal(types.SpecStatePassed)) Ω(failure).Should(BeZero()) }) }) Context("when the function fails", func() { BeforeEach(func() { outcome, failure = build(func(done Done) { didRun = true failer.Fail("bam", innerCodeLocation) time.Sleep(20 * time.Millisecond) defer close(done) panic("doesn't matter") }, 10*time.Millisecond, failer, componentCodeLocation).Run() }) It("should return the failure", func() { Ω(didRun).Should(BeTrue()) Ω(outcome).Should(Equal(types.SpecStateFailed)) Ω(failure).Should(Equal(types.SpecFailure{ Message: "bam", Location: innerCodeLocation, ForwardedPanic: "", ComponentIndex: componentIndex, ComponentType: componentType, ComponentCodeLocation: componentCodeLocation, })) }) }) Context("when the function doesn't close the done channel in time", func() { var guard chan struct{} BeforeEach(func() { guard = make(chan struct{}) outcome, failure = build(func(done Done) { didRun = true close(guard) }, 10*time.Millisecond, failer, componentCodeLocation).Run() }) It("should return a timeout", func() { <-guard Ω(didRun).Should(BeTrue()) Ω(outcome).Should(Equal(types.SpecStateTimedOut)) Ω(failure).Should(Equal(types.SpecFailure{ Message: "Timed out", Location: componentCodeLocation, ForwardedPanic: "", ComponentIndex: componentIndex, ComponentType: componentType, ComponentCodeLocation: componentCodeLocation, })) }) }) Context("when the function panics", func() { BeforeEach(func() { outcome, failure = build(func(done Done) { didRun = true innerCodeLocation = codelocation.New(0) panic("ack!") }, 100*time.Millisecond, failer, componentCodeLocation).Run() }) It("should return the panic", func() { Ω(didRun).Should(BeTrue()) Ω(outcome).Should(Equal(types.SpecStatePanicked)) Ω(failure.ForwardedPanic).Should(Equal("ack!")) }) }) Context("when the function panics with a nil value", func() { BeforeEach(func() { outcome, failure = build(func(done Done) { didRun = true innerCodeLocation = codelocation.New(0) panic(nil) }, 100*time.Millisecond, failer, componentCodeLocation).Run() }) It("should return the nil-valued panic", func() { Ω(didRun).Should(BeTrue()) Ω(outcome).Should(Equal(types.SpecStatePanicked)) Ω(failure.ForwardedPanic).Should(Equal("")) }) }) }) } func InvalidSharedRunnerBehaviors(build func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable, componentType types.SpecComponentType) { var ( failer *Failer.Failer componentCodeLocation types.CodeLocation ) BeforeEach(func() { failer = Failer.New() componentCodeLocation = codelocation.New(0) }) Describe("invalid functions", func() { Context("when passed something that's not a function", func() { It("should panic", func() { Ω(func() { build("not a function", 0, failer, componentCodeLocation) }).Should(Panic()) }) }) Context("when the function takes the wrong kind of argument", func() { It("should panic", func() { Ω(func() { build(func(oops string) {}, 0, failer, componentCodeLocation) }).Should(Panic()) }) }) Context("when the function takes more than one argument", func() { It("should panic", func() { Ω(func() { build(func(done Done, oops string) {}, 0, failer, componentCodeLocation) }).Should(Panic()) }) }) }) } var _ = Describe("Shared RunnableNode behavior", func() { Describe("It Nodes", func() { build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable { return NewItNode("", body, types.FlagTypeFocused, componentCodeLocation, timeout, failer, 3) } SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeIt, 3) AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeIt, 3) InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeIt) }) Describe("Measure Nodes", func() { build := func(body interface{}, _ time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable { return NewMeasureNode("", func(Benchmarker) { reflect.ValueOf(body).Call([]reflect.Value{}) }, types.FlagTypeFocused, componentCodeLocation, 10, failer, 3) } SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeMeasure, 3) }) Describe("BeforeEach Nodes", func() { build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable { return NewBeforeEachNode(body, componentCodeLocation, timeout, failer, 3) } SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeBeforeEach, 3) AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeBeforeEach, 3) InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeBeforeEach) }) Describe("AfterEach Nodes", func() { build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable { return NewAfterEachNode(body, componentCodeLocation, timeout, failer, 3) } SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeAfterEach, 3) AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeAfterEach, 3) InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeAfterEach) }) Describe("JustBeforeEach Nodes", func() { build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable { return NewJustBeforeEachNode(body, componentCodeLocation, timeout, failer, 3) } SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeJustBeforeEach, 3) AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeJustBeforeEach, 3) InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeJustBeforeEach) }) }) ginkgo-1.14.2/internal/leafnodes/suite_nodes.go000066400000000000000000000027401374111457300215120ustar00rootroot00000000000000package leafnodes import ( "time" "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) type SuiteNode interface { Run(parallelNode int, parallelTotal int, syncHost string) bool Passed() bool Summary() *types.SetupSummary } type simpleSuiteNode struct { runner *runner outcome types.SpecState failure types.SpecFailure runTime time.Duration } func (node *simpleSuiteNode) Run(parallelNode int, parallelTotal int, syncHost string) bool { t := time.Now() node.outcome, node.failure = node.runner.run() node.runTime = time.Since(t) return node.outcome == types.SpecStatePassed } func (node *simpleSuiteNode) Passed() bool { return node.outcome == types.SpecStatePassed } func (node *simpleSuiteNode) Summary() *types.SetupSummary { return &types.SetupSummary{ ComponentType: node.runner.nodeType, CodeLocation: node.runner.codeLocation, State: node.outcome, RunTime: node.runTime, Failure: node.failure, } } func NewBeforeSuiteNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer) SuiteNode { return &simpleSuiteNode{ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeBeforeSuite, 0), } } func NewAfterSuiteNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer) SuiteNode { return &simpleSuiteNode{ runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeAfterSuite, 0), } } ginkgo-1.14.2/internal/leafnodes/suite_nodes_test.go000066400000000000000000000166261374111457300225610ustar00rootroot00000000000000package leafnodes_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/ginkgo/internal/leafnodes" "time" "github.com/onsi/ginkgo/internal/codelocation" Failer "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) var _ = Describe("SuiteNodes", func() { Describe("BeforeSuite nodes", func() { var befSuite SuiteNode var failer *Failer.Failer var codeLocation types.CodeLocation var innerCodeLocation types.CodeLocation var outcome bool BeforeEach(func() { failer = Failer.New() codeLocation = codelocation.New(0) innerCodeLocation = codelocation.New(0) }) Context("when the body passes", func() { BeforeEach(func() { befSuite = NewBeforeSuiteNode(func() { time.Sleep(10 * time.Millisecond) }, codeLocation, 0, failer) outcome = befSuite.Run(0, 0, "") }) It("should return true when run and report as passed", func() { Ω(outcome).Should(BeTrue()) Ω(befSuite.Passed()).Should(BeTrue()) }) It("should have the correct summary", func() { summary := befSuite.Summary() Ω(summary.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) Ω(summary.CodeLocation).Should(Equal(codeLocation)) Ω(summary.State).Should(Equal(types.SpecStatePassed)) Ω(summary.RunTime).Should(BeNumerically(">=", 10*time.Millisecond)) Ω(summary.Failure).Should(BeZero()) }) }) Context("when the body fails", func() { BeforeEach(func() { befSuite = NewBeforeSuiteNode(func() { failer.Fail("oops", innerCodeLocation) }, codeLocation, 0, failer) outcome = befSuite.Run(0, 0, "") }) It("should return false when run and report as failed", func() { Ω(outcome).Should(BeFalse()) Ω(befSuite.Passed()).Should(BeFalse()) }) It("should have the correct summary", func() { summary := befSuite.Summary() Ω(summary.State).Should(Equal(types.SpecStateFailed)) Ω(summary.Failure.Message).Should(Equal("oops")) Ω(summary.Failure.Location).Should(Equal(innerCodeLocation)) Ω(summary.Failure.ForwardedPanic).Should(BeEmpty()) Ω(summary.Failure.ComponentIndex).Should(Equal(0)) Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) }) }) Context("when the body times out", func() { BeforeEach(func() { befSuite = NewBeforeSuiteNode(func(done Done) { }, codeLocation, time.Millisecond, failer) outcome = befSuite.Run(0, 0, "") }) It("should return false when run and report as failed", func() { Ω(outcome).Should(BeFalse()) Ω(befSuite.Passed()).Should(BeFalse()) }) It("should have the correct summary", func() { summary := befSuite.Summary() Ω(summary.State).Should(Equal(types.SpecStateTimedOut)) Ω(summary.Failure.ForwardedPanic).Should(BeEmpty()) Ω(summary.Failure.ComponentIndex).Should(Equal(0)) Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) }) }) Context("when the body panics", func() { BeforeEach(func() { befSuite = NewBeforeSuiteNode(func() { panic("bam") }, codeLocation, 0, failer) outcome = befSuite.Run(0, 0, "") }) It("should return false when run and report as failed", func() { Ω(outcome).Should(BeFalse()) Ω(befSuite.Passed()).Should(BeFalse()) }) It("should have the correct summary", func() { summary := befSuite.Summary() Ω(summary.State).Should(Equal(types.SpecStatePanicked)) Ω(summary.Failure.ForwardedPanic).Should(Equal("bam")) Ω(summary.Failure.ComponentIndex).Should(Equal(0)) Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) }) }) }) Describe("AfterSuite nodes", func() { var aftSuite SuiteNode var failer *Failer.Failer var codeLocation types.CodeLocation var innerCodeLocation types.CodeLocation var outcome bool BeforeEach(func() { failer = Failer.New() codeLocation = codelocation.New(0) innerCodeLocation = codelocation.New(0) }) Context("when the body passes", func() { BeforeEach(func() { aftSuite = NewAfterSuiteNode(func() { time.Sleep(10 * time.Millisecond) }, codeLocation, 0, failer) outcome = aftSuite.Run(0, 0, "") }) It("should return true when run and report as passed", func() { Ω(outcome).Should(BeTrue()) Ω(aftSuite.Passed()).Should(BeTrue()) }) It("should have the correct summary", func() { summary := aftSuite.Summary() Ω(summary.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite)) Ω(summary.CodeLocation).Should(Equal(codeLocation)) Ω(summary.State).Should(Equal(types.SpecStatePassed)) Ω(summary.RunTime).Should(BeNumerically(">=", 10*time.Millisecond)) Ω(summary.Failure).Should(BeZero()) }) }) Context("when the body fails", func() { BeforeEach(func() { aftSuite = NewAfterSuiteNode(func() { failer.Fail("oops", innerCodeLocation) }, codeLocation, 0, failer) outcome = aftSuite.Run(0, 0, "") }) It("should return false when run and report as failed", func() { Ω(outcome).Should(BeFalse()) Ω(aftSuite.Passed()).Should(BeFalse()) }) It("should have the correct summary", func() { summary := aftSuite.Summary() Ω(summary.State).Should(Equal(types.SpecStateFailed)) Ω(summary.Failure.Message).Should(Equal("oops")) Ω(summary.Failure.Location).Should(Equal(innerCodeLocation)) Ω(summary.Failure.ForwardedPanic).Should(BeEmpty()) Ω(summary.Failure.ComponentIndex).Should(Equal(0)) Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite)) Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) }) }) Context("when the body times out", func() { BeforeEach(func() { aftSuite = NewAfterSuiteNode(func(done Done) { }, codeLocation, time.Millisecond, failer) outcome = aftSuite.Run(0, 0, "") }) It("should return false when run and report as failed", func() { Ω(outcome).Should(BeFalse()) Ω(aftSuite.Passed()).Should(BeFalse()) }) It("should have the correct summary", func() { summary := aftSuite.Summary() Ω(summary.State).Should(Equal(types.SpecStateTimedOut)) Ω(summary.Failure.ForwardedPanic).Should(BeEmpty()) Ω(summary.Failure.ComponentIndex).Should(Equal(0)) Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite)) Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) }) }) Context("when the body panics", func() { BeforeEach(func() { aftSuite = NewAfterSuiteNode(func() { panic("bam") }, codeLocation, 0, failer) outcome = aftSuite.Run(0, 0, "") }) It("should return false when run and report as failed", func() { Ω(outcome).Should(BeFalse()) Ω(aftSuite.Passed()).Should(BeFalse()) }) It("should have the correct summary", func() { summary := aftSuite.Summary() Ω(summary.State).Should(Equal(types.SpecStatePanicked)) Ω(summary.Failure.ForwardedPanic).Should(Equal("bam")) Ω(summary.Failure.ComponentIndex).Should(Equal(0)) Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite)) Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) }) }) }) }) ginkgo-1.14.2/internal/leafnodes/synchronized_after_suite_node.go000066400000000000000000000042121374111457300253030ustar00rootroot00000000000000package leafnodes import ( "encoding/json" "io/ioutil" "net/http" "time" "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) type synchronizedAfterSuiteNode struct { runnerA *runner runnerB *runner outcome types.SpecState failure types.SpecFailure runTime time.Duration } func NewSynchronizedAfterSuiteNode(bodyA interface{}, bodyB interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer) SuiteNode { return &synchronizedAfterSuiteNode{ runnerA: newRunner(bodyA, codeLocation, timeout, failer, types.SpecComponentTypeAfterSuite, 0), runnerB: newRunner(bodyB, codeLocation, timeout, failer, types.SpecComponentTypeAfterSuite, 0), } } func (node *synchronizedAfterSuiteNode) Run(parallelNode int, parallelTotal int, syncHost string) bool { node.outcome, node.failure = node.runnerA.run() if parallelNode == 1 { if parallelTotal > 1 { node.waitUntilOtherNodesAreDone(syncHost) } outcome, failure := node.runnerB.run() if node.outcome == types.SpecStatePassed { node.outcome, node.failure = outcome, failure } } return node.outcome == types.SpecStatePassed } func (node *synchronizedAfterSuiteNode) Passed() bool { return node.outcome == types.SpecStatePassed } func (node *synchronizedAfterSuiteNode) Summary() *types.SetupSummary { return &types.SetupSummary{ ComponentType: node.runnerA.nodeType, CodeLocation: node.runnerA.codeLocation, State: node.outcome, RunTime: node.runTime, Failure: node.failure, } } func (node *synchronizedAfterSuiteNode) waitUntilOtherNodesAreDone(syncHost string) { for { if node.canRun(syncHost) { return } time.Sleep(50 * time.Millisecond) } } func (node *synchronizedAfterSuiteNode) canRun(syncHost string) bool { resp, err := http.Get(syncHost + "/RemoteAfterSuiteData") if err != nil || resp.StatusCode != http.StatusOK { return false } body, err := ioutil.ReadAll(resp.Body) if err != nil { return false } resp.Body.Close() afterSuiteData := types.RemoteAfterSuiteData{} err = json.Unmarshal(body, &afterSuiteData) if err != nil { return false } return afterSuiteData.CanRun } ginkgo-1.14.2/internal/leafnodes/synchronized_after_suite_node_test.go000066400000000000000000000114401374111457300263430ustar00rootroot00000000000000package leafnodes_test import ( "sync" . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" "net/http" "github.com/onsi/gomega/ghttp" "time" "github.com/onsi/ginkgo/internal/codelocation" Failer "github.com/onsi/ginkgo/internal/failer" ) var _ = Describe("SynchronizedAfterSuiteNode", func() { var failer *Failer.Failer var node SuiteNode var codeLocation types.CodeLocation var innerCodeLocation types.CodeLocation var outcome bool var server *ghttp.Server var things []string var lock *sync.Mutex BeforeEach(func() { things = []string{} server = ghttp.NewServer() codeLocation = codelocation.New(0) innerCodeLocation = codelocation.New(0) failer = Failer.New() lock = &sync.Mutex{} }) AfterEach(func() { server.Close() }) newNode := func(bodyA interface{}, bodyB interface{}) SuiteNode { return NewSynchronizedAfterSuiteNode(bodyA, bodyB, codeLocation, time.Millisecond, failer) } ranThing := func(thing string) { lock.Lock() defer lock.Unlock() things = append(things, thing) } thingsThatRan := func() []string { lock.Lock() defer lock.Unlock() return things } Context("when not running in parallel", func() { Context("when all is well", func() { BeforeEach(func() { node = newNode(func() { ranThing("A") }, func() { ranThing("B") }) outcome = node.Run(1, 1, server.URL()) }) It("should run A, then B", func() { Ω(thingsThatRan()).Should(Equal([]string{"A", "B"})) }) It("should report success", func() { Ω(outcome).Should(BeTrue()) Ω(node.Passed()).Should(BeTrue()) Ω(node.Summary().State).Should(Equal(types.SpecStatePassed)) }) }) Context("when A fails", func() { BeforeEach(func() { node = newNode(func() { ranThing("A") failer.Fail("bam", innerCodeLocation) }, func() { ranThing("B") }) outcome = node.Run(1, 1, server.URL()) }) It("should still run B", func() { Ω(thingsThatRan()).Should(Equal([]string{"A", "B"})) }) It("should report failure", func() { Ω(outcome).Should(BeFalse()) Ω(node.Passed()).Should(BeFalse()) Ω(node.Summary().State).Should(Equal(types.SpecStateFailed)) }) }) Context("when B fails", func() { BeforeEach(func() { node = newNode(func() { ranThing("A") }, func() { ranThing("B") failer.Fail("bam", innerCodeLocation) }) outcome = node.Run(1, 1, server.URL()) }) It("should run all the things", func() { Ω(thingsThatRan()).Should(Equal([]string{"A", "B"})) }) It("should report failure", func() { Ω(outcome).Should(BeFalse()) Ω(node.Passed()).Should(BeFalse()) Ω(node.Summary().State).Should(Equal(types.SpecStateFailed)) }) }) }) Context("when running in parallel", func() { Context("as the first node", func() { BeforeEach(func() { server.AppendHandlers(ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"), func(writer http.ResponseWriter, request *http.Request) { ranThing("Request1") }, ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: false}), ), ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"), func(writer http.ResponseWriter, request *http.Request) { ranThing("Request2") }, ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: false}), ), ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"), func(writer http.ResponseWriter, request *http.Request) { ranThing("Request3") }, ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: true}), )) node = newNode(func() { ranThing("A") }, func() { ranThing("B") }) outcome = node.Run(1, 3, server.URL()) }) It("should run A and, when the server says its time, run B", func() { Ω(thingsThatRan()).Should(Equal([]string{"A", "Request1", "Request2", "Request3", "B"})) }) It("should report success", func() { Ω(outcome).Should(BeTrue()) Ω(node.Passed()).Should(BeTrue()) Ω(node.Summary().State).Should(Equal(types.SpecStatePassed)) }) }) Context("as any other node", func() { BeforeEach(func() { node = newNode(func() { ranThing("A") }, func() { ranThing("B") }) outcome = node.Run(2, 3, server.URL()) }) It("should run A, and not run B", func() { Ω(thingsThatRan()).Should(Equal([]string{"A"})) }) It("should not talk to the server", func() { Ω(server.ReceivedRequests()).Should(BeEmpty()) }) It("should report success", func() { Ω(outcome).Should(BeTrue()) Ω(node.Passed()).Should(BeTrue()) Ω(node.Summary().State).Should(Equal(types.SpecStatePassed)) }) }) }) }) ginkgo-1.14.2/internal/leafnodes/synchronized_before_suite_node.go000066400000000000000000000132661374111457300254550ustar00rootroot00000000000000package leafnodes import ( "bytes" "encoding/json" "io/ioutil" "net/http" "reflect" "time" "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) type synchronizedBeforeSuiteNode struct { runnerA *runner runnerB *runner data []byte outcome types.SpecState failure types.SpecFailure runTime time.Duration } func NewSynchronizedBeforeSuiteNode(bodyA interface{}, bodyB interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer) SuiteNode { node := &synchronizedBeforeSuiteNode{} node.runnerA = newRunner(node.wrapA(bodyA), codeLocation, timeout, failer, types.SpecComponentTypeBeforeSuite, 0) node.runnerB = newRunner(node.wrapB(bodyB), codeLocation, timeout, failer, types.SpecComponentTypeBeforeSuite, 0) return node } func (node *synchronizedBeforeSuiteNode) Run(parallelNode int, parallelTotal int, syncHost string) bool { t := time.Now() defer func() { node.runTime = time.Since(t) }() if parallelNode == 1 { node.outcome, node.failure = node.runA(parallelTotal, syncHost) } else { node.outcome, node.failure = node.waitForA(syncHost) } if node.outcome != types.SpecStatePassed { return false } node.outcome, node.failure = node.runnerB.run() return node.outcome == types.SpecStatePassed } func (node *synchronizedBeforeSuiteNode) runA(parallelTotal int, syncHost string) (types.SpecState, types.SpecFailure) { outcome, failure := node.runnerA.run() if parallelTotal > 1 { state := types.RemoteBeforeSuiteStatePassed if outcome != types.SpecStatePassed { state = types.RemoteBeforeSuiteStateFailed } json := (types.RemoteBeforeSuiteData{ Data: node.data, State: state, }).ToJSON() http.Post(syncHost+"/BeforeSuiteState", "application/json", bytes.NewBuffer(json)) } return outcome, failure } func (node *synchronizedBeforeSuiteNode) waitForA(syncHost string) (types.SpecState, types.SpecFailure) { failure := func(message string) types.SpecFailure { return types.SpecFailure{ Message: message, Location: node.runnerA.codeLocation, ComponentType: node.runnerA.nodeType, ComponentIndex: node.runnerA.componentIndex, ComponentCodeLocation: node.runnerA.codeLocation, } } for { resp, err := http.Get(syncHost + "/BeforeSuiteState") if err != nil || resp.StatusCode != http.StatusOK { return types.SpecStateFailed, failure("Failed to fetch BeforeSuite state") } body, err := ioutil.ReadAll(resp.Body) if err != nil { return types.SpecStateFailed, failure("Failed to read BeforeSuite state") } resp.Body.Close() beforeSuiteData := types.RemoteBeforeSuiteData{} err = json.Unmarshal(body, &beforeSuiteData) if err != nil { return types.SpecStateFailed, failure("Failed to decode BeforeSuite state") } switch beforeSuiteData.State { case types.RemoteBeforeSuiteStatePassed: node.data = beforeSuiteData.Data return types.SpecStatePassed, types.SpecFailure{} case types.RemoteBeforeSuiteStateFailed: return types.SpecStateFailed, failure("BeforeSuite on Node 1 failed") case types.RemoteBeforeSuiteStateDisappeared: return types.SpecStateFailed, failure("Node 1 disappeared before completing BeforeSuite") } time.Sleep(50 * time.Millisecond) } } func (node *synchronizedBeforeSuiteNode) Passed() bool { return node.outcome == types.SpecStatePassed } func (node *synchronizedBeforeSuiteNode) Summary() *types.SetupSummary { return &types.SetupSummary{ ComponentType: node.runnerA.nodeType, CodeLocation: node.runnerA.codeLocation, State: node.outcome, RunTime: node.runTime, Failure: node.failure, } } func (node *synchronizedBeforeSuiteNode) wrapA(bodyA interface{}) interface{} { typeA := reflect.TypeOf(bodyA) if typeA.Kind() != reflect.Func { panic("SynchronizedBeforeSuite expects a function as its first argument") } takesNothing := typeA.NumIn() == 0 takesADoneChannel := typeA.NumIn() == 1 && typeA.In(0).Kind() == reflect.Chan && typeA.In(0).Elem().Kind() == reflect.Interface returnsBytes := typeA.NumOut() == 1 && typeA.Out(0).Kind() == reflect.Slice && typeA.Out(0).Elem().Kind() == reflect.Uint8 if !((takesNothing || takesADoneChannel) && returnsBytes) { panic("SynchronizedBeforeSuite's first argument should be a function that returns []byte and either takes no arguments or takes a Done channel.") } if takesADoneChannel { return func(done chan<- interface{}) { out := reflect.ValueOf(bodyA).Call([]reflect.Value{reflect.ValueOf(done)}) node.data = out[0].Interface().([]byte) } } return func() { out := reflect.ValueOf(bodyA).Call([]reflect.Value{}) node.data = out[0].Interface().([]byte) } } func (node *synchronizedBeforeSuiteNode) wrapB(bodyB interface{}) interface{} { typeB := reflect.TypeOf(bodyB) if typeB.Kind() != reflect.Func { panic("SynchronizedBeforeSuite expects a function as its second argument") } returnsNothing := typeB.NumOut() == 0 takesBytesOnly := typeB.NumIn() == 1 && typeB.In(0).Kind() == reflect.Slice && typeB.In(0).Elem().Kind() == reflect.Uint8 takesBytesAndDone := typeB.NumIn() == 2 && typeB.In(0).Kind() == reflect.Slice && typeB.In(0).Elem().Kind() == reflect.Uint8 && typeB.In(1).Kind() == reflect.Chan && typeB.In(1).Elem().Kind() == reflect.Interface if !((takesBytesOnly || takesBytesAndDone) && returnsNothing) { panic("SynchronizedBeforeSuite's second argument should be a function that returns nothing and either takes []byte or ([]byte, Done)") } if takesBytesAndDone { return func(done chan<- interface{}) { reflect.ValueOf(bodyB).Call([]reflect.Value{reflect.ValueOf(node.data), reflect.ValueOf(done)}) } } return func() { reflect.ValueOf(bodyB).Call([]reflect.Value{reflect.ValueOf(node.data)}) } } ginkgo-1.14.2/internal/leafnodes/synchronized_before_suite_node_test.go000066400000000000000000000265351374111457300265170ustar00rootroot00000000000000package leafnodes_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/leafnodes" . "github.com/onsi/gomega" "net/http" "github.com/onsi/gomega/ghttp" "time" "github.com/onsi/ginkgo/internal/codelocation" Failer "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/types" ) var _ = Describe("SynchronizedBeforeSuiteNode", func() { var failer *Failer.Failer var node SuiteNode var codeLocation types.CodeLocation var innerCodeLocation types.CodeLocation var outcome bool var server *ghttp.Server BeforeEach(func() { server = ghttp.NewServer() codeLocation = codelocation.New(0) innerCodeLocation = codelocation.New(0) failer = Failer.New() }) AfterEach(func() { server.Close() }) newNode := func(bodyA interface{}, bodyB interface{}) SuiteNode { return NewSynchronizedBeforeSuiteNode(bodyA, bodyB, codeLocation, time.Millisecond, failer) } Describe("when not running in parallel", func() { Context("when all is well", func() { var data []byte BeforeEach(func() { data = nil node = newNode(func() []byte { return []byte("my data") }, func(d []byte) { data = d }) outcome = node.Run(1, 1, server.URL()) }) It("should run A, then B passing the output from A to B", func() { Ω(data).Should(Equal([]byte("my data"))) }) It("should report success", func() { Ω(outcome).Should(BeTrue()) Ω(node.Passed()).Should(BeTrue()) Ω(node.Summary().State).Should(Equal(types.SpecStatePassed)) }) }) Context("when A fails", func() { var ranB bool BeforeEach(func() { ranB = false node = newNode(func() []byte { failer.Fail("boom", innerCodeLocation) return nil }, func([]byte) { ranB = true }) outcome = node.Run(1, 1, server.URL()) }) It("should not run B", func() { Ω(ranB).Should(BeFalse()) }) It("should report failure", func() { Ω(outcome).Should(BeFalse()) Ω(node.Passed()).Should(BeFalse()) Ω(node.Summary().State).Should(Equal(types.SpecStateFailed)) }) }) Context("when B fails", func() { BeforeEach(func() { node = newNode(func() []byte { return nil }, func([]byte) { failer.Fail("boom", innerCodeLocation) }) outcome = node.Run(1, 1, server.URL()) }) It("should report failure", func() { Ω(outcome).Should(BeFalse()) Ω(node.Passed()).Should(BeFalse()) Ω(node.Summary().State).Should(Equal(types.SpecStateFailed)) }) }) Context("when A times out", func() { var ranB bool BeforeEach(func() { ranB = false node = newNode(func(Done) []byte { time.Sleep(time.Second) return nil }, func([]byte) { ranB = true }) outcome = node.Run(1, 1, server.URL()) }) It("should not run B", func() { Ω(ranB).Should(BeFalse()) }) It("should report failure", func() { Ω(outcome).Should(BeFalse()) Ω(node.Passed()).Should(BeFalse()) Ω(node.Summary().State).Should(Equal(types.SpecStateTimedOut)) }) }) Context("when B times out", func() { BeforeEach(func() { node = newNode(func() []byte { return nil }, func([]byte, Done) { time.Sleep(time.Second) }) outcome = node.Run(1, 1, server.URL()) }) It("should report failure", func() { Ω(outcome).Should(BeFalse()) Ω(node.Passed()).Should(BeFalse()) Ω(node.Summary().State).Should(Equal(types.SpecStateTimedOut)) }) }) }) Describe("when running in parallel", func() { var ranB bool var parallelNode, parallelTotal int BeforeEach(func() { ranB = false parallelNode, parallelTotal = 1, 3 }) Context("as the first node, it runs A", func() { var expectedState types.RemoteBeforeSuiteData BeforeEach(func() { parallelNode, parallelTotal = 1, 3 }) JustBeforeEach(func() { server.AppendHandlers(ghttp.CombineHandlers( ghttp.VerifyRequest("POST", "/BeforeSuiteState"), ghttp.VerifyJSONRepresenting(expectedState), )) outcome = node.Run(parallelNode, parallelTotal, server.URL()) }) Context("when A succeeds", func() { BeforeEach(func() { expectedState = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStatePassed} node = newNode(func() []byte { return []byte("my data") }, func([]byte) { ranB = true }) }) It("should post about A succeeding", func() { Ω(server.ReceivedRequests()).Should(HaveLen(1)) }) It("should run B", func() { Ω(ranB).Should(BeTrue()) }) It("should report success", func() { Ω(outcome).Should(BeTrue()) }) }) Context("when A fails", func() { BeforeEach(func() { expectedState = types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStateFailed} node = newNode(func() []byte { panic("BAM") }, func([]byte) { ranB = true }) }) It("should post about A failing", func() { Ω(server.ReceivedRequests()).Should(HaveLen(1)) }) It("should not run B", func() { Ω(ranB).Should(BeFalse()) }) It("should report failure", func() { Ω(outcome).Should(BeFalse()) }) }) }) Context("as the Nth node", func() { var statusCode int var response interface{} var ranA bool var bData []byte BeforeEach(func() { ranA = false bData = nil statusCode = http.StatusOK server.AppendHandlers(ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/BeforeSuiteState"), ghttp.RespondWith(http.StatusOK, string((types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending}).ToJSON())), ), ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/BeforeSuiteState"), ghttp.RespondWith(http.StatusOK, string((types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending}).ToJSON())), ), ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/BeforeSuiteState"), ghttp.RespondWithJSONEncodedPtr(&statusCode, &response), )) node = newNode(func() []byte { ranA = true return nil }, func(data []byte) { bData = data }) parallelNode, parallelTotal = 2, 3 }) Context("when A on node1 succeeds", func() { BeforeEach(func() { response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStatePassed} outcome = node.Run(parallelNode, parallelTotal, server.URL()) }) It("should not run A", func() { Ω(ranA).Should(BeFalse()) }) It("should poll for A", func() { Ω(server.ReceivedRequests()).Should(HaveLen(3)) }) It("should run B when the polling succeeds", func() { Ω(bData).Should(Equal([]byte("my data"))) }) It("should succeed", func() { Ω(outcome).Should(BeTrue()) Ω(node.Passed()).Should(BeTrue()) }) }) Context("when A on node1 fails", func() { BeforeEach(func() { response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStateFailed} outcome = node.Run(parallelNode, parallelTotal, server.URL()) }) It("should not run A", func() { Ω(ranA).Should(BeFalse()) }) It("should poll for A", func() { Ω(server.ReceivedRequests()).Should(HaveLen(3)) }) It("should not run B", func() { Ω(bData).Should(BeNil()) }) It("should fail", func() { Ω(outcome).Should(BeFalse()) Ω(node.Passed()).Should(BeFalse()) summary := node.Summary() Ω(summary.State).Should(Equal(types.SpecStateFailed)) Ω(summary.Failure.Message).Should(Equal("BeforeSuite on Node 1 failed")) Ω(summary.Failure.Location).Should(Equal(codeLocation)) Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) Ω(summary.Failure.ComponentIndex).Should(Equal(0)) Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) }) }) Context("when node1 disappears", func() { BeforeEach(func() { response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStateDisappeared} outcome = node.Run(parallelNode, parallelTotal, server.URL()) }) It("should not run A", func() { Ω(ranA).Should(BeFalse()) }) It("should poll for A", func() { Ω(server.ReceivedRequests()).Should(HaveLen(3)) }) It("should not run B", func() { Ω(bData).Should(BeNil()) }) It("should fail", func() { Ω(outcome).Should(BeFalse()) Ω(node.Passed()).Should(BeFalse()) summary := node.Summary() Ω(summary.State).Should(Equal(types.SpecStateFailed)) Ω(summary.Failure.Message).Should(Equal("Node 1 disappeared before completing BeforeSuite")) Ω(summary.Failure.Location).Should(Equal(codeLocation)) Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) Ω(summary.Failure.ComponentIndex).Should(Equal(0)) Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) }) }) }) }) Describe("construction", func() { Describe("the first function", func() { Context("when the first function returns a byte array", func() { Context("and takes nothing", func() { It("should be fine", func() { Ω(func() { newNode(func() []byte { return nil }, func([]byte) {}) }).ShouldNot(Panic()) }) }) Context("and takes a done function", func() { It("should be fine", func() { Ω(func() { newNode(func(Done) []byte { return nil }, func([]byte) {}) }).ShouldNot(Panic()) }) }) Context("and takes more than one thing", func() { It("should panic", func() { Ω(func() { newNode(func(Done, Done) []byte { return nil }, func([]byte) {}) }).Should(Panic()) }) }) Context("and takes something else", func() { It("should panic", func() { Ω(func() { newNode(func(bool) []byte { return nil }, func([]byte) {}) }).Should(Panic()) }) }) }) Context("when the first function does not return a byte array", func() { It("should panic", func() { Ω(func() { newNode(func() {}, func([]byte) {}) }).Should(Panic()) Ω(func() { newNode(func() []int { return nil }, func([]byte) {}) }).Should(Panic()) }) }) }) Describe("the second function", func() { Context("when the second function takes a byte array", func() { It("should be fine", func() { Ω(func() { newNode(func() []byte { return nil }, func([]byte) {}) }).ShouldNot(Panic()) }) }) Context("when it also takes a done channel", func() { It("should be fine", func() { Ω(func() { newNode(func() []byte { return nil }, func([]byte, Done) {}) }).ShouldNot(Panic()) }) }) Context("if it takes anything else", func() { It("should panic", func() { Ω(func() { newNode(func() []byte { return nil }, func([]byte, chan bool) {}) }).Should(Panic()) Ω(func() { newNode(func() []byte { return nil }, func(string) {}) }).Should(Panic()) }) }) Context("if it takes nothing at all", func() { It("should panic", func() { Ω(func() { newNode(func() []byte { return nil }, func() {}) }).Should(Panic()) }) }) Context("if it returns something", func() { It("should panic", func() { Ω(func() { newNode(func() []byte { return nil }, func([]byte) []byte { return nil }) }).Should(Panic()) }) }) }) }) }) ginkgo-1.14.2/internal/remote/000077500000000000000000000000001374111457300161725ustar00rootroot00000000000000ginkgo-1.14.2/internal/remote/aggregator.go000066400000000000000000000216611374111457300206510ustar00rootroot00000000000000/* Aggregator is a reporter used by the Ginkgo CLI to aggregate and present parallel test output coherently as tests complete. You shouldn't need to use this in your code. To run tests in parallel: ginkgo -nodes=N where N is the number of nodes you desire. */ package remote import ( "time" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/reporters/stenographer" "github.com/onsi/ginkgo/types" ) type configAndSuite struct { config config.GinkgoConfigType summary *types.SuiteSummary } type Aggregator struct { nodeCount int config config.DefaultReporterConfigType stenographer stenographer.Stenographer result chan bool suiteBeginnings chan configAndSuite aggregatedSuiteBeginnings []configAndSuite beforeSuites chan *types.SetupSummary aggregatedBeforeSuites []*types.SetupSummary afterSuites chan *types.SetupSummary aggregatedAfterSuites []*types.SetupSummary specCompletions chan *types.SpecSummary completedSpecs []*types.SpecSummary suiteEndings chan *types.SuiteSummary aggregatedSuiteEndings []*types.SuiteSummary specs []*types.SpecSummary startTime time.Time } func NewAggregator(nodeCount int, result chan bool, config config.DefaultReporterConfigType, stenographer stenographer.Stenographer) *Aggregator { aggregator := &Aggregator{ nodeCount: nodeCount, result: result, config: config, stenographer: stenographer, suiteBeginnings: make(chan configAndSuite), beforeSuites: make(chan *types.SetupSummary), afterSuites: make(chan *types.SetupSummary), specCompletions: make(chan *types.SpecSummary), suiteEndings: make(chan *types.SuiteSummary), } go aggregator.mux() return aggregator } func (aggregator *Aggregator) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) { aggregator.suiteBeginnings <- configAndSuite{config, summary} } func (aggregator *Aggregator) BeforeSuiteDidRun(setupSummary *types.SetupSummary) { aggregator.beforeSuites <- setupSummary } func (aggregator *Aggregator) AfterSuiteDidRun(setupSummary *types.SetupSummary) { aggregator.afterSuites <- setupSummary } func (aggregator *Aggregator) SpecWillRun(specSummary *types.SpecSummary) { //noop } func (aggregator *Aggregator) SpecDidComplete(specSummary *types.SpecSummary) { aggregator.specCompletions <- specSummary } func (aggregator *Aggregator) SpecSuiteDidEnd(summary *types.SuiteSummary) { aggregator.suiteEndings <- summary } func (aggregator *Aggregator) mux() { loop: for { select { case configAndSuite := <-aggregator.suiteBeginnings: aggregator.registerSuiteBeginning(configAndSuite) case setupSummary := <-aggregator.beforeSuites: aggregator.registerBeforeSuite(setupSummary) case setupSummary := <-aggregator.afterSuites: aggregator.registerAfterSuite(setupSummary) case specSummary := <-aggregator.specCompletions: aggregator.registerSpecCompletion(specSummary) case suite := <-aggregator.suiteEndings: finished, passed := aggregator.registerSuiteEnding(suite) if finished { aggregator.result <- passed break loop } } } } func (aggregator *Aggregator) registerSuiteBeginning(configAndSuite configAndSuite) { aggregator.aggregatedSuiteBeginnings = append(aggregator.aggregatedSuiteBeginnings, configAndSuite) if len(aggregator.aggregatedSuiteBeginnings) == 1 { aggregator.startTime = time.Now() } if len(aggregator.aggregatedSuiteBeginnings) != aggregator.nodeCount { return } aggregator.stenographer.AnnounceSuite(configAndSuite.summary.SuiteDescription, configAndSuite.config.RandomSeed, configAndSuite.config.RandomizeAllSpecs, aggregator.config.Succinct) totalNumberOfSpecs := 0 if len(aggregator.aggregatedSuiteBeginnings) > 0 { totalNumberOfSpecs = configAndSuite.summary.NumberOfSpecsBeforeParallelization } aggregator.stenographer.AnnounceTotalNumberOfSpecs(totalNumberOfSpecs, aggregator.config.Succinct) aggregator.stenographer.AnnounceAggregatedParallelRun(aggregator.nodeCount, aggregator.config.Succinct) aggregator.flushCompletedSpecs() } func (aggregator *Aggregator) registerBeforeSuite(setupSummary *types.SetupSummary) { aggregator.aggregatedBeforeSuites = append(aggregator.aggregatedBeforeSuites, setupSummary) aggregator.flushCompletedSpecs() } func (aggregator *Aggregator) registerAfterSuite(setupSummary *types.SetupSummary) { aggregator.aggregatedAfterSuites = append(aggregator.aggregatedAfterSuites, setupSummary) aggregator.flushCompletedSpecs() } func (aggregator *Aggregator) registerSpecCompletion(specSummary *types.SpecSummary) { aggregator.completedSpecs = append(aggregator.completedSpecs, specSummary) aggregator.specs = append(aggregator.specs, specSummary) aggregator.flushCompletedSpecs() } func (aggregator *Aggregator) flushCompletedSpecs() { if len(aggregator.aggregatedSuiteBeginnings) != aggregator.nodeCount { return } for _, setupSummary := range aggregator.aggregatedBeforeSuites { aggregator.announceBeforeSuite(setupSummary) } for _, specSummary := range aggregator.completedSpecs { aggregator.announceSpec(specSummary) } for _, setupSummary := range aggregator.aggregatedAfterSuites { aggregator.announceAfterSuite(setupSummary) } aggregator.aggregatedBeforeSuites = []*types.SetupSummary{} aggregator.completedSpecs = []*types.SpecSummary{} aggregator.aggregatedAfterSuites = []*types.SetupSummary{} } func (aggregator *Aggregator) announceBeforeSuite(setupSummary *types.SetupSummary) { aggregator.stenographer.AnnounceCapturedOutput(setupSummary.CapturedOutput) if setupSummary.State != types.SpecStatePassed { aggregator.stenographer.AnnounceBeforeSuiteFailure(setupSummary, aggregator.config.Succinct, aggregator.config.FullTrace) } } func (aggregator *Aggregator) announceAfterSuite(setupSummary *types.SetupSummary) { aggregator.stenographer.AnnounceCapturedOutput(setupSummary.CapturedOutput) if setupSummary.State != types.SpecStatePassed { aggregator.stenographer.AnnounceAfterSuiteFailure(setupSummary, aggregator.config.Succinct, aggregator.config.FullTrace) } } func (aggregator *Aggregator) announceSpec(specSummary *types.SpecSummary) { if aggregator.config.Verbose && specSummary.State != types.SpecStatePending && specSummary.State != types.SpecStateSkipped { aggregator.stenographer.AnnounceSpecWillRun(specSummary) } aggregator.stenographer.AnnounceCapturedOutput(specSummary.CapturedOutput) switch specSummary.State { case types.SpecStatePassed: if specSummary.IsMeasurement { aggregator.stenographer.AnnounceSuccessfulMeasurement(specSummary, aggregator.config.Succinct) } else if specSummary.RunTime.Seconds() >= aggregator.config.SlowSpecThreshold { aggregator.stenographer.AnnounceSuccessfulSlowSpec(specSummary, aggregator.config.Succinct) } else { aggregator.stenographer.AnnounceSuccessfulSpec(specSummary) } case types.SpecStatePending: aggregator.stenographer.AnnouncePendingSpec(specSummary, aggregator.config.NoisyPendings && !aggregator.config.Succinct) case types.SpecStateSkipped: aggregator.stenographer.AnnounceSkippedSpec(specSummary, aggregator.config.Succinct || !aggregator.config.NoisySkippings, aggregator.config.FullTrace) case types.SpecStateTimedOut: aggregator.stenographer.AnnounceSpecTimedOut(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace) case types.SpecStatePanicked: aggregator.stenographer.AnnounceSpecPanicked(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace) case types.SpecStateFailed: aggregator.stenographer.AnnounceSpecFailed(specSummary, aggregator.config.Succinct, aggregator.config.FullTrace) } } func (aggregator *Aggregator) registerSuiteEnding(suite *types.SuiteSummary) (finished bool, passed bool) { aggregator.aggregatedSuiteEndings = append(aggregator.aggregatedSuiteEndings, suite) if len(aggregator.aggregatedSuiteEndings) < aggregator.nodeCount { return false, false } aggregatedSuiteSummary := &types.SuiteSummary{} aggregatedSuiteSummary.SuiteSucceeded = true for _, suiteSummary := range aggregator.aggregatedSuiteEndings { if !suiteSummary.SuiteSucceeded { aggregatedSuiteSummary.SuiteSucceeded = false } aggregatedSuiteSummary.NumberOfSpecsThatWillBeRun += suiteSummary.NumberOfSpecsThatWillBeRun aggregatedSuiteSummary.NumberOfTotalSpecs += suiteSummary.NumberOfTotalSpecs aggregatedSuiteSummary.NumberOfPassedSpecs += suiteSummary.NumberOfPassedSpecs aggregatedSuiteSummary.NumberOfFailedSpecs += suiteSummary.NumberOfFailedSpecs aggregatedSuiteSummary.NumberOfPendingSpecs += suiteSummary.NumberOfPendingSpecs aggregatedSuiteSummary.NumberOfSkippedSpecs += suiteSummary.NumberOfSkippedSpecs aggregatedSuiteSummary.NumberOfFlakedSpecs += suiteSummary.NumberOfFlakedSpecs } aggregatedSuiteSummary.RunTime = time.Since(aggregator.startTime) aggregator.stenographer.SummarizeFailures(aggregator.specs) aggregator.stenographer.AnnounceSpecRunCompletion(aggregatedSuiteSummary, aggregator.config.Succinct) return true, aggregatedSuiteSummary.SuiteSucceeded } ginkgo-1.14.2/internal/remote/aggregator_test.go000066400000000000000000000224061374111457300217060ustar00rootroot00000000000000package remote_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "time" "github.com/onsi/ginkgo/config" . "github.com/onsi/ginkgo/internal/remote" st "github.com/onsi/ginkgo/reporters/stenographer" "github.com/onsi/ginkgo/types" ) var _ = Describe("Aggregator", func() { var ( aggregator *Aggregator reporterConfig config.DefaultReporterConfigType stenographer *st.FakeStenographer result chan bool ginkgoConfig1 config.GinkgoConfigType ginkgoConfig2 config.GinkgoConfigType suiteSummary1 *types.SuiteSummary suiteSummary2 *types.SuiteSummary beforeSummary *types.SetupSummary afterSummary *types.SetupSummary specSummary *types.SpecSummary suiteDescription string ) BeforeEach(func() { reporterConfig = config.DefaultReporterConfigType{ NoColor: false, SlowSpecThreshold: 0.1, NoisyPendings: true, Succinct: false, Verbose: true, } stenographer = st.NewFakeStenographer() result = make(chan bool, 1) aggregator = NewAggregator(2, result, reporterConfig, stenographer) // // now set up some fixture data // ginkgoConfig1 = config.GinkgoConfigType{ RandomSeed: 1138, RandomizeAllSpecs: true, ParallelNode: 1, ParallelTotal: 2, } ginkgoConfig2 = config.GinkgoConfigType{ RandomSeed: 1138, RandomizeAllSpecs: true, ParallelNode: 2, ParallelTotal: 2, } suiteDescription = "My Parallel Suite" suiteSummary1 = &types.SuiteSummary{ SuiteDescription: suiteDescription, NumberOfSpecsBeforeParallelization: 30, NumberOfTotalSpecs: 17, NumberOfSpecsThatWillBeRun: 15, NumberOfPendingSpecs: 1, NumberOfSkippedSpecs: 1, } suiteSummary2 = &types.SuiteSummary{ SuiteDescription: suiteDescription, NumberOfSpecsBeforeParallelization: 30, NumberOfTotalSpecs: 13, NumberOfSpecsThatWillBeRun: 8, NumberOfPendingSpecs: 2, NumberOfSkippedSpecs: 3, } beforeSummary = &types.SetupSummary{ State: types.SpecStatePassed, CapturedOutput: "BeforeSuiteOutput", } afterSummary = &types.SetupSummary{ State: types.SpecStatePassed, CapturedOutput: "AfterSuiteOutput", } specSummary = &types.SpecSummary{ State: types.SpecStatePassed, CapturedOutput: "SpecOutput", } }) call := st.NewFakeStenographerCall beginSuite := func() { stenographer.Reset() aggregator.SpecSuiteWillBegin(ginkgoConfig2, suiteSummary2) aggregator.SpecSuiteWillBegin(ginkgoConfig1, suiteSummary1) Eventually(func() interface{} { return len(stenographer.Calls()) }).Should(BeNumerically(">=", 3)) } Describe("Announcing the beginning of the suite", func() { Context("When one of the parallel-suites starts", func() { BeforeEach(func() { aggregator.SpecSuiteWillBegin(ginkgoConfig2, suiteSummary2) }) It("should be silent", func() { Consistently(func() interface{} { return stenographer.Calls() }).Should(BeEmpty()) }) }) Context("once all of the parallel-suites have started", func() { BeforeEach(func() { aggregator.SpecSuiteWillBegin(ginkgoConfig2, suiteSummary2) aggregator.SpecSuiteWillBegin(ginkgoConfig1, suiteSummary1) Eventually(func() interface{} { return stenographer.Calls() }).Should(HaveLen(3)) }) It("should announce the beginning of the suite", func() { Ω(stenographer.Calls()).Should(HaveLen(3)) Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuite", suiteDescription, ginkgoConfig1.RandomSeed, true, false))) Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceTotalNumberOfSpecs", 30, false))) Ω(stenographer.Calls()[2]).Should(Equal(call("AnnounceAggregatedParallelRun", 2, false))) }) }) }) Describe("Announcing specs and before suites", func() { Context("when the parallel-suites have not all started", func() { BeforeEach(func() { aggregator.BeforeSuiteDidRun(beforeSummary) aggregator.AfterSuiteDidRun(afterSummary) aggregator.SpecDidComplete(specSummary) }) It("should not announce any specs", func() { Consistently(func() interface{} { return stenographer.Calls() }).Should(BeEmpty()) }) Context("when the parallel-suites subsequently start", func() { BeforeEach(func() { beginSuite() }) It("should announce the specs, the before suites and the after suites", func() { Eventually(func() interface{} { return stenographer.Calls() }).Should(ContainElement(call("AnnounceSuccessfulSpec", specSummary))) Ω(stenographer.Calls()).Should(ContainElement(call("AnnounceCapturedOutput", beforeSummary.CapturedOutput))) Ω(stenographer.Calls()).Should(ContainElement(call("AnnounceCapturedOutput", afterSummary.CapturedOutput))) }) }) }) Context("When the parallel-suites have all started", func() { BeforeEach(func() { beginSuite() stenographer.Reset() }) Context("When a spec completes", func() { BeforeEach(func() { aggregator.BeforeSuiteDidRun(beforeSummary) aggregator.SpecDidComplete(specSummary) aggregator.AfterSuiteDidRun(afterSummary) Eventually(func() interface{} { return stenographer.Calls() }).Should(HaveLen(5)) }) It("should announce the captured output of the BeforeSuite", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceCapturedOutput", beforeSummary.CapturedOutput))) }) It("should announce that the spec will run (when in verbose mode)", func() { Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceSpecWillRun", specSummary))) }) It("should announce the captured stdout of the spec", func() { Ω(stenographer.Calls()[2]).Should(Equal(call("AnnounceCapturedOutput", specSummary.CapturedOutput))) }) It("should announce completion", func() { Ω(stenographer.Calls()[3]).Should(Equal(call("AnnounceSuccessfulSpec", specSummary))) }) It("should announce the captured output of the AfterSuite", func() { Ω(stenographer.Calls()[4]).Should(Equal(call("AnnounceCapturedOutput", afterSummary.CapturedOutput))) }) }) }) }) Describe("Announcing the end of the suite", func() { BeforeEach(func() { beginSuite() stenographer.Reset() }) Context("When one of the parallel-suites ends", func() { BeforeEach(func() { aggregator.SpecSuiteDidEnd(suiteSummary2) }) It("should be silent", func() { Consistently(func() interface{} { return stenographer.Calls() }).Should(BeEmpty()) }) It("should not notify the channel", func() { Ω(result).Should(BeEmpty()) }) }) Context("once all of the parallel-suites end", func() { BeforeEach(func() { time.Sleep(200 * time.Millisecond) suiteSummary1.SuiteSucceeded = true suiteSummary1.NumberOfPassedSpecs = 15 suiteSummary1.NumberOfFailedSpecs = 0 suiteSummary1.NumberOfFlakedSpecs = 3 suiteSummary2.SuiteSucceeded = false suiteSummary2.NumberOfPassedSpecs = 5 suiteSummary2.NumberOfFailedSpecs = 3 suiteSummary2.NumberOfFlakedSpecs = 4 aggregator.SpecSuiteDidEnd(suiteSummary2) aggregator.SpecSuiteDidEnd(suiteSummary1) Eventually(func() interface{} { return stenographer.Calls() }).Should(HaveLen(2)) }) It("should announce the end of the suite", func() { compositeSummary := stenographer.Calls()[1].Args[0].(*types.SuiteSummary) Ω(compositeSummary.SuiteSucceeded).Should(BeFalse()) Ω(compositeSummary.NumberOfSpecsThatWillBeRun).Should(Equal(23)) Ω(compositeSummary.NumberOfTotalSpecs).Should(Equal(30)) Ω(compositeSummary.NumberOfPassedSpecs).Should(Equal(20)) Ω(compositeSummary.NumberOfFailedSpecs).Should(Equal(3)) Ω(compositeSummary.NumberOfPendingSpecs).Should(Equal(3)) Ω(compositeSummary.NumberOfSkippedSpecs).Should(Equal(4)) Ω(compositeSummary.NumberOfFlakedSpecs).Should(Equal(7)) Ω(compositeSummary.RunTime.Seconds()).Should(BeNumerically(">", 0.2)) }) }) Context("when all the parallel-suites pass", func() { BeforeEach(func() { suiteSummary1.SuiteSucceeded = true suiteSummary2.SuiteSucceeded = true aggregator.SpecSuiteDidEnd(suiteSummary2) aggregator.SpecSuiteDidEnd(suiteSummary1) Eventually(func() interface{} { return stenographer.Calls() }).Should(HaveLen(2)) }) It("should report success", func() { compositeSummary := stenographer.Calls()[1].Args[0].(*types.SuiteSummary) Ω(compositeSummary.SuiteSucceeded).Should(BeTrue()) }) It("should notify the channel that it succeded", func(done Done) { Ω(<-result).Should(BeTrue()) close(done) }) }) Context("when one of the parallel-suites fails", func() { BeforeEach(func() { suiteSummary1.SuiteSucceeded = true suiteSummary2.SuiteSucceeded = false aggregator.SpecSuiteDidEnd(suiteSummary2) aggregator.SpecSuiteDidEnd(suiteSummary1) Eventually(func() interface{} { return stenographer.Calls() }).Should(HaveLen(2)) }) It("should report failure", func() { compositeSummary := stenographer.Calls()[1].Args[0].(*types.SuiteSummary) Ω(compositeSummary.SuiteSucceeded).Should(BeFalse()) }) It("should notify the channel that it failed", func(done Done) { Ω(<-result).Should(BeFalse()) close(done) }) }) }) }) ginkgo-1.14.2/internal/remote/fake_output_interceptor_test.go000066400000000000000000000010631374111457300245240ustar00rootroot00000000000000package remote_test import "os" type fakeOutputInterceptor struct { DidStartInterceptingOutput bool DidStopInterceptingOutput bool InterceptedOutput string } func (interceptor *fakeOutputInterceptor) StartInterceptingOutput() error { interceptor.DidStartInterceptingOutput = true return nil } func (interceptor *fakeOutputInterceptor) StopInterceptingAndReturnOutput() (string, error) { interceptor.DidStopInterceptingOutput = true return interceptor.InterceptedOutput, nil } func (interceptor *fakeOutputInterceptor) StreamTo(*os.File) { } ginkgo-1.14.2/internal/remote/fake_poster_test.go000066400000000000000000000010661374111457300220650ustar00rootroot00000000000000package remote_test import ( "io" "io/ioutil" "net/http" ) type post struct { url string bodyType string bodyContent []byte } type fakePoster struct { posts []post } func newFakePoster() *fakePoster { return &fakePoster{ posts: make([]post, 0), } } func (poster *fakePoster) Post(url string, bodyType string, body io.Reader) (resp *http.Response, err error) { bodyContent, _ := ioutil.ReadAll(body) poster.posts = append(poster.posts, post{ url: url, bodyType: bodyType, bodyContent: bodyContent, }) return nil, nil } ginkgo-1.14.2/internal/remote/forwarding_reporter.go000066400000000000000000000112151374111457300226050ustar00rootroot00000000000000package remote import ( "bytes" "encoding/json" "fmt" "io" "net/http" "os" "github.com/onsi/ginkgo/internal/writer" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/reporters/stenographer" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/types" ) //An interface to net/http's client to allow the injection of fakes under test type Poster interface { Post(url string, bodyType string, body io.Reader) (resp *http.Response, err error) } /* The ForwardingReporter is a Ginkgo reporter that forwards information to a Ginkgo remote server. When streaming parallel test output, this repoter is automatically installed by Ginkgo. This is accomplished by passing in the GINKGO_REMOTE_REPORTING_SERVER environment variable to `go test`, the Ginkgo test runner detects this environment variable (which should contain the host of the server) and automatically installs a ForwardingReporter in place of Ginkgo's DefaultReporter. */ type ForwardingReporter struct { serverHost string poster Poster outputInterceptor OutputInterceptor debugMode bool debugFile *os.File nestedReporter *reporters.DefaultReporter } func NewForwardingReporter(config config.DefaultReporterConfigType, serverHost string, poster Poster, outputInterceptor OutputInterceptor, ginkgoWriter *writer.Writer, debugFile string) *ForwardingReporter { reporter := &ForwardingReporter{ serverHost: serverHost, poster: poster, outputInterceptor: outputInterceptor, } if debugFile != "" { var err error reporter.debugMode = true reporter.debugFile, err = os.Create(debugFile) if err != nil { fmt.Println(err.Error()) os.Exit(1) } if !config.Verbose { //if verbose is true then the GinkgoWriter emits to stdout. Don't _also_ redirect GinkgoWriter output as that will result in duplication. ginkgoWriter.AndRedirectTo(reporter.debugFile) } outputInterceptor.StreamTo(reporter.debugFile) //This is not working stenographer := stenographer.New(false, true, reporter.debugFile) config.Succinct = false config.Verbose = true config.FullTrace = true reporter.nestedReporter = reporters.NewDefaultReporter(config, stenographer) } return reporter } func (reporter *ForwardingReporter) post(path string, data interface{}) { encoded, _ := json.Marshal(data) buffer := bytes.NewBuffer(encoded) reporter.poster.Post(reporter.serverHost+path, "application/json", buffer) } func (reporter *ForwardingReporter) SpecSuiteWillBegin(conf config.GinkgoConfigType, summary *types.SuiteSummary) { data := struct { Config config.GinkgoConfigType `json:"config"` Summary *types.SuiteSummary `json:"suite-summary"` }{ conf, summary, } reporter.outputInterceptor.StartInterceptingOutput() if reporter.debugMode { reporter.nestedReporter.SpecSuiteWillBegin(conf, summary) reporter.debugFile.Sync() } reporter.post("/SpecSuiteWillBegin", data) } func (reporter *ForwardingReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) { output, _ := reporter.outputInterceptor.StopInterceptingAndReturnOutput() reporter.outputInterceptor.StartInterceptingOutput() setupSummary.CapturedOutput = output if reporter.debugMode { reporter.nestedReporter.BeforeSuiteDidRun(setupSummary) reporter.debugFile.Sync() } reporter.post("/BeforeSuiteDidRun", setupSummary) } func (reporter *ForwardingReporter) SpecWillRun(specSummary *types.SpecSummary) { if reporter.debugMode { reporter.nestedReporter.SpecWillRun(specSummary) reporter.debugFile.Sync() } reporter.post("/SpecWillRun", specSummary) } func (reporter *ForwardingReporter) SpecDidComplete(specSummary *types.SpecSummary) { output, _ := reporter.outputInterceptor.StopInterceptingAndReturnOutput() reporter.outputInterceptor.StartInterceptingOutput() specSummary.CapturedOutput = output if reporter.debugMode { reporter.nestedReporter.SpecDidComplete(specSummary) reporter.debugFile.Sync() } reporter.post("/SpecDidComplete", specSummary) } func (reporter *ForwardingReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) { output, _ := reporter.outputInterceptor.StopInterceptingAndReturnOutput() reporter.outputInterceptor.StartInterceptingOutput() setupSummary.CapturedOutput = output if reporter.debugMode { reporter.nestedReporter.AfterSuiteDidRun(setupSummary) reporter.debugFile.Sync() } reporter.post("/AfterSuiteDidRun", setupSummary) } func (reporter *ForwardingReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { reporter.outputInterceptor.StopInterceptingAndReturnOutput() if reporter.debugMode { reporter.nestedReporter.SpecSuiteDidEnd(summary) reporter.debugFile.Sync() } reporter.post("/SpecSuiteDidEnd", summary) } ginkgo-1.14.2/internal/remote/forwarding_reporter_test.go000066400000000000000000000130411374111457300236430ustar00rootroot00000000000000package remote_test import ( "encoding/json" . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/config" . "github.com/onsi/ginkgo/internal/remote" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" ) var _ = Describe("ForwardingReporter", func() { var ( reporter *ForwardingReporter interceptor *fakeOutputInterceptor poster *fakePoster suiteSummary *types.SuiteSummary specSummary *types.SpecSummary setupSummary *types.SetupSummary serverHost string ) BeforeEach(func() { serverHost = "http://127.0.0.1:7788" poster = newFakePoster() interceptor = &fakeOutputInterceptor{ InterceptedOutput: "The intercepted output!", } reporter = NewForwardingReporter(config.DefaultReporterConfigType{}, serverHost, poster, interceptor, nil, "") suiteSummary = &types.SuiteSummary{ SuiteDescription: "My Test Suite", } setupSummary = &types.SetupSummary{ State: types.SpecStatePassed, } specSummary = &types.SpecSummary{ ComponentTexts: []string{"My", "Spec"}, State: types.SpecStatePassed, } }) Context("When a suite begins", func() { BeforeEach(func() { reporter.SpecSuiteWillBegin(config.GinkgoConfig, suiteSummary) }) It("should start intercepting output", func() { Ω(interceptor.DidStartInterceptingOutput).Should(BeTrue()) }) It("should POST the SuiteSummary and Ginkgo Config to the Ginkgo server", func() { Ω(poster.posts).Should(HaveLen(1)) Ω(poster.posts[0].url).Should(Equal("http://127.0.0.1:7788/SpecSuiteWillBegin")) Ω(poster.posts[0].bodyType).Should(Equal("application/json")) var sentData struct { SentConfig config.GinkgoConfigType `json:"config"` SentSuiteSummary *types.SuiteSummary `json:"suite-summary"` } err := json.Unmarshal(poster.posts[0].bodyContent, &sentData) Ω(err).ShouldNot(HaveOccurred()) Ω(sentData.SentConfig).Should(Equal(config.GinkgoConfig)) Ω(sentData.SentSuiteSummary).Should(Equal(suiteSummary)) }) }) Context("when a BeforeSuite completes", func() { BeforeEach(func() { reporter.BeforeSuiteDidRun(setupSummary) }) It("should stop, then start intercepting output", func() { Ω(interceptor.DidStopInterceptingOutput).Should(BeTrue()) Ω(interceptor.DidStartInterceptingOutput).Should(BeTrue()) }) It("should POST the SetupSummary to the Ginkgo server", func() { Ω(poster.posts).Should(HaveLen(1)) Ω(poster.posts[0].url).Should(Equal("http://127.0.0.1:7788/BeforeSuiteDidRun")) Ω(poster.posts[0].bodyType).Should(Equal("application/json")) var summary *types.SetupSummary err := json.Unmarshal(poster.posts[0].bodyContent, &summary) Ω(err).ShouldNot(HaveOccurred()) setupSummary.CapturedOutput = interceptor.InterceptedOutput Ω(summary).Should(Equal(setupSummary)) }) }) Context("when an AfterSuite completes", func() { BeforeEach(func() { reporter.AfterSuiteDidRun(setupSummary) }) It("should stop, then start intercepting output", func() { Ω(interceptor.DidStopInterceptingOutput).Should(BeTrue()) Ω(interceptor.DidStartInterceptingOutput).Should(BeTrue()) }) It("should POST the SetupSummary to the Ginkgo server", func() { Ω(poster.posts).Should(HaveLen(1)) Ω(poster.posts[0].url).Should(Equal("http://127.0.0.1:7788/AfterSuiteDidRun")) Ω(poster.posts[0].bodyType).Should(Equal("application/json")) var summary *types.SetupSummary err := json.Unmarshal(poster.posts[0].bodyContent, &summary) Ω(err).ShouldNot(HaveOccurred()) setupSummary.CapturedOutput = interceptor.InterceptedOutput Ω(summary).Should(Equal(setupSummary)) }) }) Context("When a spec will run", func() { BeforeEach(func() { reporter.SpecWillRun(specSummary) }) It("should POST the SpecSummary to the Ginkgo server", func() { Ω(poster.posts).Should(HaveLen(1)) Ω(poster.posts[0].url).Should(Equal("http://127.0.0.1:7788/SpecWillRun")) Ω(poster.posts[0].bodyType).Should(Equal("application/json")) var summary *types.SpecSummary err := json.Unmarshal(poster.posts[0].bodyContent, &summary) Ω(err).ShouldNot(HaveOccurred()) Ω(summary).Should(Equal(specSummary)) }) Context("When a spec completes", func() { BeforeEach(func() { specSummary.State = types.SpecStatePanicked reporter.SpecDidComplete(specSummary) }) It("should POST the SpecSummary to the Ginkgo server and include any intercepted output", func() { Ω(poster.posts).Should(HaveLen(2)) Ω(poster.posts[1].url).Should(Equal("http://127.0.0.1:7788/SpecDidComplete")) Ω(poster.posts[1].bodyType).Should(Equal("application/json")) var summary *types.SpecSummary err := json.Unmarshal(poster.posts[1].bodyContent, &summary) Ω(err).ShouldNot(HaveOccurred()) specSummary.CapturedOutput = interceptor.InterceptedOutput Ω(summary).Should(Equal(specSummary)) }) It("should stop, then start intercepting output", func() { Ω(interceptor.DidStopInterceptingOutput).Should(BeTrue()) Ω(interceptor.DidStartInterceptingOutput).Should(BeTrue()) }) }) }) Context("When a suite ends", func() { BeforeEach(func() { reporter.SpecSuiteDidEnd(suiteSummary) }) It("should POST the SuiteSummary to the Ginkgo server", func() { Ω(poster.posts).Should(HaveLen(1)) Ω(poster.posts[0].url).Should(Equal("http://127.0.0.1:7788/SpecSuiteDidEnd")) Ω(poster.posts[0].bodyType).Should(Equal("application/json")) var summary *types.SuiteSummary err := json.Unmarshal(poster.posts[0].bodyContent, &summary) Ω(err).ShouldNot(HaveOccurred()) Ω(summary).Should(Equal(suiteSummary)) }) }) }) ginkgo-1.14.2/internal/remote/output_interceptor.go000066400000000000000000000004601374111457300224770ustar00rootroot00000000000000package remote import "os" /* The OutputInterceptor is used by the ForwardingReporter to intercept and capture all stdin and stderr output during a test run. */ type OutputInterceptor interface { StartInterceptingOutput() error StopInterceptingAndReturnOutput() (string, error) StreamTo(*os.File) } ginkgo-1.14.2/internal/remote/output_interceptor_darwin.go000066400000000000000000000002261374111457300240430ustar00rootroot00000000000000// +build darwin package remote import ( "golang.org/x/sys/unix" ) func interceptorDupx(oldfd int, newfd int) { unix.Dup2(oldfd, newfd) } ginkgo-1.14.2/internal/remote/output_interceptor_dragonfly.go000066400000000000000000000002311374111457300245400ustar00rootroot00000000000000// +build dragonfly package remote import ( "golang.org/x/sys/unix" ) func interceptorDupx(oldfd int, newfd int) { unix.Dup2(oldfd, newfd) } ginkgo-1.14.2/internal/remote/output_interceptor_freebsd.go000066400000000000000000000002271374111457300241720ustar00rootroot00000000000000// +build freebsd package remote import ( "golang.org/x/sys/unix" ) func interceptorDupx(oldfd int, newfd int) { unix.Dup2(oldfd, newfd) } ginkgo-1.14.2/internal/remote/output_interceptor_linux.go000066400000000000000000000002511374111457300237140ustar00rootroot00000000000000// +build linux // +build !mips64le package remote import ( "golang.org/x/sys/unix" ) func interceptorDupx(oldfd int, newfd int) { unix.Dup2(oldfd, newfd) } ginkgo-1.14.2/internal/remote/output_interceptor_linux_mips64le.go000066400000000000000000000002531374111457300254410ustar00rootroot00000000000000// +build linux // +build mips64le package remote import ( "golang.org/x/sys/unix" ) func interceptorDupx(oldfd int, newfd int) { unix.Dup3(oldfd, newfd, 0) } ginkgo-1.14.2/internal/remote/output_interceptor_netbsd.go000066400000000000000000000002261374111457300240360ustar00rootroot00000000000000// +build netbsd package remote import ( "golang.org/x/sys/unix" ) func interceptorDupx(oldfd int, newfd int) { unix.Dup2(oldfd, newfd) } ginkgo-1.14.2/internal/remote/output_interceptor_openbsd.go000066400000000000000000000002271374111457300242120ustar00rootroot00000000000000// +build openbsd package remote import ( "golang.org/x/sys/unix" ) func interceptorDupx(oldfd int, newfd int) { unix.Dup2(oldfd, newfd) } ginkgo-1.14.2/internal/remote/output_interceptor_solaris.go000066400000000000000000000002271374111457300242340ustar00rootroot00000000000000// +build solaris package remote import ( "golang.org/x/sys/unix" ) func interceptorDupx(oldfd int, newfd int) { unix.Dup2(oldfd, newfd) } ginkgo-1.14.2/internal/remote/output_interceptor_unix.go000066400000000000000000000034341374111457300235460ustar00rootroot00000000000000// +build freebsd openbsd netbsd dragonfly darwin linux solaris package remote import ( "errors" "io/ioutil" "os" "github.com/nxadm/tail" ) func NewOutputInterceptor() OutputInterceptor { return &outputInterceptor{} } type outputInterceptor struct { redirectFile *os.File streamTarget *os.File intercepting bool tailer *tail.Tail doneTailing chan bool } func (interceptor *outputInterceptor) StartInterceptingOutput() error { if interceptor.intercepting { return errors.New("Already intercepting output!") } interceptor.intercepting = true var err error interceptor.redirectFile, err = ioutil.TempFile("", "ginkgo-output") if err != nil { return err } interceptorDupx(int(interceptor.redirectFile.Fd()), 1) interceptorDupx(int(interceptor.redirectFile.Fd()), 2) if interceptor.streamTarget != nil { interceptor.tailer, _ = tail.TailFile(interceptor.redirectFile.Name(), tail.Config{Follow: true}) interceptor.doneTailing = make(chan bool) go func() { for line := range interceptor.tailer.Lines { interceptor.streamTarget.Write([]byte(line.Text + "\n")) } close(interceptor.doneTailing) }() } return nil } func (interceptor *outputInterceptor) StopInterceptingAndReturnOutput() (string, error) { if !interceptor.intercepting { return "", errors.New("Not intercepting output!") } interceptor.redirectFile.Close() output, err := ioutil.ReadFile(interceptor.redirectFile.Name()) os.Remove(interceptor.redirectFile.Name()) interceptor.intercepting = false if interceptor.streamTarget != nil { interceptor.tailer.Stop() interceptor.tailer.Cleanup() <-interceptor.doneTailing interceptor.streamTarget.Sync() } return string(output), err } func (interceptor *outputInterceptor) StreamTo(out *os.File) { interceptor.streamTarget = out } ginkgo-1.14.2/internal/remote/output_interceptor_win.go000066400000000000000000000012351374111457300233550ustar00rootroot00000000000000// +build windows package remote import ( "errors" "os" ) func NewOutputInterceptor() OutputInterceptor { return &outputInterceptor{} } type outputInterceptor struct { intercepting bool } func (interceptor *outputInterceptor) StartInterceptingOutput() error { if interceptor.intercepting { return errors.New("Already intercepting output!") } interceptor.intercepting = true // not working on windows... return nil } func (interceptor *outputInterceptor) StopInterceptingAndReturnOutput() (string, error) { // not working on windows... interceptor.intercepting = false return "", nil } func (interceptor *outputInterceptor) StreamTo(*os.File) {} ginkgo-1.14.2/internal/remote/remote_suite_test.go000066400000000000000000000003171374111457300222650ustar00rootroot00000000000000package remote_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestRemote(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Remote Spec Forwarding Suite") } ginkgo-1.14.2/internal/remote/server.go000066400000000000000000000143761374111457300200420ustar00rootroot00000000000000/* The remote package provides the pieces to allow Ginkgo test suites to report to remote listeners. This is used, primarily, to enable streaming parallel test output but has, in principal, broader applications (e.g. streaming test output to a browser). */ package remote import ( "encoding/json" "io/ioutil" "net" "net/http" "sync" "github.com/onsi/ginkgo/internal/spec_iterator" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/types" ) /* Server spins up on an automatically selected port and listens for communication from the forwarding reporter. It then forwards that communication to attached reporters. */ type Server struct { listener net.Listener reporters []reporters.Reporter alives []func() bool lock *sync.Mutex beforeSuiteData types.RemoteBeforeSuiteData parallelTotal int counter int } //Create a new server, automatically selecting a port func NewServer(parallelTotal int) (*Server, error) { listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { return nil, err } return &Server{ listener: listener, lock: &sync.Mutex{}, alives: make([]func() bool, parallelTotal), beforeSuiteData: types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending}, parallelTotal: parallelTotal, }, nil } //Start the server. You don't need to `go s.Start()`, just `s.Start()` func (server *Server) Start() { httpServer := &http.Server{} mux := http.NewServeMux() httpServer.Handler = mux //streaming endpoints mux.HandleFunc("/SpecSuiteWillBegin", server.specSuiteWillBegin) mux.HandleFunc("/BeforeSuiteDidRun", server.beforeSuiteDidRun) mux.HandleFunc("/AfterSuiteDidRun", server.afterSuiteDidRun) mux.HandleFunc("/SpecWillRun", server.specWillRun) mux.HandleFunc("/SpecDidComplete", server.specDidComplete) mux.HandleFunc("/SpecSuiteDidEnd", server.specSuiteDidEnd) //synchronization endpoints mux.HandleFunc("/BeforeSuiteState", server.handleBeforeSuiteState) mux.HandleFunc("/RemoteAfterSuiteData", server.handleRemoteAfterSuiteData) mux.HandleFunc("/counter", server.handleCounter) mux.HandleFunc("/has-counter", server.handleHasCounter) //for backward compatibility go httpServer.Serve(server.listener) } //Stop the server func (server *Server) Close() { server.listener.Close() } //The address the server can be reached it. Pass this into the `ForwardingReporter`. func (server *Server) Address() string { return "http://" + server.listener.Addr().String() } // // Streaming Endpoints // //The server will forward all received messages to Ginkgo reporters registered with `RegisterReporters` func (server *Server) readAll(request *http.Request) []byte { defer request.Body.Close() body, _ := ioutil.ReadAll(request.Body) return body } func (server *Server) RegisterReporters(reporters ...reporters.Reporter) { server.reporters = reporters } func (server *Server) specSuiteWillBegin(writer http.ResponseWriter, request *http.Request) { body := server.readAll(request) var data struct { Config config.GinkgoConfigType `json:"config"` Summary *types.SuiteSummary `json:"suite-summary"` } json.Unmarshal(body, &data) for _, reporter := range server.reporters { reporter.SpecSuiteWillBegin(data.Config, data.Summary) } } func (server *Server) beforeSuiteDidRun(writer http.ResponseWriter, request *http.Request) { body := server.readAll(request) var setupSummary *types.SetupSummary json.Unmarshal(body, &setupSummary) for _, reporter := range server.reporters { reporter.BeforeSuiteDidRun(setupSummary) } } func (server *Server) afterSuiteDidRun(writer http.ResponseWriter, request *http.Request) { body := server.readAll(request) var setupSummary *types.SetupSummary json.Unmarshal(body, &setupSummary) for _, reporter := range server.reporters { reporter.AfterSuiteDidRun(setupSummary) } } func (server *Server) specWillRun(writer http.ResponseWriter, request *http.Request) { body := server.readAll(request) var specSummary *types.SpecSummary json.Unmarshal(body, &specSummary) for _, reporter := range server.reporters { reporter.SpecWillRun(specSummary) } } func (server *Server) specDidComplete(writer http.ResponseWriter, request *http.Request) { body := server.readAll(request) var specSummary *types.SpecSummary json.Unmarshal(body, &specSummary) for _, reporter := range server.reporters { reporter.SpecDidComplete(specSummary) } } func (server *Server) specSuiteDidEnd(writer http.ResponseWriter, request *http.Request) { body := server.readAll(request) var suiteSummary *types.SuiteSummary json.Unmarshal(body, &suiteSummary) for _, reporter := range server.reporters { reporter.SpecSuiteDidEnd(suiteSummary) } } // // Synchronization Endpoints // func (server *Server) RegisterAlive(node int, alive func() bool) { server.lock.Lock() defer server.lock.Unlock() server.alives[node-1] = alive } func (server *Server) nodeIsAlive(node int) bool { server.lock.Lock() defer server.lock.Unlock() alive := server.alives[node-1] if alive == nil { return true } return alive() } func (server *Server) handleBeforeSuiteState(writer http.ResponseWriter, request *http.Request) { if request.Method == "POST" { dec := json.NewDecoder(request.Body) dec.Decode(&(server.beforeSuiteData)) } else { beforeSuiteData := server.beforeSuiteData if beforeSuiteData.State == types.RemoteBeforeSuiteStatePending && !server.nodeIsAlive(1) { beforeSuiteData.State = types.RemoteBeforeSuiteStateDisappeared } enc := json.NewEncoder(writer) enc.Encode(beforeSuiteData) } } func (server *Server) handleRemoteAfterSuiteData(writer http.ResponseWriter, request *http.Request) { afterSuiteData := types.RemoteAfterSuiteData{ CanRun: true, } for i := 2; i <= server.parallelTotal; i++ { afterSuiteData.CanRun = afterSuiteData.CanRun && !server.nodeIsAlive(i) } enc := json.NewEncoder(writer) enc.Encode(afterSuiteData) } func (server *Server) handleCounter(writer http.ResponseWriter, request *http.Request) { c := spec_iterator.Counter{} server.lock.Lock() c.Index = server.counter server.counter++ server.lock.Unlock() json.NewEncoder(writer).Encode(c) } func (server *Server) handleHasCounter(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte("")) } ginkgo-1.14.2/internal/remote/server_test.go000066400000000000000000000167641374111457300211040ustar00rootroot00000000000000package remote_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/remote" . "github.com/onsi/gomega" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/types" "bytes" "encoding/json" "net/http" ) var _ = Describe("Server", func() { var ( server *Server ) BeforeEach(func() { var err error server, err = NewServer(3) Ω(err).ShouldNot(HaveOccurred()) server.Start() }) AfterEach(func() { server.Close() }) Describe("Streaming endpoints", func() { var ( reporterA, reporterB *reporters.FakeReporter forwardingReporter *ForwardingReporter suiteSummary *types.SuiteSummary setupSummary *types.SetupSummary specSummary *types.SpecSummary ) BeforeEach(func() { reporterA = reporters.NewFakeReporter() reporterB = reporters.NewFakeReporter() server.RegisterReporters(reporterA, reporterB) forwardingReporter = NewForwardingReporter(config.DefaultReporterConfigType{}, server.Address(), &http.Client{}, &fakeOutputInterceptor{}, nil, "") suiteSummary = &types.SuiteSummary{ SuiteDescription: "My Test Suite", } setupSummary = &types.SetupSummary{ State: types.SpecStatePassed, } specSummary = &types.SpecSummary{ ComponentTexts: []string{"My", "Spec"}, State: types.SpecStatePassed, } }) It("should make its address available", func() { Ω(server.Address()).Should(MatchRegexp(`http://127.0.0.1:\d{2,}`)) }) Describe("/SpecSuiteWillBegin", func() { It("should decode and forward the Ginkgo config and suite summary", func(done Done) { forwardingReporter.SpecSuiteWillBegin(config.GinkgoConfig, suiteSummary) Ω(reporterA.Config).Should(Equal(config.GinkgoConfig)) Ω(reporterB.Config).Should(Equal(config.GinkgoConfig)) Ω(reporterA.BeginSummary).Should(Equal(suiteSummary)) Ω(reporterB.BeginSummary).Should(Equal(suiteSummary)) close(done) }) }) Describe("/BeforeSuiteDidRun", func() { It("should decode and forward the setup summary", func() { forwardingReporter.BeforeSuiteDidRun(setupSummary) Ω(reporterA.BeforeSuiteSummary).Should(Equal(setupSummary)) Ω(reporterB.BeforeSuiteSummary).Should(Equal(setupSummary)) }) }) Describe("/AfterSuiteDidRun", func() { It("should decode and forward the setup summary", func() { forwardingReporter.AfterSuiteDidRun(setupSummary) Ω(reporterA.AfterSuiteSummary).Should(Equal(setupSummary)) Ω(reporterB.AfterSuiteSummary).Should(Equal(setupSummary)) }) }) Describe("/SpecWillRun", func() { It("should decode and forward the spec summary", func(done Done) { forwardingReporter.SpecWillRun(specSummary) Ω(reporterA.SpecWillRunSummaries[0]).Should(Equal(specSummary)) Ω(reporterB.SpecWillRunSummaries[0]).Should(Equal(specSummary)) close(done) }) }) Describe("/SpecDidComplete", func() { It("should decode and forward the spec summary", func(done Done) { forwardingReporter.SpecDidComplete(specSummary) Ω(reporterA.SpecSummaries[0]).Should(Equal(specSummary)) Ω(reporterB.SpecSummaries[0]).Should(Equal(specSummary)) close(done) }) }) Describe("/SpecSuiteDidEnd", func() { It("should decode and forward the suite summary", func(done Done) { forwardingReporter.SpecSuiteDidEnd(suiteSummary) Ω(reporterA.EndSummary).Should(Equal(suiteSummary)) Ω(reporterB.EndSummary).Should(Equal(suiteSummary)) close(done) }) }) }) Describe("Synchronization endpoints", func() { Describe("GETting and POSTing BeforeSuiteState", func() { getBeforeSuite := func() types.RemoteBeforeSuiteData { resp, err := http.Get(server.Address() + "/BeforeSuiteState") Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusOK)) r := types.RemoteBeforeSuiteData{} decoder := json.NewDecoder(resp.Body) err = decoder.Decode(&r) Ω(err).ShouldNot(HaveOccurred()) return r } postBeforeSuite := func(r types.RemoteBeforeSuiteData) { resp, err := http.Post(server.Address()+"/BeforeSuiteState", "application/json", bytes.NewReader(r.ToJSON())) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusOK)) } Context("when the first node's Alive has not been registered yet", func() { It("should return pending", func() { state := getBeforeSuite() Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) state = getBeforeSuite() Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) }) }) Context("when the first node is Alive but has not responded yet", func() { BeforeEach(func() { server.RegisterAlive(1, func() bool { return true }) }) It("should return pending", func() { state := getBeforeSuite() Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) state = getBeforeSuite() Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) }) }) Context("when the first node has responded", func() { var state types.RemoteBeforeSuiteData BeforeEach(func() { server.RegisterAlive(1, func() bool { return false }) state = types.RemoteBeforeSuiteData{ Data: []byte("my data"), State: types.RemoteBeforeSuiteStatePassed, } postBeforeSuite(state) }) It("should return the passed in state", func() { returnedState := getBeforeSuite() Ω(returnedState).Should(Equal(state)) }) }) Context("when the first node is no longer Alive and has not responded yet", func() { BeforeEach(func() { server.RegisterAlive(1, func() bool { return false }) }) It("should return disappeared", func() { state := getBeforeSuite() Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStateDisappeared})) state = getBeforeSuite() Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStateDisappeared})) }) }) }) Describe("GETting RemoteAfterSuiteData", func() { getRemoteAfterSuiteData := func() bool { resp, err := http.Get(server.Address() + "/RemoteAfterSuiteData") Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusOK)) a := types.RemoteAfterSuiteData{} decoder := json.NewDecoder(resp.Body) err = decoder.Decode(&a) Ω(err).ShouldNot(HaveOccurred()) return a.CanRun } Context("when there are unregistered nodes", func() { BeforeEach(func() { server.RegisterAlive(2, func() bool { return false }) }) It("should return false", func() { Ω(getRemoteAfterSuiteData()).Should(BeFalse()) }) }) Context("when all none-node-1 nodes are still running", func() { BeforeEach(func() { server.RegisterAlive(2, func() bool { return true }) server.RegisterAlive(3, func() bool { return false }) }) It("should return false", func() { Ω(getRemoteAfterSuiteData()).Should(BeFalse()) }) }) Context("when all none-1 nodes are done", func() { BeforeEach(func() { server.RegisterAlive(2, func() bool { return false }) server.RegisterAlive(3, func() bool { return false }) }) It("should return true", func() { Ω(getRemoteAfterSuiteData()).Should(BeTrue()) }) }) }) }) }) ginkgo-1.14.2/internal/spec/000077500000000000000000000000001374111457300156315ustar00rootroot00000000000000ginkgo-1.14.2/internal/spec/spec.go000066400000000000000000000152601374111457300171160ustar00rootroot00000000000000package spec import ( "fmt" "io" "time" "sync" "github.com/onsi/ginkgo/internal/containernode" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/types" ) type Spec struct { subject leafnodes.SubjectNode focused bool announceProgress bool containers []*containernode.ContainerNode state types.SpecState runTime time.Duration startTime time.Time failure types.SpecFailure previousFailures bool stateMutex *sync.Mutex } func New(subject leafnodes.SubjectNode, containers []*containernode.ContainerNode, announceProgress bool) *Spec { spec := &Spec{ subject: subject, containers: containers, focused: subject.Flag() == types.FlagTypeFocused, announceProgress: announceProgress, stateMutex: &sync.Mutex{}, } spec.processFlag(subject.Flag()) for i := len(containers) - 1; i >= 0; i-- { spec.processFlag(containers[i].Flag()) } return spec } func (spec *Spec) processFlag(flag types.FlagType) { if flag == types.FlagTypeFocused { spec.focused = true } else if flag == types.FlagTypePending { spec.setState(types.SpecStatePending) } } func (spec *Spec) Skip() { spec.setState(types.SpecStateSkipped) } func (spec *Spec) Failed() bool { return spec.getState() == types.SpecStateFailed || spec.getState() == types.SpecStatePanicked || spec.getState() == types.SpecStateTimedOut } func (spec *Spec) Passed() bool { return spec.getState() == types.SpecStatePassed } func (spec *Spec) Flaked() bool { return spec.getState() == types.SpecStatePassed && spec.previousFailures } func (spec *Spec) Pending() bool { return spec.getState() == types.SpecStatePending } func (spec *Spec) Skipped() bool { return spec.getState() == types.SpecStateSkipped } func (spec *Spec) Focused() bool { return spec.focused } func (spec *Spec) IsMeasurement() bool { return spec.subject.Type() == types.SpecComponentTypeMeasure } func (spec *Spec) Summary(suiteID string) *types.SpecSummary { componentTexts := make([]string, len(spec.containers)+1) componentCodeLocations := make([]types.CodeLocation, len(spec.containers)+1) for i, container := range spec.containers { componentTexts[i] = container.Text() componentCodeLocations[i] = container.CodeLocation() } componentTexts[len(spec.containers)] = spec.subject.Text() componentCodeLocations[len(spec.containers)] = spec.subject.CodeLocation() runTime := spec.runTime if runTime == 0 && !spec.startTime.IsZero() { runTime = time.Since(spec.startTime) } return &types.SpecSummary{ IsMeasurement: spec.IsMeasurement(), NumberOfSamples: spec.subject.Samples(), ComponentTexts: componentTexts, ComponentCodeLocations: componentCodeLocations, State: spec.getState(), RunTime: runTime, Failure: spec.failure, Measurements: spec.measurementsReport(), SuiteID: suiteID, } } func (spec *Spec) ConcatenatedString() string { s := "" for _, container := range spec.containers { s += container.Text() + " " } return s + spec.subject.Text() } func (spec *Spec) Run(writer io.Writer) { if spec.getState() == types.SpecStateFailed { spec.previousFailures = true } spec.startTime = time.Now() defer func() { spec.runTime = time.Since(spec.startTime) }() for sample := 0; sample < spec.subject.Samples(); sample++ { spec.runSample(sample, writer) if spec.getState() != types.SpecStatePassed { return } } } func (spec *Spec) getState() types.SpecState { spec.stateMutex.Lock() defer spec.stateMutex.Unlock() return spec.state } func (spec *Spec) setState(state types.SpecState) { spec.stateMutex.Lock() defer spec.stateMutex.Unlock() spec.state = state } func (spec *Spec) runSample(sample int, writer io.Writer) { spec.setState(types.SpecStatePassed) spec.failure = types.SpecFailure{} innerMostContainerIndexToUnwind := -1 defer func() { for i := innerMostContainerIndexToUnwind; i >= 0; i-- { container := spec.containers[i] for _, justAfterEach := range container.SetupNodesOfType(types.SpecComponentTypeJustAfterEach) { spec.announceSetupNode(writer, "JustAfterEach", container, justAfterEach) justAfterEachState, justAfterEachFailure := justAfterEach.Run() if justAfterEachState != types.SpecStatePassed && spec.state == types.SpecStatePassed { spec.state = justAfterEachState spec.failure = justAfterEachFailure } } } for i := innerMostContainerIndexToUnwind; i >= 0; i-- { container := spec.containers[i] for _, afterEach := range container.SetupNodesOfType(types.SpecComponentTypeAfterEach) { spec.announceSetupNode(writer, "AfterEach", container, afterEach) afterEachState, afterEachFailure := afterEach.Run() if afterEachState != types.SpecStatePassed && spec.getState() == types.SpecStatePassed { spec.setState(afterEachState) spec.failure = afterEachFailure } } } }() for i, container := range spec.containers { innerMostContainerIndexToUnwind = i for _, beforeEach := range container.SetupNodesOfType(types.SpecComponentTypeBeforeEach) { spec.announceSetupNode(writer, "BeforeEach", container, beforeEach) s, f := beforeEach.Run() spec.failure = f spec.setState(s) if spec.getState() != types.SpecStatePassed { return } } } for _, container := range spec.containers { for _, justBeforeEach := range container.SetupNodesOfType(types.SpecComponentTypeJustBeforeEach) { spec.announceSetupNode(writer, "JustBeforeEach", container, justBeforeEach) s, f := justBeforeEach.Run() spec.failure = f spec.setState(s) if spec.getState() != types.SpecStatePassed { return } } } spec.announceSubject(writer, spec.subject) s, f := spec.subject.Run() spec.failure = f spec.setState(s) } func (spec *Spec) announceSetupNode(writer io.Writer, nodeType string, container *containernode.ContainerNode, setupNode leafnodes.BasicNode) { if spec.announceProgress { s := fmt.Sprintf("[%s] %s\n %s\n", nodeType, container.Text(), setupNode.CodeLocation().String()) writer.Write([]byte(s)) } } func (spec *Spec) announceSubject(writer io.Writer, subject leafnodes.SubjectNode) { if spec.announceProgress { nodeType := "" switch subject.Type() { case types.SpecComponentTypeIt: nodeType = "It" case types.SpecComponentTypeMeasure: nodeType = "Measure" } s := fmt.Sprintf("[%s] %s\n %s\n", nodeType, subject.Text(), subject.CodeLocation().String()) writer.Write([]byte(s)) } } func (spec *Spec) measurementsReport() map[string]*types.SpecMeasurement { if !spec.IsMeasurement() || spec.Failed() { return map[string]*types.SpecMeasurement{} } return spec.subject.(*leafnodes.MeasureNode).MeasurementsReport() } ginkgo-1.14.2/internal/spec/spec_suite_test.go000066400000000000000000000002711374111457300213620ustar00rootroot00000000000000package spec_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestSpec(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Spec Suite") } ginkgo-1.14.2/internal/spec/spec_test.go000066400000000000000000000544231374111457300201610ustar00rootroot00000000000000package spec_test import ( "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" . "github.com/onsi/ginkgo/internal/spec" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/containernode" Failer "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/types" ) var noneFlag = types.FlagTypeNone var focusedFlag = types.FlagTypeFocused var pendingFlag = types.FlagTypePending var _ = Describe("Spec", func() { var ( failer *Failer.Failer codeLocation types.CodeLocation nodesThatRan []string spec *Spec buffer *gbytes.Buffer ) newBody := func(text string, fail bool) func() { return func() { nodesThatRan = append(nodesThatRan, text) if fail { failer.Fail(text, codeLocation) } } } newIt := func(text string, flag types.FlagType, fail bool) *leafnodes.ItNode { return leafnodes.NewItNode(text, newBody(text, fail), flag, codeLocation, 0, failer, 0) } newItWithBody := func(text string, body interface{}) *leafnodes.ItNode { return leafnodes.NewItNode(text, body, noneFlag, codeLocation, 0, failer, 0) } newMeasure := func(text string, flag types.FlagType, fail bool, samples int) *leafnodes.MeasureNode { return leafnodes.NewMeasureNode(text, func(Benchmarker) { nodesThatRan = append(nodesThatRan, text) if fail { failer.Fail(text, codeLocation) } }, flag, codeLocation, samples, failer, 0) } newBef := func(text string, fail bool) leafnodes.BasicNode { return leafnodes.NewBeforeEachNode(newBody(text, fail), codeLocation, 0, failer, 0) } newAft := func(text string, fail bool) leafnodes.BasicNode { return leafnodes.NewAfterEachNode(newBody(text, fail), codeLocation, 0, failer, 0) } newJusBef := func(text string, fail bool) leafnodes.BasicNode { return leafnodes.NewJustBeforeEachNode(newBody(text, fail), codeLocation, 0, failer, 0) } newJusAft := func(text string, fail bool) leafnodes.BasicNode { return leafnodes.NewJustAfterEachNode(newBody(text, fail), codeLocation, 0, failer, 0) } newContainer := func(text string, flag types.FlagType, setupNodes ...leafnodes.BasicNode) *containernode.ContainerNode { c := containernode.New(text, flag, codeLocation) for _, node := range setupNodes { c.PushSetupNode(node) } return c } containers := func(containers ...*containernode.ContainerNode) []*containernode.ContainerNode { return containers } BeforeEach(func() { buffer = gbytes.NewBuffer() failer = Failer.New() codeLocation = codelocation.New(0) nodesThatRan = []string{} }) Describe("marking specs focused and pending", func() { It("should satisfy various caes", func() { cases := []struct { ContainerFlags []types.FlagType SubjectFlag types.FlagType Pending bool Focused bool }{ {[]types.FlagType{}, noneFlag, false, false}, {[]types.FlagType{}, focusedFlag, false, true}, {[]types.FlagType{}, pendingFlag, true, false}, {[]types.FlagType{noneFlag}, noneFlag, false, false}, {[]types.FlagType{focusedFlag}, noneFlag, false, true}, {[]types.FlagType{pendingFlag}, noneFlag, true, false}, {[]types.FlagType{noneFlag}, focusedFlag, false, true}, {[]types.FlagType{focusedFlag}, focusedFlag, false, true}, {[]types.FlagType{pendingFlag}, focusedFlag, true, true}, {[]types.FlagType{noneFlag}, pendingFlag, true, false}, {[]types.FlagType{focusedFlag}, pendingFlag, true, true}, {[]types.FlagType{pendingFlag}, pendingFlag, true, false}, {[]types.FlagType{focusedFlag, noneFlag}, noneFlag, false, true}, {[]types.FlagType{noneFlag, focusedFlag}, noneFlag, false, true}, {[]types.FlagType{pendingFlag, noneFlag}, noneFlag, true, false}, {[]types.FlagType{noneFlag, pendingFlag}, noneFlag, true, false}, {[]types.FlagType{focusedFlag, pendingFlag}, noneFlag, true, true}, } for i, c := range cases { subject := newIt("it node", c.SubjectFlag, false) containers := []*containernode.ContainerNode{} for _, flag := range c.ContainerFlags { containers = append(containers, newContainer("container", flag)) } spec := New(subject, containers, false) Ω(spec.Pending()).Should(Equal(c.Pending), "Case %d: %#v", i, c) Ω(spec.Focused()).Should(Equal(c.Focused), "Case %d: %#v", i, c) if c.Pending { Ω(spec.Summary("").State).Should(Equal(types.SpecStatePending)) } } }) }) Describe("Skip", func() { It("should be skipped", func() { spec := New(newIt("it node", noneFlag, false), containers(newContainer("container", noneFlag)), false) Ω(spec.Skipped()).Should(BeFalse()) spec.Skip() Ω(spec.Skipped()).Should(BeTrue()) Ω(spec.Summary("").State).Should(Equal(types.SpecStateSkipped)) }) }) Describe("IsMeasurement", func() { It("should be true if the subject is a measurement node", func() { spec := New(newIt("it node", noneFlag, false), containers(newContainer("container", noneFlag)), false) Ω(spec.IsMeasurement()).Should(BeFalse()) Ω(spec.Summary("").IsMeasurement).Should(BeFalse()) Ω(spec.Summary("").NumberOfSamples).Should(Equal(1)) spec = New(newMeasure("measure node", noneFlag, false, 10), containers(newContainer("container", noneFlag)), false) Ω(spec.IsMeasurement()).Should(BeTrue()) Ω(spec.Summary("").IsMeasurement).Should(BeTrue()) Ω(spec.Summary("").NumberOfSamples).Should(Equal(10)) }) }) Describe("Passed", func() { It("should pass when the subject passed", func() { spec := New(newIt("it node", noneFlag, false), containers(), false) spec.Run(buffer) Ω(spec.Passed()).Should(BeTrue()) Ω(spec.Failed()).Should(BeFalse()) Ω(spec.Summary("").State).Should(Equal(types.SpecStatePassed)) Ω(spec.Summary("").Failure).Should(BeZero()) }) }) Describe("Flaked", func() { It("should work if Run is called twice and gets different results", func() { i := 0 spec := New(newItWithBody("flaky it", func() { i++ if i == 1 { failer.Fail("oops", codeLocation) } }), containers(), false) spec.Run(buffer) Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(spec.Flaked()).Should(BeFalse()) Ω(spec.Summary("").State).Should(Equal(types.SpecStateFailed)) Ω(spec.Summary("").Failure.Message).Should(Equal("oops")) spec.Run(buffer) Ω(spec.Passed()).Should(BeTrue()) Ω(spec.Failed()).Should(BeFalse()) Ω(spec.Flaked()).Should(BeTrue()) Ω(spec.Summary("").State).Should(Equal(types.SpecStatePassed)) }) }) Describe("Failed", func() { It("should be failed if the failure was panic", func() { spec := New(newItWithBody("panicky it", func() { panic("bam") }), containers(), false) spec.Run(buffer) Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(spec.Summary("").State).Should(Equal(types.SpecStatePanicked)) Ω(spec.Summary("").Failure.Message).Should(Equal("Test Panicked")) Ω(spec.Summary("").Failure.ForwardedPanic).Should(Equal("bam")) }) It("should be failed if the failure was a timeout", func() { spec := New(newItWithBody("sleepy it", func(done Done) {}), containers(), false) spec.Run(buffer) Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(spec.Summary("").State).Should(Equal(types.SpecStateTimedOut)) Ω(spec.Summary("").Failure.Message).Should(Equal("Timed out")) }) It("should be failed if the failure was... a failure", func() { spec := New(newItWithBody("failing it", func() { failer.Fail("bam", codeLocation) }), containers(), false) spec.Run(buffer) Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(spec.Summary("").State).Should(Equal(types.SpecStateFailed)) Ω(spec.Summary("").Failure.Message).Should(Equal("bam")) }) }) Describe("Concatenated string", func() { It("should concatenate the texts of the containers and the subject", func() { spec := New( newIt("it node", noneFlag, false), containers( newContainer("outer container", noneFlag), newContainer("inner container", noneFlag), ), false, ) Ω(spec.ConcatenatedString()).Should(Equal("outer container inner container it node")) }) }) Describe("running it specs", func() { Context("with just an it", func() { Context("that succeeds", func() { It("should run the it and report on its success", func() { spec := New(newIt("it node", noneFlag, false), containers(), false) spec.Run(buffer) Ω(spec.Passed()).Should(BeTrue()) Ω(spec.Failed()).Should(BeFalse()) Ω(nodesThatRan).Should(Equal([]string{"it node"})) }) }) Context("that fails", func() { It("should run the it and report on its success", func() { spec := New(newIt("it node", noneFlag, true), containers(), false) spec.Run(buffer) Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(spec.Summary("").Failure.Message).Should(Equal("it node")) Ω(nodesThatRan).Should(Equal([]string{"it node"})) }) }) }) Context("with a full set of setup nodes", func() { var failingNodes map[string]bool BeforeEach(func() { failingNodes = map[string]bool{} }) JustBeforeEach(func() { spec = New( newIt("it node", noneFlag, failingNodes["it node"]), containers( newContainer("outer container", noneFlag, newBef("outer bef A", failingNodes["outer bef A"]), newBef("outer bef B", failingNodes["outer bef B"]), newJusBef("outer jusbef A", failingNodes["outer jusbef A"]), newJusBef("outer jusbef B", failingNodes["outer jusbef B"]), newJusAft("outer jusaft A", failingNodes["outer jusaft A"]), newJusAft("outer jusaft B", failingNodes["outer jusaft B"]), newAft("outer aft A", failingNodes["outer aft A"]), newAft("outer aft B", failingNodes["outer aft B"]), ), newContainer("inner container", noneFlag, newBef("inner bef A", failingNodes["inner bef A"]), newBef("inner bef B", failingNodes["inner bef B"]), newJusBef("inner jusbef A", failingNodes["inner jusbef A"]), newJusBef("inner jusbef B", failingNodes["inner jusbef B"]), newJusAft("inner jusaft A", failingNodes["inner jusaft A"]), newJusAft("inner jusaft B", failingNodes["inner jusaft B"]), newAft("inner aft A", failingNodes["inner aft A"]), newAft("inner aft B", failingNodes["inner aft B"]), ), ), false, ) spec.Run(buffer) }) Context("that all pass", func() { It("should walk through the nodes in the correct order", func() { Ω(spec.Passed()).Should(BeTrue()) Ω(spec.Failed()).Should(BeFalse()) Ω(nodesThatRan).Should(Equal([]string{ "outer bef A", "outer bef B", "inner bef A", "inner bef B", "outer jusbef A", "outer jusbef B", "inner jusbef A", "inner jusbef B", "it node", "inner jusaft A", "inner jusaft B", "outer jusaft A", "outer jusaft B", "inner aft A", "inner aft B", "outer aft A", "outer aft B", })) }) }) Context("when the subject fails", func() { BeforeEach(func() { failingNodes["it node"] = true }) It("should run the afters", func() { Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(nodesThatRan).Should(Equal([]string{ "outer bef A", "outer bef B", "inner bef A", "inner bef B", "outer jusbef A", "outer jusbef B", "inner jusbef A", "inner jusbef B", "it node", "inner jusaft A", "inner jusaft B", "outer jusaft A", "outer jusaft B", "inner aft A", "inner aft B", "outer aft A", "outer aft B", })) Ω(spec.Summary("").Failure.Message).Should(Equal("it node")) }) }) Context("when an inner before fails", func() { BeforeEach(func() { failingNodes["inner bef A"] = true }) It("should not run any other befores, but it should run the subsequent afters", func() { Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(nodesThatRan).Should(Equal([]string{ "outer bef A", "outer bef B", "inner bef A", "inner jusaft A", "inner jusaft B", "outer jusaft A", "outer jusaft B", "inner aft A", "inner aft B", "outer aft A", "outer aft B", })) Ω(spec.Summary("").Failure.Message).Should(Equal("inner bef A")) }) }) Context("when an outer before fails", func() { BeforeEach(func() { failingNodes["outer bef B"] = true }) It("should not run any other befores, but it should run the subsequent afters", func() { Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(nodesThatRan).Should(Equal([]string{ "outer bef A", "outer bef B", "outer jusaft A", "outer jusaft B", "outer aft A", "outer aft B", })) Ω(spec.Summary("").Failure.Message).Should(Equal("outer bef B")) }) }) Context("when an after fails", func() { BeforeEach(func() { failingNodes["inner aft B"] = true }) It("should run all other afters, but mark the test as failed", func() { Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(nodesThatRan).Should(Equal([]string{ "outer bef A", "outer bef B", "inner bef A", "inner bef B", "outer jusbef A", "outer jusbef B", "inner jusbef A", "inner jusbef B", "it node", "inner jusaft A", "inner jusaft B", "outer jusaft A", "outer jusaft B", "inner aft A", "inner aft B", "outer aft A", "outer aft B", })) Ω(spec.Summary("").Failure.Message).Should(Equal("inner aft B")) }) }) Context("when a just before each fails", func() { BeforeEach(func() { failingNodes["outer jusbef B"] = true }) It("should run the afters, but not the subject", func() { Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(nodesThatRan).Should(Equal([]string{ "outer bef A", "outer bef B", "inner bef A", "inner bef B", "outer jusbef A", "outer jusbef B", "inner jusaft A", "inner jusaft B", "outer jusaft A", "outer jusaft B", "inner aft A", "inner aft B", "outer aft A", "outer aft B", })) Ω(spec.Summary("").Failure.Message).Should(Equal("outer jusbef B")) }) }) Context("when a just after each fails", func() { BeforeEach(func() { failingNodes["outer jusaft A"] = true }) It("should run all other afters, but mark the test as failed", func() { Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(nodesThatRan).Should(Equal([]string{ "outer bef A", "outer bef B", "inner bef A", "inner bef B", "outer jusbef A", "outer jusbef B", "inner jusbef A", "inner jusbef B", "it node", "inner jusaft A", "inner jusaft B", "outer jusaft A", "outer jusaft B", "inner aft A", "inner aft B", "outer aft A", "outer aft B", })) Ω(spec.Summary("").Failure.Message).Should(Equal("outer jusaft A")) }) }) Context("when an after fails after an earlier node has failed", func() { BeforeEach(func() { failingNodes["it node"] = true failingNodes["inner aft B"] = true }) It("should record the earlier failure", func() { Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(nodesThatRan).Should(Equal([]string{ "outer bef A", "outer bef B", "inner bef A", "inner bef B", "outer jusbef A", "outer jusbef B", "inner jusbef A", "inner jusbef B", "it node", "inner jusaft A", "inner jusaft B", "outer jusaft A", "outer jusaft B", "inner aft A", "inner aft B", "outer aft A", "outer aft B", })) Ω(spec.Summary("").Failure.Message).Should(Equal("it node")) }) }) }) }) Describe("running measurement specs", func() { Context("when the measurement succeeds", func() { It("should run N samples", func() { spec = New( newMeasure("measure node", noneFlag, false, 3), containers( newContainer("container", noneFlag, newBef("bef A", false), newJusBef("jusbef A", false), newJusAft("jusaft A", false), newAft("aft A", false), ), ), false, ) spec.Run(buffer) Ω(spec.Passed()).Should(BeTrue()) Ω(spec.Failed()).Should(BeFalse()) Ω(nodesThatRan).Should(Equal([]string{ "bef A", "jusbef A", "measure node", "jusaft A", "aft A", "bef A", "jusbef A", "measure node", "jusaft A", "aft A", "bef A", "jusbef A", "measure node", "jusaft A", "aft A", })) }) }) Context("when the measurement fails", func() { It("should bail after the failure occurs", func() { spec = New( newMeasure("measure node", noneFlag, true, 3), containers( newContainer("container", noneFlag, newBef("bef A", false), newJusBef("jusbef A", false), newJusAft("jusaft A", false), newAft("aft A", false), ), ), false, ) spec.Run(buffer) Ω(spec.Passed()).Should(BeFalse()) Ω(spec.Failed()).Should(BeTrue()) Ω(nodesThatRan).Should(Equal([]string{ "bef A", "jusbef A", "measure node", "jusaft A", "aft A", })) }) }) }) Describe("Summary", func() { var ( subjectCodeLocation types.CodeLocation outerContainerCodeLocation types.CodeLocation innerContainerCodeLocation types.CodeLocation summary *types.SpecSummary ) BeforeEach(func() { subjectCodeLocation = codelocation.New(0) outerContainerCodeLocation = codelocation.New(0) innerContainerCodeLocation = codelocation.New(0) spec = New( leafnodes.NewItNode("it node", func() { time.Sleep(10 * time.Millisecond) }, noneFlag, subjectCodeLocation, 0, failer, 0), containers( containernode.New("outer container", noneFlag, outerContainerCodeLocation), containernode.New("inner container", noneFlag, innerContainerCodeLocation), ), false, ) spec.Run(buffer) Ω(spec.Passed()).Should(BeTrue()) summary = spec.Summary("suite id") }) It("should have the suite id", func() { Ω(summary.SuiteID).Should(Equal("suite id")) }) It("should have the component texts and code locations", func() { Ω(summary.ComponentTexts).Should(Equal([]string{"outer container", "inner container", "it node"})) Ω(summary.ComponentCodeLocations).Should(Equal([]types.CodeLocation{outerContainerCodeLocation, innerContainerCodeLocation, subjectCodeLocation})) }) It("should have a runtime", func() { Ω(summary.RunTime).Should(BeNumerically(">=", 10*time.Millisecond)) }) It("should have a runtime which remains consistent after spec run", func() { totalRunTime := summary.RunTime Ω(totalRunTime).Should(BeNumerically(">=", 10*time.Millisecond)) Consistently(func() time.Duration { return spec.Summary("suite id").RunTime }).Should(Equal(totalRunTime)) }) It("should not be a measurement, or have a measurement summary", func() { Ω(summary.IsMeasurement).Should(BeFalse()) Ω(summary.Measurements).Should(BeEmpty()) }) }) Describe("Summaries for measurements", func() { var summary *types.SpecSummary BeforeEach(func() { spec = New(leafnodes.NewMeasureNode("measure node", func(b Benchmarker) { b.RecordValue("a value", 7, "some info") b.RecordValueWithPrecision("another value", 8, "ns", 5, "more info") }, noneFlag, codeLocation, 4, failer, 0), containers(), false) spec.Run(buffer) Ω(spec.Passed()).Should(BeTrue()) summary = spec.Summary("suite id") }) It("should include the number of samples", func() { Ω(summary.NumberOfSamples).Should(Equal(4)) }) It("should be a measurement", func() { Ω(summary.IsMeasurement).Should(BeTrue()) }) It("should have the measurements report", func() { Ω(summary.Measurements).Should(HaveKey("a value")) report := summary.Measurements["a value"] Ω(report.Name).Should(Equal("a value")) Ω(report.Info).Should(Equal("some info")) Ω(report.Results).Should(Equal([]float64{7, 7, 7, 7})) Ω(summary.Measurements).Should(HaveKey("another value")) report = summary.Measurements["another value"] Ω(report.Name).Should(Equal("another value")) Ω(report.Info).Should(Equal("more info")) Ω(report.Results).Should(Equal([]float64{8, 8, 8, 8})) Ω(report.Units).Should(Equal("ns")) Ω(report.Precision).Should(Equal(5)) }) }) Describe("When told to emit progress", func() { It("should emit progress to the writer as it runs Befores, JustBefores, Afters, and Its", func() { spec = New( newIt("it node", noneFlag, false), containers( newContainer("outer container", noneFlag, newBef("outer bef A", false), newJusBef("outer jusbef A", false), newJusAft("outer jusaft A", false), newAft("outer aft A", false), ), newContainer("inner container", noneFlag, newBef("inner bef A", false), newJusBef("inner jusbef A", false), newJusAft("inner jusaft A", false), newAft("inner aft A", false), ), ), true, ) spec.Run(buffer) Ω(buffer).Should(gbytes.Say(`\[BeforeEach\] outer container`)) Ω(buffer).Should(gbytes.Say(`\[BeforeEach\] inner container`)) Ω(buffer).Should(gbytes.Say(`\[JustBeforeEach\] outer container`)) Ω(buffer).Should(gbytes.Say(`\[JustBeforeEach\] inner container`)) Ω(buffer).Should(gbytes.Say(`\[It\] it node`)) Ω(buffer).Should(gbytes.Say(`\[JustAfterEach\] inner container`)) Ω(buffer).Should(gbytes.Say(`\[JustAfterEach\] outer container`)) Ω(buffer).Should(gbytes.Say(`\[AfterEach\] inner container`)) Ω(buffer).Should(gbytes.Say(`\[AfterEach\] outer container`)) }) It("should emit progress to the writer as it runs Befores, JustBefores, JustAfters, Afters, and Measures", func() { spec = New( newMeasure("measure node", noneFlag, false, 2), containers(), true, ) spec.Run(buffer) Ω(buffer).Should(gbytes.Say(`\[Measure\] measure node`)) Ω(buffer).Should(gbytes.Say(`\[Measure\] measure node`)) }) }) }) ginkgo-1.14.2/internal/spec/specs.go000066400000000000000000000054701374111457300173030ustar00rootroot00000000000000package spec import ( "math/rand" "regexp" "sort" ) type Specs struct { specs []*Spec names []string hasProgrammaticFocus bool RegexScansFilePath bool } func NewSpecs(specs []*Spec) *Specs { names := make([]string, len(specs)) for i, spec := range specs { names[i] = spec.ConcatenatedString() } return &Specs{ specs: specs, names: names, } } func (e *Specs) Specs() []*Spec { return e.specs } func (e *Specs) HasProgrammaticFocus() bool { return e.hasProgrammaticFocus } func (e *Specs) Shuffle(r *rand.Rand) { sort.Sort(e) permutation := r.Perm(len(e.specs)) shuffledSpecs := make([]*Spec, len(e.specs)) names := make([]string, len(e.specs)) for i, j := range permutation { shuffledSpecs[i] = e.specs[j] names[i] = e.names[j] } e.specs = shuffledSpecs e.names = names } func (e *Specs) ApplyFocus(description string, focusString string, skipString string) { if focusString == "" && skipString == "" { e.applyProgrammaticFocus() } else { e.applyRegExpFocusAndSkip(description, focusString, skipString) } } func (e *Specs) applyProgrammaticFocus() { e.hasProgrammaticFocus = false for _, spec := range e.specs { if spec.Focused() && !spec.Pending() { e.hasProgrammaticFocus = true break } } if e.hasProgrammaticFocus { for _, spec := range e.specs { if !spec.Focused() { spec.Skip() } } } } // toMatch returns a byte[] to be used by regex matchers. When adding new behaviours to the matching function, // this is the place which we append to. func (e *Specs) toMatch(description string, i int) []byte { if i > len(e.names) { return nil } if e.RegexScansFilePath { return []byte( description + " " + e.names[i] + " " + e.specs[i].subject.CodeLocation().FileName) } else { return []byte( description + " " + e.names[i]) } } func (e *Specs) applyRegExpFocusAndSkip(description string, focusString string, skipString string) { var focusFilter *regexp.Regexp if focusString != "" { focusFilter = regexp.MustCompile(focusString) } var skipFilter *regexp.Regexp if skipString != "" { skipFilter = regexp.MustCompile(skipString) } for i, spec := range e.specs { matchesFocus := true matchesSkip := false toMatch := e.toMatch(description, i) if focusFilter != nil { matchesFocus = focusFilter.Match(toMatch) } if skipFilter != nil { matchesSkip = skipFilter.Match(toMatch) } if !matchesFocus || matchesSkip { spec.Skip() } } } func (e *Specs) SkipMeasurements() { for _, spec := range e.specs { if spec.IsMeasurement() { spec.Skip() } } } //sort.Interface func (e *Specs) Len() int { return len(e.specs) } func (e *Specs) Less(i, j int) bool { return e.names[i] < e.names[j] } func (e *Specs) Swap(i, j int) { e.names[i], e.names[j] = e.names[j], e.names[i] e.specs[i], e.specs[j] = e.specs[j], e.specs[i] } ginkgo-1.14.2/internal/spec/specs_test.go000066400000000000000000000207501374111457300203400ustar00rootroot00000000000000package spec_test import ( "math/rand" . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/spec" . "github.com/onsi/gomega" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/containernode" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/types" ) var _ = Describe("Specs", func() { var specs *Specs newSpec := func(text string, flag types.FlagType) *Spec { subject := leafnodes.NewItNode(text, func() {}, flag, codelocation.New(0), 0, nil, 0) return New(subject, []*containernode.ContainerNode{}, false) } newMeasureSpec := func(text string, flag types.FlagType) *Spec { subject := leafnodes.NewMeasureNode(text, func(Benchmarker) {}, flag, codelocation.New(0), 0, nil, 0) return New(subject, []*containernode.ContainerNode{}, false) } newSpecs := func(args ...interface{}) *Specs { specs := []*Spec{} for index := 0; index < len(args)-1; index += 2 { specs = append(specs, newSpec(args[index].(string), args[index+1].(types.FlagType))) } return NewSpecs(specs) } specTexts := func(specs *Specs) []string { texts := []string{} for _, spec := range specs.Specs() { texts = append(texts, spec.ConcatenatedString()) } return texts } willRunTexts := func(specs *Specs) []string { texts := []string{} for _, spec := range specs.Specs() { if !(spec.Skipped() || spec.Pending()) { texts = append(texts, spec.ConcatenatedString()) } } return texts } skippedTexts := func(specs *Specs) []string { texts := []string{} for _, spec := range specs.Specs() { if spec.Skipped() { texts = append(texts, spec.ConcatenatedString()) } } return texts } pendingTexts := func(specs *Specs) []string { texts := []string{} for _, spec := range specs.Specs() { if spec.Pending() { texts = append(texts, spec.ConcatenatedString()) } } return texts } Describe("Shuffling specs", func() { It("should shuffle the specs using the passed in randomizer", func() { specs17 := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag) specs17.Shuffle(rand.New(rand.NewSource(17))) texts17 := specTexts(specs17) specs17Again := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag) specs17Again.Shuffle(rand.New(rand.NewSource(17))) texts17Again := specTexts(specs17Again) specs15 := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag) specs15.Shuffle(rand.New(rand.NewSource(15))) texts15 := specTexts(specs15) specsUnshuffled := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag) textsUnshuffled := specTexts(specsUnshuffled) Ω(textsUnshuffled).Should(Equal([]string{"C", "A", "B"})) Ω(texts17).Should(Equal(texts17Again)) Ω(texts17).ShouldNot(Equal(texts15)) Ω(texts17).ShouldNot(Equal(textsUnshuffled)) Ω(texts15).ShouldNot(Equal(textsUnshuffled)) Ω(texts17).Should(HaveLen(3)) Ω(texts17).Should(ContainElement("A")) Ω(texts17).Should(ContainElement("B")) Ω(texts17).Should(ContainElement("C")) Ω(texts15).Should(HaveLen(3)) Ω(texts15).Should(ContainElement("A")) Ω(texts15).Should(ContainElement("B")) Ω(texts15).Should(ContainElement("C")) }) }) Describe("with no programmatic focus", func() { BeforeEach(func() { specs = newSpecs("A1", noneFlag, "A2", noneFlag, "B1", noneFlag, "B2", pendingFlag) specs.ApplyFocus("", "", "") }) It("should not report as having programmatic specs", func() { Ω(specs.HasProgrammaticFocus()).Should(BeFalse()) }) }) Describe("Applying focus/skip", func() { var description, focusString, skipString string BeforeEach(func() { description, focusString, skipString = "", "", "" }) JustBeforeEach(func() { specs = newSpecs("A1", focusedFlag, "A2", noneFlag, "B1", focusedFlag, "B2", pendingFlag) specs.ApplyFocus(description, focusString, skipString) }) Context("with neither a focus string nor a skip string", func() { It("should apply the programmatic focus", func() { Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "B1"})) Ω(skippedTexts(specs)).Should(Equal([]string{"A2", "B2"})) Ω(pendingTexts(specs)).Should(BeEmpty()) }) It("should report as having programmatic specs", func() { Ω(specs.HasProgrammaticFocus()).Should(BeTrue()) }) }) Context("with a focus regexp", func() { BeforeEach(func() { focusString = "A" }) It("should override the programmatic focus", func() { Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "A2"})) Ω(skippedTexts(specs)).Should(Equal([]string{"B1", "B2"})) Ω(pendingTexts(specs)).Should(BeEmpty()) }) It("should not report as having programmatic specs", func() { Ω(specs.HasProgrammaticFocus()).Should(BeFalse()) }) }) Context("with a focus regexp", func() { BeforeEach(func() { focusString = "B" }) It("should not override any pendings", func() { Ω(willRunTexts(specs)).Should(Equal([]string{"B1"})) Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2"})) Ω(pendingTexts(specs)).Should(Equal([]string{"B2"})) }) }) Context("with a description", func() { BeforeEach(func() { description = "C" focusString = "C" }) It("should include the description in the focus determination", func() { Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "A2", "B1"})) Ω(skippedTexts(specs)).Should(BeEmpty()) Ω(pendingTexts(specs)).Should(Equal([]string{"B2"})) }) }) Context("with a description", func() { BeforeEach(func() { description = "C" skipString = "C" }) It("should include the description in the focus determination", func() { Ω(willRunTexts(specs)).Should(BeEmpty()) Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2", "B1", "B2"})) Ω(pendingTexts(specs)).Should(BeEmpty()) }) }) Context("with a skip regexp", func() { BeforeEach(func() { skipString = "A" }) It("should override the programmatic focus", func() { Ω(willRunTexts(specs)).Should(Equal([]string{"B1"})) Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2"})) Ω(pendingTexts(specs)).Should(Equal([]string{"B2"})) }) It("should not report as having programmatic specs", func() { Ω(specs.HasProgrammaticFocus()).Should(BeFalse()) }) }) Context("with both a focus and a skip regexp", func() { BeforeEach(func() { focusString = "1" skipString = "B" }) It("should AND the two", func() { Ω(willRunTexts(specs)).Should(Equal([]string{"A1"})) Ω(skippedTexts(specs)).Should(Equal([]string{"A2", "B1", "B2"})) Ω(pendingTexts(specs)).Should(BeEmpty()) }) It("should not report as having programmatic specs", func() { Ω(specs.HasProgrammaticFocus()).Should(BeFalse()) }) }) }) Describe("With a focused spec within a pending context and a pending spec within a focused context", func() { BeforeEach(func() { pendingInFocused := New( leafnodes.NewItNode("PendingInFocused", func() {}, pendingFlag, codelocation.New(0), 0, nil, 0), []*containernode.ContainerNode{ containernode.New("", focusedFlag, codelocation.New(0)), }, false) focusedInPending := New( leafnodes.NewItNode("FocusedInPending", func() {}, focusedFlag, codelocation.New(0), 0, nil, 0), []*containernode.ContainerNode{ containernode.New("", pendingFlag, codelocation.New(0)), }, false) specs = NewSpecs([]*Spec{ newSpec("A", noneFlag), newSpec("B", noneFlag), pendingInFocused, focusedInPending, }) specs.ApplyFocus("", "", "") }) It("should not have a programmatic focus and should run all tests", func() { Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B"})) Ω(skippedTexts(specs)).Should(BeEmpty()) Ω(pendingTexts(specs)).Should(ConsistOf(ContainSubstring("PendingInFocused"), ContainSubstring("FocusedInPending"))) }) }) Describe("skipping measurements", func() { BeforeEach(func() { specs = NewSpecs([]*Spec{ newSpec("A", noneFlag), newSpec("B", noneFlag), newSpec("C", pendingFlag), newMeasureSpec("measurementA", noneFlag), newMeasureSpec("measurementB", pendingFlag), }) }) It("should skip measurements", func() { Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B", "measurementA"})) Ω(skippedTexts(specs)).Should(BeEmpty()) Ω(pendingTexts(specs)).Should(Equal([]string{"C", "measurementB"})) specs.SkipMeasurements() Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B"})) Ω(skippedTexts(specs)).Should(Equal([]string{"measurementA", "measurementB"})) Ω(pendingTexts(specs)).Should(Equal([]string{"C"})) }) }) }) ginkgo-1.14.2/internal/spec_iterator/000077500000000000000000000000001374111457300175425ustar00rootroot00000000000000ginkgo-1.14.2/internal/spec_iterator/index_computer.go000066400000000000000000000032471374111457300231240ustar00rootroot00000000000000package spec_iterator func ParallelizedIndexRange(length int, parallelTotal int, parallelNode int) (startIndex int, count int) { if length == 0 { return 0, 0 } // We have more nodes than tests. Trivial case. if parallelTotal >= length { if parallelNode > length { return 0, 0 } else { return parallelNode - 1, 1 } } // This is the minimum amount of tests that a node will be required to run minTestsPerNode := length / parallelTotal // This is the maximum amount of tests that a node will be required to run // The algorithm guarantees that this would be equal to at least the minimum amount // and at most one more maxTestsPerNode := minTestsPerNode if length%parallelTotal != 0 { maxTestsPerNode++ } // Number of nodes that will have to run the maximum amount of tests per node numMaxLoadNodes := length % parallelTotal // Number of nodes that precede the current node and will have to run the maximum amount of tests per node var numPrecedingMaxLoadNodes int if parallelNode > numMaxLoadNodes { numPrecedingMaxLoadNodes = numMaxLoadNodes } else { numPrecedingMaxLoadNodes = parallelNode - 1 } // Number of nodes that precede the current node and will have to run the minimum amount of tests per node var numPrecedingMinLoadNodes int if parallelNode <= numMaxLoadNodes { numPrecedingMinLoadNodes = 0 } else { numPrecedingMinLoadNodes = parallelNode - numMaxLoadNodes - 1 } // Evaluate the test start index and number of tests to run startIndex = numPrecedingMaxLoadNodes*maxTestsPerNode + numPrecedingMinLoadNodes*minTestsPerNode if parallelNode > numMaxLoadNodes { count = minTestsPerNode } else { count = maxTestsPerNode } return } ginkgo-1.14.2/internal/spec_iterator/index_computer_test.go000066400000000000000000000105331374111457300241570ustar00rootroot00000000000000package spec_iterator_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/spec_iterator" . "github.com/onsi/gomega" ) var _ = Describe("ParallelizedIndexRange", func() { var startIndex, count int It("should return the correct index range for 4 tests on 2 nodes", func() { startIndex, count = ParallelizedIndexRange(4, 2, 1) Ω(startIndex).Should(Equal(0)) Ω(count).Should(Equal(2)) startIndex, count = ParallelizedIndexRange(4, 2, 2) Ω(startIndex).Should(Equal(2)) Ω(count).Should(Equal(2)) }) It("should return the correct index range for 5 tests on 2 nodes", func() { startIndex, count = ParallelizedIndexRange(5, 2, 1) Ω(startIndex).Should(Equal(0)) Ω(count).Should(Equal(3)) startIndex, count = ParallelizedIndexRange(5, 2, 2) Ω(startIndex).Should(Equal(3)) Ω(count).Should(Equal(2)) }) It("should return the correct index range for 5 tests on 3 nodes", func() { startIndex, count = ParallelizedIndexRange(5, 3, 1) Ω(startIndex).Should(Equal(0)) Ω(count).Should(Equal(2)) startIndex, count = ParallelizedIndexRange(5, 3, 2) Ω(startIndex).Should(Equal(2)) Ω(count).Should(Equal(2)) startIndex, count = ParallelizedIndexRange(5, 3, 3) Ω(startIndex).Should(Equal(4)) Ω(count).Should(Equal(1)) }) It("should return the correct index range for 5 tests on 4 nodes", func() { startIndex, count = ParallelizedIndexRange(5, 4, 1) Ω(startIndex).Should(Equal(0)) Ω(count).Should(Equal(2)) startIndex, count = ParallelizedIndexRange(5, 4, 2) Ω(startIndex).Should(Equal(2)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 4, 3) Ω(startIndex).Should(Equal(3)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 4, 4) Ω(startIndex).Should(Equal(4)) Ω(count).Should(Equal(1)) }) It("should return the correct index range for 5 tests on 5 nodes", func() { startIndex, count = ParallelizedIndexRange(5, 5, 1) Ω(startIndex).Should(Equal(0)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 5, 2) Ω(startIndex).Should(Equal(1)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 5, 3) Ω(startIndex).Should(Equal(2)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 5, 4) Ω(startIndex).Should(Equal(3)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 5, 5) Ω(startIndex).Should(Equal(4)) Ω(count).Should(Equal(1)) }) It("should return the correct index range for 5 tests on 6 nodes", func() { startIndex, count = ParallelizedIndexRange(5, 6, 1) Ω(startIndex).Should(Equal(0)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 6, 2) Ω(startIndex).Should(Equal(1)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 6, 3) Ω(startIndex).Should(Equal(2)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 6, 4) Ω(startIndex).Should(Equal(3)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 6, 5) Ω(startIndex).Should(Equal(4)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(5, 6, 6) Ω(count).Should(Equal(0)) }) It("should return the correct index range for 5 tests on 7 nodes", func() { startIndex, count = ParallelizedIndexRange(5, 7, 6) Ω(count).Should(Equal(0)) startIndex, count = ParallelizedIndexRange(5, 7, 7) Ω(count).Should(Equal(0)) }) It("should return the correct index range for 11 tests on 7 nodes", func() { startIndex, count = ParallelizedIndexRange(11, 7, 1) Ω(startIndex).Should(Equal(0)) Ω(count).Should(Equal(2)) startIndex, count = ParallelizedIndexRange(11, 7, 2) Ω(startIndex).Should(Equal(2)) Ω(count).Should(Equal(2)) startIndex, count = ParallelizedIndexRange(11, 7, 3) Ω(startIndex).Should(Equal(4)) Ω(count).Should(Equal(2)) startIndex, count = ParallelizedIndexRange(11, 7, 4) Ω(startIndex).Should(Equal(6)) Ω(count).Should(Equal(2)) startIndex, count = ParallelizedIndexRange(11, 7, 5) Ω(startIndex).Should(Equal(8)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(11, 7, 6) Ω(startIndex).Should(Equal(9)) Ω(count).Should(Equal(1)) startIndex, count = ParallelizedIndexRange(11, 7, 7) Ω(startIndex).Should(Equal(10)) Ω(count).Should(Equal(1)) }) }) ginkgo-1.14.2/internal/spec_iterator/parallel_spec_iterator.go000066400000000000000000000021751374111457300246150ustar00rootroot00000000000000package spec_iterator import ( "encoding/json" "fmt" "net/http" "github.com/onsi/ginkgo/internal/spec" ) type ParallelIterator struct { specs []*spec.Spec host string client *http.Client } func NewParallelIterator(specs []*spec.Spec, host string) *ParallelIterator { return &ParallelIterator{ specs: specs, host: host, client: &http.Client{}, } } func (s *ParallelIterator) Next() (*spec.Spec, error) { resp, err := s.client.Get(s.host + "/counter") if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) } var counter Counter err = json.NewDecoder(resp.Body).Decode(&counter) if err != nil { return nil, err } if counter.Index >= len(s.specs) { return nil, ErrClosed } return s.specs[counter.Index], nil } func (s *ParallelIterator) NumberOfSpecsPriorToIteration() int { return len(s.specs) } func (s *ParallelIterator) NumberOfSpecsToProcessIfKnown() (int, bool) { return -1, false } func (s *ParallelIterator) NumberOfSpecsThatWillBeRunIfKnown() (int, bool) { return -1, false } ginkgo-1.14.2/internal/spec_iterator/parallel_spec_iterator_test.go000066400000000000000000000056731374111457300256620ustar00rootroot00000000000000package spec_iterator_test import ( "net/http" . "github.com/onsi/ginkgo/internal/spec_iterator" "github.com/onsi/gomega/ghttp" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/containernode" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/internal/spec" "github.com/onsi/ginkgo/types" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("ParallelSpecIterator", func() { var specs []*spec.Spec var iterator *ParallelIterator var server *ghttp.Server newSpec := func(text string, flag types.FlagType) *spec.Spec { subject := leafnodes.NewItNode(text, func() {}, flag, codelocation.New(0), 0, nil, 0) return spec.New(subject, []*containernode.ContainerNode{}, false) } BeforeEach(func() { specs = []*spec.Spec{ newSpec("A", types.FlagTypePending), newSpec("B", types.FlagTypeNone), newSpec("C", types.FlagTypeNone), newSpec("D", types.FlagTypeNone), } specs[3].Skip() server = ghttp.NewServer() iterator = NewParallelIterator(specs, "http://"+server.Addr()) }) AfterEach(func() { server.Close() }) It("should report the total number of specs", func() { Ω(iterator.NumberOfSpecsPriorToIteration()).Should(Equal(4)) }) It("should not report the number to be processed", func() { n, known := iterator.NumberOfSpecsToProcessIfKnown() Ω(n).Should(Equal(-1)) Ω(known).Should(BeFalse()) }) It("should not report the number that will be run", func() { n, known := iterator.NumberOfSpecsThatWillBeRunIfKnown() Ω(n).Should(Equal(-1)) Ω(known).Should(BeFalse()) }) Describe("iterating", func() { Describe("when the server returns well-formed responses", func() { BeforeEach(func() { server.AppendHandlers( ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 0}), ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 1}), ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 3}), ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 4}), ) }) It("should return the specs in question", func() { Ω(iterator.Next()).Should(Equal(specs[0])) Ω(iterator.Next()).Should(Equal(specs[1])) Ω(iterator.Next()).Should(Equal(specs[3])) spec, err := iterator.Next() Ω(spec).Should(BeNil()) Ω(err).Should(MatchError(ErrClosed)) }) }) Describe("when the server 404s", func() { BeforeEach(func() { server.AppendHandlers( ghttp.RespondWith(http.StatusNotFound, ""), ) }) It("should return an error", func() { spec, err := iterator.Next() Ω(spec).Should(BeNil()) Ω(err).Should(MatchError("unexpected status code 404")) }) }) Describe("when the server returns gibberish", func() { BeforeEach(func() { server.AppendHandlers( ghttp.RespondWith(http.StatusOK, "ß"), ) }) It("should error", func() { spec, err := iterator.Next() Ω(spec).Should(BeNil()) Ω(err).ShouldNot(BeNil()) }) }) }) }) ginkgo-1.14.2/internal/spec_iterator/serial_spec_iterator.go000066400000000000000000000014561374111457300243010ustar00rootroot00000000000000package spec_iterator import ( "github.com/onsi/ginkgo/internal/spec" ) type SerialIterator struct { specs []*spec.Spec index int } func NewSerialIterator(specs []*spec.Spec) *SerialIterator { return &SerialIterator{ specs: specs, index: 0, } } func (s *SerialIterator) Next() (*spec.Spec, error) { if s.index >= len(s.specs) { return nil, ErrClosed } spec := s.specs[s.index] s.index += 1 return spec, nil } func (s *SerialIterator) NumberOfSpecsPriorToIteration() int { return len(s.specs) } func (s *SerialIterator) NumberOfSpecsToProcessIfKnown() (int, bool) { return len(s.specs), true } func (s *SerialIterator) NumberOfSpecsThatWillBeRunIfKnown() (int, bool) { count := 0 for _, s := range s.specs { if !s.Skipped() && !s.Pending() { count += 1 } } return count, true } ginkgo-1.14.2/internal/spec_iterator/serial_spec_iterator_test.go000066400000000000000000000034171374111457300253370ustar00rootroot00000000000000package spec_iterator_test import ( . "github.com/onsi/ginkgo/internal/spec_iterator" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/containernode" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/internal/spec" "github.com/onsi/ginkgo/types" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("SerialSpecIterator", func() { var specs []*spec.Spec var iterator *SerialIterator newSpec := func(text string, flag types.FlagType) *spec.Spec { subject := leafnodes.NewItNode(text, func() {}, flag, codelocation.New(0), 0, nil, 0) return spec.New(subject, []*containernode.ContainerNode{}, false) } BeforeEach(func() { specs = []*spec.Spec{ newSpec("A", types.FlagTypePending), newSpec("B", types.FlagTypeNone), newSpec("C", types.FlagTypeNone), newSpec("D", types.FlagTypeNone), } specs[3].Skip() iterator = NewSerialIterator(specs) }) It("should report the total number of specs", func() { Ω(iterator.NumberOfSpecsPriorToIteration()).Should(Equal(4)) }) It("should report the number to be processed", func() { n, known := iterator.NumberOfSpecsToProcessIfKnown() Ω(n).Should(Equal(4)) Ω(known).Should(BeTrue()) }) It("should report the number that will be run", func() { n, known := iterator.NumberOfSpecsThatWillBeRunIfKnown() Ω(n).Should(Equal(2)) Ω(known).Should(BeTrue()) }) Describe("iterating", func() { It("should return the specs in order", func() { Ω(iterator.Next()).Should(Equal(specs[0])) Ω(iterator.Next()).Should(Equal(specs[1])) Ω(iterator.Next()).Should(Equal(specs[2])) Ω(iterator.Next()).Should(Equal(specs[3])) spec, err := iterator.Next() Ω(spec).Should(BeNil()) Ω(err).Should(MatchError(ErrClosed)) }) }) }) ginkgo-1.14.2/internal/spec_iterator/sharded_parallel_spec_iterator.go000066400000000000000000000020671374111457300263070ustar00rootroot00000000000000package spec_iterator import "github.com/onsi/ginkgo/internal/spec" type ShardedParallelIterator struct { specs []*spec.Spec index int maxIndex int } func NewShardedParallelIterator(specs []*spec.Spec, total int, node int) *ShardedParallelIterator { startIndex, count := ParallelizedIndexRange(len(specs), total, node) return &ShardedParallelIterator{ specs: specs, index: startIndex, maxIndex: startIndex + count, } } func (s *ShardedParallelIterator) Next() (*spec.Spec, error) { if s.index >= s.maxIndex { return nil, ErrClosed } spec := s.specs[s.index] s.index += 1 return spec, nil } func (s *ShardedParallelIterator) NumberOfSpecsPriorToIteration() int { return len(s.specs) } func (s *ShardedParallelIterator) NumberOfSpecsToProcessIfKnown() (int, bool) { return s.maxIndex - s.index, true } func (s *ShardedParallelIterator) NumberOfSpecsThatWillBeRunIfKnown() (int, bool) { count := 0 for i := s.index; i < s.maxIndex; i += 1 { if !s.specs[i].Skipped() && !s.specs[i].Pending() { count += 1 } } return count, true } ginkgo-1.14.2/internal/spec_iterator/sharded_parallel_spec_iterator_test.go000066400000000000000000000033221374111457300273410ustar00rootroot00000000000000package spec_iterator_test import ( . "github.com/onsi/ginkgo/internal/spec_iterator" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/containernode" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/internal/spec" "github.com/onsi/ginkgo/types" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("ShardedParallelSpecIterator", func() { var specs []*spec.Spec var iterator *ShardedParallelIterator newSpec := func(text string, flag types.FlagType) *spec.Spec { subject := leafnodes.NewItNode(text, func() {}, flag, codelocation.New(0), 0, nil, 0) return spec.New(subject, []*containernode.ContainerNode{}, false) } BeforeEach(func() { specs = []*spec.Spec{ newSpec("A", types.FlagTypePending), newSpec("B", types.FlagTypeNone), newSpec("C", types.FlagTypeNone), newSpec("D", types.FlagTypeNone), } specs[3].Skip() iterator = NewShardedParallelIterator(specs, 2, 1) }) It("should report the total number of specs", func() { Ω(iterator.NumberOfSpecsPriorToIteration()).Should(Equal(4)) }) It("should report the number to be processed", func() { n, known := iterator.NumberOfSpecsToProcessIfKnown() Ω(n).Should(Equal(2)) Ω(known).Should(BeTrue()) }) It("should report the number that will be run", func() { n, known := iterator.NumberOfSpecsThatWillBeRunIfKnown() Ω(n).Should(Equal(1)) Ω(known).Should(BeTrue()) }) Describe("iterating", func() { It("should return the specs in order", func() { Ω(iterator.Next()).Should(Equal(specs[0])) Ω(iterator.Next()).Should(Equal(specs[1])) spec, err := iterator.Next() Ω(spec).Should(BeNil()) Ω(err).Should(MatchError(ErrClosed)) }) }) }) ginkgo-1.14.2/internal/spec_iterator/spec_iterator.go000066400000000000000000000005741374111457300227420ustar00rootroot00000000000000package spec_iterator import ( "errors" "github.com/onsi/ginkgo/internal/spec" ) var ErrClosed = errors.New("no more specs to run") type SpecIterator interface { Next() (*spec.Spec, error) NumberOfSpecsPriorToIteration() int NumberOfSpecsToProcessIfKnown() (int, bool) NumberOfSpecsThatWillBeRunIfKnown() (int, bool) } type Counter struct { Index int `json:"index"` } ginkgo-1.14.2/internal/spec_iterator/spec_iterator_suite_test.go000066400000000000000000000003221374111457300252010ustar00rootroot00000000000000package spec_iterator_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestSpecIterator(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "SpecIterator Suite") } ginkgo-1.14.2/internal/specrunner/000077500000000000000000000000001374111457300170635ustar00rootroot00000000000000ginkgo-1.14.2/internal/specrunner/random_id.go000066400000000000000000000003421374111457300213450ustar00rootroot00000000000000package specrunner import ( "crypto/rand" "fmt" ) func randomID() string { b := make([]byte, 8) _, err := rand.Read(b) if err != nil { return "" } return fmt.Sprintf("%x-%x-%x-%x", b[0:2], b[2:4], b[4:6], b[6:8]) } ginkgo-1.14.2/internal/specrunner/spec_runner.go000066400000000000000000000251101374111457300217340ustar00rootroot00000000000000package specrunner import ( "fmt" "os" "os/signal" "sync" "syscall" "github.com/onsi/ginkgo/internal/spec_iterator" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/internal/spec" Writer "github.com/onsi/ginkgo/internal/writer" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/types" "time" ) type SpecRunner struct { description string beforeSuiteNode leafnodes.SuiteNode iterator spec_iterator.SpecIterator afterSuiteNode leafnodes.SuiteNode reporters []reporters.Reporter startTime time.Time suiteID string runningSpec *spec.Spec writer Writer.WriterInterface config config.GinkgoConfigType interrupted bool processedSpecs []*spec.Spec lock *sync.Mutex } func New(description string, beforeSuiteNode leafnodes.SuiteNode, iterator spec_iterator.SpecIterator, afterSuiteNode leafnodes.SuiteNode, reporters []reporters.Reporter, writer Writer.WriterInterface, config config.GinkgoConfigType) *SpecRunner { return &SpecRunner{ description: description, beforeSuiteNode: beforeSuiteNode, iterator: iterator, afterSuiteNode: afterSuiteNode, reporters: reporters, writer: writer, config: config, suiteID: randomID(), lock: &sync.Mutex{}, } } func (runner *SpecRunner) Run() bool { if runner.config.DryRun { runner.performDryRun() return true } runner.reportSuiteWillBegin() signalRegistered := make(chan struct{}) go runner.registerForInterrupts(signalRegistered) <-signalRegistered suitePassed := runner.runBeforeSuite() if suitePassed { suitePassed = runner.runSpecs() } runner.blockForeverIfInterrupted() suitePassed = runner.runAfterSuite() && suitePassed runner.reportSuiteDidEnd(suitePassed) return suitePassed } func (runner *SpecRunner) performDryRun() { runner.reportSuiteWillBegin() if runner.beforeSuiteNode != nil { summary := runner.beforeSuiteNode.Summary() summary.State = types.SpecStatePassed runner.reportBeforeSuite(summary) } for { spec, err := runner.iterator.Next() if err == spec_iterator.ErrClosed { break } if err != nil { fmt.Println("failed to iterate over tests:\n" + err.Error()) break } runner.processedSpecs = append(runner.processedSpecs, spec) summary := spec.Summary(runner.suiteID) runner.reportSpecWillRun(summary) if summary.State == types.SpecStateInvalid { summary.State = types.SpecStatePassed } runner.reportSpecDidComplete(summary, false) } if runner.afterSuiteNode != nil { summary := runner.afterSuiteNode.Summary() summary.State = types.SpecStatePassed runner.reportAfterSuite(summary) } runner.reportSuiteDidEnd(true) } func (runner *SpecRunner) runBeforeSuite() bool { if runner.beforeSuiteNode == nil || runner.wasInterrupted() { return true } runner.writer.Truncate() conf := runner.config passed := runner.beforeSuiteNode.Run(conf.ParallelNode, conf.ParallelTotal, conf.SyncHost) if !passed { runner.writer.DumpOut() } runner.reportBeforeSuite(runner.beforeSuiteNode.Summary()) return passed } func (runner *SpecRunner) runAfterSuite() bool { if runner.afterSuiteNode == nil { return true } runner.writer.Truncate() conf := runner.config passed := runner.afterSuiteNode.Run(conf.ParallelNode, conf.ParallelTotal, conf.SyncHost) if !passed { runner.writer.DumpOut() } runner.reportAfterSuite(runner.afterSuiteNode.Summary()) return passed } func (runner *SpecRunner) runSpecs() bool { suiteFailed := false skipRemainingSpecs := false for { spec, err := runner.iterator.Next() if err == spec_iterator.ErrClosed { break } if err != nil { fmt.Println("failed to iterate over tests:\n" + err.Error()) suiteFailed = true break } runner.processedSpecs = append(runner.processedSpecs, spec) if runner.wasInterrupted() { break } if skipRemainingSpecs { spec.Skip() } if !spec.Skipped() && !spec.Pending() { if passed := runner.runSpec(spec); !passed { suiteFailed = true } } else if spec.Pending() && runner.config.FailOnPending { runner.reportSpecWillRun(spec.Summary(runner.suiteID)) suiteFailed = true runner.reportSpecDidComplete(spec.Summary(runner.suiteID), spec.Failed()) } else { runner.reportSpecWillRun(spec.Summary(runner.suiteID)) runner.reportSpecDidComplete(spec.Summary(runner.suiteID), spec.Failed()) } if spec.Failed() && runner.config.FailFast { skipRemainingSpecs = true } } return !suiteFailed } func (runner *SpecRunner) runSpec(spec *spec.Spec) (passed bool) { maxAttempts := 1 if runner.config.FlakeAttempts > 0 { // uninitialized configs count as 1 maxAttempts = runner.config.FlakeAttempts } for i := 0; i < maxAttempts; i++ { runner.reportSpecWillRun(spec.Summary(runner.suiteID)) runner.runningSpec = spec spec.Run(runner.writer) runner.runningSpec = nil runner.reportSpecDidComplete(spec.Summary(runner.suiteID), spec.Failed()) if !spec.Failed() { return true } } return false } func (runner *SpecRunner) CurrentSpecSummary() (*types.SpecSummary, bool) { if runner.runningSpec == nil { return nil, false } return runner.runningSpec.Summary(runner.suiteID), true } func (runner *SpecRunner) registerForInterrupts(signalRegistered chan struct{}) { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) close(signalRegistered) <-c signal.Stop(c) runner.markInterrupted() go runner.registerForHardInterrupts() runner.writer.DumpOutWithHeader(` Received interrupt. Emitting contents of GinkgoWriter... --------------------------------------------------------- `) if runner.afterSuiteNode != nil { fmt.Fprint(os.Stderr, ` --------------------------------------------------------- Received interrupt. Running AfterSuite... ^C again to terminate immediately `) runner.runAfterSuite() } runner.reportSuiteDidEnd(false) os.Exit(1) } func (runner *SpecRunner) registerForHardInterrupts() { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) <-c fmt.Fprintln(os.Stderr, "\nReceived second interrupt. Shutting down.") os.Exit(1) } func (runner *SpecRunner) blockForeverIfInterrupted() { runner.lock.Lock() interrupted := runner.interrupted runner.lock.Unlock() if interrupted { select {} } } func (runner *SpecRunner) markInterrupted() { runner.lock.Lock() defer runner.lock.Unlock() runner.interrupted = true } func (runner *SpecRunner) wasInterrupted() bool { runner.lock.Lock() defer runner.lock.Unlock() return runner.interrupted } func (runner *SpecRunner) reportSuiteWillBegin() { runner.startTime = time.Now() summary := runner.suiteWillBeginSummary() for _, reporter := range runner.reporters { reporter.SpecSuiteWillBegin(runner.config, summary) } } func (runner *SpecRunner) reportBeforeSuite(summary *types.SetupSummary) { for _, reporter := range runner.reporters { reporter.BeforeSuiteDidRun(summary) } } func (runner *SpecRunner) reportAfterSuite(summary *types.SetupSummary) { for _, reporter := range runner.reporters { reporter.AfterSuiteDidRun(summary) } } func (runner *SpecRunner) reportSpecWillRun(summary *types.SpecSummary) { runner.writer.Truncate() for _, reporter := range runner.reporters { reporter.SpecWillRun(summary) } } func (runner *SpecRunner) reportSpecDidComplete(summary *types.SpecSummary, failed bool) { if len(summary.CapturedOutput) == 0 { summary.CapturedOutput = string(runner.writer.Bytes()) } for i := len(runner.reporters) - 1; i >= 1; i-- { runner.reporters[i].SpecDidComplete(summary) } if failed { runner.writer.DumpOut() } runner.reporters[0].SpecDidComplete(summary) } func (runner *SpecRunner) reportSuiteDidEnd(success bool) { summary := runner.suiteDidEndSummary(success) summary.RunTime = time.Since(runner.startTime) for _, reporter := range runner.reporters { reporter.SpecSuiteDidEnd(summary) } } func (runner *SpecRunner) countSpecsThatRanSatisfying(filter func(ex *spec.Spec) bool) (count int) { count = 0 for _, spec := range runner.processedSpecs { if filter(spec) { count++ } } return count } func (runner *SpecRunner) suiteDidEndSummary(success bool) *types.SuiteSummary { numberOfSpecsThatWillBeRun := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool { return !ex.Skipped() && !ex.Pending() }) numberOfPendingSpecs := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool { return ex.Pending() }) numberOfSkippedSpecs := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool { return ex.Skipped() }) numberOfPassedSpecs := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool { return ex.Passed() }) numberOfFlakedSpecs := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool { return ex.Flaked() }) numberOfFailedSpecs := runner.countSpecsThatRanSatisfying(func(ex *spec.Spec) bool { return ex.Failed() }) if runner.beforeSuiteNode != nil && !runner.beforeSuiteNode.Passed() && !runner.config.DryRun { var known bool numberOfSpecsThatWillBeRun, known = runner.iterator.NumberOfSpecsThatWillBeRunIfKnown() if !known { numberOfSpecsThatWillBeRun = runner.iterator.NumberOfSpecsPriorToIteration() } numberOfFailedSpecs = numberOfSpecsThatWillBeRun } return &types.SuiteSummary{ SuiteDescription: runner.description, SuiteSucceeded: success, SuiteID: runner.suiteID, NumberOfSpecsBeforeParallelization: runner.iterator.NumberOfSpecsPriorToIteration(), NumberOfTotalSpecs: len(runner.processedSpecs), NumberOfSpecsThatWillBeRun: numberOfSpecsThatWillBeRun, NumberOfPendingSpecs: numberOfPendingSpecs, NumberOfSkippedSpecs: numberOfSkippedSpecs, NumberOfPassedSpecs: numberOfPassedSpecs, NumberOfFailedSpecs: numberOfFailedSpecs, NumberOfFlakedSpecs: numberOfFlakedSpecs, } } func (runner *SpecRunner) suiteWillBeginSummary() *types.SuiteSummary { numTotal, known := runner.iterator.NumberOfSpecsToProcessIfKnown() if !known { numTotal = -1 } numToRun, known := runner.iterator.NumberOfSpecsThatWillBeRunIfKnown() if !known { numToRun = -1 } return &types.SuiteSummary{ SuiteDescription: runner.description, SuiteID: runner.suiteID, NumberOfSpecsBeforeParallelization: runner.iterator.NumberOfSpecsPriorToIteration(), NumberOfTotalSpecs: numTotal, NumberOfSpecsThatWillBeRun: numToRun, NumberOfPendingSpecs: -1, NumberOfSkippedSpecs: -1, NumberOfPassedSpecs: -1, NumberOfFailedSpecs: -1, NumberOfFlakedSpecs: -1, } } ginkgo-1.14.2/internal/specrunner/spec_runner_suite_test.go000066400000000000000000000003141374111457300242030ustar00rootroot00000000000000package specrunner_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestSpecRunner(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Spec Runner Suite") } ginkgo-1.14.2/internal/specrunner/spec_runner_test.go000066400000000000000000000673041374111457300230060ustar00rootroot00000000000000package specrunner_test import ( . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/internal/spec_iterator" . "github.com/onsi/ginkgo/internal/specrunner" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/internal/containernode" Failer "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/internal/spec" Writer "github.com/onsi/ginkgo/internal/writer" "github.com/onsi/ginkgo/reporters" ) var noneFlag = types.FlagTypeNone var pendingFlag = types.FlagTypePending var _ = Describe("Spec Runner", func() { var ( reporter1 *reporters.FakeReporter reporter2 *reporters.FakeReporter failer *Failer.Failer writer *Writer.FakeGinkgoWriter thingsThatRan []string runner *SpecRunner ) newBefSuite := func(text string, fail bool) leafnodes.SuiteNode { return leafnodes.NewBeforeSuiteNode(func() { writer.AddEvent(text) thingsThatRan = append(thingsThatRan, text) if fail { failer.Fail(text, codelocation.New(0)) } }, codelocation.New(0), 0, failer) } newAftSuite := func(text string, fail bool) leafnodes.SuiteNode { return leafnodes.NewAfterSuiteNode(func() { writer.AddEvent(text) thingsThatRan = append(thingsThatRan, text) if fail { failer.Fail(text, codelocation.New(0)) } }, codelocation.New(0), 0, failer) } newSpec := func(text string, flag types.FlagType, fail bool) *spec.Spec { subject := leafnodes.NewItNode(text, func() { writer.AddEvent(text) thingsThatRan = append(thingsThatRan, text) if fail { failer.Fail(text, codelocation.New(0)) } }, flag, codelocation.New(0), 0, failer, 0) return spec.New(subject, []*containernode.ContainerNode{}, false) } newFlakySpec := func(text string, flag types.FlagType, failures int) *spec.Spec { runs := 0 subject := leafnodes.NewItNode(text, func() { writer.AddEvent(text) thingsThatRan = append(thingsThatRan, text) runs++ if runs < failures { failer.Fail(text, codelocation.New(0)) } }, flag, codelocation.New(0), 0, failer, 0) return spec.New(subject, []*containernode.ContainerNode{}, false) } newSpecWithBody := func(text string, body interface{}) *spec.Spec { subject := leafnodes.NewItNode(text, body, noneFlag, codelocation.New(0), 0, failer, 0) return spec.New(subject, []*containernode.ContainerNode{}, false) } newRunner := func(config config.GinkgoConfigType, beforeSuiteNode leafnodes.SuiteNode, afterSuiteNode leafnodes.SuiteNode, specs ...*spec.Spec) *SpecRunner { iterator := spec_iterator.NewSerialIterator(specs) return New("description", beforeSuiteNode, iterator, afterSuiteNode, []reporters.Reporter{reporter1, reporter2}, writer, config) } BeforeEach(func() { reporter1 = reporters.NewFakeReporter() reporter2 = reporters.NewFakeReporter() writer = Writer.NewFake() failer = Failer.New() thingsThatRan = []string{} }) Describe("Running and Reporting", func() { var specA, pendingSpec, anotherPendingSpec, failedSpec, specB, skippedSpec *spec.Spec var willRunCalls, didCompleteCalls []string var conf config.GinkgoConfigType JustBeforeEach(func() { willRunCalls = []string{} didCompleteCalls = []string{} specA = newSpec("spec A", noneFlag, false) pendingSpec = newSpec("pending spec", pendingFlag, false) anotherPendingSpec = newSpec("another pending spec", pendingFlag, false) failedSpec = newSpec("failed spec", noneFlag, true) specB = newSpec("spec B", noneFlag, false) skippedSpec = newSpec("skipped spec", noneFlag, false) skippedSpec.Skip() reporter1.SpecWillRunStub = func(specSummary *types.SpecSummary) { willRunCalls = append(willRunCalls, "Reporter1") } reporter2.SpecWillRunStub = func(specSummary *types.SpecSummary) { willRunCalls = append(willRunCalls, "Reporter2") } reporter1.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { didCompleteCalls = append(didCompleteCalls, "Reporter1") } reporter2.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { didCompleteCalls = append(didCompleteCalls, "Reporter2") } runner = newRunner(conf, newBefSuite("BefSuite", false), newAftSuite("AftSuite", false), specA, pendingSpec, anotherPendingSpec, failedSpec, specB, skippedSpec) runner.Run() }) BeforeEach(func() { conf = config.GinkgoConfigType{RandomSeed: 17} }) It("should skip skipped/pending tests", func() { Ω(thingsThatRan).Should(Equal([]string{"BefSuite", "spec A", "failed spec", "spec B", "AftSuite"})) }) It("should report to any attached reporters", func() { Ω(reporter1.Config).Should(Equal(reporter2.Config)) Ω(reporter1.BeforeSuiteSummary).Should(Equal(reporter2.BeforeSuiteSummary)) Ω(reporter1.BeginSummary).Should(Equal(reporter2.BeginSummary)) Ω(reporter1.SpecWillRunSummaries).Should(Equal(reporter2.SpecWillRunSummaries)) Ω(reporter1.SpecSummaries).Should(Equal(reporter2.SpecSummaries)) Ω(reporter1.AfterSuiteSummary).Should(Equal(reporter2.AfterSuiteSummary)) Ω(reporter1.EndSummary).Should(Equal(reporter2.EndSummary)) }) It("should report that a spec did end in reverse order", func() { Ω(willRunCalls[0:4]).Should(Equal([]string{"Reporter1", "Reporter2", "Reporter1", "Reporter2"})) Ω(didCompleteCalls[0:4]).Should(Equal([]string{"Reporter2", "Reporter1", "Reporter2", "Reporter1"})) }) It("should report the passed in config", func() { Ω(reporter1.Config.RandomSeed).Should(BeNumerically("==", 17)) }) It("should report the beginning of the suite", func() { Ω(reporter1.BeginSummary.SuiteDescription).Should(Equal("description")) Ω(reporter1.BeginSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) Ω(reporter1.BeginSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) Ω(reporter1.BeginSummary.NumberOfTotalSpecs).Should(Equal(6)) Ω(reporter1.BeginSummary.NumberOfSpecsThatWillBeRun).Should(Equal(3)) Ω(reporter1.BeginSummary.NumberOfPendingSpecs).Should(Equal(-1)) Ω(reporter1.BeginSummary.NumberOfSkippedSpecs).Should(Equal(-1)) }) It("should report the end of the suite", func() { Ω(reporter1.EndSummary.SuiteDescription).Should(Equal("description")) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) Ω(reporter1.EndSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) Ω(reporter1.EndSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) Ω(reporter1.EndSummary.NumberOfTotalSpecs).Should(Equal(6)) Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(3)) Ω(reporter1.EndSummary.NumberOfPendingSpecs).Should(Equal(2)) Ω(reporter1.EndSummary.NumberOfSkippedSpecs).Should(Equal(1)) Ω(reporter1.EndSummary.NumberOfPassedSpecs).Should(Equal(2)) Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(1)) }) Context("when told to perform a dry run", func() { BeforeEach(func() { conf.DryRun = true }) It("should report to the reporters", func() { Ω(reporter1.Config).Should(Equal(reporter2.Config)) Ω(reporter1.BeforeSuiteSummary).Should(Equal(reporter2.BeforeSuiteSummary)) Ω(reporter1.BeginSummary).Should(Equal(reporter2.BeginSummary)) Ω(reporter1.SpecWillRunSummaries).Should(Equal(reporter2.SpecWillRunSummaries)) Ω(reporter1.SpecSummaries).Should(Equal(reporter2.SpecSummaries)) Ω(reporter1.AfterSuiteSummary).Should(Equal(reporter2.AfterSuiteSummary)) Ω(reporter1.EndSummary).Should(Equal(reporter2.EndSummary)) }) It("should not actually run anything", func() { Ω(thingsThatRan).Should(BeEmpty()) }) It("report before and after suites as passed", func() { Ω(reporter1.BeforeSuiteSummary.State).Should(Equal(types.SpecStatePassed)) Ω(reporter1.AfterSuiteSummary.State).Should(Equal(types.SpecStatePassed)) }) It("should report specs as passed", func() { summaries := reporter1.SpecSummaries Ω(summaries).Should(HaveLen(6)) Ω(summaries[0].ComponentTexts).Should(ContainElement("spec A")) Ω(summaries[0].State).Should(Equal(types.SpecStatePassed)) Ω(summaries[1].ComponentTexts).Should(ContainElement("pending spec")) Ω(summaries[1].State).Should(Equal(types.SpecStatePending)) Ω(summaries[2].ComponentTexts).Should(ContainElement("another pending spec")) Ω(summaries[2].State).Should(Equal(types.SpecStatePending)) Ω(summaries[3].ComponentTexts).Should(ContainElement("failed spec")) Ω(summaries[3].State).Should(Equal(types.SpecStatePassed)) Ω(summaries[4].ComponentTexts).Should(ContainElement("spec B")) Ω(summaries[4].State).Should(Equal(types.SpecStatePassed)) Ω(summaries[5].ComponentTexts).Should(ContainElement("skipped spec")) Ω(summaries[5].State).Should(Equal(types.SpecStateSkipped)) }) It("should report the end of the suite", func() { Ω(reporter1.EndSummary.SuiteDescription).Should(Equal("description")) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeTrue()) Ω(reporter1.EndSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) Ω(reporter1.EndSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) Ω(reporter1.EndSummary.NumberOfTotalSpecs).Should(Equal(6)) Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(3)) Ω(reporter1.EndSummary.NumberOfPendingSpecs).Should(Equal(2)) Ω(reporter1.EndSummary.NumberOfSkippedSpecs).Should(Equal(1)) Ω(reporter1.EndSummary.NumberOfPassedSpecs).Should(Equal(0)) Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(0)) }) It("should not report a slow test", func() { summaries := reporter1.SpecSummaries for _, s := range summaries { Expect(s.RunTime).To(BeZero()) } }) }) }) Describe("reporting on specs", func() { var proceed chan bool var ready chan bool var finished chan bool BeforeEach(func() { ready = make(chan bool) proceed = make(chan bool) finished = make(chan bool) skippedSpec := newSpec("SKIP", noneFlag, false) skippedSpec.Skip() runner = newRunner( config.GinkgoConfigType{}, newBefSuite("BefSuite", false), newAftSuite("AftSuite", false), skippedSpec, newSpec("PENDING", pendingFlag, false), newSpecWithBody("RUN", func() { close(ready) <-proceed }), ) go func() { runner.Run() close(finished) }() }) It("should report about pending/skipped specs", func() { <-ready Ω(reporter1.SpecWillRunSummaries).Should(HaveLen(3)) Ω(reporter1.SpecWillRunSummaries[0].ComponentTexts[0]).Should(Equal("SKIP")) Ω(reporter1.SpecWillRunSummaries[1].ComponentTexts[0]).Should(Equal("PENDING")) Ω(reporter1.SpecWillRunSummaries[2].ComponentTexts[0]).Should(Equal("RUN")) Ω(reporter1.SpecSummaries[0].ComponentTexts[0]).Should(Equal("SKIP")) Ω(reporter1.SpecSummaries[1].ComponentTexts[0]).Should(Equal("PENDING")) Ω(reporter1.SpecSummaries).Should(HaveLen(2)) close(proceed) <-finished Ω(reporter1.SpecSummaries).Should(HaveLen(3)) Ω(reporter1.SpecSummaries[2].ComponentTexts[0]).Should(Equal("RUN")) }) }) Describe("Running and Reporting when there's flakes", func() { var specA, pendingSpec, flakySpec, failedSpec, specB, skippedSpec *spec.Spec var willRunCalls, didCompleteCalls []string var conf config.GinkgoConfigType var failedSpecFlag = noneFlag JustBeforeEach(func() { willRunCalls = []string{} didCompleteCalls = []string{} specA = newSpec("spec A", noneFlag, false) pendingSpec = newSpec("pending spec", pendingFlag, false) flakySpec = newFlakySpec("flaky spec", noneFlag, 3) failedSpec = newSpec("failed spec", failedSpecFlag, true) specB = newSpec("spec B", noneFlag, false) skippedSpec = newSpec("skipped spec", noneFlag, false) skippedSpec.Skip() reporter1.SpecWillRunStub = func(specSummary *types.SpecSummary) { willRunCalls = append(willRunCalls, "Reporter1") } reporter2.SpecWillRunStub = func(specSummary *types.SpecSummary) { willRunCalls = append(willRunCalls, "Reporter2") } reporter1.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { didCompleteCalls = append(didCompleteCalls, "Reporter1") } reporter2.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { didCompleteCalls = append(didCompleteCalls, "Reporter2") } runner = newRunner(conf, newBefSuite("BefSuite", false), newAftSuite("AftSuite", false), specA, pendingSpec, flakySpec, failedSpec, specB, skippedSpec) runner.Run() }) BeforeEach(func() { failedSpecFlag = noneFlag conf = config.GinkgoConfigType{ RandomSeed: 17, FlakeAttempts: 5, } }) It("should skip skipped/pending tests", func() { Ω(thingsThatRan).Should(Equal([]string{"BefSuite", "spec A", "flaky spec", "flaky spec", "flaky spec", "failed spec", "failed spec", "failed spec", "failed spec", "failed spec", "spec B", "AftSuite"})) }) It("should report to any attached reporters", func() { Ω(reporter1.Config).Should(Equal(reporter2.Config)) Ω(reporter1.BeforeSuiteSummary).Should(Equal(reporter2.BeforeSuiteSummary)) Ω(reporter1.BeginSummary).Should(Equal(reporter2.BeginSummary)) Ω(reporter1.SpecWillRunSummaries).Should(Equal(reporter2.SpecWillRunSummaries)) Ω(reporter1.SpecSummaries).Should(Equal(reporter2.SpecSummaries)) Ω(reporter1.AfterSuiteSummary).Should(Equal(reporter2.AfterSuiteSummary)) Ω(reporter1.EndSummary).Should(Equal(reporter2.EndSummary)) }) It("should report that a spec did end in reverse order", func() { Ω(willRunCalls[0:4]).Should(Equal([]string{"Reporter1", "Reporter2", "Reporter1", "Reporter2"})) Ω(didCompleteCalls[0:4]).Should(Equal([]string{"Reporter2", "Reporter1", "Reporter2", "Reporter1"})) }) It("should report the passed in config", func() { Ω(reporter1.Config.RandomSeed).Should(BeNumerically("==", 17)) }) It("should report the beginning of the suite", func() { Ω(reporter1.BeginSummary.SuiteDescription).Should(Equal("description")) Ω(reporter1.BeginSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) Ω(reporter1.BeginSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) Ω(reporter1.BeginSummary.NumberOfTotalSpecs).Should(Equal(6)) Ω(reporter1.BeginSummary.NumberOfSpecsThatWillBeRun).Should(Equal(4)) Ω(reporter1.BeginSummary.NumberOfPendingSpecs).Should(Equal(-1)) Ω(reporter1.BeginSummary.NumberOfSkippedSpecs).Should(Equal(-1)) }) It("should report the end of the suite", func() { Ω(reporter1.EndSummary.SuiteDescription).Should(Equal("description")) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) Ω(reporter1.EndSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) Ω(reporter1.EndSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) Ω(reporter1.EndSummary.NumberOfTotalSpecs).Should(Equal(6)) Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(4)) Ω(reporter1.EndSummary.NumberOfPendingSpecs).Should(Equal(1)) Ω(reporter1.EndSummary.NumberOfSkippedSpecs).Should(Equal(1)) Ω(reporter1.EndSummary.NumberOfPassedSpecs).Should(Equal(3)) Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(1)) Ω(reporter1.EndSummary.NumberOfFlakedSpecs).Should(Equal(1)) }) Context("when nothing fails", func() { BeforeEach(func() { failedSpecFlag = pendingFlag }) It("the suite should pass even with flakes", func() { Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeTrue()) Ω(reporter1.EndSummary.NumberOfFlakedSpecs).Should(Equal(1)) }) }) Context("when told to perform a dry run", func() { BeforeEach(func() { conf.DryRun = true }) It("should report to the reporters", func() { Ω(reporter1.Config).Should(Equal(reporter2.Config)) Ω(reporter1.BeforeSuiteSummary).Should(Equal(reporter2.BeforeSuiteSummary)) Ω(reporter1.BeginSummary).Should(Equal(reporter2.BeginSummary)) Ω(reporter1.SpecWillRunSummaries).Should(Equal(reporter2.SpecWillRunSummaries)) Ω(reporter1.SpecSummaries).Should(Equal(reporter2.SpecSummaries)) Ω(reporter1.AfterSuiteSummary).Should(Equal(reporter2.AfterSuiteSummary)) Ω(reporter1.EndSummary).Should(Equal(reporter2.EndSummary)) }) It("should not actually run anything", func() { Ω(thingsThatRan).Should(BeEmpty()) }) It("report before and after suites as passed", func() { Ω(reporter1.BeforeSuiteSummary.State).Should(Equal(types.SpecStatePassed)) Ω(reporter1.AfterSuiteSummary.State).Should(Equal(types.SpecStatePassed)) }) It("should report specs as passed", func() { summaries := reporter1.SpecSummaries Ω(summaries).Should(HaveLen(6)) Ω(summaries[0].ComponentTexts).Should(ContainElement("spec A")) Ω(summaries[0].State).Should(Equal(types.SpecStatePassed)) Ω(summaries[1].ComponentTexts).Should(ContainElement("pending spec")) Ω(summaries[1].State).Should(Equal(types.SpecStatePending)) Ω(summaries[2].ComponentTexts).Should(ContainElement("flaky spec")) Ω(summaries[2].State).Should(Equal(types.SpecStatePassed)) Ω(summaries[3].ComponentTexts).Should(ContainElement("failed spec")) Ω(summaries[3].State).Should(Equal(types.SpecStatePassed)) Ω(summaries[4].ComponentTexts).Should(ContainElement("spec B")) Ω(summaries[4].State).Should(Equal(types.SpecStatePassed)) Ω(summaries[5].ComponentTexts).Should(ContainElement("skipped spec")) Ω(summaries[5].State).Should(Equal(types.SpecStateSkipped)) }) It("should report the end of the suite", func() { Ω(reporter1.EndSummary.SuiteDescription).Should(Equal("description")) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeTrue()) Ω(reporter1.EndSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) Ω(reporter1.EndSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) Ω(reporter1.EndSummary.NumberOfTotalSpecs).Should(Equal(6)) Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(4)) Ω(reporter1.EndSummary.NumberOfPendingSpecs).Should(Equal(1)) Ω(reporter1.EndSummary.NumberOfSkippedSpecs).Should(Equal(1)) Ω(reporter1.EndSummary.NumberOfPassedSpecs).Should(Equal(0)) Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(0)) }) }) }) Describe("Running BeforeSuite & AfterSuite", func() { var success bool var befSuite leafnodes.SuiteNode var aftSuite leafnodes.SuiteNode Context("with a nil BeforeSuite & AfterSuite", func() { BeforeEach(func() { runner = newRunner( config.GinkgoConfigType{}, nil, nil, newSpec("A", noneFlag, false), newSpec("B", noneFlag, false), ) success = runner.Run() }) It("should not report about the BeforeSuite", func() { Ω(reporter1.BeforeSuiteSummary).Should(BeNil()) }) It("should not report about the AfterSuite", func() { Ω(reporter1.AfterSuiteSummary).Should(BeNil()) }) It("should run the specs", func() { Ω(thingsThatRan).Should(Equal([]string{"A", "B"})) }) }) Context("when the BeforeSuite & AfterSuite pass", func() { BeforeEach(func() { befSuite = newBefSuite("BefSuite", false) aftSuite = newBefSuite("AftSuite", false) runner = newRunner( config.GinkgoConfigType{}, befSuite, aftSuite, newSpec("A", noneFlag, false), newSpec("B", noneFlag, false), ) success = runner.Run() }) It("should run the BeforeSuite, the AfterSuite and the specs", func() { Ω(thingsThatRan).Should(Equal([]string{"BefSuite", "A", "B", "AftSuite"})) }) It("should report about the BeforeSuite", func() { Ω(reporter1.BeforeSuiteSummary).Should(Equal(befSuite.Summary())) }) It("should report about the AfterSuite", func() { Ω(reporter1.AfterSuiteSummary).Should(Equal(aftSuite.Summary())) }) It("should report success", func() { Ω(success).Should(BeTrue()) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeTrue()) Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(0)) }) It("should not dump the writer", func() { Ω(writer.EventStream).ShouldNot(ContainElement("DUMP")) }) }) Context("when the BeforeSuite fails", func() { BeforeEach(func() { befSuite = newBefSuite("BefSuite", true) aftSuite = newBefSuite("AftSuite", false) skipped := newSpec("Skipped", noneFlag, false) skipped.Skip() runner = newRunner( config.GinkgoConfigType{}, befSuite, aftSuite, newSpec("A", noneFlag, false), newSpec("B", noneFlag, false), newSpec("Pending", pendingFlag, false), skipped, ) success = runner.Run() }) It("should not run the specs, but it should run the AfterSuite", func() { Ω(thingsThatRan).Should(Equal([]string{"BefSuite", "AftSuite"})) }) It("should report about the BeforeSuite", func() { Ω(reporter1.BeforeSuiteSummary).Should(Equal(befSuite.Summary())) }) It("should report about the AfterSuite", func() { Ω(reporter1.AfterSuiteSummary).Should(Equal(aftSuite.Summary())) }) It("should report failure", func() { Ω(success).Should(BeFalse()) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(2)) Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(2)) }) It("should dump the writer", func() { Ω(writer.EventStream).Should(ContainElement("DUMP")) }) }) Context("when some other test fails", func() { BeforeEach(func() { aftSuite = newBefSuite("AftSuite", false) runner = newRunner( config.GinkgoConfigType{}, nil, aftSuite, newSpec("A", noneFlag, true), ) success = runner.Run() }) It("should still run the AfterSuite", func() { Ω(thingsThatRan).Should(Equal([]string{"A", "AftSuite"})) }) It("should report about the AfterSuite", func() { Ω(reporter1.AfterSuiteSummary).Should(Equal(aftSuite.Summary())) }) It("should report failure", func() { Ω(success).Should(BeFalse()) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(1)) Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(1)) }) }) Context("when the AfterSuite fails", func() { BeforeEach(func() { befSuite = newBefSuite("BefSuite", false) aftSuite = newBefSuite("AftSuite", true) runner = newRunner( config.GinkgoConfigType{}, befSuite, aftSuite, newSpec("A", noneFlag, false), newSpec("B", noneFlag, false), ) success = runner.Run() }) It("should run everything", func() { Ω(thingsThatRan).Should(Equal([]string{"BefSuite", "A", "B", "AftSuite"})) }) It("should report about the BeforeSuite", func() { Ω(reporter1.BeforeSuiteSummary).Should(Equal(befSuite.Summary())) }) It("should report about the AfterSuite", func() { Ω(reporter1.AfterSuiteSummary).Should(Equal(aftSuite.Summary())) }) It("should report failure", func() { Ω(success).Should(BeFalse()) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(0)) }) It("should dump the writer", func() { Ω(writer.EventStream).Should(ContainElement("DUMP")) }) }) }) Describe("When instructed to fail fast", func() { BeforeEach(func() { conf := config.GinkgoConfigType{ FailFast: true, } runner = newRunner(conf, nil, newAftSuite("after-suite", false), newSpec("passing", noneFlag, false), newSpec("failing", noneFlag, true), newSpec("dont-see", noneFlag, true), newSpec("dont-see", noneFlag, true)) }) It("should return false, report failure, and not run anything past the failing test", func() { Ω(runner.Run()).Should(BeFalse()) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) Ω(thingsThatRan).Should(Equal([]string{"passing", "failing", "after-suite"})) }) It("should announce the subsequent specs as skipped", func() { runner.Run() Ω(reporter1.SpecSummaries).Should(HaveLen(4)) Ω(reporter1.SpecSummaries[2].State).Should(Equal(types.SpecStateSkipped)) Ω(reporter1.SpecSummaries[3].State).Should(Equal(types.SpecStateSkipped)) }) It("should mark all subsequent specs as skipped", func() { runner.Run() Ω(reporter1.EndSummary.NumberOfSkippedSpecs).Should(Equal(2)) }) }) Describe("Marking failure and success", func() { Context("when all tests pass", func() { BeforeEach(func() { runner = newRunner(config.GinkgoConfigType{}, nil, nil, newSpec("passing", noneFlag, false), newSpec("pending", pendingFlag, false)) }) It("should return true and report success", func() { Ω(runner.Run()).Should(BeTrue()) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeTrue()) }) }) Context("when a test fails", func() { BeforeEach(func() { runner = newRunner(config.GinkgoConfigType{}, nil, nil, newSpec("failing", noneFlag, true), newSpec("pending", pendingFlag, false)) }) It("should return false and report failure", func() { Ω(runner.Run()).Should(BeFalse()) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) }) }) Context("when there is a pending test, but pendings count as failures", func() { BeforeEach(func() { runner = newRunner(config.GinkgoConfigType{FailOnPending: true}, nil, nil, newSpec("passing", noneFlag, false), newSpec("pending", pendingFlag, false)) }) It("should return false and report failure", func() { Ω(runner.Run()).Should(BeFalse()) Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) }) }) }) Describe("Managing the writer", func() { BeforeEach(func() { runner = newRunner( config.GinkgoConfigType{}, nil, nil, newSpec("A", noneFlag, false), newSpec("B", noneFlag, true), newSpec("C", noneFlag, false), ) reporter1.SpecWillRunStub = func(specSummary *types.SpecSummary) { writer.AddEvent("R1.WillRun") } reporter2.SpecWillRunStub = func(specSummary *types.SpecSummary) { writer.AddEvent("R2.WillRun") } reporter1.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { writer.AddEvent("R1.DidComplete") } reporter2.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { writer.AddEvent("R2.DidComplete") } runner.Run() }) It("should truncate between tests, but only dump if a test fails", func() { Ω(writer.EventStream).Should(Equal([]string{ "TRUNCATE", "R1.WillRun", "R2.WillRun", "A", "BYTES", "R2.DidComplete", "R1.DidComplete", "TRUNCATE", "R1.WillRun", "R2.WillRun", "B", "BYTES", "R2.DidComplete", "DUMP", "R1.DidComplete", "TRUNCATE", "R1.WillRun", "R2.WillRun", "C", "BYTES", "R2.DidComplete", "R1.DidComplete", })) }) }) Describe("CurrentSpecSummary", func() { It("should return the spec summary for the currently running spec", func() { var summary *types.SpecSummary runner = newRunner( config.GinkgoConfigType{}, nil, nil, newSpec("A", noneFlag, false), newSpecWithBody("B", func() { var ok bool summary, ok = runner.CurrentSpecSummary() Ω(ok).Should(BeTrue()) }), newSpec("C", noneFlag, false), ) runner.Run() Ω(summary.ComponentTexts).Should(Equal([]string{"B"})) summary, ok := runner.CurrentSpecSummary() Ω(summary).Should(BeNil()) Ω(ok).Should(BeFalse()) }) }) Describe("generating a suite id", func() { It("should generate an id randomly", func() { runnerA := newRunner(config.GinkgoConfigType{}, nil, nil) runnerA.Run() IDA := reporter1.BeginSummary.SuiteID runnerB := newRunner(config.GinkgoConfigType{}, nil, nil) runnerB.Run() IDB := reporter1.BeginSummary.SuiteID IDRegexp := "[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}" Ω(IDA).Should(MatchRegexp(IDRegexp)) Ω(IDB).Should(MatchRegexp(IDRegexp)) Ω(IDA).ShouldNot(Equal(IDB)) }) }) }) ginkgo-1.14.2/internal/suite/000077500000000000000000000000001374111457300160305ustar00rootroot00000000000000ginkgo-1.14.2/internal/suite/suite.go000066400000000000000000000211401374111457300175060ustar00rootroot00000000000000package suite import ( "math/rand" "net/http" "time" "github.com/onsi/ginkgo/internal/spec_iterator" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/internal/containernode" "github.com/onsi/ginkgo/internal/failer" "github.com/onsi/ginkgo/internal/leafnodes" "github.com/onsi/ginkgo/internal/spec" "github.com/onsi/ginkgo/internal/specrunner" "github.com/onsi/ginkgo/internal/writer" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/types" ) type ginkgoTestingT interface { Fail() } type deferredContainerNode struct { text string body func() flag types.FlagType codeLocation types.CodeLocation } type Suite struct { topLevelContainer *containernode.ContainerNode currentContainer *containernode.ContainerNode deferredContainerNodes []deferredContainerNode containerIndex int beforeSuiteNode leafnodes.SuiteNode afterSuiteNode leafnodes.SuiteNode runner *specrunner.SpecRunner failer *failer.Failer running bool expandTopLevelNodes bool } func New(failer *failer.Failer) *Suite { topLevelContainer := containernode.New("[Top Level]", types.FlagTypeNone, types.CodeLocation{}) return &Suite{ topLevelContainer: topLevelContainer, currentContainer: topLevelContainer, failer: failer, containerIndex: 1, deferredContainerNodes: []deferredContainerNode{}, } } func (suite *Suite) Run(t ginkgoTestingT, description string, reporters []reporters.Reporter, writer writer.WriterInterface, config config.GinkgoConfigType) (bool, bool) { if config.ParallelTotal < 1 { panic("ginkgo.parallel.total must be >= 1") } if config.ParallelNode > config.ParallelTotal || config.ParallelNode < 1 { panic("ginkgo.parallel.node is one-indexed and must be <= ginkgo.parallel.total") } suite.expandTopLevelNodes = true for _, deferredNode := range suite.deferredContainerNodes { suite.PushContainerNode(deferredNode.text, deferredNode.body, deferredNode.flag, deferredNode.codeLocation) } r := rand.New(rand.NewSource(config.RandomSeed)) suite.topLevelContainer.Shuffle(r) iterator, hasProgrammaticFocus := suite.generateSpecsIterator(description, config) suite.runner = specrunner.New(description, suite.beforeSuiteNode, iterator, suite.afterSuiteNode, reporters, writer, config) suite.running = true success := suite.runner.Run() if !success { t.Fail() } return success, hasProgrammaticFocus } func (suite *Suite) generateSpecsIterator(description string, config config.GinkgoConfigType) (spec_iterator.SpecIterator, bool) { specsSlice := []*spec.Spec{} suite.topLevelContainer.BackPropagateProgrammaticFocus() for _, collatedNodes := range suite.topLevelContainer.Collate() { specsSlice = append(specsSlice, spec.New(collatedNodes.Subject, collatedNodes.Containers, config.EmitSpecProgress)) } specs := spec.NewSpecs(specsSlice) specs.RegexScansFilePath = config.RegexScansFilePath if config.RandomizeAllSpecs { specs.Shuffle(rand.New(rand.NewSource(config.RandomSeed))) } specs.ApplyFocus(description, config.FocusString, config.SkipString) if config.SkipMeasurements { specs.SkipMeasurements() } var iterator spec_iterator.SpecIterator if config.ParallelTotal > 1 { iterator = spec_iterator.NewParallelIterator(specs.Specs(), config.SyncHost) resp, err := http.Get(config.SyncHost + "/has-counter") if err != nil || resp.StatusCode != http.StatusOK { iterator = spec_iterator.NewShardedParallelIterator(specs.Specs(), config.ParallelTotal, config.ParallelNode) } } else { iterator = spec_iterator.NewSerialIterator(specs.Specs()) } return iterator, specs.HasProgrammaticFocus() } func (suite *Suite) CurrentRunningSpecSummary() (*types.SpecSummary, bool) { if !suite.running { return nil, false } return suite.runner.CurrentSpecSummary() } func (suite *Suite) SetBeforeSuiteNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.beforeSuiteNode != nil { panic("You may only call BeforeSuite once!") } suite.beforeSuiteNode = leafnodes.NewBeforeSuiteNode(body, codeLocation, timeout, suite.failer) } func (suite *Suite) SetAfterSuiteNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.afterSuiteNode != nil { panic("You may only call AfterSuite once!") } suite.afterSuiteNode = leafnodes.NewAfterSuiteNode(body, codeLocation, timeout, suite.failer) } func (suite *Suite) SetSynchronizedBeforeSuiteNode(bodyA interface{}, bodyB interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.beforeSuiteNode != nil { panic("You may only call BeforeSuite once!") } suite.beforeSuiteNode = leafnodes.NewSynchronizedBeforeSuiteNode(bodyA, bodyB, codeLocation, timeout, suite.failer) } func (suite *Suite) SetSynchronizedAfterSuiteNode(bodyA interface{}, bodyB interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.afterSuiteNode != nil { panic("You may only call AfterSuite once!") } suite.afterSuiteNode = leafnodes.NewSynchronizedAfterSuiteNode(bodyA, bodyB, codeLocation, timeout, suite.failer) } func (suite *Suite) PushContainerNode(text string, body func(), flag types.FlagType, codeLocation types.CodeLocation) { /* We defer walking the container nodes (which immediately evaluates the `body` function) until `RunSpecs` is called. We do this by storing off the deferred container nodes. Then, when `RunSpecs` is called we actually go through and add the container nodes to the test structure. This allows us to defer calling all the `body` functions until _after_ the top level functions have been walked, _after_ func init()s have been called, and _after_ `go test` has called `flag.Parse()`. This allows users to load up configuration information in the `TestX` go test hook just before `RunSpecs` is invoked and solves issues like #693 and makes the lifecycle easier to reason about. */ if !suite.expandTopLevelNodes { suite.deferredContainerNodes = append(suite.deferredContainerNodes, deferredContainerNode{text, body, flag, codeLocation}) return } container := containernode.New(text, flag, codeLocation) suite.currentContainer.PushContainerNode(container) previousContainer := suite.currentContainer suite.currentContainer = container suite.containerIndex++ body() suite.containerIndex-- suite.currentContainer = previousContainer } func (suite *Suite) PushItNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, timeout time.Duration) { if suite.running { suite.failer.Fail("You may only call It from within a Describe, Context or When", codeLocation) } suite.currentContainer.PushSubjectNode(leafnodes.NewItNode(text, body, flag, codeLocation, timeout, suite.failer, suite.containerIndex)) } func (suite *Suite) PushMeasureNode(text string, body interface{}, flag types.FlagType, codeLocation types.CodeLocation, samples int) { if suite.running { suite.failer.Fail("You may only call Measure from within a Describe, Context or When", codeLocation) } suite.currentContainer.PushSubjectNode(leafnodes.NewMeasureNode(text, body, flag, codeLocation, samples, suite.failer, suite.containerIndex)) } func (suite *Suite) PushBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.running { suite.failer.Fail("You may only call BeforeEach from within a Describe, Context or When", codeLocation) } suite.currentContainer.PushSetupNode(leafnodes.NewBeforeEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) } func (suite *Suite) PushJustBeforeEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.running { suite.failer.Fail("You may only call JustBeforeEach from within a Describe, Context or When", codeLocation) } suite.currentContainer.PushSetupNode(leafnodes.NewJustBeforeEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) } func (suite *Suite) PushJustAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.running { suite.failer.Fail("You may only call JustAfterEach from within a Describe or Context", codeLocation) } suite.currentContainer.PushSetupNode(leafnodes.NewJustAfterEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) } func (suite *Suite) PushAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { if suite.running { suite.failer.Fail("You may only call AfterEach from within a Describe, Context or When", codeLocation) } suite.currentContainer.PushSetupNode(leafnodes.NewAfterEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) } ginkgo-1.14.2/internal/suite/suite_suite_test.go000066400000000000000000000020371374111457300217620ustar00rootroot00000000000000package suite_test import ( "fmt" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) var dynamicallyGeneratedTests = []string{} func Test(t *testing.T) { RegisterFailHandler(Fail) dynamicallyGeneratedTests = []string{"Test A", "Test B", "Test C"} RunSpecs(t, "Suite") } var numBeforeSuiteRuns = 0 var numAfterSuiteRuns = 0 var numDynamicallyGeneratedTests = 0 var _ = BeforeSuite(func() { numBeforeSuiteRuns++ }) var _ = AfterSuite(func() { numAfterSuiteRuns++ Ω(numBeforeSuiteRuns).Should(Equal(1)) Ω(numAfterSuiteRuns).Should(Equal(1)) Ω(numDynamicallyGeneratedTests).Should(Equal(3), "Expected three test to be dynamically generated") }) var _ = Describe("Top-level cotnainer node lifecycle", func() { for _, test := range dynamicallyGeneratedTests { numDynamicallyGeneratedTests += 1 It(fmt.Sprintf("runs dynamically generated test: %s", test), func() { Ω(true).Should(BeTrue()) }) } }) //Fakes type fakeTestingT struct { didFail bool } func (fakeT *fakeTestingT) Fail() { fakeT.didFail = true } ginkgo-1.14.2/internal/suite/suite_test.go000066400000000000000000000275451374111457300205640ustar00rootroot00000000000000package suite_test import ( "bytes" . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/suite" . "github.com/onsi/gomega" "math/rand" "time" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/internal/codelocation" Failer "github.com/onsi/ginkgo/internal/failer" Writer "github.com/onsi/ginkgo/internal/writer" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/types" ) var _ = Describe("Suite", func() { var ( specSuite *Suite fakeT *fakeTestingT fakeR *reporters.FakeReporter writer *Writer.FakeGinkgoWriter failer *Failer.Failer ) BeforeEach(func() { writer = Writer.NewFake() fakeT = &fakeTestingT{} fakeR = reporters.NewFakeReporter() failer = Failer.New() specSuite = New(failer) }) Describe("running a suite", func() { var ( runOrder []string randomizeAllSpecs bool randomSeed int64 focusString string parallelNode int parallelTotal int runResult bool hasProgrammaticFocus bool ) var f = func(runText string) func() { return func() { runOrder = append(runOrder, runText) } } BeforeEach(func() { randomizeAllSpecs = false randomSeed = 11 parallelNode = 1 parallelTotal = 1 focusString = "" runOrder = make([]string, 0) specSuite.SetBeforeSuiteNode(f("BeforeSuite"), codelocation.New(0), 0) specSuite.PushBeforeEachNode(f("top BE"), codelocation.New(0), 0) specSuite.PushJustBeforeEachNode(f("top JBE"), codelocation.New(0), 0) specSuite.PushAfterEachNode(f("top AE"), codelocation.New(0), 0) specSuite.PushContainerNode("container", func() { specSuite.PushBeforeEachNode(f("BE"), codelocation.New(0), 0) specSuite.PushJustBeforeEachNode(f("JBE"), codelocation.New(0), 0) specSuite.PushAfterEachNode(f("AE"), codelocation.New(0), 0) specSuite.PushItNode("it", f("IT"), types.FlagTypeNone, codelocation.New(0), 0) specSuite.PushContainerNode("inner container", func() { specSuite.PushItNode("inner it", f("inner IT"), types.FlagTypeNone, codelocation.New(0), 0) }, types.FlagTypeNone, codelocation.New(0)) }, types.FlagTypeNone, codelocation.New(0)) specSuite.PushContainerNode("container 2", func() { specSuite.PushBeforeEachNode(f("BE 2"), codelocation.New(0), 0) specSuite.PushItNode("it 2", f("IT 2"), types.FlagTypeNone, codelocation.New(0), 0) }, types.FlagTypeNone, codelocation.New(0)) specSuite.PushItNode("top level it", f("top IT"), types.FlagTypeNone, codelocation.New(0), 0) specSuite.SetAfterSuiteNode(f("AfterSuite"), codelocation.New(0), 0) }) JustBeforeEach(func() { runResult, hasProgrammaticFocus = specSuite.Run(fakeT, "suite description", []reporters.Reporter{fakeR}, writer, config.GinkgoConfigType{ RandomSeed: randomSeed, RandomizeAllSpecs: randomizeAllSpecs, FocusString: focusString, ParallelNode: parallelNode, ParallelTotal: parallelTotal, }) }) It("provides the config and suite description to the reporter", func() { Ω(fakeR.Config.RandomSeed).Should(Equal(randomSeed)) Ω(fakeR.Config.RandomizeAllSpecs).Should(Equal(randomizeAllSpecs)) Ω(fakeR.BeginSummary.SuiteDescription).Should(Equal("suite description")) }) It("reports that the BeforeSuite node ran", func() { Ω(fakeR.BeforeSuiteSummary).ShouldNot(BeNil()) }) It("reports that the AfterSuite node ran", func() { Ω(fakeR.AfterSuiteSummary).ShouldNot(BeNil()) }) It("provides information about the current test", func() { description := CurrentGinkgoTestDescription() Ω(description.ComponentTexts).Should(Equal([]string{"Suite", "running a suite", "provides information about the current test"})) Ω(description.FullTestText).Should(Equal("Suite running a suite provides information about the current test")) Ω(description.TestText).Should(Equal("provides information about the current test")) Ω(description.IsMeasurement).Should(BeFalse()) Ω(description.FileName).Should(ContainSubstring("suite_test.go")) Ω(description.LineNumber).Should(BeNumerically(">", 50)) Ω(description.LineNumber).Should(BeNumerically("<", 150)) Ω(description.Failed).Should(BeFalse()) Ω(description.Duration).Should(BeNumerically(">", 0)) }) Measure("should run measurements", func(b Benchmarker) { r := rand.New(rand.NewSource(time.Now().UnixNano())) runtime := b.Time("sleeping", func() { sleepTime := time.Duration(r.Float64() * 0.01 * float64(time.Second)) time.Sleep(sleepTime) }) Ω(runtime.Seconds()).Should(BeNumerically("<=", 1)) Ω(runtime.Seconds()).Should(BeNumerically(">=", 0)) randomValue := r.Float64() * 10.0 b.RecordValue("random value", randomValue) Ω(randomValue).Should(BeNumerically("<=", 10.0)) Ω(randomValue).Should(BeNumerically(">=", 0.0)) b.RecordValueWithPrecision("specific value", 123.4567, "ms", 2) b.RecordValueWithPrecision("specific value", 234.5678, "ms", 2) }, 10) It("creates a node hierarchy, converts it to a spec collection, and runs it", func() { Ω(runOrder).Should(Equal([]string{ "BeforeSuite", "top BE", "BE", "top JBE", "JBE", "IT", "AE", "top AE", "top BE", "BE", "top JBE", "JBE", "inner IT", "AE", "top AE", "top BE", "BE 2", "top JBE", "IT 2", "top AE", "top BE", "top JBE", "top IT", "top AE", "AfterSuite", })) }) Context("when in an AfterEach block", func() { AfterEach(func() { description := CurrentGinkgoTestDescription() Ω(description.IsMeasurement).Should(BeFalse()) Ω(description.FileName).Should(ContainSubstring("suite_test.go")) Ω(description.Failed).Should(BeFalse()) Ω(description.Duration).Should(BeNumerically(">", 0)) }) It("still provides information about the current test", func() { Ω(true).To(BeTrue()) }) }) Context("when told to randomize all specs", func() { BeforeEach(func() { randomizeAllSpecs = true }) It("does", func() { Ω(runOrder).Should(Equal([]string{ "BeforeSuite", "top BE", "top JBE", "top IT", "top AE", "top BE", "BE", "top JBE", "JBE", "inner IT", "AE", "top AE", "top BE", "BE", "top JBE", "JBE", "IT", "AE", "top AE", "top BE", "BE 2", "top JBE", "IT 2", "top AE", "AfterSuite", })) }) }) Context("when provided with a filter", func() { BeforeEach(func() { focusString = `inner|\d` }) It("converts the filter to a regular expression and uses it to filter the running specs", func() { Ω(runOrder).Should(Equal([]string{ "BeforeSuite", "top BE", "BE", "top JBE", "JBE", "inner IT", "AE", "top AE", "top BE", "BE 2", "top JBE", "IT 2", "top AE", "AfterSuite", })) }) It("should not report a programmatic focus", func() { Ω(hasProgrammaticFocus).Should(BeFalse()) }) }) Context("with a programatically focused spec", func() { BeforeEach(func() { specSuite.PushItNode("focused it", f("focused it"), types.FlagTypeFocused, codelocation.New(0), 0) specSuite.PushContainerNode("focused container", func() { specSuite.PushItNode("inner focused it", f("inner focused it"), types.FlagTypeFocused, codelocation.New(0), 0) specSuite.PushItNode("inner unfocused it", f("inner unfocused it"), types.FlagTypeNone, codelocation.New(0), 0) }, types.FlagTypeFocused, codelocation.New(0)) }) It("should only run the focused test, applying backpropagation to favor most deeply focused leaf nodes", func() { Ω(runOrder).Should(Equal([]string{ "BeforeSuite", "top BE", "top JBE", "focused it", "top AE", "top BE", "top JBE", "inner focused it", "top AE", "AfterSuite", })) }) It("should report a programmatic focus", func() { Ω(hasProgrammaticFocus).Should(BeTrue()) }) }) Context("when the specs pass", func() { It("doesn't report a failure", func() { Ω(fakeT.didFail).Should(BeFalse()) }) It("should return true", func() { Ω(runResult).Should(BeTrue()) }) }) Context("when a spec fails", func() { var location types.CodeLocation BeforeEach(func() { specSuite.PushItNode("top level it", func() { location = codelocation.New(0) failer.Fail("oops!", location) }, types.FlagTypeNone, codelocation.New(0), 0) }) It("should return false", func() { Ω(runResult).Should(BeFalse()) }) It("reports a failure", func() { Ω(fakeT.didFail).Should(BeTrue()) }) It("generates the correct failure data", func() { Ω(fakeR.SpecSummaries[0].Failure.Message).Should(Equal("oops!")) Ω(fakeR.SpecSummaries[0].Failure.Location).Should(Equal(location)) }) }) Context("when runnable nodes are nested within other runnable nodes", func() { Context("when an It is nested", func() { BeforeEach(func() { specSuite.PushItNode("top level it", func() { specSuite.PushItNode("nested it", f("oops"), types.FlagTypeNone, codelocation.New(0), 0) }, types.FlagTypeNone, codelocation.New(0), 0) }) It("should fail", func() { Ω(fakeT.didFail).Should(BeTrue()) }) }) Context("when a Measure is nested", func() { BeforeEach(func() { specSuite.PushItNode("top level it", func() { specSuite.PushMeasureNode("nested measure", func(Benchmarker) {}, types.FlagTypeNone, codelocation.New(0), 10) }, types.FlagTypeNone, codelocation.New(0), 0) }) It("should fail", func() { Ω(fakeT.didFail).Should(BeTrue()) }) }) Context("when a BeforeEach is nested", func() { BeforeEach(func() { specSuite.PushItNode("top level it", func() { specSuite.PushBeforeEachNode(f("nested bef"), codelocation.New(0), 0) }, types.FlagTypeNone, codelocation.New(0), 0) }) It("should fail", func() { Ω(fakeT.didFail).Should(BeTrue()) }) }) Context("when a JustBeforeEach is nested", func() { BeforeEach(func() { specSuite.PushItNode("top level it", func() { specSuite.PushJustBeforeEachNode(f("nested jbef"), codelocation.New(0), 0) }, types.FlagTypeNone, codelocation.New(0), 0) }) It("should fail", func() { Ω(fakeT.didFail).Should(BeTrue()) }) }) Context("when a AfterEach is nested", func() { BeforeEach(func() { specSuite.PushItNode("top level it", func() { specSuite.PushAfterEachNode(f("nested aft"), codelocation.New(0), 0) }, types.FlagTypeNone, codelocation.New(0), 0) }) It("should fail", func() { Ω(fakeT.didFail).Should(BeTrue()) }) }) }) }) Describe("BeforeSuite", func() { Context("when setting BeforeSuite more than once", func() { It("should panic", func() { specSuite.SetBeforeSuiteNode(func() {}, codelocation.New(0), 0) Ω(func() { specSuite.SetBeforeSuiteNode(func() {}, codelocation.New(0), 0) }).Should(Panic()) }) }) }) Describe("AfterSuite", func() { Context("when setting AfterSuite more than once", func() { It("should panic", func() { specSuite.SetAfterSuiteNode(func() {}, codelocation.New(0), 0) Ω(func() { specSuite.SetAfterSuiteNode(func() {}, codelocation.New(0), 0) }).Should(Panic()) }) }) }) Describe("By", func() { It("writes to the GinkgoWriter", func() { originalGinkgoWriter := GinkgoWriter buffer := &bytes.Buffer{} GinkgoWriter = buffer By("Saying Hello GinkgoWriter") GinkgoWriter = originalGinkgoWriter Ω(buffer.String()).Should(ContainSubstring("STEP")) Ω(buffer.String()).Should(ContainSubstring(": Saying Hello GinkgoWriter\n")) }) It("calls the passed-in callback if present", func() { a := 0 By("calling the callback", func() { a = 1 }) Ω(a).Should(Equal(1)) }) It("panics if there is more than one callback", func() { Ω(func() { By("registering more than one callback", func() {}, func() {}) }).Should(Panic()) }) }) Describe("GinkgoRandomSeed", func() { It("returns the current config's random seed", func() { Ω(GinkgoRandomSeed()).Should(Equal(config.GinkgoConfig.RandomSeed)) }) }) }) ginkgo-1.14.2/internal/testingtproxy/000077500000000000000000000000001374111457300176425ustar00rootroot00000000000000ginkgo-1.14.2/internal/testingtproxy/testing_t_proxy.go000066400000000000000000000041601374111457300234330ustar00rootroot00000000000000package testingtproxy import ( "fmt" "io" ) type failFunc func(message string, callerSkip ...int) type skipFunc func(message string, callerSkip ...int) type failedFunc func() bool type nameFunc func() string func New(writer io.Writer, fail failFunc, skip skipFunc, failed failedFunc, name nameFunc, offset int) *ginkgoTestingTProxy { return &ginkgoTestingTProxy{ fail: fail, offset: offset, writer: writer, skip: skip, failed: failed, name: name, } } type ginkgoTestingTProxy struct { fail failFunc skip skipFunc failed failedFunc name nameFunc offset int writer io.Writer } func (t *ginkgoTestingTProxy) Cleanup(func()) { // No-op } func (t *ginkgoTestingTProxy) Error(args ...interface{}) { t.fail(fmt.Sprintln(args...), t.offset) } func (t *ginkgoTestingTProxy) Errorf(format string, args ...interface{}) { t.fail(fmt.Sprintf(format, args...), t.offset) } func (t *ginkgoTestingTProxy) Fail() { t.fail("failed", t.offset) } func (t *ginkgoTestingTProxy) FailNow() { t.fail("failed", t.offset) } func (t *ginkgoTestingTProxy) Failed() bool { return t.failed() } func (t *ginkgoTestingTProxy) Fatal(args ...interface{}) { t.fail(fmt.Sprintln(args...), t.offset) } func (t *ginkgoTestingTProxy) Fatalf(format string, args ...interface{}) { t.fail(fmt.Sprintf(format, args...), t.offset) } func (t *ginkgoTestingTProxy) Helper() { // No-op } func (t *ginkgoTestingTProxy) Log(args ...interface{}) { fmt.Fprintln(t.writer, args...) } func (t *ginkgoTestingTProxy) Logf(format string, args ...interface{}) { t.Log(fmt.Sprintf(format, args...)) } func (t *ginkgoTestingTProxy) Name() string { return t.name() } func (t *ginkgoTestingTProxy) Parallel() { // No-op } func (t *ginkgoTestingTProxy) Skip(args ...interface{}) { t.skip(fmt.Sprintln(args...), t.offset) } func (t *ginkgoTestingTProxy) SkipNow() { t.skip("skip", t.offset) } func (t *ginkgoTestingTProxy) Skipf(format string, args ...interface{}) { t.skip(fmt.Sprintf(format, args...), t.offset) } func (t *ginkgoTestingTProxy) Skipped() bool { return false } func (t *ginkgoTestingTProxy) TempDir() string { // No-op return "" } ginkgo-1.14.2/internal/testingtproxy/testingtproxy_suite_test.go000066400000000000000000000003241374111457300254030ustar00rootroot00000000000000package testingtproxy_test import ( "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) func TestTestingtproxy(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Testingtproxy Suite") } ginkgo-1.14.2/internal/testingtproxy/testingtproxy_test.go000066400000000000000000000070251374111457300241770ustar00rootroot00000000000000package testingtproxy_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "github.com/onsi/ginkgo/internal/testingtproxy" ) type messagedCall struct { message string callerSkip []int } var _ = Describe("Testingtproxy", func() { var t GinkgoTInterface var failFunc func(message string, callerSkip ...int) var skipFunc func(message string, callerSkip ...int) var failedFunc func() bool var nameFunc func() string var nameToReturn string var failedToReturn bool var failFuncCall messagedCall var skipFuncCall messagedCall var offset int var buf *gbytes.Buffer BeforeEach(func() { failFuncCall = messagedCall{} skipFuncCall = messagedCall{} nameToReturn = "" failedToReturn = false offset = 3 failFunc = func(message string, callerSkip ...int) { failFuncCall.message = message failFuncCall.callerSkip = callerSkip } skipFunc = func(message string, callerSkip ...int) { skipFuncCall.message = message skipFuncCall.callerSkip = callerSkip } failedFunc = func() bool { return failedToReturn } nameFunc = func() string { return nameToReturn } buf = gbytes.NewBuffer() t = testingtproxy.New(buf, failFunc, skipFunc, failedFunc, nameFunc, offset) }) It("ignores Cleanup", func() { GinkgoT().Cleanup(func() { panic("bam!") }) //is a no-op }) It("supports Error", func() { t.Error("a", 17) Ω(failFuncCall.message).Should(Equal("a 17\n")) Ω(failFuncCall.callerSkip).Should(Equal([]int{offset})) }) It("supports Errorf", func() { t.Errorf("%s %d!", "a", 17) Ω(failFuncCall.message).Should(Equal("a 17!")) Ω(failFuncCall.callerSkip).Should(Equal([]int{offset})) }) It("supports Fail", func() { t.Fail() Ω(failFuncCall.message).Should(Equal("failed")) Ω(failFuncCall.callerSkip).Should(Equal([]int{offset})) }) It("supports FailNow", func() { t.Fail() Ω(failFuncCall.message).Should(Equal("failed")) Ω(failFuncCall.callerSkip).Should(Equal([]int{offset})) }) It("supports Fatal", func() { t.Fatal("a", 17) Ω(failFuncCall.message).Should(Equal("a 17\n")) Ω(failFuncCall.callerSkip).Should(Equal([]int{offset})) }) It("supports Fatalf", func() { t.Fatalf("%s %d!", "a", 17) Ω(failFuncCall.message).Should(Equal("a 17!")) Ω(failFuncCall.callerSkip).Should(Equal([]int{offset})) }) It("ignores Helper", func() { GinkgoT().Helper() //is a no-op }) It("supports Log", func() { t.Log("a", 17) Ω(string(buf.Contents())).Should(Equal("a 17\n")) }) It("supports Logf", func() { t.Logf("%s %d!", "a", 17) Ω(string(buf.Contents())).Should(Equal("a 17!\n")) }) It("supports Name", func() { nameToReturn = "C.S. Lewis" Ω(t.Name()).Should(Equal("C.S. Lewis")) Ω(GinkgoT().Name()).Should(ContainSubstring("supports Name")) }) It("ignores Parallel", func() { GinkgoT().Parallel() //is a no-op }) It("supports Skip", func() { t.Skip("a", 17) Ω(skipFuncCall.message).Should(Equal("a 17\n")) Ω(skipFuncCall.callerSkip).Should(Equal([]int{offset})) }) It("supports SkipNow", func() { t.SkipNow() Ω(skipFuncCall.message).Should(Equal("skip")) Ω(skipFuncCall.callerSkip).Should(Equal([]int{offset})) }) It("supports Skipf", func() { t.Skipf("%s %d!", "a", 17) Ω(skipFuncCall.message).Should(Equal("a 17!")) Ω(skipFuncCall.callerSkip).Should(Equal([]int{offset})) }) It("always returns false for Skipped", func() { Ω(GinkgoT().Skipped()).Should(BeFalse()) }) It("returns empty string for TempDir", func() { Ω(GinkgoT().TempDir()).Should(Equal("")) }) }) ginkgo-1.14.2/internal/writer/000077500000000000000000000000001374111457300162135ustar00rootroot00000000000000ginkgo-1.14.2/internal/writer/fake_writer.go000066400000000000000000000015271374111457300210510ustar00rootroot00000000000000package writer type FakeGinkgoWriter struct { EventStream []string } func NewFake() *FakeGinkgoWriter { return &FakeGinkgoWriter{ EventStream: []string{}, } } func (writer *FakeGinkgoWriter) AddEvent(event string) { writer.EventStream = append(writer.EventStream, event) } func (writer *FakeGinkgoWriter) Truncate() { writer.EventStream = append(writer.EventStream, "TRUNCATE") } func (writer *FakeGinkgoWriter) DumpOut() { writer.EventStream = append(writer.EventStream, "DUMP") } func (writer *FakeGinkgoWriter) DumpOutWithHeader(header string) { writer.EventStream = append(writer.EventStream, "DUMP_WITH_HEADER: "+header) } func (writer *FakeGinkgoWriter) Bytes() []byte { writer.EventStream = append(writer.EventStream, "BYTES") return nil } func (writer *FakeGinkgoWriter) Write(data []byte) (n int, err error) { return 0, nil } ginkgo-1.14.2/internal/writer/writer.go000066400000000000000000000026671374111457300200710ustar00rootroot00000000000000package writer import ( "bytes" "io" "sync" ) type WriterInterface interface { io.Writer Truncate() DumpOut() DumpOutWithHeader(header string) Bytes() []byte } type Writer struct { buffer *bytes.Buffer outWriter io.Writer lock *sync.Mutex stream bool redirector io.Writer } func New(outWriter io.Writer) *Writer { return &Writer{ buffer: &bytes.Buffer{}, lock: &sync.Mutex{}, outWriter: outWriter, stream: true, } } func (w *Writer) AndRedirectTo(writer io.Writer) { w.redirector = writer } func (w *Writer) SetStream(stream bool) { w.lock.Lock() defer w.lock.Unlock() w.stream = stream } func (w *Writer) Write(b []byte) (n int, err error) { w.lock.Lock() defer w.lock.Unlock() n, err = w.buffer.Write(b) if w.redirector != nil { w.redirector.Write(b) } if w.stream { return w.outWriter.Write(b) } return n, err } func (w *Writer) Truncate() { w.lock.Lock() defer w.lock.Unlock() w.buffer.Reset() } func (w *Writer) DumpOut() { w.lock.Lock() defer w.lock.Unlock() if !w.stream { w.buffer.WriteTo(w.outWriter) } } func (w *Writer) Bytes() []byte { w.lock.Lock() defer w.lock.Unlock() b := w.buffer.Bytes() copied := make([]byte, len(b)) copy(copied, b) return copied } func (w *Writer) DumpOutWithHeader(header string) { w.lock.Lock() defer w.lock.Unlock() if !w.stream && w.buffer.Len() > 0 { w.outWriter.Write([]byte(header)) w.buffer.WriteTo(w.outWriter) } } ginkgo-1.14.2/internal/writer/writer_suite_test.go000066400000000000000000000002771374111457300223340ustar00rootroot00000000000000package writer_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestWriter(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Writer Suite") } ginkgo-1.14.2/internal/writer/writer_test.go000066400000000000000000000034411374111457300211170ustar00rootroot00000000000000package writer_test import ( "github.com/onsi/gomega/gbytes" . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/internal/writer" . "github.com/onsi/gomega" ) var _ = Describe("Writer", func() { var writer *Writer var out *gbytes.Buffer BeforeEach(func() { out = gbytes.NewBuffer() writer = New(out) }) It("should stream directly to the outbuffer by default", func() { writer.Write([]byte("foo")) Ω(out).Should(gbytes.Say("foo")) }) It("should not emit the header when asked to DumpOutWitHeader", func() { writer.Write([]byte("foo")) writer.DumpOutWithHeader("my header") Ω(out).ShouldNot(gbytes.Say("my header")) Ω(out).Should(gbytes.Say("foo")) }) Context("when told not to stream", func() { BeforeEach(func() { writer.SetStream(false) }) It("should only write to the buffer when told to DumpOut", func() { writer.Write([]byte("foo")) Ω(out).ShouldNot(gbytes.Say("foo")) writer.DumpOut() Ω(out).Should(gbytes.Say("foo")) }) It("should truncate the internal buffer when told to truncate", func() { writer.Write([]byte("foo")) writer.Truncate() writer.DumpOut() Ω(out).ShouldNot(gbytes.Say("foo")) writer.Write([]byte("bar")) writer.DumpOut() Ω(out).Should(gbytes.Say("bar")) }) Describe("emitting a header", func() { Context("when the buffer has content", func() { It("should emit the header followed by the content", func() { writer.Write([]byte("foo")) writer.DumpOutWithHeader("my header") Ω(out).Should(gbytes.Say("my header")) Ω(out).Should(gbytes.Say("foo")) }) }) Context("when the buffer has no content", func() { It("should not emit the header", func() { writer.DumpOutWithHeader("my header") Ω(out).ShouldNot(gbytes.Say("my header")) }) }) }) }) }) ginkgo-1.14.2/reporters/000077500000000000000000000000001374111457300151105ustar00rootroot00000000000000ginkgo-1.14.2/reporters/default_reporter.go000066400000000000000000000072411374111457300210110ustar00rootroot00000000000000/* Ginkgo's Default Reporter A number of command line flags are available to tweak Ginkgo's default output. These are documented [here](http://onsi.github.io/ginkgo/#running_tests) */ package reporters import ( "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/reporters/stenographer" "github.com/onsi/ginkgo/types" ) type DefaultReporter struct { config config.DefaultReporterConfigType stenographer stenographer.Stenographer specSummaries []*types.SpecSummary } func NewDefaultReporter(config config.DefaultReporterConfigType, stenographer stenographer.Stenographer) *DefaultReporter { return &DefaultReporter{ config: config, stenographer: stenographer, } } func (reporter *DefaultReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) { reporter.stenographer.AnnounceSuite(summary.SuiteDescription, config.RandomSeed, config.RandomizeAllSpecs, reporter.config.Succinct) if config.ParallelTotal > 1 { reporter.stenographer.AnnounceParallelRun(config.ParallelNode, config.ParallelTotal, reporter.config.Succinct) } else { reporter.stenographer.AnnounceNumberOfSpecs(summary.NumberOfSpecsThatWillBeRun, summary.NumberOfTotalSpecs, reporter.config.Succinct) } } func (reporter *DefaultReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) { if setupSummary.State != types.SpecStatePassed { reporter.stenographer.AnnounceBeforeSuiteFailure(setupSummary, reporter.config.Succinct, reporter.config.FullTrace) } } func (reporter *DefaultReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) { if setupSummary.State != types.SpecStatePassed { reporter.stenographer.AnnounceAfterSuiteFailure(setupSummary, reporter.config.Succinct, reporter.config.FullTrace) } } func (reporter *DefaultReporter) SpecWillRun(specSummary *types.SpecSummary) { if reporter.config.Verbose && !reporter.config.Succinct && specSummary.State != types.SpecStatePending && specSummary.State != types.SpecStateSkipped { reporter.stenographer.AnnounceSpecWillRun(specSummary) } } func (reporter *DefaultReporter) SpecDidComplete(specSummary *types.SpecSummary) { switch specSummary.State { case types.SpecStatePassed: if specSummary.IsMeasurement { reporter.stenographer.AnnounceSuccessfulMeasurement(specSummary, reporter.config.Succinct) } else if specSummary.RunTime.Seconds() >= reporter.config.SlowSpecThreshold { reporter.stenographer.AnnounceSuccessfulSlowSpec(specSummary, reporter.config.Succinct) } else { reporter.stenographer.AnnounceSuccessfulSpec(specSummary) if reporter.config.ReportPassed { reporter.stenographer.AnnounceCapturedOutput(specSummary.CapturedOutput) } } case types.SpecStatePending: reporter.stenographer.AnnouncePendingSpec(specSummary, reporter.config.NoisyPendings && !reporter.config.Succinct) case types.SpecStateSkipped: reporter.stenographer.AnnounceSkippedSpec(specSummary, reporter.config.Succinct || !reporter.config.NoisySkippings, reporter.config.FullTrace) case types.SpecStateTimedOut: reporter.stenographer.AnnounceSpecTimedOut(specSummary, reporter.config.Succinct, reporter.config.FullTrace) case types.SpecStatePanicked: reporter.stenographer.AnnounceSpecPanicked(specSummary, reporter.config.Succinct, reporter.config.FullTrace) case types.SpecStateFailed: reporter.stenographer.AnnounceSpecFailed(specSummary, reporter.config.Succinct, reporter.config.FullTrace) } reporter.specSummaries = append(reporter.specSummaries, specSummary) } func (reporter *DefaultReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { reporter.stenographer.SummarizeFailures(reporter.specSummaries) reporter.stenographer.AnnounceSpecRunCompletion(summary, reporter.config.Succinct) } ginkgo-1.14.2/reporters/default_reporter_test.go000066400000000000000000000306621374111457300220530ustar00rootroot00000000000000package reporters_test import ( "time" . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/reporters" st "github.com/onsi/ginkgo/reporters/stenographer" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" ) var _ = Describe("DefaultReporter", func() { var ( reporter *reporters.DefaultReporter reporterConfig config.DefaultReporterConfigType stenographer *st.FakeStenographer ginkgoConfig config.GinkgoConfigType suite *types.SuiteSummary spec *types.SpecSummary ) BeforeEach(func() { stenographer = st.NewFakeStenographer() reporterConfig = config.DefaultReporterConfigType{ NoColor: false, SlowSpecThreshold: 0.1, NoisyPendings: false, NoisySkippings: false, Verbose: true, FullTrace: true, } reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) }) call := st.NewFakeStenographerCall Describe("SpecSuiteWillBegin", func() { BeforeEach(func() { suite = &types.SuiteSummary{ SuiteDescription: "A Sweet Suite", NumberOfTotalSpecs: 10, NumberOfSpecsThatWillBeRun: 8, } ginkgoConfig = config.GinkgoConfigType{ RandomSeed: 1138, RandomizeAllSpecs: true, } }) Context("when a serial (non-parallel) suite begins", func() { BeforeEach(func() { ginkgoConfig.ParallelTotal = 1 reporter.SpecSuiteWillBegin(ginkgoConfig, suite) }) It("should announce the suite, then announce the number of specs", func() { Ω(stenographer.Calls()).Should(HaveLen(2)) Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuite", "A Sweet Suite", ginkgoConfig.RandomSeed, true, false))) Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceNumberOfSpecs", 8, 10, false))) }) }) Context("when a parallel suite begins", func() { BeforeEach(func() { ginkgoConfig.ParallelTotal = 2 ginkgoConfig.ParallelNode = 1 suite.NumberOfSpecsBeforeParallelization = 20 reporter.SpecSuiteWillBegin(ginkgoConfig, suite) }) It("should announce the suite, announce that it's a parallel run, then announce the number of specs", func() { Ω(stenographer.Calls()).Should(HaveLen(2)) Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuite", "A Sweet Suite", ginkgoConfig.RandomSeed, true, false))) Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceParallelRun", 1, 2, false))) }) }) }) Describe("BeforeSuiteDidRun", func() { Context("when the BeforeSuite passes", func() { It("should announce nothing", func() { reporter.BeforeSuiteDidRun(&types.SetupSummary{ State: types.SpecStatePassed, }) Ω(stenographer.Calls()).Should(BeEmpty()) }) }) Context("when the BeforeSuite fails", func() { It("should announce the failure", func() { summary := &types.SetupSummary{ State: types.SpecStateFailed, } reporter.BeforeSuiteDidRun(summary) Ω(stenographer.Calls()).Should(HaveLen(1)) Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceBeforeSuiteFailure", summary, false, true))) }) }) }) Describe("AfterSuiteDidRun", func() { Context("when the AfterSuite passes", func() { It("should announce nothing", func() { reporter.AfterSuiteDidRun(&types.SetupSummary{ State: types.SpecStatePassed, }) Ω(stenographer.Calls()).Should(BeEmpty()) }) }) Context("when the AfterSuite fails", func() { It("should announce the failure", func() { summary := &types.SetupSummary{ State: types.SpecStateFailed, } reporter.AfterSuiteDidRun(summary) Ω(stenographer.Calls()).Should(HaveLen(1)) Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceAfterSuiteFailure", summary, false, true))) }) }) }) Describe("SpecWillRun", func() { Context("When running in verbose mode", func() { Context("and the spec will run", func() { BeforeEach(func() { spec = &types.SpecSummary{} reporter.SpecWillRun(spec) }) It("should announce that the spec will run", func() { Ω(stenographer.Calls()).Should(HaveLen(1)) Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecWillRun", spec))) }) }) Context("and the spec will not run", func() { Context("because it is pending", func() { BeforeEach(func() { spec = &types.SpecSummary{ State: types.SpecStatePending, } reporter.SpecWillRun(spec) }) It("should announce nothing", func() { Ω(stenographer.Calls()).Should(BeEmpty()) }) }) Context("because it is skipped", func() { BeforeEach(func() { spec = &types.SpecSummary{ State: types.SpecStateSkipped, } reporter.SpecWillRun(spec) }) It("should announce nothing", func() { Ω(stenographer.Calls()).Should(BeEmpty()) }) }) }) }) Context("When running in verbose & succinct mode", func() { BeforeEach(func() { reporterConfig.Succinct = true reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) spec = &types.SpecSummary{} reporter.SpecWillRun(spec) }) It("should announce nothing", func() { Ω(stenographer.Calls()).Should(BeEmpty()) }) }) Context("When not running in verbose mode", func() { BeforeEach(func() { reporterConfig.Verbose = false reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) spec = &types.SpecSummary{} reporter.SpecWillRun(spec) }) It("should announce nothing", func() { Ω(stenographer.Calls()).Should(BeEmpty()) }) }) }) Describe("SpecDidComplete", func() { JustBeforeEach(func() { reporter.SpecDidComplete(spec) }) BeforeEach(func() { spec = &types.SpecSummary{} }) Context("When the spec passed", func() { BeforeEach(func() { spec.State = types.SpecStatePassed }) Context("When the spec was a measurement", func() { BeforeEach(func() { spec.IsMeasurement = true }) It("should announce the measurement", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccessfulMeasurement", spec, false))) }) }) Context("When the spec is slow", func() { BeforeEach(func() { spec.RunTime = time.Second }) It("should announce that it was slow", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccessfulSlowSpec", spec, false))) }) }) Context("When the spec is successful", func() { It("should announce the successful spec", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccessfulSpec", spec))) }) Context("When ReportPassed flag is set", func() { BeforeEach(func() { reporterConfig.ReportPassed = true reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) spec.CapturedOutput = "test scenario" }) It("should announce the captured output", func() { Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceCapturedOutput", spec.CapturedOutput))) }) }) }) }) Context("When the spec is pending", func() { BeforeEach(func() { spec.State = types.SpecStatePending }) It("should announce the pending spec, succinctly", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnouncePendingSpec", spec, false))) }) }) Context("When the spec is skipped", func() { BeforeEach(func() { spec.State = types.SpecStateSkipped }) It("should announce the skipped spec, succinctly", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, true, true))) }) }) Context("When the spec timed out", func() { BeforeEach(func() { spec.State = types.SpecStateTimedOut }) It("should announce the timedout spec", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecTimedOut", spec, false, true))) }) }) Context("When the spec panicked", func() { BeforeEach(func() { spec.State = types.SpecStatePanicked }) It("should announce the panicked spec", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecPanicked", spec, false, true))) }) }) Context("When the spec failed", func() { BeforeEach(func() { spec.State = types.SpecStateFailed }) It("should announce the failed spec", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecFailed", spec, false, true))) }) }) Context("in noisy pendings mode", func() { BeforeEach(func() { reporterConfig.Succinct = false reporterConfig.NoisyPendings = true reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) }) Context("When the spec is pending", func() { BeforeEach(func() { spec.State = types.SpecStatePending }) It("should announce the pending spec, noisily", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnouncePendingSpec", spec, true))) }) }) }) Context("in noisy skippings mode", func() { BeforeEach(func() { reporterConfig.Succinct = false reporterConfig.NoisySkippings = true reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) }) Context("When the spec is skipped", func() { BeforeEach(func() { spec.State = types.SpecStateSkipped }) It("should announce the skipped spec, noisily", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, false, true))) }) }) }) Context("in succinct mode", func() { BeforeEach(func() { reporterConfig.Succinct = true reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) }) Context("When the spec passed", func() { BeforeEach(func() { spec.State = types.SpecStatePassed }) Context("When the spec was a measurement", func() { BeforeEach(func() { spec.IsMeasurement = true }) It("should announce the measurement", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccessfulMeasurement", spec, true))) }) }) Context("When the spec is slow", func() { BeforeEach(func() { spec.RunTime = time.Second }) It("should announce that it was slow", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccessfulSlowSpec", spec, true))) }) }) Context("When the spec is successful", func() { It("should announce the successful spec", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccessfulSpec", spec))) }) Context("When ReportPassed flag is set", func() { BeforeEach(func() { reporterConfig.ReportPassed = true reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) spec.CapturedOutput = "test scenario" }) It("should announce the captured output", func() { Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceCapturedOutput", spec.CapturedOutput))) }) }) }) }) Context("When the spec is pending", func() { BeforeEach(func() { spec.State = types.SpecStatePending }) It("should announce the pending spec, succinctly", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnouncePendingSpec", spec, false))) }) }) Context("When the spec is skipped", func() { BeforeEach(func() { spec.State = types.SpecStateSkipped }) It("should announce the skipped spec", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, true, true))) }) }) Context("When the spec timed out", func() { BeforeEach(func() { spec.State = types.SpecStateTimedOut }) It("should announce the timedout spec", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecTimedOut", spec, true, true))) }) }) Context("When the spec panicked", func() { BeforeEach(func() { spec.State = types.SpecStatePanicked }) It("should announce the panicked spec", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecPanicked", spec, true, true))) }) }) Context("When the spec failed", func() { BeforeEach(func() { spec.State = types.SpecStateFailed }) It("should announce the failed spec", func() { Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecFailed", spec, true, true))) }) }) }) }) Describe("SpecSuiteDidEnd", func() { BeforeEach(func() { suite = &types.SuiteSummary{} reporter.SpecSuiteDidEnd(suite) }) It("should announce the spec run's completion", func() { Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceSpecRunCompletion", suite, false))) }) }) }) ginkgo-1.14.2/reporters/fake_reporter.go000066400000000000000000000032771374111457300203000ustar00rootroot00000000000000package reporters import ( "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/types" ) //FakeReporter is useful for testing purposes type FakeReporter struct { Config config.GinkgoConfigType BeginSummary *types.SuiteSummary BeforeSuiteSummary *types.SetupSummary SpecWillRunSummaries []*types.SpecSummary SpecSummaries []*types.SpecSummary AfterSuiteSummary *types.SetupSummary EndSummary *types.SuiteSummary SpecWillRunStub func(specSummary *types.SpecSummary) SpecDidCompleteStub func(specSummary *types.SpecSummary) } func NewFakeReporter() *FakeReporter { return &FakeReporter{ SpecWillRunSummaries: make([]*types.SpecSummary, 0), SpecSummaries: make([]*types.SpecSummary, 0), } } func (fakeR *FakeReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) { fakeR.Config = config fakeR.BeginSummary = summary } func (fakeR *FakeReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) { fakeR.BeforeSuiteSummary = setupSummary } func (fakeR *FakeReporter) SpecWillRun(specSummary *types.SpecSummary) { if fakeR.SpecWillRunStub != nil { fakeR.SpecWillRunStub(specSummary) } fakeR.SpecWillRunSummaries = append(fakeR.SpecWillRunSummaries, specSummary) } func (fakeR *FakeReporter) SpecDidComplete(specSummary *types.SpecSummary) { if fakeR.SpecDidCompleteStub != nil { fakeR.SpecDidCompleteStub(specSummary) } fakeR.SpecSummaries = append(fakeR.SpecSummaries, specSummary) } func (fakeR *FakeReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) { fakeR.AfterSuiteSummary = setupSummary } func (fakeR *FakeReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { fakeR.EndSummary = summary } ginkgo-1.14.2/reporters/junit_reporter.go000066400000000000000000000135441374111457300205210ustar00rootroot00000000000000/* JUnit XML Reporter for Ginkgo For usage instructions: http://onsi.github.io/ginkgo/#generating_junit_xml_output */ package reporters import ( "encoding/xml" "fmt" "math" "os" "path/filepath" "strings" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/types" ) type JUnitTestSuite struct { XMLName xml.Name `xml:"testsuite"` TestCases []JUnitTestCase `xml:"testcase"` Name string `xml:"name,attr"` Tests int `xml:"tests,attr"` Failures int `xml:"failures,attr"` Errors int `xml:"errors,attr"` Time float64 `xml:"time,attr"` } type JUnitTestCase struct { Name string `xml:"name,attr"` ClassName string `xml:"classname,attr"` PassedMessage *JUnitPassedMessage `xml:"passed,omitempty"` FailureMessage *JUnitFailureMessage `xml:"failure,omitempty"` Skipped *JUnitSkipped `xml:"skipped,omitempty"` Time float64 `xml:"time,attr"` SystemOut string `xml:"system-out,omitempty"` } type JUnitPassedMessage struct { Message string `xml:",chardata"` } type JUnitFailureMessage struct { Type string `xml:"type,attr"` Message string `xml:",chardata"` } type JUnitSkipped struct { Message string `xml:",chardata"` } type JUnitReporter struct { suite JUnitTestSuite filename string testSuiteName string ReporterConfig config.DefaultReporterConfigType } //NewJUnitReporter creates a new JUnit XML reporter. The XML will be stored in the passed in filename. func NewJUnitReporter(filename string) *JUnitReporter { return &JUnitReporter{ filename: filename, } } func (reporter *JUnitReporter) SpecSuiteWillBegin(ginkgoConfig config.GinkgoConfigType, summary *types.SuiteSummary) { reporter.suite = JUnitTestSuite{ Name: summary.SuiteDescription, TestCases: []JUnitTestCase{}, } reporter.testSuiteName = summary.SuiteDescription reporter.ReporterConfig = config.DefaultReporterConfig } func (reporter *JUnitReporter) SpecWillRun(specSummary *types.SpecSummary) { } func (reporter *JUnitReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) { reporter.handleSetupSummary("BeforeSuite", setupSummary) } func (reporter *JUnitReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) { reporter.handleSetupSummary("AfterSuite", setupSummary) } func failureMessage(failure types.SpecFailure) string { return fmt.Sprintf("%s\n%s\n%s", failure.ComponentCodeLocation.String(), failure.Message, failure.Location.String()) } func (reporter *JUnitReporter) handleSetupSummary(name string, setupSummary *types.SetupSummary) { if setupSummary.State != types.SpecStatePassed { testCase := JUnitTestCase{ Name: name, ClassName: reporter.testSuiteName, } testCase.FailureMessage = &JUnitFailureMessage{ Type: reporter.failureTypeForState(setupSummary.State), Message: failureMessage(setupSummary.Failure), } testCase.SystemOut = setupSummary.CapturedOutput testCase.Time = setupSummary.RunTime.Seconds() reporter.suite.TestCases = append(reporter.suite.TestCases, testCase) } } func (reporter *JUnitReporter) SpecDidComplete(specSummary *types.SpecSummary) { testCase := JUnitTestCase{ Name: strings.Join(specSummary.ComponentTexts[1:], " "), ClassName: reporter.testSuiteName, } if reporter.ReporterConfig.ReportPassed && specSummary.State == types.SpecStatePassed { testCase.PassedMessage = &JUnitPassedMessage{ Message: specSummary.CapturedOutput, } } if specSummary.State == types.SpecStateFailed || specSummary.State == types.SpecStateTimedOut || specSummary.State == types.SpecStatePanicked { testCase.FailureMessage = &JUnitFailureMessage{ Type: reporter.failureTypeForState(specSummary.State), Message: failureMessage(specSummary.Failure), } if specSummary.State == types.SpecStatePanicked { testCase.FailureMessage.Message += fmt.Sprintf("\n\nPanic: %s\n\nFull stack:\n%s", specSummary.Failure.ForwardedPanic, specSummary.Failure.Location.FullStackTrace) } testCase.SystemOut = specSummary.CapturedOutput } if specSummary.State == types.SpecStateSkipped || specSummary.State == types.SpecStatePending { testCase.Skipped = &JUnitSkipped{} if specSummary.Failure.Message != "" { testCase.Skipped.Message = failureMessage(specSummary.Failure) } } testCase.Time = specSummary.RunTime.Seconds() reporter.suite.TestCases = append(reporter.suite.TestCases, testCase) } func (reporter *JUnitReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { reporter.suite.Tests = summary.NumberOfSpecsThatWillBeRun reporter.suite.Time = math.Trunc(summary.RunTime.Seconds()*1000) / 1000 reporter.suite.Failures = summary.NumberOfFailedSpecs reporter.suite.Errors = 0 if reporter.ReporterConfig.ReportFile != "" { reporter.filename = reporter.ReporterConfig.ReportFile fmt.Printf("\nJUnit path was configured: %s\n", reporter.filename) } filePath, _ := filepath.Abs(reporter.filename) dirPath := filepath.Dir(filePath) err := os.MkdirAll(dirPath, os.ModePerm) if err != nil { fmt.Printf("\nFailed to create JUnit directory: %s\n\t%s", filePath, err.Error()) } file, err := os.Create(filePath) if err != nil { fmt.Fprintf(os.Stderr, "Failed to create JUnit report file: %s\n\t%s", filePath, err.Error()) } defer file.Close() file.WriteString(xml.Header) encoder := xml.NewEncoder(file) encoder.Indent(" ", " ") err = encoder.Encode(reporter.suite) if err == nil { fmt.Fprintf(os.Stdout, "\nJUnit report was created: %s\n", filePath) } else { fmt.Fprintf(os.Stderr,"\nFailed to generate JUnit report data:\n\t%s", err.Error()) } } func (reporter *JUnitReporter) failureTypeForState(state types.SpecState) string { switch state { case types.SpecStateFailed: return "Failure" case types.SpecStateTimedOut: return "Timeout" case types.SpecStatePanicked: return "Panic" default: return "" } } ginkgo-1.14.2/reporters/junit_reporter_test.go000066400000000000000000000263711374111457300215620ustar00rootroot00000000000000package reporters_test import ( "encoding/xml" "io/ioutil" "os" "time" . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" ) var _ = Describe("JUnit Reporter", func() { var ( outputFile string reporter *reporters.JUnitReporter ) testSuiteTime := 12456999 * time.Microsecond reportedSuiteTime := 12.456 readOutputFile := func() reporters.JUnitTestSuite { bytes, err := ioutil.ReadFile(outputFile) Expect(err).ToNot(HaveOccurred()) var suite reporters.JUnitTestSuite err = xml.Unmarshal(bytes, &suite) Expect(err).ToNot(HaveOccurred()) return suite } BeforeEach(func() { f, err := ioutil.TempFile("", "output") Expect(err).ToNot(HaveOccurred()) f.Close() outputFile = f.Name() reporter = reporters.NewJUnitReporter(outputFile) reporter.SpecSuiteWillBegin(config.GinkgoConfigType{}, &types.SuiteSummary{ SuiteDescription: "My test suite", NumberOfSpecsThatWillBeRun: 1, }) }) AfterEach(func() { os.RemoveAll(outputFile) }) Describe("when configured with ReportPassed, and test has passed", func() { BeforeEach(func() { beforeSuite := &types.SetupSummary{ State: types.SpecStatePassed, } reporter.BeforeSuiteDidRun(beforeSuite) afterSuite := &types.SetupSummary{ State: types.SpecStatePassed, } reporter.AfterSuiteDidRun(afterSuite) // Set the ReportPassed config flag, in order to show captured output when tests have passed. reporter.ReporterConfig.ReportPassed = true spec := &types.SpecSummary{ ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, CapturedOutput: "Test scenario...", State: types.SpecStatePassed, RunTime: 5 * time.Second, } reporter.SpecWillRun(spec) reporter.SpecDidComplete(spec) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 0, RunTime: testSuiteTime, }) }) It("should record the test as passing, including detailed output", func() { output := readOutputFile() Expect(output.Name).To(Equal("My test suite")) Expect(output.Tests).To(Equal(1)) Expect(output.Failures).To(Equal(0)) Expect(output.Time).To(Equal(reportedSuiteTime)) Expect(output.Errors).To(Equal(0)) Expect(output.TestCases).To(HaveLen(1)) Expect(output.TestCases[0].Name).To(Equal("A B C")) Expect(output.TestCases[0].ClassName).To(Equal("My test suite")) Expect(output.TestCases[0].FailureMessage).To(BeNil()) Expect(output.TestCases[0].Skipped).To(BeNil()) Expect(output.TestCases[0].Time).To(Equal(5.0)) Expect(output.TestCases[0].PassedMessage.Message).To(ContainSubstring("Test scenario")) }) }) Describe("when configured with ReportFile ", func() { BeforeEach(func() { beforeSuite := &types.SetupSummary{ State: types.SpecStatePassed, } reporter.BeforeSuiteDidRun(beforeSuite) afterSuite := &types.SetupSummary{ State: types.SpecStatePassed, } reporter.AfterSuiteDidRun(afterSuite) reporter.SpecSuiteWillBegin(config.GinkgoConfigType{}, &types.SuiteSummary{ SuiteDescription: "My test suite", NumberOfSpecsThatWillBeRun: 1, }) // Set the ReportFile config flag with a new directory and new file path to be created. d, err := ioutil.TempDir("", "new-junit-dir") Expect(err).ToNot(HaveOccurred()) f, err := ioutil.TempFile(d, "output") Expect(err).ToNot(HaveOccurred()) f.Close() outputFile = f.Name() err = os.RemoveAll(d) Expect(err).ToNot(HaveOccurred()) reporter.ReporterConfig.ReportFile = outputFile spec := &types.SpecSummary{ ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, CapturedOutput: "Test scenario...", State: types.SpecStatePassed, RunTime: 5 * time.Second, } reporter.SpecWillRun(spec) reporter.SpecDidComplete(spec) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 0, RunTime: testSuiteTime, }) }) It("should create the report (and parent directories) as specified by ReportFile path", func() { output := readOutputFile() Expect(output.Name).To(Equal("My test suite")) Expect(output.Tests).To(Equal(1)) Expect(output.Failures).To(Equal(0)) Expect(output.Time).To(Equal(reportedSuiteTime)) Expect(output.Errors).To(Equal(0)) Expect(output.TestCases).To(HaveLen(1)) Expect(output.TestCases[0].Name).To(Equal("A B C")) Expect(output.TestCases[0].ClassName).To(Equal("My test suite")) Expect(output.TestCases[0].FailureMessage).To(BeNil()) Expect(output.TestCases[0].Skipped).To(BeNil()) Expect(output.TestCases[0].Time).To(Equal(5.0)) }) }) Describe("when the BeforeSuite fails", func() { var beforeSuite *types.SetupSummary BeforeEach(func() { beforeSuite = &types.SetupSummary{ State: types.SpecStateFailed, RunTime: 3 * time.Second, Failure: types.SpecFailure{ Message: "failed to setup", ComponentCodeLocation: codelocation.New(0), Location: codelocation.New(2), }, } reporter.BeforeSuiteDidRun(beforeSuite) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 1, RunTime: testSuiteTime, }) }) It("should record the test as having failed", func() { output := readOutputFile() Expect(output.Name).To(Equal("My test suite")) Expect(output.Tests).To(Equal(1)) Expect(output.Failures).To(Equal(1)) Expect(output.Time).To(Equal(reportedSuiteTime)) Expect(output.Errors).To(Equal(0)) Expect(output.TestCases[0].Name).To(Equal("BeforeSuite")) Expect(output.TestCases[0].Time).To(Equal(3.0)) Expect(output.TestCases[0].ClassName).To(Equal("My test suite")) Expect(output.TestCases[0].FailureMessage.Type).To(Equal("Failure")) Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring("failed to setup")) Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring(beforeSuite.Failure.ComponentCodeLocation.String())) Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring(beforeSuite.Failure.Location.String())) Expect(output.TestCases[0].Skipped).To(BeNil()) }) }) Describe("when the AfterSuite fails", func() { var afterSuite *types.SetupSummary BeforeEach(func() { afterSuite = &types.SetupSummary{ State: types.SpecStateFailed, RunTime: 3 * time.Second, Failure: types.SpecFailure{ Message: "failed to setup", ComponentCodeLocation: codelocation.New(0), Location: codelocation.New(2), }, } reporter.AfterSuiteDidRun(afterSuite) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 1, RunTime: testSuiteTime, }) }) It("should record the test as having failed", func() { output := readOutputFile() Expect(output.Name).To(Equal("My test suite")) Expect(output.Tests).To(Equal(1)) Expect(output.Failures).To(Equal(1)) Expect(output.Time).To(Equal(reportedSuiteTime)) Expect(output.Errors).To(Equal(0)) Expect(output.TestCases[0].Name).To(Equal("AfterSuite")) Expect(output.TestCases[0].Time).To(Equal(3.0)) Expect(output.TestCases[0].ClassName).To(Equal("My test suite")) Expect(output.TestCases[0].FailureMessage.Type).To(Equal("Failure")) Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring("failed to setup")) Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring(afterSuite.Failure.ComponentCodeLocation.String())) Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring(afterSuite.Failure.Location.String())) Expect(output.TestCases[0].Skipped).To(BeNil()) }) }) specStateCases := []struct { state types.SpecState message string // Only for SpecStatePanicked. forwardedPanic string }{ {types.SpecStateFailed, "Failure", ""}, {types.SpecStateTimedOut, "Timeout", ""}, {types.SpecStatePanicked, "Panic", "artifical panic"}, } for _, specStateCase := range specStateCases { specStateCase := specStateCase Describe("a failing test", func() { var spec *types.SpecSummary BeforeEach(func() { spec = &types.SpecSummary{ ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, State: specStateCase.state, RunTime: 5 * time.Second, Failure: types.SpecFailure{ ComponentCodeLocation: codelocation.New(0), Location: codelocation.New(2), Message: "I failed", ForwardedPanic: specStateCase.forwardedPanic, }, } reporter.SpecWillRun(spec) reporter.SpecDidComplete(spec) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 1, RunTime: testSuiteTime, }) }) It("should record test as failing", func() { output := readOutputFile() Expect(output.Name).To(Equal("My test suite")) Expect(output.Tests).To(Equal(1)) Expect(output.Failures).To(Equal(1)) Expect(output.Time).To(Equal(reportedSuiteTime)) Expect(output.Errors).To(Equal(0)) Expect(output.TestCases[0].Name).To(Equal("A B C")) Expect(output.TestCases[0].ClassName).To(Equal("My test suite")) Expect(output.TestCases[0].FailureMessage.Type).To(Equal(specStateCase.message)) Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring("I failed")) Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring(spec.Failure.ComponentCodeLocation.String())) Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring(spec.Failure.Location.String())) Expect(output.TestCases[0].Skipped).To(BeNil()) if specStateCase.state == types.SpecStatePanicked { Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring("\nPanic: " + specStateCase.forwardedPanic + "\n")) Expect(output.TestCases[0].FailureMessage.Message).To(ContainSubstring("\nFull stack:\n" + spec.Failure.Location.FullStackTrace)) } }) }) } for _, specStateCase := range []types.SpecState{types.SpecStatePending, types.SpecStateSkipped} { specStateCase := specStateCase Describe("a skipped test", func() { var spec *types.SpecSummary BeforeEach(func() { spec = &types.SpecSummary{ ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, State: specStateCase, RunTime: 5 * time.Second, Failure: types.SpecFailure{ Message: "skipped reason", }, } reporter.SpecWillRun(spec) reporter.SpecDidComplete(spec) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 0, RunTime: testSuiteTime, }) }) It("should record test as failing", func() { output := readOutputFile() Expect(output.Tests).To(Equal(1)) Expect(output.Failures).To(Equal(0)) Expect(output.Time).To(Equal(reportedSuiteTime)) Expect(output.Errors).To(Equal(0)) Expect(output.TestCases[0].Name).To(Equal("A B C")) Expect(output.TestCases[0].Skipped.Message).To(ContainSubstring("skipped reason")) }) }) } }) ginkgo-1.14.2/reporters/reporter.go000066400000000000000000000007021374111457300173000ustar00rootroot00000000000000package reporters import ( "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/types" ) type Reporter interface { SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) BeforeSuiteDidRun(setupSummary *types.SetupSummary) SpecWillRun(specSummary *types.SpecSummary) SpecDidComplete(specSummary *types.SpecSummary) AfterSuiteDidRun(setupSummary *types.SetupSummary) SpecSuiteDidEnd(summary *types.SuiteSummary) } ginkgo-1.14.2/reporters/reporters_suite_test.go000066400000000000000000000003101374111457300217260ustar00rootroot00000000000000package reporters_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestReporters(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Reporters Suite") } ginkgo-1.14.2/reporters/stenographer/000077500000000000000000000000001374111457300176115ustar00rootroot00000000000000ginkgo-1.14.2/reporters/stenographer/console_logging.go000066400000000000000000000027351374111457300233170ustar00rootroot00000000000000package stenographer import ( "fmt" "strings" ) func (s *consoleStenographer) colorize(colorCode string, format string, args ...interface{}) string { var out string if len(args) > 0 { out = fmt.Sprintf(format, args...) } else { out = format } if s.color { return fmt.Sprintf("%s%s%s", colorCode, out, defaultStyle) } else { return out } } func (s *consoleStenographer) printBanner(text string, bannerCharacter string) { fmt.Fprintln(s.w, text) fmt.Fprintln(s.w, strings.Repeat(bannerCharacter, len(text))) } func (s *consoleStenographer) printNewLine() { fmt.Fprintln(s.w, "") } func (s *consoleStenographer) printDelimiter() { fmt.Fprintln(s.w, s.colorize(grayColor, "%s", strings.Repeat("-", 30))) } func (s *consoleStenographer) print(indentation int, format string, args ...interface{}) { fmt.Fprint(s.w, s.indent(indentation, format, args...)) } func (s *consoleStenographer) println(indentation int, format string, args ...interface{}) { fmt.Fprintln(s.w, s.indent(indentation, format, args...)) } func (s *consoleStenographer) indent(indentation int, format string, args ...interface{}) string { var text string if len(args) > 0 { text = fmt.Sprintf(format, args...) } else { text = format } stringArray := strings.Split(text, "\n") padding := "" if indentation >= 0 { padding = strings.Repeat(" ", indentation) } for i, s := range stringArray { stringArray[i] = fmt.Sprintf("%s%s", padding, s) } return strings.Join(stringArray, "\n") } ginkgo-1.14.2/reporters/stenographer/fake_stenographer.go000066400000000000000000000114461374111457300236350ustar00rootroot00000000000000package stenographer import ( "sync" "github.com/onsi/ginkgo/types" ) func NewFakeStenographerCall(method string, args ...interface{}) FakeStenographerCall { return FakeStenographerCall{ Method: method, Args: args, } } type FakeStenographer struct { calls []FakeStenographerCall lock *sync.Mutex } type FakeStenographerCall struct { Method string Args []interface{} } func NewFakeStenographer() *FakeStenographer { stenographer := &FakeStenographer{ lock: &sync.Mutex{}, } stenographer.Reset() return stenographer } func (stenographer *FakeStenographer) Calls() []FakeStenographerCall { stenographer.lock.Lock() defer stenographer.lock.Unlock() return stenographer.calls } func (stenographer *FakeStenographer) Reset() { stenographer.lock.Lock() defer stenographer.lock.Unlock() stenographer.calls = make([]FakeStenographerCall, 0) } func (stenographer *FakeStenographer) CallsTo(method string) []FakeStenographerCall { stenographer.lock.Lock() defer stenographer.lock.Unlock() results := make([]FakeStenographerCall, 0) for _, call := range stenographer.calls { if call.Method == method { results = append(results, call) } } return results } func (stenographer *FakeStenographer) registerCall(method string, args ...interface{}) { stenographer.lock.Lock() defer stenographer.lock.Unlock() stenographer.calls = append(stenographer.calls, NewFakeStenographerCall(method, args...)) } func (stenographer *FakeStenographer) AnnounceSuite(description string, randomSeed int64, randomizingAll bool, succinct bool) { stenographer.registerCall("AnnounceSuite", description, randomSeed, randomizingAll, succinct) } func (stenographer *FakeStenographer) AnnounceAggregatedParallelRun(nodes int, succinct bool) { stenographer.registerCall("AnnounceAggregatedParallelRun", nodes, succinct) } func (stenographer *FakeStenographer) AnnounceParallelRun(node int, nodes int, succinct bool) { stenographer.registerCall("AnnounceParallelRun", node, nodes, succinct) } func (stenographer *FakeStenographer) AnnounceNumberOfSpecs(specsToRun int, total int, succinct bool) { stenographer.registerCall("AnnounceNumberOfSpecs", specsToRun, total, succinct) } func (stenographer *FakeStenographer) AnnounceTotalNumberOfSpecs(total int, succinct bool) { stenographer.registerCall("AnnounceTotalNumberOfSpecs", total, succinct) } func (stenographer *FakeStenographer) AnnounceSpecRunCompletion(summary *types.SuiteSummary, succinct bool) { stenographer.registerCall("AnnounceSpecRunCompletion", summary, succinct) } func (stenographer *FakeStenographer) AnnounceSpecWillRun(spec *types.SpecSummary) { stenographer.registerCall("AnnounceSpecWillRun", spec) } func (stenographer *FakeStenographer) AnnounceBeforeSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool) { stenographer.registerCall("AnnounceBeforeSuiteFailure", summary, succinct, fullTrace) } func (stenographer *FakeStenographer) AnnounceAfterSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool) { stenographer.registerCall("AnnounceAfterSuiteFailure", summary, succinct, fullTrace) } func (stenographer *FakeStenographer) AnnounceCapturedOutput(output string) { stenographer.registerCall("AnnounceCapturedOutput", output) } func (stenographer *FakeStenographer) AnnounceSuccessfulSpec(spec *types.SpecSummary) { stenographer.registerCall("AnnounceSuccessfulSpec", spec) } func (stenographer *FakeStenographer) AnnounceSuccessfulSlowSpec(spec *types.SpecSummary, succinct bool) { stenographer.registerCall("AnnounceSuccessfulSlowSpec", spec, succinct) } func (stenographer *FakeStenographer) AnnounceSuccessfulMeasurement(spec *types.SpecSummary, succinct bool) { stenographer.registerCall("AnnounceSuccessfulMeasurement", spec, succinct) } func (stenographer *FakeStenographer) AnnouncePendingSpec(spec *types.SpecSummary, noisy bool) { stenographer.registerCall("AnnouncePendingSpec", spec, noisy) } func (stenographer *FakeStenographer) AnnounceSkippedSpec(spec *types.SpecSummary, succinct bool, fullTrace bool) { stenographer.registerCall("AnnounceSkippedSpec", spec, succinct, fullTrace) } func (stenographer *FakeStenographer) AnnounceSpecTimedOut(spec *types.SpecSummary, succinct bool, fullTrace bool) { stenographer.registerCall("AnnounceSpecTimedOut", spec, succinct, fullTrace) } func (stenographer *FakeStenographer) AnnounceSpecPanicked(spec *types.SpecSummary, succinct bool, fullTrace bool) { stenographer.registerCall("AnnounceSpecPanicked", spec, succinct, fullTrace) } func (stenographer *FakeStenographer) AnnounceSpecFailed(spec *types.SpecSummary, succinct bool, fullTrace bool) { stenographer.registerCall("AnnounceSpecFailed", spec, succinct, fullTrace) } func (stenographer *FakeStenographer) SummarizeFailures(summaries []*types.SpecSummary) { stenographer.registerCall("SummarizeFailures", summaries) } ginkgo-1.14.2/reporters/stenographer/stenographer.go000066400000000000000000000433471374111457300226540ustar00rootroot00000000000000/* The stenographer is used by Ginkgo's reporters to generate output. Move along, nothing to see here. */ package stenographer import ( "fmt" "io" "runtime" "strings" "github.com/onsi/ginkgo/types" ) const defaultStyle = "\x1b[0m" const boldStyle = "\x1b[1m" const redColor = "\x1b[91m" const greenColor = "\x1b[32m" const yellowColor = "\x1b[33m" const cyanColor = "\x1b[36m" const grayColor = "\x1b[90m" const lightGrayColor = "\x1b[37m" type cursorStateType int const ( cursorStateTop cursorStateType = iota cursorStateStreaming cursorStateMidBlock cursorStateEndBlock ) type Stenographer interface { AnnounceSuite(description string, randomSeed int64, randomizingAll bool, succinct bool) AnnounceAggregatedParallelRun(nodes int, succinct bool) AnnounceParallelRun(node int, nodes int, succinct bool) AnnounceTotalNumberOfSpecs(total int, succinct bool) AnnounceNumberOfSpecs(specsToRun int, total int, succinct bool) AnnounceSpecRunCompletion(summary *types.SuiteSummary, succinct bool) AnnounceSpecWillRun(spec *types.SpecSummary) AnnounceBeforeSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool) AnnounceAfterSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool) AnnounceCapturedOutput(output string) AnnounceSuccessfulSpec(spec *types.SpecSummary) AnnounceSuccessfulSlowSpec(spec *types.SpecSummary, succinct bool) AnnounceSuccessfulMeasurement(spec *types.SpecSummary, succinct bool) AnnouncePendingSpec(spec *types.SpecSummary, noisy bool) AnnounceSkippedSpec(spec *types.SpecSummary, succinct bool, fullTrace bool) AnnounceSpecTimedOut(spec *types.SpecSummary, succinct bool, fullTrace bool) AnnounceSpecPanicked(spec *types.SpecSummary, succinct bool, fullTrace bool) AnnounceSpecFailed(spec *types.SpecSummary, succinct bool, fullTrace bool) SummarizeFailures(summaries []*types.SpecSummary) } func New(color bool, enableFlakes bool, writer io.Writer) Stenographer { denoter := "•" if runtime.GOOS == "windows" { denoter = "+" } return &consoleStenographer{ color: color, denoter: denoter, cursorState: cursorStateTop, enableFlakes: enableFlakes, w: writer, } } type consoleStenographer struct { color bool denoter string cursorState cursorStateType enableFlakes bool w io.Writer } var alternatingColors = []string{defaultStyle, grayColor} func (s *consoleStenographer) AnnounceSuite(description string, randomSeed int64, randomizingAll bool, succinct bool) { if succinct { s.print(0, "[%d] %s ", randomSeed, s.colorize(boldStyle, description)) return } s.printBanner(fmt.Sprintf("Running Suite: %s", description), "=") s.print(0, "Random Seed: %s", s.colorize(boldStyle, "%d", randomSeed)) if randomizingAll { s.print(0, " - Will randomize all specs") } s.printNewLine() } func (s *consoleStenographer) AnnounceParallelRun(node int, nodes int, succinct bool) { if succinct { s.print(0, "- node #%d ", node) return } s.println(0, "Parallel test node %s/%s.", s.colorize(boldStyle, "%d", node), s.colorize(boldStyle, "%d", nodes), ) s.printNewLine() } func (s *consoleStenographer) AnnounceAggregatedParallelRun(nodes int, succinct bool) { if succinct { s.print(0, "- %d nodes ", nodes) return } s.println(0, "Running in parallel across %s nodes", s.colorize(boldStyle, "%d", nodes), ) s.printNewLine() } func (s *consoleStenographer) AnnounceNumberOfSpecs(specsToRun int, total int, succinct bool) { if succinct { s.print(0, "- %d/%d specs ", specsToRun, total) s.stream() return } s.println(0, "Will run %s of %s specs", s.colorize(boldStyle, "%d", specsToRun), s.colorize(boldStyle, "%d", total), ) s.printNewLine() } func (s *consoleStenographer) AnnounceTotalNumberOfSpecs(total int, succinct bool) { if succinct { s.print(0, "- %d specs ", total) s.stream() return } s.println(0, "Will run %s specs", s.colorize(boldStyle, "%d", total), ) s.printNewLine() } func (s *consoleStenographer) AnnounceSpecRunCompletion(summary *types.SuiteSummary, succinct bool) { if succinct && summary.SuiteSucceeded { s.print(0, " %s %s ", s.colorize(greenColor, "SUCCESS!"), summary.RunTime) return } s.printNewLine() color := greenColor if !summary.SuiteSucceeded { color = redColor } s.println(0, s.colorize(boldStyle+color, "Ran %d of %d Specs in %.3f seconds", summary.NumberOfSpecsThatWillBeRun, summary.NumberOfTotalSpecs, summary.RunTime.Seconds())) status := "" if summary.SuiteSucceeded { status = s.colorize(boldStyle+greenColor, "SUCCESS!") } else { status = s.colorize(boldStyle+redColor, "FAIL!") } flakes := "" if s.enableFlakes { flakes = " | " + s.colorize(yellowColor+boldStyle, "%d Flaked", summary.NumberOfFlakedSpecs) } s.print(0, "%s -- %s | %s | %s | %s\n", status, s.colorize(greenColor+boldStyle, "%d Passed", summary.NumberOfPassedSpecs), s.colorize(redColor+boldStyle, "%d Failed", summary.NumberOfFailedSpecs)+flakes, s.colorize(yellowColor+boldStyle, "%d Pending", summary.NumberOfPendingSpecs), s.colorize(cyanColor+boldStyle, "%d Skipped", summary.NumberOfSkippedSpecs), ) } func (s *consoleStenographer) AnnounceSpecWillRun(spec *types.SpecSummary) { s.startBlock() for i, text := range spec.ComponentTexts[1 : len(spec.ComponentTexts)-1] { s.print(0, s.colorize(alternatingColors[i%2], text)+" ") } indentation := 0 if len(spec.ComponentTexts) > 2 { indentation = 1 s.printNewLine() } index := len(spec.ComponentTexts) - 1 s.print(indentation, s.colorize(boldStyle, spec.ComponentTexts[index])) s.printNewLine() s.print(indentation, s.colorize(lightGrayColor, spec.ComponentCodeLocations[index].String())) s.printNewLine() s.midBlock() } func (s *consoleStenographer) AnnounceBeforeSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool) { s.announceSetupFailure("BeforeSuite", summary, succinct, fullTrace) } func (s *consoleStenographer) AnnounceAfterSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool) { s.announceSetupFailure("AfterSuite", summary, succinct, fullTrace) } func (s *consoleStenographer) announceSetupFailure(name string, summary *types.SetupSummary, succinct bool, fullTrace bool) { s.startBlock() var message string switch summary.State { case types.SpecStateFailed: message = "Failure" case types.SpecStatePanicked: message = "Panic" case types.SpecStateTimedOut: message = "Timeout" } s.println(0, s.colorize(redColor+boldStyle, "%s [%.3f seconds]", message, summary.RunTime.Seconds())) indentation := s.printCodeLocationBlock([]string{name}, []types.CodeLocation{summary.CodeLocation}, summary.ComponentType, 0, summary.State, true) s.printNewLine() s.printFailure(indentation, summary.State, summary.Failure, fullTrace) s.endBlock() } func (s *consoleStenographer) AnnounceCapturedOutput(output string) { if output == "" { return } s.startBlock() s.println(0, output) s.midBlock() } func (s *consoleStenographer) AnnounceSuccessfulSpec(spec *types.SpecSummary) { s.print(0, s.colorize(greenColor, s.denoter)) s.stream() } func (s *consoleStenographer) AnnounceSuccessfulSlowSpec(spec *types.SpecSummary, succinct bool) { s.printBlockWithMessage( s.colorize(greenColor, "%s [SLOW TEST:%.3f seconds]", s.denoter, spec.RunTime.Seconds()), "", spec, succinct, ) } func (s *consoleStenographer) AnnounceSuccessfulMeasurement(spec *types.SpecSummary, succinct bool) { s.printBlockWithMessage( s.colorize(greenColor, "%s [MEASUREMENT]", s.denoter), s.measurementReport(spec, succinct), spec, succinct, ) } func (s *consoleStenographer) AnnouncePendingSpec(spec *types.SpecSummary, noisy bool) { if noisy { s.printBlockWithMessage( s.colorize(yellowColor, "P [PENDING]"), "", spec, false, ) } else { s.print(0, s.colorize(yellowColor, "P")) s.stream() } } func (s *consoleStenographer) AnnounceSkippedSpec(spec *types.SpecSummary, succinct bool, fullTrace bool) { // Skips at runtime will have a non-empty spec.Failure. All others should be succinct. if succinct || spec.Failure == (types.SpecFailure{}) { s.print(0, s.colorize(cyanColor, "S")) s.stream() } else { s.startBlock() s.println(0, s.colorize(cyanColor+boldStyle, "S [SKIPPING]%s [%.3f seconds]", s.failureContext(spec.Failure.ComponentType), spec.RunTime.Seconds())) indentation := s.printCodeLocationBlock(spec.ComponentTexts, spec.ComponentCodeLocations, spec.Failure.ComponentType, spec.Failure.ComponentIndex, spec.State, succinct) s.printNewLine() s.printSkip(indentation, spec.Failure) s.endBlock() } } func (s *consoleStenographer) AnnounceSpecTimedOut(spec *types.SpecSummary, succinct bool, fullTrace bool) { s.printSpecFailure(fmt.Sprintf("%s... Timeout", s.denoter), spec, succinct, fullTrace) } func (s *consoleStenographer) AnnounceSpecPanicked(spec *types.SpecSummary, succinct bool, fullTrace bool) { s.printSpecFailure(fmt.Sprintf("%s! Panic", s.denoter), spec, succinct, fullTrace) } func (s *consoleStenographer) AnnounceSpecFailed(spec *types.SpecSummary, succinct bool, fullTrace bool) { s.printSpecFailure(fmt.Sprintf("%s Failure", s.denoter), spec, succinct, fullTrace) } func (s *consoleStenographer) SummarizeFailures(summaries []*types.SpecSummary) { failingSpecs := []*types.SpecSummary{} for _, summary := range summaries { if summary.HasFailureState() { failingSpecs = append(failingSpecs, summary) } } if len(failingSpecs) == 0 { return } s.printNewLine() s.printNewLine() plural := "s" if len(failingSpecs) == 1 { plural = "" } s.println(0, s.colorize(redColor+boldStyle, "Summarizing %d Failure%s:", len(failingSpecs), plural)) for _, summary := range failingSpecs { s.printNewLine() if summary.HasFailureState() { if summary.TimedOut() { s.print(0, s.colorize(redColor+boldStyle, "[Timeout...] ")) } else if summary.Panicked() { s.print(0, s.colorize(redColor+boldStyle, "[Panic!] ")) } else if summary.Failed() { s.print(0, s.colorize(redColor+boldStyle, "[Fail] ")) } s.printSpecContext(summary.ComponentTexts, summary.ComponentCodeLocations, summary.Failure.ComponentType, summary.Failure.ComponentIndex, summary.State, true) s.printNewLine() s.println(0, s.colorize(lightGrayColor, summary.Failure.Location.String())) } } } func (s *consoleStenographer) startBlock() { if s.cursorState == cursorStateStreaming { s.printNewLine() s.printDelimiter() } else if s.cursorState == cursorStateMidBlock { s.printNewLine() } } func (s *consoleStenographer) midBlock() { s.cursorState = cursorStateMidBlock } func (s *consoleStenographer) endBlock() { s.printDelimiter() s.cursorState = cursorStateEndBlock } func (s *consoleStenographer) stream() { s.cursorState = cursorStateStreaming } func (s *consoleStenographer) printBlockWithMessage(header string, message string, spec *types.SpecSummary, succinct bool) { s.startBlock() s.println(0, header) indentation := s.printCodeLocationBlock(spec.ComponentTexts, spec.ComponentCodeLocations, types.SpecComponentTypeInvalid, 0, spec.State, succinct) if message != "" { s.printNewLine() s.println(indentation, message) } s.endBlock() } func (s *consoleStenographer) printSpecFailure(message string, spec *types.SpecSummary, succinct bool, fullTrace bool) { s.startBlock() s.println(0, s.colorize(redColor+boldStyle, "%s%s [%.3f seconds]", message, s.failureContext(spec.Failure.ComponentType), spec.RunTime.Seconds())) indentation := s.printCodeLocationBlock(spec.ComponentTexts, spec.ComponentCodeLocations, spec.Failure.ComponentType, spec.Failure.ComponentIndex, spec.State, succinct) s.printNewLine() s.printFailure(indentation, spec.State, spec.Failure, fullTrace) s.endBlock() } func (s *consoleStenographer) failureContext(failedComponentType types.SpecComponentType) string { switch failedComponentType { case types.SpecComponentTypeBeforeSuite: return " in Suite Setup (BeforeSuite)" case types.SpecComponentTypeAfterSuite: return " in Suite Teardown (AfterSuite)" case types.SpecComponentTypeBeforeEach: return " in Spec Setup (BeforeEach)" case types.SpecComponentTypeJustBeforeEach: return " in Spec Setup (JustBeforeEach)" case types.SpecComponentTypeAfterEach: return " in Spec Teardown (AfterEach)" } return "" } func (s *consoleStenographer) printSkip(indentation int, spec types.SpecFailure) { s.println(indentation, s.colorize(cyanColor, spec.Message)) s.printNewLine() s.println(indentation, spec.Location.String()) } func (s *consoleStenographer) printFailure(indentation int, state types.SpecState, failure types.SpecFailure, fullTrace bool) { if state == types.SpecStatePanicked { s.println(indentation, s.colorize(redColor+boldStyle, failure.Message)) s.println(indentation, s.colorize(redColor, failure.ForwardedPanic)) s.println(indentation, failure.Location.String()) s.printNewLine() s.println(indentation, s.colorize(redColor, "Full Stack Trace")) s.println(indentation, failure.Location.FullStackTrace) } else { s.println(indentation, s.colorize(redColor, failure.Message)) s.printNewLine() s.println(indentation, failure.Location.String()) if fullTrace { s.printNewLine() s.println(indentation, s.colorize(redColor, "Full Stack Trace")) s.println(indentation, failure.Location.FullStackTrace) } } } func (s *consoleStenographer) printSpecContext(componentTexts []string, componentCodeLocations []types.CodeLocation, failedComponentType types.SpecComponentType, failedComponentIndex int, state types.SpecState, succinct bool) int { startIndex := 1 indentation := 0 if len(componentTexts) == 1 { startIndex = 0 } for i := startIndex; i < len(componentTexts); i++ { if (state.IsFailure() || state == types.SpecStateSkipped) && i == failedComponentIndex { color := redColor if state == types.SpecStateSkipped { color = cyanColor } blockType := "" switch failedComponentType { case types.SpecComponentTypeBeforeSuite: blockType = "BeforeSuite" case types.SpecComponentTypeAfterSuite: blockType = "AfterSuite" case types.SpecComponentTypeBeforeEach: blockType = "BeforeEach" case types.SpecComponentTypeJustBeforeEach: blockType = "JustBeforeEach" case types.SpecComponentTypeAfterEach: blockType = "AfterEach" case types.SpecComponentTypeIt: blockType = "It" case types.SpecComponentTypeMeasure: blockType = "Measurement" } if succinct { s.print(0, s.colorize(color+boldStyle, "[%s] %s ", blockType, componentTexts[i])) } else { s.println(indentation, s.colorize(color+boldStyle, "%s [%s]", componentTexts[i], blockType)) s.println(indentation, s.colorize(grayColor, "%s", componentCodeLocations[i])) } } else { if succinct { s.print(0, s.colorize(alternatingColors[i%2], "%s ", componentTexts[i])) } else { s.println(indentation, componentTexts[i]) s.println(indentation, s.colorize(grayColor, "%s", componentCodeLocations[i])) } } indentation++ } return indentation } func (s *consoleStenographer) printCodeLocationBlock(componentTexts []string, componentCodeLocations []types.CodeLocation, failedComponentType types.SpecComponentType, failedComponentIndex int, state types.SpecState, succinct bool) int { indentation := s.printSpecContext(componentTexts, componentCodeLocations, failedComponentType, failedComponentIndex, state, succinct) if succinct { if len(componentTexts) > 0 { s.printNewLine() s.print(0, s.colorize(lightGrayColor, "%s", componentCodeLocations[len(componentCodeLocations)-1])) } s.printNewLine() indentation = 1 } else { indentation-- } return indentation } func (s *consoleStenographer) orderedMeasurementKeys(measurements map[string]*types.SpecMeasurement) []string { orderedKeys := make([]string, len(measurements)) for key, measurement := range measurements { orderedKeys[measurement.Order] = key } return orderedKeys } func (s *consoleStenographer) measurementReport(spec *types.SpecSummary, succinct bool) string { if len(spec.Measurements) == 0 { return "Found no measurements" } message := []string{} orderedKeys := s.orderedMeasurementKeys(spec.Measurements) if succinct { message = append(message, fmt.Sprintf("%s samples:", s.colorize(boldStyle, "%d", spec.NumberOfSamples))) for _, key := range orderedKeys { measurement := spec.Measurements[key] message = append(message, fmt.Sprintf(" %s - %s: %s%s, %s: %s%s ± %s%s, %s: %s%s", s.colorize(boldStyle, "%s", measurement.Name), measurement.SmallestLabel, s.colorize(greenColor, measurement.PrecisionFmt(), measurement.Smallest), measurement.Units, measurement.AverageLabel, s.colorize(cyanColor, measurement.PrecisionFmt(), measurement.Average), measurement.Units, s.colorize(cyanColor, measurement.PrecisionFmt(), measurement.StdDeviation), measurement.Units, measurement.LargestLabel, s.colorize(redColor, measurement.PrecisionFmt(), measurement.Largest), measurement.Units, )) } } else { message = append(message, fmt.Sprintf("Ran %s samples:", s.colorize(boldStyle, "%d", spec.NumberOfSamples))) for _, key := range orderedKeys { measurement := spec.Measurements[key] info := "" if measurement.Info != nil { message = append(message, fmt.Sprintf("%v", measurement.Info)) } message = append(message, fmt.Sprintf("%s:\n%s %s: %s%s\n %s: %s%s\n %s: %s%s ± %s%s", s.colorize(boldStyle, "%s", measurement.Name), info, measurement.SmallestLabel, s.colorize(greenColor, measurement.PrecisionFmt(), measurement.Smallest), measurement.Units, measurement.LargestLabel, s.colorize(redColor, measurement.PrecisionFmt(), measurement.Largest), measurement.Units, measurement.AverageLabel, s.colorize(cyanColor, measurement.PrecisionFmt(), measurement.Average), measurement.Units, s.colorize(cyanColor, measurement.PrecisionFmt(), measurement.StdDeviation), measurement.Units, )) } } return strings.Join(message, "\n") } ginkgo-1.14.2/reporters/stenographer/support/000077500000000000000000000000001374111457300213255ustar00rootroot00000000000000ginkgo-1.14.2/reporters/stenographer/support/README.md000066400000000000000000000003321374111457300226020ustar00rootroot00000000000000## Colorize Windows These packages are used for colorize on Windows and contributed by mattn.jp@gmail.com * go-colorable: * go-isatty: ginkgo-1.14.2/reporters/stenographer/support/go-colorable/000077500000000000000000000000001374111457300236725ustar00rootroot00000000000000ginkgo-1.14.2/reporters/stenographer/support/go-colorable/LICENSE000066400000000000000000000020751374111457300247030ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 Yasuhiro Matsumoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ginkgo-1.14.2/reporters/stenographer/support/go-colorable/README.md000066400000000000000000000015101374111457300251460ustar00rootroot00000000000000# go-colorable Colorable writer for windows. For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.) This package is possible to handle escape sequence for ansi color on windows. ## Too Bad! ![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png) ## So Good! ![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png) ## Usage ```go logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true}) logrus.SetOutput(colorable.NewColorableStdout()) logrus.Info("succeeded") logrus.Warn("not correct") logrus.Error("something error") logrus.Fatal("panic") ``` You can compile above code on non-windows OSs. ## Installation ``` $ go get github.com/mattn/go-colorable ``` # License MIT # Author Yasuhiro Matsumoto (a.k.a mattn) ginkgo-1.14.2/reporters/stenographer/support/go-colorable/colorable_others.go000066400000000000000000000005031374111457300275450ustar00rootroot00000000000000// +build !windows package colorable import ( "io" "os" ) func NewColorable(file *os.File) io.Writer { if file == nil { panic("nil passed instead of *os.File to NewColorable()") } return file } func NewColorableStdout() io.Writer { return os.Stdout } func NewColorableStderr() io.Writer { return os.Stderr } ginkgo-1.14.2/reporters/stenographer/support/go-colorable/colorable_windows.go000066400000000000000000000426131374111457300277430ustar00rootroot00000000000000package colorable import ( "bytes" "fmt" "io" "math" "os" "strconv" "strings" "syscall" "unsafe" "github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty" ) const ( foregroundBlue = 0x1 foregroundGreen = 0x2 foregroundRed = 0x4 foregroundIntensity = 0x8 foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity) backgroundBlue = 0x10 backgroundGreen = 0x20 backgroundRed = 0x40 backgroundIntensity = 0x80 backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) ) type wchar uint16 type short int16 type dword uint32 type word uint16 type coord struct { x short y short } type smallRect struct { left short top short right short bottom short } type consoleScreenBufferInfo struct { size coord cursorPosition coord attributes word window smallRect maximumWindowSize coord } var ( kernel32 = syscall.NewLazyDLL("kernel32.dll") procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute") ) type Writer struct { out io.Writer handle syscall.Handle lastbuf bytes.Buffer oldattr word } func NewColorable(file *os.File) io.Writer { if file == nil { panic("nil passed instead of *os.File to NewColorable()") } if isatty.IsTerminal(file.Fd()) { var csbi consoleScreenBufferInfo handle := syscall.Handle(file.Fd()) procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) return &Writer{out: file, handle: handle, oldattr: csbi.attributes} } else { return file } } func NewColorableStdout() io.Writer { return NewColorable(os.Stdout) } func NewColorableStderr() io.Writer { return NewColorable(os.Stderr) } var color256 = map[int]int{ 0: 0x000000, 1: 0x800000, 2: 0x008000, 3: 0x808000, 4: 0x000080, 5: 0x800080, 6: 0x008080, 7: 0xc0c0c0, 8: 0x808080, 9: 0xff0000, 10: 0x00ff00, 11: 0xffff00, 12: 0x0000ff, 13: 0xff00ff, 14: 0x00ffff, 15: 0xffffff, 16: 0x000000, 17: 0x00005f, 18: 0x000087, 19: 0x0000af, 20: 0x0000d7, 21: 0x0000ff, 22: 0x005f00, 23: 0x005f5f, 24: 0x005f87, 25: 0x005faf, 26: 0x005fd7, 27: 0x005fff, 28: 0x008700, 29: 0x00875f, 30: 0x008787, 31: 0x0087af, 32: 0x0087d7, 33: 0x0087ff, 34: 0x00af00, 35: 0x00af5f, 36: 0x00af87, 37: 0x00afaf, 38: 0x00afd7, 39: 0x00afff, 40: 0x00d700, 41: 0x00d75f, 42: 0x00d787, 43: 0x00d7af, 44: 0x00d7d7, 45: 0x00d7ff, 46: 0x00ff00, 47: 0x00ff5f, 48: 0x00ff87, 49: 0x00ffaf, 50: 0x00ffd7, 51: 0x00ffff, 52: 0x5f0000, 53: 0x5f005f, 54: 0x5f0087, 55: 0x5f00af, 56: 0x5f00d7, 57: 0x5f00ff, 58: 0x5f5f00, 59: 0x5f5f5f, 60: 0x5f5f87, 61: 0x5f5faf, 62: 0x5f5fd7, 63: 0x5f5fff, 64: 0x5f8700, 65: 0x5f875f, 66: 0x5f8787, 67: 0x5f87af, 68: 0x5f87d7, 69: 0x5f87ff, 70: 0x5faf00, 71: 0x5faf5f, 72: 0x5faf87, 73: 0x5fafaf, 74: 0x5fafd7, 75: 0x5fafff, 76: 0x5fd700, 77: 0x5fd75f, 78: 0x5fd787, 79: 0x5fd7af, 80: 0x5fd7d7, 81: 0x5fd7ff, 82: 0x5fff00, 83: 0x5fff5f, 84: 0x5fff87, 85: 0x5fffaf, 86: 0x5fffd7, 87: 0x5fffff, 88: 0x870000, 89: 0x87005f, 90: 0x870087, 91: 0x8700af, 92: 0x8700d7, 93: 0x8700ff, 94: 0x875f00, 95: 0x875f5f, 96: 0x875f87, 97: 0x875faf, 98: 0x875fd7, 99: 0x875fff, 100: 0x878700, 101: 0x87875f, 102: 0x878787, 103: 0x8787af, 104: 0x8787d7, 105: 0x8787ff, 106: 0x87af00, 107: 0x87af5f, 108: 0x87af87, 109: 0x87afaf, 110: 0x87afd7, 111: 0x87afff, 112: 0x87d700, 113: 0x87d75f, 114: 0x87d787, 115: 0x87d7af, 116: 0x87d7d7, 117: 0x87d7ff, 118: 0x87ff00, 119: 0x87ff5f, 120: 0x87ff87, 121: 0x87ffaf, 122: 0x87ffd7, 123: 0x87ffff, 124: 0xaf0000, 125: 0xaf005f, 126: 0xaf0087, 127: 0xaf00af, 128: 0xaf00d7, 129: 0xaf00ff, 130: 0xaf5f00, 131: 0xaf5f5f, 132: 0xaf5f87, 133: 0xaf5faf, 134: 0xaf5fd7, 135: 0xaf5fff, 136: 0xaf8700, 137: 0xaf875f, 138: 0xaf8787, 139: 0xaf87af, 140: 0xaf87d7, 141: 0xaf87ff, 142: 0xafaf00, 143: 0xafaf5f, 144: 0xafaf87, 145: 0xafafaf, 146: 0xafafd7, 147: 0xafafff, 148: 0xafd700, 149: 0xafd75f, 150: 0xafd787, 151: 0xafd7af, 152: 0xafd7d7, 153: 0xafd7ff, 154: 0xafff00, 155: 0xafff5f, 156: 0xafff87, 157: 0xafffaf, 158: 0xafffd7, 159: 0xafffff, 160: 0xd70000, 161: 0xd7005f, 162: 0xd70087, 163: 0xd700af, 164: 0xd700d7, 165: 0xd700ff, 166: 0xd75f00, 167: 0xd75f5f, 168: 0xd75f87, 169: 0xd75faf, 170: 0xd75fd7, 171: 0xd75fff, 172: 0xd78700, 173: 0xd7875f, 174: 0xd78787, 175: 0xd787af, 176: 0xd787d7, 177: 0xd787ff, 178: 0xd7af00, 179: 0xd7af5f, 180: 0xd7af87, 181: 0xd7afaf, 182: 0xd7afd7, 183: 0xd7afff, 184: 0xd7d700, 185: 0xd7d75f, 186: 0xd7d787, 187: 0xd7d7af, 188: 0xd7d7d7, 189: 0xd7d7ff, 190: 0xd7ff00, 191: 0xd7ff5f, 192: 0xd7ff87, 193: 0xd7ffaf, 194: 0xd7ffd7, 195: 0xd7ffff, 196: 0xff0000, 197: 0xff005f, 198: 0xff0087, 199: 0xff00af, 200: 0xff00d7, 201: 0xff00ff, 202: 0xff5f00, 203: 0xff5f5f, 204: 0xff5f87, 205: 0xff5faf, 206: 0xff5fd7, 207: 0xff5fff, 208: 0xff8700, 209: 0xff875f, 210: 0xff8787, 211: 0xff87af, 212: 0xff87d7, 213: 0xff87ff, 214: 0xffaf00, 215: 0xffaf5f, 216: 0xffaf87, 217: 0xffafaf, 218: 0xffafd7, 219: 0xffafff, 220: 0xffd700, 221: 0xffd75f, 222: 0xffd787, 223: 0xffd7af, 224: 0xffd7d7, 225: 0xffd7ff, 226: 0xffff00, 227: 0xffff5f, 228: 0xffff87, 229: 0xffffaf, 230: 0xffffd7, 231: 0xffffff, 232: 0x080808, 233: 0x121212, 234: 0x1c1c1c, 235: 0x262626, 236: 0x303030, 237: 0x3a3a3a, 238: 0x444444, 239: 0x4e4e4e, 240: 0x585858, 241: 0x626262, 242: 0x6c6c6c, 243: 0x767676, 244: 0x808080, 245: 0x8a8a8a, 246: 0x949494, 247: 0x9e9e9e, 248: 0xa8a8a8, 249: 0xb2b2b2, 250: 0xbcbcbc, 251: 0xc6c6c6, 252: 0xd0d0d0, 253: 0xdadada, 254: 0xe4e4e4, 255: 0xeeeeee, } func (w *Writer) Write(data []byte) (n int, err error) { var csbi consoleScreenBufferInfo procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) er := bytes.NewBuffer(data) loop: for { r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) if r1 == 0 { break loop } c1, _, err := er.ReadRune() if err != nil { break loop } if c1 != 0x1b { fmt.Fprint(w.out, string(c1)) continue } c2, _, err := er.ReadRune() if err != nil { w.lastbuf.WriteRune(c1) break loop } if c2 != 0x5b { w.lastbuf.WriteRune(c1) w.lastbuf.WriteRune(c2) continue } var buf bytes.Buffer var m rune for { c, _, err := er.ReadRune() if err != nil { w.lastbuf.WriteRune(c1) w.lastbuf.WriteRune(c2) w.lastbuf.Write(buf.Bytes()) break loop } if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { m = c break } buf.Write([]byte(string(c))) } var csbi consoleScreenBufferInfo switch m { case 'A': n, err = strconv.Atoi(buf.String()) if err != nil { continue } procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y -= short(n) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'B': n, err = strconv.Atoi(buf.String()) if err != nil { continue } procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y += short(n) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'C': n, err = strconv.Atoi(buf.String()) if err != nil { continue } procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x -= short(n) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'D': n, err = strconv.Atoi(buf.String()) if err != nil { continue } if n, err = strconv.Atoi(buf.String()); err == nil { var csbi consoleScreenBufferInfo procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x += short(n) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) } case 'E': n, err = strconv.Atoi(buf.String()) if err != nil { continue } procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = 0 csbi.cursorPosition.y += short(n) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'F': n, err = strconv.Atoi(buf.String()) if err != nil { continue } procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = 0 csbi.cursorPosition.y -= short(n) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'G': n, err = strconv.Atoi(buf.String()) if err != nil { continue } procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = short(n) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'H': token := strings.Split(buf.String(), ";") if len(token) != 2 { continue } n1, err := strconv.Atoi(token[0]) if err != nil { continue } n2, err := strconv.Atoi(token[1]) if err != nil { continue } csbi.cursorPosition.x = short(n2) csbi.cursorPosition.x = short(n1) procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) case 'J': n, err := strconv.Atoi(buf.String()) if err != nil { continue } var cursor coord switch n { case 0: cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} case 1: cursor = coord{x: csbi.window.left, y: csbi.window.top} case 2: cursor = coord{x: csbi.window.left, y: csbi.window.top} } var count, written dword count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) case 'K': n, err := strconv.Atoi(buf.String()) if err != nil { continue } var cursor coord switch n { case 0: cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} case 1: cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} case 2: cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} } var count, written dword count = dword(csbi.size.x - csbi.cursorPosition.x) procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) case 'm': attr := csbi.attributes cs := buf.String() if cs == "" { procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) continue } token := strings.Split(cs, ";") for i := 0; i < len(token); i += 1 { ns := token[i] if n, err = strconv.Atoi(ns); err == nil { switch { case n == 0 || n == 100: attr = w.oldattr case 1 <= n && n <= 5: attr |= foregroundIntensity case n == 7: attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) case 22 == n || n == 25 || n == 25: attr |= foregroundIntensity case n == 27: attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) case 30 <= n && n <= 37: attr = (attr & backgroundMask) if (n-30)&1 != 0 { attr |= foregroundRed } if (n-30)&2 != 0 { attr |= foregroundGreen } if (n-30)&4 != 0 { attr |= foregroundBlue } case n == 38: // set foreground color. if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") { if n256, err := strconv.Atoi(token[i+2]); err == nil { if n256foreAttr == nil { n256setup() } attr &= backgroundMask attr |= n256foreAttr[n256] i += 2 } } else { attr = attr & (w.oldattr & backgroundMask) } case n == 39: // reset foreground color. attr &= backgroundMask attr |= w.oldattr & foregroundMask case 40 <= n && n <= 47: attr = (attr & foregroundMask) if (n-40)&1 != 0 { attr |= backgroundRed } if (n-40)&2 != 0 { attr |= backgroundGreen } if (n-40)&4 != 0 { attr |= backgroundBlue } case n == 48: // set background color. if i < len(token)-2 && token[i+1] == "5" { if n256, err := strconv.Atoi(token[i+2]); err == nil { if n256backAttr == nil { n256setup() } attr &= foregroundMask attr |= n256backAttr[n256] i += 2 } } else { attr = attr & (w.oldattr & foregroundMask) } case n == 49: // reset foreground color. attr &= foregroundMask attr |= w.oldattr & backgroundMask case 90 <= n && n <= 97: attr = (attr & backgroundMask) attr |= foregroundIntensity if (n-90)&1 != 0 { attr |= foregroundRed } if (n-90)&2 != 0 { attr |= foregroundGreen } if (n-90)&4 != 0 { attr |= foregroundBlue } case 100 <= n && n <= 107: attr = (attr & foregroundMask) attr |= backgroundIntensity if (n-100)&1 != 0 { attr |= backgroundRed } if (n-100)&2 != 0 { attr |= backgroundGreen } if (n-100)&4 != 0 { attr |= backgroundBlue } } procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) } } } } return len(data) - w.lastbuf.Len(), nil } type consoleColor struct { rgb int red bool green bool blue bool intensity bool } func (c consoleColor) foregroundAttr() (attr word) { if c.red { attr |= foregroundRed } if c.green { attr |= foregroundGreen } if c.blue { attr |= foregroundBlue } if c.intensity { attr |= foregroundIntensity } return } func (c consoleColor) backgroundAttr() (attr word) { if c.red { attr |= backgroundRed } if c.green { attr |= backgroundGreen } if c.blue { attr |= backgroundBlue } if c.intensity { attr |= backgroundIntensity } return } var color16 = []consoleColor{ consoleColor{0x000000, false, false, false, false}, consoleColor{0x000080, false, false, true, false}, consoleColor{0x008000, false, true, false, false}, consoleColor{0x008080, false, true, true, false}, consoleColor{0x800000, true, false, false, false}, consoleColor{0x800080, true, false, true, false}, consoleColor{0x808000, true, true, false, false}, consoleColor{0xc0c0c0, true, true, true, false}, consoleColor{0x808080, false, false, false, true}, consoleColor{0x0000ff, false, false, true, true}, consoleColor{0x00ff00, false, true, false, true}, consoleColor{0x00ffff, false, true, true, true}, consoleColor{0xff0000, true, false, false, true}, consoleColor{0xff00ff, true, false, true, true}, consoleColor{0xffff00, true, true, false, true}, consoleColor{0xffffff, true, true, true, true}, } type hsv struct { h, s, v float32 } func (a hsv) dist(b hsv) float32 { dh := a.h - b.h switch { case dh > 0.5: dh = 1 - dh case dh < -0.5: dh = -1 - dh } ds := a.s - b.s dv := a.v - b.v return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv))) } func toHSV(rgb int) hsv { r, g, b := float32((rgb&0xFF0000)>>16)/256.0, float32((rgb&0x00FF00)>>8)/256.0, float32(rgb&0x0000FF)/256.0 min, max := minmax3f(r, g, b) h := max - min if h > 0 { if max == r { h = (g - b) / h if h < 0 { h += 6 } } else if max == g { h = 2 + (b-r)/h } else { h = 4 + (r-g)/h } } h /= 6.0 s := max - min if max != 0 { s /= max } v := max return hsv{h: h, s: s, v: v} } type hsvTable []hsv func toHSVTable(rgbTable []consoleColor) hsvTable { t := make(hsvTable, len(rgbTable)) for i, c := range rgbTable { t[i] = toHSV(c.rgb) } return t } func (t hsvTable) find(rgb int) consoleColor { hsv := toHSV(rgb) n := 7 l := float32(5.0) for i, p := range t { d := hsv.dist(p) if d < l { l, n = d, i } } return color16[n] } func minmax3f(a, b, c float32) (min, max float32) { if a < b { if b < c { return a, c } else if a < c { return a, b } else { return c, b } } else { if a < c { return b, c } else if b < c { return b, a } else { return c, a } } } var n256foreAttr []word var n256backAttr []word func n256setup() { n256foreAttr = make([]word, 256) n256backAttr = make([]word, 256) t := toHSVTable(color16) for i, rgb := range color256 { c := t.find(rgb) n256foreAttr[i] = c.foregroundAttr() n256backAttr[i] = c.backgroundAttr() } } ginkgo-1.14.2/reporters/stenographer/support/go-colorable/noncolorable.go000066400000000000000000000017221374111457300267000ustar00rootroot00000000000000package colorable import ( "bytes" "fmt" "io" ) type NonColorable struct { out io.Writer lastbuf bytes.Buffer } func NewNonColorable(w io.Writer) io.Writer { return &NonColorable{out: w} } func (w *NonColorable) Write(data []byte) (n int, err error) { er := bytes.NewBuffer(data) loop: for { c1, _, err := er.ReadRune() if err != nil { break loop } if c1 != 0x1b { fmt.Fprint(w.out, string(c1)) continue } c2, _, err := er.ReadRune() if err != nil { w.lastbuf.WriteRune(c1) break loop } if c2 != 0x5b { w.lastbuf.WriteRune(c1) w.lastbuf.WriteRune(c2) continue } var buf bytes.Buffer for { c, _, err := er.ReadRune() if err != nil { w.lastbuf.WriteRune(c1) w.lastbuf.WriteRune(c2) w.lastbuf.Write(buf.Bytes()) break loop } if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { break } buf.Write([]byte(string(c))) } } return len(data) - w.lastbuf.Len(), nil } ginkgo-1.14.2/reporters/stenographer/support/go-isatty/000077500000000000000000000000001374111457300232455ustar00rootroot00000000000000ginkgo-1.14.2/reporters/stenographer/support/go-isatty/LICENSE000066400000000000000000000021131374111457300242470ustar00rootroot00000000000000Copyright (c) Yasuhiro MATSUMOTO MIT License (Expat) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ginkgo-1.14.2/reporters/stenographer/support/go-isatty/README.md000066400000000000000000000005661374111457300245330ustar00rootroot00000000000000# go-isatty isatty for golang ## Usage ```go package main import ( "fmt" "github.com/mattn/go-isatty" "os" ) func main() { if isatty.IsTerminal(os.Stdout.Fd()) { fmt.Println("Is Terminal") } else { fmt.Println("Is Not Terminal") } } ``` ## Installation ``` $ go get github.com/mattn/go-isatty ``` # License MIT # Author Yasuhiro Matsumoto (a.k.a mattn) ginkgo-1.14.2/reporters/stenographer/support/go-isatty/doc.go000066400000000000000000000001001374111457300243300ustar00rootroot00000000000000// Package isatty implements interface to isatty package isatty ginkgo-1.14.2/reporters/stenographer/support/go-isatty/isatty_appengine.go000066400000000000000000000003421374111457300271360ustar00rootroot00000000000000// +build appengine package isatty // IsTerminal returns true if the file descriptor is terminal which // is always false on on appengine classic which is a sandboxed PaaS. func IsTerminal(fd uintptr) bool { return false } ginkgo-1.14.2/reporters/stenographer/support/go-isatty/isatty_bsd.go000066400000000000000000000006371374111457300257470ustar00rootroot00000000000000// +build darwin freebsd openbsd netbsd // +build !appengine package isatty import ( "syscall" "unsafe" ) const ioctlReadTermios = syscall.TIOCGETA // IsTerminal return true if the file descriptor is terminal. func IsTerminal(fd uintptr) bool { var termios syscall.Termios _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) return err == 0 } ginkgo-1.14.2/reporters/stenographer/support/go-isatty/isatty_linux.go000066400000000000000000000006051374111457300263310ustar00rootroot00000000000000// +build linux // +build !appengine package isatty import ( "syscall" "unsafe" ) const ioctlReadTermios = syscall.TCGETS // IsTerminal return true if the file descriptor is terminal. func IsTerminal(fd uintptr) bool { var termios syscall.Termios _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) return err == 0 } ginkgo-1.14.2/reporters/stenographer/support/go-isatty/isatty_solaris.go000066400000000000000000000006221374111457300266450ustar00rootroot00000000000000// +build solaris // +build !appengine package isatty import ( "golang.org/x/sys/unix" ) // IsTerminal returns true if the given file descriptor is a terminal. // see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c func IsTerminal(fd uintptr) bool { var termio unix.Termio err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio) return err == nil } ginkgo-1.14.2/reporters/stenographer/support/go-isatty/isatty_windows.go000066400000000000000000000006621374111457300266670ustar00rootroot00000000000000// +build windows // +build !appengine package isatty import ( "syscall" "unsafe" ) var kernel32 = syscall.NewLazyDLL("kernel32.dll") var procGetConsoleMode = kernel32.NewProc("GetConsoleMode") // IsTerminal return true if the file descriptor is terminal. func IsTerminal(fd uintptr) bool { var st uint32 r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) return r != 0 && e == 0 } ginkgo-1.14.2/reporters/teamcity_reporter.go000066400000000000000000000100661374111457300212030ustar00rootroot00000000000000/* TeamCity Reporter for Ginkgo Makes use of TeamCity's support for Service Messages http://confluence.jetbrains.com/display/TCD7/Build+Script+Interaction+with+TeamCity#BuildScriptInteractionwithTeamCity-ReportingTests */ package reporters import ( "fmt" "io" "strings" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/types" ) const ( messageId = "##teamcity" ) type TeamCityReporter struct { writer io.Writer testSuiteName string ReporterConfig config.DefaultReporterConfigType } func NewTeamCityReporter(writer io.Writer) *TeamCityReporter { return &TeamCityReporter{ writer: writer, } } func (reporter *TeamCityReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) { reporter.testSuiteName = escape(summary.SuiteDescription) fmt.Fprintf(reporter.writer, "%s[testSuiteStarted name='%s']\n", messageId, reporter.testSuiteName) } func (reporter *TeamCityReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) { reporter.handleSetupSummary("BeforeSuite", setupSummary) } func (reporter *TeamCityReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) { reporter.handleSetupSummary("AfterSuite", setupSummary) } func (reporter *TeamCityReporter) handleSetupSummary(name string, setupSummary *types.SetupSummary) { if setupSummary.State != types.SpecStatePassed { testName := escape(name) fmt.Fprintf(reporter.writer, "%s[testStarted name='%s']\n", messageId, testName) message := reporter.failureMessage(setupSummary.Failure) details := reporter.failureDetails(setupSummary.Failure) fmt.Fprintf(reporter.writer, "%s[testFailed name='%s' message='%s' details='%s']\n", messageId, testName, message, details) durationInMilliseconds := setupSummary.RunTime.Seconds() * 1000 fmt.Fprintf(reporter.writer, "%s[testFinished name='%s' duration='%v']\n", messageId, testName, durationInMilliseconds) } } func (reporter *TeamCityReporter) SpecWillRun(specSummary *types.SpecSummary) { testName := escape(strings.Join(specSummary.ComponentTexts[1:], " ")) fmt.Fprintf(reporter.writer, "%s[testStarted name='%s']\n", messageId, testName) } func (reporter *TeamCityReporter) SpecDidComplete(specSummary *types.SpecSummary) { testName := escape(strings.Join(specSummary.ComponentTexts[1:], " ")) if reporter.ReporterConfig.ReportPassed && specSummary.State == types.SpecStatePassed { details := escape(specSummary.CapturedOutput) fmt.Fprintf(reporter.writer, "%s[testPassed name='%s' details='%s']\n", messageId, testName, details) } if specSummary.State == types.SpecStateFailed || specSummary.State == types.SpecStateTimedOut || specSummary.State == types.SpecStatePanicked { message := reporter.failureMessage(specSummary.Failure) details := reporter.failureDetails(specSummary.Failure) fmt.Fprintf(reporter.writer, "%s[testFailed name='%s' message='%s' details='%s']\n", messageId, testName, message, details) } if specSummary.State == types.SpecStateSkipped || specSummary.State == types.SpecStatePending { fmt.Fprintf(reporter.writer, "%s[testIgnored name='%s']\n", messageId, testName) } durationInMilliseconds := specSummary.RunTime.Seconds() * 1000 fmt.Fprintf(reporter.writer, "%s[testFinished name='%s' duration='%v']\n", messageId, testName, durationInMilliseconds) } func (reporter *TeamCityReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { fmt.Fprintf(reporter.writer, "%s[testSuiteFinished name='%s']\n", messageId, reporter.testSuiteName) } func (reporter *TeamCityReporter) failureMessage(failure types.SpecFailure) string { return escape(failure.ComponentCodeLocation.String()) } func (reporter *TeamCityReporter) failureDetails(failure types.SpecFailure) string { return escape(fmt.Sprintf("%s\n%s", failure.Message, failure.Location.String())) } func escape(output string) string { output = strings.Replace(output, "|", "||", -1) output = strings.Replace(output, "'", "|'", -1) output = strings.Replace(output, "\n", "|n", -1) output = strings.Replace(output, "\r", "|r", -1) output = strings.Replace(output, "[", "|[", -1) output = strings.Replace(output, "]", "|]", -1) return output } ginkgo-1.14.2/reporters/teamcity_reporter_test.go000066400000000000000000000157641374111457300222540ustar00rootroot00000000000000package reporters_test import ( "bytes" "fmt" "time" . "github.com/onsi/ginkgo" "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/internal/codelocation" "github.com/onsi/ginkgo/reporters" "github.com/onsi/ginkgo/types" . "github.com/onsi/gomega" ) var _ = Describe("TeamCity Reporter", func() { var ( buffer bytes.Buffer reporter *reporters.TeamCityReporter ) BeforeEach(func() { buffer.Truncate(0) reporter = reporters.NewTeamCityReporter(&buffer) reporter.SpecSuiteWillBegin(config.GinkgoConfigType{}, &types.SuiteSummary{ SuiteDescription: "Foo's test suite", NumberOfSpecsThatWillBeRun: 1, }) }) Describe("a passing test", func() { BeforeEach(func() { beforeSuite := &types.SetupSummary{ State: types.SpecStatePassed, } reporter.BeforeSuiteDidRun(beforeSuite) afterSuite := &types.SetupSummary{ State: types.SpecStatePassed, } reporter.AfterSuiteDidRun(afterSuite) // Set the ReportPassed config flag, in order to show captured output when tests have passed. reporter.ReporterConfig.ReportPassed = true spec := &types.SpecSummary{ ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, CapturedOutput: "Test scenario...", State: types.SpecStatePassed, RunTime: 5 * time.Second, } reporter.SpecWillRun(spec) reporter.SpecDidComplete(spec) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 0, RunTime: 10 * time.Second, }) }) It("should record the test as passing", func() { actual := buffer.String() expected := "##teamcity[testSuiteStarted name='Foo|'s test suite']\n" + "##teamcity[testStarted name='A B C']\n" + "##teamcity[testPassed name='A B C' details='Test scenario...']\n" + "##teamcity[testFinished name='A B C' duration='5000']\n" + "##teamcity[testSuiteFinished name='Foo|'s test suite']\n" Ω(actual).Should(Equal(expected)) }) }) Describe("when the BeforeSuite fails", func() { var beforeSuite *types.SetupSummary BeforeEach(func() { beforeSuite = &types.SetupSummary{ State: types.SpecStateFailed, RunTime: 3 * time.Second, Failure: types.SpecFailure{ Message: "failed to setup\n", ComponentCodeLocation: codelocation.New(0), Location: codelocation.New(2), }, } reporter.BeforeSuiteDidRun(beforeSuite) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 1, RunTime: 10 * time.Second, }) }) It("should record the test as having failed", func() { actual := buffer.String() expected := fmt.Sprintf( "##teamcity[testSuiteStarted name='Foo|'s test suite']\n"+ "##teamcity[testStarted name='BeforeSuite']\n"+ "##teamcity[testFailed name='BeforeSuite' message='%s' details='failed to setup|n|n%s']\n"+ "##teamcity[testFinished name='BeforeSuite' duration='3000']\n"+ "##teamcity[testSuiteFinished name='Foo|'s test suite']\n", beforeSuite.Failure.ComponentCodeLocation.String(), beforeSuite.Failure.Location.String(), ) Ω(actual).Should(Equal(expected)) }) }) Describe("when the AfterSuite fails", func() { var afterSuite *types.SetupSummary BeforeEach(func() { afterSuite = &types.SetupSummary{ State: types.SpecStateFailed, RunTime: 3 * time.Second, Failure: types.SpecFailure{ Message: "failed to setup\n", ComponentCodeLocation: codelocation.New(0), Location: codelocation.New(2), }, } reporter.AfterSuiteDidRun(afterSuite) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 1, RunTime: 10 * time.Second, }) }) It("should record the test as having failed", func() { actual := buffer.String() expected := fmt.Sprintf( "##teamcity[testSuiteStarted name='Foo|'s test suite']\n"+ "##teamcity[testStarted name='AfterSuite']\n"+ "##teamcity[testFailed name='AfterSuite' message='%s' details='failed to setup|n|n%s']\n"+ "##teamcity[testFinished name='AfterSuite' duration='3000']\n"+ "##teamcity[testSuiteFinished name='Foo|'s test suite']\n", afterSuite.Failure.ComponentCodeLocation.String(), afterSuite.Failure.Location.String(), ) Ω(actual).Should(Equal(expected)) }) }) specStateCases := []struct { state types.SpecState message string }{ {types.SpecStateFailed, "Failure"}, {types.SpecStateTimedOut, "Timeout"}, {types.SpecStatePanicked, "Panic"}, } for _, specStateCase := range specStateCases { specStateCase := specStateCase Describe("a failing test", func() { var spec *types.SpecSummary BeforeEach(func() { spec = &types.SpecSummary{ ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, State: specStateCase.state, RunTime: 5 * time.Second, Failure: types.SpecFailure{ ComponentCodeLocation: codelocation.New(0), Location: codelocation.New(2), Message: "I failed", }, } reporter.SpecWillRun(spec) reporter.SpecDidComplete(spec) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 1, RunTime: 10 * time.Second, }) }) It("should record test as failing", func() { actual := buffer.String() expected := fmt.Sprintf("##teamcity[testSuiteStarted name='Foo|'s test suite']\n"+ "##teamcity[testStarted name='A B C']\n"+ "##teamcity[testFailed name='A B C' message='%s' details='I failed|n%s']\n"+ "##teamcity[testFinished name='A B C' duration='5000']\n"+ "##teamcity[testSuiteFinished name='Foo|'s test suite']\n", spec.Failure.ComponentCodeLocation.String(), spec.Failure.Location.String(), ) Ω(actual).Should(Equal(expected)) }) }) } for _, specStateCase := range []types.SpecState{types.SpecStatePending, types.SpecStateSkipped} { specStateCase := specStateCase Describe("a skipped test", func() { var spec *types.SpecSummary BeforeEach(func() { spec = &types.SpecSummary{ ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, State: specStateCase, RunTime: 5 * time.Second, } reporter.SpecWillRun(spec) reporter.SpecDidComplete(spec) reporter.SpecSuiteDidEnd(&types.SuiteSummary{ NumberOfSpecsThatWillBeRun: 1, NumberOfFailedSpecs: 0, RunTime: 10 * time.Second, }) }) It("should record test as ignored", func() { actual := buffer.String() expected := "##teamcity[testSuiteStarted name='Foo|'s test suite']\n" + "##teamcity[testStarted name='A B C']\n" + "##teamcity[testIgnored name='A B C']\n" + "##teamcity[testFinished name='A B C' duration='5000']\n" + "##teamcity[testSuiteFinished name='Foo|'s test suite']\n" Ω(actual).Should(Equal(expected)) }) }) } }) ginkgo-1.14.2/types/000077500000000000000000000000001374111457300142275ustar00rootroot00000000000000ginkgo-1.14.2/types/code_location.go000066400000000000000000000004041374111457300173560ustar00rootroot00000000000000package types import ( "fmt" ) type CodeLocation struct { FileName string LineNumber int FullStackTrace string } func (codeLocation CodeLocation) String() string { return fmt.Sprintf("%s:%d", codeLocation.FileName, codeLocation.LineNumber) } ginkgo-1.14.2/types/synchronization.go000066400000000000000000000007661374111457300200300ustar00rootroot00000000000000package types import ( "encoding/json" ) type RemoteBeforeSuiteState int const ( RemoteBeforeSuiteStateInvalid RemoteBeforeSuiteState = iota RemoteBeforeSuiteStatePending RemoteBeforeSuiteStatePassed RemoteBeforeSuiteStateFailed RemoteBeforeSuiteStateDisappeared ) type RemoteBeforeSuiteData struct { Data []byte State RemoteBeforeSuiteState } func (r RemoteBeforeSuiteData) ToJSON() []byte { data, _ := json.Marshal(r) return data } type RemoteAfterSuiteData struct { CanRun bool } ginkgo-1.14.2/types/types.go000066400000000000000000000070041374111457300157230ustar00rootroot00000000000000package types import ( "strconv" "time" ) const GINKGO_FOCUS_EXIT_CODE = 197 /* SuiteSummary represents the a summary of the test suite and is passed to both Reporter.SpecSuiteWillBegin Reporter.SpecSuiteDidEnd this is unfortunate as these two methods should receive different objects. When running in parallel each node does not deterministically know how many specs it will end up running. Unfortunately making such a change would break backward compatibility. Until Ginkgo 2.0 comes out we will continue to reuse this struct but populate unknown fields with -1. */ type SuiteSummary struct { SuiteDescription string SuiteSucceeded bool SuiteID string NumberOfSpecsBeforeParallelization int NumberOfTotalSpecs int NumberOfSpecsThatWillBeRun int NumberOfPendingSpecs int NumberOfSkippedSpecs int NumberOfPassedSpecs int NumberOfFailedSpecs int // Flaked specs are those that failed initially, but then passed on a // subsequent try. NumberOfFlakedSpecs int RunTime time.Duration } type SpecSummary struct { ComponentTexts []string ComponentCodeLocations []CodeLocation State SpecState RunTime time.Duration Failure SpecFailure IsMeasurement bool NumberOfSamples int Measurements map[string]*SpecMeasurement CapturedOutput string SuiteID string } func (s SpecSummary) HasFailureState() bool { return s.State.IsFailure() } func (s SpecSummary) TimedOut() bool { return s.State == SpecStateTimedOut } func (s SpecSummary) Panicked() bool { return s.State == SpecStatePanicked } func (s SpecSummary) Failed() bool { return s.State == SpecStateFailed } func (s SpecSummary) Passed() bool { return s.State == SpecStatePassed } func (s SpecSummary) Skipped() bool { return s.State == SpecStateSkipped } func (s SpecSummary) Pending() bool { return s.State == SpecStatePending } type SetupSummary struct { ComponentType SpecComponentType CodeLocation CodeLocation State SpecState RunTime time.Duration Failure SpecFailure CapturedOutput string SuiteID string } type SpecFailure struct { Message string Location CodeLocation ForwardedPanic string ComponentIndex int ComponentType SpecComponentType ComponentCodeLocation CodeLocation } type SpecMeasurement struct { Name string Info interface{} Order int Results []float64 Smallest float64 Largest float64 Average float64 StdDeviation float64 SmallestLabel string LargestLabel string AverageLabel string Units string Precision int } func (s SpecMeasurement) PrecisionFmt() string { if s.Precision == 0 { return "%f" } str := strconv.Itoa(s.Precision) return "%." + str + "f" } type SpecState uint const ( SpecStateInvalid SpecState = iota SpecStatePending SpecStateSkipped SpecStatePassed SpecStateFailed SpecStatePanicked SpecStateTimedOut ) func (state SpecState) IsFailure() bool { return state == SpecStateTimedOut || state == SpecStatePanicked || state == SpecStateFailed } type SpecComponentType uint const ( SpecComponentTypeInvalid SpecComponentType = iota SpecComponentTypeContainer SpecComponentTypeBeforeSuite SpecComponentTypeAfterSuite SpecComponentTypeBeforeEach SpecComponentTypeJustBeforeEach SpecComponentTypeJustAfterEach SpecComponentTypeAfterEach SpecComponentTypeIt SpecComponentTypeMeasure ) type FlagType uint const ( FlagTypeNone FlagType = iota FlagTypeFocused FlagTypePending ) ginkgo-1.14.2/types/types_suite_test.go000066400000000000000000000002741374111457300201750ustar00rootroot00000000000000package types_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestTypes(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Types Suite") } ginkgo-1.14.2/types/types_test.go000066400000000000000000000047201374111457300167640ustar00rootroot00000000000000package types_test import ( . "github.com/onsi/ginkgo/types" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var specStates = []SpecState{ SpecStatePassed, SpecStateTimedOut, SpecStatePanicked, SpecStateFailed, SpecStatePending, SpecStateSkipped, } func verifySpecSummary(caller func(SpecSummary) bool, trueStates ...SpecState) { summary := SpecSummary{} trueStateLookup := map[SpecState]bool{} for _, state := range trueStates { trueStateLookup[state] = true summary.State = state Ω(caller(summary)).Should(BeTrue()) } for _, state := range specStates { if trueStateLookup[state] { continue } summary.State = state Ω(caller(summary)).Should(BeFalse()) } } var _ = Describe("Types", func() { Describe("IsFailureState", func() { It("knows when it is in a failure-like state", func() { verifySpecSummary(func(summary SpecSummary) bool { return summary.State.IsFailure() }, SpecStateTimedOut, SpecStatePanicked, SpecStateFailed) }) }) Describe("SpecSummary", func() { It("knows when it is in a failure-like state", func() { verifySpecSummary(func(summary SpecSummary) bool { return summary.HasFailureState() }, SpecStateTimedOut, SpecStatePanicked, SpecStateFailed) }) It("knows when it passed", func() { verifySpecSummary(func(summary SpecSummary) bool { return summary.Passed() }, SpecStatePassed) }) It("knows when it has failed", func() { verifySpecSummary(func(summary SpecSummary) bool { return summary.Failed() }, SpecStateFailed) }) It("knows when it has panicked", func() { verifySpecSummary(func(summary SpecSummary) bool { return summary.Panicked() }, SpecStatePanicked) }) It("knows when it has timed out", func() { verifySpecSummary(func(summary SpecSummary) bool { return summary.TimedOut() }, SpecStateTimedOut) }) It("knows when it is pending", func() { verifySpecSummary(func(summary SpecSummary) bool { return summary.Pending() }, SpecStatePending) }) It("knows when it is skipped", func() { verifySpecSummary(func(summary SpecSummary) bool { return summary.Skipped() }, SpecStateSkipped) }) }) Describe("SpecMeasurement", func() { It("knows how to format values when the precision is 0", func() { Ω(SpecMeasurement{}.PrecisionFmt()).Should(Equal("%f")) }) It("knows how to format the values when the precision is 3", func() { Ω(SpecMeasurement{Precision: 3}.PrecisionFmt()).Should(Equal("%.3f")) }) }) })