github.com/fufuok/utils@v1.0.10/xjson/sjson/sjson_test.go (about) 1 package sjson 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "math/rand" 7 "testing" 8 "time" 9 10 "github.com/fufuok/utils/xjson/gjson" 11 "github.com/fufuok/utils/xjson/pretty" 12 ) 13 14 const ( 15 setRaw = 1 16 setBool = 2 17 setInt = 3 18 setFloat = 4 19 setString = 5 20 setDelete = 6 21 ) 22 23 func sortJSON(json string) string { 24 opts := pretty.Options{SortKeys: true} 25 return string(pretty.Ugly(pretty.PrettyOptions([]byte(json), &opts))) 26 } 27 28 func testRaw(t *testing.T, kind int, expect, json, path string, value interface{}) { 29 t.Helper() 30 expect = sortJSON(expect) 31 var json2 string 32 var err error 33 switch kind { 34 default: 35 json2, err = Set(json, path, value) 36 case setRaw: 37 json2, err = SetRaw(json, path, value.(string)) 38 case setDelete: 39 json2, err = Delete(json, path) 40 } 41 42 if err != nil { 43 t.Fatal(err) 44 } 45 json2 = sortJSON(json2) 46 if json2 != expect { 47 t.Fatalf("expected '%v', got '%v'", expect, json2) 48 } 49 var json3 []byte 50 switch kind { 51 default: 52 json3, err = SetBytes([]byte(json), path, value) 53 case setRaw: 54 json3, err = SetRawBytes([]byte(json), path, []byte(value.(string))) 55 case setDelete: 56 json3, err = DeleteBytes([]byte(json), path) 57 } 58 json3 = []byte(sortJSON(string(json3))) 59 if err != nil { 60 t.Fatal(err) 61 } else if string(json3) != expect { 62 t.Fatalf("expected '%v', got '%v'", expect, string(json3)) 63 } 64 } 65 66 func TestBasic(t *testing.T) { 67 testRaw(t, setRaw, `[{"hiw":"planet","hi":"world"}]`, `[{"hi":"world"}]`, "0.hiw", `"planet"`) 68 testRaw(t, setRaw, `[true]`, ``, "0", `true`) 69 testRaw(t, setRaw, `[null,true]`, ``, "1", `true`) 70 testRaw(t, setRaw, `[1,null,true]`, `[1]`, "2", `true`) 71 testRaw(t, setRaw, `[1,true,false]`, `[1,null,false]`, "1", `true`) 72 testRaw(t, setRaw, 73 `[1,{"hello":"when","this":[0,null,2]},false]`, 74 `[1,{"hello":"when","this":[0,1,2]},false]`, 75 "1.this.1", `null`) 76 testRaw(t, setRaw, 77 `{"a":1,"b":{"hello":"when","this":[0,null,2]},"c":false}`, 78 `{"a":1,"b":{"hello":"when","this":[0,1,2]},"c":false}`, 79 "b.this.1", `null`) 80 testRaw(t, setRaw, 81 `{"a":1,"b":{"hello":"when","this":[0,null,2,null,4]},"c":false}`, 82 `{"a":1,"b":{"hello":"when","this":[0,null,2]},"c":false}`, 83 "b.this.4", `4`) 84 testRaw(t, setRaw, 85 `{"b":{"this":[null,null,null,null,4]}}`, 86 ``, 87 "b.this.4", `4`) 88 testRaw(t, setRaw, 89 `[null,{"this":[null,null,null,null,4]}]`, 90 ``, 91 "1.this.4", `4`) 92 testRaw(t, setRaw, 93 `{"1":{"this":[null,null,null,null,4]}}`, 94 ``, 95 ":1.this.4", `4`) 96 testRaw(t, setRaw, 97 `{":1":{"this":[null,null,null,null,4]}}`, 98 ``, 99 "\\:1.this.4", `4`) 100 testRaw(t, setRaw, 101 `{":\\1":{"this":[null,null,null,null,{".HI":4}]}}`, 102 ``, 103 "\\:\\\\1.this.4.\\.HI", `4`) 104 testRaw(t, setRaw, 105 `{"app.token":"cde"}`, 106 `{"app.token":"abc"}`, 107 "app\\.token", `"cde"`) 108 testRaw(t, setRaw, 109 `{"b":{"this":{"😇":""}}}`, 110 ``, 111 "b.this.😇", `""`) 112 testRaw(t, setRaw, 113 `[ 1,2 ,3]`, 114 ` [ 1,2 ] `, 115 "-1", `3`) 116 testRaw(t, setInt, `[1234]`, ``, `0`, int64(1234)) 117 testRaw(t, setFloat, `[1234.5]`, ``, `0`, float64(1234.5)) 118 testRaw(t, setString, `["1234.5"]`, ``, `0`, "1234.5") 119 testRaw(t, setBool, `[true]`, ``, `0`, true) 120 testRaw(t, setBool, `[null]`, ``, `0`, nil) 121 testRaw(t, setString, `{"arr":[1]}`, ``, `arr.-1`, 1) 122 testRaw(t, setString, `{"a":"\\"}`, ``, `a`, "\\") 123 testRaw(t, setString, `{"a":"C:\\Windows\\System32"}`, ``, `a`, `C:\Windows\System32`) 124 } 125 126 func TestDelete(t *testing.T) { 127 testRaw(t, setDelete, `[456]`, `[123,456]`, `0`, nil) 128 testRaw(t, setDelete, `[123,789]`, `[123,456,789]`, `1`, nil) 129 testRaw(t, setDelete, `[123,456]`, `[123,456,789]`, `-1`, nil) 130 testRaw(t, setDelete, `{"a":[123,456]}`, `{"a":[123,456,789]}`, `a.-1`, nil) 131 testRaw(t, setDelete, `{"and":"another"}`, `{"this":"that","and":"another"}`, `this`, nil) 132 testRaw(t, setDelete, `{"this":"that"}`, `{"this":"that","and":"another"}`, `and`, nil) 133 testRaw(t, setDelete, `{}`, `{"and":"another"}`, `and`, nil) 134 testRaw(t, setDelete, `{"1":"2"}`, `{"1":"2"}`, `3`, nil) 135 } 136 137 // TestRandomData is a fuzzing test that throws random data at SetRaw 138 // function looking for panics. 139 func TestRandomData(t *testing.T) { 140 var lstr string 141 defer func() { 142 if v := recover(); v != nil { 143 println("'" + hex.EncodeToString([]byte(lstr)) + "'") 144 println("'" + lstr + "'") 145 panic(v) 146 } 147 }() 148 rand.Seed(time.Now().UnixNano()) 149 b := make([]byte, 200) 150 for i := 0; i < 2000000; i++ { 151 n, err := rand.Read(b[:rand.Int()%len(b)]) 152 if err != nil { 153 t.Fatal(err) 154 } 155 lstr = string(b[:n]) 156 SetRaw(lstr, "zzzz.zzzz.zzzz", "123") 157 } 158 } 159 160 func TestDeleteIssue21(t *testing.T) { 161 json := `{"country_code_from":"NZ","country_code_to":"SA","date_created":"2018-09-13T02:56:11.25783Z","date_updated":"2018-09-14T03:15:16.67356Z","disabled":false,"last_edited_by":"Developers","id":"a3e...bc454","merchant_id":"f2b...b91abf","signed_date":"2018-02-01T00:00:00Z","start_date":"2018-03-01T00:00:00Z","url":"https://www.google.com"}` 162 res1 := gjson.Get(json, "date_updated") 163 var err error 164 json, err = Delete(json, "date_updated") 165 if err != nil { 166 t.Fatal(err) 167 } 168 res2 := gjson.Get(json, "date_updated") 169 res3 := gjson.Get(json, "date_created") 170 if !res1.Exists() || res2.Exists() || !res3.Exists() { 171 t.Fatal("bad news") 172 } 173 174 // We change the number of characters in this to make the section of the string before the section that we want to delete a certain length 175 176 // --------------------------- 177 lenBeforeToDeleteIs307AsBytes := `{"1":"","0":"012345678901234567890123456789012345678901234567890123456789012345678901234567","to_delete":"0","2":""}` 178 179 expectedForLenBefore307AsBytes := `{"1":"","0":"012345678901234567890123456789012345678901234567890123456789012345678901234567","2":""}` 180 // --------------------------- 181 182 // --------------------------- 183 lenBeforeToDeleteIs308AsBytes := `{"1":"","0":"0123456789012345678901234567890123456789012345678901234567890123456789012345678","to_delete":"0","2":""}` 184 185 expectedForLenBefore308AsBytes := `{"1":"","0":"0123456789012345678901234567890123456789012345678901234567890123456789012345678","2":""}` 186 // --------------------------- 187 188 // --------------------------- 189 lenBeforeToDeleteIs309AsBytes := `{"1":"","0":"01234567890123456789012345678901234567890123456789012345678901234567890123456","to_delete":"0","2":""}` 190 191 expectedForLenBefore309AsBytes := `{"1":"","0":"01234567890123456789012345678901234567890123456789012345678901234567890123456","2":""}` 192 // --------------------------- 193 194 data := []struct { 195 desc string 196 input string 197 expected string 198 }{ 199 { 200 desc: "len before \"to_delete\"... = 307", 201 input: lenBeforeToDeleteIs307AsBytes, 202 expected: expectedForLenBefore307AsBytes, 203 }, 204 { 205 desc: "len before \"to_delete\"... = 308", 206 input: lenBeforeToDeleteIs308AsBytes, 207 expected: expectedForLenBefore308AsBytes, 208 }, 209 { 210 desc: "len before \"to_delete\"... = 309", 211 input: lenBeforeToDeleteIs309AsBytes, 212 expected: expectedForLenBefore309AsBytes, 213 }, 214 } 215 216 for i, d := range data { 217 result, err := Delete(d.input, "to_delete") 218 if err != nil { 219 t.Error(fmtErrorf(testError{ 220 unexpected: "error", 221 desc: d.desc, 222 i: i, 223 lenInput: len(d.input), 224 input: d.input, 225 expected: d.expected, 226 result: result, 227 })) 228 } 229 if result != d.expected { 230 t.Error(fmtErrorf(testError{ 231 unexpected: "result", 232 desc: d.desc, 233 i: i, 234 lenInput: len(d.input), 235 input: d.input, 236 expected: d.expected, 237 result: result, 238 })) 239 } 240 } 241 } 242 243 type testError struct { 244 unexpected string 245 desc string 246 i int 247 lenInput int 248 input interface{} 249 expected interface{} 250 result interface{} 251 } 252 253 func fmtErrorf(e testError) string { 254 return fmt.Sprintf( 255 "Unexpected %s:\n\t"+ 256 "for=%q\n\t"+ 257 "i=%d\n\t"+ 258 "len(input)=%d\n\t"+ 259 "input=%v\n\t"+ 260 "expected=%v\n\t"+ 261 "result=%v", 262 e.unexpected, e.desc, e.i, e.lenInput, e.input, e.expected, e.result, 263 ) 264 } 265 266 func TestSetDotKeyIssue10(t *testing.T) { 267 json := `{"app.token":"abc"}` 268 json, _ = Set(json, `app\.token`, "cde") 269 if json != `{"app.token":"cde"}` { 270 t.Fatalf("expected '%v', got '%v'", `{"app.token":"cde"}`, json) 271 } 272 } 273 274 func TestDeleteDotKeyIssue19(t *testing.T) { 275 json := []byte(`{"data":{"key1":"value1","key2.something":"value2"}}`) 276 json, _ = DeleteBytes(json, `data.key2\.something`) 277 if string(json) != `{"data":{"key1":"value1"}}` { 278 t.Fatalf("expected '%v', got '%v'", `{"data":{"key1":"value1"}}`, json) 279 } 280 } 281 282 func TestIssue36(t *testing.T) { 283 json := ` 284 { 285 "size": 1000 286 } 287 ` 288 raw := ` 289 { 290 "sample": "hello" 291 } 292 ` 293 _ = raw 294 if true { 295 json, _ = SetRaw(json, "aggs", raw) 296 } 297 if !gjson.Valid(json) { 298 t.Fatal("invalid json") 299 } 300 res := gjson.Get(json, "aggs.sample").String() 301 if res != "hello" { 302 t.Fatal("unexpected result") 303 } 304 } 305 306 var example = ` 307 { 308 "name": {"first": "Tom", "last": "Anderson"}, 309 "age":37, 310 "children": ["Sara","Alex","Jack"], 311 "fav.movie": "Deer Hunter", 312 "friends": [ 313 {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]}, 314 {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]}, 315 {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]} 316 ] 317 } 318 ` 319 320 func TestIndex(t *testing.T) { 321 path := `friends.#(last="Murphy").last` 322 json, err := Set(example, path, "Johnson") 323 if err != nil { 324 t.Fatal(err) 325 } 326 if gjson.Get(json, "friends.#.last").String() != `["Johnson","Craig","Murphy"]` { 327 t.Fatal("mismatch") 328 } 329 } 330 331 func TestIndexes(t *testing.T) { 332 path := `friends.#(last="Murphy")#.last` 333 json, err := Set(example, path, "Johnson") 334 if err != nil { 335 t.Fatal(err) 336 } 337 if gjson.Get(json, "friends.#.last").String() != `["Johnson","Craig","Johnson"]` { 338 t.Fatal("mismatch") 339 } 340 }