Exemple #1
0
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>")
	})
}
Exemple #2
0
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)
}
Exemple #3
0
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)
	})
}
Exemple #4
0
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()
		})
	})
}
Exemple #5
0
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")
	})
}
Exemple #6
0
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)
	})
}
Exemple #7
0
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
`))
		})
	})
}
Exemple #8
0
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")
	})
}
Exemple #10
0
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))
				})
			}
		})
}
Exemple #11
0
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")
	})
}