// Copyright 2011 Google Inc. All Rights Reserved. // Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package datastore import ( "bytes" "encoding/gob" "encoding/json" "testing" "golang.org/x/net/context" "google.golang.org/appengine/internal" ) func TestKeyEncoding(t *testing.T) { testCases := []struct { desc string key *Key exp string }{ { desc: "A simple key with an int ID", key: &Key{ kind: "Person", intID: 1, appID: "glibrary", }, exp: "aghnbGlicmFyeXIMCxIGUGVyc29uGAEM", }, { desc: "A simple key with a string ID", key: &Key{ kind: "Graph", stringID: "graph:7-day-active", appID: "glibrary", }, exp: "aghnbGlicmFyeXIdCxIFR3JhcGgiEmdyYXBoOjctZGF5LWFjdGl2ZQw", }, { desc: "A key with a parent", key: &Key{ kind: "WordIndex", intID: 1033, parent: &Key{ kind: "WordIndex", intID: 1020032, appID: "glibrary", }, appID: "glibrary", }, exp: "aghnbGlicmFyeXIhCxIJV29yZEluZGV4GIChPgwLEglXb3JkSW5kZXgYiQgM", }, } for _, tc := range testCases { enc := tc.key.Encode() if enc != tc.exp { t.Errorf("%s: got %q, want %q", tc.desc, enc, tc.exp) } key, err := DecodeKey(tc.exp) if err != nil { t.Errorf("%s: failed decoding key: %v", tc.desc, err) continue } if !key.Equal(tc.key) { t.Errorf("%s: decoded key %v, want %v", tc.desc, key, tc.key) } } } func TestKeyGob(t *testing.T) { k := &Key{ kind: "Gopher", intID: 3, parent: &Key{ kind: "Mom", stringID: "narwhal", appID: "gopher-con", }, appID: "gopher-con", } buf := new(bytes.Buffer) if err := gob.NewEncoder(buf).Encode(k); err != nil { t.Fatalf("gob encode failed: %v", err) } k2 := new(Key) if err := gob.NewDecoder(buf).Decode(k2); err != nil { t.Fatalf("gob decode failed: %v", err) } if !k2.Equal(k) { t.Errorf("gob round trip of %v produced %v", k, k2) } } func TestNilKeyGob(t *testing.T) { type S struct { Key *Key } s1 := new(S) buf := new(bytes.Buffer) if err := gob.NewEncoder(buf).Encode(s1); err != nil { t.Fatalf("gob encode failed: %v", err) } s2 := new(S) if err := gob.NewDecoder(buf).Decode(s2); err != nil { t.Fatalf("gob decode failed: %v", err) } if s2.Key != nil { t.Errorf("gob round trip of nil key produced %v", s2.Key) } } func TestKeyJSON(t *testing.T) { k := &Key{ kind: "Gopher", intID: 2, parent: &Key{ kind: "Mom", stringID: "narwhal", appID: "gopher-con", }, appID: "gopher-con", } exp := `"` + k.Encode() + `"` buf, err := json.Marshal(k) if err != nil { t.Fatalf("json.Marshal failed: %v", err) } if s := string(buf); s != exp { t.Errorf("JSON encoding of key %v: got %q, want %q", k, s, exp) } k2 := new(Key) if err := json.Unmarshal(buf, k2); err != nil { t.Fatalf("json.Unmarshal failed: %v", err) } if !k2.Equal(k) { t.Errorf("JSON round trip of %v produced %v", k, k2) } } func TestNilKeyJSON(t *testing.T) { type S struct { Key *Key } s1 := new(S) buf, err := json.Marshal(s1) if err != nil { t.Fatalf("json.Marshal failed: %v", err) } s2 := new(S) if err := json.Unmarshal(buf, s2); err != nil { t.Fatalf("json.Unmarshal failed: %v", err) } if s2.Key != nil { t.Errorf("JSON round trip of nil key produced %v", s2.Key) } } func TestIncompleteKeyWithParent(t *testing.T) { c := internal.WithAppIDOverride(context.Background(), "s~some-app") // fadduh is a complete key. fadduh := NewKey(c, "Person", "", 1, nil) if fadduh.Incomplete() { t.Fatalf("fadduh is incomplete") } // robert is an incomplete key with fadduh as a parent. robert := NewIncompleteKey(c, "Person", fadduh) if !robert.Incomplete() { t.Fatalf("robert is complete") } // Both should be valid keys. if !fadduh.valid() { t.Errorf("fadduh is invalid: %v", fadduh) } if !robert.valid() { t.Errorf("robert is invalid: %v", robert) } } func TestNamespace(t *testing.T) { key := &Key{ kind: "Person", intID: 1, appID: "s~some-app", namespace: "mynamespace", } if g, w := key.Namespace(), "mynamespace"; g != w { t.Errorf("key.Namespace() = %q, want %q", g, w) } }