blob: 759138df0c26810e81860f55e590387e4f3d26ae [file] [log] [blame]
package checkers
import (
"reflect"
"regexp"
)
// Checkers used with the c.Assert() and c.Check() helpers must have
// this interface.
type Checker interface {
Name() string
ObtainedLabel() (varName, varLabel string)
ExpectedLabel() (varName, varLabel string)
NeedsExpectedValue() bool
Check(obtained, expected interface{}) (result bool, error string)
}
type CheckerType struct{}
// Trick to ensure it matchers the desired interface.
var _ Checker = (*CheckerType)(nil)
// The function name used to build the matcher.
func (checker *CheckerType) Name() string {
return "Checker"
}
// Method must return true if the given matcher needs to be informed
// of an expected value in addition to the actual value obtained to
// verify its expectations.
func (checker *CheckerType) NeedsExpectedValue() bool {
return true
}
// Label to be used for the obtained value when reporting a failure
// in the expectations established.
func (checker *CheckerType) ObtainedLabel() (varName, varLabel string) {
return "obtained", "Obtained"
}
// Label to be used for the obtained value when reporting a failure
// in the expectations established.
func (checker *CheckerType) ExpectedLabel() (varName, varLabel string) {
return "expected", "Expected"
}
// Method must return true if the obtained value succeeds the
// expectations established by the given matcher. If an error is
// returned, it means the provided parameters are somehow invalid.
func (checker *CheckerType) Check(obtained, expected interface{}) (
result bool, error string) {
return false, ""
}
// -----------------------------------------------------------------------
// Equals checker.
var Equals Checker = &equalsChecker{}
type equalsChecker struct {
CheckerType
}
func (checker *equalsChecker) Name() string {
return "Equals"
}
func (checker *equalsChecker) Check(obtained, expected interface{}) (
result bool, error string) {
// This will use a fast path to check for equality of normal types,
// and then fallback to reflect.DeepEqual if things go wrong.
defer func() {
if recover() != nil {
result = reflect.DeepEqual(obtained, expected)
}
}()
return obtained == expected, ""
}
// -----------------------------------------------------------------------
// Matches checker.
var Matches Checker = &matchesChecker{}
type matchesChecker struct {
CheckerType
}
func (checker *matchesChecker) Name() string {
return "Matches"
}
func (checker *matchesChecker) ObtainedLabel() (varName, varLabel string) {
return "value", "Value"
}
func (checker *matchesChecker) ExpectedLabel() (varName, varLabel string) {
return "regex", "Expected to match regex"
}
type hasString interface {
String() string
}
func (checker *matchesChecker) Check(value, re interface{}) (bool, string) {
reStr, ok := re.(string)
if !ok {
return false, "Regex must be a string"
}
valueStr, valueIsStr := value.(string)
if !valueIsStr {
if valueWithStr, valueHasStr := value.(hasString); valueHasStr {
valueStr, valueIsStr = valueWithStr.String(), true
}
}
if valueIsStr {
matches, err := regexp.MatchString("^" + reStr + "$", valueStr)
if err != nil {
return false, "Can't compile regex: " + err.String()
}
return matches, ""
}
return false, "Obtained value is not a string and has no .String()"
}