Full Code of smartystreets/goconvey for AI

master a50310f1e3e5 cached
125 files
1.3 MB
372.2k tokens
1036 symbols
1 requests
Download .txt
Showing preview only (1,361K chars total). Download the full file or copy to clipboard to get everything.
Repository: smartystreets/goconvey
Branch: master
Commit: a50310f1e3e5
Files: 125
Total size: 1.3 MB

Directory structure:
gitextract_udu2kvxk/

├── .gitattributes
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── check_third_party.sh
├── convey/
│   ├── assertions.go
│   ├── context.go
│   ├── convey.goconvey
│   ├── discovery.go
│   ├── doc.go
│   ├── focused_execution_test.go
│   ├── gotest/
│   │   ├── doc_test.go
│   │   └── utils.go
│   ├── init.go
│   ├── isolated_execution_test.go
│   ├── nilReporter.go
│   ├── reporting/
│   │   ├── console.go
│   │   ├── doc.go
│   │   ├── dot.go
│   │   ├── dot_test.go
│   │   ├── gotest.go
│   │   ├── gotest_test.go
│   │   ├── init.go
│   │   ├── json.go
│   │   ├── printer.go
│   │   ├── printer_test.go
│   │   ├── problems.go
│   │   ├── problems_test.go
│   │   ├── reporter.go
│   │   ├── reporter_test.go
│   │   ├── reporting.goconvey
│   │   ├── reports.go
│   │   ├── statistics.go
│   │   └── story.go
│   ├── reporting_hooks_test.go
│   ├── stack_trace_test.go
│   ├── story_conventions_test.go
│   └── update_assertions.sh
├── examples/
│   ├── assertion_examples_test.go
│   ├── bowling_game.go
│   ├── bowling_game_test.go
│   ├── doc.go
│   ├── examples.goconvey
│   └── simple_example_test.go
├── go.mod
├── go.sum
├── goconvey.go
└── web/
    ├── client/
    │   ├── composer.html
    │   ├── index.html
    │   └── resources/
    │       ├── css/
    │       │   ├── common.css
    │       │   ├── composer.css
    │       │   ├── themes/
    │       │   │   ├── dark-bigtext.css
    │       │   │   ├── dark.css
    │       │   │   └── light.css
    │       │   └── tipsy.css
    │       ├── fonts/
    │       │   ├── FontAwesome/
    │       │   │   ├── README.md
    │       │   │   ├── css/
    │       │   │   │   └── font-awesome.css
    │       │   │   └── fonts/
    │       │   │       └── FontAwesome.otf
    │       │   ├── Open_Sans/
    │       │   │   └── LICENSE.txt
    │       │   ├── Orbitron/
    │       │   │   └── OFL.txt
    │       │   └── Oswald/
    │       │       └── OFL.txt
    │       └── js/
    │           ├── composer.js
    │           ├── config.js
    │           ├── convey.js
    │           ├── goconvey.js
    │           ├── lib/
    │           │   ├── ansispan.js
    │           │   ├── diff_match_patch.js
    │           │   ├── jquery-ui.js
    │           │   ├── jquery-ui.js.url
    │           │   ├── jquery.js
    │           │   ├── jquery.js.url
    │           │   ├── jquery.pretty-text-diff.js
    │           │   ├── jquery.pretty-text-diff.js.url
    │           │   ├── jquery.tipsy.js
    │           │   ├── jquery.tipsy.js.url
    │           │   ├── markup.js
    │           │   ├── markup.js.url
    │           │   ├── moment.js
    │           │   ├── moment.js.url
    │           │   ├── taboverride.js
    │           │   ├── taboverride.js.url
    │           │   └── update.sh
    │           └── poller.js
    └── server/
        ├── api/
        │   ├── api.goconvey
        │   ├── server.go
        │   └── server_test.go
        ├── contract/
        │   ├── contracts.go
        │   ├── doc_test.go
        │   └── result.go
        ├── executor/
        │   ├── contract.go
        │   ├── coordinator.go
        │   ├── executor.go
        │   ├── executor.goconvey
        │   ├── executor_test.go
        │   ├── tester.go
        │   └── tester_test.go
        ├── messaging/
        │   ├── doc_test.go
        │   └── messages.go
        ├── parser/
        │   ├── packageParser.go
        │   ├── package_parser_test.go
        │   ├── parser.go
        │   ├── parser.goconvey
        │   ├── parser_test.go
        │   ├── rules.go
        │   ├── testParser.go
        │   └── util.go
        ├── system/
        │   ├── shell.go
        │   ├── shell_integration_test.go
        │   ├── shell_test.go
        │   └── system.goconvey
        └── watch/
            ├── functional_core.go
            ├── functional_core_test.go
            ├── imperative_shell.go
            ├── integration.go
            ├── integration_test.go
            ├── integration_testing/
            │   ├── doc_test.go
            │   ├── main.go
            │   └── sub/
            │       ├── .gitignore
            │       ├── stuff.go
            │       ├── stuff_test.go
            │       └── sub.goconvey
            ├── util_test.go
            └── watch.goconvey

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
web/client/resources/js/lib/* linguist-vendored


================================================
FILE: .gitignore
================================================
.DS_Store
Thumbs.db
examples/output.json
web/client/reports/
/.idea
/goconvey


================================================
FILE: .travis.yml
================================================
arch:
  - amd64
  - ppc64le

language: go

go:
  - 1.13.x
  - 1.14.x
  - 1.15.x
  - 1.16.x
  - master

install:
  - go get -t ./...

before_script: ./check_third_party.sh
script: go test -short -v ./...

sudo: false


================================================
FILE: CONTRIBUTING.md
================================================
# Subject: GoConvey maintainers wanted

We'd like to open the project up to additional maintainers who want to move the project forward in a meaningful way.

We've spent significant time at SmartyStreets building GoConvey and it has perfectly met (and exceeded) all of our initial design specifications. We've used it to great effect. Being so well-matched to our development workflows at SmartyStreets, we haven't had a need to hack on it lately. This had been frustrating to many in the community who have ideas for the project and would like to see new features released (and some old bugs fixed). The release of Go 1.5 and the new vendoring experiment has been a source of confusion and hassle for those who have already upgraded and find that GoConvey needs to be brought up to speed.

GoConvey is a popular 2-pronged, open-source github project (1,600+ stargazers, 100+ forks):

- A package you import in your test code that allows you to write BDD-style tests.
- An executable that runs a local web server which displays auto-updating test results in a web browser.

----

- https://github.com/smartystreets/goconvey
- https://github.com/smartystreets/goconvey/wiki

_I should mention that the [assertions package](https://github.com/smartystreets/assertions) imported by the convey package is used by other projects at SmartyStreets and so we will be continuing to maintain that project internally._

We hope to hear from you soon. Thanks!

---

# Contributing

In general, the code posted to the [SmartyStreets github organization](https://github.com/smartystreets) is created to solve specific problems at SmartyStreets that are ancillary to our core products in the address verification industry and may or may not be useful to other organizations or developers. Our reason for posting said code isn't necessarily to solicit feedback or contributions from the community but more as a showcase of some of the approaches to solving problems we have adopted.

Having stated that, we do consider issues raised by other githubbers as well as contributions submitted via pull requests. When submitting such a pull request, please follow these guidelines:

- _Look before you leap:_ If the changes you plan to make are significant, it's in everyone's best interest for you to discuss them with a SmartyStreets team member prior to opening a pull request.
- _License and ownership:_ If modifying the `LICENSE.md` file, limit your changes to fixing typographical mistakes. Do NOT modify the actual terms in the license or the copyright by **SmartyStreets, LLC**. Code submitted to SmartyStreets projects becomes property of SmartyStreets and must be compatible with the associated license.
- _Testing:_ If the code you are submitting resides in packages/modules covered by automated tests, be sure to add passing tests that cover your changes and assert expected behavior and state. Submit the additional test cases as part of your change set.
- _Style:_ Match your approach to **naming** and **formatting** with the surrounding code. Basically, the code you submit shouldn't stand out.
  - "Naming" refers to such constructs as variables, methods, functions, classes, structs, interfaces, packages, modules, directories, files, etc...
  - "Formatting" refers to such constructs as whitespace, horizontal line length, vertical function length, vertical file length, indentation, curly braces, etc...


================================================
FILE: LICENSE.md
================================================
MIT License

Copyright (c) 2022 Smarty

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.

NOTE: Various optional and subordinate components carry their own licensing
requirements and restrictions.  Use of those components is subject to the terms
and conditions outlined the respective license of each component.


================================================
FILE: README.md
================================================
# SMARTY DISCLAIMER: Subject to the terms of the associated license agreement, this software is freely available for your use. This software is FREE, AS IN PUPPIES, and is a gift. Enjoy your new responsibility. This means that while we may consider enhancement requests, we may or may not choose to entertain requests at our sole and absolute discretion.

GoConvey is awesome Go testing
==============================

[![Build Status](https://app.travis-ci.com/smartystreets/goconvey.svg?branch=master)](https://app.travis-ci.com/smartystreets/goconvey)
[![GoDoc](https://godoc.org/github.com/smartystreets/goconvey?status.svg)](http://godoc.org/github.com/smartystreets/goconvey)


Welcome to GoConvey, a yummy Go testing tool for gophers. Works with `go test`. Use it in the terminal or browser according to your viewing pleasure.

GoConvey supports the current versions of Go (see the official Go
[release policy](https://golang.org/doc/devel/release#policy)). Currently
this means Go 1.16 and Go 1.17 are supported.

**Features:**

- Directly integrates with `go test`
- Fully-automatic web UI (works with native Go tests, too)
- Huge suite of regression tests
- Shows test coverage
- Readable, colorized console output (understandable by any manager, IT or not)
- Test code generator
- Desktop notifications (optional)
- Immediately open problem lines in [Sublime Text](http://www.sublimetext.com) ([some assembly required](https://github.com/asuth/subl-handler))


You can ask questions about how to use GoConvey on [StackOverflow](http://stackoverflow.com/questions/ask?tags=goconvey,go&title=GoConvey%3A%20). Use the tags `go` and `goconvey`.

**Menu:**

- [Installation](#installation)
- [Quick start](#quick-start)
- [Documentation](#documentation)
- [Screenshots](#screenshots)
- [Contributors](#contributors)




Installation
------------

	$ go install github.com/smartystreets/goconvey

[Quick start](https://github.com/smartystreets/goconvey/wiki#get-going-in-25-seconds)
-----------

Make a test, for example:

```go
package package_name

import (
    "testing"
    . "github.com/smartystreets/goconvey/convey"
)

func TestSpec(t *testing.T) {

	// Only pass t into top-level Convey calls
	Convey("Given some integer with a starting value", t, func() {
		x := 1

		Convey("When the integer is incremented", func() {
			x++

			Convey("The value should be greater by one", func() {
				So(x, ShouldEqual, 2)
			})
		})
	})
}
```


#### [In the browser](https://github.com/smartystreets/goconvey/wiki/Web-UI)

Start up the GoConvey web server at your project's path:

	$ $GOPATH/bin/goconvey

Then watch the test results display in your browser at:

	http://localhost:8080


If the browser doesn't open automatically, please click [http://localhost:8080](http://localhost:8080) to open manually.

There you have it.
![](http://d79i1fxsrar4t.cloudfront.net/goconvey.co/gc-1-dark.png)
As long as GoConvey is running, test results will automatically update in your browser window.

![](http://d79i1fxsrar4t.cloudfront.net/goconvey.co/gc-5-dark.png)
The design is responsive, so you can squish the browser real tight if you need to put it beside your code.


The [web UI](https://github.com/smartystreets/goconvey/wiki/Web-UI) supports traditional Go tests, so use it even if you're not using GoConvey tests.



#### [In the terminal](https://github.com/smartystreets/goconvey/wiki/Execution)

Just do what you do best:

    $ go test

Or if you want the output to include the story:

    $ go test -v


[Documentation](https://github.com/smartystreets/goconvey/wiki)
-----------

Check out the

- [GoConvey wiki](https://github.com/smartystreets/goconvey/wiki),
- [![GoDoc](https://godoc.org/github.com/smartystreets/goconvey?status.png)](http://godoc.org/github.com/smartystreets/goconvey)
- and the *_test.go files scattered throughout this project.

Contributors
----------------------

GoConvey is brought to you by [SmartyStreets](https://github.com/smartystreets) and [several contributors](https://github.com/smartystreets/goconvey/graphs/contributors) (Thanks!).


================================================
FILE: check_third_party.sh
================================================
#!/usr/bin/env bash

cd "$(dirname $(realpath $0))"

bash ./web/client/resources/js/lib/update.sh

if ! (git diff-files --quiet web/client/resources/js/lib); then
  echo "Third party libraries don't match their .url files."
  echo "Re-run ./web/client/resources/js/lib/update.sh"
  exit 1
fi


================================================
FILE: convey/assertions.go
================================================
package convey

// DO NOT EDIT: generated by update_assertions.sh

//go:generate ./update_assertions.sh

import "github.com/smarty/assertions"

// These assertions are forwarded from github.com/smarty/assertions
// in order to make convey self-contained.
var (
	ShouldAlmostEqual            = assertions.ShouldAlmostEqual
	ShouldBeBetween              = assertions.ShouldBeBetween
	ShouldBeBetweenOrEqual       = assertions.ShouldBeBetweenOrEqual
	ShouldBeBlank                = assertions.ShouldBeBlank
	ShouldBeChronological        = assertions.ShouldBeChronological
	ShouldBeEmpty                = assertions.ShouldBeEmpty
	ShouldBeError                = assertions.ShouldBeError
	ShouldBeFalse                = assertions.ShouldBeFalse
	ShouldBeGreaterThan          = assertions.ShouldBeGreaterThan
	ShouldBeGreaterThanOrEqualTo = assertions.ShouldBeGreaterThanOrEqualTo
	ShouldBeIn                   = assertions.ShouldBeIn
	ShouldBeLessThan             = assertions.ShouldBeLessThan
	ShouldBeLessThanOrEqualTo    = assertions.ShouldBeLessThanOrEqualTo
	ShouldBeNil                  = assertions.ShouldBeNil
	ShouldBeTrue                 = assertions.ShouldBeTrue
	ShouldBeZeroValue            = assertions.ShouldBeZeroValue
	ShouldContain                = assertions.ShouldContain
	ShouldContainKey             = assertions.ShouldContainKey
	ShouldContainSubstring       = assertions.ShouldContainSubstring
	ShouldEndWith                = assertions.ShouldEndWith
	ShouldEqual                  = assertions.ShouldEqual
	ShouldEqualJSON              = assertions.ShouldEqualJSON
	ShouldEqualTrimSpace         = assertions.ShouldEqualTrimSpace
	ShouldEqualWithout           = assertions.ShouldEqualWithout
	ShouldHappenAfter            = assertions.ShouldHappenAfter
	ShouldHappenBefore           = assertions.ShouldHappenBefore
	ShouldHappenBetween          = assertions.ShouldHappenBetween
	ShouldHappenOnOrAfter        = assertions.ShouldHappenOnOrAfter
	ShouldHappenOnOrBefore       = assertions.ShouldHappenOnOrBefore
	ShouldHappenOnOrBetween      = assertions.ShouldHappenOnOrBetween
	ShouldHappenWithin           = assertions.ShouldHappenWithin
	ShouldHaveLength             = assertions.ShouldHaveLength
	ShouldHaveSameTypeAs         = assertions.ShouldHaveSameTypeAs
	ShouldImplement              = assertions.ShouldImplement
	ShouldNotAlmostEqual         = assertions.ShouldNotAlmostEqual
	ShouldNotBeBetween           = assertions.ShouldNotBeBetween
	ShouldNotBeBetweenOrEqual    = assertions.ShouldNotBeBetweenOrEqual
	ShouldNotBeBlank             = assertions.ShouldNotBeBlank
	ShouldNotBeChronological     = assertions.ShouldNotBeChronological
	ShouldNotBeEmpty             = assertions.ShouldNotBeEmpty
	ShouldNotBeIn                = assertions.ShouldNotBeIn
	ShouldNotBeNil               = assertions.ShouldNotBeNil
	ShouldNotBeZeroValue         = assertions.ShouldNotBeZeroValue
	ShouldNotContain             = assertions.ShouldNotContain
	ShouldNotContainKey          = assertions.ShouldNotContainKey
	ShouldNotContainSubstring    = assertions.ShouldNotContainSubstring
	ShouldNotEndWith             = assertions.ShouldNotEndWith
	ShouldNotEqual               = assertions.ShouldNotEqual
	ShouldNotHappenOnOrBetween   = assertions.ShouldNotHappenOnOrBetween
	ShouldNotHappenWithin        = assertions.ShouldNotHappenWithin
	ShouldNotHaveSameTypeAs      = assertions.ShouldNotHaveSameTypeAs
	ShouldNotImplement           = assertions.ShouldNotImplement
	ShouldNotPanic               = assertions.ShouldNotPanic
	ShouldNotPanicWith           = assertions.ShouldNotPanicWith
	ShouldNotPointTo             = assertions.ShouldNotPointTo
	ShouldNotResemble            = assertions.ShouldNotResemble
	ShouldNotStartWith           = assertions.ShouldNotStartWith
	ShouldPanic                  = assertions.ShouldPanic
	ShouldPanicWith              = assertions.ShouldPanicWith
	ShouldPointTo                = assertions.ShouldPointTo
	ShouldResemble               = assertions.ShouldResemble
	ShouldStartWith              = assertions.ShouldStartWith
	ShouldWrap                   = assertions.ShouldWrap
)


================================================
FILE: convey/context.go
================================================
package convey

import (
	"fmt"

	"github.com/jtolds/gls"
	"github.com/smartystreets/goconvey/convey/reporting"
)

type conveyErr struct {
	fmt    string
	params []any
}

func (e *conveyErr) Error() string {
	return fmt.Sprintf(e.fmt, e.params...)
}

func conveyPanic(fmt string, params ...any) {
	panic(&conveyErr{fmt, params})
}

const (
	missingGoTest = `Top-level calls to Convey(...) need a reference to the *testing.T.
		Hint: Convey("description here", t, func() { /* notice that the second argument was the *testing.T (t)! */ }) `
	extraGoTest    = `Only the top-level call to Convey(...) needs a reference to the *testing.T.`
	noStackContext = "Convey operation made without context on goroutine stack.\n" +
		"Hint: Perhaps you meant to use `Convey(..., func(c C){...})` ?"
	differentConveySituations = "Different set of Convey statements on subsequent pass!\nDid not expect %#v."
	multipleIdenticalConvey   = "Multiple convey suites with identical names: %#v"
)

const (
	failureHalt = "___FAILURE_HALT___"

	nodeKey = "node"
)

///////////////////////////////// Stack Context /////////////////////////////////

func getCurrentContext() *context {
	ctx, ok := ctxMgr.GetValue(nodeKey)
	if ok {
		return ctx.(*context)
	}
	return nil
}

func mustGetCurrentContext() *context {
	ctx := getCurrentContext()
	if ctx == nil {
		conveyPanic(noStackContext)
	}
	return ctx
}

//////////////////////////////////// Context ////////////////////////////////////

// context magically handles all coordination of Convey's and So assertions.
//
// It is tracked on the stack as goroutine-local-storage with the gls package,
// or explicitly if the user decides to call convey like:
//
//   Convey(..., func(c C) {
//     c.So(...)
//   })
//
// This implements the `C` interface.
type context struct {
	reporter reporting.Reporter

	children map[string]*context

	resets []func()

	executedOnce   bool
	expectChildRun *bool
	complete       bool

	focus       bool
	failureMode FailureMode
	stackMode   StackMode
}

// rootConvey is the main entry point to a test suite. This is called when
// there's no context in the stack already, and items must contain a `t` object,
// or this panics.
func rootConvey(items ...any) {
	entry := discover(items)

	if entry.Test == nil {
		conveyPanic(missingGoTest)
	}

	expectChildRun := true
	ctx := &context{
		reporter: buildReporter(),

		children: make(map[string]*context),

		expectChildRun: &expectChildRun,

		focus:       entry.Focus,
		failureMode: defaultFailureMode.combine(entry.FailMode),
		stackMode:   defaultStackMode.combine(entry.StackMode),
	}
	ctxMgr.SetValues(gls.Values{nodeKey: ctx}, func() {
		ctx.reporter.BeginStory(reporting.NewStoryReport(entry.Test))
		defer ctx.reporter.EndStory()

		for ctx.shouldVisit() {
			ctx.conveyInner(entry.Situation, entry.Func)
			expectChildRun = true
		}
	})
}

//////////////////////////////////// Methods ////////////////////////////////////

func (ctx *context) SkipConvey(items ...any) {
	ctx.Convey(items, skipConvey)
}

func (ctx *context) FocusConvey(items ...any) {
	ctx.Convey(items, focusConvey)
}

func (ctx *context) Convey(items ...any) {
	entry := discover(items)

	// we're a branch, or leaf (on the wind)
	if entry.Test != nil {
		conveyPanic(extraGoTest)
	}
	if ctx.focus && !entry.Focus {
		return
	}

	var inner_ctx *context
	if ctx.executedOnce {
		var ok bool
		inner_ctx, ok = ctx.children[entry.Situation]
		if !ok {
			conveyPanic(differentConveySituations, entry.Situation)
		}
	} else {
		if _, ok := ctx.children[entry.Situation]; ok {
			conveyPanic(multipleIdenticalConvey, entry.Situation)
		}
		inner_ctx = &context{
			reporter: ctx.reporter,

			children: make(map[string]*context),

			expectChildRun: ctx.expectChildRun,

			focus:       entry.Focus,
			failureMode: ctx.failureMode.combine(entry.FailMode),
			stackMode:   ctx.stackMode.combine(entry.StackMode),
		}
		ctx.children[entry.Situation] = inner_ctx
	}

	if inner_ctx.shouldVisit() {
		ctxMgr.SetValues(gls.Values{nodeKey: inner_ctx}, func() {
			inner_ctx.conveyInner(entry.Situation, entry.Func)
		})
	}
}

func (ctx *context) SkipSo(stuff ...any) {
	ctx.assertionReport(reporting.NewSkipReport())
}

func (ctx *context) So(actual any, assert Assertion, expected ...any) {
	if result := assert(actual, expected...); result == assertionSuccess {
		ctx.assertionReport(reporting.NewSuccessReport())
	} else {
		ctx.assertionReport(reporting.NewFailureReport(result, ctx.shouldShowStack()))
	}
}

func (ctx *context) SoMsg(msg string, actual any, assert Assertion, expected ...any) {
	if result := assert(actual, expected...); result == assertionSuccess {
		ctx.assertionReport(reporting.NewSuccessReport())
		return
	} else {
		ctx.reporter.Enter(reporting.NewScopeReport(msg))
		defer ctx.reporter.Exit()
		ctx.assertionReport(reporting.NewFailureReport(result, ctx.shouldShowStack()))
	}
}

func (ctx *context) Reset(action func()) {
	/* TODO: Failure mode configuration */
	ctx.resets = append(ctx.resets, action)
}

func (ctx *context) Print(items ...any) (int, error) {
	fmt.Fprint(ctx.reporter, items...)
	return fmt.Print(items...)
}

func (ctx *context) Println(items ...any) (int, error) {
	fmt.Fprintln(ctx.reporter, items...)
	return fmt.Println(items...)
}

func (ctx *context) Printf(format string, items ...any) (int, error) {
	fmt.Fprintf(ctx.reporter, format, items...)
	return fmt.Printf(format, items...)
}

//////////////////////////////////// Private ////////////////////////////////////

// shouldVisit returns true iff we should traverse down into a Convey. Note
// that just because we don't traverse a Convey this time, doesn't mean that
// we may not traverse it on a subsequent pass.
func (c *context) shouldVisit() bool {
	return !c.complete && *c.expectChildRun
}

func (c *context) shouldShowStack() bool {
	return c.stackMode == StackFail
}

// conveyInner is the function which actually executes the user's anonymous test
// function body. At this point, Convey or RootConvey has decided that this
// function should actually run.
func (ctx *context) conveyInner(situation string, f func(C)) {
	// Record/Reset state for next time.
	defer func() {
		ctx.executedOnce = true

		// This is only needed at the leaves, but there's no harm in also setting it
		// when returning from branch Convey's
		*ctx.expectChildRun = false
	}()

	// Set up+tear down our scope for the reporter
	ctx.reporter.Enter(reporting.NewScopeReport(situation))
	defer ctx.reporter.Exit()

	// Recover from any panics in f, and assign the `complete` status for this
	// node of the tree.
	defer func() {
		ctx.complete = true
		if problem := recover(); problem != nil {
			if problem, ok := problem.(*conveyErr); ok {
				panic(problem)
			}
			if problem != failureHalt {
				ctx.reporter.Report(reporting.NewErrorReport(problem))
			}
		} else {
			for _, child := range ctx.children {
				if !child.complete {
					ctx.complete = false
					return
				}
			}
		}
	}()

	// Resets are registered as the `f` function executes, so nil them here.
	// All resets are run in registration order (FIFO).
	ctx.resets = []func(){}
	defer func() {
		for _, r := range ctx.resets {
			// panics handled by the previous defer
			r()
		}
	}()

	if f == nil {
		// if f is nil, this was either a Convey(..., nil), or a SkipConvey
		ctx.reporter.Report(reporting.NewSkipReport())
	} else {
		f(ctx)
	}
}

// assertionReport is a helper for So and SkipSo which makes the report and
// then possibly panics, depending on the current context's failureMode.
func (ctx *context) assertionReport(r *reporting.AssertionResult) {
	ctx.reporter.Report(r)
	if r.Failure != "" && ctx.failureMode == FailureHalts {
		panic(failureHalt)
	}
}


================================================
FILE: convey/convey.goconvey
================================================
#ignore
-timeout=1s
#-covermode=count
#-coverpkg=github.com/smartystreets/goconvey/convey,github.com/smartystreets/goconvey/convey/gotest,github.com/smartystreets/goconvey/convey/reporting

================================================
FILE: convey/discovery.go
================================================
package convey

type actionSpecifier uint8

const (
	noSpecifier actionSpecifier = iota
	skipConvey
	focusConvey
)

type suite struct {
	Situation string
	Test      t
	Focus     bool
	Func      func(C) // nil means skipped
	FailMode  FailureMode
	StackMode StackMode
}

func newSuite(situation string, failureMode FailureMode, stackMode StackMode, f func(C), test t, specifier actionSpecifier) *suite {
	ret := &suite{
		Situation: situation,
		Test:      test,
		Func:      f,
		FailMode:  failureMode,
		StackMode: stackMode,
	}
	switch specifier {
	case skipConvey:
		ret.Func = nil
	case focusConvey:
		ret.Focus = true
	}
	return ret
}

func discover(items []any) *suite {
	name, items := parseName(items)
	test, items := parseGoTest(items)
	failure, items := parseFailureMode(items)
	stack, items := parseStackMode(items)
	action, items := parseAction(items)
	specifier, items := parseSpecifier(items)

	if len(items) != 0 {
		conveyPanic(parseError)
	}

	return newSuite(name, failure, stack, action, test, specifier)
}
func item(items []any) any {
	if len(items) == 0 {
		conveyPanic(parseError)
	}
	return items[0]
}
func parseName(items []any) (string, []any) {
	if name, parsed := item(items).(string); parsed {
		return name, items[1:]
	}
	conveyPanic(parseError)
	panic("never get here")
}
func parseGoTest(items []any) (t, []any) {
	if test, parsed := item(items).(t); parsed {
		return test, items[1:]
	}
	return nil, items
}
func parseFailureMode(items []any) (FailureMode, []any) {
	if mode, parsed := item(items).(FailureMode); parsed {
		return mode, items[1:]
	}
	return FailureInherits, items
}
func parseStackMode(items []any) (StackMode, []any) {
	if mode, parsed := item(items).(StackMode); parsed {
		return mode, items[1:]
	}
	return StackInherits, items
}
func parseAction(items []any) (func(C), []any) {
	switch x := item(items).(type) {
	case nil:
		return nil, items[1:]
	case func(C):
		return x, items[1:]
	case func():
		return func(C) { x() }, items[1:]
	}
	conveyPanic(parseError)
	panic("never get here")
}
func parseSpecifier(items []any) (actionSpecifier, []any) {
	if len(items) == 0 {
		return noSpecifier, items
	}
	if spec, ok := items[0].(actionSpecifier); ok {
		return spec, items[1:]
	}
	conveyPanic(parseError)
	panic("never get here")
}

// This interface allows us to pass the *testing.T struct
// throughout the internals of this package without ever
// having to import the "testing" package.
type t interface {
	Fail()
}

const parseError = "You must provide a name (string), then a *testing.T (if in outermost scope), an optional FailureMode and / or StackMode, and then an action (func())."


================================================
FILE: convey/doc.go
================================================
// Package convey contains all of the public-facing entry points to this project.
// This means that it should never be required of the user to import any other
// packages from this project as they serve internal purposes.
package convey

import "github.com/smartystreets/goconvey/convey/reporting"

////////////////////////////////// suite //////////////////////////////////

// C is the Convey context which you can optionally obtain in your action
// by calling Convey like:
//
//   Convey(..., func(c C) {
//     ...
//   })
//
// See the documentation on Convey for more details.
//
// All methods in this context behave identically to the global functions of the
// same name in this package.
type C interface {
	Convey(items ...any)
	SkipConvey(items ...any)
	FocusConvey(items ...any)

	So(actual any, assert Assertion, expected ...any)
	SoMsg(msg string, actual any, assert Assertion, expected ...any)
	SkipSo(stuff ...any)

	Reset(action func())

	Println(items ...any) (int, error)
	Print(items ...any) (int, error)
	Printf(format string, items ...any) (int, error)
}

// Convey is the method intended for use when declaring the scopes of
// a specification. Each scope has a description and a func() which may contain
// other calls to Convey(), Reset() or Should-style assertions. Convey calls can
// be nested as far as you see fit.
//
// IMPORTANT NOTE: The top-level Convey() within a Test method
// must conform to the following signature:
//
//     Convey(description string, t *testing.T, action func())
//
// All other calls should look like this (no need to pass in *testing.T):
//
//     Convey(description string, action func())
//
// Don't worry, goconvey will panic if you get it wrong so you can fix it.
//
// Additionally, you may explicitly obtain access to the Convey context by doing:
//
//     Convey(description string, action func(c C))
//
// You may need to do this if you want to pass the context through to a
// goroutine, or to close over the context in a handler to a library which
// calls your handler in a goroutine (httptest comes to mind).
//
// All Convey()-blocks also accept an optional parameter of FailureMode which sets
// how goconvey should treat failures for So()-assertions in the block and
// nested blocks. See the constants in this file for the available options.
//
// By default it will inherit from its parent block and the top-level blocks
// default to the FailureHalts setting.
//
// This parameter is inserted before the block itself:
//
//     Convey(description string, t *testing.T, mode FailureMode, action func())
//     Convey(description string, mode FailureMode, action func())
//
// See the examples package for, well, examples.
func Convey(items ...any) {
	if ctx := getCurrentContext(); ctx == nil {
		rootConvey(items...)
	} else {
		ctx.Convey(items...)
	}
}

// SkipConvey is analogous to Convey except that the scope is not executed
// (which means that child scopes defined within this scope are not run either).
// The reporter will be notified that this step was skipped.
func SkipConvey(items ...any) {
	Convey(append(items, skipConvey)...)
}

// FocusConvey is has the inverse effect of SkipConvey. If the top-level
// Convey is changed to `FocusConvey`, only nested scopes that are defined
// with FocusConvey will be run. The rest will be ignored completely. This
// is handy when debugging a large suite that runs a misbehaving function
// repeatedly as you can disable all but one of that function
// without swaths of `SkipConvey` calls, just a targeted chain of calls
// to FocusConvey.
func FocusConvey(items ...any) {
	Convey(append(items, focusConvey)...)
}

// Reset registers a cleanup function to be run after each Convey()
// in the same scope. See the examples package for a simple use case.
func Reset(action func()) {
	mustGetCurrentContext().Reset(action)
}

/////////////////////////////////// Assertions ///////////////////////////////////

// Assertion is an alias for a function with a signature that the convey.So()
// method can handle. Any future or custom assertions should conform to this
// method signature. The return value should be an empty string if the assertion
// passes and a well-formed failure message if not.
type Assertion func(actual any, expected ...any) string

const assertionSuccess = ""

// So is the means by which assertions are made against the system under test.
// The majority of exported names in the assertions package begin with the word
// 'Should' and describe how the first argument (actual) should compare with any
// of the final (expected) arguments. How many final arguments are accepted
// depends on the particular assertion that is passed in as the assert argument.
// See the examples package for use cases and the assertions package for
// documentation on specific assertion methods. A failing assertion will
// cause t.Fail() to be invoked--you should never call this method (or other
// failure-inducing methods) in your test code. Leave that to GoConvey.
func So(actual any, assert Assertion, expected ...any) {
	mustGetCurrentContext().So(actual, assert, expected...)
}

// SoMsg is an extension of So that allows you to specify a message to report on error.
func SoMsg(msg string, actual any, assert Assertion, expected ...any) {
	mustGetCurrentContext().SoMsg(msg, actual, assert, expected...)
}

// SkipSo is analogous to So except that the assertion that would have been passed
// to So is not executed and the reporter is notified that the assertion was skipped.
func SkipSo(stuff ...any) {
	mustGetCurrentContext().SkipSo()
}

// FailureMode is a type which determines how the So() blocks should fail
// if their assertion fails. See constants further down for acceptable values
type FailureMode string

// StackMode is a type which determines whether the So() blocks should report
// stack traces their assertion fails. See constants further down for acceptable values
type StackMode string

const (

	// FailureContinues is a failure mode which prevents failing
	// So()-assertions from halting Convey-block execution, instead
	// allowing the test to continue past failing So()-assertions.
	FailureContinues FailureMode = "continue"

	// FailureHalts is the default setting for a top-level Convey()-block
	// and will cause all failing So()-assertions to halt further execution
	// in that test-arm and continue on to the next arm.
	FailureHalts FailureMode = "halt"

	// FailureInherits is the default setting for failure-mode, it will
	// default to the failure-mode of the parent block. You should never
	// need to specify this mode in your tests..
	FailureInherits FailureMode = "inherits"

	// StackError is a stack mode which tells Convey to print stack traces
	// only for errors and not for test failures
	StackError StackMode = "error"

	// StackFail is a stack mode which tells Convey to print stack traces
	// for both errors and test failures
	StackFail StackMode = "fail"

	// StackInherits is the default setting for stack-mode, it will
	// default to the stack-mode of the parent block. You should never
	// need to specify this mode in your tests..
	StackInherits StackMode = "inherits"
)

func (f FailureMode) combine(other FailureMode) FailureMode {
	if other == FailureInherits {
		return f
	}
	return other
}

var defaultFailureMode FailureMode = FailureHalts

// SetDefaultFailureMode allows you to specify the default failure mode
// for all Convey blocks. It is meant to be used in an init function to
// allow the default mode to be changed across all tests for an entire packgae
// but it can be used anywhere.
func SetDefaultFailureMode(mode FailureMode) {
	if mode == FailureContinues || mode == FailureHalts {
		defaultFailureMode = mode
	} else {
		panic("You may only use the constants named 'FailureContinues' and 'FailureHalts' as default failure modes.")
	}
}

func (s StackMode) combine(other StackMode) StackMode {
	if other == StackInherits {
		return s
	}
	return other
}

var defaultStackMode StackMode = StackError

// SetDefaultStackMode allows you to specify the default stack mode
// for all Convey blocks. It is meant to be used in an init function to
// allow the default mode to be changed across all tests for an entire packgae
// but it can be used anywhere.
func SetDefaultStackMode(mode StackMode) {
	if mode == StackError || mode == StackFail {
		defaultStackMode = mode
	} else {
		panic("You may only use the constants named 'StackError' and 'StackFail' as default stack modes.")
	}
}

//////////////////////////////////// Print functions ////////////////////////////////////

// Print is analogous to fmt.Print (and it even calls fmt.Print). It ensures that
// output is aligned with the corresponding scopes in the web UI.
func Print(items ...any) (written int, err error) {
	return mustGetCurrentContext().Print(items...)
}

// Print is analogous to fmt.Println (and it even calls fmt.Println). It ensures that
// output is aligned with the corresponding scopes in the web UI.
func Println(items ...any) (written int, err error) {
	return mustGetCurrentContext().Println(items...)
}

// Print is analogous to fmt.Printf (and it even calls fmt.Printf). It ensures that
// output is aligned with the corresponding scopes in the web UI.
func Printf(format string, items ...any) (written int, err error) {
	return mustGetCurrentContext().Printf(format, items...)
}

///////////////////////////////////////////////////////////////////////////////

// SuppressConsoleStatistics prevents automatic printing of console statistics.
// Calling PrintConsoleStatistics explicitly will force printing of statistics.
func SuppressConsoleStatistics() {
	reporting.SuppressConsoleStatistics()
}

// PrintConsoleStatistics may be called at any time to print assertion statistics.
// Generally, the best place to do this would be in a TestMain function,
// after all tests have been run. Something like this:
//
// func TestMain(m *testing.M) {
//     convey.SuppressConsoleStatistics()
//     result := m.Run()
//     convey.PrintConsoleStatistics()
//     os.Exit(result)
// }
//
func PrintConsoleStatistics() {
	reporting.PrintConsoleStatistics()
}


================================================
FILE: convey/focused_execution_test.go
================================================
package convey

import "testing"

func TestFocusOnlyAtTopLevel(t *testing.T) {
	output := prepare()

	FocusConvey("hi", t, func() {
		output += "done"
	})

	expectEqual(t, "done", output)
}

func TestFocus(t *testing.T) {
	output := prepare()

	FocusConvey("hi", t, func() {
		output += "1"

		Convey("bye", func() {
			output += "2"
		})
	})

	expectEqual(t, "1", output)
}

func TestNestedFocus(t *testing.T) {
	output := prepare()

	FocusConvey("hi", t, func() {
		output += "1"

		Convey("This shouldn't run", func() {
			output += "boink!"
		})

		FocusConvey("This should run", func() {
			output += "2"

			FocusConvey("The should run too", func() {
				output += "3"

			})

			Convey("The should NOT run", func() {
				output += "blah blah blah!"
			})
		})
	})

	expectEqual(t, "123", output)
}

func TestForgotTopLevelFocus(t *testing.T) {
	output := prepare()

	Convey("1", t, func() {
		output += "1"

		FocusConvey("This will be run because the top-level lacks Focus", func() {
			output += "2"
		})

		Convey("3", func() {
			output += "3"
		})
	})

	expectEqual(t, "1213", output)
}


================================================
FILE: convey/gotest/doc_test.go
================================================
package gotest


================================================
FILE: convey/gotest/utils.go
================================================
// Package gotest contains internal functionality. Although this package
// contains one or more exported names it is not intended for public
// consumption. See the examples package for how to use this project.
package gotest

import (
	"runtime"
	"strings"
)

func ResolveExternalCaller() (file string, line int, name string) {
	var caller_id uintptr
	callers := runtime.Callers(0, callStack)

	for x := 0; x < callers; x++ {
		caller_id, file, line, _ = runtime.Caller(x)
		if strings.HasSuffix(file, "_test.go") || strings.HasSuffix(file, "_tests.go") {
			name = runtime.FuncForPC(caller_id).Name()
			return
		}
	}
	file, line, name = "<unknown file>", -1, "<unknown name>"
	return // panic?
}

const maxStackDepth = 100 // This had better be enough...

var callStack []uintptr = make([]uintptr, maxStackDepth, maxStackDepth)


================================================
FILE: convey/init.go
================================================
package convey

import (
	"flag"
	"os"

	"github.com/jtolds/gls"
	"github.com/smarty/assertions"
	"github.com/smartystreets/goconvey/convey/reporting"
)

func init() {
	assertions.GoConveyMode(true)

	declareFlags()

	ctxMgr = gls.NewContextManager()
}

func declareFlags() {
	flag.BoolVar(&json, "convey-json", false, "When true, emits results in JSON blocks. Default: 'false'")
	flag.BoolVar(&silent, "convey-silent", false, "When true, all output from GoConvey is suppressed.")
	flag.BoolVar(&story, "convey-story", false, "When true, emits story output, otherwise emits dot output. When not provided, this flag mirrors the value of the '-test.v' flag")

	if noStoryFlagProvided() {
		story = verboseEnabled
	}

	// FYI: flag.Parse() is called from the testing package.
}

func noStoryFlagProvided() bool {
	return !story && !storyDisabled
}

func buildReporter() reporting.Reporter {
	selectReporter := os.Getenv("GOCONVEY_REPORTER")

	switch {
	case testReporter != nil:
		return testReporter
	case json || selectReporter == "json":
		return reporting.BuildJsonReporter()
	case silent || selectReporter == "silent":
		return reporting.BuildSilentReporter()
	case selectReporter == "dot":
		// Story is turned on when verbose is set, so we need to check for dot reporter first.
		return reporting.BuildDotReporter()
	case story || selectReporter == "story":
		return reporting.BuildStoryReporter()
	default:
		return reporting.BuildDotReporter()
	}
}

var (
	ctxMgr *gls.ContextManager

	// only set by internal tests
	testReporter reporting.Reporter
)

var (
	json   bool
	silent bool
	story  bool

	verboseEnabled = flagFound("-test.v=true")
	storyDisabled  = flagFound("-story=false")
)

// flagFound parses the command line args manually for flags defined in other
// packages. Like the '-v' flag from the "testing" package, for instance.
func flagFound(flagValue string) bool {
	for _, arg := range os.Args {
		if arg == flagValue {
			return true
		}
	}
	return false
}


================================================
FILE: convey/isolated_execution_test.go
================================================
package convey

import (
	"strconv"
	"testing"
	"time"
)

func TestSingleScope(t *testing.T) {
	output := prepare()

	Convey("hi", t, func() {
		output += "done"
	})

	expectEqual(t, "done", output)
}

func TestSingleScopeWithMultipleConveys(t *testing.T) {
	output := prepare()

	Convey("1", t, func() {
		output += "1"
	})

	Convey("2", t, func() {
		output += "2"
	})

	expectEqual(t, "12", output)
}

func TestNestedScopes(t *testing.T) {
	output := prepare()

	Convey("a", t, func() {
		output += "a "

		Convey("bb", func() {
			output += "bb "

			Convey("ccc", func() {
				output += "ccc | "
			})
		})
	})

	expectEqual(t, "a bb ccc | ", output)
}

func TestNestedScopesWithIsolatedExecution(t *testing.T) {
	output := prepare()

	Convey("a", t, func() {
		output += "a "

		Convey("aa", func() {
			output += "aa "

			Convey("aaa", func() {
				output += "aaa | "
			})

			Convey("aaa1", func() {
				output += "aaa1 | "
			})
		})

		Convey("ab", func() {
			output += "ab "

			Convey("abb", func() {
				output += "abb | "
			})
		})
	})

	expectEqual(t, "a aa aaa | a aa aaa1 | a ab abb | ", output)
}

func TestSingleScopeWithConveyAndNestedReset(t *testing.T) {
	output := prepare()

	Convey("1", t, func() {
		output += "1"

		Reset(func() {
			output += "a"
		})
	})

	expectEqual(t, "1a", output)
}

func TestPanicingReset(t *testing.T) {
	output := prepare()

	Convey("1", t, func() {
		output += "1"

		Reset(func() {
			panic("nooo")
		})

		Convey("runs since the reset hasn't yet", func() {
			output += "a"
		})

		Convey("but this doesnt", func() {
			output += "nope"
		})
	})

	expectEqual(t, "1a", output)
}

func TestSingleScopeWithMultipleRegistrationsAndReset(t *testing.T) {
	output := prepare()

	Convey("reset after each nested convey", t, func() {
		Convey("first output", func() {
			output += "1"
		})

		Convey("second output", func() {
			output += "2"
		})

		Reset(func() {
			output += "a"
		})
	})

	expectEqual(t, "1a2a", output)
}

func TestSingleScopeWithMultipleRegistrationsAndMultipleResets(t *testing.T) {
	output := prepare()

	Convey("each reset is run at end of each nested convey", t, func() {
		Convey("1", func() {
			output += "1"
		})

		Convey("2", func() {
			output += "2"
		})

		Reset(func() {
			output += "a"
		})

		Reset(func() {
			output += "b"
		})
	})

	expectEqual(t, "1ab2ab", output)
}

func Test_Failure_AtHigherLevelScopePreventsChildScopesFromRunning(t *testing.T) {
	output := prepare()

	Convey("This step fails", t, func() {
		So(1, ShouldEqual, 2)

		Convey("this should NOT be executed", func() {
			output += "a"
		})
	})

	expectEqual(t, "", output)
}

func Test_Panic_AtHigherLevelScopePreventsChildScopesFromRunning(t *testing.T) {
	output := prepare()

	Convey("This step panics", t, func() {
		Convey("this happens, because the panic didn't happen yet", func() {
			output += "1"
		})

		output += "a"

		Convey("this should NOT be executed", func() {
			output += "2"
		})

		output += "b"

		panic("Hi")

		output += "nope"
	})

	expectEqual(t, "1ab", output)
}

func Test_Panic_InChildScopeDoes_NOT_PreventExecutionOfSiblingScopes(t *testing.T) {
	output := prepare()

	Convey("This is the parent", t, func() {
		Convey("This step panics", func() {
			panic("Hi")
			output += "1"
		})

		Convey("This sibling should execute", func() {
			output += "2"
		})
	})

	expectEqual(t, "2", output)
}

func Test_Failure_InChildScopeDoes_NOT_PreventExecutionOfSiblingScopes(t *testing.T) {
	output := prepare()

	Convey("This is the parent", t, func() {
		Convey("This step fails", func() {
			So(1, ShouldEqual, 2)
			output += "1"
		})

		Convey("This sibling should execute", func() {
			output += "2"
		})
	})

	expectEqual(t, "2", output)
}

func TestResetsAreAlwaysExecutedAfterScope_Panics(t *testing.T) {
	output := prepare()

	Convey("This is the parent", t, func() {
		Convey("This step panics", func() {
			panic("Hi")
			output += "1"
		})

		Convey("This sibling step does not panic", func() {
			output += "a"

			Reset(func() {
				output += "b"
			})
		})

		Reset(func() {
			output += "2"
		})
	})

	expectEqual(t, "2ab2", output)
}

func TestResetsAreAlwaysExecutedAfterScope_Failures(t *testing.T) {
	output := prepare()

	Convey("This is the parent", t, func() {
		Convey("This step fails", func() {
			So(1, ShouldEqual, 2)
			output += "1"
		})

		Convey("This sibling step does not fail", func() {
			output += "a"

			Reset(func() {
				output += "b"
			})
		})

		Reset(func() {
			output += "2"
		})
	})

	expectEqual(t, "2ab2", output)
}

func TestSkipTopLevel(t *testing.T) {
	output := prepare()

	SkipConvey("hi", t, func() {
		output += "This shouldn't be executed!"
	})

	expectEqual(t, "", output)
}

func TestSkipNestedLevel(t *testing.T) {
	output := prepare()

	Convey("hi", t, func() {
		output += "yes"

		SkipConvey("bye", func() {
			output += "no"
		})
	})

	expectEqual(t, "yes", output)
}

func TestSkipNestedLevelSkipsAllChildLevels(t *testing.T) {
	output := prepare()

	Convey("hi", t, func() {
		output += "yes"

		SkipConvey("bye", func() {
			output += "no"

			Convey("byebye", func() {
				output += "no-no"
			})
		})
	})

	expectEqual(t, "yes", output)
}

func TestIterativeConveys(t *testing.T) {
	output := prepare()

	Convey("Test", t, func() {
		for x := 0; x < 10; x++ {
			y := strconv.Itoa(x)

			Convey(y, func() {
				output += y
			})
		}
	})

	expectEqual(t, "0123456789", output)
}

func TestClosureVariables(t *testing.T) {
	output := prepare()

	i := 0

	Convey("A", t, func() {
		i = i + 1
		j := i

		output += "A" + strconv.Itoa(i) + " "

		Convey("B", func() {
			k := j
			j = j + 1

			output += "B" + strconv.Itoa(k) + " "

			Convey("C", func() {
				output += "C" + strconv.Itoa(k) + strconv.Itoa(j) + " "
			})

			Convey("D", func() {
				output += "D" + strconv.Itoa(k) + strconv.Itoa(j) + " "
			})
		})

		Convey("C", func() {
			output += "C" + strconv.Itoa(j) + " "
		})
	})

	output += "D" + strconv.Itoa(i) + " "

	expectEqual(t, "A1 B1 C12 A2 B2 D23 A3 C3 D3 ", output)
}

func TestClosureVariablesWithReset(t *testing.T) {
	output := prepare()

	i := 0

	Convey("A", t, func() {
		i = i + 1
		j := i

		output += "A" + strconv.Itoa(i) + " "

		Reset(func() {
			output += "R" + strconv.Itoa(i) + strconv.Itoa(j) + " "
		})

		Convey("B", func() {
			output += "B" + strconv.Itoa(j) + " "
		})

		Convey("C", func() {
			output += "C" + strconv.Itoa(j) + " "
		})
	})

	output += "D" + strconv.Itoa(i) + " "

	expectEqual(t, "A1 B1 R11 A2 C2 R22 D2 ", output)
}

func TestWrappedSimple(t *testing.T) {
	prepare()
	output := resetTestString{""}

	Convey("A", t, func() {
		func() {
			output.output += "A "

			Convey("B", func() {
				output.output += "B "

				Convey("C", func() {
					output.output += "C "
				})

			})

			Convey("D", func() {
				output.output += "D "
			})
		}()
	})

	expectEqual(t, "A B C A D ", output.output)
}

type resetTestString struct {
	output string
}

func addReset(o *resetTestString, f func()) func() {
	return func() {
		Reset(func() {
			o.output += "R "
		})

		f()
	}
}

func TestWrappedReset(t *testing.T) {
	prepare()
	output := resetTestString{""}

	Convey("A", t, addReset(&output, func() {
		output.output += "A "

		Convey("B", func() {
			output.output += "B "
		})

		Convey("C", func() {
			output.output += "C "
		})
	}))

	expectEqual(t, "A B R A C R ", output.output)
}

func TestWrappedReset2(t *testing.T) {
	prepare()
	output := resetTestString{""}

	Convey("A", t, func() {
		Reset(func() {
			output.output += "R "
		})

		func() {
			output.output += "A "

			Convey("B", func() {
				output.output += "B "

				Convey("C", func() {
					output.output += "C "
				})
			})

			Convey("D", func() {
				output.output += "D "
			})
		}()
	})

	expectEqual(t, "A B C R A D R ", output.output)
}

func TestInfiniteLoopWithTrailingFail(t *testing.T) {
	done := make(chan int)

	go func() {
		Convey("This fails", t, func() {
			Convey("and this is run", func() {
				So(true, ShouldEqual, true)
			})

			/* And this prevents the whole block to be marked as run */
			So(false, ShouldEqual, true)
		})

		done <- 1
	}()

	select {
	case <-done:
		return
	case <-time.After(1 * time.Millisecond):
		t.Fail()
	}
}

func TestOutermostResetInvokedForGrandchildren(t *testing.T) {
	output := prepare()

	Convey("A", t, func() {
		output += "A "

		Reset(func() {
			output += "rA "
		})

		Convey("B", func() {
			output += "B "

			Reset(func() {
				output += "rB "
			})

			Convey("C", func() {
				output += "C "

				Reset(func() {
					output += "rC "
				})
			})

			Convey("D", func() {
				output += "D "

				Reset(func() {
					output += "rD "
				})
			})
		})
	})

	expectEqual(t, "A B C rC rB rA A B D rD rB rA ", output)
}

func TestFailureOption(t *testing.T) {
	output := prepare()

	Convey("A", t, FailureHalts, func() {
		output += "A "
		So(true, ShouldEqual, true)
		output += "B "
		So(false, ShouldEqual, true)
		output += "C "
	})

	expectEqual(t, "A B ", output)
}

func TestFailureOption2(t *testing.T) {
	output := prepare()

	Convey("A", t, func() {
		output += "A "
		So(true, ShouldEqual, true)
		output += "B "
		So(false, ShouldEqual, true)
		output += "C "
	})

	expectEqual(t, "A B ", output)
}

func TestFailureOption3(t *testing.T) {
	output := prepare()

	Convey("A", t, FailureContinues, func() {
		output += "A "
		So(true, ShouldEqual, true)
		output += "B "
		So(false, ShouldEqual, true)
		output += "C "
	})

	expectEqual(t, "A B C ", output)
}

func TestFailureOptionInherit(t *testing.T) {
	output := prepare()

	Convey("A", t, FailureContinues, func() {
		output += "A1 "
		So(false, ShouldEqual, true)
		output += "A2 "

		Convey("B", func() {
			output += "B1 "
			So(true, ShouldEqual, true)
			output += "B2 "
			So(false, ShouldEqual, true)
			output += "B3 "
		})
	})

	expectEqual(t, "A1 A2 B1 B2 B3 ", output)
}

func TestFailureOptionInherit2(t *testing.T) {
	output := prepare()

	Convey("A", t, FailureHalts, func() {
		output += "A1 "
		So(false, ShouldEqual, true)
		output += "A2 "

		Convey("B", func() {
			output += "A1 "
			So(true, ShouldEqual, true)
			output += "A2 "
			So(false, ShouldEqual, true)
			output += "A3 "
		})
	})

	expectEqual(t, "A1 ", output)
}

func TestFailureOptionInherit3(t *testing.T) {
	output := prepare()

	Convey("A", t, FailureHalts, func() {
		output += "A1 "
		So(true, ShouldEqual, true)
		output += "A2 "

		Convey("B", func() {
			output += "B1 "
			So(true, ShouldEqual, true)
			output += "B2 "
			So(false, ShouldEqual, true)
			output += "B3 "
		})
	})

	expectEqual(t, "A1 A2 B1 B2 ", output)
}

func TestFailureOptionNestedOverride(t *testing.T) {
	output := prepare()

	Convey("A", t, FailureContinues, func() {
		output += "A "
		So(false, ShouldEqual, true)
		output += "B "

		Convey("C", FailureHalts, func() {
			output += "C "
			So(true, ShouldEqual, true)
			output += "D "
			So(false, ShouldEqual, true)
			output += "E "
		})
	})

	expectEqual(t, "A B C D ", output)
}

func TestFailureOptionNestedOverride2(t *testing.T) {
	output := prepare()

	Convey("A", t, FailureHalts, func() {
		output += "A "
		So(true, ShouldEqual, true)
		output += "B "

		Convey("C", FailureContinues, func() {
			output += "C "
			So(true, ShouldEqual, true)
			output += "D "
			So(false, ShouldEqual, true)
			output += "E "
		})
	})

	expectEqual(t, "A B C D E ", output)
}

func TestMultipleInvocationInheritance(t *testing.T) {
	output := prepare()

	Convey("A", t, FailureHalts, func() {
		output += "A1 "
		So(true, ShouldEqual, true)
		output += "A2 "

		Convey("B", FailureContinues, func() {
			output += "B1 "
			So(true, ShouldEqual, true)
			output += "B2 "
			So(false, ShouldEqual, true)
			output += "B3 "
		})

		Convey("C", func() {
			output += "C1 "
			So(true, ShouldEqual, true)
			output += "C2 "
			So(false, ShouldEqual, true)
			output += "C3 "
		})
	})

	expectEqual(t, "A1 A2 B1 B2 B3 A1 A2 C1 C2 ", output)
}

func TestMultipleInvocationInheritance2(t *testing.T) {
	output := prepare()

	Convey("A", t, FailureContinues, func() {
		output += "A1 "
		So(true, ShouldEqual, true)
		output += "A2 "
		So(false, ShouldEqual, true)
		output += "A3 "

		Convey("B", FailureHalts, func() {
			output += "B1 "
			So(true, ShouldEqual, true)
			output += "B2 "
			So(false, ShouldEqual, true)
			output += "B3 "
		})

		Convey("C", func() {
			output += "C1 "
			So(true, ShouldEqual, true)
			output += "C2 "
			So(false, ShouldEqual, true)
			output += "C3 "
		})
	})

	expectEqual(t, "A1 A2 A3 B1 B2 A1 A2 A3 C1 C2 C3 ", output)
}

func TestSetDefaultFailureMode(t *testing.T) {
	output := prepare()

	SetDefaultFailureMode(FailureContinues) // the default is normally FailureHalts
	defer SetDefaultFailureMode(FailureHalts)

	Convey("A", t, func() {
		output += "A1 "
		So(true, ShouldBeFalse)
		output += "A2 "
	})

	expectEqual(t, "A1 A2 ", output)
}

func prepare() string {
	testReporter = newNilReporter()
	return ""
}


================================================
FILE: convey/nilReporter.go
================================================
package convey

import (
	"github.com/smartystreets/goconvey/convey/reporting"
)

type nilReporter struct{}

func (self *nilReporter) BeginStory(story *reporting.StoryReport)  {}
func (self *nilReporter) Enter(scope *reporting.ScopeReport)       {}
func (self *nilReporter) Report(report *reporting.AssertionResult) {}
func (self *nilReporter) Exit()                                    {}
func (self *nilReporter) EndStory()                                {}
func (self *nilReporter) Write(p []byte) (int, error)              { return len(p), nil }
func newNilReporter() *nilReporter                                 { return &nilReporter{} }


================================================
FILE: convey/reporting/console.go
================================================
package reporting

import (
	"fmt"
	"io"
)

type console struct{}

func (self *console) Write(p []byte) (n int, err error) {
	return fmt.Print(string(p))
}

func NewConsole() io.Writer {
	return new(console)
}


================================================
FILE: convey/reporting/doc.go
================================================
// Package reporting contains internal functionality related
// to console reporting and output. Although this package has
// exported names is not intended for public consumption. See the
// examples package for how to use this project.
package reporting


================================================
FILE: convey/reporting/dot.go
================================================
package reporting

import "fmt"

type dot struct{ out *Printer }

func (self *dot) BeginStory(story *StoryReport) {}

func (self *dot) Enter(scope *ScopeReport) {}

func (self *dot) Report(report *AssertionResult) {
	if report.Error != nil {
		fmt.Print(redColor)
		self.out.Insert(dotError)
	} else if report.Failure != "" {
		fmt.Print(yellowColor)
		self.out.Insert(dotFailure)
	} else if report.Skipped {
		fmt.Print(yellowColor)
		self.out.Insert(dotSkip)
	} else {
		fmt.Print(greenColor)
		self.out.Insert(dotSuccess)
	}
	fmt.Print(resetColor)
}

func (self *dot) Exit() {}

func (self *dot) EndStory() {}

func (self *dot) Write(content []byte) (written int, err error) {
	return len(content), nil // no-op
}

func NewDotReporter(out *Printer) *dot {
	self := new(dot)
	self.out = out
	return self
}


================================================
FILE: convey/reporting/dot_test.go
================================================
package reporting

import (
	"errors"
	"testing"
)

func TestDotReporterAssertionPrinting(t *testing.T) {
	monochrome()
	file := newMemoryFile()
	printer := NewPrinter(file)
	reporter := NewDotReporter(printer)

	reporter.Report(NewSuccessReport())
	reporter.Report(NewFailureReport("failed", false))
	reporter.Report(NewErrorReport(errors.New("error")))
	reporter.Report(NewSkipReport())

	expected := dotSuccess + dotFailure + dotError + dotSkip

	if file.buffer != expected {
		t.Errorf("\nExpected: '%s'\nActual:  '%s'", expected, file.buffer)
	}
}

func TestDotReporterOnlyReportsAssertions(t *testing.T) {
	monochrome()
	file := newMemoryFile()
	printer := NewPrinter(file)
	reporter := NewDotReporter(printer)

	reporter.BeginStory(nil)
	reporter.Enter(nil)
	reporter.Exit()
	reporter.EndStory()

	if file.buffer != "" {
		t.Errorf("\nExpected: '(blank)'\nActual:  '%s'", file.buffer)
	}
}


================================================
FILE: convey/reporting/gotest.go
================================================
package reporting

type gotestReporter struct{ test T }

func (self *gotestReporter) BeginStory(story *StoryReport) {
	self.test = story.Test
}

func (self *gotestReporter) Enter(scope *ScopeReport) {}

func (self *gotestReporter) Report(r *AssertionResult) {
	if !passed(r) {
		self.test.Fail()
	}
}

func (self *gotestReporter) Exit() {}

func (self *gotestReporter) EndStory() {
	self.test = nil
}

func (self *gotestReporter) Write(content []byte) (written int, err error) {
	return len(content), nil // no-op
}

func NewGoTestReporter() *gotestReporter {
	return new(gotestReporter)
}

func passed(r *AssertionResult) bool {
	return r.Error == nil && r.Failure == ""
}


================================================
FILE: convey/reporting/gotest_test.go
================================================
package reporting

import "testing"

func TestReporterReceivesSuccessfulReport(t *testing.T) {
	reporter := NewGoTestReporter()
	test := new(fakeTest)
	reporter.BeginStory(NewStoryReport(test))
	reporter.Report(NewSuccessReport())

	if test.failed {
		t.Errorf("Should have have marked test as failed--the report reflected success.")
	}
}

func TestReporterReceivesFailureReport(t *testing.T) {
	reporter := NewGoTestReporter()
	test := new(fakeTest)
	reporter.BeginStory(NewStoryReport(test))
	reporter.Report(NewFailureReport("This is a failure.", false))

	if !test.failed {
		t.Errorf("Test should have been marked as failed (but it wasn't).")
	}
}

func TestReporterReceivesErrorReport(t *testing.T) {
	reporter := NewGoTestReporter()
	test := new(fakeTest)
	reporter.BeginStory(NewStoryReport(test))
	reporter.Report(NewErrorReport("This is an error."))

	if !test.failed {
		t.Errorf("Test should have been marked as failed (but it wasn't).")
	}
}

func TestReporterIsResetAtTheEndOfTheStory(t *testing.T) {
	defer catch(t)
	reporter := NewGoTestReporter()
	test := new(fakeTest)
	reporter.BeginStory(NewStoryReport(test))
	reporter.EndStory()

	reporter.Report(NewSuccessReport())
}

func TestReporterNoopMethods(t *testing.T) {
	reporter := NewGoTestReporter()
	reporter.Enter(NewScopeReport("title"))
	reporter.Exit()
}

func catch(t *testing.T) {
	if r := recover(); r != nil {
		t.Log("Getting to this point means we've passed (because we caught a panic appropriately).")
	}
}

type fakeTest struct {
	failed bool
}

func (self *fakeTest) Fail() {
	self.failed = true
}


================================================
FILE: convey/reporting/init.go
================================================
package reporting

import (
	"os"
	"runtime"
	"strings"
)

func init() {
	if !isColorableTerminal() {
		monochrome()
	}

	if runtime.GOOS == "windows" {
		success, failure, error_ = dotSuccess, dotFailure, dotError
	}
}

func BuildJsonReporter() Reporter {
	out := NewPrinter(NewConsole())
	return NewReporters(
		NewGoTestReporter(),
		NewJsonReporter(out))
}
func BuildDotReporter() Reporter {
	out := NewPrinter(NewConsole())
	return NewReporters(
		NewGoTestReporter(),
		NewDotReporter(out),
		NewProblemReporter(out),
		consoleStatistics)
}
func BuildStoryReporter() Reporter {
	out := NewPrinter(NewConsole())
	return NewReporters(
		NewGoTestReporter(),
		NewStoryReporter(out),
		NewProblemReporter(out),
		consoleStatistics)
}
func BuildSilentReporter() Reporter {
	out := NewPrinter(NewConsole())
	return NewReporters(
		NewGoTestReporter(),
		NewSilentProblemReporter(out))
}

var (
	newline         = "\n"
	success         = "✔"
	failure         = "✘"
	error_          = "🔥"
	skip            = "⚠"
	dotSuccess      = "."
	dotFailure      = "x"
	dotError        = "E"
	dotSkip         = "S"
	errorTemplate   = "* %s \nLine %d: - %v \n%s\n"
	failureTemplate = "* %s \nLine %d:\n%s\n"
	stackTemplate   = "%s\n"
)

var (
	greenColor  = "\033[32m"
	yellowColor = "\033[33m"
	redColor    = "\033[31m"
	resetColor  = "\033[0m"
)

var consoleStatistics = NewStatisticsReporter(NewPrinter(NewConsole()))

func SuppressConsoleStatistics() { consoleStatistics.Suppress() }
func PrintConsoleStatistics()    { consoleStatistics.PrintSummary() }

// QuietMode disables all console output symbols. This is only meant to be used
// for tests that are internal to goconvey where the output is distracting or
// otherwise not needed in the test output.
func QuietMode() {
	success, failure, error_, skip, dotSuccess, dotFailure, dotError, dotSkip = "", "", "", "", "", "", "", ""
}

func monochrome() {
	greenColor, yellowColor, redColor, resetColor = "", "", "", ""
}

func isColorableTerminal() bool {
	return strings.Contains(os.Getenv("TERM"), "color")
}

// This interface allows us to pass the *testing.T struct
// throughout the internals of this tool without ever
// having to import the "testing" package.
type T interface {
	Fail()
}


================================================
FILE: convey/reporting/json.go
================================================
// TODO: under unit test

package reporting

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strings"
)

type JsonReporter struct {
	out        *Printer
	currentKey []string
	current    *ScopeResult
	index      map[string]*ScopeResult
	scopes     []*ScopeResult
}

func (self *JsonReporter) depth() int { return len(self.currentKey) }

func (self *JsonReporter) BeginStory(story *StoryReport) {}

func (self *JsonReporter) Enter(scope *ScopeReport) {
	self.currentKey = append(self.currentKey, scope.Title)
	ID := strings.Join(self.currentKey, "|")
	if _, found := self.index[ID]; !found {
		next := newScopeResult(scope.Title, self.depth(), scope.File, scope.Line)
		self.scopes = append(self.scopes, next)
		self.index[ID] = next
	}
	self.current = self.index[ID]
}

func (self *JsonReporter) Report(report *AssertionResult) {
	self.current.Assertions = append(self.current.Assertions, report)
}

func (self *JsonReporter) Exit() {
	self.currentKey = self.currentKey[:len(self.currentKey)-1]
}

func (self *JsonReporter) EndStory() {
	self.report()
	self.reset()
}
func (self *JsonReporter) report() {
	scopes := []string{}
	for _, scope := range self.scopes {
		serialized, err := json.Marshal(scope)
		if err != nil {
			self.out.Println(jsonMarshalFailure)
			panic(err)
		}
		var buffer bytes.Buffer
		json.Indent(&buffer, serialized, "", "  ")
		scopes = append(scopes, buffer.String())
	}
	self.out.Print(fmt.Sprintf("%s\n%s,\n%s\n", OpenJson, strings.Join(scopes, ","), CloseJson))
}
func (self *JsonReporter) reset() {
	self.scopes = []*ScopeResult{}
	self.index = map[string]*ScopeResult{}
	self.currentKey = nil
}

func (self *JsonReporter) Write(content []byte) (written int, err error) {
	self.current.Output += string(content)
	return len(content), nil
}

func NewJsonReporter(out *Printer) *JsonReporter {
	self := new(JsonReporter)
	self.out = out
	self.reset()
	return self
}

const OpenJson = ">->->OPEN-JSON->->->"   // "⌦"
const CloseJson = "<-<-<-CLOSE-JSON<-<-<" // "⌫"
const jsonMarshalFailure = `

GOCONVEY_JSON_MARSHALL_FAILURE: There was an error when attempting to convert test results to JSON.
Please file a bug report and reference the code that caused this failure if possible.

Here's the panic:

`


================================================
FILE: convey/reporting/printer.go
================================================
package reporting

import (
	"fmt"
	"io"
	"strings"
)

type Printer struct {
	out    io.Writer
	prefix string
}

func (self *Printer) Println(message string, values ...any) {
	formatted := self.format(message, values...) + newline
	self.out.Write([]byte(formatted))
}

func (self *Printer) Print(message string, values ...any) {
	formatted := self.format(message, values...)
	self.out.Write([]byte(formatted))
}

func (self *Printer) Insert(text string) {
	self.out.Write([]byte(text))
}

func (self *Printer) format(message string, values ...any) string {
	var formatted string
	if len(values) == 0 {
		formatted = self.prefix + message
	} else {
		formatted = self.prefix + fmt_Sprintf(message, values...)
	}
	indented := strings.Replace(formatted, newline, newline+self.prefix, -1)
	return strings.TrimRight(indented, space)
}

// Extracting fmt.Sprintf to a separate variable circumvents go vet, which, as of go 1.10 is run with go test.
var fmt_Sprintf = fmt.Sprintf

func (self *Printer) Indent() {
	self.prefix += pad
}

func (self *Printer) Dedent() {
	if len(self.prefix) >= padLength {
		self.prefix = self.prefix[:len(self.prefix)-padLength]
	}
}

func NewPrinter(out io.Writer) *Printer {
	self := new(Printer)
	self.out = out
	return self
}

const space = " "
const pad = space + space
const padLength = len(pad)


================================================
FILE: convey/reporting/printer_test.go
================================================
package reporting

import "testing"

func TestPrint(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)
	const expected = "Hello, World!"

	printer.Print(expected)

	if file.buffer != expected {
		t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
	}
}

func TestPrintFormat(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)
	template := "Hi, %s"
	name := "Ralph"
	expected := "Hi, Ralph"

	printer.Print(template, name)

	if file.buffer != expected {
		t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
	}
}

func TestPrintPreservesEncodedStrings(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)
	const expected = "= -> %%3D"
	printer.Print(expected)

	if file.buffer != expected {
		t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
	}
}

func TestPrintln(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)
	const expected = "Hello, World!"

	printer.Println(expected)

	if file.buffer != expected+"\n" {
		t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
	}
}

func TestPrintlnFormat(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)
	template := "Hi, %s"
	name := "Ralph"
	expected := "Hi, Ralph\n"

	printer.Println(template, name)

	if file.buffer != expected {
		t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
	}
}

func TestPrintlnPreservesEncodedStrings(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)
	const expected = "= -> %%3D"
	printer.Println(expected)

	if file.buffer != expected+"\n" {
		t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
	}
}

func TestPrintIndented(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)
	const message = "Hello, World!\nGoodbye, World!"
	const expected = "  Hello, World!\n  Goodbye, World!"

	printer.Indent()
	printer.Print(message)

	if file.buffer != expected {
		t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
	}
}

func TestPrintDedented(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)
	const expected = "Hello, World!\nGoodbye, World!"

	printer.Indent()
	printer.Dedent()
	printer.Print(expected)

	if file.buffer != expected {
		t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
	}
}

func TestPrintlnIndented(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)
	const message = "Hello, World!\nGoodbye, World!"
	const expected = "  Hello, World!\n  Goodbye, World!\n"

	printer.Indent()
	printer.Println(message)

	if file.buffer != expected {
		t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
	}
}

func TestPrintlnDedented(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)
	const expected = "Hello, World!\nGoodbye, World!"

	printer.Indent()
	printer.Dedent()
	printer.Println(expected)

	if file.buffer != expected+"\n" {
		t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
	}
}

func TestDedentTooFarShouldNotPanic(t *testing.T) {
	defer func() {
		if r := recover(); r != nil {
			t.Error("Should not have panicked!")
		}
	}()
	file := newMemoryFile()
	printer := NewPrinter(file)

	printer.Dedent()

	t.Log("Getting to this point without panicking means we passed.")
}

func TestInsert(t *testing.T) {
	file := newMemoryFile()
	printer := NewPrinter(file)

	printer.Indent()
	printer.Print("Hi")
	printer.Insert(" there")
	printer.Dedent()

	expected := "  Hi there"
	if file.buffer != expected {
		t.Errorf("Should have written '%s' but instead wrote '%s'.", expected, file.buffer)
	}
}

////////////////// memoryFile ////////////////////

type memoryFile struct {
	buffer string
}

func (self *memoryFile) Write(p []byte) (n int, err error) {
	self.buffer += string(p)
	return len(p), nil
}

func (self *memoryFile) String() string {
	return self.buffer
}

func newMemoryFile() *memoryFile {
	return new(memoryFile)
}


================================================
FILE: convey/reporting/problems.go
================================================
package reporting

import "fmt"

type problem struct {
	silent   bool
	out      *Printer
	errors   []*AssertionResult
	failures []*AssertionResult
}

func (self *problem) BeginStory(story *StoryReport) {}

func (self *problem) Enter(scope *ScopeReport) {}

func (self *problem) Report(report *AssertionResult) {
	if report.Error != nil {
		self.errors = append(self.errors, report)
	} else if report.Failure != "" {
		self.failures = append(self.failures, report)
	}
}

func (self *problem) Exit() {}

func (self *problem) EndStory() {
	self.show(self.showErrors, redColor)
	self.show(self.showFailures, yellowColor)
	self.prepareForNextStory()
}
func (self *problem) show(display func(), color string) {
	if !self.silent {
		fmt.Print(color)
	}
	display()
	if !self.silent {
		fmt.Print(resetColor)
	}
	self.out.Dedent()
}
func (self *problem) showErrors() {
	for i, e := range self.errors {
		if i == 0 {
			self.out.Println("\nErrors:\n")
			self.out.Indent()
		}
		self.out.Println(errorTemplate, e.File, e.Line, e.Error, e.StackTrace)
	}
}
func (self *problem) showFailures() {
	for i, f := range self.failures {
		if i == 0 {
			self.out.Println("\nFailures:\n")
			self.out.Indent()
		}
		self.out.Println(failureTemplate, f.File, f.Line, f.Failure)
		if f.StackTrace != "" {
			self.out.Println(stackTemplate, f.StackTrace)
		}
	}
}

func (self *problem) Write(content []byte) (written int, err error) {
	return len(content), nil // no-op
}

func NewProblemReporter(out *Printer) *problem {
	self := new(problem)
	self.out = out
	self.prepareForNextStory()
	return self
}

func NewSilentProblemReporter(out *Printer) *problem {
	self := NewProblemReporter(out)
	self.silent = true
	return self
}

func (self *problem) prepareForNextStory() {
	self.errors = []*AssertionResult{}
	self.failures = []*AssertionResult{}
}


================================================
FILE: convey/reporting/problems_test.go
================================================
package reporting

import (
	"strings"
	"testing"
)

func TestNoopProblemReporterActions(t *testing.T) {
	file, reporter := setup()
	reporter.BeginStory(nil)
	reporter.Enter(nil)
	reporter.Exit()
	expected := ""
	actual := file.String()
	if expected != actual {
		t.Errorf("Expected: '(blank)'\nActual:  '%s'", actual)
	}
}

func TestReporterPrintsFailuresAndErrorsAtTheEndOfTheStory(t *testing.T) {
	file, reporter := setup()
	reporter.Report(NewFailureReport("failed", false))
	reporter.Report(NewErrorReport("error"))
	reporter.Report(NewSuccessReport())
	reporter.EndStory()

	result := file.String()
	if !strings.Contains(result, "Errors:\n") {
		t.Errorf("Expected errors, found none.")
	}
	if !strings.Contains(result, "Failures:\n") {
		t.Errorf("Expected failures, found none.")
	}

	// Each stack trace looks like: `* /path/to/file.go`, so look for `* `.
	// With go 1.4+ there is a line in some stack traces that looks like this:
	//   `testing.(*M).Run(0x2082d60a0, 0x25b7c0)`
	// So we can't just look for "*" anymore.
	problemCount := strings.Count(result, "* ")
	if problemCount != 2 {
		t.Errorf("Expected one failure and one error (total of 2 '*' characters). Got %d", problemCount)
	}
}

func setup() (file *memoryFile, reporter *problem) {
	monochrome()
	file = newMemoryFile()
	printer := NewPrinter(file)
	reporter = NewProblemReporter(printer)
	return
}


================================================
FILE: convey/reporting/reporter.go
================================================
package reporting

import "io"

type Reporter interface {
	BeginStory(story *StoryReport)
	Enter(scope *ScopeReport)
	Report(r *AssertionResult)
	Exit()
	EndStory()
	io.Writer
}

type reporters struct{ collection []Reporter }

func (self *reporters) BeginStory(s *StoryReport) { self.foreach(func(r Reporter) { r.BeginStory(s) }) }
func (self *reporters) Enter(s *ScopeReport)      { self.foreach(func(r Reporter) { r.Enter(s) }) }
func (self *reporters) Report(a *AssertionResult) { self.foreach(func(r Reporter) { r.Report(a) }) }
func (self *reporters) Exit()                     { self.foreach(func(r Reporter) { r.Exit() }) }
func (self *reporters) EndStory()                 { self.foreach(func(r Reporter) { r.EndStory() }) }

func (self *reporters) Write(contents []byte) (written int, err error) {
	self.foreach(func(r Reporter) {
		written, err = r.Write(contents)
	})
	return written, err
}

func (self *reporters) foreach(action func(Reporter)) {
	for _, r := range self.collection {
		action(r)
	}
}

func NewReporters(collection ...Reporter) *reporters {
	self := new(reporters)
	self.collection = collection
	return self
}


================================================
FILE: convey/reporting/reporter_test.go
================================================
package reporting

import (
	"runtime"
	"testing"
)

func TestEachNestedReporterReceivesTheCallFromTheContainingReporter(t *testing.T) {
	fake1 := newFakeReporter()
	fake2 := newFakeReporter()
	reporter := NewReporters(fake1, fake2)

	reporter.BeginStory(nil)
	assertTrue(t, fake1.begun)
	assertTrue(t, fake2.begun)

	reporter.Enter(NewScopeReport("scope"))
	assertTrue(t, fake1.entered)
	assertTrue(t, fake2.entered)

	reporter.Report(NewSuccessReport())
	assertTrue(t, fake1.reported)
	assertTrue(t, fake2.reported)

	reporter.Exit()
	assertTrue(t, fake1.exited)
	assertTrue(t, fake2.exited)

	reporter.EndStory()
	assertTrue(t, fake1.ended)
	assertTrue(t, fake2.ended)

	content := []byte("hi")
	written, err := reporter.Write(content)
	assertTrue(t, fake1.written)
	assertTrue(t, fake2.written)
	assertEqual(t, written, len(content))
	assertNil(t, err)

}

func assertTrue(t *testing.T, value bool) {
	if !value {
		_, _, line, _ := runtime.Caller(1)
		t.Errorf("Value should have been true (but was false). See line %d", line)
	}
}

func assertEqual(t *testing.T, expected, actual int) {
	if actual != expected {
		_, _, line, _ := runtime.Caller(1)
		t.Errorf("Value should have been %d (but was %d). See line %d", expected, actual, line)
	}
}

func assertNil(t *testing.T, err error) {
	if err != nil {
		_, _, line, _ := runtime.Caller(1)
		t.Errorf("Error should have been <nil> (but wasn't). See line %d. %v", err, line)
	}
}

type fakeReporter struct {
	begun    bool
	entered  bool
	reported bool
	exited   bool
	ended    bool
	written  bool
}

func newFakeReporter() *fakeReporter {
	return &fakeReporter{}
}

func (self *fakeReporter) BeginStory(story *StoryReport) {
	self.begun = true
}
func (self *fakeReporter) Enter(scope *ScopeReport) {
	self.entered = true
}
func (self *fakeReporter) Report(report *AssertionResult) {
	self.reported = true
}
func (self *fakeReporter) Exit() {
	self.exited = true
}
func (self *fakeReporter) EndStory() {
	self.ended = true
}
func (self *fakeReporter) Write(content []byte) (int, error) {
	self.written = true
	return len(content), nil
}


================================================
FILE: convey/reporting/reporting.goconvey
================================================
#ignore
-timeout=1s


================================================
FILE: convey/reporting/reports.go
================================================
package reporting

import (
	"encoding/json"
	"fmt"
	"runtime"
	"strings"

	"github.com/smartystreets/goconvey/convey/gotest"
)

////////////////// ScopeReport ////////////////////

type ScopeReport struct {
	Title string
	File  string
	Line  int
}

func NewScopeReport(title string) *ScopeReport {
	file, line, _ := gotest.ResolveExternalCaller()
	self := new(ScopeReport)
	self.Title = title
	self.File = file
	self.Line = line
	return self
}

////////////////// ScopeResult ////////////////////

type ScopeResult struct {
	Title      string
	File       string
	Line       int
	Depth      int
	Assertions []*AssertionResult
	Output     string
}

func newScopeResult(title string, depth int, file string, line int) *ScopeResult {
	self := new(ScopeResult)
	self.Title = title
	self.Depth = depth
	self.File = file
	self.Line = line
	self.Assertions = []*AssertionResult{}
	return self
}

/////////////////// StoryReport /////////////////////

type StoryReport struct {
	Test T
	Name string
	File string
	Line int
}

func NewStoryReport(test T) *StoryReport {
	file, line, name := gotest.ResolveExternalCaller()
	name = removePackagePath(name)
	self := new(StoryReport)
	self.Test = test
	self.Name = name
	self.File = file
	self.Line = line
	return self
}

// name comes in looking like "github.com/smartystreets/goconvey/examples.TestName".
// We only want the stuff after the last '.', which is the name of the test function.
func removePackagePath(name string) string {
	parts := strings.Split(name, ".")
	return parts[len(parts)-1]
}

/////////////////// FailureView ////////////////////////

// FailureView is also declared in github.com/smarty/assertions.
// The json struct tags should be equal in both declarations.
type FailureView struct {
	Message  string `json:"Message"`
	Expected string `json:"Expected"`
	Actual   string `json:"Actual"`
}

////////////////////AssertionResult //////////////////////

type AssertionResult struct {
	File       string
	Line       int
	Expected   string
	Actual     string
	Failure    string
	Error      any
	StackTrace string
	Skipped    bool
}

func NewFailureReport(failure string, showStack bool) *AssertionResult {
	report := new(AssertionResult)
	report.File, report.Line = caller()
	if showStack {
		report.StackTrace = stackTrace()
	}
	parseFailure(failure, report)
	return report
}
func parseFailure(failure string, report *AssertionResult) {
	view := new(FailureView)
	err := json.Unmarshal([]byte(failure), view)
	if err == nil {
		report.Failure = view.Message
		report.Expected = view.Expected
		report.Actual = view.Actual
	} else {
		report.Failure = failure
	}
}
func NewErrorReport(err any) *AssertionResult {
	report := new(AssertionResult)
	report.File, report.Line = caller()
	report.StackTrace = fullStackTrace()
	report.Error = fmt.Sprintf("%v", err)
	return report
}
func NewSuccessReport() *AssertionResult {
	return new(AssertionResult)
}
func NewSkipReport() *AssertionResult {
	report := new(AssertionResult)
	report.File, report.Line = caller()
	report.StackTrace = fullStackTrace()
	report.Skipped = true
	return report
}

func caller() (file string, line int) {
	file, line, _ = gotest.ResolveExternalCaller()
	return
}

func stackTrace() string {
	buffer := make([]byte, 1024*64)
	n := runtime.Stack(buffer, false)
	return removeInternalEntries(string(buffer[:n]))
}
func fullStackTrace() string {
	buffer := make([]byte, 1024*64)
	n := runtime.Stack(buffer, true)
	return removeInternalEntries(string(buffer[:n]))
}
func removeInternalEntries(stack string) string {
	lines := strings.Split(stack, newline)
	filtered := []string{}
	for _, line := range lines {
		if !isExternal(line) {
			filtered = append(filtered, line)
		}
	}
	return strings.Join(filtered, newline)
}
func isExternal(line string) bool {
	for _, p := range internalPackages {
		if strings.Contains(line, p) {
			return true
		}
	}
	return false
}

// NOTE: any new packages that host goconvey packages will need to be added here!
// An alternative is to scan the goconvey directory and then exclude stuff like
// the examples package but that's nasty too.
var internalPackages = []string{
	"goconvey/assertions",
	"goconvey/convey",
	"goconvey/execution",
	"goconvey/gotest",
	"goconvey/reporting",
}


================================================
FILE: convey/reporting/statistics.go
================================================
package reporting

import (
	"fmt"
	"sync"
)

func (self *statistics) BeginStory(story *StoryReport) {}

func (self *statistics) Enter(scope *ScopeReport) {}

func (self *statistics) Report(report *AssertionResult) {
	self.Lock()
	defer self.Unlock()

	if !self.failing && report.Failure != "" {
		self.failing = true
	}
	if !self.erroring && report.Error != nil {
		self.erroring = true
	}
	if report.Skipped {
		self.skipped += 1
	} else {
		self.total++
	}
}

func (self *statistics) Exit() {}

func (self *statistics) EndStory() {
	self.Lock()
	defer self.Unlock()

	if !self.suppressed {
		self.printSummaryLocked()
	}
}

func (self *statistics) Suppress() {
	self.Lock()
	defer self.Unlock()
	self.suppressed = true
}

func (self *statistics) PrintSummary() {
	self.Lock()
	defer self.Unlock()
	self.printSummaryLocked()
}

func (self *statistics) printSummaryLocked() {
	self.reportAssertionsLocked()
	self.reportSkippedSectionsLocked()
	self.completeReportLocked()
}
func (self *statistics) reportAssertionsLocked() {
	self.decideColorLocked()
	self.out.Print("\n%d total %s", self.total, plural("assertion", self.total))
}
func (self *statistics) decideColorLocked() {
	if self.failing && !self.erroring {
		fmt.Print(yellowColor)
	} else if self.erroring {
		fmt.Print(redColor)
	} else {
		fmt.Print(greenColor)
	}
}
func (self *statistics) reportSkippedSectionsLocked() {
	if self.skipped > 0 {
		fmt.Print(yellowColor)
		self.out.Print(" (one or more sections skipped)")
	}
}
func (self *statistics) completeReportLocked() {
	fmt.Print(resetColor)
	self.out.Print("\n")
	self.out.Print("\n")
}

func (self *statistics) Write(content []byte) (written int, err error) {
	return len(content), nil // no-op
}

func NewStatisticsReporter(out *Printer) *statistics {
	self := statistics{}
	self.out = out
	return &self
}

type statistics struct {
	sync.Mutex

	out        *Printer
	total      int
	failing    bool
	erroring   bool
	skipped    int
	suppressed bool
}

func plural(word string, count int) string {
	if count == 1 {
		return word
	}
	return word + "s"
}


================================================
FILE: convey/reporting/story.go
================================================
// TODO: in order for this reporter to be completely honest
// we need to retrofit to be more like the json reporter such that:
// 1. it maintains ScopeResult collections, which count assertions
// 2. it reports only after EndStory(), so that all tick marks
//    are placed near the appropriate title.
// 3. Under unit test

package reporting

import (
	"fmt"
	"strings"
)

type story struct {
	out        *Printer
	titlesById map[string]string
	currentKey []string
}

func (self *story) BeginStory(story *StoryReport) {}

func (self *story) Enter(scope *ScopeReport) {
	self.out.Indent()

	self.currentKey = append(self.currentKey, scope.Title)
	ID := strings.Join(self.currentKey, "|")

	if _, found := self.titlesById[ID]; !found {
		self.out.Println("")
		self.out.Print(scope.Title)
		self.out.Insert(" ")
		self.titlesById[ID] = scope.Title
	}
}

func (self *story) Report(report *AssertionResult) {
	if report.Error != nil {
		fmt.Print(redColor)
		self.out.Insert(error_)
	} else if report.Failure != "" {
		fmt.Print(yellowColor)
		self.out.Insert(failure)
	} else if report.Skipped {
		fmt.Print(yellowColor)
		self.out.Insert(skip)
	} else {
		fmt.Print(greenColor)
		self.out.Insert(success)
	}
	fmt.Print(resetColor)
}

func (self *story) Exit() {
	self.out.Dedent()
	self.currentKey = self.currentKey[:len(self.currentKey)-1]
}

func (self *story) EndStory() {
	self.titlesById = make(map[string]string)
	self.out.Println("\n")
}

func (self *story) Write(content []byte) (written int, err error) {
	return len(content), nil // no-op
}

func NewStoryReporter(out *Printer) *story {
	self := new(story)
	self.out = out
	self.titlesById = make(map[string]string)
	return self
}


================================================
FILE: convey/reporting_hooks_test.go
================================================
package convey

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"path"
	"runtime"
	"strconv"
	"strings"
	"testing"

	"github.com/smartystreets/goconvey/convey/reporting"
)

func TestSingleScopeReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		So(1, ShouldEqual, 1)
	})

	expectEqual(t, "Begin|A|Success|Exit|End", myReporter.wholeStory())
}

func TestNestedScopeReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		Convey("B", func() {
			So(1, ShouldEqual, 1)
		})
	})

	expectEqual(t, "Begin|A|B|Success|Exit|Exit|End", myReporter.wholeStory())
}

func TestFailureReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		So(1, ShouldBeNil)
	})

	expectEqual(t, "Begin|A|Failure|Exit|End", myReporter.wholeStory())
}

func TestFirstFailureEndsScopeExecution(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		So(1, ShouldBeNil)
		So(nil, ShouldBeNil)
	})

	expectEqual(t, "Begin|A|Failure|Exit|End", myReporter.wholeStory())
}

func TestComparisonFailureDeserializedAndReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		So("hi", ShouldEqual, "bye")
	})

	expectEqual(t, `Begin|A|Failure("bye"/"hi")|Exit|End`, myReporter.wholeStory())
}

func TestNestedFailureReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		Convey("B", func() {
			So(2, ShouldBeNil)
		})
	})

	expectEqual(t, "Begin|A|B|Failure|Exit|Exit|End", myReporter.wholeStory())
}

func TestSuccessAndFailureReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		So(nil, ShouldBeNil)
		So(1, ShouldBeNil)
	})

	expectEqual(t, "Begin|A|Success|Failure|Exit|End", myReporter.wholeStory())
}

func TestIncompleteActionReportedAsSkipped(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		Convey("B", nil)
	})

	expectEqual(t, "Begin|A|B|Skipped|Exit|Exit|End", myReporter.wholeStory())
}

func TestSkippedConveyReportedAsSkipped(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		SkipConvey("B", func() {
			So(1, ShouldEqual, 1)
		})
	})

	expectEqual(t, "Begin|A|B|Skipped|Exit|Exit|End", myReporter.wholeStory())
}

func TestMultipleSkipsAreReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		Convey("0", func() {
			So(nil, ShouldBeNil)
		})

		SkipConvey("1", func() {})
		SkipConvey("2", func() {})

		Convey("3", nil)
		Convey("4", nil)

		Convey("5", func() {
			So(nil, ShouldBeNil)
		})
	})

	expected := "Begin" +
		"|A|0|Success|Exit|Exit" +
		"|A|1|Skipped|Exit|Exit" +
		"|A|2|Skipped|Exit|Exit" +
		"|A|3|Skipped|Exit|Exit" +
		"|A|4|Skipped|Exit|Exit" +
		"|A|5|Success|Exit|Exit" +
		"|End"

	expectEqual(t, expected, myReporter.wholeStory())
}

func TestSkippedAssertionIsNotReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		SkipSo(1, ShouldEqual, 1)
	})

	expectEqual(t, "Begin|A|Skipped|Exit|End", myReporter.wholeStory())
}

func TestMultipleSkippedAssertionsAreNotReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		SkipSo(1, ShouldEqual, 1)
		So(1, ShouldEqual, 1)
		SkipSo(1, ShouldEqual, 1)
	})

	expectEqual(t, "Begin|A|Skipped|Success|Skipped|Exit|End", myReporter.wholeStory())
}

func TestErrorByManualPanicReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		panic("Gopher alert!")
	})

	expectEqual(t, "Begin|A|Error|Exit|End", myReporter.wholeStory())
}

func TestIterativeConveysReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		for x := 0; x < 3; x++ {
			Convey(strconv.Itoa(x), func() {
				So(x, ShouldEqual, x)
			})
		}
	})

	expectEqual(t, "Begin|A|0|Success|Exit|Exit|A|1|Success|Exit|Exit|A|2|Success|Exit|Exit|End", myReporter.wholeStory())
}

func TestNestedIterativeConveysReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func() {
		for x := 0; x < 3; x++ {
			Convey(strconv.Itoa(x), func() {
				for y := 0; y < 3; y++ {
					Convey("< "+strconv.Itoa(y), func() {
						So(x, ShouldBeLessThan, y)
					})
				}
			})
		}
	})

	expectEqual(t, ("Begin|" +
		"A|0|< 0|Failure|Exit|Exit|Exit|" +
		"A|0|< 1|Success|Exit|Exit|Exit|" +
		"A|0|< 2|Success|Exit|Exit|Exit|" +
		"A|1|< 0|Failure|Exit|Exit|Exit|" +
		"A|1|< 1|Failure|Exit|Exit|Exit|" +
		"A|1|< 2|Success|Exit|Exit|Exit|" +
		"A|2|< 0|Failure|Exit|Exit|Exit|" +
		"A|2|< 1|Failure|Exit|Exit|Exit|" +
		"A|2|< 2|Failure|Exit|Exit|Exit|" +
		"End"), myReporter.wholeStory())
}

func TestEmbeddedAssertionReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	Convey("A", test, func(c C) {
		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			c.So(r.FormValue("msg"), ShouldEqual, "ping")
		}))
		http.DefaultClient.Get(ts.URL + "?msg=ping")
	})

	expectEqual(t, "Begin|A|Success|Exit|End", myReporter.wholeStory())
}

func TestEmbeddedContextHelperReported(t *testing.T) {
	myReporter, test := setupFakeReporter()

	helper := func(c C) http.HandlerFunc {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			c.Convey("Embedded", func() {
				So(r.FormValue("msg"), ShouldEqual, "ping")
			})
		})
	}

	Convey("A", test, func(c C) {
		ts := httptest.NewServer(helper(c))
		http.DefaultClient.Get(ts.URL + "?msg=ping")
	})

	expectEqual(t, "Begin|A|Embedded|Success|Exit|Exit|End", myReporter.wholeStory())
}

func expectEqual(t *testing.T, expected any, actual any) {
	if expected != actual {
		_, file, line, _ := runtime.Caller(1)
		t.Errorf("Expected '%v' to be '%v' but it wasn't. See '%s' at line %d.",
			actual, expected, path.Base(file), line)
	}
}

func setupFakeReporter() (*fakeReporter, *fakeGoTest) {
	myReporter := new(fakeReporter)
	myReporter.calls = []string{}
	testReporter = myReporter
	return myReporter, new(fakeGoTest)
}

type fakeReporter struct {
	calls []string
}

func (self *fakeReporter) BeginStory(story *reporting.StoryReport) {
	self.calls = append(self.calls, "Begin")
}

func (self *fakeReporter) Enter(scope *reporting.ScopeReport) {
	self.calls = append(self.calls, scope.Title)
}

func (self *fakeReporter) Report(report *reporting.AssertionResult) {
	if report.Error != nil {
		self.calls = append(self.calls, "Error")
	} else if report.Failure != "" {
		message := "Failure"
		if report.Expected != "" || report.Actual != "" {
			message += fmt.Sprintf("(%s/%s)", report.Expected, report.Actual)
		}
		self.calls = append(self.calls, message)
	} else if report.Skipped {
		self.calls = append(self.calls, "Skipped")
	} else {
		self.calls = append(self.calls, "Success")
	}
}

func (self *fakeReporter) Exit() {
	self.calls = append(self.calls, "Exit")
}

func (self *fakeReporter) EndStory() {
	self.calls = append(self.calls, "End")
}

func (self *fakeReporter) Write(content []byte) (int, error) {
	return len(content), nil // no-op
}

func (self *fakeReporter) wholeStory() string {
	return strings.Join(self.calls, "|")
}

////////////////////////////////

type fakeGoTest struct{}

func (self *fakeGoTest) Fail()                             {}
func (self *fakeGoTest) Fatalf(format string, args ...any) {}

var test t = new(fakeGoTest)


================================================
FILE: convey/stack_trace_test.go
================================================
package convey

import (
	"fmt"
	"regexp"
	"strings"
	"testing"

	"github.com/smartystreets/goconvey/convey/reporting"
)

var goroutineRE = regexp.MustCompile(`goroutine \d+ \[`)

// countGoroutines takes a test output file and counts the number of goroutines
// that were mentioned inside it. This does this by hunting for lines such as
// "goroutine 42 [running]", while excluding secondary mentions of already-counted
// goroutines.
func countGoroutines(testOutput string) int {
	return len(goroutineRE.FindAllStringSubmatch(testOutput, -1))
}

func TestStackTrace(t *testing.T) {
	file, test := setupFileReporter()

	Convey("A", test, func() {
		So(1, ShouldEqual, 2)
	})

	if !strings.Contains(file.String(), "Failures:\n") {
		t.Errorf("Expected errors, found none.")
	}
	if strings.Contains(file.String(), "goroutine ") {
		t.Errorf("Found stack trace, expected none.")
	}

	Convey("A", test, StackFail, func() {
		So(1, ShouldEqual, 2)
	})

	if !strings.Contains(file.String(), "goroutine ") {
		t.Errorf("Expected stack trace, found none.")
	}
}

func TestSetDefaultStackMode(t *testing.T) {
	file, test := setupFileReporter()
	SetDefaultStackMode(StackFail) // the default is normally StackError
	defer SetDefaultStackMode(StackError)

	Convey("A", test, func() {
		So(1, ShouldEqual, 2)
	})

	if !strings.Contains(file.String(), "goroutine ") {
		t.Errorf("Expected stack trace, found none.")
	}
}

func TestStackModeMultipleInvocationInheritance(t *testing.T) {
	file, test := setupFileReporter()

	// initial convey should default to StaskError, so no stack trace
	Convey("A", test, FailureContinues, func() {
		So(1, ShouldEqual, 2)

		// nested convey has explicit StaskFail, so should emit stack trace
		Convey("B", StackFail, func() {
			So(1, ShouldEqual, 2)
		})
	})
	stackCount := countGoroutines(file.String())
	if stackCount != 1 {
		t.Errorf("Expected 1 stack trace, found %d.", stackCount)
		fmt.Printf("RESULT: %s \n", file.String())
	}
}

func TestStackModeMultipleInvocationInheritance2(t *testing.T) {
	file, test := setupFileReporter()

	// Explicit StackFail, expect stack trace
	Convey("A", test, FailureContinues, StackFail, func() {
		So(1, ShouldEqual, 2)

		// Nested Convey inherits StackFail, expect stack trace
		Convey("B", func() {
			So(1, ShouldEqual, 2)
		})
	})

	stackCount := countGoroutines(file.String())
	if stackCount != 2 {
		t.Errorf("Expected 2 stack traces, found %d.", stackCount)
	}
}

func TestStackModeMultipleInvocationInheritance3(t *testing.T) {
	file, test := setupFileReporter()

	// Explicit StackFail, expect stack trace
	Convey("A", test, FailureContinues, StackFail, func() {
		So(1, ShouldEqual, 2)

		// Nested Convey explicitly sets StackError, so no stack trace
		Convey("B", StackError, func() {
			So(1, ShouldEqual, 2)
		})
	})

	stackCount := countGoroutines(file.String())
	if stackCount != 1 {
		t.Errorf("Expected 1 stack trace1, found %d.", stackCount)
	}
}

func setupFileReporter() (*memoryFile, *fakeGoTest) {
	//monochrome()
	file := newMemoryFile()
	printer := reporting.NewPrinter(file)
	reporter := reporting.NewProblemReporter(printer)
	testReporter = reporter

	return file, new(fakeGoTest)
}

////////////////// memoryFile ////////////////////

type memoryFile struct {
	buffer string
}

func (mf *memoryFile) Write(p []byte) (n int, err error) {
	mf.buffer += string(p)
	return len(p), nil
}

func (mf *memoryFile) String() string {
	return mf.buffer
}

func newMemoryFile() *memoryFile {
	return new(memoryFile)
}

// func monochrome() {
// 	greenColor, yellowColor, redColor, resetColor = "", "", "", ""
// }


================================================
FILE: convey/story_conventions_test.go
================================================
package convey

import (
	"reflect"
	"testing"
)

func expectPanic(t *testing.T, f string) any {
	r := recover()
	if r != nil {
		if cp, ok := r.(*conveyErr); ok {
			if cp.fmt != f {
				t.Error("Incorrect panic message.")
			}
		} else {
			t.Errorf("Incorrect panic type. %s", reflect.TypeOf(r))
		}
	} else {
		t.Error("Expected panic but none occurred")
	}
	return r
}

func TestMissingTopLevelGoTestReferenceCausesPanic(t *testing.T) {
	output := map[string]bool{}

	defer expectEqual(t, false, output["good"])
	defer expectPanic(t, missingGoTest)

	Convey("Hi", func() {
		output["bad"] = true // this shouldn't happen
	})
}

func TestMissingTopLevelGoTestReferenceAfterGoodExample(t *testing.T) {
	output := map[string]bool{}

	defer func() {
		expectEqual(t, true, output["good"])
		expectEqual(t, false, output["bad"])
	}()
	defer expectPanic(t, missingGoTest)

	Convey("Good example", t, func() {
		output["good"] = true
	})

	Convey("Bad example", func() {
		output["bad"] = true // shouldn't happen
	})
}

func TestExtraReferencePanics(t *testing.T) {
	output := map[string]bool{}

	defer expectEqual(t, false, output["bad"])
	defer expectPanic(t, extraGoTest)

	Convey("Good example", t, func() {
		Convey("Bad example - passing in *testing.T a second time!", t, func() {
			output["bad"] = true // shouldn't happen
		})
	})
}

func TestParseRegistrationMissingRequiredElements(t *testing.T) {
	defer expectPanic(t, parseError)

	Convey()
}

func TestParseRegistration_MissingNameString(t *testing.T) {
	defer expectPanic(t, parseError)

	Convey(func() {})
}

func TestParseRegistration_MissingActionFunc(t *testing.T) {
	defer expectPanic(t, parseError)

	Convey("Hi there", 12345)
}

func TestFailureModeNoContext(t *testing.T) {
	Convey("Foo", t, func() {
		done := make(chan int, 1)
		go func() {
			defer func() { done <- 1 }()
			defer expectPanic(t, noStackContext)
			So(len("I have no context"), ShouldBeGreaterThan, 0)
		}()
		<-done
	})
}

func TestFailureModeDuplicateSuite(t *testing.T) {
	Convey("cool", t, func() {
		defer expectPanic(t, multipleIdenticalConvey)

		Convey("dup", nil)
		Convey("dup", nil)
	})
}

func TestFailureModeIndeterminentSuiteNames(t *testing.T) {
	defer expectPanic(t, differentConveySituations)

	name := "bob"
	Convey("cool", t, func() {
		for i := 0; i < 3; i++ {
			Convey(name, func() {})
			name += "bob"
		}
	})
}

func TestFailureModeNestedIndeterminentSuiteNames(t *testing.T) {
	defer expectPanic(t, differentConveySituations)

	name := "bob"
	Convey("cool", t, func() {
		Convey("inner", func() {
			for i := 0; i < 3; i++ {
				Convey(name, func() {})
				name += "bob"
			}
		})
	})
}

func TestFailureModeParameterButMissing(t *testing.T) {
	defer expectPanic(t, parseError)

	prepare()

	Convey("Foobar", t, FailureHalts)
}

func TestFailureModeParameterWithAction(t *testing.T) {
	prepare()

	Convey("Foobar", t, FailureHalts, func() {})
}

func TestExtraConveyParameters(t *testing.T) {
	defer expectPanic(t, parseError)

	prepare()

	Convey("Foobar", t, FailureHalts, func() {}, "This is not supposed to be here")
}

func TestExtraConveyParameters2(t *testing.T) {
	defer expectPanic(t, parseError)

	prepare()

	Convey("Foobar", t, func() {}, "This is not supposed to be here")
}

func TestExtraConveyParameters3(t *testing.T) {
	defer expectPanic(t, parseError)

	output := prepare()

	Convey("A", t, func() {
		output += "A "

		Convey("B", func() {
			output += "B "
		}, "This is not supposed to be here")
	})

	expectEqual(t, "A ", output)
}


================================================
FILE: convey/update_assertions.sh
================================================
#!/usr/bin/env bash

cd "$(dirname $(realpath $0))"

ASSERTIONS=($(
  go tool nm "$(go list -export -f '{{.Export}}' github.com/smarty/assertions)" |\
    awk '/ T github\.com\/smarty\/assertions\.Should/{split($3, a, "."); print a[3]}' |\
    sort | uniq))

(
  echo "package convey"
  echo
  echo "// DO NOT EDIT: generated by update_assertions.sh"
  echo
  echo "//go:generate ./update_assertions.sh"
  echo
  echo "import \"github.com/smarty/assertions\""
  echo
  echo "// These assertions are forwarded from github.com/smarty/assertions"
  echo "// in order to make convey self-contained."
  echo "var ("

  for assertion in "${ASSERTIONS[@]}"
  do
    echo "  $assertion = assertions.$assertion"
  done

  echo ")"
) > ./assertions.go

go fmt ./assertions.go


================================================
FILE: examples/assertion_examples_test.go
================================================
package examples

import (
	"bytes"
	"io"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
)

func TestAssertionsAreAvailableFromConveyPackage(t *testing.T) {
	SetDefaultFailureMode(FailureContinues)
	defer SetDefaultFailureMode(FailureHalts)

	Convey("Equality assertions should be accessible", t, func() {
		thing1a := thing{a: "asdf"}
		thing1b := thing{a: "asdf"}
		thing2 := thing{a: "qwer"}

		So(1, ShouldEqual, 1)
		So(1, ShouldNotEqual, 2)
		So(1, ShouldAlmostEqual, 1.000000000000001)
		So(1, ShouldNotAlmostEqual, 2, 0.5)
		So(thing1a, ShouldResemble, thing1b)
		So(thing1a, ShouldNotResemble, thing2)
		So(&thing1a, ShouldPointTo, &thing1a)
		So(&thing1a, ShouldNotPointTo, &thing1b)
		So(nil, ShouldBeNil)
		So(1, ShouldNotBeNil)
		So(true, ShouldBeTrue)
		So(false, ShouldBeFalse)
		So(0, ShouldBeZeroValue)
		So(1, ShouldNotBeZeroValue)
	})

	Convey("Numeric comparison assertions should be accessible", t, func() {
		So(1, ShouldBeGreaterThan, 0)
		So(1, ShouldBeGreaterThanOrEqualTo, 1)
		So(1, ShouldBeLessThan, 2)
		So(1, ShouldBeLessThanOrEqualTo, 1)
		So(1, ShouldBeBetween, 0, 2)
		So(1, ShouldNotBeBetween, 2, 4)
		So(1, ShouldBeBetweenOrEqual, 1, 2)
		So(1, ShouldNotBeBetweenOrEqual, 2, 4)
	})

	Convey("Container assertions should be accessible", t, func() {
		So([]int{1, 2, 3}, ShouldContain, 2)
		So([]int{1, 2, 3}, ShouldNotContain, 4)
		So(map[int]int{1: 1, 2: 2, 3: 3}, ShouldContainKey, 2)
		So(map[int]int{1: 1, 2: 2, 3: 3}, ShouldNotContainKey, 4)
		So(1, ShouldBeIn, []int{1, 2, 3})
		So(4, ShouldNotBeIn, []int{1, 2, 3})
		So([]int{}, ShouldBeEmpty)
		So([]int{1}, ShouldNotBeEmpty)
		So([]int{1, 2}, ShouldHaveLength, 2)
	})

	Convey("String assertions should be accessible", t, func() {
		So("asdf", ShouldStartWith, "a")
		So("asdf", ShouldNotStartWith, "z")
		So("asdf", ShouldEndWith, "df")
		So("asdf", ShouldNotEndWith, "as")
		So("", ShouldBeBlank)
		So("asdf", ShouldNotBeBlank)
		So("asdf", ShouldContainSubstring, "sd")
		So("asdf", ShouldNotContainSubstring, "af")
	})

	Convey("Panic recovery assertions should be accessible", t, func() {
		So(panics, ShouldPanic)
		So(func() {}, ShouldNotPanic)
		So(panics, ShouldPanicWith, "Goofy Gophers!")
		So(panics, ShouldNotPanicWith, "Guileless Gophers!")
	})

	Convey("Type-checking assertions should be accessible", t, func() {

		// NOTE: Values or pointers may be checked.  If a value is passed,
		// it will be cast as a pointer to the value to avoid cases where
		// the struct being tested takes pointer receivers. Go allows values
		// or pointers to be passed as receivers on methods with a value
		// receiver, but only pointers on methods with pointer receivers.
		// See:
		// http://golang.org/doc/effective_go.html#pointers_vs_values
		// http://golang.org/doc/effective_go.html#blank_implements
		// http://blog.golang.org/laws-of-reflection

		So(1, ShouldHaveSameTypeAs, 0)
		So(1, ShouldNotHaveSameTypeAs, "1")

		So(bytes.NewBufferString(""), ShouldImplement, (*io.Reader)(nil))
		So("string", ShouldNotImplement, (*io.Reader)(nil))
	})

	Convey("Time assertions should be accessible", t, func() {
		january1, _ := time.Parse(timeLayout, "2013-01-01 00:00")
		january2, _ := time.Parse(timeLayout, "2013-01-02 00:00")
		january3, _ := time.Parse(timeLayout, "2013-01-03 00:00")
		january4, _ := time.Parse(timeLayout, "2013-01-04 00:00")
		january5, _ := time.Parse(timeLayout, "2013-01-05 00:00")
		oneDay, _ := time.ParseDuration("24h0m0s")

		So(january1, ShouldHappenBefore, january4)
		So(january1, ShouldHappenOnOrBefore, january1)
		So(january2, ShouldHappenAfter, january1)
		So(january2, ShouldHappenOnOrAfter, january2)
		So(january3, ShouldHappenBetween, january2, january5)
		So(january3, ShouldHappenOnOrBetween, january3, january5)
		So(january1, ShouldNotHappenOnOrBetween, january2, january5)
		So(january2, ShouldHappenWithin, oneDay, january3)
		So(january5, ShouldNotHappenWithin, oneDay, january1)
		So([]time.Time{january1, january2}, ShouldBeChronological)
	})
}

type thing struct {
	a string
}

func panics() {
	panic("Goofy Gophers!")
}

const timeLayout = "2006-01-02 15:04"


================================================
FILE: examples/bowling_game.go
================================================
package examples

// Game contains the state of a bowling game.
type Game struct {
	rolls   []int
	current int
}

// NewGame allocates and starts a new game of bowling.
func NewGame() *Game {
	game := new(Game)
	game.rolls = make([]int, maxThrowsPerGame)
	return game
}

// Roll rolls the ball and knocks down the number of pins specified by pins.
func (self *Game) Roll(pins int) {
	self.rolls[self.current] = pins
	self.current++
}

// Score calculates and returns the player's current score.
func (self *Game) Score() (sum int) {
	for throw, frame := 0, 0; frame < framesPerGame; frame++ {
		if self.isStrike(throw) {
			sum += self.strikeBonusFor(throw)
			throw += 1
		} else if self.isSpare(throw) {
			sum += self.spareBonusFor(throw)
			throw += 2
		} else {
			sum += self.framePointsAt(throw)
			throw += 2
		}
	}
	return sum
}

// isStrike determines if a given throw is a strike or not. A strike is knocking
// down all pins in one throw.
func (self *Game) isStrike(throw int) bool {
	return self.rolls[throw] == allPins
}

// strikeBonusFor calculates and returns the strike bonus for a throw.
func (self *Game) strikeBonusFor(throw int) int {
	return allPins + self.framePointsAt(throw+1)
}

// isSpare determines if a given frame is a spare or not. A spare is knocking
// down all pins in one frame with two throws.
func (self *Game) isSpare(throw int) bool {
	return self.framePointsAt(throw) == allPins
}

// spareBonusFor calculates and returns the spare bonus for a throw.
func (self *Game) spareBonusFor(throw int) int {
	return allPins + self.rolls[throw+2]
}

// framePointsAt computes and returns the score in a frame specified by throw.
func (self *Game) framePointsAt(throw int) int {
	return self.rolls[throw] + self.rolls[throw+1]
}

const (
	// allPins is the number of pins allocated per fresh throw.
	allPins          = 10
	
	// framesPerGame is the number of frames per bowling game.
	framesPerGame    = 10
	
	// maxThrowsPerGame is the maximum number of throws possible in a single game.
	maxThrowsPerGame = 21
)


================================================
FILE: examples/bowling_game_test.go
================================================
/*

Reference: http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata

See the very first link (which happens to be the very first word of
the first paragraph) on the page for a tutorial.

*/

package examples

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestBowlingGameScoring(t *testing.T) {
	Convey("Given a fresh score card", t, func() {
		game := NewGame()

		Convey("When all gutter balls are thrown", func() {
			game.rollMany(20, 0)

			Convey("The score should be zero", func() {
				So(game.Score(), ShouldEqual, 0)
			})
		})

		Convey("When all throws knock down only one pin", func() {
			game.rollMany(20, 1)

			Convey("The score should be 20", func() {
				So(game.Score(), ShouldEqual, 20)
			})
		})

		Convey("When a spare is thrown", func() {
			game.rollSpare()
			game.Roll(3)
			game.rollMany(17, 0)

			Convey("The score should include a spare bonus.", func() {
				So(game.Score(), ShouldEqual, 16)
			})
		})

		Convey("When a strike is thrown", func() {
			game.rollStrike()
			game.Roll(3)
			game.Roll(4)
			game.rollMany(16, 0)

			Convey("The score should include a strike bonus.", func() {
				So(game.Score(), ShouldEqual, 24)
			})
		})

		Convey("When all strikes are thrown", func() {
			game.rollMany(21, 10)

			Convey("The score should be 300.", func() {
				So(game.Score(), ShouldEqual, 300)
			})
		})
	})
}

func (self *Game) rollMany(times, pins int) {
	for x := 0; x < times; x++ {
		self.Roll(pins)
	}
}
func (self *Game) rollSpare() {
	self.Roll(5)
	self.Roll(5)
}
func (self *Game) rollStrike() {
	self.Roll(10)
}


================================================
FILE: examples/doc.go
================================================
// Package examples contains, well, examples of how to use goconvey to
// specify behavior of a system under test. It contains a well-known example
// by Robert C. Martin called "Bowling Game Kata" as well as another very
// trivial example that demonstrates Reset() and some of the assertions.
package examples


================================================
FILE: examples/examples.goconvey
================================================
// Uncomment the next line to disable the package when running the GoConvey UI:
//IGNORE

// Uncomment the next line to limit testing to the specified test function name pattern:
//-run=TestAssertionsAreAvailableFromConveyPackage

// Uncomment the next line to limit testing to those tests that don't bail when testing.Short() is true:
//-short

// include any additional `go test` flags or application-specific flags below:

-timeout=1s


================================================
FILE: examples/simple_example_test.go
================================================
package examples

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestIntegerManipulation(t *testing.T) {
	t.Parallel()

	Convey("Given a starting integer value", t, func() {
		x := 42

		Convey("When incremented", func() {
			x++

			Convey("The value should be greater by one", func() {
				So(x, ShouldEqual, 43)
			})
			Convey("The value should NOT be what it used to be", func() {
				So(x, ShouldNotEqual, 42)
			})
		})
		Convey("When decremented", func() {
			x--

			Convey("The value should be lesser by one", func() {
				So(x, ShouldEqual, 41)
			})
			Convey("The value should NOT be what it used to be", func() {
				So(x, ShouldNotEqual, 42)
			})
		})
	})
}


================================================
FILE: go.mod
================================================
module github.com/smartystreets/goconvey

go 1.21.7

require (
	github.com/jtolds/gls v4.20.0+incompatible
	github.com/smarty/assertions v1.15.1
	golang.org/x/tools v0.18.0
)

require (
	github.com/gopherjs/gopherjs v1.17.2 // indirect
	golang.org/x/mod v0.15.0 // indirect
)


================================================
FILE: go.sum
================================================
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/smarty/assertions v1.15.1 h1:812oFiXI+G55vxsFf+8bIZ1ux30qtkdqzKbEFwyX3Tk=
github.com/smarty/assertions v1.15.1/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=


================================================
FILE: goconvey.go
================================================
// This executable provides an HTTP server that watches for file system changes
// to .go files within the working directory (and all nested go packages).
// Navigating to the configured host and port in a web browser will display the
// latest results of running `go test` in each go package.
package main

import (
	"context"
	"embed"
	"flag"
	"fmt"
	"io/fs"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"strings"
	"syscall"
	"time"

	"golang.org/x/tools/go/packages"

	"github.com/smartystreets/goconvey/web/server/api"
	"github.com/smartystreets/goconvey/web/server/contract"
	"github.com/smartystreets/goconvey/web/server/executor"
	"github.com/smartystreets/goconvey/web/server/messaging"
	"github.com/smartystreets/goconvey/web/server/parser"
	"github.com/smartystreets/goconvey/web/server/system"
	"github.com/smartystreets/goconvey/web/server/watch"
)

func init() {
	flag.IntVar(&port, "port", 8080, "The port at which to serve http.")
	flag.StringVar(&host, "host", "127.0.0.1", "The host at which to serve http.")
	flag.DurationVar(&nap, "poll", quarterSecond, "The interval to wait between polling the file system for changes.")
	flag.IntVar(&parallelPackages, "packages", 10, "The number of packages to test in parallel. Higher == faster but more costly in terms of computing.")
	flag.StringVar(&gobin, "gobin", "go", "The path to the 'go' binary (default: search on the PATH).")
	flag.BoolVar(&cover, "cover", true, "Enable package-level coverage statistics.")
	flag.IntVar(&depth, "depth", -1, "The directory scanning depth. If -1, scan infinitely deep directory structures. 0: scan working directory. 1+: Scan into nested directories, limited to value.")
	flag.StringVar(&timeout, "timeout", "0", "The test execution timeout if none is specified in the *.goconvey file (default is '0', which is the same as not providing this option).")
	flag.StringVar(&watchedSuffixes, "watchedSuffixes", ".go", "A comma separated list of file suffixes to watch for modifications.")
	flag.StringVar(&excludedDirs, "excludedDirs", "vendor,node_modules", "A comma separated list of directories that will be excluded from being watched.")
	flag.StringVar(&workDir, "workDir", "", "set goconvey working directory (default current directory).")
	flag.BoolVar(&autoLaunchBrowser, "launchBrowser", true, "toggle auto launching of browser.")
	flag.BoolVar(&leakTemp, "leakTemp", false, "leak temp dir with coverage reports.")

	log.SetOutput(os.Stdout)
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

func main() {
	flag.Parse()

	printHeader()

	tmpDir, err := ioutil.TempDir("", "*.goconvey")
	if err != nil {
		log.Fatal(err)
	}
	reports := filepath.Join(tmpDir, "coverage_out")
	if err := os.Mkdir(reports, 0700); err != nil {
		log.Fatal(err)
	}
	if leakTemp {
		log.Printf("leaking temporary directory %q\n", tmpDir)
	} else {
		defer func() {
			if err := os.RemoveAll(tmpDir); err != nil {
				log.Printf("failed to clean temporary directory %q: %s\n", tmpDir, err)
			}
		}()
	}

	done := make(chan os.Signal)
	signal.Notify(done, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)

	working := getWorkDir()
	shell := system.NewShell(gobin, reports, cover, timeout)

	watcherInput := make(chan messaging.WatcherCommand)
	watcherOutput := make(chan messaging.Folders)
	excludedDirItems := strings.Split(excludedDirs, `,`)
	watcher := watch.NewWatcher(working, depth, nap, watcherInput, watcherOutput, watchedSuffixes, excludedDirItems)

	parser := parser.NewParser(parser.ParsePackageResults)
	tester := executor.NewConcurrentTester(shell)
	tester.SetBatchSize(parallelPackages)

	longpollChan := make(chan chan string)
	executor := executor.NewExecutor(tester, parser, longpollChan)
	server := api.NewHTTPServer(working, watcherInput, executor, longpollChan)
	listener := createListener()
	go runTestOnUpdates(watcherOutput, executor, server)
	go watcher.Listen()
	if autoLaunchBrowser {
		go launchBrowser(listener.Addr().String())
	}
	srv := serveHTTP(reports, server, listener)

	<-done
	log.Println("shutting down")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Printf("failed to shutdown: %s\n", err)
	}
}

func printHeader() {
	log.Println("GoConvey server: ")
	serverVersion := "<unknown>"
	if binfo, ok := debug.ReadBuildInfo(); ok {
		serverVersion = binfo.Main.Version
	}
	log.Println("  version:", serverVersion)
	log.Println("  host:", host)
	log.Println("  port:", port)
	log.Println("  poll:", nap)
	log.Println("  cover:", cover)
	log.Println()
}

func browserCmd() (string, bool) {
	browser := map[string]string{
		"darwin":  "open",
		"linux":   "xdg-open",
		"windows": "start",
	}
	cmd, ok := browser[runtime.GOOS]
	return cmd, ok
}

func launchBrowser(addr string) {
	browser, ok := browserCmd()
	if !ok {
		log.Printf("Skipped launching browser for this OS: %s", runtime.GOOS)
		return
	}

	log.Printf("Launching browser on %s", addr)
	url := fmt.Sprintf("http://%s", addr)
	cmd := exec.Command(browser, url)

	output, err := cmd.CombinedOutput()
	if err != nil {
		log.Println(err)
	}
	log.Println(string(output))
}

func runTestOnUpdates(queue chan messaging.Folders, executor contract.Executor, server contract.Server) {
	for update := range queue {
		log.Println("Received request from watcher to execute tests...")
		packages := extractPackages(update)
		output := executor.ExecuteTests(packages)
		root := extractRoot(update, packages)
		server.ReceiveUpdate(root, output)
	}
}

func extractPackages(folderList messaging.Folders) []*contract.Package {
	packageList := []*contract.Package{}
	for _, folder := range folderList {
		if isInsideTestdata(folder) {
			continue
		}
		hasImportCycle := testFilesImportTheirOwnPackage(folder.Path)
		packageName := resolvePackageName(folder.Path)
		packageList = append(
			packageList,
			contract.NewPackage(folder, packageName, hasImportCycle),
		)
	}
	return packageList
}

// For packages that operate on Go source code files, such as Go tooling, it is
// important to have a location that will not be considered part of package
// source to store those files. The official Go tooling selected the testdata
// folder for this purpose, so we need to ignore folders inside testdata.
func isInsideTestdata(folder *messaging.Folder) bool {
	relativePath, err := filepath.Rel(folder.Root, folder.Path)
	if err != nil {
		// There should never be a folder that's not inside the root, but if
		// there is, we can presumably count it as outside a testdata folder as
		// well
		return false
	}

	for _, directory := range strings.Split(filepath.ToSlash(relativePath), "/") {
		if directory == "testdata" {
			return true
		}
	}

	return false
}

func extractRoot(folderList messaging.Folders, packageList []*contract.Package) string {
	path := packageList[0].Path
	folder := folderList[path]
	return folder.Root
}

func createListener() net.Listener {
	l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		log.Println(err)
	}
	if l == nil {
		os.Exit(1)
	}
	return l
}

//go:embed web/client
var static embed.FS

func serveHTTP(reports string, server contract.Server, listener net.Listener) *http.Server {
	webclient, err := fs.Sub(static, "web/client")
	if err != nil {
		log.Fatal(err)
	}
	http.Handle("/", http.FileServer(http.FS(webclient)))

	http.HandleFunc("/watch", server.Watch)
	http.HandleFunc("/ignore", server.Ignore)
	http.HandleFunc("/reinstate", server.Reinstate)
	http.HandleFunc("/latest", server.Results)
	http.HandleFunc("/execute", server.Execute)
	http.HandleFunc("/status", server.Status)
	http.HandleFunc("/status/poll", server.LongPollStatus)
	http.HandleFunc("/pause", server.TogglePause)

	http.Handle("/reports/", http.StripPrefix("/reports/", http.FileServer(http.Dir(reports))))

	log.Printf("Serving HTTP at: http://%s\n", listener.Addr())
	ret := &http.Server{}
	go func() {
		err := ret.Serve(listener)
		if err != nil {
			log.Println(err)
		}
	}()
	return ret
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func getWorkDir() string {
	working := ""
	var err error
	if workDir != "" {
		working = workDir
	} else {
		working, err = os.Getwd()
		if err != nil {
			log.Fatal(err)
		}
	}
	result, err := exists(working)
	if err != nil {
		log.Fatal(err)
	}
	if !result {
		log.Fatalf("Path:%s does not exists", working)
	}
	return working
}

var (
	port              int
	host              string
	gobin             string
	nap               time.Duration
	parallelPackages  int
	cover             bool
	depth             int
	timeout           string
	watchedSuffixes   string
	excludedDirs      string
	autoLaunchBrowser bool
	leakTemp          bool

	quarterSecond = time.Millisecond * 250
	workDir       string
)

const (
	separator = string(filepath.Separator)
	endGoPath = separator + "src" + separator
)

// This method exists because of a bug in the go cover tool that
// causes an infinite loop when you try to run `go test -cover`
// on a package that has an import cycle defined in one of it's
// test files. Yuck.
func testFilesImportTheirOwnPackage(packagePath string) bool {
	meta, err := packages.Load(
		&packages.Config{
			Mode:  packages.NeedName | packages.NeedImports,
			Tests: true,
		},
		packagePath,
	)
	if err != nil {
		return false
	}

	testPackageID := fmt.Sprintf("%s [%s.test]", meta[0], meta[0])

	for _, testPackage := range meta[1:] {
		if testPackage.ID != testPackageID {
			continue
		}

		for dependency := range testPackage.Imports {
			if dependency == meta[0].PkgPath {
				return true
			}
		}
		break
	}
	return false
}

func resolvePackageName(path string) string {
	pkg, err := packages.Load(
		&packages.Config{
			Mode: packages.NeedName,
		},
		path,
	)
	if err == nil {
		return pkg[0].PkgPath
	}

	nameArr := strings.Split(path, endGoPath)
	return nameArr[len(nameArr)-1]
}


================================================
FILE: web/client/composer.html
================================================
<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="content-type" content="text/html; charset=UTF-8">
		<title>GoConvey Composer</title>
		<link rel="stylesheet" type="text/css" href="/resources/css/composer.css">
		<script src="/resources/js/lib/markup.js"></script>
		<script src="/resources/js/lib/taboverride.js"></script>
		<script src="/resources/js/lib/jquery.js"></script>
		<script src="/resources/js/composer.js"></script>
	</head>
	<body>
		<header>
			<h1>
				<span class="logo">GoConvey</span>
				<span class="afterlogo">Composer</span>
			</h1>
		</header>
		<main>
			<textarea id="input" placeholder="Type test cases here, one per line, with tab indentation"></textarea>
			<div id="output"></div>
		</main>

<script id="tpl-convey" type="text/template">{{.}}{{if .|notTestFunc}}{{depth|indent}}Convey("{{title}}", {{if showT}}t, {{/if}}{{if stories|empty}}nil{{else}}func() {

{{stories|recursivelyRender}}{{depth|indent}}}{{/if}})
{{else}}func {{title|properCase|safeFunc}}(t *testing.T) {

{{stories|recursivelyRender}}}
{{/if}}
{{/.}}</script>


	</body>
</html>

================================================
FILE: web/client/index.html
================================================
<!DOCTYPE html>
<html>
	<head>
		<title>GoConvey</title>
		<meta name="apple-mobile-web-app-capable" content="yes">
		<link rel="stylesheet" href="/resources/fonts/FontAwesome/css/font-awesome.css">
		<link rel="stylesheet" href="/resources/css/tipsy.css">
		<link rel="stylesheet" href="/resources/css/common.css">
		<link rel="icon" class="favicon" href="/favicon.ico" type="image/vnd.microsoft.icon">
		<link rel="shortcut icon" class="favicon" href="/favicon.ico" type="image/vnd.microsoft.icon">
		<script src="/resources/js/lib/markup.js"></script>
		<script src="/resources/js/lib/moment.js"></script>
		<script src="/resources/js/lib/ansispan.js"></script>
		<script src="/resources/js/lib/diff_match_patch.js"></script>
		<script src="/resources/js/lib/jquery.js"></script>
		<script src="/resources/js/lib/jquery-ui.js"></script>
		<script src="/resources/js/lib/jquery.pretty-text-diff.js"></script>
		<script src="/resources/js/lib/jquery.tipsy.js"></script>

		<!-- Script ordering is important -->
		<script src="/resources/js/poller.js"></script>
		<script src="/resources/js/convey.js"></script>
		<script src="/resources/js/config.js"></script>
		<script src="/resources/js/goconvey.js"></script>
	</head>
	<body>
		<header>
			<div class="overall ok">
				<div class="status">PASS</div>
			</div>

			<div class="toggler narrow" data-toggle="controls">
				Controls
			</div>

			<div id="controls" class="controls hide-narrow">
				<div class="server-not-down">
					<ul>
						<li id="logo" title="Powered by GoConvey"><a href="https://github.com/smartystreets/goconvey" target="_blank">GoConvey</a></li>
					</ul>

					<div class="float-left" id="path-container">
						<input type="text" id="path" placeholder="Watched directory" title="Change watched directory">
					</div>

					<ul class="float-right" id="control-buttons">
						<li class="fa fa-pause" id="play-pause" title="Play/pause tests"></li>
						<li class="fa fa-refresh" id="run-tests" title="Run tests"></li>
						<li class="fa fa-history" id="show-history" title="Test history"></li>
						<li class="fa fa-bell-o" id="toggle-notif" title="Toggle notifications"></li>
						<li class="fa fa-cog" id="show-settings" title="Settings"></li>
						<li class="fa fa-pencil-square-o" id="show-gen" title="Composer"></li>
					</ul>
				</div>
				<div class="server-down">
					<span class="flash">NOTICE:</span>
					<span class="notice-message"><!-- Populated by Javascript --></span>
				</div>

				<hr class="clear">


				<div class="expandable settings settings-general">
					<div class="container">
						<div class="setting">
							<div class="setting-meta">
								Theme
							</div>
							<div class="setting-val">
								<ol class="enum" id="theme"><!-- Populated by Javascript --></ol>
								<script id="tpl-theme-enum" type="text/template">
									{{.}}<li data-theme="{{id}}">{{name}}</li>{{/.}}
								</script>
							</div>
						</div>
						<div class="setting">
							<div class="setting-meta">
								Default
							</div>
							<div class="setting-val">
								<ol class="enum" id="pkg-expand-collapse">
									<li data-pkg-expand-collapse="expanded">Expand All</li>
									<li data-pkg-expand-collapse="collapsed">Collapse All</li>
								</ol>
							</div>
						</div>
						<div class="setting">
							<div class="setting-meta">
								Debug Output
							</div>
							<div class="setting-val">
								<ol class="enum" id="show-debug-output">
									<li data-show-debug-output="show">All</li>
									<li data-show-debug-output="fail">Failed</li>
									<li data-show-debug-output="hide">None</li>
								</ol>
							</div>
						</div>
						<div class="setting">
							<div class="setting-meta">
								Effects
							</div>
							<div class="setting-val">
								<ol class="enum" id="ui-effects">
									<li data-ui-effects="true">Cinematic</li>
									<li data-ui-effects="false">Off</li>
								</ol>
							</div>
						</div>
					</div>
				</div>

				<div class="expandable history">
					<div class="container"><!-- Populated by Javascript --></div>
					<script id="tpl-history" type="text/template">
						<div class="item {{overall.status.class}} frame-{{id}}" data-frameid="{{id}}">
							<div class="status momentjs" id="frame-{{id}}"></div>
							<div class="summary">{{overall.status.text|upcase}}<br>{{overall.passed}}/{{overall.assertions}} pass<br>{{overall.failures}} fail, {{overall.skipped}} skip</div>
						</div>
					</script>
				</div>

				<div class="expandable settings settings-notification">
					<div class="container">
						<div class="setting">
							<div class="setting-meta">
								Notifications
							</div>
							<div class="setting-val">
								<ol class="enum" id="notification">
									<li data-notification="true">On</li>
									<li data-notification="false">Off</li>
								</ol>
							</div>
						</div>
						<div class="setting">
							<div class="setting-meta">
								Level
							</div>
							<div class="setting-val">
								<ol class="enum" id="notification-level">
									<li data-notification-level=".*">Always</li>
									<li data-notification-level="fail|panic">Fail or Panic</li>
									<li data-notification-level="ok">Success Only</li>
								</ol>
							</div>
						</div>
					</div>
				</div>


			</div>
		</header>






		<div class="frame cf">


			<div class="col" id="col-1">
				<div class="toggler" data-toggle="coverage">
					Coverage
				</div>
				<div class="togglable" id="coverage"><!-- Populated by Javascript --></div>
				<script id="tpl-coverage" type="text/template">
					<div class="templated">
						{{.}}
						<div class="pkg-cover">
							<div class="pkg-cover-bar" data-pkg="{{PackageName}}" data-width="{{Coverage|coveragePct}}"></div>
							<div class="pkg-cover-name rtl pad-right{{if Coverage|coveragePct|equals>0}} no-coverage{{/if}}" title="{{Coverage|coveragePct}}% coverage">
								<a class="fa fa-level-down" href="#pkg-{{_id}}" style="padding: 0 5px;"></a>{{if Coverage|more>0}}<a href="/reports/{{PackageName|coverageReportName}}.html" target="_blank">{{PackageName|boldPkgName}}</a>{{else}}{{PackageName|boldPkgName}}{{/if}}
							</div>
						</div>
						{{/.}}
					</div>
				</script>



				<div class="toggler" data-toggle="ignored">
					Ignored
				</div>
				<div class="togglable" id="ignored"><!-- Populated by Javascript --></div>
				<script id="tpl-ignored" type="text/template">
					<div class="templated">
						<div class="rtl pkg-list">
						{{.}}
							<div>
								<a class="fa fa-level-down" href="#pkg-{{_id}}" style="padding: 0 5px;"></a>{{PackageName|boldPkgName}}
							</div>
						{{/.}}
						</div>
					</div>
				</script>


				<div class="toggler" data-toggle="notestfn">
					No Test Functions
				</div>
				<div class="togglable" id="notestfn"><!-- Populated by Javascript --></div>
				<script id="tpl-notestfn" type="text/template">
					<div class="templated">
						<div class="rtl pkg-list">
						{{.}}
							{{PackageName|boldPkgName}}<br>
						{{/.}}
						</div>
					</div>
				</script>


				<div class="toggler" data-toggle="notestfiles">
					No Test Files
				</div>
				<div class="togglable" id="notestfiles"><!-- Populated by Javascript --></div>
				<script id="tpl-notestfiles" type="text/template">
					<div class="templated">
						<div class="rtl pkg-list">
						{{.}}
							{{PackageName|boldPkgName}}<br>
						{{/.}}
						</div>
					</div>
				</script>



				<div class="toggler" data-toggle="nogofiles">
					No Go Files
				</div>
				<div class="togglable" id="nogofiles"><!-- Populated by Javascript --></div>
				<script id="tpl-nogofiles" type="text/template">
					<div class="templated">
						<div class="rtl pkg-list">
						{{.}}
							{{PackageName|boldPkgName}}<br>
						{{/.}}
						</div>
					</div>
				</script>
			</div>











			<div class="col" id="col-2">

				<div class="toggler buildfailures" data-toggle="buildfailures">
					Build Failures
				</div>
				<div class="togglable buildfailures" id="buildfailures"><!-- Populated by Javascript --></div>
				<script id="tpl-buildfailures" type="text/template">
					<div class="templated">
						{{.}}
						<div class="buildfail">
							<div class="buildfail-pkg"><i class="fa fa-wrench"></i>&nbsp; {{PackageName|boldPkgName}}</div>
							<div class="buildfail-output">{{BuildOutput|htmlSafe|ansiColours}}</div>
						</div>
						{{/.}}
					</div>
				</script>



				<div class="toggler panics" data-toggle="panics">
					Panics
				</div>
				<div class="togglable panics" id="panics"><!-- Populated by Javascript --></div>
				<script id="tpl-panics" type="text/template">
					<div class="templated">
						{{.}}
						<div class="panic">
							<div class="panic-pkg">
								<i class="fa fa-bomb"></i>&nbsp; {{_pkg|boldPkgName}}
							</div>
						<div class="panic-details">
							<div class="panic-story">
							<div class="panic-file">
								{{if File|notempty}}
								<a href="goconvey://open/?url=file://{{File|url}}&line={{Line}}">{{File|relativePath}}{{if Line|more>0}}:{{Line}}{{/if}}&nbsp; <i class="fa fa-external-link"></i></a>
								{{else}}
								<b>{{TestName}}</b>
								{{/if}}
						</div>
					{{if _path|notempty}}
						{{_path}}
							<div class="story-links{{if Depth|more>-1}} depth-{{Depth}}{{/if}}"><a href="#test-{{_id}}">{{Title|htmlSafe|ansiColours}}</a></div>
						{{/_path}}
					{{/if}}
							{{if StackTrace|notempty}}<div class="depth-{{_maxDepth}} panic-summary">{{Error}}</div>{{/if}}
							</div>
							<div class="panic-output">{{if StackTrace|empty}}{{Error|htmlSafe|ansiColours}}{{else}}{{StackTrace|htmlSafe|ansiColours}}{{/if}}</div>
						</div>
						{{/.}}
					</div>
				</script>




				<div class="toggler failures" data-toggle="failures">
					Failures
				</div>
				<div class="togglable failures" id="failures"><!-- Populated by Javascript --></div>
				<script id="tpl-failures" type="text/template">
					<div class="templated">
						{{.}}
						<div class="failure">
							<div class="failure-pkg"><i class="fa fa-file-code-o"></i>&nbsp; {{_pkg|boldPkgName}}</div>
							<div class="failure-details">
								<div class="failure-story">
									<div class="failure-file">
										{{if File|notempty}}
										<a href="goconvey://open/?url=file://{{File|url}}&line={{Line}}">{{File|relativePath}}{{if Line|more>0}}:{{Line}}{{/if}}&nbsp; <i class="fa fa-external-link"></i></a>
										{{else}}
										<b class="test-name-link"><a href="#test-{{_id}}">{{TestName}}</a></b>
										{{/if}}
									</div>
							{{if _path|notempty}}
								{{_path}}
									<div class="story-links{{if Depth|more>-1}} depth-{{Depth}}{{/if}}"><a href="#test-{{_id}}">{{Title|htmlSafe|ansiColours}}</a></div>
								{{/_path}}
							{{/if}}
								</div>
								<div class="failure-output">{{if Failure|notempty}}{{Failure|htmlSafe|ansiColours}}{{else}}{{if Message|notempty}}{{Message|htmlSafe|ansiColours}}{{else}}{{StackTrace|htmlSafe|ansiColours}}{{/if}}{{/if}}</div>
								{{if .|needsDiff}}
								<table class="diffviewer">
									<tr>
										<td class="exp">Expected</td>
										<td class="original">{{Expected|htmlSafe|ansiColours}}</td>
									</tr>
									<tr>
										<td class="act">Actual</td>
										<td class="changed">{{Actual|htmlSafe|ansiColours}}</td>
									</tr>
									<tr>
										<td>Diff</td>
										<td class="diff"></td>
									</tr>
								</table>
								{{/if}}
							</div>
						</div>
						{{/.}}
					</div>
				</script>




				<div class="toggler stories" data-toggle="stories">
					Stories
				</div>
				<div class="togglable stories" id="stories"><!-- Populated by Javascript --></div>

				<script id="tpl-stories" type="text/template">
					<table>
					{{.}}
						<tr class="story-pkg expanded pkg-{{_id}}" data-pkg="{{_id}}" data-pkg-name="{{PackageName}}" data-pkg-state="expanded" id="pkg-{{_id}}">
							<td colspan="2">
								<span class="pkg-toggle-container">
									<a href="javascript:" class="fa fa-minus-square-o pkg-toggle"></a>
									<span class="toggle-all-pkg">ALL</span>
								</span>
							</td>
							<td class="story-pkg-name">
								{{PackageName|boldPkgName}}
							</td>
							<td class="story-pkg-summary">
								{{if _panicked|more>0}}<span class="story-pkg-panic-count"><span class="statusicon panic"><i class="fa fa-bolt"></i></span> {{_panicked}}
								&nbsp;</span>{{/if}}
								{{if _failed|more>0}}<span class="story-pkg-failure-count"><span class="statusicon fail">&#10007;</span> {{_failed}}
								&nbsp;</span>{{/if}}
								{{if _passed|more>0}}<span class="story-pkg-pass-count"><span class="statusicon ok">&#10003;</span> {{_passed}}</span>{{/if}}
								{{if _skipped|more>0}}<span class="story-pkg-skip-count">&nbsp; <span class="statusicon skip"><b>S</b></span> {{_skipped}}</span>{{/if}}
							</td>
							<td class="story-pkg-watch-td">
								{{if Outcome|equals>disabled}}
								<span class="fa fa-lg fa-eye-slash disabled" title="Disabled"></span>
								{{else}}
								<a class="fa fa-lg ignore {{if Outcome|notequals>ignored}}fa-eye unwatch{{else}}fa-eye-slash watch clr-red{{/if}}" href="javascript:" title="Toggle ignore" data-pkg="{{PackageName}}"></a>
								{{/if}}
							</td>
						</tr>
						{{TestResults}}
						<tr id="test-{{_id}}" class="story-line {{if _status.class}}{{_status.class}}{{else}}skip{{/if}} test-{{_id}} pkg-{{_pkgid}}">
							<td class="story-line-status"></td>
							<td class="story-line-summary-container">
								
									{{if Stories|empty}} <!-- Not apparently a GoConvey test -->
										{{if _passed}}<span class="statusicon ok">&#10003;</span><br>{{/if}}
										{{if _failed}}<span class="statusicon fail">&#10007;</span><br>{{/if}}
										{{if _panicked}}<span class="statusicon panic"><i class="fa fa-bolt"></i></span><br>{{/if}}
										{{if _skipped}}<span class="statusicon skip"><b>S</b></span><br>{{/if}}
									{{/if}}

							</td>
							<td colspan="3" class="depth-0 story-line-desc">
								<b>{{TestName|htmlSafe|ansiColours}}</b>
								{{if Message}}<div class="message">{{Message|htmlSafe|ansiColours}}</div>{{/if}}
							</td>
						</tr>



							{{Stories}}
							<tr class="story-line {{if _status.class}}{{_status.class}}{{else}}skip{{/if}} pkg-{{_pkgid}}"  id="test-{{_id}}">
								<td class="story-line-status"></td>
								<td class="story-line-summary-container">
									
									{{if _passed}}<span class="statusicon ok">&#10003; {{_passed}}</span><br>{{/if}}
									{{if _failed}}<span class="statusicon fail">&#10007; {{_failed}}</span><br>{{/if}}
									{{if _panicked}}<span class="statusicon panic"><i class="fa fa-bolt"></i> {{_panicked}}</span><br>{{/if}}
									{{if _skipped}}<span class="statusicon skip"><b>S</b> {{_skipped}}</span><br>{{/if}}

								</td>
								<td colspan="3" class="depth-{{Depth}} story-line-desc">
									{{Title|htmlSafe|ansiColours}}
									{{if Output}}<div class="message">{{Output|htmlSafe|ansiColours}}</div>{{/if}}
									{{if _failed}}
										{{Assertions}}
											{{if _failed}}
											<div class="failure">
												<div class="failure-details">
													<div class="failure-output">{{if Failure|notempty}}{{Failure|htmlSafe|ansiColours}}{{else}}{{if Message|notempty}}{{Message|htmlSafe|ansiColours}}{{else}}
															{{StackTrace|htmlSafe|ansiColours}}{{/if}}{{/if}}</div>
												</div>
											</div>
											{{/if}}
										{{/Assertions}}
									{{/if}}
									{{if _panicked}}
										{{Assertions}}
											{{if _panicked}}
											<div class="panic">
												<div class="panic-details">
													<div class="panic-output">{{if Panic|notempty}}{{Panic|htmlSafe|ansiColours}}{{else}}{{if Message|notempty}}{{Message|htmlSafe|ansiColours}}{{else}}{{StackTrace|htmlSafe|ansiColours}}{{/if}}{{/if}}</div>
												</div>
											</div>
											{{/if}}
										{{/Assertions}}
									{{/if}}
								</td>
							</tr>
							{{/Stories}}


						{{/TestResults}}
					{{/.}}
					</table>
				</script>
			</div>



			<div class="col" id="col-3">
				<div class="toggler" data-toggle="log">
					LOG
				</div>
				<div class="togglable log" id="log"><!-- Populated by Javascript --></div>
				<script id="tpl-log-line" type="text/template">
					<div class="line"><span class="timestamp">[{{time}}]</span> {{msg|clean}}</div>
				</script>
			</div>

		</div>

		<footer>
			<section>
				<span id="summary">
					<span class="info" id="time"><!-- Populated by Javascript --></span>
					<span class="info" id="last-test-container">Last test <span id="last-test"><!-- Populated by Javascript --></span></span>
					<span class="info" id="assert-count"><!-- Populated by Javascript --></span>
					<span class="info fail-clr" id="fail-count"><!-- Populated by Javascript --></span>
					<span class="info panic-clr" id="panic-count"><!-- Populated by Javascript --></span>
					<span class="info skip-clr" id="skip-count"><!-- Populated by Javascript --></span>
					<span class="momentjs" id="duration"><!-- Populated by Javascript --></span>
				</span>
				<span id="narrow-summary">
					<span id="narrow-assert-count"><!-- Populated by Javascript --></span>:
					<span class="fail-clr" id="narrow-fail-count"><!-- Populated by Javascript --></span> /
					<span class="panic-clr" id="narrow-panic-count"><!-- Populated by Javascript --></span> /
					<span class="skip-clr" id="narrow-skip-count"><!-- Populated by Javascript --></span>
				</span>
			</section>
			<section>
				<span class="server-not-down">
					<span class="recording">
						<i class="fa fa-circle"></i> LIVE
					</span>
					<span class="replay" title="Click for current test results">
						<i class="fa fa-play"></i> REPLAY
					</span>
					<span class="paused">
						<i class="fa fa-pause"></i> PAUSED
					</span>
				</span>
				<span class="server-down">
					<i class="fa fa-exclamation-triangle fa-lg flash"></i>
					<span class="notice-message"><!-- Populated by Javascript --></span>
				</span>
			</section>
		</footer>

	</body>
</html>


================================================
FILE: web/client/resources/css/common.css
================================================
/* Eric Meyer's Reset CSS v2.0 */
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0}

@font-face {
	font-family: 'Open Sans';
	src: local("Open Sans"), url("../fonts/Open_Sans/OpenSans-Regular.ttf");
}
@font-face {
	font-family: 'Orbitron';
	src: local("Orbitron"), url("../fonts/Orbitron/Orbitron-Regular.ttf");
}
@font-face {
	font-family: 'Oswald';
	src: local("Oswald"), url("../fonts/Oswald/Oswald-Regular.ttf");
}

::selection {
	background: #87AFBC;
	color: #FFF;
	text-shadow: none;
}

::-moz-selection {
	background: #87AFBC;
	color: #FFF;
	text-shadow: none;
}

::-webkit-input-placeholder {
	font-style: italic;
}
:-moz-placeholder {
	font-style: italic;
}
::-moz-placeholder {
	font-style: italic;
}
:-ms-input-placeholder {
	font-style: italic;
}



html, body {
	height: 100%;
	min-height: 100%;
}

body {
	-webkit-transform: translate3d(0, 0, 0);	/* attempts to fix Chrome glitching on Mac */
	background-position: fixed;
	background-repeat: no-repeat;
	font-family: Menlo, Monaco, 'Courier New', monospace;
	line-height: 1.5em;
	font-size: 14px;
	overflow: hidden;
	display: none;
}

a {
	text-decoration: none;
}

a:hover {
	text-decoration: underline;
}

a.fa {
	text-decoration: none;
}

b {
	font-weight: bold;
}

i {
	font-style: italic;
}

hr {
	border: 0;
	background: 0;
	height: 0;
	margin: 0;
	padding: 0;
}

input[type=text] {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;

	background: none;
	border: none;
	border-bottom-width: 1px;
	border-bottom-style: solid;
	outline: none;
	padding-bottom: .1em;
	font: 300 18px/1.5em 'Open Sans', sans-serif;
}

.overall {
	padding: 30px 0 15px;
	position: relative;
	z-index: 50;
}

.status {
	line-height: 1em;
	font-family: 'Orbitron', monospace;
	text-align: center;
}

.overall .status {
	font-size: 46px;
	letter-spacing: 5px;
	text-transform: uppercase;
	white-space: nowrap;
}

.toggler {
	font-size: 10px;
	padding: 3px 5px;
	text-decoration: none;
	text-transform: uppercase;
	cursor: pointer;
	line-height: 1.5em;
}

.toggler.narrow {
	display: none;
}

.togglable {
	overflow-x: auto;
}

.controls {
	font-size: 18px;
	line-height: 1em;
}

.controls li {
	text-decoration: none;
	display: block;
	float: left;
	padding: .75em;
	cursor: pointer;
}

.server-down {
	display: none;
	text-align: center;
	padding: 10px 0;
}

footer .server-down {
	padding: 8px 15px;
	text-transform: uppercase;
}

#logo {
	font-family: 'Oswald', 'Impact', 'Arial Black', sans-serif;
}

#path-container {
	margin-top: .4em;
}

#path {
	width: 100%;
	text-align: center;
	border-bottom-width: 0;
}

#path:hover,
#path:focus {
	border-bottom-width: 1px;
}

.expandable {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;

	border-top-width: 1px;
	border-top-style: solid;
	overflow-y: hidden;
	overflow-x: auto;
	text-align: center;
	white-space: nowrap;
	display: none;
}

.settings {
	white-space: normal;
	overflow-x: auto;
	white-space: nowrap;
}

.settings .setting-meta,
.settings .setting-val {
	display: inline-block;
}

.settings .container {
	padding: 15px 0;
}

.settings .setting {
	font-size: 13px;
	display: inline-block;
	margin-right: 5%;
}

.settings .setting:first-child {
	margin-left: 5%;
}

.settings .setting .setting-meta {
	text-align: right;
	padding-right: 1em;
	vertical-align: middle;
	max-width: 150px;
}

.settings .setting .setting-meta small {
	font-size: 8px;
	text-transform: uppercase;
	display: block;
	line-height: 1.25em;
}

.history .container {
	padding: 15px 0 15px 25%;
}

.history .item {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;

	transition: all .1s linear;
	-moz-transition: all .1s linear;
	-webkit-transition: all .1s linear;
	-o-transition: all .1s linear;

	display: inline-block;
	text-align: left;
	margin: 0 20px;
	padding: 20px;
	height: 100%;
	width: 175px;
	opacity: .7;
	cursor: pointer;
}

.history .item:hover {
	opacity: 1;
}

.history .item:nth-child(odd):hover {
	-webkit-transform: scale(1.1) rotate(5deg);
	-moz-transform: scale(1.1) rotate(5deg);
}

.history .item:nth-child(even):hover {
	-webkit-transform: scale(1.1) rotate(-5deg);
	-moz-transform: scale(1.1) rotate(-5deg);
}

.history .item .summary {
	font: 14px/1.5em 'Monaco', 'Menlo', 'Courier New', monospace;
}

.history .item.selected {
	opacity: 1;
}

.history .status {
	font-size: 13px;
}






.frame {
	position: relative;
	z-index: 0;
	width: 100%;
}

.frame .col {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;

	border-right-width: 1px;
	border-right-style: solid;
	float: left;
	height: 100%;
	overflow-y: auto;
}

.frame .col:first-child {
	border-left: none;
}

.frame .col:last-child {
	border-right: none;
}


#col-1 {
	width: 15%;
}

#col-2 {
	width: 60%;
}

#col-3 {
	width: 25%;
}

#coverage {
	font-size: 10px;
	white-space: nowrap;
}

#coverage-color-template {
	display: none;
}

.rtl {
	direction: rtl;
}

.pkg-cover {
	position: relative;
}

.pkg-cover a {
	color: inherit !important;
	text-decoration: none;
}

.pkg-cover-bar {
	position: absolute;
	top: 0;
	left: 0;
	height: 100%;
	z-index: 1;
}

.pkg-cover-name {
	position: relative;
	z-index: 2;
}

.pkg-cover-name,
.pkg-list {
	font-family: 'Menlo', monospace;
	font-size: 10px;
	padding-right: 2%;
	white-space: nowrap;
}

.buildfail-pkg,
.panic-pkg,
.failure-pkg {
	padding: 5px 10px;
	font: 14px 'Open Sans', sans-serif;
}

.buildfail-output,
.panic-output,
.failure-output {
	padding: 10px;
	font-size: 12px;
	line-height: 1.25em;
	overflow-y: auto;
	white-space: pre-wrap;
	font-family: 'Menlo', monospace;
}

.panic-story,
.failure-story {
	font-size: 10px;
	line-height: 1.25em;
	font-family: 'Open Sans', sans-serif;
}

.panic-summary {
	font-size: 14px;
	font-weight: bold;
	line-height: 1.5em;
}

.panic-file,
.failure-file {
	font-size: 13px;
	line-height: 1.5em;
}

.diffviewer {
	border-collapse: collapse;
	width: 100%;
}

.diffviewer td {
	border-bottom-width: 1px;
	border-bottom-style: solid;
	padding: 2px 5px;
	font-size: 14px;
}

.diffviewer .original,
.diffviewer .changed,
.diffviewer .diff {
	white-space: pre-wrap;
}

.diffviewer tr:first-child td {
	border-top-width: 1px;
	border-top-style: solid;
}

.diffviewer td:first-child {
	width: 65px;
	font-size: 10px;
	border-right-width: 1px;
	border-right-style: solid;
	text-transform: uppercase;
}

.diff ins {
	text-decoration: none;
}



#stories table {
	width: 100%;
}


.story-pkg {
	cursor: pointer;
}

.story-pkg td {
	font: 16px 'Open Sans', sans-serif;
	white-space: nowrap;
	padding: 10px;
}

.story-pkg td:first-child {
	width: 1em;
}

.story-line {
	font: 12px 'Open Sans', sans-serif;
	cursor: default;
}

.story-line td {
	padding-top: 7px;
	padding-bottom: 7px;
}

.pkg-toggle-container {
	position: relative;
	display: inline-block;
}

.toggle-all-pkg {
	font-size: 10px;
	text-transform: uppercase;
	position: absolute;
	padding: 5px;
	font-family: 'Menlo', 'Open Sans', sans-serif;
	display: none;
}

.story-line-summary-container {
	padding: 0 10px 0 10px;
	white-space: nowrap;
	width: 35px;
	text-align: center;
}

.story-line-status {
	width: 6px;
	min-width: 6px;
	height: 100%;
}

.story-line-desc {
	padding: 5px;
}

.story-line-desc .message {
	font-family: 'Menlo', monospace;
	white-space: pre-wrap;
}

.statusicon {
	font: 14px 'Open Sans', sans-serif;
}

.statusicon.skip {
	font-size: 16px;
}


.depth-0 { padding-left: 1.5em !important; }
.depth-1 { padding-left: 3em !important; }
.depth-2 { padding-left: 4.5em !important; }
.depth-3 { padding-left: 6em !important; }
.depth-4 { padding-left: 7.5em !important; }
.depth-5 { padding-left: 9em !important; }
.depth-6 { padding-left: 10.5em !important; }
.depth-7 { padding-left: 11em !important; }


.log {
	font-size: 11px;
	line-height: 1.5em;
	padding: 5px;
	padding-bottom: .5em;
}

.log .line {
	white-space: pre-wrap;
	padding-left: 2em;
	text-indent: -2em;
}





footer {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;

	position: absolute;
	bottom: 0;
	left: 0;
	padding: 5px 15px;
	width: 100%;
	border-top-width: 1px;
	border-top-style: solid;
	font-size: 12px;
}

footer section {
	float: left;
}

footer section:first-child {
	width: 80%;
}

footer section:last-child {
	text-align: right;
	width: 20%;
}

footer .info {
	padding: 0 10px;
}

footer .info:first-child {
	padding-left: 0;
}

#narrow-summary {
	display: none;
}

footer .replay,
footer .paused {
	display: none;
}

footer .replay {
	cursor: pointer;
}

footer .server-down .notice-message {
	font-size: 10px;
}




.rel {
	position: relative;
}

.text-right {
	text-align: right;
}

.text-center {
	text-align: center;
}

.text-left {
	text-align: left;
}

.float-left {
	float: left;
}

.float-right {
	float: right;
}

.clear {
	clear: both;
}

.nowrap {
	white-space: nowrap;
}

.clr-blue {
	color: #2B597F;
}

.show {
	display: block;
}

.hide {
	display: none;
}

.enum {
	cursor: pointer;
	display: inline-block;
	font-size: 12px;
	border-width: 1px;
	border-style: solid;
	border-radius: 9px;
	vertical-align: middle;
}

.enum > li {
	display: block;
	float: left;
	padding: 5px 12px;
	border-left-width: 1px;
	border-left-style: solid;
}

.enum > li:first-child {
	border-left: 0px;
	border-top-left-radius: 8px;
	border-bottom-left-radius: 8px;
}

.enum > li:last-child {
	border-top-right-radius: 8px;
	border-bottom-right-radius: 8px;
}








.disabled {
	cursor: default !important;
	background: transparent !important;
}

.spin-once {
	-webkit-animation: fa-spin 0.5s 1 ease;
	animation: fa-spin 0.5s 1 ease;
}

.spin-slowly {
	-webkit-animation: fa-spin .75s infinite linear;
	animation: fa-spin .75s infinite linear;
}

.throb {
	-webkit-animation: throb 2.5s ease-in-out infinite;
	-moz-animation: throb 2.5s ease-in-out infinite;
	-o-animation: throb 2.5s ease-in-out infinite;
	animation: throb 2.5s ease-in-out infinite;
}

.flash {
	-webkit-animation: flash 4s linear infinite;
	-moz-animation: flash 4s linear infinite;
	-o-animation: flash 4s linear infinite;
	animation: flash 4s linear infinite;
}





/* Clearfix */
.cf:before,
.cf:after {
	content: " ";
	display: table;
}
.cf:after {
	clear: both;
}






@media (max-width: 1099px) {
	#col-1 {
		width: 25%;
	}

	#col-2 {
		width: 75%;
		border-right: none;
	}

	#col-3 {
		display: none;
	}

	footer #duration {
		display: none;
	}
}

@media (max-width: 900px) {
	footer #last-test-container {
		display: none;
	}
}

@media (min-width: 850px) and (max-width: 1220px) {
	#path {
		font-size: 14px;
		margin-top: 5px;
	}
}

@media (min-width: 700px) and (max-width: 849px) {
	#path {
		font-size: 12px;
		margin-top: 8px;
	}
}

@media (max-width: 799px) {
	#col-1 {
		display: none;
	}

	#col-2 {
		width: 100%;
	}

	#stories .story-pkg-name {
		font-size: 14px;
	}

	#stories .story-pkg-watch-td {
		display: none;
	}
}

@media (max-width: 700px) {
	#path-container {
		display: none;
	}

	footer #time {
		display: none;
	}

	footer .info {
		padding: 0 5px;
	}

	footer .server-down .notice-message {
		display: none;
	}
}

@media (max-width: 499px) {
	.toggler.narrow {
		display: block;
	}

	#show-gen {
		display: none;
	}

	.hide-narrow {
		display: none;
	}

	.show-narrow {
		display: block;
	}

	.overall .status {
		font-size: 28px;
		letter-spacing: 1px;
	}

	.toggler {
		display: block;
	}

	.controls ul {
		text-align: center;
		float: none;
	}

	.controls li {
		display: inline-block;
		float: none;
	}

	.enum > li {
		float: left;
		display: block;
	}

	#logo {
		display: none;
	}

	.history .item {
		margin: 0 5px;
	}

	.history .item .summary {
		display: none;
	}

	.server-down {
		font-size: 14px;
	}

	#stories .story-pkg-name {
		font-size: 16px;
	}
	
	#stories .not-pkg-name {
		display: none;
	}

	footer #duration {
		display: none;
	}

	footer #summary {
		display: none;
	}

	footer #narrow-summary {
		display: inline;
	}
}




/**
	Custom CSS Animations
**/



@-webkit-keyframes throb {
	0% { opacity: 1; }
	50% { opacity: .35; }
	100% { opacity: 1; }
}
@-moz-keyframes throb {
	0% { opacity: 1; }
	50% { opacity: .35; }
	100% { opacity: 1; }
}
@-o-keyframes throb {
	0% { opacity: 1; }
	50% { opacity: .35; }
	100% { opacity: 1; }
}
@keyframes throb {
	0% { opacity: 1; }
	50% { opacity: .35; }
	100% { opacity: 1; }
}


@-webkit-keyframes flash {
	70% { opacity: 1; }
	90% { opacity: 0; }
	98% { opacity: 0; }
	100% { opacity: 1; }
}
@-moz-keyframes flash {
	70% { opacity: 1; }
	90% { opacity: 0; }
	98% { opacity: 0; }
	100% { opacity: 1; }
}
@-o-keyframes flash {
	70% { opacity: 1; }
	90% { opacity: 0; }
	98% { opacity: 0; }
	100% { opacity: 1; }
}
@keyframes flash {
	70% { opacity: 1; }
	90% { opacity: 0; }
	98% { opacity: 0; }
	100% { opacity: 1; }
}











/*
#coverage {
	perspective: 1000;
}

#coverage .pkg-cover {
	-webkit-transition: .7s;
	transform-style: preserve-3d;
	position: relative;
}

#coverage:hover .pkg-cover {
	-webkit-transform: rotateX(180deg);
}*/


================================================
FILE: web/client/resources/css/composer.css
================================================
/* Eric Meyer's Reset CSS v2.0 */
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0}

@font-face {
	font-family: 'Open Sans';
	src: local("Open Sans"), url("../fonts/Open_Sans/OpenSans-Regular.ttf");
}
@font-face {
	font-family: 'Oswald';
	src: local("Oswald"), url("../fonts/Oswald/Oswald-Regular.ttf");
}

body {
	font-family: 'Open Sans', 'Helvetica Neue', sans-serif;
	font-size: 16px;
}

header {
	background: #2C3F49;
	padding: 10px;
}

.logo {
	font-family: Oswald, sans-serif;
	font-size: 24px;
	margin-right: 5px;
	color: #DDD;
}

.afterlogo {
	font-size: 12px;
	text-transform: uppercase;
	position: relative;
	top: -3px;
	color: #999;
}

#input,
#output {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;

	padding: 15px;
	height: 80%;
	float: left;
	overflow: auto;
}

#input {
	border: 0;
	font: 300 18px/1.5em 'Open Sans';
	resize: none;
	outline: none;
	width: 50%;
}

#output {
	width: 50%;
	display: inline-block;
	background: #F0F0F0;
	font: 14px/1.25em 'Menlo', 'Monaco', 'Courier New', monospace;
	border-left: 1px solid #CCC;
	white-space: pre-wrap;
}

================================================
FILE: web/client/resources/css/themes/dark-bigtext.css
================================================
/* This is a fork of the dark.css theme. The only changes from dark.css are near the very end. */

::-webkit-scrollbar {
	width: 10px;
	height: 10px;
}

::-webkit-scrollbar-corner {
	background: transparent;
}

::-webkit-scrollbar-thumb {
	background-color: rgba(255, 255, 255, .35);
	border-radius: 10px;
}

body {
	color: #D0D0D0;
	background: fixed #040607;
	background: fixed -moz-linear-gradient(top, hsl(200,27%,2%) 0%, hsl(203,29%,26%) 100%);
	background: fixed -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsl(200,27%,2%)), color-stop(100%,hsl(203,29%,26%)));
	background: fixed -webkit-linear-gradient(top, hsl(200,27%,2%) 0%,hsl(203,29%,26%) 100%);
	background: fixed -o-linear-gradient(top, hsl(200,27%,2%) 0%,hsl(203,29%,26%) 100%);
	background: fixed -ms-linear-gradient(top, hsl(200,27%,2%) 0%,hsl(203,29%,26%) 100%);
	background: fixed linear-gradient(to bottom, hsl(200,27%,2%) 0%,hsl(203,29%,26%) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#040607', endColorstr='#2f4756',GradientType=0 );
}

a,
.toggle-all-pkg {
	color: #247D9E;
}

a:hover,
.toggle-all-pkg:hover {
	color: #33B5E5;
}

input[type=text] {
	border-bottom-color: #33B5E5;
	color: #BBB;
}

::-webkit-input-placeholder {
	color: #555;
}
:-moz-placeholder {
	color: #555;
}
::-moz-placeholder {
	color: #555;
}
:-ms-input-placeholder {
	color: #555;
}

.overall {
	/*
		Using box-shadow here is not very performant but allows us
		to animate the change of the background color much more easily.
		This box-shadow is an ALTERNATIVE, not supplement, to using gradients
		in this case.
	*/
	box-shadow: inset 0 150px 100px -110px rgba(0, 0, 0, .5);
}

.overall.ok {
	background: #688E00;
}

.overall.fail {
	background: #DB8700;
}

.overall.panic {
	background: #A80000;
}

.overall.buildfail {
	background: #A4A8AA;
}

.overall .status {
	color: #EEE;
}

.server-down {
	background: rgba(255, 45, 45, 0.55);
	color: #FFF;
}

.toggler {
	background: #132535;
}

.toggler:hover {
	background: #1C374F;
}

.controls {
	border-bottom: 1px solid #33B5E5;
}

.controls li {
	color: #2A5A84;
}

.controls li:hover {
	background: #132535;
	color: #33B5E5;
}

.sel {
	background: #33B5E5 !important;
	color: #FFF !important;
}

.pkg-cover-name {
	text-shadow: 1px 1px 0px #000;
}

.pkg-cover-name b, 
.story-pkg-name b {
	color: #FFF;
	font-weight: bold;
}

.pkg-cover:hover,
.pkg-cover:hover b {
	color: #FFF;
}

.expandable {
	border-top-color: #33B5E5;
}

.expandable {
	background: rgba(0, 0, 0, .2);
}

.history .item.ok {
	background: #3f5400;
	background: -moz-linear-gradient(top, hsl(75,100%,16%) 0%, hsl(76,100%,28%) 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsl(75,100%,16%)), color-stop(100%,hsl(76,100%,28%)));
	background: -webkit-linear-gradient(top, hsl(75,100%,16%) 0%,hsl(76,100%,28%) 100%);
	background: -o-linear-gradient(top, hsl(75,100%,16%) 0%,hsl(76,100%,28%) 100%);
	background: -ms-linear-gradient(top, hsl(75,100%,16%) 0%,hsl(76,100%,28%) 100%);
	background: linear-gradient(to bottom, hsl(75,100%,16%) 0%,hsl(76,100%,28%) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3f5400', endColorstr='#698f00',GradientType=0 );
}

.history .item.fail {
	background: #7f4e00;
	background: -moz-linear-gradient(top, hsl(37,100%,25%) 0%, hsl(37,100%,43%) 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsl(37,100%,25%)), color-stop(100%,hsl(37,100%,43%)));
	background: -webkit-linear-gradient(top, hsl(37,100%,25%) 0%,hsl(37,100%,43%) 100%);
	background: -o-linear-gradient(top, hsl(37,100%,25%) 0%,hsl(37,100%,43%) 100%);
	background: -ms-linear-gradient(top, hsl(37,100%,25%) 0%,hsl(37,100%,43%) 100%);
	background: linear-gradient(to bottom, hsl(37,100%,25%) 0%,hsl(37,100%,43%) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#7f4e00', endColorstr='#db8700',GradientType=0 );
}

.history .item.panic {
	background: #660000;
	background: -moz-linear-gradient(top, hsl(0,100%,20%) 0%, hsl(0,100%,33%) 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsl(0,100%,20%)), color-stop(100%,hsl(0,100%,33%)));
	background: -webkit-linear-gradient(top, hsl(0,100%,20%) 0%,hsl(0,100%,33%) 100%);
	background: -o-linear-gradient(top, hsl(0,100%,20%) 0%,hsl(0,100%,33%) 100%);
	background: -ms-linear-gradient(top, hsl(0,100%,20%) 0%,hsl(0,100%,33%) 100%);
	background: linear-gradient(to bottom, hsl(0,100%,20%) 0%,hsl(0,100%,33%) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#660000', endColorstr='#a80000',GradientType=0 );
}

.history .item.buildfail {
	background: #282f33;
	background: -moz-linear-gradient(top, hsl(202,12%,18%) 0%, hsl(208,5%,48%) 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsl(202,12%,18%)), color-stop(100%,hsl(208,5%,48%)));
	background: -webkit-linear-gradient(top, hsl(202,12%,18%) 0%,hsl(208,5%,48%) 100%);
	background: -o-linear-gradient(top, hsl(202,12%,18%) 0%,hsl(208,5%,48%) 100%);
	background: -ms-linear-gradient(top, hsl(202,12%,18%) 0%,hsl(208,5%,48%) 100%);
	background: linear-gradient(to bottom, hsl(202,12%,18%) 0%,hsl(208,5%,48%) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#282f33', endColorstr='#757c82',GradientType=0 );
}

.enum {
	border-color: #2B597F;
}

.enum > li {
	border-left-color: #2B597F;
}

.enum > li:hover {
	background: rgba(55, 114, 163, .25);
}

.group {
	background: -moz-linear-gradient(top, rgba(16,59,71,0) 0%, rgba(16,59,71,1) 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(16,59,71,0)), color-stop(100%,rgba(16,59,71,1)));
	background: -webkit-linear-gradient(top, rgba(16,59,71,0) 0%,rgba(16,59,71,1) 100%);
	background: -o-linear-gradient(top, rgba(16,59,71,0) 0%,rgba(16,59,71,1) 100%);
	background: -ms-linear-gradient(top, rgba(16,59,71,0) 0%,rgba(16,59,71,1) 100%);
	background: linear-gradient(to top, rgba(16,59,71,0) 0%,rgba(16,59,71,1) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00103b47', endColorstr='#103b47',GradientType=0 );
}

.stats {
	color: #FFF;
}

.error {
	color: #F58888 !important;
	background: rgba(255, 45, 45, 0.35) !important;
}

.spin-slowly,
.spin-once {
	color: #33B5E5 !important;
}

.frame .col,
footer {
	border-color: #33B5E5;
}

footer {
	background: rgba(0, 0, 0, .5);
}

footer .recording .fa {
	color: #CC0000;
}

footer .replay .fa {
	color: #33B5E5;
}

footer .paused .fa {
	color: #AAA;
}

footer .recording.replay .fa {
	color: #33B5E5;
}



.buildfail-pkg {
	background: rgba(255, 255, 255, .1);
}
.buildfail-output {
	background: rgba(255, 255, 255, .2);
}



.panic-pkg {
	background: rgba(255, 0, 0, .3);
}
.panic-story {
	padding: 10px;
	background: rgba(255, 0, 0, .1);
}
.panic-story a,
.panic-summary {
	color: #E94A4A;
}
.panic-output {
	color: #FF8181;
}



.failure-pkg {
	background: rgba(255, 153, 0, .42);
}
.failure-story {
	padding: 10px;
	background: rgba(255, 153, 0, .1);
}
.failure-story a {
	color: #FFB518;
}
.failure-output {
	color: #FFBD47;
}
.failure-file {
	color: #FFF;
}


.diffviewer td {
	border-color: rgba(0, 0, 0, .3);
}

/* prettyTextDiff expected/deleted colors */
.diffviewer .exp,
.diff del {
	background: rgba(131, 252, 131, 0.22);
}

/* prettyTextDiff actual/inserted colors */
.diffviewer .act,
.diff ins {
	background: rgba(255, 52, 52, 0.33);
}



.story-links a,
.test-name-link a {
	color: inherit;
}



.story-pkg {
	background: rgba(0, 0, 0, .4);
}

.story-pkg:hover {
	background: rgba(255, 255, 255, .05);
}

.story-line + .story-line {
	border-top: 1px dashed rgba(255, 255, 255, .08);
}

.story-line-desc .message {
	color: #999;
}

.story-line-summary-container {
	border-right: 1px dashed #333;
}

.story-line.ok .story-line-status { background: #008000; }
.story-line.ok:hover, .story-line.ok.story-line-sel { background: rgba(0, 128, 0, .1); }

.story-line.fail .story-line-status { background: #EA9C4D; }
.story-line.fail:hover, .story-line.fail.story-line-sel { background: rgba(234, 156, 77, .1); }

.story-line.panic .story-line-status { background: #FF3232; }
.story-line.panic:hover, .story-line.panic.story-line-sel { background: rgba(255, 50, 50, .1); }

.story-line.skip .story-line-status { background: #AAA; }
.story-line.skip:hover, .story-line.skip.story-line-sel { background: rgba(255, 255, 255, .1); }

.statusicon.ok { color: #76C13C; }
.statusicon.fail, .fail-clr { color: #EA9C4D; }
.statusicon.panic, .statusicon.panic .fa, .panic-clr { color: #FF3232; }
.statusicon.skip, .skip-clr { color: #888; }


.log .timestamp {
	color: #999;
}


.clr-red {
	color: #FF2222;
}


.tipsy-inner {
	background-color: #FAFAFA;
	color: #222;
}

.tipsy-arrow {
	border: 8px dashed #FAFAFA;
}

.tipsy-arrow-n,
.tipsy-arrow-s,
.tipsy-arrow-e,
.tipsy-arrow-w,
{
	border-color: #FAFAFA;
}

/***************************************************************/
/*************************** Tweaks ****************************/
/***************************************************************/


/* More space for stories */
div#col-3 { display: none; } /* hides the log */
div#col-2 { width: 85%; }    /* fill it in with stories */

/* Bigger Text */
.story-line       { font-size: 16px; }
.story-line b     { font-size: 20px; }
td.story-pkg-name { font-size: 24px; }

/* Smaller Header */
div.overall      { padding: 10px 0 0px; }
.overall .status { font-size: 36px; }

/***************************************************************/


================================================
FILE: web/client/resources/css/themes/dark.css
================================================
::-webkit-scrollbar {
	width: 10px;
	height: 10px;
}

::-webkit-scrollbar-corner {
	background: transparent;
}

::-webkit-scrollbar-thumb {
	background-color: rgba(255, 255, 255, .35);
	border-radius: 10px;
}

body {
	color: #D0D0D0;
	background: fixed #040607;
	background: fixed -moz-linear-gradient(top, hsl(200,27%,2%) 0%, hsl(203,29%,26%) 100%);
	background: fixed -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsl(200,27%,2%)), color-stop(100%,hsl(203,29%,26%)));
	background: fixed -webkit-linear-gradient(top, hsl(200,27%,2%) 0%,hsl(203,29%,26%) 100%);
	background: fixed -o-linear-gradient(top, hsl(200,27%,2%) 0%,hsl(203,29%,26%) 100%);
	background: fixed -ms-linear-gradient(top, hsl(200,27%,2%) 0%,hsl(203,29%,26%) 100%);
	background: fixed linear-gradient(to bottom, hsl(200,27%,2%) 0%,hsl(203,29%,26%) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#040607', endColorstr='#2f4756',GradientType=0 );
}

a,
.toggle-all-pkg {
	color: #247D9E;
}

a:hover,
.toggle-all-pkg:hover {
	color: #33B5E5;
}

input[type=text] {
	border-bottom-color: #33B5E5;
	color: #BBB;
}

::-webkit-input-placeholder {
	color: #555;
}
:-moz-placeholder {
	color: #555;
}
::-moz-placeholder {
	color: #555;
}
:-ms-input-placeholder {
	color: #555;
}

.overall {
	/*
		Using box-shadow here is not very performant but allows us
		to animate the change of the background color much more easily.
		This box-shadow is an ALTERNATIVE, not supplement, to using gradients
		in this case.
	*/
	box-shadow: inset 0 150px 100px -110px rgba(0, 0, 0, .5);
}

.overall.ok {
	background: #688E00;
}

.overall.fail {
	background: #DB8700;
}

.overall.panic {
	background: #A80000;
}

.overall.buildfail {
	background: #A4A8AA;
}

.overall .status {
	color: #EEE;
}

.server-down {
	background: rgba(255, 45, 45, 0.55);
	color: #FFF;
}

.toggler {
	background: #132535;
}

.toggler:hover {
	background: #1C374F;
}

.controls {
	border-bottom: 1px solid #33B5E5;
}

.controls li {
	color: #2A5A84;
}

.controls li:hover {
	background: #132535;
	color: #33B5E5;
}

.sel {
	background: #33B5E5 !important;
	color: #FFF !important;
}

.pkg-cover-name {
	text-shadow: 1px 1px 0px #000;
}

.pkg-cover-name b, 
.story-pkg-name b {
	color: #FFF;
	font-weight: bold;
}

.pkg-cover:hover,
.pkg-cover:hover b {
	color: #FFF;
}

.expandable {
	border-top-color: #33B5E5;
}

.expandable {
	background: rgba(0, 0, 0, .2);
}

.history .item.ok {
	background: #3f5400;
	background: -moz-linear-gradient(top, hsl(75,100%,16%) 0%, hsl(76,100%,28%) 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsl(75,100%,16%)), color-stop(100%,hsl(76,100%,28%)));
	background: -webkit-linear-gradient(top, hsl(75,100%,16%) 0%,hsl(76,100%,28%) 100%);
	background: -o-linear-gradient(top, hsl(75,100%,16%) 0%,hsl(76,100%,28%) 100%);
	background: -ms-linear-gradient(top, hsl(75,100%,16%) 0%,hsl(76,100%,28%) 100%);
	background: linear-gradient(to bottom, hsl(75,100%,16%) 0%,hsl(76,100%,28%) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3f5400', endColorstr='#698f00',GradientType=0 );
}

.history .item.fail {
	background: #7f4e00;
	background: -moz-linear-gradient(top, hsl(37,100%,25%) 0%, hsl(37,100%,43%) 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsl(37,100%,25%)), color-stop(100%,hsl(37,100%,43%)));
	background: -webkit-linear-gradient(top, hsl(37,100%,25%) 0%,hsl(37,100%,43%) 100%);
	background: -o-linear-gradient(top, hsl(37,100%,25%) 0%,hsl(37,100%,43%) 100%);
	background: -ms-linear-gradient(top, hsl(37,100%,25%) 0%,hsl(37,100%,43%) 100%);
	background: linear-gradient(to bottom, hsl(37,100%,25%) 0%,hsl(37,100%,43%) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#7f4e00', endColorstr='#db8700',GradientType=0 );
}

.history .item.panic {
	background: #660000;
	background: -moz-linear-gradient(top, hsl(0,100%,20%) 0%, hsl(0,100%,33%) 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsl(0,100%,20%)), color-stop(100%,hsl(0,100%,33%)));
	background: -webkit-linear-gradient(top, hsl(0,100%,20%) 0%,hsl(0,100%,33%) 100%);
	background: -o-linear-gradient(top, hsl(0,100%,20%) 0%,hsl(0,100%,33%) 100%);
	background: -ms-linear-gradient(top, hsl(0,100%,20%) 0%,hsl(0,100%,33%) 100%);
	background: linear-gradient(to bottom, hsl(0,100%,20%) 0%,hsl(0,100%,33%) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#660000', endColorstr='#a80000',GradientType=0 );
}

.history .item.buildfail {
	background: #282f33;
	background: -moz-linear-gradient(top, hsl(202,12%,18%) 0%, hsl(208,5%,48%) 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsl(202,12%,18%)), color-stop(100%,hsl(208,5%,48%)));
	background: -webkit-linear-gradient(top, hsl(202,12%,18%) 0%,hsl(208,5%,48%) 100%);
	background: -o-linear-gradient(top, hsl(202,12%,18%) 0%,hsl(208,5%,48%) 100%);
	background: -ms-linear-gradient(top, hsl(202,12%,18%) 0%,hsl(208,5%,48%) 100%);
	background: linear-gradient(to bottom, hsl(202,12%,18%) 0%,hsl(208,5%,48%) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#282f33', endColorstr='#757c82',GradientType=0 );
}

.enum {
	border-color: #2B597F;
}

.enum > li {
	border-left-color: #2B597F;
}

.enum > li:hover {
	background: rgba(55, 114, 163, .25);
}

.group {
	background: -moz-linear-gradient(top, rgba(16,59,71,0) 0%, rgba(16,59,71,1) 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(16,59,71,0)), color-stop(100%,rgba(16,59,71,1)));
	background: -webkit-linear-gradient(top, rgba(16,59,71,0) 0%,rgba(16,59,71,1) 100%);
	background: -o-linear-gradient(top, rgba(16,59,71,0) 0%,rgba(16,59,71,1) 100%);
	background: -ms-linear-gradient(top, rgba(16,59,71,0) 0%,rgba(16,59,71,1) 100%);
	background: linear-gradient(to top, rgba(16,59,71,0) 0%,rgba(16,59,71,1) 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00103b47', endColorstr='#103b47',GradientType=0 );
}

.stats {
	color: #FFF;
}

.error {
	color: #F58888 !important;
	background: rgba(255, 45, 45, 0.35) !important;
}

.spin-slowly,
.spin-once {
	color: #33B5E5 !important;
}

.frame .col,
footer {
	border-color: #33B5E5;
}

footer {
	background: rgba(0, 0, 0, .5);
}

footer .recording .fa {
	color: #CC0000;
}

footer .replay .fa {
	color: #33B5E5;
}

footer .paused .fa {
	color: #AAA;
}

footer .recording.replay .fa {
	color: #33B5E5;
}



.buildfail-pkg {
	background: rgba(255, 255, 255, .1);
}
.buildfail-output {
	background: rgba(255, 255, 255, .2);
}



.panic-pkg {
	background: rgba(255, 0, 0, .3);
}
.panic-story {
	padding: 10px;
	background: rgba(255, 0, 0, .1);
}
.panic-story a,
.panic-summary {
	color: #E94A4A;
}
.panic-output {
	color: #FF8181;
}



.failure-pkg {
	background: rgba(255, 153, 0, .42);
}
.failure-story {
	padding: 10px;
	background: rgba(255, 153, 0, .1);
}
.failure-story a {
	color: #FFB518;
}
.failure-output {
	color: #FFBD47;
}
.failure-file {
	color: #FFF;
}


.diffviewer td {
	border-color: rgba(0, 0, 0, .3);
}

/* prettyTextDiff expected/deleted colors */
.diffviewer .exp,
.diff del {
	background: rgba(131, 252, 131, 0.22);
}

/* prettyTextDiff actual/inserted colors */
.diffviewer .act,
.diff ins {
	background: rgba(255, 52, 52, 0.33);
}



.story-links a,
.test-name-link a {
	color: inherit;
}



.story-pkg {
	background: rgba(0, 0, 0, .4);
}

.story-pkg:hover {
	background: rgba(255, 255, 255, .05);
}

.story-line + .story-line {
	border-top: 1px dashed rgba(255, 255, 255, .08);
}

.story-line-desc .message {
	color: #999;
}

.story-line-summary-container {
	border-right: 1px dashed #333;
}

.story-line.ok .story-line-status { background: #008000; }
.story-line.ok:hover, .story-line.ok.story-line-sel { background: rgba(0, 128, 0, .1); }

.story-line.fail .story-line-status { background: #EA9C4D; }
.story-line.fail:hover, .story-line.fail.story-line-sel { background: rgba(234, 156, 77, .1); }

.story-line.panic .story-line-status { background: #FF3232; }
.story-line.panic:hover, .story-line.panic.story-line-sel { background: rgba(255, 50, 50, .1); }

.story-line.skip .story-line-status { background: #AAA; }
.story-line.skip:hover, .story-line.skip.story-line-sel { background: rgba(255, 255, 255, .1); }

.statusicon.ok { color: #76C13C; }
.statusicon.fail, .fail-clr { color: #EA9C4D; }
.statusicon.panic, .statusicon.panic .fa, .panic-clr { color: #FF3232; }
.statusicon.skip, .skip-clr { color: #888; }

.ansi-green { color: #76C13C; }
.ansi-yellow { color: #EA9C4D; }
.ansi-red { color: #FF3232; }
.ansi-black { color: #000000; }
.ansi-blue { color: #FF3232; }
.ansi-purple { color: #C646C6; }
.ansi-cyan { color: #00CDCD; }
.ansi-white { color: #FFFFFF; }

.log .timestamp {
	color: #999;
}


.clr-red {
	color: #FF2222;
}


.tipsy-inner {
	background-color: #FAFAFA;
	color: #222;
}

.tipsy-arrow {
	border: 8px dashed #FAFAFA;
}

.tipsy-arrow-n,
.tipsy-arrow-s,
.tipsy-arrow-e,
.tipsy-arrow-w,
{
	border-color: #FAFAFA;
}


================================================
FILE: web/client/resources/css/themes/light.css
================================================
::-webkit-scrollbar-thumb {
	background-color: rgba(0, 0, 0, .35);
	border-radius: 10px;
}

::-webkit-input-placeholder {
    color: #CCC;
}
:-moz-placeholder {
	color: #CCC;
}
::-moz-placeholder {
	color: #CCC;
}
:-ms-input-placeholder {
	color: #CCC;
}

body {
	color: #444;
	background: #F4F4F4;
}

a {
	color: #247D9E;
}

a:hover {
	color: #33B5E5;
}

.overall.ok,
.history .item.ok {
	background: #8CB700; /* Can't decide: #5AA02C */
}

.overall.fail,
.history .item.fail {
	background: #E79C07;
}

.overall.panic,
.history .item.panic {
	background: #BB0000;
}

.overall.buildfail,
.history .item.buildfail {
	background: #828c95;
}

.overall .status {
	color: #EEE;
}

.server-down {
	background: #BB0000;
	color: #FFF;
}

.toggler {
	background: #6887A3;
	color: #FFF;
}

.toggler:hover {
	background: #465B6D;
}

.toggler .fa {
	color: #FFF;
}

#logo {
	color: #6887A3;
}

.controls {
	border-bottom: 1px solid #33B5E5;
}

li.fa,
a.fa,
.toggle-all-pkg {
	color: #6887A3;
}

li.fa:hover,
a.fa:hover,
.toggle-all-pkg:hover {
	color: #465B6D;
}

li.fa:active,
a.fa:active,
.toggle-all-pkg:active {
	color: #33B5E5;
}

.controls li,
.enum > li {
	border-left-color: #33B5E5;
}

.controls li:hover,
.enum > li:hover {
	background: #CFE6F9;
}

.enum {
	border-color: #33B5E5;
}

.sel {
	background: #33B5E5 !important;
	color: #FFF !important;
}

.pkg-cover-name b, 
.story-pkg-name b {
	color: #000;
	font-weight: bold;
}

.expandable {
	background: rgba(0, 0, 0, .1);
	border-top-color: #33B5E5;
}

.history .item {
	color: #FFF;
}

.spin-slowly,
.spin-once {
	color: #33B5E5 !important;
}


input[type=text] {
	border-bottom-color: #33B5E5;
	color: #333;
}

.error {
	color: #CC0000 !important;
	background: #FFD2D2 !important;
}


footer {
	background: #F4F4F4;
}

.frame .col,
footer {
	border-color: #33B5E5;
}

footer .recording .fa {
	color: #CC0000;
}

footer .replay .fa {
	color: #33B5E5;
}

footer .paused .fa {
	color: #333;
}


.buildfail-pkg {
	background: #CCC;
}
.buildfail-output {
	background: #EEE;
}



.panic-pkg {
	background: #E94D4D;
	color: #FFF;
}
.panics .panic-details {
	border: 5px solid #E94D4D;
	border-top: 0;
	border-bottom: 0;
}
.panic-details {
	color: #CC0000;
}
.panics .panic:last-child .panic-details {
	border-bottom: 5px solid #E94D4D;
}
.panic-story {
	padding: 10px;
}
.panics .panic-output {
	background: #FFF;
}




.failure-pkg {
	background: #FFA300;
	color: #FFF;
}
.failures .failure-details {
	border: 5px solid #FFA300;
	border-top: 0;
	border-bottom: 0;
}
.failures .failure:last-child .failure-details {
	border-bottom: 5px solid #FFA300;
}
.failure-story {
	padding: 10px;
	color: #A87A00;
}
.stories .failure-output {
	color: #EA9C4D;
}
.failures .failure-output {
	background: #FFF;
}
.failure-file {
	color: #000;
}

.diffviewer td {
	border-color: #CCC;
	background: #FFF;
}

/* prettyTextDiff expected/deleted colors */
.diffviewer .exp,
.diff del {
	background: #ADFFAD;
}

/* prettyTextDiff actual/inserted colors */
.diffviewer .act,
.diff ins {
	background: #FFC0C0;
}



.story-links a,
.test-name-link a {
	color: inherit;
}



.story-pkg {
	background: #E8E8E8;
}

.story-pkg:hover {
	background: #DFDFDF;
}

.story-line {
	background: #FFF;
}

.story-line-desc .message {
	color: #888;
}

.story-line + .story-line {
	border-top: 1px dashed #DDD;
}

.story-line-summary-container {
	border-right: 1px dashed #DDD;
}

.story-line.ok .story-line-status { background: #8CB700; }
.story-line.ok:hover, .story-line.ok.story-line-sel { background: #F4FFD8; }

.story-line.fail .story-line-status { background: #E79C07; }
.story-line.fail:hover, .story-line.fail.story-line-sel { background: #FFF1DB; }

.story-line.panic .story-line-status { background: #DD0606; }
.story-line.panic:hover, .story-line.panic.story-line-sel { background: #FFE8E8; }

.story-line.skip .story-line-status { background: #4E4E4E; }
.story-line.skip:hover, .story-line.skip.story-line-sel { background: #F2F2F2; }

.statusicon.ok { color: #76C13C; }
.statusicon.fail, .fail-clr { color: #EA9C4D; }
.statusicon.panic, .statusicon.panic .fa, .panic-clr { color: #FF3232; }
.statusicon.skip, .skip-clr { color: #AAA; }

.ansi-green { color: #76C13C; }
.ansi-yellow   { color: #EA9C4D; }

.log .timestamp {
	color: #999;
}

.clr-red,
a.clr-red {
	color: #CC0000;
}


.tipsy-inner {
	background-color: #000;
	color: #FFF;
}

.tipsy-arrow {
	border: 8px dashed #000;
}

.tipsy-arrow-n,
.tipsy-arrow-s,
.tipsy-arrow-e,
.tipsy-arrow-w,
{
	border-color: #000;
}


================================================
FILE: web/client/resources/css/tipsy.css
================================================
.tipsy {
	font-size: 12px;
	position: absolute;
	padding: 8px;
	z-index: 100000;
	font-family: 'Open Sans';
	line-height: 1.25em;
}

.tipsy-inner {
	max-width: 200px;
	padding: 5px 7px;
	text-align: center;
}

/* Rounded corners */
/*.tipsy-inner { border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; }*/

/* Shadow */
/*.tipsy-inner { box-shadow: 0 0 5px #000000; -webkit-box-shadow: 0 0 5px #000000; -moz-box-shadow: 0 0 5px #000000; }*/

.tipsy-arrow {
	position: absolute;
	width: 0;
	height: 0;
	line-height: 0;
}

.tipsy-n .tipsy-arrow,
.tipsy-nw .tipsy-arrow,
.tipsy-ne .tipsy-arrow {
	border-bottom-style: solid;
	border-top: none;
	border-left-color: transparent;
	border-right-color: transparent;
}


.tipsy-n .tipsy-arrow {
	top: 0px;
	left: 50%;
	margin-left: -7px;
}
.tipsy-nw .tipsy-arrow {
	top: 0;
	left: 10px;
}
.tipsy-ne .tipsy-arrow {
	top: 0;
	right: 10px;
}

.tipsy-s .tipsy-arrow,
.tipsy-sw .tipsy-arrow,
.tipsy-se .tipsy-arrow {
	border-top-style: solid;
	border-bottom: none;
	border-left-color: transparent;
	border-right-color: transparent;
}
	

.tipsy-s .tipsy-arrow {
	bottom: 0;
	left: 50%;
	margin-left: -7px;
}

.tipsy-sw .tipsy-arrow {
	bottom: 0;
	left: 10px;
}

.tipsy-se .tipsy-arrow {
	bottom: 0;
	right: 10px;
}

.tipsy-e .tipsy-arrow {
	right: 0;
	top: 50%;
	margin-top: -7px;
	border-left-style: solid;
	border-right: none;
	border-top-color: transparent;
	border-bottom-color: transparent;
}

.tipsy-w .tipsy-arrow {
	left: 0;
	top: 50%;
	margin-top: -7px;
	border-right-style: solid;
	border-left: none;
	border-top-color: transparent;
	border-bottom-color: transparent;
}

================================================
FILE: web/client/resources/fonts/FontAwesome/README.md
================================================
#[Font Awesome v4.5.0](http://fontawesome.io)
###The iconic font and CSS framework

Font Awesome is a full suite of 605 pictographic icons for easy scalable vector graphics on websites,
created and maintained by [Dave Gandy](http://twitter.com/davegandy).
Stay up to date with the latest release and announcements on Twitter:
[@fontawesome](http://twitter.com/fontawesome).

Get started at http://fontawesome.io!

##License
- The Font Awesome font is licensed under the SIL OFL 1.1:
  - http://scripts.sil.org/OFL
- Font Awesome CSS, LESS, and Sass files are licensed under the MIT License:
  - http://opensource.org/licenses/mit-license.html
- The Font Awesome documentation is licensed under the CC BY 3.0 License:
  - http://creativecommons.org/licenses/by/3.0/
- Attribution is no longer required as of Font Awesome 3.0, but much appreciated:
  - `Font Awesome by Dave Gandy - http://fontawesome.io`
- Full details: http://fontawesome.io/license

##Changelog
- [v4.5.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?q=milestone%3A4.5.0+is%3Aclosed)
- [v4.4.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?q=milestone%3A4.4.0+is%3Aclosed)
- [v4.3.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?q=milestone%3A4.3.0+is%3Aclosed)
- [v4.2.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=12&page=1&state=closed)
- [v4.1.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=6&page=1&state=closed)
- [v4.0.3 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=9&page=1&state=closed)
- [v4.0.2 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=8&page=1&state=closed)
- [v4.0.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=7&page=1&state=closed)
- [v4.0.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=2&page=1&state=closed)
- [v3.2.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=5&page=1&state=closed)
- [v3.2.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=3&page=1&state=closed)
- [v3.1.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=4&page=1&state=closed)
- v3.1.0 - Added 54 icons, icon stacking styles, flipping and rotating icons, removed Sass support
- v3.0.2 - much improved rendering and alignment in IE7
- v3.0.1 - much improved rendering in webkit, various bug fixes
- v3.0.0 - all icons redesigned from scratch, optimized for Bootstrap's 14px default

## Contributing

Please read through our [contributing guidelines](https://github.com/FortAwesome/Font-Awesome/blob/master/CONTRIBUTING.md).
Included are directions for opening issues, coding standards, and notes on development.

##Versioning

Font Awesome will be maintained under the Semantic Versioning guidelines as much as possible. Releases will be numbered
with the following format:

`<major>.<minor>.<patch>`

And constructed with the following guidelines:

* Breaking backward compatibility bumps the major (and resets the minor and patch)
* New additions, including new icons, without breaking backward compatibility bumps the minor (and resets the patch)
* Bug fixes and misc changes bumps the patch

For more information on SemVer, please visit http://semver.org.

##Author
- Email: dave@fontawesome.io
- Twitter: http://twitter.com/davegandy
- GitHub: https://github.com/davegandy

##Component
To include as a [component](http://github.com/component/component), just run

    $ component install FortAwesome/Font-Awesome

Or add

    "FortAwesome/Font-Awesome": "*"

to the `dependencies` in your `component.json`.

## Hacking on Font Awesome

**Before you can build the project**, you must first have the following installed:

- [Ruby](https://www.ruby-lang.org/en/)
- Ruby Development Headers
  - **Ubuntu:** `sudo apt-get install ruby-dev` *(Only if you're __NOT__ using `rbenv` or `rvm`)*
  - **Windows:** [DevKit](http://rubyinstaller.org/)
- [Bundler](http://bundler.io/) (Run `gem install bundler` to install).
- [Node Package Manager (AKA NPM)](https://docs.npmjs.com/getting-started/installing-node)
- [Less](http://lesscss.org/) (Run `npm install -g less` to install).
- [Less Plugin: Clean CSS](https://github.com/less/less-plugin-clean-css) (Run `npm install -g less-plugin-clean-css` to install).

From the root of the repository, install the tools used to develop.

    $ bundle install
    $ npm install

Build the project and documentation:

    $ bundle exec jekyll build

Or serve it on a local server on http://localhost:7998/Font-Awesome/:

    $ bundle exec jekyll -w serve


================================================
FILE: web/client/resources/fonts/FontAwesome/css/font-awesome.css
================================================
/*!
 *  Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome
 *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
 */
/* FONT PATH
 * -------------------------- */
@font-face {
  font-family: 'FontAwesome';
  src: url('../fonts/fontawesome-webfont.eot?v=4.5.0');
  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');
  font-weight: normal;
  font-style: normal;
}
.fa {
  display: inline-block;
  font: normal normal normal 14px/1 FontAwesome;
  font-size: inherit;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
/* makes the font 33% larger relative to the icon container */
.fa-lg {
  font-size: 1.33333333em;
  line-height: 0.75em;
  vertical-align: -15%;
}
.fa-2x {
  font-size: 2em;
}
.fa-3x {
  font-size: 3em;
}
.fa-4x {
  font-size: 4em;
}
.fa-5x {
  font-size: 5em;
}
.fa-fw {
  width: 1.28571429em;
  text-align: center;
}
.fa-ul {
  padding-left: 0;
  margin-left: 2.14285714em;
  list-style-type: none;
}
.fa-ul > li {
  position: relative;
}
.fa-li {
  position: absolute;
  left: -2.14285714em;
  width: 2.14285714em;
  top: 0.14285714em;
  text-align: center;
}
.fa-li.fa-lg {
  left: -1.85714286em;
}
.fa-border {
  padding: .2em .25em .15em;
  border: solid 0.08em #eeeeee;
  border-radius: .1em;
}
.fa-pull-left {
  float: left;
}
.fa-pull-right {
  float: right;
}
.fa.fa-pull-left {
  margin-right: .3em;
}
.fa.fa-pull-right {
  margin-left: .3em;
}
/* Deprecated as of 4.4.0 */
.pull-right {
  float: right;
}
.pull-left {
  float: left;
}
.fa.pull-left {
  margin-right: .3em;
}
.fa.pull-right {
  margin-left: .3em;
}
.fa-spin {
  -webkit-animation: fa-spin 2s infinite linear;
  animation: fa-spin 2s infinite linear;
}
.fa-pulse {
  -webkit-animation: fa-spin 1s infinite steps(8);
  animation: fa-spin 1s infinite steps(8);
}
@-webkit-keyframes fa-spin {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(359deg);
    transform: rotate(359deg);
  }
}
@keyframes fa-spin {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(359deg);
    transform: rotate(359deg);
  }
}
.fa-rotate-90 {
  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
  -webkit-transform: rotate(90deg);
  -ms-transform: rotate(90deg);
  transform: rotate(90deg);
}
.fa-rotate-180 {
  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
  -webkit-transform: rotate(180deg);
  -ms-transform: rotate(180deg);
  transform: rotate(180deg);
}
.fa-rotate-270 {
  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
  -webkit-transform: rotate(270deg);
  -ms-transform: rotate(270deg);
  transform: rotate(270deg);
}
.fa-flip-horizontal {
  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);
  -webkit-transform: scale(-1, 1);
  -ms-transform: scale(-1, 1);
  transform: scale(-1, 1);
}
.fa-flip-vertical {
  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);
  -webkit-transform: scale(1, -1);
  -ms-transform: scale(1, -1);
  transform: scale(1, -1);
}
:root .fa-rotate-90,
:root .fa-rotate-180,
:root .fa-rotate-270,
:root .fa-flip-horizontal,
:root .fa-flip-vertical {
  filter: none;
}
.fa-stack {
  position: relative;
  display: inline-block;
  width: 2em;
  height: 2em;
  line-height: 2em;
  vertical-align: middle;
}
.fa-stack-1x,
.fa-stack-2x {
  position: absolute;
  left: 0;
  width: 100%;
  text-align: center;
}
.fa-stack-1x {
  line-height: inherit;
}
.fa-stack-2x {
  font-size: 2em;
}
.fa-inverse {
  color: #ffffff;
}
/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
   readers do not read off random characters that represent icons */
.fa-glass:before {
  content: "\f000";
}
.fa-music:before {
  content: "\f001";
}
.fa-search:before {
  content: "\f002";
}
.fa-envelope-o:before {
  content: "\f003";
}
.fa-heart:before {
  content: "\f004";
}
.fa-star:before {
  content: "\f005";
}
.fa-star-o:before {
  content: "\f006";
}
.fa-user:before {
  content: "\f007";
}
.fa-film:before {
  content: "\f008";
}
.fa-th-large:before {
  content: "\f009";
}
.fa-th:before {
  content: "\f00a";
}
.fa-th-list:before {
  content: "\f00b";
}
.fa-check:before {
  content: "\f00c";
}
.fa-remove:before,
.fa-close:before,
.fa-times:before {
  content: "\f00d";
}
.fa-search-plus:before {
  content: "\f00e";
}
.fa-search-minus:before {
  content: "\f010";
}
.fa-power-off:before {
  content: "\f011";
}
.fa-signal:before {
  content: "\f012";
}
.fa-gear:before,
.fa-cog:before {
  content: "\f013";
}
.fa-trash-o:before {
  content: "\f014";
}
.fa-home:before {
  content: "\f015";
}
.fa-file-o:before {
  content: "\f016";
}
.fa-clock-o:before {
  content: "\f017";
}
.fa-road:before {
  content: "\f018";
}
.fa-download:before {
  content: "\f019";
}
.fa-arrow-circle-o-down:before {
  content: "\f01a";
}
.fa-arrow-circle-o-up:before {
  content: "\f01b";
}
.fa-inbox:before {
  content: "\f01c";
}
.fa-play-circle-o:before {
  content: "\f01d";
}
.fa-rotate-right:before,
.fa-repeat:before {
  content: "\f01e";
}
.fa-refresh:before {
  content: "\f021";
}
.fa-list-alt:before {
  content: "\f022";
}
.fa-lock:before {
  content: "\f023";
}
.fa-flag:before {
  content: "\f024";
}
.fa-headphones:before {
  content: "\f025";
}
.fa-volume-off:before {
  content: "\f026";
}
.fa-volume-down:before {
  content: "\f027";
}
.fa-volume-up:before {
  content: "\f028";
}
.fa-qrcode:before {
  content: "\f029";
}
.fa-barcode:before {
  content: "\f02a";
}
.fa-tag:before {
  content: "\f02b";
}
.fa-tags:before {
  content: "\f02c";
}
.fa-book:before {
  content: "\f02d";
}
.fa-bookmark:before {
  content: "\f02e";
}
.fa-print:before {
  content: "\f02f";
}
.fa-camera:before {
  content: "\f030";
}
.fa-font:before {
  content: "\f031";
}
.fa-bold:before {
  content: "\f032";
}
.fa-italic:before {
  content: "\f033";
}
.fa-text-height:before {
  content: "\f034";
}
.fa-text-width:before {
  content: "\f035";
}
.fa-align-left:before {
  content: "\f036";
}
.fa-align-center:before {
  content: "\f037";
}
.fa-align-right:before {
  content: "\f038";
}
.fa-align-justify:before {
  content: "\f039";
}
.fa-list:before {
  content: "\f03a";
}
.fa-dedent:before,
.fa-outdent:before {
  content: "\f03b";
}
.fa-indent:before {
  content: "\f03c";
}
.fa-video-camera:before {
  content: "\f03d";
}
.fa-photo:before,
.fa-image:before,
.fa-picture-o:before {
  content: "\f03e";
}
.fa-pencil:before {
  content: "\f040";
}
.fa-map-marker:before {
  content: "\f041";
}
.fa-adjust:before {
  content: "\f042";
}
.fa-tint:before {
  content: "\f043";
}
.fa-edit:before,
.fa-pencil-square-o:before {
  content: "\f044";
}
.fa-share-square-o:before {
  content: "\f045";
}
.fa-check-square-o:before {
  content: "\f046";
}
.fa-arrows:before {
  content: "\f047";
}
.fa-step-backward:before {
  content: "\f048";
}
.fa-fast-backward:before {
  content: "\f049";
}
.fa-backward:before {
  content: "\f04a";
}
.fa-play:before {
  content: "\f04b";
}
.fa-pause:before {
  content: "\f04c";
}
.fa-stop:before {
  content: "\f04d";
}
.fa-forward:before {
  content: "\f04e";
}
.fa-fast-forward:before {
  content: "\f050";
}
.fa-step-forward:before {
  content: "\f051";
}
.fa-eject:before {
  content: "\f052";
}
.fa-chevron-left:before {
  content: "\f053";
}
.fa-chevron-right:before {
  content: "\f054";
}
.fa-plus-circle:before {
  content: "\f055";
}
.fa-minus-circle:before {
  content: "\f056";
}
.fa-times-circle:before {
  content: "\f057";
}
.fa-check-circle:before {
  content: "\f058";
}
.fa-question-circle:before {
  content: "\f059";
}
.fa-info-circle:before {
  content: "\f05a";
}
.fa-crosshairs:before {
  content: "\f05b";
}
.fa-times-circle-o:before {
  content: "\f05c";
}
.fa-check-circle-o:before {
  content: "\f05d";
}
.fa-ban:before {
  content: "\f05e";
}
.fa-arrow-left:before {
  content: "\f060";
}
.fa-arrow-right:before {
  content: "\f061";
}
.fa-arrow-up:before {
  content: "\f062";
}
.fa-arrow-down:before {
  content: "\f063";
}
.fa-mail-forward:before,
.fa-share:before {
  content: "\f064";
}
.fa-expand:before {
  content: "\f065";
}
.fa-compress:before {
  content: "\f066";
}
.fa-plus:before {
  content: "\f067";
}
.fa-minus:before {
  content: "\f068";
}
.fa-asterisk:before {
  content: "\f069";
}
.fa-exclamation-circle:before {
  content: "\f06a";
}
.fa-gift:before {
  content: "\f06b";
}
.fa-leaf:before {
  content: "\f06c";
}
.fa-fire:before {
  content: "\f06d";
}
.fa-eye:before {
  content: "\f06e";
}
.fa-eye-slash:before {
  content: "\f070";
}
.fa-warning:before,
.fa-exclamation-triangle:before {
  content: "\f071";
}
.fa-plane:before {
  content: "\f072";
}
.fa-calendar:before {
  content: "\f073";
}
.fa-random:before {
  content: "\f074";
}
.fa-comment:before {
  content: "\f075";
}
.fa-magnet:before {
  content: "\f076";
}
.fa-chevron-up:before {
  content: "\f077";
}
.fa-chevron-down:before {
  content: "\f078";
}
.fa-retweet:before {
  content: "\f079";
}
.fa-shopping-cart:before {
  content: "\f07a";
}
.fa-folder:before {
  content: "\f07b";
}
.fa-folder-open:before {
  content: "\f07c";
}
.fa-arrows-v:before {
  content: "\f07d";
}
.fa-arrows-h:before {
  content: "\f07e";
}
.fa-bar-chart-o:before,
.fa-bar-chart:before {
  content: "\f080";
}
.fa-twitter-square:before {
  content: "\f081";
}
.fa-facebook-square:before {
  content: "\f082";
}
.fa-camera-retro:before {
  content: "\f083";
}
.fa-key:before {
  content: "\f084";
}
.fa-gears:before,
.fa-cogs:before {
  content: "\f085";
}
.fa-comments:before {
  content: "\f086";
}
.fa-thumbs-o-up:before {
  content: "\f087";
}
.fa-thumbs-o-down:before {
  content: "\f088";
}
.fa-star-half:before {
  content: "\f089";
}
.fa-heart-o:before {
  content: "\f08a";
}
.fa-sign-out:before {
  content: "\f08b";
}
.fa-linkedin-square:before {
  content: "\f08c";
}
.fa-thumb-tack:before {
  content: "\f08d";
}
.fa-external-link:before {
  content: "\f08e";
}
.fa-sign-in:before {
  content: "\f090";
}
.fa-trophy:before {
  content: "\f091";
}
.fa-github-square:before {
  content: "\f092";
}
.fa-upload:before {
  content: "\f093";
}
.fa-lemon-o:before {
  content: "\f094";
}
.fa-phone:before {
  content: "\f095";
}
.fa-square-o:before {
  content: "\f096";
}
.fa-bookmark-o:before {
  content: "\f097";
}
.fa-phone-square:before {
  content: "\f098";
}
.fa-twitter:before {
  content: "\f099";
}
.fa-facebook-f:before,
.fa-facebook:before {
  content: "\f09a";
}
.fa-github:before {
  content: "\f09b";
}
.fa-unlock:before {
  content: "\f09c";
}
.fa-credit-card:before {
  content: "\f09d";
}
.fa-feed:before,
.fa-rss:before {
  content: "\f09e";
}
.fa-hdd-o:before {
  content: "\f0a0";
}
.fa-bullhorn:before {
  content: "\f0a1";
}
.fa-bell:before {
  content: "\f0f3";
}
.fa-certificate:before {
  content: "\f0a3";
}
.fa-hand-o-right:before {
  content: "\f0a4";
}
.fa-hand-o-left:before {
  content: "\f0a5";
}
.fa-hand-o-up:before {
  content: "\f0a6";
}
.fa-hand-o-down:before {
  content: "\f0a7";
}
.fa-arrow-circle-left:before {
  content: "\f0a8";
}
.fa-arrow-circle-right:before {
  content: "
Download .txt
gitextract_udu2kvxk/

├── .gitattributes
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── check_third_party.sh
├── convey/
│   ├── assertions.go
│   ├── context.go
│   ├── convey.goconvey
│   ├── discovery.go
│   ├── doc.go
│   ├── focused_execution_test.go
│   ├── gotest/
│   │   ├── doc_test.go
│   │   └── utils.go
│   ├── init.go
│   ├── isolated_execution_test.go
│   ├── nilReporter.go
│   ├── reporting/
│   │   ├── console.go
│   │   ├── doc.go
│   │   ├── dot.go
│   │   ├── dot_test.go
│   │   ├── gotest.go
│   │   ├── gotest_test.go
│   │   ├── init.go
│   │   ├── json.go
│   │   ├── printer.go
│   │   ├── printer_test.go
│   │   ├── problems.go
│   │   ├── problems_test.go
│   │   ├── reporter.go
│   │   ├── reporter_test.go
│   │   ├── reporting.goconvey
│   │   ├── reports.go
│   │   ├── statistics.go
│   │   └── story.go
│   ├── reporting_hooks_test.go
│   ├── stack_trace_test.go
│   ├── story_conventions_test.go
│   └── update_assertions.sh
├── examples/
│   ├── assertion_examples_test.go
│   ├── bowling_game.go
│   ├── bowling_game_test.go
│   ├── doc.go
│   ├── examples.goconvey
│   └── simple_example_test.go
├── go.mod
├── go.sum
├── goconvey.go
└── web/
    ├── client/
    │   ├── composer.html
    │   ├── index.html
    │   └── resources/
    │       ├── css/
    │       │   ├── common.css
    │       │   ├── composer.css
    │       │   ├── themes/
    │       │   │   ├── dark-bigtext.css
    │       │   │   ├── dark.css
    │       │   │   └── light.css
    │       │   └── tipsy.css
    │       ├── fonts/
    │       │   ├── FontAwesome/
    │       │   │   ├── README.md
    │       │   │   ├── css/
    │       │   │   │   └── font-awesome.css
    │       │   │   └── fonts/
    │       │   │       └── FontAwesome.otf
    │       │   ├── Open_Sans/
    │       │   │   └── LICENSE.txt
    │       │   ├── Orbitron/
    │       │   │   └── OFL.txt
    │       │   └── Oswald/
    │       │       └── OFL.txt
    │       └── js/
    │           ├── composer.js
    │           ├── config.js
    │           ├── convey.js
    │           ├── goconvey.js
    │           ├── lib/
    │           │   ├── ansispan.js
    │           │   ├── diff_match_patch.js
    │           │   ├── jquery-ui.js
    │           │   ├── jquery-ui.js.url
    │           │   ├── jquery.js
    │           │   ├── jquery.js.url
    │           │   ├── jquery.pretty-text-diff.js
    │           │   ├── jquery.pretty-text-diff.js.url
    │           │   ├── jquery.tipsy.js
    │           │   ├── jquery.tipsy.js.url
    │           │   ├── markup.js
    │           │   ├── markup.js.url
    │           │   ├── moment.js
    │           │   ├── moment.js.url
    │           │   ├── taboverride.js
    │           │   ├── taboverride.js.url
    │           │   └── update.sh
    │           └── poller.js
    └── server/
        ├── api/
        │   ├── api.goconvey
        │   ├── server.go
        │   └── server_test.go
        ├── contract/
        │   ├── contracts.go
        │   ├── doc_test.go
        │   └── result.go
        ├── executor/
        │   ├── contract.go
        │   ├── coordinator.go
        │   ├── executor.go
        │   ├── executor.goconvey
        │   ├── executor_test.go
        │   ├── tester.go
        │   └── tester_test.go
        ├── messaging/
        │   ├── doc_test.go
        │   └── messages.go
        ├── parser/
        │   ├── packageParser.go
        │   ├── package_parser_test.go
        │   ├── parser.go
        │   ├── parser.goconvey
        │   ├── parser_test.go
        │   ├── rules.go
        │   ├── testParser.go
        │   └── util.go
        ├── system/
        │   ├── shell.go
        │   ├── shell_integration_test.go
        │   ├── shell_test.go
        │   └── system.goconvey
        └── watch/
            ├── functional_core.go
            ├── functional_core_test.go
            ├── imperative_shell.go
            ├── integration.go
            ├── integration_test.go
            ├── integration_testing/
            │   ├── doc_test.go
            │   ├── main.go
            │   └── sub/
            │       ├── .gitignore
            │       ├── stuff.go
            │       ├── stuff_test.go
            │       └── sub.goconvey
            ├── util_test.go
            └── watch.goconvey
Download .txt
SYMBOL INDEX (1036 symbols across 70 files)

FILE: convey/context.go
  type conveyErr (line 10) | type conveyErr struct
    method Error (line 15) | func (e *conveyErr) Error() string {
  function conveyPanic (line 19) | func conveyPanic(fmt string, params ...any) {
  constant missingGoTest (line 24) | missingGoTest = `Top-level calls to Convey(...) need a reference to the ...
  constant extraGoTest (line 26) | extraGoTest    = `Only the top-level call to Convey(...) needs a referen...
  constant noStackContext (line 27) | noStackContext = "Convey operation made without context on goroutine sta...
  constant differentConveySituations (line 29) | differentConveySituations = "Different set of Convey statements on subse...
  constant multipleIdenticalConvey (line 30) | multipleIdenticalConvey   = "Multiple convey suites with identical names...
  constant failureHalt (line 34) | failureHalt = "___FAILURE_HALT___"
  constant nodeKey (line 36) | nodeKey = "node"
  function getCurrentContext (line 41) | func getCurrentContext() *context {
  function mustGetCurrentContext (line 49) | func mustGetCurrentContext() *context {
  type context (line 69) | type context struct
    method SkipConvey (line 120) | func (ctx *context) SkipConvey(items ...any) {
    method FocusConvey (line 124) | func (ctx *context) FocusConvey(items ...any) {
    method Convey (line 128) | func (ctx *context) Convey(items ...any) {
    method SkipSo (line 171) | func (ctx *context) SkipSo(stuff ...any) {
    method So (line 175) | func (ctx *context) So(actual any, assert Assertion, expected ...any) {
    method SoMsg (line 183) | func (ctx *context) SoMsg(msg string, actual any, assert Assertion, ex...
    method Reset (line 194) | func (ctx *context) Reset(action func()) {
    method Print (line 199) | func (ctx *context) Print(items ...any) (int, error) {
    method Println (line 204) | func (ctx *context) Println(items ...any) (int, error) {
    method Printf (line 209) | func (ctx *context) Printf(format string, items ...any) (int, error) {
    method shouldVisit (line 219) | func (c *context) shouldVisit() bool {
    method shouldShowStack (line 223) | func (c *context) shouldShowStack() bool {
    method conveyInner (line 230) | func (ctx *context) conveyInner(situation string, f func(C)) {
    method assertionReport (line 285) | func (ctx *context) assertionReport(r *reporting.AssertionResult) {
  function rootConvey (line 88) | func rootConvey(items ...any) {

FILE: convey/discovery.go
  type actionSpecifier (line 3) | type actionSpecifier
  constant noSpecifier (line 6) | noSpecifier actionSpecifier = iota
  constant skipConvey (line 7) | skipConvey
  constant focusConvey (line 8) | focusConvey
  type suite (line 11) | type suite struct
  function newSuite (line 20) | func newSuite(situation string, failureMode FailureMode, stackMode Stack...
  function discover (line 37) | func discover(items []any) *suite {
  function item (line 51) | func item(items []any) any {
  function parseName (line 57) | func parseName(items []any) (string, []any) {
  function parseGoTest (line 64) | func parseGoTest(items []any) (t, []any) {
  function parseFailureMode (line 70) | func parseFailureMode(items []any) (FailureMode, []any) {
  function parseStackMode (line 76) | func parseStackMode(items []any) (StackMode, []any) {
  function parseAction (line 82) | func parseAction(items []any) (func(C), []any) {
  function parseSpecifier (line 94) | func parseSpecifier(items []any) (actionSpecifier, []any) {
  type t (line 108) | type t interface
  constant parseError (line 112) | parseError = "You must provide a name (string), then a *testing.T (if in...

FILE: convey/doc.go
  type C (line 21) | type C interface
  function Convey (line 74) | func Convey(items ...any) {
  function SkipConvey (line 85) | func SkipConvey(items ...any) {
  function FocusConvey (line 96) | func FocusConvey(items ...any) {
  function Reset (line 102) | func Reset(action func()) {
  type Assertion (line 112) | type Assertion
  constant assertionSuccess (line 114) | assertionSuccess = ""
  function So (line 125) | func So(actual any, assert Assertion, expected ...any) {
  function SoMsg (line 130) | func SoMsg(msg string, actual any, assert Assertion, expected ...any) {
  function SkipSo (line 136) | func SkipSo(stuff ...any) {
  type FailureMode (line 142) | type FailureMode
    method combine (line 179) | func (f FailureMode) combine(other FailureMode) FailureMode {
  type StackMode (line 146) | type StackMode
    method combine (line 200) | func (s StackMode) combine(other StackMode) StackMode {
  constant FailureContinues (line 153) | FailureContinues FailureMode = "continue"
  constant FailureHalts (line 158) | FailureHalts FailureMode = "halt"
  constant FailureInherits (line 163) | FailureInherits FailureMode = "inherits"
  constant StackError (line 167) | StackError StackMode = "error"
  constant StackFail (line 171) | StackFail StackMode = "fail"
  constant StackInherits (line 176) | StackInherits StackMode = "inherits"
  function SetDefaultFailureMode (line 192) | func SetDefaultFailureMode(mode FailureMode) {
  function SetDefaultStackMode (line 213) | func SetDefaultStackMode(mode StackMode) {
  function Print (line 225) | func Print(items ...any) (written int, err error) {
  function Println (line 231) | func Println(items ...any) (written int, err error) {
  function Printf (line 237) | func Printf(format string, items ...any) (written int, err error) {
  function SuppressConsoleStatistics (line 245) | func SuppressConsoleStatistics() {
  function PrintConsoleStatistics (line 260) | func PrintConsoleStatistics() {

FILE: convey/focused_execution_test.go
  function TestFocusOnlyAtTopLevel (line 5) | func TestFocusOnlyAtTopLevel(t *testing.T) {
  function TestFocus (line 15) | func TestFocus(t *testing.T) {
  function TestNestedFocus (line 29) | func TestNestedFocus(t *testing.T) {
  function TestForgotTopLevelFocus (line 56) | func TestForgotTopLevelFocus(t *testing.T) {

FILE: convey/gotest/utils.go
  function ResolveExternalCaller (line 11) | func ResolveExternalCaller() (file string, line int, name string) {
  constant maxStackDepth (line 26) | maxStackDepth = 100

FILE: convey/init.go
  function init (line 12) | func init() {
  function declareFlags (line 20) | func declareFlags() {
  function noStoryFlagProvided (line 32) | func noStoryFlagProvided() bool {
  function buildReporter (line 36) | func buildReporter() reporting.Reporter {
  function flagFound (line 74) | func flagFound(flagValue string) bool {

FILE: convey/isolated_execution_test.go
  function TestSingleScope (line 9) | func TestSingleScope(t *testing.T) {
  function TestSingleScopeWithMultipleConveys (line 19) | func TestSingleScopeWithMultipleConveys(t *testing.T) {
  function TestNestedScopes (line 33) | func TestNestedScopes(t *testing.T) {
  function TestNestedScopesWithIsolatedExecution (line 51) | func TestNestedScopesWithIsolatedExecution(t *testing.T) {
  function TestSingleScopeWithConveyAndNestedReset (line 81) | func TestSingleScopeWithConveyAndNestedReset(t *testing.T) {
  function TestPanicingReset (line 95) | func TestPanicingReset(t *testing.T) {
  function TestSingleScopeWithMultipleRegistrationsAndReset (line 117) | func TestSingleScopeWithMultipleRegistrationsAndReset(t *testing.T) {
  function TestSingleScopeWithMultipleRegistrationsAndMultipleResets (line 137) | func TestSingleScopeWithMultipleRegistrationsAndMultipleResets(t *testin...
  function Test_Failure_AtHigherLevelScopePreventsChildScopesFromRunning (line 161) | func Test_Failure_AtHigherLevelScopePreventsChildScopesFromRunning(t *te...
  function Test_Panic_AtHigherLevelScopePreventsChildScopesFromRunning (line 175) | func Test_Panic_AtHigherLevelScopePreventsChildScopesFromRunning(t *test...
  function Test_Panic_InChildScopeDoes_NOT_PreventExecutionOfSiblingScopes (line 199) | func Test_Panic_InChildScopeDoes_NOT_PreventExecutionOfSiblingScopes(t *...
  function Test_Failure_InChildScopeDoes_NOT_PreventExecutionOfSiblingScopes (line 216) | func Test_Failure_InChildScopeDoes_NOT_PreventExecutionOfSiblingScopes(t...
  function TestResetsAreAlwaysExecutedAfterScope_Panics (line 233) | func TestResetsAreAlwaysExecutedAfterScope_Panics(t *testing.T) {
  function TestResetsAreAlwaysExecutedAfterScope_Failures (line 258) | func TestResetsAreAlwaysExecutedAfterScope_Failures(t *testing.T) {
  function TestSkipTopLevel (line 283) | func TestSkipTopLevel(t *testing.T) {
  function TestSkipNestedLevel (line 293) | func TestSkipNestedLevel(t *testing.T) {
  function TestSkipNestedLevelSkipsAllChildLevels (line 307) | func TestSkipNestedLevelSkipsAllChildLevels(t *testing.T) {
  function TestIterativeConveys (line 325) | func TestIterativeConveys(t *testing.T) {
  function TestClosureVariables (line 341) | func TestClosureVariables(t *testing.T) {
  function TestClosureVariablesWithReset (line 377) | func TestClosureVariablesWithReset(t *testing.T) {
  function TestWrappedSimple (line 406) | func TestWrappedSimple(t *testing.T) {
  type resetTestString (line 432) | type resetTestString struct
  function addReset (line 436) | func addReset(o *resetTestString, f func()) func() {
  function TestWrappedReset (line 446) | func TestWrappedReset(t *testing.T) {
  function TestWrappedReset2 (line 465) | func TestWrappedReset2(t *testing.T) {
  function TestInfiniteLoopWithTrailingFail (line 494) | func TestInfiniteLoopWithTrailingFail(t *testing.T) {
  function TestOutermostResetInvokedForGrandchildren (line 518) | func TestOutermostResetInvokedForGrandchildren(t *testing.T) {
  function TestFailureOption (line 556) | func TestFailureOption(t *testing.T) {
  function TestFailureOption2 (line 570) | func TestFailureOption2(t *testing.T) {
  function TestFailureOption3 (line 584) | func TestFailureOption3(t *testing.T) {
  function TestFailureOptionInherit (line 598) | func TestFailureOptionInherit(t *testing.T) {
  function TestFailureOptionInherit2 (line 618) | func TestFailureOptionInherit2(t *testing.T) {
  function TestFailureOptionInherit3 (line 638) | func TestFailureOptionInherit3(t *testing.T) {
  function TestFailureOptionNestedOverride (line 658) | func TestFailureOptionNestedOverride(t *testing.T) {
  function TestFailureOptionNestedOverride2 (line 678) | func TestFailureOptionNestedOverride2(t *testing.T) {
  function TestMultipleInvocationInheritance (line 698) | func TestMultipleInvocationInheritance(t *testing.T) {
  function TestMultipleInvocationInheritance2 (line 726) | func TestMultipleInvocationInheritance2(t *testing.T) {
  function TestSetDefaultFailureMode (line 756) | func TestSetDefaultFailureMode(t *testing.T) {
  function prepare (line 771) | func prepare() string {

FILE: convey/nilReporter.go
  type nilReporter (line 7) | type nilReporter struct
    method BeginStory (line 9) | func (self *nilReporter) BeginStory(story *reporting.StoryReport)  {}
    method Enter (line 10) | func (self *nilReporter) Enter(scope *reporting.ScopeReport)       {}
    method Report (line 11) | func (self *nilReporter) Report(report *reporting.AssertionResult) {}
    method Exit (line 12) | func (self *nilReporter) Exit()                                    {}
    method EndStory (line 13) | func (self *nilReporter) EndStory()                                {}
    method Write (line 14) | func (self *nilReporter) Write(p []byte) (int, error)              { r...
  function newNilReporter (line 15) | func newNilReporter() *nilReporter                                 { ret...

FILE: convey/reporting/console.go
  type console (line 8) | type console struct
    method Write (line 10) | func (self *console) Write(p []byte) (n int, err error) {
  function NewConsole (line 14) | func NewConsole() io.Writer {

FILE: convey/reporting/dot.go
  type dot (line 5) | type dot struct
    method BeginStory (line 7) | func (self *dot) BeginStory(story *StoryReport) {}
    method Enter (line 9) | func (self *dot) Enter(scope *ScopeReport) {}
    method Report (line 11) | func (self *dot) Report(report *AssertionResult) {
    method Exit (line 28) | func (self *dot) Exit() {}
    method EndStory (line 30) | func (self *dot) EndStory() {}
    method Write (line 32) | func (self *dot) Write(content []byte) (written int, err error) {
  function NewDotReporter (line 36) | func NewDotReporter(out *Printer) *dot {

FILE: convey/reporting/dot_test.go
  function TestDotReporterAssertionPrinting (line 8) | func TestDotReporterAssertionPrinting(t *testing.T) {
  function TestDotReporterOnlyReportsAssertions (line 26) | func TestDotReporterOnlyReportsAssertions(t *testing.T) {

FILE: convey/reporting/gotest.go
  type gotestReporter (line 3) | type gotestReporter struct
    method BeginStory (line 5) | func (self *gotestReporter) BeginStory(story *StoryReport) {
    method Enter (line 9) | func (self *gotestReporter) Enter(scope *ScopeReport) {}
    method Report (line 11) | func (self *gotestReporter) Report(r *AssertionResult) {
    method Exit (line 17) | func (self *gotestReporter) Exit() {}
    method EndStory (line 19) | func (self *gotestReporter) EndStory() {
    method Write (line 23) | func (self *gotestReporter) Write(content []byte) (written int, err er...
  function NewGoTestReporter (line 27) | func NewGoTestReporter() *gotestReporter {
  function passed (line 31) | func passed(r *AssertionResult) bool {

FILE: convey/reporting/gotest_test.go
  function TestReporterReceivesSuccessfulReport (line 5) | func TestReporterReceivesSuccessfulReport(t *testing.T) {
  function TestReporterReceivesFailureReport (line 16) | func TestReporterReceivesFailureReport(t *testing.T) {
  function TestReporterReceivesErrorReport (line 27) | func TestReporterReceivesErrorReport(t *testing.T) {
  function TestReporterIsResetAtTheEndOfTheStory (line 38) | func TestReporterIsResetAtTheEndOfTheStory(t *testing.T) {
  function TestReporterNoopMethods (line 48) | func TestReporterNoopMethods(t *testing.T) {
  function catch (line 54) | func catch(t *testing.T) {
  type fakeTest (line 60) | type fakeTest struct
    method Fail (line 64) | func (self *fakeTest) Fail() {

FILE: convey/reporting/init.go
  function init (line 9) | func init() {
  function BuildJsonReporter (line 19) | func BuildJsonReporter() Reporter {
  function BuildDotReporter (line 25) | func BuildDotReporter() Reporter {
  function BuildStoryReporter (line 33) | func BuildStoryReporter() Reporter {
  function BuildSilentReporter (line 41) | func BuildSilentReporter() Reporter {
  function SuppressConsoleStatistics (line 72) | func SuppressConsoleStatistics() { consoleStatistics.Suppress() }
  function PrintConsoleStatistics (line 73) | func PrintConsoleStatistics()    { consoleStatistics.PrintSummary() }
  function QuietMode (line 78) | func QuietMode() {
  function monochrome (line 82) | func monochrome() {
  function isColorableTerminal (line 86) | func isColorableTerminal() bool {
  type T (line 93) | type T interface

FILE: convey/reporting/json.go
  type JsonReporter (line 12) | type JsonReporter struct
    method depth (line 20) | func (self *JsonReporter) depth() int { return len(self.currentKey) }
    method BeginStory (line 22) | func (self *JsonReporter) BeginStory(story *StoryReport) {}
    method Enter (line 24) | func (self *JsonReporter) Enter(scope *ScopeReport) {
    method Report (line 35) | func (self *JsonReporter) Report(report *AssertionResult) {
    method Exit (line 39) | func (self *JsonReporter) Exit() {
    method EndStory (line 43) | func (self *JsonReporter) EndStory() {
    method report (line 47) | func (self *JsonReporter) report() {
    method reset (line 61) | func (self *JsonReporter) reset() {
    method Write (line 67) | func (self *JsonReporter) Write(content []byte) (written int, err erro...
  function NewJsonReporter (line 72) | func NewJsonReporter(out *Printer) *JsonReporter {
  constant OpenJson (line 79) | OpenJson = ">->->OPEN-JSON->->->"
  constant CloseJson (line 80) | CloseJson = "<-<-<-CLOSE-JSON<-<-<"
  constant jsonMarshalFailure (line 81) | jsonMarshalFailure = `

FILE: convey/reporting/printer.go
  type Printer (line 9) | type Printer struct
    method Println (line 14) | func (self *Printer) Println(message string, values ...any) {
    method Print (line 19) | func (self *Printer) Print(message string, values ...any) {
    method Insert (line 24) | func (self *Printer) Insert(text string) {
    method format (line 28) | func (self *Printer) format(message string, values ...any) string {
    method Indent (line 42) | func (self *Printer) Indent() {
    method Dedent (line 46) | func (self *Printer) Dedent() {
  function NewPrinter (line 52) | func NewPrinter(out io.Writer) *Printer {
  constant space (line 58) | space = " "
  constant pad (line 59) | pad = space + space
  constant padLength (line 60) | padLength = len(pad)

FILE: convey/reporting/printer_test.go
  function TestPrint (line 5) | func TestPrint(t *testing.T) {
  function TestPrintFormat (line 17) | func TestPrintFormat(t *testing.T) {
  function TestPrintPreservesEncodedStrings (line 31) | func TestPrintPreservesEncodedStrings(t *testing.T) {
  function TestPrintln (line 42) | func TestPrintln(t *testing.T) {
  function TestPrintlnFormat (line 54) | func TestPrintlnFormat(t *testing.T) {
  function TestPrintlnPreservesEncodedStrings (line 68) | func TestPrintlnPreservesEncodedStrings(t *testing.T) {
  function TestPrintIndented (line 79) | func TestPrintIndented(t *testing.T) {
  function TestPrintDedented (line 93) | func TestPrintDedented(t *testing.T) {
  function TestPrintlnIndented (line 107) | func TestPrintlnIndented(t *testing.T) {
  function TestPrintlnDedented (line 121) | func TestPrintlnDedented(t *testing.T) {
  function TestDedentTooFarShouldNotPanic (line 135) | func TestDedentTooFarShouldNotPanic(t *testing.T) {
  function TestInsert (line 149) | func TestInsert(t *testing.T) {
  type memoryFile (line 166) | type memoryFile struct
    method Write (line 170) | func (self *memoryFile) Write(p []byte) (n int, err error) {
    method String (line 175) | func (self *memoryFile) String() string {
  function newMemoryFile (line 179) | func newMemoryFile() *memoryFile {

FILE: convey/reporting/problems.go
  type problem (line 5) | type problem struct
    method BeginStory (line 12) | func (self *problem) BeginStory(story *StoryReport) {}
    method Enter (line 14) | func (self *problem) Enter(scope *ScopeReport) {}
    method Report (line 16) | func (self *problem) Report(report *AssertionResult) {
    method Exit (line 24) | func (self *problem) Exit() {}
    method EndStory (line 26) | func (self *problem) EndStory() {
    method show (line 31) | func (self *problem) show(display func(), color string) {
    method showErrors (line 41) | func (self *problem) showErrors() {
    method showFailures (line 50) | func (self *problem) showFailures() {
    method Write (line 63) | func (self *problem) Write(content []byte) (written int, err error) {
    method prepareForNextStory (line 80) | func (self *problem) prepareForNextStory() {
  function NewProblemReporter (line 67) | func NewProblemReporter(out *Printer) *problem {
  function NewSilentProblemReporter (line 74) | func NewSilentProblemReporter(out *Printer) *problem {

FILE: convey/reporting/problems_test.go
  function TestNoopProblemReporterActions (line 8) | func TestNoopProblemReporterActions(t *testing.T) {
  function TestReporterPrintsFailuresAndErrorsAtTheEndOfTheStory (line 20) | func TestReporterPrintsFailuresAndErrorsAtTheEndOfTheStory(t *testing.T) {
  function setup (line 45) | func setup() (file *memoryFile, reporter *problem) {

FILE: convey/reporting/reporter.go
  type Reporter (line 5) | type Reporter interface
  type reporters (line 14) | type reporters struct
    method BeginStory (line 16) | func (self *reporters) BeginStory(s *StoryReport) { self.foreach(func(...
    method Enter (line 17) | func (self *reporters) Enter(s *ScopeReport)      { self.foreach(func(...
    method Report (line 18) | func (self *reporters) Report(a *AssertionResult) { self.foreach(func(...
    method Exit (line 19) | func (self *reporters) Exit()                     { self.foreach(func(...
    method EndStory (line 20) | func (self *reporters) EndStory()                 { self.foreach(func(...
    method Write (line 22) | func (self *reporters) Write(contents []byte) (written int, err error) {
    method foreach (line 29) | func (self *reporters) foreach(action func(Reporter)) {
  function NewReporters (line 35) | func NewReporters(collection ...Reporter) *reporters {

FILE: convey/reporting/reporter_test.go
  function TestEachNestedReporterReceivesTheCallFromTheContainingReporter (line 8) | func TestEachNestedReporterReceivesTheCallFromTheContainingReporter(t *t...
  function assertTrue (line 42) | func assertTrue(t *testing.T, value bool) {
  function assertEqual (line 49) | func assertEqual(t *testing.T, expected, actual int) {
  function assertNil (line 56) | func assertNil(t *testing.T, err error) {
  type fakeReporter (line 63) | type fakeReporter struct
    method BeginStory (line 76) | func (self *fakeReporter) BeginStory(story *StoryReport) {
    method Enter (line 79) | func (self *fakeReporter) Enter(scope *ScopeReport) {
    method Report (line 82) | func (self *fakeReporter) Report(report *AssertionResult) {
    method Exit (line 85) | func (self *fakeReporter) Exit() {
    method EndStory (line 88) | func (self *fakeReporter) EndStory() {
    method Write (line 91) | func (self *fakeReporter) Write(content []byte) (int, error) {
  function newFakeReporter (line 72) | func newFakeReporter() *fakeReporter {

FILE: convey/reporting/reports.go
  type ScopeReport (line 14) | type ScopeReport struct
  function NewScopeReport (line 20) | func NewScopeReport(title string) *ScopeReport {
  type ScopeResult (line 31) | type ScopeResult struct
  function newScopeResult (line 40) | func newScopeResult(title string, depth int, file string, line int) *Sco...
  type StoryReport (line 52) | type StoryReport struct
  function NewStoryReport (line 59) | func NewStoryReport(test T) *StoryReport {
  function removePackagePath (line 72) | func removePackagePath(name string) string {
  type FailureView (line 81) | type FailureView struct
  type AssertionResult (line 89) | type AssertionResult struct
  function NewFailureReport (line 100) | func NewFailureReport(failure string, showStack bool) *AssertionResult {
  function parseFailure (line 109) | func parseFailure(failure string, report *AssertionResult) {
  function NewErrorReport (line 120) | func NewErrorReport(err any) *AssertionResult {
  function NewSuccessReport (line 127) | func NewSuccessReport() *AssertionResult {
  function NewSkipReport (line 130) | func NewSkipReport() *AssertionResult {
  function caller (line 138) | func caller() (file string, line int) {
  function stackTrace (line 143) | func stackTrace() string {
  function fullStackTrace (line 148) | func fullStackTrace() string {
  function removeInternalEntries (line 153) | func removeInternalEntries(stack string) string {
  function isExternal (line 163) | func isExternal(line string) bool {

FILE: convey/reporting/statistics.go
  function NewStatisticsReporter (line 86) | func NewStatisticsReporter(out *Printer) *statistics {
  type statistics (line 92) | type statistics struct
    method BeginStory (line 8) | func (self *statistics) BeginStory(story *StoryReport) {}
    method Enter (line 10) | func (self *statistics) Enter(scope *ScopeReport) {}
    method Report (line 12) | func (self *statistics) Report(report *AssertionResult) {
    method Exit (line 29) | func (self *statistics) Exit() {}
    method EndStory (line 31) | func (self *statistics) EndStory() {
    method Suppress (line 40) | func (self *statistics) Suppress() {
    method PrintSummary (line 46) | func (self *statistics) PrintSummary() {
    method printSummaryLocked (line 52) | func (self *statistics) printSummaryLocked() {
    method reportAssertionsLocked (line 57) | func (self *statistics) reportAssertionsLocked() {
    method decideColorLocked (line 61) | func (self *statistics) decideColorLocked() {
    method reportSkippedSectionsLocked (line 70) | func (self *statistics) reportSkippedSectionsLocked() {
    method completeReportLocked (line 76) | func (self *statistics) completeReportLocked() {
    method Write (line 82) | func (self *statistics) Write(content []byte) (written int, err error) {
  function plural (line 103) | func plural(word string, count int) string {

FILE: convey/reporting/story.go
  type story (line 15) | type story struct
    method BeginStory (line 21) | func (self *story) BeginStory(story *StoryReport) {}
    method Enter (line 23) | func (self *story) Enter(scope *ScopeReport) {
    method Report (line 37) | func (self *story) Report(report *AssertionResult) {
    method Exit (line 54) | func (self *story) Exit() {
    method EndStory (line 59) | func (self *story) EndStory() {
    method Write (line 64) | func (self *story) Write(content []byte) (written int, err error) {
  function NewStoryReporter (line 68) | func NewStoryReporter(out *Printer) *story {

FILE: convey/reporting_hooks_test.go
  function TestSingleScopeReported (line 16) | func TestSingleScopeReported(t *testing.T) {
  function TestNestedScopeReported (line 26) | func TestNestedScopeReported(t *testing.T) {
  function TestFailureReported (line 38) | func TestFailureReported(t *testing.T) {
  function TestFirstFailureEndsScopeExecution (line 48) | func TestFirstFailureEndsScopeExecution(t *testing.T) {
  function TestComparisonFailureDeserializedAndReported (line 59) | func TestComparisonFailureDeserializedAndReported(t *testing.T) {
  function TestNestedFailureReported (line 69) | func TestNestedFailureReported(t *testing.T) {
  function TestSuccessAndFailureReported (line 81) | func TestSuccessAndFailureReported(t *testing.T) {
  function TestIncompleteActionReportedAsSkipped (line 92) | func TestIncompleteActionReportedAsSkipped(t *testing.T) {
  function TestSkippedConveyReportedAsSkipped (line 102) | func TestSkippedConveyReportedAsSkipped(t *testing.T) {
  function TestMultipleSkipsAreReported (line 114) | func TestMultipleSkipsAreReported(t *testing.T) {
  function TestSkippedAssertionIsNotReported (line 145) | func TestSkippedAssertionIsNotReported(t *testing.T) {
  function TestMultipleSkippedAssertionsAreNotReported (line 155) | func TestMultipleSkippedAssertionsAreNotReported(t *testing.T) {
  function TestErrorByManualPanicReported (line 167) | func TestErrorByManualPanicReported(t *testing.T) {
  function TestIterativeConveysReported (line 177) | func TestIterativeConveysReported(t *testing.T) {
  function TestNestedIterativeConveysReported (line 191) | func TestNestedIterativeConveysReported(t *testing.T) {
  function TestEmbeddedAssertionReported (line 219) | func TestEmbeddedAssertionReported(t *testing.T) {
  function TestEmbeddedContextHelperReported (line 232) | func TestEmbeddedContextHelperReported(t *testing.T) {
  function expectEqual (line 251) | func expectEqual(t *testing.T, expected any, actual any) {
  function setupFakeReporter (line 259) | func setupFakeReporter() (*fakeReporter, *fakeGoTest) {
  type fakeReporter (line 266) | type fakeReporter struct
    method BeginStory (line 270) | func (self *fakeReporter) BeginStory(story *reporting.StoryReport) {
    method Enter (line 274) | func (self *fakeReporter) Enter(scope *reporting.ScopeReport) {
    method Report (line 278) | func (self *fakeReporter) Report(report *reporting.AssertionResult) {
    method Exit (line 294) | func (self *fakeReporter) Exit() {
    method EndStory (line 298) | func (self *fakeReporter) EndStory() {
    method Write (line 302) | func (self *fakeReporter) Write(content []byte) (int, error) {
    method wholeStory (line 306) | func (self *fakeReporter) wholeStory() string {
  type fakeGoTest (line 312) | type fakeGoTest struct
    method Fail (line 314) | func (self *fakeGoTest) Fail()                             {}
    method Fatalf (line 315) | func (self *fakeGoTest) Fatalf(format string, args ...any) {}

FILE: convey/stack_trace_test.go
  function countGoroutines (line 18) | func countGoroutines(testOutput string) int {
  function TestStackTrace (line 22) | func TestStackTrace(t *testing.T) {
  function TestSetDefaultStackMode (line 45) | func TestSetDefaultStackMode(t *testing.T) {
  function TestStackModeMultipleInvocationInheritance (line 59) | func TestStackModeMultipleInvocationInheritance(t *testing.T) {
  function TestStackModeMultipleInvocationInheritance2 (line 78) | func TestStackModeMultipleInvocationInheritance2(t *testing.T) {
  function TestStackModeMultipleInvocationInheritance3 (line 97) | func TestStackModeMultipleInvocationInheritance3(t *testing.T) {
  function setupFileReporter (line 116) | func setupFileReporter() (*memoryFile, *fakeGoTest) {
  type memoryFile (line 128) | type memoryFile struct
    method Write (line 132) | func (mf *memoryFile) Write(p []byte) (n int, err error) {
    method String (line 137) | func (mf *memoryFile) String() string {
  function newMemoryFile (line 141) | func newMemoryFile() *memoryFile {

FILE: convey/story_conventions_test.go
  function expectPanic (line 8) | func expectPanic(t *testing.T, f string) any {
  function TestMissingTopLevelGoTestReferenceCausesPanic (line 24) | func TestMissingTopLevelGoTestReferenceCausesPanic(t *testing.T) {
  function TestMissingTopLevelGoTestReferenceAfterGoodExample (line 35) | func TestMissingTopLevelGoTestReferenceAfterGoodExample(t *testing.T) {
  function TestExtraReferencePanics (line 53) | func TestExtraReferencePanics(t *testing.T) {
  function TestParseRegistrationMissingRequiredElements (line 66) | func TestParseRegistrationMissingRequiredElements(t *testing.T) {
  function TestParseRegistration_MissingNameString (line 72) | func TestParseRegistration_MissingNameString(t *testing.T) {
  function TestParseRegistration_MissingActionFunc (line 78) | func TestParseRegistration_MissingActionFunc(t *testing.T) {
  function TestFailureModeNoContext (line 84) | func TestFailureModeNoContext(t *testing.T) {
  function TestFailureModeDuplicateSuite (line 96) | func TestFailureModeDuplicateSuite(t *testing.T) {
  function TestFailureModeIndeterminentSuiteNames (line 105) | func TestFailureModeIndeterminentSuiteNames(t *testing.T) {
  function TestFailureModeNestedIndeterminentSuiteNames (line 117) | func TestFailureModeNestedIndeterminentSuiteNames(t *testing.T) {
  function TestFailureModeParameterButMissing (line 131) | func TestFailureModeParameterButMissing(t *testing.T) {
  function TestFailureModeParameterWithAction (line 139) | func TestFailureModeParameterWithAction(t *testing.T) {
  function TestExtraConveyParameters (line 145) | func TestExtraConveyParameters(t *testing.T) {
  function TestExtraConveyParameters2 (line 153) | func TestExtraConveyParameters2(t *testing.T) {
  function TestExtraConveyParameters3 (line 161) | func TestExtraConveyParameters3(t *testing.T) {

FILE: examples/assertion_examples_test.go
  function TestAssertionsAreAvailableFromConveyPackage (line 12) | func TestAssertionsAreAvailableFromConveyPackage(t *testing.T) {
  type thing (line 118) | type thing struct
  function panics (line 122) | func panics() {
  constant timeLayout (line 126) | timeLayout = "2006-01-02 15:04"

FILE: examples/bowling_game.go
  type Game (line 4) | type Game struct
    method Roll (line 17) | func (self *Game) Roll(pins int) {
    method Score (line 23) | func (self *Game) Score() (sum int) {
    method isStrike (line 41) | func (self *Game) isStrike(throw int) bool {
    method strikeBonusFor (line 46) | func (self *Game) strikeBonusFor(throw int) int {
    method isSpare (line 52) | func (self *Game) isSpare(throw int) bool {
    method spareBonusFor (line 57) | func (self *Game) spareBonusFor(throw int) int {
    method framePointsAt (line 62) | func (self *Game) framePointsAt(throw int) int {
  function NewGame (line 10) | func NewGame() *Game {
  constant allPins (line 68) | allPins          = 10
  constant framesPerGame (line 71) | framesPerGame    = 10
  constant maxThrowsPerGame (line 74) | maxThrowsPerGame = 21

FILE: examples/bowling_game_test.go
  function TestBowlingGameScoring (line 18) | func TestBowlingGameScoring(t *testing.T) {
  method rollMany (line 69) | func (self *Game) rollMany(times, pins int) {
  method rollSpare (line 74) | func (self *Game) rollSpare() {
  method rollStrike (line 78) | func (self *Game) rollStrike() {

FILE: examples/simple_example_test.go
  function TestIntegerManipulation (line 9) | func TestIntegerManipulation(t *testing.T) {

FILE: goconvey.go
  function init (line 38) | func init() {
  function main (line 57) | func main() {
  function printHeader (line 115) | func printHeader() {
  function browserCmd (line 129) | func browserCmd() (string, bool) {
  function launchBrowser (line 139) | func launchBrowser(addr string) {
  function runTestOnUpdates (line 157) | func runTestOnUpdates(queue chan messaging.Folders, executor contract.Ex...
  function extractPackages (line 167) | func extractPackages(folderList messaging.Folders) []*contract.Package {
  function isInsideTestdata (line 187) | func isInsideTestdata(folder *messaging.Folder) bool {
  function extractRoot (line 205) | func extractRoot(folderList messaging.Folders, packageList []*contract.P...
  function createListener (line 211) | func createListener() net.Listener {
  function serveHTTP (line 225) | func serveHTTP(reports string, server contract.Server, listener net.List...
  function exists (line 254) | func exists(path string) (bool, error) {
  function getWorkDir (line 265) | func getWorkDir() string {
  constant separator (line 305) | separator = string(filepath.Separator)
  constant endGoPath (line 306) | endGoPath = separator + "src" + separator
  function testFilesImportTheirOwnPackage (line 313) | func testFilesImportTheirOwnPackage(packagePath string) bool {
  function resolvePackageName (line 342) | func resolvePackageName(path string) string {

FILE: web/client/resources/js/composer.js
  function generate (line 100) | function generate(input)
  function parseInput (line 108) | function parseInput(input)
  function suppress (line 161) | function suppress(event)

FILE: web/client/resources/js/goconvey.js
  function init (line 10) | function init()
  function loadTheme (line 22) | function loadTheme(thmID)
  function initPoller (line 57) | function initPoller()
  function wireup (line 118) | function wireup()
  function setTooltips (line 412) | function setTooltips()
  function setDebugOutputUI (line 433) | function setDebugOutputUI(newSetting){
  function setNotifUI (line 449) | function setNotifUI()
  function expandAll (line 455) | function expandAll()
  function collapseAll (line 460) | function collapseAll()
  function expandPackage (line 465) | function expandPackage(pkgId)
  function collapsePackage (line 479) | function collapsePackage(pkgId)
  function togglePackage (line 493) | function togglePackage(storyPkgElem)
  function loadSettingsFromStorage (line 508) | function loadSettingsFromStorage()
  function latest (line 554) | function latest()
  function process (line 560) | function process(data, status, jqxhr)
  function renderFrame (line 869) | function renderFrame(frame)
  function enumSel (line 945) | function enumSel(id, val)
  function toggle (line 962) | function toggle(jqelem, switchelem)
  function changeStatus (line 994) | function changeStatus(newStatus, isHistoricalFrame)
  function updateWatchPath (line 1043) | function updateWatchPath()
  function notifSummary (line 1054) | function notifSummary(frame)
  function redrawCoverageBars (line 1079) | function redrawCoverageBars()
  function colorizeCoverageBars (line 1102) | function colorizeCoverageBars()
  function getFrame (line 1117) | function getFrame(id)
  function render (line 1124) | function render(templateID, context)
  function reframe (line 1130) | function reframe()
  function notif (line 1140) | function notif()
  function showServerDown (line 1145) | function showServerDown(message)
  function hideServerDown (line 1153) | function hideServerDown()
  function log (line 1160) | function log(msg)
  function zerofill (line 1179) | function zerofill(val, count)
  function sortPackages (line 1188) | function sortPackages(a, b)
  function get (line 1214) | function get(key)
  function save (line 1223) | function save(key, val)
  function splitPathName (line 1232) | function splitPathName(str)
  function newFrame (line 1238) | function newFrame()
  function emptyOverall (line 1252) | function emptyOverall()
  function emptyAssertions (line 1267) | function emptyAssertions()
  function makeContext (line 1277) | function makeContext(obj)
  function current (line 1287) | function current()
  function assignStatus (line 1292) | function assignStatus(obj)
  function showCoverDelta (line 1306) | function showCoverDelta(delta)
  function customMarkupPipes (line 1316) | function customMarkupPipes()
  function suppress (line 1363) | function suppress(event)

FILE: web/client/resources/js/lib/diff_match_patch.js
  function diff_match_patch (line 30) | function diff_match_patch() {
  function diff_linesToCharsMunge_ (line 459) | function diff_linesToCharsMunge_(text) {
  function diff_halfMatchI_ (line 661) | function diff_halfMatchI_(longtext, shorttext, i) {
  function diff_cleanupSemanticScore_ (line 855) | function diff_cleanupSemanticScore_(one, two) {
  function match_bitapScore_ (line 1455) | function match_bitapScore_(e, x) {

FILE: web/client/resources/js/lib/jquery-ui.js
  function focusable (line 123) | function focusable( element, isTabIndexNotNaN ) {
  function visible (line 144) | function visible( element ) {
  function reduce (line 186) | function reduce( elem, size, border, margin ) {
  function handlerProxy (line 692) | function handlerProxy() {
  function handlerProxy (line 728) | function handlerProxy() {
  function getOffsets (line 998) | function getOffsets( offsets, width, height ) {
  function parseCss (line 1005) | function parseCss( element, property ) {
  function getDimensions (line 1009) | function getDimensions( elem ) {
  function Datepicker (line 3013) | function Datepicker() {
  function bindHover (line 4945) | function bindHover(dpDiv) {
  function extendRemove (line 4971) | function extendRemove(target, props) {
  function checkFocus (line 5276) | function checkFocus() {
  function filteredUi (line 5456) | function filteredUi( ui ) {
  function filteredUi (line 5498) | function filteredUi( ui ) {
  function isOverAxis (line 6775) | function isOverAxis( x, reference, size ) {
  function clamp (line 7302) | function clamp( value, prop, allowEmpty ) {
  function stringParse (line 7328) | function stringParse( string ) {
  function hue2rgb (line 7578) | function hue2rgb( p, q, h ) {
  function getElementStyles (line 7846) | function getElementStyles( elem ) {
  function styleDifference (line 7874) | function styleDifference( oldStyle, newStyle ) {
  function _normalizeArguments (line 8195) | function _normalizeArguments( effect, options, speed, callback ) {
  function standardAnimationOption (line 8247) | function standardAnimationOption( option ) {
  function run (line 8292) | function run( next ) {
  function childComplete (line 8722) | function childComplete() {
  function animComplete (line 8771) | function animComplete() {
  function escape (line 9571) | function escape( value ) {
  function num (line 10147) | function num(v) {
  function isNumber (line 10151) | function isNumber(value) {
  function isOverAxis (line 12033) | function isOverAxis( x, reference, size ) {
  function isFloating (line 12037) | function isFloating(item) {
  function addItems (line 12656) | function addItems() {
  function delayEvent (line 13218) | function delayEvent( type, instance, container ) {
  function modifier (line 13307) | function modifier( fn ) {
  function checkFocus (line 13431) | function checkFocus() {
  function getNextTabId (line 13792) | function getNextTabId() {
  function isLocal (line 13796) | function isLocal( anchor ) {
  function constrain (line 14016) | function constrain() {
  function complete (line 14362) | function complete() {
  function show (line 14367) | function show() {
  function addDescribedBy (line 14626) | function addDescribedBy( elem, id ) {
  function removeDescribedBy (line 14634) | function removeDescribedBy( elem ) {
  function position (line 14855) | function position( event ) {

FILE: web/client/resources/js/lib/jquery.js
  function isArraylike (line 537) | function isArraylike( obj ) {
  function Sizzle (line 732) | function Sizzle( selector, context, results, seed ) {
  function createCache (line 847) | function createCache() {
  function markFunction (line 865) | function markFunction( fn ) {
  function assert (line 874) | function assert( fn ) {
  function addHandle (line 896) | function addHandle( attrs, handler ) {
  function siblingCheck (line 911) | function siblingCheck( a, b ) {
  function createInputPseudo (line 938) | function createInputPseudo( type ) {
  function createButtonPseudo (line 949) | function createButtonPseudo( type ) {
  function createPositionalPseudo (line 960) | function createPositionalPseudo( fn ) {
  function testContext (line 983) | function testContext( context ) {
  function setFilters (line 1977) | function setFilters() {}
  function tokenize (line 1981) | function tokenize( selector, parseOnly ) {
  function toSelector (line 2048) | function toSelector( tokens ) {
  function addCombinator (line 2058) | function addCombinator( matcher, combinator, base ) {
  function elementMatcher (line 2111) | function elementMatcher( matchers ) {
  function condense (line 2125) | function condense( unmatched, map, filter, context, xml ) {
  function setMatcher (line 2146) | function setMatcher( preFilter, selector, matcher, postFilter, postFinde...
  function matcherFromTokens (line 2239) | function matcherFromTokens( tokens ) {
  function matcherFromGroupMatchers (line 2294) | function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
  function multipleContexts (line 2420) | function multipleContexts( selector, contexts, results ) {
  function select (line 2429) | function select( selector, context, results, seed ) {
  function winnow (line 2581) | function winnow( elements, qualifier, not ) {
  function sibling (line 2906) | function sibling( cur, dir ) {
  function createOptions (line 2984) | function createOptions( options ) {
  function completed (line 3377) | function completed() {
  function Data (line 3482) | function Data() {
  function dataAttr (line 3674) | function dataAttr( elem, key, data ) {
  function returnTrue (line 4002) | function returnTrue() {
  function returnFalse (line 4006) | function returnFalse() {
  function safeActiveElement (line 4010) | function safeActiveElement() {
  function manipulationTarget (line 4873) | function manipulationTarget( elem, content ) {
  function disableScript (line 4883) | function disableScript( elem ) {
  function restoreScript (line 4887) | function restoreScript( elem ) {
  function setGlobalEval (line 4900) | function setGlobalEval( elems, refElements ) {
  function cloneCopyEvent (line 4911) | function cloneCopyEvent( src, dest ) {
  function getAll (line 4945) | function getAll( context, tag ) {
  function fixInput (line 4956) | function fixInput( src, dest ) {
  function actualDisplay (line 5414) | function actualDisplay( name, doc ) {
  function defaultDisplay (line 5435) | function defaultDisplay( nodeName ) {
  function curCSS (line 5475) | function curCSS( elem, name, computed ) {
  function addGetHookIf (line 5523) | function addGetHookIf( conditionFn, hookFn ) {
  function computePixelPositionAndBoxSizingReliable (line 5562) | function computePixelPositionAndBoxSizingReliable() {
  function vendorPropName (line 5657) | function vendorPropName( style, name ) {
  function setPositiveNumber (line 5679) | function setPositiveNumber( elem, value, subtract ) {
  function augmentWidthOrHeight (line 5687) | function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
  function getWidthOrHeight (line 5726) | function getWidthOrHeight( elem, name, extra ) {
  function showHide (line 5770) | function showHide( elements, show ) {
  function Tween (line 6073) | function Tween( elem, options, prop, end, easing ) {
  function createFxNow (line 6242) | function createFxNow() {
  function genFx (line 6250) | function genFx( type, includeWidth ) {
  function createTween (line 6270) | function createTween( value, prop, animation ) {
  function defaultPrefilter (line 6284) | function defaultPrefilter( elem, props, opts ) {
  function propFilter (line 6411) | function propFilter( props, specialEasing ) {
  function Animation (line 6448) | function Animation( elem, properties, options ) {
  function addToPrefiltersOrTransports (line 7505) | function addToPrefiltersOrTransports( structure ) {
  function inspectPrefiltersOrTransports (line 7537) | function inspectPrefiltersOrTransports( structure, options, originalOpti...
  function ajaxExtend (line 7564) | function ajaxExtend( target, src ) {
  function ajaxHandleResponses (line 7584) | function ajaxHandleResponses( s, jqXHR, responses ) {
  function ajaxConvert (line 7640) | function ajaxConvert( s, response, jqXHR, isSuccess ) {
  function done (line 8097) | function done( status, nativeStatusText, responses, headers ) {
  function buildParams (line 8349) | function buildParams( prefix, obj, traditional, add ) {
  function getWindow (line 8827) | function getWindow( elem ) {

FILE: web/client/resources/js/lib/jquery.tipsy.js
  function fixTitle (line 8) | function fixTitle($ele) {
  function Tipsy (line 14) | function Tipsy(element, options) {
  function get (line 122) | function get(ele) {
  function enter (line 131) | function enter() {
  function leave (line 141) | function leave() {

FILE: web/client/resources/js/lib/moment.js
  function utils_hooks__hooks (line 15) | function utils_hooks__hooks () {
  function setHookCallback (line 21) | function setHookCallback (callback) {
  function defaultParsingFlags (line 25) | function defaultParsingFlags() {
  function isArray (line 41) | function isArray(input) {
  function isDate (line 45) | function isDate(input) {
  function map (line 49) | function map(arr, fn) {
  function hasOwnProp (line 57) | function hasOwnProp(a, b) {
  function extend (line 61) | function extend(a, b) {
  function create_utc__createUTC (line 79) | function create_utc__createUTC (input, format, locale, strict) {
  function valid__isValid (line 83) | function valid__isValid(m) {
  function valid__createInvalid (line 103) | function valid__createInvalid (flags) {
  function copyConfig (line 117) | function copyConfig(to, from) {
  function Moment (line 167) | function Moment(config) {
  function isMoment (line 179) | function isMoment (obj) {
  function toInt (line 183) | function toInt(argumentForCoercion) {
  function compareArrays (line 198) | function compareArrays(array1, array2, dontConvert) {
  function Locale (line 212) | function Locale() {
  function normalizeLocale (line 218) | function normalizeLocale(key) {
  function chooseLocale (line 225) | function chooseLocale(names) {
  function loadLocale (line 249) | function loadLocale(name) {
  function locale_locales__getSetGlobalLocale (line 268) | function locale_locales__getSetGlobalLocale (key, values) {
  function defineLocale (line 287) | function defineLocale (name, values) {
  function locale_locales__getLocale (line 307) | function locale_locales__getLocale (key) {
  function addUnitAlias (line 332) | function addUnitAlias (unit, shorthand) {
  function normalizeUnits (line 337) | function normalizeUnits(units) {
  function normalizeObjectUnits (line 341) | function normalizeObjectUnits(inputObject) {
  function makeGetSet (line 358) | function makeGetSet (unit, keepTime) {
  function get_set__get (line 370) | function get_set__get (mom, unit) {
  function get_set__set (line 374) | function get_set__set (mom, unit, value) {
  function getSet (line 380) | function getSet (units, value) {
  function zeroFill (line 395) | function zeroFill(number, targetLength, forceSign) {
  function addFormatToken (line 417) | function addFormatToken (token, padded, ordinal, callback) {
  function removeFormattingTokens (line 439) | function removeFormattingTokens(input) {
  function makeFormatFunction (line 446) | function makeFormatFunction(format) {
  function formatMoment (line 467) | function formatMoment(m, format) {
  function expandFormat (line 481) | function expandFormat(format, locale) {
  function addRegexToken (line 520) | function addRegexToken (token, regex, strictRegex) {
  function getParseRegexForToken (line 526) | function getParseRegexForToken (token, config) {
  function unescapeFormat (line 535) | function unescapeFormat(s) {
  function addParseToken (line 543) | function addParseToken (token, callback) {
  function addWeekParseToken (line 558) | function addWeekParseToken (token, callback) {
  function addTimeToArrayFromToken (line 565) | function addTimeToArrayFromToken(token, input, config) {
  function daysInMonth (line 579) | function daysInMonth(year, month) {
  function localeMonths (line 625) | function localeMonths (m) {
  function localeMonthsShort (line 630) | function localeMonthsShort (m) {
  function localeMonthsParse (line 634) | function localeMonthsParse (monthName, format, strict) {
  function setMonth (line 667) | function setMonth (mom, value) {
  function getSetMonth (line 684) | function getSetMonth (value) {
  function getDaysInMonth (line 694) | function getDaysInMonth () {
  function checkOverflow (line 698) | function checkOverflow (m) {
  function warn (line 722) | function warn(msg) {
  function deprecate (line 728) | function deprecate(msg, fn) {
  function deprecateSimple (line 741) | function deprecateSimple(name, msg) {
  function configFromISO (line 771) | function configFromISO(config) {
  function configFromString (line 801) | function configFromString(config) {
  function createDate (line 826) | function createDate (y, m, d, h, M, s, ms) {
  function createUTCDate (line 838) | function createUTCDate (y) {
  function daysInYear (line 873) | function daysInYear(year) {
  function isLeapYear (line 877) | function isLeapYear(year) {
  function getIsLeapYear (line 891) | function getIsLeapYear () {
  function weekOfYear (line 923) | function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
  function localeWeek (line 946) | function localeWeek (mom) {
  function localeFirstDayOfWeek (line 955) | function localeFirstDayOfWeek () {
  function localeFirstDayOfYear (line 959) | function localeFirstDayOfYear () {
  function getSetWeek (line 965) | function getSetWeek (input) {
  function getSetISOWeek (line 970) | function getSetISOWeek (input) {
  function dayOfYearFromWeeks (line 992) | function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, f...
  function getSetDayOfYear (line 1010) | function getSetDayOfYear (input) {
  function defaults (line 1016) | function defaults(a, b, c) {
  function currentDateArray (line 1026) | function currentDateArray(config) {
  function configFromArray (line 1038) | function configFromArray (config) {
  function dayOfYearFromWeekInfo (line 1100) | function dayOfYearFromWeekInfo(config) {
  function configFromStringAndFormat (line 1145) | function configFromStringAndFormat(config) {
  function meridiemFixWrap (line 1207) | function meridiemFixWrap (locale, hour, meridiem) {
  function configFromStringAndArray (line 1232) | function configFromStringAndArray(config) {
  function configFromObject (line 1277) | function configFromObject(config) {
  function createFromConfig (line 1288) | function createFromConfig (config) {
  function configFromInput (line 1323) | function configFromInput(config) {
  function createLocalOrUTC (line 1346) | function createLocalOrUTC (input, format, locale, strict, isUTC) {
  function local__createLocal (line 1366) | function local__createLocal (input, format, locale, strict) {
  function pickBy (line 1391) | function pickBy(fn, moments) {
  function min (line 1409) | function min () {
  function max (line 1415) | function max () {
  function Duration (line 1421) | function Duration (duration) {
  function isDuration (line 1456) | function isDuration (obj) {
  function offset (line 1460) | function offset (token, separator) {
  function offsetFromString (line 1491) | function offsetFromString(string) {
  function cloneWithOffset (line 1501) | function cloneWithOffset(input, model) {
  function getDateOffset (line 1516) | function getDateOffset (m) {
  function getSetOffset (line 1540) | function getSetOffset (input, keepLocalTime) {
  function getSetZone (line 1573) | function getSetZone (input, keepLocalTime) {
  function setOffsetToUTC (line 1587) | function setOffsetToUTC (keepLocalTime) {
  function setOffsetToLocal (line 1591) | function setOffsetToLocal (keepLocalTime) {
  function setOffsetToParsedOffset (line 1603) | function setOffsetToParsedOffset () {
  function hasAlignedHourOffset (line 1612) | function hasAlignedHourOffset (input) {
  function isDaylightSavingTime (line 1623) | function isDaylightSavingTime () {
  function isDaylightSavingTimeShifted (line 1630) | function isDaylightSavingTimeShifted () {
  function isLocal (line 1639) | function isLocal () {
  function isUtcOffset (line 1643) | function isUtcOffset () {
  function isUtc (line 1647) | function isUtc () {
  function create__createDuration (line 1657) | function create__createDuration (input, key) {
  function parseIso (line 1720) | function parseIso (inp, sign) {
  function positiveMomentsDifference (line 1729) | function positiveMomentsDifference(base, other) {
  function momentsDifference (line 1743) | function momentsDifference(base, other) {
  function createAdder (line 1757) | function createAdder(direction, name) {
  function add_subtract__addSubtract (line 1773) | function add_subtract__addSubtract (mom, duration, isAdding, updateOffse...
  function moment_calendar__calendar (line 1796) | function moment_calendar__calendar (time) {
  function clone (line 1811) | function clone () {
  function isAfter (line 1815) | function isAfter (input, units) {
  function isBefore (line 1827) | function isBefore (input, units) {
  function isBetween (line 1839) | function isBetween (from, to, units) {
  function isSame (line 1843) | function isSame (input, units) {
  function absFloor (line 1855) | function absFloor (number) {
  function diff (line 1863) | function diff (input, units, asFloat) {
  function monthDiff (line 1889) | function monthDiff (a, b) {
  function toString (line 1911) | function toString () {
  function moment_format__toISOString (line 1915) | function moment_format__toISOString () {
  function format (line 1929) | function format (inputString) {
  function from (line 1934) | function from (time, withoutSuffix) {
  function fromNow (line 1938) | function fromNow (withoutSuffix) {
  function locale (line 1942) | function locale (key) {
  function localeData (line 1967) | function localeData () {
  function startOf (line 1971) | function startOf (units) {
  function endOf (line 2014) | function endOf (units) {
  function to_type__valueOf (line 2022) | function to_type__valueOf () {
  function unix (line 2026) | function unix () {
  function toDate (line 2030) | function toDate () {
  function toArray (line 2034) | function toArray () {
  function moment_valid__isValid (line 2039) | function moment_valid__isValid () {
  function parsingFlags (line 2043) | function parsingFlags () {
  function invalidAt (line 2047) | function invalidAt () {
  function addWeekYearFormatToken (line 2059) | function addWeekYearFormatToken (token, getter) {
  function weeksInYear (line 2094) | function weeksInYear(year, dow, doy) {
  function getSetWeekYear (line 2100) | function getSetWeekYear (input) {
  function getSetISOWeekYear (line 2105) | function getSetISOWeekYear (input) {
  function getISOWeeksInYear (line 2110) | function getISOWeeksInYear () {
  function getWeeksInYear (line 2114) | function getWeeksInYear () {
  function getSetQuarter (line 2134) | function getSetQuarter (input) {
  function parseWeekday (line 2209) | function parseWeekday(input, locale) {
  function localeWeekdays (line 2227) | function localeWeekdays (m) {
  function localeWeekdaysShort (line 2232) | function localeWeekdaysShort (m) {
  function localeWeekdaysMin (line 2237) | function localeWeekdaysMin (m) {
  function localeWeekdaysParse (line 2241) | function localeWeekdaysParse (weekdayName) {
  function getSetDayOfWeek (line 2264) | function getSetDayOfWeek (input) {
  function getSetLocaleDayOfWeek (line 2274) | function getSetLocaleDayOfWeek (input) {
  function getSetISODayOfWeek (line 2279) | function getSetISODayOfWeek (input) {
  function meridiem (line 2291) | function meridiem (token, lowercase) {
  function matchMeridiem (line 2306) | function matchMeridiem (isStrict, locale) {
  function localeIsPM (line 2329) | function localeIsPM (input) {
  function localeMeridiem (line 2336) | function localeMeridiem (hours, minutes, isLower) {
  function millisecond__milliseconds (line 2393) | function millisecond__milliseconds (token) {
  function getZoneAbbr (line 2423) | function getZoneAbbr () {
  function getZoneName (line 2427) | function getZoneName () {
  function moment__createUnix (line 2530) | function moment__createUnix (input) {
  function moment__createInZone (line 2534) | function moment__createInZone () {
  function locale_calendar__calendar (line 2547) | function locale_calendar__calendar (key, mom, now) {
  function longDateFormat (line 2561) | function longDateFormat (key) {
  function invalidDate (line 2574) | function invalidDate () {
  function ordinal (line 2581) | function ordinal (number) {
  function preParsePostFormat (line 2585) | function preParsePostFormat (string) {
  function relative__relativeTime (line 2605) | function relative__relativeTime (number, withoutSuffix, string, isFuture) {
  function pastFuture (line 2612) | function pastFuture (diff, output) {
  function locale_set__set (line 2617) | function locale_set__set (config) {
  function lists__get (line 2677) | function lists__get (format, index, field, setter) {
  function list (line 2683) | function list (format, index, field, count, setter) {
  function lists__listMonths (line 2703) | function lists__listMonths (format, index) {
  function lists__listMonthsShort (line 2707) | function lists__listMonthsShort (format, index) {
  function lists__listWeekdays (line 2711) | function lists__listWeekdays (format, index) {
  function lists__listWeekdaysShort (line 2715) | function lists__listWeekdaysShort (format, index) {
  function lists__listWeekdaysMin (line 2719) | function lists__listWeekdaysMin (format, index) {
  function duration_abs__abs (line 2741) | function duration_abs__abs () {
  function duration_add_subtract__addSubtract (line 2758) | function duration_add_subtract__addSubtract (duration, input, value, dir...
  function duration_add_subtract__add (line 2769) | function duration_add_subtract__add (input, value) {
  function duration_add_subtract__subtract (line 2774) | function duration_add_subtract__subtract (input, value) {
  function bubble (line 2778) | function bubble () {
  function daysToYears (line 2820) | function daysToYears (days) {
  function yearsToDays (line 2825) | function yearsToDays (years) {
  function as (line 2831) | function as (units) {
  function duration_as__valueOf (line 2859) | function duration_as__valueOf () {
  function makeAs (line 2868) | function makeAs (alias) {
  function duration_get__get (line 2883) | function duration_get__get (units) {
  function makeGetter (line 2888) | function makeGetter(name) {
  function weeks (line 2902) | function weeks () {
  function substituteTimeAgo (line 2916) | function substituteTimeAgo(string, number, withoutSuffix, isFuture, loca...
  function duration_humanize__relativeTime (line 2920) | function duration_humanize__relativeTime (posNegDuration, withoutSuffix,...
  function duration_humanize__getSetRelativeTimeThreshold (line 2947) | function duration_humanize__getSetRelativeTimeThreshold (threshold, limi...
  function humanize (line 2958) | function humanize (withSuffix) {
  function iso_string__toISOString (line 2971) | function iso_string__toISOString() {

FILE: web/client/resources/js/lib/taboverride.js
  function isValidModifierKeyCombo (line 64) | function isValidModifierKeyCombo(modifierKeys, e) {
  function tabKeyComboPressed (line 124) | function tabKeyComboPressed(keyCode, e) {
  function untabKeyComboPressed (line 137) | function untabKeyComboPressed(keyCode, e) {
  function createKeyComboFunction (line 151) | function createKeyComboFunction(keyFunc, modifierKeys) {
  function overrideKeyDown (line 188) | function overrideKeyDown(e) {
  function overrideKeyPress (line 469) | function overrideKeyPress(e) {
  function executeExtensions (line 494) | function executeExtensions(hook, args) {
  function createListeners (line 529) | function createListeners(handlerList) {
  function addListeners (line 587) | function addListeners(elem) {
  function removeListeners (line 602) | function removeListeners(elem) {

FILE: web/client/resources/js/poller.js
  function Poller (line 1) | function Poller(config)

FILE: web/server/api/server.go
  type HTTPServer (line 15) | type HTTPServer struct
    method ReceiveUpdate (line 24) | func (self *HTTPServer) ReceiveUpdate(root string, update *contract.Co...
    method Watch (line 29) | func (self *HTTPServer) Watch(response http.ResponseWriter, request *h...
    method adjustRoot (line 37) | func (self *HTTPServer) adjustRoot(response http.ResponseWriter, reque...
    method Ignore (line 54) | func (self *HTTPServer) Ignore(response http.ResponseWriter, request *...
    method Reinstate (line 64) | func (self *HTTPServer) Reinstate(response http.ResponseWriter, reques...
    method parseQueryString (line 74) | func (self *HTTPServer) parseQueryString(key string, response http.Res...
    method Status (line 89) | func (self *HTTPServer) Status(response http.ResponseWriter, request *...
    method LongPollStatus (line 94) | func (self *HTTPServer) LongPollStatus(response http.ResponseWriter, r...
    method Results (line 120) | func (self *HTTPServer) Results(response http.ResponseWriter, request ...
    method Execute (line 132) | func (self *HTTPServer) Execute(response http.ResponseWriter, request ...
    method execute (line 136) | func (self *HTTPServer) execute() {
    method TogglePause (line 140) | func (self *HTTPServer) TogglePause(response http.ResponseWriter, requ...
  function NewHTTPServer (line 152) | func NewHTTPServer(

FILE: web/server/api/server_test.go
  constant initialRoot (line 18) | initialRoot = "/root/gopath/src/github.com/smartystreets/project"
  constant nonexistentRoot (line 19) | nonexistentRoot = "I don't exist"
  constant unreadableContent (line 20) | unreadableContent = "!!error!!"
  function TestHTTPServer (line 22) | func TestHTTPServer(t *testing.T) {
  type ServerFixture (line 286) | type ServerFixture struct
    method ReceiveUpdate (line 293) | func (self *ServerFixture) ReceiveUpdate(root string, update *contract...
    method RequestLatest (line 297) | func (self *ServerFixture) RequestLatest() (*contract.CompleteOutput, ...
    method QueryRootWatch (line 309) | func (self *ServerFixture) QueryRootWatch(newclient bool) (string, int) {
    method AdjustRootWatchMalformed (line 322) | func (self *ServerFixture) AdjustRootWatchMalformed() (status int, bod...
    method AdjustRootWatch (line 332) | func (self *ServerFixture) AdjustRootWatch(newRoot string) (status int...
    method IgnoreMalformed (line 343) | func (self *ServerFixture) IgnoreMalformed() (status int, body string) {
    method Ignore (line 353) | func (self *ServerFixture) Ignore(folder string) (status int, body str...
    method ReinstateMalformed (line 364) | func (self *ServerFixture) ReinstateMalformed() (status int, body stri...
    method Reinstate (line 374) | func (self *ServerFixture) Reinstate(folder string) (status int, body ...
    method SetExecutorStatus (line 385) | func (self *ServerFixture) SetExecutorStatus(status string) {
    method RequestExecutorStatus (line 393) | func (self *ServerFixture) RequestExecutorStatus() (code int, status s...
    method ManualExecution (line 403) | func (self *ServerFixture) ManualExecution() int {
    method TogglePause (line 413) | func (self *ServerFixture) TogglePause() string {
  function newServerFixture (line 422) | func newServerFixture() *ServerFixture {
  type FakeExecutor (line 434) | type FakeExecutor struct
    method Status (line 441) | func (self *FakeExecutor) Status() string {
    method ClearStatusFlag (line 445) | func (self *FakeExecutor) ClearStatusFlag() bool {
    method ExecuteTests (line 451) | func (self *FakeExecutor) ExecuteTests(watched []*contract.Package) *c...
  function newFakeExecutor (line 457) | func newFakeExecutor(status string, statusUpdate chan chan string) *Fake...

FILE: web/server/contract/contracts.go
  type Server (line 6) | type Server interface
  type Executor (line 18) | type Executor interface
  type Shell (line 24) | type Shell interface

FILE: web/server/contract/result.go
  type Package (line 8) | type Package struct
    method Active (line 35) | func (self *Package) Active() bool {
    method HasUsableResult (line 39) | func (self *Package) HasUsableResult() bool {
  function NewPackage (line 22) | func NewPackage(folder *messaging.Folder, name string, hasImportCycle bo...
  type CompleteOutput (line 43) | type CompleteOutput struct
  type PackageResult (line 63) | type PackageResult struct
  function NewPackageResult (line 72) | func NewPackageResult(packageName string) *PackageResult {
  type TestResult (line 80) | type TestResult struct
  function NewTestResult (line 94) | func NewTestResult(testName string) *TestResult {

FILE: web/server/executor/contract.go
  type Parser (line 5) | type Parser interface
  type Tester (line 9) | type Tester interface

FILE: web/server/executor/coordinator.go
  type concurrentCoordinator (line 13) | type concurrentCoordinator struct
    method ExecuteConcurrently (line 21) | func (self *concurrentCoordinator) ExecuteConcurrently() {
    method enlistWorkers (line 27) | func (self *concurrentCoordinator) enlistWorkers() {
    method worker (line 33) | func (self *concurrentCoordinator) worker(id int) {
    method scheduleTasks (line 53) | func (self *concurrentCoordinator) scheduleTasks() {
    method awaitCompletion (line 59) | func (self *concurrentCoordinator) awaitCompletion() {
  function newConcurrentCoordinator (line 64) | func newConcurrentCoordinator(folders []*contract.Package, batchSize int...

FILE: web/server/executor/executor.go
  constant Idle (line 11) | Idle      = "idle"
  constant Executing (line 12) | Executing = "executing"
  type Executor (line 15) | type Executor struct
    method Status (line 23) | func (self *Executor) Status() string {
    method ClearStatusFlag (line 27) | func (self *Executor) ClearStatusFlag() bool {
    method ExecuteTests (line 33) | func (self *Executor) ExecuteTests(folders []*contract.Package) *contr...
    method execute (line 40) | func (self *Executor) execute(folders []*contract.Package) {
    method parse (line 45) | func (self *Executor) parse(folders []*contract.Package) *contract.Com...
    method setStatus (line 54) | func (self *Executor) setStatus(status string) {
  function NewExecutor (line 72) | func NewExecutor(tester Tester, parser Parser, ch chan chan string) *Exe...

FILE: web/server/executor/executor_test.go
  function TestExecutor (line 12) | func TestExecutor(t *testing.T) {
  type ExecutorFixture (line 49) | type ExecutorFixture struct
    method ExecuteTests (line 59) | func (self *ExecutorFixture) ExecuteTests() {
    method CaptureStatusDuringExecutionPhase (line 63) | func (self *ExecutorFixture) CaptureStatusDuringExecutionPhase() string {
    method delayedExecution (line 69) | func (self *ExecutorFixture) delayedExecution(nap time.Duration) string {
    method ResultShouldBePopulated (line 75) | func (self *ExecutorFixture) ResultShouldBePopulated() {
  function newExecutorFixture (line 87) | func newExecutorFixture() *ExecutorFixture {
  type FakeTester (line 111) | type FakeTester struct
    method SetBatchSize (line 115) | func (self *FakeTester) SetBatchSize(batchSize int) { panic("NOT SUPPO...
    method TestAll (line 116) | func (self *FakeTester) TestAll(folders []*contract.Package) {
    method addDelay (line 122) | func (self *FakeTester) addDelay(nap time.Duration) {
  function newFakeTester (line 126) | func newFakeTester() *FakeTester {
  type FakeParser (line 135) | type FakeParser struct
    method Parse (line 139) | func (self *FakeParser) Parse(packages []*contract.Package) {
    method addDelay (line 151) | func (self *FakeParser) addDelay(nap time.Duration) {
  function newFakeParser (line 155) | func newFakeParser() *FakeParser {

FILE: web/server/executor/tester.go
  type ConcurrentTester (line 12) | type ConcurrentTester struct
    method SetBatchSize (line 17) | func (self *ConcurrentTester) SetBatchSize(batchSize int) {
    method TestAll (line 22) | func (self *ConcurrentTester) TestAll(folders []*contract.Package) {
    method executeSynchronously (line 31) | func (self *ConcurrentTester) executeSynchronously(folders []*contract...
  function NewConcurrentTester (line 49) | func NewConcurrentTester(shell contract.Shell) *ConcurrentTester {
  constant defaultBatchSize (line 56) | defaultBatchSize = 10

FILE: web/server/executor/tester_test.go
  function init (line 15) | func init() {
  function TestConcurrentTester (line 19) | func TestConcurrentTester(t *testing.T) {
  constant concurrentBatchSize (line 70) | concurrentBatchSize = 2
  type TesterFixture (line 72) | type TesterFixture struct
    method InBatchesOf (line 98) | func (self *TesterFixture) InBatchesOf(batchSize int) *TesterFixture {
    method SetupAbnormalError (line 103) | func (self *TesterFixture) SetupAbnormalError(message string) *TesterF...
    method SetupFailedTestSuites (line 108) | func (self *TesterFixture) SetupFailedTestSuites() *TesterFixture {
    method RunTests (line 113) | func (self *TesterFixture) RunTests() {
    method ShouldHaveRecordOfExecutionCommands (line 127) | func (self *TesterFixture) ShouldHaveRecordOfExecutionCommands() {
    method ShouldHaveOneOutputPerInput (line 140) | func (self *TesterFixture) ShouldHaveOneOutputPerInput() {
    method OutputShouldBeAsExpected (line 144) | func (self *TesterFixture) OutputShouldBeAsExpected() {
    method TestsShouldHaveRunContiguously (line 160) | func (self *TesterFixture) TestsShouldHaveRunContiguously() {
    method TestsShouldHaveRunInBatchesOfTwo (line 173) | func (self *TesterFixture) TestsShouldHaveRunInBatchesOfTwo() {
  function NewTesterFixture (line 82) | func NewTesterFixture() *TesterFixture {
  type ShellCommand (line 181) | type ShellCommand struct
  type TimedShell (line 187) | type TimedShell struct
    method Executions (line 193) | func (self *TimedShell) Executions() []*ShellCommand {
    method MaxConcurrentCommands (line 197) | func (self *TimedShell) MaxConcurrentCommands() int {
    method setTripWire (line 221) | func (self *TimedShell) setTripWire(message string) {
    method setExitWithError (line 225) | func (self *TimedShell) setExitWithError() {
    method GoTest (line 229) | func (self *TimedShell) GoTest(directory, packageName string, argument...
    method composeCommand (line 240) | func (self *TimedShell) composeCommand(commandText string) *ShellComma...
  function concurrentWith (line 216) | func concurrentWith(current, comparison *ShellCommand) bool {
  function NewTimedShell (line 247) | func NewTimedShell() *TimedShell {

FILE: web/server/messaging/messages.go
  type WatcherCommand (line 5) | type WatcherCommand struct
  type WatcherInstruction (line 10) | type WatcherInstruction
    method String (line 12) | func (this WatcherInstruction) String() string {
  constant WatcherPause (line 34) | WatcherPause WatcherInstruction = iota
  constant WatcherResume (line 35) | WatcherResume
  constant WatcherIgnore (line 36) | WatcherIgnore
  constant WatcherReinstate (line 37) | WatcherReinstate
  constant WatcherAdjustRoot (line 38) | WatcherAdjustRoot
  constant WatcherExecute (line 39) | WatcherExecute
  constant WatcherStop (line 40) | WatcherStop
  type Folders (line 45) | type Folders
  type Folder (line 47) | type Folder struct

FILE: web/server/parser/packageParser.go
  function ParsePackageResults (line 17) | func ParsePackageResults(result *contract.PackageResult, rawOutput strin...
  type outputParser (line 21) | type outputParser struct
    method parse (line 43) | func (self *outputParser) parse() {
    method separateTestFunctionsAndMetadata (line 48) | func (self *outputParser) separateTestFunctionsAndMetadata() {
    method processNonTestOutput (line 65) | func (self *outputParser) processNonTestOutput() bool {
    method recordFinalOutcome (line 84) | func (self *outputParser) recordFinalOutcome(outcome string) {
    method processTestOutput (line 89) | func (self *outputParser) processTestOutput() {
    method registerTestFunction (line 106) | func (self *outputParser) registerTestFunction() {
    method recordTestMetadata (line 115) | func (self *outputParser) recordTestMetadata() {
    method recordPackageMetadata (line 124) | func (self *outputParser) recordPackageMetadata() {
    method recordTestingOutcome (line 135) | func (self *outputParser) recordTestingOutcome(outcome string) {
    method recordCoverageSummary (line 144) | func (self *outputParser) recordCoverageSummary(summary string) {
    method saveLineForParsingLater (line 154) | func (self *outputParser) saveLineForParsingLater() {
    method parseEachTestFunction (line 179) | func (self *outputParser) parseEachTestFunction() {
  function newOutputParser (line 33) | func newOutputParser(result *contract.PackageResult, rawOutput string) *...
  type TestResults (line 164) | type TestResults
    method Len (line 166) | func (r TestResults) Len() int {
    method Less (line 171) | func (r TestResults) Less(i, j int) bool {
    method Swap (line 175) | func (r TestResults) Swap(i, j int) {

FILE: web/server/parser/package_parser_test.go
  function init (line 15) | func init() {
  function TestParsePackage_NoGoFiles_ReturnsPackageResult (line 19) | func TestParsePackage_NoGoFiles_ReturnsPackageResult(t *testing.T) {
  function TestParsePackage_NoTestFiles_ReturnsPackageResult (line 25) | func TestParsePackage_NoTestFiles_ReturnsPackageResult(t *testing.T) {
  function TestParsePacakge_NoTestFunctions_ReturnsPackageResult (line 31) | func TestParsePacakge_NoTestFunctions_ReturnsPackageResult(t *testing.T) {
  function TestParsePackage_BuildFailed_ReturnsPackageResult (line 37) | func TestParsePackage_BuildFailed_ReturnsPackageResult(t *testing.T) {
  function TestParsePackage_OldSchoolWithFailureOutput_ReturnsCompletePackageResult (line 59) | func TestParsePackage_OldSchoolWithFailureOutput_ReturnsCompletePackageR...
  function TestParsePackage_OldSchoolWithSuccessOutput_ReturnsCompletePackageResult (line 65) | func TestParsePackage_OldSchoolWithSuccessOutput_ReturnsCompletePackageR...
  function TestParsePackage_GoConveyWithDiffOutput_ReturnsPackageResult (line 71) | func TestParsePackage_GoConveyWithDiffOutput_ReturnsPackageResult(t *tes...
  function TestParsePackage_GoConveyWithDiff2Output_ReturnsPackageResult (line 77) | func TestParsePackage_GoConveyWithDiff2Output_ReturnsPackageResult(t *te...
  function TestParsePackage_OldSchoolWithPanicOutput_ReturnsCompletePackageResult (line 83) | func TestParsePackage_OldSchoolWithPanicOutput_ReturnsCompletePackageRes...
  function TestParsePackage_GoConveyOutput_ReturnsCompletePackageResult (line 89) | func TestParsePackage_GoConveyOutput_ReturnsCompletePackageResult(t *tes...
  function TestParsePackage_ActualPackageNameDifferentThanDirectoryName_ReturnsActualPackageName (line 95) | func TestParsePackage_ActualPackageNameDifferentThanDirectoryName_Return...
  function TestParsePackage_GoConveyOutputMalformed_CausesPanic (line 101) | func TestParsePackage_GoConveyOutputMalformed_CausesPanic(t *testing.T) {
  function TestParsePackage_GoConveyWithRandomOutput_ReturnsPackageResult (line 117) | func TestParsePackage_GoConveyWithRandomOutput_ReturnsPackageResult(t *t...
  function TestParsePackage_OldSchoolWithSuccessAndBogusCoverage_ReturnsCompletePackageResult (line 123) | func TestParsePackage_OldSchoolWithSuccessAndBogusCoverage_ReturnsComple...
  function TestParsePackage_NestedTests_ReturnsPackageResult (line 129) | func TestParsePackage_NestedTests_ReturnsPackageResult(t *testing.T) {
  function TestParsePackage_WithExampleFunctions_ReturnsPackageResult (line 135) | func TestParsePackage_WithExampleFunctions_ReturnsPackageResult(t *testi...
  function TestParsePackage_Golang15Output_ShouldNotPanic (line 141) | func TestParsePackage_Golang15Output_ShouldNotPanic(t *testing.T) {
  function TestParsePackage_Golang17Subtests_ReturnsPackageResult (line 147) | func TestParsePackage_Golang17Subtests_ReturnsPackageResult(t *testing.T) {
  function assertEqual (line 153) | func assertEqual(t *testing.T, expected, actual any) {
  constant failureTemplate (line 161) | failureTemplate = "Comparison failed:\n  Expected: %v\n    Actual: %v\n"
  constant input_NoGoFiles (line 163) | input_NoGoFiles = `can't load package: package github.com/smartystreets/...
  constant input_NoTestFiles (line 171) | input_NoTestFiles = `?   	pkg.smartystreets.net/liveaddress-zipapi	[no t...
  constant input_NoTestFunctions (line 179) | input_NoTestFunctions = `testing: warning: no tests to run
  constant input_BuildFailed_InvalidPackageDeclaration (line 189) | input_BuildFailed_InvalidPackageDeclaration = `
  constant input_BuildFailed_CantFindPackage (line 201) | input_BuildFailed_CantFindPackage = `
  constant input_BuildFailed_ConfictingImport (line 214) | input_BuildFailed_ConfictingImport = `
  constant input_BuildFailed_OtherErrors (line 224) | input_BuildFailed_OtherErrors = `
  constant input_BuildFailed_ImportCycle (line 246) | input_BuildFailed_ImportCycle = `
  constant inputOldSchool_Passes (line 258) | inputOldSchool_Passes = `
  constant inputOldSchool_Fails (line 310) | inputOldSchool_Fails = `
  constant inputOldSchoolWithDiff2_Fails (line 371) | inputOldSchoolWithDiff2_Fails = `
  constant inputOldSchoolWithDiff_Fails (line 464) | inputOldSchoolWithDiff_Fails = `
  constant inputOldSchool_Panics (line 551) | inputOldSchool_Panics = `
  constant inputGoConvey_Malformed (line 615) | inputGoConvey_Malformed = `
  constant inputGoConvey (line 643) | inputGoConvey = `
  constant inputGoConvey_WithRandomOutput (line 704) | inputGoConvey_WithRandomOutput = `
  constant inputOldSchool_PassesButCoverageIsBogus (line 804) | inputOldSchool_PassesButCoverageIsBogus = `
  constant inputNestedTests (line 843) | inputNestedTests = `
  constant inputExampleFunctions (line 928) | inputExampleFunctions = `
  constant inputGolang15 (line 968) | inputGolang15 = `
  constant inputGolang17Subtests (line 992) | inputGolang17Subtests = `
  constant inputGinkgo_Passes (line 1072) | inputGinkgo_Passes = `
  function TestParsePackage_GinkgoWithSuccessOutput (line 1084) | func TestParsePackage_GinkgoWithSuccessOutput(t *testing.T) {
  constant inputGinkgo_Fails (line 1090) | inputGinkgo_Fails = `
  function TestParsePackage_GinkgoWithFailureOutput (line 1108) | func TestParsePackage_GinkgoWithFailureOutput(t *testing.T) {

FILE: web/server/parser/parser.go
  type Parser (line 9) | type Parser struct
    method Parse (line 13) | func (self *Parser) Parse(packages []*contract.Package) {
  function NewParser (line 28) | func NewParser(helper func(*contract.PackageResult, string)) *Parser {

FILE: web/server/parser/parser_test.go
  function TestParser (line 11) | func TestParser(t *testing.T) {
  function fakeParserImplementation (line 45) | func fakeParserImplementation(result *contract.PackageResult, rawOutput ...

FILE: web/server/parser/rules.go
  function noGoFiles (line 5) | func noGoFiles(line string) bool {
  function buildFailed (line 11) | func buildFailed(line string) bool {
  function noTestFunctions (line 17) | func noTestFunctions(line string) bool {
  function noTestFiles (line 20) | func noTestFiles(line string) bool {
  function isNewTest (line 23) | func isNewTest(line string) bool {
  function isTestResult (line 26) | func isTestResult(line string) bool {
  function isPackageReport (line 29) | func isPackageReport(line string) bool {
  function packageFailed (line 37) | func packageFailed(line string) bool {
  function packagePassed (line 40) | func packagePassed(line string) bool {
  function isCoverageSummary (line 43) | func isCoverageSummary(line string) bool {

FILE: web/server/parser/testParser.go
  type testParser (line 13) | type testParser struct
    method parseTestFunctionOutput (line 34) | func (self *testParser) parseTestFunctionOutput() {
    method processLines (line 42) | func (self *testParser) processLines() {
    method processLine (line 50) | func (self *testParser) processLine() bool {
    method accountForOutputWithoutNewline (line 79) | func (self *testParser) accountForOutputWithoutNewline() {
    method deserializeJson (line 86) | func (self *testParser) deserializeJson() {
    method parsePanicOutput (line 95) | func (self *testParser) parsePanicOutput() {
    method parsePanicLocation (line 102) | func (self *testParser) parsePanicLocation(index int, line string) {
    method preserveStackTraceIndentation (line 114) | func (self *testParser) preserveStackTraceIndentation(index int, line ...
    method parseLogLocation (line 119) | func (self *testParser) parseLogLocation() {
    method composeCapturedOutput (line 130) | func (self *testParser) composeCapturedOutput() {
  function parseTestOutput (line 22) | func parseTestOutput(test *contract.TestResult) *contract.TestResult {
  function newTestParser (line 28) | func newTestParser(test *contract.TestResult) *testParser {
  function createArrayForJsonItems (line 134) | func createArrayForJsonItems(lines []string) []byte {
  function removeTrailingComma (line 139) | func removeTrailingComma(rawJson string) string {
  function trailingComma (line 145) | func trailingComma(value string) bool {
  function isGoTestLogOutput (line 149) | func isGoTestLogOutput(line string) bool {
  function isPanic (line 153) | func isPanic(line string) bool {
  function panicLineHasMetadata (line 157) | func panicLineHasMetadata(line string) bool {
  function panicLineShouldBeIndented (line 160) | func panicLineShouldBeIndented(index int, line string) bool {
  constant bugReportRequest (line 164) | bugReportRequest = `

FILE: web/server/parser/util.go
  function parseTestFunctionDuration (line 12) | func parseTestFunctionDuration(line string) float64 {
  function parseDurationInSeconds (line 19) | func parseDurationInSeconds(raw string, precision int) float64 {
  function round (line 36) | func round(x float64, precision int) float64 {

FILE: web/server/system/shell.go
  type Shell (line 15) | type Shell struct
    method GoTest (line 31) | func (self *Shell) GoTest(directory, packageName string, tags, argumen...
  function NewShell (line 22) | func NewShell(gobin, reportsPath string, coverage bool, defaultTimeout s...
  function findGoConvey (line 50) | func findGoConvey(directory, gobin, packageName, tagsArg string) Command {
  function runWithCoverage (line 54) | func runWithCoverage(goconvey Command, coverage bool, reportPath, direct...
  function runWithoutCoverage (line 79) | func runWithoutCoverage(withCoverage, goconvey Command, directory, gobin...
  function generateReports (line 106) | func generateReports(previous Command, coverage bool, directory, gobin, ...
  type Command (line 122) | type Command struct
    method Execute (line 139) | func (this Command) Execute() Command {
  function NewCommand (line 131) | func NewCommand(directory, executable string, arguments ...string) Comma...
  constant goconveyDSLImport (line 158) | goconveyDSLImport = "github.com/smartystreets/goconvey/convey "
  constant gopathProblem (line 159) | gopathProblem = "Please run goconvey from within $GOPATH/src (also, syml...

FILE: web/server/system/shell_integration_test.go
  function TestShellIntegration (line 12) | func TestShellIntegration(t *testing.T) {

FILE: web/server/system/shell_test.go
  function TestShellCommandComposition (line 10) | func TestShellCommandComposition(t *testing.T) {

FILE: web/server/watch/functional_core.go
  function Categorize (line 14) | func Categorize(items chan *FileSystemItem, root string, watchSuffixes [...
  function foundInHiddenDirectory (line 33) | func foundInHiddenDirectory(item *FileSystemItem, root string) bool {
  function isHidden (line 47) | func isHidden(path string) bool {
  function ParseProfile (line 53) | func ParseProfile(profile string) (isDisabled bool, tags, arguments []st...
  function CreateFolders (line 91) | func CreateFolders(items []*FileSystemItem) messaging.Folders {
  function LimitDepth (line 103) | func LimitDepth(folders messaging.Folders, depth int) {
  function AttachProfiles (line 117) | func AttachProfiles(folders messaging.Folders, items []*FileSystemItem) {
  function MarkIgnored (line 144) | func MarkIgnored(folders messaging.Folders, ignored map[string]struct{}) {
  function ActiveFolders (line 160) | func ActiveFolders(folders messaging.Folders) messaging.Folders {
  function Sum (line 175) | func Sum(folders messaging.Folders, items []*FileSystemItem) int64 {
  constant slash (line 187) | slash = string(os.PathSeparator)

FILE: web/server/watch/functional_core_test.go
  function TestCategorize (line 11) | func TestCategorize(t *testing.T) {
  function TestParseProfile (line 132) | func TestParseProfile(t *testing.T) {
  function TestCreateFolders (line 224) | func TestCreateFolders(t *testing.T) {
  function TestLimitDepth (line 246) | func TestLimitDepth(t *testing.T) {
  function TestAttachProfiles (line 284) | func TestAttachProfiles(t *testing.T) {
  function TestAttachMainProfiles (line 340) | func TestAttachMainProfiles(t *testing.T) {
  function TestMarkIgnored (line 393) | func TestMarkIgnored(t *testing.T) {
  function TestActiveFolders (line 433) | func TestActiveFolders(t *testing.T) {
  function TestSum (line 459) | func TestSum(t *testing.T) {

FILE: web/server/watch/imperative_shell.go
  type FileSystemItem (line 13) | type FileSystemItem struct
  function YieldFileSystemItems (line 28) | func YieldFileSystemItems(root string, excludedDirs []string) chan *File...
  function ReadContents (line 71) | func ReadContents(path string) string {

FILE: web/server/watch/integration.go
  type Watcher (line 13) | type Watcher struct
    method Listen (line 46) | func (w *Watcher) Listen() {
    method respond (line 63) | func (w *Watcher) respond(command messaging.WatcherCommand) bool {
    method execute (line 109) | func (w *Watcher) execute() {
    method scan (line 114) | func (w *Watcher) scan() {
    method gather (line 127) | func (w *Watcher) gather() (folders messaging.Folders, checksum int64) {
    method set (line 150) | func (w *Watcher) set(state int64) {
    method sendToExecutor (line 154) | func (w *Watcher) sendToExecutor(folders messaging.Folders) {
    method ignore (line 158) | func (w *Watcher) ignore(paths string) {
    method reinstate (line 166) | func (w *Watcher) reinstate(paths string) {
    method protectedWrite (line 173) | func (w *Watcher) protectedWrite(protected func()) {
    method protectedRead (line 178) | func (w *Watcher) protectedRead(protected func()) {
  function NewWatcher (line 30) | func NewWatcher(rootFolder string, folderDepth int, nap time.Duration,

FILE: web/server/watch/integration_test.go
  function TestWatcher (line 17) | func TestWatcher(t *testing.T) {

FILE: web/server/watch/integration_testing/main.go
  function main (line 8) | func main() {

FILE: web/server/watch/integration_testing/sub/stuff_test.go
  function TestStuff (line 11) | func TestStuff(t *testing.T) {

FILE: web/server/watch/util_test.go
  function CopyFile (line 10) | func CopyFile(source string, destination string) (err error) {
  function CopyDir (line 35) | func CopyDir(source string, destination string) (err error) {
  type CustomError (line 85) | type CustomError struct
    method Error (line 90) | func (this *CustomError) Error() string {
Condensed preview — 125 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,483K chars).
[
  {
    "path": ".gitattributes",
    "chars": 48,
    "preview": "web/client/resources/js/lib/* linguist-vendored\n"
  },
  {
    "path": ".gitignore",
    "chars": 78,
    "preview": ".DS_Store\nThumbs.db\nexamples/output.json\nweb/client/reports/\n/.idea\n/goconvey\n"
  },
  {
    "path": ".travis.yml",
    "chars": 216,
    "preview": "arch:\n  - amd64\n  - ppc64le\n\nlanguage: go\n\ngo:\n  - 1.13.x\n  - 1.14.x\n  - 1.15.x\n  - 1.16.x\n  - master\n\ninstall:\n  - go g"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3402,
    "preview": "# Subject: GoConvey maintainers wanted\n\nWe'd like to open the project up to additional maintainers who want to move the "
  },
  {
    "path": "LICENSE.md",
    "chars": 1286,
    "preview": "MIT License\n\nCopyright (c) 2022 Smarty\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "README.md",
    "chars": 4083,
    "preview": "# SMARTY DISCLAIMER: Subject to the terms of the associated license agreement, this software is freely available for you"
  },
  {
    "path": "check_third_party.sh",
    "chars": 292,
    "preview": "#!/usr/bin/env bash\n\ncd \"$(dirname $(realpath $0))\"\n\nbash ./web/client/resources/js/lib/update.sh\n\nif ! (git diff-files "
  },
  {
    "path": "convey/assertions.go",
    "chars": 4122,
    "preview": "package convey\n\n// DO NOT EDIT: generated by update_assertions.sh\n\n//go:generate ./update_assertions.sh\n\nimport \"github."
  },
  {
    "path": "convey/context.go",
    "chars": 7716,
    "preview": "package convey\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jtolds/gls\"\n\t\"github.com/smartystreets/goconvey/convey/reporting\"\n)\n\ntype "
  },
  {
    "path": "convey/convey.goconvey",
    "chars": 188,
    "preview": "#ignore\n-timeout=1s\n#-covermode=count\n#-coverpkg=github.com/smartystreets/goconvey/convey,github.com/smartystreets/gocon"
  },
  {
    "path": "convey/discovery.go",
    "chars": 2645,
    "preview": "package convey\n\ntype actionSpecifier uint8\n\nconst (\n\tnoSpecifier actionSpecifier = iota\n\tskipConvey\n\tfocusConvey\n)\n\ntype"
  },
  {
    "path": "convey/doc.go",
    "chars": 10155,
    "preview": "// Package convey contains all of the public-facing entry points to this project.\n// This means that it should never be "
  },
  {
    "path": "convey/focused_execution_test.go",
    "chars": 1099,
    "preview": "package convey\n\nimport \"testing\"\n\nfunc TestFocusOnlyAtTopLevel(t *testing.T) {\n\toutput := prepare()\n\n\tFocusConvey(\"hi\", "
  },
  {
    "path": "convey/gotest/doc_test.go",
    "chars": 15,
    "preview": "package gotest\n"
  },
  {
    "path": "convey/gotest/utils.go",
    "chars": 832,
    "preview": "// Package gotest contains internal functionality. Although this package\n// contains one or more exported names it is no"
  },
  {
    "path": "convey/init.go",
    "chars": 1980,
    "preview": "package convey\n\nimport (\n\t\"flag\"\n\t\"os\"\n\n\t\"github.com/jtolds/gls\"\n\t\"github.com/smarty/assertions\"\n\t\"github.com/smartystre"
  },
  {
    "path": "convey/isolated_execution_test.go",
    "chars": 12974,
    "preview": "package convey\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestSingleScope(t *testing.T) {\n\toutput := prepare()\n\n\tCo"
  },
  {
    "path": "convey/nilReporter.go",
    "chars": 642,
    "preview": "package convey\n\nimport (\n\t\"github.com/smartystreets/goconvey/convey/reporting\"\n)\n\ntype nilReporter struct{}\n\nfunc (self "
  },
  {
    "path": "convey/reporting/console.go",
    "chars": 210,
    "preview": "package reporting\n\nimport (\n\t\"fmt\"\n\t\"io\"\n)\n\ntype console struct{}\n\nfunc (self *console) Write(p []byte) (n int, err erro"
  },
  {
    "path": "convey/reporting/doc.go",
    "chars": 256,
    "preview": "// Package reporting contains internal functionality related\n// to console reporting and output. Although this package h"
  },
  {
    "path": "convey/reporting/dot.go",
    "chars": 808,
    "preview": "package reporting\n\nimport \"fmt\"\n\ntype dot struct{ out *Printer }\n\nfunc (self *dot) BeginStory(story *StoryReport) {}\n\nfu"
  },
  {
    "path": "convey/reporting/dot_test.go",
    "chars": 897,
    "preview": "package reporting\n\nimport (\n\t\"errors\"\n\t\"testing\"\n)\n\nfunc TestDotReporterAssertionPrinting(t *testing.T) {\n\tmonochrome()\n"
  },
  {
    "path": "convey/reporting/gotest.go",
    "chars": 674,
    "preview": "package reporting\n\ntype gotestReporter struct{ test T }\n\nfunc (self *gotestReporter) BeginStory(story *StoryReport) {\n\ts"
  },
  {
    "path": "convey/reporting/gotest_test.go",
    "chars": 1582,
    "preview": "package reporting\n\nimport \"testing\"\n\nfunc TestReporterReceivesSuccessfulReport(t *testing.T) {\n\treporter := NewGoTestRep"
  },
  {
    "path": "convey/reporting/init.go",
    "chars": 2239,
    "preview": "package reporting\n\nimport (\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n)\n\nfunc init() {\n\tif !isColorableTerminal() {\n\t\tmonochrome()\n\t}\n"
  },
  {
    "path": "convey/reporting/json.go",
    "chars": 2227,
    "preview": "// TODO: under unit test\n\npackage reporting\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype JsonReporter s"
  },
  {
    "path": "convey/reporting/printer.go",
    "chars": 1326,
    "preview": "package reporting\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n)\n\ntype Printer struct {\n\tout    io.Writer\n\tprefix string\n}\n\nfunc (s"
  },
  {
    "path": "convey/reporting/printer_test.go",
    "chars": 3933,
    "preview": "package reporting\n\nimport \"testing\"\n\nfunc TestPrint(t *testing.T) {\n\tfile := newMemoryFile()\n\tprinter := NewPrinter(file"
  },
  {
    "path": "convey/reporting/problems.go",
    "chars": 1826,
    "preview": "package reporting\n\nimport \"fmt\"\n\ntype problem struct {\n\tsilent   bool\n\tout      *Printer\n\terrors   []*AssertionResult\n\tf"
  },
  {
    "path": "convey/reporting/problems_test.go",
    "chars": 1376,
    "preview": "package reporting\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestNoopProblemReporterActions(t *testing.T) {\n\tfile, reporter"
  },
  {
    "path": "convey/reporting/reporter.go",
    "chars": 1138,
    "preview": "package reporting\n\nimport \"io\"\n\ntype Reporter interface {\n\tBeginStory(story *StoryReport)\n\tEnter(scope *ScopeReport)\n\tRe"
  },
  {
    "path": "convey/reporting/reporter_test.go",
    "chars": 2093,
    "preview": "package reporting\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n)\n\nfunc TestEachNestedReporterReceivesTheCallFromTheContainingReporter"
  },
  {
    "path": "convey/reporting/reporting.goconvey",
    "chars": 20,
    "preview": "#ignore\n-timeout=1s\n"
  },
  {
    "path": "convey/reporting/reports.go",
    "chars": 4248,
    "preview": "package reporting\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/smartystreets/goconvey/convey/go"
  },
  {
    "path": "convey/reporting/statistics.go",
    "chars": 2074,
    "preview": "package reporting\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc (self *statistics) BeginStory(story *StoryReport) {}\n\nfunc (self *sta"
  },
  {
    "path": "convey/reporting/story.go",
    "chars": 1691,
    "preview": "// TODO: in order for this reporter to be completely honest\n// we need to retrofit to be more like the json reporter suc"
  },
  {
    "path": "convey/reporting_hooks_test.go",
    "chars": 7460,
    "preview": "package convey\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"path\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\""
  },
  {
    "path": "convey/stack_trace_test.go",
    "chars": 3601,
    "preview": "package convey\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/smartystreets/goconvey/convey/reporting\"\n)"
  },
  {
    "path": "convey/story_conventions_test.go",
    "chars": 3521,
    "preview": "package convey\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc expectPanic(t *testing.T, f string) any {\n\tr := recover()\n\tif r !"
  },
  {
    "path": "convey/update_assertions.sh",
    "chars": 766,
    "preview": "#!/usr/bin/env bash\n\ncd \"$(dirname $(realpath $0))\"\n\nASSERTIONS=($(\n  go tool nm \"$(go list -export -f '{{.Export}}' git"
  },
  {
    "path": "examples/assertion_examples_test.go",
    "chars": 4131,
    "preview": "package examples\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/smartystreets/goconvey/convey\"\n)\n\nfunc Test"
  },
  {
    "path": "examples/bowling_game.go",
    "chars": 2045,
    "preview": "package examples\n\n// Game contains the state of a bowling game.\ntype Game struct {\n\trolls   []int\n\tcurrent int\n}\n\n// New"
  },
  {
    "path": "examples/bowling_game_test.go",
    "chars": 1598,
    "preview": "/*\n\nReference: http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata\n\nSee the very first link (which happens to be"
  },
  {
    "path": "examples/doc.go",
    "chars": 312,
    "preview": "// Package examples contains, well, examples of how to use goconvey to\n// specify behavior of a system under test. It co"
  },
  {
    "path": "examples/examples.goconvey",
    "chars": 438,
    "preview": "// Uncomment the next line to disable the package when running the GoConvey UI:\n//IGNORE\n\n// Uncomment the next line to "
  },
  {
    "path": "examples/simple_example_test.go",
    "chars": 702,
    "preview": "package examples\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/smartystreets/goconvey/convey\"\n)\n\nfunc TestIntegerManipulation(t *"
  },
  {
    "path": "go.mod",
    "chars": 276,
    "preview": "module github.com/smartystreets/goconvey\n\ngo 1.21.7\n\nrequire (\n\tgithub.com/jtolds/gls v4.20.0+incompatible\n\tgithub.com/s"
  },
  {
    "path": "go.sum",
    "chars": 1006,
    "preview": "github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=\ngithub.com/gopherjs/gopherjs v1.17."
  },
  {
    "path": "goconvey.go",
    "chars": 10044,
    "preview": "// This executable provides an HTTP server that watches for file system changes\n// to .go files within the working direc"
  },
  {
    "path": "web/client/composer.html",
    "chars": 1083,
    "preview": "<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n\t\t<title>GoConvey C"
  },
  {
    "path": "web/client/index.html",
    "chars": 18262,
    "preview": "<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<title>GoConvey</title>\n\t\t<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n\t\t<l"
  },
  {
    "path": "web/client/resources/css/common.css",
    "chars": 13719,
    "preview": "/* Eric Meyer's Reset CSS v2.0 */\nhtml,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acro"
  },
  {
    "path": "web/client/resources/css/composer.css",
    "chars": 1823,
    "preview": "/* Eric Meyer's Reset CSS v2.0 */\nhtml,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acro"
  },
  {
    "path": "web/client/resources/css/themes/dark-bigtext.css",
    "chars": 9562,
    "preview": "/* This is a fork of the dark.css theme. The only changes from dark.css are near the very end. */\n\n::-webkit-scrollbar {"
  },
  {
    "path": "web/client/resources/css/themes/dark.css",
    "chars": 9074,
    "preview": "::-webkit-scrollbar {\n\twidth: 10px;\n\theight: 10px;\n}\n\n::-webkit-scrollbar-corner {\n\tbackground: transparent;\n}\n\n::-webki"
  },
  {
    "path": "web/client/resources/css/themes/light.css",
    "chars": 4496,
    "preview": "::-webkit-scrollbar-thumb {\n\tbackground-color: rgba(0, 0, 0, .35);\n\tborder-radius: 10px;\n}\n\n::-webkit-input-placeholder "
  },
  {
    "path": "web/client/resources/css/tipsy.css",
    "chars": 1634,
    "preview": ".tipsy {\n\tfont-size: 12px;\n\tposition: absolute;\n\tpadding: 8px;\n\tz-index: 100000;\n\tfont-family: 'Open Sans';\n\tline-height"
  },
  {
    "path": "web/client/resources/fonts/FontAwesome/README.md",
    "chars": 4734,
    "preview": "#[Font Awesome v4.5.0](http://fontawesome.io)\n###The iconic font and CSS framework\n\nFont Awesome is a full suite of 605 "
  },
  {
    "path": "web/client/resources/fonts/FontAwesome/css/font-awesome.css",
    "chars": 33233,
    "preview": "/*!\n *  Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/lice"
  },
  {
    "path": "web/client/resources/fonts/Open_Sans/LICENSE.txt",
    "chars": 11560,
    "preview": "\r\n                                 Apache License\r\n                           Version 2.0, January 2004\r\n               "
  },
  {
    "path": "web/client/resources/fonts/Orbitron/OFL.txt",
    "chars": 4488,
    "preview": "Copyright (c) 2009, Matt McInerney (matt@pixelspread.com),\r\nwith Reserved Font Name Orbitron.\r\nThis Font Software is lic"
  },
  {
    "path": "web/client/resources/fonts/Oswald/OFL.txt",
    "chars": 4494,
    "preview": "Copyright (c) 2011-2012, Vernon Adams (vern@newtypography.co.uk), with Reserved Font Names 'Oswald'\r\nThis Font Software "
  },
  {
    "path": "web/client/resources/js/composer.js",
    "chars": 3614,
    "preview": "var composer = {\n\ttab: \"\\t\",\n\ttemplate: \"\",\n\tisFunc: function(scope)\n\t{\n\t\tif (!scope.title || typeof scope.depth === 'un"
  },
  {
    "path": "web/client/resources/js/config.js",
    "chars": 560,
    "preview": "// Configure the GoConvey web UI client in here\n\nconvey.config = {\n\n\t// Install new themes by adding them here; the firs"
  },
  {
    "path": "web/client/resources/js/convey.js",
    "chars": 2110,
    "preview": "var convey = {\n\n\t//\t*** Don't edit in here unless you're brave ***\n\n\tstatuses: {\t\t\t\t// contains some constants related t"
  },
  {
    "path": "web/client/resources/js/goconvey.js",
    "chars": 35188,
    "preview": "$(init);\n\n$(window).load(function()\n{\n\t// Things may shift after all the elements (images/fonts) are loaded\n\t// In Chrom"
  },
  {
    "path": "web/client/resources/js/lib/ansispan.js",
    "chars": 2166,
    "preview": "/*\nCopyright (C) 2011 by Maciej Małecki\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
  },
  {
    "path": "web/client/resources/js/lib/diff_match_patch.js",
    "chars": 76493,
    "preview": "/**\n * Diff Match and Patch\n *\n * Copyright 2006 Google Inc.\n * http://code.google.com/p/google-diff-match-patch/\n *\n * "
  },
  {
    "path": "web/client/resources/js/lib/jquery-ui.js",
    "chars": 436715,
    "preview": "/*! jQuery UI - v1.10.4 - 2014-01-17\n* http://jqueryui.com\n* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui"
  },
  {
    "path": "web/client/resources/js/lib/jquery-ui.js.url",
    "chars": 47,
    "preview": "https://code.jquery.com/ui/1.10.4/jquery-ui.js\n"
  },
  {
    "path": "web/client/resources/js/lib/jquery.js",
    "chars": 244963,
    "preview": "/*!\n * jQuery JavaScript Library v2.1.0\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Cop"
  },
  {
    "path": "web/client/resources/js/lib/jquery.js.url",
    "chars": 40,
    "preview": "https://code.jquery.com/jquery-2.1.0.js\n"
  },
  {
    "path": "web/client/resources/js/lib/jquery.pretty-text-diff.js",
    "chars": 2208,
    "preview": "// Generated by CoffeeScript 1.4.0\n\n/*\n@preserve jQuery.PrettyTextDiff 1.0.2\nSee https://github.com/arnab/jQuery.PrettyT"
  },
  {
    "path": "web/client/resources/js/lib/jquery.pretty-text-diff.js.url",
    "chars": 95,
    "preview": "https://raw.githubusercontent.com/arnab/jQuery.PrettyTextDiff/1.0.2/jquery.pretty-text-diff.js\n"
  },
  {
    "path": "web/client/resources/js/lib/jquery.tipsy.js",
    "chars": 7282,
    "preview": "// tipsy, facebook style tooltips for jquery\n// version 1.0.0a\n// (c) 2008-2010 jason frame [jason@onehackoranother.com]"
  },
  {
    "path": "web/client/resources/js/lib/jquery.tipsy.js.url",
    "chars": 87,
    "preview": "https://raw.githubusercontent.com/jaz303/tipsy/v1.0.0a/src/javascripts/jquery.tipsy.js\n"
  },
  {
    "path": "web/client/resources/js/lib/markup.js",
    "chars": 14153,
    "preview": "/*\n  Markup.js v1.5.21: http://github.com/adammark/Markup.js\n  MIT License\n  (c) 2011 - 2014 Adam Mark\n*/\nvar Mark = {\n "
  },
  {
    "path": "web/client/resources/js/lib/markup.js.url",
    "chars": 74,
    "preview": "https://raw.githubusercontent.com/adammark/Markup.js/master/src/markup.js\n"
  },
  {
    "path": "web/client/resources/js/lib/moment.js",
    "chars": 100788,
    "preview": "//! moment.js\n//! version : 2.10.2\n//! authors : Tim Wood, Iskren Chernev, Moment.js contributors\n//! license : MIT\n//! "
  },
  {
    "path": "web/client/resources/js/lib/moment.js.url",
    "chars": 65,
    "preview": "https://raw.githubusercontent.com/moment/moment/2.10.2/moment.js\n"
  },
  {
    "path": "web/client/resources/js/lib/taboverride.js",
    "chars": 30839,
    "preview": "/*! taboverride v4.0.3 | https://github.com/wjbryant/taboverride\n(c) 2015 Bill Bryant | http://opensource.org/licenses/m"
  },
  {
    "path": "web/client/resources/js/lib/taboverride.js.url",
    "chars": 89,
    "preview": "https://raw.githubusercontent.com/wjbryant/taboverride/4.0.3/build/output/taboverride.js\n"
  },
  {
    "path": "web/client/resources/js/lib/update.sh",
    "chars": 247,
    "preview": "#!/usr/bin/env bash\n\ncd \"$(dirname $(realpath $0))\"\n\nconfig_file=()\n\nfor url in *.url; do\n  config_file+=(-o\"$(basename "
  },
  {
    "path": "web/client/resources/js/poller.js",
    "chars": 2619,
    "preview": "function Poller(config)\n{\n\t// CONFIGURABLE\n\tvar endpoints = {\n\t\tup: \"/status/poll\",\t\t// url to poll when the server is u"
  },
  {
    "path": "web/server/api/api.goconvey",
    "chars": 20,
    "preview": "#ignore\n-timeout=1s\n"
  },
  {
    "path": "web/server/api/server.go",
    "chars": 4516,
    "preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/smartystreets/goconvey/"
  },
  {
    "path": "web/server/api/server_test.go",
    "chars": 13929,
    "preview": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n"
  },
  {
    "path": "web/server/contract/contracts.go",
    "chars": 847,
    "preview": "package contract\n\nimport \"net/http\"\n\ntype (\n\tServer interface {\n\t\tReceiveUpdate(root string, update *CompleteOutput)\n\t\tW"
  },
  {
    "path": "web/server/contract/doc_test.go",
    "chars": 17,
    "preview": "package contract\n"
  },
  {
    "path": "web/server/contract/result.go",
    "chars": 2231,
    "preview": "package contract\n\nimport (\n\t\"github.com/smartystreets/goconvey/convey/reporting\"\n\t\"github.com/smartystreets/goconvey/web"
  },
  {
    "path": "web/server/executor/contract.go",
    "chars": 230,
    "preview": "package executor\n\nimport \"github.com/smartystreets/goconvey/web/server/contract\"\n\ntype Parser interface {\n\tParse([]*cont"
  },
  {
    "path": "web/server/executor/coordinator.go",
    "chars": 1791,
    "preview": "package executor\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/smartystreets/goconvey/web/server/co"
  },
  {
    "path": "web/server/executor/executor.go",
    "chars": 1632,
    "preview": "package executor\n\nimport (\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/smartystreets/goconvey/web/server/contract\"\n)\n\nconst (\n\tIdle    "
  },
  {
    "path": "web/server/executor/executor.goconvey",
    "chars": 20,
    "preview": "#ignore\n-timeout=1s\n"
  },
  {
    "path": "web/server/executor/executor_test.go",
    "chars": 3936,
    "preview": "package executor\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/smartystreets/goconvey/convey\"\n\t\"github.com/sma"
  },
  {
    "path": "web/server/executor/tester.go",
    "chars": 1513,
    "preview": "package executor\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/smartystreets/goconvey/web/server/contract\"\n"
  },
  {
    "path": "web/server/executor/tester_test.go",
    "chars": 6473,
    "preview": "package executor\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/smartystreets/goconve"
  },
  {
    "path": "web/server/messaging/doc_test.go",
    "chars": 18,
    "preview": "package messaging\n"
  },
  {
    "path": "web/server/messaging/messages.go",
    "chars": 1111,
    "preview": "package messaging\n\n///////////////////////////////////////////////////////////////////////////////\n\ntype WatcherCommand "
  },
  {
    "path": "web/server/parser/packageParser.go",
    "chars": 5125,
    "preview": "package parser\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/smartystreets/goconvey/web/server/"
  },
  {
    "path": "web/server/parser/package_parser_test.go",
    "chars": 44433,
    "preview": "package parser\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/smartystreets/goconvey"
  },
  {
    "path": "web/server/parser/parser.go",
    "chars": 716,
    "preview": "package parser\n\nimport (\n\t\"log\"\n\n\t\"github.com/smartystreets/goconvey/web/server/contract\"\n)\n\ntype Parser struct {\n\tparse"
  },
  {
    "path": "web/server/parser/parser.goconvey",
    "chars": 20,
    "preview": "#ignore\n-timeout=1s\n"
  },
  {
    "path": "web/server/parser/parser_test.go",
    "chars": 1537,
    "preview": "package parser\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t. \"github.com/smartystreets/goconvey/convey\"\n\t\"github.com/smartystreets/"
  },
  {
    "path": "web/server/parser/rules.go",
    "chars": 1635,
    "preview": "package parser\n\nimport \"strings\"\n\nfunc noGoFiles(line string) bool {\n\treturn strings.HasPrefix(line, \"can't load package"
  },
  {
    "path": "web/server/parser/testParser.go",
    "chars": 4657,
    "preview": "package parser\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/smartystreets/goconvey/convey/repor"
  },
  {
    "path": "web/server/parser/util.go",
    "chars": 1253,
    "preview": "package parser\n\nimport (\n\t\"math\"\n\t\"strings\"\n\t\"time\"\n)\n\n// parseTestFunctionDuration parses the duration in seconds as a "
  },
  {
    "path": "web/server/system/shell.go",
    "chars": 5285,
    "preview": "package system\n\nimport (\n\t\"log\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n)\n\n////////////////////////////////////"
  },
  {
    "path": "web/server/system/shell_integration_test.go",
    "chars": 909,
    "preview": "package system\n\nimport (\n\t\"log\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"testing\"\n)\n\nfunc TestShellIntegration(t *testi"
  },
  {
    "path": "web/server/system/shell_test.go",
    "chars": 8154,
    "preview": "package system\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t. \"github.com/smartystreets/goconvey/convey\"\n)\n\nfunc TestShellCommandCom"
  },
  {
    "path": "web/server/system/system.goconvey",
    "chars": 26,
    "preview": "#ignore\n-timeout=1s\n-short"
  },
  {
    "path": "web/server/watch/functional_core.go",
    "chars": 4974,
    "preview": "package watch\n\nimport (\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/smartystreets/goconvey/web/server/messag"
  },
  {
    "path": "web/server/watch/functional_core_test.go",
    "chars": 12340,
    "preview": "package watch\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t. \"github.com/smartystreets/goconvey/convey\"\n\t\"github.com/smartystreets/goco"
  },
  {
    "path": "web/server/watch/imperative_shell.go",
    "chars": 1938,
    "preview": "package watch\n\nimport (\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n////////////////////////////////////////"
  },
  {
    "path": "web/server/watch/integration.go",
    "chars": 4447,
    "preview": "package watch\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/smartystreets/goconvey/web/server/messagin"
  },
  {
    "path": "web/server/watch/integration_test.go",
    "chars": 5213,
    "preview": "package watch\n\nimport (\n\t\"bytes\"\n\t\"log\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/"
  },
  {
    "path": "web/server/watch/integration_testing/doc_test.go",
    "chars": 13,
    "preview": "package main\n"
  },
  {
    "path": "web/server/watch/integration_testing/main.go",
    "chars": 203,
    "preview": "// This file's only purpose is to provide a realistic\n// environment from which to run integration tests\n// against the "
  },
  {
    "path": "web/server/watch/integration_testing/sub/.gitignore",
    "chars": 159,
    "preview": "github.com-smartystreets-goconvey-web-server-watch-integration_testing-sub.html\ngithub.com-smartystreets-goconvey-web-se"
  },
  {
    "path": "web/server/watch/integration_testing/sub/stuff.go",
    "chars": 141,
    "preview": "// This file's only purpose is to provide a realistic\n// environment from which to run integration tests\n// against the "
  },
  {
    "path": "web/server/watch/integration_testing/sub/stuff_test.go",
    "chars": 255,
    "preview": "// This file's only purpose is to provide a realistic\n// environment from which to run integration tests\n// against the "
  },
  {
    "path": "web/server/watch/integration_testing/sub/sub.goconvey",
    "chars": 159,
    "preview": "IGNORE\n-short\n-run=TestStuff\n\n// This file's only purpose is to provide a realistic\n// environment from which to run int"
  },
  {
    "path": "web/server/watch/util_test.go",
    "chars": 1965,
    "preview": "// Credits: https://gist.github.com/jaybill/2876519\npackage watch\n\nimport \"os\"\nimport \"io\"\nimport \"io/ioutil\"\nimport \"lo"
  },
  {
    "path": "web/server/watch/watch.goconvey",
    "chars": 26,
    "preview": "#ignore\n-timeout=1s\n-short"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the smartystreets/goconvey GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 125 files (1.3 MB), approximately 372.2k tokens, and a symbol index with 1036 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!