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  }