text:
// 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/base64"
	"encoding/gob"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"

	"google.golang.org/appengine/internal"
	pb "google.golang.org/appengine/internal/datastore"
)

// Key represents the datastore key for a stored entity, and is immutable.
type Key struct {
	kind      string
	stringID  string
	intID     int64
	parent    *Key
	appID     string
	namespace string
}

// Kind returns the key's kind (also known as entity type).
func (k *Key) Kind() string {
	return k.kind
}

// StringID returns the key's string ID (also known as an entity name or key
// name), which may be "".
func (k *Key) StringID() string {
	return k.stringID
}

// IntID returns the key's integer ID, which may be 0.
func (k *Key) IntID() int64 {
	return k.intID
}

// Parent returns the key's parent key, which may be nil.
func (k *Key) Parent() *Key {
	return k.parent
}

// AppID returns the key's application ID.
func (k *Key) AppID() string {
	return k.appID
}

// Namespace returns the key's namespace.
func (k *Key) Namespace() string {
	return k.namespace
}

// Incomplete returns whether the key does not refer to a stored entity.
// In particular, whether the key has a zero StringID and a zero IntID.
func (k *Key) Incomplete() bool {
	return k.stringID == "" && k.intID == 0
}

// valid returns whether the key is valid.
func (k *Key) valid() bool {
	if k == nil {
		return false
	}
	for ; k != nil; k = k.parent {
		if k.kind == "" || k.appID == "" {
			return false
		}
		if k.stringID != "" && k.intID != 0 {
			return false
		}
		if k.parent != nil {
			if k.parent.Incomplete() {
				return false
			}
			if k.parent.appID != k.appID || k.parent.namespace != k.namespace {
				return false
			}
		}
	}
	return true
}

// Equal returns whether two keys are equal.
func (k *Key) Equal(o *Key) bool {
	for k != nil && o != nil {
		if k.kind != o.kind || k.stringID != o.stringID || k.intID != o.intID || k.appID != o.appID || k.namespace != o.namespace {
			return false
		}
		k, o = k.parent, o.parent
	}
	return k == o
}

// root returns the furthest ancestor of a key, which may be itself.
func (k *Key) root() *Key {
	for k.parent != nil {
		k = k.parent
	}
	return k
}

// marshal marshals the key's string representation to the buffer.
func (k *Key) marshal(b *bytes.Buffer) {
	if k.parent != nil {
		k.parent.marshal(b)
	}
	b.WriteByte('/')
	b.WriteString(k.kind)
	b.WriteByte(',')
	if k.stringID != "" {
		b.WriteString(k.stringID)
	} else {
		b.WriteString(strconv.FormatInt(k.intID, 10))
	}
}

// String returns a string representation of the key.
func (k *Key) String() string {
	if k == nil {
		return ""
	}
	b := bytes.NewBuffer(make([]byte, 0, 512))
	k.marshal(b)
	return b.String()
}

type gobKey struct {
	Kind      string
	StringID  string
	IntID     int64
	Parent    *gobKey
	AppID     string
	Namespace string
}

func keyToGobKey(k *Key) *gobKey {
	if k == nil {
		return nil
	}
	return &gobKey{
		Kind:      k.kind,
		StringID:  k.stringID,
		IntID:     k.intID,
		Parent:    keyToGobKey(k.parent),
		AppID:     k.appID,
		Namespace: k.namespace,
	}
}

func gobKeyToKey(gk *gobKey) *Key {
	if gk == nil {
		return nil
	}
	return &Key{
		kind:      gk.Kind,
		stringID:  gk.StringID,
		intID:     gk.IntID,
		parent:    gobKeyToKey(gk.Parent),
		appID:     gk.AppID,
		namespace: gk.Namespace,
	}
}

func (k *Key) GobEncode() ([]byte, error) {
	buf := new(bytes.Buffer)
	if err := gob.NewEncoder(buf).Encode(keyToGobKey(k)); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (k *Key) GobDecode(buf []byte) error {
	gk := new(gobKey)
	if err := gob.NewDecoder(bytes.NewBuffer(buf)).Decode(gk); err != nil {
		return err
	}
	*k = *gobKeyToKey(gk)
	return nil
}

func (k *Key) MarshalJSON() ([]byte, error) {
	return []byte(`"` + k.Encode() + `"`), nil
}

func (k *Key) UnmarshalJSON(buf []byte) error {
	if len(buf) < 2 || buf[0] != '"' || buf[len(buf)-1] != '"' {
		return errors.New("datastore: bad JSON key")
	}
	k2, err := DecodeKey(string(buf[1 : len(buf)-1]))
	if err != nil {
		return err
	}
	*k = *k2
	return nil
}

// Encode returns an opaque representation of the key
// suitable for use in HTML and URLs.
// This is compatible with the Python and Java runtimes.
func (k *Key) Encode() string {
	ref := keyToProto("", k)

	b, err := proto.Marshal(ref)
	if err != nil {
		panic(err)
	}

	// Trailing padding is stripped.
	return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
}

// DecodeKey decodes a key from the opaque representation returned by Encode.
func DecodeKey(encoded string) (*Key, error) {
	// Re-add padding.
	if m := len(encoded) % 4; m != 0 {
		encoded += strings.Repeat("=", 4-m)
	}

	b, err := base64.URLEncoding.DecodeString(encoded)
	if err != nil {
		return nil, err
	}

	ref := new(pb.Reference)
	if err := proto.Unmarshal(b, ref); err != nil {
		return nil, err
	}

	return protoToKey(ref)
}

// NewIncompleteKey creates a new incomplete key.
// kind cannot be empty.
func NewIncompleteKey(c context.Context, kind string, parent *Key) *Key {
	return NewKey(c, kind, "", 0, parent)
}

// NewKey creates a new key.
// kind cannot be empty.
// Either one or both of stringID and intID must be zero. If both are zero,
// the key returned is incomplete.
// parent must either be a complete key or nil.
func NewKey(c context.Context, kind, stringID string, intID int64, parent *Key) *Key {
	// If there's a parent key, use its namespace.
	// Otherwise, use any namespace attached to the context.
	var namespace string
	if parent != nil {
		namespace = parent.namespace
	} else {
		namespace = internal.NamespaceFromContext(c)
	}

	return &Key{
		kind:      kind,
		stringID:  stringID,
		intID:     intID,
		parent:    parent,
		appID:     internal.FullyQualifiedAppID(c),
		namespace: namespace,
	}
}

// AllocateIDs returns a range of n integer IDs with the given kind and parent
// combination. kind cannot be empty; parent may be nil. The IDs in the range
// returned will not be used by the datastore's automatic ID sequence generator
// and may be used with NewKey without conflict.
//
// The range is inclusive at the low end and exclusive at the high end. In
// other words, valid intIDs x satisfy low <= x && x < high.
//
// If no error is returned, low + n == high.
func AllocateIDs(c context.Context, kind string, parent *Key, n int) (low, high int64, err error) {
	if kind == "" {
		return 0, 0, errors.New("datastore: AllocateIDs given an empty kind")
	}
	if n < 0 {
		return 0, 0, fmt.Errorf("datastore: AllocateIDs given a negative count: %d", n)
	}
	if n == 0 {
		return 0, 0, nil
	}
	req := &pb.AllocateIdsRequest{
		ModelKey: keyToProto("", NewIncompleteKey(c, kind, parent)),
		Size:     proto.Int64(int64(n)),
	}
	res := &pb.AllocateIdsResponse{}
	if err := internal.Call(c, "datastore_v3", "AllocateIds", req, res); err != nil {
		return 0, 0, err
	}
	// The protobuf is inclusive at both ends. Idiomatic Go (e.g. slices, for loops)
	// is inclusive at the low end and exclusive at the high end, so we add 1.
	low = res.GetStart()
	high = res.GetEnd() + 1
	if low+int64(n) != high {
		return 0, 0, fmt.Errorf("datastore: internal error: could not allocate %d IDs", n)
	}
	return low, high, nil
}


text:
// 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 (
	"reflect"
	"testing"
	"time"

	"google.golang.org/appengine"
)

func TestValidPropertyName(t *testing.T) {
	testCases := []struct {
		name string
		want bool
	}{
		// Invalid names.
		{"", false},
		{"'", false},
		{".", false},
		{"..", false},
		{".foo", false},
		{"0", false},
		{"00", false},
		{"X.X.4.X.X", false},
		{"\n", false},
		{"\x00", false},
		{"abc\xffz", false},
		{"foo.", false},
		{"foo..", false},
		{"foo..bar", false},
		{"☃", false},
		{`"`, false},
		// Valid names.
		{"AB", true},
		{"Abc", true},
		{"X.X.X.X.X", true},
		{"_", true},
		{"_0", true},
		{"a", true},
		{"a_B", true},
		{"f00", true},
		{"f0o", true},
		{"fo0", true},
		{"foo", true},
		{"foo.bar", true},
		{"foo.bar.baz", true},
		{"世界", true},
	}
	for _, tc := range testCases {
		got := validPropertyName(tc.name)
		if got != tc.want {
			t.Errorf("%q: got %v, want %v", tc.name, got, tc.want)
		}
	}
}

func TestStructCodec(t *testing.T) {
	type oStruct struct {
		O int
	}
	type pStruct struct {
		P int
		Q int
	}
	type rStruct struct {
		R int
		S pStruct
		T oStruct
		oStruct
	}
	type uStruct struct {
		U int
		v int
	}
	type vStruct struct {
		V string `datastore:",noindex"`
	}
	oStructCodec := &structCodec{
		byIndex: []structTag{
			{name: "O"},
		},
		byName: map[string]fieldCodec{
			"O": {index: 0},
		},
		complete: true,
	}
	pStructCodec := &structCodec{
		byIndex: []structTag{
			{name: "P"},
			{name: "Q"},
		},
		byName: map[string]fieldCodec{
			"P": {index: 0},
			"Q": {index: 1},
		},
		complete: true,
	}
	rStructCodec := &structCodec{
		byIndex: []structTag{
			{name: "R"},
			{name: "S."},
			{name: "T."},
			{name: ""},
		},
		byName: map[string]fieldCodec{
			"R":   {index: 0},
			"S.P": {index: 1, substructCodec: pStructCodec},
			"S.Q": {index: 1, substructCodec: pStructCodec},
			"T.O": {index: 2, substructCodec: oStructCodec},
			"O":   {index: 3, substructCodec: oStructCodec},
		},
		complete: true,
	}
	uStructCodec := &structCodec{
		byIndex: []structTag{
			{name: "U"},
			{name: "v"},
		},
		byName: map[string]fieldCodec{
			"U": {index: 0},
			"v": {index: 1},
		},
		complete: true,
	}
	vStructCodec := &structCodec{
		byIndex: []structTag{
			{name: "V", noIndex: true},
		},
		byName: map[string]fieldCodec{
			"V": {index: 0},
		},
		complete: true,
	}

	testCases := []struct {
		desc        string
		structValue interface{}
		want        *structCodec
	}{
		{
			"oStruct",
			oStruct{},
			oStructCodec,
		},
		{
			"pStruct",
			pStruct{},
			pStructCodec,
		},
		{
			"rStruct",
			rStruct{},
			rStructCodec,
		},
		{
			"uStruct",
			uStruct{},
			uStructCodec,
		},
		{
			"non-basic fields",
			struct {
				B appengine.BlobKey
				K *Key
				T time.Time
			}{},
			&structCodec{
				byIndex: []structTag{
					{name: "B"},
					{name: "K"},
					{name: "T"},
				},
				byName: map[string]fieldCodec{
					"B": {index: 0},
					"K": {index: 1},
					"T": {index: 2},
				},
				complete: true,
			},
		},
		{
			"struct tags with ignored embed",
			struct {
				A       int `datastore:"a,noindex"`
				B       int `datastore:"b"`
				C       int `datastore:",noindex"`
				D       int `datastore:""`
				E       int
				I       int `datastore:"-"`
				J       int `datastore:",noindex" json:"j"`
				oStruct `datastore:"-"`
			}{},
			&structCodec{
				byIndex: []structTag{
					{name: "a", noIndex: true},
					{name: "b", noIndex: false},
					{name: "C", noIndex: true},
					{name: "D", noIndex: false},
					{name: "E", noIndex: false},
					{name: "-", noIndex: false},
					{name: "J", noIndex: true},
					{name: "-", noIndex: false},
				},
				byName: map[string]fieldCodec{
					"a": {index: 0},
					"b": {index: 1},
					"C": {index: 2},
					"D": {index: 3},
					"E": {index: 4},
					"J": {index: 6},
				},
				complete: true,
			},
		},
		{
			"unexported fields",
			struct {
				A int
				b int
				C int `datastore:"x"`
				d int `datastore:"Y"`
			}{},
			&structCodec{
				byIndex: []structTag{
					{name: "A"},
					{name: "b"},
					{name: "x"},
					{name: "Y"},
				},
				byName: map[string]fieldCodec{
					"A": {index: 0},
					"b": {index: 1},
					"x": {index: 2},
					"Y": {index: 3},
				},
				complete: true,
			},
		},
		{
			"nested and embedded structs",
			struct {
				A   int
				B   int
				CC  oStruct
				DDD rStruct
				oStruct
			}{},
			&structCodec{
				byIndex: []structTag{
					{name: "A"},
					{name: "B"},
					{name: "CC."},
					{name: "DDD."},
					{name: ""},
				},
				byName: map[string]fieldCodec{
					"A":       {index: 0},
					"B":       {index: 1},
					"CC.O":    {index: 2, substructCodec: oStructCodec},
					"DDD.R":   {index: 3, substructCodec: rStructCodec},
					"DDD.S.P": {index: 3, substructCodec: rStructCodec},
					"DDD.S.Q": {index: 3, substructCodec: rStructCodec},
					"DDD.T.O": {index: 3, substructCodec: rStructCodec},
					"DDD.O":   {index: 3, substructCodec: rStructCodec},
					"O":       {index: 4, substructCodec: oStructCodec},
				},
				complete: true,
			},
		},
		{
			"struct tags with nested and embedded structs",
			struct {
				A       int     `datastore:"-"`
				B       int     `datastore:"w"`
				C       oStruct `datastore:"xx"`
				D       rStruct `datastore:"y"`
				oStruct `datastore:"z"`
			}{},
			&structCodec{
				byIndex: []structTag{
					{name: "-"},
					{name: "w"},
					{name: "xx."},
					{name: "y."},
					{name: "z."},
				},
				byName: map[string]fieldCodec{
					"w":     {index: 1},
					"xx.O":  {index: 2, substructCodec: oStructCodec},
					"y.R":   {index: 3, substructCodec: rStructCodec},
					"y.S.P": {index: 3, substructCodec: rStructCodec},
					"y.S.Q": {index: 3, substructCodec: rStructCodec},
					"y.T.O": {index: 3, substructCodec: rStructCodec},
					"y.O":   {index: 3, substructCodec: rStructCodec},
					"z.O":   {index: 4, substructCodec: oStructCodec},
				},
				complete: true,
			},
		},
		{
			"unexported nested and embedded structs",
			struct {
				a int
				B int
				c uStruct
				D uStruct
				uStruct
			}{},
			&structCodec{
				byIndex: []structTag{
					{name: "a"},
					{name: "B"},
					{name: "c."},
					{name: "D."},
					{name: ""},
				},
				byName: map[string]fieldCodec{
					"a":   {index: 0},
					"B":   {index: 1},
					"c.U": {index: 2, substructCodec: uStructCodec},
					"c.v": {index: 2, substructCodec: uStructCodec},
					"D.U": {index: 3, substructCodec: uStructCodec},
					"D.v": {index: 3, substructCodec: uStructCodec},
					"U":   {index: 4, substructCodec: uStructCodec},
					"v":   {index: 4, substructCodec: uStructCodec},
				},
				complete: true,
			},
		},
		{
			"noindex nested struct",
			struct {
				A oStruct `datastore:",noindex"`
			}{},
			&structCodec{
				byIndex: []structTag{
					{name: "A.", noIndex: true},
				},
				byName: map[string]fieldCodec{
					"A.O": {index: 0, substructCodec: oStructCodec},
				},
				complete: true,
			},
		},
		{
			"noindex slice",
			struct {
				A []string `datastore:",noindex"`
			}{},
			&structCodec{
				byIndex: []structTag{
					{name: "A", noIndex: true},
				},
				byName: map[string]fieldCodec{
					"A": {index: 0},
				},
				hasSlice: true,
				complete: true,
			},
		},
		{
			"noindex embedded struct slice",
			struct {
				// vStruct has a single field, V, also with noindex.
				A []vStruct `datastore:",noindex"`
			}{},
			&structCodec{
				byIndex: []structTag{
					{name: "A.", noIndex: true},
				},
				byName: map[string]fieldCodec{
					"A.V": {index: 0, substructCodec: vStructCodec},
				},
				hasSlice: true,
				complete: true,
			},
		},
	}

	for _, tc := range testCases {
		got, err := getStructCodec(reflect.TypeOf(tc.structValue))
		if err != nil {
			t.Errorf("%s: getStructCodec: %v", tc.desc, err)
			continue
		}
		if !reflect.DeepEqual(got, tc.want) {
			t.Errorf("%s\ngot  %+v\nwant %+v\n", tc.desc, got, tc.want)
			continue
		}
	}
}

func TestRepeatedPropertyName(t *testing.T) {
	good := []interface{}{
		struct {
			A int `datastore:"-"`
		}{},
		struct {
			A int `datastore:"b"`
			B int
		}{},
		struct {
			A int
			B int `datastore:"B"`
		}{},
		struct {
			A int `datastore:"B"`
			B int `datastore:"-"`
		}{},
		struct {
			A int `datastore:"-"`
			B int `datastore:"A"`
		}{},
		struct {
			A int `datastore:"B"`
			B int `datastore:"A"`
		}{},
		struct {
			A int `datastore:"B"`
			B int `datastore:"C"`
			C int `datastore:"A"`
		}{},
		struct {
			A int `datastore:"B"`
			B int `datastore:"C"`
			C int `datastore:"D"`
		}{},
	}
	bad := []interface{}{
		struct {
			A int `datastore:"B"`
			B int
		}{},
		struct {
			A int
			B int `datastore:"A"`
		}{},
		struct {
			A int `datastore:"C"`
			B int `datastore:"C"`
		}{},
		struct {
			A int `datastore:"B"`
			B int `datastore:"C"`
			C int `datastore:"B"`
		}{},
	}
	testGetStructCodec(t, good, bad)
}

func TestFlatteningNestedStructs(t *testing.T) {
	type deepGood struct {
		A struct {
			B []struct {
				C struct {
					D int
				}
			}
		}
	}
	type deepBad struct {
		A struct {
			B []struct {
				C struct {
					D []int
				}
			}
		}
	}
	type iSay struct {
		Tomato int
	}
	type youSay struct {
		Tomato int
	}
	type tweedledee struct {
		Dee int `datastore:"D"`
	}
	type tweedledum struct {
		Dum int `datastore:"D"`
	}

	good := []interface{}{
		struct {
			X []struct {
				Y string
			}
		}{},
		struct {
			X []struct {
				Y []byte
			}
		}{},
		struct {
			P []int
			X struct {
				Y []int
			}
		}{},
		struct {
			X struct {
				Y []int
			}
			Q []int
		}{},
		struct {
			P []int
			X struct {
				Y []int
			}
			Q []int
		}{},
		struct {
			deepGood
		}{},
		struct {
			DG deepGood
		}{},
		struct {
			Foo struct {
				Z int `datastore:"X"`
			} `datastore:"A"`
			Bar struct {
				Z int `datastore:"Y"`
			} `datastore:"A"`
		}{},
	}
	bad := []interface{}{
		struct {
			X []struct {
				Y []string
			}
		}{},
		struct {
			X []struct {
				Y []int
			}
		}{},
		struct {
			deepBad
		}{},
		struct {
			DB deepBad
		}{},
		struct {
			iSay
			youSay
		}{},
		struct {
			tweedledee
			tweedledum
		}{},
		struct {
			Foo struct {
				Z int
			} `datastore:"A"`
			Bar struct {
				Z int
			} `datastore:"A"`
		}{},
	}
	testGetStructCodec(t, good, bad)
}

func testGetStructCodec(t *testing.T, good []interface{}, bad []interface{}) {
	for _, x := range good {
		if _, err := getStructCodec(reflect.TypeOf(x)); err != nil {
			t.Errorf("type %T: got non-nil error (%s), want nil", x, err)
		}
	}
	for _, x := range bad {
		if _, err := getStructCodec(reflect.TypeOf(x)); err == nil {
			t.Errorf("type %T: got nil error, want non-nil", x)
		}
	}
}

func TestNilKeyIsStored(t *testing.T) {
	x := struct {
		K *Key
		I int
	}{}
	p := PropertyList{}
	// Save x as properties.
	p1, _ := SaveStruct(&x)
	p.Load(p1)
	// Set x's fields to non-zero.
	x.K = &Key{}
	x.I = 2
	// Load x from properties.
	p2, _ := p.Save()
	LoadStruct(&x, p2)
	// Check that x's fields were set to zero.
	if x.K != nil {
		t.Errorf("K field was not zero")
	}
	if x.I != 0 {
		t.Errorf("I field was not zero")
	}
}

repo_name: dan-v/dosxvpn

repo_language: Go

mime_type: text/x-shellscript


text:
// 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 (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"reflect"
	"strings"
	"testing"
	"time"

	"google.golang.org/appengine"
	"google.golang.org/appengine/internal/aetesting"
	pb "google.golang.org/appengine/internal/datastore"
)

const testAppID = "testApp"

type (
	myBlob   []byte
	myByte   byte
	myString string
)

func makeMyByteSlice(n int) []myByte {
	b := make([]myByte, n)
	for i := range b {
		b[i] = myByte(i)
	}
	return b
}

func makeInt8Slice(n int) []int8 {
	b := make([]int8, n)
	for i := range b {
		b[i] = int8(i)
	}
	return b
}

func makeUint8Slice(n int) []uint8 {
	b := make([]uint8, n)
	for i := range b {
		b[i] = uint8(i)
	}
	return b
}

func newKey(stringID string, parent *Key) *Key {
	return &Key{
		kind:     "kind",
		stringID: stringID,
		intID:    0,
		parent:   parent,
		appID:    testAppID,
	}
}

var (
	testKey0     = newKey("name0", nil)
	testKey1a    = newKey("name1", nil)
	testKey1b    = newKey("name1", nil)
	testKey2a    = newKey("name2", testKey0)
	testKey2b    = newKey("name2", testKey0)
	testGeoPt0   = appengine.GeoPoint{Lat: 1.2, Lng: 3.4}
	testGeoPt1   = appengine.GeoPoint{Lat: 5, Lng: 10}
	testBadGeoPt = appengine.GeoPoint{Lat: 1000, Lng: 34}
)

type B0 struct {
	B []byte
}

type B1 struct {
	B []int8
}

type B2 struct {
	B myBlob
}

type B3 struct {
	B []myByte
}

type B4 struct {
	B [][]byte
}

type B5 struct {
	B ByteString
}

type C0 struct {
	I int
	C chan int
}

type C1 struct {
	I int
	C *chan int
}

type C2 struct {
	I int
	C []chan int
}

type C3 struct {
	C string
}

type E struct{}

type G0 struct {
	G appengine.GeoPoint
}

type G1 struct {
	G []appengine.GeoPoint
}

type K0 struct {
	K *Key
}

type K1 struct {
	K []*Key
}

type N0 struct {
	X0
	Nonymous X0
	Ignore   string `datastore:"-"`
	Other    string
}

type N1 struct {
	X0
	Nonymous []X0
	Ignore   string `datastore:"-"`
	Other    string
}

type N2 struct {
	N1    `datastore:"red"`
	Green N1 `datastore:"green"`
	Blue  N1
	White N1 `datastore:"-"`
}

type O0 struct {
	I int64
}

type O1 struct {
	I int32
}

type U0 struct {
	U uint
}

type U1 struct {
	U string
}

type T struct {
	T time.Time
}

type X0 struct {
	S string
	I int
	i int
}

type X1 struct {
	S myString
	I int32
	J int64
}

type X2 struct {
	Z string
	i int
}

type X3 struct {
	S bool
	I int
}

type Y0 struct {
	B bool
	F []float64
	G []float64
}

type Y1 struct {
	B bool
	F float64
}

type Y2 struct {
	B bool
	F []int64
}

type Tagged struct {
	A int   `datastore:"a,noindex"`
	B []int `datastore:"b"`
	C int   `datastore:",noindex"`
	D int   `datastore:""`
	E int
	// The "flatten" option is parsed but ignored for now.
	F int `datastore:",noindex,flatten"`
	G int `datastore:",flatten"`
	I int `datastore:"-"`
	J int `datastore:",noindex" json:"j"`

	Y0 `datastore:"-"`
	Z  chan int `datastore:"-,"`
}

type InvalidTagged1 struct {
	I int `datastore:"\t"`
}

type InvalidTagged2 struct {
	I int
	J int `datastore:"I"`
}

type Inner1 struct {
	W int32
	X string
}

type Inner2 struct {
	Y float64
}

type Inner3 struct {
	Z bool
}

type Outer struct {
	A int16
	I []Inner1
	J Inner2
	Inner3
}

type OuterEquivalent struct {
	A     int16
	IDotW []int32  `datastore:"I.W"`
	IDotX []string `datastore:"I.X"`
	JDotY float64  `datastore:"J.Y"`
	Z     bool
}

type Dotted struct {
	A DottedA `datastore:"A0.A1.A2"`
}

type DottedA struct {
	B DottedB `datastore:"B3"`
}

type DottedB struct {
	C int `datastore:"C4.C5"`
}

type SliceOfSlices struct {
	I int
	S []struct {
		J int
		F []float64
	}
}

type Recursive struct {
	I int
	R []Recursive
}

type MutuallyRecursive0 struct {
	I int
	R []MutuallyRecursive1
}

type MutuallyRecursive1 struct {
	I int
	R []MutuallyRecursive0
}

type Doubler struct {
	S string
	I int64
	B bool
}

func (d *Doubler) Load(props []Property) error {
	return LoadStruct(d, props)
}

func (d *Doubler) Save() ([]Property, error) {
	// Save the default Property slice to an in-memory buffer (a PropertyList).
	props, err := SaveStruct(d)
	if err != nil {
		return nil, err
	}
	var list PropertyList
	if err := list.Load(props); err != nil {
		return nil, err
	}

	// Edit that PropertyList, and send it on.
	for i := range list {
		switch v := list[i].Value.(type) {
		case string:
			// + means string concatenation.
			list[i].Value = v + v
		case int64:
			// + means integer addition.
			list[i].Value = v + v
		}
	}
	return list.Save()
}

var _ PropertyLoadSaver = (*Doubler)(nil)

type Deriver struct {
	S, Derived, Ignored string
}

func (e *Deriver) Load(props []Property) error {
	for _, p := range props {
		if p.Name != "S" {
			continue
		}
		e.S = p.Value.(string)
		e.Derived = "derived+" + e.S
	}
	return nil
}

func (e *Deriver) Save() ([]Property, error) {
	return []Property{
		{
			Name:  "S",
			Value: e.S,
		},
	}, nil
}

var _ PropertyLoadSaver = (*Deriver)(nil)

type BadMultiPropEntity struct{}

func (e *BadMultiPropEntity) Load(props []Property) error {
	return errors.New("unimplemented")
}

func (e *BadMultiPropEntity) Save() ([]Property, error) {
	// Write multiple properties with the same name "I", but Multiple is false.
	var props []Property
	for i := 0; i < 3; i++ {
		props = append(props, Property{
			Name:  "I",
			Value: int64(i),
		})
	}
	return props, nil
}

var _ PropertyLoadSaver = (*BadMultiPropEntity)(nil)

type BK struct {
	Key appengine.BlobKey
}

type testCase struct {
	desc   string
	src    interface{}
	want   interface{}
	putErr string
	getErr string
}

var testCases = []testCase{
	{
		"chan save fails",
		&C0{I: -1},
		&E{},
		"unsupported struct field",
		"",
	},
	{
		"*chan save fails",
		&C1{I: -1},
		&E{},
		"unsupported struct field",
		"",
	},
	{
		"[]chan save fails",
		&C2{I: -1, C: make([]chan int, 8)},
		&E{},
		"unsupported struct field",
		"",
	},
	{
		"chan load fails",
		&C3{C: "not a chan"},
		&C0{},
		"",
		"type mismatch",
	},
	{
		"*chan load fails",
		&C3{C: "not a *chan"},
		&C1{},
		"",
		"type mismatch",
	},
	{
		"[]chan load fails",
		&C3{C: "not a []chan"},
		&C2{},
		"",
		"type mismatch",
	},
	{
		"empty struct",
		&E{},
		&E{},
		"",
		"",
	},
	{
		"geopoint",
		&G0{G: testGeoPt0},
		&G0{G: testGeoPt0},
		"",
		"",
	},
	{
		"geopoint invalid",
		&G0{G: testBadGeoPt},
		&G0{},
		"invalid GeoPoint value",
		"",
	},
	{
		"geopoint as props",
		&G0{G: testGeoPt0},
		&PropertyList{
			Property{Name: "G", Value: testGeoPt0, NoIndex: false, Multiple: false},
		},
		"",
		"",
	},
	{
		"geopoint slice",
		&G1{G: []appengine.GeoPoint{testGeoPt0, testGeoPt1}},
		&G1{G: []appengine.GeoPoint{testGeoPt0, testGeoPt1}},
		"",
		"",
	},
	{
		"key",
		&K0{K: testKey1a},
		&K0{K: testKey1b},
		"",
		"",
	},
	{
		"key with parent",
		&K0{K: testKey2a},
		&K0{K: testKey2b},
		"",
		"",
	},
	{
		"nil key",
		&K0{},
		&K0{},
		"",
		"",
	},
	{
		"all nil keys in slice",
		&K1{[]*Key{nil, nil}},
		&K1{[]*Key{nil, nil}},
		"",
		"",
	},
	{
		"some nil keys in slice",
		&K1{[]*Key{testKey1a, nil, testKey2a}},
		&K1{[]*Key{testKey1b, nil, testKey2b}},
		"",
		"",
	},
	{
		"overflow",
		&O0{I: 1 << 48},
		&O1{},
		"",
		"overflow",
	},
	{
		"time",
		&T{T: time.Unix(1e9, 0)},
		&T{T: time.Unix(1e9, 0)},
		"",
		"",
	},
	{
		"time as props",
		&T{T: time.Unix(1e9, 0)},
		&PropertyList{
			Property{Name: "T", Value: time.Unix(1e9, 0).UTC(), NoIndex: false, Multiple: false},
		},
		"",
		"",
	},
	{
		"uint save",
		&U0{U: 1},
		&U0{},
		"unsupported struct field",
		"",
	},
	{
		"uint load",
		&U1{U: "not a uint"},
		&U0{},
		"",
		"type mismatch",
	},
	{
		"zero",
		&X0{},
		&X0{},
		"",
		"",
	},
	{
		"basic",
		&X0{S: "one", I: 2, i: 3},
		&X0{S: "one", I: 2},
		"",
		"",
	},
	{
		"save string/int load myString/int32",
		&X0{S: "one", I: 2, i: 3},
		&X1{S: "one", I: 2},
		"",
		"",
	},
	{
		"missing fields",
		&X0{S: "one", I: 2, i: 3},
		&X2{},
		"",
		"no such struct field",
	},
	{
		"save string load bool",
		&X0{S: "one", I: 2, i: 3},
		&X3{I: 2},
		"",
		"type mismatch",
	},
	{
		"basic slice",
		&Y0{B: true, F: []float64{7, 8, 9}},
		&Y0{B: true, F: []float64{7, 8, 9}},
		"",
		"",
	},
	{
		"save []float64 load float64",
		&Y0{B: true, F: []float64{7, 8, 9}},
		&Y1{B: true},
		"",
		"requires a slice",
	},
	{
		"save []float64 load []int64",
		&Y0{B: true, F: []float64{7, 8, 9}},
		&Y2{B: true},
		"",
		"type mismatch",
	},
	{
		"single slice is too long",
		&Y0{F: make([]float64, maxIndexedProperties+1)},
		&Y0{},
		"too many indexed properties",
		"",
	},
	{
		"two slices are too long",
		&Y0{F: make([]float64, maxIndexedProperties), G: make([]float64, maxIndexedProperties)},
		&Y0{},
		"too many indexed properties",
		"",
	},
	{
		"one slice and one scalar are too long",
		&Y0{F: make([]float64, maxIndexedProperties), B: true},
		&Y0{},
		"too many indexed properties",
		"",
	},
	{
		"long blob",
		&B0{B: makeUint8Slice(maxIndexedProperties + 1)},
		&B0{B: makeUint8Slice(maxIndexedProperties + 1)},
		"",
		"",
	},
	{
		"long []int8 is too long",
		&B1{B: makeInt8Slice(maxIndexedProperties + 1)},
		&B1{},
		"too many indexed properties",
		"",
	},
	{
		"short []int8",
		&B1{B: makeInt8Slice(3)},
		&B1{B: makeInt8Slice(3)},
		"",
		"",
	},
	{
		"long myBlob",
		&B2{B: makeUint8Slice(maxIndexedProperties + 1)},
		&B2{B: makeUint8Slice(maxIndexedProperties + 1)},
		"",
		"",
	},
	{
		"short myBlob",
		&B2{B: makeUint8Slice(3)},
		&B2{B: makeUint8Slice(3)},
		"",
		"",
	},
	{
		"long []myByte",
		&B3{B: makeMyByteSlice(maxIndexedProperties + 1)},
		&B3{B: makeMyByteSlice(maxIndexedProperties + 1)},
		"",
		"",
	},
	{
		"short []myByte",
		&B3{B: makeMyByteSlice(3)},
		&B3{B: makeMyByteSlice(3)},
		"",
		"",
	},
	{
		"slice of blobs",
		&B4{B: [][]byte{
			makeUint8Slice(3),
			makeUint8Slice(4),
			makeUint8Slice(5),
		}},
		&B4{B: [][]byte{
			makeUint8Slice(3),
			makeUint8Slice(4),
			makeUint8Slice(5),
		}},
		"",
		"",
	},
	{
		"short ByteString",
		&B5{B: ByteString(makeUint8Slice(3))},
		&B5{B: ByteString(makeUint8Slice(3))},
		"",
		"",
	},
	{
		"short ByteString as props",
		&B5{B: ByteString(makeUint8Slice(3))},
		&PropertyList{
			Property{Name: "B", Value: ByteString(makeUint8Slice(3)), NoIndex: false, Multiple: false},
		},
		"",
		"",
	},
	{
		"short ByteString into string",
		&B5{B: ByteString("legacy")},
		&struct{ B string }{"legacy"},
		"",
		"",
	},
	{
		"[]byte must be noindex",
		&PropertyList{
			Property{Name: "B", Value: makeUint8Slice(3), NoIndex: false},
		},
		nil,
		"cannot index a []byte valued Property",
		"",
	},
	{
		"save tagged load props",
		&Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, F: 6, G: 7, I: 8, J: 9},
		&PropertyList{
			// A and B are renamed to a and b; A and C are noindex, I is ignored.
			// Indexed properties are loaded before raw properties. Thus, the
			// result is: b, b, b, D, E, a, c.
			Property{Name: "b", Value: int64(21), NoIndex: false, Multiple: true},
			Property{Name: "b", Value: int64(22), NoIndex: false, Multiple: true},
			Property{Name: "b", Value: int64(23), NoIndex: false, Multiple: true},
			Property{Name: "D", Value: int64(4), NoIndex: false, Multiple: false},
			Property{Name: "E", Value: int64(5), NoIndex: false, Multiple: false},
			Property{Name: "G", Value: int64(7), NoIndex: false, Multiple: false},
			Property{Name: "a", Value: int64(1), NoIndex: true, Multiple: false},
			Property{Name: "C", Value: int64(3), NoIndex: true, Multiple: false},
			Property{Name: "F", Value: int64(6), NoIndex: true, Multiple: false},
			Property{Name: "J", Value: int64(9), NoIndex: true, Multiple: false},
		},
		"",
		"",
	},
	{
		"save tagged load tagged",
		&Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6, J: 7},
		&Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, J: 7},
		"",
		"",
	},
	{
		"save props load tagged",
		&PropertyList{
			Property{Name: "A", Value: int64(11), NoIndex: true, Multiple: false},
			Property{Name: "a", Value: int64(12), NoIndex: true, Multiple: false},
		},
		&Tagged{A: 12},
		"",
		`cannot load field "A"`,
	},
	{
		"invalid tagged1",
		&InvalidTagged1{I: 1},
		&InvalidTagged1{},
		"struct tag has invalid property name",
		"",
	},
	{
		"invalid tagged2",
		&InvalidTagged2{I: 1, J: 2},
		&InvalidTagged2{},
		"struct tag has repeated property name",
		"",
	},
	{
		"doubler",
		&Doubler{S: "s", I: 1, B: true},
		&Doubler{S: "ss", I: 2, B: true},
		"",
		"",
	},
	{
		"save struct load props",
		&X0{S: "s", I: 1},
		&PropertyList{
			Property{Name: "S", Value: "s", NoIndex: false, Multiple: false},
			Property{Name: "I", Value: int64(1), NoIndex: false, Multiple: false},
		},
		"",
		"",
	},
	{
		"save props load struct",
		&PropertyList{
			Property{Name: "S", Value: "s", NoIndex: false, Multiple: false},
			Property{Name: "I", Value: int64(1), NoIndex: false, Multiple: false},
		},
		&X0{S: "s", I: 1},
		"",
		"",
	},
	{
		"nil-value props",
		&PropertyList{
			Property{Name: "I", Value: nil, NoIndex: false, Multiple: false},
			Property{Name: "B", Value: nil, NoIndex: false, Multiple: false},
			Property{Name: "S", Value: nil, NoIndex: false, Multiple: false},
			Property{Name: "F", Value: nil, NoIndex: false, Multiple: false},
			Property{Name: "K", Value: nil, NoIndex: false, Multiple: false},
			Property{Name: "T", Value: nil, NoIndex: false, Multiple: false},
			Property{Name: "J", Value: nil, NoIndex: false, Multiple: true},
			Property{Name: "J", Value: int64(7), NoIndex: false, Multiple: true},
			Property{Name: "J", Value: nil, NoIndex: false, Multiple: true},
		},
		&struct {
			I int64
			B bool
			S string
			F float64
			K *Key
			T time.Time
			J []int64
		}{
			J: []int64{0, 7, 0},
		},
		"",
		"",
	},
	{
		"save outer load props",
		&Outer{
			A: 1,
			I: []Inner1{
				{10, "ten"},
				{20, "twenty"},
				{30, "thirty"},
			},
			J: Inner2{
				Y: 3.14,
			},
			Inner3: Inner3{
				Z: true,
			},
		},
		&PropertyList{
			Property{Name: "A", Value: int64(1), NoIndex: false, Multiple: false},
			Property{Name: "I.W", Value: int64(10), NoIndex: false, Multiple: true},
			Property{Name: "I.X", Value: "ten", NoIndex: false, Multiple: true},
			Property{Name: "I.W", Value: int64(20), NoIndex: false, Multiple: true},
			Property{Name: "I.X", Value: "twenty", NoIndex: false, Multiple: true},
			Property{Name: "I.W", Value: int64(30), NoIndex: false, Multiple: true},
			Property{Name: "I.X", Value: "thirty", NoIndex: false, Multiple: true},
			Property{Name: "J.Y", Value: float64(3.14), NoIndex: false, Multiple: false},
			Property{Name: "Z", Value: true, NoIndex: false, Multiple: false},
		},
		"",
		"",
	},
	{
		"save props load outer-equivalent",
		&PropertyList{
			Property{Name: "A", Value: int64(1), NoIndex: false, Multiple: false},
			Property{Name: "I.W", Value: int64(10), NoIndex: false, Multiple: true},
			Property{Name: "I.X", Value: "ten", NoIndex: false, Multiple: true},
			Property{Name: "I.W", Value: int64(20), NoIndex: false, Multiple: true},
			Property{Name: "I.X", Value: "twenty", NoIndex: false, Multiple: true},
			Property{Name: "I.W", Value: int64(30), NoIndex: false, Multiple: true},
			Property{Name: "I.X", Value: "thirty", NoIndex: false, Multiple: true},
			Property{Name: "J.Y", Value: float64(3.14), NoIndex: false, Multiple: false},
			Property{Name: "Z", Value: true, NoIndex: false, Multiple: false},
		},
		&OuterEquivalent{
			A:     1,
			IDotW: []int32{10, 20, 30},
			IDotX: []string{"ten", "twenty", "thirty"},
			JDotY: 3.14,
			Z:     true,
		},
		"",
		"",
	},
	{
		"save outer-equivalent load outer",
		&OuterEquivalent{
			A:     1,
			IDotW: []int32{10, 20, 30},
			IDotX: []string{"ten", "twenty", "thirty"},
			JDotY: 3.14,
			Z:     true,
		},
		&Outer{
			A: 1,
			I: []Inner1{
				{10, "ten"},
				{20, "twenty"},
				{30, "thirty"},
			},
			J: Inner2{
				Y: 3.14,
			},
			Inner3: Inner3{
				Z: true,
			},
		},
		"",
		"",
	},
	{
		"dotted names save",
		&Dotted{A: DottedA{B: DottedB{C: 88}}},
		&PropertyList{
			Property{Name: "A0.A1.A2.B3.C4.C5", Value: int64(88), NoIndex: false, Multiple: false},
		},
		"",
		"",
	},
	{
		"dotted names load",
		&PropertyList{
			Property{Name: "A0.A1.A2.B3.C4.C5", Value: int64(99), NoIndex: false, Multiple: false},
		},
		&Dotted{A: DottedA{B: DottedB{C: 99}}},
		"",
		"",
	},
	{
		"save struct load deriver",
		&X0{S: "s", I: 1},
		&Deriver{S: "s", Derived: "derived+s"},
		"",
		"",
	},
	{
		"save deriver load struct",
		&Deriver{S: "s", Derived: "derived+s", Ignored: "ignored"},
		&X0{S: "s"},
		"",
		"",
	},
	{
		"bad multi-prop entity",
		&BadMultiPropEntity{},
		&BadMultiPropEntity{},
		"Multiple is false",
		"",
	},
	// Regression: CL 25062824 broke handling of appengine.BlobKey fields.
	{
		"appengine.BlobKey",
		&BK{Key: "blah"},
		&BK{Key: "blah"},
		"",
		"",
	},
	{
		"zero time.Time",
		&T{T: time.Time{}},
		&T{T: time.Time{}},
		"",
		"",
	},
	{
		"time.Time near Unix zero time",
		&T{T: time.Unix(0, 4e3)},
		&T{T: time.Unix(0, 4e3)},
		"",
		"",
	},
	{
		"time.Time, far in the future",
		&T{T: time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC)},
		&T{T: time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC)},
		"",
		"",
	},
	{
		"time.Time, very far in the past",
		&T{T: time.Date(-300000, 1, 1, 0, 0, 0, 0, time.UTC)},
		&T{},
		"time value out of range",
		"",
	},
	{
		"time.Time, very far in the future",
		&T{T: time.Date(294248, 1, 1, 0, 0, 0, 0, time.UTC)},
		&T{},
		"time value out of range",
		"",
	},
	{
		"structs",
		&N0{
			X0:       X0{S: "one", I: 2, i: 3},
			Nonymous: X0{S: "four", I: 5, i: 6},
			Ignore:   "ignore",
			Other:    "other",
		},
		&N0{
			X0:       X0{S: "one", I: 2},
			Nonymous: X0{S: "four", I: 5},
			Other:    "other",
		},
		"",
		"",
	},
	{
		"slice of structs",
		&N1{
			X0: X0{S: "one", I: 2, i: 3},
			Nonymous: []X0{
				{S: "four", I: 5, i: 6},
				{S: "seven", I: 8, i: 9},
				{S: "ten", I: 11, i: 12},
				{S: "thirteen", I: 14, i: 15},
			},
			Ignore: "ignore",
			Other:  "other",
		},
		&N1{
			X0: X0{S: "one", I: 2},
			Nonymous: []X0{
				{S: "four", I: 5},
				{S: "seven", I: 8},
				{S: "ten", I: 11},
				{S: "thirteen", I: 14},
			},
			Other: "other",
		},
		"",
		"",
	},
	{
		"structs with slices of structs",
		&N2{
			N1: N1{
				X0: X0{S: "rouge"},
				Nonymous: []X0{
					{S: "rosso0"},
					{S: "rosso1"},
				},
			},
			Green: N1{
				X0: X0{S: "vert"},
				Nonymous: []X0{
					{S: "verde0"},
					{S: "verde1"},
					{S: "verde2"},
				},
			},
			Blue: N1{
				X0: X0{S: "bleu"},
				Nonymous: []X0{
					{S: "blu0"},
					{S: "blu1"},
					{S: "blu2"},
					{S: "blu3"},
				},
			},
		},
		&N2{
			N1: N1{
				X0: X0{S: "rouge"},
				Nonymous: []X0{
					{S: "rosso0"},
					{S: "rosso1"},
				},
			},
			Green: N1{
				X0: X0{S: "vert"},
				Nonymous: []X0{
					{S: "verde0"},
					{S: "verde1"},
					{S: "verde2"},
				},
			},
			Blue: N1{
				X0: X0{S: "bleu"},
				Nonymous: []X0{
					{S: "blu0"},
					{S: "blu1"},
					{S: "blu2"},
					{S: "blu3"},
				},
			},
		},
		"",
		"",
	},
	{
		"save structs load props",
		&N2{
			N1: N1{
				X0: X0{S: "rouge"},
				Nonymous: []X0{
					{S: "rosso0"},
					{S: "rosso1"},
				},
			},
			Green: N1{
				X0: X0{S: "vert"},
				Nonymous: []X0{
					{S: "verde0"},
					{S: "verde1"},
					{S: "verde2"},
				},
			},
			Blue: N1{
				X0: X0{S: "bleu"},
				Nonymous: []X0{
					{S: "blu0"},
					{S: "blu1"},
					{S: "blu2"},
					{S: "blu3"},
				},
			},
		},
		&PropertyList{
			Property{Name: "red.S", Value: "rouge", NoIndex: false, Multiple: false},
			Property{Name: "red.I", Value: int64(0), NoIndex: false, Multiple: false},
			Property{Name: "red.Nonymous.S", Value: "rosso0", NoIndex: false, Multiple: true},
			Property{Name: "red.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
			Property{Name: "red.Nonymous.S", Value: "rosso1", NoIndex: false, Multiple: true},
			Property{Name: "red.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
			Property{Name: "red.Other", Value: "", NoIndex: false, Multiple: false},
			Property{Name: "green.S", Value: "vert", NoIndex: false, Multiple: false},
			Property{Name: "green.I", Value: int64(0), NoIndex: false, Multiple: false},
			Property{Name: "green.Nonymous.S", Value: "verde0", NoIndex: false, Multiple: true},
			Property{Name: "green.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
			Property{Name: "green.Nonymous.S", Value: "verde1", NoIndex: false, Multiple: true},
			Property{Name: "green.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
			Property{Name: "green.Nonymous.S", Value: "verde2", NoIndex: false, Multiple: true},
			Property{Name: "green.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
			Property{Name: "green.Other", Value: "", NoIndex: false, Multiple: false},
			Property{Name: "Blue.S", Value: "bleu", NoIndex: false, Multiple: false},
			Property{Name: "Blue.I", Value: int64(0), NoIndex: false, Multiple: false},
			Property{Name: "Blue.Nonymous.S", Value: "blu0", NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.S", Value: "blu1", NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.S", Value: "blu2", NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.S", Value: "blu3", NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
			Property{Name: "Blue.Other", Value: "", NoIndex: false, Multiple: false},
		},
		"",
		"",
	},
	{
		"save props load structs with ragged fields",
		&PropertyList{
			Property{Name: "red.S", Value: "rot", NoIndex: false, Multiple: false},
			Property{Name: "green.Nonymous.I", Value: int64(10), NoIndex: false, Multiple: true},
			Property{Name: "green.Nonymous.I", Value: int64(11), NoIndex: false, Multiple: true},
			Property{Name: "green.Nonymous.I", Value: int64(12), NoIndex: false, Multiple: true},
			Property{Name: "green.Nonymous.I", Value: int64(13), NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.S", Value: "blau0", NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.I", Value: int64(20), NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.S", Value: "blau1", NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.I", Value: int64(21), NoIndex: false, Multiple: true},
			Property{Name: "Blue.Nonymous.S", Value: "blau2", NoIndex: false, Multiple: true},
		},
		&N2{
			N1: N1{
				X0: X0{S: "rot"},
			},
			Green: N1{
				Nonymous: []X0{
					{I: 10},
					{I: 11},
					{I: 12},
					{I: 13},
				},
			},
			Blue: N1{
				Nonymous: []X0{
					{S: "blau0", I: 20},
					{S: "blau1", I: 21},
					{S: "blau2"},
				},
			},
		},
		"",
		"",
	},
	{
		"save structs with noindex tags",
		&struct {
			A struct {
				X string `datastore:",noindex"`
				Y string
			} `datastore:",noindex"`
			B struct {
				X string `datastore:",noindex"`
				Y string
			}
		}{},
		&PropertyList{
			Property{Name: "B.Y", Value: "", NoIndex: false, Multiple: false},
			Property{Name: "A.X", Value: "", NoIndex: true, Multiple: false},
			Property{Name: "A.Y", Value: "", NoIndex: true, Multiple: false},
			Property{Name: "B.X", Value: "", NoIndex: true, Multiple: false},
		},
		"",
		"",
	},
	{
		"embedded struct with name override",
		&struct {
			Inner1 `datastore:"foo"`
		}{},
		&PropertyList{
			Property{Name: "foo.W", Value: int64(0), NoIndex: false, Multiple: false},
			Property{Name: "foo.X", Value: "", NoIndex: false, Multiple: false},
		},
		"",
		"",
	},
	{
		"slice of slices",
		&SliceOfSlices{},
		nil,
		"flattening nested structs leads to a slice of slices",
		"",
	},
	{
		"recursive struct",
		&Recursive{},
		nil,
		"recursive struct",
		"",
	},
	{
		"mutually recursive struct",
		&MutuallyRecursive0{},
		nil,
		"recursive struct",
		"",
	},
	{
		"non-exported struct fields",
		&struct {
			i, J int64
		}{i: 1, J: 2},
		&PropertyList{
			Property{Name: "J", Value: int64(2), NoIndex: false, Multiple: false},
		},
		"",
		"",
	},
	{
		"json.RawMessage",
		&struct {
			J json.RawMessage
		}{
			J: json.RawMessage("rawr"),
		},
		&PropertyList{
			Property{Name: "J", Value: []byte("rawr"), NoIndex: true, Multiple: false},
		},
		"",
		"",
	},
	{
		"json.RawMessage to myBlob",
		&struct {
			B json.RawMessage
		}{
			B: json.RawMessage("rawr"),
		},
		&B2{B: myBlob("rawr")},
		"",
		"",
	},
}

// checkErr returns the empty string if either both want and err are zero,
// or if want is a non-empty substring of err's string representation.
func checkErr(want string, err error) string {
	if err != nil {
		got := err.Error()
		if want == "" || strings.Index(got, want) == -1 {
			return got
		}
	} else if want != "" {
		return fmt.Sprintf("want error %q", want)
	}
	return ""
}

func TestRoundTrip(t *testing.T) {
	for _, tc := range testCases {
		p, err := saveEntity(testAppID, testKey0, tc.src)
		if s := checkErr(tc.putErr, err); s != "" {
			t.Errorf("%s: save: %s", tc.desc, s)
			continue
		}
		if p == nil {
			continue
		}
		var got interface{}
		if _, ok := tc.want.(*PropertyList); ok {
			got = new(PropertyList)
		} else {
			got = reflect.New(reflect.TypeOf(tc.want).Elem()).Interface()
		}
		err = loadEntity(got, p)
		if s := checkErr(tc.getErr, err); s != "" {
			t.Errorf("%s: load: %s", tc.desc, s)
			continue
		}
		equal := false
		if gotT, ok := got.(*T); ok {
			// Round tripping a time.Time can result in a different time.Location: Local instead of UTC.
			// We therefore test equality explicitly, instead of relying on reflect.DeepEqual.
			equal = gotT.T.Equal(tc.want.(*T).T)
		} else {
			equal = reflect.DeepEqual(got, tc.want)
		}
		if !equal {
			t.Errorf("%s: compare: got %v want %v", tc.desc, got, tc.want)
			continue
		}
	}
}

func TestQueryConstruction(t *testing.T) {
	tests := []struct {
		q, exp *Query
		err    string
	}{
		{
			q: NewQuery("Foo"),
			exp: &Query{
				kind:  "Foo",
				limit: -1,
			},
		},
		{
			// Regular filtered query with standard spacing.
			q: NewQuery("Foo").Filter("foo >", 7),
			exp: &Query{
				kind: "Foo",
				filter: []filter{
					{
						FieldName: "foo",
						Op:        greaterThan,
						Value:     7,
					},
				},
				limit: -1,
			},
		},
		{
			// Filtered query with no spacing.
			q: NewQuery("Foo").Filter("foo=", 6),
			exp: &Query{
				kind: "Foo",
				filter: []filter{
					{
						FieldName: "foo",
						Op:        equal,
						Value:     6,
					},
				},
				limit: -1,
			},
		},
		{
			// Filtered query with funky spacing.
			q: NewQuery("Foo").Filter(" foo< ", 8),
			exp: &Query{
				kind: "Foo",
				filter: []filter{
					{
						FieldName: "foo",
						Op:        lessThan,
						Value:     8,
					},
				},
				limit: -1,
			},
		},
		{
			// Filtered query with multicharacter op.
			q: NewQuery("Foo").Filter("foo >=", 9),
			exp: &Query{
				kind: "Foo",
				filter: []filter{
					{
						FieldName: "foo",
						Op:        greaterEq,
						Value:     9,
					},
				},
				limit: -1,
			},
		},
		{
			// Query with ordering.
			q: NewQuery("Foo").Order("bar"),
			exp: &Query{
				kind: "Foo",
				order: []order{
					{
						FieldName: "bar",
						Direction: ascending,
					},
				},
				limit: -1,
			},
		},
		{
			// Query with reverse ordering, and funky spacing.
			q: NewQuery("Foo").Order(" - bar"),
			exp: &Query{
				kind: "Foo",
				order: []order{
					{
						FieldName: "bar",
						Direction: descending,
					},
				},
				limit: -1,
			},
		},
		{
			// Query with an empty ordering.
			q:   NewQuery("Foo").Order(""),
			err: "empty order",
		},
		{
			// Query with a + ordering.
			q:   NewQuery("Foo").Order("+bar"),
			err: "invalid order",
		},
	}
	for i, test := range tests {
		if test.q.err != nil {
			got := test.q.err.Error()
			if !strings.Contains(got, test.err) {
				t.Errorf("%d: error mismatch: got %q want something containing %q", i, got, test.err)
			}
			continue
		}
		if !reflect.DeepEqual(test.q, test.exp) {
			t.Errorf("%d: mismatch: got %v want %v", i, test.q, test.exp)
		}
	}
}

func TestStringMeaning(t *testing.T) {
	var xx [4]interface{}
	xx[0] = &struct {
		X string
	}{"xx0"}
	xx[1] = &struct {
		X string `datastore:",noindex"`
	}{"xx1"}
	xx[2] = &struct {
		X []byte
	}{[]byte("xx2")}
	xx[3] = &struct {
		X []byte `datastore:",noindex"`
	}{[]byte("xx3")}

	indexed := [4]bool{
		true,
		false,
		false, // A []byte is always no-index.
		false,
	}
	want := [4]pb.Property_Meaning{
		pb.Property_NO_MEANING,
		pb.Property_TEXT,
		pb.Property_BLOB,
		pb.Property_BLOB,
	}

	for i, x := range xx {
		props, err := SaveStruct(x)
		if err != nil {
			t.Errorf("i=%d: SaveStruct: %v", i, err)
			continue
		}
		e, err := propertiesToProto("appID", testKey0, props)
		if err != nil {
			t.Errorf("i=%d: propertiesToProto: %v", i, err)
			continue
		}
		var p *pb.Property
		switch {
		case indexed[i] && len(e.Property) == 1:
			p = e.Property[0]
		case !indexed[i] && len(e.RawProperty) == 1:
			p = e.RawProperty[0]
		default:
			t.Errorf("i=%d: EntityProto did not have expected property slice", i)
			continue
		}
		if got := p.GetMeaning(); got != want[i] {
			t.Errorf("i=%d: meaning: got %v, want %v", i, got, want[i])
			continue
		}
	}
}

func TestNamespaceResetting(t *testing.T) {
	// These environment variables are necessary because *Query.Run will
	// call internal.FullyQualifiedAppID which checks these variables or falls
	// back to the Metadata service that is not available in tests.
	environ := []struct {
		key, value string
	}{
		{"GAE_LONG_APP_ID", "my-app-id"},
		{"GAE_PARTITION", "1"},
	}
	for _, v := range environ {
		old := os.Getenv(v.key)
		os.Setenv(v.key, v.value)
		v.value = old
	}
	defer func() { // Restore old environment after the test completes.
		for _, v := range environ {
			if v.value == "" {
				os.Unsetenv(v.key)
				continue
			}
			os.Setenv(v.key, v.value)
		}
	}()

	namec := make(chan *string, 1)
	c0 := aetesting.FakeSingleContext(t, "datastore_v3", "RunQuery", func(req *pb.Query, res *pb.QueryResult) error {
		namec <- req.NameSpace
		return fmt.Errorf("RPC error")
	})

	// Check that wrapping c0 in a namespace twice works correctly.
	c1, err := appengine.Namespace(c0, "A")
	if err != nil {
		t.Fatalf("appengine.Namespace: %v", err)
	}
	c2, err := appengine.Namespace(c1, "") // should act as the original context
	if err != nil {
		t.Fatalf("appengine.Namespace: %v", err)
	}

	q := NewQuery("SomeKind")

	q.Run(c0)
	if ns := <-namec; ns != nil {
		t.Errorf(`RunQuery with c0: ns = %q, want nil`, *ns)
	}

	q.Run(c1)
	if ns := <-namec; ns == nil {
		t.Error(`RunQuery with c1: ns = nil, want "A"`)
	} else if *ns != "A" {
		t.Errorf(`RunQuery with c1: ns = %q, want "A"`, *ns)
	}

	q.Run(c2)
	if ns := <-namec; ns != nil {
		t.Errorf(`RunQuery with c2: ns = %q, want nil`, *ns)
	}
}


text:
// 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 provides a client for App Engine's datastore service.

Basic Operations

Entities are the unit of storage and are associated with a key. A key
consists of an optional parent key, a string application ID, a string kind
(also known as an entity type), and either a StringID or an IntID. A
StringID is also known as an entity name or key name.

It is valid to create a key with a zero StringID and a zero IntID; this is
called an incomplete key, and does not refer to any saved entity. Putting an
entity into the datastore under an incomplete key will cause a unique key
to be generated for that entity, with a non-zero IntID.

An entity's contents are a mapping from case-sensitive field names to values.
Valid value types are:
  - signed integers (int, int8, int16, int32 and int64),
  - bool,
  - string,
  - float32 and float64,
  - []byte (up to 1 megabyte in length),
  - any type whose underlying type is one of the above predeclared types,
  - ByteString,
  - *Key,
  - time.Time (stored with microsecond precision),
  - appengine.BlobKey,
  - appengine.GeoPoint,
  - structs whose fields are all valid value types,
  - slices of any of the above.

Slices of structs are valid, as are structs that contain slices. However, if
one struct contains another, then at most one of those can be repeated. This
disqualifies recursively defined struct types: any struct T that (directly or
indirectly) contains a []T.

The Get and Put functions load and save an entity's contents. An entity's
contents are typically represented by a struct pointer.

Example code:

	type Entity struct {
		Value string
	}

	func handle(w http.ResponseWriter, r *http.Request) {
		ctx := appengine.NewContext(r)

		k := datastore.NewKey(ctx, "Entity", "stringID", 0, nil)
		e := new(Entity)
		if err := datastore.Get(ctx, k, e); err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		old := e.Value
		e.Value = r.URL.Path

		if _, err := datastore.Put(ctx, k, e); err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		fmt.Fprintf(w, "old=%q\nnew=%q\n", old, e.Value)
	}

GetMulti, PutMulti and DeleteMulti are batch versions of the Get, Put and
Delete functions. They take a []*Key instead of a *Key, and may return an
appengine.MultiError when encountering partial failure.

Properties

An entity's contents can be represented by a variety of types. These are
typically struct pointers, but can also be any type that implements the
PropertyLoadSaver interface. If using a struct pointer, you do not have to
explicitly implement the PropertyLoadSaver interface; the datastore will
automatically convert via reflection. If a struct pointer does implement that
interface then those methods will be used in preference to the default
behavior for struct pointers. Struct pointers are more strongly typed and are
easier to use; PropertyLoadSavers are more flexible.

The actual types passed do not have to match between Get and Put calls or even
across different App Engine requests. It is valid to put a *PropertyList and
get that same entity as a *myStruct, or put a *myStruct0 and get a *myStruct1.
Conceptually, any entity is saved as a sequence of properties, and is loaded
into the destination value on a property-by-property basis. When loading into
a struct pointer, an entity that cannot be completely represented (such as a
missing field) will result in an ErrFieldMismatch error but it is up to the
caller whether this error is fatal, recoverable or ignorable.

By default, for struct pointers, all properties are potentially indexed, and
the property name is the same as the field name (and hence must start with an
upper case letter). Fields may have a `datastore:"name,options"` tag. The tag
name is the property name, which must be one or more valid Go identifiers
joined by ".", but may start with a lower case letter. An empty tag name means
to just use the field name. A "-" tag name means that the datastore will
ignore that field. If options is "noindex" then the field will not be indexed.
If the options is "" then the comma may be omitted. There are no other
recognized options.

Fields (except for []byte) are indexed by default. Strings longer than 1500
bytes cannot be indexed; fields used to store long strings should be
tagged with "noindex". Similarly, ByteStrings longer than 1500 bytes cannot be
indexed.

Example code:

	// A and B are renamed to a and b.
	// A, C and J are not indexed.
	// D's tag is equivalent to having no tag at all (E).
	// I is ignored entirely by the datastore.
	// J has tag information for both the datastore and json packages.
	type TaggedStruct struct {
		A int `datastore:"a,noindex"`
		B int `datastore:"b"`
		C int `datastore:",noindex"`
		D int `datastore:""`
		E int
		I int `datastore:"-"`
		J int `datastore:",noindex" json:"j"`
	}

Structured Properties

If the struct pointed to contains other structs, then the nested or embedded
structs are flattened. For example, given these definitions:

	type Inner1 struct {
		W int32
		X string
	}

	type Inner2 struct {
		Y float64
	}

	type Inner3 struct {
		Z bool
	}

	type Outer struct {
		A int16
		I []Inner1
		J Inner2
		Inner3
	}

then an Outer's properties would be equivalent to those of:

	type OuterEquivalent struct {
		A     int16
		IDotW []int32  `datastore:"I.W"`
		IDotX []string `datastore:"I.X"`
		JDotY float64  `datastore:"J.Y"`
		Z     bool
	}

If Outer's embedded Inner3 field was tagged as `datastore:"Foo"` then the
equivalent field would instead be: FooDotZ bool `datastore:"Foo.Z"`.

If an outer struct is tagged "noindex" then all of its implicit flattened
fields are effectively "noindex".

The PropertyLoadSaver Interface

An entity's contents can also be represented by any type that implements the
PropertyLoadSaver interface. This type may be a struct pointer, but it does
not have to be. The datastore package will call Load when getting the entity's
contents, and Save when putting the entity's contents.
Possible uses include deriving non-stored fields, verifying fields, or indexing
a field only if its value is positive.

Example code:

	type CustomPropsExample struct {
		I, J int
		// Sum is not stored, but should always be equal to I + J.
		Sum int `datastore:"-"`
	}

	func (x *CustomPropsExample) Load(ps []datastore.Property) error {
		// Load I and J as usual.
		if err := datastore.LoadStruct(x, ps); err != nil {
			return err
		}
		// Derive the Sum field.
		x.Sum = x.I + x.J
		return nil
	}

	func (x *CustomPropsExample) Save() ([]datastore.Property, error) {
		// Validate the Sum field.
		if x.Sum != x.I + x.J {
			return errors.New("CustomPropsExample has inconsistent sum")
		}
		// Save I and J as usual. The code below is equivalent to calling
		// "return datastore.SaveStruct(x)", but is done manually for
		// demonstration purposes.
		return []datastore.Property{
			{
				Name:  "I",
				Value: int64(x.I),
			},
			{
				Name:  "J",
				Value: int64(x.J),
			},
		}
	}

The *PropertyList type implements PropertyLoadSaver, and can therefore hold an
arbitrary entity's contents.

Queries

Queries retrieve entities based on their properties or key's ancestry. Running
a query yields an iterator of results: either keys or (key, entity) pairs.
Queries are re-usable and it is safe to call Query.Run from concurrent
goroutines. Iterators are not safe for concurrent use.

Queries are immutable, and are either created by calling NewQuery, or derived
from an existing query by calling a method like Filter or Order that returns a
new query value. A query is typically constructed by calling NewQuery followed
by a chain of zero or more such methods. These methods are:
  - Ancestor and Filter constrain the entities returned by running a query.
  - Order affects the order in which they are returned.
  - Project constrains the fields returned.
  - Distinct de-duplicates projected entities.
  - KeysOnly makes the iterator return only keys, not (key, entity) pairs.
  - Start, End, Offset and Limit define which sub-sequence of matching entities
    to return. Start and End take cursors, Offset and Limit take integers. Start
    and Offset affect the first result, End and Limit affect the last result.
    If both Start and Offset are set, then the offset is relative to Start.
    If both End and Limit are set, then the earliest constraint wins. Limit is
    relative to Start+Offset, not relative to End. As a special case, a
    negative limit means unlimited.

Example code:

	type Widget struct {
		Description string
		Price       int
	}

	func handle(w http.ResponseWriter, r *http.Request) {
		ctx := appengine.NewContext(r)
		q := datastore.NewQuery("Widget").
			Filter("Price <", 1000).
			Order("-Price")
		b := new(bytes.Buffer)
		for t := q.Run(ctx); ; {
			var x Widget
			key, err := t.Next(&x)
			if err == datastore.Done {
				break
			}
			if err != nil {
				serveError(ctx, w, err)
				return
			}
			fmt.Fprintf(b, "Key=%v\nWidget=%#v\n\n", key, x)
		}
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		io.Copy(w, b)
	}

Transactions

RunInTransaction runs a function in a transaction.

Example code:

	type Counter struct {
		Count int
	}

	func inc(ctx context.Context, key *datastore.Key) (int, error) {
		var x Counter
		if err := datastore.Get(ctx, key, &x); err != nil && err != datastore.ErrNoSuchEntity {
			return 0, err
		}
		x.Count++
		if _, err := datastore.Put(ctx, key, &x); err != nil {
			return 0, err
		}
		return x.Count, nil
	}

	func handle(w http.ResponseWriter, r *http.Request) {
		ctx := appengine.NewContext(r)
		var count int
		err := datastore.RunInTransaction(ctx, func(ctx context.Context) error {
			var err1 error
			count, err1 = inc(ctx, datastore.NewKey(ctx, "Counter", "singleton", 0, nil))
			return err1
		}, nil)
		if err != nil {
			serveError(ctx, w, err)
			return
		}
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		fmt.Fprintf(w, "Count=%d", count)
	}

Metadata

The datastore package provides access to some of App Engine's datastore
metadata. This metadata includes information about the entity groups,
namespaces, entity kinds, and properties in the datastore, as well as the
property representations for each property.

Example code:

	func handle(w http.ResponseWriter, r *http.Request) {
		// Print all the kinds in the datastore, with all the indexed
		// properties (and their representations) for each.
		ctx := appengine.NewContext(r)

		kinds, err := datastore.Kinds(ctx)
		if err != nil {
			serveError(ctx, w, err)
			return
		}

		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		for _, kind := range kinds {
			fmt.Fprintf(w, "%s:\n", kind)
			props, err := datastore.KindProperties(ctx, kind)
			if err != nil {
				fmt.Fprintln(w, "\t(unable to retrieve properties)")
				continue
			}
			for p, rep := range props {
				fmt.Fprintf(w, "\t-%s (%s)\n", p, strings.Join(", ", rep))
			}
		}
	}
*/
package datastore // import "google.golang.org/appengine/datastore"


text:
// 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)
	}
}


text:
// 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 (
	"fmt"
	"reflect"
	"strings"
	"sync"
	"unicode"
)

// Entities with more than this many indexed properties will not be saved.
const maxIndexedProperties = 20000

// []byte fields more than 1 megabyte long will not be loaded or saved.
const maxBlobLen = 1 << 20

// Property is a name/value pair plus some metadata. A datastore entity's
// contents are loaded and saved as a sequence of Properties. An entity can
// have multiple Properties with the same name, provided that p.Multiple is
// true on all of that entity's Properties with that name.
type Property struct {
	// Name is the property name.
	Name string
	// Value is the property value. The valid types are:
	//	- int64
	//	- bool
	//	- string
	//	- float64
	//	- ByteString
	//	- *Key
	//	- time.Time
	//	- appengine.BlobKey
	//	- appengine.GeoPoint
	//	- []byte (up to 1 megabyte in length)
	// This set is smaller than the set of valid struct field types that the
	// datastore can load and save. A Property Value cannot be a slice (apart
	// from []byte); use multiple Properties instead. Also, a Value's type
	// must be explicitly on the list above; it is not sufficient for the
	// underlying type to be on that list. For example, a Value of "type
	// myInt64 int64" is invalid. Smaller-width integers and floats are also
	// invalid. Again, this is more restrictive than the set of valid struct
	// field types.
	//
	// A Value will have an opaque type when loading entities from an index,
	// such as via a projection query. Load entities into a struct instead
	// of a PropertyLoadSaver when using a projection query.
	//
	// A Value may also be the nil interface value; this is equivalent to
	// Python's None but not directly representable by a Go struct. Loading
	// a nil-valued property into a struct will set that field to the zero
	// value.
	Value interface{}
	// NoIndex is whether the datastore cannot index this property.
	NoIndex bool
	// Multiple is whether the entity can have multiple properties with
	// the same name. Even if a particular instance only has one property with
	// a certain name, Multiple should be true if a struct would best represent
	// it as a field of type []T instead of type T.
	Multiple bool
}

// ByteString is a short byte slice (up to 1500 bytes) that can be indexed.
type ByteString []byte

// PropertyLoadSaver can be converted from and to a slice of Properties.
type PropertyLoadSaver interface {
	Load([]Property) error
	Save() ([]Property, error)
}

// PropertyList converts a []Property to implement PropertyLoadSaver.
type PropertyList []Property

var (
	typeOfPropertyLoadSaver = reflect.TypeOf((*PropertyLoadSaver)(nil)).Elem()
	typeOfPropertyList      = reflect.TypeOf(PropertyList(nil))
)

// Load loads all of the provided properties into l.
// It does not first reset *l to an empty slice.
func (l *PropertyList) Load(p []Property) error {
	*l = append(*l, p...)
	return nil
}

// Save saves all of l's properties as a slice or Properties.
func (l *PropertyList) Save() ([]Property, error) {
	return *l, nil
}

// validPropertyName returns whether name consists of one or more valid Go
// identifiers joined by ".".
func validPropertyName(name string) bool {
	if name == "" {
		return false
	}
	for _, s := range strings.Split(name, ".") {
		if s == "" {
			return false
		}
		first := true
		for _, c := range s {
			if first {
				first = false
				if c != '_' && !unicode.IsLetter(c) {
					return false
				}
			} else {
				if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
					return false
				}
			}
		}
	}
	return true
}

// structTag is the parsed `datastore:"name,options"` tag of a struct field.
// If a field has no tag, or the tag has an empty name, then the structTag's
// name is just the field name. A "-" name means that the datastore ignores
// that field.
type structTag struct {
	name    string
	noIndex bool
}

// structCodec describes how to convert a struct to and from a sequence of
// properties.
type structCodec struct {
	// byIndex gives the structTag for the i'th field.
	byIndex []structTag
	// byName gives the field codec for the structTag with the given name.
	byName map[string]fieldCodec
	// hasSlice is whether a struct or any of its nested or embedded structs
	// has a slice-typed field (other than []byte).
	hasSlice bool
	// complete is whether the structCodec is complete. An incomplete
	// structCodec may be encountered when walking a recursive struct.
	complete bool
}

// fieldCodec is a struct field's index and, if that struct field's type is
// itself a struct, that substruct's structCodec.
type fieldCodec struct {
	index          int
	substructCodec *structCodec
}

// structCodecs collects the structCodecs that have already been calculated.
var (
	structCodecsMutex sync.Mutex
	structCodecs      = make(map[reflect.Type]*structCodec)
)

// getStructCodec returns the structCodec for the given struct type.
func getStructCodec(t reflect.Type) (*structCodec, error) {
	structCodecsMutex.Lock()
	defer structCodecsMutex.Unlock()
	return getStructCodecLocked(t)
}

// getStructCodecLocked implements getStructCodec. The structCodecsMutex must
// be held when calling this function.
func getStructCodecLocked(t reflect.Type) (ret *structCodec, retErr error) {
	c, ok := structCodecs[t]
	if ok {
		return c, nil
	}
	c = &structCodec{
		byIndex: make([]structTag, t.NumField()),
		byName:  make(map[string]fieldCodec),
	}

	// Add c to the structCodecs map before we are sure it is good. If t is
	// a recursive type, it needs to find the incomplete entry for itself in
	// the map.
	structCodecs[t] = c
	defer func() {
		if retErr != nil {
			delete(structCodecs, t)
		}
	}()

	for i := range c.byIndex {
		f := t.Field(i)
		tags := strings.Split(f.Tag.Get("datastore"), ",")
		name := tags[0]
		opts := make(map[string]bool)
		for _, t := range tags[1:] {
			opts[t] = true
		}
		if name == "" {
			if !f.Anonymous {
				name = f.Name
			}
		} else if name == "-" {
			c.byIndex[i] = structTag{name: name}
			continue
		} else if !validPropertyName(name) {
			return nil, fmt.Errorf("datastore: struct tag has invalid property name: %q", name)
		}

		substructType, fIsSlice := reflect.Type(nil), false
		switch f.Type.Kind() {
		case reflect.Struct:
			substructType = f.Type
		case reflect.Slice:
			if f.Type.Elem().Kind() == reflect.Struct {
				substructType = f.Type.Elem()
			}
			fIsSlice = f.Type != typeOfByteSlice
			c.hasSlice = c.hasSlice || fIsSlice
		}

		if substructType != nil && substructType != typeOfTime && substructType != typeOfGeoPoint {
			if name != "" {
				name = name + "."
			}
			sub, err := getStructCodecLocked(substructType)
			if err != nil {
				return nil, err
			}
			if !sub.complete {
				return nil, fmt.Errorf("datastore: recursive struct: field %q", f.Name)
			}
			if fIsSlice && sub.hasSlice {
				return nil, fmt.Errorf(
					"datastore: flattening nested structs leads to a slice of slices: field %q", f.Name)
			}
			c.hasSlice = c.hasSlice || sub.hasSlice
			for relName := range sub.byName {
				absName := name + relName
				if _, ok := c.byName[absName]; ok {
					return nil, fmt.Errorf("datastore: struct tag has repeated property name: %q", absName)
				}
				c.byName[absName] = fieldCodec{index: i, substructCodec: sub}
			}
		} else {
			if _, ok := c.byName[name]; ok {
				return nil, fmt.Errorf("datastore: struct tag has repeated property name: %q", name)
			}
			c.byName[name] = fieldCodec{index: i}
		}

		c.byIndex[i] = structTag{
			name:    name,
			noIndex: opts["noindex"],
		}
	}
	c.complete = true
	return c, nil
}

// structPLS adapts a struct to be a PropertyLoadSaver.
type structPLS struct {
	v     reflect.Value
	codec *structCodec
}

// newStructPLS returns a PropertyLoadSaver for the struct pointer p.
func newStructPLS(p interface{}) (PropertyLoadSaver, error) {
	v := reflect.ValueOf(p)
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
		return nil, ErrInvalidEntityType
	}
	v = v.Elem()
	codec, err := getStructCodec(v.Type())
	if err != nil {
		return nil, err
	}
	return structPLS{v, codec}, nil
}

// LoadStruct loads the properties from p to dst.
// dst must be a struct pointer.
func LoadStruct(dst interface{}, p []Property) error {
	x, err := newStructPLS(dst)
	if err != nil {
		return err
	}
	return x.Load(p)
}

// SaveStruct returns the properties from src as a slice of Properties.
// src must be a struct pointer.
func SaveStruct(src interface{}) ([]Property, error) {
	x, err := newStructPLS(src)
	if err != nil {
		return nil, err
	}
	return x.Save()
}


text:
// Copyright 2016 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 "golang.org/x/net/context"

// Datastore kinds for the metadata entities.
const (
	namespaceKind = "__namespace__"
	kindKind      = "__kind__"
	propertyKind  = "__property__"
)

// Namespaces returns all the datastore namespaces.
func Namespaces(ctx context.Context) ([]string, error) {
	// TODO(djd): Support range queries.
	q := NewQuery(namespaceKind).KeysOnly()
	keys, err := q.GetAll(ctx, nil)
	if err != nil {
		return nil, err
	}
	// The empty namespace key uses a numeric ID (==1), but luckily
	// the string ID defaults to "" for numeric IDs anyway.
	return keyNames(keys), nil
}

// Kinds returns the names of all the kinds in the current namespace.
func Kinds(ctx context.Context) ([]string, error) {
	// TODO(djd): Support range queries.
	q := NewQuery(kindKind).KeysOnly()
	keys, err := q.GetAll(ctx, nil)
	if err != nil {
		return nil, err
	}
	return keyNames(keys), nil
}

// keyNames returns a slice of the provided keys' names (string IDs).
func keyNames(keys []*Key) []string {
	n := make([]string, 0, len(keys))
	for _, k := range keys {
		n = append(n, k.StringID())
	}
	return n
}

// KindProperties returns all the indexed properties for the given kind.
// The properties are returned as a map of property names to a slice of the
// representation types. The representation types for the supported Go property
// types are:
//   "INT64":     signed integers and time.Time
//   "DOUBLE":    float32 and float64
//   "BOOLEAN":   bool
//   "STRING":    string, []byte and ByteString
//   "POINT":     appengine.GeoPoint
//   "REFERENCE": *Key
//   "USER":      (not used in the Go runtime)
func KindProperties(ctx context.Context, kind string) (map[string][]string, error) {
	// TODO(djd): Support range queries.
	kindKey := NewKey(ctx, kindKind, kind, 0, nil)
	q := NewQuery(propertyKind).Ancestor(kindKey)

	propMap := map[string][]string{}
	props := []struct {
		Repr []string `datastore:property_representation`
	}{}

	keys, err := q.GetAll(ctx, &props)
	if err != nil {
		return nil, err
	}
	for i, p := range props {
		propMap[keys[i].StringID()] = p.Repr
	}
	return propMap, nil
}


text:
// 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 (
	"errors"
	"fmt"
	"math"
	"reflect"
	"time"

	"github.com/golang/protobuf/proto"

	"google.golang.org/appengine"
	pb "google.golang.org/appengine/internal/datastore"
)

func toUnixMicro(t time.Time) int64 {
	// We cannot use t.UnixNano() / 1e3 because we want to handle times more than
	// 2^63 nanoseconds (which is about 292 years) away from 1970, and those cannot
	// be represented in the numerator of a single int64 divide.
	return t.Unix()*1e6 + int64(t.Nanosecond()/1e3)
}

func fromUnixMicro(t int64) time.Time {
	return time.Unix(t/1e6, (t%1e6)*1e3).UTC()
}

var (
	minTime = time.Unix(int64(math.MinInt64)/1e6, (int64(math.MinInt64)%1e6)*1e3)
	maxTime = time.Unix(int64(math.MaxInt64)/1e6, (int64(math.MaxInt64)%1e6)*1e3)
)

// valueToProto converts a named value to a newly allocated Property.
// The returned error string is empty on success.
func valueToProto(defaultAppID, name string, v reflect.Value, multiple bool) (p *pb.Property, errStr string) {
	var (
		pv          pb.PropertyValue
		unsupported bool
	)
	switch v.Kind() {
	case reflect.Invalid:
		// No-op.
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		pv.Int64Value = proto.Int64(v.Int())
	case reflect.Bool:
		pv.BooleanValue = proto.Bool(v.Bool())
	case reflect.String:
		pv.StringValue = proto.String(v.String())
	case reflect.Float32, reflect.Float64:
		pv.DoubleValue = proto.Float64(v.Float())
	case reflect.Ptr:
		if k, ok := v.Interface().(*Key); ok {
			if k != nil {
				pv.Referencevalue = keyToReferenceValue(defaultAppID, k)
			}
		} else {
			unsupported = true
		}
	case reflect.Struct:
		switch t := v.Interface().(type) {
		case time.Time:
			if t.Before(minTime) || t.After(maxTime) {
				return nil, "time value out of range"
			}
			pv.Int64Value = proto.Int64(toUnixMicro(t))
		case appengine.GeoPoint:
			if !t.Valid() {
				return nil, "invalid GeoPoint value"
			}
			// NOTE: Strangely, latitude maps to X, longitude to Y.
			pv.Pointvalue = &pb.PropertyValue_PointValue{X: &t.Lat, Y: &t.Lng}
		default:
			unsupported = true
		}
	case reflect.Slice:
		if b, ok := v.Interface().([]byte); ok {
			pv.StringValue = proto.String(string(b))
		} else {
			// nvToProto should already catch slice values.
			// If we get here, we have a slice of slice values.
			unsupported = true
		}
	default:
		unsupported = true
	}
	if unsupported {
		return nil, "unsupported datastore value type: " + v.Type().String()
	}
	p = &pb.Property{
		Name:     proto.String(name),
		Value:    &pv,
		Multiple: proto.Bool(multiple),
	}
	if v.IsValid() {
		switch v.Interface().(type) {
		case []byte:
			p.Meaning = pb.Property_BLOB.Enum()
		case ByteString:
			p.Meaning = pb.Property_BYTESTRING.Enum()
		case appengine.BlobKey:
			p.Meaning = pb.Property_BLOBKEY.Enum()
		case time.Time:
			p.Meaning = pb.Property_GD_WHEN.Enum()
		case appengine.GeoPoint:
			p.Meaning = pb.Property_GEORSS_POINT.Enum()
		}
	}
	return p, ""
}

// saveEntity saves an EntityProto into a PropertyLoadSaver or struct pointer.
func saveEntity(defaultAppID string, key *Key, src interface{}) (*pb.EntityProto, error) {
	var err error
	var props []Property
	if e, ok := src.(PropertyLoadSaver); ok {
		props, err = e.Save()
	} else {
		props, err = SaveStruct(src)
	}
	if err != nil {
		return nil, err
	}
	return propertiesToProto(defaultAppID, key, props)
}

func saveStructProperty(props *[]Property, name string, noIndex, multiple bool, v reflect.Value) error {
	p := Property{
		Name:     name,
		NoIndex:  noIndex,
		Multiple: multiple,
	}
	switch x := v.Interface().(type) {
	case *Key:
		p.Value = x
	case time.Time:
		p.Value = x
	case appengine.BlobKey:
		p.Value = x
	case appengine.GeoPoint:
		p.Value = x
	case ByteString:
		p.Value = x
	default:
		switch v.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			p.Value = v.Int()
		case reflect.Bool:
			p.Value = v.Bool()
		case reflect.String:
			p.Value = v.String()
		case reflect.Float32, reflect.Float64:
			p.Value = v.Float()
		case reflect.Slice:
			if v.Type().Elem().Kind() == reflect.Uint8 {
				p.NoIndex = true
				p.Value = v.Bytes()
			}
		case reflect.Struct:
			if !v.CanAddr() {
				return fmt.Errorf("datastore: unsupported struct field: value is unaddressable")
			}
			sub, err := newStructPLS(v.Addr().Interface())
			if err != nil {
				return fmt.Errorf("datastore: unsupported struct field: %v", err)
			}
			return sub.(structPLS).save(props, name, noIndex, multiple)
		}
	}
	if p.Value == nil {
		return fmt.Errorf("datastore: unsupported struct field type: %v", v.Type())
	}
	*props = append(*props, p)
	return nil
}

func (s structPLS) Save() ([]Property, error) {
	var props []Property
	if err := s.save(&props, "", false, false); err != nil {
		return nil, err
	}
	return props, nil
}

func (s structPLS) save(props *[]Property, prefix string, noIndex, multiple bool) error {
	for i, t := range s.codec.byIndex {
		if t.name == "-" {
			continue
		}
		name := t.name
		if prefix != "" {
			name = prefix + name
		}
		v := s.v.Field(i)
		if !v.IsValid() || !v.CanSet() {
			continue
		}
		noIndex1 := noIndex || t.noIndex
		// For slice fields that aren't []byte, save each element.
		if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 {
			for j := 0; j < v.Len(); j++ {
				if err := saveStructProperty(props, name, noIndex1, true, v.Index(j)); err != nil {
					return err
				}
			}
			continue
		}
		// Otherwise, save the field itself.
		if err := saveStructProperty(props, name, noIndex1, multiple, v); err != nil {
			return err
		}
	}
	return nil
}

func propertiesToProto(defaultAppID string, key *Key, props []Property) (*pb.EntityProto, error) {
	e := &pb.EntityProto{
		Key: keyToProto(defaultAppID, key),
	}
	if key.parent == nil {
		e.EntityGroup = &pb.Path{}
	} else {
		e.EntityGroup = keyToProto(defaultAppID, key.root()).Path
	}
	prevMultiple := make(map[string]bool)

	for _, p := range props {
		if pm, ok := prevMultiple[p.Name]; ok {
			if !pm || !p.Multiple {
				return nil, fmt.Errorf("datastore: multiple Properties with Name %q, but Multiple is false", p.Name)
			}
		} else {
			prevMultiple[p.Name] = p.Multiple
		}

		x := &pb.Property{
			Name:     proto.String(p.Name),
			Value:    new(pb.PropertyValue),
			Multiple: proto.Bool(p.Multiple),
		}
		switch v := p.Value.(type) {
		case int64:
			x.Value.Int64Value = proto.Int64(v)
		case bool:
			x.Value.BooleanValue = proto.Bool(v)
		case string:
			x.Value.StringValue = proto.String(v)
			if p.NoIndex {
				x.Meaning = pb.Property_TEXT.Enum()
			}
		case float64:
			x.Value.DoubleValue = proto.Float64(v)
		case *Key:
			if v != nil {
				x.Value.Referencevalue = keyToReferenceValue(defaultAppID, v)
			}
		case time.Time:
			if v.Before(minTime) || v.After(maxTime) {
				return nil, fmt.Errorf("datastore: time value out of range")
			}
			x.Value.Int64Value = proto.Int64(toUnixMicro(v))
			x.Meaning = pb.Property_GD_WHEN.Enum()
		case appengine.BlobKey:
			x.Value.StringValue = proto.String(string(v))
			x.Meaning = pb.Property_BLOBKEY.Enum()
		case appengine.GeoPoint:
			if !v.Valid() {
				return nil, fmt.Errorf("datastore: invalid GeoPoint value")
			}
			// NOTE: Strangely, latitude maps to X, longitude to Y.
			x.Value.Pointvalue = &pb.PropertyValue_PointValue{X: &v.Lat, Y: &v.Lng}
			x.Meaning = pb.Property_GEORSS_POINT.Enum()
		case []byte:
			x.Value.StringValue = proto.String(string(v))
			x.Meaning = pb.Property_BLOB.Enum()
			if !p.NoIndex {
				return nil, fmt.Errorf("datastore: cannot index a []byte valued Property with Name %q", p.Name)
			}
		case ByteString:
			x.Value.StringValue = proto.String(string(v))
			x.Meaning = pb.Property_BYTESTRING.Enum()
		default:
			if p.Value != nil {
				return nil, fmt.Errorf("datastore: invalid Value type for a Property with Name %q", p.Name)
			}
		}

		if p.NoIndex {
			e.RawProperty = append(e.RawProperty, x)
		} else {
			e.Property = append(e.Property, x)
			if len(e.Property) > maxIndexedProperties {
				return nil, errors.New("datastore: too many indexed properties")
			}
		}
	}
	return e, nil
}


text:
// Copyright 2012 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 remote_api implements the /_ah/remote_api endpoint.
This endpoint is used by offline tools such as the bulk loader.
*/
package remote_api // import "google.golang.org/appengine/remote_api"

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/golang/protobuf/proto"

	"google.golang.org/appengine"
	"google.golang.org/appengine/internal"
	pb "google.golang.org/appengine/internal/remote_api"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/user"
)

func init() {
	http.HandleFunc("/_ah/remote_api", handle)
}

func handle(w http.ResponseWriter, req *http.Request) {
	c := appengine.NewContext(req)

	u := user.Current(c)
	if u == nil {
		u, _ = user.CurrentOAuth(c,
			"https://www.googleapis.com/auth/cloud-platform",
			"https://www.googleapis.com/auth/appengine.apis",
		)
	}

	if u == nil || !u.Admin {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusUnauthorized)
		io.WriteString(w, "You must be logged in as an administrator to access this.\n")
		return
	}
	if req.Header.Get("X-Appcfg-Api-Version") == "" {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusForbidden)
		io.WriteString(w, "This request did not contain a necessary header.\n")
		return
	}

	if req.Method != "POST" {
		// Response must be YAML.
		rtok := req.FormValue("rtok")
		if rtok == "" {
			rtok = "0"
		}
		w.Header().Set("Content-Type", "text/yaml; charset=utf-8")
		fmt.Fprintf(w, `{app_id: %q, rtok: %q}`, internal.FullyQualifiedAppID(c), rtok)
		return
	}

	defer req.Body.Close()
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		log.Errorf(c, "Failed reading body: %v", err)
		return
	}
	remReq := &pb.Request{}
	if err := proto.Unmarshal(body, remReq); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		log.Errorf(c, "Bad body: %v", err)
		return
	}

	service, method := *remReq.ServiceName, *remReq.Method
	if !requestSupported(service, method) {
		w.WriteHeader(http.StatusBadRequest)
		log.Errorf(c, "Unsupported RPC /%s.%s", service, method)
		return
	}

	rawReq := &rawMessage{remReq.Request}
	rawRes := &rawMessage{}
	err = internal.Call(c, service, method, rawReq, rawRes)

	remRes := &pb.Response{}
	if err == nil {
		remRes.Response = rawRes.buf
	} else if ae, ok := err.(*internal.APIError); ok {
		remRes.ApplicationError = &pb.ApplicationError{
			Code:   &ae.Code,
			Detail: &ae.Detail,
		}
	} else {
		// This shouldn't normally happen.
		log.Errorf(c, "appengine/remote_api: Unexpected error of type %T: %v", err, err)
		remRes.ApplicationError = &pb.ApplicationError{
			Code:   proto.Int32(0),
			Detail: proto.String(err.Error()),
		}
	}
	out, err := proto.Marshal(remRes)
	if err != nil {
		// This should not be possible.
		w.WriteHeader(500)
		log.Errorf(c, "proto.Marshal: %v", err)
		return
	}

	log.Infof(c, "Spooling %d bytes of response to /%s.%s", len(out), service, method)
	w.Header().Set("Content-Type", "application/octet-stream")
	w.Header().Set("Content-Length", strconv.Itoa(len(out)))
	w.Write(out)
}

// rawMessage is a protocol buffer type that is already serialised.
// This allows the remote_api code here to handle messages
// without having to know the real type.
type rawMessage struct {
	buf []byte
}

func (rm *rawMessage) Marshal() ([]byte, error) {
	return rm.buf, nil
}

func (rm *rawMessage) Unmarshal(buf []byte) error {
	rm.buf = make([]byte, len(buf))
	copy(rm.buf, buf)
	return nil
}

func requestSupported(service, method string) bool {
	// This list of supported services is taken from SERVICE_PB_MAP in remote_api_services.py
	switch service {
	case "app_identity_service", "blobstore", "capability_service", "channel", "datastore_v3",
		"datastore_v4", "file", "images", "logservice", "mail", "matcher", "memcache", "remote_datastore",
		"remote_socket", "search", "modules", "system", "taskqueue", "urlfetch", "user", "xmpp":
		return true
	}
	return false
}

// Methods to satisfy proto.Message.
func (rm *rawMessage) Reset()         { rm.buf = nil }
func (rm *rawMessage) String() string { return strconv.Quote(string(rm.buf)) }
func (*rawMessage) ProtoMessage()     {}


text:
// Copyright 2013 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 remote_api

// This file provides the client for connecting remotely to a user's production
// application.

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"

	"google.golang.org/appengine/internal"
	pb "google.golang.org/appengine/internal/remote_api"
)

// NewRemoteContext returns a context that gives access to the production
// APIs for the application at the given host. All communication will be
// performed over SSL unless the host is localhost.
func NewRemoteContext(host string, client *http.Client) (context.Context, error) {
	// Add an appcfg header to outgoing requests.
	t := client.Transport
	if t == nil {
		t = http.DefaultTransport
	}
	client.Transport = &headerAddingRoundTripper{t}

	url := url.URL{
		Scheme: "https",
		Host:   host,
		Path:   "/_ah/remote_api",
	}
	if host == "localhost" || strings.HasPrefix(host, "localhost:") {
		url.Scheme = "http"
	}
	u := url.String()
	appID, err := getAppID(client, u)
	if err != nil {
		return nil, fmt.Errorf("unable to contact server: %v", err)
	}
	rc := &remoteContext{
		client: client,
		url:    u,
	}
	ctx := internal.WithCallOverride(context.Background(), rc.call)
	ctx = internal.WithLogOverride(ctx, rc.logf)
	ctx = internal.WithAppIDOverride(ctx, appID)
	return ctx, nil
}

type remoteContext struct {
	client *http.Client
	url    string
}

var logLevels = map[int64]string{
	0: "DEBUG",
	1: "INFO",
	2: "WARNING",
	3: "ERROR",
	4: "CRITICAL",
}

func (c *remoteContext) logf(level int64, format string, args ...interface{}) {
	log.Printf(logLevels[level]+": "+format, args...)
}

func (c *remoteContext) call(ctx context.Context, service, method string, in, out proto.Message) error {
	req, err := proto.Marshal(in)
	if err != nil {
		return fmt.Errorf("error marshalling request: %v", err)
	}

	remReq := &pb.Request{
		ServiceName: proto.String(service),
		Method:      proto.String(method),
		Request:     req,
		// NOTE(djd): RequestId is unused in the server.
	}

	req, err = proto.Marshal(remReq)
	if err != nil {
		return fmt.Errorf("proto.Marshal: %v", err)
	}

	// TODO(djd): Respect ctx.Deadline()?
	resp, err := c.client.Post(c.url, "application/octet-stream", bytes.NewReader(req))
	if err != nil {
		return fmt.Errorf("error sending request: %v", err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("bad response %d; body: %q", resp.StatusCode, body)
	}
	if err != nil {
		return fmt.Errorf("failed reading response: %v", err)
	}
	remResp := &pb.Response{}
	if err := proto.Unmarshal(body, remResp); err != nil {
		return fmt.Errorf("error unmarshalling response: %v", err)
	}

	if ae := remResp.GetApplicationError(); ae != nil {
		return &internal.APIError{
			Code:    ae.GetCode(),
			Detail:  ae.GetDetail(),
			Service: service,
		}
	}

	if remResp.Response == nil {
		return fmt.Errorf("unexpected response: %s", proto.MarshalTextString(remResp))
	}

	return proto.Unmarshal(remResp.Response, out)
}

// This is a forgiving regexp designed to parse the app ID from YAML.
var appIDRE = regexp.MustCompile(`app_id["']?\s*:\s*['"]?([-a-z0-9.:~]+)`)

func getAppID(client *http.Client, url string) (string, error) {
	// Generate a pseudo-random token for handshaking.
	token := strconv.Itoa(rand.New(rand.NewSource(time.Now().UnixNano())).Int())

	resp, err := client.Get(fmt.Sprintf("%s?rtok=%s", url, token))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("bad response %d; body: %q", resp.StatusCode, body)
	}
	if err != nil {
		return "", fmt.Errorf("failed reading response: %v", err)
	}

	// Check the token is present in response.
	if !bytes.Contains(body, []byte(token)) {
		return "", fmt.Errorf("token not found: want %q; body %q", token, body)
	}

	match := appIDRE.FindSubmatch(body)
	if match == nil {
		return "", fmt.Errorf("app ID not found: body %q", body)
	}

	return string(match[1]), nil
}

type headerAddingRoundTripper struct {
	Wrapped http.RoundTripper
}

func (t *headerAddingRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
	r.Header.Set("X-Appcfg-Api-Version", "1")
	return t.Wrapped.RoundTrip(r)
}


text:
// Copyright 2014 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 remote_api

import (
	"testing"
)

func TestAppIDRE(t *testing.T) {
	appID := "s~my-appid-539"
	tests := []string{
		"{rtok: 8306111115908860449, app_id: s~my-appid-539}\n",
		"{rtok: 8306111115908860449, app_id: 's~my-appid-539'}\n",
		`{rtok: 8306111115908860449, app_id: "s~my-appid-539"}`,
		`{rtok: 8306111115908860449, "app_id":"s~my-appid-539"}`,
	}
	for _, v := range tests {
		if g := appIDRE.FindStringSubmatch(v); g == nil || g[1] != appID {
			t.Errorf("appIDRE.FindStringSubmatch(%s) got %q, want %q", v, g, appID)
		}
	}
}