deep_equals.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Copyright 2012 Aaron Jacobs. All Rights Reserved.
  2. // Author: aaronjjacobs@gmail.com (Aaron Jacobs)
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. package oglematchers
  16. import (
  17. "bytes"
  18. "errors"
  19. "fmt"
  20. "reflect"
  21. )
  22. var byteSliceType reflect.Type = reflect.TypeOf([]byte{})
  23. // DeepEquals returns a matcher that matches based on 'deep equality', as
  24. // defined by the reflect package. This matcher requires that values have
  25. // identical types to x.
  26. func DeepEquals(x interface{}) Matcher {
  27. return &deepEqualsMatcher{x}
  28. }
  29. type deepEqualsMatcher struct {
  30. x interface{}
  31. }
  32. func (m *deepEqualsMatcher) Description() string {
  33. xDesc := fmt.Sprintf("%v", m.x)
  34. xValue := reflect.ValueOf(m.x)
  35. // Special case: fmt.Sprintf presents nil slices as "[]", but
  36. // reflect.DeepEqual makes a distinction between nil and empty slices. Make
  37. // this less confusing.
  38. if xValue.Kind() == reflect.Slice && xValue.IsNil() {
  39. xDesc = "<nil slice>"
  40. }
  41. return fmt.Sprintf("deep equals: %s", xDesc)
  42. }
  43. func (m *deepEqualsMatcher) Matches(c interface{}) error {
  44. // Make sure the types match.
  45. ct := reflect.TypeOf(c)
  46. xt := reflect.TypeOf(m.x)
  47. if ct != xt {
  48. return NewFatalError(fmt.Sprintf("which is of type %v", ct))
  49. }
  50. // Special case: handle byte slices more efficiently.
  51. cValue := reflect.ValueOf(c)
  52. xValue := reflect.ValueOf(m.x)
  53. if ct == byteSliceType && !cValue.IsNil() && !xValue.IsNil() {
  54. xBytes := m.x.([]byte)
  55. cBytes := c.([]byte)
  56. if bytes.Equal(cBytes, xBytes) {
  57. return nil
  58. }
  59. return errors.New("")
  60. }
  61. // Defer to the reflect package.
  62. if reflect.DeepEqual(m.x, c) {
  63. return nil
  64. }
  65. // Special case: if the comparison failed because c is the nil slice, given
  66. // an indication of this (since its value is printed as "[]").
  67. if cValue.Kind() == reflect.Slice && cValue.IsNil() {
  68. return errors.New("which is nil")
  69. }
  70. return errors.New("")
  71. }