diff --git a/util/json/json.go b/util/json/json.go deleted file mode 100755 index 5abe9906..00000000 --- a/util/json/json.go +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright © 2016 Abcum Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package json - -import ( - "encoding/json" - "fmt" - "reflect" - "strings" -) - -type Operation struct { - Op string `json:"op"` - Path string `json:"path"` - Value interface{} `json:"value,omitempty"` -} - -type ByPath []Operation - -func (a ByPath) Len() int { return len(a) } -func (a ByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a ByPath) Less(i, j int) bool { return a[i].Path < a[j].Path } - -func NewPatch(op, path string, value interface{}) Operation { - return Operation{Op: op, Path: path, Value: value} -} - -// CreatePatch creates a patch as specified in http://jsonpatch.com/ -// -// 'a' is original, 'b' is the modified document. Both are to be given as json encoded content. -// The function will return an array of Operations -// -// An error will be returned if any of the two documents are invalid. -func Diff(a, b interface{}) ([]Operation, error) { - - va, oka := a.([]byte) - vb, okb := b.([]byte) - - if oka && okb { - ia := map[string]interface{}{} - ib := map[string]interface{}{} - err := json.Unmarshal(va, &ia) - if err != nil { - return nil, err - } - err = json.Unmarshal(vb, &ib) - if err != nil { - return nil, err - } - return diff(ia, ib, "", []Operation{}) - } - - ma, oka := a.(map[string]interface{}) - mb, okb := b.(map[string]interface{}) - - if oka && okb { - return diff(ma, mb, "", []Operation{}) - } - - return nil, fmt.Errorf("Invalid input format") - -} - -// Returns true if the values matches (must be json types) -// The types of the values must match, otherwise it will always return false -// If two map[string]interface{} are given, all elements must match. -func matchesValue(av, bv interface{}) bool { - if reflect.TypeOf(av) != reflect.TypeOf(bv) { - return false - } - switch at := av.(type) { - case string: - bt := bv.(string) - if bt == at { - return true - } - case float64: - bt := bv.(float64) - if bt == at { - return true - } - case bool: - bt := bv.(bool) - if bt == at { - return true - } - case map[string]interface{}: - bt := bv.(map[string]interface{}) - for key := range at { - if !matchesValue(at[key], bt[key]) { - return false - } - } - for key := range bt { - if !matchesValue(at[key], bt[key]) { - return false - } - } - return true - case []interface{}: - bt := bv.([]interface{}) - if len(bt) != len(at) { - return false - } - for key := range at { - if !matchesValue(at[key], bt[key]) { - return false - } - } - for key := range bt { - if !matchesValue(at[key], bt[key]) { - return false - } - } - return true - } - return false -} - -func makePath(path string, newPart interface{}) string { - if path == "" { - return fmt.Sprintf("/%v", newPart) - } else { - if strings.HasSuffix(path, "/") { - path = path + fmt.Sprintf("%v", newPart) - } else { - path = path + fmt.Sprintf("/%v", newPart) - } - } - return path -} - -// diff returns the (recursive) difference between a and b as an array of Operations. -func diff(a, b map[string]interface{}, path string, patch []Operation) ([]Operation, error) { - for key, bv := range b { - p := makePath(path, key) - av, ok := a[key] - // value was added - if !ok { - patch = append(patch, NewPatch("add", p, bv)) - continue - } - // If types have changed, replace completely - if reflect.TypeOf(av) != reflect.TypeOf(bv) { - patch = append(patch, NewPatch("replace", p, bv)) - continue - } - // Types are the same, compare values - var err error - patch, err = handleValues(av, bv, p, patch) - if err != nil { - return nil, err - } - } - // Now add all deleted values as nil - for key := range a { - _, found := b[key] - if !found { - p := makePath(path, key) - - patch = append(patch, NewPatch("remove", p, nil)) - } - } - return patch, nil -} - -func handleValues(av, bv interface{}, p string, patch []Operation) ([]Operation, error) { - var err error - switch at := av.(type) { - case map[string]interface{}: - bt := bv.(map[string]interface{}) - patch, err = diff(at, bt, p, patch) - if err != nil { - return nil, err - } - case string, float64, bool: - if !matchesValue(av, bv) { - patch = append(patch, NewPatch("replace", p, bv)) - } - case []interface{}: - bt := bv.([]interface{}) - if len(at) != len(bt) { - // arrays are not the same - patch = append(patch, compareArray(at, bt, p)...) - - } else { - for i, _ := range bt { - patch, err = handleValues(at[i], bt[i], makePath(p, i), patch) - if err != nil { - return nil, err - } - } - } - case nil: - switch bv.(type) { - case nil: - // Both nil, fine. - default: - patch = append(patch, NewPatch("add", p, bv)) - } - default: - panic(fmt.Sprintf("Unknown type:%T ", av)) - } - return patch, nil -} - -func compareArray(av, bv []interface{}, p string) []Operation { - retval := []Operation{} - // var err error - for i, v := range av { - found := false - for _, v2 := range bv { - if reflect.DeepEqual(v, v2) { - found = true - } - } - if !found { - retval = append(retval, NewPatch("remove", makePath(p, i), nil)) - } - } - - for i, v := range bv { - found := false - for _, v2 := range av { - if reflect.DeepEqual(v, v2) { - found = true - } - } - if !found { - retval = append(retval, NewPatch("add", makePath(p, i), v)) - } - } - - return retval -} diff --git a/util/json/merge.go b/util/json/merge.go deleted file mode 100755 index e4a5c2fd..00000000 --- a/util/json/merge.go +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright © 2016 Abcum Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package json - -/*import ( - "encoding/json" - "fmt" - "reflect" - "strings" -) - -func merge(cur, patch *lazyNode) *lazyNode { - curDoc, err := cur.intoDoc() - - if err != nil { - pruneNulls(patch) - return patch - } - - patchDoc, err := patch.intoDoc() - - if err != nil { - return patch - } - - mergeDocs(curDoc, patchDoc) - - return cur -} - -func mergeDocs(doc, patch *partialDoc) { - for k, v := range *patch { - k := decodePatchKey(k) - if v == nil { - delete(*doc, k) - } else { - cur, ok := (*doc)[k] - - if !ok || cur == nil { - pruneNulls(v) - (*doc)[k] = v - } else { - (*doc)[k] = merge(cur, v) - } - } - } -} - -func pruneNulls(n *lazyNode) { - sub, err := n.intoDoc() - - if err == nil { - pruneDocNulls(sub) - } else { - ary, err := n.intoAry() - - if err == nil { - pruneAryNulls(ary) - } - } -} - -func pruneDocNulls(doc *partialDoc) *partialDoc { - for k, v := range *doc { - if v == nil { - delete(*doc, k) - } else { - pruneNulls(v) - } - } - - return doc -} - -func pruneAryNulls(ary *partialArray) *partialArray { - newAry := []*lazyNode{} - - for _, v := range *ary { - if v != nil { - pruneNulls(v) - newAry = append(newAry, v) - } - } - - *ary = newAry - - return ary -} - -var errBadJSONDoc = fmt.Errorf("Invalid JSON Document") -var errBadJSONPatch = fmt.Errorf("Invalid JSON Patch") - -// MergePatch merges the patchData into the docData. -func MergePatch(docData, patchData []byte) ([]byte, error) { - doc := &partialDoc{} - - docErr := json.Unmarshal(docData, doc) - - patch := &partialDoc{} - - patchErr := json.Unmarshal(patchData, patch) - - if _, ok := docErr.(*json.SyntaxError); ok { - return nil, errBadJSONDoc - } - - if _, ok := patchErr.(*json.SyntaxError); ok { - return nil, errBadJSONPatch - } - - if docErr == nil && *doc == nil { - return nil, errBadJSONDoc - } - - if patchErr == nil && *patch == nil { - return nil, errBadJSONPatch - } - - if docErr != nil || patchErr != nil { - // Not an error, just not a doc, so we turn straight into the patch - if patchErr == nil { - doc = pruneDocNulls(patch) - } else { - patchAry := &partialArray{} - patchErr = json.Unmarshal(patchData, patchAry) - - if patchErr != nil { - return nil, errBadJSONPatch - } - - pruneAryNulls(patchAry) - - out, patchErr := json.Marshal(patchAry) - - if patchErr != nil { - return nil, errBadJSONPatch - } - - return out, nil - } - } else { - mergeDocs(doc, patch) - } - - return json.Marshal(doc) -} - -// CreateMergePatch creates a merge patch as specified in http://tools.ietf.org/html/draft-ietf-appsawg-json-merge-patch-07 -// -// 'a' is original, 'b' is the modified document. Both are to be given as json encoded content. -// The function will return a mergeable json document with differences from a to b. -// -// An error will be returned if any of the two documents are invalid. -func CreateMergePatch(a, b []byte) ([]byte, error) { - aI := map[string]interface{}{} - bI := map[string]interface{}{} - err := json.Unmarshal(a, &aI) - if err != nil { - return nil, errBadJSONDoc - } - err = json.Unmarshal(b, &bI) - if err != nil { - return nil, errBadJSONDoc - } - dest, err := getDiff(aI, bI) - if err != nil { - return nil, err - } - return json.Marshal(dest) -} - -// Returns true if the array matches (must be json types). -// As is idiomatic for go, an empty array is not the same as a nil array. -func matchesArray(a, b []interface{}) bool { - if len(a) != len(b) { - return false - } - if (a == nil && b != nil) || (a != nil && b == nil) { - return false - } - for i := range a { - if !matchesValue(a[i], b[i]) { - return false - } - } - return true -} - -// Returns true if the values matches (must be json types) -// The types of the values must match, otherwise it will always return false -// If two map[string]interface{} are given, all elements must match. -func matchesValue(av, bv interface{}) bool { - if reflect.TypeOf(av) != reflect.TypeOf(bv) { - return false - } - switch at := av.(type) { - case string: - bt := bv.(string) - if bt == at { - return true - } - case float64: - bt := bv.(float64) - if bt == at { - return true - } - case bool: - bt := bv.(bool) - if bt == at { - return true - } - case map[string]interface{}: - bt := bv.(map[string]interface{}) - for key := range at { - if !matchesValue(at[key], bt[key]) { - return false - } - } - for key := range bt { - if !matchesValue(at[key], bt[key]) { - return false - } - } - return true - case []interface{}: - bt := bv.([]interface{}) - return matchesArray(at, bt) - } - return false -} - -// getDiff returns the (recursive) difference between a and b as a map[string]interface{}. -func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) { - into := map[string]interface{}{} - for key, bv := range b { - escapedKey := encodePatchKey(key) - av, ok := a[key] - // value was added - if !ok { - into[escapedKey] = bv - continue - } - // If types have changed, replace completely - if reflect.TypeOf(av) != reflect.TypeOf(bv) { - into[escapedKey] = bv - continue - } - // Types are the same, compare values - switch at := av.(type) { - case map[string]interface{}: - bt := bv.(map[string]interface{}) - dst := make(map[string]interface{}, len(bt)) - dst, err := getDiff(at, bt) - if err != nil { - return nil, err - } - if len(dst) > 0 { - into[escapedKey] = dst - } - case string, float64, bool: - if !matchesValue(av, bv) { - into[escapedKey] = bv - } - case []interface{}: - bt := bv.([]interface{}) - if !matchesArray(at, bt) { - into[escapedKey] = bv - } - case nil: - switch bv.(type) { - case nil: - // Both nil, fine. - default: - into[escapedKey] = bv - } - default: - panic(fmt.Sprintf("Unknown type:%T in key %s", av, key)) - } - } - // Now add all deleted values as nil - for key := range a { - _, found := b[key] - if !found { - into[key] = nil - } - } - return into, nil -} - -// From http://tools.ietf.org/html/rfc6901#section-4 : -// -// Evaluation of each reference token begins by decoding any escaped -// character sequence. This is performed by first transforming any -// occurrence of the sequence '~1' to '/', and then transforming any -// occurrence of the sequence '~0' to '~'. - -var ( - rfc6901Encoder = strings.NewReplacer("~", "~0", "/", "~1") - rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~") -) - -func decodePatchKey(k string) string { - return rfc6901Decoder.Replace(k) -} - -func encodePatchKey(k string) string { - return rfc6901Encoder.Replace(k) -} -*/ diff --git a/util/json/merge_test.go b/util/json/merge_test.go deleted file mode 100755 index 5ea2b5cf..00000000 --- a/util/json/merge_test.go +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright © 2016 Abcum Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package json - -// import ( -// "strings" -// "testing" -// ) - -// func mergePatch(doc, patch string) string { -// out, err := MergePatch([]byte(doc), []byte(patch)) - -// if err != nil { -// panic(err) -// } - -// return string(out) -// } - -// func TestMergePatchReplaceKey(t *testing.T) { -// doc := `{ "title": "hello" }` -// pat := `{ "title": "goodbye" }` - -// res := mergePatch(doc, pat) - -// if !compareJSON(pat, res) { -// t.Fatalf("Key was not replaced") -// } -// } - -// func TestMergePatchIgnoresOtherValues(t *testing.T) { -// doc := `{ "title": "hello", "age": 18 }` -// pat := `{ "title": "goodbye" }` - -// res := mergePatch(doc, pat) - -// exp := `{ "title": "goodbye", "age": 18 }` - -// if !compareJSON(exp, res) { -// t.Fatalf("Key was not replaced") -// } -// } - -// func TestMergePatchNilDoc(t *testing.T) { -// doc := `{ "title": null }` -// pat := `{ "title": {"foo": "bar"} }` - -// res := mergePatch(doc, pat) - -// exp := `{ "title": {"foo": "bar"} }` - -// if !compareJSON(exp, res) { -// t.Fatalf("Key was not replaced") -// } -// } - -// func TestMergePatchRecursesIntoObjects(t *testing.T) { -// doc := `{ "person": { "title": "hello", "age": 18 } }` -// pat := `{ "person": { "title": "goodbye" } }` - -// res := mergePatch(doc, pat) - -// exp := `{ "person": { "title": "goodbye", "age": 18 } }` - -// if !compareJSON(exp, res) { -// t.Fatalf("Key was not replaced") -// } -// } - -// type nonObjectCases struct { -// doc, pat, res string -// } - -// func TestMergePatchReplacesNonObjectsWholesale(t *testing.T) { -// a1 := `[1]` -// a2 := `[2]` -// o1 := `{ "a": 1 }` -// o2 := `{ "a": 2 }` -// o3 := `{ "a": 1, "b": 1 }` -// o4 := `{ "a": 2, "b": 1 }` - -// cases := []nonObjectCases{ -// {a1, a2, a2}, -// {o1, a2, a2}, -// {a1, o1, o1}, -// {o3, o2, o4}, -// } - -// for _, c := range cases { -// act := mergePatch(c.doc, c.pat) - -// if !compareJSON(c.res, act) { -// t.Errorf("whole object replacement failed") -// } -// } -// } - -// func TestMergePatchReturnsErrorOnBadJSON(t *testing.T) { -// _, err := MergePatch([]byte(`[[[[`), []byte(`1`)) - -// if err == nil { -// t.Errorf("Did not return an error for bad json: %s", err) -// } - -// _, err = MergePatch([]byte(`1`), []byte(`[[[[`)) - -// if err == nil { -// t.Errorf("Did not return an error for bad json: %s", err) -// } -// } - -// func TestMergePatchReturnsEmptyArrayOnEmptyArray(t *testing.T) { -// doc := `{ "array": ["one", "two"] }` -// pat := `{ "array": [] }` - -// exp := `{ "array": [] }` - -// res, err := MergePatch([]byte(doc), []byte(pat)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// if !compareJSON(exp, string(res)) { -// t.Fatalf("Emtpy array did not return not return as empty array") -// } -// } - -// var rfcTests = []struct { -// target string -// patch string -// expected string -// }{ -// // test cases from https://tools.ietf.org/html/rfc7386#appendix-A -// {target: `{"a":"b"}`, patch: `{"a":"c"}`, expected: `{"a":"c"}`}, -// {target: `{"a":"b"}`, patch: `{"b":"c"}`, expected: `{"a":"b","b":"c"}`}, -// {target: `{"a":"b"}`, patch: `{"a":null}`, expected: `{}`}, -// {target: `{"a":"b","b":"c"}`, patch: `{"a":null}`, expected: `{"b":"c"}`}, -// {target: `{"a":["b"]}`, patch: `{"a":"c"}`, expected: `{"a":"c"}`}, -// {target: `{"a":"c"}`, patch: `{"a":["b"]}`, expected: `{"a":["b"]}`}, -// {target: `{"a":{"b": "c"}}`, patch: `{"a": {"b": "d","c": null}}`, expected: `{"a":{"b":"d"}}`}, -// {target: `{"a":[{"b":"c"}]}`, patch: `{"a":[1]}`, expected: `{"a":[1]}`}, -// {target: `["a","b"]`, patch: `["c","d"]`, expected: `["c","d"]`}, -// {target: `{"a":"b"}`, patch: `["c"]`, expected: `["c"]`}, -// // {target: `{"a":"foo"}`, patch: `null`, expected: `null`}, -// // {target: `{"a":"foo"}`, patch: `"bar"`, expected: `"bar"`}, -// {target: `{"e":null}`, patch: `{"a":1}`, expected: `{"a":1,"e":null}`}, -// {target: `[1,2]`, patch: `{"a":"b","c":null}`, expected: `{"a":"b"}`}, -// {target: `{}`, patch: `{"a":{"bb":{"ccc":null}}}`, expected: `{"a":{"bb":{}}}`}, -// } - -// func TestMergePatchRFCCases(t *testing.T) { -// for i, c := range rfcTests { -// out := mergePatch(c.target, c.patch) - -// if !compareJSON(out, c.expected) { -// t.Errorf("case[%d], patch '%s' did not apply properly to '%s'. expected:\n'%s'\ngot:\n'%s'", i, c.patch, c.target, c.expected, out) -// } -// } -// } - -// var rfcFailTests = ` -// {"a":"foo"} | null -// {"a":"foo"} | "bar" -// ` - -// func TestMergePatchFailRFCCases(t *testing.T) { -// tests := strings.Split(rfcFailTests, "\n") - -// for _, c := range tests { -// if strings.TrimSpace(c) == "" { -// continue -// } - -// parts := strings.SplitN(c, "|", 2) - -// doc := strings.TrimSpace(parts[0]) -// pat := strings.TrimSpace(parts[1]) - -// out, err := MergePatch([]byte(doc), []byte(pat)) - -// if err != errBadJSONPatch { -// t.Errorf("error not returned properly: %s, %s", err, string(out)) -// } -// } - -// } - -// func TestMergeReplaceKey(t *testing.T) { -// doc := `{ "title": "hello", "nested": {"one": 1, "two": 2} }` -// pat := `{ "title": "goodbye", "nested": {"one": 2, "two": 2} }` - -// exp := `{ "title": "goodbye", "nested": {"one": 2} }` - -// res, err := CreateMergePatch([]byte(doc), []byte(pat)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// if !compareJSON(exp, string(res)) { -// t.Fatalf("Key was not replaced") -// } -// } - -// func TestMergeGetArray(t *testing.T) { -// doc := `{ "title": "hello", "array": ["one", "two"], "notmatch": [1, 2, 3] }` -// pat := `{ "title": "hello", "array": ["one", "two", "three"], "notmatch": [1, 2, 3] }` - -// exp := `{ "array": ["one", "two", "three"] }` - -// res, err := CreateMergePatch([]byte(doc), []byte(pat)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// if !compareJSON(exp, string(res)) { -// t.Fatalf("Array was not added") -// } -// } - -// func TestMergeGetObjArray(t *testing.T) { -// doc := `{ "title": "hello", "array": [{"banana": true}, {"evil": false}], "notmatch": [{"one":1}, {"two":2}, {"three":3}] }` -// pat := `{ "title": "hello", "array": [{"banana": false}, {"evil": true}], "notmatch": [{"one":1}, {"two":2}, {"three":3}] }` - -// exp := `{ "array": [{"banana": false}, {"evil": true}] }` - -// res, err := CreateMergePatch([]byte(doc), []byte(pat)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// if !compareJSON(exp, string(res)) { -// t.Fatalf("Object array was not added") -// } -// } - -// func TestMergeDeleteKey(t *testing.T) { -// doc := `{ "title": "hello", "nested": {"one": 1, "two": 2} }` -// pat := `{ "title": "hello", "nested": {"one": 1} }` - -// exp := `{"nested":{"two":null}}` - -// res, err := CreateMergePatch([]byte(doc), []byte(pat)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// // We cannot use "compareJSON", since Equals does not report a difference if the value is null -// if exp != string(res) { -// t.Fatalf("Key was not removed") -// } -// } - -// func TestMergeEmptyArray(t *testing.T) { -// doc := `{ "array": null }` -// pat := `{ "array": [] }` - -// exp := `{"array":[]}` - -// res, err := CreateMergePatch([]byte(doc), []byte(pat)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// // We cannot use "compareJSON", since Equals does not report a difference if the value is null -// if exp != string(res) { -// t.Fatalf("Key was not removed") -// } -// } - -// func TestMergeObjArray(t *testing.T) { -// doc := `{ "array": [ {"a": {"b": 2}}, {"a": {"b": 3}} ]}` -// exp := `{}` - -// res, err := CreateMergePatch([]byte(doc), []byte(doc)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// // We cannot use "compareJSON", since Equals does not report a difference if the value is null -// if exp != string(res) { -// t.Fatalf("Array was not empty, was " + string(res)) -// } -// } - -// func TestMergeComplexMatch(t *testing.T) { -// doc := `{"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4], "nested": {"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4]} }` -// empty := `{}` -// res, err := CreateMergePatch([]byte(doc), []byte(doc)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// // We cannot use "compareJSON", since Equals does not report a difference if the value is null -// if empty != string(res) { -// t.Fatalf("Did not get empty result, was:%s", string(res)) -// } -// } - -// func TestMergeComplexAddAll(t *testing.T) { -// doc := `{"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4], "nested": {"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4]} }` -// empty := `{}` -// res, err := CreateMergePatch([]byte(empty), []byte(doc)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// if !compareJSON(doc, string(res)) { -// t.Fatalf("Did not get everything as, it was:\n%s", string(res)) -// } -// } - -// func TestMergeComplexRemoveAll(t *testing.T) { -// doc := `{"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4], "nested": {"hello": "world","t": true ,"f": false, "n": null,"i": 123,"pi": 3.1416,"a": [1, 2, 3, 4]} }` -// exp := `{"a":null,"f":null,"hello":null,"i":null,"n":null,"nested":null,"pi":null,"t":null}` -// empty := `{}` -// res, err := CreateMergePatch([]byte(doc), []byte(empty)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// if exp != string(res) { -// t.Fatalf("Did not get result, was:%s", string(res)) -// } - -// // FIXME: Crashes if using compareJSON like this: -// /* -// if !compareJSON(doc, string(res)) { -// t.Fatalf("Did not get everything as, it was:\n%s", string(res)) -// } -// */ -// } - -// func TestMergeObjectWithInnerArray(t *testing.T) { -// stateString := `{ -// "OuterArray": [ -// { -// "InnerArray": [ -// { -// "StringAttr": "abc123" -// } -// ], -// "StringAttr": "def456" -// } -// ] -// }` - -// patch, err := CreateMergePatch([]byte(stateString), []byte(stateString)) -// if err != nil { -// t.Fatal(err) -// } - -// if string(patch) != "{}" { -// t.Fatalf("Patch should have been {} but was: %v", string(patch)) -// } -// } - -// func TestMergeReplaceKeyRequiringEscape(t *testing.T) { -// doc := `{ "title": "hello", "nested": {"title/escaped": 1, "two": 2} }` -// pat := `{ "title": "goodbye", "nested": {"title/escaped": 2, "two": 2} }` - -// exp := `{ "title": "goodbye", "nested": {"title~1escaped": 2} }` - -// res, err := CreateMergePatch([]byte(doc), []byte(pat)) - -// if err != nil { -// t.Errorf("Unexpected error: %s, %s", err, string(res)) -// } - -// if !compareJSON(exp, string(res)) { -// t.Log(string(res)) -// t.Fatalf("Key was not replaced") -// } -// } - -// func TestMergePatchReplaceKeyRequiringEscaping(t *testing.T) { -// doc := `{ "obj": { "title/escaped": "hello" } }` -// pat := `{ "obj": { "title~1escaped": "goodbye" } }` -// exp := `{ "obj": { "title/escaped": "goodbye" } }` - -// res := mergePatch(doc, pat) - -// if !compareJSON(exp, res) { -// t.Fatalf("Key was not replaced") -// } -// } diff --git a/util/json/patch.go b/util/json/patch.go deleted file mode 100755 index 91c0419d..00000000 --- a/util/json/patch.go +++ /dev/null @@ -1,601 +0,0 @@ -// Copyright © 2016 Abcum Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package json - -/*import ( - "bytes" - "encoding/json" - "fmt" - "strconv" - "strings" -) - -const ( - eRaw = iota - eDoc - eAry -) - -const LeftBrace byte = 91 // []byte("[") - -type lazyNode struct { - raw *json.RawMessage - doc partialDoc - ary partialArray - which int -} - -type operation map[string]*json.RawMessage - -// Patch is an ordered collection of operations. -type Patch []operation - -type partialDoc map[string]*lazyNode -type partialArray []*lazyNode - -type container interface { - get(key string) (*lazyNode, error) - set(key string, val *lazyNode) error - add(key string, val *lazyNode) error - remove(key string) error -} - -func newLazyNode(raw *json.RawMessage) *lazyNode { - return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw} -} - -func (n *lazyNode) MarshalJSON() ([]byte, error) { - switch n.which { - case eRaw: - return json.Marshal(n.raw) - case eDoc: - return json.Marshal(n.doc) - case eAry: - return json.Marshal(n.ary) - default: - return nil, fmt.Errorf("Unknown type") - } -} - -func (n *lazyNode) UnmarshalJSON(data []byte) error { - dest := make(json.RawMessage, len(data)) - copy(dest, data) - n.raw = &dest - n.which = eRaw - return nil -} - -func (n *lazyNode) intoDoc() (*partialDoc, error) { - if n.which == eDoc { - return &n.doc, nil - } - - err := json.Unmarshal(*n.raw, &n.doc) - - if err != nil { - return nil, err - } - - n.which = eDoc - return &n.doc, nil -} - -func (n *lazyNode) intoAry() (*partialArray, error) { - if n.which == eAry { - return &n.ary, nil - } - - err := json.Unmarshal(*n.raw, &n.ary) - - if err != nil { - return nil, err - } - - n.which = eAry - return &n.ary, nil -} - -func (n *lazyNode) compact() []byte { - buf := &bytes.Buffer{} - - err := json.Compact(buf, *n.raw) - - if err != nil { - return *n.raw - } - - return buf.Bytes() -} - -func (n *lazyNode) tryDoc() bool { - err := json.Unmarshal(*n.raw, &n.doc) - - if err != nil { - return false - } - - n.which = eDoc - return true -} - -func (n *lazyNode) tryAry() bool { - err := json.Unmarshal(*n.raw, &n.ary) - - if err != nil { - return false - } - - n.which = eAry - return true -} - -func (n *lazyNode) equal(o *lazyNode) bool { - if n.which == eRaw { - if !n.tryDoc() && !n.tryAry() { - if o.which != eRaw { - return false - } - - return bytes.Equal(n.compact(), o.compact()) - } - } - - if n.which == eDoc { - if o.which == eRaw { - if !o.tryDoc() { - return false - } - } - - if o.which != eDoc { - return false - } - - for k, v := range n.doc { - ov, ok := o.doc[k] - - if !ok { - return false - } - - if v == nil && ov == nil { - continue - } - - if !v.equal(ov) { - return false - } - } - - return true - } - - if o.which != eAry && !o.tryAry() { - return false - } - - if len(n.ary) != len(o.ary) { - return false - } - - for idx, val := range n.ary { - if !val.equal(o.ary[idx]) { - return false - } - } - - return true -} - -func (o operation) kind() string { - if obj, ok := o["op"]; ok { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown" - } - - return op - } - - return "unknown" -} - -func (o operation) path() string { - if obj, ok := o["path"]; ok { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown" - } - - return op - } - - return "unknown" -} - -func (o operation) from() string { - if obj, ok := o["from"]; ok { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown" - } - - return op - } - - return "unknown" -} - -func (o operation) value() *lazyNode { - if obj, ok := o["value"]; ok { - return newLazyNode(obj) - } - - return nil -} - -func isArray(buf []byte) bool { -Loop: - for _, c := range buf { - switch c { - case ' ': - case '\n': - case '\t': - continue - case '[': - return true - default: - break Loop - } - } - - return false -} - -func findObject(pd *container, path string) (container, string) { - doc := *pd - - split := strings.Split(path, "/") - - parts := split[1 : len(split)-1] - - key := split[len(split)-1] - - var err error - - for _, part := range parts { - - next, ok := doc.get(decodePatchKey(part)) - - if next == nil || ok != nil { - return nil, "" - } - - if isArray(*next.raw) { - doc, err = next.intoAry() - - if err != nil { - return nil, "" - } - } else { - doc, err = next.intoDoc() - - if err != nil { - return nil, "" - } - } - } - - return doc, decodePatchKey(key) -} - -func (d *partialDoc) set(key string, val *lazyNode) error { - (*d)[key] = val - return nil -} - -func (d *partialDoc) add(key string, val *lazyNode) error { - (*d)[key] = val - return nil -} - -func (d *partialDoc) get(key string) (*lazyNode, error) { - return (*d)[key], nil -} - -func (d *partialDoc) remove(key string) error { - _, ok := (*d)[key] - if !ok { - return fmt.Errorf("Unable to remove nonexistent key: %s", key) - } - - delete(*d, key) - return nil -} - -func (d *partialArray) set(key string, val *lazyNode) error { - if key == "-" { - *d = append(*d, val) - return nil - } - - idx, err := strconv.Atoi(key) - if err != nil { - return err - } - - sz := len(*d) - if idx+1 > sz { - sz = idx + 1 - } - - ary := make([]*lazyNode, sz) - - cur := *d - - copy(ary, cur) - - if idx >= len(ary) { - return fmt.Errorf("Unable to access invalid index: %d", idx) - } - - ary[idx] = val - - *d = ary - return nil -} - -func (d *partialArray) add(key string, val *lazyNode) error { - if key == "-" { - *d = append(*d, val) - return nil - } - - idx, err := strconv.Atoi(key) - if err != nil { - return err - } - - ary := make([]*lazyNode, len(*d)+1) - - cur := *d - - copy(ary[0:idx], cur[0:idx]) - ary[idx] = val - copy(ary[idx+1:], cur[idx:]) - - *d = ary - return nil -} - -func (d *partialArray) get(key string) (*lazyNode, error) { - idx, err := strconv.Atoi(key) - - if err != nil { - return nil, err - } - - if idx >= len(*d) { - return nil, fmt.Errorf("Unable to access invalid index: %d", idx) - } - - return (*d)[idx], nil -} - -func (d *partialArray) remove(key string) error { - idx, err := strconv.Atoi(key) - if err != nil { - return err - } - - cur := *d - - if idx >= len(cur) { - return fmt.Errorf("Unable to remove invalid index: %d", idx) - } - - ary := make([]*lazyNode, len(cur)-1) - - copy(ary[0:idx], cur[0:idx]) - copy(ary[idx:], cur[idx+1:]) - - *d = ary - return nil - -} - -func (p Patch) add(doc *container, op operation) error { - path := op.path() - - con, key := findObject(doc, path) - - if con == nil { - return fmt.Errorf("jsonpatch add operation does not apply: doc is missing path: %s", path) - } - - return con.add(key, op.value()) -} - -func (p Patch) remove(doc *container, op operation) error { - path := op.path() - - con, key := findObject(doc, path) - - if con == nil { - return fmt.Errorf("jsonpatch remove operation does not apply: doc is missing path: %s", path) - } - - return con.remove(key) -} - -func (p Patch) replace(doc *container, op operation) error { - path := op.path() - - con, key := findObject(doc, path) - - if con == nil { - return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing path: %s", path) - } - - return con.set(key, op.value()) -} - -func (p Patch) move(doc *container, op operation) error { - from := op.from() - - con, key := findObject(doc, from) - - if con == nil { - return fmt.Errorf("jsonpatch move operation does not apply: doc is missing from path: %s", from) - } - - val, err := con.get(key) - if err != nil { - return err - } - - err = con.remove(key) - if err != nil { - return err - } - - path := op.path() - - con, key = findObject(doc, path) - - if con == nil { - return fmt.Errorf("jsonpatch move operation does not apply: doc is missing destination path: %s", path) - } - - return con.set(key, val) -} - -func (p Patch) test(doc *container, op operation) error { - path := op.path() - - con, key := findObject(doc, path) - - if con == nil { - return fmt.Errorf("jsonpatch test operation does not apply: is missing path: %s", path) - } - - val, err := con.get(key) - - if err != nil { - return err - } - - if val == nil { - if op.value().raw == nil { - return nil - } else { - return fmt.Errorf("Testing value %s failed", path) - } - } - - if val.equal(op.value()) { - return nil - } - - return fmt.Errorf("Testing value %s failed", path) -} - -// Equal indicates if 2 JSON documents have the same structural equality. -func Equal(a, b []byte) bool { - ra := make(json.RawMessage, len(a)) - copy(ra, a) - la := newLazyNode(&ra) - - rb := make(json.RawMessage, len(b)) - copy(rb, b) - lb := newLazyNode(&rb) - - return la.equal(lb) -} - -// DecodePatch decodes the passed JSON document as an RFC 6902 patch. -func DecodePatch(buf []byte) (Patch, error) { - var p Patch - - err := json.Unmarshal(buf, &p) - - if err != nil { - return nil, err - } - - return p, nil -} - -// Apply mutates a JSON document according to the patch, and returns the new -// document. -func (p Patch) Apply(doc []byte) ([]byte, error) { - return p.ApplyIndent(doc, "") -} - -// ApplyIndent mutates a JSON document according to the patch, and returns the new -// document indented. -func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) { - var pd container - if doc[0] == LeftBrace { - pd = &partialArray{} - } else { - pd = &partialDoc{} - } - - err := json.Unmarshal(doc, pd) - - if err != nil { - return nil, err - } - - err = nil - - for _, op := range p { - switch op.kind() { - case "add": - err = p.add(&pd, op) - case "remove": - err = p.remove(&pd, op) - case "replace": - err = p.replace(&pd, op) - case "move": - err = p.move(&pd, op) - case "test": - err = p.test(&pd, op) - default: - err = fmt.Errorf("Unexpected kind: %s", op.kind()) - } - - if err != nil { - return nil, err - } - } - - if indent != "" { - return json.MarshalIndent(pd, "", indent) - } - - return json.Marshal(pd) -} -*/ diff --git a/util/json/patch_test.go b/util/json/patch_test.go deleted file mode 100755 index 9bfc63f1..00000000 --- a/util/json/patch_test.go +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright © 2016 Abcum Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package json - -// import ( -// "bytes" -// "encoding/json" -// "fmt" -// "reflect" -// "testing" -// ) - -// func reformatJSON(j string) string { -// buf := new(bytes.Buffer) - -// json.Indent(buf, []byte(j), "", " ") - -// return buf.String() -// } - -// func compareJSON(a, b string) bool { -// // return Equal([]byte(a), []byte(b)) - -// var obj_a, obj_b map[string]interface{} -// json.Unmarshal([]byte(a), &obj_a) -// json.Unmarshal([]byte(b), &obj_b) - -// // fmt.Printf("Comparing %#v\nagainst %#v\n", obj_a, obj_b) -// return reflect.DeepEqual(obj_a, obj_b) -// } - -// func applyPatch(doc, patch string) (string, error) { -// obj, err := DecodePatch([]byte(patch)) - -// if err != nil { -// panic(err) -// } - -// out, err := obj.Apply([]byte(doc)) - -// if err != nil { -// return "", err -// } - -// return string(out), nil -// } - -// type Case struct { -// doc, patch, result string -// } - -// var Cases = []Case{ -// { -// `{ "foo": "bar"}`, -// `[ -// { "op": "add", "path": "/baz", "value": "qux" } -// ]`, -// `{ -// "baz": "qux", -// "foo": "bar" -// }`, -// }, -// { -// `{ "foo": [ "bar", "baz" ] }`, -// `[ -// { "op": "add", "path": "/foo/1", "value": "qux" } -// ]`, -// `{ "foo": [ "bar", "qux", "baz" ] }`, -// }, -// { -// `{ "baz": "qux", "foo": "bar" }`, -// `[ { "op": "remove", "path": "/baz" } ]`, -// `{ "foo": "bar" }`, -// }, -// { -// `{ "foo": [ "bar", "qux", "baz" ] }`, -// `[ { "op": "remove", "path": "/foo/1" } ]`, -// `{ "foo": [ "bar", "baz" ] }`, -// }, -// { -// `{ "baz": "qux", "foo": "bar" }`, -// `[ { "op": "replace", "path": "/baz", "value": "boo" } ]`, -// `{ "baz": "boo", "foo": "bar" }`, -// }, -// { -// `{ -// "foo": { -// "bar": "baz", -// "waldo": "fred" -// }, -// "qux": { -// "corge": "grault" -// } -// }`, -// `[ { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" } ]`, -// `{ -// "foo": { -// "bar": "baz" -// }, -// "qux": { -// "corge": "grault", -// "thud": "fred" -// } -// }`, -// }, -// { -// `{ "foo": [ "all", "grass", "cows", "eat" ] }`, -// `[ { "op": "move", "from": "/foo/1", "path": "/foo/3" } ]`, -// `{ "foo": [ "all", "cows", "eat", "grass" ] }`, -// }, -// { -// `{ "foo": "bar" }`, -// `[ { "op": "add", "path": "/child", "value": { "grandchild": { } } } ]`, -// `{ "foo": "bar", "child": { "grandchild": { } } }`, -// }, -// { -// `{ "foo": ["bar"] }`, -// `[ { "op": "add", "path": "/foo/-", "value": ["abc", "def"] } ]`, -// `{ "foo": ["bar", ["abc", "def"]] }`, -// }, -// { -// `{ "foo": "bar", "qux": { "baz": 1, "bar": null } }`, -// `[ { "op": "remove", "path": "/qux/bar" } ]`, -// `{ "foo": "bar", "qux": { "baz": 1 } }`, -// }, -// { -// `{ "foo": "bar" }`, -// `[ { "op": "add", "path": "/baz", "value": null } ]`, -// `{ "baz": null, "foo": "bar" }`, -// }, -// { -// `{ "foo": ["bar"]}`, -// `[ { "op": "replace", "path": "/foo/0", "value": "baz"}]`, -// `{ "foo": ["baz"]}`, -// }, -// { -// `{ "foo": ["bar","baz"]}`, -// `[ { "op": "replace", "path": "/foo/0", "value": "bum"}]`, -// `{ "foo": ["bum","baz"]}`, -// }, -// { -// `{ "foo": ["bar","qux","baz"]}`, -// `[ { "op": "replace", "path": "/foo/1", "value": "bum"}]`, -// `{ "foo": ["bar", "bum","baz"]}`, -// }, -// { -// `[ {"foo": ["bar","qux","baz"]}]`, -// `[ { "op": "replace", "path": "/0/foo/0", "value": "bum"}]`, -// `[ {"foo": ["bum","qux","baz"]}]`, -// }, -// } - -// type BadCase struct { -// doc, patch string -// } - -// var MutationTestCases = []BadCase{ -// { -// `{ "foo": "bar", "qux": { "baz": 1, "bar": null } }`, -// `[ { "op": "remove", "path": "/qux/bar" } ]`, -// }, -// { -// `{ "foo": "bar", "qux": { "baz": 1, "bar": null } }`, -// `[ { "op": "replace", "path": "/qux/baz", "value": null } ]`, -// }, -// } - -// var BadCases = []BadCase{ -// { -// `{ "foo": "bar" }`, -// `[ { "op": "add", "path": "/baz/bat", "value": "qux" } ]`, -// }, -// { -// `{ "a": { "b": { "d": 1 } } }`, -// `[ { "op": "remove", "path": "/a/b/c" } ]`, -// }, -// { -// `{ "a": { "b": { "d": 1 } } }`, -// `[ { "op": "move", "from": "/a/b/c", "path": "/a/b/e" } ]`, -// }, -// { -// `{ "a": { "b": [1] } }`, -// `[ { "op": "remove", "path": "/a/b/1" } ]`, -// }, -// { -// `{ "a": { "b": [1] } }`, -// `[ { "op": "move", "from": "/a/b/1", "path": "/a/b/2" } ]`, -// }, -// } - -// func TestAllCases(t *testing.T) { -// for _, c := range Cases { -// out, err := applyPatch(c.doc, c.patch) - -// if err != nil { -// t.Errorf("Unable to apply patch: %s", err) -// } - -// if !compareJSON(out, c.result) { -// t.Errorf("Patch did not apply. Expected:\n%s\n\nActual:\n%s", -// reformatJSON(c.result), reformatJSON(out)) -// } -// } - -// for _, c := range MutationTestCases { -// out, err := applyPatch(c.doc, c.patch) - -// if err != nil { -// t.Errorf("Unable to apply patch: %s", err) -// } - -// if compareJSON(out, c.doc) { -// t.Errorf("Patch did not apply. Original:\n%s\n\nPatched:\n%s", -// reformatJSON(c.doc), reformatJSON(out)) -// } -// } - -// for _, c := range BadCases { -// _, err := applyPatch(c.doc, c.patch) - -// if err == nil { -// t.Errorf("Patch should have failed to apply but it did not") -// } -// } -// } - -// type TestCase struct { -// doc, patch string -// result bool -// failedPath string -// } - -// var TestCases = []TestCase{ -// { -// `{ -// "baz": "qux", -// "foo": [ "a", 2, "c" ] -// }`, -// `[ -// { "op": "test", "path": "/baz", "value": "qux" }, -// { "op": "test", "path": "/foo/1", "value": 2 } -// ]`, -// true, -// "", -// }, -// { -// `{ "baz": "qux" }`, -// `[ { "op": "test", "path": "/baz", "value": "bar" } ]`, -// false, -// "/baz", -// }, -// { -// `{ -// "baz": "qux", -// "foo": ["a", 2, "c"] -// }`, -// `[ -// { "op": "test", "path": "/baz", "value": "qux" }, -// { "op": "test", "path": "/foo/1", "value": "c" } -// ]`, -// false, -// "/foo/1", -// }, -// { -// `{ "baz": "qux" }`, -// `[ { "op": "test", "path": "/foo", "value": 42 } ]`, -// false, -// "/foo", -// }, -// { -// `{ "baz": "qux" }`, -// `[ { "op": "test", "path": "/foo", "value": null } ]`, -// true, -// "", -// }, -// { -// `{ "baz/foo": "qux" }`, -// `[ { "op": "test", "path": "/baz~1foo", "value": "qux"} ]`, -// true, -// "", -// }, -// } - -// func TestAllTest(t *testing.T) { -// for _, c := range TestCases { -// _, err := applyPatch(c.doc, c.patch) - -// if c.result && err != nil { -// t.Errorf("Testing failed when it should have passed: %s", err) -// } else if !c.result && err == nil { -// t.Errorf("Testing passed when it should have faild: %s", err) -// } else if !c.result { -// expected := fmt.Sprintf("Testing value %s failed", c.failedPath) -// if err.Error() != expected { -// t.Errorf("Testing failed as expected but invalid message: expected [%s], got [%s]", expected, err) -// } -// } -// } -// }