...

Source file src/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go

Documentation: k8s.io/apimachinery/pkg/util/strategicpatch

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package strategicpatch
    18  
    19  import (
    20  	"fmt"
    21  	"path/filepath"
    22  	"reflect"
    23  	"strings"
    24  	"testing"
    25  
    26  	"sigs.k8s.io/yaml"
    27  
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  	"k8s.io/apimachinery/pkg/util/dump"
    30  	"k8s.io/apimachinery/pkg/util/json"
    31  	"k8s.io/apimachinery/pkg/util/mergepatch"
    32  	"k8s.io/apimachinery/pkg/util/sets"
    33  	sptest "k8s.io/apimachinery/pkg/util/strategicpatch/testing"
    34  )
    35  
    36  var (
    37  	fakeMergeItemSchema     = sptest.Fake{Path: filepath.Join("testdata", "swagger-merge-item.json")}
    38  	fakePrecisionItemSchema = sptest.Fake{Path: filepath.Join("testdata", "swagger-precision-item.json")}
    39  
    40  	fakeMergeItemV3Schema     = sptest.OpenAPIV3Getter{Path: filepath.Join("testdata", "swagger-merge-item-v3.json")}
    41  	fakePrecisionItemV3Schema = sptest.OpenAPIV3Getter{Path: filepath.Join("testdata", "swagger-precision-item-v3.json")}
    42  )
    43  
    44  type SortMergeListTestCases struct {
    45  	TestCases []SortMergeListTestCase
    46  }
    47  
    48  type SortMergeListTestCase struct {
    49  	Description string
    50  	Original    map[string]interface{}
    51  	Sorted      map[string]interface{}
    52  }
    53  
    54  type StrategicMergePatchTestCases struct {
    55  	TestCases []StrategicMergePatchTestCase
    56  }
    57  
    58  type StrategicMergePatchTestCase struct {
    59  	Description string
    60  	StrategicMergePatchTestCaseData
    61  }
    62  
    63  type StrategicMergePatchRawTestCase struct {
    64  	Description string
    65  	StrategicMergePatchRawTestCaseData
    66  }
    67  
    68  type StrategicMergePatchTestCaseData struct {
    69  	// Original is the original object (last-applied config in annotation)
    70  	Original map[string]interface{}
    71  	// Modified is the modified object (new config we want)
    72  	Modified map[string]interface{}
    73  	// Current is the current object (live config in the server)
    74  	Current map[string]interface{}
    75  	// TwoWay is the expected two-way merge patch diff between original and modified
    76  	TwoWay map[string]interface{}
    77  	// ThreeWay is the expected three-way merge patch
    78  	ThreeWay map[string]interface{}
    79  	// Result is the expected object after applying the three-way patch on current object.
    80  	Result map[string]interface{}
    81  	// TwoWayResult is the expected object after applying the two-way patch on current object.
    82  	// If nil, Modified is used.
    83  	TwoWayResult map[string]interface{}
    84  }
    85  
    86  // The meaning of each field is the same as StrategicMergePatchTestCaseData's.
    87  // The difference is that all the fields in StrategicMergePatchRawTestCaseData are json-encoded data.
    88  type StrategicMergePatchRawTestCaseData struct {
    89  	Original      []byte
    90  	Modified      []byte
    91  	Current       []byte
    92  	TwoWay        []byte
    93  	ThreeWay      []byte
    94  	Result        []byte
    95  	TwoWayResult  []byte
    96  	ExpectedError string
    97  }
    98  
    99  type MergeItem struct {
   100  	Name                  string               `json:"name,omitempty"`
   101  	Value                 string               `json:"value,omitempty"`
   102  	Other                 string               `json:"other,omitempty"`
   103  	MergingList           []MergeItem          `json:"mergingList,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
   104  	NonMergingList        []MergeItem          `json:"nonMergingList,omitempty"`
   105  	MergingIntList        []int                `json:"mergingIntList,omitempty" patchStrategy:"merge"`
   106  	NonMergingIntList     []int                `json:"nonMergingIntList,omitempty"`
   107  	MergeItemPtr          *MergeItem           `json:"mergeItemPtr,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
   108  	SimpleMap             map[string]string    `json:"simpleMap,omitempty"`
   109  	ReplacingItem         runtime.RawExtension `json:"replacingItem,omitempty" patchStrategy:"replace"`
   110  	RetainKeysMap         RetainKeysMergeItem  `json:"retainKeysMap,omitempty" patchStrategy:"retainKeys"`
   111  	RetainKeysMergingList []MergeItem          `json:"retainKeysMergingList,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name"`
   112  }
   113  
   114  type RetainKeysMergeItem struct {
   115  	Name           string            `json:"name,omitempty"`
   116  	Value          string            `json:"value,omitempty"`
   117  	Other          string            `json:"other,omitempty"`
   118  	SimpleMap      map[string]string `json:"simpleMap,omitempty"`
   119  	MergingIntList []int             `json:"mergingIntList,omitempty" patchStrategy:"merge"`
   120  	MergingList    []MergeItem       `json:"mergingList,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
   121  	NonMergingList []MergeItem       `json:"nonMergingList,omitempty"`
   122  }
   123  
   124  var (
   125  	mergeItem             MergeItem
   126  	mergeItemStructSchema = PatchMetaFromStruct{T: GetTagStructTypeOrDie(mergeItem)}
   127  )
   128  
   129  // These are test cases for SortMergeList, used to assert that it (recursively)
   130  // sorts both merging and non merging lists correctly.
   131  var sortMergeListTestCaseData = []byte(`
   132  testCases:
   133    - description: sort one list of maps
   134      original:
   135        mergingList:
   136          - name: 1
   137          - name: 3
   138          - name: 2
   139      sorted:
   140        mergingList:
   141          - name: 1
   142          - name: 2
   143          - name: 3
   144    - description: sort lists of maps but not nested lists of maps
   145      original:
   146        mergingList:
   147          - name: 2
   148            nonMergingList:
   149              - name: 1
   150              - name: 3
   151              - name: 2
   152          - name: 1
   153            nonMergingList:
   154              - name: 2
   155              - name: 1
   156      sorted:
   157        mergingList:
   158          - name: 1
   159            nonMergingList:
   160              - name: 2
   161              - name: 1
   162          - name: 2
   163            nonMergingList:
   164              - name: 1
   165              - name: 3
   166              - name: 2
   167    - description: sort lists of maps and nested lists of maps
   168      original:
   169        mergingList:
   170          - name: 2
   171            mergingList:
   172              - name: 1
   173              - name: 3
   174              - name: 2
   175          - name: 1
   176            mergingList:
   177              - name: 2
   178              - name: 1
   179      sorted:
   180        mergingList:
   181          - name: 1
   182            mergingList:
   183              - name: 1
   184              - name: 2
   185          - name: 2
   186            mergingList:
   187              - name: 1
   188              - name: 2
   189              - name: 3
   190    - description: merging list should NOT sort when nested in non merging list
   191      original:
   192        nonMergingList:
   193          - name: 2
   194            mergingList:
   195              - name: 1
   196              - name: 3
   197              - name: 2
   198          - name: 1
   199            mergingList:
   200              - name: 2
   201              - name: 1
   202      sorted:
   203        nonMergingList:
   204          - name: 2
   205            mergingList:
   206              - name: 1
   207              - name: 3
   208              - name: 2
   209          - name: 1
   210            mergingList:
   211              - name: 2
   212              - name: 1
   213    - description: sort very nested list of maps
   214      fieldTypes:
   215      original:
   216        mergingList:
   217          - mergingList:
   218              - mergingList:
   219                  - name: 2
   220                  - name: 1
   221      sorted:
   222        mergingList:
   223          - mergingList:
   224              - mergingList:
   225                  - name: 1
   226                  - name: 2
   227    - description: sort nested lists of ints
   228      original:
   229        mergingList:
   230          - name: 2
   231            mergingIntList:
   232              - 1
   233              - 3
   234              - 2
   235          - name: 1
   236            mergingIntList:
   237              - 2
   238              - 1
   239      sorted:
   240        mergingList:
   241          - name: 1
   242            mergingIntList:
   243              - 1
   244              - 2
   245          - name: 2
   246            mergingIntList:
   247              - 1
   248              - 2
   249              - 3
   250    - description: sort nested pointers of ints
   251      original:
   252        mergeItemPtr:
   253          - name: 2
   254            mergingIntList:
   255              - 1
   256              - 3
   257              - 2
   258          - name: 1
   259            mergingIntList:
   260              - 2
   261              - 1
   262      sorted:
   263        mergeItemPtr:
   264          - name: 1
   265            mergingIntList:
   266              - 1
   267              - 2
   268          - name: 2
   269            mergingIntList:
   270              - 1
   271              - 2
   272              - 3
   273    - description: sort merging list by pointer
   274      original:
   275        mergeItemPtr:
   276          - name: 1
   277          - name: 3
   278          - name: 2
   279      sorted:
   280        mergeItemPtr:
   281          - name: 1
   282          - name: 2
   283          - name: 3
   284  `)
   285  
   286  func TestSortMergeLists(t *testing.T) {
   287  	mergeItemOpenapiSchema := PatchMetaFromOpenAPI{
   288  		Schema: sptest.GetSchemaOrDie(&fakeMergeItemSchema, "mergeItem"),
   289  	}
   290  	mergeItemOpenapiV3Schema := PatchMetaFromOpenAPIV3{
   291  		SchemaList: fakeMergeItemV3Schema.SchemaOrDie().Components.Schemas,
   292  		Schema:     fakeMergeItemV3Schema.SchemaOrDie().Components.Schemas["mergeItem"],
   293  	}
   294  	schemas := []LookupPatchMeta{
   295  		mergeItemStructSchema,
   296  		mergeItemOpenapiSchema,
   297  		mergeItemOpenapiV3Schema,
   298  	}
   299  
   300  	tc := SortMergeListTestCases{}
   301  	err := yaml.Unmarshal(sortMergeListTestCaseData, &tc)
   302  	if err != nil {
   303  		t.Errorf("can't unmarshal test cases: %s\n", err)
   304  		return
   305  	}
   306  
   307  	for _, schema := range schemas {
   308  		for _, c := range tc.TestCases {
   309  			temp := testObjectToJSONOrFail(t, c.Original)
   310  			got := sortJsonOrFail(t, temp, c.Description, schema)
   311  			expected := testObjectToJSONOrFail(t, c.Sorted)
   312  			if !reflect.DeepEqual(got, expected) {
   313  				t.Errorf("using %s error in test case: %s\ncannot sort object:\n%s\nexpected:\n%s\ngot:\n%s\n",
   314  					getSchemaType(schema), c.Description, mergepatch.ToYAMLOrError(c.Original), mergepatch.ToYAMLOrError(c.Sorted), jsonToYAMLOrError(got))
   315  			}
   316  		}
   317  	}
   318  }
   319  
   320  // These are test cases for StrategicMergePatch that cannot be generated using
   321  // CreateTwoWayMergePatch because it may be one of the following cases:
   322  // - not use the replace directive.
   323  // - generate duplicate integers for a merging list patch.
   324  // - generate empty merging lists.
   325  // - use patch format from an old client.
   326  var customStrategicMergePatchTestCaseData = []byte(`
   327  testCases:
   328    - description: unique scalars when merging lists
   329      original:
   330        mergingIntList:
   331          - 1
   332          - 2
   333      twoWay:
   334        mergingIntList:
   335          - 2
   336          - 3
   337      modified:
   338        mergingIntList:
   339          - 1
   340          - 2
   341          - 3
   342    - description: delete map from nested map
   343      original:
   344        simpleMap:
   345          key1: 1
   346          key2: 1
   347      twoWay:
   348        simpleMap:
   349          $patch: delete
   350      modified:
   351        simpleMap:
   352          {}
   353    - description: delete all items from merging list
   354      original:
   355        mergingList:
   356          - name: 1
   357          - name: 2
   358      twoWay:
   359        mergingList:
   360          - $patch: replace
   361      modified:
   362        mergingList: []
   363    - description: merge empty merging lists
   364      original:
   365        mergingList: []
   366      twoWay:
   367        mergingList: []
   368      modified:
   369        mergingList: []
   370    - description: delete all keys from map
   371      original:
   372        name: 1
   373        value: 1
   374      twoWay:
   375        $patch: replace
   376      modified: {}
   377    - description: add key and delete all keys from map
   378      original:
   379        name: 1
   380        value: 1
   381      twoWay:
   382        other: a
   383        $patch: replace
   384      modified:
   385        other: a
   386    - description: delete all duplicate entries in a merging list
   387      original:
   388        mergingList:
   389          - name: 1
   390          - name: 1
   391          - name: 2
   392            value: a
   393          - name: 3
   394          - name: 3
   395      twoWay:
   396        mergingList:
   397          - name: 1
   398            $patch: delete
   399          - name: 3
   400            $patch: delete
   401      modified:
   402        mergingList:
   403          - name: 2
   404            value: a
   405    - description: retainKeys map can add a field when no retainKeys directive present
   406      original:
   407        retainKeysMap:
   408          name: foo
   409      twoWay:
   410        retainKeysMap:
   411          value: bar
   412      modified:
   413        retainKeysMap:
   414          name: foo
   415          value: bar
   416    - description: retainKeys map can change a field when no retainKeys directive present
   417      original:
   418        retainKeysMap:
   419          name: foo
   420          value: a
   421      twoWay:
   422        retainKeysMap:
   423          value: b
   424      modified:
   425        retainKeysMap:
   426          name: foo
   427          value: b
   428    - description: retainKeys map can delete a field when no retainKeys directive present
   429      original:
   430        retainKeysMap:
   431          name: foo
   432          value: a
   433      twoWay:
   434        retainKeysMap:
   435          value: null
   436      modified:
   437        retainKeysMap:
   438          name: foo
   439    - description: retainKeys map merge an empty map
   440      original:
   441        retainKeysMap:
   442          name: foo
   443          value: a
   444      twoWay:
   445        retainKeysMap: {}
   446      modified:
   447        retainKeysMap:
   448          name: foo
   449          value: a
   450    - description: retainKeys list can add a field when no retainKeys directive present
   451      original:
   452        retainKeysMergingList:
   453        - name: bar
   454        - name: foo
   455      twoWay:
   456        retainKeysMergingList:
   457        - name: foo
   458          value: a
   459      modified:
   460        retainKeysMergingList:
   461        - name: bar
   462        - name: foo
   463          value: a
   464    - description: retainKeys list can change a field when no retainKeys directive present
   465      original:
   466        retainKeysMergingList:
   467        - name: bar
   468        - name: foo
   469          value: a
   470      twoWay:
   471        retainKeysMergingList:
   472        - name: foo
   473          value: b
   474      modified:
   475        retainKeysMergingList:
   476        - name: bar
   477        - name: foo
   478          value: b
   479    - description: retainKeys list can delete a field when no retainKeys directive present
   480      original:
   481        retainKeysMergingList:
   482        - name: bar
   483        - name: foo
   484          value: a
   485      twoWay:
   486        retainKeysMergingList:
   487        - name: foo
   488          value: null
   489      modified:
   490        retainKeysMergingList:
   491        - name: bar
   492        - name: foo
   493    - description: preserve the order from the patch in a merging list
   494      original:
   495        mergingList:
   496          - name: 1
   497          - name: 2
   498            value: b
   499          - name: 3
   500      twoWay:
   501        mergingList:
   502          - name: 3
   503            value: c
   504          - name: 1
   505            value: a
   506          - name: 2
   507            other: x
   508      modified:
   509        mergingList:
   510          - name: 3
   511            value: c
   512          - name: 1
   513            value: a
   514          - name: 2
   515            value: b
   516            other: x
   517    - description: preserve the order from the patch in a merging list 2
   518      original:
   519        mergingList:
   520          - name: 1
   521          - name: 2
   522            value: b
   523          - name: 3
   524      twoWay:
   525        mergingList:
   526          - name: 3
   527            value: c
   528          - name: 1
   529            value: a
   530      modified:
   531        mergingList:
   532          - name: 2
   533            value: b
   534          - name: 3
   535            value: c
   536          - name: 1
   537            value: a
   538    - description: preserve the order from the patch in a merging int list
   539      original:
   540        mergingIntList:
   541          - 1
   542          - 2
   543          - 3
   544      twoWay:
   545        mergingIntList:
   546          - 3
   547          - 1
   548          - 2
   549      modified:
   550        mergingIntList:
   551          - 3
   552          - 1
   553          - 2
   554    - description: preserve the order from the patch in a merging int list
   555      original:
   556        mergingIntList:
   557          - 1
   558          - 2
   559          - 3
   560      twoWay:
   561        mergingIntList:
   562          - 3
   563          - 1
   564      modified:
   565        mergingIntList:
   566          - 2
   567          - 3
   568          - 1
   569  `)
   570  
   571  var customStrategicMergePatchRawTestCases = []StrategicMergePatchRawTestCase{
   572  	{
   573  		Description: "$setElementOrder contains item that is not present in the list to be merged",
   574  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
   575  			Original: []byte(`
   576  mergingList:
   577    - name: 1
   578    - name: 3
   579  `),
   580  			TwoWay: []byte(`
   581  $setElementOrder/mergingList:
   582    - name: 3
   583    - name: 2
   584    - name: 1
   585  mergingList:
   586    - name: 3
   587      value: 3
   588    - name: 1
   589      value: 1
   590  `),
   591  			Modified: []byte(`
   592  mergingList:
   593    - name: 3
   594      value: 3
   595    - name: 1
   596      value: 1
   597  `),
   598  		},
   599  	},
   600  	{
   601  		Description: "$setElementOrder contains item that is not present in the int list to be merged",
   602  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
   603  			Original: []byte(`
   604  mergingIntList:
   605    - 1
   606    - 3
   607  `),
   608  			TwoWay: []byte(`
   609  $setElementOrder/mergingIntList:
   610    - 3
   611    - 2
   612    - 1
   613  `),
   614  			Modified: []byte(`
   615  mergingIntList:
   616    - 3
   617    - 1
   618  `),
   619  		},
   620  	},
   621  	{
   622  		Description: "should check if order in $setElementOrder and patch list match",
   623  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
   624  			Original: []byte(`
   625  mergingList:
   626    - name: 1
   627    - name: 3
   628    - name: 2
   629  `),
   630  			TwoWay: []byte(`
   631  $setElementOrder/mergingList:
   632    - name: 1
   633    - name: 2
   634    - name: 3
   635  mergingList:
   636    - name: 3
   637      value: 3
   638    - name: 1
   639      value: 1
   640  `),
   641  			ExpectedError: "doesn't match",
   642  		},
   643  	},
   644  	{
   645  		Description: "$setElementOrder contains item that is not present in the int list to be merged",
   646  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
   647  			Original: []byte(`
   648  mergingIntList:
   649    - 1
   650    - 3
   651    - 2
   652  `),
   653  			TwoWay: []byte(`
   654  $setElementOrder/mergingIntList:
   655    - 1
   656    - 2
   657    - 3
   658  mergingIntList:
   659    - 3
   660    - 1
   661  `),
   662  			ExpectedError: "doesn't match",
   663  		},
   664  	},
   665  	{
   666  		Description: "missing merge key should error out",
   667  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
   668  			Original: []byte(`
   669  mergingList:
   670    - name: 1
   671      value: a
   672  `),
   673  			TwoWay: []byte(`
   674  mergingList:
   675    - value: b
   676  `),
   677  			ExpectedError: "does not contain declared merge key",
   678  		},
   679  	},
   680  	{
   681  		Description: "$deleteFromPrimitiveList of nonexistent item in primitive list should not add the item to the list",
   682  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
   683  			Original: []byte(`
   684  mergingIntList:
   685    - 1
   686    - 2
   687  `),
   688  			TwoWay: []byte(`
   689  $deleteFromPrimitiveList/mergingIntList:
   690    - 3
   691  `),
   692  			Modified: []byte(`
   693  mergingIntList:
   694    - 1
   695    - 2
   696  `),
   697  		},
   698  	},
   699  	{
   700  		Description: "$deleteFromPrimitiveList on empty primitive list should not add the item to the list",
   701  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
   702  			Original: []byte(`
   703  mergingIntList:
   704  `),
   705  			TwoWay: []byte(`
   706  $deleteFromPrimitiveList/mergingIntList:
   707    - 3
   708  `),
   709  			Modified: []byte(`
   710  mergingIntList:
   711  `),
   712  		},
   713  	},
   714  	{
   715  		Description: "$deleteFromPrimitiveList on nonexistent primitive list should not add the primitive list",
   716  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
   717  			Original: []byte(`
   718  foo:
   719    - bar
   720  `),
   721  			TwoWay: []byte(`
   722  $deleteFromPrimitiveList/mergingIntList:
   723    - 3
   724  `),
   725  			Modified: []byte(`
   726  foo:
   727    - bar
   728  `),
   729  		},
   730  	},
   731  	{
   732  		Description: "$deleteFromPrimitiveList should delete item from a list with merge patch strategy",
   733  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
   734  			Original: []byte(`
   735  mergingIntList:
   736    - 1
   737    - 2
   738    - 3
   739  `),
   740  			TwoWay: []byte(`
   741  $deleteFromPrimitiveList/mergingIntList:
   742    - 2
   743  `),
   744  			Modified: []byte(`
   745  mergingIntList:
   746    - 1
   747    - 3
   748  `),
   749  		},
   750  	},
   751  	{
   752  		Description: "$deleteFromPrimitiveList should delete item from a list without merge patch strategy",
   753  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
   754  			Original: []byte(`
   755  nonMergingIntList:
   756    - 1
   757    - 2
   758    - 3
   759  `),
   760  			TwoWay: []byte(`
   761  $deleteFromPrimitiveList/nonMergingIntList:
   762    - 2
   763  `),
   764  			Modified: []byte(`
   765  nonMergingIntList:
   766    - 1
   767    - 3
   768  `),
   769  		},
   770  	},
   771  }
   772  
   773  func TestCustomStrategicMergePatch(t *testing.T) {
   774  	mergeItemOpenapiSchema := PatchMetaFromOpenAPI{
   775  		Schema: sptest.GetSchemaOrDie(&fakeMergeItemSchema, "mergeItem"),
   776  	}
   777  	mergeItemOpenapiV3Schema := PatchMetaFromOpenAPIV3{
   778  		SchemaList: fakeMergeItemV3Schema.SchemaOrDie().Components.Schemas,
   779  		Schema:     fakeMergeItemV3Schema.SchemaOrDie().Components.Schemas["mergeItem"],
   780  	}
   781  	schemas := []LookupPatchMeta{
   782  		mergeItemStructSchema,
   783  		mergeItemOpenapiSchema,
   784  		mergeItemOpenapiV3Schema,
   785  	}
   786  
   787  	tc := StrategicMergePatchTestCases{}
   788  	err := yaml.Unmarshal(customStrategicMergePatchTestCaseData, &tc)
   789  	if err != nil {
   790  		t.Errorf("can't unmarshal test cases: %v\n", err)
   791  		return
   792  	}
   793  
   794  	for _, c := range tc.TestCases {
   795  		t.Run(c.Description, func(t *testing.T) {
   796  			for _, schema := range schemas {
   797  				t.Run(schema.Name(), func(t *testing.T) {
   798  					original, expectedTwoWayPatch, _, expectedResult := twoWayTestCaseToJSONOrFail(t, c, schema)
   799  					testPatchApplication(t, original, expectedTwoWayPatch, expectedResult, c.Description, "", schema)
   800  				})
   801  
   802  				for _, c := range customStrategicMergePatchRawTestCases {
   803  					original, expectedTwoWayPatch, _, expectedResult := twoWayRawTestCaseToJSONOrFail(t, c)
   804  					testPatchApplication(t, original, expectedTwoWayPatch, expectedResult, c.Description, c.ExpectedError, schema)
   805  				}
   806  			}
   807  		})
   808  	}
   809  }
   810  
   811  // These are test cases for StrategicMergePatch, to assert that applying  a patch
   812  // yields the correct outcome. They are also test cases for CreateTwoWayMergePatch
   813  // and CreateThreeWayMergePatch, to assert that they both generate the correct patch
   814  // for the given set of input documents.
   815  var createStrategicMergePatchTestCaseData = []byte(`
   816  testCases:
   817    - description: nil original
   818      twoWay:
   819        name: 1
   820        value: 1
   821      modified:
   822        name: 1
   823        value: 1
   824      current:
   825        name: 1
   826        other: a
   827      threeWay:
   828        value: 1
   829      result:
   830        name: 1
   831        value: 1
   832        other: a
   833    - description: nil patch
   834      original:
   835        name: 1
   836      twoWay:
   837        {}
   838      modified:
   839        name: 1
   840      current:
   841        name: 1
   842      threeWay:
   843        {}
   844      result:
   845        name: 1
   846    - description: add field to map
   847      original:
   848        name: 1
   849      twoWay:
   850        value: 1
   851      modified:
   852        name: 1
   853        value: 1
   854      current:
   855        name: 1
   856        other: a
   857      threeWay:
   858        value: 1
   859      result:
   860        name: 1
   861        value: 1
   862        other: a
   863    - description: add field to map with conflict
   864      original:
   865        name: 1
   866      twoWay:
   867        value: 1
   868      modified:
   869        name: 1
   870        value: 1
   871      current:
   872        name: a
   873        other: a
   874      threeWay:
   875        name: 1
   876        value: 1
   877      result:
   878        name: 1
   879        value: 1
   880        other: a
   881    - description: add field and delete field from map
   882      original:
   883        name: 1
   884      twoWay:
   885        name: null
   886        value: 1
   887      modified:
   888        value: 1
   889      current:
   890        name: 1
   891        other: a
   892      threeWay:
   893        name: null
   894        value: 1
   895      result:
   896        value: 1
   897        other: a
   898    - description: add field and delete field from map with conflict
   899      original:
   900        name: 1
   901      twoWay:
   902        name: null
   903        value: 1
   904      modified:
   905        value: 1
   906      current:
   907        name: a
   908        other: a
   909      threeWay:
   910        name: null
   911        value: 1
   912      result:
   913        value: 1
   914        other: a
   915    - description: delete field from nested map
   916      original:
   917        simpleMap:
   918          key1: 1
   919          key2: 1
   920      twoWay:
   921        simpleMap:
   922          key2: null
   923      modified:
   924        simpleMap:
   925          key1: 1
   926      current:
   927        simpleMap:
   928          key1: 1
   929          key2: 1
   930          other: a
   931      threeWay:
   932        simpleMap:
   933          key2: null
   934      result:
   935        simpleMap:
   936          key1: 1
   937          other: a
   938    - description: delete field from nested map with conflict
   939      original:
   940        simpleMap:
   941          key1: 1
   942          key2: 1
   943      twoWay:
   944        simpleMap:
   945          key2: null
   946      modified:
   947        simpleMap:
   948          key1: 1
   949      current:
   950        simpleMap:
   951          key1: a
   952          key2: 1
   953          other: a
   954      threeWay:
   955        simpleMap:
   956          key1: 1
   957          key2: null
   958      result:
   959        simpleMap:
   960          key1: 1
   961          other: a
   962    - description: delete all fields from map
   963      original:
   964        name: 1
   965        value: 1
   966      twoWay:
   967        name: null
   968        value: null
   969      modified: {}
   970      current:
   971        name: 1
   972        value: 1
   973        other: a
   974      threeWay:
   975        name: null
   976        value: null
   977      result:
   978        other: a
   979    - description: delete all fields from map with conflict
   980      original:
   981        name: 1
   982        value: 1
   983      twoWay:
   984        name: null
   985        value: null
   986      modified: {}
   987      current:
   988        name: 1
   989        value: a
   990        other: a
   991      threeWay:
   992        name: null
   993        value: null
   994      result:
   995        other: a
   996    - description: add field and delete all fields from map
   997      original:
   998        name: 1
   999        value: 1
  1000      twoWay:
  1001        name: null
  1002        value: null
  1003        other: a
  1004      modified:
  1005        other: a
  1006      current:
  1007        name: 1
  1008        value: 1
  1009        other: a
  1010      threeWay:
  1011        name: null
  1012        value: null
  1013      result:
  1014        other: a
  1015    - description: add field and delete all fields from map with conflict
  1016      original:
  1017        name: 1
  1018        value: 1
  1019      twoWay:
  1020        name: null
  1021        value: null
  1022        other: a
  1023      modified:
  1024        other: a
  1025      current:
  1026        name: 1
  1027        value: 1
  1028        other: b
  1029      threeWay:
  1030        name: null
  1031        value: null
  1032        other: a
  1033      result:
  1034        other: a
  1035    - description: replace list of scalars
  1036      original:
  1037        nonMergingIntList:
  1038          - 1
  1039          - 2
  1040      twoWay:
  1041        nonMergingIntList:
  1042          - 2
  1043          - 3
  1044      modified:
  1045        nonMergingIntList:
  1046          - 2
  1047          - 3
  1048      current:
  1049        nonMergingIntList:
  1050          - 1
  1051          - 2
  1052      threeWay:
  1053        nonMergingIntList:
  1054          - 2
  1055          - 3
  1056      result:
  1057        nonMergingIntList:
  1058          - 2
  1059          - 3
  1060    - description: replace list of scalars with conflict
  1061      original:
  1062        nonMergingIntList:
  1063          - 1
  1064          - 2
  1065      twoWay:
  1066        nonMergingIntList:
  1067          - 2
  1068          - 3
  1069      modified:
  1070        nonMergingIntList:
  1071          - 2
  1072          - 3
  1073      current:
  1074        nonMergingIntList:
  1075          - 1
  1076          - 4
  1077      threeWay:
  1078        nonMergingIntList:
  1079          - 2
  1080          - 3
  1081      result:
  1082        nonMergingIntList:
  1083          - 2
  1084          - 3
  1085    - description: delete all maps from merging list
  1086      original:
  1087        mergingList:
  1088          - name: 1
  1089          - name: 2
  1090      twoWay:
  1091        mergingList:
  1092          - name: 1
  1093            $patch: delete
  1094          - name: 2
  1095            $patch: delete
  1096      modified:
  1097        mergingList: []
  1098      current:
  1099        mergingList:
  1100          - name: 1
  1101          - name: 2
  1102      threeWay:
  1103        mergingList:
  1104          - name: 1
  1105            $patch: delete
  1106          - name: 2
  1107            $patch: delete
  1108      result:
  1109        mergingList: []
  1110    - description: delete all maps from merging list with conflict
  1111      original:
  1112        mergingList:
  1113          - name: 1
  1114          - name: 2
  1115      twoWay:
  1116        mergingList:
  1117          - name: 1
  1118            $patch: delete
  1119          - name: 2
  1120            $patch: delete
  1121      modified:
  1122        mergingList: []
  1123      current:
  1124        mergingList:
  1125          - name: 1
  1126            other: a
  1127          - name: 2
  1128            other: b
  1129      threeWay:
  1130        mergingList:
  1131          - name: 1
  1132            $patch: delete
  1133          - name: 2
  1134            $patch: delete
  1135      result:
  1136        mergingList: []
  1137    - description: delete all maps from empty merging list
  1138      original:
  1139        mergingList:
  1140          - name: 1
  1141          - name: 2
  1142      twoWay:
  1143        mergingList:
  1144          - name: 1
  1145            $patch: delete
  1146          - name: 2
  1147            $patch: delete
  1148      modified:
  1149        mergingList: []
  1150      current:
  1151        mergingList: []
  1152      threeWay:
  1153        mergingList:
  1154          - name: 1
  1155            $patch: delete
  1156          - name: 2
  1157            $patch: delete
  1158      result:
  1159        mergingList: []
  1160    - description: merge empty merging lists
  1161      original:
  1162        mergingList: []
  1163      twoWay:
  1164        {}
  1165      modified:
  1166        mergingList: []
  1167      current:
  1168        mergingList: []
  1169      threeWay:
  1170        {}
  1171      result:
  1172        mergingList: []
  1173    - description: defined null values should propagate overwrite current fields (with conflict)
  1174      original:
  1175        name: 2
  1176      twoWay:
  1177        name: 1
  1178        value: 1
  1179        other: null
  1180      twoWayResult:
  1181        name: 1
  1182        value: 1
  1183      modified:
  1184        name: 1
  1185        value: 1
  1186        other: null
  1187      current:
  1188        name: a
  1189        other: a
  1190      threeWay:
  1191        name: 1
  1192        value: 1
  1193        other: null
  1194      result:
  1195        name: 1
  1196        value: 1
  1197    - description: defined null values should propagate removing original fields
  1198      original:
  1199        name: original-name
  1200        value: original-value
  1201      current:
  1202        name: original-name
  1203        value: original-value
  1204        other: current-other
  1205      modified:
  1206        name: modified-name
  1207        value: null
  1208      twoWay:
  1209        name: modified-name
  1210        value: null
  1211      twoWayResult:
  1212        name: modified-name
  1213      threeWay:
  1214        name: modified-name
  1215        value: null
  1216      result:
  1217        name: modified-name
  1218        other: current-other
  1219    - description: nil patch with retainKeys map
  1220      original:
  1221        name: a
  1222        retainKeysMap:
  1223          name: foo
  1224      current:
  1225        name: a
  1226        value: b
  1227        retainKeysMap:
  1228          name: foo
  1229      modified:
  1230        name: a
  1231        retainKeysMap:
  1232          name: foo
  1233      twoWay: {}
  1234      threeWay: {}
  1235      result:
  1236        name: a
  1237        value: b
  1238        retainKeysMap:
  1239          name: foo
  1240    - description: retainKeys map with no change should not be present
  1241      original:
  1242        name: a
  1243        retainKeysMap:
  1244          name: foo
  1245      current:
  1246        name: a
  1247        other: c
  1248        retainKeysMap:
  1249          name: foo
  1250      modified:
  1251        name: a
  1252        value: b
  1253        retainKeysMap:
  1254          name: foo
  1255      twoWay:
  1256        value: b
  1257      threeWay:
  1258        value: b
  1259      result:
  1260        name: a
  1261        value: b
  1262        other: c
  1263        retainKeysMap:
  1264          name: foo
  1265  `)
  1266  
  1267  var strategicMergePatchRawTestCases = []StrategicMergePatchRawTestCase{
  1268  	{
  1269  		Description: "nested patch merge with empty list",
  1270  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1271  			Original: []byte(`
  1272  name: hi
  1273  `),
  1274  			Current: []byte(`
  1275  name: hi
  1276  mergingList:
  1277  - name: hello2
  1278  `),
  1279  			Modified: []byte(`
  1280  name: hi
  1281  mergingList:
  1282  - name: hello
  1283  - $patch: delete
  1284    name: doesntexist
  1285  `),
  1286  			TwoWay: []byte(`
  1287  mergingList:
  1288  - name: hello
  1289  - $patch: delete
  1290    name: doesntexist
  1291  `),
  1292  			ThreeWay: []byte(`
  1293  $setElementOrder/mergingList:
  1294  - name: hello
  1295  - name: doesntexist
  1296  mergingList:
  1297  - name: hello
  1298  `),
  1299  			TwoWayResult: []byte(`
  1300  name: hi
  1301  mergingList:
  1302  - name: hello
  1303  `),
  1304  			Result: []byte(`
  1305  name: hi
  1306  mergingList:
  1307  - name: hello
  1308  - name: hello2
  1309  `),
  1310  		},
  1311  	},
  1312  	{
  1313  		Description: "delete items in lists of scalars",
  1314  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1315  			Original: []byte(`
  1316  mergingIntList:
  1317    - 1
  1318    - 2
  1319    - 3
  1320  `),
  1321  			TwoWay: []byte(`
  1322  $setElementOrder/mergingIntList:
  1323    - 1
  1324    - 2
  1325  $deleteFromPrimitiveList/mergingIntList:
  1326    - 3
  1327  `),
  1328  			Modified: []byte(`
  1329  mergingIntList:
  1330    - 1
  1331    - 2
  1332  `),
  1333  			Current: []byte(`
  1334  mergingIntList:
  1335    - 1
  1336    - 2
  1337    - 3
  1338    - 4
  1339  `),
  1340  			ThreeWay: []byte(`
  1341  $setElementOrder/mergingIntList:
  1342    - 1
  1343    - 2
  1344  $deleteFromPrimitiveList/mergingIntList:
  1345    - 3
  1346  `),
  1347  			Result: []byte(`
  1348  mergingIntList:
  1349    - 1
  1350    - 2
  1351    - 4
  1352  `),
  1353  		},
  1354  	},
  1355  	{
  1356  		Description: "delete all duplicate items in lists of scalars",
  1357  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1358  			Original: []byte(`
  1359  mergingIntList:
  1360    - 1
  1361    - 2
  1362    - 3
  1363    - 3
  1364  `),
  1365  			TwoWay: []byte(`
  1366  $setElementOrder/mergingIntList:
  1367    - 1
  1368    - 2
  1369  $deleteFromPrimitiveList/mergingIntList:
  1370    - 3
  1371  `),
  1372  			Modified: []byte(`
  1373  mergingIntList:
  1374    - 1
  1375    - 2
  1376  `),
  1377  			Current: []byte(`
  1378  mergingIntList:
  1379    - 1
  1380    - 2
  1381    - 3
  1382    - 3
  1383    - 4
  1384  `),
  1385  			ThreeWay: []byte(`
  1386  $setElementOrder/mergingIntList:
  1387    - 1
  1388    - 2
  1389  $deleteFromPrimitiveList/mergingIntList:
  1390    - 3
  1391  `),
  1392  			Result: []byte(`
  1393  mergingIntList:
  1394    - 1
  1395    - 2
  1396    - 4
  1397  `),
  1398  		},
  1399  	},
  1400  	{
  1401  		Description: "add and delete items in lists of scalars",
  1402  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1403  			Original: []byte(`
  1404  mergingIntList:
  1405    - 1
  1406    - 2
  1407    - 3
  1408  `),
  1409  			TwoWay: []byte(`
  1410  $setElementOrder/mergingIntList:
  1411    - 1
  1412    - 2
  1413    - 4
  1414  $deleteFromPrimitiveList/mergingIntList:
  1415    - 3
  1416  mergingIntList:
  1417    - 4
  1418  `),
  1419  			Modified: []byte(`
  1420  mergingIntList:
  1421    - 1
  1422    - 2
  1423    - 4
  1424  `),
  1425  			Current: []byte(`
  1426  mergingIntList:
  1427    - 1
  1428    - 2
  1429    - 3
  1430    - 4
  1431  `),
  1432  			ThreeWay: []byte(`
  1433  $setElementOrder/mergingIntList:
  1434    - 1
  1435    - 2
  1436    - 4
  1437  $deleteFromPrimitiveList/mergingIntList:
  1438    - 3
  1439  `),
  1440  			Result: []byte(`
  1441  mergingIntList:
  1442    - 1
  1443    - 2
  1444    - 4
  1445  `),
  1446  		},
  1447  	},
  1448  	{
  1449  		Description: "merge lists of maps",
  1450  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1451  			Original: []byte(`
  1452  mergingList:
  1453    - name: 1
  1454    - name: 2
  1455      value: 2
  1456  `),
  1457  			TwoWay: []byte(`
  1458  $setElementOrder/mergingList:
  1459    - name: 4
  1460    - name: 1
  1461    - name: 2
  1462    - name: 3
  1463  mergingList:
  1464    - name: 4
  1465      value: 4
  1466    - name: 3
  1467      value: 3
  1468  `),
  1469  			Modified: []byte(`
  1470  mergingList:
  1471    - name: 4
  1472      value: 4
  1473    - name: 1
  1474    - name: 2
  1475      value: 2
  1476    - name: 3
  1477      value: 3
  1478  `),
  1479  			Current: []byte(`
  1480  mergingList:
  1481    - name: 1
  1482      other: a
  1483    - name: 2
  1484      value: 2
  1485      other: b
  1486  `),
  1487  			ThreeWay: []byte(`
  1488  $setElementOrder/mergingList:
  1489    - name: 4
  1490    - name: 1
  1491    - name: 2
  1492    - name: 3
  1493  mergingList:
  1494    - name: 4
  1495      value: 4
  1496    - name: 3
  1497      value: 3
  1498  `),
  1499  			Result: []byte(`
  1500  mergingList:
  1501    - name: 4
  1502      value: 4
  1503    - name: 1
  1504      other: a
  1505    - name: 2
  1506      value: 2
  1507      other: b
  1508    - name: 3
  1509      value: 3
  1510  `),
  1511  		},
  1512  	},
  1513  	{
  1514  		Description: "merge lists of maps with conflict",
  1515  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1516  			Original: []byte(`
  1517  mergingList:
  1518    - name: 1
  1519    - name: 2
  1520      value: 2
  1521  `),
  1522  			TwoWay: []byte(`
  1523  $setElementOrder/mergingList:
  1524    - name: 1
  1525    - name: 2
  1526    - name: 3
  1527  mergingList:
  1528    - name: 3
  1529      value: 3
  1530  `),
  1531  			Modified: []byte(`
  1532  mergingList:
  1533    - name: 1
  1534    - name: 2
  1535      value: 2
  1536    - name: 3
  1537      value: 3
  1538  `),
  1539  			Current: []byte(`
  1540  mergingList:
  1541    - name: 1
  1542      other: a
  1543    - name: 2
  1544      value: 3
  1545      other: b
  1546  `),
  1547  			ThreeWay: []byte(`
  1548  $setElementOrder/mergingList:
  1549    - name: 1
  1550    - name: 2
  1551    - name: 3
  1552  mergingList:
  1553    - name: 2
  1554      value: 2
  1555    - name: 3
  1556      value: 3
  1557  `),
  1558  			Result: []byte(`
  1559  mergingList:
  1560    - name: 1
  1561      other: a
  1562    - name: 2
  1563      value: 2
  1564      other: b
  1565    - name: 3
  1566      value: 3
  1567  `),
  1568  		},
  1569  	},
  1570  	{
  1571  		Description: "add field to map in merging list",
  1572  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1573  			Original: []byte(`
  1574  mergingList:
  1575    - name: 1
  1576    - name: 2
  1577      value: 2
  1578  `),
  1579  			TwoWay: []byte(`
  1580  $setElementOrder/mergingList:
  1581    - name: 1
  1582    - name: 2
  1583  mergingList:
  1584    - name: 1
  1585      value: 1
  1586  `),
  1587  			Modified: []byte(`
  1588  mergingList:
  1589    - name: 1
  1590      value: 1
  1591    - name: 2
  1592      value: 2
  1593  `),
  1594  			Current: []byte(`
  1595  mergingList:
  1596    - name: 1
  1597      other: a
  1598    - name: 2
  1599      value: 2
  1600      other: b
  1601  `),
  1602  			ThreeWay: []byte(`
  1603  $setElementOrder/mergingList:
  1604    - name: 1
  1605    - name: 2
  1606  mergingList:
  1607    - name: 1
  1608      value: 1
  1609  `),
  1610  			Result: []byte(`
  1611  mergingList:
  1612    - name: 1
  1613      value: 1
  1614      other: a
  1615    - name: 2
  1616      value: 2
  1617      other: b
  1618  `),
  1619  		},
  1620  	},
  1621  	{
  1622  		Description: "add field to map in merging list",
  1623  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1624  			Original: []byte(`
  1625  mergingList:
  1626    - name: 1
  1627    - name: 2
  1628      value: 2
  1629  `),
  1630  			TwoWay: []byte(`
  1631  $setElementOrder/mergingList:
  1632    - name: 1
  1633    - name: 2
  1634  mergingList:
  1635    - name: 1
  1636      value: 1
  1637  `),
  1638  			Modified: []byte(`
  1639  mergingList:
  1640    - name: 1
  1641      value: 1
  1642    - name: 2
  1643      value: 2
  1644  `),
  1645  			Current: []byte(`
  1646  mergingList:
  1647    - name: 1
  1648      other: a
  1649    - name: 2
  1650      value: 2
  1651      other: b
  1652  `),
  1653  			ThreeWay: []byte(`
  1654  $setElementOrder/mergingList:
  1655    - name: 1
  1656    - name: 2
  1657  mergingList:
  1658    - name: 1
  1659      value: 1
  1660  `),
  1661  			Result: []byte(`
  1662  mergingList:
  1663    - name: 1
  1664      value: 1
  1665      other: a
  1666    - name: 2
  1667      value: 2
  1668      other: b
  1669  `),
  1670  		},
  1671  	},
  1672  	{
  1673  		Description: "add field to map in merging list with conflict",
  1674  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1675  			Original: []byte(`
  1676  mergingList:
  1677    - name: 1
  1678    - name: 2
  1679      value: 2
  1680  `),
  1681  			TwoWay: []byte(`
  1682  $setElementOrder/mergingList:
  1683    - name: 1
  1684    - name: 2
  1685  mergingList:
  1686    - name: 1
  1687      value: 1
  1688  `),
  1689  			Modified: []byte(`
  1690  mergingList:
  1691    - name: 1
  1692      value: 1
  1693    - name: 2
  1694      value: 2
  1695  `),
  1696  			Current: []byte(`
  1697  mergingList:
  1698    - name: 1
  1699      other: a
  1700    - name: 3
  1701      value: 2
  1702      other: b
  1703  `),
  1704  			ThreeWay: []byte(`
  1705  $setElementOrder/mergingList:
  1706    - name: 1
  1707    - name: 2
  1708  mergingList:
  1709    - name: 1
  1710      value: 1
  1711    - name: 2
  1712      value: 2
  1713  `),
  1714  			Result: []byte(`
  1715  mergingList:
  1716    - name: 1
  1717      value: 1
  1718      other: a
  1719    - name: 2
  1720      value: 2
  1721    - name: 3
  1722      value: 2
  1723      other: b
  1724  `),
  1725  		},
  1726  	},
  1727  	{
  1728  		Description: "add duplicate field to map in merging list",
  1729  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1730  			Original: []byte(`
  1731  mergingList:
  1732    - name: 1
  1733    - name: 2
  1734      value: 2
  1735  `),
  1736  			TwoWay: []byte(`
  1737  $setElementOrder/mergingList:
  1738    - name: 1
  1739    - name: 2
  1740  mergingList:
  1741    - name: 1
  1742      value: 1
  1743  `),
  1744  			Modified: []byte(`
  1745  mergingList:
  1746    - name: 1
  1747      value: 1
  1748    - name: 2
  1749      value: 2
  1750  `),
  1751  			Current: []byte(`
  1752  mergingList:
  1753    - name: 1
  1754      value: 1
  1755      other: a
  1756    - name: 2
  1757      value: 2
  1758      other: b
  1759  `),
  1760  			ThreeWay: []byte(`{}`),
  1761  			Result: []byte(`
  1762  mergingList:
  1763    - name: 1
  1764      value: 1
  1765      other: a
  1766    - name: 2
  1767      value: 2
  1768      other: b
  1769  `),
  1770  		},
  1771  	},
  1772  	{
  1773  		Description: "add an item that already exists in current object in merging list",
  1774  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1775  			Original: []byte(`
  1776  mergingList:
  1777    - name: 1
  1778      value: a
  1779    - name: 2
  1780  `),
  1781  			TwoWay: []byte(`
  1782  $setElementOrder/mergingList:
  1783    - name: 1
  1784    - name: 2
  1785    - name: 3
  1786  mergingList:
  1787    - name: 3
  1788  `),
  1789  			Modified: []byte(`
  1790  mergingList:
  1791    - name: 1
  1792      value: a
  1793    - name: 2
  1794    - name: 3
  1795  `),
  1796  			Current: []byte(`
  1797  mergingList:
  1798    - name: 1
  1799      value: a
  1800      other: x
  1801    - name: 2
  1802    - name: 3
  1803  `),
  1804  			ThreeWay: []byte(`{}`),
  1805  			Result: []byte(`
  1806  mergingList:
  1807    - name: 1
  1808      value: a
  1809      other: x
  1810    - name: 2
  1811    - name: 3
  1812  `),
  1813  		},
  1814  	},
  1815  	{
  1816  		Description: "add duplicate field to map in merging list with conflict",
  1817  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1818  			Original: []byte(`
  1819  mergingList:
  1820    - name: 1
  1821    - name: 2
  1822      value: 2
  1823  `),
  1824  			TwoWay: []byte(`
  1825  $setElementOrder/mergingList:
  1826    - name: 1
  1827    - name: 2
  1828  mergingList:
  1829    - name: 1
  1830      value: 1
  1831  `),
  1832  			Modified: []byte(`
  1833  mergingList:
  1834    - name: 1
  1835      value: 1
  1836    - name: 2
  1837      value: 2
  1838  `),
  1839  			Current: []byte(`
  1840  mergingList:
  1841    - name: 1
  1842      value: 1
  1843      other: a
  1844    - name: 2
  1845      value: 3
  1846      other: b
  1847  `),
  1848  			ThreeWay: []byte(`
  1849  $setElementOrder/mergingList:
  1850    - name: 1
  1851    - name: 2
  1852  mergingList:
  1853    - name: 2
  1854      value: 2
  1855  `),
  1856  			Result: []byte(`
  1857  mergingList:
  1858    - name: 1
  1859      value: 1
  1860      other: a
  1861    - name: 2
  1862      value: 2
  1863      other: b
  1864  `),
  1865  		},
  1866  	},
  1867  	{
  1868  		Description: "replace map field value in merging list",
  1869  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1870  			Original: []byte(`
  1871  mergingList:
  1872    - name: 1
  1873      value: 1
  1874    - name: 2
  1875      value: 2
  1876  `),
  1877  			TwoWay: []byte(`
  1878  $setElementOrder/mergingList:
  1879    - name: 1
  1880    - name: 2
  1881  mergingList:
  1882    - name: 1
  1883      value: a
  1884  `),
  1885  			Modified: []byte(`
  1886  mergingList:
  1887    - name: 1
  1888      value: a
  1889    - name: 2
  1890      value: 2
  1891  `),
  1892  			Current: []byte(`
  1893  mergingList:
  1894    - name: 1
  1895      value: 1
  1896      other: a
  1897    - name: 2
  1898      value: 2
  1899      other: b
  1900  `),
  1901  			ThreeWay: []byte(`
  1902  $setElementOrder/mergingList:
  1903    - name: 1
  1904    - name: 2
  1905  mergingList:
  1906    - name: 1
  1907      value: a
  1908  `),
  1909  			Result: []byte(`
  1910  mergingList:
  1911    - name: 1
  1912      value: a
  1913      other: a
  1914    - name: 2
  1915      value: 2
  1916      other: b
  1917  `),
  1918  		},
  1919  	},
  1920  	{
  1921  		Description: "replace map field value in merging list with conflict",
  1922  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1923  			Original: []byte(`
  1924  mergingList:
  1925    - name: 1
  1926      value: 1
  1927    - name: 2
  1928      value: 2
  1929  `),
  1930  			TwoWay: []byte(`
  1931  $setElementOrder/mergingList:
  1932    - name: 1
  1933    - name: 2
  1934  mergingList:
  1935    - name: 1
  1936      value: a
  1937  `),
  1938  			Modified: []byte(`
  1939  mergingList:
  1940    - name: 1
  1941      value: a
  1942    - name: 2
  1943      value: 2
  1944  `),
  1945  			Current: []byte(`
  1946  mergingList:
  1947    - name: 1
  1948      value: 3
  1949      other: a
  1950    - name: 2
  1951      value: 2
  1952      other: b
  1953  `),
  1954  			ThreeWay: []byte(`
  1955  $setElementOrder/mergingList:
  1956    - name: 1
  1957    - name: 2
  1958  mergingList:
  1959    - name: 1
  1960      value: a
  1961  `),
  1962  			Result: []byte(`
  1963  mergingList:
  1964    - name: 1
  1965      value: a
  1966      other: a
  1967    - name: 2
  1968      value: 2
  1969      other: b
  1970  `),
  1971  		},
  1972  	},
  1973  	{
  1974  		Description: "delete map from merging list",
  1975  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  1976  			Original: []byte(`
  1977  mergingList:
  1978    - name: 1
  1979    - name: 2
  1980  `),
  1981  			TwoWay: []byte(`
  1982  $setElementOrder/mergingList:
  1983    - name: 2
  1984  mergingList:
  1985    - name: 1
  1986      $patch: delete
  1987  `),
  1988  			Modified: []byte(`
  1989  mergingList:
  1990    - name: 2
  1991  `),
  1992  			Current: []byte(`
  1993  mergingList:
  1994    - name: 1
  1995    - name: 2
  1996      other: b
  1997  `),
  1998  			ThreeWay: []byte(`
  1999  $setElementOrder/mergingList:
  2000    - name: 2
  2001  mergingList:
  2002    - name: 1
  2003      $patch: delete
  2004  `),
  2005  			Result: []byte(`
  2006  mergingList:
  2007    - name: 2
  2008      other: b
  2009  `),
  2010  		},
  2011  	},
  2012  	{
  2013  		Description: "delete map from merging list with conflict",
  2014  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2015  			Original: []byte(`
  2016  mergingList:
  2017    - name: 1
  2018    - name: 2
  2019  `),
  2020  			TwoWay: []byte(`
  2021  $setElementOrder/mergingList:
  2022    - name: 2
  2023  mergingList:
  2024    - name: 1
  2025      $patch: delete
  2026  `),
  2027  			Modified: []byte(`
  2028  mergingList:
  2029    - name: 2
  2030  `),
  2031  			Current: []byte(`
  2032  mergingList:
  2033    - name: 1
  2034      other: a
  2035    - name: 2
  2036      other: b
  2037  `),
  2038  			ThreeWay: []byte(`
  2039  $setElementOrder/mergingList:
  2040    - name: 2
  2041  mergingList:
  2042    - name: 1
  2043      $patch: delete
  2044  `),
  2045  			Result: []byte(`
  2046  mergingList:
  2047    - name: 2
  2048      other: b
  2049  `),
  2050  		},
  2051  	},
  2052  	{
  2053  		Description: "delete missing map from merging list",
  2054  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2055  			Original: []byte(`
  2056  mergingList:
  2057    - name: 1
  2058    - name: 2
  2059  `),
  2060  			TwoWay: []byte(`
  2061  $setElementOrder/mergingList:
  2062    - name: 2
  2063  mergingList:
  2064    - name: 1
  2065      $patch: delete
  2066  `),
  2067  			Modified: []byte(`
  2068  mergingList:
  2069    - name: 2
  2070  `),
  2071  			Current: []byte(`
  2072  mergingList:
  2073    - name: 2
  2074      other: b
  2075  `),
  2076  			ThreeWay: []byte(`
  2077  $setElementOrder/mergingList:
  2078    - name: 2
  2079  mergingList:
  2080    - name: 1
  2081      $patch: delete
  2082  `),
  2083  			Result: []byte(`
  2084  mergingList:
  2085    - name: 2
  2086      other: b
  2087  `),
  2088  		},
  2089  	},
  2090  	{
  2091  		Description: "delete missing map from merging list with conflict",
  2092  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2093  			Original: []byte(`
  2094  mergingList:
  2095    - name: 1
  2096    - name: 2
  2097  `),
  2098  			TwoWay: []byte(`
  2099  $setElementOrder/mergingList:
  2100    - name: 2
  2101  mergingList:
  2102    - name: 1
  2103      $patch: delete
  2104  `),
  2105  			Modified: []byte(`
  2106  mergingList:
  2107    - name: 2
  2108  `),
  2109  			Current: []byte(`
  2110  mergingList:
  2111    - name: 3
  2112      other: a
  2113  `),
  2114  			ThreeWay: []byte(`
  2115  $setElementOrder/mergingList:
  2116    - name: 2
  2117  mergingList:
  2118    - name: 2
  2119    - name: 1
  2120      $patch: delete
  2121  `),
  2122  			Result: []byte(`
  2123  mergingList:
  2124    - name: 2
  2125    - name: 3
  2126      other: a
  2127  `),
  2128  		},
  2129  	},
  2130  	{
  2131  		Description: "add map and delete map from merging list",
  2132  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2133  			Original: []byte(`
  2134  mergingList:
  2135    - name: 1
  2136    - name: 2
  2137  `),
  2138  			TwoWay: []byte(`
  2139  $setElementOrder/mergingList:
  2140    - name: 2
  2141    - name: 3
  2142  mergingList:
  2143    - name: 3
  2144    - name: 1
  2145      $patch: delete
  2146  `),
  2147  			Modified: []byte(`
  2148  mergingList:
  2149    - name: 2
  2150    - name: 3
  2151  `),
  2152  			Current: []byte(`
  2153  mergingList:
  2154    - name: 1
  2155    - name: 2
  2156      other: b
  2157    - name: 4
  2158      other: c
  2159  `),
  2160  			ThreeWay: []byte(`
  2161  $setElementOrder/mergingList:
  2162    - name: 2
  2163    - name: 3
  2164  mergingList:
  2165    - name: 3
  2166    - name: 1
  2167      $patch: delete
  2168  `),
  2169  			Result: []byte(`
  2170  mergingList:
  2171    - name: 2
  2172      other: b
  2173    - name: 4
  2174      other: c
  2175    - name: 3
  2176  `),
  2177  		},
  2178  	},
  2179  	{
  2180  		Description: "add map and delete map from merging list with conflict",
  2181  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2182  			Original: []byte(`
  2183  mergingList:
  2184    - name: 1
  2185    - name: 2
  2186  `),
  2187  			TwoWay: []byte(`
  2188  $setElementOrder/mergingList:
  2189    - name: 2
  2190    - name: 3
  2191  mergingList:
  2192    - name: 3
  2193    - name: 1
  2194      $patch: delete
  2195  `),
  2196  			Modified: []byte(`
  2197  mergingList:
  2198    - name: 2
  2199    - name: 3
  2200  `),
  2201  			Current: []byte(`
  2202  mergingList:
  2203    - name: 1
  2204      other: a
  2205    - name: 4
  2206      other: c
  2207  `),
  2208  			ThreeWay: []byte(`
  2209  $setElementOrder/mergingList:
  2210    - name: 2
  2211    - name: 3
  2212  mergingList:
  2213    - name: 2
  2214    - name: 3
  2215    - name: 1
  2216      $patch: delete
  2217  `),
  2218  			Result: []byte(`
  2219  mergingList:
  2220    - name: 4
  2221      other: c
  2222    - name: 2
  2223    - name: 3
  2224  `),
  2225  		},
  2226  	},
  2227  	{
  2228  		Description: "delete field from map in merging list",
  2229  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2230  			Original: []byte(`
  2231  mergingList:
  2232    - name: 1
  2233      value: 1
  2234    - name: 2
  2235      value: 2
  2236  `),
  2237  			TwoWay: []byte(`
  2238  $setElementOrder/mergingList:
  2239    - name: 1
  2240    - name: 2
  2241  mergingList:
  2242    - name: 1
  2243      value: null
  2244  `),
  2245  			Modified: []byte(`
  2246  mergingList:
  2247    - name: 1
  2248    - name: 2
  2249      value: 2
  2250  `),
  2251  			Current: []byte(`
  2252  mergingList:
  2253    - name: 1
  2254      value: 1
  2255      other: a
  2256    - name: 2
  2257      value: 2
  2258      other: b
  2259  `),
  2260  			ThreeWay: []byte(`
  2261  $setElementOrder/mergingList:
  2262    - name: 1
  2263    - name: 2
  2264  mergingList:
  2265    - name: 1
  2266      value: null
  2267  `),
  2268  			Result: []byte(`
  2269  mergingList:
  2270    - name: 1
  2271      other: a
  2272    - name: 2
  2273      value: 2
  2274      other: b
  2275  `),
  2276  		},
  2277  	},
  2278  	{
  2279  		Description: "delete field from map in merging list with conflict",
  2280  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2281  			Original: []byte(`
  2282  mergingList:
  2283    - name: 1
  2284      value: 1
  2285    - name: 2
  2286      value: 2
  2287  `),
  2288  			TwoWay: []byte(`
  2289  $setElementOrder/mergingList:
  2290    - name: 1
  2291    - name: 2
  2292  mergingList:
  2293    - name: 1
  2294      value: null
  2295  `),
  2296  			Modified: []byte(`
  2297  mergingList:
  2298    - name: 1
  2299    - name: 2
  2300      value: 2
  2301  `),
  2302  			Current: []byte(`
  2303  mergingList:
  2304    - name: 1
  2305      value: a
  2306      other: a
  2307    - name: 2
  2308      value: 2
  2309  `),
  2310  			ThreeWay: []byte(`
  2311  $setElementOrder/mergingList:
  2312    - name: 1
  2313    - name: 2
  2314  mergingList:
  2315    - name: 1
  2316      value: null
  2317  `),
  2318  			Result: []byte(`
  2319  mergingList:
  2320    - name: 1
  2321      other: a
  2322    - name: 2
  2323      value: 2
  2324  `),
  2325  		},
  2326  	},
  2327  	{
  2328  		Description: "delete missing field from map in merging list",
  2329  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2330  			Original: []byte(`
  2331  mergingList:
  2332    - name: 1
  2333      value: 1
  2334    - name: 2
  2335      value: 2
  2336  `),
  2337  			TwoWay: []byte(`
  2338  $setElementOrder/mergingList:
  2339    - name: 1
  2340    - name: 2
  2341  mergingList:
  2342    - name: 1
  2343      value: null
  2344  `),
  2345  			Modified: []byte(`
  2346  mergingList:
  2347    - name: 1
  2348    - name: 2
  2349      value: 2
  2350  `),
  2351  			Current: []byte(`
  2352  mergingList:
  2353    - name: 1
  2354      other: a
  2355    - name: 2
  2356      value: 2
  2357      other: b
  2358  `),
  2359  			ThreeWay: []byte(`
  2360  $setElementOrder/mergingList:
  2361    - name: 1
  2362    - name: 2
  2363  mergingList:
  2364    - name: 1
  2365      value: null
  2366  `),
  2367  			Result: []byte(`
  2368  mergingList:
  2369    - name: 1
  2370      other: a
  2371    - name: 2
  2372      value: 2
  2373      other: b
  2374  `),
  2375  		},
  2376  	},
  2377  	{
  2378  		Description: "delete missing field from map in merging list with conflict",
  2379  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2380  			Original: []byte(`
  2381  mergingList:
  2382    - name: 1
  2383      value: 1
  2384    - name: 2
  2385      value: 2
  2386  `),
  2387  			TwoWay: []byte(`
  2388  $setElementOrder/mergingList:
  2389    - name: 1
  2390    - name: 2
  2391  mergingList:
  2392    - name: 1
  2393      value: null
  2394  `),
  2395  			Modified: []byte(`
  2396  mergingList:
  2397    - name: 1
  2398    - name: 2
  2399      value: 2
  2400  `),
  2401  			Current: []byte(`
  2402  mergingList:
  2403    - name: 1
  2404      other: a
  2405    - name: 2
  2406      other: b
  2407  `),
  2408  			ThreeWay: []byte(`
  2409  $setElementOrder/mergingList:
  2410    - name: 1
  2411    - name: 2
  2412  mergingList:
  2413    - name: 1
  2414      value: null
  2415    - name: 2
  2416      value: 2
  2417  `),
  2418  			Result: []byte(`
  2419  mergingList:
  2420    - name: 1
  2421      other: a
  2422    - name: 2
  2423      value: 2
  2424      other: b
  2425  `),
  2426  		},
  2427  	},
  2428  	{
  2429  		Description: "replace non merging list nested in merging list",
  2430  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2431  			Original: []byte(`
  2432  mergingList:
  2433    - name: 1
  2434      nonMergingList:
  2435        - name: 1
  2436        - name: 2
  2437          value: 2
  2438    - name: 2
  2439  `),
  2440  			TwoWay: []byte(`
  2441  $setElementOrder/mergingList:
  2442    - name: 1
  2443    - name: 2
  2444  mergingList:
  2445    - name: 1
  2446      nonMergingList:
  2447        - name: 1
  2448          value: 1
  2449  `),
  2450  			Modified: []byte(`
  2451  mergingList:
  2452    - name: 1
  2453      nonMergingList:
  2454        - name: 1
  2455          value: 1
  2456    - name: 2
  2457  `),
  2458  			Current: []byte(`
  2459  mergingList:
  2460    - name: 1
  2461      other: a
  2462      nonMergingList:
  2463        - name: 1
  2464        - name: 2
  2465          value: 2
  2466    - name: 2
  2467      other: b
  2468  `),
  2469  			ThreeWay: []byte(`
  2470  $setElementOrder/mergingList:
  2471    - name: 1
  2472    - name: 2
  2473  mergingList:
  2474    - name: 1
  2475      nonMergingList:
  2476        - name: 1
  2477          value: 1
  2478  `),
  2479  			Result: []byte(`
  2480  mergingList:
  2481    - name: 1
  2482      other: a
  2483      nonMergingList:
  2484        - name: 1
  2485          value: 1
  2486    - name: 2
  2487      other: b
  2488  `),
  2489  		},
  2490  	},
  2491  	{
  2492  		Description: "replace non merging list nested in merging list with value conflict",
  2493  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2494  			Original: []byte(`
  2495  mergingList:
  2496    - name: 1
  2497      nonMergingList:
  2498        - name: 1
  2499        - name: 2
  2500          value: 2
  2501    - name: 2
  2502  `),
  2503  			TwoWay: []byte(`
  2504  $setElementOrder/mergingList:
  2505    - name: 1
  2506    - name: 2
  2507  mergingList:
  2508    - name: 1
  2509      nonMergingList:
  2510        - name: 1
  2511          value: 1
  2512  `),
  2513  			Modified: []byte(`
  2514  mergingList:
  2515    - name: 1
  2516      nonMergingList:
  2517        - name: 1
  2518          value: 1
  2519    - name: 2
  2520  `),
  2521  			Current: []byte(`
  2522  mergingList:
  2523    - name: 1
  2524      other: a
  2525      nonMergingList:
  2526        - name: 1
  2527          value: c
  2528    - name: 2
  2529      other: b
  2530  `),
  2531  			ThreeWay: []byte(`
  2532  $setElementOrder/mergingList:
  2533    - name: 1
  2534    - name: 2
  2535  mergingList:
  2536    - name: 1
  2537      nonMergingList:
  2538        - name: 1
  2539          value: 1
  2540  `),
  2541  			Result: []byte(`
  2542  mergingList:
  2543    - name: 1
  2544      other: a
  2545      nonMergingList:
  2546        - name: 1
  2547          value: 1
  2548    - name: 2
  2549      other: b
  2550  `),
  2551  		},
  2552  	},
  2553  	{
  2554  		Description: "replace non merging list nested in merging list with deletion conflict",
  2555  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2556  			Original: []byte(`
  2557  mergingList:
  2558    - name: 1
  2559      nonMergingList:
  2560        - name: 1
  2561        - name: 2
  2562          value: 2
  2563    - name: 2
  2564  `),
  2565  			TwoWay: []byte(`
  2566  $setElementOrder/mergingList:
  2567    - name: 1
  2568    - name: 2
  2569  mergingList:
  2570    - name: 1
  2571      nonMergingList:
  2572        - name: 1
  2573          value: 1
  2574  `),
  2575  			Modified: []byte(`
  2576  mergingList:
  2577    - name: 1
  2578      nonMergingList:
  2579        - name: 1
  2580          value: 1
  2581    - name: 2
  2582  `),
  2583  			Current: []byte(`
  2584  mergingList:
  2585    - name: 1
  2586      other: a
  2587      nonMergingList:
  2588        - name: 2
  2589          value: 2
  2590    - name: 2
  2591      other: b
  2592  `),
  2593  			ThreeWay: []byte(`
  2594  $setElementOrder/mergingList:
  2595    - name: 1
  2596    - name: 2
  2597  mergingList:
  2598    - name: 1
  2599      nonMergingList:
  2600        - name: 1
  2601          value: 1
  2602  `),
  2603  			Result: []byte(`
  2604  mergingList:
  2605    - name: 1
  2606      other: a
  2607      nonMergingList:
  2608        - name: 1
  2609          value: 1
  2610    - name: 2
  2611      other: b
  2612  `),
  2613  		},
  2614  	},
  2615  	{
  2616  		Description: "add field to map in merging list nested in merging list",
  2617  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2618  			Original: []byte(`
  2619  mergingList:
  2620    - name: 1
  2621      mergingList:
  2622        - name: 1
  2623        - name: 2
  2624          value: 2
  2625    - name: 2
  2626  `),
  2627  			TwoWay: []byte(`
  2628  $setElementOrder/mergingList:
  2629    - name: 1
  2630    - name: 2
  2631  mergingList:
  2632    - $setElementOrder/mergingList:
  2633        - name: 1
  2634        - name: 2
  2635      name: 1
  2636      mergingList:
  2637        - name: 1
  2638          value: 1
  2639  `),
  2640  			Modified: []byte(`
  2641  mergingList:
  2642    - name: 1
  2643      mergingList:
  2644        - name: 1
  2645          value: 1
  2646        - name: 2
  2647          value: 2
  2648    - name: 2
  2649  `),
  2650  			Current: []byte(`
  2651  mergingList:
  2652    - name: 1
  2653      other: a
  2654      mergingList:
  2655        - name: 1
  2656        - name: 2
  2657          value: 2
  2658    - name: 2
  2659      other: b
  2660  `),
  2661  			ThreeWay: []byte(`
  2662  $setElementOrder/mergingList:
  2663    - name: 1
  2664    - name: 2
  2665  mergingList:
  2666    - $setElementOrder/mergingList:
  2667        - name: 1
  2668        - name: 2
  2669      name: 1
  2670      mergingList:
  2671        - name: 1
  2672          value: 1
  2673  `),
  2674  			Result: []byte(`
  2675  mergingList:
  2676    - name: 1
  2677      other: a
  2678      mergingList:
  2679        - name: 1
  2680          value: 1
  2681        - name: 2
  2682          value: 2
  2683    - name: 2
  2684      other: b
  2685  `),
  2686  		},
  2687  	},
  2688  	{
  2689  		Description: "add field to map in merging list nested in merging list with value conflict",
  2690  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2691  			Original: []byte(`
  2692  mergingList:
  2693    - name: 1
  2694      mergingList:
  2695        - name: 1
  2696        - name: 2
  2697          value: 2
  2698    - name: 2
  2699  `),
  2700  			TwoWay: []byte(`
  2701  $setElementOrder/mergingList:
  2702    - name: 1
  2703    - name: 2
  2704  mergingList:
  2705    - $setElementOrder/mergingList:
  2706        - name: 1
  2707        - name: 2
  2708      name: 1
  2709      mergingList:
  2710        - name: 1
  2711          value: 1
  2712  `),
  2713  			Modified: []byte(`
  2714  mergingList:
  2715    - name: 1
  2716      mergingList:
  2717        - name: 1
  2718          value: 1
  2719        - name: 2
  2720          value: 2
  2721    - name: 2
  2722  `),
  2723  			Current: []byte(`
  2724  mergingList:
  2725    - name: 1
  2726      other: a
  2727      mergingList:
  2728        - name: 1
  2729          value: a
  2730          other: c
  2731        - name: 2
  2732          value: b
  2733          other: d
  2734    - name: 2
  2735      other: b
  2736  `),
  2737  			ThreeWay: []byte(`
  2738  $setElementOrder/mergingList:
  2739    - name: 1
  2740    - name: 2
  2741  mergingList:
  2742    - $setElementOrder/mergingList:
  2743        - name: 1
  2744        - name: 2
  2745      name: 1
  2746      mergingList:
  2747        - name: 1
  2748          value: 1
  2749        - name: 2
  2750          value: 2
  2751  `),
  2752  			Result: []byte(`
  2753  mergingList:
  2754    - name: 1
  2755      other: a
  2756      mergingList:
  2757        - name: 1
  2758          value: 1
  2759          other: c
  2760        - name: 2
  2761          value: 2
  2762          other: d
  2763    - name: 2
  2764      other: b
  2765  `),
  2766  		},
  2767  	},
  2768  	{
  2769  		Description: "add field to map in merging list nested in merging list with deletion conflict",
  2770  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2771  			Original: []byte(`
  2772  mergingList:
  2773    - name: 1
  2774      mergingList:
  2775        - name: 1
  2776        - name: 2
  2777          value: 2
  2778    - name: 2
  2779  `),
  2780  			TwoWay: []byte(`
  2781  $setElementOrder/mergingList:
  2782    - name: 1
  2783    - name: 2
  2784  mergingList:
  2785    - $setElementOrder/mergingList:
  2786        - name: 1
  2787        - name: 2
  2788      name: 1
  2789      mergingList:
  2790        - name: 1
  2791          value: 1
  2792  `),
  2793  			Modified: []byte(`
  2794  mergingList:
  2795    - name: 1
  2796      mergingList:
  2797        - name: 1
  2798          value: 1
  2799        - name: 2
  2800          value: 2
  2801    - name: 2
  2802  `),
  2803  			Current: []byte(`
  2804  mergingList:
  2805    - name: 1
  2806      other: a
  2807      mergingList:
  2808        - name: 2
  2809          value: 2
  2810          other: d
  2811    - name: 2
  2812      other: b
  2813  `),
  2814  			ThreeWay: []byte(`
  2815  $setElementOrder/mergingList:
  2816    - name: 1
  2817    - name: 2
  2818  mergingList:
  2819    - $setElementOrder/mergingList:
  2820        - name: 1
  2821        - name: 2
  2822      name: 1
  2823      mergingList:
  2824        - name: 1
  2825          value: 1
  2826  `),
  2827  			Result: []byte(`
  2828  mergingList:
  2829    - name: 1
  2830      other: a
  2831      mergingList:
  2832        - name: 1
  2833          value: 1
  2834        - name: 2
  2835          value: 2
  2836          other: d
  2837    - name: 2
  2838      other: b
  2839  `),
  2840  		},
  2841  	},
  2842  
  2843  	{
  2844  		Description: "add field to map in merging list nested in merging list with deletion conflict",
  2845  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2846  			Original: []byte(`
  2847  mergingList:
  2848    - name: 1
  2849      mergingList:
  2850        - name: 1
  2851        - name: 2
  2852          value: 2
  2853    - name: 2
  2854  `),
  2855  			TwoWay: []byte(`
  2856  $setElementOrder/mergingList:
  2857    - name: 1
  2858    - name: 2
  2859  mergingList:
  2860    - $setElementOrder/mergingList:
  2861        - name: 2
  2862        - name: 1
  2863      name: 1
  2864      mergingList:
  2865        - name: 1
  2866          value: 1
  2867  `),
  2868  			Modified: []byte(`
  2869  mergingList:
  2870    - name: 1
  2871      mergingList:
  2872        - name: 2
  2873          value: 2
  2874        - name: 1
  2875          value: 1
  2876    - name: 2
  2877  `),
  2878  			Current: []byte(`
  2879  mergingList:
  2880    - name: 1
  2881      other: a
  2882      mergingList:
  2883        - name: 2
  2884          value: 2
  2885          other: d
  2886    - name: 2
  2887      other: b
  2888  `),
  2889  			ThreeWay: []byte(`
  2890  $setElementOrder/mergingList:
  2891    - name: 1
  2892    - name: 2
  2893  mergingList:
  2894    - $setElementOrder/mergingList:
  2895        - name: 2
  2896        - name: 1
  2897      name: 1
  2898      mergingList:
  2899        - name: 1
  2900          value: 1
  2901  `),
  2902  			Result: []byte(`
  2903  mergingList:
  2904    - name: 1
  2905      other: a
  2906      mergingList:
  2907        - name: 2
  2908          value: 2
  2909          other: d
  2910        - name: 1
  2911          value: 1
  2912    - name: 2
  2913      other: b
  2914  `),
  2915  		},
  2916  	},
  2917  	{
  2918  		Description: "add map to merging list by pointer",
  2919  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2920  			Original: []byte(`
  2921  mergeItemPtr:
  2922    - name: 1
  2923  `),
  2924  			TwoWay: []byte(`
  2925  $setElementOrder/mergeItemPtr:
  2926    - name: 1
  2927    - name: 2
  2928  mergeItemPtr:
  2929    - name: 2
  2930  `),
  2931  			Modified: []byte(`
  2932  mergeItemPtr:
  2933    - name: 1
  2934    - name: 2
  2935  `),
  2936  			Current: []byte(`
  2937  mergeItemPtr:
  2938    - name: 1
  2939      other: a
  2940    - name: 3
  2941  `),
  2942  			ThreeWay: []byte(`
  2943  $setElementOrder/mergeItemPtr:
  2944    - name: 1
  2945    - name: 2
  2946  mergeItemPtr:
  2947    - name: 2
  2948  `),
  2949  			Result: []byte(`
  2950  mergeItemPtr:
  2951    - name: 1
  2952      other: a
  2953    - name: 2
  2954    - name: 3
  2955  `),
  2956  		},
  2957  	},
  2958  	{
  2959  		Description: "add map to merging list by pointer with conflict",
  2960  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  2961  			Original: []byte(`
  2962  mergeItemPtr:
  2963    - name: 1
  2964  `),
  2965  			TwoWay: []byte(`
  2966  $setElementOrder/mergeItemPtr:
  2967    - name: 1
  2968    - name: 2
  2969  mergeItemPtr:
  2970    - name: 2
  2971  `),
  2972  			Modified: []byte(`
  2973  mergeItemPtr:
  2974    - name: 1
  2975    - name: 2
  2976  `),
  2977  			Current: []byte(`
  2978  mergeItemPtr:
  2979    - name: 3
  2980  `),
  2981  			ThreeWay: []byte(`
  2982  $setElementOrder/mergeItemPtr:
  2983    - name: 1
  2984    - name: 2
  2985  mergeItemPtr:
  2986    - name: 1
  2987    - name: 2
  2988  `),
  2989  			Result: []byte(`
  2990  mergeItemPtr:
  2991    - name: 1
  2992    - name: 2
  2993    - name: 3
  2994  `),
  2995  		},
  2996  	},
  2997  	{
  2998  		Description: "add field to map in merging list by pointer",
  2999  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3000  			Original: []byte(`
  3001  mergeItemPtr:
  3002    - name: 1
  3003      mergeItemPtr:
  3004        - name: 1
  3005        - name: 2
  3006          value: 2
  3007    - name: 2
  3008  `),
  3009  			TwoWay: []byte(`
  3010  $setElementOrder/mergeItemPtr:
  3011    - name: 1
  3012    - name: 2
  3013  mergeItemPtr:
  3014    - $setElementOrder/mergeItemPtr:
  3015        - name: 1
  3016        - name: 2
  3017      name: 1
  3018      mergeItemPtr:
  3019        - name: 1
  3020          value: 1
  3021  `),
  3022  			Modified: []byte(`
  3023  mergeItemPtr:
  3024    - name: 1
  3025      mergeItemPtr:
  3026        - name: 1
  3027          value: 1
  3028        - name: 2
  3029          value: 2
  3030    - name: 2
  3031  `),
  3032  			Current: []byte(`
  3033  mergeItemPtr:
  3034    - name: 1
  3035      other: a
  3036      mergeItemPtr:
  3037        - name: 1
  3038          other: a
  3039        - name: 2
  3040          value: 2
  3041          other: b
  3042    - name: 2
  3043      other: b
  3044  `),
  3045  			ThreeWay: []byte(`
  3046  $setElementOrder/mergeItemPtr:
  3047    - name: 1
  3048    - name: 2
  3049  mergeItemPtr:
  3050    - $setElementOrder/mergeItemPtr:
  3051        - name: 1
  3052        - name: 2
  3053      name: 1
  3054      mergeItemPtr:
  3055        - name: 1
  3056          value: 1
  3057  `),
  3058  			Result: []byte(`
  3059  mergeItemPtr:
  3060    - name: 1
  3061      other: a
  3062      mergeItemPtr:
  3063        - name: 1
  3064          value: 1
  3065          other: a
  3066        - name: 2
  3067          value: 2
  3068          other: b
  3069    - name: 2
  3070      other: b
  3071  `),
  3072  		},
  3073  	},
  3074  	{
  3075  		Description: "add field to map in merging list by pointer with conflict",
  3076  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3077  			Original: []byte(`
  3078  mergeItemPtr:
  3079    - name: 1
  3080      mergeItemPtr:
  3081        - name: 1
  3082        - name: 2
  3083          value: 2
  3084    - name: 2
  3085  `),
  3086  			TwoWay: []byte(`
  3087  $setElementOrder/mergeItemPtr:
  3088    - name: 1
  3089    - name: 2
  3090  mergeItemPtr:
  3091    - $setElementOrder/mergeItemPtr:
  3092        - name: 1
  3093        - name: 2
  3094      name: 1
  3095      mergeItemPtr:
  3096        - name: 1
  3097          value: 1
  3098  `),
  3099  			Modified: []byte(`
  3100  mergeItemPtr:
  3101    - name: 1
  3102      mergeItemPtr:
  3103        - name: 1
  3104          value: 1
  3105        - name: 2
  3106          value: 2
  3107    - name: 2
  3108  `),
  3109  			Current: []byte(`
  3110  mergeItemPtr:
  3111    - name: 1
  3112      other: a
  3113      mergeItemPtr:
  3114        - name: 1
  3115          value: a
  3116        - name: 2
  3117          value: 2
  3118          other: b
  3119    - name: 2
  3120      other: b
  3121  `),
  3122  			ThreeWay: []byte(`
  3123  $setElementOrder/mergeItemPtr:
  3124    - name: 1
  3125    - name: 2
  3126  mergeItemPtr:
  3127    - $setElementOrder/mergeItemPtr:
  3128        - name: 1
  3129        - name: 2
  3130      name: 1
  3131      mergeItemPtr:
  3132        - name: 1
  3133          value: 1
  3134  `),
  3135  			Result: []byte(`
  3136  mergeItemPtr:
  3137    - name: 1
  3138      other: a
  3139      mergeItemPtr:
  3140        - name: 1
  3141          value: 1
  3142        - name: 2
  3143          value: 2
  3144          other: b
  3145    - name: 2
  3146      other: b
  3147  `),
  3148  		},
  3149  	},
  3150  	{
  3151  		Description: "merge lists of scalars",
  3152  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3153  			Original: []byte(`
  3154  mergingIntList:
  3155  - 1
  3156  - 2
  3157  `),
  3158  			TwoWay: []byte(`
  3159  $setElementOrder/mergingIntList:
  3160  - 1
  3161  - 2
  3162  - 3
  3163  mergingIntList:
  3164  - 3
  3165  `),
  3166  			Modified: []byte(`
  3167  mergingIntList:
  3168  - 1
  3169  - 2
  3170  - 3
  3171  `),
  3172  			Current: []byte(`
  3173  mergingIntList:
  3174  - 1
  3175  - 2
  3176  - 4
  3177  `),
  3178  			ThreeWay: []byte(`
  3179  $setElementOrder/mergingIntList:
  3180  - 1
  3181  - 2
  3182  - 3
  3183  mergingIntList:
  3184  - 3
  3185  `),
  3186  			Result: []byte(`
  3187  mergingIntList:
  3188  - 1
  3189  - 2
  3190  - 3
  3191  - 4
  3192  `),
  3193  		},
  3194  	},
  3195  	{
  3196  		Description: "add duplicate field to map in merging int list",
  3197  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3198  			Original: []byte(`
  3199  mergingIntList:
  3200    - 1
  3201    - 2
  3202  `),
  3203  			TwoWay: []byte(`
  3204  $setElementOrder/mergingIntList:
  3205    - 1
  3206    - 2
  3207    - 3
  3208  mergingIntList:
  3209    - 3
  3210  `),
  3211  			Modified: []byte(`
  3212  mergingIntList:
  3213    - 1
  3214    - 2
  3215    - 3
  3216  `),
  3217  			Current: []byte(`
  3218  mergingIntList:
  3219    - 1
  3220    - 2
  3221    - 3
  3222  `),
  3223  			ThreeWay: []byte(`{}`),
  3224  			Result: []byte(`
  3225  mergingIntList:
  3226    - 1
  3227    - 2
  3228    - 3
  3229  `),
  3230  		},
  3231  	},
  3232  	// test case for setElementOrder
  3233  	{
  3234  		Description: "add an item in a list of primitives and preserve order",
  3235  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3236  			Original: []byte(`
  3237  mergingIntList:
  3238  - 1
  3239  - 2
  3240  `),
  3241  			TwoWay: []byte(`
  3242  $setElementOrder/mergingIntList:
  3243  - 3
  3244  - 1
  3245  - 2
  3246  mergingIntList:
  3247  - 3
  3248  `),
  3249  			Modified: []byte(`
  3250  mergingIntList:
  3251  - 3
  3252  - 1
  3253  - 2
  3254  `),
  3255  			Current: []byte(`
  3256  mergingIntList:
  3257  - 1
  3258  - 4
  3259  - 2
  3260  `),
  3261  			ThreeWay: []byte(`
  3262  $setElementOrder/mergingIntList:
  3263  - 3
  3264  - 1
  3265  - 2
  3266  mergingIntList:
  3267  - 3
  3268  `),
  3269  			Result: []byte(`
  3270  mergingIntList:
  3271  - 3
  3272  - 1
  3273  - 4
  3274  - 2
  3275  `),
  3276  		},
  3277  	},
  3278  	{
  3279  		Description: "delete an item in a list of primitives and preserve order",
  3280  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3281  			Original: []byte(`
  3282  mergingIntList:
  3283  - 1
  3284  - 2
  3285  - 3
  3286  `),
  3287  			TwoWay: []byte(`
  3288  $setElementOrder/mergingIntList:
  3289  - 2
  3290  - 1
  3291  $deleteFromPrimitiveList/mergingIntList:
  3292  - 3
  3293  `),
  3294  			Modified: []byte(`
  3295  mergingIntList:
  3296  - 2
  3297  - 1
  3298  `),
  3299  			Current: []byte(`
  3300  mergingIntList:
  3301  - 1
  3302  - 2
  3303  - 3
  3304  `),
  3305  			ThreeWay: []byte(`
  3306  $setElementOrder/mergingIntList:
  3307  - 2
  3308  - 1
  3309  $deleteFromPrimitiveList/mergingIntList:
  3310  - 3
  3311  `),
  3312  			Result: []byte(`
  3313  mergingIntList:
  3314  - 2
  3315  - 1
  3316  `),
  3317  		},
  3318  	},
  3319  	{
  3320  		Description: "add an item in a list and preserve order",
  3321  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3322  			Original: []byte(`
  3323  mergingList:
  3324    - name: 1
  3325    - name: 2
  3326      value: 2
  3327  `),
  3328  			TwoWay: []byte(`
  3329  $setElementOrder/mergingList:
  3330    - name: 3
  3331    - name: 1
  3332    - name: 2
  3333  mergingList:
  3334    - name: 3
  3335      value: 3
  3336  `),
  3337  			Modified: []byte(`
  3338  mergingList:
  3339    - name: 3
  3340      value: 3
  3341    - name: 1
  3342    - name: 2
  3343      value: 2
  3344  `),
  3345  			Current: []byte(`
  3346  mergingList:
  3347    - name: 1
  3348      other: a
  3349    - name: 2
  3350      value: 2
  3351      other: b
  3352  `),
  3353  			ThreeWay: []byte(`
  3354  $setElementOrder/mergingList:
  3355    - name: 3
  3356    - name: 1
  3357    - name: 2
  3358  mergingList:
  3359    - name: 3
  3360      value: 3
  3361  `),
  3362  			Result: []byte(`
  3363  mergingList:
  3364    - name: 3
  3365      value: 3
  3366    - name: 1
  3367      other: a
  3368    - name: 2
  3369      value: 2
  3370      other: b
  3371  `),
  3372  		},
  3373  	},
  3374  	{
  3375  		Description: "add multiple items in a list and preserve order",
  3376  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3377  			Original: []byte(`
  3378  mergingList:
  3379    - name: 1
  3380    - name: 2
  3381      value: 2
  3382  `),
  3383  			TwoWay: []byte(`
  3384  $setElementOrder/mergingList:
  3385    - name: 1
  3386    - name: 4
  3387    - name: 2
  3388    - name: 3
  3389  mergingList:
  3390    - name: 4
  3391      value: 4
  3392    - name: 3
  3393      value: 3
  3394  `),
  3395  			Modified: []byte(`
  3396  mergingList:
  3397    - name: 1
  3398    - name: 4
  3399      value: 4
  3400    - name: 2
  3401      value: 2
  3402    - name: 3
  3403      value: 3
  3404  `),
  3405  			Current: []byte(`
  3406  mergingList:
  3407    - name: 1
  3408      other: a
  3409    - name: 2
  3410      value: 2
  3411      other: b
  3412  `),
  3413  			ThreeWay: []byte(`
  3414  $setElementOrder/mergingList:
  3415    - name: 1
  3416    - name: 4
  3417    - name: 2
  3418    - name: 3
  3419  mergingList:
  3420    - name: 4
  3421      value: 4
  3422    - name: 3
  3423      value: 3
  3424  `),
  3425  			Result: []byte(`
  3426  mergingList:
  3427    - name: 1
  3428      other: a
  3429    - name: 4
  3430      value: 4
  3431    - name: 2
  3432      value: 2
  3433      other: b
  3434    - name: 3
  3435      value: 3
  3436  `),
  3437  		},
  3438  	},
  3439  	{
  3440  		Description: "delete an item in a list and preserve order",
  3441  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3442  			Original: []byte(`
  3443  mergingList:
  3444    - name: 1
  3445    - name: 3
  3446      value: 3
  3447    - name: 2
  3448      value: 2
  3449  `),
  3450  			TwoWay: []byte(`
  3451  $setElementOrder/mergingList:
  3452    - name: 2
  3453    - name: 1
  3454  mergingList:
  3455    - name: 3
  3456      $patch: delete
  3457  `),
  3458  			Modified: []byte(`
  3459  mergingList:
  3460    - name: 2
  3461      value: 2
  3462    - name: 1
  3463  `),
  3464  			Current: []byte(`
  3465  mergingList:
  3466    - name: 1
  3467      other: a
  3468    - name: 2
  3469      value: 2
  3470      other: b
  3471    - name: 3
  3472      value: 3
  3473  `),
  3474  			ThreeWay: []byte(`
  3475  $setElementOrder/mergingList:
  3476    - name: 2
  3477    - name: 1
  3478  mergingList:
  3479    - name: 3
  3480      $patch: delete
  3481  `),
  3482  			Result: []byte(`
  3483  mergingList:
  3484    - name: 2
  3485      value: 2
  3486      other: b
  3487    - name: 1
  3488      other: a
  3489  `),
  3490  		},
  3491  	},
  3492  	{
  3493  		Description: "change an item in a list and preserve order",
  3494  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3495  			Original: []byte(`
  3496  mergingList:
  3497    - name: 1
  3498    - name: 3
  3499      value: 3
  3500    - name: 2
  3501      value: 2
  3502  `),
  3503  			TwoWay: []byte(`
  3504  $setElementOrder/mergingList:
  3505    - name: 2
  3506    - name: 3
  3507    - name: 1
  3508  mergingList:
  3509    - name: 3
  3510      value: x
  3511  `),
  3512  			Modified: []byte(`
  3513  mergingList:
  3514    - name: 2
  3515      value: 2
  3516    - name: 3
  3517      value: x
  3518    - name: 1
  3519  `),
  3520  			Current: []byte(`
  3521  mergingList:
  3522    - name: 1
  3523      other: a
  3524    - name: 2
  3525      value: 2
  3526      other: b
  3527    - name: 3
  3528      value: 3
  3529  `),
  3530  			ThreeWay: []byte(`
  3531  $setElementOrder/mergingList:
  3532    - name: 2
  3533    - name: 3
  3534    - name: 1
  3535  mergingList:
  3536    - name: 3
  3537      value: x
  3538  `),
  3539  			Result: []byte(`
  3540  mergingList:
  3541    - name: 2
  3542      value: 2
  3543      other: b
  3544    - name: 3
  3545      value: x
  3546    - name: 1
  3547      other: a
  3548  `),
  3549  		},
  3550  	},
  3551  	{
  3552  		Description: "add and delete an item in a list and preserve order",
  3553  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3554  			Original: []byte(`
  3555  mergingList:
  3556    - name: 1
  3557    - name: 3
  3558      value: 3
  3559    - name: 2
  3560      value: 2
  3561  `),
  3562  			TwoWay: []byte(`
  3563  $setElementOrder/mergingList:
  3564    - name: 4
  3565    - name: 2
  3566    - name: 1
  3567  mergingList:
  3568    - name: 4
  3569      value: 4
  3570    - name: 3
  3571      $patch: delete
  3572  `),
  3573  			Modified: []byte(`
  3574  mergingList:
  3575    - name: 4
  3576      value: 4
  3577    - name: 2
  3578      value: 2
  3579    - name: 1
  3580  `),
  3581  			Current: []byte(`
  3582  mergingList:
  3583    - name: 1
  3584      other: a
  3585    - name: 2
  3586      value: 2
  3587      other: b
  3588    - name: 3
  3589      value: 3
  3590  `),
  3591  			ThreeWay: []byte(`
  3592  $setElementOrder/mergingList:
  3593    - name: 4
  3594    - name: 2
  3595    - name: 1
  3596  mergingList:
  3597    - name: 4
  3598      value: 4
  3599    - name: 3
  3600      $patch: delete
  3601  `),
  3602  			Result: []byte(`
  3603  mergingList:
  3604    - name: 4
  3605      value: 4
  3606    - name: 2
  3607      value: 2
  3608      other: b
  3609    - name: 1
  3610      other: a
  3611  `),
  3612  		},
  3613  	},
  3614  	{
  3615  		Description: "set elements order in a list",
  3616  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3617  			Original: []byte(`
  3618  mergingList:
  3619    - name: 1
  3620    - name: 3
  3621      value: 3
  3622    - name: 4
  3623      value: 4
  3624    - name: 2
  3625      value: 2
  3626  `),
  3627  			TwoWay: []byte(`
  3628  $setElementOrder/mergingList:
  3629    - name: 4
  3630    - name: 2
  3631    - name: 3
  3632    - name: 1
  3633  `),
  3634  			Modified: []byte(`
  3635  mergingList:
  3636    - name: 4
  3637      value: 4
  3638    - name: 2
  3639      value: 2
  3640    - name: 3
  3641      value: 3
  3642    - name: 1
  3643  `),
  3644  			Current: []byte(`
  3645  mergingList:
  3646    - name: 1
  3647      other: a
  3648    - name: 3
  3649      value: 3
  3650    - name: 4
  3651      value: 4
  3652    - name: 2
  3653      value: 2
  3654  `),
  3655  			ThreeWay: []byte(`
  3656  $setElementOrder/mergingList:
  3657    - name: 4
  3658    - name: 2
  3659    - name: 3
  3660    - name: 1
  3661  `),
  3662  			Result: []byte(`
  3663  mergingList:
  3664    - name: 4
  3665      value: 4
  3666    - name: 2
  3667      value: 2
  3668    - name: 3
  3669      value: 3
  3670    - name: 1
  3671      other: a
  3672  `),
  3673  		},
  3674  	},
  3675  	{
  3676  		Description: "set elements order in a list with server-only items",
  3677  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3678  			Original: []byte(`
  3679  mergingList:
  3680    - name: 1
  3681    - name: 3
  3682      value: 3
  3683    - name: 4
  3684      value: 4
  3685    - name: 2
  3686      value: 2
  3687  `),
  3688  			TwoWay: []byte(`
  3689  $setElementOrder/mergingList:
  3690    - name: 4
  3691    - name: 2
  3692    - name: 3
  3693    - name: 1
  3694  `),
  3695  			Modified: []byte(`
  3696  mergingList:
  3697    - name: 4
  3698      value: 4
  3699    - name: 2
  3700      value: 2
  3701    - name: 3
  3702      value: 3
  3703    - name: 1
  3704  `),
  3705  			Current: []byte(`
  3706  mergingList:
  3707    - name: 1
  3708      other: a
  3709    - name: 3
  3710      value: 3
  3711    - name: 4
  3712      value: 4
  3713    - name: 2
  3714      value: 2
  3715    - name: 9
  3716  `),
  3717  			ThreeWay: []byte(`
  3718  $setElementOrder/mergingList:
  3719    - name: 4
  3720    - name: 2
  3721    - name: 3
  3722    - name: 1
  3723  `),
  3724  			Result: []byte(`
  3725  mergingList:
  3726    - name: 4
  3727      value: 4
  3728    - name: 2
  3729      value: 2
  3730    - name: 3
  3731      value: 3
  3732    - name: 1
  3733      other: a
  3734    - name: 9
  3735  `),
  3736  		},
  3737  	},
  3738  	{
  3739  		Description: "set elements order in a list with server-only items 2",
  3740  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3741  			Original: []byte(`
  3742  mergingList:
  3743    - name: 1
  3744    - name: 2
  3745      value: 2
  3746    - name: 3
  3747      value: 3
  3748    - name: 4
  3749      value: 4
  3750  `),
  3751  			TwoWay: []byte(`
  3752  $setElementOrder/mergingList:
  3753    - name: 2
  3754    - name: 1
  3755    - name: 4
  3756    - name: 3
  3757  `),
  3758  			Modified: []byte(`
  3759  mergingList:
  3760    - name: 2
  3761      value: 2
  3762    - name: 1
  3763    - name: 4
  3764      value: 4
  3765    - name: 3
  3766      value: 3
  3767  `),
  3768  			Current: []byte(`
  3769  mergingList:
  3770    - name: 1
  3771      other: a
  3772    - name: 2
  3773      value: 2
  3774    - name: 9
  3775    - name: 3
  3776      value: 3
  3777    - name: 4
  3778      value: 4
  3779  `),
  3780  			ThreeWay: []byte(`
  3781  $setElementOrder/mergingList:
  3782    - name: 2
  3783    - name: 1
  3784    - name: 4
  3785    - name: 3
  3786  `),
  3787  			Result: []byte(`
  3788  mergingList:
  3789    - name: 2
  3790      value: 2
  3791    - name: 1
  3792      other: a
  3793    - name: 9
  3794    - name: 4
  3795      value: 4
  3796    - name: 3
  3797      value: 3
  3798  `),
  3799  		},
  3800  	},
  3801  	{
  3802  		Description: "set elements order in a list with server-only items 3",
  3803  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3804  			Original: []byte(`
  3805  mergingList:
  3806    - name: 1
  3807    - name: 2
  3808      value: 2
  3809    - name: 3
  3810      value: 3
  3811    - name: 4
  3812      value: 4
  3813  `),
  3814  			TwoWay: []byte(`
  3815  $setElementOrder/mergingList:
  3816    - name: 2
  3817    - name: 1
  3818    - name: 4
  3819    - name: 3
  3820  `),
  3821  			Modified: []byte(`
  3822  mergingList:
  3823    - name: 2
  3824      value: 2
  3825    - name: 1
  3826    - name: 4
  3827      value: 4
  3828    - name: 3
  3829      value: 3
  3830  `),
  3831  			Current: []byte(`
  3832  mergingList:
  3833    - name: 1
  3834      other: a
  3835    - name: 2
  3836      value: 2
  3837    - name: 7
  3838    - name: 9
  3839    - name: 8
  3840    - name: 3
  3841      value: 3
  3842    - name: 4
  3843      value: 4
  3844  `),
  3845  			ThreeWay: []byte(`
  3846  $setElementOrder/mergingList:
  3847    - name: 2
  3848    - name: 1
  3849    - name: 4
  3850    - name: 3
  3851  `),
  3852  			Result: []byte(`
  3853  mergingList:
  3854    - name: 2
  3855      value: 2
  3856    - name: 1
  3857      other: a
  3858    - name: 7
  3859    - name: 9
  3860    - name: 8
  3861    - name: 4
  3862      value: 4
  3863    - name: 3
  3864      value: 3
  3865  `),
  3866  		},
  3867  	},
  3868  	{
  3869  		Description: "add an item in a int list and preserve order",
  3870  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3871  			Original: []byte(`
  3872  mergingIntList:
  3873    - 1
  3874    - 2
  3875  `),
  3876  			TwoWay: []byte(`
  3877  $setElementOrder/mergingIntList:
  3878    - 3
  3879    - 1
  3880    - 2
  3881  mergingIntList:
  3882    - 3
  3883  `),
  3884  			Modified: []byte(`
  3885  mergingIntList:
  3886    - 3
  3887    - 1
  3888    - 2
  3889  `),
  3890  			Current: []byte(`
  3891  mergingIntList:
  3892    - 1
  3893    - 2
  3894  `),
  3895  			ThreeWay: []byte(`
  3896  $setElementOrder/mergingIntList:
  3897    - 3
  3898    - 1
  3899    - 2
  3900  mergingIntList:
  3901    - 3
  3902  `),
  3903  			Result: []byte(`
  3904  mergingIntList:
  3905    - 3
  3906    - 1
  3907    - 2
  3908  `),
  3909  		},
  3910  	},
  3911  	{
  3912  		Description: "add multiple items in a int list and preserve order",
  3913  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3914  			Original: []byte(`
  3915  mergingIntList:
  3916    - 1
  3917    - 2
  3918  `),
  3919  			TwoWay: []byte(`
  3920  $setElementOrder/mergingIntList:
  3921    - 1
  3922    - 4
  3923    - 2
  3924    - 3
  3925  mergingIntList:
  3926    - 4
  3927    - 3
  3928  `),
  3929  			Modified: []byte(`
  3930  mergingIntList:
  3931    - 1
  3932    - 4
  3933    - 2
  3934    - 3
  3935  `),
  3936  			Current: []byte(`
  3937  mergingIntList:
  3938    - 1
  3939    - 2
  3940  `),
  3941  			ThreeWay: []byte(`
  3942  $setElementOrder/mergingIntList:
  3943    - 1
  3944    - 4
  3945    - 2
  3946    - 3
  3947  mergingIntList:
  3948    - 4
  3949    - 3
  3950  `),
  3951  			Result: []byte(`
  3952  mergingIntList:
  3953    - 1
  3954    - 4
  3955    - 2
  3956    - 3
  3957  `),
  3958  		},
  3959  	},
  3960  	{
  3961  		Description: "delete an item in a int list and preserve order",
  3962  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  3963  			Original: []byte(`
  3964  mergingIntList:
  3965    - 1
  3966    - 3
  3967    - 2
  3968  `),
  3969  			TwoWay: []byte(`
  3970  $setElementOrder/mergingIntList:
  3971    - 2
  3972    - 1
  3973  $deleteFromPrimitiveList/mergingIntList:
  3974    - 3
  3975  `),
  3976  			Modified: []byte(`
  3977  mergingIntList:
  3978    - 2
  3979    - 1
  3980  `),
  3981  			Current: []byte(`
  3982  mergingIntList:
  3983    - 1
  3984    - 2
  3985    - 3
  3986  `),
  3987  			ThreeWay: []byte(`
  3988  $setElementOrder/mergingIntList:
  3989    - 2
  3990    - 1
  3991  $deleteFromPrimitiveList/mergingIntList:
  3992    - 3
  3993  `),
  3994  			Result: []byte(`
  3995  mergingIntList:
  3996    - 2
  3997    - 1
  3998  `),
  3999  		},
  4000  	},
  4001  	{
  4002  		Description: "add and delete an item in a int list and preserve order",
  4003  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4004  			Original: []byte(`
  4005  mergingIntList:
  4006    - 1
  4007    - 3
  4008    - 2
  4009  `),
  4010  			TwoWay: []byte(`
  4011  $setElementOrder/mergingIntList:
  4012    - 4
  4013    - 2
  4014    - 1
  4015  mergingIntList:
  4016    - 4
  4017  $deleteFromPrimitiveList/mergingIntList:
  4018    - 3
  4019  `),
  4020  			Modified: []byte(`
  4021  mergingIntList:
  4022    - 4
  4023    - 2
  4024    - 1
  4025  `),
  4026  			Current: []byte(`
  4027  mergingIntList:
  4028    - 1
  4029    - 2
  4030    - 3
  4031  `),
  4032  			ThreeWay: []byte(`
  4033  $setElementOrder/mergingIntList:
  4034    - 4
  4035    - 2
  4036    - 1
  4037  mergingIntList:
  4038    - 4
  4039  $deleteFromPrimitiveList/mergingIntList:
  4040    - 3
  4041  `),
  4042  			Result: []byte(`
  4043  mergingIntList:
  4044    - 4
  4045    - 2
  4046    - 1
  4047  `),
  4048  		},
  4049  	},
  4050  	{
  4051  		Description: "set elements order in a int list",
  4052  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4053  			Original: []byte(`
  4054  mergingIntList:
  4055    - 1
  4056    - 3
  4057    - 4
  4058    - 2
  4059  `),
  4060  			TwoWay: []byte(`
  4061  $setElementOrder/mergingIntList:
  4062    - 4
  4063    - 2
  4064    - 3
  4065    - 1
  4066  `),
  4067  			Modified: []byte(`
  4068  mergingIntList:
  4069    - 4
  4070    - 2
  4071    - 3
  4072    - 1
  4073  `),
  4074  			Current: []byte(`
  4075  mergingIntList:
  4076    - 1
  4077    - 3
  4078    - 4
  4079    - 2
  4080  `),
  4081  			ThreeWay: []byte(`
  4082  $setElementOrder/mergingIntList:
  4083    - 4
  4084    - 2
  4085    - 3
  4086    - 1
  4087  `),
  4088  			Result: []byte(`
  4089  mergingIntList:
  4090    - 4
  4091    - 2
  4092    - 3
  4093    - 1
  4094  `),
  4095  		},
  4096  	},
  4097  	{
  4098  		Description: "set elements order in a int list with server-only items",
  4099  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4100  			Original: []byte(`
  4101  mergingIntList:
  4102    - 1
  4103    - 3
  4104    - 4
  4105    - 2
  4106  `),
  4107  			TwoWay: []byte(`
  4108  $setElementOrder/mergingIntList:
  4109    - 4
  4110    - 2
  4111    - 3
  4112    - 1
  4113  `),
  4114  			Modified: []byte(`
  4115  mergingIntList:
  4116    - 4
  4117    - 2
  4118    - 3
  4119    - 1
  4120  `),
  4121  			Current: []byte(`
  4122  mergingIntList:
  4123    - 1
  4124    - 3
  4125    - 4
  4126    - 2
  4127    - 9
  4128  `),
  4129  			ThreeWay: []byte(`
  4130  $setElementOrder/mergingIntList:
  4131    - 4
  4132    - 2
  4133    - 3
  4134    - 1
  4135  `),
  4136  			Result: []byte(`
  4137  mergingIntList:
  4138    - 4
  4139    - 2
  4140    - 3
  4141    - 1
  4142    - 9
  4143  `),
  4144  		},
  4145  	},
  4146  	{
  4147  		Description: "set elements order in a int list with server-only items 2",
  4148  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4149  			Original: []byte(`
  4150  mergingIntList:
  4151    - 1
  4152    - 2
  4153    - 3
  4154    - 4
  4155  `),
  4156  			TwoWay: []byte(`
  4157  $setElementOrder/mergingIntList:
  4158    - 2
  4159    - 1
  4160    - 4
  4161    - 3
  4162  `),
  4163  			Modified: []byte(`
  4164  mergingIntList:
  4165    - 2
  4166    - 1
  4167    - 4
  4168    - 3
  4169  `),
  4170  			Current: []byte(`
  4171  mergingIntList:
  4172    - 1
  4173    - 2
  4174    - 9
  4175    - 3
  4176    - 4
  4177  `),
  4178  			ThreeWay: []byte(`
  4179  $setElementOrder/mergingIntList:
  4180    - 2
  4181    - 1
  4182    - 4
  4183    - 3
  4184  `),
  4185  			Result: []byte(`
  4186  mergingIntList:
  4187    - 2
  4188    - 1
  4189    - 9
  4190    - 4
  4191    - 3
  4192  `),
  4193  		},
  4194  	},
  4195  	{
  4196  		Description: "set elements order in a int list with server-only items 3",
  4197  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4198  			Original: []byte(`
  4199  mergingIntList:
  4200    - 1
  4201    - 2
  4202    - 3
  4203    - 4
  4204  `),
  4205  			TwoWay: []byte(`
  4206  $setElementOrder/mergingIntList:
  4207    - 2
  4208    - 1
  4209    - 4
  4210    - 3
  4211  `),
  4212  			Modified: []byte(`
  4213  mergingIntList:
  4214    - 2
  4215    - 1
  4216    - 4
  4217    - 3
  4218  `),
  4219  			Current: []byte(`
  4220  mergingIntList:
  4221    - 1
  4222    - 2
  4223    - 7
  4224    - 9
  4225    - 8
  4226    - 3
  4227    - 4
  4228  `),
  4229  			ThreeWay: []byte(`
  4230  $setElementOrder/mergingIntList:
  4231    - 2
  4232    - 1
  4233    - 4
  4234    - 3
  4235  `),
  4236  			Result: []byte(`
  4237  mergingIntList:
  4238    - 2
  4239    - 1
  4240    - 7
  4241    - 9
  4242    - 8
  4243    - 4
  4244    - 3
  4245  `),
  4246  		},
  4247  	},
  4248  	{
  4249  		// This test case is used just to demonstrate the behavior when dealing with a list with duplicate
  4250  		Description: "behavior of set element order for a merging list with duplicate",
  4251  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4252  			Original: []byte(`
  4253  mergingList:
  4254  - name: 1
  4255  - name: 2
  4256    value: dup1
  4257  - name: 3
  4258  - name: 2
  4259    value: dup2
  4260  - name: 4
  4261  `),
  4262  			Current: []byte(`
  4263  mergingList:
  4264  - name: 1
  4265  - name: 2
  4266    value: dup1
  4267  - name: 3
  4268  - name: 2
  4269    value: dup2
  4270  - name: 4
  4271  `),
  4272  			Modified: []byte(`
  4273  mergingList:
  4274  - name: 2
  4275    value: dup1
  4276  - name: 1
  4277  - name: 4
  4278  - name: 3
  4279  - name: 2
  4280    value: dup2
  4281  `),
  4282  			TwoWay: []byte(`
  4283  $setElementOrder/mergingList:
  4284  - name: 2
  4285  - name: 1
  4286  - name: 4
  4287  - name: 3
  4288  - name: 2
  4289  `),
  4290  			TwoWayResult: []byte(`
  4291  mergingList:
  4292  - name: 2
  4293    value: dup1
  4294  - name: 2
  4295    value: dup2
  4296  - name: 1
  4297  - name: 4
  4298  - name: 3
  4299  `),
  4300  			ThreeWay: []byte(`
  4301  $setElementOrder/mergingList:
  4302  - name: 2
  4303  - name: 1
  4304  - name: 4
  4305  - name: 3
  4306  - name: 2
  4307  `),
  4308  			Result: []byte(`
  4309  mergingList:
  4310  - name: 2
  4311    value: dup1
  4312  - name: 2
  4313    value: dup2
  4314  - name: 1
  4315  - name: 4
  4316  - name: 3
  4317  `),
  4318  		},
  4319  	},
  4320  	{
  4321  		// This test case is used just to demonstrate the behavior when dealing with a list with duplicate
  4322  		Description: "behavior of set element order for a merging int list with duplicate",
  4323  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4324  			Original: []byte(`
  4325  mergingIntList:
  4326  - 1
  4327  - 2
  4328  - 3
  4329  - 2
  4330  - 4
  4331  `),
  4332  			Current: []byte(`
  4333  mergingIntList:
  4334  - 1
  4335  - 2
  4336  - 3
  4337  - 2
  4338  - 4
  4339  `),
  4340  			Modified: []byte(`
  4341  mergingIntList:
  4342  - 2
  4343  - 1
  4344  - 4
  4345  - 3
  4346  - 2
  4347  `),
  4348  			TwoWay: []byte(`
  4349  $setElementOrder/mergingIntList:
  4350  - 2
  4351  - 1
  4352  - 4
  4353  - 3
  4354  - 2
  4355  `),
  4356  			TwoWayResult: []byte(`
  4357  mergingIntList:
  4358  - 2
  4359  - 2
  4360  - 1
  4361  - 4
  4362  - 3
  4363  `),
  4364  			ThreeWay: []byte(`
  4365  $setElementOrder/mergingIntList:
  4366  - 2
  4367  - 1
  4368  - 4
  4369  - 3
  4370  - 2
  4371  `),
  4372  			Result: []byte(`
  4373  mergingIntList:
  4374  - 2
  4375  - 2
  4376  - 1
  4377  - 4
  4378  - 3
  4379  `),
  4380  		},
  4381  	},
  4382  	{
  4383  		Description: "retainKeys map should clear defaulted field",
  4384  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4385  			Original: []byte(`{}`),
  4386  			Current: []byte(`
  4387  retainKeysMap:
  4388    value: foo
  4389  `),
  4390  			Modified: []byte(`
  4391  retainKeysMap:
  4392    other: bar
  4393  `),
  4394  			TwoWay: []byte(`
  4395  retainKeysMap:
  4396    other: bar
  4397  `),
  4398  			ThreeWay: []byte(`
  4399  retainKeysMap:
  4400    $retainKeys:
  4401      - other
  4402    other: bar
  4403  `),
  4404  			Result: []byte(`
  4405  retainKeysMap:
  4406    other: bar
  4407  `),
  4408  		},
  4409  	},
  4410  	{
  4411  		Description: "retainKeys map should clear defaulted field with conflict (discriminated union)",
  4412  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4413  			Original: []byte(`{}`),
  4414  			Current: []byte(`
  4415  retainKeysMap:
  4416    name: type1
  4417    value: foo
  4418  `),
  4419  			Modified: []byte(`
  4420  retainKeysMap:
  4421    name: type2
  4422    other: bar
  4423  `),
  4424  			TwoWay: []byte(`
  4425  retainKeysMap:
  4426    name: type2
  4427    other: bar
  4428  `),
  4429  			ThreeWay: []byte(`
  4430  retainKeysMap:
  4431    $retainKeys:
  4432      - name
  4433      - other
  4434    name: type2
  4435    other: bar
  4436  `),
  4437  			Result: []byte(`
  4438  retainKeysMap:
  4439    name: type2
  4440    other: bar
  4441  `),
  4442  		},
  4443  	},
  4444  	{
  4445  		Description: "retainKeys map adds a field",
  4446  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4447  			Original: []byte(`
  4448  retainKeysMap:
  4449    name: foo
  4450  `),
  4451  			Current: []byte(`
  4452  retainKeysMap:
  4453    name: foo
  4454  `),
  4455  			Modified: []byte(`
  4456  retainKeysMap:
  4457    name: foo
  4458    value: bar
  4459  `),
  4460  			TwoWay: []byte(`
  4461  retainKeysMap:
  4462    $retainKeys:
  4463      - name
  4464      - value
  4465    value: bar
  4466  `),
  4467  			ThreeWay: []byte(`
  4468  retainKeysMap:
  4469    $retainKeys:
  4470      - name
  4471      - value
  4472    value: bar
  4473  `),
  4474  			Result: []byte(`
  4475  retainKeysMap:
  4476    name: foo
  4477    value: bar
  4478  `),
  4479  		},
  4480  	},
  4481  	{
  4482  		Description: "retainKeys map adds a field and clear a field",
  4483  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4484  			Original: []byte(`
  4485  retainKeysMap:
  4486    name: foo
  4487  `),
  4488  			Current: []byte(`
  4489  retainKeysMap:
  4490    name: foo
  4491    other: a
  4492  `),
  4493  			Modified: []byte(`
  4494  retainKeysMap:
  4495    name: foo
  4496    value: bar
  4497  `),
  4498  			TwoWay: []byte(`
  4499  retainKeysMap:
  4500    $retainKeys:
  4501      - name
  4502      - value
  4503    value: bar
  4504  `),
  4505  			ThreeWay: []byte(`
  4506  retainKeysMap:
  4507    $retainKeys:
  4508      - name
  4509      - value
  4510    value: bar
  4511  `),
  4512  			Result: []byte(`
  4513  retainKeysMap:
  4514    name: foo
  4515    value: bar
  4516  `),
  4517  		},
  4518  	},
  4519  	{
  4520  		Description: "retainKeys map deletes a field",
  4521  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4522  			Original: []byte(`
  4523  retainKeysMap:
  4524    name: foo
  4525    value: bar
  4526  `),
  4527  			Current: []byte(`
  4528  retainKeysMap:
  4529    name: foo
  4530    value: bar
  4531  `),
  4532  			Modified: []byte(`
  4533  retainKeysMap:
  4534    name: foo
  4535  `),
  4536  			TwoWay: []byte(`
  4537  retainKeysMap:
  4538    $retainKeys:
  4539      - name
  4540    value: null
  4541  `),
  4542  			ThreeWay: []byte(`
  4543  retainKeysMap:
  4544    $retainKeys:
  4545      - name
  4546    value: null
  4547  `),
  4548  			Result: []byte(`
  4549  retainKeysMap:
  4550    name: foo
  4551  `),
  4552  		},
  4553  	},
  4554  	{
  4555  		Description: "retainKeys map deletes a field and clears a field",
  4556  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4557  			Original: []byte(`
  4558  retainKeysMap:
  4559    name: foo
  4560    value: bar
  4561  `),
  4562  			Current: []byte(`
  4563  retainKeysMap:
  4564    name: foo
  4565    value: bar
  4566    other: a
  4567  `),
  4568  			Modified: []byte(`
  4569  retainKeysMap:
  4570    name: foo
  4571  `),
  4572  			TwoWay: []byte(`
  4573  retainKeysMap:
  4574    $retainKeys:
  4575      - name
  4576    value: null
  4577  `),
  4578  			ThreeWay: []byte(`
  4579  retainKeysMap:
  4580    $retainKeys:
  4581      - name
  4582    value: null
  4583  `),
  4584  			Result: []byte(`
  4585  retainKeysMap:
  4586    name: foo
  4587  `),
  4588  		},
  4589  	},
  4590  	{
  4591  		Description: "retainKeys map clears a field",
  4592  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4593  			Original: []byte(`
  4594  retainKeysMap:
  4595    name: foo
  4596    value: bar
  4597  `),
  4598  			Current: []byte(`
  4599  retainKeysMap:
  4600    name: foo
  4601    value: bar
  4602    other: a
  4603  `),
  4604  			Modified: []byte(`
  4605  retainKeysMap:
  4606    name: foo
  4607    value: bar
  4608  `),
  4609  			TwoWay: []byte(`{}`),
  4610  			ThreeWay: []byte(`
  4611  retainKeysMap:
  4612    $retainKeys:
  4613      - name
  4614      - value
  4615  `),
  4616  			Result: []byte(`
  4617  retainKeysMap:
  4618    name: foo
  4619    value: bar
  4620  `),
  4621  		},
  4622  	},
  4623  	{
  4624  		Description: "retainKeys map nested map with no change",
  4625  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4626  			Original: []byte(`
  4627  retainKeysMap:
  4628    name: foo
  4629    simpleMap:
  4630      key1: a
  4631  `),
  4632  			Current: []byte(`
  4633  retainKeysMap:
  4634    name: foo
  4635    simpleMap:
  4636      key1: a
  4637  `),
  4638  			Modified: []byte(`
  4639  retainKeysMap:
  4640    name: foo
  4641    value: bar
  4642    simpleMap:
  4643      key1: a
  4644  `),
  4645  			TwoWay: []byte(`
  4646  retainKeysMap:
  4647    $retainKeys:
  4648      - name
  4649      - simpleMap
  4650      - value
  4651    value: bar
  4652  `),
  4653  			ThreeWay: []byte(`
  4654  retainKeysMap:
  4655    $retainKeys:
  4656      - name
  4657      - simpleMap
  4658      - value
  4659    value: bar
  4660  `),
  4661  			Result: []byte(`
  4662  retainKeysMap:
  4663    name: foo
  4664    value: bar
  4665    simpleMap:
  4666      key1: a
  4667  `),
  4668  		},
  4669  	},
  4670  	{
  4671  		Description: "retainKeys map adds a field in a nested map",
  4672  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4673  			Original: []byte(`
  4674  retainKeysMap:
  4675    name: foo
  4676    value: bar
  4677    simpleMap:
  4678      key1: a
  4679  `),
  4680  			Current: []byte(`
  4681  retainKeysMap:
  4682    name: foo
  4683    value: bar
  4684    simpleMap:
  4685      key1: a
  4686      key3: c
  4687  `),
  4688  			Modified: []byte(`
  4689  retainKeysMap:
  4690    name: foo
  4691    value: bar
  4692    simpleMap:
  4693      key1: a
  4694      key2: b
  4695  `),
  4696  			TwoWay: []byte(`
  4697  retainKeysMap:
  4698    $retainKeys:
  4699      - name
  4700      - simpleMap
  4701      - value
  4702    simpleMap:
  4703      key2: b
  4704  `),
  4705  			ThreeWay: []byte(`
  4706  retainKeysMap:
  4707    $retainKeys:
  4708      - name
  4709      - simpleMap
  4710      - value
  4711    simpleMap:
  4712      key2: b
  4713  `),
  4714  			Result: []byte(`
  4715  retainKeysMap:
  4716    name: foo
  4717    value: bar
  4718    simpleMap:
  4719      key1: a
  4720      key2: b
  4721      key3: c
  4722  `),
  4723  		},
  4724  	},
  4725  	{
  4726  		Description: "retainKeys map deletes a field in a nested map",
  4727  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4728  			Original: []byte(`
  4729  retainKeysMap:
  4730    name: foo
  4731    value: bar
  4732    simpleMap:
  4733      key1: a
  4734      key2: b
  4735  `),
  4736  			Current: []byte(`
  4737  retainKeysMap:
  4738    name: foo
  4739    value: bar
  4740    simpleMap:
  4741      key1: a
  4742      key2: b
  4743      key3: c
  4744  `),
  4745  			Modified: []byte(`
  4746  retainKeysMap:
  4747    name: foo
  4748    value: bar
  4749    simpleMap:
  4750      key1: a
  4751  `),
  4752  			TwoWay: []byte(`
  4753  retainKeysMap:
  4754    $retainKeys:
  4755      - name
  4756      - simpleMap
  4757      - value
  4758    simpleMap:
  4759      key2: null
  4760  `),
  4761  			ThreeWay: []byte(`
  4762  retainKeysMap:
  4763    $retainKeys:
  4764      - name
  4765      - simpleMap
  4766      - value
  4767    simpleMap:
  4768      key2: null
  4769  `),
  4770  			Result: []byte(`
  4771  retainKeysMap:
  4772    name: foo
  4773    value: bar
  4774    simpleMap:
  4775      key1: a
  4776      key3: c
  4777  `),
  4778  		},
  4779  	},
  4780  	{
  4781  		Description: "retainKeys map changes a field in a nested map",
  4782  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4783  			Original: []byte(`
  4784  retainKeysMap:
  4785    name: foo
  4786    value: bar
  4787    simpleMap:
  4788      key1: a
  4789      key2: b
  4790  `),
  4791  			Current: []byte(`
  4792  retainKeysMap:
  4793    name: foo
  4794    value: bar
  4795    simpleMap:
  4796      key1: a
  4797      key2: b
  4798      key3: c
  4799  `),
  4800  			Modified: []byte(`
  4801  retainKeysMap:
  4802    name: foo
  4803    value: bar
  4804    simpleMap:
  4805      key1: x
  4806      key2: b
  4807  `),
  4808  			TwoWay: []byte(`
  4809  retainKeysMap:
  4810    $retainKeys:
  4811      - name
  4812      - simpleMap
  4813      - value
  4814    simpleMap:
  4815      key1: x
  4816  `),
  4817  			ThreeWay: []byte(`
  4818  retainKeysMap:
  4819    $retainKeys:
  4820      - name
  4821      - simpleMap
  4822      - value
  4823    simpleMap:
  4824      key1: x
  4825  `),
  4826  			Result: []byte(`
  4827  retainKeysMap:
  4828    name: foo
  4829    value: bar
  4830    simpleMap:
  4831      key1: x
  4832      key2: b
  4833      key3: c
  4834  `),
  4835  		},
  4836  	},
  4837  	{
  4838  		Description: "retainKeys map changes a field in a nested map with conflict",
  4839  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4840  			Original: []byte(`
  4841  retainKeysMap:
  4842    name: foo
  4843    value: bar
  4844    simpleMap:
  4845      key1: old
  4846      key2: b
  4847  `),
  4848  			Current: []byte(`
  4849  retainKeysMap:
  4850    name: foo
  4851    value: bar
  4852    simpleMap:
  4853      key1: new
  4854      key2: b
  4855      key3: c
  4856  `),
  4857  			Modified: []byte(`
  4858  retainKeysMap:
  4859    name: foo
  4860    value: bar
  4861    simpleMap:
  4862      key1: modified
  4863      key2: b
  4864  `),
  4865  			TwoWay: []byte(`
  4866  retainKeysMap:
  4867    $retainKeys:
  4868      - name
  4869      - simpleMap
  4870      - value
  4871    simpleMap:
  4872      key1: modified
  4873  `),
  4874  			ThreeWay: []byte(`
  4875  retainKeysMap:
  4876    $retainKeys:
  4877      - name
  4878      - simpleMap
  4879      - value
  4880    simpleMap:
  4881      key1: modified
  4882  `),
  4883  			Result: []byte(`
  4884  retainKeysMap:
  4885    name: foo
  4886    value: bar
  4887    simpleMap:
  4888      key1: modified
  4889      key2: b
  4890      key3: c
  4891  `),
  4892  		},
  4893  	},
  4894  	{
  4895  		Description: "retainKeys map replaces non-merging list",
  4896  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4897  			Original: []byte(`
  4898  retainKeysMap:
  4899    name: foo
  4900    value: bar
  4901    nonMergingList:
  4902    - name: a
  4903    - name: b
  4904  `),
  4905  			Current: []byte(`
  4906  retainKeysMap:
  4907    name: foo
  4908    value: bar
  4909    nonMergingList:
  4910    - name: a
  4911    - name: b
  4912  `),
  4913  			Modified: []byte(`
  4914  retainKeysMap:
  4915    name: foo
  4916    value: bar
  4917    nonMergingList:
  4918    - name: a
  4919    - name: c
  4920    - name: b
  4921  `),
  4922  			TwoWay: []byte(`
  4923  retainKeysMap:
  4924    $retainKeys:
  4925      - name
  4926      - nonMergingList
  4927      - value
  4928    nonMergingList:
  4929    - name: a
  4930    - name: c
  4931    - name: b
  4932  `),
  4933  			ThreeWay: []byte(`
  4934  retainKeysMap:
  4935    $retainKeys:
  4936      - name
  4937      - nonMergingList
  4938      - value
  4939    nonMergingList:
  4940    - name: a
  4941    - name: c
  4942    - name: b
  4943  `),
  4944  			Result: []byte(`
  4945  retainKeysMap:
  4946    name: foo
  4947    value: bar
  4948    nonMergingList:
  4949    - name: a
  4950    - name: c
  4951    - name: b
  4952  `),
  4953  		},
  4954  	},
  4955  	{
  4956  		Description: "retainKeys map nested non-merging list with no change",
  4957  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  4958  			Original: []byte(`
  4959  retainKeysMap:
  4960    name: foo
  4961    nonMergingList:
  4962    - name: a
  4963    - name: b
  4964  `),
  4965  			Current: []byte(`
  4966  retainKeysMap:
  4967    name: foo
  4968    nonMergingList:
  4969    - name: a
  4970    - name: b
  4971  `),
  4972  			Modified: []byte(`
  4973  retainKeysMap:
  4974    name: foo
  4975    value: bar
  4976    nonMergingList:
  4977    - name: a
  4978    - name: b
  4979  `),
  4980  			TwoWay: []byte(`
  4981  retainKeysMap:
  4982    $retainKeys:
  4983      - name
  4984      - nonMergingList
  4985      - value
  4986    value: bar
  4987  `),
  4988  			ThreeWay: []byte(`
  4989  retainKeysMap:
  4990    $retainKeys:
  4991      - name
  4992      - nonMergingList
  4993      - value
  4994    value: bar
  4995  `),
  4996  			Result: []byte(`
  4997  retainKeysMap:
  4998    name: foo
  4999    value: bar
  5000    nonMergingList:
  5001    - name: a
  5002    - name: b
  5003  `),
  5004  		},
  5005  	},
  5006  	{
  5007  		Description: "retainKeys map nested non-merging list with no change with conflict",
  5008  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5009  			Original: []byte(`
  5010  retainKeysMap:
  5011    name: foo
  5012    nonMergingList:
  5013    - name: a
  5014    - name: b
  5015  `),
  5016  			Current: []byte(`
  5017  retainKeysMap:
  5018    name: foo
  5019    nonMergingList:
  5020    - name: a
  5021    - name: b
  5022    - name: c
  5023  `),
  5024  			Modified: []byte(`
  5025  retainKeysMap:
  5026    name: foo
  5027    value: bar
  5028    nonMergingList:
  5029    - name: a
  5030    - name: b
  5031  `),
  5032  			TwoWay: []byte(`
  5033  retainKeysMap:
  5034    $retainKeys:
  5035      - name
  5036      - nonMergingList
  5037      - value
  5038    value: bar
  5039  `),
  5040  			ThreeWay: []byte(`
  5041  retainKeysMap:
  5042    $retainKeys:
  5043      - name
  5044      - nonMergingList
  5045      - value
  5046    value: bar
  5047    nonMergingList:
  5048    - name: a
  5049    - name: b
  5050  `),
  5051  			Result: []byte(`
  5052  retainKeysMap:
  5053    name: foo
  5054    value: bar
  5055    nonMergingList:
  5056    - name: a
  5057    - name: b
  5058  `),
  5059  		},
  5060  	},
  5061  	{
  5062  		Description: "retainKeys map deletes nested non-merging list",
  5063  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5064  			Original: []byte(`
  5065  retainKeysMap:
  5066    name: foo
  5067    nonMergingList:
  5068    - name: a
  5069    - name: b
  5070  `),
  5071  			Current: []byte(`
  5072  retainKeysMap:
  5073    name: foo
  5074    nonMergingList:
  5075    - name: a
  5076    - name: b
  5077  `),
  5078  			Modified: []byte(`
  5079  retainKeysMap:
  5080    name: foo
  5081    value: bar
  5082  `),
  5083  			TwoWay: []byte(`
  5084  retainKeysMap:
  5085    $retainKeys:
  5086      - name
  5087      - value
  5088    value: bar
  5089    nonMergingList: null
  5090  `),
  5091  			ThreeWay: []byte(`
  5092  retainKeysMap:
  5093    $retainKeys:
  5094      - name
  5095      - value
  5096    value: bar
  5097    nonMergingList: null
  5098  `),
  5099  			Result: []byte(`
  5100  retainKeysMap:
  5101    name: foo
  5102    value: bar
  5103  `),
  5104  		},
  5105  	},
  5106  	{
  5107  		Description: "retainKeys map delete nested non-merging list with conflict",
  5108  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5109  			Original: []byte(`
  5110  retainKeysMap:
  5111    name: foo
  5112    nonMergingList:
  5113    - name: a
  5114    - name: b
  5115  `),
  5116  			Current: []byte(`
  5117  retainKeysMap:
  5118    name: foo
  5119    nonMergingList:
  5120    - name: a
  5121    - name: b
  5122    - name: c
  5123  `),
  5124  			Modified: []byte(`
  5125  retainKeysMap:
  5126    name: foo
  5127    value: bar
  5128  `),
  5129  			TwoWay: []byte(`
  5130  retainKeysMap:
  5131    $retainKeys:
  5132      - name
  5133      - value
  5134    value: bar
  5135    nonMergingList: null
  5136  `),
  5137  			ThreeWay: []byte(`
  5138  retainKeysMap:
  5139    $retainKeys:
  5140      - name
  5141      - value
  5142    value: bar
  5143    nonMergingList: null
  5144  `),
  5145  			Result: []byte(`
  5146  retainKeysMap:
  5147    name: foo
  5148    value: bar
  5149  `),
  5150  		},
  5151  	},
  5152  	{
  5153  		Description: "retainKeys map nested merging int list with no change",
  5154  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5155  			Original: []byte(`
  5156  retainKeysMap:
  5157    name: foo
  5158    mergingIntList:
  5159    - 1
  5160    - 2
  5161  `),
  5162  			Current: []byte(`
  5163  retainKeysMap:
  5164    name: foo
  5165    mergingIntList:
  5166    - 1
  5167    - 2
  5168    - 3
  5169  `),
  5170  			Modified: []byte(`
  5171  retainKeysMap:
  5172    name: foo
  5173    value: bar
  5174    mergingIntList:
  5175    - 1
  5176    - 2
  5177  `),
  5178  			TwoWay: []byte(`
  5179  retainKeysMap:
  5180    $retainKeys:
  5181      - mergingIntList
  5182      - name
  5183      - value
  5184    value: bar
  5185  `),
  5186  			ThreeWay: []byte(`
  5187  retainKeysMap:
  5188    $retainKeys:
  5189      - mergingIntList
  5190      - name
  5191      - value
  5192    $setElementOrder/mergingIntList:
  5193      - 1
  5194      - 2
  5195    value: bar
  5196  `),
  5197  			Result: []byte(`
  5198  retainKeysMap:
  5199    name: foo
  5200    value: bar
  5201    mergingIntList:
  5202    - 1
  5203    - 2
  5204    - 3
  5205  `),
  5206  		},
  5207  	},
  5208  	{
  5209  		Description: "retainKeys map adds an item in nested merging int list",
  5210  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5211  			Original: []byte(`
  5212  retainKeysMap:
  5213    name: foo
  5214    mergingIntList:
  5215    - 1
  5216    - 2
  5217  `),
  5218  			Current: []byte(`
  5219  retainKeysMap:
  5220    name: foo
  5221    mergingIntList:
  5222    - 1
  5223    - 2
  5224    - 3
  5225  `),
  5226  			Modified: []byte(`
  5227  retainKeysMap:
  5228    name: foo
  5229    mergingIntList:
  5230    - 1
  5231    - 2
  5232    - 4
  5233  `),
  5234  			TwoWay: []byte(`
  5235  retainKeysMap:
  5236    $setElementOrder/mergingIntList:
  5237      - 1
  5238      - 2
  5239      - 4
  5240    $retainKeys:
  5241      - mergingIntList
  5242      - name
  5243    mergingIntList:
  5244    - 4
  5245  `),
  5246  			ThreeWay: []byte(`
  5247  retainKeysMap:
  5248    $setElementOrder/mergingIntList:
  5249      - 1
  5250      - 2
  5251      - 4
  5252    $retainKeys:
  5253      - mergingIntList
  5254      - name
  5255    mergingIntList:
  5256    - 4
  5257  `),
  5258  			Result: []byte(`
  5259  retainKeysMap:
  5260    name: foo
  5261    mergingIntList:
  5262    - 1
  5263    - 2
  5264    - 4
  5265    - 3
  5266  `),
  5267  		},
  5268  	},
  5269  	{
  5270  		Description: "retainKeys map deletes an item in nested merging int list",
  5271  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5272  			Original: []byte(`
  5273  retainKeysMap:
  5274    name: foo
  5275    mergingIntList:
  5276    - 1
  5277    - 2
  5278    - 3
  5279  `),
  5280  			Current: []byte(`
  5281  retainKeysMap:
  5282    name: foo
  5283    mergingIntList:
  5284    - 1
  5285    - 2
  5286    - 3
  5287    - 4
  5288  `),
  5289  			Modified: []byte(`
  5290  retainKeysMap:
  5291    name: foo
  5292    mergingIntList:
  5293    - 1
  5294    - 3
  5295  `),
  5296  			TwoWay: []byte(`
  5297  retainKeysMap:
  5298    $retainKeys:
  5299      - mergingIntList
  5300      - name
  5301    $deleteFromPrimitiveList/mergingIntList:
  5302    - 2
  5303    $setElementOrder/mergingIntList:
  5304      - 1
  5305      - 3
  5306  `),
  5307  			ThreeWay: []byte(`
  5308  retainKeysMap:
  5309    $retainKeys:
  5310      - mergingIntList
  5311      - name
  5312    $deleteFromPrimitiveList/mergingIntList:
  5313    - 2
  5314    $setElementOrder/mergingIntList:
  5315      - 1
  5316      - 3
  5317  `),
  5318  			Result: []byte(`
  5319  retainKeysMap:
  5320    name: foo
  5321    mergingIntList:
  5322    - 1
  5323    - 3
  5324    - 4
  5325  `),
  5326  		},
  5327  	},
  5328  	{
  5329  		Description: "retainKeys map adds an item and deletes an item in nested merging int list",
  5330  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5331  			Original: []byte(`
  5332  retainKeysMap:
  5333    name: foo
  5334    mergingIntList:
  5335    - 1
  5336    - 2
  5337    - 3
  5338  `),
  5339  			Current: []byte(`
  5340  retainKeysMap:
  5341    name: foo
  5342    mergingIntList:
  5343    - 1
  5344    - 2
  5345    - 3
  5346    - 4
  5347  `),
  5348  			Modified: []byte(`
  5349  retainKeysMap:
  5350    name: foo
  5351    mergingIntList:
  5352    - 1
  5353    - 3
  5354    - 5
  5355  `),
  5356  			TwoWay: []byte(`
  5357  retainKeysMap:
  5358    $retainKeys:
  5359      - mergingIntList
  5360      - name
  5361    mergingIntList:
  5362    - 5
  5363    $deleteFromPrimitiveList/mergingIntList:
  5364    - 2
  5365    $setElementOrder/mergingIntList:
  5366      - 1
  5367      - 3
  5368      - 5
  5369  `),
  5370  			ThreeWay: []byte(`
  5371  retainKeysMap:
  5372    $retainKeys:
  5373      - mergingIntList
  5374      - name
  5375    mergingIntList:
  5376    - 5
  5377    $deleteFromPrimitiveList/mergingIntList:
  5378    - 2
  5379    $setElementOrder/mergingIntList:
  5380      - 1
  5381      - 3
  5382      - 5
  5383  `),
  5384  			Result: []byte(`
  5385  retainKeysMap:
  5386    name: foo
  5387    mergingIntList:
  5388    - 1
  5389    - 3
  5390    - 5
  5391    - 4
  5392  `),
  5393  		},
  5394  	},
  5395  	{
  5396  		Description: "retainKeys map deletes nested merging int list",
  5397  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5398  			Original: []byte(`
  5399  retainKeysMap:
  5400    name: foo
  5401    mergingIntList:
  5402    - 1
  5403    - 2
  5404    - 3
  5405  `),
  5406  			Current: []byte(`
  5407  retainKeysMap:
  5408    name: foo
  5409    mergingIntList:
  5410    - 1
  5411    - 2
  5412    - 3
  5413  `),
  5414  			Modified: []byte(`
  5415  retainKeysMap:
  5416    name: foo
  5417  `),
  5418  			TwoWay: []byte(`
  5419  retainKeysMap:
  5420    $retainKeys:
  5421      - name
  5422    mergingIntList: null
  5423  `),
  5424  			ThreeWay: []byte(`
  5425  retainKeysMap:
  5426    $retainKeys:
  5427      - name
  5428    mergingIntList: null
  5429  `),
  5430  			Result: []byte(`
  5431  retainKeysMap:
  5432    name: foo
  5433  `),
  5434  		},
  5435  	},
  5436  	{
  5437  		Description: "retainKeys map nested merging list with no change",
  5438  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5439  			Original: []byte(`
  5440  retainKeysMap:
  5441    name: foo
  5442    mergingList:
  5443    - name: a
  5444    - name: b
  5445  `),
  5446  			Current: []byte(`
  5447  retainKeysMap:
  5448    name: foo
  5449    mergingList:
  5450    - name: a
  5451    - name: b
  5452    - name: c
  5453  `),
  5454  			Modified: []byte(`
  5455  retainKeysMap:
  5456    name: foo
  5457    value: bar
  5458    mergingList:
  5459    - name: a
  5460    - name: b
  5461  `),
  5462  			TwoWay: []byte(`
  5463  retainKeysMap:
  5464    $retainKeys:
  5465      - mergingList
  5466      - name
  5467      - value
  5468    value: bar
  5469  `),
  5470  			ThreeWay: []byte(`
  5471  retainKeysMap:
  5472    $retainKeys:
  5473      - mergingList
  5474      - name
  5475      - value
  5476    $setElementOrder/mergingList:
  5477      - name: a
  5478      - name: b
  5479    value: bar
  5480  `),
  5481  			Result: []byte(`
  5482  retainKeysMap:
  5483    name: foo
  5484    value: bar
  5485    mergingList:
  5486    - name: a
  5487    - name: b
  5488    - name: c
  5489  `),
  5490  		},
  5491  	},
  5492  	{
  5493  		Description: "retainKeys map adds an item in nested merging list",
  5494  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5495  			Original: []byte(`
  5496  retainKeysMap:
  5497    name: foo
  5498    mergingList:
  5499    - name: a
  5500    - name: b
  5501  `),
  5502  			Current: []byte(`
  5503  retainKeysMap:
  5504    name: foo
  5505    mergingList:
  5506    - name: a
  5507    - name: b
  5508    - name: x
  5509  `),
  5510  			Modified: []byte(`
  5511  retainKeysMap:
  5512    name: foo
  5513    mergingList:
  5514    - name: a
  5515    - name: b
  5516    - name: c
  5517  `),
  5518  			TwoWay: []byte(`
  5519  retainKeysMap:
  5520    $retainKeys:
  5521      - mergingList
  5522      - name
  5523    $setElementOrder/mergingList:
  5524      - name: a
  5525      - name: b
  5526      - name: c
  5527    mergingList:
  5528    - name: c
  5529  `),
  5530  			ThreeWay: []byte(`
  5531  retainKeysMap:
  5532    $retainKeys:
  5533      - mergingList
  5534      - name
  5535    $setElementOrder/mergingList:
  5536      - name: a
  5537      - name: b
  5538      - name: c
  5539    mergingList:
  5540    - name: c
  5541  `),
  5542  			Result: []byte(`
  5543  retainKeysMap:
  5544    name: foo
  5545    mergingList:
  5546    - name: a
  5547    - name: b
  5548    - name: c
  5549    - name: x
  5550  `),
  5551  		},
  5552  	},
  5553  	{
  5554  		Description: "retainKeys map changes an item in nested merging list",
  5555  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5556  			Original: []byte(`
  5557  retainKeysMap:
  5558    name: foo
  5559    mergingList:
  5560    - name: a
  5561    - name: b
  5562      value: foo
  5563  `),
  5564  			Current: []byte(`
  5565  retainKeysMap:
  5566    name: foo
  5567    mergingList:
  5568    - name: a
  5569    - name: b
  5570      value: foo
  5571    - name: x
  5572  `),
  5573  			Modified: []byte(`
  5574  retainKeysMap:
  5575    name: foo
  5576    mergingList:
  5577    - name: a
  5578    - name: b
  5579      value: bar
  5580  `),
  5581  			TwoWay: []byte(`
  5582  retainKeysMap:
  5583    $retainKeys:
  5584      - mergingList
  5585      - name
  5586    $setElementOrder/mergingList:
  5587      - name: a
  5588      - name: b
  5589    mergingList:
  5590    - name: b
  5591      value: bar
  5592  `),
  5593  			ThreeWay: []byte(`
  5594  retainKeysMap:
  5595    $retainKeys:
  5596      - mergingList
  5597      - name
  5598    $setElementOrder/mergingList:
  5599      - name: a
  5600      - name: b
  5601    mergingList:
  5602    - name: b
  5603      value: bar
  5604  `),
  5605  			Result: []byte(`
  5606  retainKeysMap:
  5607    name: foo
  5608    mergingList:
  5609    - name: a
  5610    - name: b
  5611      value: bar
  5612    - name: x
  5613  `),
  5614  		},
  5615  	},
  5616  	{
  5617  		Description: "retainKeys map deletes nested merging list",
  5618  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5619  			Original: []byte(`
  5620  retainKeysMap:
  5621    name: foo
  5622    mergingList:
  5623    - name: a
  5624    - name: b
  5625  `),
  5626  			Current: []byte(`
  5627  retainKeysMap:
  5628    name: foo
  5629    mergingList:
  5630    - name: a
  5631    - name: b
  5632  `),
  5633  			Modified: []byte(`
  5634  retainKeysMap:
  5635    name: foo
  5636    value: bar
  5637  `),
  5638  			TwoWay: []byte(`
  5639  retainKeysMap:
  5640    $retainKeys:
  5641      - name
  5642      - value
  5643    value: bar
  5644    mergingList: null
  5645  `),
  5646  			ThreeWay: []byte(`
  5647  retainKeysMap:
  5648    $retainKeys:
  5649      - name
  5650      - value
  5651    value: bar
  5652    mergingList: null
  5653  `),
  5654  			Result: []byte(`
  5655  retainKeysMap:
  5656    name: foo
  5657    value: bar
  5658  `),
  5659  		},
  5660  	},
  5661  	{
  5662  		Description: "retainKeys map deletes an item in nested merging list",
  5663  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5664  			Original: []byte(`
  5665  retainKeysMap:
  5666    name: foo
  5667    mergingList:
  5668    - name: a
  5669    - name: b
  5670  `),
  5671  			Current: []byte(`
  5672  retainKeysMap:
  5673    name: foo
  5674    mergingList:
  5675    - name: a
  5676    - name: b
  5677    - name: x
  5678  `),
  5679  			Modified: []byte(`
  5680  retainKeysMap:
  5681    name: foo
  5682    mergingList:
  5683    - name: a
  5684  `),
  5685  			TwoWay: []byte(`
  5686  retainKeysMap:
  5687    $retainKeys:
  5688      - mergingList
  5689      - name
  5690    $setElementOrder/mergingList:
  5691      - name: a
  5692    mergingList:
  5693    - name: b
  5694      $patch: delete
  5695  `),
  5696  			ThreeWay: []byte(`
  5697  retainKeysMap:
  5698    $retainKeys:
  5699      - mergingList
  5700      - name
  5701    $setElementOrder/mergingList:
  5702      - name: a
  5703    mergingList:
  5704    - name: b
  5705      $patch: delete
  5706  `),
  5707  			Result: []byte(`
  5708  retainKeysMap:
  5709    name: foo
  5710    mergingList:
  5711    - name: a
  5712    - name: x
  5713  `),
  5714  		},
  5715  	},
  5716  	{
  5717  		Description: "retainKeys list of maps clears a field",
  5718  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5719  			Original: []byte(`
  5720  retainKeysMergingList:
  5721  - name: bar
  5722  - name: foo
  5723    value: a
  5724  `),
  5725  			Current: []byte(`
  5726  retainKeysMergingList:
  5727  - name: bar
  5728  - name: foo
  5729    value: a
  5730    other: x
  5731  `),
  5732  			Modified: []byte(`
  5733  retainKeysMergingList:
  5734  - name: bar
  5735  - name: foo
  5736    value: a
  5737  `),
  5738  			TwoWay: []byte(`{}`),
  5739  			ThreeWay: []byte(`
  5740  $setElementOrder/retainKeysMergingList:
  5741    - name: bar
  5742    - name: foo
  5743  retainKeysMergingList:
  5744  - $retainKeys:
  5745      - name
  5746      - value
  5747    name: foo
  5748  `),
  5749  			Result: []byte(`
  5750  retainKeysMergingList:
  5751  - name: bar
  5752  - name: foo
  5753    value: a
  5754  `),
  5755  		},
  5756  	},
  5757  	{
  5758  		Description: "retainKeys list of maps clears a field with conflict",
  5759  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5760  			Original: []byte(`
  5761  retainKeysMergingList:
  5762  - name: bar
  5763  - name: foo
  5764    value: old
  5765  `),
  5766  			Current: []byte(`
  5767  retainKeysMergingList:
  5768  - name: bar
  5769  - name: foo
  5770    value: new
  5771    other: x
  5772  `),
  5773  			Modified: []byte(`
  5774  retainKeysMergingList:
  5775  - name: bar
  5776  - name: foo
  5777    value: modified
  5778  `),
  5779  			TwoWay: []byte(`
  5780  $setElementOrder/retainKeysMergingList:
  5781    - name: bar
  5782    - name: foo
  5783  retainKeysMergingList:
  5784  - $retainKeys:
  5785      - name
  5786      - value
  5787    name: foo
  5788    value: modified
  5789  `),
  5790  			ThreeWay: []byte(`
  5791  $setElementOrder/retainKeysMergingList:
  5792    - name: bar
  5793    - name: foo
  5794  retainKeysMergingList:
  5795  - $retainKeys:
  5796      - name
  5797      - value
  5798    name: foo
  5799    value: modified
  5800  `),
  5801  			Result: []byte(`
  5802  retainKeysMergingList:
  5803  - name: bar
  5804  - name: foo
  5805    value: modified
  5806  `),
  5807  		},
  5808  	},
  5809  	{
  5810  		Description: "retainKeys list of maps changes a field and clear a field",
  5811  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5812  			Original: []byte(`
  5813  retainKeysMergingList:
  5814  - name: bar
  5815  - name: foo
  5816    value: old
  5817  `),
  5818  			Current: []byte(`
  5819  retainKeysMergingList:
  5820  - name: bar
  5821  - name: foo
  5822    value: old
  5823    other: x
  5824  `),
  5825  			Modified: []byte(`
  5826  retainKeysMergingList:
  5827  - name: bar
  5828  - name: foo
  5829    value: new
  5830  `),
  5831  			TwoWay: []byte(`
  5832  $setElementOrder/retainKeysMergingList:
  5833    - name: bar
  5834    - name: foo
  5835  retainKeysMergingList:
  5836  - $retainKeys:
  5837      - name
  5838      - value
  5839    name: foo
  5840    value: new
  5841  `),
  5842  			ThreeWay: []byte(`
  5843  $setElementOrder/retainKeysMergingList:
  5844    - name: bar
  5845    - name: foo
  5846  retainKeysMergingList:
  5847  - $retainKeys:
  5848      - name
  5849      - value
  5850    name: foo
  5851    value: new
  5852  `),
  5853  			Result: []byte(`
  5854  retainKeysMergingList:
  5855  - name: bar
  5856  - name: foo
  5857    value: new
  5858  `),
  5859  		},
  5860  	},
  5861  	{
  5862  		Description: "retainKeys list of maps changes a field and clear a field with conflict",
  5863  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5864  			Original: []byte(`
  5865  retainKeysMergingList:
  5866  - name: bar
  5867  - name: foo
  5868    value: old
  5869  `),
  5870  			Current: []byte(`
  5871  retainKeysMergingList:
  5872  - name: bar
  5873  - name: foo
  5874    value: modified
  5875    other: x
  5876  `),
  5877  			Modified: []byte(`
  5878  retainKeysMergingList:
  5879  - name: bar
  5880  - name: foo
  5881    value: new
  5882  `),
  5883  			TwoWay: []byte(`
  5884  $setElementOrder/retainKeysMergingList:
  5885    - name: bar
  5886    - name: foo
  5887  retainKeysMergingList:
  5888  - $retainKeys:
  5889      - name
  5890      - value
  5891    name: foo
  5892    value: new
  5893  `),
  5894  			ThreeWay: []byte(`
  5895  $setElementOrder/retainKeysMergingList:
  5896    - name: bar
  5897    - name: foo
  5898  retainKeysMergingList:
  5899  - $retainKeys:
  5900      - name
  5901      - value
  5902    name: foo
  5903    value: new
  5904  `),
  5905  			Result: []byte(`
  5906  retainKeysMergingList:
  5907  - name: bar
  5908  - name: foo
  5909    value: new
  5910  `),
  5911  		},
  5912  	},
  5913  	{
  5914  		Description: "retainKeys list of maps adds a field",
  5915  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5916  			Original: []byte(`
  5917  retainKeysMergingList:
  5918  - name: bar
  5919  - name: foo
  5920  `),
  5921  			Current: []byte(`
  5922  retainKeysMergingList:
  5923  - name: bar
  5924  - name: foo
  5925  `),
  5926  			Modified: []byte(`
  5927  retainKeysMergingList:
  5928  - name: bar
  5929  - name: foo
  5930    value: a
  5931  `),
  5932  			TwoWay: []byte(`
  5933  $setElementOrder/retainKeysMergingList:
  5934    - name: bar
  5935    - name: foo
  5936  retainKeysMergingList:
  5937  - $retainKeys:
  5938      - name
  5939      - value
  5940    name: foo
  5941    value: a
  5942  `),
  5943  			ThreeWay: []byte(`
  5944  $setElementOrder/retainKeysMergingList:
  5945    - name: bar
  5946    - name: foo
  5947  retainKeysMergingList:
  5948  - $retainKeys:
  5949      - name
  5950      - value
  5951    name: foo
  5952    value: a
  5953  `),
  5954  			Result: []byte(`
  5955  retainKeysMergingList:
  5956  - name: bar
  5957  - name: foo
  5958    value: a
  5959  `),
  5960  		},
  5961  	},
  5962  	{
  5963  		Description: "retainKeys list of maps adds a field and clear a field",
  5964  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  5965  			Original: []byte(`
  5966  retainKeysMergingList:
  5967  - name: bar
  5968  - name: foo
  5969  `),
  5970  			Current: []byte(`
  5971  retainKeysMergingList:
  5972  - name: bar
  5973  - name: foo
  5974    other: x
  5975  `),
  5976  			Modified: []byte(`
  5977  retainKeysMergingList:
  5978  - name: bar
  5979  - name: foo
  5980    value: a
  5981  `),
  5982  			TwoWay: []byte(`
  5983  $setElementOrder/retainKeysMergingList:
  5984    - name: bar
  5985    - name: foo
  5986  retainKeysMergingList:
  5987  - $retainKeys:
  5988      - name
  5989      - value
  5990    name: foo
  5991    value: a
  5992  `),
  5993  			ThreeWay: []byte(`
  5994  $setElementOrder/retainKeysMergingList:
  5995    - name: bar
  5996    - name: foo
  5997  retainKeysMergingList:
  5998  - $retainKeys:
  5999      - name
  6000      - value
  6001    name: foo
  6002    value: a
  6003  `),
  6004  			Result: []byte(`
  6005  retainKeysMergingList:
  6006  - name: bar
  6007  - name: foo
  6008    value: a
  6009  `),
  6010  		},
  6011  	},
  6012  	{
  6013  		Description: "retainKeys list of maps deletes a field",
  6014  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  6015  			Original: []byte(`
  6016  retainKeysMergingList:
  6017  - name: bar
  6018  - name: foo
  6019    value: a
  6020  `),
  6021  			Current: []byte(`
  6022  retainKeysMergingList:
  6023  - name: bar
  6024  - name: foo
  6025    value: a
  6026  `),
  6027  			Modified: []byte(`
  6028  retainKeysMergingList:
  6029  - name: bar
  6030  - name: foo
  6031  `),
  6032  			TwoWay: []byte(`
  6033  $setElementOrder/retainKeysMergingList:
  6034    - name: bar
  6035    - name: foo
  6036  retainKeysMergingList:
  6037  - $retainKeys:
  6038      - name
  6039    name: foo
  6040    value: null
  6041  `),
  6042  			ThreeWay: []byte(`
  6043  $setElementOrder/retainKeysMergingList:
  6044    - name: bar
  6045    - name: foo
  6046  retainKeysMergingList:
  6047  - $retainKeys:
  6048      - name
  6049    name: foo
  6050    value: null
  6051  `),
  6052  			Result: []byte(`
  6053  retainKeysMergingList:
  6054  - name: bar
  6055  - name: foo
  6056  `),
  6057  		},
  6058  	},
  6059  	{
  6060  		Description: "retainKeys list of maps deletes a field and clear a field",
  6061  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  6062  			Original: []byte(`
  6063  retainKeysMergingList:
  6064  - name: bar
  6065  - name: foo
  6066    value: a
  6067  `),
  6068  			Current: []byte(`
  6069  retainKeysMergingList:
  6070  - name: bar
  6071  - name: foo
  6072    value: a
  6073    other: x
  6074  `),
  6075  			Modified: []byte(`
  6076  retainKeysMergingList:
  6077  - name: bar
  6078  - name: foo
  6079  `),
  6080  			TwoWay: []byte(`
  6081  $setElementOrder/retainKeysMergingList:
  6082    - name: bar
  6083    - name: foo
  6084  retainKeysMergingList:
  6085  - $retainKeys:
  6086      - name
  6087    name: foo
  6088    value: null
  6089  `),
  6090  			ThreeWay: []byte(`
  6091  $setElementOrder/retainKeysMergingList:
  6092    - name: bar
  6093    - name: foo
  6094  retainKeysMergingList:
  6095  - $retainKeys:
  6096      - name
  6097    name: foo
  6098    value: null
  6099  `),
  6100  			Result: []byte(`
  6101  retainKeysMergingList:
  6102  - name: bar
  6103  - name: foo
  6104  `),
  6105  		},
  6106  	},
  6107  	{
  6108  		Description: "delete and reorder in one list, reorder in another",
  6109  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  6110  			Original: []byte(`
  6111  mergingList:
  6112  - name: a
  6113    value: a
  6114  - name: b
  6115    value: b
  6116  mergeItemPtr:
  6117  - name: c
  6118    value: c
  6119  - name: d
  6120    value: d
  6121  `),
  6122  			Current: []byte(`
  6123  mergingList:
  6124  - name: a
  6125    value: a
  6126  - name: b
  6127    value: b
  6128  mergeItemPtr:
  6129  - name: c
  6130    value: c
  6131  - name: d
  6132    value: d
  6133  `),
  6134  			Modified: []byte(`
  6135  mergingList:
  6136  - name: b
  6137    value: b
  6138  mergeItemPtr:
  6139  - name: d
  6140    value: d
  6141  - name: c
  6142    value: c
  6143  `),
  6144  			TwoWay: []byte(`
  6145  $setElementOrder/mergingList:
  6146  - name: b
  6147  $setElementOrder/mergeItemPtr:
  6148  - name: d
  6149  - name: c
  6150  mergingList:
  6151  - $patch: delete
  6152    name: a
  6153  `),
  6154  			ThreeWay: []byte(`
  6155  $setElementOrder/mergingList:
  6156  - name: b
  6157  $setElementOrder/mergeItemPtr:
  6158  - name: d
  6159  - name: c
  6160  mergingList:
  6161  - $patch: delete
  6162    name: a
  6163  `),
  6164  			Result: []byte(`
  6165  mergingList:
  6166  - name: b
  6167    value: b
  6168  mergeItemPtr:
  6169  - name: d
  6170    value: d
  6171  - name: c
  6172    value: c
  6173  `),
  6174  		},
  6175  	},
  6176  }
  6177  
  6178  func TestStrategicMergePatch(t *testing.T) {
  6179  	testStrategicMergePatchWithCustomArgumentsUsingStruct(t, "bad struct",
  6180  		"{}", "{}", []byte("<THIS IS NOT A STRUCT>"), mergepatch.ErrBadArgKind(struct{}{}, []byte{}))
  6181  
  6182  	mergeItemOpenapiSchema := PatchMetaFromOpenAPI{
  6183  		Schema: sptest.GetSchemaOrDie(&fakeMergeItemSchema, "mergeItem"),
  6184  	}
  6185  	mergeItemOpenapiV3Schema := PatchMetaFromOpenAPIV3{
  6186  		SchemaList: fakeMergeItemV3Schema.SchemaOrDie().Components.Schemas,
  6187  		Schema:     fakeMergeItemV3Schema.SchemaOrDie().Components.Schemas["mergeItem"],
  6188  	}
  6189  	schemas := []LookupPatchMeta{
  6190  		mergeItemStructSchema,
  6191  		mergeItemOpenapiSchema,
  6192  		mergeItemOpenapiV3Schema,
  6193  	}
  6194  
  6195  	tc := StrategicMergePatchTestCases{}
  6196  	err := yaml.Unmarshal(createStrategicMergePatchTestCaseData, &tc)
  6197  	if err != nil {
  6198  		t.Errorf("can't unmarshal test cases: %s\n", err)
  6199  		return
  6200  	}
  6201  
  6202  	for _, schema := range schemas {
  6203  		t.Run(schema.Name(), func(t *testing.T) {
  6204  
  6205  			testStrategicMergePatchWithCustomArguments(t, "bad original",
  6206  				"<THIS IS NOT JSON>", "{}", schema, mergepatch.ErrBadJSONDoc)
  6207  			testStrategicMergePatchWithCustomArguments(t, "bad patch",
  6208  				"{}", "<THIS IS NOT JSON>", schema, mergepatch.ErrBadJSONDoc)
  6209  			testStrategicMergePatchWithCustomArguments(t, "nil struct",
  6210  				"{}", "{}", nil, mergepatch.ErrBadArgKind(struct{}{}, nil))
  6211  
  6212  			for _, c := range tc.TestCases {
  6213  				t.Run(c.Description+"/TwoWay", func(t *testing.T) {
  6214  					testTwoWayPatch(t, c, schema)
  6215  				})
  6216  				t.Run(c.Description+"/ThreeWay", func(t *testing.T) {
  6217  					testThreeWayPatch(t, c, schema)
  6218  				})
  6219  			}
  6220  		})
  6221  
  6222  		// run multiple times to exercise different map traversal orders
  6223  		for i := 0; i < 10; i++ {
  6224  			for _, c := range strategicMergePatchRawTestCases {
  6225  				t.Run(c.Description+"/TwoWay", func(t *testing.T) {
  6226  					testTwoWayPatchForRawTestCase(t, c, schema)
  6227  				})
  6228  				t.Run(c.Description+"/ThreeWay", func(t *testing.T) {
  6229  					testThreeWayPatchForRawTestCase(t, c, schema)
  6230  				})
  6231  			}
  6232  		}
  6233  	}
  6234  }
  6235  
  6236  func testStrategicMergePatchWithCustomArgumentsUsingStruct(t *testing.T, description, original, patch string, dataStruct interface{}, expected error) {
  6237  	schema, actual := NewPatchMetaFromStruct(dataStruct)
  6238  	// If actual is not nil, check error. If errors match, return.
  6239  	if actual != nil {
  6240  		checkErrorsEqual(t, description, expected, actual, schema)
  6241  		return
  6242  	}
  6243  	testStrategicMergePatchWithCustomArguments(t, description, original, patch, schema, expected)
  6244  }
  6245  
  6246  func testStrategicMergePatchWithCustomArguments(t *testing.T, description, original, patch string, schema LookupPatchMeta, expected error) {
  6247  	_, actual := StrategicMergePatch([]byte(original), []byte(patch), schema)
  6248  	checkErrorsEqual(t, description, expected, actual, schema)
  6249  }
  6250  
  6251  func checkErrorsEqual(t *testing.T, description string, expected, actual error, schema LookupPatchMeta) {
  6252  	if actual != expected {
  6253  		if actual == nil {
  6254  			t.Errorf("using %s expected error: %s\ndid not occur in test case: %s", getSchemaType(schema), expected, description)
  6255  			return
  6256  		}
  6257  
  6258  		if expected == nil || actual.Error() != expected.Error() {
  6259  			t.Errorf("using %s unexpected error: %s\noccurred in test case: %s", getSchemaType(schema), actual, description)
  6260  			return
  6261  		}
  6262  	}
  6263  }
  6264  
  6265  func testTwoWayPatch(t *testing.T, c StrategicMergePatchTestCase, schema LookupPatchMeta) {
  6266  	original, expectedPatch, modified, expectedResult := twoWayTestCaseToJSONOrFail(t, c, schema)
  6267  
  6268  	actualPatch, err := CreateTwoWayMergePatchUsingLookupPatchMeta(original, modified, schema)
  6269  	if err != nil {
  6270  		t.Errorf("using %s error: %s\nin test case: %s\ncannot create two way patch: %s:\n%s\n",
  6271  			getSchemaType(schema), err, c.Description, original, mergepatch.ToYAMLOrError(c.StrategicMergePatchTestCaseData))
  6272  		return
  6273  	}
  6274  
  6275  	testPatchCreation(t, expectedPatch, actualPatch, c.Description)
  6276  	testPatchApplication(t, original, actualPatch, expectedResult, c.Description, "", schema)
  6277  }
  6278  
  6279  func testTwoWayPatchForRawTestCase(t *testing.T, c StrategicMergePatchRawTestCase, schema LookupPatchMeta) {
  6280  	original, expectedPatch, modified, expectedResult := twoWayRawTestCaseToJSONOrFail(t, c)
  6281  
  6282  	actualPatch, err := CreateTwoWayMergePatchUsingLookupPatchMeta(original, modified, schema)
  6283  	if err != nil {
  6284  		t.Errorf("error: %s\nin test case: %s\ncannot create two way patch:\noriginal:%s\ntwoWay:%s\nmodified:%s\ncurrent:%s\nthreeWay:%s\nresult:%s\n",
  6285  			err, c.Description, c.Original, c.TwoWay, c.Modified, c.Current, c.ThreeWay, c.Result)
  6286  		return
  6287  	}
  6288  
  6289  	testPatchCreation(t, expectedPatch, actualPatch, c.Description)
  6290  	testPatchApplication(t, original, actualPatch, expectedResult, c.Description, c.ExpectedError, schema)
  6291  }
  6292  
  6293  func twoWayTestCaseToJSONOrFail(t *testing.T, c StrategicMergePatchTestCase, schema LookupPatchMeta) ([]byte, []byte, []byte, []byte) {
  6294  	expectedResult := c.TwoWayResult
  6295  	if expectedResult == nil {
  6296  		expectedResult = c.Modified
  6297  	}
  6298  	return sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Original), c.Description, schema),
  6299  		sortJsonOrFail(t, testObjectToJSONOrFail(t, c.TwoWay), c.Description, schema),
  6300  		sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Modified), c.Description, schema),
  6301  		sortJsonOrFail(t, testObjectToJSONOrFail(t, expectedResult), c.Description, schema)
  6302  }
  6303  
  6304  func twoWayRawTestCaseToJSONOrFail(t *testing.T, c StrategicMergePatchRawTestCase) ([]byte, []byte, []byte, []byte) {
  6305  	expectedResult := c.TwoWayResult
  6306  	if expectedResult == nil {
  6307  		expectedResult = c.Modified
  6308  	}
  6309  	return yamlToJSONOrError(t, c.Original),
  6310  		yamlToJSONOrError(t, c.TwoWay),
  6311  		yamlToJSONOrError(t, c.Modified),
  6312  		yamlToJSONOrError(t, expectedResult)
  6313  }
  6314  
  6315  func testThreeWayPatch(t *testing.T, c StrategicMergePatchTestCase, schema LookupPatchMeta) {
  6316  	original, modified, current, expected, result := threeWayTestCaseToJSONOrFail(t, c, schema)
  6317  	actual, err := CreateThreeWayMergePatch(original, modified, current, schema, false)
  6318  	if err != nil {
  6319  		if !mergepatch.IsConflict(err) {
  6320  			t.Errorf("using %s error: %s\nin test case: %s\ncannot create three way patch:\n%s\n",
  6321  				getSchemaType(schema), err, c.Description, mergepatch.ToYAMLOrError(c.StrategicMergePatchTestCaseData))
  6322  			return
  6323  		}
  6324  
  6325  		if !strings.Contains(c.Description, "conflict") {
  6326  			t.Errorf("using %s unexpected conflict: %s\nin test case: %s\ncannot create three way patch:\n%s\n",
  6327  				getSchemaType(schema), err, c.Description, mergepatch.ToYAMLOrError(c.StrategicMergePatchTestCaseData))
  6328  			return
  6329  		}
  6330  
  6331  		if len(c.Result) > 0 {
  6332  			actual, err := CreateThreeWayMergePatch(original, modified, current, schema, true)
  6333  			if err != nil {
  6334  				t.Errorf("using %s error: %s\nin test case: %s\ncannot force three way patch application:\n%s\n",
  6335  					getSchemaType(schema), err, c.Description, mergepatch.ToYAMLOrError(c.StrategicMergePatchTestCaseData))
  6336  				return
  6337  			}
  6338  
  6339  			testPatchCreation(t, expected, actual, c.Description)
  6340  			testPatchApplication(t, current, actual, result, c.Description, "", schema)
  6341  		}
  6342  
  6343  		return
  6344  	}
  6345  
  6346  	if strings.Contains(c.Description, "conflict") || len(c.Result) < 1 {
  6347  		t.Errorf("using %s error in test case: %s\nexpected conflict did not occur:\n%s\n",
  6348  			getSchemaType(schema), c.Description, mergepatch.ToYAMLOrError(c.StrategicMergePatchTestCaseData))
  6349  		return
  6350  	}
  6351  
  6352  	testPatchCreation(t, expected, actual, c.Description)
  6353  	testPatchApplication(t, current, actual, result, c.Description, "", schema)
  6354  }
  6355  
  6356  func testThreeWayPatchForRawTestCase(t *testing.T, c StrategicMergePatchRawTestCase, schema LookupPatchMeta) {
  6357  	original, modified, current, expected, result := threeWayRawTestCaseToJSONOrFail(t, c)
  6358  	actual, err := CreateThreeWayMergePatch(original, modified, current, schema, false)
  6359  	if err != nil {
  6360  		if !mergepatch.IsConflict(err) {
  6361  			t.Errorf("using %s error: %s\nin test case: %s\ncannot create three way patch:\noriginal:%s\ntwoWay:%s\nmodified:%s\ncurrent:%s\nthreeWay:%s\nresult:%s\n",
  6362  				getSchemaType(schema), err, c.Description, c.Original, c.TwoWay, c.Modified, c.Current, c.ThreeWay, c.Result)
  6363  			return
  6364  		}
  6365  
  6366  		if !strings.Contains(c.Description, "conflict") {
  6367  			t.Errorf("using %s unexpected conflict: %s\nin test case: %s\ncannot create three way patch:\noriginal:%s\ntwoWay:%s\nmodified:%s\ncurrent:%s\nthreeWay:%s\nresult:%s\n",
  6368  				getSchemaType(schema), err, c.Description, c.Original, c.TwoWay, c.Modified, c.Current, c.ThreeWay, c.Result)
  6369  			return
  6370  		}
  6371  
  6372  		if len(c.Result) > 0 {
  6373  			actual, err := CreateThreeWayMergePatch(original, modified, current, schema, true)
  6374  			if err != nil {
  6375  				t.Errorf("using %s error: %s\nin test case: %s\ncannot force three way patch application:\noriginal:%s\ntwoWay:%s\nmodified:%s\ncurrent:%s\nthreeWay:%s\nresult:%s\n",
  6376  					getSchemaType(schema), err, c.Description, c.Original, c.TwoWay, c.Modified, c.Current, c.ThreeWay, c.Result)
  6377  				return
  6378  			}
  6379  
  6380  			testPatchCreation(t, expected, actual, c.Description)
  6381  			testPatchApplication(t, current, actual, result, c.Description, c.ExpectedError, schema)
  6382  		}
  6383  
  6384  		return
  6385  	}
  6386  
  6387  	if strings.Contains(c.Description, "conflict") || len(c.Result) < 1 {
  6388  		t.Errorf("using %s error: %s\nin test case: %s\nexpected conflict did not occur:\noriginal:%s\ntwoWay:%s\nmodified:%s\ncurrent:%s\nthreeWay:%s\nresult:%s\n",
  6389  			getSchemaType(schema), err, c.Description, c.Original, c.TwoWay, c.Modified, c.Current, c.ThreeWay, c.Result)
  6390  		return
  6391  	}
  6392  
  6393  	testPatchCreation(t, expected, actual, c.Description)
  6394  	testPatchApplication(t, current, actual, result, c.Description, c.ExpectedError, schema)
  6395  }
  6396  
  6397  func threeWayTestCaseToJSONOrFail(t *testing.T, c StrategicMergePatchTestCase, schema LookupPatchMeta) ([]byte, []byte, []byte, []byte, []byte) {
  6398  	return sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Original), c.Description, schema),
  6399  		sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Modified), c.Description, schema),
  6400  		sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Current), c.Description, schema),
  6401  		sortJsonOrFail(t, testObjectToJSONOrFail(t, c.ThreeWay), c.Description, schema),
  6402  		sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Result), c.Description, schema)
  6403  }
  6404  
  6405  func threeWayRawTestCaseToJSONOrFail(t *testing.T, c StrategicMergePatchRawTestCase) ([]byte, []byte, []byte, []byte, []byte) {
  6406  	return yamlToJSONOrError(t, c.Original),
  6407  		yamlToJSONOrError(t, c.Modified),
  6408  		yamlToJSONOrError(t, c.Current),
  6409  		yamlToJSONOrError(t, c.ThreeWay),
  6410  		yamlToJSONOrError(t, c.Result)
  6411  }
  6412  
  6413  func testPatchCreation(t *testing.T, expected, actual []byte, description string) {
  6414  	if !reflect.DeepEqual(actual, expected) {
  6415  		t.Errorf("error in test case: %s\nexpected patch:\n%s\ngot:\n%s\n",
  6416  			description, jsonToYAMLOrError(expected), jsonToYAMLOrError(actual))
  6417  		return
  6418  	}
  6419  }
  6420  
  6421  func testPatchApplication(t *testing.T, original, patch, expected []byte, description, expectedError string, schema LookupPatchMeta) {
  6422  	result, err := StrategicMergePatchUsingLookupPatchMeta(original, patch, schema)
  6423  	if len(expectedError) != 0 {
  6424  		if err != nil && strings.Contains(err.Error(), expectedError) {
  6425  			return
  6426  		}
  6427  		t.Errorf("using %s expected error should contain:\n%s\nin test case: %s\nbut got:\n%s\n", getSchemaType(schema), expectedError, description, err)
  6428  	}
  6429  	if err != nil {
  6430  		t.Errorf("using %s error: %s\nin test case: %s\ncannot apply patch:\n%s\nto original:\n%s\n",
  6431  			getSchemaType(schema), err, description, jsonToYAMLOrError(patch), jsonToYAMLOrError(original))
  6432  		return
  6433  	}
  6434  
  6435  	if !reflect.DeepEqual(result, expected) {
  6436  		format := "using error in test case: %s\npatch application failed:\noriginal:\n%s\npatch:\n%s\nexpected:\n%s\ngot:\n%s\n"
  6437  		t.Errorf(format, description,
  6438  			jsonToYAMLOrError(original), jsonToYAMLOrError(patch),
  6439  			jsonToYAMLOrError(expected), jsonToYAMLOrError(result))
  6440  		return
  6441  	}
  6442  }
  6443  
  6444  func testObjectToJSONOrFail(t *testing.T, o map[string]interface{}) []byte {
  6445  	if o == nil {
  6446  		return nil
  6447  	}
  6448  
  6449  	j, err := toJSON(o)
  6450  	if err != nil {
  6451  		t.Error(err)
  6452  	}
  6453  	return j
  6454  }
  6455  
  6456  func sortJsonOrFail(t *testing.T, j []byte, description string, schema LookupPatchMeta) []byte {
  6457  	if j == nil {
  6458  		return nil
  6459  	}
  6460  	r, err := sortMergeListsByName(j, schema)
  6461  	if err != nil {
  6462  		t.Errorf("using %s error: %s\n in test case: %s\ncannot sort object:\n%s\n", getSchemaType(schema), err, description, j)
  6463  		return nil
  6464  	}
  6465  
  6466  	return r
  6467  }
  6468  
  6469  func getSchemaType(schema LookupPatchMeta) string {
  6470  	return reflect.TypeOf(schema).String()
  6471  }
  6472  
  6473  func jsonToYAMLOrError(j []byte) string {
  6474  	y, err := jsonToYAML(j)
  6475  	if err != nil {
  6476  		return err.Error()
  6477  	}
  6478  
  6479  	return string(y)
  6480  }
  6481  
  6482  func toJSON(v interface{}) ([]byte, error) {
  6483  	j, err := json.Marshal(v)
  6484  	if err != nil {
  6485  		return nil, fmt.Errorf("json marshal failed: %v\n%v\n", err, dump.Pretty(v))
  6486  	}
  6487  
  6488  	return j, nil
  6489  }
  6490  
  6491  func jsonToYAML(j []byte) ([]byte, error) {
  6492  	y, err := yaml.JSONToYAML(j)
  6493  	if err != nil {
  6494  		return nil, fmt.Errorf("json to yaml failed: %v\n%v\n", err, j)
  6495  	}
  6496  
  6497  	return y, nil
  6498  }
  6499  
  6500  func yamlToJSON(y []byte) ([]byte, error) {
  6501  	j, err := yaml.YAMLToJSON(y)
  6502  	if err != nil {
  6503  		return nil, fmt.Errorf("yaml to json failed: %v\n%v\n", err, y)
  6504  	}
  6505  
  6506  	return j, nil
  6507  }
  6508  
  6509  func yamlToJSONOrError(t *testing.T, y []byte) []byte {
  6510  	j, err := yamlToJSON(y)
  6511  	if err != nil {
  6512  		t.Errorf("%v", err)
  6513  	}
  6514  
  6515  	return j
  6516  }
  6517  
  6518  type PrecisionItem struct {
  6519  	Name    string  `json:"name,omitempty"`
  6520  	Int32   int32   `json:"int32,omitempty"`
  6521  	Int64   int64   `json:"int64,omitempty"`
  6522  	Float32 float32 `json:"float32,omitempty"`
  6523  	Float64 float64 `json:"float64,omitempty"`
  6524  }
  6525  
  6526  var (
  6527  	precisionItem             PrecisionItem
  6528  	precisionItemStructSchema = PatchMetaFromStruct{T: GetTagStructTypeOrDie(precisionItem)}
  6529  )
  6530  
  6531  func TestNumberConversion(t *testing.T) {
  6532  	testcases := map[string]struct {
  6533  		Old            string
  6534  		New            string
  6535  		ExpectedPatch  string
  6536  		ExpectedResult string
  6537  	}{
  6538  		"empty": {
  6539  			Old:            `{}`,
  6540  			New:            `{}`,
  6541  			ExpectedPatch:  `{}`,
  6542  			ExpectedResult: `{}`,
  6543  		},
  6544  		"int32 medium": {
  6545  			Old:            `{"int32":1000000}`,
  6546  			New:            `{"int32":1000000,"name":"newname"}`,
  6547  			ExpectedPatch:  `{"name":"newname"}`,
  6548  			ExpectedResult: `{"int32":1000000,"name":"newname"}`,
  6549  		},
  6550  		"int32 max": {
  6551  			Old:            `{"int32":2147483647}`,
  6552  			New:            `{"int32":2147483647,"name":"newname"}`,
  6553  			ExpectedPatch:  `{"name":"newname"}`,
  6554  			ExpectedResult: `{"int32":2147483647,"name":"newname"}`,
  6555  		},
  6556  		"int64 medium": {
  6557  			Old:            `{"int64":1000000}`,
  6558  			New:            `{"int64":1000000,"name":"newname"}`,
  6559  			ExpectedPatch:  `{"name":"newname"}`,
  6560  			ExpectedResult: `{"int64":1000000,"name":"newname"}`,
  6561  		},
  6562  		"int64 max": {
  6563  			Old:            `{"int64":9223372036854775807}`,
  6564  			New:            `{"int64":9223372036854775807,"name":"newname"}`,
  6565  			ExpectedPatch:  `{"name":"newname"}`,
  6566  			ExpectedResult: `{"int64":9223372036854775807,"name":"newname"}`,
  6567  		},
  6568  		"float32 max": {
  6569  			Old:            `{"float32":3.4028234663852886e+38}`,
  6570  			New:            `{"float32":3.4028234663852886e+38,"name":"newname"}`,
  6571  			ExpectedPatch:  `{"name":"newname"}`,
  6572  			ExpectedResult: `{"float32":3.4028234663852886e+38,"name":"newname"}`,
  6573  		},
  6574  		"float64 max": {
  6575  			Old:            `{"float64":1.7976931348623157e+308}`,
  6576  			New:            `{"float64":1.7976931348623157e+308,"name":"newname"}`,
  6577  			ExpectedPatch:  `{"name":"newname"}`,
  6578  			ExpectedResult: `{"float64":1.7976931348623157e+308,"name":"newname"}`,
  6579  		},
  6580  	}
  6581  
  6582  	precisionItemOpenapiSchema := PatchMetaFromOpenAPI{
  6583  		Schema: sptest.GetSchemaOrDie(&fakePrecisionItemSchema, "precisionItem"),
  6584  	}
  6585  	precisionItemOpenapiV3Schema := PatchMetaFromOpenAPIV3{
  6586  		SchemaList: fakePrecisionItemV3Schema.SchemaOrDie().Components.Schemas,
  6587  		Schema:     fakePrecisionItemV3Schema.SchemaOrDie().Components.Schemas["precisionItem"],
  6588  	}
  6589  	precisionItemSchemas := []LookupPatchMeta{
  6590  		precisionItemStructSchema,
  6591  		precisionItemOpenapiSchema,
  6592  		precisionItemOpenapiV3Schema,
  6593  	}
  6594  
  6595  	for _, schema := range precisionItemSchemas {
  6596  		for k, tc := range testcases {
  6597  			patch, err := CreateTwoWayMergePatchUsingLookupPatchMeta([]byte(tc.Old), []byte(tc.New), schema)
  6598  			if err != nil {
  6599  				t.Errorf("using %s in testcase %s: unexpected error %v", getSchemaType(schema), k, err)
  6600  				continue
  6601  			}
  6602  			if tc.ExpectedPatch != string(patch) {
  6603  				t.Errorf("using %s in testcase %s: expected %s, got %s", getSchemaType(schema), k, tc.ExpectedPatch, string(patch))
  6604  				continue
  6605  			}
  6606  
  6607  			result, err := StrategicMergePatchUsingLookupPatchMeta([]byte(tc.Old), patch, schema)
  6608  			if err != nil {
  6609  				t.Errorf("using %s in testcase %s: unexpected error %v", getSchemaType(schema), k, err)
  6610  				continue
  6611  			}
  6612  			if tc.ExpectedResult != string(result) {
  6613  				t.Errorf("using %s in testcase %s: expected %s, got %s", getSchemaType(schema), k, tc.ExpectedResult, string(result))
  6614  				continue
  6615  			}
  6616  		}
  6617  	}
  6618  }
  6619  
  6620  var replaceRawExtensionPatchTestCases = []StrategicMergePatchRawTestCase{
  6621  	{
  6622  		Description: "replace RawExtension field, rest unchanched",
  6623  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  6624  			Original: []byte(`
  6625  name: my-object
  6626  value: some-value
  6627  other: current-other
  6628  replacingItem:
  6629    Some: Generic
  6630    Yaml: Inside
  6631    The: RawExtension
  6632    Field: Period
  6633  `),
  6634  			Current: []byte(`
  6635  name: my-object
  6636  value: some-value
  6637  other: current-other
  6638  mergingList:
  6639    - name: 1
  6640    - name: 2
  6641    - name: 3
  6642  replacingItem:
  6643    Some: Generic
  6644    Yaml: Inside
  6645    The: RawExtension
  6646    Field: Period
  6647  `),
  6648  			Modified: []byte(`
  6649  name: my-object
  6650  value: some-value
  6651  other: current-other
  6652  mergingList:
  6653    - name: 1
  6654    - name: 2
  6655    - name: 3
  6656  replacingItem:
  6657    Newly: Modified
  6658    Yaml: Inside
  6659    The: RawExtension
  6660  `),
  6661  			TwoWay: []byte(`
  6662  mergingList:
  6663    - name: 1
  6664    - name: 2
  6665    - name: 3
  6666  replacingItem:
  6667    Newly: Modified
  6668    Yaml: Inside
  6669    The: RawExtension
  6670  `),
  6671  			TwoWayResult: []byte(`
  6672  name: my-object
  6673  value: some-value
  6674  other: current-other
  6675  mergingList:
  6676    - name: 1
  6677    - name: 2
  6678    - name: 3
  6679  replacingItem:
  6680    Newly: Modified
  6681    Yaml: Inside
  6682    The: RawExtension
  6683  `),
  6684  			ThreeWay: []byte(`
  6685  replacingItem:
  6686    Newly: Modified
  6687    Yaml: Inside
  6688    The: RawExtension
  6689  `),
  6690  			Result: []byte(`
  6691  name: my-object
  6692  value: some-value
  6693  other: current-other
  6694  mergingList:
  6695    - name: 1
  6696    - name: 2
  6697    - name: 3
  6698  replacingItem:
  6699    Newly: Modified
  6700    Yaml: Inside
  6701    The: RawExtension
  6702  `),
  6703  		},
  6704  	},
  6705  	{
  6706  		Description: "replace RawExtension field and merge list",
  6707  		StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{
  6708  			Original: []byte(`
  6709  name: my-object
  6710  value: some-value
  6711  other: current-other
  6712  mergingList:
  6713    - name: 1
  6714  replacingItem:
  6715    Some: Generic
  6716    Yaml: Inside
  6717    The: RawExtension
  6718    Field: Period
  6719  `),
  6720  			Current: []byte(`
  6721  name: my-object
  6722  value: some-value
  6723  other: current-other
  6724  mergingList:
  6725    - name: 1
  6726    - name: 3
  6727  replacingItem:
  6728    Some: Generic
  6729    Yaml: Inside
  6730    The: RawExtension
  6731    Field: Period
  6732  `),
  6733  			Modified: []byte(`
  6734  name: my-object
  6735  value: some-value
  6736  other: current-other
  6737  mergingList:
  6738    - name: 1
  6739    - name: 2
  6740  replacingItem:
  6741    Newly: Modified
  6742    Yaml: Inside
  6743    The: RawExtension
  6744  `),
  6745  			TwoWay: []byte(`
  6746  $setElementOrder/mergingList:
  6747    - name: 1
  6748    - name: 2
  6749  mergingList:
  6750    - name: 2
  6751  replacingItem:
  6752    Newly: Modified
  6753    Yaml: Inside
  6754    The: RawExtension
  6755  `),
  6756  			TwoWayResult: []byte(`
  6757  name: my-object
  6758  value: some-value
  6759  other: current-other
  6760  mergingList:
  6761    - name: 1
  6762    - name: 2
  6763  replacingItem:
  6764    Newly: Modified
  6765    Yaml: Inside
  6766    The: RawExtension
  6767  `),
  6768  			ThreeWay: []byte(`
  6769  $setElementOrder/mergingList:
  6770    - name: 1
  6771    - name: 2
  6772  mergingList:
  6773    - name: 2
  6774  replacingItem:
  6775    Newly: Modified
  6776    Yaml: Inside
  6777    The: RawExtension
  6778  `),
  6779  			Result: []byte(`
  6780  name: my-object
  6781  value: some-value
  6782  other: current-other
  6783  mergingList:
  6784    - name: 1
  6785    - name: 2
  6786    - name: 3
  6787  replacingItem:
  6788    Newly: Modified
  6789    Yaml: Inside
  6790    The: RawExtension
  6791  `),
  6792  		},
  6793  	},
  6794  }
  6795  
  6796  func TestReplaceWithRawExtension(t *testing.T) {
  6797  	mergeItemOpenapiSchema := PatchMetaFromOpenAPI{
  6798  		Schema: sptest.GetSchemaOrDie(&fakeMergeItemSchema, "mergeItem"),
  6799  	}
  6800  	mergeItemOpenapiV3Schema := PatchMetaFromOpenAPIV3{
  6801  		SchemaList: fakeMergeItemV3Schema.SchemaOrDie().Components.Schemas,
  6802  		Schema:     fakeMergeItemV3Schema.SchemaOrDie().Components.Schemas["mergeItem"],
  6803  	}
  6804  	schemas := []LookupPatchMeta{
  6805  		mergeItemStructSchema,
  6806  		mergeItemOpenapiSchema,
  6807  		mergeItemOpenapiV3Schema,
  6808  	}
  6809  
  6810  	for _, schema := range schemas {
  6811  		for _, c := range replaceRawExtensionPatchTestCases {
  6812  			testTwoWayPatchForRawTestCase(t, c, schema)
  6813  			testThreeWayPatchForRawTestCase(t, c, schema)
  6814  		}
  6815  	}
  6816  }
  6817  
  6818  func TestUnknownField(t *testing.T) {
  6819  	testcases := map[string]struct {
  6820  		Original string
  6821  		Current  string
  6822  		Modified string
  6823  
  6824  		ExpectedTwoWay         string
  6825  		ExpectedTwoWayErr      string
  6826  		ExpectedTwoWayResult   string
  6827  		ExpectedThreeWay       string
  6828  		ExpectedThreeWayErr    string
  6829  		ExpectedThreeWayResult string
  6830  	}{
  6831  		// cases we can successfully strategically merge
  6832  		"no diff": {
  6833  			Original: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6834  			Current:  `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6835  			Modified: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6836  
  6837  			ExpectedTwoWay:         `{}`,
  6838  			ExpectedTwoWayResult:   `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6839  			ExpectedThreeWay:       `{}`,
  6840  			ExpectedThreeWayResult: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6841  		},
  6842  		"no diff even if modified null": {
  6843  			Original: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6844  			Current:  `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6845  			Modified: `{"array":[1,2,3],"complex":{"nested":true},"complex_nullable":{"key":null},"name":"foo","scalar":true}`,
  6846  
  6847  			ExpectedTwoWay:         `{"complex_nullable":{"key":null}}`,
  6848  			ExpectedTwoWayResult:   `{"array":[1,2,3],"complex":{"nested":true},"complex_nullable":{},"name":"foo","scalar":true}`,
  6849  			ExpectedThreeWay:       `{"complex_nullable":{"key":null}}`,
  6850  			ExpectedThreeWayResult: `{"array":[1,2,3],"complex":{"nested":true},"complex_nullable":{},"name":"foo","scalar":true}`,
  6851  		},
  6852  		"discard nulls in nested and adds not nulls": {
  6853  			Original: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6854  			Current:  `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6855  			Modified: `{"array":[1,2,3],"complex":{"nested":true},"complex_nullable":{"key":{"keynotnull":"value","keynull":null}},"name":"foo","scalar":true}`,
  6856  
  6857  			ExpectedTwoWay:         `{"complex_nullable":{"key":{"keynotnull":"value","keynull":null}}}`,
  6858  			ExpectedTwoWayResult:   `{"array":[1,2,3],"complex":{"nested":true},"complex_nullable":{"key":{"keynotnull":"value"}},"name":"foo","scalar":true}`,
  6859  			ExpectedThreeWay:       `{"complex_nullable":{"key":{"keynotnull":"value","keynull":null}}}`,
  6860  			ExpectedThreeWayResult: `{"array":[1,2,3],"complex":{"nested":true},"complex_nullable":{"key":{"keynotnull":"value"}},"name":"foo","scalar":true}`,
  6861  		},
  6862  		"discard if modified all nulls": {
  6863  			Original: `{}`,
  6864  			Current:  `{}`,
  6865  			Modified: `{"complex":{"nested":null}}`,
  6866  
  6867  			ExpectedTwoWay:         `{"complex":{"nested":null}}`,
  6868  			ExpectedTwoWayResult:   `{"complex":{}}`,
  6869  			ExpectedThreeWay:       `{"complex":{"nested":null}}`,
  6870  			ExpectedThreeWayResult: `{"complex":{}}`,
  6871  		},
  6872  		"add only not nulls": {
  6873  			Original: `{}`,
  6874  			Current:  `{}`,
  6875  			Modified: `{"complex":{"nested":null,"nested2":"foo"}}`,
  6876  
  6877  			ExpectedTwoWay:         `{"complex":{"nested":null,"nested2":"foo"}}`,
  6878  			ExpectedTwoWayResult:   `{"complex":{"nested2":"foo"}}`,
  6879  			ExpectedThreeWay:       `{"complex":{"nested":null,"nested2":"foo"}}`,
  6880  			ExpectedThreeWayResult: `{"complex":{"nested2":"foo"}}`,
  6881  		},
  6882  		"null values in original are preserved": {
  6883  			Original: `{"thing":null}`,
  6884  			Current:  `{"thing":null}`,
  6885  			Modified: `{"nested":{"value":5},"thing":null}`,
  6886  
  6887  			ExpectedTwoWay:         `{"nested":{"value":5}}`,
  6888  			ExpectedTwoWayResult:   `{"nested":{"value":5},"thing":null}`,
  6889  			ExpectedThreeWay:       `{"nested":{"value":5}}`,
  6890  			ExpectedThreeWayResult: `{"nested":{"value":5},"thing":null}`,
  6891  		},
  6892  		"nested null values in original are preserved": {
  6893  			Original: `{"complex":{"key":null},"thing":null}`,
  6894  			Current:  `{"complex":{"key":null},"thing":null}`,
  6895  			Modified: `{"complex":{"key":null},"nested":{"value":5},"thing":null}`,
  6896  
  6897  			ExpectedTwoWay:         `{"nested":{"value":5}}`,
  6898  			ExpectedTwoWayResult:   `{"complex":{"key":null},"nested":{"value":5},"thing":null}`,
  6899  			ExpectedThreeWay:       `{"nested":{"value":5}}`,
  6900  			ExpectedThreeWayResult: `{"complex":{"key":null},"nested":{"value":5},"thing":null}`,
  6901  		},
  6902  		"add empty slices": {
  6903  			Original: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6904  			Current:  `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6905  			Modified: `{"array":[1,2,3],"complex":{"nested":true},"complex_nullable":[],"name":"foo","scalar":true}`,
  6906  
  6907  			ExpectedTwoWay:         `{"complex_nullable":[]}`,
  6908  			ExpectedTwoWayResult:   `{"array":[1,2,3],"complex":{"nested":true},"complex_nullable":[],"name":"foo","scalar":true}`,
  6909  			ExpectedThreeWay:       `{"complex_nullable":[]}`,
  6910  			ExpectedThreeWayResult: `{"array":[1,2,3],"complex":{"nested":true},"complex_nullable":[],"name":"foo","scalar":true}`,
  6911  		},
  6912  		"filter nulls from nested slices": {
  6913  			Original: `{}`,
  6914  			Current:  `{}`,
  6915  			Modified: `{"complex_nullable":[{"inner_one":{"key_one":"foo","key_two":null}}]}`,
  6916  
  6917  			ExpectedTwoWay:         `{"complex_nullable":[{"inner_one":{"key_one":"foo","key_two":null}}]}`,
  6918  			ExpectedTwoWayResult:   `{"complex_nullable":[{"inner_one":{"key_one":"foo"}}]}`,
  6919  			ExpectedThreeWay:       `{"complex_nullable":[{"inner_one":{"key_one":"foo","key_two":null}}]}`,
  6920  			ExpectedThreeWayResult: `{"complex_nullable":[{"inner_one":{"key_one":"foo"}}]}`,
  6921  		},
  6922  		"filter if slice is all empty": {
  6923  			Original: `{}`,
  6924  			Current:  `{}`,
  6925  			Modified: `{"complex_nullable":[{"inner_one":{"key_one":null,"key_two":null}}]}`,
  6926  
  6927  			ExpectedTwoWay:         `{"complex_nullable":[{"inner_one":{"key_one":null,"key_two":null}}]}`,
  6928  			ExpectedTwoWayResult:   `{"complex_nullable":[{"inner_one":{}}]}`,
  6929  			ExpectedThreeWay:       `{"complex_nullable":[{"inner_one":{"key_one":null,"key_two":null}}]}`,
  6930  			ExpectedThreeWayResult: `{"complex_nullable":[{"inner_one":{}}]}`,
  6931  		},
  6932  		"not filter nulls from non-associative slice": {
  6933  			Original: `{}`,
  6934  			Current:  `{}`,
  6935  			Modified: `{"complex_nullable":["key1",null,"key2"]}`,
  6936  
  6937  			ExpectedTwoWay:         `{"complex_nullable":["key1",null,"key2"]}`,
  6938  			ExpectedTwoWayResult:   `{"complex_nullable":["key1",null,"key2"]}`,
  6939  			ExpectedThreeWay:       `{"complex_nullable":["key1",null,"key2"]}`,
  6940  			ExpectedThreeWayResult: `{"complex_nullable":["key1",null,"key2"]}`,
  6941  		},
  6942  		"added only": {
  6943  			Original: `{"name":"foo"}`,
  6944  			Current:  `{"name":"foo"}`,
  6945  			Modified: `{"name":"foo","scalar":true,"complex":{"nested":true},"array":[1,2,3]}`,
  6946  
  6947  			ExpectedTwoWay:         `{"array":[1,2,3],"complex":{"nested":true},"scalar":true}`,
  6948  			ExpectedTwoWayResult:   `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6949  			ExpectedThreeWay:       `{"array":[1,2,3],"complex":{"nested":true},"scalar":true}`,
  6950  			ExpectedThreeWayResult: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6951  		},
  6952  		"removed only": {
  6953  			Original: `{"name":"foo","scalar":true,"complex":{"nested":true}}`,
  6954  			Current:  `{"name":"foo","scalar":true,"complex":{"nested":true},"array":[1,2,3]}`,
  6955  			Modified: `{"name":"foo"}`,
  6956  
  6957  			ExpectedTwoWay:         `{"complex":null,"scalar":null}`,
  6958  			ExpectedTwoWayResult:   `{"name":"foo"}`,
  6959  			ExpectedThreeWay:       `{"complex":null,"scalar":null}`,
  6960  			ExpectedThreeWayResult: `{"array":[1,2,3],"name":"foo"}`,
  6961  		},
  6962  
  6963  		// cases we cannot successfully strategically merge (expect errors)
  6964  		"diff": {
  6965  			Original: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6966  			Current:  `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`,
  6967  			Modified: `{"array":[1,2,3],"complex":{"nested":false},"name":"foo","scalar":true}`,
  6968  
  6969  			ExpectedTwoWayErr:   `unable to find api field`,
  6970  			ExpectedThreeWayErr: `unable to find api field`,
  6971  		},
  6972  	}
  6973  
  6974  	mergeItemOpenapiSchema := PatchMetaFromOpenAPI{
  6975  		Schema: sptest.GetSchemaOrDie(&fakeMergeItemSchema, "mergeItem"),
  6976  	}
  6977  	mergeItemOpenapiV3Schema := PatchMetaFromOpenAPIV3{
  6978  		SchemaList: fakeMergeItemV3Schema.SchemaOrDie().Components.Schemas,
  6979  		Schema:     fakeMergeItemV3Schema.SchemaOrDie().Components.Schemas["mergeItem"],
  6980  	}
  6981  	schemas := []LookupPatchMeta{
  6982  		mergeItemStructSchema,
  6983  		mergeItemOpenapiSchema,
  6984  		mergeItemOpenapiV3Schema,
  6985  	}
  6986  
  6987  	for _, k := range sets.StringKeySet(testcases).List() {
  6988  		t.Run(k, func(t *testing.T) {
  6989  			tc := testcases[k]
  6990  			for _, schema := range schemas {
  6991  				t.Run(schema.Name()+"/TwoWay", func(t *testing.T) {
  6992  					twoWay, err := CreateTwoWayMergePatchUsingLookupPatchMeta([]byte(tc.Original), []byte(tc.Modified), schema)
  6993  					if err != nil {
  6994  						if len(tc.ExpectedTwoWayErr) == 0 {
  6995  							t.Errorf("using %s in testcase %s: error making two-way patch: %v", getSchemaType(schema), k, err)
  6996  						}
  6997  						if !strings.Contains(err.Error(), tc.ExpectedTwoWayErr) {
  6998  							t.Errorf("using %s in testcase %s: expected error making two-way patch to contain '%s', got %s", getSchemaType(schema), k, tc.ExpectedTwoWayErr, err)
  6999  						}
  7000  						return
  7001  					}
  7002  
  7003  					if string(twoWay) != tc.ExpectedTwoWay {
  7004  						t.Errorf("using %s in testcase %s: expected two-way patch:\n\t%s\ngot\n\t%s", getSchemaType(schema), k, string(tc.ExpectedTwoWay), string(twoWay))
  7005  						return
  7006  					}
  7007  
  7008  					twoWayResult, err := StrategicMergePatchUsingLookupPatchMeta([]byte(tc.Original), twoWay, schema)
  7009  					if err != nil {
  7010  						t.Errorf("using %s in testcase %s: error applying two-way patch: %v", getSchemaType(schema), k, err)
  7011  						return
  7012  					}
  7013  					if string(twoWayResult) != tc.ExpectedTwoWayResult {
  7014  						t.Errorf("using %s in testcase %s: expected two-way result:\n\t%s\ngot\n\t%s", getSchemaType(schema), k, string(tc.ExpectedTwoWayResult), string(twoWayResult))
  7015  						return
  7016  					}
  7017  				})
  7018  
  7019  				t.Run(schema.Name()+"/ThreeWay", func(t *testing.T) {
  7020  					threeWay, err := CreateThreeWayMergePatch([]byte(tc.Original), []byte(tc.Modified), []byte(tc.Current), schema, false)
  7021  					if err != nil {
  7022  						if len(tc.ExpectedThreeWayErr) == 0 {
  7023  							t.Errorf("using %s in testcase %s: error making three-way patch: %v", getSchemaType(schema), k, err)
  7024  						} else if !strings.Contains(err.Error(), tc.ExpectedThreeWayErr) {
  7025  							t.Errorf("using %s in testcase %s: expected error making three-way patch to contain '%s', got %s", getSchemaType(schema), k, tc.ExpectedThreeWayErr, err)
  7026  						}
  7027  						return
  7028  					}
  7029  
  7030  					if string(threeWay) != tc.ExpectedThreeWay {
  7031  						t.Errorf("using %s in testcase %s: expected three-way patch:\n\t%s\ngot\n\t%s", getSchemaType(schema), k, string(tc.ExpectedThreeWay), string(threeWay))
  7032  						return
  7033  					}
  7034  
  7035  					threeWayResult, err := StrategicMergePatch([]byte(tc.Current), threeWay, schema)
  7036  					if err != nil {
  7037  						t.Errorf("using %s in testcase %s: error applying three-way patch: %v", getSchemaType(schema), k, err)
  7038  						return
  7039  					} else if string(threeWayResult) != tc.ExpectedThreeWayResult {
  7040  						t.Errorf("using %s in testcase %s: expected three-way result:\n\t%s\ngot\n\t%s", getSchemaType(schema), k, string(tc.ExpectedThreeWayResult), string(threeWayResult))
  7041  						return
  7042  					}
  7043  				})
  7044  			}
  7045  		})
  7046  	}
  7047  }
  7048  

View as plain text