equal_method.go 1.9 KB
Newer Older
W
wangkang101 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
package assertions

import "reflect"

type equalityMethodSpecification struct {
	a interface{}
	b interface{}

	aType reflect.Type
	bType reflect.Type

	equalMethod reflect.Value
}

func newEqualityMethodSpecification(a, b interface{}) *equalityMethodSpecification {
	return &equalityMethodSpecification{
		a: a,
		b: b,
	}
}

func (this *equalityMethodSpecification) IsSatisfied() bool {
	if !this.bothAreSameType() {
		return false
	}
	if !this.typeHasEqualMethod() {
		return false
	}
	if !this.equalMethodReceivesSameTypeForComparison() {
		return false
	}
	if !this.equalMethodReturnsBool() {
		return false
	}
	return true
}

func (this *equalityMethodSpecification) bothAreSameType() bool {
	this.aType = reflect.TypeOf(this.a)
	if this.aType == nil {
		return false
	}
	if this.aType.Kind() == reflect.Ptr {
		this.aType = this.aType.Elem()
	}
	this.bType = reflect.TypeOf(this.b)
	return this.aType == this.bType
}
func (this *equalityMethodSpecification) typeHasEqualMethod() bool {
	aInstance := reflect.ValueOf(this.a)
	this.equalMethod = aInstance.MethodByName("Equal")
	return this.equalMethod != reflect.Value{}
}

func (this *equalityMethodSpecification) equalMethodReceivesSameTypeForComparison() bool {
	signature := this.equalMethod.Type()
	return signature.NumIn() == 1 && signature.In(0) == this.aType
}

func (this *equalityMethodSpecification) equalMethodReturnsBool() bool {
	signature := this.equalMethod.Type()
	return signature.NumOut() == 1 && signature.Out(0) == reflect.TypeOf(true)
}

func (this *equalityMethodSpecification) AreEqual() bool {
	a := reflect.ValueOf(this.a)
	b := reflect.ValueOf(this.b)
	return areEqual(a, b) && areEqual(b, a)
}
func areEqual(receiver reflect.Value, argument reflect.Value) bool {
	equalMethod := receiver.MethodByName("Equal")
	argumentList := []reflect.Value{argument}
	result := equalMethod.Call(argumentList)
	return result[0].Bool()
}