github.com/youryharchenko/gjson@v0.0.0-20161216162241-e3f249f4fdf3/gjson_test.go (about)

     1  package gjson
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"math/rand"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/buger/jsonparser"
    15  	"github.com/mailru/easyjson/jlexer"
    16  	fflib "github.com/pquerna/ffjson/fflib/v1"
    17  )
    18  
    19  // TestRandomData is a fuzzing test that throws random data at the Parse
    20  // function looking for panics.
    21  func TestRandomData(t *testing.T) {
    22  	var lstr string
    23  	defer func() {
    24  		if v := recover(); v != nil {
    25  			println("'" + hex.EncodeToString([]byte(lstr)) + "'")
    26  			println("'" + lstr + "'")
    27  			panic(v)
    28  		}
    29  	}()
    30  	rand.Seed(time.Now().UnixNano())
    31  	b := make([]byte, 200)
    32  	for i := 0; i < 2000000; i++ {
    33  		n, err := rand.Read(b[:rand.Int()%len(b)])
    34  		if err != nil {
    35  			t.Fatal(err)
    36  		}
    37  		lstr = string(b[:n])
    38  		GetBytes([]byte(lstr), "zzzz")
    39  		Parse(lstr)
    40  	}
    41  }
    42  
    43  func TestRandomValidStrings(t *testing.T) {
    44  	rand.Seed(time.Now().UnixNano())
    45  	b := make([]byte, 200)
    46  	for i := 0; i < 100000; i++ {
    47  		n, err := rand.Read(b[:rand.Int()%len(b)])
    48  		if err != nil {
    49  			t.Fatal(err)
    50  		}
    51  		sm, err := json.Marshal(string(b[:n]))
    52  		if err != nil {
    53  			t.Fatal(err)
    54  		}
    55  		var su string
    56  		if err := json.Unmarshal([]byte(sm), &su); err != nil {
    57  			t.Fatal(err)
    58  		}
    59  		token := Get(`{"str":`+string(sm)+`}`, "str")
    60  		if token.Type != String || token.Str != su {
    61  			println("["+token.Raw+"]", "["+token.Str+"]", "["+su+"]", "["+string(sm)+"]")
    62  			t.Fatal("string mismatch")
    63  		}
    64  	}
    65  }
    66  func testEscapePath(t *testing.T, json, path, expect string) {
    67  	if Get(json, path).String() != expect {
    68  		t.Fatalf("expected '%v', got '%v'", expect, Get(json, path).String())
    69  	}
    70  }
    71  
    72  func TestEscapePath(t *testing.T) {
    73  	json := `{
    74  		"test":{
    75  			"*":"valZ",
    76  			"*v":"val0",
    77  			"keyv*":"val1",
    78  			"key*v":"val2",
    79  			"keyv?":"val3",
    80  			"key?v":"val4",
    81  			"keyv.":"val5",
    82  			"key.v":"val6",
    83  			"keyk*":{"key?":"val7"}
    84  		}
    85  	}`
    86  
    87  	testEscapePath(t, json, "test.\\*", "valZ")
    88  	testEscapePath(t, json, "test.\\*v", "val0")
    89  	testEscapePath(t, json, "test.keyv\\*", "val1")
    90  	testEscapePath(t, json, "test.key\\*v", "val2")
    91  	testEscapePath(t, json, "test.keyv\\?", "val3")
    92  	testEscapePath(t, json, "test.key\\?v", "val4")
    93  	testEscapePath(t, json, "test.keyv\\.", "val5")
    94  	testEscapePath(t, json, "test.key\\.v", "val6")
    95  	testEscapePath(t, json, "test.keyk\\*.key\\?", "val7")
    96  }
    97  
    98  // this json block is poorly formed on purpose.
    99  var basicJSON = `{"age":100, "name":{"here":"B\\\"R"},
   100  	"noop":{"what is a wren?":"a bird"},
   101  	"happy":true,"immortal":false,
   102  	"items":[1,2,3,{"tags":[1,2,3],"points":[[1,2],[3,4]]},4,5,6,7],
   103  	"arr":["1",2,"3",{"hello":"world"},"4",5],
   104  	"vals":[1,2,3,{"sadf":sdf"asdf"}],"name":{"first":"tom","last":null},
   105  	"loggy":{
   106  		"programmers": [
   107      	    {
   108      	        "firstName": "Brett",
   109      	        "lastName": "McLaughlin",
   110      	        "email": "aaaa",
   111  				"tag": "good"
   112      	    },
   113      	    {
   114      	        "firstName": "Jason",
   115      	        "lastName": "Hunter",
   116      	        "email": "bbbb",
   117  				"tag": "bad"
   118      	    },
   119      	    {
   120      	        "firstName": "Elliotte",
   121      	        "lastName": "Harold",
   122      	        "email": "cccc",
   123  				"tag":, "good"
   124      	    },
   125  			{
   126  				"firstName": 1002.3,
   127  				"age": 101
   128  			}
   129      	]
   130  	}
   131  }`
   132  var basicJSONB = []byte(basicJSON)
   133  
   134  func TestByteSafety(t *testing.T) {
   135  	jsonb := []byte(`{"name":"Janet","age":38}`)
   136  	mtok := GetBytes(jsonb, "name")
   137  	if mtok.String() != "Janet" {
   138  		t.Fatalf("expected %v, got %v", "Jason", mtok.String())
   139  	}
   140  	mtok2 := GetBytes(jsonb, "age")
   141  	if mtok2.Raw != "38" {
   142  		t.Fatalf("expected %v, got %v", "Jason", mtok2.Raw)
   143  	}
   144  	jsonb[9] = 'T'
   145  	jsonb[12] = 'd'
   146  	jsonb[13] = 'y'
   147  	if mtok.String() != "Janet" {
   148  		t.Fatalf("expected %v, got %v", "Jason", mtok.String())
   149  	}
   150  }
   151  
   152  func get(json, path string) Result {
   153  	return GetBytes([]byte(basicJSONB), path)
   154  }
   155  
   156  func TestBasic(t *testing.T) {
   157  	var mtok Result
   158  	mtok = get(basicJSON, `loggy.programmers.#[tag="good"].firstName`)
   159  	if mtok.String() != "Brett" {
   160  		t.Fatalf("expected %v, got %v", "Brett", mtok.String())
   161  	}
   162  	mtok = get(basicJSON, `loggy.programmers.#[tag="good"]#.firstName`)
   163  	if mtok.String() != `["Brett","Elliotte"]` {
   164  		t.Fatalf("expected %v, got %v", `["Brett","Elliotte"]`, mtok.String())
   165  	}
   166  
   167  	mtok = get(basicJSON, `loggy.programmers`)
   168  	var count int
   169  	mtok.ForEach(func(key, value Result) bool {
   170  		if key.Exists() {
   171  			t.Fatalf("expected %v, got %v", false, key.Exists())
   172  		}
   173  		count++
   174  		if count == 3 {
   175  			return false
   176  		}
   177  		if count == 1 {
   178  			i := 0
   179  			value.ForEach(func(key, value Result) bool {
   180  				switch i {
   181  				case 0:
   182  					if key.String() != "firstName" || value.String() != "Brett" {
   183  						t.Fatalf("expected %v/%v got %v/%v", "firstName", "Brett", key.String(), value.String())
   184  					}
   185  				case 1:
   186  					if key.String() != "lastName" || value.String() != "McLaughlin" {
   187  						t.Fatalf("expected %v/%v got %v/%v", "lastName", "McLaughlin", key.String(), value.String())
   188  					}
   189  				case 2:
   190  					if key.String() != "email" || value.String() != "aaaa" {
   191  						t.Fatalf("expected %v/%v got %v/%v", "email", "aaaa", key.String(), value.String())
   192  					}
   193  				}
   194  				i++
   195  				return true
   196  			})
   197  		}
   198  		return true
   199  	})
   200  	if count != 3 {
   201  		t.Fatalf("expected %v, got %v", 3, count)
   202  	}
   203  	mtok = get(basicJSON, `loggy.programmers.#[age=101].firstName`)
   204  	if mtok.String() != "1002.3" {
   205  		t.Fatalf("expected %v, got %v", "1002.3", mtok.String())
   206  	}
   207  	mtok = get(basicJSON, `loggy.programmers.#[firstName != "Brett"].firstName`)
   208  	if mtok.String() != "Jason" {
   209  		t.Fatalf("expected %v, got %v", "Jason", mtok.String())
   210  	}
   211  	mtok = get(basicJSON, `loggy.programmers.#[firstName % "Bre*"].email`)
   212  	if mtok.String() != "aaaa" {
   213  		t.Fatalf("expected %v, got %v", "aaaa", mtok.String())
   214  	}
   215  	mtok = get(basicJSON, `loggy.programmers.#[firstName == "Brett"].email`)
   216  	if mtok.String() != "aaaa" {
   217  		t.Fatalf("expected %v, got %v", "aaaa", mtok.String())
   218  	}
   219  	mtok = get(basicJSON, "loggy")
   220  	if mtok.Type != JSON {
   221  		t.Fatalf("expected %v, got %v", JSON, mtok.Type)
   222  	}
   223  	if len(mtok.Map()) != 1 {
   224  		t.Fatalf("expected %v, got %v", 1, len(mtok.Map()))
   225  	}
   226  	programmers := mtok.Map()["programmers"]
   227  	if programmers.Array()[1].Map()["firstName"].Str != "Jason" {
   228  		t.Fatalf("expected %v, got %v", "Jason", mtok.Map()["programmers"].Array()[1].Map()["firstName"].Str)
   229  	}
   230  
   231  	if Parse(basicJSON).Get("loggy.programmers").Get("1").Get("firstName").Str != "Jason" {
   232  		t.Fatalf("expected %v, got %v", "Jason", Parse(basicJSON).Get("loggy.programmers").Get("1").Get("firstName").Str)
   233  	}
   234  	var token Result
   235  	if token = Parse("-102"); token.Num != -102 {
   236  		t.Fatal("expected %v, got %v", -102, token.Num)
   237  	}
   238  	if token = Parse("102"); token.Num != 102 {
   239  		t.Fatal("expected %v, got %v", 102, token.Num)
   240  	}
   241  	if token = Parse("102.2"); token.Num != 102.2 {
   242  		t.Fatal("expected %v, got %v", 102.2, token.Num)
   243  	}
   244  	if token = Parse(`"hello"`); token.Str != "hello" {
   245  		t.Fatal("expected %v, got %v", "hello", token.Str)
   246  	}
   247  	if token = Parse(`"\"he\nllo\""`); token.Str != "\"he\nllo\"" {
   248  		t.Fatal("expected %v, got %v", "\"he\nllo\"", token.Str)
   249  	}
   250  	mtok = get(basicJSON, "loggy.programmers.#.firstName")
   251  	if len(mtok.Array()) != 4 {
   252  		t.Fatalf("expected 4, got %v", len(mtok.Array()))
   253  	}
   254  	for i, ex := range []string{"Brett", "Jason", "Elliotte", "1002.3"} {
   255  		if mtok.Array()[i].String() != ex {
   256  			t.Fatalf("expected '%v', got '%v'", ex, mtok.Array()[i].String())
   257  		}
   258  	}
   259  	mtok = get(basicJSON, "loggy.programmers.#.asd")
   260  	if mtok.Type != JSON {
   261  		t.Fatal("expected %v, got %v", JSON, mtok.Type)
   262  	}
   263  	if len(mtok.Array()) != 0 {
   264  		t.Fatalf("expected 0, got %v", len(mtok.Array()))
   265  	}
   266  
   267  	if get(basicJSON, "items.3.tags.#").Num != 3 {
   268  		t.Fatalf("expected 3, got %v", get(basicJSON, "items.3.tags.#").Num)
   269  	}
   270  	if get(basicJSON, "items.3.points.1.#").Num != 2 {
   271  		t.Fatalf("expected 2, got %v", get(basicJSON, "items.3.points.1.#").Num)
   272  	}
   273  	if get(basicJSON, "items.#").Num != 8 {
   274  		t.Fatalf("expected 6, got %v", get(basicJSON, "items.#").Num)
   275  	}
   276  	if get(basicJSON, "vals.#").Num != 4 {
   277  		t.Fatalf("expected 4, got %v", get(basicJSON, "vals.#").Num)
   278  	}
   279  	if !get(basicJSON, "name.last").Exists() {
   280  		t.Fatal("expected true, got false")
   281  	}
   282  	token = get(basicJSON, "name.here")
   283  	if token.String() != "B\\\"R" {
   284  		t.Fatal("expecting 'B\\\"R'", "got", token.String())
   285  	}
   286  	token = get(basicJSON, "arr.#")
   287  	if token.String() != "6" {
   288  		t.Fatal("expecting '6'", "got", token.String())
   289  	}
   290  	token = get(basicJSON, "arr.3.hello")
   291  	if token.String() != "world" {
   292  		t.Fatal("expecting 'world'", "got", token.String())
   293  	}
   294  	_ = token.Value().(string)
   295  	token = get(basicJSON, "name.first")
   296  	if token.String() != "tom" {
   297  		t.Fatal("expecting 'tom'", "got", token.String())
   298  	}
   299  	_ = token.Value().(string)
   300  	token = get(basicJSON, "name.last")
   301  	if token.String() != "null" {
   302  		t.Fatal("expecting 'null'", "got", token.String())
   303  	}
   304  	if token.Value() != nil {
   305  		t.Fatal("should be nil")
   306  	}
   307  	token = get(basicJSON, "age")
   308  	if token.String() != "100" {
   309  		t.Fatal("expecting '100'", "got", token.String())
   310  	}
   311  	_ = token.Value().(float64)
   312  	token = get(basicJSON, "happy")
   313  	if token.String() != "true" {
   314  		t.Fatal("expecting 'true'", "got", token.String())
   315  	}
   316  	_ = token.Value().(bool)
   317  	token = get(basicJSON, "immortal")
   318  	if token.String() != "false" {
   319  		t.Fatal("expecting 'false'", "got", token.String())
   320  	}
   321  	_ = token.Value().(bool)
   322  	token = get(basicJSON, "noop")
   323  	if token.String() != `{"what is a wren?":"a bird"}` {
   324  		t.Fatal("expecting '"+`{"what is a wren?":"a bird"}`+"'", "got", token.String())
   325  	}
   326  	_ = token.Value().(map[string]interface{})
   327  
   328  	if get(basicJSON, "").Value() != nil {
   329  		t.Fatal("should be nil")
   330  	}
   331  
   332  	get(basicJSON, "vals.hello")
   333  
   334  	mm := Parse(basicJSON).Value().(map[string]interface{})
   335  	fn := mm["loggy"].(map[string]interface{})["programmers"].([]interface{})[1].(map[string]interface{})["firstName"].(string)
   336  	if fn != "Jason" {
   337  		t.Fatalf("expecting %v, got %v", "Jason", fn)
   338  	}
   339  }
   340  func TestUnicode(t *testing.T) {
   341  	var json = `{"key":0,"的情况下解":{"key":1,"的情况":2}}`
   342  	if Get(json, "的情况下解.key").Num != 1 {
   343  		t.Fatal("fail")
   344  	}
   345  	if Get(json, "的情况下解.的情况").Num != 2 {
   346  		t.Fatal("fail")
   347  	}
   348  	if Get(json, "的情况下解.的?况").Num != 2 {
   349  		t.Fatal("fail")
   350  	}
   351  	if Get(json, "的情况下解.的?*").Num != 2 {
   352  		t.Fatal("fail")
   353  	}
   354  	if Get(json, "的情况下解.*?况").Num != 2 {
   355  		t.Fatal("fail")
   356  	}
   357  	if Get(json, "的情?下解.*?况").Num != 2 {
   358  		t.Fatal("fail")
   359  	}
   360  	if Get(json, "的情下解.*?况").Num != 0 {
   361  		t.Fatal("fail")
   362  	}
   363  }
   364  
   365  func TestUnescape(t *testing.T) {
   366  	unescape(string([]byte{'\\', '\\', 0}))
   367  	unescape(string([]byte{'\\', '/', '\\', 'b', '\\', 'f'}))
   368  }
   369  func assert(t testing.TB, cond bool) {
   370  	if !cond {
   371  		t.Fatal("assert failed")
   372  	}
   373  }
   374  func TestLess(t *testing.T) {
   375  	assert(t, !Result{Type: Null}.Less(Result{Type: Null}, true))
   376  	assert(t, Result{Type: Null}.Less(Result{Type: False}, true))
   377  	assert(t, Result{Type: Null}.Less(Result{Type: True}, true))
   378  	assert(t, Result{Type: Null}.Less(Result{Type: JSON}, true))
   379  	assert(t, Result{Type: Null}.Less(Result{Type: Number}, true))
   380  	assert(t, Result{Type: Null}.Less(Result{Type: String}, true))
   381  	assert(t, !Result{Type: False}.Less(Result{Type: Null}, true))
   382  	assert(t, Result{Type: False}.Less(Result{Type: True}, true))
   383  	assert(t, Result{Type: String, Str: "abc"}.Less(Result{Type: String, Str: "bcd"}, true))
   384  	assert(t, Result{Type: String, Str: "ABC"}.Less(Result{Type: String, Str: "abc"}, true))
   385  	assert(t, !Result{Type: String, Str: "ABC"}.Less(Result{Type: String, Str: "abc"}, false))
   386  	assert(t, Result{Type: Number, Num: 123}.Less(Result{Type: Number, Num: 456}, true))
   387  	assert(t, !Result{Type: Number, Num: 456}.Less(Result{Type: Number, Num: 123}, true))
   388  	assert(t, !Result{Type: Number, Num: 456}.Less(Result{Type: Number, Num: 456}, true))
   389  	assert(t, stringLessInsensitive("abcde", "BBCDE"))
   390  	assert(t, stringLessInsensitive("abcde", "bBCDE"))
   391  	assert(t, stringLessInsensitive("Abcde", "BBCDE"))
   392  	assert(t, stringLessInsensitive("Abcde", "bBCDE"))
   393  	assert(t, !stringLessInsensitive("bbcde", "aBCDE"))
   394  	assert(t, !stringLessInsensitive("bbcde", "ABCDE"))
   395  	assert(t, !stringLessInsensitive("Bbcde", "aBCDE"))
   396  	assert(t, !stringLessInsensitive("Bbcde", "ABCDE"))
   397  	assert(t, !stringLessInsensitive("abcde", "ABCDE"))
   398  	assert(t, !stringLessInsensitive("Abcde", "ABCDE"))
   399  	assert(t, !stringLessInsensitive("abcde", "ABCDE"))
   400  	assert(t, !stringLessInsensitive("ABCDE", "ABCDE"))
   401  	assert(t, !stringLessInsensitive("abcde", "abcde"))
   402  	assert(t, !stringLessInsensitive("123abcde", "123Abcde"))
   403  	assert(t, !stringLessInsensitive("123Abcde", "123Abcde"))
   404  	assert(t, !stringLessInsensitive("123Abcde", "123abcde"))
   405  	assert(t, !stringLessInsensitive("123abcde", "123abcde"))
   406  	assert(t, !stringLessInsensitive("124abcde", "123abcde"))
   407  	assert(t, !stringLessInsensitive("124Abcde", "123Abcde"))
   408  	assert(t, !stringLessInsensitive("124Abcde", "123abcde"))
   409  	assert(t, !stringLessInsensitive("124abcde", "123abcde"))
   410  	assert(t, stringLessInsensitive("124abcde", "125abcde"))
   411  	assert(t, stringLessInsensitive("124Abcde", "125Abcde"))
   412  	assert(t, stringLessInsensitive("124Abcde", "125abcde"))
   413  	assert(t, stringLessInsensitive("124abcde", "125abcde"))
   414  }
   415  
   416  func TestIssue6(t *testing.T) {
   417  	data := `{
   418        "code": 0,
   419        "msg": "",
   420        "data": {
   421          "sz002024": {
   422            "qfqday": [
   423              [
   424                "2014-01-02",
   425                "8.93",
   426                "9.03",
   427                "9.17",
   428                "8.88",
   429                "621143.00"
   430              ],
   431              [
   432                "2014-01-03",
   433                "9.03",
   434                "9.30",
   435                "9.47",
   436                "8.98",
   437                "1624438.00"
   438              ]
   439            ]
   440          }
   441        }
   442      }`
   443  
   444  	var num []string
   445  	for _, v := range Get(data, "data.sz002024.qfqday.0").Array() {
   446  		num = append(num, v.String())
   447  	}
   448  	if fmt.Sprintf("%v", num) != "[2014-01-02 8.93 9.03 9.17 8.88 621143.00]" {
   449  		t.Fatalf("invalid result")
   450  	}
   451  }
   452  
   453  var exampleJSON = `{
   454  	"widget": {
   455  		"debug": "on",
   456  		"window": {
   457  			"title": "Sample Konfabulator Widget",
   458  			"name": "main_window",
   459  			"width": 500,
   460  			"height": 500
   461  		},
   462  		"image": {
   463  			"src": "Images/Sun.png",
   464  			"hOffset": 250,
   465  			"vOffset": 250,
   466  			"alignment": "center"
   467  		},
   468  		"text": {
   469  			"data": "Click Here",
   470  			"size": 36,
   471  			"style": "bold",
   472  			"vOffset": 100,
   473  			"alignment": "center",
   474  			"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
   475  		}
   476  	}
   477  }`
   478  
   479  func TestNewParse(t *testing.T) {
   480  	//fmt.Printf("%v\n", parse2(exampleJSON, "widget").String())
   481  }
   482  
   483  func TestUnmarshalMap(t *testing.T) {
   484  	var m1 = Parse(exampleJSON).Value().(map[string]interface{})
   485  	var m2 map[string]interface{}
   486  	if err := json.Unmarshal([]byte(exampleJSON), &m2); err != nil {
   487  		t.Fatal(err)
   488  	}
   489  	b1, err := json.Marshal(m1)
   490  	if err != nil {
   491  		t.Fatal(err)
   492  	}
   493  	b2, err := json.Marshal(m2)
   494  	if err != nil {
   495  		t.Fatal(err)
   496  	}
   497  	if bytes.Compare(b1, b2) != 0 {
   498  		t.Fatal("b1 != b2")
   499  	}
   500  }
   501  
   502  func TestSingleArrayValue(t *testing.T) {
   503  	var json = `{"key": "value","key2":[1,2,3,4,"A"]}`
   504  	var result = Get(json, "key")
   505  	var array = result.Array()
   506  	if len(array) != 1 {
   507  		t.Fatal("array is empty")
   508  	}
   509  	if array[0].String() != "value" {
   510  		t.Fatal("got %s, should be %s", array[0].String(), "value")
   511  	}
   512  
   513  	array = Get(json, "key2.#").Array()
   514  	if len(array) != 1 {
   515  		t.Fatal("got '%v', expected '%v'", len(array), 1)
   516  	}
   517  
   518  	array = Get(json, "key3").Array()
   519  	if len(array) != 0 {
   520  		t.Fatal("got '%v', expected '%v'", len(array), 0)
   521  	}
   522  
   523  }
   524  
   525  var manyJSON = `  {
   526  	"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
   527  	"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
   528  	"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
   529  	"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
   530  	"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
   531  	"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
   532  	"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"hello":"world"
   533  	}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
   534  	"position":{"type":"Point","coordinates":[-115.24,33.09]},
   535  	"loves":["world peace"],
   536  	"name":{"last":"Anderson","first":"Nancy"},
   537  	"age":31
   538  	"":{"a":"emptya","b":"emptyb"},
   539  	"name.last":"Yellow",
   540  	"name.first":"Cat",
   541  }`
   542  
   543  func combine(results []Result) string {
   544  	return fmt.Sprintf("%v", results)
   545  }
   546  func TestManyBasic(t *testing.T) {
   547  	testWatchForFallback = true
   548  	defer func() {
   549  		testWatchForFallback = false
   550  	}()
   551  	testMany := func(shouldFallback bool, expect string, paths ...string) {
   552  		results := GetMany(
   553  			manyJSON,
   554  			paths...,
   555  		)
   556  		if len(results) != len(paths) {
   557  			t.Fatalf("expected %v, got %v", len(paths), len(results))
   558  		}
   559  		if fmt.Sprintf("%v", results) != expect {
   560  			t.Fatalf("expected %v, got %v", expect, results)
   561  		}
   562  		return
   563  		if testLastWasFallback != shouldFallback {
   564  			t.Fatalf("expected %v, got %v", shouldFallback, testLastWasFallback)
   565  		}
   566  	}
   567  	testMany(false, "[Point]", "position.type")
   568  	testMany(false, `[emptya ["world peace"] 31]`, ".a", "loves", "age")
   569  	testMany(false, `[["world peace"]]`, "loves")
   570  	testMany(false, `[{"last":"Anderson","first":"Nancy"} Nancy]`, "name", "name.first")
   571  	testMany(true, `[null]`, strings.Repeat("a.", 40)+"hello")
   572  	res := Get(manyJSON, strings.Repeat("a.", 48)+"a")
   573  	testMany(true, `[`+res.String()+`]`, strings.Repeat("a.", 48)+"a")
   574  	// these should fallback
   575  	testMany(true, `[Cat Nancy]`, "name\\.first", "name.first")
   576  	testMany(true, `[world]`, strings.Repeat("a.", 70)+"hello")
   577  }
   578  
   579  func TestRandomMany(t *testing.T) {
   580  	var lstr string
   581  	defer func() {
   582  		if v := recover(); v != nil {
   583  			println("'" + hex.EncodeToString([]byte(lstr)) + "'")
   584  			println("'" + lstr + "'")
   585  			panic(v)
   586  		}
   587  	}()
   588  	rand.Seed(time.Now().UnixNano())
   589  	b := make([]byte, 512)
   590  	for i := 0; i < 50000; i++ {
   591  		n, err := rand.Read(b[:rand.Int()%len(b)])
   592  		if err != nil {
   593  			t.Fatal(err)
   594  		}
   595  		lstr = string(b[:n])
   596  		paths := make([]string, rand.Int()%64)
   597  		for i := range paths {
   598  			var b []byte
   599  			n := rand.Int() % 5
   600  			for j := 0; j < n; j++ {
   601  				if j > 0 {
   602  					b = append(b, '.')
   603  				}
   604  				nn := rand.Int() % 10
   605  				for k := 0; k < nn; k++ {
   606  					b = append(b, 'a'+byte(rand.Int()%26))
   607  				}
   608  			}
   609  			paths[i] = string(b)
   610  		}
   611  		GetMany(lstr, paths...)
   612  	}
   613  }
   614  
   615  type BenchStruct struct {
   616  	Widget struct {
   617  		Window struct {
   618  			Name string `json:"name"`
   619  		} `json:"window"`
   620  		Image struct {
   621  			HOffset int `json:"hOffset"`
   622  		} `json:"image"`
   623  		Text struct {
   624  			OnMouseUp string `json:"onMouseUp"`
   625  		} `json:"text"`
   626  	} `json:"widget"`
   627  }
   628  
   629  var benchPaths = []string{
   630  	"widget.window.name",
   631  	"widget.image.hOffset",
   632  	"widget.text.onMouseUp",
   633  }
   634  
   635  var benchManyPaths = []string{
   636  	"widget.window.name",
   637  	"widget.image.hOffset",
   638  	"widget.text.onMouseUp",
   639  	"widget.window.title",
   640  	"widget.image.alignment",
   641  	"widget.text.style",
   642  	"widget.window.height",
   643  	"widget.image.src",
   644  	"widget.text.data",
   645  	"widget.text.size",
   646  }
   647  
   648  func BenchmarkGJSONGet(t *testing.B) {
   649  	t.ReportAllocs()
   650  	t.ResetTimer()
   651  	for i := 0; i < t.N; i++ {
   652  		for j := 0; j < len(benchPaths); j++ {
   653  			if Get(exampleJSON, benchPaths[j]).Type == Null {
   654  				t.Fatal("did not find the value")
   655  			}
   656  		}
   657  	}
   658  	t.N *= len(benchPaths) // because we are running against 3 paths
   659  }
   660  func BenchmarkGJSONGetMany4Paths(t *testing.B) {
   661  	benchmarkGJSONGetManyN(t, 4)
   662  }
   663  func BenchmarkGJSONGetMany8Paths(t *testing.B) {
   664  	benchmarkGJSONGetManyN(t, 8)
   665  }
   666  func BenchmarkGJSONGetMany16Paths(t *testing.B) {
   667  	benchmarkGJSONGetManyN(t, 16)
   668  }
   669  func BenchmarkGJSONGetMany32Paths(t *testing.B) {
   670  	benchmarkGJSONGetManyN(t, 32)
   671  }
   672  func BenchmarkGJSONGetMany64Paths(t *testing.B) {
   673  	benchmarkGJSONGetManyN(t, 64)
   674  }
   675  func BenchmarkGJSONGetMany128Paths(t *testing.B) {
   676  	benchmarkGJSONGetManyN(t, 128)
   677  }
   678  func BenchmarkGJSONGetMany256Paths(t *testing.B) {
   679  	benchmarkGJSONGetManyN(t, 256)
   680  }
   681  func BenchmarkGJSONGetMany512Paths(t *testing.B) {
   682  	benchmarkGJSONGetManyN(t, 512)
   683  }
   684  func benchmarkGJSONGetManyN(t *testing.B, n int) {
   685  	var paths []string
   686  	for len(paths) < n {
   687  		paths = append(paths, benchManyPaths...)
   688  	}
   689  	paths = paths[:n]
   690  	t.ReportAllocs()
   691  	t.ResetTimer()
   692  	for i := 0; i < t.N; i++ {
   693  		results := GetMany(exampleJSON, paths...)
   694  		if len(results) == 0 {
   695  			t.Fatal("did not find the value")
   696  		}
   697  		for j := 0; j < len(results); j++ {
   698  			if results[j].Type == Null {
   699  				t.Fatal("did not find the value")
   700  			}
   701  		}
   702  	}
   703  	t.N *= len(paths) // because we are running against 3 paths
   704  }
   705  
   706  func BenchmarkGJSONUnmarshalMap(t *testing.B) {
   707  	t.ReportAllocs()
   708  	t.ResetTimer()
   709  	for i := 0; i < t.N; i++ {
   710  		for j := 0; j < len(benchPaths); j++ {
   711  			parts := strings.Split(benchPaths[j], ".")
   712  			m, _ := Parse(exampleJSON).Value().(map[string]interface{})
   713  			var v interface{}
   714  			for len(parts) > 0 {
   715  				part := parts[0]
   716  				if len(parts) > 1 {
   717  					m = m[part].(map[string]interface{})
   718  					if m == nil {
   719  						t.Fatal("did not find the value")
   720  					}
   721  				} else {
   722  					v = m[part]
   723  					if v == nil {
   724  						t.Fatal("did not find the value")
   725  					}
   726  				}
   727  				parts = parts[1:]
   728  			}
   729  		}
   730  	}
   731  	t.N *= len(benchPaths) // because we are running against 3 paths
   732  }
   733  
   734  func BenchmarkJSONUnmarshalMap(t *testing.B) {
   735  	t.ReportAllocs()
   736  	t.ResetTimer()
   737  	for i := 0; i < t.N; i++ {
   738  		for j := 0; j < len(benchPaths); j++ {
   739  			parts := strings.Split(benchPaths[j], ".")
   740  			var m map[string]interface{}
   741  			if err := json.Unmarshal([]byte(exampleJSON), &m); err != nil {
   742  				t.Fatal(err)
   743  			}
   744  			var v interface{}
   745  			for len(parts) > 0 {
   746  				part := parts[0]
   747  				if len(parts) > 1 {
   748  					m = m[part].(map[string]interface{})
   749  					if m == nil {
   750  						t.Fatal("did not find the value")
   751  					}
   752  				} else {
   753  					v = m[part]
   754  					if v == nil {
   755  						t.Fatal("did not find the value")
   756  					}
   757  				}
   758  				parts = parts[1:]
   759  			}
   760  		}
   761  	}
   762  	t.N *= len(benchPaths) // because we are running against 3 paths
   763  }
   764  
   765  func BenchmarkJSONUnmarshalStruct(t *testing.B) {
   766  	t.ReportAllocs()
   767  	t.ResetTimer()
   768  	for i := 0; i < t.N; i++ {
   769  		for j := 0; j < len(benchPaths); j++ {
   770  			var s BenchStruct
   771  			if err := json.Unmarshal([]byte(exampleJSON), &s); err != nil {
   772  				t.Fatal(err)
   773  			}
   774  			switch benchPaths[j] {
   775  			case "widget.window.name":
   776  				if s.Widget.Window.Name == "" {
   777  					t.Fatal("did not find the value")
   778  				}
   779  			case "widget.image.hOffset":
   780  				if s.Widget.Image.HOffset == 0 {
   781  					t.Fatal("did not find the value")
   782  				}
   783  			case "widget.text.onMouseUp":
   784  				if s.Widget.Text.OnMouseUp == "" {
   785  					t.Fatal("did not find the value")
   786  				}
   787  			}
   788  		}
   789  	}
   790  	t.N *= len(benchPaths) // because we are running against 3 paths
   791  }
   792  
   793  func BenchmarkJSONDecoder(t *testing.B) {
   794  	t.ReportAllocs()
   795  	t.ResetTimer()
   796  	for i := 0; i < t.N; i++ {
   797  		for j := 0; j < len(benchPaths); j++ {
   798  			dec := json.NewDecoder(bytes.NewBuffer([]byte(exampleJSON)))
   799  			var found bool
   800  		outer:
   801  			for {
   802  				tok, err := dec.Token()
   803  				if err != nil {
   804  					if err == io.EOF {
   805  						break
   806  					}
   807  					t.Fatal(err)
   808  				}
   809  				switch v := tok.(type) {
   810  				case string:
   811  					if found {
   812  						// break out once we find the value.
   813  						break outer
   814  					}
   815  					switch benchPaths[j] {
   816  					case "widget.window.name":
   817  						if v == "name" {
   818  							found = true
   819  						}
   820  					case "widget.image.hOffset":
   821  						if v == "hOffset" {
   822  							found = true
   823  						}
   824  					case "widget.text.onMouseUp":
   825  						if v == "onMouseUp" {
   826  							found = true
   827  						}
   828  					}
   829  				}
   830  			}
   831  			if !found {
   832  				t.Fatal("field not found")
   833  			}
   834  		}
   835  	}
   836  	t.N *= len(benchPaths) // because we are running against 3 paths
   837  }
   838  
   839  func BenchmarkFFJSONLexer(t *testing.B) {
   840  	t.ReportAllocs()
   841  	t.ResetTimer()
   842  	for i := 0; i < t.N; i++ {
   843  		for j := 0; j < len(benchPaths); j++ {
   844  			l := fflib.NewFFLexer([]byte(exampleJSON))
   845  			var found bool
   846  		outer:
   847  			for {
   848  				t := l.Scan()
   849  				if t == fflib.FFTok_eof {
   850  					break
   851  				}
   852  				if t == fflib.FFTok_string {
   853  					b, _ := l.CaptureField(t)
   854  					v := string(b)
   855  					if found {
   856  						// break out once we find the value.
   857  						break outer
   858  					}
   859  					switch benchPaths[j] {
   860  					case "widget.window.name":
   861  						if v == "\"name\"" {
   862  							found = true
   863  						}
   864  					case "widget.image.hOffset":
   865  						if v == "\"hOffset\"" {
   866  							found = true
   867  						}
   868  					case "widget.text.onMouseUp":
   869  						if v == "\"onMouseUp\"" {
   870  							found = true
   871  						}
   872  					}
   873  				}
   874  			}
   875  			if !found {
   876  				t.Fatal("field not found")
   877  			}
   878  		}
   879  	}
   880  	t.N *= len(benchPaths) // because we are running against 3 paths
   881  }
   882  
   883  func BenchmarkEasyJSONLexer(t *testing.B) {
   884  	skipCC := func(l *jlexer.Lexer, n int) {
   885  		for i := 0; i < n; i++ {
   886  			l.Skip()
   887  			l.WantColon()
   888  			l.Skip()
   889  			l.WantComma()
   890  		}
   891  	}
   892  	skipGroup := func(l *jlexer.Lexer, n int) {
   893  		l.WantColon()
   894  		l.Delim('{')
   895  		skipCC(l, n)
   896  		l.Delim('}')
   897  		l.WantComma()
   898  	}
   899  	t.ReportAllocs()
   900  	t.ResetTimer()
   901  	for i := 0; i < t.N; i++ {
   902  		for j := 0; j < len(benchPaths); j++ {
   903  			l := &jlexer.Lexer{Data: []byte(exampleJSON)}
   904  			l.Delim('{')
   905  			if l.String() == "widget" {
   906  				l.WantColon()
   907  				l.Delim('{')
   908  				switch benchPaths[j] {
   909  				case "widget.window.name":
   910  					skipCC(l, 1)
   911  					if l.String() == "window" {
   912  						l.WantColon()
   913  						l.Delim('{')
   914  						skipCC(l, 1)
   915  						if l.String() == "name" {
   916  							l.WantColon()
   917  							if l.String() == "" {
   918  								t.Fatal("did not find the value")
   919  							}
   920  						}
   921  					}
   922  				case "widget.image.hOffset":
   923  					skipCC(l, 1)
   924  					if l.String() == "window" {
   925  						skipGroup(l, 4)
   926  					}
   927  					if l.String() == "image" {
   928  						l.WantColon()
   929  						l.Delim('{')
   930  						skipCC(l, 1)
   931  						if l.String() == "hOffset" {
   932  							l.WantColon()
   933  							if l.Int() == 0 {
   934  								t.Fatal("did not find the value")
   935  							}
   936  						}
   937  					}
   938  				case "widget.text.onMouseUp":
   939  					skipCC(l, 1)
   940  					if l.String() == "window" {
   941  						skipGroup(l, 4)
   942  					}
   943  					if l.String() == "image" {
   944  						skipGroup(l, 4)
   945  					}
   946  					if l.String() == "text" {
   947  						l.WantColon()
   948  						l.Delim('{')
   949  						skipCC(l, 5)
   950  						if l.String() == "onMouseUp" {
   951  							l.WantColon()
   952  							if l.String() == "" {
   953  								t.Fatal("did not find the value")
   954  							}
   955  						}
   956  					}
   957  				}
   958  			}
   959  		}
   960  	}
   961  	t.N *= len(benchPaths) // because we are running against 3 paths
   962  }
   963  
   964  func BenchmarkJSONParserGet(t *testing.B) {
   965  	data := []byte(exampleJSON)
   966  	keys := make([][]string, 0, len(benchPaths))
   967  	for i := 0; i < len(benchPaths); i++ {
   968  		keys = append(keys, strings.Split(benchPaths[i], "."))
   969  	}
   970  	t.ReportAllocs()
   971  	t.ResetTimer()
   972  	for i := 0; i < t.N; i++ {
   973  		for j, k := range keys {
   974  			if j == 1 {
   975  				// "widget.image.hOffset" is a number
   976  				v, _ := jsonparser.GetInt(data, k...)
   977  				if v == 0 {
   978  					t.Fatal("did not find the value")
   979  				}
   980  			} else {
   981  				// "widget.window.name",
   982  				// "widget.text.onMouseUp",
   983  				v, _ := jsonparser.GetString(data, k...)
   984  				if v == "" {
   985  					t.Fatal("did not find the value")
   986  				}
   987  			}
   988  		}
   989  	}
   990  	t.N *= len(benchPaths) // because we are running against 3 paths
   991  }
   992  
   993  var massiveJSON = func() string {
   994  	var buf bytes.Buffer
   995  	buf.WriteString("[")
   996  	for i := 0; i < 100; i++ {
   997  		if i > 0 {
   998  			buf.WriteByte(',')
   999  		}
  1000  		buf.WriteString(exampleJSON)
  1001  	}
  1002  	buf.WriteString("]")
  1003  	return buf.String()
  1004  }()
  1005  
  1006  func BenchmarkConvertNone(t *testing.B) {
  1007  	json := massiveJSON
  1008  	t.ReportAllocs()
  1009  	t.ResetTimer()
  1010  	for i := 0; i < t.N; i++ {
  1011  		Get(json, "50.widget.text.onMouseUp")
  1012  	}
  1013  }
  1014  func BenchmarkConvertGet(t *testing.B) {
  1015  	data := []byte(massiveJSON)
  1016  	t.ReportAllocs()
  1017  	t.ResetTimer()
  1018  	for i := 0; i < t.N; i++ {
  1019  		Get(string(data), "50.widget.text.onMouseUp")
  1020  	}
  1021  }
  1022  func BenchmarkConvertGetBytes(t *testing.B) {
  1023  	data := []byte(massiveJSON)
  1024  	t.ReportAllocs()
  1025  	t.ResetTimer()
  1026  	for i := 0; i < t.N; i++ {
  1027  		GetBytes(data, "50.widget.text.onMouseUp")
  1028  	}
  1029  }