| // Copyright 2020 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package fake |
| |
| import ( |
| "bytes" |
| "context" |
| "encoding/gob" |
| "testing" |
| "time" |
| |
| "cloud.google.com/go/datastore" |
| "github.com/google/go-cmp/cmp" |
| ) |
| |
| type author struct { |
| Name string |
| } |
| |
| func TestClientGet(t *testing.T) { |
| cases := []struct { |
| desc string |
| db map[string]map[string][]byte |
| key *datastore.Key |
| dst interface{} |
| want *author |
| wantErr bool |
| }{ |
| { |
| desc: "correct key", |
| db: map[string]map[string][]byte{ |
| "Author": {datastore.NameKey("Author", "The Trial", nil).Encode(): gobEncode(t, &author{Name: "Kafka"})}, |
| }, |
| key: datastore.NameKey("Author", "The Trial", nil), |
| dst: new(author), |
| want: &author{Name: "Kafka"}, |
| }, |
| { |
| desc: "incorrect key errors", |
| db: map[string]map[string][]byte{ |
| "Author": {datastore.NameKey("Author", "The Trial", nil).Encode(): gobEncode(t, &author{Name: "Kafka"})}, |
| }, |
| key: datastore.NameKey("Author", "The Go Programming Language", nil), |
| dst: new(author), |
| wantErr: true, |
| }, |
| { |
| desc: "nil dst errors", |
| db: map[string]map[string][]byte{ |
| "Author": {datastore.NameKey("Author", "The Trial", nil).Encode(): gobEncode(t, &author{Name: "Kafka"})}, |
| }, |
| key: datastore.NameKey("Author", "The Go Programming Language", nil), |
| wantErr: true, |
| }, |
| { |
| desc: "incorrect dst type errors", |
| db: map[string]map[string][]byte{ |
| "Author": {datastore.NameKey("Author", "The Trial", nil).Encode(): gobEncode(t, &author{Name: "Kafka"})}, |
| }, |
| key: datastore.NameKey("Author", "The Go Programming Language", nil), |
| dst: &time.Time{}, |
| wantErr: true, |
| }, |
| { |
| desc: "non-pointer dst errors", |
| db: map[string]map[string][]byte{ |
| "Author": {datastore.NameKey("Author", "The Trial", nil).Encode(): gobEncode(t, &author{Name: "Kafka"})}, |
| }, |
| key: datastore.NameKey("Author", "The Go Programming Language", nil), |
| dst: author{}, |
| wantErr: true, |
| }, |
| { |
| desc: "nil dst errors", |
| db: map[string]map[string][]byte{ |
| "Author": {datastore.NameKey("Author", "The Trial", nil).Encode(): gobEncode(t, &author{Name: "Kafka"})}, |
| }, |
| key: datastore.NameKey("Author", "The Go Programming Language", nil), |
| dst: nil, |
| wantErr: true, |
| }, |
| { |
| desc: "empty db errors", |
| key: datastore.NameKey("Author", "The Go Programming Language", nil), |
| dst: nil, |
| wantErr: true, |
| }, |
| } |
| for _, c := range cases { |
| t.Run(c.desc, func(t *testing.T) { |
| cl := &Client{db: c.db} |
| |
| if err := cl.Get(context.Background(), c.key, c.dst); (err != nil) != c.wantErr { |
| t.Fatalf("cl.Get(_, %v, %v) = %q, wantErr: %v", c.key, c.dst, err, c.wantErr) |
| } |
| if c.wantErr { |
| return |
| } |
| if diff := cmp.Diff(c.want, c.dst); diff != "" { |
| t.Errorf("author mismatch (-want +got):\n%s", diff) |
| } |
| }) |
| } |
| } |
| |
| func TestClientGetAll(t *testing.T) { |
| cases := []struct { |
| desc string |
| db map[string]map[string][]byte |
| query *datastore.Query |
| want []*author |
| wantKeys []*datastore.Key |
| wantErr bool |
| }{ |
| { |
| desc: "all of a Kind", |
| db: map[string]map[string][]byte{ |
| "Author": {datastore.NameKey("Author", "The Trial", nil).Encode(): gobEncode(t, &author{Name: "Kafka"})}, |
| }, |
| query: datastore.NewQuery("Author"), |
| wantKeys: []*datastore.Key{datastore.NameKey("Author", "The Trial", nil)}, |
| want: []*author{{Name: "Kafka"}}, |
| }, |
| { |
| desc: "all of a non-existent kind", |
| db: map[string]map[string][]byte{ |
| "Author": {datastore.NameKey("Author", "The Trial", nil).Encode(): gobEncode(t, &author{Name: "Kafka"})}, |
| }, |
| query: datastore.NewQuery("Book"), |
| wantErr: false, |
| }, |
| } |
| for _, c := range cases { |
| t.Run(c.desc, func(t *testing.T) { |
| cl := &Client{db: c.db} |
| |
| var got []*author |
| keys, err := cl.GetAll(context.Background(), c.query, &got) |
| if (err != nil) != c.wantErr { |
| t.Fatalf("cl.Getall(_, %v, %v) = %q, wantErr: %v", c.query, got, err, c.wantErr) |
| } |
| if diff := cmp.Diff(c.want, got); diff != "" { |
| t.Errorf("authors mismatch (-want +got):\n%s", diff) |
| } |
| if diff := cmp.Diff(c.wantKeys, keys); diff != "" { |
| t.Errorf("keys mismatch (-want +got):\n%s", diff) |
| } |
| }) |
| } |
| } |
| |
| func TestClientPut(t *testing.T) { |
| cl := &Client{} |
| src := &author{Name: "Kafka"} |
| key := datastore.NameKey("Author", "The Trial", nil) |
| |
| gotKey, err := cl.Put(context.Background(), key, src) |
| if err != nil { |
| t.Fatalf("cl.Put(_, %v, %v) = %v, %q, wanted no error", gotKey, key, src, err) |
| } |
| got := new(author) |
| gobDecode(t, cl.db["Author"][key.Encode()], got) |
| |
| if diff := cmp.Diff(src, got); diff != "" { |
| t.Errorf("author mismatch (-want +got):\n%s", diff) |
| } |
| if diff := cmp.Diff(key, gotKey); diff != "" { |
| t.Errorf("keys mismatch (-want +got):\n%s", diff) |
| } |
| } |
| |
| // gobEncode encodes src with gob, returning the encoded byte slice. |
| // It will report errors on the provided testing.T. |
| func gobEncode(t *testing.T, src interface{}) []byte { |
| t.Helper() |
| dst := bytes.Buffer{} |
| e := gob.NewEncoder(&dst) |
| if err := e.Encode(src); err != nil { |
| t.Errorf("e.Encode(%v) = %q, wanted no error", src, err) |
| return nil |
| } |
| return dst.Bytes() |
| } |
| |
| // gobDecode decodes v into dst with gob. It will report errors on the |
| // provided testing.T. |
| func gobDecode(t *testing.T, v []byte, dst interface{}) { |
| t.Helper() |
| d := gob.NewDecoder(bytes.NewReader(v)) |
| if err := d.Decode(dst); err != nil { |
| t.Errorf("d.Decode(%v) = %q, wanted no error", dst, err) |
| } |
| } |