mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			2119 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			2119 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2014 The Kubernetes Authors.
 | |
| 
 | |
| 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 strategicpatch
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"reflect"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/davecgh/go-spew/spew"
 | |
| 	"github.com/ghodss/yaml"
 | |
| )
 | |
| 
 | |
| type SortMergeListTestCases struct {
 | |
| 	TestCases []SortMergeListTestCase
 | |
| }
 | |
| 
 | |
| type SortMergeListTestCase struct {
 | |
| 	Description string
 | |
| 	Original    map[string]interface{}
 | |
| 	Sorted      map[string]interface{}
 | |
| }
 | |
| 
 | |
| type StrategicMergePatchTestCases struct {
 | |
| 	TestCases []StrategicMergePatchTestCase
 | |
| }
 | |
| 
 | |
| type StrategicMergePatchTestCase struct {
 | |
| 	Description string
 | |
| 	StrategicMergePatchTestCaseData
 | |
| }
 | |
| 
 | |
| type StrategicMergePatchTestCaseData struct {
 | |
| 	Original map[string]interface{}
 | |
| 	TwoWay   map[string]interface{}
 | |
| 	Modified map[string]interface{}
 | |
| 	Current  map[string]interface{}
 | |
| 	ThreeWay map[string]interface{}
 | |
| 	Result   map[string]interface{}
 | |
| }
 | |
| 
 | |
| type MergeItem struct {
 | |
| 	Name              string
 | |
| 	Value             string
 | |
| 	Other             string
 | |
| 	MergingList       []MergeItem `patchStrategy:"merge" patchMergeKey:"name"`
 | |
| 	NonMergingList    []MergeItem
 | |
| 	MergingIntList    []int `patchStrategy:"merge"`
 | |
| 	NonMergingIntList []int
 | |
| 	MergeItemPtr      *MergeItem `patchStrategy:"merge" patchMergeKey:"name"`
 | |
| 	SimpleMap         map[string]string
 | |
| }
 | |
| 
 | |
| var mergeItem MergeItem
 | |
| 
 | |
| // These are test cases for SortMergeList, used to assert that it (recursively)
 | |
| // sorts both merging and non merging lists correctly.
 | |
| var sortMergeListTestCaseData = []byte(`
 | |
| testCases:
 | |
|   - description: sort one list of maps
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 3
 | |
|         - name: 2
 | |
|     sorted:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|         - name: 3
 | |
|   - description: sort lists of maps but not nested lists of maps
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|             - name: 3
 | |
|             - name: 2
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 2
 | |
|             - name: 1
 | |
|     sorted:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 2
 | |
|             - name: 1
 | |
|         - name: 2
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|             - name: 3
 | |
|             - name: 2
 | |
|   - description: sort lists of maps and nested lists of maps
 | |
|     fieldTypes:
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|             - name: 3
 | |
|             - name: 2
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 2
 | |
|             - name: 1
 | |
|     sorted:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|         - name: 2
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|             - name: 3
 | |
|   - description: merging list should NOT sort when nested in non merging list
 | |
|     original:
 | |
|       nonMergingList:
 | |
|         - name: 2
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|             - name: 3
 | |
|             - name: 2
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 2
 | |
|             - name: 1
 | |
|     sorted:
 | |
|       nonMergingList:
 | |
|         - name: 2
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|             - name: 3
 | |
|             - name: 2
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 2
 | |
|             - name: 1
 | |
|   - description: sort very nested list of maps
 | |
|     fieldTypes:
 | |
|     original:
 | |
|       mergingList:
 | |
|         - mergingList:
 | |
|             - mergingList:
 | |
|                 - name: 2
 | |
|                 - name: 1
 | |
|     sorted:
 | |
|       mergingList:
 | |
|         - mergingList:
 | |
|             - mergingList:
 | |
|                 - name: 1
 | |
|                 - name: 2
 | |
|   - description: sort nested lists of ints
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|           mergingIntList:
 | |
|             - 1
 | |
|             - 3
 | |
|             - 2
 | |
|         - name: 1
 | |
|           mergingIntList:
 | |
|             - 2
 | |
|             - 1
 | |
|     sorted:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingIntList:
 | |
|             - 1
 | |
|             - 2
 | |
|         - name: 2
 | |
|           mergingIntList:
 | |
|             - 1
 | |
|             - 2
 | |
|             - 3
 | |
|   - description: sort nested pointers of ints
 | |
|     original:
 | |
|       mergeItemPtr:
 | |
|         - name: 2
 | |
|           mergingIntList:
 | |
|             - 1
 | |
|             - 3
 | |
|             - 2
 | |
|         - name: 1
 | |
|           mergingIntList:
 | |
|             - 2
 | |
|             - 1
 | |
|     sorted:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           mergingIntList:
 | |
|             - 1
 | |
|             - 2
 | |
|         - name: 2
 | |
|           mergingIntList:
 | |
|             - 1
 | |
|             - 2
 | |
|             - 3
 | |
|   - description: sort merging list by pointer
 | |
|     original:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|         - name: 3
 | |
|         - name: 2
 | |
|     sorted:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|         - name: 3
 | |
| `)
 | |
| 
 | |
| func TestSortMergeLists(t *testing.T) {
 | |
| 	tc := SortMergeListTestCases{}
 | |
| 	err := yaml.Unmarshal(sortMergeListTestCaseData, &tc)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("can't unmarshal test cases: %s\n", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	for _, c := range tc.TestCases {
 | |
| 		original := testObjectToJSONOrFail(t, c.Original, c.Description)
 | |
| 		sorted := testObjectToJSONOrFail(t, c.Sorted, c.Description)
 | |
| 		if !reflect.DeepEqual(original, sorted) {
 | |
| 			t.Errorf("error in test case: %s\ncannot sort object:\n%s\nexpected:\n%s\ngot:\n%s\n",
 | |
| 				c.Description, toYAMLOrError(c.Original), toYAMLOrError(c.Sorted), jsonToYAMLOrError(original))
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // These are test cases for StrategicMergePatch that cannot be generated using
 | |
| // CreateTwoWayMergePatch because it doesn't use the replace directive, generate
 | |
| // duplicate integers for a merging list patch, or generate empty merging lists.
 | |
| var customStrategicMergePatchTestCaseData = []byte(`
 | |
| testCases:
 | |
|   - description: unique scalars when merging lists
 | |
|     original:
 | |
|       mergingIntList:
 | |
|         - 1
 | |
|         - 2
 | |
|     twoWay:
 | |
|       mergingIntList:
 | |
|         - 2
 | |
|         - 3
 | |
|     modified:
 | |
|       mergingIntList:
 | |
|         - 1
 | |
|         - 2
 | |
|         - 3
 | |
|   - description: delete map from nested map
 | |
|     original:
 | |
|       simpleMap:
 | |
|         key1: 1
 | |
|         key2: 1
 | |
|     twoWay:
 | |
|       simpleMap:
 | |
|         $patch: delete
 | |
|     modified:
 | |
|       simpleMap:
 | |
|         {}
 | |
|   - description: delete all items from merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - $patch: replace
 | |
|     modified:
 | |
|       mergingList: []
 | |
|   - description: merge empty merging lists
 | |
|     original:
 | |
|       mergingList: []
 | |
|     twoWay:
 | |
|       mergingList: []
 | |
|     modified:
 | |
|       mergingList: []
 | |
|   - description: delete all keys from map
 | |
|     original:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     twoWay:
 | |
|       $patch: replace
 | |
|     modified: {}
 | |
|   - description: add key and delete all keys from map
 | |
|     original:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     twoWay:
 | |
|       other: a
 | |
|       $patch: replace
 | |
|     modified:
 | |
|       other: a
 | |
| `)
 | |
| 
 | |
| func TestCustomStrategicMergePatch(t *testing.T) {
 | |
| 	tc := StrategicMergePatchTestCases{}
 | |
| 	err := yaml.Unmarshal(customStrategicMergePatchTestCaseData, &tc)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("can't unmarshal test cases: %v\n", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	for _, c := range tc.TestCases {
 | |
| 		original, twoWay, modified := twoWayTestCaseToJSONOrFail(t, c)
 | |
| 		testPatchApplication(t, original, twoWay, modified, c.Description)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // These are test cases for StrategicMergePatch, to assert that applying  a patch
 | |
| // yields the correct outcome. They are also test cases for CreateTwoWayMergePatch
 | |
| // and CreateThreeWayMergePatch, to assert that they both generate the correct patch
 | |
| // for the given set of input documents.
 | |
| //
 | |
| var createStrategicMergePatchTestCaseData = []byte(`
 | |
| testCases:
 | |
|   - description: nil original
 | |
|     twoWay:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     modified:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     current:
 | |
|       name: 1
 | |
|       other: a
 | |
|     threeWay:
 | |
|       value: 1
 | |
|     result:
 | |
|       name: 1
 | |
|       value: 1
 | |
|       other: a
 | |
|   - description: nil patch
 | |
|     original:
 | |
|       name: 1
 | |
|     twoWay:
 | |
|       {}
 | |
|     modified:
 | |
|       name: 1
 | |
|     current:
 | |
|       name: 1
 | |
|     threeWay:
 | |
|       {}
 | |
|     result:
 | |
|       name: 1
 | |
|   - description: add field to map
 | |
|     original:
 | |
|       name: 1
 | |
|     twoWay:
 | |
|       value: 1
 | |
|     modified:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     current:
 | |
|       name: 1
 | |
|       other: a
 | |
|     threeWay:
 | |
|       value: 1
 | |
|     result:
 | |
|       name: 1
 | |
|       value: 1
 | |
|       other: a
 | |
|   - description: add field to map with conflict
 | |
|     original:
 | |
|       name: 1
 | |
|     twoWay:
 | |
|       value: 1
 | |
|     modified:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     current:
 | |
|       name: a
 | |
|       other: a
 | |
|     threeWay:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     result:
 | |
|       name: 1
 | |
|       value: 1
 | |
|       other: a
 | |
|   - description: add field and delete field from map
 | |
|     original:
 | |
|       name: 1
 | |
|     twoWay:
 | |
|       name: null
 | |
|       value: 1
 | |
|     modified:
 | |
|       value: 1
 | |
|     current:
 | |
|       name: 1
 | |
|       other: a
 | |
|     threeWay:
 | |
|       name: null
 | |
|       value: 1
 | |
|     result:
 | |
|       value: 1
 | |
|       other: a
 | |
|   - description: add field and delete field from map with conflict
 | |
|     original:
 | |
|       name: 1
 | |
|     twoWay:
 | |
|       name: null
 | |
|       value: 1
 | |
|     modified:
 | |
|       value: 1
 | |
|     current:
 | |
|       name: a
 | |
|       other: a
 | |
|     threeWay:
 | |
|       name: null
 | |
|       value: 1
 | |
|     result:
 | |
|       value: 1
 | |
|       other: a
 | |
|   - description: delete field from nested map
 | |
|     original:
 | |
|       simpleMap:
 | |
|         key1: 1
 | |
|         key2: 1
 | |
|     twoWay:
 | |
|       simpleMap:
 | |
|         key2: null
 | |
|     modified:
 | |
|       simpleMap:
 | |
|         key1: 1
 | |
|     current:
 | |
|       simpleMap:
 | |
|         key1: 1
 | |
|         key2: 1
 | |
|         other: a
 | |
|     threeWay:
 | |
|       simpleMap:
 | |
|         key2: null
 | |
|     result:
 | |
|       simpleMap:
 | |
|         key1: 1
 | |
|         other: a
 | |
|   - description: delete field from nested map with conflict
 | |
|     original:
 | |
|       simpleMap:
 | |
|         key1: 1
 | |
|         key2: 1
 | |
|     twoWay:
 | |
|       simpleMap:
 | |
|         key2: null
 | |
|     modified:
 | |
|       simpleMap:
 | |
|         key1: 1
 | |
|     current:
 | |
|       simpleMap:
 | |
|         key1: a
 | |
|         key2: 1
 | |
|         other: a
 | |
|     threeWay:
 | |
|       simpleMap:
 | |
|         key1: 1
 | |
|         key2: null
 | |
|     result:
 | |
|       simpleMap:
 | |
|         key1: 1
 | |
|         other: a
 | |
|   - description: delete all fields from map
 | |
|     original:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     twoWay:
 | |
|       name: null
 | |
|       value: null
 | |
|     modified: {}
 | |
|     current:
 | |
|       name: 1
 | |
|       value: 1
 | |
|       other: a
 | |
|     threeWay:
 | |
|       name: null
 | |
|       value: null
 | |
|     result: 
 | |
|       other: a
 | |
|   - description: delete all fields from map with conflict
 | |
|     original:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     twoWay:
 | |
|       name: null
 | |
|       value: null
 | |
|     modified: {}
 | |
|     current:
 | |
|       name: 1
 | |
|       value: a
 | |
|       other: a
 | |
|     threeWay:
 | |
|       name: null
 | |
|       value: null
 | |
|     result: 
 | |
|       other: a
 | |
|   - description: add field and delete all fields from map
 | |
|     original:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     twoWay:
 | |
|       name: null
 | |
|       value: null
 | |
|       other: a
 | |
|     modified:
 | |
|       other: a
 | |
|     current:
 | |
|       name: 1
 | |
|       value: 1
 | |
|       other: a
 | |
|     threeWay:
 | |
|       name: null
 | |
|       value: null
 | |
|     result:
 | |
|       other: a
 | |
|   - description: add field and delete all fields from map with conflict
 | |
|     original:
 | |
|       name: 1
 | |
|       value: 1
 | |
|     twoWay:
 | |
|       name: null
 | |
|       value: null
 | |
|       other: a
 | |
|     modified:
 | |
|       other: a
 | |
|     current:
 | |
|       name: 1
 | |
|       value: 1
 | |
|       other: b
 | |
|     threeWay:
 | |
|       name: null
 | |
|       value: null
 | |
|       other: a
 | |
|     result:
 | |
|       other: a
 | |
|   - description: replace list of scalars
 | |
|     original:
 | |
|       nonMergingIntList:
 | |
|         - 1
 | |
|         - 2
 | |
|     twoWay:
 | |
|       nonMergingIntList:
 | |
|         - 2
 | |
|         - 3
 | |
|     modified:
 | |
|       nonMergingIntList:
 | |
|         - 2
 | |
|         - 3
 | |
|     current:
 | |
|       nonMergingIntList:
 | |
|         - 1
 | |
|         - 2
 | |
|     threeWay:
 | |
|       nonMergingIntList:
 | |
|         - 2
 | |
|         - 3
 | |
|     result:
 | |
|       nonMergingIntList:
 | |
|         - 2
 | |
|         - 3
 | |
|   - description: replace list of scalars with conflict
 | |
|     original:
 | |
|       nonMergingIntList:
 | |
|         - 1
 | |
|         - 2
 | |
|     twoWay:
 | |
|       nonMergingIntList:
 | |
|         - 2
 | |
|         - 3
 | |
|     modified:
 | |
|       nonMergingIntList:
 | |
|         - 2
 | |
|         - 3
 | |
|     current:
 | |
|       nonMergingIntList:
 | |
|         - 1
 | |
|         - 4
 | |
|     threeWay:
 | |
|       nonMergingIntList:
 | |
|         - 2
 | |
|         - 3
 | |
|     result:
 | |
|       nonMergingIntList:
 | |
|         - 2
 | |
|         - 3
 | |
|   - description: merge lists of scalars
 | |
|     original:
 | |
|       mergingIntList:
 | |
|         - 1
 | |
|         - 2
 | |
|     twoWay:
 | |
|       mergingIntList:
 | |
|         - 3
 | |
|     modified:
 | |
|       mergingIntList:
 | |
|         - 1
 | |
|         - 2
 | |
|         - 3
 | |
|     current:
 | |
|       mergingIntList:
 | |
|         - 1
 | |
|         - 2
 | |
|         - 4
 | |
|     threeWay:
 | |
|       mergingIntList:
 | |
|         - 3
 | |
|     result:
 | |
|       mergingIntList:
 | |
|         - 1
 | |
|         - 2
 | |
|         - 3
 | |
|         - 4
 | |
|   - description: merge lists of maps
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 3
 | |
|           value: 3
 | |
|         - name: 4 
 | |
|           value: 4 
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 4 
 | |
|           value: 4 
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|         - name: 3
 | |
|           value: 3
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 3
 | |
|           value: 3
 | |
|         - name: 4 
 | |
|           value: 4 
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|         - name: 3
 | |
|           value: 3
 | |
|         - name: 4 
 | |
|           value: 4 
 | |
|   - description: merge lists of maps with conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 3
 | |
|           value: 3
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|         - name: 3
 | |
|           value: 3
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 3
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|           value: 2
 | |
|         - name: 3
 | |
|           value: 3
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|         - name: 3
 | |
|           value: 3
 | |
|   - description: add field to map in merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|   - description: add field to map in merging list with conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 3
 | |
|           value: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|         - name: 3
 | |
|           value: 2
 | |
|           other: b
 | |
|   - description: add duplicate field to map in merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       {}
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|   - description: add duplicate field to map in merging list with conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 3
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|   - description: replace map field value in merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: a
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: a
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: a
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|   - description: replace map field value in merging list with conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: a
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 3
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: a
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: a
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|   - description: delete map from merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|           other: b
 | |
|   - description: delete map from merging list with conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|           other: b
 | |
|   - description: delete missing map from merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|           other: b
 | |
|   - description: delete missing map from merging list with conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 3
 | |
|           other: a
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 2
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 2
 | |
|         - name: 3
 | |
|           other: a
 | |
|   - description: add map and delete map from merging list
 | |
|     original:
 | |
|       merginglist:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       merginglist:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 3
 | |
|     modified:
 | |
|       merginglist:
 | |
|         - name: 2
 | |
|         - name: 3
 | |
|     current:
 | |
|       merginglist:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           other: b
 | |
|         - name: 4
 | |
|           other: c
 | |
|     threeWay:
 | |
|       merginglist:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 3
 | |
|     result:
 | |
|       merginglist:
 | |
|         - name: 2
 | |
|           other: b
 | |
|         - name: 3
 | |
|         - name: 4
 | |
|           other: c
 | |
|   - description: add map and delete map from merging list with conflict
 | |
|     original:
 | |
|       merginglist:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       merginglist:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 3
 | |
|     modified:
 | |
|       merginglist:
 | |
|         - name: 2
 | |
|         - name: 3
 | |
|     current:
 | |
|       merginglist:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 4
 | |
|           other: c
 | |
|     threeWay:
 | |
|       merginglist:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 2
 | |
|         - name: 3
 | |
|     result:
 | |
|       merginglist:
 | |
|         - name: 2
 | |
|         - name: 3
 | |
|         - name: 4
 | |
|           other: c
 | |
|   - description: delete all maps from merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 2
 | |
|           $patch: delete
 | |
|     modified:
 | |
|       mergingList: []
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 2
 | |
|           $patch: delete
 | |
|     result:
 | |
|       mergingList: []
 | |
|   - description: delete all maps from merging list with conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 2
 | |
|           $patch: delete
 | |
|     modified:
 | |
|       mergingList: []
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 2
 | |
|           $patch: delete
 | |
|     result:
 | |
|       mergingList: []
 | |
|   - description: delete all maps from empty merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 2
 | |
|           $patch: delete
 | |
|     modified:
 | |
|       mergingList: []
 | |
|     current:
 | |
|       mergingList: []
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           $patch: delete
 | |
|         - name: 2
 | |
|           $patch: delete
 | |
|     result:
 | |
|       mergingList: []
 | |
|   - description: delete field from map in merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: null
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: null
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|   - description: delete field from map in merging list with conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: null
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: a
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: null
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|   - description: delete missing field from map in merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: null
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: null
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|   - description: delete missing field from map in merging list with conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: null
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           value: null
 | |
|         - name: 2
 | |
|           value: 2
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|           value: 2
 | |
|           other: b
 | |
|   - description: replace non merging list nested in merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|         - name: 2
 | |
|           other: b
 | |
|   - description: replace non merging list nested in merging list with value conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: c
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|         - name: 2
 | |
|           other: b
 | |
|   - description: replace non merging list nested in merging list with deletion conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           nonMergingList:
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           nonMergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|         - name: 2
 | |
|           other: b
 | |
|   - description: add field to map in merging list nested in merging list
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|           other: b
 | |
|   - description: add field to map in merging list nested in merging list with value conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: a
 | |
|               other: c
 | |
|             - name: 2
 | |
|               value: b
 | |
|               other: d
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|               other: c
 | |
|             - name: 2
 | |
|               value: 2
 | |
|               other: d
 | |
|         - name: 2
 | |
|           other: b
 | |
|   - description: add field to map in merging list nested in merging list with deletion conflict
 | |
|     original:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     modified:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           mergingList:
 | |
|             - name: 2
 | |
|               value: 2
 | |
|               other: d
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     result:
 | |
|       mergingList:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           mergingList:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|               other: d
 | |
|         - name: 2
 | |
|           other: b
 | |
|   - description: merge empty merging lists
 | |
|     original:
 | |
|       mergingList: []
 | |
|     twoWay:
 | |
|       {}
 | |
|     modified:
 | |
|       mergingList: []
 | |
|     current:
 | |
|       mergingList: []
 | |
|     threeWay:
 | |
|       {}
 | |
|     result:
 | |
|       mergingList: []
 | |
|   - description: add map to merging list by pointer
 | |
|     original:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|     twoWay:
 | |
|       mergeItemPtr:
 | |
|         - name: 2
 | |
|     modified:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 3
 | |
|     threeWay:
 | |
|       mergeItemPtr:
 | |
|         - name: 2
 | |
|     result:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           other: a
 | |
|         - name: 2
 | |
|         - name: 3
 | |
|   - description: add map to merging list by pointer with conflict
 | |
|     original:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|     twoWay:
 | |
|       mergeItemPtr:
 | |
|         - name: 2
 | |
|     modified:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergeItemPtr:
 | |
|         - name: 3
 | |
|     threeWay:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|     result:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|         - name: 2
 | |
|         - name: 3
 | |
|   - description: add field to map in merging list by pointer
 | |
|     original:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     modified:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|               other: a
 | |
|             - name: 2
 | |
|               value: 2
 | |
|               other: b
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     result:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|               other: a
 | |
|             - name: 2
 | |
|               value: 2
 | |
|               other: b
 | |
|         - name: 2
 | |
|           other: b
 | |
|   - description: add field to map in merging list by pointer with conflict
 | |
|     original:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     twoWay:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     modified:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|         - name: 2
 | |
|     current:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|               value: a
 | |
|             - name: 2
 | |
|               value: 2
 | |
|               other: b
 | |
|         - name: 2
 | |
|           other: b
 | |
|     threeWay:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|     result:
 | |
|       mergeItemPtr:
 | |
|         - name: 1
 | |
|           other: a
 | |
|           mergeItemPtr:
 | |
|             - name: 1
 | |
|               value: 1
 | |
|             - name: 2
 | |
|               value: 2
 | |
|               other: b
 | |
|         - name: 2
 | |
|           other: b
 | |
| `)
 | |
| 
 | |
| func TestStrategicMergePatch(t *testing.T) {
 | |
| 	testStrategicMergePatchWithCustomArguments(t, "bad original",
 | |
| 		"<THIS IS NOT JSON>", "{}", mergeItem, errBadJSONDoc)
 | |
| 	testStrategicMergePatchWithCustomArguments(t, "bad patch",
 | |
| 		"{}", "<THIS IS NOT JSON>", mergeItem, errBadJSONDoc)
 | |
| 	testStrategicMergePatchWithCustomArguments(t, "bad struct",
 | |
| 		"{}", "{}", []byte("<THIS IS NOT A STRUCT>"), fmt.Errorf(errBadArgTypeFmt, "struct", "slice"))
 | |
| 	testStrategicMergePatchWithCustomArguments(t, "nil struct",
 | |
| 		"{}", "{}", nil, fmt.Errorf(errBadArgTypeFmt, "struct", "nil"))
 | |
| 
 | |
| 	tc := StrategicMergePatchTestCases{}
 | |
| 	err := yaml.Unmarshal(createStrategicMergePatchTestCaseData, &tc)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("can't unmarshal test cases: %s\n", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	for _, c := range tc.TestCases {
 | |
| 		testTwoWayPatch(t, c)
 | |
| 		testThreeWayPatch(t, c)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func testStrategicMergePatchWithCustomArguments(t *testing.T, description, original, patch string, dataStruct interface{}, err error) {
 | |
| 	_, err2 := StrategicMergePatch([]byte(original), []byte(patch), dataStruct)
 | |
| 	if err2 != err {
 | |
| 		if err2 == nil {
 | |
| 			t.Errorf("expected error: %s\ndid not occur in test case: %s", err, description)
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		if err == nil || err2.Error() != err.Error() {
 | |
| 			t.Errorf("unexpected error: %s\noccurred in test case: %s", err2, description)
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func testTwoWayPatch(t *testing.T, c StrategicMergePatchTestCase) {
 | |
| 	original, expected, modified := twoWayTestCaseToJSONOrFail(t, c)
 | |
| 
 | |
| 	actual, err := CreateTwoWayMergePatch(original, modified, mergeItem)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("error: %s\nin test case: %s\ncannot create two way patch: %s:\n%s\n",
 | |
| 			err, c.Description, original, toYAMLOrError(c.StrategicMergePatchTestCaseData))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	testPatchCreation(t, expected, actual, c.Description)
 | |
| 	testPatchApplication(t, original, actual, modified, c.Description)
 | |
| }
 | |
| 
 | |
| func twoWayTestCaseToJSONOrFail(t *testing.T, c StrategicMergePatchTestCase) ([]byte, []byte, []byte) {
 | |
| 	return testObjectToJSONOrFail(t, c.Original, c.Description),
 | |
| 		testObjectToJSONOrFail(t, c.TwoWay, c.Description),
 | |
| 		testObjectToJSONOrFail(t, c.Modified, c.Description)
 | |
| }
 | |
| 
 | |
| func testThreeWayPatch(t *testing.T, c StrategicMergePatchTestCase) {
 | |
| 	original, modified, current, expected, result := threeWayTestCaseToJSONOrFail(t, c)
 | |
| 	actual, err := CreateThreeWayMergePatch(original, modified, current, mergeItem, false)
 | |
| 	if err != nil {
 | |
| 		if !IsConflict(err) {
 | |
| 			t.Errorf("error: %s\nin test case: %s\ncannot create three way patch:\n%s\n",
 | |
| 				err, c.Description, toYAMLOrError(c.StrategicMergePatchTestCaseData))
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		if !strings.Contains(c.Description, "conflict") {
 | |
| 			t.Errorf("unexpected conflict: %s\nin test case: %s\ncannot create three way patch:\n%s\n",
 | |
| 				err, c.Description, toYAMLOrError(c.StrategicMergePatchTestCaseData))
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		if len(c.Result) > 0 {
 | |
| 			actual, err := CreateThreeWayMergePatch(original, modified, current, mergeItem, true)
 | |
| 			if err != nil {
 | |
| 				t.Errorf("error: %s\nin test case: %s\ncannot force three way patch application:\n%s\n",
 | |
| 					err, c.Description, toYAMLOrError(c.StrategicMergePatchTestCaseData))
 | |
| 				return
 | |
| 			}
 | |
| 
 | |
| 			testPatchCreation(t, expected, actual, c.Description)
 | |
| 			testPatchApplication(t, current, actual, result, c.Description)
 | |
| 		}
 | |
| 
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if strings.Contains(c.Description, "conflict") || len(c.Result) < 1 {
 | |
| 		t.Errorf("error in test case: %s\nexpected conflict did not occur:\n%s\n",
 | |
| 			c.Description, toYAMLOrError(c.StrategicMergePatchTestCaseData))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	testPatchCreation(t, expected, actual, c.Description)
 | |
| 	testPatchApplication(t, current, actual, result, c.Description)
 | |
| }
 | |
| 
 | |
| func threeWayTestCaseToJSONOrFail(t *testing.T, c StrategicMergePatchTestCase) ([]byte, []byte, []byte, []byte, []byte) {
 | |
| 	return testObjectToJSONOrFail(t, c.Original, c.Description),
 | |
| 		testObjectToJSONOrFail(t, c.Modified, c.Description),
 | |
| 		testObjectToJSONOrFail(t, c.Current, c.Description),
 | |
| 		testObjectToJSONOrFail(t, c.ThreeWay, c.Description),
 | |
| 		testObjectToJSONOrFail(t, c.Result, c.Description)
 | |
| }
 | |
| 
 | |
| func testPatchCreation(t *testing.T, expected, actual []byte, description string) {
 | |
| 	sorted, err := sortMergeListsByName(actual, mergeItem)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("error: %s\nin test case: %s\ncannot sort patch:\n%s\n",
 | |
| 			err, description, jsonToYAMLOrError(actual))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if !reflect.DeepEqual(sorted, expected) {
 | |
| 		t.Errorf("error in test case: %s\nexpected patch:\n%s\ngot:\n%s\n",
 | |
| 			description, jsonToYAMLOrError(expected), jsonToYAMLOrError(sorted))
 | |
| 		return
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func testPatchApplication(t *testing.T, original, patch, expected []byte, description string) {
 | |
| 	result, err := StrategicMergePatch(original, patch, mergeItem)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("error: %s\nin test case: %s\ncannot apply patch:\n%s\nto original:\n%s\n",
 | |
| 			err, description, jsonToYAMLOrError(patch), jsonToYAMLOrError(original))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	sorted, err := sortMergeListsByName(result, mergeItem)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("error: %s\nin test case: %s\ncannot sort result object:\n%s\n",
 | |
| 			err, description, jsonToYAMLOrError(result))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if !reflect.DeepEqual(sorted, expected) {
 | |
| 		format := "error in test case: %s\npatch application failed:\noriginal:\n%s\npatch:\n%s\nexpected:\n%s\ngot:\n%s\n"
 | |
| 		t.Errorf(format, description,
 | |
| 			jsonToYAMLOrError(original), jsonToYAMLOrError(patch),
 | |
| 			jsonToYAMLOrError(expected), jsonToYAMLOrError(sorted))
 | |
| 		return
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func testObjectToJSONOrFail(t *testing.T, o map[string]interface{}, description string) []byte {
 | |
| 	if o == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	j, err := toJSON(o)
 | |
| 	if err != nil {
 | |
| 		t.Error(err)
 | |
| 	}
 | |
| 
 | |
| 	r, err := sortMergeListsByName(j, mergeItem)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("error: %s\nin test case: %s\ncannot sort object:\n%s\n", err, description, j)
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| func jsonToYAMLOrError(j []byte) string {
 | |
| 	y, err := jsonToYAML(j)
 | |
| 	if err != nil {
 | |
| 		return err.Error()
 | |
| 	}
 | |
| 
 | |
| 	return string(y)
 | |
| }
 | |
| 
 | |
| func toJSON(v interface{}) ([]byte, error) {
 | |
| 	j, err := json.Marshal(v)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("json marshal failed: %v\n%v\n", err, spew.Sdump(v))
 | |
| 	}
 | |
| 
 | |
| 	return j, nil
 | |
| }
 | |
| 
 | |
| func jsonToYAML(j []byte) ([]byte, error) {
 | |
| 	y, err := yaml.JSONToYAML(j)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("json to yaml failed: %v\n%v\n", err, j)
 | |
| 	}
 | |
| 
 | |
| 	return y, nil
 | |
| }
 | |
| 
 | |
| func TestHasConflicts(t *testing.T) {
 | |
| 	testCases := []struct {
 | |
| 		A   interface{}
 | |
| 		B   interface{}
 | |
| 		Ret bool
 | |
| 	}{
 | |
| 		{A: "hello", B: "hello", Ret: false}, // 0
 | |
| 		{A: "hello", B: "hell", Ret: true},
 | |
| 		{A: "hello", B: nil, Ret: true},
 | |
| 		{A: "hello", B: 1, Ret: true},
 | |
| 		{A: "hello", B: float64(1.0), Ret: true},
 | |
| 		{A: "hello", B: false, Ret: true},
 | |
| 		{A: 1, B: 1, Ret: false},
 | |
| 		{A: false, B: false, Ret: false},
 | |
| 		{A: float64(3), B: float64(3), Ret: false},
 | |
| 
 | |
| 		{A: "hello", B: []interface{}{}, Ret: true}, // 6
 | |
| 		{A: []interface{}{1}, B: []interface{}{}, Ret: true},
 | |
| 		{A: []interface{}{}, B: []interface{}{}, Ret: false},
 | |
| 		{A: []interface{}{1}, B: []interface{}{1}, Ret: false},
 | |
| 		{A: map[string]interface{}{}, B: []interface{}{1}, Ret: true},
 | |
| 
 | |
| 		{A: map[string]interface{}{}, B: map[string]interface{}{"a": 1}, Ret: false}, // 11
 | |
| 		{A: map[string]interface{}{"a": 1}, B: map[string]interface{}{"a": 1}, Ret: false},
 | |
| 		{A: map[string]interface{}{"a": 1}, B: map[string]interface{}{"a": 2}, Ret: true},
 | |
| 		{A: map[string]interface{}{"a": 1}, B: map[string]interface{}{"b": 2}, Ret: false},
 | |
| 
 | |
| 		{ // 15
 | |
| 			A:   map[string]interface{}{"a": []interface{}{1}},
 | |
| 			B:   map[string]interface{}{"a": []interface{}{1}},
 | |
| 			Ret: false,
 | |
| 		},
 | |
| 		{
 | |
| 			A:   map[string]interface{}{"a": []interface{}{1}},
 | |
| 			B:   map[string]interface{}{"a": []interface{}{}},
 | |
| 			Ret: true,
 | |
| 		},
 | |
| 		{
 | |
| 			A:   map[string]interface{}{"a": []interface{}{1}},
 | |
| 			B:   map[string]interface{}{"a": 1},
 | |
| 			Ret: true,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for i, testCase := range testCases {
 | |
| 		out, err := HasConflicts(testCase.A, testCase.B)
 | |
| 		if err != nil {
 | |
| 			t.Errorf("%d: unexpected error: %v", i, err)
 | |
| 		}
 | |
| 		if out != testCase.Ret {
 | |
| 			t.Errorf("%d: expected %t got %t", i, testCase.Ret, out)
 | |
| 			continue
 | |
| 		}
 | |
| 		out, err = HasConflicts(testCase.B, testCase.A)
 | |
| 		if err != nil {
 | |
| 			t.Errorf("%d: unexpected error: %v", i, err)
 | |
| 		}
 | |
| 		if out != testCase.Ret {
 | |
| 			t.Errorf("%d: expected reversed %t got %t", i, testCase.Ret, out)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type PrecisionItem struct {
 | |
| 	Name    string
 | |
| 	Int32   int32
 | |
| 	Int64   int64
 | |
| 	Float32 float32
 | |
| 	Float64 float64
 | |
| }
 | |
| 
 | |
| var precisionItem PrecisionItem
 | |
| 
 | |
| func TestNumberConversion(t *testing.T) {
 | |
| 	testcases := map[string]struct {
 | |
| 		Old            string
 | |
| 		New            string
 | |
| 		ExpectedPatch  string
 | |
| 		ExpectedResult string
 | |
| 	}{
 | |
| 		"empty": {
 | |
| 			Old:            `{}`,
 | |
| 			New:            `{}`,
 | |
| 			ExpectedPatch:  `{}`,
 | |
| 			ExpectedResult: `{}`,
 | |
| 		},
 | |
| 		"int32 medium": {
 | |
| 			Old:            `{"int32":1000000}`,
 | |
| 			New:            `{"int32":1000000,"name":"newname"}`,
 | |
| 			ExpectedPatch:  `{"name":"newname"}`,
 | |
| 			ExpectedResult: `{"int32":1000000,"name":"newname"}`,
 | |
| 		},
 | |
| 		"int32 max": {
 | |
| 			Old:            `{"int32":2147483647}`,
 | |
| 			New:            `{"int32":2147483647,"name":"newname"}`,
 | |
| 			ExpectedPatch:  `{"name":"newname"}`,
 | |
| 			ExpectedResult: `{"int32":2147483647,"name":"newname"}`,
 | |
| 		},
 | |
| 		"int64 medium": {
 | |
| 			Old:            `{"int64":1000000}`,
 | |
| 			New:            `{"int64":1000000,"name":"newname"}`,
 | |
| 			ExpectedPatch:  `{"name":"newname"}`,
 | |
| 			ExpectedResult: `{"int64":1000000,"name":"newname"}`,
 | |
| 		},
 | |
| 		"int64 max": {
 | |
| 			Old:            `{"int64":9223372036854775807}`,
 | |
| 			New:            `{"int64":9223372036854775807,"name":"newname"}`,
 | |
| 			ExpectedPatch:  `{"name":"newname"}`,
 | |
| 			ExpectedResult: `{"int64":9223372036854775807,"name":"newname"}`,
 | |
| 		},
 | |
| 		"float32 max": {
 | |
| 			Old:            `{"float32":3.4028234663852886e+38}`,
 | |
| 			New:            `{"float32":3.4028234663852886e+38,"name":"newname"}`,
 | |
| 			ExpectedPatch:  `{"name":"newname"}`,
 | |
| 			ExpectedResult: `{"float32":3.4028234663852886e+38,"name":"newname"}`,
 | |
| 		},
 | |
| 		"float64 max": {
 | |
| 			Old:            `{"float64":1.7976931348623157e+308}`,
 | |
| 			New:            `{"float64":1.7976931348623157e+308,"name":"newname"}`,
 | |
| 			ExpectedPatch:  `{"name":"newname"}`,
 | |
| 			ExpectedResult: `{"float64":1.7976931348623157e+308,"name":"newname"}`,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for k, tc := range testcases {
 | |
| 		patch, err := CreateTwoWayMergePatch([]byte(tc.Old), []byte(tc.New), precisionItem)
 | |
| 		if err != nil {
 | |
| 			t.Errorf("%s: unexpected error %v", k, err)
 | |
| 			continue
 | |
| 		}
 | |
| 		if tc.ExpectedPatch != string(patch) {
 | |
| 			t.Errorf("%s: expected %s, got %s", k, tc.ExpectedPatch, string(patch))
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		result, err := StrategicMergePatch([]byte(tc.Old), patch, precisionItem)
 | |
| 		if err != nil {
 | |
| 			t.Errorf("%s: unexpected error %v", k, err)
 | |
| 			continue
 | |
| 		}
 | |
| 		if tc.ExpectedResult != string(result) {
 | |
| 			t.Errorf("%s: expected %s, got %s", k, tc.ExpectedResult, string(result))
 | |
| 			continue
 | |
| 		}
 | |
| 	}
 | |
| }
 | 
