Skip to content
Snippets Groups Projects
Commit 3bb7903f authored by Anthony Fok's avatar Anthony Fok
Browse files

New upstream version 0.19.5

parents 5ea9e921 2446e21c
No related branches found
No related tags found
1 merge request!2Set upstream metadata fields: Repository, Repository-Browse
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.pDqezepze0YqRx4u6M8GFaWtnVR-utTWZic-GX-RvMATAoYpG4H2sc9tlnGNCxa44dbRY0vY10qfBU7Sno8vkp21fsK42ofGLfen_suum_0ilm0sFS0X-kAwk7TIq5L5lPPKiChPMUiGp5oJW-g5MqMFX1jNiI-4fP-vSM3B3-eyZtJD_O517TgfIRLnblCzqwIkyRmAfPNopi-Fe8Y31TmO2Vd0nFc1Aqro_VaJSACzEVxOHTNpjETcMjlYzwgMXLeiAfLV-5hM0f6DXgHMlLSuMkB_Ndnw25dkB7hreGk4x0tHQ3X9mUfTgLq1hIDoyeeKDIM83Tqw4LBRph20BQ.qd_pNuyi23B0PlWz.JtpO7kqOm0SWOGzWDalkWheHuNd-eDpVbqI9WPAEFDOIBvz7TbsYMBlIYVWEGWbat4mkx_ejxnMn1L1l996NJnyP7eY-QE82cfPJbjx94d0Ob70KZ4DCm_UxcY2t-OKFiPJqxW7MA5jKyDuGD16bdxpjLEoe_cMSEr8FNu-MVG6wcchPcyYyRkqTQSl4mb09KikkAzHjwjo-DcO0f8ps4Uzsoc0aqAAWdE-ocG0YqierLoemjusYMiLH-eLF6MvaLRvHSte-cLzPuYCeZURnBDgxu3i3UApgddnX7g1c7tdGGBGvgCl-tEEDW58Vxgdjksim2S7y3lfoJ8FFzSWeRH2y7Kq04hgew3b2J_RiDB9ejzIopzG8ZGjJa3EO1-i9ORTl12nXK1RdlLGqu604ENaeVOPCIHL-0C8e6_wHdUGHydLZImSxKYSrNvy8resP1D_9t4B-3q2mkS9mhnMONrXbPDVw5QY5mvXlWs0Db99ARwzsl-Qlu0A_tsZwMjWT2I1QMvWPyTRScmMm0FJSv9zStjzxWa_q2GL7Naz1fI4Dd6ZgNJWYYq-mHN5chEeBdIcwb_zMPHczMQXXNL5nmfRGM1aPffkToFWCDpIlI8IXec83ZC6_POxZegS6n9Drrvc.6Nz8EXxs1lWX3ASaCeNElA
\ No newline at end of file
clone:
path: github.com/go-openapi/jsonpointer
matrix:
GO_VERSION:
- "1.6"
build:
integration:
image: golang:$$GO_VERSION
pull: true
commands:
- go get -u github.com/stretchr/testify/assert
- go get -u github.com/go-openapi/swag
- go test -race
- go test -v -cover -coverprofile=coverage.out -covermode=count ./...
notify:
slack:
channel: bots
webhook_url: $$SLACK_URL
username: drone
publish:
coverage:
server: https://coverage.vmware.run
token: $$GITHUB_TOKEN
# threshold: 70
# must_increase: true
when:
matrix:
GO_VERSION: "1.6"
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
# Set default charset
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
charset = utf-8
# Tab indentation (no size specified)
[*.go]
indent_style = tab
[*.md]
trim_trailing_whitespace = false
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2
secrets.yml
approve_by_comment: true
approve_regex: '^(:shipit:|:\+1:|\+1|LGTM|lgtm|Approved)'
reject_regex: ^[Rr]ejected
reset_on_push: false
reviewers:
members:
- casualjim
- chancez
- frapposelli
- vburenin
- pytlesk4
name: pullapprove
required: 1
after_success:
- bash <(curl -s https://codecov.io/bash)
go:
- 1.14.x
- 1.15.x
install:
- GO111MODULE=off go get -u gotest.tools/gotestsum
env:
- GO111MODULE=on
language: go
notifications:
slack:
secure: a5VgoiwB1G/AZqzmephPZIhEB9avMlsWSlVnM1dSAtYAwdrQHGTQxAmpOxYIoSPDhWNN5bfZmjd29++UlTwLcHSR+e0kJhH6IfDlsHj/HplNCJ9tyI0zYc7XchtdKgeMxMzBKCzgwFXGSbQGydXTliDNBo0HOzmY3cou/daMFTP60K+offcjS+3LRAYb1EroSRXZqrk1nuF/xDL3792DZUdPMiFR/L/Df6y74D6/QP4sTkTDFQitz4Wy/7jbsfj8dG6qK2zivgV6/l+w4OVjFkxVpPXogDWY10vVXNVynqxfJ7to2d1I9lNCHE2ilBCkWMIPdyJF7hjF8pKW+82yP4EzRh0vu8Xn0HT5MZpQxdRY/YMxNrWaG7SxsoEaO4q5uhgdzAqLYY3TRa7MjIK+7Ur+aqOeTXn6OKwVi0CjvZ6mIU3WUKSwiwkFZMbjRAkSb5CYwMEfGFO/z964xz83qGt6WAtBXNotqCQpTIiKtDHQeLOMfksHImCg6JLhQcWBVxamVgu0G3Pdh8Y6DyPnxraXY95+QDavbjqv7TeYT9T/FNnrkXaTTK0s4iWE5H4ACU0Qvz0wUYgfQrZv0/Hp7V17+rabUwnzYySHCy9SWX/7OV9Cfh31iMp9ZIffr76xmmThtOEqs8TrTtU6BWI3rWwvA9cXQipZTVtL0oswrGw=
script:
- gotestsum -f short-verbose -- -race -coverprofile=coverage.txt -covermode=atomic ./...
# gojsonpointer [![Build Status](https://ci.vmware.run/api/badges/go-openapi/jsonpointer/status.svg)](https://ci.vmware.run/go-openapi/jsonpointer) [![Coverage](https://coverage.vmware.run/badges/go-openapi/jsonpointer/coverage.svg)](https://coverage.vmware.run/go-openapi/jsonpointer) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) # gojsonpointer [![Build Status](https://travis-ci.org/go-openapi/jsonpointer.svg?branch=master)](https://travis-ci.org/go-openapi/jsonpointer) [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonpointer?status.svg)](http://godoc.org/github.com/go-openapi/jsonpointer) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonpointer?status.svg)](http://godoc.org/github.com/go-openapi/jsonpointer)
An implementation of JSON Pointer - Go language An implementation of JSON Pointer - Go language
......
go.mod 0 → 100644
module github.com/go-openapi/jsonpointer
require (
github.com/go-openapi/swag v0.19.5
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect
github.com/stretchr/testify v1.3.0
)
go 1.13
go.sum 0 → 100644
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
...@@ -43,6 +43,7 @@ const ( ...@@ -43,6 +43,7 @@ const (
) )
var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem() var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
var jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem()
// JSONPointable is an interface for structs to implement when they need to customize the // JSONPointable is an interface for structs to implement when they need to customize the
// json pointer process // json pointer process
...@@ -50,16 +51,10 @@ type JSONPointable interface { ...@@ -50,16 +51,10 @@ type JSONPointable interface {
JSONLookup(string) (interface{}, error) JSONLookup(string) (interface{}, error)
} }
type implStruct struct { // JSONSetable is an interface for structs to implement when they need to customize the
mode string // "SET" or "GET" // json pointer process
type JSONSetable interface {
inDocument interface{} JSONSet(string, interface{}) error
setInValue interface{}
getOutNode interface{}
getOutKind reflect.Kind
outError error
} }
// New creates a new json pointer for the given string // New creates a new json pointer for the given string
...@@ -100,25 +95,35 @@ func (p *Pointer) Get(document interface{}) (interface{}, reflect.Kind, error) { ...@@ -100,25 +95,35 @@ func (p *Pointer) Get(document interface{}) (interface{}, reflect.Kind, error) {
return p.get(document, swag.DefaultJSONNameProvider) return p.get(document, swag.DefaultJSONNameProvider)
} }
// Set uses the pointer to set a value from a JSON document
func (p *Pointer) Set(document interface{}, value interface{}) (interface{}, error) {
return document, p.set(document, value, swag.DefaultJSONNameProvider)
}
// GetForToken gets a value for a json pointer token 1 level deep // GetForToken gets a value for a json pointer token 1 level deep
func GetForToken(document interface{}, decodedToken string) (interface{}, reflect.Kind, error) { func GetForToken(document interface{}, decodedToken string) (interface{}, reflect.Kind, error) {
return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider) return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider)
} }
// SetForToken gets a value for a json pointer token 1 level deep
func SetForToken(document interface{}, decodedToken string, value interface{}) (interface{}, error) {
return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
}
func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) { func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) {
kind := reflect.Invalid
rValue := reflect.Indirect(reflect.ValueOf(node)) rValue := reflect.Indirect(reflect.ValueOf(node))
kind = rValue.Kind() kind := rValue.Kind()
switch kind {
case reflect.Struct: if rValue.Type().Implements(jsonPointableType) {
if rValue.Type().Implements(jsonPointableType) { r, err := node.(JSONPointable).JSONLookup(decodedToken)
r, err := node.(JSONPointable).JSONLookup(decodedToken) if err != nil {
if err != nil { return nil, kind, err
return nil, kind, err
}
return r, kind, nil
} }
return r, kind, nil
}
switch kind {
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok { if !ok {
return nil, kind, fmt.Errorf("object has no field %q", decodedToken) return nil, kind, fmt.Errorf("object has no field %q", decodedToken)
...@@ -129,7 +134,8 @@ func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.Nam ...@@ -129,7 +134,8 @@ func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.Nam
case reflect.Map: case reflect.Map:
kv := reflect.ValueOf(decodedToken) kv := reflect.ValueOf(decodedToken)
mv := rValue.MapIndex(kv) mv := rValue.MapIndex(kv)
if mv.IsValid() && !swag.IsZero(mv) {
if mv.IsValid() {
return mv.Interface(), kind, nil return mv.Interface(), kind, nil
} }
return nil, kind, fmt.Errorf("object has no key %q", decodedToken) return nil, kind, fmt.Errorf("object has no key %q", decodedToken)
...@@ -141,7 +147,7 @@ func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.Nam ...@@ -141,7 +147,7 @@ func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.Nam
} }
sLength := rValue.Len() sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength { if tokenIndex < 0 || tokenIndex >= sLength {
return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex) return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength-1, tokenIndex)
} }
elem := rValue.Index(tokenIndex) elem := rValue.Index(tokenIndex)
...@@ -153,6 +159,57 @@ func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.Nam ...@@ -153,6 +159,57 @@ func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.Nam
} }
func setSingleImpl(node, data interface{}, decodedToken string, nameProvider *swag.NameProvider) error {
rValue := reflect.Indirect(reflect.ValueOf(node))
if ns, ok := node.(JSONSetable); ok { // pointer impl
return ns.JSONSet(decodedToken, data)
}
if rValue.Type().Implements(jsonSetableType) {
return node.(JSONSetable).JSONSet(decodedToken, data)
}
switch rValue.Kind() {
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return fmt.Errorf("object has no field %q", decodedToken)
}
fld := rValue.FieldByName(nm)
if fld.IsValid() {
fld.Set(reflect.ValueOf(data))
}
return nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
rValue.SetMapIndex(kv, reflect.ValueOf(data))
return nil
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
}
elem := rValue.Index(tokenIndex)
if !elem.CanSet() {
return fmt.Errorf("can't set slice index %s to %v", decodedToken, data)
}
elem.Set(reflect.ValueOf(data))
return nil
default:
return fmt.Errorf("invalid token reference %q", decodedToken)
}
}
func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) { func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) {
if nameProvider == nil { if nameProvider == nil {
...@@ -184,6 +241,101 @@ func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interf ...@@ -184,6 +241,101 @@ func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interf
return node, kind, nil return node, kind, nil
} }
func (p *Pointer) set(node, data interface{}, nameProvider *swag.NameProvider) error {
knd := reflect.ValueOf(node).Kind()
if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
return fmt.Errorf("only structs, pointers, maps and slices are supported for setting values")
}
if nameProvider == nil {
nameProvider = swag.DefaultJSONNameProvider
}
// Full document when empty
if len(p.referenceTokens) == 0 {
return nil
}
lastI := len(p.referenceTokens) - 1
for i, token := range p.referenceTokens {
isLastToken := i == lastI
decodedToken := Unescape(token)
if isLastToken {
return setSingleImpl(node, data, decodedToken, nameProvider)
}
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if rValue.Type().Implements(jsonPointableType) {
r, err := node.(JSONPointable).JSONLookup(decodedToken)
if err != nil {
return err
}
fld := reflect.ValueOf(r)
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
node = fld.Addr().Interface()
continue
}
node = r
continue
}
switch kind {
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return fmt.Errorf("object has no field %q", decodedToken)
}
fld := rValue.FieldByName(nm)
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
node = fld.Addr().Interface()
continue
}
node = fld.Interface()
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
mv := rValue.MapIndex(kv)
if !mv.IsValid() {
return fmt.Errorf("object has no key %q", decodedToken)
}
if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr {
node = mv.Addr().Interface()
continue
}
node = mv.Interface()
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
}
elem := rValue.Index(tokenIndex)
if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Ptr {
node = elem.Addr().Interface()
continue
}
node = elem.Interface()
default:
return fmt.Errorf("invalid token reference %q", decodedToken)
}
}
return nil
}
// DecodedTokens returns the decoded tokens // DecodedTokens returns the decoded tokens
func (p *Pointer) DecodedTokens() []string { func (p *Pointer) DecodedTokens() []string {
result := make([]string, 0, len(p.referenceTokens)) result := make([]string, 0, len(p.referenceTokens))
......
...@@ -28,6 +28,7 @@ package jsonpointer ...@@ -28,6 +28,7 @@ package jsonpointer
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strconv"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
...@@ -83,19 +84,12 @@ func TestEscaping(t *testing.T) { ...@@ -83,19 +84,12 @@ func TestEscaping(t *testing.T) {
outs := []float64{0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8} outs := []float64{0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8}
for i := range ins { for i := range ins {
p, err := New(ins[i]) p, err := New(ins[i])
if err != nil { if assert.NoError(t, err, "input: %v", ins[i]) {
t.Errorf("New(%v) error %v", ins[i], err.Error()) result, _, err := p.Get(testDocumentJSON)
} if assert.NoError(t, err, "input: %v", ins[i]) {
assert.Equal(t, outs[i], result, "input: %v", ins[i])
result, _, err := p.Get(testDocumentJSON) }
if err != nil {
t.Errorf("Get(%v) error %v", ins[i], err.Error())
}
if result != outs[i] {
t.Errorf("Get(%v) = %v, expect %v", ins[i], result, outs[i])
} }
} }
...@@ -173,6 +167,21 @@ func (p pointableImpl) JSONLookup(token string) (interface{}, error) { ...@@ -173,6 +167,21 @@ func (p pointableImpl) JSONLookup(token string) (interface{}, error) {
return nil, fmt.Errorf("object has no field %q", token) return nil, fmt.Errorf("object has no field %q", token)
} }
type pointableMap map[string]string
func (p pointableMap) JSONLookup(token string) (interface{}, error) {
if token == "swap" {
return p["swapped"], nil
}
v, ok := p[token]
if ok {
return v, nil
}
return nil, fmt.Errorf("object has no key %q", token)
}
func TestPointableInterface(t *testing.T) { func TestPointableInterface(t *testing.T) {
p := &pointableImpl{"hello"} p := &pointableImpl{"hello"}
...@@ -183,6 +192,15 @@ func TestPointableInterface(t *testing.T) { ...@@ -183,6 +192,15 @@ func TestPointableInterface(t *testing.T) {
result, _, err = GetForToken(p, "something") result, _, err = GetForToken(p, "something")
assert.Error(t, err) assert.Error(t, err)
assert.Nil(t, result) assert.Nil(t, result)
pm := pointableMap{"swapped": "hello", "a": "world"}
result, _, err = GetForToken(pm, "swap")
assert.NoError(t, err)
assert.Equal(t, pm["swapped"], result)
result, _, err = GetForToken(pm, "a")
assert.NoError(t, err)
assert.Equal(t, pm["a"], result)
} }
func TestGetNode(t *testing.T) { func TestGetNode(t *testing.T) {
...@@ -311,3 +329,269 @@ func TestObject(t *testing.T) { ...@@ -311,3 +329,269 @@ func TestObject(t *testing.T) {
assert.EqualValues(t, outs[i], result) assert.EqualValues(t, outs[i], result)
} }
} }
type setJsonDocEle struct {
B int `json:"b"`
C int `json:"c"`
}
type setJsonDoc struct {
A []struct {
B int `json:"b"`
C int `json:"c"`
} `json:"a"`
D int `json:"d"`
}
type settableDoc struct {
Coll settableColl
Int settableInt
}
func (s settableDoc) MarshalJSON() ([]byte, error) {
var res struct {
A settableColl `json:"a"`
D settableInt `json:"d"`
}
res.A = s.Coll
res.D = s.Int
return json.Marshal(res)
}
func (s *settableDoc) UnmarshalJSON(data []byte) error {
var res struct {
A settableColl `json:"a"`
D settableInt `json:"d"`
}
if err := json.Unmarshal(data, &res); err != nil {
return err
}
s.Coll = res.A
s.Int = res.D
return nil
}
// JSONLookup implements an interface to customize json pointer lookup
func (s settableDoc) JSONLookup(token string) (interface{}, error) {
switch token {
case "a":
return &s.Coll, nil
case "d":
return &s.Int, nil
default:
return nil, fmt.Errorf("%s is not a known field", token)
}
}
// JSONLookup implements an interface to customize json pointer lookup
func (s *settableDoc) JSONSet(token string, data interface{}) error {
switch token {
case "a":
switch dt := data.(type) {
case settableColl:
s.Coll = dt
return nil
case *settableColl:
if dt != nil {
s.Coll = *dt
} else {
s.Coll = settableColl{}
}
return nil
case []settableCollItem:
s.Coll.Items = dt
return nil
}
case "d":
switch dt := data.(type) {
case settableInt:
s.Int = dt
return nil
case int:
s.Int.Value = dt
return nil
case int8:
s.Int.Value = int(dt)
return nil
case int16:
s.Int.Value = int(dt)
return nil
case int32:
s.Int.Value = int(dt)
return nil
case int64:
s.Int.Value = int(dt)
return nil
default:
return fmt.Errorf("invalid type %T for %s", data, token)
}
}
return fmt.Errorf("%s is not a known field", token)
}
type settableColl struct {
Items []settableCollItem
}
func (s settableColl) MarshalJSON() ([]byte, error) {
return json.Marshal(s.Items)
}
func (s *settableColl) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &s.Items)
}
// JSONLookup implements an interface to customize json pointer lookup
func (s settableColl) JSONLookup(token string) (interface{}, error) {
if tok, err := strconv.Atoi(token); err == nil {
return &s.Items[tok], nil
}
return nil, fmt.Errorf("%s is not a valid index", token)
}
// JSONLookup implements an interface to customize json pointer lookup
func (s *settableColl) JSONSet(token string, data interface{}) error {
if _, err := strconv.Atoi(token); err == nil {
_, err := SetForToken(s.Items, token, data)
return err
}
return fmt.Errorf("%s is not a valid index", token)
}
type settableCollItem struct {
B int `json:"b"`
C int `json:"c"`
}
type settableInt struct {
Value int
}
func (s settableInt) MarshalJSON() ([]byte, error) {
return json.Marshal(s.Value)
}
func (s *settableInt) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &s.Value)
}
func TestSetNode(t *testing.T) {
jsonText := `{"a":[{"b": 1, "c": 2}], "d": 3}`
var jsonDocument interface{}
if assert.NoError(t, json.Unmarshal([]byte(jsonText), &jsonDocument)) {
in := "/a/0/c"
p, err := New(in)
if assert.NoError(t, err) {
_, err = p.Set(jsonDocument, 999)
assert.NoError(t, err)
firstNode := jsonDocument.(map[string]interface{})
assert.Len(t, firstNode, 2)
sliceNode := firstNode["a"].([]interface{})
assert.Len(t, sliceNode, 1)
changedNode := sliceNode[0].(map[string]interface{})
chNodeVI := changedNode["c"]
if assert.IsType(t, 0, chNodeVI) {
changedNodeValue := chNodeVI.(int)
if assert.Equal(t, 999, changedNodeValue) {
assert.Len(t, sliceNode, 1)
}
}
}
v, err := New("/a/0")
if assert.NoError(t, err) {
_, err = v.Set(jsonDocument, map[string]interface{}{"b": 3, "c": 8})
if assert.NoError(t, err) {
firstNode := jsonDocument.(map[string]interface{})
assert.Len(t, firstNode, 2)
sliceNode := firstNode["a"].([]interface{})
assert.Len(t, sliceNode, 1)
changedNode := sliceNode[0].(map[string]interface{})
assert.Equal(t, 3, changedNode["b"])
assert.Equal(t, 8, changedNode["c"])
}
}
}
var structDoc setJsonDoc
if assert.NoError(t, json.Unmarshal([]byte(jsonText), &structDoc)) {
g, err := New("/a")
if assert.NoError(t, err) {
_, err = g.Set(&structDoc, []struct {
B int `json:"b"`
C int `json:"c"`
}{{B: 4, C: 7}})
if assert.NoError(t, err) {
assert.Len(t, structDoc.A, 1)
changedNode := structDoc.A[0]
assert.Equal(t, 4, changedNode.B)
assert.Equal(t, 7, changedNode.C)
}
}
v, err := New("/a/0")
if assert.NoError(t, err) {
_, err = v.Set(structDoc, struct {
B int `json:"b"`
C int `json:"c"`
}{B: 3, C: 8})
if assert.NoError(t, err) {
assert.Len(t, structDoc.A, 1)
changedNode := structDoc.A[0]
assert.Equal(t, 3, changedNode.B)
assert.Equal(t, 8, changedNode.C)
}
}
p, err := New("/a/0/c")
if assert.NoError(t, err) {
_, err = p.Set(&structDoc, 999)
assert.NoError(t, err)
if assert.Len(t, structDoc.A, 1) {
assert.Equal(t, 999, structDoc.A[0].C)
}
}
}
var setDoc settableDoc
if assert.NoError(t, json.Unmarshal([]byte(jsonText), &setDoc)) {
g, err := New("/a")
if assert.NoError(t, err) {
_, err = g.Set(&setDoc, []settableCollItem{{B: 4, C: 7}})
if assert.NoError(t, err) {
assert.Len(t, setDoc.Coll.Items, 1)
changedNode := setDoc.Coll.Items[0]
assert.Equal(t, 4, changedNode.B)
assert.Equal(t, 7, changedNode.C)
}
}
v, err := New("/a/0")
if assert.NoError(t, err) {
_, err = v.Set(setDoc, settableCollItem{B: 3, C: 8})
if assert.NoError(t, err) {
assert.Len(t, setDoc.Coll.Items, 1)
changedNode := setDoc.Coll.Items[0]
assert.Equal(t, 3, changedNode.B)
assert.Equal(t, 8, changedNode.C)
}
}
p, err := New("/a/0/c")
if assert.NoError(t, err) {
_, err = p.Set(setDoc, 999)
assert.NoError(t, err)
if assert.Len(t, setDoc.Coll.Items, 1) {
assert.Equal(t, 999, setDoc.Coll.Items[0].C)
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment