Fix errors to print their string values.
Also, fmt.Stringer is a more conventional interface
type than hasString.
R=
CC=
https://codereview.appspot.com/5418043
diff --git a/checkers.go b/checkers.go
index 738ccaa..5ffc449 100644
--- a/checkers.go
+++ b/checkers.go
@@ -196,7 +196,9 @@
if !ok {
return false, "Value is not an error"
}
- return matches(err.Error(), params[1])
+ params[0] = err.Error()
+ names[0] = "error"
+ return matches(params[0], params[1])
}
// -----------------------------------------------------------------------
@@ -248,7 +250,6 @@
type panicsChecker struct {
*CheckerInfo
- check func(obtained, expected interface{}) (bool, string)
}
// The Panics checker verifies that calling the provided zero-argument
@@ -261,29 +262,6 @@
//
var Panics Checker = &panicsChecker{
&CheckerInfo{Name: "Panics", Params: []string{"function", "expected"}},
- func(obtained, expected interface{}) (bool, string) {
- return reflect.DeepEqual(obtained, expected), ""
- },
-}
-
-// The PanicMatches checker verifies that calling the provided zero-argument
-// function will cause a panic with an error value matching
-// the regular expression provided.
-//
-// For example:
-//
-// c.Assert(func() { f(1, 2) }, PanicMatches, `open.*: no such file or directory`).
-//
-//
-var PanicMatches Checker = &panicsChecker{
- &CheckerInfo{Name: "PanicMatches", Params: []string{"function", "expected"}},
- func(obtained, expected interface{}) (bool, string) {
- v, ok := obtained.(error)
- if !ok {
- return false, "Panic value is not an error"
- }
- return matches(v.Error(), expected)
- },
}
func (checker *panicsChecker) Check(params []interface{}, names []string) (result bool, error string) {
@@ -296,12 +274,52 @@
if error != "" {
return
}
- obtained := recover()
- expected := params[1]
- params[0] = obtained
+ params[0] = recover()
names[0] = "panic"
+ result = reflect.DeepEqual(params[0], params[1])
+ }()
+ f.Call(nil)
+ return false, "Function has not panicked"
+}
- result, error = checker.check(obtained, expected)
+type panicMatchesChecker struct {
+ *CheckerInfo
+}
+
+// The PanicMatches checker verifies that calling the provided zero-argument
+// function will cause a panic with an error value matching
+// the regular expression provided.
+//
+// For example:
+//
+// c.Assert(func() { f(1, 2) }, PanicMatches, `open.*: no such file or directory`).
+//
+//
+var PanicMatches Checker = &panicMatchesChecker{
+ &CheckerInfo{Name: "PanicMatches", Params: []string{"function", "expected"}},
+}
+
+func (checker *panicMatchesChecker) Check(params []interface{}, names []string) (result bool, errmsg string) {
+ f := reflect.ValueOf(params[0])
+ if f.Kind() != reflect.Func || f.Type().NumIn() != 0 {
+ return false, "Function must take zero arguments"
+ }
+ defer func() {
+ // If the function has not panicked, then don't do the check.
+ if errmsg != "" {
+ return
+ }
+ obtained := recover()
+ names[0] = "panic"
+ if e, ok := obtained.(error); ok {
+ params[0] = e.Error()
+ } else if _, ok := obtained.(string); ok {
+ params[0] = obtained
+ } else {
+ errmsg = "Panic value is not a string or an error"
+ return
+ }
+ result, errmsg = matches(params[0], params[1])
}()
f.Call(nil)
return false, "Function has not panicked"
diff --git a/checkers_test.go b/checkers_test.go
index a4ac329..e802f2f 100644
--- a/checkers_test.go
+++ b/checkers_test.go
@@ -116,6 +116,11 @@
testCheck(c, gocheck.ErrorMatches, false, "Value is not an error", 1, "some error")
testCheck(c, gocheck.ErrorMatches, true, "", errors.New("some error"), "some error")
testCheck(c, gocheck.ErrorMatches, true, "", errors.New("some error"), "so.*or")
+
+ // Verify params mutation
+ params, names := testCheck(c, gocheck.ErrorMatches, false, "", errors.New("some error"), "other error")
+ c.Assert(params[0], gocheck.Equals, "some error")
+ c.Assert(names[0], gocheck.Equals, "error")
}
func (s *CheckersS) TestMatches(c *gocheck.C) {
@@ -179,13 +184,18 @@
testCheck(c, gocheck.PanicMatches, false, "Function has not panicked", func() bool { return false }, "BOOM")
testCheck(c, gocheck.PanicMatches, false, "Function must take zero arguments", 1, "BOOM")
+ // Plain strings.
+ testCheck(c, gocheck.PanicMatches, true, "", func() { panic("BOOM") }, "BO.M")
+ testCheck(c, gocheck.PanicMatches, false, "", func() { panic("KABOOM") }, "BOOM")
+ testCheck(c, gocheck.PanicMatches, true, "", func() bool { panic("BOOM") }, "BO.M")
+
// Verify params/names mutation
params, names := testCheck(c, gocheck.PanicMatches, false, "", func() { panic(errors.New("KABOOM")) }, "BOOM")
- c.Assert(params[0], gocheck.ErrorMatches, "KABOOM")
+ c.Assert(params[0], gocheck.Equals, "KABOOM")
c.Assert(names[0], gocheck.Equals, "panic")
// Verify a nil panic
- testCheck(c, gocheck.PanicMatches, false, "Panic value is not an error", func() { panic(nil) }, "")
+ testCheck(c, gocheck.PanicMatches, false, "Panic value is not a string or an error", func() { panic(nil) }, "")
}
func (s *CheckersS) TestFitsTypeOf(c *gocheck.C) {
diff --git a/foundation_test.go b/foundation_test.go
index cd0ce9f..b69eb5e 100644
--- a/foundation_test.go
+++ b/foundation_test.go
@@ -11,6 +11,8 @@
"strings"
"regexp"
"fmt"
+ "log"
+ "os"
)
// -----------------------------------------------------------------------
@@ -288,6 +290,28 @@
}
// -----------------------------------------------------------------------
+// Check minimum *log.Logger interface provided by *gocheck.C.
+
+type minLogger interface {
+ Output(calldepth int, s string) error
+}
+
+func (s *BootstrapS) TestMinLogger(c *gocheck.C) {
+ var logger minLogger
+ logger = log.New(os.Stderr, "", 0)
+ logger = c
+ logger.Output(0, "Hello there")
+ expected := "\\[LOG\\] [.0-9]+ Hello there\n"
+ output := c.GetTestLog()
+ matched, err := regexp.MatchString(expected, output)
+ if err != nil {
+ c.Error("Bad expression: ", expected)
+ } else if !matched {
+ c.Error("Output() didn't log properly:\n", output)
+ }
+}
+
+// -----------------------------------------------------------------------
// Ensure that suites with embedded types are working fine, including the
// the workaround for issue 906.
diff --git a/gocheck.go b/gocheck.go
index b5e0875..a05789e 100644
--- a/gocheck.go
+++ b/gocheck.go
@@ -237,7 +237,7 @@
c.logf("... Panic: %s (PC=0x%X)\n", value, pc)
}
name := niceFuncName(pc)
- if name == "reflect.internalValue.call" || name == "gocheck.forkTest" {
+ if name == "reflect.Value.call" || name == "gocheck.forkTest" {
break
}
c.logf("%s:%d\n in %s", nicePath(file), line, name)
diff --git a/helpers.go b/helpers.go
index 8be5143..1e71e69 100644
--- a/helpers.go
+++ b/helpers.go
@@ -3,6 +3,7 @@
import (
"fmt"
"strings"
+ "time"
)
// -----------------------------------------------------------------------
@@ -88,6 +89,15 @@
c.logf(format, args...)
}
+// Output enables *C to be used as a logger in functions that require only
+// the minimum interface of *log.Logger.
+func (c *C) Output(calldepth int, s string) error {
+ ns := time.Now().Sub(time.Time{}).Nanoseconds()
+ t := float64(ns%100e9) / 1e9
+ c.Logf("[LOG] %.05f %s", t, s)
+ return nil
+}
+
// Log an error into the test error output, and mark the test as failed.
// The provided arguments will be assembled together into a string using
// fmt.Sprint().
diff --git a/helpers_test.go b/helpers_test.go
index 6150119..11b2d0d 100644
--- a/helpers_test.go
+++ b/helpers_test.go
@@ -379,7 +379,7 @@
func isDir(path string) bool {
if stat, err := os.Stat(path); err == nil {
- return stat.IsDirectory()
+ return stat.IsDir()
}
return false
}