mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
gjson,gredis测试用例编写
This commit is contained in:
@ -7,133 +7,203 @@
|
||||
package gredis_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/database/gredis"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
"time"
|
||||
"github.com/gogf/gf/g/database/gredis"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
redis2 "github.com/gogf/gf/third/github.com/gomodule/redigo/redis"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
config = gredis.Config{
|
||||
Host : "127.0.0.1",
|
||||
Port : 6379,
|
||||
Db : 1,
|
||||
}
|
||||
config = gredis.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
Db: 1,
|
||||
}
|
||||
)
|
||||
|
||||
func Test_NewClose(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
gtest.AssertNE(redis, nil)
|
||||
err := redis.Close()
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
gtest.AssertNE(redis, nil)
|
||||
err := redis.Close()
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Do(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
_, err := redis.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
_, err := redis.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
_, err = redis.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
_, err = redis.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Send(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
err := redis.Send("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
err := redis.Send("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
})
|
||||
r, err := redis.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Stats(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
redis.SetMaxIdle(2)
|
||||
redis.SetMaxActive(100)
|
||||
redis.SetIdleTimeout(500*time.Millisecond)
|
||||
redis.SetMaxConnLifetime(500*time.Millisecond)
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
redis.SetMaxIdle(2)
|
||||
redis.SetMaxActive(100)
|
||||
redis.SetIdleTimeout(500 * time.Millisecond)
|
||||
redis.SetMaxConnLifetime(500 * time.Millisecond)
|
||||
|
||||
array := make([]*gredis.Conn, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array = append(array, redis.Conn())
|
||||
}
|
||||
stats := redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 10)
|
||||
gtest.Assert(stats.IdleCount, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array[i].Close()
|
||||
}
|
||||
stats = redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 2)
|
||||
gtest.Assert(stats.IdleCount, 2)
|
||||
//time.Sleep(3000*time.Millisecond)
|
||||
//stats = redis.Stats()
|
||||
//fmt.Println(stats)
|
||||
//gtest.Assert(stats.ActiveCount, 0)
|
||||
//gtest.Assert(stats.IdleCount, 0)
|
||||
})
|
||||
array := make([]*gredis.Conn, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array = append(array, redis.Conn())
|
||||
}
|
||||
stats := redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 10)
|
||||
gtest.Assert(stats.IdleCount, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
array[i].Close()
|
||||
}
|
||||
stats = redis.Stats()
|
||||
gtest.Assert(stats.ActiveCount, 2)
|
||||
gtest.Assert(stats.IdleCount, 2)
|
||||
//time.Sleep(3000*time.Millisecond)
|
||||
//stats = redis.Stats()
|
||||
//fmt.Println(stats)
|
||||
//gtest.Assert(stats.ActiveCount, 0)
|
||||
//gtest.Assert(stats.IdleCount, 0)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Conn(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
gtest.Case(t, func() {
|
||||
redis := gredis.New(config)
|
||||
defer redis.Close()
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Instance(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
group := "my-test"
|
||||
gredis.SetConfig(config, group)
|
||||
defer gredis.RemoveConfig(group)
|
||||
redis := gredis.Instance(group)
|
||||
defer redis.Close()
|
||||
gtest.Case(t, func() {
|
||||
group := "my-test"
|
||||
gredis.SetConfig(config, group)
|
||||
defer gredis.RemoveConfig(group)
|
||||
redis := gredis.Instance(group)
|
||||
defer redis.Close()
|
||||
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
conn := redis.Conn()
|
||||
defer conn.Close()
|
||||
|
||||
_, err := conn.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
_, err := conn.Do("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
r, err := conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, []byte("v"))
|
||||
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
_, err = conn.Do("DEL", "k")
|
||||
gtest.Assert(err, nil)
|
||||
r, err = conn.Do("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(r, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
config1 := gredis.Config{
|
||||
Host: "127.0.0.2",
|
||||
Port: 6379,
|
||||
Db: 1,
|
||||
}
|
||||
redis := gredis.New(config1)
|
||||
_, err := redis.Do("info")
|
||||
gtest.Assert(err == nil, false)
|
||||
|
||||
config1 = gredis.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
Db: 1,
|
||||
Pass: "666666",
|
||||
}
|
||||
redis = gredis.New(config1)
|
||||
_, err = redis.Do("info")
|
||||
gtest.Assert(err == nil, false)
|
||||
|
||||
config1 = gredis.Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: 6379,
|
||||
Db: 100,
|
||||
}
|
||||
redis = gredis.New(config1)
|
||||
_, err = redis.Do("info")
|
||||
gtest.Assert(err == nil, false)
|
||||
|
||||
redis = gredis.Instance("gf")
|
||||
gtest.Assert(redis == nil, true)
|
||||
gredis.ClearConfig()
|
||||
|
||||
redis = gredis.New(config)
|
||||
defer redis.Close()
|
||||
_, err = redis.DoVar("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
v, err := redis.DoVar("GET", "k")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v.String(), "v")
|
||||
|
||||
conn := redis.GetConn()
|
||||
_, err = conn.DoVar("SET", "k", "v")
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
//v, err = conn.ReceiveVar()
|
||||
//gtest.Assert(err, nil)
|
||||
//gtest.Assert(v.String(), "v")
|
||||
|
||||
psc := redis2.PubSubConn{Conn: conn}
|
||||
psc.Subscribe("gf")
|
||||
redis.DoVar("PUBLISH", "gf", "gf test")
|
||||
go func() {
|
||||
for {
|
||||
v, _ := conn.ReceiveVar()
|
||||
switch obj := v.Val().(type) {
|
||||
case redis2.Message:
|
||||
gtest.Assert(string(obj.Data), "gf test")
|
||||
case redis2.Subscription:
|
||||
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
time.Sleep(time.Second)
|
||||
})
|
||||
}
|
||||
|
||||
@ -17,17 +17,17 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// Separator char for hierarchical data access.
|
||||
gDEFAULT_SPLIT_CHAR = '.'
|
||||
// Separator char for hierarchical data access.
|
||||
gDEFAULT_SPLIT_CHAR = '.'
|
||||
)
|
||||
|
||||
// The customized JSON struct.
|
||||
type Json struct {
|
||||
mu *rwmutex.RWMutex
|
||||
p *interface{} // Pointer for hierarchical data access, it's the root of data in default.
|
||||
c byte // Char separator('.' in default).
|
||||
vc bool // Violence Check(false in default), which is used to access data
|
||||
// when the hierarchical data key contains separator char.
|
||||
mu *rwmutex.RWMutex
|
||||
p *interface{} // Pointer for hierarchical data access, it's the root of data in default.
|
||||
c byte // Char separator('.' in default).
|
||||
vc bool // Violence Check(false in default), which is used to access data
|
||||
// when the hierarchical data key contains separator char.
|
||||
}
|
||||
|
||||
// Set <value> by <pattern>.
|
||||
@ -35,300 +35,306 @@ type Json struct {
|
||||
// 1. If value is nil and removed is true, means deleting this value;
|
||||
// 2. It's quite complicated in hierarchical data search, node creating and data assignment;
|
||||
func (j *Json) setValue(pattern string, value interface{}, removed bool) error {
|
||||
array := strings.Split(pattern, string(j.c))
|
||||
length := len(array)
|
||||
value = j.convertValue(value)
|
||||
// 初始化判断
|
||||
if *j.p == nil {
|
||||
if gstr.IsNumeric(array[0]) {
|
||||
*j.p = make([]interface{}, 0)
|
||||
} else {
|
||||
*j.p = make(map[string]interface{})
|
||||
}
|
||||
}
|
||||
var pparent *interface{} = nil // 父级元素项(设置时需要根据子级的内容确定数据类型,所以必须记录父级)
|
||||
var pointer *interface{} = j.p // 当前操作层级项
|
||||
j.mu.Lock()
|
||||
defer j.mu.Unlock()
|
||||
for i:= 0; i < length; i++ {
|
||||
switch (*pointer).(type) {
|
||||
case map[string]interface{}:
|
||||
if i == length - 1 {
|
||||
if removed && value == nil {
|
||||
// 删除map元素
|
||||
delete((*pointer).(map[string]interface{}), array[i])
|
||||
} else {
|
||||
(*pointer).(map[string]interface{})[array[i]] = value
|
||||
}
|
||||
} else {
|
||||
// 当键名不存在的情况这里会进行处理
|
||||
if v, ok := (*pointer).(map[string]interface{})[array[i]]; !ok {
|
||||
if removed && value == nil {
|
||||
goto done
|
||||
}
|
||||
// 创建新节点
|
||||
if gstr.IsNumeric(array[i + 1]) {
|
||||
// 创建array节点
|
||||
n, _ := strconv.Atoi(array[i + 1])
|
||||
var v interface{} = make([]interface{}, n + 1)
|
||||
pparent = j.setPointerWithValue(pointer, array[i], v)
|
||||
pointer = &v
|
||||
} else {
|
||||
// 创建map节点
|
||||
var v interface{} = make(map[string]interface{})
|
||||
pparent = j.setPointerWithValue(pointer, array[i], v)
|
||||
pointer = &v
|
||||
}
|
||||
} else {
|
||||
pparent = pointer
|
||||
pointer = &v
|
||||
}
|
||||
}
|
||||
array := strings.Split(pattern, string(j.c))
|
||||
length := len(array)
|
||||
value = j.convertValue(value)
|
||||
// 初始化判断
|
||||
if *j.p == nil {
|
||||
if gstr.IsNumeric(array[0]) {
|
||||
*j.p = make([]interface{}, 0)
|
||||
} else {
|
||||
*j.p = make(map[string]interface{})
|
||||
}
|
||||
}
|
||||
var pparent *interface{} = nil // 父级元素项(设置时需要根据子级的内容确定数据类型,所以必须记录父级)
|
||||
var pointer *interface{} = j.p // 当前操作层级项
|
||||
j.mu.Lock()
|
||||
defer j.mu.Unlock()
|
||||
for i := 0; i < length; i++ {
|
||||
switch (*pointer).(type) {
|
||||
case map[string]interface{}:
|
||||
if i == length-1 {
|
||||
if removed && value == nil {
|
||||
// 删除map元素
|
||||
delete((*pointer).(map[string]interface{}), array[i])
|
||||
} else {
|
||||
(*pointer).(map[string]interface{})[array[i]] = value
|
||||
}
|
||||
} else {
|
||||
// 当键名不存在的情况这里会进行处理
|
||||
if v, ok := (*pointer).(map[string]interface{})[array[i]]; !ok {
|
||||
if removed && value == nil {
|
||||
goto done
|
||||
}
|
||||
// 创建新节点
|
||||
if gstr.IsNumeric(array[i+1]) {
|
||||
// 创建array节点
|
||||
n, _ := strconv.Atoi(array[i+1])
|
||||
var v interface{} = make([]interface{}, n+1)
|
||||
pparent = j.setPointerWithValue(pointer, array[i], v)
|
||||
pointer = &v
|
||||
} else {
|
||||
// 创建map节点
|
||||
var v interface{} = make(map[string]interface{})
|
||||
pparent = j.setPointerWithValue(pointer, array[i], v)
|
||||
pointer = &v
|
||||
}
|
||||
} else {
|
||||
pparent = pointer
|
||||
pointer = &v
|
||||
}
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
// 键名与当前指针类型不符合,需要执行**覆盖操作**
|
||||
if !gstr.IsNumeric(array[i]) {
|
||||
if i == length - 1 {
|
||||
*pointer = map[string]interface{}{ array[i] : value }
|
||||
} else {
|
||||
var v interface{} = make(map[string]interface{})
|
||||
*pointer = v
|
||||
pparent = pointer
|
||||
pointer = &v
|
||||
}
|
||||
continue
|
||||
}
|
||||
case []interface{}:
|
||||
// 键名与当前指针类型不符合,需要执行**覆盖操作**
|
||||
if !gstr.IsNumeric(array[i]) {
|
||||
if i == length-1 {
|
||||
*pointer = map[string]interface{}{array[i]: value}
|
||||
} else {
|
||||
var v interface{} = make(map[string]interface{})
|
||||
*pointer = v
|
||||
pparent = pointer
|
||||
pointer = &v
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
valn, err := strconv.Atoi(array[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 叶子节点
|
||||
if i == length - 1 {
|
||||
if len((*pointer).([]interface{})) > valn {
|
||||
if removed && value == nil {
|
||||
// 删除数据元素
|
||||
j.setPointerWithValue(pparent, array[i - 1], append((*pointer).([]interface{})[ : valn], (*pointer).([]interface{})[valn + 1 : ]...))
|
||||
} else {
|
||||
(*pointer).([]interface{})[valn] = value
|
||||
}
|
||||
} else {
|
||||
if removed && value == nil {
|
||||
goto done
|
||||
}
|
||||
if pparent == nil {
|
||||
// 表示根节点
|
||||
j.setPointerWithValue(pointer, array[i], value)
|
||||
} else {
|
||||
// 非根节点
|
||||
s := make([]interface{}, valn + 1)
|
||||
copy(s, (*pointer).([]interface{}))
|
||||
s[valn] = value
|
||||
j.setPointerWithValue(pparent, array[i - 1], s)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if gstr.IsNumeric(array[i + 1]) {
|
||||
n, _ := strconv.Atoi(array[i + 1])
|
||||
if len((*pointer).([]interface{})) > valn {
|
||||
(*pointer).([]interface{})[valn] = make([]interface{}, n + 1)
|
||||
pparent = pointer
|
||||
pointer = &(*pointer).([]interface{})[valn]
|
||||
} else {
|
||||
if removed && value == nil {
|
||||
goto done
|
||||
}
|
||||
var v interface{} = make([]interface{}, n + 1)
|
||||
pparent = j.setPointerWithValue(pointer, array[i], v)
|
||||
pointer = &v
|
||||
}
|
||||
} else {
|
||||
var v interface{} = make(map[string]interface{})
|
||||
pparent = j.setPointerWithValue(pointer, array[i], v)
|
||||
pointer = &v
|
||||
}
|
||||
}
|
||||
valn, err := strconv.Atoi(array[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 叶子节点
|
||||
if i == length-1 {
|
||||
if len((*pointer).([]interface{})) > valn {
|
||||
if removed && value == nil {
|
||||
// 删除数据元素
|
||||
j.setPointerWithValue(pparent, array[i-1], append((*pointer).([]interface{})[:valn], (*pointer).([]interface{})[valn+1:]...))
|
||||
} else {
|
||||
(*pointer).([]interface{})[valn] = value
|
||||
}
|
||||
} else {
|
||||
if removed && value == nil {
|
||||
goto done
|
||||
}
|
||||
if pparent == nil {
|
||||
// 表示根节点
|
||||
j.setPointerWithValue(pointer, array[i], value)
|
||||
} else {
|
||||
// 非根节点
|
||||
s := make([]interface{}, valn+1)
|
||||
copy(s, (*pointer).([]interface{}))
|
||||
s[valn] = value
|
||||
j.setPointerWithValue(pparent, array[i-1], s)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if gstr.IsNumeric(array[i+1]) {
|
||||
n, _ := strconv.Atoi(array[i+1])
|
||||
if len((*pointer).([]interface{})) > valn {
|
||||
(*pointer).([]interface{})[valn] = make([]interface{}, n+1)
|
||||
pparent = pointer
|
||||
pointer = &(*pointer).([]interface{})[valn]
|
||||
} else {
|
||||
if removed && value == nil {
|
||||
goto done
|
||||
}
|
||||
var v interface{} = make([]interface{}, n+1)
|
||||
pparent = j.setPointerWithValue(pointer, array[i], v)
|
||||
pointer = &v
|
||||
}
|
||||
} else {
|
||||
var v interface{} = make(map[string]interface{})
|
||||
pparent = j.setPointerWithValue(pointer, array[i], v)
|
||||
pointer = &v
|
||||
}
|
||||
}
|
||||
|
||||
// 如果当前指针指向的变量不是引用类型的,
|
||||
// 那么修改变量必须通过父级进行修改,即 pparent
|
||||
default:
|
||||
if removed && value == nil {
|
||||
goto done
|
||||
}
|
||||
if gstr.IsNumeric(array[i]) {
|
||||
n, _ := strconv.Atoi(array[i])
|
||||
s := make([]interface{}, n + 1)
|
||||
if i == length - 1 {
|
||||
s[n] = value
|
||||
}
|
||||
if pparent != nil {
|
||||
pparent = j.setPointerWithValue(pparent, array[i - 1], s)
|
||||
} else {
|
||||
*pointer = s
|
||||
pparent = pointer
|
||||
}
|
||||
} else {
|
||||
var v interface{} = make(map[string]interface{})
|
||||
if i == length - 1 {
|
||||
v = map[string]interface{}{
|
||||
array[i] : value,
|
||||
}
|
||||
}
|
||||
if pparent != nil {
|
||||
pparent = j.setPointerWithValue(pparent, array[i - 1], v)
|
||||
} else {
|
||||
*pointer = v
|
||||
pparent = pointer
|
||||
}
|
||||
pointer = &v
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果当前指针指向的变量不是引用类型的,
|
||||
// 那么修改变量必须通过父级进行修改,即 pparent
|
||||
default:
|
||||
if removed && value == nil {
|
||||
goto done
|
||||
}
|
||||
if gstr.IsNumeric(array[i]) {
|
||||
n, _ := strconv.Atoi(array[i])
|
||||
s := make([]interface{}, n+1)
|
||||
if i == length-1 {
|
||||
s[n] = value
|
||||
}
|
||||
if pparent != nil {
|
||||
pparent = j.setPointerWithValue(pparent, array[i-1], s)
|
||||
} else {
|
||||
*pointer = s
|
||||
pparent = pointer
|
||||
}
|
||||
} else {
|
||||
var v interface{} = make(map[string]interface{})
|
||||
if i == length-1 {
|
||||
v = map[string]interface{}{
|
||||
array[i]: value,
|
||||
}
|
||||
}
|
||||
if pparent != nil {
|
||||
pparent = j.setPointerWithValue(pparent, array[i-1], v)
|
||||
} else {
|
||||
*pointer = v
|
||||
pparent = pointer
|
||||
}
|
||||
pointer = &v
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert <value> to map[string]interface{} or []interface{},
|
||||
// which can be supported for hierarchical data access.
|
||||
func (j *Json) convertValue(value interface{}) interface{} {
|
||||
switch value.(type) {
|
||||
case map[string]interface{}:
|
||||
return value
|
||||
case []interface{}:
|
||||
return value
|
||||
default:
|
||||
rv := reflect.ValueOf(value)
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Array: return gconv.Interfaces(value)
|
||||
case reflect.Slice: return gconv.Interfaces(value)
|
||||
case reflect.Map: return gconv.Map(value)
|
||||
case reflect.Struct: return gconv.Map(value)
|
||||
default:
|
||||
// Use json decode/encode at last.
|
||||
b, _ := Encode(value)
|
||||
v, _ := Decode(b)
|
||||
return v
|
||||
}
|
||||
}
|
||||
switch value.(type) {
|
||||
case map[string]interface{}:
|
||||
return value
|
||||
case []interface{}:
|
||||
return value
|
||||
default:
|
||||
rv := reflect.ValueOf(value)
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Array:
|
||||
return gconv.Interfaces(value)
|
||||
case reflect.Slice:
|
||||
return gconv.Interfaces(value)
|
||||
case reflect.Map:
|
||||
return gconv.Map(value)
|
||||
case reflect.Struct:
|
||||
return gconv.Map(value)
|
||||
default:
|
||||
// Use json decode/encode at last.
|
||||
b, _ := Encode(value)
|
||||
v, _ := Decode(b)
|
||||
return v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set <key>:<value> to <pointer>, the <key> may be a map key or slice index.
|
||||
// It returns the pointer to the new value set.
|
||||
func (j *Json) setPointerWithValue(pointer *interface{}, key string, value interface{}) *interface{} {
|
||||
switch (*pointer).(type) {
|
||||
case map[string]interface{}:
|
||||
(*pointer).(map[string]interface{})[key] = value
|
||||
return &value
|
||||
case []interface{}:
|
||||
n, _ := strconv.Atoi(key)
|
||||
if len((*pointer).([]interface{})) > n {
|
||||
(*pointer).([]interface{})[n] = value
|
||||
return &(*pointer).([]interface{})[n]
|
||||
} else {
|
||||
s := make([]interface{}, n + 1)
|
||||
copy(s, (*pointer).([]interface{}))
|
||||
s[n] = value
|
||||
*pointer = s
|
||||
return &s[n]
|
||||
}
|
||||
default:
|
||||
*pointer = value
|
||||
}
|
||||
return pointer
|
||||
switch (*pointer).(type) {
|
||||
case map[string]interface{}:
|
||||
(*pointer).(map[string]interface{})[key] = value
|
||||
return &value
|
||||
case []interface{}:
|
||||
n, _ := strconv.Atoi(key)
|
||||
if len((*pointer).([]interface{})) > n {
|
||||
(*pointer).([]interface{})[n] = value
|
||||
return &(*pointer).([]interface{})[n]
|
||||
} else {
|
||||
s := make([]interface{}, n+1)
|
||||
copy(s, (*pointer).([]interface{}))
|
||||
s[n] = value
|
||||
*pointer = s
|
||||
return &s[n]
|
||||
}
|
||||
default:
|
||||
*pointer = value
|
||||
}
|
||||
return pointer
|
||||
}
|
||||
|
||||
// Get a pointer to the value by specified <pattern>.
|
||||
func (j *Json) getPointerByPattern(pattern string) *interface{} {
|
||||
if j.vc {
|
||||
return j.getPointerByPatternWithViolenceCheck(pattern)
|
||||
} else {
|
||||
return j.getPointerByPatternWithoutViolenceCheck(pattern)
|
||||
}
|
||||
if j.vc {
|
||||
return j.getPointerByPatternWithViolenceCheck(pattern)
|
||||
} else {
|
||||
return j.getPointerByPatternWithoutViolenceCheck(pattern)
|
||||
}
|
||||
}
|
||||
|
||||
// Get a pointer to the value of specified <pattern> with violence check.
|
||||
func (j *Json) getPointerByPatternWithViolenceCheck(pattern string) *interface{} {
|
||||
if !j.vc {
|
||||
return j.getPointerByPatternWithoutViolenceCheck(pattern)
|
||||
}
|
||||
index := len(pattern)
|
||||
start := 0
|
||||
length := 0
|
||||
pointer := j.p
|
||||
if index == 0 {
|
||||
return pointer
|
||||
}
|
||||
for {
|
||||
if r := j.checkPatternByPointer(pattern[start:index], pointer); r != nil {
|
||||
length += index - start
|
||||
if start > 0 {
|
||||
length += 1
|
||||
}
|
||||
start = index + 1
|
||||
index = len(pattern)
|
||||
if length == len(pattern) {
|
||||
return r
|
||||
} else {
|
||||
pointer = r
|
||||
}
|
||||
} else {
|
||||
// Get the position for next separator char.
|
||||
index = strings.LastIndexByte(pattern[start:index], j.c)
|
||||
if index != -1 && length > 0 {
|
||||
index += length + 1
|
||||
}
|
||||
}
|
||||
if start >= index {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
//todo 此判断冗余
|
||||
if !j.vc {
|
||||
return j.getPointerByPatternWithoutViolenceCheck(pattern)
|
||||
}
|
||||
index := len(pattern)
|
||||
start := 0
|
||||
length := 0
|
||||
pointer := j.p
|
||||
if index == 0 {
|
||||
return pointer
|
||||
}
|
||||
for {
|
||||
if r := j.checkPatternByPointer(pattern[start:index], pointer); r != nil {
|
||||
length += index - start
|
||||
if start > 0 {
|
||||
length += 1
|
||||
}
|
||||
start = index + 1
|
||||
index = len(pattern)
|
||||
if length == len(pattern) {
|
||||
return r
|
||||
} else {
|
||||
pointer = r
|
||||
}
|
||||
} else {
|
||||
// Get the position for next separator char.
|
||||
index = strings.LastIndexByte(pattern[start:index], j.c)
|
||||
if index != -1 && length > 0 {
|
||||
index += length + 1
|
||||
}
|
||||
}
|
||||
if start >= index {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get a pointer to the value of specified <pattern>, with no violence check.
|
||||
func (j *Json) getPointerByPatternWithoutViolenceCheck(pattern string) *interface{} {
|
||||
if j.vc {
|
||||
return j.getPointerByPatternWithViolenceCheck(pattern)
|
||||
}
|
||||
pointer := j.p
|
||||
if len(pattern) == 0 {
|
||||
return pointer
|
||||
}
|
||||
array := strings.Split(pattern, string(j.c))
|
||||
for k, v := range array {
|
||||
if r := j.checkPatternByPointer(v, pointer); r != nil {
|
||||
if k == len(array) - 1 {
|
||||
return r
|
||||
} else {
|
||||
pointer = r
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
//todo 此判断冗余
|
||||
if j.vc {
|
||||
return j.getPointerByPatternWithViolenceCheck(pattern)
|
||||
}
|
||||
pointer := j.p
|
||||
if len(pattern) == 0 {
|
||||
return pointer
|
||||
}
|
||||
array := strings.Split(pattern, string(j.c))
|
||||
for k, v := range array {
|
||||
if r := j.checkPatternByPointer(v, pointer); r != nil {
|
||||
if k == len(array)-1 {
|
||||
return r
|
||||
} else {
|
||||
pointer = r
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check whether there's value by <key> in specified <pointer>.
|
||||
// It returns a pointer to the value.
|
||||
func (j *Json) checkPatternByPointer(key string, pointer *interface{}) *interface{} {
|
||||
switch (*pointer).(type) {
|
||||
case map[string]interface{}:
|
||||
if v, ok := (*pointer).(map[string]interface{})[key]; ok {
|
||||
return &v
|
||||
}
|
||||
case []interface{}:
|
||||
if gstr.IsNumeric(key) {
|
||||
n, err := strconv.Atoi(key)
|
||||
if err == nil && len((*pointer).([]interface{})) > n {
|
||||
return &(*pointer).([]interface{})[n]
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
switch (*pointer).(type) {
|
||||
case map[string]interface{}:
|
||||
if v, ok := (*pointer).(map[string]interface{})[key]; ok {
|
||||
return &v
|
||||
}
|
||||
case []interface{}:
|
||||
if gstr.IsNumeric(key) {
|
||||
n, err := strconv.Atoi(key)
|
||||
if err == nil && len((*pointer).([]interface{})) > n {
|
||||
return &(*pointer).([]interface{})[n]
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -377,3 +377,86 @@ func Test_Convert2(t *testing.T) {
|
||||
gtest.Assert(len(j.ToArray()), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.New(`{"name":"gf","time":"2019-06-12"}`)
|
||||
j.SetViolenceCheck(true)
|
||||
gtest.Assert(j.Get("").(g.Map)["name"], "gf")
|
||||
gtest.Assert(j.Get("").(g.Map)["name1"], nil)
|
||||
j.SetViolenceCheck(false)
|
||||
gtest.Assert(j.Get("").(g.Map)["name"], "gf")
|
||||
|
||||
err := j.Set("name", "gf1")
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("name"), "gf1")
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Set("\"0\".1", 11)
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("1"), 11)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Set("11111111111111111111111", 11)
|
||||
gtest.Assert(err == nil, false)
|
||||
|
||||
//此测试用例测出bug,数组下表越界,暂且注释起来,
|
||||
/*j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("1")
|
||||
gtest.Assert(err == nil, false)
|
||||
gtest.Assert(j.Get("0"), nil)*/
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("3")
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("0"), 1)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("0.3")
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(len(j.Get("0").([]interface{})), 3)
|
||||
|
||||
j = gjson.New(`[1,2,3]`)
|
||||
err = j.Remove("0.a")
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(len(j.Get("0").(g.Map)), 0)
|
||||
|
||||
name := struct {
|
||||
Name string
|
||||
}{Name: "gf"}
|
||||
j = gjson.New(name)
|
||||
gtest.Assert(j.Get("Name"), "gf")
|
||||
err = j.Remove("Name")
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("Name"), nil)
|
||||
|
||||
err = j.Set("Name", "gf1")
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("Name"), "gf1")
|
||||
|
||||
j = gjson.New(nil)
|
||||
err = j.Remove("Name")
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("Name"), nil)
|
||||
|
||||
j = gjson.New(name)
|
||||
gtest.Assert(j.Get("Name"), "gf")
|
||||
err = j.Set("Name1", g.Map{"Name": "gf1"})
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("Name1").(g.Map)["Name"], "gf1")
|
||||
err = j.Set("Name2", g.Slice{1, 2, 3})
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("Name2").(g.Slice)[0], 1)
|
||||
err = j.Set("Name3", name)
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("Name3").(g.Map)["Name"], "gf")
|
||||
err = j.Set("Name4", &name)
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("Name4").(g.Map)["Name"], "gf")
|
||||
arr := [3]int{1, 2, 3}
|
||||
err = j.Set("Name5", arr)
|
||||
gtest.Assert(err == nil, true)
|
||||
gtest.Assert(j.Get("Name5").(g.Array)[0], 1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -185,11 +185,9 @@ func Test_Load_Basic(t *testing.T) {
|
||||
gtest.Assert(j.Value(), nil)
|
||||
|
||||
j, err = gjson.LoadContent(`{"name": "gf"}`)
|
||||
t.Log(err)
|
||||
gtest.Assert(err == nil, true)
|
||||
|
||||
j, err = gjson.LoadContent(`{"name": "gf"""}`)
|
||||
t.Log(err)
|
||||
gtest.Assert(err == nil, false)
|
||||
|
||||
j = gjson.New(&g.Map{"name": "gf"})
|
||||
|
||||
Reference in New Issue
Block a user