| package gocheck |
| |
| import ( |
| "reflect" |
| "regexp" |
| "fmt" |
| ) |
| |
| |
| // ----------------------------------------------------------------------- |
| // BugInfo and Bug() helper, to attach extra information to checks. |
| |
| type bugInfo struct { |
| format string |
| args []interface{} |
| } |
| |
| // Function to attach some information to an Assert() or Check() call. |
| // This should be used as, for instance: |
| // |
| // Assert(a, Equals, 8192, Bug("Buffer size is incorrect, bug #123")) |
| // |
| // If the matching fails, the provided arguments will be passed to |
| // fmt.Sprintf(), and will be presented next to the logged failure. Note |
| // that it must be the last argument provided. |
| func Bug(format string, args ...interface{}) BugInfo { |
| return &bugInfo{format, args} |
| } |
| |
| // Interface which must be supported for attaching extra information to |
| // checks. See the Bug() function. |
| type BugInfo interface { |
| GetBugInfo() string |
| } |
| |
| func (bug *bugInfo) GetBugInfo() string { |
| return fmt.Sprintf(bug.format, bug.args...) |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // A useful Checker template. |
| |
| // Checkers used with the c.Assert() and c.Check() verification methods |
| // must have this interface. See the CheckerType type for an understanding |
| // of how the individual methods must work. |
| type Checker interface { |
| Name() string |
| VarNames() (obtained, expected string) |
| NeedsExpectedValue() bool |
| Check(obtained, expected interface{}) (result bool, error string) |
| } |
| |
| // Sample checker type with some sane defaults. |
| type CheckerType struct{} |
| |
| // Trick to ensure it matchers the desired interface. |
| var _ Checker = (*CheckerType)(nil) |
| |
| |
| // The function name used to build the matcher. E.g. "IsNil". |
| 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. E.g. false for IsNil. |
| func (checker *CheckerType) NeedsExpectedValue() bool { |
| return true |
| } |
| |
| // Variable names to be used for the obtained and expected values when |
| // reporting a failure in the expectations established. E.g. |
| // "obtained" and "expected". |
| func (checker *CheckerType) VarNames() (obtained, expected string) { |
| return "obtained", "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, "" |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // Not() checker logic inverter. |
| |
| // Invert the logic of the provided checker. The resulting checker will |
| // succeed where the original one failed, and vice versa. E.g. |
| // Assert(a, Not(Equals), b) |
| func Not(checker Checker) Checker { |
| return ¬Checker{checker} |
| } |
| |
| type notChecker struct { |
| sub Checker |
| } |
| |
| func (checker *notChecker) Name() string { |
| return "Not(" + checker.sub.Name() + ")" |
| } |
| |
| func (checker *notChecker) NeedsExpectedValue() bool { |
| return checker.sub.NeedsExpectedValue() |
| } |
| |
| func (checker *notChecker) VarNames() (obtained, expected string) { |
| obtained, expected = checker.sub.VarNames() |
| return |
| } |
| |
| func (checker *notChecker) Check(obtained, expected interface{}) (result bool, error string) { |
| result, error = checker.sub.Check(obtained, expected) |
| result = !result // So much for so little. :-) |
| return |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // IsNil checker. |
| |
| // Check if the obtained value is nil. E.g. Assert(err, IsNil). |
| var IsNil Checker = &isNilChecker{} |
| |
| type isNilChecker struct { |
| CheckerType |
| } |
| |
| func (checker *isNilChecker) Name() string { |
| return "IsNil" |
| } |
| |
| func (checker *isNilChecker) NeedsExpectedValue() bool { |
| return false |
| } |
| |
| func (checker *isNilChecker) VarNames() (obtained, expected string) { |
| return "value", "" |
| } |
| |
| func (checker *isNilChecker) Check(obtained, expected interface{}) (result bool, error string) { |
| return isNil(obtained), "" |
| } |
| |
| type hasIsNil interface { |
| IsNil() bool |
| } |
| |
| func isNil(obtained interface{}) (result bool) { |
| if obtained == nil { |
| result = true |
| } else { |
| if v, ok := reflect.NewValue(obtained).(hasIsNil); ok { |
| result = v.IsNil() |
| } |
| } |
| return |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // NotNil checker. Alias for Not(IsNil), since it's so common. |
| |
| // Check if the obtained value is not nil. E.g. Assert(iface, NotNil). |
| // This is an Alias for Not(IsNil), since it's a fairly common check. |
| var NotNil Checker = ¬NilChecker{} |
| |
| type notNilChecker struct { |
| isNilChecker |
| } |
| |
| func (checker *notNilChecker) Name() string { |
| return "NotNil" |
| } |
| |
| func (checker *notNilChecker) Check(obtained, expected interface{}) (result bool, error string) { |
| return !isNil(obtained), "" |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // Equals checker. |
| |
| // Check that the obtained value is equal to the expected value. The |
| // check will work correctly even when facing arrays, interfaces, and |
| // values of different types (which always fails the test). E.g. |
| // Assert(value, Equals, 42). |
| 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) { |
| return reflect.DeepEqual(obtained, expected), "" |
| } |
| |
| |
| // ----------------------------------------------------------------------- |
| // Matches checker. |
| |
| // Check that the string provided as the obtained value (or the result of |
| // its .String() method, in case the value is not a string) matches the |
| // regular expression provided. Note that, given the interface os.Error |
| // commonly used for errors, this checker will correctly verify its |
| // string representation. E.g. Assert(err, Matches, "perm.*denied") |
| var Matches Checker = &matchesChecker{} |
| |
| type matchesChecker struct { |
| CheckerType |
| } |
| |
| func (checker *matchesChecker) Name() string { |
| return "Matches" |
| } |
| |
| func (checker *matchesChecker) VarNames() (obtained, expected string) { |
| return "value", "regex" |
| } |
| |
| 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()" |
| } |