Selaa lähdekoodia

tt: Support custom return value matching.

Qi Xiao 6 vuotta sitten
vanhempi
säilyke
9f22d2ce91
1 muutettua tiedostoa jossa 29 lisäystä ja 11 poistoa
  1. 29 11
      tt/tt.go

+ 29 - 11
tt/tt.go

@@ -26,22 +26,14 @@ func Args(args ...interface{}) *Case {
 }
 
 // Rets modifies the test case so that it requires the return values to match
-// the given values. It returns the receiver.
+// the given values. It returns the receiver. The arguments may implement the
+// Matcher interface, in which case its Match method is called with the actual
+// return value. Otherwise, reflect.DeepEqual is used to determine matches.
 func (c *Case) Rets(matchers ...interface{}) *Case {
 	c.retsMatchers = append(c.retsMatchers, matchers)
 	return c
 }
 
-func match(matchers, actual []interface{}) bool {
-	for i, matcher := range matchers {
-		// TODO: Support custom matching strategy
-		if !reflect.DeepEqual(matcher, actual[i]) {
-			return false
-		}
-	}
-	return true
-}
-
 // FnToTest describes a function to test.
 type FnToTest struct {
 	name    string
@@ -99,6 +91,32 @@ func Test(t T, fn *FnToTest, tests Table) {
 	}
 }
 
+// RetValue is an empty interface used in the Matcher interface.
+type RetValue interface{}
+
+// Matcher wraps the Match method.
+type Matcher interface {
+	// Match reports whether a return value is considered a match. The argument
+	// is of type RetValue so that it cannot be implemented accidentally.
+	Match(RetValue) bool
+}
+
+func match(matchers, actual []interface{}) bool {
+	for i, matcher := range matchers {
+		if !matchOne(matcher, actual[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+func matchOne(m, a interface{}) bool {
+	if m, ok := m.(Matcher); ok {
+		return m.Match(a)
+	}
+	return reflect.DeepEqual(m, a)
+}
+
 func sprintArgs(args ...interface{}) string {
 	return sprintCommaDelimited(args...)
 }