summaryrefslogtreecommitdiff
path: root/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go
blob: 6392956848584bf3b5a4176934f5d2f7003e6fe3 (plain)
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package matchers

import (
	"fmt"
	"reflect"
	"strings"
)

func formattedMessage(comparisonMessage string, failurePath []interface{}) string {
	var diffMessage string
	if len(failurePath) == 0 {
		diffMessage = ""
	} else {
		diffMessage = fmt.Sprintf("\n\nfirst mismatched key: %s", formattedFailurePath(failurePath))
	}
	return fmt.Sprintf("%s%s", comparisonMessage, diffMessage)
}

func formattedFailurePath(failurePath []interface{}) string {
	formattedPaths := []string{}
	for i := len(failurePath) - 1; i >= 0; i-- {
		switch p := failurePath[i].(type) {
		case int:
			formattedPaths = append(formattedPaths, fmt.Sprintf(`[%d]`, p))
		default:
			if i != len(failurePath)-1 {
				formattedPaths = append(formattedPaths, ".")
			}
			formattedPaths = append(formattedPaths, fmt.Sprintf(`"%s"`, p))
		}
	}
	return strings.Join(formattedPaths, "")
}

func deepEqual(a interface{}, b interface{}) (bool, []interface{}) {
	var errorPath []interface{}
	if reflect.TypeOf(a) != reflect.TypeOf(b) {
		return false, errorPath
	}

	switch a.(type) {
	case []interface{}:
		if len(a.([]interface{})) != len(b.([]interface{})) {
			return false, errorPath
		}

		for i, v := range a.([]interface{}) {
			elementEqual, keyPath := deepEqual(v, b.([]interface{})[i])
			if !elementEqual {
				return false, append(keyPath, i)
			}
		}
		return true, errorPath

	case map[interface{}]interface{}:
		if len(a.(map[interface{}]interface{})) != len(b.(map[interface{}]interface{})) {
			return false, errorPath
		}

		for k, v1 := range a.(map[interface{}]interface{}) {
			v2, ok := b.(map[interface{}]interface{})[k]
			if !ok {
				return false, errorPath
			}
			elementEqual, keyPath := deepEqual(v1, v2)
			if !elementEqual {
				return false, append(keyPath, k)
			}
		}
		return true, errorPath

	case map[string]interface{}:
		if len(a.(map[string]interface{})) != len(b.(map[string]interface{})) {
			return false, errorPath
		}

		for k, v1 := range a.(map[string]interface{}) {
			v2, ok := b.(map[string]interface{})[k]
			if !ok {
				return false, errorPath
			}
			elementEqual, keyPath := deepEqual(v1, v2)
			if !elementEqual {
				return false, append(keyPath, k)
			}
		}
		return true, errorPath

	default:
		return a == b, errorPath
	}
}