github.com/bytedance/go-tagexpr/v2@v2.9.8/binding/gjson/gjson_test.go (about) 1 package gjson 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "math/rand" 7 "reflect" 8 "sync" 9 "testing" 10 11 "github.com/andeya/ameda" 12 "github.com/stretchr/testify/assert" 13 14 "github.com/bytedance/go-tagexpr/v2/binding/gjson/internal/rt" 15 ) 16 17 func TestMap(t *testing.T) { 18 type X struct { 19 M1 map[string]interface{} 20 M2 map[string]struct { 21 A string 22 B int 23 } 24 M3 map[string]*struct { 25 A string 26 B int 27 } 28 } 29 x := X{ 30 M1: map[string]interface{}{"i": float64(9), "j": "*"}, 31 M2: map[string]struct { 32 A string 33 B int 34 }{"k2": {"a2", 12}}, 35 M3: map[string]*struct { 36 A string 37 B int 38 }{"k3": {"a2", 13}}, 39 } 40 data, _ := json.MarshalIndent(x, "", " ") 41 t.Log(string(data)) 42 43 var x2 X 44 45 err := Unmarshal(data, &x2) 46 assert.NoError(t, err) 47 assert.Equal(t, x, x2) 48 49 data = []byte(`{ 50 "M1": { 51 "i": 9, 52 "j": "*" 53 }, 54 "M2": { 55 "k2": { 56 "A": "a2", 57 "B": 12 58 } 59 }, 60 "M3": { 61 "k3": { 62 "A": "a2", 63 "B": "13" 64 } 65 } 66 }`) 67 68 var x3 *X 69 err = Unmarshal(data, &x3) 70 assert.NoError(t, err) 71 assert.Equal(t, x, *x3) 72 } 73 74 func TestStruct(t *testing.T) { 75 type a struct { 76 V int `json:"v"` 77 } 78 type B struct { 79 a 80 A2 **a 81 } 82 type C struct { 83 *B `json:"b"` 84 } 85 type D struct { 86 *C `json:","` 87 C2 *int 88 } 89 type E struct { 90 D 91 K int `json:"k"` 92 int 93 } 94 data := []byte(`{ 95 "k":1, 96 "C2":null, 97 "b":{"v":2,"A2":{"v":3}} 98 }`) 99 std := &E{} 100 err := json.Unmarshal(data, std) 101 if assert.NoError(t, err) { 102 assert.Equal(t, 1, std.K) 103 assert.Equal(t, 2, std.V) 104 assert.Equal(t, 3, (*std.A2).V) 105 } 106 g := &E{} 107 err = Unmarshal(data, g) 108 assert.NoError(t, err) 109 assert.Equal(t, std, g) 110 111 type X struct { 112 *X 113 Y int 114 } 115 data2 := []byte(`{"X":{"Y":2}}`) 116 std2 := &X{} 117 err = json.Unmarshal(data2, std2) 118 if assert.NoError(t, err) { 119 t.Logf("%#v", std2) 120 } 121 g2 := &X{} 122 err = Unmarshal(data2, g2) 123 assert.NoError(t, err) 124 assert.Equal(t, std2, g2) 125 } 126 127 func TestAliasBUG1(t *testing.T) { 128 type DeviceUUID string 129 type DeviceUUIDMap map[DeviceUUID]string 130 type AttachedMobiles struct { 131 AttachedAndroid DeviceUUIDMap `json:"android,omitempty"` 132 AttachedIOS DeviceUUIDMap `json:"ios,omitempty"` 133 } 134 b, err := json.MarshalIndent(ameda.InitSampleValue(reflect.TypeOf(AttachedMobiles{}), 10).Interface(), "", " ") 135 assert.NoError(t, err) 136 var r AttachedMobiles 137 err = Unmarshal(b, &r) 138 assert.NoError(t, err) 139 // b, err = json.Marshal(map[float32]int{ 140 // 1.0: 4, 141 // }) 142 // assert.NoError(t, err) 143 // t.Log(string(b)) 144 } 145 146 func TestBingSliceWithObject(t *testing.T) { 147 type F struct { 148 UID int64 149 } 150 type foo struct { 151 F1 []F `json:"f1"` 152 F2 []F `json:"f2"` 153 } 154 str := `{"f1":{"UID":1},"f2":[{"UID":"2233"}]}` 155 156 obj := foo{} 157 err := Unmarshal([]byte(str), &obj) 158 159 assert.NoError(t, err) 160 assert.Len(t, obj.F1, 0) 161 } 162 func BenchmarkGetFiledInfo(b *testing.B) { 163 var types []reflect.Type 164 const count = 2000 165 for i := 0; i < count; i++ { 166 xtype := genStruct(i) 167 168 getFiledInfo(xtype) 169 170 types = append(types, xtype) 171 } 172 b.ResetTimer() 173 b.RunParallel(func(pb *testing.PB) { 174 var i int64 175 for pb.Next() { 176 getFiledInfo(types[i%count]) 177 i++ 178 } 179 }) 180 } 181 func BenchmarkGetFieldInfoByMap(b *testing.B) { 182 var types []reflect.Type 183 const count = 2000 184 for i := 0; i < count; i++ { 185 xtype := genStruct(i) 186 187 getFiledInfoWithMap(xtype) 188 189 types = append(types, xtype) 190 } 191 b.ResetTimer() 192 b.RunParallel(func(pb *testing.PB) { 193 var i int64 194 for pb.Next() { 195 getFiledInfoWithMap(types[i%count]) 196 i++ 197 } 198 }) 199 } 200 201 func genStruct(n int) reflect.Type { 202 numOfFields := rand.Intn(50) + 1 203 field := make([]reflect.StructField, 0, numOfFields) 204 for i := 0; i < numOfFields; i++ { 205 field = append(field, reflect.StructField{ 206 Name: fmt.Sprintf("F%d_%d", n, i), 207 PkgPath: "", 208 Type: reflect.TypeOf(struct { 209 A int 210 B map[int]interface{} 211 }{}), 212 }) 213 } 214 ot := reflect.StructOf(field) 215 return ot 216 } 217 218 var fieldsmu sync.RWMutex 219 var fields = make(map[uintptr]map[string][]int) 220 221 func getFiledInfoWithMap(t reflect.Type) map[string][]int { 222 223 runtimeTypeID := ameda.RuntimeTypeID(t) 224 fieldsmu.RLock() 225 sf := fields[runtimeTypeID] 226 fieldsmu.RUnlock() 227 if sf == nil { 228 fieldsmu.Lock() 229 defer fieldsmu.Unlock() 230 231 d := rt.UnpackType(t) 232 sf1, _ := computeTypeInfo(d) 233 sf = sf1.(map[string][]int) 234 fields[runtimeTypeID] = sf 235 236 } 237 return sf 238 } 239 240 // MarshalJSON to output non base64 encoded []byte 241 func (j ByteSlice) MarshalJSON() ([]byte, error) { 242 if len(j) == 0 { 243 return []byte("null"), nil 244 } 245 246 return json.RawMessage(j).MarshalJSON() 247 } 248 249 // UnmarshalJSON to deserialize []byte 250 func (j *ByteSlice) UnmarshalJSON(b []byte) error { 251 result := json.RawMessage{} 252 err := result.UnmarshalJSON(b) 253 *j = ByteSlice(result) 254 return err 255 } 256 257 type ByteSlice []byte 258 259 func TestCustomizedGjsonUnmarshal(t *testing.T) { 260 str := `{"h1":{"h2":1}}` 261 type F struct { 262 H ByteSlice `json:"h1"` 263 } 264 265 obj := F{} 266 err := Unmarshal([]byte(str), &obj) 267 268 assert.NoError(t, err) 269 assert.Equal(t, "{\"h2\":1}", string(obj.H)) 270 271 obj2 := F{} 272 err = json.Unmarshal([]byte(str), &obj2) 273 assert.NoError(t, err) 274 assert.Equal(t, "{\"h2\":1}", string(obj2.H)) 275 276 assert.Equal(t, obj.H, obj2.H) 277 }