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
 }