func FuncNameSpec(c nanospec.Context) { c.Specify("The name of a function can be retrieved from a function reference", func() { name := functionName(dummyFunction) c.Expect(name).Equals("gospec.dummyFunction") }) c.Specify("Getting the name of an anonymous functions will fail gracefully", func() { name := functionName(func() {}) c.Expect(name).Equals("<unknown function>") }) }
func ConcurrencySpec(c nanospec.Context) { r := NewRunner() r.AddSpec(VerySlowDummySpec) start := time.Nanoseconds() r.Run() end := time.Nanoseconds() totalTime := end - start // If the spec is executed single-threadedly, then it would take // at least 4*DELAY to execute. If executed multi-threadedly, it // would take at least 2*DELAY to execute, because the first spec // needs to be executed fully before the other specs are found, but // after that the other specs can be executed in parallel. expectedMaxTime := int64(math.Floor(2.9 * DELAY)) if totalTime > expectedMaxTime { c.Errorf("Expected the run to take less than %v ms but it took %v ms", expectedMaxTime/MILLISECOND, totalTime/MILLISECOND) } runCounts := countSpecNames(r.executed) c.Expect(runCounts["Child A"]).Equals(1) c.Expect(runCounts["Child B"]).Equals(1) c.Expect(runCounts["Child C"]).Equals(1) c.Expect(runCounts["Child D"]).Equals(1) }
func LocationSpec(c nanospec.Context) { c.Specify("Location of the current method can be found", func() { loc := currentLocation() // line 16 c.Expect(loc.FileName()).Equals("location_test.go") c.Expect(loc.Line()).Equals(16) }) c.Specify("The line number is that of the call instruction; not where the call will return to", func() { // This indirection is needed to reproduce the off-by-one issue, because // there must be no instructions on the same line after the call itself. var loc *Location f := func() { loc = callerLocation() } f() // line 27; call returns to line 28 c.Expect(loc.Line()).Equals(27) }) c.Specify("Location of the calling method can be found", func() { loc := callerLocation() c.Expect(loc.FileName()).Equals("context.go") }) c.Specify("The name of the method is provided", func() { loc := methodWhereLocationIsCalled() c.Expect(loc.Name()).Equals("gospec.methodWhereLocationIsCalled") }) c.Specify("Calls to newLocation are synced with the helper methods", func() { c.Expect(newLocation(0).Name()).Equals(currentLocation().Name()) c.Expect(newLocation(0).File()).Equals(currentLocation().File()) c.Expect(newLocation(1).Name()).Equals(callerLocation().Name()) c.Expect(newLocation(1).File()).Equals(callerLocation().File()) }) c.Specify("Program Counters can be converted to Locations", func() { expectedLine := currentLocation().Line() + 1 pc, _, _, _ := runtime.Caller(0) loc := locationForPC(pc) c.Expect(loc.FileName()).Equals("location_test.go") c.Expect(loc.Line()).Equals(expectedLine) }) }
func RecoverSpec(c nanospec.Context) { c.Specify("When the called function panics", func() { err := recoverOnPanic(boom2) c.Specify("the cause is returned", func() { c.Expect(err.Cause).Equals("boom!") }) c.Specify("the stack trace begins with the panicking line", func() { c.Expect(err.StackTrace[0].Name()).Equals("gospec.boom0") }) c.Specify("the stack trace includes all parent functions", func() { c.Expect(err.StackTrace[1].Name()).Equals("gospec.boom1") }) c.Specify("the stack trace ends with the called function", func() { lastEntry := err.StackTrace[len(err.StackTrace)-1] c.Expect(lastEntry.Name()).Equals("gospec.boom2") }) c.Specify("the stack trace line numbers are the line of the call; not where the call will return", func() { // For an explanation, see the comments at http://code.google.com/p/go/issues/detail?id=1100 c.Expect(err.StackTrace[0].Line()).Equals(19) }) }) c.Specify("When the called function does not panic", func() { err := recoverOnPanic(noBoom) c.Specify("there is no error", func() { c.Expect(err == nil).IsTrue() }) }) }
func ExpectationsSpec(c nanospec.Context) { c.Specify("When a spec has passing expectations or assumptions", func() { results := runSpec(func(c Context) { c.Expect(1, Equals, 1) c.Assume(1, Equals, 1) c.Specify("Child", func() {}) }) c.Specify("then the spec passes", func() { c.Expect(results.FailCount()).Equals(0) }) c.Specify("then its children are executed", func() { c.Expect(results.TotalCount()).Equals(2) }) }) c.Specify("When a spec has failing expectations", func() { results := runSpec(func(c Context) { c.Expect(1, Equals, 2) c.Specify("Child", func() {}) }) c.Specify("then the spec fails", func() { c.Expect(results.FailCount()).Equals(1) }) c.Specify("then its children are executed", func() { c.Expect(results.TotalCount()).Equals(2) }) }) c.Specify("When a spec has failing assumptions", func() { results := runSpec(func(c Context) { c.Assume(1, Equals, 2) c.Specify("Child", func() {}) }) c.Specify("then the spec fails", func() { c.Expect(results.FailCount()).Equals(1) }) c.Specify("then its children are NOT executed", func() { c.Expect(results.TotalCount()).Equals(1) }) }) c.Specify("The location of a failed expectation is reported", func() { results := runSpec(func(c Context) { c.Expect(1, Equals, 2) }) c.Expect(fileOfError(results)).Equals("expectations_test.go") }) c.Specify("The location of a failed assumption is reported", func() { results := runSpec(func(c Context) { c.Assume(1, Equals, 2) }) c.Expect(fileOfError(results)).Equals("expectations_test.go") }) }
func ContextSpec(c nanospec.Context) { c.Specify("When specs are executed", func() { result := runSpecWithContext(DummySpecWithTwoChildren, newInitialContext()) executed := result.executedSpecs postponed := result.postponedSpecs c.Specify("executed specs are reported", func() { c.Expect(len(executed)).Equals(2) c.Expect(executed[0].name).Equals("RootSpec") c.Expect(executed[1].name).Equals("Child A") }) c.Specify("postponed specs are reported", func() { c.Expect(len(postponed)).Equals(1) c.Expect(postponed[0].name).Equals("Child B") }) }) c.Specify("When some of the specs have previously been executed", func() { result := runSpecWithContext(DummySpecWithTwoChildren, newExplicitContext([]int{1})) executed := result.executedSpecs postponed := result.postponedSpecs c.Specify("previously executed specs are NOT reported", func() { c.Expect(len(executed)).Equals(2) c.Expect(executed[0].name).Equals("RootSpec") c.Expect(executed[1].name).Equals("Child B") c.Expect(len(postponed)).Equals(0) }) }) c.Specify("Postponed specs are scheduled for execution, until they all have been executed", func() { r := NewRunner() r.AddSpec(DummySpecWithTwoChildren) r.Run() runCounts := countSpecNames(r.executed) c.Expect(len(runCounts)).Equals(3) c.Expect(runCounts["gospec.DummySpecWithTwoChildren"]).Equals(2) c.Expect(runCounts["Child A"]).Equals(1) c.Expect(runCounts["Child B"]).Equals(1) }) c.Specify("Multiple specs can be executed in one batch", func() { r := NewRunner() r.AddSpec(DummySpecWithOneChild) r.AddSpec(DummySpecWithTwoChildren) r.Run() runCounts := countSpecNames(r.executed) c.Expect(runCounts["gospec.DummySpecWithOneChild"]).Equals(1) c.Expect(runCounts["gospec.DummySpecWithTwoChildren"]).Equals(2) }) }
func PrinterSpec(c nanospec.Context) { trim := strings.TrimSpace out := new(bytes.Buffer) p := NewPrinter(SimplePrintFormat(out)) c.Specify("When showing the summary", func() { p.ShowAll() p.ShowSummary() c.Specify("then the summary is printed", func() { p.VisitSpec(0, "Passing 1", noErrors) p.VisitSpec(0, "Passing 2", noErrors) p.VisitSpec(0, "Failing", someError) p.VisitEnd(2, 1) c.Expect(trim(out.String())).Equals(trim(` - Passing 1 - Passing 2 - Failing [FAIL] *** some error 3 specs, 1 failures `)) }) }) c.Specify("When hiding the summary", func() { p.ShowAll() p.HideSummary() c.Specify("then the summary is not printed", func() { p.VisitSpec(0, "Passing 1", noErrors) p.VisitSpec(0, "Passing 2", noErrors) p.VisitSpec(0, "Failing", someError) p.VisitEnd(2, 1) c.Expect(trim(out.String())).Equals(trim(` - Passing 1 - Passing 2 - Failing [FAIL] *** some error `)) }) }) c.Specify("When showing all specs", func() { p.ShowAll() c.Specify("then passing and failing specs are printed", func() { p.VisitSpec(0, "Passing", noErrors) p.VisitSpec(0, "Failing", someError) c.Expect(trim(out.String())).Equals(trim(` - Passing - Failing [FAIL] *** some error `)) }) }) c.Specify("When showing only failing specs", func() { p.ShowOnlyFailing() c.Specify("then only failing specs are printed", func() { p.VisitSpec(0, "Passing", noErrors) p.VisitSpec(0, "Failing", someError) c.Expect(trim(out.String())).Equals(trim(` - Failing [FAIL] *** some error `)) }) c.Specify("then the parents of failing specs are printed", func() { p.VisitSpec(0, "Passing parent", noErrors) p.VisitSpec(1, "Failing child", someError) c.Expect(trim(out.String())).Equals(trim(` - Passing parent - Failing child [FAIL] *** some error `)) }) c.Specify("Case: passing parent with many failing children; should print the parent only once", func() { p.VisitSpec(0, "Passing parent", noErrors) p.VisitSpec(1, "Failing child A", someError) p.VisitSpec(1, "Failing child B", someError) c.Expect(trim(out.String())).Equals(trim(` - Passing parent - Failing child A [FAIL] *** some error - Failing child B [FAIL] *** some error `)) }) c.Specify("Case: failing parent with a failing grandchild; should print the child in the middle", func() { p.VisitSpec(0, "Failing parent", someError) p.VisitSpec(1, "Passing child", noErrors) p.VisitSpec(2, "Failing grandchild", someError) c.Expect(trim(out.String())).Equals(trim(` - Failing parent [FAIL] *** some error - Passing child - Failing grandchild [FAIL] *** some error `)) }) c.Specify("Case: failing parent and ghosts of unrelated specs; should not print unrelated specs", func() { p.VisitSpec(0, "Don't show me 0", noErrors) p.VisitSpec(1, "Don't show me 1", noErrors) p.VisitSpec(2, "Don't show me 2", noErrors) p.VisitSpec(0, "Failing parent", someError) p.VisitSpec(1, "Failing child", someError) c.Expect(trim(out.String())).Equals(trim(` - Failing parent [FAIL] *** some error - Failing child [FAIL] *** some error `)) }) }) }
func ResultsSpec(c nanospec.Context) { results := newResultCollector() c.Specify("When results have many root specs", func() { results.Update(newSpecRun("RootSpec2", nil, nil, nil)) results.Update(newSpecRun("RootSpec1", nil, nil, nil)) results.Update(newSpecRun("RootSpec3", nil, nil, nil)) c.Specify("then the roots are sorted alphabetically", func() { c.Expect(results).Matches(ReportIs(` - RootSpec1 - RootSpec2 - RootSpec3 3 specs, 0 failures `)) }) }) c.Specify("When results have many child specs", func() { // In tests, when a spec has many children, make sure // to pass a common parent instance to all the siblings. // Otherwise the parent's numberOfChildren is not // incremented and the children's paths will be wrong. // use names which would not sort alphabetically root := newSpecRun("RootSpec", nil, nil, nil) child1 := newSpecRun("one", nil, root, nil) child2 := newSpecRun("two", nil, root, nil) child3 := newSpecRun("three", nil, root, nil) // register in random order results.Update(root) results.Update(child1) results.Update(root) results.Update(child3) results.Update(root) results.Update(child2) c.Specify("then the children are sorted by their declaration order", func() { c.Expect(results).Matches(ReportIs(` - RootSpec - one - two - three 4 specs, 0 failures `)) }) }) c.Specify("Case: zero specs", func() { c.Expect(results).Matches(ReportIs(` 0 specs, 0 failures `)) }) c.Specify("Case: spec with no children", func() { a1 := newSpecRun("RootSpec", nil, nil, nil) results.Update(a1) c.Expect(results).Matches(ReportIs(` - RootSpec 1 specs, 0 failures `)) }) c.Specify("Case: spec with a child", func() { a1 := newSpecRun("RootSpec", nil, nil, nil) a2 := newSpecRun("Child A", nil, a1, nil) results.Update(a1) results.Update(a2) c.Expect(results).Matches(ReportIs(` - RootSpec - Child A 2 specs, 0 failures `)) }) c.Specify("Case: spec with nested children", func() { a1 := newSpecRun("RootSpec", nil, nil, nil) a2 := newSpecRun("Child A", nil, a1, nil) a3 := newSpecRun("Child AA", nil, a2, nil) results.Update(a1) results.Update(a2) results.Update(a3) c.Expect(results).Matches(ReportIs(` - RootSpec - Child A - Child AA 3 specs, 0 failures `)) }) c.Specify("Case: spec with multiple nested children", func() { runner := NewRunner() runner.AddSpec(DummySpecWithMultipleNestedChildren) runner.Run() c.Expect(runner.Results()).Matches(ReportIs(` - gospec.DummySpecWithMultipleNestedChildren - Child A - Child AA - Child AB - Child B - Child BA - Child BB - Child BC 8 specs, 0 failures `)) }) c.Specify("When specs fail", func() { a1 := newSpecRun("Failing", nil, nil, nil) a1.AddError(newError(OtherError, "X did not equal Y", "", []*Location{})) results.Update(a1) b1 := newSpecRun("Passing", nil, nil, nil) b2 := newSpecRun("Child failing", nil, b1, nil) b2.AddError(newError(OtherError, "moon was not cheese", "", []*Location{})) results.Update(b1) results.Update(b2) c.Specify("then the errors are reported", func() { c.Expect(results).Matches(ReportIs(` - Failing [FAIL] *** X did not equal Y - Passing - Child failing [FAIL] *** moon was not cheese 3 specs, 2 failures `)) }) }) c.Specify("When spec passes on 1st run but fails on 2nd run", func() { i := 0 runner := NewRunner() runner.AddNamedSpec("RootSpec", func(c Context) { if i == 1 { c.Expect(10, Equals, 20) } i++ c.Specify("Child A", func() {}) c.Specify("Child B", func() {}) }) runner.Run() c.Specify("then the error is reported", func() { c.Expect(runner.Results()).Matches(ReportIs(` - RootSpec [FAIL] *** Expected: equals “20” got: “10” at results_test.go - Child A - Child B 3 specs, 1 failures `)) }) }) c.Specify("When root spec fails sporadically", func() { runner := NewRunner() runner.AddNamedSpec("RootSpec", func(c Context) { i := 0 c.Specify("Child A", func() { i = 1 }) c.Specify("Child B", func() { i = 2 }) c.Expect(10, Equals, 20) // stays same - will be reported once c.Expect(10+i, Equals, 20) // changes - will be reported many times }) runner.Run() c.Specify("then the errors are merged together", func() { c.Expect(runner.Results()).Matches(ReportIs(` - RootSpec [FAIL] *** Expected: equals “20” got: “10” at results_test.go *** Expected: equals “20” got: “11” at results_test.go *** Expected: equals “20” got: “12” at results_test.go - Child A - Child B 3 specs, 1 failures `)) }) }) c.Specify("When non-root spec fails sporadically", func() { runner := NewRunner() runner.AddNamedSpec("RootSpec", func(c Context) { c.Specify("Failing", func() { i := 0 c.Specify("Child A", func() { i = 1 }) c.Specify("Child B", func() { i = 2 }) c.Expect(10, Equals, 20) // stays same - will be reported once c.Expect(10+i, Equals, 20) // changes - will be reported many times }) }) runner.Run() c.Specify("then the errors are merged together", func() { c.Expect(runner.Results()).Matches(ReportIs(` - RootSpec - Failing [FAIL] *** Expected: equals “20” got: “10” at results_test.go *** Expected: equals “20” got: “11” at results_test.go *** Expected: equals “20” got: “12” at results_test.go - Child A - Child B 4 specs, 1 failures `)) }) }) c.Specify("When an expectation gives an error", func() { runner := NewRunner() runner.AddNamedSpec("RootSpec", func(c Context) { c.Expect(1, IsWithin(0.1), 1.0) }) runner.Run() c.Specify("the error is reported as-is", func() { c.Expect(runner.Results()).Matches(ReportIs(` - RootSpec [FAIL] *** type error: expected a float, but was “1” of type “int” at results_test.go 1 specs, 1 failures `)) }) }) c.Specify("When a spec panics", func() { runner := NewRunner() runner.AddNamedSpec("RootSpec", func(c Context) { c.Specify("Child A", func() { boom2() }) }) runner.Run() c.Specify("then the panic's stack trace is reported", func() { c.Expect(runner.Results()).Matches(ReportIs(` - RootSpec - Child A [FAIL] *** panic: boom! at recover_test.go at recover_test.go at recover_test.go at results_test.go 2 specs, 1 failures `)) }) }) c.Specify("When a root spec panics", func() { runner := NewRunner() runner.AddNamedSpec("RootSpec", func(c Context) { boom2() }) runner.Run() c.Specify("the bootstrap code in runner.go does not show up in the stack trace", func() { c.Expect(runner.Results()).Matches(ReportIs(` - RootSpec [FAIL] *** panic: boom! at recover_test.go at recover_test.go at recover_test.go at results_test.go 1 specs, 1 failures `)) }) }) }
func ExecutionModelSpec(c nanospec.Context) { c.Specify("Specs with children, but without siblings, are executed fully on one run", func() { c.Specify("Case: no children", func() { runSpecWithContext(DummySpecWithNoChildren, newInitialContext()) c.Expect(testSpy).Equals("root") }) c.Specify("Case: one child", func() { runSpecWithContext(DummySpecWithOneChild, newInitialContext()) c.Expect(testSpy).Equals("root,a") }) c.Specify("Case: nested children", func() { runSpecWithContext(DummySpecWithNestedChildren, newInitialContext()) c.Expect(testSpy).Equals("root,a,aa") }) }) c.Specify("Specs with siblings are executed only one sibling at a time", func() { c.Specify("Case: on initial run, the 1st child is executed", func() { runSpecWithContext(DummySpecWithTwoChildren, newInitialContext()) c.Expect(testSpy).Equals("root,a") }) c.Specify("Case: explicitly execute the 1st child", func() { runSpecWithContext(DummySpecWithTwoChildren, newExplicitContext([]int{0})) c.Expect(testSpy).Equals("root,a") }) c.Specify("Case: explicitly execute the 2nd child", func() { runSpecWithContext(DummySpecWithTwoChildren, newExplicitContext([]int{1})) c.Expect(testSpy).Equals("root,b") }) }) c.Specify("Specs with nested siblings: eventually all siblings are executed, one at a time, in isolation", func() { r := NewRunner() r.AddSpec(DummySpecWithMultipleNestedChildren) // Execute manually instead of calling Run(), in order to avoid running // the specs multi-threadedly, which would mess up the test spy. runs := new(vector.StringVector) for r.hasScheduledTasks() { resetTestSpy() r.executeNextScheduledTask() runs.Push(testSpy) } sort.Sort(runs) c.Expect(runs.Len()).Equals(5) c.Expect(runs.At(0)).Equals("root,a,aa") c.Expect(runs.At(1)).Equals("root,a,ab") c.Expect(runs.At(2)).Equals("root,b,ba") c.Expect(runs.At(3)).Equals("root,b,bb") c.Expect(runs.At(4)).Equals("root,b,bc") }) }
func MatchersSpec(c nanospec.Context) { c.Specify("Matcher: Equals", func() { c.Specify("strings", func() { c.Expect(E("apple", Equals, "apple")).Matches(Passes) c.Expect(E("apple", Equals, "orange")).Matches(FailsWithMessage( "equals “orange”", "does NOT equal “orange”")) }) c.Specify("ints", func() { c.Expect(E(42, Equals, 42)).Matches(Passes) c.Expect(E(42, Equals, 999)).Matches(Fails) }) c.Specify("structs", func() { c.Expect(E(DummyStruct{42, 1}, Equals, DummyStruct{42, 2})).Matches(Passes) c.Expect(E(DummyStruct{42, 1}, Equals, DummyStruct{999, 2})).Matches(Fails) }) c.Specify("struct pointers", func() { c.Expect(E(&DummyStruct{42, 1}, Equals, &DummyStruct{42, 2})).Matches(Passes) c.Expect(E(&DummyStruct{42, 1}, Equals, &DummyStruct{999, 2})).Matches(Fails) }) }) c.Specify("Matcher: IsSame", func() { a1 := new(os.File) a2 := a1 b := new(os.File) c.Expect(E(a1, IsSame, a2)).Matches(Passes) c.Expect(E(a1, IsSame, b)).Matches(FailsWithMessage( fmt.Sprintf("is same as “%v”", b), fmt.Sprintf("is NOT same as “%v”", b))) c.Specify("cannot compare values, but only pointers", func() { c.Expect(E(1, IsSame, b)).Matches(GivesError("type error: expected a pointer, but was “1” of type “int”")) c.Expect(E(b, IsSame, 1)).Matches(GivesError("type error: expected a pointer, but was “1” of type “int”")) }) }) c.Specify("Matcher: IsNil", func() { c.Expect(E(nil, IsNil)).Matches(Passes) // interface value nil c.Expect(E((*int)(nil), IsNil)).Matches(Passes) // typed pointer nil inside an interface value c.Expect(E(new(int), IsNil)).Matches(Fails) c.Expect(E(1, IsNil)).Matches(FailsWithMessage( "is <nil>", "is NOT <nil>")) }) c.Specify("Matcher: IsTrue", func() { c.Expect(E(true, IsTrue)).Matches(Passes) c.Expect(E(false, IsTrue)).Matches(FailsWithMessage( "is <true>", "is NOT <true>")) }) c.Specify("Matcher: IsFalse", func() { c.Expect(E(false, IsFalse)).Matches(Passes) c.Expect(E(true, IsFalse)).Matches(FailsWithMessage( "is <false>", "is NOT <false>")) }) c.Specify("Matcher: Satisfies", func() { value := 42 c.Expect(E(value, Satisfies, value < 100)).Matches(Passes) c.Expect(E(value, Satisfies, value > 100)).Matches(FailsWithMessage( "satisfies the criteria", "does NOT satisfy the criteria")) }) c.Specify("Matcher: IsWithin", func() { value := float64(3.141) pi := float64(math.Pi) c.Expect(E(value, IsWithin(0.001), pi)).Matches(Passes) c.Expect(E(value, IsWithin(0.0001), pi)).Matches(FailsWithMessage( "is within 3.141592653589793 ± 0.0001", "is NOT within 3.141592653589793 ± 0.0001")) c.Specify("cannot compare ints", func() { value := int(3) pi := float64(math.Pi) c.Expect(E(value, IsWithin(0.001), pi)).Matches(GivesError("type error: expected a float, but was “3” of type “int”")) c.Expect(E(pi, IsWithin(0.001), value)).Matches(GivesError("type error: expected a float, but was “3” of type “int”")) }) }) c.Specify("Matcher: Contains", func() { values := []string{"one", "two", "three"} c.Expect(E(values, Contains, "one")).Matches(Passes) c.Expect(E(values, Contains, "two")).Matches(Passes) c.Expect(E(values, Contains, "three")).Matches(Passes) c.Expect(E(values, Contains, "four")).Matches(FailsWithMessage( "contains “four”", "does NOT contain “four”")) }) c.Specify("Matcher: ContainsAll", func() { values := []string{"one", "two", "three"} c.Expect(E(values, ContainsAll, Values())).Matches(Passes) c.Expect(E(values, ContainsAll, Values("one"))).Matches(Passes) c.Expect(E(values, ContainsAll, Values("three", "two"))).Matches(Passes) c.Expect(E(values, ContainsAll, Values("one", "two", "three"))).Matches(Passes) c.Expect(E(values, ContainsAll, Values("four"))).Matches(Fails) c.Expect(E(values, ContainsAll, Values("one", "four"))).Matches(FailsWithMessage( "contains all of “[one four]”", "does NOT contain all of “[one four]”")) }) c.Specify("Matcher: ContainsAny", func() { values := []string{"one", "two", "three"} c.Expect(E(values, ContainsAny, Values("one"))).Matches(Passes) c.Expect(E(values, ContainsAny, Values("three", "two"))).Matches(Passes) c.Expect(E(values, ContainsAny, Values("four", "one", "five"))).Matches(Passes) c.Expect(E(values, ContainsAny, Values("one", "two", "three"))).Matches(Passes) c.Expect(E(values, ContainsAny, Values())).Matches(Fails) c.Expect(E(values, ContainsAny, Values("four"))).Matches(Fails) c.Expect(E(values, ContainsAny, Values("four", "five"))).Matches(FailsWithMessage( "contains any of “[four five]”", "does NOT contain any of “[four five]”")) }) c.Specify("Matcher: ContainsExactly", func() { values := []string{"one", "two", "three"} c.Expect(E(values, ContainsExactly, Values("one", "two", "three"))).Matches(Passes) c.Expect(E(values, ContainsExactly, Values("three", "one", "two"))).Matches(Passes) c.Expect(E(values, ContainsExactly, Values())).Matches(Fails) c.Expect(E(values, ContainsExactly, Values("four"))).Matches(Fails) c.Expect(E(values, ContainsExactly, Values("one", "two"))).Matches(Fails) c.Expect(E(values, ContainsExactly, Values("one", "two", "three", "four"))).Matches(FailsWithMessage( "contains exactly “[one two three four]”", "does NOT contain exactly “[one two three four]”")) // duplicate values are allowed values = []string{"a", "a", "b"} c.Expect(E(values, ContainsExactly, Values("a", "a", "b"))).Matches(Passes) c.Expect(E(values, ContainsExactly, Values("a", "b", "a"))).Matches(Passes) c.Expect(E(values, ContainsExactly, Values("a", "b", "b"))).Matches(Fails) c.Expect(E(values, ContainsExactly, Values("a", "a", "a", "b"))).Matches(Fails) c.Expect(E(values, ContainsExactly, Values("a", "a", "b", "b"))).Matches(Fails) }) c.Specify("Matcher: ContainsInOrder", func() { values := []string{"one", "two", "three"} c.Expect(E(values, ContainsInOrder, Values("one", "two", "three"))).Matches(Passes) c.Expect(E(values, ContainsInOrder, Values())).Matches(Fails) c.Expect(E(values, ContainsInOrder, Values("one", "two"))).Matches(Fails) c.Expect(E(values, ContainsInOrder, Values("one", "two", "four"))).Matches(Fails) c.Expect(E(values, ContainsInOrder, Values("one", "two", "three", "four"))).Matches(Fails) c.Expect(E(values, ContainsInOrder, Values("three", "one", "two"))).Matches(FailsWithMessage( "contains in order “[three one two]”", "does NOT contain in order “[three one two]”")) }) c.Specify("Matcher: ContainsInPartialOrder", func() { values := []string{"1", "2", "2", "3", "4"} c.Expect(E(values, ContainsInPartialOrder, Values())).Matches(Passes) c.Expect(E(values, ContainsInPartialOrder, Values("1"))).Matches(Passes) c.Expect(E(values, ContainsInPartialOrder, Values("1", "2", "2"))).Matches(Passes) c.Expect(E(values, ContainsInPartialOrder, Values("1", "2", "3"))).Matches(Passes) c.Expect(E(values, ContainsInPartialOrder, Values("1", "2", "2", "3", "4"))).Matches(Passes) c.Expect(E(values, ContainsInPartialOrder, Values("1", "1"))).Matches(Fails) c.Expect(E(values, ContainsInPartialOrder, Values("2", "1"))).Matches(Fails) c.Expect(E(values, ContainsInPartialOrder, Values("2", "2", "2"))).Matches(Fails) c.Expect(E(values, ContainsInPartialOrder, Values("1", "4", "3"))).Matches(FailsWithMessage( "contains in partial order “[1 4 3]”", "does NOT contain in partial order “[1 4 3]”")) }) c.Specify("Conversions for containment matchers", func() { c.Specify("array to array", func() { values := [...]string{"one", "two", "three"} result, _ := toArray(values) c.Expect(len(result)).Equals(3) c.Expect(result[0]).Equals("one") c.Expect(result[1]).Equals("two") c.Expect(result[2]).Equals("three") }) c.Specify("channel to array", func() { values := make(chan string, 10) values <- "one" values <- "two" values <- "three" close(values) result, _ := toArray(values) c.Expect(len(result)).Equals(3) c.Expect(result[0]).Equals("one") c.Expect(result[1]).Equals("two") c.Expect(result[2]).Equals("three") }) c.Specify("vector to array", func() { values := new(vector.Vector) values.Push("one") values.Push("two") values.Push("three") result, _ := toArray(values) c.Expect(len(result)).Equals(3) c.Expect(result[0]).Equals("one") c.Expect(result[1]).Equals("two") c.Expect(result[2]).Equals("three") }) c.Specify("list to array", func() { values := list.New() values.PushBack("one") values.PushBack("two") values.PushBack("three") result, _ := toArray(values) c.Expect(len(result)).Equals(3) c.Expect(result[0]).Equals("one") c.Expect(result[1]).Equals("two") c.Expect(result[2]).Equals("three") }) c.Specify("unsupported value to array", func() { _, err := toArray("foo") c.Expect(err.String()).Equals("type error: expected a collection type, but was “foo” of type “string”") }) }) c.Specify("Containment matchers convert the actual value to a printable array "+ "when it's not originally printable", func() { values := list.New() values.PushBack("one") values.PushBack("two") values.PushBack("three") nonPrintableList := values listAsString := "[one two three]" c.Expect(fmt.Sprint(nonPrintableList)).NotEquals(listAsString) c.Specify("Matcher: Contains", func() { c.Expect(func(c Context) { c.Expect(nonPrintableList, Contains, "xxx") }).Matches(SpecsReportContains(listAsString)) }) multiValueMatchers := []Matcher{ ContainsAll, ContainsAny, ContainsExactly, ContainsInOrder, ContainsInPartialOrder, } for _, matcher := range multiValueMatchers { c.Specify("Matcher: "+functionName(matcher), func() { c.Expect(func(c Context) { c.Expect(nonPrintableList, matcher, Values("xxx")) }).Matches(SpecsReportContains(listAsString)) }) } }) }
func MatcherMessagesSpec(c nanospec.Context) { spy := new(SpyErrorLogger) m := newMatcherAdapter(nil, spy, ExpectFailed) c.Specify("Positive expectation failures are reported with the positive message", func() { m.Expect(1, DummyEquals, 1) c.Expect(spy.LastError()).Equals("") m.Expect(1, DummyEquals, 2) c.Expect(spy.LastError()).Equals("1 should equal 2") }) c.Specify("Negative expectation failures are reported with the negative message", func() { m.Expect(1, Not(DummyEquals), 2) c.Expect(spy.LastError()).Equals("") m.Expect(1, Not(DummyEquals), 1) c.Expect(spy.LastError()).Equals("1 should NOT equal 1") }) c.Specify("Errors in expectations are reported with the error message", func() { m.Expect(666, DummyEquals, 1) c.Expect(spy.LastError()).Equals("666 illegal value") }) }