| Index: go/src/infra/gae/libs/wrapper/memory/testing_utils_test.go
 | 
| diff --git a/go/src/infra/gae/libs/wrapper/memory/testing_utils_test.go b/go/src/infra/gae/libs/wrapper/memory/testing_utils_test.go
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..2e172bcabaf2e8def826100fbe80a52374ba8593
 | 
| --- /dev/null
 | 
| +++ b/go/src/infra/gae/libs/wrapper/memory/testing_utils_test.go
 | 
| @@ -0,0 +1,122 @@
 | 
| +// Copyright 2015 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +package memory
 | 
| +
 | 
| +import (
 | 
| +	"bytes"
 | 
| +	"fmt"
 | 
| +	"reflect"
 | 
| +	"time"
 | 
| +
 | 
| +	"appengine/datastore"
 | 
| +
 | 
| +	"github.com/luci/luci-go/common/funnybase"
 | 
| +)
 | 
| +
 | 
| +type kv struct{ k, v []byte }
 | 
| +
 | 
| +func indx(kind string, orders ...string) *qIndex {
 | 
| +	ancestor := false
 | 
| +	if kind[len(kind)-1] == '!' {
 | 
| +		ancestor = true
 | 
| +		kind = kind[:len(kind)-1]
 | 
| +	}
 | 
| +	ret := &qIndex{kind, ancestor, nil}
 | 
| +	for _, o := range orders {
 | 
| +		dir := qASC
 | 
| +		if o[0] == '-' {
 | 
| +			dir = qDEC
 | 
| +			o = o[1:]
 | 
| +		}
 | 
| +		ret.sortby = append(ret.sortby, qSortBy{o, dir})
 | 
| +	}
 | 
| +	return ret
 | 
| +}
 | 
| +
 | 
| +func pl(props ...datastore.Property) *propertyList {
 | 
| +	return (*propertyList)(&props)
 | 
| +}
 | 
| +
 | 
| +func prop(name string, val interface{}, noIndex ...bool) (ret datastore.Property) {
 | 
| +	ret.Name = name
 | 
| +	ret.Value = val
 | 
| +	if len(noIndex) > 0 {
 | 
| +		ret.NoIndex = noIndex[0]
 | 
| +	}
 | 
| +	return
 | 
| +}
 | 
| +
 | 
| +func key(kind string, id interface{}, parent ...*datastore.Key) *datastore.Key {
 | 
| +	stringID := ""
 | 
| +	intID := int64(0)
 | 
| +	switch x := id.(type) {
 | 
| +	case string:
 | 
| +		stringID = x
 | 
| +	case int:
 | 
| +		intID = int64(x)
 | 
| +	default:
 | 
| +		panic(fmt.Errorf("what the %T: %v", id, id))
 | 
| +	}
 | 
| +	par := (*datastore.Key)(nil)
 | 
| +	if len(parent) > 0 {
 | 
| +		par = parent[0]
 | 
| +	}
 | 
| +	return newKey("ns", kind, stringID, intID, par)
 | 
| +}
 | 
| +
 | 
| +func mustLoadLocation(loc string) *time.Location {
 | 
| +	if z, err := time.LoadLocation(loc); err != nil {
 | 
| +		panic(err)
 | 
| +	} else {
 | 
| +		return z
 | 
| +	}
 | 
| +}
 | 
| +
 | 
| +// cat is a convenience method for concatenating anything with an underlying
 | 
| +// byte representation into a single []byte.
 | 
| +func cat(bytethings ...interface{}) []byte {
 | 
| +	buf := &bytes.Buffer{}
 | 
| +	for _, thing := range bytethings {
 | 
| +		switch x := thing.(type) {
 | 
| +		case int, int64:
 | 
| +			funnybase.Write(buf, reflect.ValueOf(x).Int())
 | 
| +		case uint, uint64:
 | 
| +			funnybase.WriteUint(buf, reflect.ValueOf(x).Uint())
 | 
| +		case float64:
 | 
| +			writeFloat64(buf, x)
 | 
| +		case byte, propValType:
 | 
| +			buf.WriteByte(byte(reflect.ValueOf(x).Uint()))
 | 
| +		case []byte, serializedPval:
 | 
| +			buf.Write(reflect.ValueOf(x).Convert(byteSliceType).Interface().([]byte))
 | 
| +		case string:
 | 
| +			writeString(buf, x)
 | 
| +		case time.Time:
 | 
| +			writeTime(buf, x)
 | 
| +		case *datastore.Key:
 | 
| +			writeKey(buf, noNS, x)
 | 
| +		case *qIndex:
 | 
| +			x.WriteBinary(buf)
 | 
| +		default:
 | 
| +			panic(fmt.Errorf("I don't know how to deal with %T: %#v", thing, thing))
 | 
| +		}
 | 
| +	}
 | 
| +	ret := buf.Bytes()
 | 
| +	if ret == nil {
 | 
| +		ret = []byte{}
 | 
| +	}
 | 
| +	return ret
 | 
| +}
 | 
| +
 | 
| +func icat(bytethings ...interface{}) []byte {
 | 
| +	ret := cat(bytethings...)
 | 
| +	for i := range ret {
 | 
| +		ret[i] ^= 0xFF
 | 
| +	}
 | 
| +	return ret
 | 
| +}
 | 
| +
 | 
| +func sat(bytethings ...interface{}) string {
 | 
| +	return string(cat(bytethings...))
 | 
| +}
 | 
| 
 |