1package messagediff
2
3import (
4	"testing"
5	"time"
6
7	"github.com/d4l3k/messagediff/testdata"
8)
9
10type testStruct struct {
11	A, b int
12	C    []int
13	D    [3]int
14}
15
16type RecursiveStruct struct {
17	Key   int
18	Child *RecursiveStruct
19}
20
21func newRecursiveStruct(key int) *RecursiveStruct {
22	a := &RecursiveStruct{
23		Key: key,
24	}
25	b := &RecursiveStruct{
26		Key:   key,
27		Child: a,
28	}
29	a.Child = b
30	return a
31}
32
33type testCase struct {
34	a, b  interface{}
35	diff  string
36	equal bool
37}
38
39func checkTestCases(t *testing.T, testData []testCase) {
40	for i, td := range testData {
41		diff, equal := PrettyDiff(td.a, td.b)
42		if diff != td.diff {
43			t.Errorf("%d. PrettyDiff(%#v, %#v) diff = %#v; not %#v", i, td.a, td.b, diff, td.diff)
44		}
45		if equal != td.equal {
46			t.Errorf("%d. PrettyDiff(%#v, %#v) equal = %#v; not %#v", i, td.a, td.b, equal, td.equal)
47		}
48	}
49}
50
51func TestPrettyDiff(t *testing.T) {
52	testData := []testCase{
53		{
54			true,
55			false,
56			"modified:  = false\n",
57			false,
58		},
59		{
60			true,
61			0,
62			"modified:  = 0\n",
63			false,
64		},
65		{
66			[]int{0, 1, 2},
67			[]int{0, 1, 2, 3},
68			"added: [3] = 3\n",
69			false,
70		},
71		{
72			[]int{0, 1, 2, 3},
73			[]int{0, 1, 2},
74			"removed: [3] = 3\n",
75			false,
76		},
77		{
78			[]int{0},
79			[]int{1},
80			"modified: [0] = 1\n",
81			false,
82		},
83		{
84			&[]int{0},
85			&[]int{1},
86			"modified: [0] = 1\n",
87			false,
88		},
89		{
90			map[string]int{"a": 1, "b": 2},
91			map[string]int{"b": 4, "c": 3},
92			"added: [\"c\"] = 3\nmodified: [\"b\"] = 4\nremoved: [\"a\"] = 1\n",
93			false,
94		},
95		{
96			testStruct{1, 2, []int{1}, [3]int{4, 5, 6}},
97			testStruct{1, 3, []int{1, 2}, [3]int{4, 5, 6}},
98			"added: .C[1] = 2\nmodified: .b = 3\n",
99			false,
100		},
101		{
102			nil,
103			nil,
104			"",
105			true,
106		},
107		{
108			&struct{}{},
109			nil,
110			"modified:  = <nil>\n",
111			false,
112		},
113		{
114			nil,
115			&struct{}{},
116			"modified:  = &struct {}{}\n",
117			false,
118		},
119		{
120			time.Time{},
121			time.Time{},
122			"",
123			true,
124		},
125		{
126			testdata.MakeTest(10, "duck"),
127			testdata.MakeTest(20, "foo"),
128			"modified: .a = 20\nmodified: .b = \"foo\"\n",
129			false,
130		},
131	}
132	checkTestCases(t, testData)
133}
134
135func TestPrettyDiffRecursive(t *testing.T) {
136	testData := []testCase{
137		{
138			newRecursiveStruct(1),
139			newRecursiveStruct(1),
140			"",
141			true,
142		},
143		{
144			newRecursiveStruct(1),
145			newRecursiveStruct(2),
146			"modified: .Child.Key = 2\nmodified: .Key = 2\n",
147			false,
148		},
149	}
150	checkTestCases(t, testData)
151}
152
153func TestPathString(t *testing.T) {
154	testData := []struct {
155		in   Path
156		want string
157	}{{
158		Path{StructField("test"), SliceIndex(1), MapKey{"blue"}, MapKey{12.3}},
159		".test[1][\"blue\"][12.3]",
160	}}
161	for i, td := range testData {
162		if out := td.in.String(); out != td.want {
163			t.Errorf("%d. %#v.String() = %#v; not %#v", i, td.in, out, td.want)
164		}
165	}
166}
167
168type ignoreStruct struct {
169	A int `testdiff:"ignore"`
170	a int
171	B [3]int `testdiff:"ignore"`
172	b [3]int
173}
174
175func TestIgnoreTag(t *testing.T) {
176	s1 := ignoreStruct{1, 1, [3]int{1, 2, 3}, [3]int{4, 5, 6}}
177	s2 := ignoreStruct{2, 1, [3]int{1, 8, 3}, [3]int{4, 5, 6}}
178
179	diff, equal := PrettyDiff(s1, s2)
180	if !equal {
181		t.Errorf("Expected structs to be equal. Diff:\n%s", diff)
182	}
183
184	s2 = ignoreStruct{2, 2, [3]int{1, 8, 3}, [3]int{4, 9, 6}}
185	diff, equal = PrettyDiff(s1, s2)
186	if equal {
187		t.Errorf("Expected structs NOT to be equal.")
188	}
189	expect := "modified: .a = 2\nmodified: .b[1] = 9\n"
190	if diff != expect {
191		t.Errorf("Expected diff to be:\n%v\nbut got:\n%v", expect, diff)
192	}
193}
194