goyave.dev/goyave/v4@v4.4.11/util/walk/walk_test.go (about)

     1  package walk
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  )
     9  
    10  func TestPathHasArray(t *testing.T) {
    11  	path := &Path{
    12  		Name: "object",
    13  		Type: PathTypeObject,
    14  		Next: &Path{
    15  			Name: "array",
    16  			Type: PathTypeArray,
    17  			Next: &Path{
    18  				Type: PathTypeElement,
    19  			},
    20  		},
    21  	}
    22  
    23  	assert.True(t, path.HasArray())
    24  	assert.False(t, path.Next.Next.HasArray())
    25  }
    26  
    27  func TestPathLastParent(t *testing.T) {
    28  	path := &Path{
    29  		Name: "object",
    30  		Type: PathTypeObject,
    31  		Next: &Path{
    32  			Name: "array",
    33  			Type: PathTypeArray,
    34  			Next: &Path{
    35  				Type: PathTypeElement,
    36  			},
    37  		},
    38  	}
    39  
    40  	assert.Equal(t, path.Next, path.LastParent())
    41  	assert.Nil(t, path.Next.Next.LastParent())
    42  }
    43  
    44  func TestPathTail(t *testing.T) {
    45  	path := &Path{
    46  		Name: "object",
    47  		Type: PathTypeObject,
    48  		Next: &Path{
    49  			Name: "array",
    50  			Type: PathTypeArray,
    51  			Next: &Path{
    52  				Type: PathTypeElement,
    53  			},
    54  		},
    55  	}
    56  	assert.Equal(t, path.Next.Next, path.Tail())
    57  	assert.Equal(t, path.Next.Next, path.Next.Next.Tail())
    58  }
    59  
    60  func TestPathClone(t *testing.T) {
    61  	i := 1
    62  	path := &Path{
    63  		Name: "object",
    64  		Type: PathTypeObject,
    65  		Next: &Path{
    66  			Name:  "array",
    67  			Type:  PathTypeArray,
    68  			Index: &i,
    69  			Next: &Path{
    70  				Type: PathTypeElement,
    71  			},
    72  		},
    73  	}
    74  	clone := path.Clone()
    75  	assert.Equal(t, path, clone)
    76  }
    77  
    78  func testPathScanner(t *testing.T, path string, expected []string) {
    79  	scanner := createPathScanner(path)
    80  	result := []string{}
    81  	for scanner.Scan() {
    82  		result = append(result, scanner.Text())
    83  	}
    84  
    85  	assert.Equal(t, expected, result)
    86  	assert.Nil(t, scanner.Err())
    87  }
    88  
    89  func testPathScannerError(t *testing.T, path string) {
    90  	scanner := createPathScanner(path)
    91  	result := []string{}
    92  	for scanner.Scan() {
    93  		result = append(result, scanner.Text())
    94  	}
    95  
    96  	err := scanner.Err()
    97  	if assert.NotNil(t, err) {
    98  		assert.Contains(t, err.Error(), "Illegal syntax: ")
    99  	} else {
   100  		fmt.Printf("%#v\n", result)
   101  	}
   102  }
   103  
   104  func TestPathScanner(t *testing.T) {
   105  	testPathScanner(t, "object.array[].field", []string{"object", ".", "array", "[]", ".", "field"})
   106  	testPathScanner(t, "array[][]", []string{"array", "[]", "[]"})
   107  	testPathScanner(t, "object.field", []string{"object", ".", "field"})
   108  
   109  	testPathScannerError(t, "object[].[]")
   110  	testPathScannerError(t, "object..field")
   111  	testPathScannerError(t, "object.")
   112  	testPathScannerError(t, ".object")
   113  	testPathScannerError(t, "array[")
   114  	testPathScannerError(t, "array]")
   115  	testPathScannerError(t, "array[.]")
   116  	testPathScannerError(t, "array[aa]")
   117  	testPathScannerError(t, "array[[]]")
   118  	testPathScannerError(t, "array[a[b]c]")
   119  	testPathScannerError(t, "[]array")
   120  	testPathScannerError(t, "array[]field")
   121  	testPathScannerError(t, "array.[]field")
   122  	testPathScannerError(t, "array.[]field")
   123  	testPathScannerError(t, "")
   124  }
   125  
   126  func TestParse(t *testing.T) {
   127  	path, err := Parse("object.array[].field")
   128  	assert.Nil(t, err)
   129  	assert.Equal(t, path, &Path{
   130  		Name: "object",
   131  		Type: PathTypeObject,
   132  		Next: &Path{
   133  			Name: "array",
   134  			Type: PathTypeArray,
   135  			Next: &Path{
   136  				Type: PathTypeObject,
   137  				Next: &Path{
   138  					Name: "field",
   139  					Type: PathTypeElement,
   140  				},
   141  			},
   142  		},
   143  	})
   144  
   145  	path, err = Parse("array[][]")
   146  	assert.Nil(t, err)
   147  	assert.Equal(t, path, &Path{
   148  		Name: "array",
   149  		Type: PathTypeArray,
   150  		Next: &Path{
   151  			Type: PathTypeArray,
   152  			Next: &Path{
   153  				Type: PathTypeElement,
   154  			},
   155  		},
   156  	})
   157  
   158  	path, err = Parse("object.field")
   159  	assert.Nil(t, err)
   160  	assert.Equal(t, path, &Path{
   161  		Name: "object",
   162  		Type: PathTypeObject,
   163  		Next: &Path{
   164  			Name: "field",
   165  			Type: PathTypeElement,
   166  		},
   167  	})
   168  
   169  	path, err = Parse("array[][].field")
   170  	assert.Nil(t, err)
   171  	assert.Equal(t, path, &Path{
   172  		Name: "array",
   173  		Type: PathTypeArray,
   174  		Next: &Path{
   175  			Type: PathTypeArray,
   176  			Next: &Path{
   177  				Type: PathTypeObject,
   178  				Next: &Path{
   179  					Name: "field",
   180  					Type: PathTypeElement,
   181  				},
   182  			},
   183  		},
   184  	})
   185  
   186  	path, err = Parse("array[][].field[]")
   187  	assert.Nil(t, err)
   188  	assert.Equal(t, path, &Path{
   189  		Name: "array",
   190  		Type: PathTypeArray,
   191  		Next: &Path{
   192  			Type: PathTypeArray,
   193  			Next: &Path{
   194  				Type: PathTypeObject,
   195  				Next: &Path{
   196  					Name: "field",
   197  					Type: PathTypeArray,
   198  					Next: &Path{
   199  						Type: PathTypeElement,
   200  					},
   201  				},
   202  			},
   203  		},
   204  	})
   205  
   206  	path, err = Parse(".invalid[]path")
   207  	assert.Nil(t, path)
   208  	assert.NotNil(t, err)
   209  }
   210  
   211  func testWalk(t *testing.T, data map[string]interface{}, p string) []Context {
   212  	matches := make([]Context, 0, 5)
   213  	path, err := Parse(p)
   214  
   215  	if !assert.Nil(t, err) {
   216  		assert.FailNow(t, err.Error())
   217  	}
   218  
   219  	path.Walk(data, func(c Context) {
   220  		matches = append(matches, c)
   221  	})
   222  
   223  	return matches
   224  }
   225  
   226  func TestPathWalk(t *testing.T) {
   227  	// object.field
   228  	data := map[string]interface{}{
   229  		"object": map[string]interface{}{
   230  			"field": 5,
   231  		},
   232  	}
   233  	expected := []Context{
   234  		{
   235  			Value:  5,
   236  			Parent: data["object"],
   237  			Path: &Path{
   238  				Name: "object",
   239  				Type: PathTypeObject,
   240  				Next: &Path{Name: "field"},
   241  			},
   242  			Name:  "field",
   243  			Index: -1,
   244  			Found: Found,
   245  		},
   246  	}
   247  	matches := testWalk(t, data, "object.field")
   248  	assert.Equal(t, expected, matches)
   249  
   250  	// array[]
   251  	data = map[string]interface{}{
   252  		"array": []string{"a", "b", "c"},
   253  	}
   254  	i := 0
   255  	j := 1
   256  	k := 2
   257  	l := 3
   258  	m := -1
   259  	expected = []Context{
   260  		{
   261  			Value:  "a",
   262  			Parent: data["array"],
   263  			Path: &Path{
   264  				Name:  "array",
   265  				Type:  PathTypeArray,
   266  				Index: &i,
   267  				Next:  &Path{},
   268  			},
   269  			Name:  "",
   270  			Index: 0,
   271  			Found: Found,
   272  		},
   273  		{
   274  			Value:  "b",
   275  			Parent: data["array"],
   276  			Path: &Path{
   277  				Name:  "array",
   278  				Type:  PathTypeArray,
   279  				Index: &j,
   280  				Next:  &Path{},
   281  			},
   282  			Name:  "",
   283  			Index: 1,
   284  			Found: Found,
   285  		},
   286  		{
   287  			Value:  "c",
   288  			Parent: data["array"],
   289  			Path: &Path{
   290  				Name:  "array",
   291  				Type:  PathTypeArray,
   292  				Index: &k,
   293  				Next:  &Path{},
   294  			},
   295  			Name:  "",
   296  			Index: 2,
   297  			Found: Found,
   298  		},
   299  	}
   300  	matches = testWalk(t, data, "array[]")
   301  	assert.Equal(t, expected, matches)
   302  
   303  	// array[][]
   304  	data = map[string]interface{}{
   305  		"array": [][]string{
   306  			{},
   307  			{"a", "b"},
   308  			{"c"},
   309  		},
   310  	}
   311  	expected = []Context{
   312  		{
   313  			Value:  nil,
   314  			Parent: data["array"].([][]string)[0],
   315  			Path: &Path{
   316  				Name:  "array",
   317  				Type:  PathTypeArray,
   318  				Index: &i,
   319  				Next: &Path{
   320  					Type: PathTypeArray,
   321  					Next: &Path{},
   322  				},
   323  			},
   324  			Name:  "",
   325  			Index: -1,
   326  			Found: ElementNotFound,
   327  		},
   328  		{
   329  			Value:  "a",
   330  			Parent: data["array"].([][]string)[1],
   331  			Path: &Path{
   332  				Name:  "array",
   333  				Type:  PathTypeArray,
   334  				Index: &j,
   335  				Next: &Path{
   336  					Type:  PathTypeArray,
   337  					Index: &i,
   338  					Next:  &Path{},
   339  				},
   340  			},
   341  			Name:  "",
   342  			Index: 0,
   343  			Found: Found,
   344  		},
   345  		{
   346  			Value:  "b",
   347  			Parent: data["array"].([][]string)[1],
   348  			Path: &Path{
   349  				Name:  "array",
   350  				Type:  PathTypeArray,
   351  				Index: &j,
   352  				Next: &Path{
   353  					Type:  PathTypeArray,
   354  					Index: &j,
   355  					Next:  &Path{},
   356  				},
   357  			},
   358  			Name:  "",
   359  			Index: 1,
   360  			Found: Found,
   361  		},
   362  		{
   363  			Value:  "c",
   364  			Parent: data["array"].([][]string)[2],
   365  			Path: &Path{
   366  				Name:  "array",
   367  				Type:  PathTypeArray,
   368  				Index: &k,
   369  				Next: &Path{
   370  					Type:  PathTypeArray,
   371  					Index: &i,
   372  					Next:  &Path{},
   373  				},
   374  			},
   375  			Name:  "",
   376  			Index: 0,
   377  			Found: Found,
   378  		},
   379  	}
   380  	matches = testWalk(t, data, "array[][]")
   381  	assert.Equal(t, expected, matches)
   382  
   383  	// array[].field[]
   384  	data = map[string]interface{}{
   385  		"array": []map[string]interface{}{
   386  			{"field": []string{}},
   387  			{"field": []string{"a", "b"}},
   388  			{},
   389  			{"field": []string{"c"}},
   390  		},
   391  	}
   392  	expected = []Context{
   393  		{
   394  			Value:  nil,
   395  			Parent: data["array"].([]map[string]interface{})[0]["field"],
   396  			Path: &Path{
   397  				Name:  "array",
   398  				Type:  PathTypeArray,
   399  				Index: &i,
   400  				Next: &Path{
   401  					Type: PathTypeObject,
   402  					Next: &Path{
   403  						Name: "field",
   404  						Type: PathTypeArray,
   405  						Next: &Path{},
   406  					},
   407  				},
   408  			},
   409  			Name:  "",
   410  			Index: -1,
   411  			Found: ElementNotFound,
   412  		},
   413  		{
   414  			Value:  "a",
   415  			Parent: data["array"].([]map[string]interface{})[1]["field"],
   416  			Path: &Path{
   417  				Name:  "array",
   418  				Type:  PathTypeArray,
   419  				Index: &j,
   420  				Next: &Path{
   421  					Type: PathTypeObject,
   422  					Next: &Path{
   423  						Name:  "field",
   424  						Type:  PathTypeArray,
   425  						Index: &i,
   426  						Next:  &Path{},
   427  					},
   428  				},
   429  			},
   430  			Name:  "",
   431  			Index: 0,
   432  			Found: Found,
   433  		},
   434  		{
   435  			Value:  "b",
   436  			Parent: data["array"].([]map[string]interface{})[1]["field"],
   437  			Path: &Path{
   438  				Name:  "array",
   439  				Type:  PathTypeArray,
   440  				Index: &j,
   441  				Next: &Path{
   442  					Type: PathTypeObject,
   443  					Next: &Path{
   444  						Name:  "field",
   445  						Type:  PathTypeArray,
   446  						Index: &j,
   447  						Next:  &Path{},
   448  					},
   449  				},
   450  			},
   451  			Name:  "",
   452  			Index: 1,
   453  			Found: Found,
   454  		},
   455  		{
   456  			Value:  nil,
   457  			Parent: data["array"].([]map[string]interface{})[2],
   458  			Path: &Path{
   459  				Name:  "array",
   460  				Type:  PathTypeArray,
   461  				Index: &k,
   462  				Next: &Path{
   463  					Type: PathTypeObject,
   464  					Next: &Path{
   465  						Name:  "field",
   466  						Type:  PathTypeArray,
   467  						Index: &m,
   468  						Next:  &Path{},
   469  					},
   470  				},
   471  			},
   472  			Name:  "field",
   473  			Index: -1,
   474  			Found: ParentNotFound,
   475  		},
   476  		{
   477  			Value:  "c",
   478  			Parent: data["array"].([]map[string]interface{})[3]["field"],
   479  			Path: &Path{
   480  				Name:  "array",
   481  				Type:  PathTypeArray,
   482  				Index: &l,
   483  				Next: &Path{
   484  					Type: PathTypeObject,
   485  					Next: &Path{
   486  						Name:  "field",
   487  						Type:  PathTypeArray,
   488  						Index: &i,
   489  						Next:  &Path{},
   490  					},
   491  				},
   492  			},
   493  			Name:  "",
   494  			Index: 0,
   495  			Found: Found,
   496  		},
   497  	}
   498  	matches = testWalk(t, data, "array[].field[]")
   499  	assert.Equal(t, expected, matches)
   500  
   501  	// array[].field index check
   502  	expected = []Context{
   503  		{
   504  			Value:  []string{},
   505  			Parent: data["array"].([]map[string]interface{})[0],
   506  			Path: &Path{
   507  				Name:  "array",
   508  				Type:  PathTypeArray,
   509  				Index: &i,
   510  				Next: &Path{
   511  					Type: PathTypeObject,
   512  					Next: &Path{Name: "field"},
   513  				},
   514  			},
   515  			Name:  "field",
   516  			Index: -1,
   517  			Found: Found,
   518  		},
   519  		{
   520  			Value:  []string{"a", "b"},
   521  			Parent: data["array"].([]map[string]interface{})[1],
   522  			Path: &Path{
   523  				Name:  "array",
   524  				Type:  PathTypeArray,
   525  				Index: &j,
   526  				Next: &Path{
   527  					Type: PathTypeObject,
   528  					Next: &Path{Name: "field"},
   529  				},
   530  			},
   531  			Name:  "field",
   532  			Index: -1,
   533  			Found: Found,
   534  		},
   535  		{
   536  			Value:  nil,
   537  			Parent: data["array"].([]map[string]interface{})[2],
   538  			Path: &Path{
   539  				Name:  "array",
   540  				Type:  PathTypeArray,
   541  				Index: &k,
   542  				Next: &Path{
   543  					Type: PathTypeObject,
   544  					Next: &Path{Name: "field"},
   545  				},
   546  			},
   547  			Name:  "field",
   548  			Index: -1,
   549  			Found: ElementNotFound,
   550  		},
   551  		{
   552  			Value:  []string{"c"},
   553  			Parent: data["array"].([]map[string]interface{})[3],
   554  			Path: &Path{
   555  				Name:  "array",
   556  				Type:  PathTypeArray,
   557  				Index: &l,
   558  				Next: &Path{
   559  					Type: PathTypeObject,
   560  					Next: &Path{Name: "field"},
   561  				},
   562  			},
   563  			Name:  "field",
   564  			Index: -1,
   565  			Found: Found,
   566  		},
   567  	}
   568  	matches = testWalk(t, data, "array[].field")
   569  	assert.Equal(t, expected, matches)
   570  }
   571  
   572  func TestPathWalkEmptyArray(t *testing.T) {
   573  	data := map[string]interface{}{
   574  		"array":  []string{},
   575  		"narray": [][][]string{},
   576  	}
   577  
   578  	expected := []Context{
   579  		{
   580  			Value:  nil,
   581  			Parent: data["array"],
   582  			Name:   "",
   583  			Path: &Path{
   584  				Name: "array",
   585  				Type: PathTypeArray,
   586  				Next: &Path{},
   587  			},
   588  			Index: -1,
   589  			Found: ElementNotFound,
   590  		},
   591  	}
   592  
   593  	matches := testWalk(t, data, "array[]")
   594  	assert.Equal(t, expected, matches)
   595  
   596  	matches = testWalk(t, data, "narray[][][]")
   597  	expected = []Context{
   598  		{
   599  			Value:  nil,
   600  			Parent: data["narray"],
   601  			Name:   "",
   602  			Path: &Path{
   603  				Name: "narray",
   604  				Type: PathTypeArray,
   605  				Next: &Path{},
   606  			},
   607  			Index: -1,
   608  			Found: ParentNotFound,
   609  		},
   610  	}
   611  	assert.Equal(t, expected, matches)
   612  }
   613  
   614  func TestPathWalkNotFoundInObject(t *testing.T) {
   615  	data := map[string]interface{}{
   616  		"object": map[string]interface{}{
   617  			"field": 5,
   618  		},
   619  	}
   620  	expected := []Context{
   621  		{
   622  			Value:  nil,
   623  			Parent: data["object"],
   624  			Path: &Path{
   625  				Name: "object",
   626  				Type: PathTypeObject,
   627  				Next: &Path{Name: "notafield"},
   628  			},
   629  			Name:  "notafield",
   630  			Index: -1,
   631  			Found: ElementNotFound,
   632  		},
   633  	}
   634  	matches := testWalk(t, data, "object.notafield")
   635  	assert.Equal(t, expected, matches)
   636  }
   637  
   638  func TestPathWalkNotFoundInArray(t *testing.T) {
   639  	data := map[string]interface{}{
   640  		"array": []map[string]interface{}{},
   641  	}
   642  	expected := []Context{
   643  		{
   644  			Value:  nil,
   645  			Parent: data["array"],
   646  			Path: &Path{
   647  				Name: "array",
   648  				Type: PathTypeArray,
   649  				Next: &Path{},
   650  			},
   651  			Name:  "",
   652  			Index: -1,
   653  			Found: ParentNotFound,
   654  		},
   655  	}
   656  	matches := testWalk(t, data, "array[].field")
   657  	assert.Equal(t, expected, matches)
   658  }
   659  
   660  func TestPathWalkSliceExpected(t *testing.T) {
   661  	data := map[string]interface{}{
   662  		"object": map[string]interface{}{
   663  			"field": []string{"a", "b"},
   664  			"array": []interface{}{
   665  				5,
   666  				[]string{"a", "b"},
   667  				map[string]interface{}{"field": "1"},
   668  			},
   669  		},
   670  	}
   671  	i := 0
   672  	j := 1
   673  	k := 2
   674  	expected := []Context{
   675  		{
   676  			Value:  nil,
   677  			Parent: data["object"].(map[string]interface{})["field"],
   678  			Path: &Path{
   679  				Name: "object",
   680  				Type: PathTypeObject,
   681  				Next: &Path{
   682  					Name:  "field",
   683  					Type:  PathTypeArray,
   684  					Index: &i,
   685  					Next:  &Path{},
   686  				},
   687  			},
   688  			Name:  "",
   689  			Index: 0,
   690  			Found: ParentNotFound,
   691  		},
   692  		{
   693  			Value:  nil,
   694  			Parent: data["object"].(map[string]interface{})["field"],
   695  			Path: &Path{
   696  				Name: "object",
   697  				Type: PathTypeObject,
   698  				Next: &Path{
   699  					Name:  "field",
   700  					Type:  PathTypeArray,
   701  					Index: &j,
   702  					Next:  &Path{},
   703  				},
   704  			},
   705  			Name:  "",
   706  			Index: 1,
   707  			Found: ParentNotFound,
   708  		},
   709  	}
   710  	matches := testWalk(t, data, "object.field[][]")
   711  	assert.Equal(t, expected, matches)
   712  
   713  	expected = []Context{
   714  		{
   715  			Value:  nil,
   716  			Parent: data["object"].(map[string]interface{})["array"],
   717  			Path: &Path{
   718  				Name: "object",
   719  				Type: PathTypeObject,
   720  				Next: &Path{
   721  					Name:  "array",
   722  					Type:  PathTypeArray,
   723  					Index: &i,
   724  					Next:  &Path{},
   725  				},
   726  			},
   727  			Name:  "",
   728  			Index: 0,
   729  			Found: ParentNotFound,
   730  		},
   731  		{
   732  			Value:  "a",
   733  			Parent: data["object"].(map[string]interface{})["array"].([]interface{})[1],
   734  			Path: &Path{
   735  				Name: "object",
   736  				Type: PathTypeObject,
   737  				Next: &Path{
   738  					Name:  "array",
   739  					Type:  PathTypeArray,
   740  					Index: &j,
   741  					Next: &Path{
   742  						Type:  PathTypeArray,
   743  						Index: &i,
   744  						Next:  &Path{},
   745  					},
   746  				},
   747  			},
   748  			Name:  "",
   749  			Index: 0,
   750  			Found: Found,
   751  		},
   752  		{
   753  			Value:  "b",
   754  			Parent: data["object"].(map[string]interface{})["array"].([]interface{})[1],
   755  			Path: &Path{
   756  				Name: "object",
   757  				Type: PathTypeObject,
   758  				Next: &Path{
   759  					Name:  "array",
   760  					Type:  PathTypeArray,
   761  					Index: &j,
   762  					Next: &Path{
   763  						Type:  PathTypeArray,
   764  						Index: &j,
   765  						Next:  &Path{},
   766  					},
   767  				},
   768  			},
   769  			Name:  "",
   770  			Index: 1,
   771  			Found: Found,
   772  		},
   773  		{
   774  			Value:  nil,
   775  			Parent: data["object"].(map[string]interface{})["array"],
   776  			Path: &Path{
   777  				Name: "object",
   778  				Type: PathTypeObject,
   779  				Next: &Path{
   780  					Name:  "array",
   781  					Type:  PathTypeArray,
   782  					Index: &k,
   783  					Next:  &Path{},
   784  				},
   785  			},
   786  			Name:  "",
   787  			Index: 2,
   788  			Found: ParentNotFound,
   789  		},
   790  	}
   791  	matches = testWalk(t, data, "object.array[][]")
   792  	assert.Equal(t, expected, matches)
   793  }
   794  
   795  func TestPathWalkWithIndex(t *testing.T) {
   796  	data := map[string]interface{}{
   797  		"array": []map[string]interface{}{
   798  			{"field": []string{}},
   799  			{"field": []string{"a", "b"}},
   800  			{},
   801  			{"field": []string{"c"}},
   802  			{"field": []string{"d", "e"}},
   803  		},
   804  	}
   805  
   806  	i := 1
   807  	path := &Path{
   808  		Name:  "array",
   809  		Type:  PathTypeArray,
   810  		Index: &i,
   811  		Next: &Path{
   812  			Type: PathTypeObject,
   813  			Next: &Path{
   814  				Name:  "field",
   815  				Type:  PathTypeArray,
   816  				Index: &i,
   817  				Next:  &Path{},
   818  			},
   819  		},
   820  	}
   821  
   822  	matches := make([]Context, 0, 1)
   823  
   824  	path.Walk(data, func(c Context) {
   825  		matches = append(matches, c)
   826  	})
   827  
   828  	expected := []Context{
   829  		{
   830  			Value:  "b",
   831  			Parent: data["array"].([]map[string]interface{})[i]["field"],
   832  			Path:   path,
   833  			Name:   "",
   834  			Index:  i,
   835  			Found:  Found,
   836  		},
   837  	}
   838  	assert.Equal(t, expected, matches)
   839  }
   840  
   841  func TestPathWalkWithIndexOutOfBounds(t *testing.T) {
   842  	data := map[string]interface{}{
   843  		"array": []map[string]interface{}{
   844  			{"field": []string{}},
   845  			{"field": []string{"a", "b"}},
   846  			{},
   847  			{"field": []string{"c"}},
   848  			{"field": []string{"d", "e"}},
   849  		},
   850  	}
   851  
   852  	i := 1
   853  	j := 5
   854  	path := &Path{
   855  		Name:  "array",
   856  		Type:  PathTypeArray,
   857  		Index: &i,
   858  		Next: &Path{
   859  			Type: PathTypeObject,
   860  			Next: &Path{
   861  				Name:  "field",
   862  				Type:  PathTypeArray,
   863  				Index: &j,
   864  				Next:  &Path{},
   865  			},
   866  		},
   867  	}
   868  
   869  	matches := make([]Context, 0, 1)
   870  
   871  	path.Walk(data, func(c Context) {
   872  		matches = append(matches, c)
   873  	})
   874  
   875  	expected := []Context{
   876  		{
   877  			Value:  nil,
   878  			Parent: data["array"].([]map[string]interface{})[i]["field"],
   879  			Path:   path,
   880  			Name:   "",
   881  			Index:  j,
   882  			Found:  ElementNotFound,
   883  		},
   884  	}
   885  	assert.Equal(t, expected, matches)
   886  }
   887  
   888  func TestPathWalkMissingObject(t *testing.T) {
   889  	data := map[string]interface{}{}
   890  
   891  	path := &Path{
   892  		Name: "object",
   893  		Type: PathTypeObject,
   894  		Next: &Path{
   895  			Type: PathTypeObject,
   896  			Name: "subobject",
   897  			Next: &Path{
   898  				Name: "field",
   899  				Type: PathTypeElement,
   900  			},
   901  		},
   902  	}
   903  
   904  	matches := make([]Context, 0, 1)
   905  
   906  	path.Walk(data, func(c Context) {
   907  		matches = append(matches, c)
   908  	})
   909  
   910  	expected := []Context{
   911  		{
   912  			Value:  nil,
   913  			Parent: data,
   914  			Path:   path,
   915  			Name:   "object",
   916  			Index:  -1,
   917  			Found:  ParentNotFound,
   918  		},
   919  	}
   920  	assert.Equal(t, expected, matches)
   921  }
   922  
   923  func TestPathSetAllMissingIndexes(t *testing.T) {
   924  	path := &Path{
   925  		Name: "array",
   926  		Type: PathTypeArray,
   927  		Next: &Path{
   928  			Type: PathTypeObject,
   929  			Name: "object",
   930  			Next: &Path{
   931  				Name: "field",
   932  				Type: PathTypeArray,
   933  				Next: &Path{},
   934  			},
   935  		},
   936  	}
   937  
   938  	path.setAllMissingIndexes()
   939  
   940  	assert.Equal(t, -1, *path.Index)
   941  	assert.Equal(t, -1, *path.Next.Next.Index)
   942  }