equal_method.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. package assertions
  2. import "reflect"
  3. type equalityMethodSpecification struct {
  4. a interface{}
  5. b interface{}
  6. aType reflect.Type
  7. bType reflect.Type
  8. equalMethod reflect.Value
  9. }
  10. func newEqualityMethodSpecification(a, b interface{}) *equalityMethodSpecification {
  11. return &equalityMethodSpecification{
  12. a: a,
  13. b: b,
  14. }
  15. }
  16. func (this *equalityMethodSpecification) IsSatisfied() bool {
  17. if !this.bothAreSameType() {
  18. return false
  19. }
  20. if !this.typeHasEqualMethod() {
  21. return false
  22. }
  23. if !this.equalMethodReceivesSameTypeForComparison() {
  24. return false
  25. }
  26. if !this.equalMethodReturnsBool() {
  27. return false
  28. }
  29. return true
  30. }
  31. func (this *equalityMethodSpecification) bothAreSameType() bool {
  32. this.aType = reflect.TypeOf(this.a)
  33. if this.aType == nil {
  34. return false
  35. }
  36. if this.aType.Kind() == reflect.Ptr {
  37. this.aType = this.aType.Elem()
  38. }
  39. this.bType = reflect.TypeOf(this.b)
  40. return this.aType == this.bType
  41. }
  42. func (this *equalityMethodSpecification) typeHasEqualMethod() bool {
  43. aInstance := reflect.ValueOf(this.a)
  44. this.equalMethod = aInstance.MethodByName("Equal")
  45. return this.equalMethod != reflect.Value{}
  46. }
  47. func (this *equalityMethodSpecification) equalMethodReceivesSameTypeForComparison() bool {
  48. signature := this.equalMethod.Type()
  49. return signature.NumIn() == 1 && signature.In(0) == this.aType
  50. }
  51. func (this *equalityMethodSpecification) equalMethodReturnsBool() bool {
  52. signature := this.equalMethod.Type()
  53. return signature.NumOut() == 1 && signature.Out(0) == reflect.TypeOf(true)
  54. }
  55. func (this *equalityMethodSpecification) AreEqual() bool {
  56. a := reflect.ValueOf(this.a)
  57. b := reflect.ValueOf(this.b)
  58. return areEqual(a, b) && areEqual(b, a)
  59. }
  60. func areEqual(receiver reflect.Value, argument reflect.Value) bool {
  61. equalMethod := receiver.MethodByName("Equal")
  62. argumentList := []reflect.Value{argument}
  63. result := equalMethod.Call(argumentList)
  64. return result[0].Bool()
  65. }