package main

import (
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"math/big"
	"strings"
	"testing"
)


var schema = `{"fields":{"alinkman":{"val":"Alinkman","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"amob":{"val":"Amob","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"aname":{"val":"Aname","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"atype":{"val":"Atype","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"backup":{"val":{"aname":"Aname","atype":"Atype"},"auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":
{"admin":0},"roles":{"admin":1582972202}}}},"id":{"val":"1","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}}},"schema_auth":{"read":{"users":null,"roles":null},"write":{"users":{"admin":0},"roles":{"admin":0}}},"auth":{"read":{"users":
{"admin":0},"roles":{"admin":0}},"write":{"users":{"admin":0},"roles":{"admin":1582972202}}}}
`
var schema2 = `{"fields":{"alinkman":{"val":"Alinkman","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"amob":{"val":"Amob","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"aname":{"val":"Aname","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"atype":{"val":"Atype","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"backup":{"val":{"aname":"Aname","atype":"Atype"},"auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":
{"admin":0},"roles":{"admin":1582972202}}}},"id":{"val":"1","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}}},"schema_auth":{"read":{"users":null,"roles":null},"write":{"users":{"admin":0},"roles":{"admin":1582972202}}},"auth":{"read":{"users":
{"admin":0},"roles":{"admin":0}},"write":{"users":{"admin":0},"roles":{"admin":0}}}}
`

var schema3 = `{"fields":{"alinkman":{"val":"Alinkman","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"amob":{"val":"Amob","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"aname":{"val":"Aname","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"atype":{"val":"Atype","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}},"backup":{"val":{"aname":"Aname","atype":"Atype"},"auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":
{"admin":0},"roles":{"admin":1582972202}}}},"id":{"val":"1","auth":{"read":{"users":{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":
{"admin":1582972202}}}}},"schema_auth":{"read":{"users":null,"roles":null},"write":{"users":{"admin":0},"roles":{"admin":1582972202}}},"auth":{"read":{"users":
{"admin":0},"roles":{"admin":1582972202}},"write":{"users":{"admin":0},"roles":{"admin":0}}}}
`
/*
	以下部分是增加权限内容的测试
*/

var (
	inputUpdate = `{"id":"1","aname":"alibusi","atype":100,"alinkman":10.34,"amob":"2006-01-02 15:04:05","backup":
{"aname":"alibusi","atype":"type"}}`

	inputarrary = `[{"abail":"0","sabail":"0","id":"1","aname":"alibusi","atype":100,"alinkman":10.34,"amob":"2006-01-02 15:04:05","backup":
{"aname":"alibusi","atype":"type"},"common_name":"admin"},{"abail":"0","sabail":"0","id":"2","aname":"alibusi","atype":100,"alinkman":
10.34,"amob":"2006-01-02 15:04:05","backup":{"aname":"alibusi","atype":"type"},"common_name":"admin"}]`
	inputPutarray = `[{"id":"1","aname":"alibusi","atype":100,"alinkman":10.34,"amob":"2006-01-02 15:04:05","backup":{"aname":"alibusi",
"atype":"type"},"common_name":"admin"},{"id":"2","aname":"alibusi","atype":100,"alinkman":10.34,"amob":"2006-01-02 15:04:05","backup":
{"aname":"alibusi","atype":"type"},"common_name":"admin"}]`
)
func TestGXHSchemaAuth(t *testing.T){
	cc := new(GXHCC)
	stub := shim.NewMockStub("GXHCC",cc)
	stub.MockInit("init",nil)
	fmt.Println()
	fmt.Println("========================================invoke schema put============================================")
	fmt.Println()
	fmt.Println()
	responseByPutschema := stub.MockInvoke("invoke1",[][]byte{[]byte("schema"), []byte("put"),[]byte("alibusi"),[]byte(schema)})
	fmt.Printf("Invoke status %d,message %s and payload %s\n",
		responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
	fmt.Println()
	fmt.Println("========================================invoke schema get============================================")
	fmt.Println()
	fmt.Println()
	responseByget := stub.MockInvoke("invoke1",[][]byte{[]byte("schema"), []byte("get"),[]byte("alibusi")})
	fmt.Printf("Invoke status %d,message %s ,and payload %s \n",
		responseByget.Status,responseByget.Message,string(responseByget.Payload))
	fmt.Println()
	fmt.Println("========================================invoke schema update============================================")
	fmt.Println()
	fmt.Println()
	responseByupdate := stub.MockInvoke("invoke1",[][]byte{[]byte("schema"), []byte("update"),[]byte("alibusi"),[]byte(schema)})
	fmt.Printf("Invoke status %d,message %s ,and payload %s \n",
		responseByupdate.Status,responseByupdate.Message,string(responseByupdate.Payload))
}

/*
	测试使用table 数据构建 schema
*/
func TestGXHSchemaAuthBytable(t *testing.T){
	cc := new(GXHCC)
	stub := shim.NewMockStub("GXHCC",cc)
	stub.MockInit("init",nil)
	fmt.Println()
	fmt.Println("========================================invoke schema put============================================")
	fmt.Println()
	fmt.Println()
	responseByPutschema := stub.MockInvoke("invoke1",[][]byte{[]byte("schema"), []byte("put"),[]byte("alibusi"),[]byte(inputUpdate)})
	fmt.Printf("Invoke status %d,message %s and payload %s\n",
		responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
	fmt.Println()
	fmt.Println("========================================invoke schema get============================================")
	fmt.Println()
	fmt.Println()
	responseByget := stub.MockInvoke("invoke1",[][]byte{[]byte("schema"), []byte("get"),[]byte("alibusi")})
	fmt.Printf("Invoke status %d,message %s ,and payload %s \n",
		responseByget.Status,responseByget.Message,string(responseByget.Payload))
	fmt.Println()
	fmt.Println("========================================invoke schema update============================================")
	fmt.Println()
	fmt.Println()
	responseByupdate := stub.MockInvoke("invoke1",[][]byte{[]byte("schema"), []byte("update"),[]byte("alibusi"),[]byte(inputUpdate)})
	fmt.Printf("Invoke status %d,message %s ,and payload %s \n",
		responseByupdate.Status,responseByupdate.Message,string(responseByupdate.Payload))
}
func TestGXHDataPutAuth(t *testing.T){
	cc := new(GXHCC)
	stub := shim.NewMockStub("GXHCC",cc)
	stub.MockInit("init",nil)
	fmt.Println()
	fmt.Println("========================================invoke schema put============================================")
	fmt.Println()
	fmt.Println()
	responseByPutschema := stub.MockInvoke("invoke1",[][]byte{[]byte("schema"), []byte("put"),[]byte("alibusi"),[]byte(schema3)})
	//使用schema 数据测试过期时间err,schema right data,使用schema3 测试读取字段时的过滤
	fmt.Printf("Invoke status %d,message %s and payload %s\n",
		responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
	responseByget := stub.MockInvoke("invoke1",[][]byte{[]byte("schema"), []byte("get"),[]byte("alibusi")})
	fmt.Printf("Invoke status %d,message %s ,and payload %s \n",
		responseByget.Status,responseByget.Message,string(responseByget.Payload))
	fmt.Println()
	fmt.Println("========================================invoke data put============================================")
	fmt.Println()
	fmt.Println()
	responseByPut := stub.MockInvoke("invoke1",[][]byte{[]byte("put"), []byte("alibusi"),[]byte(inputarrary)})
	fmt.Printf("Invoke status %d,message %s ,and payload %s\n",
		responseByPut.Status,responseByPut.Message,string(responseByPut.Payload))

	responseByget = stub.MockInvoke("invoke1",[][]byte{[]byte("get"), []byte("alibusi"),[]byte(`{"id":"1"}`)})
	fmt.Printf("Invoke status %d,message %s ,and payload %s \n",
		responseByget.Status,responseByget.Message,string(responseByget.Payload))
	fmt.Println()
	fmt.Println("========================================invoke data update============================================")
	fmt.Println()
	fmt.Println()
	responseByUpdate := stub.MockInvoke("invoke1",[][]byte{[]byte("update"), []byte("alibusi"),[]byte(inputUpdate)})
	fmt.Printf("Invoke status %d,message %s ,and payload %s\n",
		responseByUpdate.Status,responseByUpdate.Message,string(responseByUpdate.Payload))

	responseByget2 := stub.MockInvoke("invoke1",[][]byte{[]byte("get"), []byte("alibusi"),[]byte(`{"id":"1"}`)})
	fmt.Printf("Invoke status %d,message %s ,and payload %s \n",
		responseByget2.Status,responseByget2.Message,string(responseByget2.Payload))
}

var testData = `{"float64":10.33,"int":10,"string":"我中国人a！","time.Time":"2020-03-06 18:30:07.49752435 +0800 CST m=+0.000270574"}`

func TestFieldCheck(t *testing.T){
	var testmap map[string]interface{}
	json.Unmarshal([]byte(testData),&testmap)
	intC := &Checks{
		FType:"int",
		Must:true,
		Fieldlen:1,
	}
	err := fieldCheckout(intC,testmap["int"])
    if err != nil{
    	t.Error(err)
	}
	floatC := &Checks{
		FType:"float64",
		Must:true,
		Fieldlen:1,
	}
	err = fieldCheckout(floatC,testmap["float64"])
	if err != nil{
		t.Error(err)
	}
	stringC := &Checks{
		FType:"string",
		Must:true,
		Fieldlen:6,
	}
	err = fieldCheckout(stringC,testmap["string"])
	if err != nil{
		t.Error(err)
	}
	timeC := &Checks{
		FType:"time.Time",
		Must:true,
		Fieldlen:1,
	}
	err = fieldCheckout(timeC,testmap["time.Time"])
	if err != nil{
		t.Error(err)
	}
}

var schemaCheck = `{"fields":{"alinkman":{"val":10.34,"auth":{"read":{"users":{"Admin@org2.example.com":0},"roles":
{"Admin@org2.example.com":1583501961}},"write":{"users":{"Admin@org2.example.com":0},"roles":
{"Admin@org2.example.com":1583501961}}},"fcheck":{"ftype":"float64","must":true,"fieldlen":1}},
"amob":{"val":"0001-01-01T00:00:00Z","auth":{"read":{"users":{"Admin@org2.example.com":0},"roles":
{"Admin@org2.example.com":1583501961}},"write":{"users":{"Admin@org2.example.com":0},"roles":{"Admin@org2.example.com":
1583501961}}},"fcheck":{"ftype":"time.Time","must":true,"fieldlen":0}},"aname":{"val":"Aname","auth":{"read":{"users":
{"Admin@org2.example.com":0},"roles":{"Admin@org2.example.com":1583501961}},"write":{"users":{"Admin@org2.example.com":0},
"roles":{"Admin@org2.example.com":1583501961}}},"fcheck":{"ftype":"string","must":true,"fieldlen":16}},"atype":{"val":100,
"auth":{"read":{"users":{"Admin@org2.example.com":0},"roles":{"Admin@org2.example.com":1583501961}},"write":{"users":
{"Admin@org2.example.com":0},"roles":{"Admin@org2.example.com":1583501961}}},"fcheck":{"ftype":"int",
"must":true,"fieldlen":1}},"backup":{"val":{"aname":"Aname","atype":"Atype"},"auth":{"read":{"users":
{"Admin@org2.example.com":0},"roles":{"Admin@org2.example.com":1583501961}},"write":{"users":{"Admin@org2.example.com":0},
"roles":{"Admin@org2.example.com":1583501961}}},"fcheck":null},"id":{"val":"1","auth":{"read":{"users":null,"roles":null},
"write":{"users":null,"roles":null}},"fcheck":null}},"schema_auth":{"read":{"users":null,"roles":null},"write":{"users":
{"Admin@org2.example.com":0},"roles":{"Admin@org2.example.com":1583501961}}},"auth":{"read":{"users":
{"Admin@org2.example.com":0},"roles":{"Admin@org2.example.com":0}},"write":{"users":{"Admin@org2.example.com":0},
"roles":{"Admin@org2.example.com":0}}}}
`
var (
	inputC = `{"id":"1","aname":"alibusi","atype":1000,"alinkman":1.233,
"amob":"new1234567890","backup":{"aname":"alibusi","atype":"type"}}`

	inputCs = `[{
	"id": "1",
	"aname": "alibusi",
	"atype": 102,
	"alinkman": 10.34,
	"amob": "0001-01-01 00:00:00 + UTC",
	"backup": {
		"aname": "alibusi",
		"atype": "type"
	}
}, {
	"id": "2",
	"aname": "alibusi",
	"atype": 102,
	"alinkman": 10.34,
	"amob": "0001-01-01 00:00:00 + UTC",
	"backup": {
		"aname": "alibusi",
		"atype": "type"
	}
}]`
)
/*
	本测试主要进行data put,update的测试操作，主要进行fieldcheck 的测试。
*/
func TestPut(t *testing.T){
	cc := new(GXHCC)
	stub := shim.NewMockStub("GXHCC",cc)
	stub.MockInit("init",nil)
	fmt.Println()
	fmt.Println("========================================invoke schema put============================================")
	fmt.Println()
	fmt.Println()
	responseByPutschema := stub.MockInvoke("invoke1",[][]byte{[]byte("schema"), []byte("put"),[]byte("alibusi"),[]byte(inputC)})
	//使用schema 数据测试过期时间err,schema right data,使用schema3 测试读取字段时的过滤
	fmt.Printf("Invoke status %d,message %s and payload %s\n",
		responseByPutschema.Status,responseByPutschema.Message,string(responseByPutschema.Payload))
	responseByget := stub.MockInvoke("invoke1",[][]byte{[]byte("schema"), []byte("get"),[]byte("alibusi")})
	fmt.Printf("Invoke status %d,message %s ,and payload %s \n",
		responseByget.Status,responseByget.Message,string(responseByget.Payload))
	fmt.Println()
	fmt.Println("========================================invoke data put============================================")
	fmt.Println()
	fmt.Println()
	responseByPut := stub.MockInvoke("invoke1",[][]byte{[]byte("put"), []byte("alibusi"),[]byte(inputCs)})
	fmt.Printf("Invoke status %d,message %s ,and payload %s\n",
		responseByPut.Status,responseByPut.Message,string(responseByPut.Payload))

	responseByget = stub.MockInvoke("invoke1",[][]byte{[]byte("get"), []byte("alibusi"),[]byte(`{"id":"1"}`)})
	fmt.Printf("Invoke status %d,message %s ,and payload %s \n",
		responseByget.Status,responseByget.Message,string(responseByget.Payload))
	fmt.Println()
	fmt.Println("========================================invoke data update============================================")
	fmt.Println()
	fmt.Println()
	responseByUpdate := stub.MockInvoke("invoke1",[][]byte{[]byte("update"), []byte("alibusi"),[]byte(inputC)})
	fmt.Printf("Invoke status %d,message %s ,and payload %s\n",
		responseByUpdate.Status,responseByUpdate.Message,string(responseByUpdate.Payload))

	responseByget2 := stub.MockInvoke("invoke1",[][]byte{[]byte("get"), []byte("alibusi"),[]byte(`{"id":"1"}`)})
	fmt.Printf("Invoke status %d,message %s ,and payload %s \n",
		responseByget2.Status,responseByget2.Message,string(responseByget2.Payload))
}


func TestDivide(t *testing.T){
	testInt := big.NewInt(23456789000000)
	i , err := dividecalc(testInt,float64(0.0056))
	if err!=nil{
		t.Error(err.Error())
	}
	fmt.Println(i)

}

//经过测试发现使用big.int 比直接使用float64 会有2500多倍的性能损失
func BenchmarkDivide(b *testing.B) {
	for i:= 0 ;i < b.N ; i++ {
		//testInt := big.NewInt(23456789)
		//i := dividecalctest(testInt,float64(0.0056))
		//if err!=nil{
		//	fmt.Println("happen err",err)
		//	return
		//}
	}
	//for i:= 0 ;i < b.N ; i++ {
	//	a := float64(23456789)
	//	_ , err := testfunc(a,float64(0.0056))
	//	if err!=nil{
	//		fmt.Println("happen err",err)
	//		return
	//	}
	//	//fmt.Println(c)
	//}
}

func testfunc(a,b float64)(float64,error){
	str := fmt.Sprintf("%v", b)
	strs := strings.Split(str, ".")
	if len(strs[1]) > 6 {
		return 0, fmt.Errorf("divide can only exist to six decimal places ")
	}
	//var mul int64
	//length := len(strs[1])
   // pow(10,int64(length))
	return a*b,nil
}
