1// Copyright 2014 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package datastore
16
17import (
18	"bytes"
19	"encoding/gob"
20	"encoding/json"
21	"testing"
22)
23
24func TestEqual(t *testing.T) {
25	testCases := []struct {
26		x, y  *Key
27		equal bool
28	}{
29		{
30			x:     nil,
31			y:     nil,
32			equal: true,
33		},
34		{
35			x:     &Key{Kind: "kindA"},
36			y:     &Key{Kind: "kindA"},
37			equal: true,
38		},
39		{
40			x:     &Key{Kind: "kindA", Name: "nameA"},
41			y:     &Key{Kind: "kindA", Name: "nameA"},
42			equal: true,
43		},
44		{
45			x:     &Key{Kind: "kindA", Name: "nameA", Namespace: "gopherspace"},
46			y:     &Key{Kind: "kindA", Name: "nameA", Namespace: "gopherspace"},
47			equal: true,
48		},
49		{
50			x:     &Key{Kind: "kindA", ID: 1337, Parent: &Key{Kind: "kindX", Name: "nameX"}},
51			y:     &Key{Kind: "kindA", ID: 1337, Parent: &Key{Kind: "kindX", Name: "nameX"}},
52			equal: true,
53		},
54		{
55			x:     &Key{Kind: "kindA", Name: "nameA"},
56			y:     &Key{Kind: "kindB", Name: "nameA"},
57			equal: false,
58		},
59		{
60			x:     &Key{Kind: "kindA", Name: "nameA"},
61			y:     &Key{Kind: "kindA", Name: "nameB"},
62			equal: false,
63		},
64		{
65			x:     &Key{Kind: "kindA", Name: "nameA"},
66			y:     &Key{Kind: "kindA", ID: 1337},
67			equal: false,
68		},
69		{
70			x:     &Key{Kind: "kindA", Name: "nameA"},
71			y:     &Key{Kind: "kindA", Name: "nameA", Namespace: "gopherspace"},
72			equal: false,
73		},
74		{
75			x:     &Key{Kind: "kindA", ID: 1337, Parent: &Key{Kind: "kindX", Name: "nameX"}},
76			y:     &Key{Kind: "kindA", ID: 1337, Parent: &Key{Kind: "kindY", Name: "nameX"}},
77			equal: false,
78		},
79		{
80			x:     &Key{Kind: "kindA", ID: 1337, Parent: &Key{Kind: "kindX", Name: "nameX"}},
81			y:     &Key{Kind: "kindA", ID: 1337},
82			equal: false,
83		},
84	}
85
86	for _, tt := range testCases {
87		if got := tt.x.Equal(tt.y); got != tt.equal {
88			t.Errorf("Equal(%v, %v) = %t; want %t", tt.x, tt.y, got, tt.equal)
89		}
90		if got := tt.y.Equal(tt.x); got != tt.equal {
91			t.Errorf("Equal(%v, %v) = %t; want %t", tt.y, tt.x, got, tt.equal)
92		}
93	}
94}
95
96func TestEncoding(t *testing.T) {
97	testCases := []struct {
98		k     *Key
99		valid bool
100	}{
101		{
102			k:     nil,
103			valid: false,
104		},
105		{
106			k:     &Key{},
107			valid: false,
108		},
109		{
110			k:     &Key{Kind: "kindA"},
111			valid: true,
112		},
113		{
114			k:     &Key{Kind: "kindA", Namespace: "gopherspace"},
115			valid: true,
116		},
117		{
118			k:     &Key{Kind: "kindA", Name: "nameA"},
119			valid: true,
120		},
121		{
122			k:     &Key{Kind: "kindA", ID: 1337},
123			valid: true,
124		},
125		{
126			k:     &Key{Kind: "kindA", Name: "nameA", ID: 1337},
127			valid: false,
128		},
129		{
130			k:     &Key{Kind: "kindA", Parent: &Key{Kind: "kindB", Name: "nameB"}},
131			valid: true,
132		},
133		{
134			k:     &Key{Kind: "kindA", Parent: &Key{Kind: "kindB"}},
135			valid: false,
136		},
137		{
138			k:     &Key{Kind: "kindA", Parent: &Key{Kind: "kindB", Name: "nameB", Namespace: "gopherspace"}},
139			valid: false,
140		},
141	}
142
143	for _, tt := range testCases {
144		if got := tt.k.valid(); got != tt.valid {
145			t.Errorf("valid(%v) = %t; want %t", tt.k, got, tt.valid)
146		}
147
148		// Check encoding/decoding for valid keys.
149		if !tt.valid {
150			continue
151		}
152		enc := tt.k.Encode()
153		dec, err := DecodeKey(enc)
154		if err != nil {
155			t.Errorf("DecodeKey(%q) from %v: %v", enc, tt.k, err)
156			continue
157		}
158		if !tt.k.Equal(dec) {
159			t.Logf("Proto: %s", keyToProto(tt.k))
160			t.Errorf("Decoded key %v not equal to %v", dec, tt.k)
161		}
162
163		b, err := json.Marshal(tt.k)
164		if err != nil {
165			t.Errorf("json.Marshal(%v): %v", tt.k, err)
166			continue
167		}
168		key := &Key{}
169		if err := json.Unmarshal(b, key); err != nil {
170			t.Errorf("json.Unmarshal(%s) for key %v: %v", b, tt.k, err)
171			continue
172		}
173		if !tt.k.Equal(key) {
174			t.Errorf("JSON decoded key %v not equal to %v", dec, tt.k)
175		}
176
177		buf := &bytes.Buffer{}
178		gobEnc := gob.NewEncoder(buf)
179		if err := gobEnc.Encode(tt.k); err != nil {
180			t.Errorf("gobEnc.Encode(%v): %v", tt.k, err)
181			continue
182		}
183		gobDec := gob.NewDecoder(buf)
184		key = &Key{}
185		if err := gobDec.Decode(key); err != nil {
186			t.Errorf("gobDec.Decode() for key %v: %v", tt.k, err)
187		}
188		if !tt.k.Equal(key) {
189			t.Errorf("gob decoded key %v not equal to %v", dec, tt.k)
190		}
191	}
192}
193
194func TestInvalidKeyDecode(t *testing.T) {
195	// Check that decoding an invalid key returns an err and doesn't panic.
196	enc := NameKey("Kind", "Foo", nil).Encode()
197
198	invalid := []string{
199		"",
200		"Laboratorio",
201		enc + "Junk",
202		enc[:len(enc)-4],
203	}
204	for _, enc := range invalid {
205		key, err := DecodeKey(enc)
206		if err == nil || key != nil {
207			t.Errorf("DecodeKey(%q) = %v, %v; want nil, error", enc, key, err)
208		}
209	}
210}
211