...

Source file src/github.com/go-openapi/jsonpointer/pointer_test.go

Documentation: github.com/go-openapi/jsonpointer

     1  // Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //   http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // author       sigu-399
    16  // author-github  https://github.com/sigu-399
    17  // author-mail    sigu.399@gmail.com
    18  //
    19  // repository-name  jsonpointer
    20  // repository-desc  An implementation of JSON Pointer - Go language
    21  //
    22  // description    Automated tests on package.
    23  //
    24  // created        03-03-2013
    25  
    26  package jsonpointer
    27  
    28  import (
    29  	"encoding/json"
    30  	"fmt"
    31  	"strconv"
    32  	"testing"
    33  
    34  	"github.com/stretchr/testify/assert"
    35  	"github.com/stretchr/testify/require"
    36  )
    37  
    38  const (
    39  	TestDocumentNBItems = 11
    40  	TestNodeObjNBItems  = 4
    41  	TestDocumentString  = `{
    42  "foo": ["bar", "baz"],
    43  "obj": { "a":1, "b":2, "c":[3,4], "d":[ {"e":9}, {"f":[50,51]} ] },
    44  "": 0,
    45  "a/b": 1,
    46  "c%d": 2,
    47  "e^f": 3,
    48  "g|h": 4,
    49  "i\\j": 5,
    50  "k\"l": 6,
    51  " ": 7,
    52  "m~n": 8
    53  }`
    54  )
    55  
    56  var testDocumentJSON any
    57  
    58  type testStructJSON struct {
    59  	Foo []string `json:"foo"`
    60  	Obj struct {
    61  		A int   `json:"a"`
    62  		B int   `json:"b"`
    63  		C []int `json:"c"`
    64  		D []struct {
    65  			E int   `json:"e"`
    66  			F []int `json:"f"`
    67  		} `json:"d"`
    68  	} `json:"obj"`
    69  }
    70  
    71  type aliasedMap map[string]any
    72  
    73  var testStructJSONDoc testStructJSON
    74  var testStructJSONPtr *testStructJSON
    75  
    76  func init() {
    77  	if err := json.Unmarshal([]byte(TestDocumentString), &testDocumentJSON); err != nil {
    78  		panic(err)
    79  	}
    80  	if err := json.Unmarshal([]byte(TestDocumentString), &testStructJSONDoc); err != nil {
    81  		panic(err)
    82  	}
    83  
    84  	testStructJSONPtr = &testStructJSONDoc
    85  }
    86  
    87  func TestEscaping(t *testing.T) {
    88  	ins := []string{`/`, `/`, `/a~1b`, `/a~1b`, `/c%d`, `/e^f`, `/g|h`, `/i\j`, `/k"l`, `/ `, `/m~0n`}
    89  	outs := []float64{0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8}
    90  
    91  	for i := range ins {
    92  		p, err := New(ins[i])
    93  		require.NoError(t, err, "input: %v", ins[i])
    94  		result, _, err := p.Get(testDocumentJSON)
    95  
    96  		require.NoError(t, err, "input: %v", ins[i])
    97  		assert.InDeltaf(t, outs[i], result, 1e-6, "input: %v", ins[i])
    98  	}
    99  
   100  }
   101  
   102  func TestFullDocument(t *testing.T) {
   103  	const in = ``
   104  
   105  	p, err := New(in)
   106  	require.NoErrorf(t, err, "New(%v) error %v", in, err)
   107  
   108  	result, _, err := p.Get(testDocumentJSON)
   109  	require.NoErrorf(t, err, "Get(%v) error %v", in, err)
   110  
   111  	asMap, ok := result.(map[string]any)
   112  	require.True(t, ok)
   113  	require.Lenf(t, asMap, TestDocumentNBItems, "Get(%v) = %v, expect full document", in, result)
   114  
   115  	result, _, err = p.get(testDocumentJSON, nil)
   116  	require.NoErrorf(t, err, "Get(%v) error %v", in, err)
   117  
   118  	asMap, ok = result.(map[string]any)
   119  	require.True(t, ok)
   120  	require.Lenf(t, asMap, TestDocumentNBItems, "Get(%v) = %v, expect full document", in, result)
   121  }
   122  
   123  func TestDecodedTokens(t *testing.T) {
   124  	p, err := New("/obj/a~1b")
   125  	require.NoError(t, err)
   126  	assert.Equal(t, []string{"obj", "a/b"}, p.DecodedTokens())
   127  }
   128  
   129  func TestIsEmpty(t *testing.T) {
   130  	p, err := New("")
   131  	require.NoError(t, err)
   132  
   133  	assert.True(t, p.IsEmpty())
   134  	p, err = New("/obj")
   135  	require.NoError(t, err)
   136  
   137  	assert.False(t, p.IsEmpty())
   138  }
   139  
   140  func TestGetSingle(t *testing.T) {
   141  	const in = `/obj`
   142  
   143  	t.Run("should create a new JSON pointer", func(t *testing.T) {
   144  		_, err := New(in)
   145  		require.NoError(t, err)
   146  	})
   147  
   148  	t.Run(`should find token "obj" in JSON`, func(t *testing.T) {
   149  		result, _, err := GetForToken(testDocumentJSON, "obj")
   150  		require.NoError(t, err)
   151  		assert.Len(t, result, TestNodeObjNBItems)
   152  	})
   153  
   154  	t.Run(`should find token "obj" in type alias interface`, func(t *testing.T) {
   155  		type alias interface{}
   156  		var in alias = testDocumentJSON
   157  		result, _, err := GetForToken(in, "obj")
   158  		require.NoError(t, err)
   159  		assert.Len(t, result, TestNodeObjNBItems)
   160  	})
   161  
   162  	t.Run(`should find token "obj" in pointer to interface`, func(t *testing.T) {
   163  		in := &testDocumentJSON
   164  		result, _, err := GetForToken(in, "obj")
   165  		require.NoError(t, err)
   166  		assert.Len(t, result, TestNodeObjNBItems)
   167  	})
   168  
   169  	t.Run(`should not find token "Obj" in struct`, func(t *testing.T) {
   170  		result, _, err := GetForToken(testStructJSONDoc, "Obj")
   171  		require.Error(t, err)
   172  		assert.Nil(t, result)
   173  	})
   174  
   175  	t.Run(`should not find token "Obj2" in struct`, func(t *testing.T) {
   176  		result, _, err := GetForToken(testStructJSONDoc, "Obj2")
   177  		require.Error(t, err)
   178  		assert.Nil(t, result)
   179  	})
   180  
   181  	t.Run(`should not find token in nil`, func(t *testing.T) {
   182  		result, _, err := GetForToken(nil, "obj")
   183  		require.Error(t, err)
   184  		assert.Nil(t, result)
   185  	})
   186  
   187  	t.Run(`should not find token in nil interface`, func(t *testing.T) {
   188  		var in interface{}
   189  		result, _, err := GetForToken(in, "obj")
   190  		require.Error(t, err)
   191  		assert.Nil(t, result)
   192  	})
   193  }
   194  
   195  type pointableImpl struct {
   196  	a string
   197  }
   198  
   199  func (p pointableImpl) JSONLookup(token string) (any, error) {
   200  	if token == "some" {
   201  		return p.a, nil
   202  	}
   203  	return nil, fmt.Errorf("object has no field %q", token)
   204  }
   205  
   206  type pointableMap map[string]string
   207  
   208  func (p pointableMap) JSONLookup(token string) (any, error) {
   209  	if token == "swap" {
   210  		return p["swapped"], nil
   211  	}
   212  
   213  	v, ok := p[token]
   214  	if ok {
   215  		return v, nil
   216  	}
   217  
   218  	return nil, fmt.Errorf("object has no key %q", token)
   219  }
   220  
   221  func TestPointableInterface(t *testing.T) {
   222  	p := &pointableImpl{"hello"}
   223  
   224  	result, _, err := GetForToken(p, "some")
   225  	require.NoError(t, err)
   226  	assert.Equal(t, p.a, result)
   227  
   228  	result, _, err = GetForToken(p, "something")
   229  	require.Error(t, err)
   230  	assert.Nil(t, result)
   231  
   232  	pm := pointableMap{"swapped": "hello", "a": "world"}
   233  	result, _, err = GetForToken(pm, "swap")
   234  	require.NoError(t, err)
   235  	assert.Equal(t, pm["swapped"], result)
   236  
   237  	result, _, err = GetForToken(pm, "a")
   238  	require.NoError(t, err)
   239  	assert.Equal(t, pm["a"], result)
   240  }
   241  
   242  func TestGetNode(t *testing.T) {
   243  	const in = `/obj`
   244  
   245  	p, err := New(in)
   246  	require.NoError(t, err)
   247  
   248  	result, _, err := p.Get(testDocumentJSON)
   249  	require.NoError(t, err)
   250  	assert.Len(t, result, TestNodeObjNBItems)
   251  
   252  	result, _, err = p.Get(aliasedMap(testDocumentJSON.(map[string]any)))
   253  	require.NoError(t, err)
   254  	assert.Len(t, result, TestNodeObjNBItems)
   255  
   256  	result, _, err = p.Get(testStructJSONDoc)
   257  	require.NoError(t, err)
   258  	assert.Equal(t, testStructJSONDoc.Obj, result)
   259  
   260  	result, _, err = p.Get(testStructJSONPtr)
   261  	require.NoError(t, err)
   262  	assert.Equal(t, testStructJSONDoc.Obj, result)
   263  }
   264  
   265  func TestArray(t *testing.T) {
   266  	ins := []string{`/foo/0`, `/foo/0`, `/foo/1`}
   267  	outs := []string{"bar", "bar", "baz"}
   268  
   269  	for i := range ins {
   270  		p, err := New(ins[i])
   271  		require.NoError(t, err)
   272  
   273  		result, _, err := p.Get(testStructJSONDoc)
   274  		require.NoError(t, err)
   275  		assert.Equal(t, outs[i], result)
   276  
   277  		result, _, err = p.Get(testStructJSONPtr)
   278  		require.NoError(t, err)
   279  		assert.Equal(t, outs[i], result)
   280  
   281  		result, _, err = p.Get(testDocumentJSON)
   282  		require.NoError(t, err)
   283  		assert.Equal(t, outs[i], result)
   284  	}
   285  }
   286  
   287  func TestOtherThings(t *testing.T) {
   288  	_, err := New("abc")
   289  	require.Error(t, err)
   290  
   291  	p, err := New("")
   292  	require.NoError(t, err)
   293  	assert.Equal(t, "", p.String())
   294  
   295  	p, err = New("/obj/a")
   296  	require.NoError(t, err)
   297  	assert.Equal(t, "/obj/a", p.String())
   298  
   299  	s := Escape("m~n")
   300  	assert.Equal(t, "m~0n", s)
   301  	s = Escape("m/n")
   302  	assert.Equal(t, "m~1n", s)
   303  
   304  	p, err = New("/foo/3")
   305  	require.NoError(t, err)
   306  	_, _, err = p.Get(testDocumentJSON)
   307  	require.Error(t, err)
   308  
   309  	p, err = New("/foo/a")
   310  	require.NoError(t, err)
   311  	_, _, err = p.Get(testDocumentJSON)
   312  	require.Error(t, err)
   313  
   314  	p, err = New("/notthere")
   315  	require.NoError(t, err)
   316  	_, _, err = p.Get(testDocumentJSON)
   317  	require.Error(t, err)
   318  
   319  	p, err = New("/invalid")
   320  	require.NoError(t, err)
   321  	_, _, err = p.Get(1234)
   322  	require.Error(t, err)
   323  
   324  	p, err = New("/foo/1")
   325  	require.NoError(t, err)
   326  	expected := "hello"
   327  	bbb := testDocumentJSON.(map[string]any)["foo"]
   328  	bbb.([]any)[1] = "hello"
   329  
   330  	v, _, err := p.Get(testDocumentJSON)
   331  	require.NoError(t, err)
   332  	assert.Equal(t, expected, v)
   333  
   334  	esc := Escape("a/")
   335  	assert.Equal(t, "a~1", esc)
   336  	unesc := Unescape(esc)
   337  	assert.Equal(t, "a/", unesc)
   338  
   339  	unesc = Unescape("~01")
   340  	assert.Equal(t, "~1", unesc)
   341  	assert.Equal(t, "~0~1", Escape("~/"))
   342  	assert.Equal(t, "~/", Unescape("~0~1"))
   343  }
   344  
   345  func TestObject(t *testing.T) {
   346  	ins := []string{`/obj/a`, `/obj/b`, `/obj/c/0`, `/obj/c/1`, `/obj/c/1`, `/obj/d/1/f/0`}
   347  	outs := []float64{1, 2, 3, 4, 4, 50}
   348  
   349  	for i := range ins {
   350  		p, err := New(ins[i])
   351  		require.NoError(t, err)
   352  
   353  		result, _, err := p.Get(testDocumentJSON)
   354  		require.NoError(t, err)
   355  		assert.InDelta(t, outs[i], result, 1e-6)
   356  
   357  		result, _, err = p.Get(testStructJSONDoc)
   358  		require.NoError(t, err)
   359  		assert.InDelta(t, outs[i], result, 1e-6)
   360  
   361  		result, _, err = p.Get(testStructJSONPtr)
   362  		require.NoError(t, err)
   363  		assert.InDelta(t, outs[i], result, 1e-6)
   364  	}
   365  }
   366  
   367  /*
   368  	type setJSONDocEle struct {
   369  		B int `json:"b"`
   370  		C int `json:"c"`
   371  	}
   372  */
   373  type setJSONDoc struct {
   374  	A []struct {
   375  		B int `json:"b"`
   376  		C int `json:"c"`
   377  	} `json:"a"`
   378  	D int `json:"d"`
   379  }
   380  
   381  type settableDoc struct {
   382  	Coll settableColl
   383  	Int  settableInt
   384  }
   385  
   386  func (s settableDoc) MarshalJSON() ([]byte, error) {
   387  	var res struct {
   388  		A settableColl `json:"a"`
   389  		D settableInt  `json:"d"`
   390  	}
   391  	res.A = s.Coll
   392  	res.D = s.Int
   393  	return json.Marshal(res)
   394  }
   395  func (s *settableDoc) UnmarshalJSON(data []byte) error {
   396  	var res struct {
   397  		A settableColl `json:"a"`
   398  		D settableInt  `json:"d"`
   399  	}
   400  
   401  	if err := json.Unmarshal(data, &res); err != nil {
   402  		return err
   403  	}
   404  	s.Coll = res.A
   405  	s.Int = res.D
   406  	return nil
   407  }
   408  
   409  // JSONLookup implements an interface to customize json pointer lookup
   410  func (s settableDoc) JSONLookup(token string) (any, error) {
   411  	switch token {
   412  	case "a":
   413  		return &s.Coll, nil
   414  	case "d":
   415  		return &s.Int, nil
   416  	default:
   417  		return nil, fmt.Errorf("%s is not a known field", token)
   418  	}
   419  }
   420  
   421  // JSONLookup implements an interface to customize json pointer lookup
   422  func (s *settableDoc) JSONSet(token string, data any) error {
   423  	switch token {
   424  	case "a":
   425  		switch dt := data.(type) {
   426  		case settableColl:
   427  			s.Coll = dt
   428  			return nil
   429  		case *settableColl:
   430  			if dt != nil {
   431  				s.Coll = *dt
   432  			} else {
   433  				s.Coll = settableColl{}
   434  			}
   435  			return nil
   436  		case []settableCollItem:
   437  			s.Coll.Items = dt
   438  			return nil
   439  		}
   440  	case "d":
   441  		switch dt := data.(type) {
   442  		case settableInt:
   443  			s.Int = dt
   444  			return nil
   445  		case int:
   446  			s.Int.Value = dt
   447  			return nil
   448  		case int8:
   449  			s.Int.Value = int(dt)
   450  			return nil
   451  		case int16:
   452  			s.Int.Value = int(dt)
   453  			return nil
   454  		case int32:
   455  			s.Int.Value = int(dt)
   456  			return nil
   457  		case int64:
   458  			s.Int.Value = int(dt)
   459  			return nil
   460  		default:
   461  			return fmt.Errorf("invalid type %T for %s", data, token)
   462  		}
   463  	}
   464  	return fmt.Errorf("%s is not a known field", token)
   465  }
   466  
   467  type settableColl struct {
   468  	Items []settableCollItem
   469  }
   470  
   471  func (s settableColl) MarshalJSON() ([]byte, error) {
   472  	return json.Marshal(s.Items)
   473  }
   474  func (s *settableColl) UnmarshalJSON(data []byte) error {
   475  	return json.Unmarshal(data, &s.Items)
   476  }
   477  
   478  // JSONLookup implements an interface to customize json pointer lookup
   479  func (s settableColl) JSONLookup(token string) (any, error) {
   480  	if tok, err := strconv.Atoi(token); err == nil {
   481  		return &s.Items[tok], nil
   482  	}
   483  	return nil, fmt.Errorf("%s is not a valid index", token)
   484  }
   485  
   486  // JSONLookup implements an interface to customize json pointer lookup
   487  func (s *settableColl) JSONSet(token string, data any) error {
   488  	if _, err := strconv.Atoi(token); err == nil {
   489  		_, err := SetForToken(s.Items, token, data)
   490  		return err
   491  	}
   492  	return fmt.Errorf("%s is not a valid index", token)
   493  }
   494  
   495  type settableCollItem struct {
   496  	B int `json:"b"`
   497  	C int `json:"c"`
   498  }
   499  
   500  type settableInt struct {
   501  	Value int
   502  }
   503  
   504  func (s settableInt) MarshalJSON() ([]byte, error) {
   505  	return json.Marshal(s.Value)
   506  }
   507  func (s *settableInt) UnmarshalJSON(data []byte) error {
   508  	return json.Unmarshal(data, &s.Value)
   509  }
   510  
   511  func TestSetNode(t *testing.T) {
   512  	const jsonText = `{"a":[{"b": 1, "c": 2}], "d": 3}`
   513  
   514  	var jsonDocument any
   515  	require.NoError(t, json.Unmarshal([]byte(jsonText), &jsonDocument))
   516  
   517  	t.Run("with set node c", func(t *testing.T) {
   518  		const in = "/a/0/c"
   519  		p, err := New(in)
   520  		require.NoError(t, err)
   521  
   522  		_, err = p.Set(jsonDocument, 999)
   523  		require.NoError(t, err)
   524  
   525  		firstNode, ok := jsonDocument.(map[string]any)
   526  		require.True(t, ok)
   527  		assert.Len(t, firstNode, 2)
   528  
   529  		sliceNode, ok := firstNode["a"].([]any)
   530  		require.True(t, ok)
   531  		assert.Len(t, sliceNode, 1)
   532  
   533  		changedNode, ok := sliceNode[0].(map[string]any)
   534  		require.True(t, ok)
   535  		chNodeVI := changedNode["c"]
   536  
   537  		require.IsType(t, 0, chNodeVI)
   538  		changedNodeValue := chNodeVI.(int)
   539  		require.Equal(t, 999, changedNodeValue)
   540  		assert.Len(t, sliceNode, 1)
   541  	})
   542  
   543  	t.Run("with set node 0 with map", func(t *testing.T) {
   544  		v, err := New("/a/0")
   545  		require.NoError(t, err)
   546  
   547  		_, err = v.Set(jsonDocument, map[string]any{"b": 3, "c": 8})
   548  		require.NoError(t, err)
   549  
   550  		firstNode, ok := jsonDocument.(map[string]any)
   551  		require.True(t, ok)
   552  		assert.Len(t, firstNode, 2)
   553  
   554  		sliceNode, ok := firstNode["a"].([]any)
   555  		require.True(t, ok)
   556  		assert.Len(t, sliceNode, 1)
   557  
   558  		changedNode, ok := sliceNode[0].(map[string]any)
   559  		require.True(t, ok)
   560  		assert.Equal(t, 3, changedNode["b"])
   561  		assert.Equal(t, 8, changedNode["c"])
   562  	})
   563  
   564  	t.Run("with struct", func(t *testing.T) {
   565  		var structDoc setJSONDoc
   566  		require.NoError(t, json.Unmarshal([]byte(jsonText), &structDoc))
   567  
   568  		t.Run("with set array node", func(t *testing.T) {
   569  			g, err := New("/a")
   570  			require.NoError(t, err)
   571  
   572  			_, err = g.Set(&structDoc, []struct {
   573  				B int `json:"b"`
   574  				C int `json:"c"`
   575  			}{{B: 4, C: 7}})
   576  			require.NoError(t, err)
   577  			assert.Len(t, structDoc.A, 1)
   578  			changedNode := structDoc.A[0]
   579  			assert.Equal(t, 4, changedNode.B)
   580  			assert.Equal(t, 7, changedNode.C)
   581  		})
   582  
   583  		t.Run("with set node 0 with struct", func(t *testing.T) {
   584  			v, err := New("/a/0")
   585  			require.NoError(t, err)
   586  
   587  			_, err = v.Set(structDoc, struct {
   588  				B int `json:"b"`
   589  				C int `json:"c"`
   590  			}{B: 3, C: 8})
   591  			require.NoError(t, err)
   592  			assert.Len(t, structDoc.A, 1)
   593  			changedNode := structDoc.A[0]
   594  			assert.Equal(t, 3, changedNode.B)
   595  			assert.Equal(t, 8, changedNode.C)
   596  		})
   597  
   598  		t.Run("with set node c with struct", func(t *testing.T) {
   599  			p, err := New("/a/0/c")
   600  			require.NoError(t, err)
   601  
   602  			_, err = p.Set(&structDoc, 999)
   603  			require.NoError(t, err)
   604  
   605  			require.Len(t, structDoc.A, 1)
   606  			assert.Equal(t, 999, structDoc.A[0].C)
   607  		})
   608  	})
   609  
   610  	t.Run("with Settable", func(t *testing.T) {
   611  		var setDoc settableDoc
   612  		require.NoError(t, json.Unmarshal([]byte(jsonText), &setDoc))
   613  
   614  		t.Run("with array node a", func(t *testing.T) {
   615  			g, err := New("/a")
   616  			require.NoError(t, err)
   617  
   618  			_, err = g.Set(&setDoc, []settableCollItem{{B: 4, C: 7}})
   619  			require.NoError(t, err)
   620  			assert.Len(t, setDoc.Coll.Items, 1)
   621  			changedNode := setDoc.Coll.Items[0]
   622  			assert.Equal(t, 4, changedNode.B)
   623  			assert.Equal(t, 7, changedNode.C)
   624  		})
   625  
   626  		t.Run("with node 0", func(t *testing.T) {
   627  			v, err := New("/a/0")
   628  			require.NoError(t, err)
   629  
   630  			_, err = v.Set(setDoc, settableCollItem{B: 3, C: 8})
   631  			require.NoError(t, err)
   632  			assert.Len(t, setDoc.Coll.Items, 1)
   633  			changedNode := setDoc.Coll.Items[0]
   634  			assert.Equal(t, 3, changedNode.B)
   635  			assert.Equal(t, 8, changedNode.C)
   636  		})
   637  
   638  		t.Run("with node c", func(t *testing.T) {
   639  			p, err := New("/a/0/c")
   640  			require.NoError(t, err)
   641  			_, err = p.Set(setDoc, 999)
   642  			require.NoError(t, err)
   643  			require.Len(t, setDoc.Coll.Items, 1)
   644  			assert.Equal(t, 999, setDoc.Coll.Items[0].C)
   645  		})
   646  	})
   647  }
   648  
   649  func TestOffset(t *testing.T) {
   650  	cases := []struct {
   651  		name     string
   652  		ptr      string
   653  		input    string
   654  		offset   int64
   655  		hasError bool
   656  	}{
   657  		{
   658  			name:   "object key",
   659  			ptr:    "/foo/bar",
   660  			input:  `{"foo": {"bar": 21}}`,
   661  			offset: 9,
   662  		},
   663  		{
   664  			name:   "complex object key",
   665  			ptr:    "/paths/~1p~1{}/get",
   666  			input:  `{"paths": {"foo": {"bar": 123, "baz": {}}, "/p/{}": {"get": {}}}}`,
   667  			offset: 53,
   668  		},
   669  		{
   670  			name:   "array index",
   671  			ptr:    "/0/1",
   672  			input:  `[[1,2], [3,4]]`,
   673  			offset: 3,
   674  		},
   675  		{
   676  			name:   "mix array index and object key",
   677  			ptr:    "/0/1/foo/0",
   678  			input:  `[[1, {"foo": ["a", "b"]}], [3, 4]]`,
   679  			offset: 14,
   680  		},
   681  		{
   682  			name:     "nonexist object key",
   683  			ptr:      "/foo/baz",
   684  			input:    `{"foo": {"bar": 21}}`,
   685  			hasError: true,
   686  		},
   687  		{
   688  			name:     "nonexist array index",
   689  			ptr:      "/0/2",
   690  			input:    `[[1,2], [3,4]]`,
   691  			hasError: true,
   692  		},
   693  	}
   694  
   695  	for _, tt := range cases {
   696  		t.Run(tt.name, func(t *testing.T) {
   697  			ptr, err := New(tt.ptr)
   698  			require.NoError(t, err)
   699  
   700  			offset, err := ptr.Offset(tt.input)
   701  			if tt.hasError {
   702  				require.Error(t, err)
   703  				return
   704  			}
   705  
   706  			t.Log(offset, err)
   707  			require.NoError(t, err)
   708  			assert.Equal(t, tt.offset, offset)
   709  		})
   710  	}
   711  }
   712  

View as plain text