1package pgtype_test
2
3import (
4	"net"
5	"reflect"
6	"testing"
7
8	"github.com/jackc/pgtype"
9	"github.com/jackc/pgtype/testutil"
10)
11
12func TestCIDRArrayTranscode(t *testing.T) {
13	testutil.TestSuccessfulTranscode(t, "cidr[]", []interface{}{
14		&pgtype.CIDRArray{
15			Elements:   nil,
16			Dimensions: nil,
17			Status:     pgtype.Present,
18		},
19		&pgtype.CIDRArray{
20			Elements: []pgtype.CIDR{
21				{IPNet: mustParseCIDR(t, "12.34.56.0/32"), Status: pgtype.Present},
22				{Status: pgtype.Null},
23			},
24			Dimensions: []pgtype.ArrayDimension{{Length: 2, LowerBound: 1}},
25			Status:     pgtype.Present,
26		},
27		&pgtype.CIDRArray{Status: pgtype.Null},
28		&pgtype.CIDRArray{
29			Elements: []pgtype.CIDR{
30				{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present},
31				{IPNet: mustParseCIDR(t, "12.34.56.0/32"), Status: pgtype.Present},
32				{IPNet: mustParseCIDR(t, "192.168.0.1/32"), Status: pgtype.Present},
33				{IPNet: mustParseCIDR(t, "2607:f8b0:4009:80b::200e/128"), Status: pgtype.Present},
34				{Status: pgtype.Null},
35				{IPNet: mustParseCIDR(t, "255.0.0.0/8"), Status: pgtype.Present},
36			},
37			Dimensions: []pgtype.ArrayDimension{{Length: 3, LowerBound: 1}, {Length: 2, LowerBound: 1}},
38			Status:     pgtype.Present,
39		},
40		&pgtype.CIDRArray{
41			Elements: []pgtype.CIDR{
42				{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present},
43				{IPNet: mustParseCIDR(t, "12.34.56.0/32"), Status: pgtype.Present},
44				{IPNet: mustParseCIDR(t, "192.168.0.1/32"), Status: pgtype.Present},
45				{IPNet: mustParseCIDR(t, "2607:f8b0:4009:80b::200e/128"), Status: pgtype.Present},
46			},
47			Dimensions: []pgtype.ArrayDimension{
48				{Length: 2, LowerBound: 4},
49				{Length: 2, LowerBound: 2},
50			},
51			Status: pgtype.Present,
52		},
53	})
54}
55
56func TestCIDRArraySet(t *testing.T) {
57	successfulTests := []struct {
58		source interface{}
59		result pgtype.CIDRArray
60	}{
61		{
62			source: []*net.IPNet{mustParseCIDR(t, "127.0.0.1/32")},
63			result: pgtype.CIDRArray{
64				Elements:   []pgtype.CIDR{{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present}},
65				Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
66				Status:     pgtype.Present},
67		},
68		{
69			source: (([]*net.IPNet)(nil)),
70			result: pgtype.CIDRArray{Status: pgtype.Null},
71		},
72		{
73			source: []net.IP{mustParseCIDR(t, "127.0.0.1/32").IP},
74			result: pgtype.CIDRArray{
75				Elements:   []pgtype.CIDR{{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present}},
76				Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
77				Status:     pgtype.Present},
78		},
79		{
80			source: (([]net.IP)(nil)),
81			result: pgtype.CIDRArray{Status: pgtype.Null},
82		},
83		{
84			source: [][]net.IP{{mustParseCIDR(t, "127.0.0.1/32").IP}, {mustParseCIDR(t, "10.0.0.1/32").IP}},
85			result: pgtype.CIDRArray{
86				Elements: []pgtype.CIDR{
87					{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present},
88					{IPNet: mustParseCIDR(t, "10.0.0.1/32"), Status: pgtype.Present}},
89				Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 2}, {LowerBound: 1, Length: 1}},
90				Status:     pgtype.Present},
91		},
92		{
93			source: [][][][]*net.IPNet{
94				{{{
95					mustParseCIDR(t, "127.0.0.1/24"),
96					mustParseCIDR(t, "10.0.0.1/24"),
97					mustParseCIDR(t, "172.16.0.1/16")}}},
98				{{{
99					mustParseCIDR(t, "192.168.0.1/16"),
100					mustParseCIDR(t, "224.0.0.1/24"),
101					mustParseCIDR(t, "169.168.0.1/16")}}}},
102			result: pgtype.CIDRArray{
103				Elements: []pgtype.CIDR{
104					{IPNet: mustParseCIDR(t, "127.0.0.1/24"), Status: pgtype.Present},
105					{IPNet: mustParseCIDR(t, "10.0.0.1/24"), Status: pgtype.Present},
106					{IPNet: mustParseCIDR(t, "172.16.0.1/16"), Status: pgtype.Present},
107					{IPNet: mustParseCIDR(t, "192.168.0.1/16"), Status: pgtype.Present},
108					{IPNet: mustParseCIDR(t, "224.0.0.1/24"), Status: pgtype.Present},
109					{IPNet: mustParseCIDR(t, "169.168.0.1/16"), Status: pgtype.Present}},
110				Dimensions: []pgtype.ArrayDimension{
111					{LowerBound: 1, Length: 2},
112					{LowerBound: 1, Length: 1},
113					{LowerBound: 1, Length: 1},
114					{LowerBound: 1, Length: 3}},
115				Status: pgtype.Present},
116		},
117		{
118			source: [2][1]net.IP{{mustParseCIDR(t, "127.0.0.1/32").IP}, {mustParseCIDR(t, "10.0.0.1/32").IP}},
119			result: pgtype.CIDRArray{
120				Elements: []pgtype.CIDR{
121					{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present},
122					{IPNet: mustParseCIDR(t, "10.0.0.1/32"), Status: pgtype.Present}},
123				Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 2}, {LowerBound: 1, Length: 1}},
124				Status:     pgtype.Present},
125		},
126		{
127			source: [2][1][1][3]*net.IPNet{
128				{{{
129					mustParseCIDR(t, "127.0.0.1/24"),
130					mustParseCIDR(t, "10.0.0.1/24"),
131					mustParseCIDR(t, "172.16.0.1/16")}}},
132				{{{
133					mustParseCIDR(t, "192.168.0.1/16"),
134					mustParseCIDR(t, "224.0.0.1/24"),
135					mustParseCIDR(t, "169.168.0.1/16")}}}},
136			result: pgtype.CIDRArray{
137				Elements: []pgtype.CIDR{
138					{IPNet: mustParseCIDR(t, "127.0.0.1/24"), Status: pgtype.Present},
139					{IPNet: mustParseCIDR(t, "10.0.0.1/24"), Status: pgtype.Present},
140					{IPNet: mustParseCIDR(t, "172.16.0.1/16"), Status: pgtype.Present},
141					{IPNet: mustParseCIDR(t, "192.168.0.1/16"), Status: pgtype.Present},
142					{IPNet: mustParseCIDR(t, "224.0.0.1/24"), Status: pgtype.Present},
143					{IPNet: mustParseCIDR(t, "169.168.0.1/16"), Status: pgtype.Present}},
144				Dimensions: []pgtype.ArrayDimension{
145					{LowerBound: 1, Length: 2},
146					{LowerBound: 1, Length: 1},
147					{LowerBound: 1, Length: 1},
148					{LowerBound: 1, Length: 3}},
149				Status: pgtype.Present},
150		},
151	}
152
153	for i, tt := range successfulTests {
154		var r pgtype.CIDRArray
155		err := r.Set(tt.source)
156		if err != nil {
157			t.Errorf("%d: %v", i, err)
158		}
159
160		if !reflect.DeepEqual(r, tt.result) {
161			t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
162		}
163	}
164}
165
166func TestCIDRArrayAssignTo(t *testing.T) {
167	var ipnetSlice []*net.IPNet
168	var ipSlice []net.IP
169	var ipSliceDim2 [][]net.IP
170	var ipnetSliceDim4 [][][][]*net.IPNet
171	var ipArrayDim2 [2][1]net.IP
172	var ipnetArrayDim4 [2][1][1][3]*net.IPNet
173
174	simpleTests := []struct {
175		src      pgtype.CIDRArray
176		dst      interface{}
177		expected interface{}
178	}{
179		{
180			src: pgtype.CIDRArray{
181				Elements:   []pgtype.CIDR{{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present}},
182				Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
183				Status:     pgtype.Present,
184			},
185			dst:      &ipnetSlice,
186			expected: []*net.IPNet{mustParseCIDR(t, "127.0.0.1/32")},
187		},
188		{
189			src: pgtype.CIDRArray{
190				Elements:   []pgtype.CIDR{{Status: pgtype.Null}},
191				Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
192				Status:     pgtype.Present,
193			},
194			dst:      &ipnetSlice,
195			expected: []*net.IPNet{nil},
196		},
197		{
198			src: pgtype.CIDRArray{
199				Elements:   []pgtype.CIDR{{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present}},
200				Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
201				Status:     pgtype.Present,
202			},
203			dst:      &ipSlice,
204			expected: []net.IP{mustParseCIDR(t, "127.0.0.1/32").IP},
205		},
206		{
207			src: pgtype.CIDRArray{
208				Elements:   []pgtype.CIDR{{Status: pgtype.Null}},
209				Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 1}},
210				Status:     pgtype.Present,
211			},
212			dst:      &ipSlice,
213			expected: []net.IP{nil},
214		},
215		{
216			src:      pgtype.CIDRArray{Status: pgtype.Null},
217			dst:      &ipnetSlice,
218			expected: (([]*net.IPNet)(nil)),
219		},
220		{
221			src:      pgtype.CIDRArray{Status: pgtype.Present},
222			dst:      &ipnetSlice,
223			expected: []*net.IPNet{},
224		},
225		{
226			src:      pgtype.CIDRArray{Status: pgtype.Null},
227			dst:      &ipSlice,
228			expected: (([]net.IP)(nil)),
229		},
230		{
231			src:      pgtype.CIDRArray{Status: pgtype.Present},
232			dst:      &ipSlice,
233			expected: []net.IP{},
234		},
235		{
236			src: pgtype.CIDRArray{
237				Elements: []pgtype.CIDR{
238					{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present},
239					{IPNet: mustParseCIDR(t, "10.0.0.1/32"), Status: pgtype.Present}},
240				Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 2}, {LowerBound: 1, Length: 1}},
241				Status:     pgtype.Present},
242			dst:      &ipSliceDim2,
243			expected: [][]net.IP{{mustParseCIDR(t, "127.0.0.1/32").IP}, {mustParseCIDR(t, "10.0.0.1/32").IP}},
244		},
245		{
246			src: pgtype.CIDRArray{
247				Elements: []pgtype.CIDR{
248					{IPNet: mustParseCIDR(t, "127.0.0.1/24"), Status: pgtype.Present},
249					{IPNet: mustParseCIDR(t, "10.0.0.1/24"), Status: pgtype.Present},
250					{IPNet: mustParseCIDR(t, "172.16.0.1/16"), Status: pgtype.Present},
251					{IPNet: mustParseCIDR(t, "192.168.0.1/16"), Status: pgtype.Present},
252					{IPNet: mustParseCIDR(t, "224.0.0.1/24"), Status: pgtype.Present},
253					{IPNet: mustParseCIDR(t, "169.168.0.1/16"), Status: pgtype.Present}},
254				Dimensions: []pgtype.ArrayDimension{
255					{LowerBound: 1, Length: 2},
256					{LowerBound: 1, Length: 1},
257					{LowerBound: 1, Length: 1},
258					{LowerBound: 1, Length: 3}},
259				Status: pgtype.Present},
260			dst: &ipnetSliceDim4,
261			expected: [][][][]*net.IPNet{
262				{{{
263					mustParseCIDR(t, "127.0.0.1/24"),
264					mustParseCIDR(t, "10.0.0.1/24"),
265					mustParseCIDR(t, "172.16.0.1/16")}}},
266				{{{
267					mustParseCIDR(t, "192.168.0.1/16"),
268					mustParseCIDR(t, "224.0.0.1/24"),
269					mustParseCIDR(t, "169.168.0.1/16")}}}},
270		},
271		{
272			src: pgtype.CIDRArray{
273				Elements: []pgtype.CIDR{
274					{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present},
275					{IPNet: mustParseCIDR(t, "10.0.0.1/32"), Status: pgtype.Present}},
276				Dimensions: []pgtype.ArrayDimension{{LowerBound: 1, Length: 2}, {LowerBound: 1, Length: 1}},
277				Status:     pgtype.Present},
278			dst:      &ipArrayDim2,
279			expected: [2][1]net.IP{{mustParseCIDR(t, "127.0.0.1/32").IP}, {mustParseCIDR(t, "10.0.0.1/32").IP}},
280		},
281		{
282			src: pgtype.CIDRArray{
283				Elements: []pgtype.CIDR{
284					{IPNet: mustParseCIDR(t, "127.0.0.1/24"), Status: pgtype.Present},
285					{IPNet: mustParseCIDR(t, "10.0.0.1/24"), Status: pgtype.Present},
286					{IPNet: mustParseCIDR(t, "172.16.0.1/16"), Status: pgtype.Present},
287					{IPNet: mustParseCIDR(t, "192.168.0.1/16"), Status: pgtype.Present},
288					{IPNet: mustParseCIDR(t, "224.0.0.1/24"), Status: pgtype.Present},
289					{IPNet: mustParseCIDR(t, "169.168.0.1/16"), Status: pgtype.Present}},
290				Dimensions: []pgtype.ArrayDimension{
291					{LowerBound: 1, Length: 2},
292					{LowerBound: 1, Length: 1},
293					{LowerBound: 1, Length: 1},
294					{LowerBound: 1, Length: 3}},
295				Status: pgtype.Present},
296			dst: &ipnetArrayDim4,
297			expected: [2][1][1][3]*net.IPNet{
298				{{{
299					mustParseCIDR(t, "127.0.0.1/24"),
300					mustParseCIDR(t, "10.0.0.1/24"),
301					mustParseCIDR(t, "172.16.0.1/16")}}},
302				{{{
303					mustParseCIDR(t, "192.168.0.1/16"),
304					mustParseCIDR(t, "224.0.0.1/24"),
305					mustParseCIDR(t, "169.168.0.1/16")}}}},
306		},
307	}
308
309	for i, tt := range simpleTests {
310		err := tt.src.AssignTo(tt.dst)
311		if err != nil {
312			t.Errorf("%d: %v", i, err)
313		}
314
315		if dst := reflect.ValueOf(tt.dst).Elem().Interface(); !reflect.DeepEqual(dst, tt.expected) {
316			t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
317		}
318	}
319}
320