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