vendor: update all dependencies to latest versions
This commit is contained in:
+546
@@ -0,0 +1,546 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package firestore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
pb "google.golang.org/genproto/googleapis/firestore/v1beta1"
|
||||
|
||||
"google.golang.org/genproto/googleapis/type/latlng"
|
||||
)
|
||||
|
||||
var (
|
||||
tm = time.Date(2016, 12, 25, 0, 0, 0, 123456789, time.UTC)
|
||||
ll = &latlng.LatLng{Latitude: 20, Longitude: 30}
|
||||
)
|
||||
|
||||
func TestCreateFromProtoValue(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in *pb.Value
|
||||
want interface{}
|
||||
}{
|
||||
{in: nullValue, want: nil},
|
||||
{in: boolval(true), want: true},
|
||||
{in: intval(3), want: int64(3)},
|
||||
{in: floatval(1.5), want: 1.5},
|
||||
{in: strval("str"), want: "str"},
|
||||
{in: tsval(tm), want: tm},
|
||||
{
|
||||
in: bytesval([]byte{1, 2}),
|
||||
want: []byte{1, 2},
|
||||
},
|
||||
{
|
||||
in: &pb.Value{&pb.Value_GeoPointValue{ll}},
|
||||
want: ll,
|
||||
},
|
||||
{
|
||||
in: arrayval(intval(1), intval(2)),
|
||||
want: []interface{}{int64(1), int64(2)},
|
||||
},
|
||||
{
|
||||
in: arrayval(),
|
||||
want: []interface{}{},
|
||||
},
|
||||
{
|
||||
in: mapval(map[string]*pb.Value{"a": intval(1), "b": intval(2)}),
|
||||
want: map[string]interface{}{"a": int64(1), "b": int64(2)},
|
||||
},
|
||||
{
|
||||
in: mapval(map[string]*pb.Value{}),
|
||||
want: map[string]interface{}{},
|
||||
},
|
||||
{
|
||||
in: refval("projects/P/databases/D/documents/c/d"),
|
||||
want: &DocumentRef{
|
||||
ID: "d",
|
||||
Parent: &CollectionRef{
|
||||
ID: "c",
|
||||
parentPath: "projects/P/databases/D",
|
||||
Path: "projects/P/databases/D/documents/c",
|
||||
Query: Query{collectionID: "c", parentPath: "projects/P/databases/D"},
|
||||
},
|
||||
Path: "projects/P/databases/D/documents/c/d",
|
||||
},
|
||||
},
|
||||
} {
|
||||
got, err := createFromProtoValue(test.in, nil)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v", test.in, err)
|
||||
continue
|
||||
}
|
||||
if !testEqual(got, test.want) {
|
||||
t.Errorf("%+v:\ngot\n%#v\nwant\n%#v", test.in, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetFromProtoValue(t *testing.T) {
|
||||
testSetFromProtoValue(t, "json", jsonTester{})
|
||||
testSetFromProtoValue(t, "firestore", protoTester{})
|
||||
}
|
||||
|
||||
func testSetFromProtoValue(t *testing.T, prefix string, r tester) {
|
||||
pi := newfloat(7)
|
||||
s := []float64{7, 8}
|
||||
ar1 := [1]float64{7}
|
||||
ar2 := [2]float64{7, 8}
|
||||
ar3 := [3]float64{7, 8, 9}
|
||||
mf := map[string]float64{"a": 7}
|
||||
|
||||
type T struct {
|
||||
I **float64
|
||||
J float64
|
||||
}
|
||||
|
||||
one := newfloat(1)
|
||||
six := newfloat(6)
|
||||
st := []*T{&T{I: &six}, nil, &T{I: &six, J: 7}}
|
||||
vs := interface{}(T{J: 1})
|
||||
vm := interface{}(map[string]float64{"i": 1})
|
||||
var (
|
||||
i int
|
||||
i8 int8
|
||||
i16 int16
|
||||
i32 int32
|
||||
i64 int64
|
||||
u8 uint8
|
||||
u16 uint16
|
||||
u32 uint32
|
||||
b bool
|
||||
ll *latlng.LatLng
|
||||
mi map[string]interface{}
|
||||
ms map[string]T
|
||||
)
|
||||
|
||||
for i, test := range []struct {
|
||||
in interface{}
|
||||
val interface{}
|
||||
want interface{}
|
||||
}{
|
||||
{&pi, r.Null(), (*float64)(nil)},
|
||||
{pi, r.Float(1), 1.0},
|
||||
{&s, r.Null(), ([]float64)(nil)},
|
||||
{&s, r.Array(r.Float(1), r.Float(2)), []float64{1, 2}},
|
||||
{&ar1, r.Array(r.Float(1), r.Float(2)), [1]float64{1}},
|
||||
{&ar2, r.Array(r.Float(1), r.Float(2)), [2]float64{1, 2}},
|
||||
{&ar3, r.Array(r.Float(1), r.Float(2)), [3]float64{1, 2, 0}},
|
||||
{&mf, r.Null(), (map[string]float64)(nil)},
|
||||
{&mf, r.Map("a", r.Float(1), "b", r.Float(2)), map[string]float64{"a": 1, "b": 2}},
|
||||
{&st, r.Array(
|
||||
r.Null(), // overwrites st[0] with nil
|
||||
r.Map("i", r.Float(1)), // sets st[1] to a new struct
|
||||
r.Map("i", r.Float(2)), // modifies st[2]
|
||||
),
|
||||
[]*T{nil, &T{I: &one}, &T{I: &six, J: 7}}},
|
||||
{&mi, r.Map("a", r.Float(1), "b", r.Float(2)), map[string]interface{}{"a": 1.0, "b": 2.0}},
|
||||
{&ms, r.Map("a", r.Map("j", r.Float(1))), map[string]T{"a": T{J: 1}}},
|
||||
{&vs, r.Map("i", r.Float(2)), map[string]interface{}{"i": 2.0}},
|
||||
{&vm, r.Map("i", r.Float(2)), map[string]interface{}{"i": 2.0}},
|
||||
{&ll, r.Null(), (*latlng.LatLng)(nil)},
|
||||
{&i, r.Int(1), int(1)},
|
||||
{&i8, r.Int(1), int8(1)},
|
||||
{&i16, r.Int(1), int16(1)},
|
||||
{&i32, r.Int(1), int32(1)},
|
||||
{&i64, r.Int(1), int64(1)},
|
||||
{&u8, r.Int(1), uint8(1)},
|
||||
{&u16, r.Int(1), uint16(1)},
|
||||
{&u32, r.Int(1), uint32(1)},
|
||||
{&b, r.Bool(true), true},
|
||||
{&i, r.Float(1), int(1)}, // can put a float with no fractional part into an int
|
||||
{pi, r.Int(1), float64(1)}, // can put an int into a float
|
||||
} {
|
||||
if err := r.Set(test.in, test.val); err != nil {
|
||||
t.Errorf("%s: #%d: got error %v", prefix, i, err)
|
||||
continue
|
||||
}
|
||||
got := reflect.ValueOf(test.in).Elem().Interface()
|
||||
if !testEqual(got, test.want) {
|
||||
t.Errorf("%s: #%d, %v:\ngot\n%+v (%T)\nwant\n%+v (%T)",
|
||||
prefix, i, test.val, got, got, test.want, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetFromProtoValueNoJSON(t *testing.T) {
|
||||
// Test code paths that we cannot compare to JSON.
|
||||
var (
|
||||
bs []byte
|
||||
tmi time.Time
|
||||
lli *latlng.LatLng
|
||||
)
|
||||
bytes := []byte{1, 2, 3}
|
||||
|
||||
for i, test := range []struct {
|
||||
in interface{}
|
||||
val *pb.Value
|
||||
want interface{}
|
||||
}{
|
||||
{&bs, bytesval(bytes), bytes},
|
||||
{&tmi, tsval(tm), tm},
|
||||
{&lli, geoval(ll), ll},
|
||||
} {
|
||||
if err := setFromProtoValue(test.in, test.val, &Client{}); err != nil {
|
||||
t.Errorf("#%d: got error %v", i, err)
|
||||
continue
|
||||
}
|
||||
got := reflect.ValueOf(test.in).Elem().Interface()
|
||||
if !testEqual(got, test.want) {
|
||||
t.Errorf("#%d, %v:\ngot\n%+v (%T)\nwant\n%+v (%T)",
|
||||
i, test.val, got, got, test.want, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetFromProtoValueErrors(t *testing.T) {
|
||||
c := &Client{}
|
||||
ival := intval(3)
|
||||
for i, test := range []struct {
|
||||
in interface{}
|
||||
val *pb.Value
|
||||
}{
|
||||
{3, ival}, // not a pointer
|
||||
{new(int8), intval(128)}, // int overflow
|
||||
{new(uint8), intval(256)}, // uint overflow
|
||||
{new(float32), floatval(2 * math.MaxFloat32)}, // float overflow
|
||||
{new(uint), ival}, // cannot set type
|
||||
{new(uint64), ival}, // cannot set type
|
||||
{new(io.Reader), ival}, // cannot set type
|
||||
{new(map[int]int),
|
||||
mapval(map[string]*pb.Value{"x": ival})}, // map key type is not string
|
||||
// the rest are all type mismatches
|
||||
{new(bool), ival},
|
||||
{new(*latlng.LatLng), ival},
|
||||
{new(time.Time), ival},
|
||||
{new(string), ival},
|
||||
{new([]byte), ival},
|
||||
{new([]int), ival},
|
||||
{new([1]int), ival},
|
||||
{new(map[string]int), ival},
|
||||
{new(*bool), ival},
|
||||
{new(struct{}), ival},
|
||||
{new(int), floatval(2.5)}, // float must be integral
|
||||
{new(uint16), intval(-1)}, // uint cannot be negative
|
||||
{new(int16), floatval(math.MaxFloat32)}, // doesn't fit
|
||||
{new(uint16), floatval(math.MaxFloat32)}, // doesn't fit
|
||||
{new(float32),
|
||||
&pb.Value{&pb.Value_IntegerValue{math.MaxInt64}}}, // overflow
|
||||
} {
|
||||
err := setFromProtoValue(test.in, test.val, c)
|
||||
if err == nil {
|
||||
t.Errorf("#%d: %v, %v: got nil, want error", i, test.in, test.val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetFromProtoValuePointers(t *testing.T) {
|
||||
// Verify that pointers are set, instead of being replaced.
|
||||
// Confirm that the behavior matches encoding/json.
|
||||
testSetPointer(t, "json", jsonTester{})
|
||||
testSetPointer(t, "firestore", protoTester{&Client{}})
|
||||
}
|
||||
|
||||
func testSetPointer(t *testing.T, prefix string, r tester) {
|
||||
// If an interface{} holds a pointer, the pointer is set.
|
||||
|
||||
set := func(x, val interface{}) {
|
||||
if err := r.Set(x, val); err != nil {
|
||||
t.Fatalf("%s: set(%v, %v): %v", prefix, x, val, err)
|
||||
}
|
||||
}
|
||||
p := new(float64)
|
||||
var st struct {
|
||||
I interface{}
|
||||
}
|
||||
|
||||
// A pointer in a slice of interface{} is set.
|
||||
s := []interface{}{p}
|
||||
set(&s, r.Array(r.Float(1)))
|
||||
if s[0] != p {
|
||||
t.Errorf("%s: pointers not identical", prefix)
|
||||
}
|
||||
if *p != 1 {
|
||||
t.Errorf("%s: got %f, want 1", prefix, *p)
|
||||
}
|
||||
// Setting a null will set the pointer to nil.
|
||||
set(&s, r.Array(r.Null()))
|
||||
if got := s[0]; got != nil {
|
||||
t.Errorf("%s: got %v, want null", prefix, got)
|
||||
}
|
||||
|
||||
// It doesn't matter how deep the pointers nest.
|
||||
p = new(float64)
|
||||
p2 := &p
|
||||
p3 := &p2
|
||||
s = []interface{}{p3}
|
||||
set(&s, r.Array(r.Float(1)))
|
||||
if s[0] != p3 {
|
||||
t.Errorf("%s: pointers not identical", prefix)
|
||||
}
|
||||
if *p != 1 {
|
||||
t.Errorf("%s: got %f, want 1", prefix, *p)
|
||||
}
|
||||
|
||||
// A pointer in an interface{} field is set.
|
||||
p = new(float64)
|
||||
st.I = p
|
||||
set(&st, r.Map("i", r.Float(1)))
|
||||
if st.I != p {
|
||||
t.Errorf("%s: pointers not identical", prefix)
|
||||
}
|
||||
if *p != 1 {
|
||||
t.Errorf("%s: got %f, want 1", prefix, *p)
|
||||
}
|
||||
// Setting a null will set the pointer to nil.
|
||||
set(&st, r.Map("i", r.Null()))
|
||||
if got := st.I; got != nil {
|
||||
t.Errorf("%s: got %v, want null", prefix, got)
|
||||
}
|
||||
|
||||
// A pointer to a slice (instead of to float64) is set.
|
||||
psi := &[]float64{7, 8, 9}
|
||||
st.I = psi
|
||||
set(&st, r.Map("i", r.Array(r.Float(1))))
|
||||
if st.I != psi {
|
||||
t.Errorf("%s: pointers not identical", prefix)
|
||||
}
|
||||
// The slice itself should be truncated and filled, not replaced.
|
||||
if got, want := cap(*psi), 3; got != want {
|
||||
t.Errorf("cap: got %d, want %d", got, want)
|
||||
}
|
||||
if want := &[]float64{1}; !testEqual(st.I, want) {
|
||||
t.Errorf("got %+v, want %+v", st.I, want)
|
||||
}
|
||||
|
||||
// A pointer to a map is set.
|
||||
pmf := &map[string]float64{"a": 7, "b": 8}
|
||||
st.I = pmf
|
||||
set(&st, r.Map("i", r.Map("a", r.Float(1))))
|
||||
if st.I != pmf {
|
||||
t.Errorf("%s: pointers not identical", prefix)
|
||||
}
|
||||
if want := map[string]float64{"a": 1, "b": 8}; !testEqual(*pmf, want) {
|
||||
t.Errorf("%s: got %+v, want %+v", prefix, *pmf, want)
|
||||
}
|
||||
|
||||
// Maps are different: since the map values aren't addressable, they
|
||||
// are always discarded, even if the map element type is not interface{}.
|
||||
|
||||
// A map's values are discarded if the value type is a pointer type.
|
||||
p = new(float64)
|
||||
m := map[string]*float64{"i": p}
|
||||
set(&m, r.Map("i", r.Float(1)))
|
||||
if m["i"] == p {
|
||||
t.Errorf("%s: pointers are identical", prefix)
|
||||
}
|
||||
if got, want := *m["i"], 1.0; got != want {
|
||||
t.Errorf("%s: got %v, want %v", prefix, got, want)
|
||||
}
|
||||
// A map's values are discarded if the value type is interface{}.
|
||||
p = new(float64)
|
||||
m2 := map[string]interface{}{"i": p}
|
||||
set(&m2, r.Map("i", r.Float(1)))
|
||||
if m2["i"] == p {
|
||||
t.Errorf("%s: pointers are identical", prefix)
|
||||
}
|
||||
if got, want := m2["i"].(float64), 1.0; got != want {
|
||||
t.Errorf("%s: got %f, want %f", prefix, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// An interface for setting and building values, to facilitate comparing firestore deserialization
|
||||
// with encoding/json.
|
||||
type tester interface {
|
||||
Set(x, val interface{}) error
|
||||
Null() interface{}
|
||||
Int(int) interface{}
|
||||
Float(float64) interface{}
|
||||
Bool(bool) interface{}
|
||||
Array(...interface{}) interface{}
|
||||
Map(keysvals ...interface{}) interface{}
|
||||
}
|
||||
|
||||
type protoTester struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
func (p protoTester) Set(x, val interface{}) error { return setFromProtoValue(x, val.(*pb.Value), p.c) }
|
||||
func (protoTester) Null() interface{} { return nullValue }
|
||||
func (protoTester) Int(i int) interface{} { return intval(i) }
|
||||
func (protoTester) Float(f float64) interface{} { return floatval(f) }
|
||||
func (protoTester) Bool(b bool) interface{} { return boolval(b) }
|
||||
|
||||
func (protoTester) Array(els ...interface{}) interface{} {
|
||||
var s []*pb.Value
|
||||
for _, el := range els {
|
||||
s = append(s, el.(*pb.Value))
|
||||
}
|
||||
return arrayval(s...)
|
||||
}
|
||||
|
||||
func (protoTester) Map(keysvals ...interface{}) interface{} {
|
||||
m := map[string]*pb.Value{}
|
||||
for i := 0; i < len(keysvals); i += 2 {
|
||||
m[keysvals[i].(string)] = keysvals[i+1].(*pb.Value)
|
||||
}
|
||||
return mapval(m)
|
||||
}
|
||||
|
||||
type jsonTester struct{}
|
||||
|
||||
func (jsonTester) Set(x, val interface{}) error { return json.Unmarshal([]byte(val.(string)), x) }
|
||||
func (jsonTester) Null() interface{} { return "null" }
|
||||
func (jsonTester) Int(i int) interface{} { return fmt.Sprint(i) }
|
||||
func (jsonTester) Float(f float64) interface{} { return fmt.Sprint(f) }
|
||||
|
||||
func (jsonTester) Bool(b bool) interface{} {
|
||||
if b {
|
||||
return "true"
|
||||
}
|
||||
return "false"
|
||||
}
|
||||
|
||||
func (jsonTester) Array(els ...interface{}) interface{} {
|
||||
var s []string
|
||||
for _, el := range els {
|
||||
s = append(s, el.(string))
|
||||
}
|
||||
return "[" + strings.Join(s, ", ") + "]"
|
||||
}
|
||||
|
||||
func (jsonTester) Map(keysvals ...interface{}) interface{} {
|
||||
var s []string
|
||||
for i := 0; i < len(keysvals); i += 2 {
|
||||
s = append(s, fmt.Sprintf("%q: %v", keysvals[i], keysvals[i+1]))
|
||||
}
|
||||
return "{" + strings.Join(s, ", ") + "}"
|
||||
}
|
||||
|
||||
func newfloat(f float64) *float64 {
|
||||
p := new(float64)
|
||||
*p = f
|
||||
return p
|
||||
}
|
||||
|
||||
func TestParseDocumentPath(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in string
|
||||
pid, dbid string
|
||||
dpath []string
|
||||
}{
|
||||
{"projects/foo-bar/databases/db2/documents/c1/d1",
|
||||
"foo-bar", "db2", []string{"c1", "d1"}},
|
||||
{"projects/P/databases/D/documents/c1/d1/c2/d2",
|
||||
"P", "D", []string{"c1", "d1", "c2", "d2"}},
|
||||
} {
|
||||
gotPid, gotDbid, gotDpath, err := parseDocumentPath(test.in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := gotPid, test.pid; got != want {
|
||||
t.Errorf("project ID: got %q, want %q", got, want)
|
||||
}
|
||||
if got, want := gotDbid, test.dbid; got != want {
|
||||
t.Errorf("db ID: got %q, want %q", got, want)
|
||||
}
|
||||
if got, want := gotDpath, test.dpath; !testEqual(got, want) {
|
||||
t.Errorf("doc path: got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseDocumentPathErrors(t *testing.T) {
|
||||
for _, badPath := range []string{
|
||||
"projects/P/databases/D/documents/c", // collection path
|
||||
"/projects/P/databases/D/documents/c/d", // initial slash
|
||||
"projects/P/databases/D/c/d", // missing "documents"
|
||||
"project/P/database/D/document/c/d",
|
||||
} {
|
||||
// Every prefix of a bad path is also bad.
|
||||
for i := 0; i <= len(badPath); i++ {
|
||||
in := badPath[:i]
|
||||
_, _, _, err := parseDocumentPath(in)
|
||||
if err == nil {
|
||||
t.Errorf("%q: got nil, want error", in)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathToDoc(t *testing.T) {
|
||||
c := &Client{}
|
||||
path := "projects/P/databases/D/documents/c1/d1/c2/d2"
|
||||
got, err := pathToDoc(path, c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := &DocumentRef{
|
||||
ID: "d2",
|
||||
Path: "projects/P/databases/D/documents/c1/d1/c2/d2",
|
||||
Parent: &CollectionRef{
|
||||
ID: "c2",
|
||||
parentPath: "projects/P/databases/D/documents/c1/d1",
|
||||
Path: "projects/P/databases/D/documents/c1/d1/c2",
|
||||
c: c,
|
||||
Query: Query{c: c, collectionID: "c2", parentPath: "projects/P/databases/D/documents/c1/d1"},
|
||||
Parent: &DocumentRef{
|
||||
ID: "d1",
|
||||
Path: "projects/P/databases/D/documents/c1/d1",
|
||||
Parent: &CollectionRef{
|
||||
ID: "c1",
|
||||
c: c,
|
||||
parentPath: "projects/P/databases/D",
|
||||
Path: "projects/P/databases/D/documents/c1",
|
||||
Parent: nil,
|
||||
Query: Query{c: c, collectionID: "c1", parentPath: "projects/P/databases/D"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !testEqual(got, want) {
|
||||
t.Errorf("\ngot %+v\nwant %+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeString(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in *pb.Value
|
||||
want string
|
||||
}{
|
||||
{nullValue, "null"},
|
||||
{intval(1), "int"},
|
||||
{floatval(1), "float"},
|
||||
{boolval(true), "bool"},
|
||||
{strval(""), "string"},
|
||||
{tsval(tm), "timestamp"},
|
||||
{geoval(ll), "GeoPoint"},
|
||||
{bytesval(nil), "bytes"},
|
||||
{refval(""), "reference"},
|
||||
{arrayval(nil), "array"},
|
||||
{mapval(nil), "map"},
|
||||
} {
|
||||
got := typeString(test.in)
|
||||
if got != test.want {
|
||||
t.Errorf("%+v: got %q, want %q", test.in, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user