<commit_before>package wally

import (
	"fmt"
	"io/ioutil"
	"strings"
	"testing"

	rdb "github.com/dancannon/gorethink"
	"github.com/stretchr/testify/assert"
)

var (
	session *rdb.Session
)

func init() {
	Database = "testing"
	DocumentTable = "documents"
	IndexTable = "indexes"

	var err error
	session, err = rdb.Connect(rdb.ConnectOpts{
		Address:  "localhost:28015",
		Database: Database,
	})

	if err != nil {
		fmt.Errorf(err.Error())
	}
}

func DbBootstrap() {
	// Reset database
	rdb.DbDrop(Database).Exec(session)
	rdb.DbCreate(Database).Exec(session)

	// Drop tables
	rdb.Db(Database).TableDrop(DocumentTable).Run(session)
	rdb.Db(Database).TableDrop(IndexTable).Run(session)

	// Create tables
	rdb.Db(Database).TableCreate(DocumentTable).Run(session)
	rdb.Db(Database).TableCreate(IndexTable).Run(session)
}

func TestIndexer_Stopper(t *testing.T) {
	tests := []struct {
		Input  string
		Output string
	}{
		{
			"computer",
			"computer",
		},

		{
			"the",
			"",
		},

		{
			"technology",
			"technology",
		},

		{
			"wasn't",
			"",
		},
	}

	for _, test := range tests {
		assert.Equal(t, test.Output, Stopper(test.Input))
	}
}

func TestIndexer_SplitTextIntoWords(t *testing.T) {
	tests := []struct {
		Input  interface{}
		Output []string
	}{
		{
			"I am a block of text",
			[]string{"I", "am", "a", "block", "of", "text"},
		},

		{
			"        superfluous    whitespace ",
			[]string{"superfluous", "whitespace"},
		},

		{
			"              ",
			[]string{},
		},

		{
			[]byte("fancy a byte?"),
			[]string{"fancy", "a", "byte?"},
		},

		{
			32,
			[]string{},
		},
	}

	for _, test := range tests {
		assert.Equal(t, test.Output, SplitTextIntoWords(test.Input))
	}
}

func TestIndexer_Parse(t *testing.T) {
	docId := "12345-67890-ABCDE"

	tests := []struct {
		Input  interface{}
		Output []Index
	}{
		{
			"I am a block of text and I am going to be parsed",
			[]Index{
				Index{Id: "block", DocumentId: docId, Count: 0},
				Index{Id: "text", DocumentId: docId, Count: 0},
				Index{Id: "going", DocumentId: docId, Count: 0},
				Index{Id: "parsed", DocumentId: docId, Count: 0},
			},
		},

		{
			[]byte("I am another block of text but now I am in bytes"),
			[]Index{
				Index{Id: "another", DocumentId: docId, Count: 0},
				Index{Id: "block", DocumentId: docId, Count: 0},
				Index{Id: "text", DocumentId: docId, Count: 0},
				Index{Id: "now", DocumentId: docId, Count: 0},
				Index{Id: "bytes", DocumentId: docId, Count: 0},
			},
		},
	}

	for _, test := range tests {
		assert.Equal(t, test.Output, Parse(test.Input, docId))
	}
}

func TestIndexer_IndexString(t *testing.T) {
	indexId := "world"

	index := Index{Id: indexId}

	assert.Equal(t, "Index#world", index.String())
}

func TestIndexer_IndexPut(t *testing.T) {
	DbBootstrap()

	index := Index{Id: "hello", Count: 5, DocumentId: "12345-67890-ABCDE"}

	err := index.Put(session)
	assert.Nil(t, err)

	res, err := rdb.Db(Database).Table(IndexTable).Get("hello").Run(session)
	assert.Nil(t, err)

	var i Index
	err = res.One(&i)
	assert.Nil(t, err)

	assert.Equal(t, i.Id, "hello")
	assert.Equal(t, i.Count, 5)
	assert.Equal(t, i.DocumentId, "12345-67890-ABCDE")
}

func TestIndexer_DocumentString(t *testing.T) {
	docId := "12345-67890-ABCDE"

	doc := Document{Id: docId}

	assert.Equal(t, "Document#12345-67890-ABCDE", doc.String())
}

func TestIndexer_DocumentPut(t *testing.T) {
	DbBootstrap()

	doc := Document{
		Source: "www.google.com",
		Content: "Lorem ipsum dolor sit amet.",
	}

	err := doc.Put(session)
	assert.Nil(t, err)

	res, err := rdb.Db(Database).Table(DocumentTable).Run(session)
	assert.Nil(t, err)

	var d Document
	err = res.One(&d)
	assert.Nil(t, err)

	assert.NotEqual(t, d.Id, "")
	assert.Equal(t, d.Source, "www.google.com")
	assert.Equal(t, d.Content, "Lorem ipsum dolor sit amet.")
}

func BenchmarkSplitTextIntoWords(b *testing.B) {
	file, err := ioutil.ReadFile("test_data/test.txt") // 30654 words
	if err != nil {
		b.Error("Could not load test data")
	}

	for n := 0; n < b.N; n++ {
		SplitTextIntoWords(file)
	}
}

func BenchmarkSplitTextIntoWords_two(b *testing.B) {
	file, err := ioutil.ReadFile("test_data/test_2.txt") // 1891 words
	if err != nil {
		b.Error("Could not load test data")
	}

	for n := 0; n < b.N; n++ {
		SplitTextIntoWords(file)
	}
}

func BenchmarkStopper(b *testing.B) {
	file, err := ioutil.ReadFile("test_data/test.txt") // 30654 words
	if err != nil {
		b.Error("Could not load test data")
	}

	data := strings.Fields(string(file))

	for n := 0; n < b.N; n++ {
		for _, word := range data {
			Stopper(word)
		}
	}
}

func BenchmarkStopper_two(b *testing.B) {
	file, err := ioutil.ReadFile("test_data/test_2.txt") // 1891 words
	if err != nil {
		b.Error("Could not load test data")
	}

	data := strings.Fields(string(file))

	for n := 0; n < b.N; n++ {
		for _, word := range data {
			Stopper(word)
		}
	}
}

func BenchmarkParse(b *testing.B) {
	docId := "12345-67890-ABCDE"
	file, err := ioutil.ReadFile("test_data/test.txt") // 30654 words
	if err != nil {
		b.Error("Could not load test data")
	}

	for n := 0; n < b.N; n++ {
		Parse(file, docId)
	}
}

func BenchmarkParse_two(b *testing.B) {
	docId := "12345-67890-ABCDE"
	file, err := ioutil.ReadFile("test_data/test_2.txt") // 30654 words
	if err != nil {
		b.Error("Could not load test data")
	}

	for n := 0; n < b.N; n++ {
		Parse(file, docId)
	}
}
<commit_msg>fix #2 reconnect to db to avoid connection closing<commit_after>package wally

import (
	"fmt"
	"io/ioutil"
	"strings"
	"testing"

	rdb "github.com/dancannon/gorethink"
	"github.com/stretchr/testify/assert"
)

var (
	session *rdb.Session
)

func init() {
	Database = "testing"
	DocumentTable = "documents"
	IndexTable = "indexes"
}

func DbConnect() {
	var err error
	session, err = rdb.Connect(rdb.ConnectOpts{
		Address:  "localhost:28015",
		Database: Database,
	})

	if err != nil {
		fmt.Errorf(err.Error())
	}
}

func DbBootstrap() {
	DbConnect()
	// Reset database
	rdb.DbDrop(Database).Exec(session)
	rdb.DbCreate(Database).Exec(session)

	DbConnect()

	// Drop tables
	rdb.Db(Database).TableDrop(DocumentTable).Run(session)
	rdb.Db(Database).TableDrop(IndexTable).Run(session)

	// Create tables
	rdb.Db(Database).TableCreate(DocumentTable).Run(session)
	rdb.Db(Database).TableCreate(IndexTable).Run(session)
}

func TestIndexer_Stopper(t *testing.T) {
	tests := []struct {
		Input  string
		Output string
	}{
		{
			"computer",
			"computer",
		},

		{
			"the",
			"",
		},

		{
			"technology",
			"technology",
		},

		{
			"wasn't",
			"",
		},
	}

	for _, test := range tests {
		assert.Equal(t, test.Output, Stopper(test.Input))
	}
}

func TestIndexer_SplitTextIntoWords(t *testing.T) {
	tests := []struct {
		Input  interface{}
		Output []string
	}{
		{
			"I am a block of text",
			[]string{"I", "am", "a", "block", "of", "text"},
		},

		{
			"        superfluous    whitespace ",
			[]string{"superfluous", "whitespace"},
		},

		{
			"              ",
			[]string{},
		},

		{
			[]byte("fancy a byte?"),
			[]string{"fancy", "a", "byte?"},
		},

		{
			32,
			[]string{},
		},
	}

	for _, test := range tests {
		assert.Equal(t, test.Output, SplitTextIntoWords(test.Input))
	}
}

func TestIndexer_Parse(t *testing.T) {
	docId := "12345-67890-ABCDE"

	tests := []struct {
		Input  interface{}
		Output []Index
	}{
		{
			"I am a block of text and I am going to be parsed",
			[]Index{
				Index{Id: "block", DocumentId: docId, Count: 0},
				Index{Id: "text", DocumentId: docId, Count: 0},
				Index{Id: "going", DocumentId: docId, Count: 0},
				Index{Id: "parsed", DocumentId: docId, Count: 0},
			},
		},

		{
			[]byte("I am another block of text but now I am in bytes"),
			[]Index{
				Index{Id: "another", DocumentId: docId, Count: 0},
				Index{Id: "block", DocumentId: docId, Count: 0},
				Index{Id: "text", DocumentId: docId, Count: 0},
				Index{Id: "now", DocumentId: docId, Count: 0},
				Index{Id: "bytes", DocumentId: docId, Count: 0},
			},
		},
	}

	for _, test := range tests {
		assert.Equal(t, test.Output, Parse(test.Input, docId))
	}
}

func TestIndexer_IndexString(t *testing.T) {
	indexId := "world"

	index := Index{Id: indexId}

	assert.Equal(t, "Index#world", index.String())
}

func TestIndexer_IndexPut(t *testing.T) {
	DbBootstrap()

	index := Index{Id: "hello", Count: 5, DocumentId: "12345-67890-ABCDE"}

	err := index.Put(session)
	assert.Nil(t, err)

	res, err := rdb.Db(Database).Table(IndexTable).Get("hello").Run(session)
	assert.Nil(t, err)

	var i Index
	err = res.One(&i)
	assert.Nil(t, err)

	assert.Equal(t, i.Id, "hello")
	assert.Equal(t, i.Count, 5)
	assert.Equal(t, i.DocumentId, "12345-67890-ABCDE")
}

func TestIndexer_DocumentString(t *testing.T) {
	docId := "12345-67890-ABCDE"

	doc := Document{Id: docId}

	assert.Equal(t, "Document#12345-67890-ABCDE", doc.String())
}

func TestIndexer_DocumentPut(t *testing.T) {
	DbBootstrap()

	doc := Document{
		Source: "www.google.com",
		Content: "Lorem ipsum dolor sit amet.",
	}

	err := doc.Put(session)
	assert.Nil(t, err)

	res, err := rdb.Db(Database).Table(DocumentTable).Run(session)
	assert.Nil(t, err)

	var d Document
	err = res.One(&d)
	assert.Nil(t, err)

	assert.NotEqual(t, d.Id, "")
	assert.Equal(t, d.Source, "www.google.com")
	assert.Equal(t, d.Content, "Lorem ipsum dolor sit amet.")
}

func BenchmarkSplitTextIntoWords(b *testing.B) {
	file, err := ioutil.ReadFile("test_data/test.txt") // 30654 words
	if err != nil {
		b.Error("Could not load test data")
	}

	for n := 0; n < b.N; n++ {
		SplitTextIntoWords(file)
	}
}

func BenchmarkSplitTextIntoWords_two(b *testing.B) {
	file, err := ioutil.ReadFile("test_data/test_2.txt") // 1891 words
	if err != nil {
		b.Error("Could not load test data")
	}

	for n := 0; n < b.N; n++ {
		SplitTextIntoWords(file)
	}
}

func BenchmarkStopper(b *testing.B) {
	file, err := ioutil.ReadFile("test_data/test.txt") // 30654 words
	if err != nil {
		b.Error("Could not load test data")
	}

	data := strings.Fields(string(file))

	for n := 0; n < b.N; n++ {
		for _, word := range data {
			Stopper(word)
		}
	}
}

func BenchmarkStopper_two(b *testing.B) {
	file, err := ioutil.ReadFile("test_data/test_2.txt") // 1891 words
	if err != nil {
		b.Error("Could not load test data")
	}

	data := strings.Fields(string(file))

	for n := 0; n < b.N; n++ {
		for _, word := range data {
			Stopper(word)
		}
	}
}

func BenchmarkParse(b *testing.B) {
	docId := "12345-67890-ABCDE"
	file, err := ioutil.ReadFile("test_data/test.txt") // 30654 words
	if err != nil {
		b.Error("Could not load test data")
	}

	for n := 0; n < b.N; n++ {
		Parse(file, docId)
	}
}

func BenchmarkParse_two(b *testing.B) {
	docId := "12345-67890-ABCDE"
	file, err := ioutil.ReadFile("test_data/test_2.txt") // 30654 words
	if err != nil {
		b.Error("Could not load test data")
	}

	for n := 0; n < b.N; n++ {
		Parse(file, docId)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/test/go-zookeeper/zk"
	"time"
)

func main() {

	servers := []string{"192.168.28.191:2181"}

	conf := zk.ConnConf{
		RecvTimeout:    5 * time.Second,
		ConnTimeout:    5 * time.Second,
		SessionTimeout: 30000,
	}

	c, _, err := zk.ConnectWithConf(servers, conf)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("connect success")

		time.Sleep(20 * time.Second)

		data, stat, err := c.Get("/zk/codis")
		if err != nil {
			fmt.Printf("get error : %+v", err)
		} else {
			fmt.Printf("get success : data: %+v stat: %+v", data, stat)
		}
		_, stat, ch, err := c.ChildrenW("/zk")
		if err != nil {
			//fmt.Printf("%+v", err)
		}
		//fmt.Printf("%+v %+v\n", children, stat)
		e := <-ch
		fmt.Printf("%+v\n", e)
	}
	/*
		c, _, err := zk.Connect([]string{"127.0.0.1"}, time.Second) //*10)
		if err != nil {
			panic(err)
		}
		children, stat, ch, err := c.ChildrenW("/")
		if err != nil {
			panic(err)
		}
		fmt.Printf("%+v %+v\n", children, stat)
		e := <-ch
		fmt.Printf("%+v\n", e)
	*/
}
<commit_msg>remove log<commit_after>package main

import (
	"fmt"
	"github.com/ngaut/go-zookeeper/zk"
	"time"
)

func main() {

	servers := []string{"192.168.28.191:2181"}

	conf := zk.ConnConf{
		RecvTimeout:    5 * time.Second,
		ConnTimeout:    5 * time.Second,
		SessionTimeout: 30000,
	}

	c, _, err := zk.ConnectWithConf(servers, conf)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("connect success")

		time.Sleep(20 * time.Second)

		data, stat, err := c.Get("/zk/codis")
		if err != nil {
			fmt.Printf("get error : %+v", err)
		} else {
			fmt.Printf("get success : data: %+v stat: %+v", data, stat)
		}
		_, stat, ch, err := c.ChildrenW("/zk")
		if err != nil {
			//fmt.Printf("%+v", err)
		}
		//fmt.Printf("%+v %+v\n", children, stat)
		e := <-ch
		fmt.Printf("%+v\n", e)
	}
	/*
		c, _, err := zk.Connect([]string{"127.0.0.1"}, time.Second) //*10)
		if err != nil {
			panic(err)
		}
		children, stat, ch, err := c.ChildrenW("/")
		if err != nil {
			panic(err)
		}
		fmt.Printf("%+v %+v\n", children, stat)
		e := <-ch
		fmt.Printf("%+v\n", e)
	*/
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"time"
	"github.com/XiaoMi/galaxy-sdk-go/sds/auth"
	"github.com/XiaoMi/galaxy-sdk-go/sds/common"
	"github.com/XiaoMi/galaxy-sdk-go/sds/client"
	"github.com/XiaoMi/galaxy-sdk-go/sds/table"
	"github.com/XiaoMi/galaxy-sdk-go/thrift"
	"github.com/XiaoMi/galaxy-sdk-go/sds/errors"
	"math/rand"
)

func main() {
	flag.Parse()

	// Set your AppId and AppSecret
	appId := ""
	appSecret := ""
	cred := auth.Credential{auth.UserType_APP_SECRET, appId, thrift.StringPtr(appSecret)}
	endpoint := "http://sds.api.xiaomi.com"

	cfAdmin := client.NewClientFactory(&cred,
		time.Duration(common.DEFAULT_ADMIN_CLIENT_TIMEOUT * int64(time.Second)))
	adminClient := cfAdmin.NewAdminClient(endpoint + common.ADMIN_SERVICE_PATH)
	cfTable := client.NewClientFactory(&cred,
		time.Duration(common.DEFAULT_CLIENT_TIMEOUT * int64(time.Second)))
	tableClient := cfTable.NewTableClient(endpoint + common.TABLE_SERVICE_PATH)

	tableName := "go-test-weather"
	tableSpec := table.TableSpec{
		Schema : &table.TableSchema{
			PrimaryIndex: []*table.KeySpec{&table.KeySpec{"cityId", true}},
			Attributes: map[string]table.DataType {
				"cityId": table.DataType_STRING,
				"timestamp": table.DataType_INT64,
				"score": table.DataType_DOUBLE,
				"pm25": table.DataType_INT64,
			},
			PreSplits: 1, // Must be set with Go SDK, the default 0 is illegal
			Ttl: -1, // Must be set with Go SDK, the default 0 is illegal
		},
		Metadata: &table.TableMetadata{
			Quota: &table.TableQuota{100 * 1024 * 1024}, // 100M
			Throughput: &table.ProvisionThroughput{10, 10},
		},
	}

	// Drop and create table
	fmt.Println("Dropping old table")
	if err := adminClient.DropTable(tableName); err != nil {
		if se, ok := err.(*errors.ServiceException); ok {
			fmt.Printf("Drop table failed, error: %s, details: %s, callId: %s\n",
				se.ErrorCode, *se.Details, *se.CallId)
		}
	}
	fmt.Println("Creating new table")
	_, err := adminClient.CreateTable(tableName, &tableSpec)
	if err != nil {
		se, ok := err.(*errors.ServiceException)
		if ok {
			fmt.Printf("Error: %s, details: %s, callId: %s\n",
				se.ErrorCode, *se.Details, *se.CallId)
		}
	}

	// put data
	cities := [...]string {"北京", "Beihai", "Dalian", "Dandong", "Fuzhou", "Guangzhou",
		"Haikou", "Hankou", "Huangpu", "Jiujiang", "Lianyungang", "Nanjing", "Nantong",
		"Ningbo", "Qingdao", "Qinhuangdao", "Rizhao", "Sanya", "Shanghai", "Shantou",
		"Shenzhen", "Tianjin", "Weihai", "Wenzhou", "Xiamen", "Yangzhou", "Yantai"}

	for i := 0; i < len(cities); i += 1 {
		put := table.PutRequest{
			TableName: tableName,
			Record: map[string]*table.Datum {
				"cityId": client.StringDatum(cities[i]),
				"timestamp": client.Int64Datum(time.Now().Unix()),
				"score": client.Float64Datum(rand.Float64() * 100),
				"pm25": client.Int64Datum(rand.Int63n(100)),
			},
		}
		if pr, err := tableClient.Put(&put); err != nil {
			fmt.Printf("Failed to put record: %s\n", err)
		} else {
			fmt.Printf("Put record: %s, %v\n", cities[i], pr.IsSetSuccess())
		}
	}

	// get data
	i := rand.Intn(len(cities))
	get := table.GetRequest{
		TableName: tableName,
		Keys: map[string]*table.Datum {
			"cityId": client.StringDatum(cities[i]),
		},
	}
	if gr, err := tableClient.Get(&get); err != nil {
		fmt.Printf("Failed to get record: %s\n", err)
	} else if gr.GetItem() != nil {
		fmt.Printf("Get record, city: %s, score: %f\n",
			client.StringValue(gr.GetItem()["cityId"]),
			client.Float64Value(gr.GetItem()["score"]))
	}

	// batch put
	batch := table.NewBatchRequest()
	for i := 0; i < 2; i += 1 {
		put := table.PutRequest{
			TableName: tableName,
			Record: map[string]*table.Datum {
				"cityId": client.StringDatum(cities[i]),
				"timestamp": client.Int64Datum(time.Now().Unix()),
				"score": client.Float64Datum(rand.Float64() * 100),
				"pm25": client.Int64Datum(rand.Int63n(100)),
			},
		}
		batch.Items = append(batch.Items, &table.BatchRequestItem{
				Action: table.BatchOp_PUT,
				Request: &table.Request{
					PutRequest: &put,
				},
			})
	}
	if br, err := tableClient.Batch(batch); err != nil {
		fmt.Printf("Failed to batch put record: %s\n", err)
	} else {
		fmt.Printf("Batch put record: %s\n", br)
	}

	// scan data
	scan := table.ScanRequest{
		TableName: tableName,
		StartKey: nil,
		StopKey: nil,
		Attributes: []string{"cityId", "score"},
		Condition: thrift.StringPtr("score > 0"), // condition to meet
		Limit: 2,
	}

	for item := range client.NewTableScanner(tableClient, &scan).Iter() {
		if datum, err := item.Datum, item.Error; err != nil {
			fmt.Printf("Failed to scan record: %s\n", err)
			break
		} else {
			fmt.Printf("Scanned record, city: %s, score: %f\n",
				client.StringValue(datum["cityId"]),
				client.Float64Value(datum["score"]))
		}
	}

	fmt.Println("Dropping table")
	err = adminClient.DropTable(tableName)
	if err != nil {
		fmt.Printf("Drop table failed: %s\n", err)
	}
}
<commit_msg>update appId to appKey<commit_after>package main

import (
	"flag"
	"fmt"
	"time"
	"github.com/XiaoMi/galaxy-sdk-go/sds/auth"
	"github.com/XiaoMi/galaxy-sdk-go/sds/common"
	"github.com/XiaoMi/galaxy-sdk-go/sds/client"
	"github.com/XiaoMi/galaxy-sdk-go/sds/table"
	"github.com/XiaoMi/galaxy-sdk-go/thrift"
	"github.com/XiaoMi/galaxy-sdk-go/sds/errors"
	"math/rand"
)

func main() {
	flag.Parse()

	// Set your AppKey and AppSecret
	appKey := ""
	appSecret := ""
	cred := auth.Credential{auth.UserType_APP_SECRET, appKey, thrift.StringPtr(appSecret)}
	endpoint := "http://sds.api.xiaomi.com"

	cfAdmin := client.NewClientFactory(&cred,
		time.Duration(common.DEFAULT_ADMIN_CLIENT_TIMEOUT * int64(time.Second)))
	adminClient := cfAdmin.NewAdminClient(endpoint + common.ADMIN_SERVICE_PATH)
	cfTable := client.NewClientFactory(&cred,
		time.Duration(common.DEFAULT_CLIENT_TIMEOUT * int64(time.Second)))
	tableClient := cfTable.NewTableClient(endpoint + common.TABLE_SERVICE_PATH)

	tableName := "go-test-weather"
	tableSpec := table.TableSpec{
		Schema : &table.TableSchema{
			PrimaryIndex: []*table.KeySpec{&table.KeySpec{"cityId", true}},
			Attributes: map[string]table.DataType {
				"cityId": table.DataType_STRING,
				"timestamp": table.DataType_INT64,
				"score": table.DataType_DOUBLE,
				"pm25": table.DataType_INT64,
			},
			PreSplits: 1, // Must be set with Go SDK, the default 0 is illegal
			Ttl: -1, // Must be set with Go SDK, the default 0 is illegal
		},
		Metadata: &table.TableMetadata{
			Quota: &table.TableQuota{100 * 1024 * 1024}, // 100M
			Throughput: &table.ProvisionThroughput{10, 10},
		},
	}

	// Drop and create table
	fmt.Println("Dropping old table")
	if err := adminClient.DropTable(tableName); err != nil {
		if se, ok := err.(*errors.ServiceException); ok {
			fmt.Printf("Drop table failed, error: %s, details: %s, callId: %s\n",
				se.ErrorCode, *se.Details, *se.CallId)
		}
	}
	fmt.Println("Creating new table")
	_, err := adminClient.CreateTable(tableName, &tableSpec)
	if err != nil {
		se, ok := err.(*errors.ServiceException)
		if ok {
			fmt.Printf("Error: %s, details: %s, callId: %s\n",
				se.ErrorCode, *se.Details, *se.CallId)
		}
	}

	// put data
	cities := [...]string {"北京", "Beihai", "Dalian", "Dandong", "Fuzhou", "Guangzhou",
		"Haikou", "Hankou", "Huangpu", "Jiujiang", "Lianyungang", "Nanjing", "Nantong",
		"Ningbo", "Qingdao", "Qinhuangdao", "Rizhao", "Sanya", "Shanghai", "Shantou",
		"Shenzhen", "Tianjin", "Weihai", "Wenzhou", "Xiamen", "Yangzhou", "Yantai"}

	for i := 0; i < len(cities); i += 1 {
		put := table.PutRequest{
			TableName: tableName,
			Record: map[string]*table.Datum {
				"cityId": client.StringDatum(cities[i]),
				"timestamp": client.Int64Datum(time.Now().Unix()),
				"score": client.Float64Datum(rand.Float64() * 100),
				"pm25": client.Int64Datum(rand.Int63n(100)),
			},
		}
		if pr, err := tableClient.Put(&put); err != nil {
			fmt.Printf("Failed to put record: %s\n", err)
		} else {
			fmt.Printf("Put record: %s, %v\n", cities[i], pr.IsSetSuccess())
		}
	}

	// get data
	i := rand.Intn(len(cities))
	get := table.GetRequest{
		TableName: tableName,
		Keys: map[string]*table.Datum {
			"cityId": client.StringDatum(cities[i]),
		},
	}
	if gr, err := tableClient.Get(&get); err != nil {
		fmt.Printf("Failed to get record: %s\n", err)
	} else if gr.GetItem() != nil {
		fmt.Printf("Get record, city: %s, score: %f\n",
			client.StringValue(gr.GetItem()["cityId"]),
			client.Float64Value(gr.GetItem()["score"]))
	}

	// batch put
	batch := table.NewBatchRequest()
	for i := 0; i < 2; i += 1 {
		put := table.PutRequest{
			TableName: tableName,
			Record: map[string]*table.Datum {
				"cityId": client.StringDatum(cities[i]),
				"timestamp": client.Int64Datum(time.Now().Unix()),
				"score": client.Float64Datum(rand.Float64() * 100),
				"pm25": client.Int64Datum(rand.Int63n(100)),
			},
		}
		batch.Items = append(batch.Items, &table.BatchRequestItem{
				Action: table.BatchOp_PUT,
				Request: &table.Request{
					PutRequest: &put,
				},
			})
	}
	if br, err := tableClient.Batch(batch); err != nil {
		fmt.Printf("Failed to batch put record: %s\n", err)
	} else {
		fmt.Printf("Batch put record: %s\n", br)
	}

	// scan data
	scan := table.ScanRequest{
		TableName: tableName,
		StartKey: nil,
		StopKey: nil,
		Attributes: []string{"cityId", "score"},
		Condition: thrift.StringPtr("score > 0"), // condition to meet
		Limit: 2,
	}

	for item := range client.NewTableScanner(tableClient, &scan).Iter() {
		if datum, err := item.Datum, item.Error; err != nil {
			fmt.Printf("Failed to scan record: %s\n", err)
			break
		} else {
			fmt.Printf("Scanned record, city: %s, score: %f\n",
				client.StringValue(datum["cityId"]),
				client.Float64Value(datum["score"]))
		}
	}

	fmt.Println("Dropping table")
	err = adminClient.DropTable(tableName)
	if err != nil {
		fmt.Printf("Drop table failed: %s\n", err)
	}
}
<|endoftext|>


<commit_before>//
// Copyright 2021, Sander van Harmelen
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package gitlab

import (
	"fmt"
	"net/http"
	"reflect"
	"testing"
	"time"
)

func TestListAllDeployKeys(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/deploy_keys", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprintf(w, `[
			{
			  "id": 1,
			  "title": "Public key",
			  "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			  "created_at": "2013-10-02T10:12:29Z"
			},
			{
			  "id": 3,
			  "title": "Another Public key",
			  "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			  "created_at": "2013-10-02T11:12:29Z"
			}
		  ]`)
	})

	deployKeys, _, err := client.DeployKeys.ListAllDeployKeys()
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned error: %v", err)
	}

	timeLayout := "2006-01-02T15:04:05Z07:00"
	createdAt, err := time.Parse(timeLayout, "2013-10-02T10:12:29Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	createdAt2, err := time.Parse(timeLayout, "2013-10-02T11:12:29Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	want := []*DeployKey{
		{
			ID:        1,
			Title:     "Public key",
			Key:       "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			CreatedAt: &createdAt,
		},
		{
			ID:        3,
			Title:     "Another Public key",
			Key:       "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			CreatedAt: &createdAt2,
		},
	}
	if !reflect.DeepEqual(want, deployKeys) {
		t.Errorf("DeployKeys.ListAllDeployKeys returned %+v, want %+v", deployKeys, want)
	}
}

func TestListProjectDeployKeys(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/5/deploy_keys", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprintf(w, `[
			{
			  "id": 1,
			  "title": "Public key",
			  "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			  "created_at": "2013-10-02T10:12:29Z",
			  "can_push": false
			},
			{
			  "id": 3,
			  "title": "Another Public key",
			  "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			  "created_at": "2013-10-02T11:12:29Z",
			  "can_push": false
			}
		  ]`)
	})

	deployKeys, _, err := client.DeployKeys.ListProjectDeployKeys(5, &ListProjectDeployKeysOptions{})
	if err != nil {
		t.Errorf("DeployKeys.ListProjectDeployKeys returned error: %v", err)
	}

	timeLayout := "2006-01-02T15:04:05Z07:00"
	createdAt, err := time.Parse(timeLayout, "2013-10-02T10:12:29Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	createdAt2, err := time.Parse(timeLayout, "2013-10-02T11:12:29Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	canPush := false

	want := []*DeployKey{
		{
			ID:        1,
			Title:     "Public key",
			Key:       "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			CreatedAt: &createdAt,
			CanPush:   &canPush,
		},
		{
			ID:        3,
			Title:     "Another Public key",
			Key:       "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			CreatedAt: &createdAt2,
			CanPush:   &canPush,
		},
	}
	if !reflect.DeepEqual(want, deployKeys) {
		t.Errorf("DeployKeys.ListProjectDeployKeys returned %+v, want %+v", deployKeys, want)
	}
}

func TestGetDeployKey(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/5/deploy_keys/11", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprintf(w, `{
			"id": 1,
			"title": "Public key",
			"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			"created_at": "2013-10-02T10:12:29Z",
			"can_push": false
		  }`)
	})

	deployKey, _, err := client.DeployKeys.GetDeployKey(5, 11)
	if err != nil {
		t.Errorf("DeployKeys.GetDeployKey returned error: %v", err)
	}

	timeLayout := "2006-01-02T15:04:05Z07:00"
	createdAt, err := time.Parse(timeLayout, "2013-10-02T10:12:29Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	canPush := false

	want := &DeployKey{
		ID:        1,
		Title:     "Public key",
		Key:       "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
		CreatedAt: &createdAt,
		CanPush:   &canPush,
	}
	if !reflect.DeepEqual(want, deployKey) {
		t.Errorf("DeployKeys.GetDeployKey returned %+v, want %+v", deployKey, want)
	}
}
<commit_msg>Added Test for AddDeployKey<commit_after>//
// Copyright 2021, Sander van Harmelen
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package gitlab

import (
	"fmt"
	"net/http"
	"reflect"
	"testing"
	"time"
)

func TestListAllDeployKeys(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/deploy_keys", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprintf(w, `[
			{
			  "id": 1,
			  "title": "Public key",
			  "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			  "created_at": "2013-10-02T10:12:29Z"
			},
			{
			  "id": 3,
			  "title": "Another Public key",
			  "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			  "created_at": "2013-10-02T11:12:29Z"
			}
		  ]`)
	})

	deployKeys, _, err := client.DeployKeys.ListAllDeployKeys()
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned error: %v", err)
	}

	timeLayout := "2006-01-02T15:04:05Z07:00"
	createdAt, err := time.Parse(timeLayout, "2013-10-02T10:12:29Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	createdAt2, err := time.Parse(timeLayout, "2013-10-02T11:12:29Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	want := []*DeployKey{
		{
			ID:        1,
			Title:     "Public key",
			Key:       "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			CreatedAt: &createdAt,
		},
		{
			ID:        3,
			Title:     "Another Public key",
			Key:       "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			CreatedAt: &createdAt2,
		},
	}
	if !reflect.DeepEqual(want, deployKeys) {
		t.Errorf("DeployKeys.ListAllDeployKeys returned %+v, want %+v", deployKeys, want)
	}
}

func TestListProjectDeployKeys(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/5/deploy_keys", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprintf(w, `[
			{
			  "id": 1,
			  "title": "Public key",
			  "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			  "created_at": "2013-10-02T10:12:29Z",
			  "can_push": false
			},
			{
			  "id": 3,
			  "title": "Another Public key",
			  "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			  "created_at": "2013-10-02T11:12:29Z",
			  "can_push": false
			}
		  ]`)
	})

	deployKeys, _, err := client.DeployKeys.ListProjectDeployKeys(5, &ListProjectDeployKeysOptions{})
	if err != nil {
		t.Errorf("DeployKeys.ListProjectDeployKeys returned error: %v", err)
	}

	timeLayout := "2006-01-02T15:04:05Z07:00"
	createdAt, err := time.Parse(timeLayout, "2013-10-02T10:12:29Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	createdAt2, err := time.Parse(timeLayout, "2013-10-02T11:12:29Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	canPush := false

	want := []*DeployKey{
		{
			ID:        1,
			Title:     "Public key",
			Key:       "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			CreatedAt: &createdAt,
			CanPush:   &canPush,
		},
		{
			ID:        3,
			Title:     "Another Public key",
			Key:       "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			CreatedAt: &createdAt2,
			CanPush:   &canPush,
		},
	}
	if !reflect.DeepEqual(want, deployKeys) {
		t.Errorf("DeployKeys.ListProjectDeployKeys returned %+v, want %+v", deployKeys, want)
	}
}

func TestGetDeployKey(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/5/deploy_keys/11", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprintf(w, `{
			"id": 1,
			"title": "Public key",
			"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
			"created_at": "2013-10-02T10:12:29Z",
			"can_push": false
		  }`)
	})

	deployKey, _, err := client.DeployKeys.GetDeployKey(5, 11)
	if err != nil {
		t.Errorf("DeployKeys.GetDeployKey returned error: %v", err)
	}

	timeLayout := "2006-01-02T15:04:05Z07:00"
	createdAt, err := time.Parse(timeLayout, "2013-10-02T10:12:29Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	canPush := false

	want := &DeployKey{
		ID:        1,
		Title:     "Public key",
		Key:       "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
		CreatedAt: &createdAt,
		CanPush:   &canPush,
	}
	if !reflect.DeepEqual(want, deployKey) {
		t.Errorf("DeployKeys.GetDeployKey returned %+v, want %+v", deployKey, want)
	}
}

func TestAddDeployKey(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/5/deploy_keys", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodPost)
		fmt.Fprintf(w, `{
			"key" : "ssh-rsa AAAA...",
			"id" : 12,
			"title" : "My deploy key",
			"can_push": true,
			"created_at" : "2015-08-29T12:44:31.550Z"
		 }`)
	})

	key := "ssh-rsa AAAA..."
	title := "My deploy key"
	canPush := true
	opt := &AddDeployKeyOptions{
		Key:     &key,
		Title:   &title,
		CanPush: &canPush,
	}
	deployKey, _, err := client.DeployKeys.AddDeployKey(5, opt)
	if err != nil {
		t.Errorf("DeployKey.AddDeployKey returned error: %v", err)
	}

	timeLayout := "2006-01-02T15:04:05Z07:00"
	createdAt, err := time.Parse(timeLayout, "2015-08-29T12:44:31.550Z")
	if err != nil {
		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
	}

	want := &DeployKey{
		Title:     title,
		ID:        12,
		Key:       key,
		CanPush:   &canPush,
		CreatedAt: &createdAt,
	}
	if !reflect.DeepEqual(want, deployKey) {
		t.Errorf("DeployKeys.AddDeployKey returned %+v, want %+v", deployKey, want)
	}
}
<|endoftext|>


<commit_before>package lsc

func longestChain(words []string) int {
	return 0
}
<commit_msg>solve 1048 using hashmap and recursion with memorization<commit_after>package lsc

import "github.com/catorpilor/leetcode/utils"

func longestChain(words []string) int {
	return useGraph(words)
}

// useGraph time complexity O(N*L^2), space complexity O(N)
func useGraph(words []string) int {
	hset := make(map[string]int, len(words))
	g := make(map[int][]int, len(words))
	// O(N)
	for i := range words {
		hset[words[i]] = i
	}
	// O(N*L^2) build adjacency list
	for i, w := range words {
		for j := 0; j < len(w); j++ { // O(L)
			nw := w[:j] + w[j+1:] // O(L)
			if idx, exists := hset[nw]; exists {
				g[idx] = append(g[idx], i)
			}
		}
	}
	res := 0
	ans := make([]int, len(words))
	for i := range words {
		helper(g, i, ans)
		res = utils.Max(res, ans[i])
	}
	return res
}

// helper use memorization to calculate the longest chain from idx
func helper(g map[int][]int, idx int, ans []int) {
	if ans[idx] > 0 {
		return
	}
	ans[idx] = 1
	// loop through its connected pos
	for _, pos := range g[idx] {
		helper(g, pos, ans)
		ans[idx] = utils.Max(ans[idx], ans[pos]+1)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017-2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package gconv

import (
	"errors"
	"fmt"
	"reflect"
	"regexp"
	"strings"

	"github.com/gogf/gf/internal/structs"
	"github.com/gogf/gf/internal/utilstr"
)

var (
	// replaceCharReg is the regular expression object for replacing chars
	// in map keys and attribute names.
	replaceCharReg, _ = regexp.Compile(`[\-\.\_\s]+`)
)

// Struct maps the params key-value pairs to the corresponding struct object's properties.
// The third parameter <mapping> is unnecessary, indicating the mapping rules between the custom key name
// and the attribute name(case sensitive).
//
// Note:
// 1. The <params> can be any type of map/struct, usually a map.
// 2. The second parameter <pointer> should be a pointer to the struct object.
// 3. Only the public attributes of struct object can be mapped.
// 4. If <params> is a map, the key of the map <params> can be lowercase.
//    It will automatically convert the first letter of the key to uppercase
//    in mapping procedure to do the matching.
//    It ignores the map key, if it does not match.
func Struct(params interface{}, pointer interface{}, mapping ...map[string]string) error {
	if params == nil {
		return errors.New("params cannot be nil")
	}
	if pointer == nil {
		return errors.New("object pointer cannot be nil")
	}
	// paramsMap is the map[string]interface{} type variable for params.
	paramsMap := Map(params)
	if paramsMap == nil {
		return fmt.Errorf("invalid params: %v", params)
	}
	// Using reflect to do the converting,
	// it also supports type of reflect.Value for <pointer>(always in internal usage).
	elem, ok := pointer.(reflect.Value)
	if !ok {
		rv := reflect.ValueOf(pointer)
		if kind := rv.Kind(); kind != reflect.Ptr {
			return fmt.Errorf("object pointer should be type of: %v", kind)
		}
		// Using IsNil on reflect.Ptr variable is OK.
		if !rv.IsValid() || rv.IsNil() {
			return errors.New("object pointer cannot be nil")
		}
		elem = rv.Elem()
	}
	// It automatically creates struct object if necessary.
	// For example, if <pointer> is **User, then <elem> is *User, which is a pointer to User.
	if elem.Type().Kind() == reflect.Ptr && (!elem.IsValid() || elem.IsNil()) {
		e := reflect.New(elem.Type().Elem()).Elem()
		elem.Set(e.Addr())
		elem = e
	}
	// It only performs one converting to the same attribute.
	// doneMap is used to check repeated converting, its key is the attribute name of the struct.
	doneMap := make(map[string]struct{})
	// It first checks the passed mapping rules.
	if len(mapping) > 0 && len(mapping[0]) > 0 {
		for mapK, mapV := range mapping[0] {
			// mapV is the the attribute name of the struct.
			if v, ok := paramsMap[mapK]; ok {
				doneMap[mapV] = struct{}{}
				if err := bindVarToStructAttr(elem, mapV, v); err != nil {
					return err
				}
			}
		}
	}
	// It secondly checks the tags of attributes.
	tagMap := structs.TagMapName(pointer, structTagPriority, true)
	for tagK, tagV := range tagMap {
		// tagV is the the attribute name of the struct.
		if _, ok := doneMap[tagV]; ok {
			continue
		}
		if v, ok := paramsMap[tagK]; ok {
			doneMap[tagV] = struct{}{}
			if err := bindVarToStructAttr(elem, tagV, v); err != nil {
				return err
			}
		}
	}
	// It finally do the converting with default rules.
	// The key of the map is the attribute name of the struct,
	// and the value is its replaced name for later comparison to improve performance.
	attrMap := make(map[string]string)
	elemType := elem.Type()
	tempName := ""
	for i := 0; i < elem.NumField(); i++ {
		// Only do converting to public attributes.
		if !utilstr.IsLetterUpper(elemType.Field(i).Name[0]) {
			continue
		}
		tempName = elemType.Field(i).Name
		attrMap[tempName] = replaceCharReg.ReplaceAllString(tempName, "")
	}
	if len(attrMap) == 0 {
		return nil
	}
	var attrName, checkName string
	for mapK, mapV := range paramsMap {
		attrName = ""
		checkName = replaceCharReg.ReplaceAllString(mapK, "")
		// Loop to find the matched attribute name with or without
		// string cases and chars like '-'/'_'/'.'/' '.
		for attrK, attrV := range attrMap {
			// Eg:
			// UserName  eq user_name
			// User-Name eq username
			// username  eq userName
			// etc.
			if strings.EqualFold(checkName, attrV) {
				attrName = attrK
				break
			}
		}
		// If the attribute name is already checked converting, then skip it.
		if attrName != "" {
			if _, ok := doneMap[attrName]; ok {
				continue
			}
			if _, ok := tagMap[attrName]; ok {
				continue
			}
		}
		// No matching, give up this attribute converting.
		if attrName == "" {
			continue
		}
		// Mark it done.
		doneMap[attrName] = struct{}{}
		if err := bindVarToStructAttr(elem, attrName, mapV); err != nil {
			return err
		}
	}
	return nil
}

// StructDeep do Struct function recursively.
// See Struct.
func StructDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error {
	if err := Struct(params, pointer, mapping...); err != nil {
		return err
	} else {
		rv, ok := pointer.(reflect.Value)
		if !ok {
			rv = reflect.ValueOf(pointer)
		}
		kind := rv.Kind()
		for kind == reflect.Ptr {
			rv = rv.Elem()
			kind = rv.Kind()
		}
		switch kind {
		case reflect.Struct:
			rt := rv.Type()
			for i := 0; i < rv.NumField(); i++ {
				// Only do converting to public attributes.
				if !utilstr.IsLetterUpper(rt.Field(i).Name[0]) {
					continue
				}
				trv := rv.Field(i)
				switch trv.Kind() {
				case reflect.Struct:
					if err := StructDeep(params, trv, mapping...); err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}

// 将参数值绑定到对象指定名称的属性上
func bindVarToStructAttr(elem reflect.Value, name string, value interface{}) (err error) {
	structFieldValue := elem.FieldByName(name)
	// 键名与对象属性匹配检测，map中如果有struct不存在的属性，那么不做处理，直接return
	if !structFieldValue.IsValid() {
		return nil
	}
	// CanSet的属性必须为公开属性(首字母大写)
	if !structFieldValue.CanSet() {
		return nil
	}
	// 必须将value转换为struct属性的数据类型，这里必须用到gconv包
	defer func() {
		// 如果转换失败，那么可能是类型不匹配造成(例如属性包含自定义类型)，那么执行递归转换
		if recover() != nil {
			err = bindVarToReflectValue(structFieldValue, value)
		}
	}()
	structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String())))
	return nil
}

// 将参数值绑定到对象指定索引位置的属性上
func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) (err error) {
	structFieldValue := elem.FieldByIndex([]int{index})
	// 键名与对象属性匹配检测
	if !structFieldValue.IsValid() {
		return nil
	}
	// CanSet的属性必须为公开属性(首字母大写)
	if !structFieldValue.CanSet() {
		return nil
	}
	// 必须将value转换为struct属性的数据类型，这里必须用到gconv包
	defer func() {
		// 如果转换失败，那么可能是类型不匹配造成(例如属性包含自定义类型)，那么执行递归转换
		if recover() != nil {
			err = bindVarToReflectValue(structFieldValue, value)
		}
	}()
	structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String())))
	return nil
}

// 当默认的基本类型转换失败时，通过recover判断后执行反射类型转换(处理复杂类型)
func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}) error {
	switch structFieldValue.Kind() {
	// 属性为结构体
	case reflect.Struct:
		if err := Struct(value, structFieldValue); err != nil {
			structFieldValue.Set(reflect.ValueOf(value))
		}

	// 属性为数组类型
	case reflect.Slice, reflect.Array:
		a := reflect.Value{}
		v := reflect.ValueOf(value)
		if v.Kind() == reflect.Slice || v.Kind() == reflect.Array {
			if v.Len() > 0 {
				a = reflect.MakeSlice(structFieldValue.Type(), v.Len(), v.Len())
				t := a.Index(0).Type()
				for i := 0; i < v.Len(); i++ {
					if t.Kind() == reflect.Ptr {
						e := reflect.New(t.Elem()).Elem()
						if err := Struct(v.Index(i).Interface(), e); err != nil {
							e.Set(reflect.ValueOf(v.Index(i).Interface()))
						}
						a.Index(i).Set(e.Addr())
					} else {
						e := reflect.New(t).Elem()
						if err := Struct(v.Index(i).Interface(), e); err != nil {
							e.Set(reflect.ValueOf(v.Index(i).Interface()))
						}
						a.Index(i).Set(e)
					}
				}
			} else {
				a = reflect.MakeSlice(structFieldValue.Type(), v.Len(), v.Len())
			}
		} else {
			a = reflect.MakeSlice(structFieldValue.Type(), 1, 1)
			t := a.Index(0).Type()
			if t.Kind() == reflect.Ptr {
				e := reflect.New(t.Elem()).Elem()
				if err := Struct(value, e); err != nil {
					e.Set(reflect.ValueOf(value))
				}
				a.Index(0).Set(e.Addr())
			} else {
				e := reflect.New(t).Elem()
				if err := Struct(value, e); err != nil {
					e.Set(reflect.ValueOf(value))
				}
				a.Index(0).Set(e)
			}
		}
		structFieldValue.Set(a)

	// 属性为指针类型
	case reflect.Ptr:
		e := reflect.New(structFieldValue.Type().Elem()).Elem()
		if err := Struct(value, e); err != nil {
			e.Set(reflect.ValueOf(value))
		}
		structFieldValue.Set(e.Addr())

	case reflect.Interface:
		if value == nil {
			structFieldValue.Set(reflect.ValueOf((*interface{})(nil)))
		} else {
			structFieldValue.Set(reflect.ValueOf(value))
		}

	default:
		return errors.New(
			fmt.Sprintf(`cannot convert to type "%s"`,
				structFieldValue.Type().String(),
			),
		)
	}
	return nil
}
<commit_msg>fix issue in empty slice converting panic for gconv.Struct<commit_after>// Copyright 2017-2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package gconv

import (
	"errors"
	"fmt"
	"reflect"
	"regexp"
	"strings"

	"github.com/gogf/gf/internal/structs"
	"github.com/gogf/gf/internal/utilstr"
)

var (
	// replaceCharReg is the regular expression object for replacing chars
	// in map keys and attribute names.
	replaceCharReg, _ = regexp.Compile(`[\-\.\_\s]+`)
)

// Struct maps the params key-value pairs to the corresponding struct object's properties.
// The third parameter <mapping> is unnecessary, indicating the mapping rules between the custom key name
// and the attribute name(case sensitive).
//
// Note:
// 1. The <params> can be any type of map/struct, usually a map.
// 2. The second parameter <pointer> should be a pointer to the struct object.
// 3. Only the public attributes of struct object can be mapped.
// 4. If <params> is a map, the key of the map <params> can be lowercase.
//    It will automatically convert the first letter of the key to uppercase
//    in mapping procedure to do the matching.
//    It ignores the map key, if it does not match.
func Struct(params interface{}, pointer interface{}, mapping ...map[string]string) error {
	if params == nil {
		return errors.New("params cannot be nil")
	}
	if pointer == nil {
		return errors.New("object pointer cannot be nil")
	}
	// paramsMap is the map[string]interface{} type variable for params.
	paramsMap := Map(params)
	if paramsMap == nil {
		return fmt.Errorf("invalid params: %v", params)
	}
	// Using reflect to do the converting,
	// it also supports type of reflect.Value for <pointer>(always in internal usage).
	elem, ok := pointer.(reflect.Value)
	if !ok {
		rv := reflect.ValueOf(pointer)
		if kind := rv.Kind(); kind != reflect.Ptr {
			return fmt.Errorf("object pointer should be type of: %v", kind)
		}
		// Using IsNil on reflect.Ptr variable is OK.
		if !rv.IsValid() || rv.IsNil() {
			return errors.New("object pointer cannot be nil")
		}
		elem = rv.Elem()
	}
	// It automatically creates struct object if necessary.
	// For example, if <pointer> is **User, then <elem> is *User, which is a pointer to User.
	if elem.Type().Kind() == reflect.Ptr && (!elem.IsValid() || elem.IsNil()) {
		e := reflect.New(elem.Type().Elem()).Elem()
		elem.Set(e.Addr())
		elem = e
	}
	// It only performs one converting to the same attribute.
	// doneMap is used to check repeated converting, its key is the attribute name of the struct.
	doneMap := make(map[string]struct{})
	// It first checks the passed mapping rules.
	if len(mapping) > 0 && len(mapping[0]) > 0 {
		for mapK, mapV := range mapping[0] {
			// mapV is the the attribute name of the struct.
			if v, ok := paramsMap[mapK]; ok {
				doneMap[mapV] = struct{}{}
				if err := bindVarToStructAttr(elem, mapV, v); err != nil {
					return err
				}
			}
		}
	}
	// It secondly checks the tags of attributes.
	tagMap := structs.TagMapName(pointer, structTagPriority, true)
	for tagK, tagV := range tagMap {
		// tagV is the the attribute name of the struct.
		if _, ok := doneMap[tagV]; ok {
			continue
		}
		if v, ok := paramsMap[tagK]; ok {
			doneMap[tagV] = struct{}{}
			if err := bindVarToStructAttr(elem, tagV, v); err != nil {
				return err
			}
		}
	}
	// It finally do the converting with default rules.
	// The key of the map is the attribute name of the struct,
	// and the value is its replaced name for later comparison to improve performance.
	attrMap := make(map[string]string)
	elemType := elem.Type()
	tempName := ""
	for i := 0; i < elem.NumField(); i++ {
		// Only do converting to public attributes.
		if !utilstr.IsLetterUpper(elemType.Field(i).Name[0]) {
			continue
		}
		tempName = elemType.Field(i).Name
		attrMap[tempName] = replaceCharReg.ReplaceAllString(tempName, "")
	}
	if len(attrMap) == 0 {
		return nil
	}
	var attrName, checkName string
	for mapK, mapV := range paramsMap {
		attrName = ""
		checkName = replaceCharReg.ReplaceAllString(mapK, "")
		// Loop to find the matched attribute name with or without
		// string cases and chars like '-'/'_'/'.'/' '.
		for attrK, attrV := range attrMap {
			// Eg:
			// UserName  eq user_name
			// User-Name eq username
			// username  eq userName
			// etc.
			if strings.EqualFold(checkName, attrV) {
				attrName = attrK
				break
			}
		}
		// If the attribute name is already checked converting, then skip it.
		if attrName != "" {
			if _, ok := doneMap[attrName]; ok {
				continue
			}
			if _, ok := tagMap[attrName]; ok {
				continue
			}
		}
		// No matching, give up this attribute converting.
		if attrName == "" {
			continue
		}
		// Mark it done.
		doneMap[attrName] = struct{}{}
		if err := bindVarToStructAttr(elem, attrName, mapV); err != nil {
			return err
		}
	}
	return nil
}

// StructDeep do Struct function recursively.
// See Struct.
func StructDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error {
	if err := Struct(params, pointer, mapping...); err != nil {
		return err
	} else {
		rv, ok := pointer.(reflect.Value)
		if !ok {
			rv = reflect.ValueOf(pointer)
		}
		kind := rv.Kind()
		for kind == reflect.Ptr {
			rv = rv.Elem()
			kind = rv.Kind()
		}
		switch kind {
		case reflect.Struct:
			rt := rv.Type()
			for i := 0; i < rv.NumField(); i++ {
				// Only do converting to public attributes.
				if !utilstr.IsLetterUpper(rt.Field(i).Name[0]) {
					continue
				}
				trv := rv.Field(i)
				switch trv.Kind() {
				case reflect.Struct:
					if err := StructDeep(params, trv, mapping...); err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}

// 将参数值绑定到对象指定名称的属性上
func bindVarToStructAttr(elem reflect.Value, name string, value interface{}) (err error) {
	structFieldValue := elem.FieldByName(name)
	// 键名与对象属性匹配检测，map中如果有struct不存在的属性，那么不做处理，直接return
	if !structFieldValue.IsValid() {
		return nil
	}
	// CanSet的属性必须为公开属性(首字母大写)
	if !structFieldValue.CanSet() {
		return nil
	}
	// 必须将value转换为struct属性的数据类型，这里必须用到gconv包
	defer func() {
		// 如果转换失败，那么可能是类型不匹配造成(例如属性包含自定义类型)，那么执行递归转换
		if recover() != nil {
			err = bindVarToReflectValue(structFieldValue, value)
		}
	}()
	structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String())))
	return nil
}

// 将参数值绑定到对象指定索引位置的属性上
func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) (err error) {
	structFieldValue := elem.FieldByIndex([]int{index})
	// 键名与对象属性匹配检测
	if !structFieldValue.IsValid() {
		return nil
	}
	// CanSet的属性必须为公开属性(首字母大写)
	if !structFieldValue.CanSet() {
		return nil
	}
	// 必须将value转换为struct属性的数据类型，这里必须用到gconv包
	defer func() {
		// 如果转换失败，那么可能是类型不匹配造成(例如属性包含自定义类型)，那么执行递归转换
		if recover() != nil {
			err = bindVarToReflectValue(structFieldValue, value)
		}
	}()
	structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String())))
	return nil
}

// 当默认的基本类型转换失败时，通过recover判断后执行反射类型转换(处理复杂类型)
func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}) error {
	switch structFieldValue.Kind() {
	// 属性为结构体
	case reflect.Struct:
		if err := Struct(value, structFieldValue); err != nil {
			structFieldValue.Set(reflect.ValueOf(value))
		}

	// 属性为数组类型
	case reflect.Slice, reflect.Array:
		a := reflect.Value{}
		v := reflect.ValueOf(value)
		if v.Kind() == reflect.Slice || v.Kind() == reflect.Array {
			a = reflect.MakeSlice(structFieldValue.Type(), v.Len(), v.Len())
			if v.Len() > 0 {
				t := a.Index(0).Type()
				for i := 0; i < v.Len(); i++ {
					if t.Kind() == reflect.Ptr {
						e := reflect.New(t.Elem()).Elem()
						if err := Struct(v.Index(i).Interface(), e); err != nil {
							e.Set(reflect.ValueOf(v.Index(i).Interface()))
						}
						a.Index(i).Set(e.Addr())
					} else {
						e := reflect.New(t).Elem()
						if err := Struct(v.Index(i).Interface(), e); err != nil {
							e.Set(reflect.ValueOf(v.Index(i).Interface()))
						}
						a.Index(i).Set(e)
					}
				}
			}
		} else {
			a = reflect.MakeSlice(structFieldValue.Type(), 1, 1)
			t := a.Index(0).Type()
			if t.Kind() == reflect.Ptr {
				e := reflect.New(t.Elem()).Elem()
				if err := Struct(value, e); err != nil {
					e.Set(reflect.ValueOf(value))
				}
				a.Index(0).Set(e.Addr())
			} else {
				e := reflect.New(t).Elem()
				if err := Struct(value, e); err != nil {
					e.Set(reflect.ValueOf(value))
				}
				a.Index(0).Set(e)
			}
		}
		structFieldValue.Set(a)

	// 属性为指针类型
	case reflect.Ptr:
		e := reflect.New(structFieldValue.Type().Elem()).Elem()
		if err := Struct(value, e); err != nil {
			e.Set(reflect.ValueOf(value))
		}
		structFieldValue.Set(e.Addr())

	case reflect.Interface:
		if value == nil {
			structFieldValue.Set(reflect.ValueOf((*interface{})(nil)))
		} else {
			structFieldValue.Set(reflect.ValueOf(value))
		}

	default:
		return errors.New(
			fmt.Sprintf(`cannot convert to type "%s"`,
				structFieldValue.Type().String(),
			),
		)
	}
	return nil
}
<|endoftext|>


<commit_before>package validate

import (
	"math"
	"net/url"
	"reflect"
	"strconv"
	"testing"

	"github.com/casualjim/go-swagger"
	"github.com/casualjim/go-swagger/errors"
	"github.com/casualjim/go-swagger/spec"
	"github.com/casualjim/go-swagger/strfmt"
	"github.com/stretchr/testify/assert"
)

type email struct {
	Address string
}

type paramFactory func(string) *spec.Parameter

var paramFactories = []paramFactory{
	spec.QueryParam,
	spec.HeaderParam,
	spec.PathParam,
	spec.FormDataParam,
}

func np(param *spec.Parameter) *paramBinder {
	return newParamBinder(*param, new(spec.Swagger), strfmt.Default)
}

var stringItems = new(spec.Items)

func init() {
	stringItems.Type = "string"
}

func testCollectionFormat(t *testing.T, param *spec.Parameter, valid bool) {
	binder := &paramBinder{
		parameter: param,
	}
	_, _, err := binder.readValue(url.Values(nil), reflect.ValueOf(nil))
	if valid {
		assert.NoError(t, err)
	} else {
		assert.Error(t, err)
		assert.Equal(t, errors.InvalidCollectionFormat(param.Name, param.In, param.CollectionFormat), err)
	}
}

func requiredError(param *spec.Parameter) *errors.Validation {
	return errors.Required(param.Name, param.In)
}

func validateRequiredTest(t *testing.T, param *spec.Parameter, value reflect.Value) {
	binder := np(param)
	err := binder.bindValue([]string{}, value)
	assert.Error(t, err)
	assert.EqualError(t, requiredError(param), err.Error())
	err = binder.bindValue([]string{""}, value)
	assert.Error(t, err)
	assert.EqualError(t, requiredError(param), err.Error())
}

func TestRequiredValidation(t *testing.T) {
	strParam := spec.QueryParam("name").Typed("string", "").AsRequired()
	validateRequiredTest(t, strParam, reflect.ValueOf(""))

	intParam := spec.QueryParam("id").Typed("integer", "int32").AsRequired()
	validateRequiredTest(t, intParam, reflect.ValueOf(int32(0)))
	longParam := spec.QueryParam("id").Typed("integer", "int64").AsRequired()
	validateRequiredTest(t, longParam, reflect.ValueOf(int64(0)))

	floatParam := spec.QueryParam("score").Typed("number", "float").AsRequired()
	validateRequiredTest(t, floatParam, reflect.ValueOf(float32(0)))
	doubleParam := spec.QueryParam("score").Typed("number", "double").AsRequired()
	validateRequiredTest(t, doubleParam, reflect.ValueOf(float64(0)))

	dateTimeParam := spec.QueryParam("registered").Typed("string", "date-time").AsRequired()
	validateRequiredTest(t, dateTimeParam, reflect.ValueOf(swagger.DateTime{}))
	dateParam := spec.QueryParam("registered").Typed("string", "date").AsRequired()
	validateRequiredTest(t, dateParam, reflect.ValueOf(swagger.DateTime{}))

	sliceParam := spec.QueryParam("tags").CollectionOf(stringItems, "").AsRequired()
	validateRequiredTest(t, sliceParam, reflect.ValueOf([]string{}))
}

func TestInvalidCollectionFormat(t *testing.T) {
	validCf1 := spec.QueryParam("validFmt").CollectionOf(stringItems, "multi")
	validCf2 := spec.FormDataParam("validFmt2").CollectionOf(stringItems, "multi")
	invalidCf1 := spec.HeaderParam("invalidHdr").CollectionOf(stringItems, "multi")
	invalidCf2 := spec.PathParam("invalidPath").CollectionOf(stringItems, "multi")

	testCollectionFormat(t, validCf1, true)
	testCollectionFormat(t, validCf2, true)
	testCollectionFormat(t, invalidCf1, false)
	testCollectionFormat(t, invalidCf2, false)
}

func invalidTypeError(param *spec.Parameter, data interface{}) *errors.Validation {
	tpe := param.Type
	if param.Format != "" {
		tpe = param.Format
	}
	return errors.InvalidType(param.Name, param.In, tpe, data)
}

func TestTypeValidation(t *testing.T) {
	for _, newParam := range paramFactories {
		intParam := newParam("badInt").Typed("integer", "int32")
		value := reflect.ValueOf(int32(0))
		binder := np(intParam)
		err := binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(intParam, "yada"), err)
		// fails for overflow
		val := int64(math.MaxInt32)
		str := strconv.FormatInt(val, 10) + "0"
		v := int32(0)
		value = reflect.ValueOf(&v).Elem()
		binder = np(intParam)
		err = binder.bindValue([]string{str}, value)
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(intParam, str), err)

		longParam := newParam("badLong").Typed("integer", "int64")
		value = reflect.ValueOf(int64(0))
		binder = np(longParam)
		err = binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(longParam, "yada"), err)
		// fails for overflow
		str2 := strconv.FormatInt(math.MaxInt64, 10) + "0"
		v2 := int64(0)
		vv2 := reflect.ValueOf(&v2).Elem()
		binder = np(longParam)
		err = binder.bindValue([]string{str2}, vv2)
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(longParam, str2), err)

		floatParam := newParam("badFloat").Typed("number", "float")
		value = reflect.ValueOf(float64(0))
		binder = np(floatParam)
		err = binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(floatParam, "yada"), err)
		// fails for overflow
		str3 := strconv.FormatFloat(math.MaxFloat64, 'f', 5, 64)
		v3 := reflect.TypeOf(float32(0))
		value = reflect.New(v3).Elem()
		binder = np(floatParam)
		err = binder.bindValue([]string{str3}, value)
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(floatParam, str3), err)

		doubleParam := newParam("badDouble").Typed("number", "double")
		value = reflect.ValueOf(float64(0))
		binder = np(doubleParam)
		err = binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(doubleParam, "yada"), err)
		// fails for overflow
		str4 := "9" + strconv.FormatFloat(math.MaxFloat64, 'f', 5, 64)
		v4 := reflect.TypeOf(float64(0))
		value = reflect.New(v4).Elem()
		binder = np(doubleParam)
		err = binder.bindValue([]string{str4}, value)
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(doubleParam, str4), err)

		dateParam := newParam("badDate").Typed("string", "date")
		value = reflect.ValueOf(swagger.Date{})
		binder = np(dateParam)
		err = binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(dateParam, "yada"), err)

		dateTimeParam := newParam("badDateTime").Typed("string", "date-time")
		value = reflect.ValueOf(swagger.DateTime{})
		binder = np(dateTimeParam)
		err = binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(dateTimeParam, "yada"), err)

		byteParam := newParam("badByte").Typed("string", "byte")
		values := url.Values(map[string][]string{})
		values.Add("badByte", "yaüda")
		v5 := []byte{}
		value = reflect.ValueOf(&v5).Elem()
		binder = np(byteParam)
		err = binder.bindValue([]string{"yaüda"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(byteParam, "yaüda"), err)
	}
}

func TestTypeDetectionInvalidItems(t *testing.T) {
	withoutItems := spec.QueryParam("without").CollectionOf(nil, "")
	binder := &paramBinder{
		name:      "without",
		parameter: withoutItems,
	}
	assert.Nil(t, binder.Type())

	items := new(spec.Items)
	items.Type = "array"
	withInvalidItems := spec.QueryParam("invalidItems").CollectionOf(items, "")
	binder = &paramBinder{
		name:      "invalidItems",
		parameter: withInvalidItems,
	}
	assert.Nil(t, binder.Type())

	noType := spec.QueryParam("invalidType")
	noType.Type = "invalid"
	binder = &paramBinder{
		name:      "invalidType",
		parameter: noType,
	}
	assert.Nil(t, binder.Type())
}

// type emailStrFmt struct {
// 	name      string
// 	tpe       reflect.Type
// 	validator FormatValidator
// }
//
// func (e *emailStrFmt) Name() string {
// 	return e.name
// }
//
// func (e *emailStrFmt) Type() reflect.Type {
// 	return e.tpe
// }
//
// func (e *emailStrFmt) Matches(str string) bool {
// 	return e.validator(str)
// }
//
// func TestTypeDetectionValid(t *testing.T) {
// 	// emlFmt := &emailStrFmt{
// 	// 	name: "email",
// 	// 	tpe:  reflect.TypeOf(email{}),
// 	// }
// 	// formats := []StringFormat{emlFmt}
//
// 	expected := map[string]reflect.Type{
// 		"name":         reflect.TypeOf(""),
// 		"id":           reflect.TypeOf(int64(0)),
// 		"age":          reflect.TypeOf(int32(0)),
// 		"score":        reflect.TypeOf(float32(0)),
// 		"factor":       reflect.TypeOf(float64(0)),
// 		"friend":       reflect.TypeOf(map[string]interface{}{}),
// 		"X-Request-Id": reflect.TypeOf(int64(0)),
// 		"tags":         reflect.TypeOf([]string{}),
// 		"confirmed":    reflect.TypeOf(true),
// 		"planned":      reflect.TypeOf(swagger.Date{}),
// 		"delivered":    reflect.TypeOf(swagger.DateTime{}),
// 		"email":        reflect.TypeOf(email{}),
// 		"picture":      reflect.TypeOf([]byte{}),
// 		"file":         reflect.TypeOf(&swagger.File{}).Elem(),
// 	}
//
// 	params := parametersForAllTypes("")
// 	emailParam := spec.QueryParam("email").Typed("string", "email")
// 	params["email"] = *emailParam
//
// 	fileParam := spec.FileParam("file")
// 	params["file"] = *fileParam
//
// 	for _, v := range params {
// 		binder := &paramBinder{
// 			formats:   formats,
// 			name:      v.Name,
// 			parameter: &v,
// 		}
// 		assert.Equal(t, expected[v.Name], binder.Type(), "name: %s", v.Name)
// 	}
// }
<commit_msg>fix remaining missing types<commit_after>package validate

import (
	"math"
	"net/url"
	"reflect"
	"strconv"
	"testing"

	"github.com/casualjim/go-swagger/errors"
	"github.com/casualjim/go-swagger/spec"
	"github.com/casualjim/go-swagger/strfmt"
	"github.com/stretchr/testify/assert"
)

type email struct {
	Address string
}

type paramFactory func(string) *spec.Parameter

var paramFactories = []paramFactory{
	spec.QueryParam,
	spec.HeaderParam,
	spec.PathParam,
	spec.FormDataParam,
}

func np(param *spec.Parameter) *paramBinder {
	return newParamBinder(*param, new(spec.Swagger), strfmt.Default)
}

var stringItems = new(spec.Items)

func init() {
	stringItems.Type = "string"
}

func testCollectionFormat(t *testing.T, param *spec.Parameter, valid bool) {
	binder := &paramBinder{
		parameter: param,
	}
	_, _, err := binder.readValue(url.Values(nil), reflect.ValueOf(nil))
	if valid {
		assert.NoError(t, err)
	} else {
		assert.Error(t, err)
		assert.Equal(t, errors.InvalidCollectionFormat(param.Name, param.In, param.CollectionFormat), err)
	}
}

func requiredError(param *spec.Parameter) *errors.Validation {
	return errors.Required(param.Name, param.In)
}

func validateRequiredTest(t *testing.T, param *spec.Parameter, value reflect.Value) {
	binder := np(param)
	err := binder.bindValue([]string{}, value)
	assert.Error(t, err)
	assert.EqualError(t, requiredError(param), err.Error())
	err = binder.bindValue([]string{""}, value)
	assert.Error(t, err)
	assert.EqualError(t, requiredError(param), err.Error())
}

func TestRequiredValidation(t *testing.T) {
	strParam := spec.QueryParam("name").Typed("string", "").AsRequired()
	validateRequiredTest(t, strParam, reflect.ValueOf(""))

	intParam := spec.QueryParam("id").Typed("integer", "int32").AsRequired()
	validateRequiredTest(t, intParam, reflect.ValueOf(int32(0)))
	longParam := spec.QueryParam("id").Typed("integer", "int64").AsRequired()
	validateRequiredTest(t, longParam, reflect.ValueOf(int64(0)))

	floatParam := spec.QueryParam("score").Typed("number", "float").AsRequired()
	validateRequiredTest(t, floatParam, reflect.ValueOf(float32(0)))
	doubleParam := spec.QueryParam("score").Typed("number", "double").AsRequired()
	validateRequiredTest(t, doubleParam, reflect.ValueOf(float64(0)))

	dateTimeParam := spec.QueryParam("registered").Typed("string", "date-time").AsRequired()
	validateRequiredTest(t, dateTimeParam, reflect.ValueOf(strfmt.DateTime{}))

	dateParam := spec.QueryParam("registered").Typed("string", "date").AsRequired()
	validateRequiredTest(t, dateParam, reflect.ValueOf(strfmt.DateTime{}))

	sliceParam := spec.QueryParam("tags").CollectionOf(stringItems, "").AsRequired()
	validateRequiredTest(t, sliceParam, reflect.ValueOf([]string{}))
}

func TestInvalidCollectionFormat(t *testing.T) {
	validCf1 := spec.QueryParam("validFmt").CollectionOf(stringItems, "multi")
	validCf2 := spec.FormDataParam("validFmt2").CollectionOf(stringItems, "multi")
	invalidCf1 := spec.HeaderParam("invalidHdr").CollectionOf(stringItems, "multi")
	invalidCf2 := spec.PathParam("invalidPath").CollectionOf(stringItems, "multi")

	testCollectionFormat(t, validCf1, true)
	testCollectionFormat(t, validCf2, true)
	testCollectionFormat(t, invalidCf1, false)
	testCollectionFormat(t, invalidCf2, false)
}

func invalidTypeError(param *spec.Parameter, data interface{}) *errors.Validation {
	tpe := param.Type
	if param.Format != "" {
		tpe = param.Format
	}
	return errors.InvalidType(param.Name, param.In, tpe, data)
}

func TestTypeValidation(t *testing.T) {
	for _, newParam := range paramFactories {
		intParam := newParam("badInt").Typed("integer", "int32")
		value := reflect.ValueOf(int32(0))
		binder := np(intParam)
		err := binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(intParam, "yada"), err)
		// fails for overflow
		val := int64(math.MaxInt32)
		str := strconv.FormatInt(val, 10) + "0"
		v := int32(0)
		value = reflect.ValueOf(&v).Elem()
		binder = np(intParam)
		err = binder.bindValue([]string{str}, value)
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(intParam, str), err)

		longParam := newParam("badLong").Typed("integer", "int64")
		value = reflect.ValueOf(int64(0))
		binder = np(longParam)
		err = binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(longParam, "yada"), err)
		// fails for overflow
		str2 := strconv.FormatInt(math.MaxInt64, 10) + "0"
		v2 := int64(0)
		vv2 := reflect.ValueOf(&v2).Elem()
		binder = np(longParam)
		err = binder.bindValue([]string{str2}, vv2)
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(longParam, str2), err)

		floatParam := newParam("badFloat").Typed("number", "float")
		value = reflect.ValueOf(float64(0))
		binder = np(floatParam)
		err = binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(floatParam, "yada"), err)
		// fails for overflow
		str3 := strconv.FormatFloat(math.MaxFloat64, 'f', 5, 64)
		v3 := reflect.TypeOf(float32(0))
		value = reflect.New(v3).Elem()
		binder = np(floatParam)
		err = binder.bindValue([]string{str3}, value)
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(floatParam, str3), err)

		doubleParam := newParam("badDouble").Typed("number", "double")
		value = reflect.ValueOf(float64(0))
		binder = np(doubleParam)
		err = binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(doubleParam, "yada"), err)
		// fails for overflow
		str4 := "9" + strconv.FormatFloat(math.MaxFloat64, 'f', 5, 64)
		v4 := reflect.TypeOf(float64(0))
		value = reflect.New(v4).Elem()
		binder = np(doubleParam)
		err = binder.bindValue([]string{str4}, value)
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(doubleParam, str4), err)

		dateParam := newParam("badDate").Typed("string", "date")
		value = reflect.ValueOf(strfmt.Date{})
		binder = np(dateParam)
		err = binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(dateParam, "yada"), err)

		dateTimeParam := newParam("badDateTime").Typed("string", "date-time")
		value = reflect.ValueOf(strfmt.DateTime{})
		binder = np(dateTimeParam)
		err = binder.bindValue([]string{"yada"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(dateTimeParam, "yada"), err)

		byteParam := newParam("badByte").Typed("string", "byte")
		values := url.Values(map[string][]string{})
		values.Add("badByte", "yaüda")
		v5 := []byte{}
		value = reflect.ValueOf(&v5).Elem()
		binder = np(byteParam)
		err = binder.bindValue([]string{"yaüda"}, value)
		// fails for invalid string
		assert.Error(t, err)
		assert.Equal(t, invalidTypeError(byteParam, "yaüda"), err)
	}
}

func TestTypeDetectionInvalidItems(t *testing.T) {
	withoutItems := spec.QueryParam("without").CollectionOf(nil, "")
	binder := &paramBinder{
		name:      "without",
		parameter: withoutItems,
	}
	assert.Nil(t, binder.Type())

	items := new(spec.Items)
	items.Type = "array"
	withInvalidItems := spec.QueryParam("invalidItems").CollectionOf(items, "")
	binder = &paramBinder{
		name:      "invalidItems",
		parameter: withInvalidItems,
	}
	assert.Nil(t, binder.Type())

	noType := spec.QueryParam("invalidType")
	noType.Type = "invalid"
	binder = &paramBinder{
		name:      "invalidType",
		parameter: noType,
	}
	assert.Nil(t, binder.Type())
}

// type emailStrFmt struct {
// 	name      string
// 	tpe       reflect.Type
// 	validator FormatValidator
// }
//
// func (e *emailStrFmt) Name() string {
// 	return e.name
// }
//
// func (e *emailStrFmt) Type() reflect.Type {
// 	return e.tpe
// }
//
// func (e *emailStrFmt) Matches(str string) bool {
// 	return e.validator(str)
// }
//
// func TestTypeDetectionValid(t *testing.T) {
// 	// emlFmt := &emailStrFmt{
// 	// 	name: "email",
// 	// 	tpe:  reflect.TypeOf(email{}),
// 	// }
// 	// formats := []StringFormat{emlFmt}
//
// 	expected := map[string]reflect.Type{
// 		"name":         reflect.TypeOf(""),
// 		"id":           reflect.TypeOf(int64(0)),
// 		"age":          reflect.TypeOf(int32(0)),
// 		"score":        reflect.TypeOf(float32(0)),
// 		"factor":       reflect.TypeOf(float64(0)),
// 		"friend":       reflect.TypeOf(map[string]interface{}{}),
// 		"X-Request-Id": reflect.TypeOf(int64(0)),
// 		"tags":         reflect.TypeOf([]string{}),
// 		"confirmed":    reflect.TypeOf(true),
// 		"planned":      reflect.TypeOf(swagger.Date{}),
// 		"delivered":    reflect.TypeOf(swagger.DateTime{}),
// 		"email":        reflect.TypeOf(email{}),
// 		"picture":      reflect.TypeOf([]byte{}),
// 		"file":         reflect.TypeOf(&swagger.File{}).Elem(),
// 	}
//
// 	params := parametersForAllTypes("")
// 	emailParam := spec.QueryParam("email").Typed("string", "email")
// 	params["email"] = *emailParam
//
// 	fileParam := spec.FileParam("file")
// 	params["file"] = *fileParam
//
// 	for _, v := range params {
// 		binder := &paramBinder{
// 			formats:   formats,
// 			name:      v.Name,
// 			parameter: &v,
// 		}
// 		assert.Equal(t, expected[v.Name], binder.Type(), "name: %s", v.Name)
// 	}
// }
<|endoftext|>


<commit_before>package controller

import (
	"math"
	"strconv"
	"strings"

	"github.com/tidwall/tile38/controller/glob"
	"github.com/tidwall/tile38/controller/server"
	"github.com/tidwall/tile38/geojson"
)

var tmfmt = "2006-01-02T15:04:05.999999999Z07:00"

// FenceMatch executes a fence match returns back json messages for fence detection.
func FenceMatch(hookName string, sw *scanWriter, fence *liveFenceSwitches, details *commandDetailsT) []string {
	jshookName := jsonString(hookName)
	jstime := jsonString(details.timestamp.Format(tmfmt))
	pattern := fence.glob
	if details.command == "drop" {
		return []string{`{"cmd":"drop","hook":` + jshookName + `,"time":` + jstime + `}`}
	}
	match := true
	if pattern != "" && pattern != "*" {
		match, _ = glob.Match(pattern, details.id)
	}
	if !match {
		return nil
	}

	sw.mu.Lock()
	nofields := sw.nofields
	sw.mu.Unlock()

	if details.obj == nil || !details.obj.IsGeometry() || (details.command == "fset" && nofields) {
		return nil
	}
	match = false

	var roamkeys, roamids []string
	var roammeters []float64
	detect := "outside"
	if fence != nil {
		if fence.roam.on {
			if details.command == "set" {
				// println("roam", fence.roam.key, fence.roam.id, strconv.FormatFloat(fence.roam.meters, 'f', -1, 64))
				roamkeys, roamids, roammeters = fenceMatchRoam(sw.c, fence, details.key, details.id, details.obj)
			}
			if len(roamids) == 0 || len(roamids) != len(roamkeys) {
				return nil
			}
			match = true
			detect = "roam"
		} else {

			// not using roaming
			match1 := fenceMatchObject(fence, details.oldObj)
			match2 := fenceMatchObject(fence, details.obj)
			if match1 && match2 {
				match = true
				detect = "inside"
			} else if match1 && !match2 {
				match = true
				detect = "exit"
			} else if !match1 && match2 {
				match = true
				detect = "enter"
				if details.command == "fset" {
					detect = "inside"
				}
			} else {
				if details.command != "fset" {
					// Maybe the old object and new object create a line that crosses the fence.
					// Must detect for that possibility.
					if details.oldObj != nil {
						ls := geojson.LineString{
							Coordinates: []geojson.Position{
								details.oldObj.CalculatedPoint(),
								details.obj.CalculatedPoint(),
							},
						}
						temp := false
						if fence.cmd == "within" {
							// because we are testing if the line croses the area we need to use
							// "intersects" instead of "within".
							fence.cmd = "intersects"
							temp = true
						}
						if fenceMatchObject(fence, ls) {
							//match = true
							detect = "cross"
						}
						if temp {
							fence.cmd = "within"
						}
					}
				}
			}
		}
	}
	if details.command == "del" {
		return []string{`{"command":"del","hook":` + jshookName + `,"id":` + jsonString(details.id) + `,"time":` + jstime + `}`}
	}
	if details.fmap == nil {
		return nil
	}
	sw.mu.Lock()
	sw.fmap = details.fmap
	sw.fullFields = true
	sw.msg.OutputType = server.JSON
	sw.writeObject(details.id, details.obj, details.fields, true)
	if sw.wr.Len() == 0 {
		sw.mu.Unlock()
		return nil
	}

	res := sw.wr.String()
	resb := make([]byte, len(res))
	copy(resb, res)
	sw.wr.Reset()
	res = string(resb)
	if strings.HasPrefix(res, ",") {
		res = res[1:]
	}
	if sw.output == outputIDs {
		res = `{"id":` + res + `}`
	}
	sw.mu.Unlock()

	jskey := jsonString(details.key)

	ores := res
	msgs := make([]string, 0, 2)
	if fence.detect == nil || fence.detect[detect] {
		if strings.HasPrefix(ores, "{") {
			res = `{"command":"` + details.command + `","detect":"` + detect + `","hook":` + jshookName + `,"key":` + jskey + `,"time":` + jstime + `,` + ores[1:]
		}
		msgs = append(msgs, res)
	}
	switch detect {
	case "enter":
		if fence.detect == nil || fence.detect["inside"] {
			msgs = append(msgs, `{"command":"`+details.command+`","detect":"inside","hook":`+jshookName+`,"key":`+jskey+`,"time":`+jstime+`,`+ores[1:])
		}
	case "exit", "cross":
		if fence.detect == nil || fence.detect["outside"] {
			msgs = append(msgs, `{"command":"`+details.command+`","detect":"outside","hook":`+jshookName+`,"key":`+jskey+`,"time":`+jstime+`,`+ores[1:])
		}
	case "roam":
		if len(msgs) > 0 {
			var nmsgs []string
			msg := msgs[0][:len(msgs[0])-1]
			for i, id := range roamids {
				nmsgs = append(nmsgs, msg+`,"nearby":{"key":`+jsonString(roamkeys[i])+`,"id":`+jsonString(id)+`,"meters":`+strconv.FormatFloat(roammeters[i], 'f', -1, 64)+`}}`)
			}
			msgs = nmsgs
		}
	}
	return msgs
}

func fenceMatchObject(fence *liveFenceSwitches, obj geojson.Object) bool {
	if obj == nil {
		return false
	}
	if fence.roam.on {
		// we need to check this object against
		return false
	}
	if fence.cmd == "nearby" {
		return obj.Nearby(geojson.Position{X: fence.lon, Y: fence.lat, Z: 0}, fence.meters)
	} else if fence.cmd == "within" {
		if fence.o != nil {
			return obj.Within(fence.o)
		}
		return obj.WithinBBox(geojson.BBox{
			Min: geojson.Position{X: fence.minLon, Y: fence.minLat, Z: 0},
			Max: geojson.Position{X: fence.maxLon, Y: fence.maxLat, Z: 0},
		})
	} else if fence.cmd == "intersects" {
		if fence.o != nil {
			return obj.Intersects(fence.o)
		}
		return obj.IntersectsBBox(geojson.BBox{
			Min: geojson.Position{X: fence.minLon, Y: fence.minLat, Z: 0},
			Max: geojson.Position{X: fence.maxLon, Y: fence.maxLat, Z: 0},
		})
	}
	return false
}

func fenceMatchRoam(c *Controller, fence *liveFenceSwitches, tkey, tid string, obj geojson.Object) (keys, ids []string, meterss []float64) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	col := c.getCol(fence.roam.key)
	if col == nil {
		return
	}
	p := obj.CalculatedPoint()
	col.Nearby(0, 0, p.Y, p.X, fence.roam.meters, math.Inf(-1), math.Inf(+1),
		func(id string, obj geojson.Object, fields []float64) bool {
			var match bool
			if id == tid {
				return true // skip self
			}
			if fence.roam.pattern {
				match, _ = glob.Match(fence.roam.id, id)
			} else {
				match = fence.roam.id == id
			}
			if match {
				keys = append(keys, fence.roam.key)
				ids = append(ids, id)
				meterss = append(meterss, obj.CalculatedPoint().DistanceTo(p))
			}
			return true
		},
	)
	return
}
<commit_msg>fix #84, roaming fence deadlock<commit_after>package controller

import (
	"math"
	"strconv"
	"strings"

	"github.com/tidwall/tile38/controller/glob"
	"github.com/tidwall/tile38/controller/server"
	"github.com/tidwall/tile38/geojson"
)

var tmfmt = "2006-01-02T15:04:05.999999999Z07:00"

// FenceMatch executes a fence match returns back json messages for fence detection.
func FenceMatch(hookName string, sw *scanWriter, fence *liveFenceSwitches, details *commandDetailsT) []string {
	jshookName := jsonString(hookName)
	jstime := jsonString(details.timestamp.Format(tmfmt))
	pattern := fence.glob
	if details.command == "drop" {
		return []string{`{"cmd":"drop","hook":` + jshookName + `,"time":` + jstime + `}`}
	}
	match := true
	if pattern != "" && pattern != "*" {
		match, _ = glob.Match(pattern, details.id)
	}
	if !match {
		return nil
	}

	sw.mu.Lock()
	nofields := sw.nofields
	sw.mu.Unlock()

	if details.obj == nil || !details.obj.IsGeometry() || (details.command == "fset" && nofields) {
		return nil
	}
	match = false

	var roamkeys, roamids []string
	var roammeters []float64
	detect := "outside"
	if fence != nil {
		if fence.roam.on {
			if details.command == "set" {
				// println("roam", fence.roam.key, fence.roam.id, strconv.FormatFloat(fence.roam.meters, 'f', -1, 64))
				roamkeys, roamids, roammeters = fenceMatchRoam(sw.c, fence, details.key, details.id, details.obj)
			}
			if len(roamids) == 0 || len(roamids) != len(roamkeys) {
				return nil
			}
			match = true
			detect = "roam"
		} else {

			// not using roaming
			match1 := fenceMatchObject(fence, details.oldObj)
			match2 := fenceMatchObject(fence, details.obj)
			if match1 && match2 {
				match = true
				detect = "inside"
			} else if match1 && !match2 {
				match = true
				detect = "exit"
			} else if !match1 && match2 {
				match = true
				detect = "enter"
				if details.command == "fset" {
					detect = "inside"
				}
			} else {
				if details.command != "fset" {
					// Maybe the old object and new object create a line that crosses the fence.
					// Must detect for that possibility.
					if details.oldObj != nil {
						ls := geojson.LineString{
							Coordinates: []geojson.Position{
								details.oldObj.CalculatedPoint(),
								details.obj.CalculatedPoint(),
							},
						}
						temp := false
						if fence.cmd == "within" {
							// because we are testing if the line croses the area we need to use
							// "intersects" instead of "within".
							fence.cmd = "intersects"
							temp = true
						}
						if fenceMatchObject(fence, ls) {
							//match = true
							detect = "cross"
						}
						if temp {
							fence.cmd = "within"
						}
					}
				}
			}
		}
	}
	if details.command == "del" {
		return []string{`{"command":"del","hook":` + jshookName + `,"id":` + jsonString(details.id) + `,"time":` + jstime + `}`}
	}
	if details.fmap == nil {
		return nil
	}
	sw.mu.Lock()
	sw.fmap = details.fmap
	sw.fullFields = true
	sw.msg.OutputType = server.JSON
	sw.writeObject(details.id, details.obj, details.fields, true)
	if sw.wr.Len() == 0 {
		sw.mu.Unlock()
		return nil
	}

	res := sw.wr.String()
	resb := make([]byte, len(res))
	copy(resb, res)
	sw.wr.Reset()
	res = string(resb)
	if strings.HasPrefix(res, ",") {
		res = res[1:]
	}
	if sw.output == outputIDs {
		res = `{"id":` + res + `}`
	}
	sw.mu.Unlock()

	jskey := jsonString(details.key)

	ores := res
	msgs := make([]string, 0, 2)
	if fence.detect == nil || fence.detect[detect] {
		if strings.HasPrefix(ores, "{") {
			res = `{"command":"` + details.command + `","detect":"` + detect + `","hook":` + jshookName + `,"key":` + jskey + `,"time":` + jstime + `,` + ores[1:]
		}
		msgs = append(msgs, res)
	}
	switch detect {
	case "enter":
		if fence.detect == nil || fence.detect["inside"] {
			msgs = append(msgs, `{"command":"`+details.command+`","detect":"inside","hook":`+jshookName+`,"key":`+jskey+`,"time":`+jstime+`,`+ores[1:])
		}
	case "exit", "cross":
		if fence.detect == nil || fence.detect["outside"] {
			msgs = append(msgs, `{"command":"`+details.command+`","detect":"outside","hook":`+jshookName+`,"key":`+jskey+`,"time":`+jstime+`,`+ores[1:])
		}
	case "roam":
		if len(msgs) > 0 {
			var nmsgs []string
			msg := msgs[0][:len(msgs[0])-1]
			for i, id := range roamids {
				nmsgs = append(nmsgs, msg+`,"nearby":{"key":`+jsonString(roamkeys[i])+`,"id":`+jsonString(id)+`,"meters":`+strconv.FormatFloat(roammeters[i], 'f', -1, 64)+`}}`)
			}
			msgs = nmsgs
		}
	}
	return msgs
}

func fenceMatchObject(fence *liveFenceSwitches, obj geojson.Object) bool {
	if obj == nil {
		return false
	}
	if fence.roam.on {
		// we need to check this object against
		return false
	}
	if fence.cmd == "nearby" {
		return obj.Nearby(geojson.Position{X: fence.lon, Y: fence.lat, Z: 0}, fence.meters)
	} else if fence.cmd == "within" {
		if fence.o != nil {
			return obj.Within(fence.o)
		}
		return obj.WithinBBox(geojson.BBox{
			Min: geojson.Position{X: fence.minLon, Y: fence.minLat, Z: 0},
			Max: geojson.Position{X: fence.maxLon, Y: fence.maxLat, Z: 0},
		})
	} else if fence.cmd == "intersects" {
		if fence.o != nil {
			return obj.Intersects(fence.o)
		}
		return obj.IntersectsBBox(geojson.BBox{
			Min: geojson.Position{X: fence.minLon, Y: fence.minLat, Z: 0},
			Max: geojson.Position{X: fence.maxLon, Y: fence.maxLat, Z: 0},
		})
	}
	return false
}

func fenceMatchRoam(c *Controller, fence *liveFenceSwitches, tkey, tid string, obj geojson.Object) (keys, ids []string, meterss []float64) {
	col := c.getCol(fence.roam.key)
	if col == nil {
		return
	}
	p := obj.CalculatedPoint()
	col.Nearby(0, 0, p.Y, p.X, fence.roam.meters, math.Inf(-1), math.Inf(+1),
		func(id string, obj geojson.Object, fields []float64) bool {
			var match bool
			if id == tid {
				return true // skip self
			}
			if fence.roam.pattern {
				match, _ = glob.Match(fence.roam.id, id)
			} else {
				match = fence.roam.id == id
			}
			if match {
				keys = append(keys, fence.roam.key)
				ids = append(ids, id)
				meterss = append(meterss, obj.CalculatedPoint().DistanceTo(p))
			}
			return true
		},
	)
	return
}
<|endoftext|>


<commit_before>package coreapi

import (
	"context"
	"crypto/rand"
	"fmt"
	"sort"

	coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
	caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
	ipfspath "github.com/ipfs/go-ipfs/path"

	peer "gx/ipfs/QmWNY7dV54ZDYmTA1ykVdwNCqC11mpU4zSUp6XDpLTH9eG/go-libp2p-peer"
	crypto "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
)

type KeyAPI struct {
	*CoreAPI
	*caopts.KeyOptions
}

type key struct {
	name   string
	peerId string
}

func (k *key) Name() string {
	return k.name
}

func (k *key) Path() coreiface.Path {
	return &path{path: ipfspath.FromString(ipfspath.Join([]string{"/ipns", k.peerId}))}
}

func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.KeyGenerateOption) (coreiface.Key, error) {
	options, err := caopts.KeyGenerateOptions(opts...)
	if err != nil {
		return nil, err
	}

	if name == "self" {
		return nil, fmt.Errorf("cannot overwrite key with name 'self'")
	}

	_, err = api.node.Repo.Keystore().Get(name)
	if err == nil {
		return nil, fmt.Errorf("key with name '%s' already exists", name)
	}

	var sk crypto.PrivKey
	var pk crypto.PubKey

	switch options.Algorithm {
	case "rsa":
		if options.Size == -1 {
			options.Size = caopts.DefaultRSALen
		}

		priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.RSA, options.Size, rand.Reader)
		if err != nil {
			return nil, err
		}

		sk = priv
		pk = pub
	case "ed25519":
		priv, pub, err := crypto.GenerateEd25519Key(rand.Reader)
		if err != nil {
			return nil, err
		}

		sk = priv
		pk = pub
	default:
		return nil, fmt.Errorf("unrecognized key type: %s", options.Algorithm)
	}

	err = api.node.Repo.Keystore().Put(name, sk)
	if err != nil {
		return nil, err
	}

	pid, err := peer.IDFromPublicKey(pk)
	if err != nil {
		return nil, err
	}

	return &key{name, pid.Pretty()}, nil
}

func (api *KeyAPI) List(ctx context.Context) ([]coreiface.Key, error) {
	keys, err := api.node.Repo.Keystore().List()
	if err != nil {
		return nil, err
	}

	sort.Strings(keys)

	out := make([]coreiface.Key, len(keys)+1)
	out[0] = &key{"self", api.node.Identity.Pretty()}

	for n, k := range keys {
		privKey, err := api.node.Repo.Keystore().Get(k)
		if err != nil {
			return nil, err
		}

		pubKey := privKey.GetPublic()

		pid, err := peer.IDFromPublicKey(pubKey)
		if err != nil {
			return nil, err
		}

		out[n+1] = &key{k, pid.Pretty()}
	}
	return out, nil
}

func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, opts ...caopts.KeyRenameOption) (coreiface.Key, bool, error) {
	options, err := caopts.KeyRenameOptions(opts...)
	if err != nil {
		return nil, false, err
	}

	ks := api.node.Repo.Keystore()

	if oldName == "self" {
		return nil, false, fmt.Errorf("cannot rename key with name 'self'")
	}

	if newName == "self" {
		return nil, false, fmt.Errorf("cannot overwrite key with name 'self'")
	}

	oldKey, err := ks.Get(oldName)
	if err != nil {
		return nil, false, fmt.Errorf("no key named %s was found", oldName)
	}

	pubKey := oldKey.GetPublic()

	pid, err := peer.IDFromPublicKey(pubKey)
	if err != nil {
		return nil, false, err
	}

	overwrite := false
	if options.Force {
		exist, err := ks.Has(newName)
		if err != nil {
			return nil, false, err
		}

		if exist {
			overwrite = true
			err := ks.Delete(newName)
			if err != nil {
				return nil, false, err
			}
		}
	}

	err = ks.Put(newName, oldKey)
	if err != nil {
		return nil, false, err
	}

	return &key{newName, pid.Pretty()}, overwrite, ks.Delete(oldName)
}

func (api *KeyAPI) Remove(ctx context.Context, name string) (coreiface.Path, error) {
	ks := api.node.Repo.Keystore()

	if name == "self" {
		return nil, fmt.Errorf("cannot remove key with name 'self'")
	}

	removed, err := ks.Get(name)
	if err != nil {
		return nil, fmt.Errorf("no key named %s was found", name)
	}

	pubKey := removed.GetPublic()

	pid, err := peer.IDFromPublicKey(pubKey)
	if err != nil {
		return nil, err
	}

	err = ks.Delete(name)
	if err != nil {
		return nil, err
	}

	return (&key{"", pid.Pretty()}).Path(), nil
}

func (api *KeyAPI) core() coreiface.CoreAPI {
	return api.CoreAPI
}
<commit_msg>docs for coreapi key method impls<commit_after>package coreapi

import (
	"context"
	"crypto/rand"
	"fmt"
	"sort"

	coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
	caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
	ipfspath "github.com/ipfs/go-ipfs/path"

	peer "gx/ipfs/QmWNY7dV54ZDYmTA1ykVdwNCqC11mpU4zSUp6XDpLTH9eG/go-libp2p-peer"
	crypto "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
)

type KeyAPI struct {
	*CoreAPI
	*caopts.KeyOptions
}

type key struct {
	name   string
	peerId string
}

// Name returns the key name
func (k *key) Name() string {
	return k.name
}

// Path returns the path of the key.
func (k *key) Path() coreiface.Path {
	return &path{path: ipfspath.FromString(ipfspath.Join([]string{"/ipns", k.peerId}))}
}

// Generate generates new key, stores it in the keystore under the specified
// name and returns a base58 encoded multihash of its public key.
func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.KeyGenerateOption) (coreiface.Key, error) {
	options, err := caopts.KeyGenerateOptions(opts...)
	if err != nil {
		return nil, err
	}

	if name == "self" {
		return nil, fmt.Errorf("cannot overwrite key with name 'self'")
	}

	_, err = api.node.Repo.Keystore().Get(name)
	if err == nil {
		return nil, fmt.Errorf("key with name '%s' already exists", name)
	}

	var sk crypto.PrivKey
	var pk crypto.PubKey

	switch options.Algorithm {
	case "rsa":
		if options.Size == -1 {
			options.Size = caopts.DefaultRSALen
		}

		priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.RSA, options.Size, rand.Reader)
		if err != nil {
			return nil, err
		}

		sk = priv
		pk = pub
	case "ed25519":
		priv, pub, err := crypto.GenerateEd25519Key(rand.Reader)
		if err != nil {
			return nil, err
		}

		sk = priv
		pk = pub
	default:
		return nil, fmt.Errorf("unrecognized key type: %s", options.Algorithm)
	}

	err = api.node.Repo.Keystore().Put(name, sk)
	if err != nil {
		return nil, err
	}

	pid, err := peer.IDFromPublicKey(pk)
	if err != nil {
		return nil, err
	}

	return &key{name, pid.Pretty()}, nil
}

// List returns a list keys stored in keystore.
func (api *KeyAPI) List(ctx context.Context) ([]coreiface.Key, error) {
	keys, err := api.node.Repo.Keystore().List()
	if err != nil {
		return nil, err
	}

	sort.Strings(keys)

	out := make([]coreiface.Key, len(keys)+1)
	out[0] = &key{"self", api.node.Identity.Pretty()}

	for n, k := range keys {
		privKey, err := api.node.Repo.Keystore().Get(k)
		if err != nil {
			return nil, err
		}

		pubKey := privKey.GetPublic()

		pid, err := peer.IDFromPublicKey(pubKey)
		if err != nil {
			return nil, err
		}

		out[n+1] = &key{k, pid.Pretty()}
	}
	return out, nil
}

// Rename renames `oldName` to `newName`. Returns the key and whether another
// key was overwritten, or an error.
func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, opts ...caopts.KeyRenameOption) (coreiface.Key, bool, error) {
	options, err := caopts.KeyRenameOptions(opts...)
	if err != nil {
		return nil, false, err
	}

	ks := api.node.Repo.Keystore()

	if oldName == "self" {
		return nil, false, fmt.Errorf("cannot rename key with name 'self'")
	}

	if newName == "self" {
		return nil, false, fmt.Errorf("cannot overwrite key with name 'self'")
	}

	oldKey, err := ks.Get(oldName)
	if err != nil {
		return nil, false, fmt.Errorf("no key named %s was found", oldName)
	}

	pubKey := oldKey.GetPublic()

	pid, err := peer.IDFromPublicKey(pubKey)
	if err != nil {
		return nil, false, err
	}

	overwrite := false
	if options.Force {
		exist, err := ks.Has(newName)
		if err != nil {
			return nil, false, err
		}

		if exist {
			overwrite = true
			err := ks.Delete(newName)
			if err != nil {
				return nil, false, err
			}
		}
	}

	err = ks.Put(newName, oldKey)
	if err != nil {
		return nil, false, err
	}

	return &key{newName, pid.Pretty()}, overwrite, ks.Delete(oldName)
}

// Remove removes keys from keystore. Returns ipns path of the removed key.
func (api *KeyAPI) Remove(ctx context.Context, name string) (coreiface.Path, error) {
	ks := api.node.Repo.Keystore()

	if name == "self" {
		return nil, fmt.Errorf("cannot remove key with name 'self'")
	}

	removed, err := ks.Get(name)
	if err != nil {
		return nil, fmt.Errorf("no key named %s was found", name)
	}

	pubKey := removed.GetPublic()

	pid, err := peer.IDFromPublicKey(pubKey)
	if err != nil {
		return nil, err
	}

	err = ks.Delete(name)
	if err != nil {
		return nil, err
	}

	return (&key{"", pid.Pretty()}).Path(), nil
}

func (api *KeyAPI) core() coreiface.CoreAPI {
	return api.CoreAPI
}
<|endoftext|>