github.com/avenga/couper@v1.12.2/eval/lib/merge_test.go (about)

     1  package lib_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/zclconf/go-cty/cty"
     7  
     8  	"github.com/avenga/couper/config/configload"
     9  	"github.com/avenga/couper/config/request"
    10  	"github.com/avenga/couper/eval"
    11  	"github.com/avenga/couper/internal/test"
    12  )
    13  
    14  func TestMerge(t *testing.T) {
    15  	helper := test.New(t)
    16  
    17  	cf, err := configload.LoadBytes([]byte(`server "test" {}`), "couper.hcl")
    18  	helper.Must(err)
    19  
    20  	hclContext := cf.Context.Value(request.ContextType).(*eval.Context).HCLContext()
    21  	mergeFn := hclContext.Functions["merge"]
    22  
    23  	tests := []struct {
    24  		name string
    25  		args []cty.Value
    26  		want cty.Value
    27  	}{
    28  		{
    29  			/*
    30  				merge(
    31  					{"k1": 1},
    32  					{"k2": {"k2.2": 2}},
    33  					{"k3": 3},
    34  					null,
    35  					{"k2": {"k4.2": 4}},
    36  					{"k3": 5},
    37  					{"k6": [6]},
    38  					null,
    39  					{"k6": ["7", true]},
    40  					{"k6": [null]},
    41  					{"k6": [8]},
    42  					{"k9": [9]},
    43  					{"k9": 10}
    44  				)
    45  			*/
    46  			"merge objects ignoring null arguments",
    47  			[]cty.Value{
    48  				cty.ObjectVal(map[string]cty.Value{
    49  					"k1": cty.NumberIntVal(1),
    50  				}),
    51  				cty.ObjectVal(map[string]cty.Value{
    52  					"k2": cty.ObjectVal(map[string]cty.Value{
    53  						"k2.2": cty.NumberIntVal(2),
    54  					}),
    55  				}),
    56  				cty.ObjectVal(map[string]cty.Value{
    57  					"k3": cty.NumberIntVal(3),
    58  				}),
    59  				cty.NullVal(cty.Bool),
    60  				cty.ObjectVal(map[string]cty.Value{
    61  					"k2": cty.MapVal(map[string]cty.Value{ // ähnlicher Typ -> mergen
    62  						"k4.2": cty.NumberIntVal(4),
    63  					}),
    64  				}),
    65  				cty.ObjectVal(map[string]cty.Value{
    66  					"k3": cty.NumberIntVal(5), // gleicher Typ, primitive -> überschreiben
    67  				}),
    68  				cty.ObjectVal(map[string]cty.Value{
    69  					"k6": cty.TupleVal([]cty.Value{
    70  						cty.NumberIntVal(6),
    71  					}),
    72  				}),
    73  				cty.NullVal(cty.Bool),
    74  				cty.ObjectVal(map[string]cty.Value{
    75  					"k6": cty.TupleVal([]cty.Value{ // gleicher Typ -> mergen
    76  						cty.StringVal("7"),
    77  						cty.BoolVal(true),
    78  					}),
    79  				}),
    80  				cty.ObjectVal(map[string]cty.Value{
    81  					"k6": cty.ListVal([]cty.Value{ // ähnlicher Typ -> mergen
    82  						cty.NullVal(cty.Bool),
    83  					}),
    84  				}),
    85  				cty.ObjectVal(map[string]cty.Value{
    86  					"k6": cty.ListVal([]cty.Value{ // ähnlicher Typ -> mergen
    87  						cty.NumberIntVal(8),
    88  					}),
    89  				}),
    90  				cty.ObjectVal(map[string]cty.Value{
    91  					"k9": cty.ListVal([]cty.Value{
    92  						cty.NumberIntVal(9),
    93  					}),
    94  				}),
    95  				cty.ObjectVal(map[string]cty.Value{
    96  					"k9": cty.NumberIntVal(10), // unterschiedlicher Typ -> überschreiben
    97  				}),
    98  			},
    99  			/*
   100  				{
   101  				  "k1": 1,
   102  				  "k2": {"k2.2": 2, "k4.2": 4},
   103  				  "k3": 5,
   104  				  "k6": [6, "7", true, null, 8],
   105  				  "k9": 10
   106  				}
   107  			*/
   108  			cty.ObjectVal(map[string]cty.Value{
   109  				"k1": cty.NumberIntVal(1),
   110  				"k2": cty.ObjectVal(map[string]cty.Value{
   111  					"k2.2": cty.NumberIntVal(2),
   112  					"k4.2": cty.NumberIntVal(4),
   113  				}),
   114  				"k3": cty.NumberIntVal(5),
   115  				"k6": cty.TupleVal([]cty.Value{
   116  					cty.NumberIntVal(6),
   117  					cty.StringVal("7"),
   118  					cty.BoolVal(true),
   119  					cty.NullVal(cty.Bool),
   120  					cty.NumberIntVal(8),
   121  				}),
   122  				"k9": cty.NumberIntVal(10),
   123  			}),
   124  		},
   125  		{
   126  			/*
   127  				merge(
   128  					{"k1": 1}
   129  				)
   130  			*/
   131  			"merge with only one object",
   132  			[]cty.Value{
   133  				cty.ObjectVal(map[string]cty.Value{
   134  					"k1": cty.NumberIntVal(1),
   135  				}),
   136  			},
   137  			/*
   138  				{
   139  				  "k1": 1
   140  				}
   141  			*/
   142  			cty.ObjectVal(map[string]cty.Value{
   143  				"k1": cty.NumberIntVal(1),
   144  			}),
   145  		},
   146  		{
   147  			/*
   148  				merge(
   149  					{"k2": {"k2.2": 2}},
   150  					{"k0": null},
   151  					{"k2": {"k4.2": 4}},
   152  					{"k2": {"k4.0": null}}
   153  				)
   154  			*/
   155  			"merge objects with null",
   156  			[]cty.Value{
   157  				cty.ObjectVal(map[string]cty.Value{
   158  					"k2": cty.ObjectVal(map[string]cty.Value{
   159  						"k2.2": cty.NumberIntVal(2),
   160  					}),
   161  				}),
   162  				cty.ObjectVal(map[string]cty.Value{
   163  					"k0": cty.NullVal(cty.Bool),
   164  				}),
   165  				cty.ObjectVal(map[string]cty.Value{
   166  					"k2": cty.MapVal(map[string]cty.Value{
   167  						"k4.2": cty.NumberIntVal(4),
   168  					}),
   169  				}),
   170  				cty.ObjectVal(map[string]cty.Value{
   171  					"k2": cty.MapVal(map[string]cty.Value{
   172  						"k4.0": cty.NullVal(cty.Bool),
   173  					}),
   174  				}),
   175  			},
   176  			/*
   177  				{
   178  				  "k0": null,
   179  				  "k2": {"k4.2": 4}
   180  				}
   181  			*/
   182  			cty.ObjectVal(map[string]cty.Value{
   183  				"k0": cty.NullVal(cty.Bool),
   184  				"k2": cty.ObjectVal(map[string]cty.Value{
   185  					"k2.2": cty.NumberIntVal(2),
   186  					"k4.2": cty.NumberIntVal(4),
   187  					"k4.0": cty.NullVal(cty.Bool),
   188  				}),
   189  			}),
   190  		},
   191  		{
   192  			/*
   193  				merge(
   194  					[1],
   195  					null,
   196  					["2"],
   197  					[true],
   198  					null,
   199  					[{"k": 4}],
   200  					[[5]]
   201  				)
   202  			*/
   203  			"merge tuples ignoring null arguments",
   204  			[]cty.Value{
   205  				cty.TupleVal([]cty.Value{
   206  					cty.NumberIntVal(1),
   207  				}),
   208  				cty.NullVal(cty.Bool),
   209  				cty.TupleVal([]cty.Value{
   210  					cty.StringVal("2"),
   211  				}),
   212  				cty.ListVal([]cty.Value{
   213  					cty.BoolVal(true),
   214  				}),
   215  				cty.NullVal(cty.Bool),
   216  				cty.TupleVal([]cty.Value{
   217  					cty.ObjectVal(map[string]cty.Value{
   218  						"k": cty.NumberIntVal(4),
   219  					}),
   220  				}),
   221  				cty.TupleVal([]cty.Value{
   222  					cty.TupleVal([]cty.Value{
   223  						cty.NumberIntVal(5),
   224  					}),
   225  				}),
   226  			},
   227  			/*
   228  				[
   229  				  1,
   230  				  "2",
   231  				  true,
   232  				  {"k": 4},
   233  				  [5]
   234  				]
   235  			*/
   236  			cty.TupleVal([]cty.Value{
   237  				cty.NumberIntVal(1),
   238  				cty.StringVal("2"),
   239  				cty.BoolVal(true),
   240  				cty.ObjectVal(map[string]cty.Value{
   241  					"k": cty.NumberIntVal(4),
   242  				}),
   243  				cty.TupleVal([]cty.Value{
   244  					cty.NumberIntVal(5),
   245  				}),
   246  			}),
   247  		},
   248  		{
   249  			/*
   250  				merge(
   251  					[1]
   252  				)
   253  			*/
   254  			"merge with only one tuple",
   255  			[]cty.Value{
   256  				cty.TupleVal([]cty.Value{
   257  					cty.NumberIntVal(1),
   258  				}),
   259  			},
   260  			/*
   261  				[
   262  				  1
   263  				]
   264  			*/
   265  			cty.TupleVal([]cty.Value{
   266  				cty.NumberIntVal(1),
   267  			}),
   268  		},
   269  		{
   270  			/*
   271  				merge()
   272  			*/
   273  			"merge without parameters",
   274  			[]cty.Value{},
   275  			/* null */
   276  			cty.NullVal(cty.Bool),
   277  		},
   278  	}
   279  
   280  	for _, tt := range tests {
   281  		t.Run(tt.name, func(subT *testing.T) {
   282  			h := test.New(subT)
   283  
   284  			mergedV, merr := mergeFn.Call(tt.args)
   285  			h.Must(merr)
   286  			if !mergedV.RawEquals(tt.want) {
   287  				subT.Errorf("Wrong return value:\nwant:\t%#v\ngot:\t%#v\n", tt.want, mergedV)
   288  			}
   289  		})
   290  	}
   291  }
   292  
   293  func TestMergeErrors(t *testing.T) {
   294  	helper := test.New(t)
   295  
   296  	cf, err := configload.LoadBytes([]byte(`server "test" {}`), "couper.hcl")
   297  	helper.Must(err)
   298  
   299  	tests := []struct {
   300  		name    string
   301  		args    []cty.Value
   302  		wantErr string
   303  	}{
   304  		{
   305  			/*
   306  				merge(
   307  					{"k1": 1},
   308  					true,
   309  					{"k3": 3},
   310  				)
   311  			*/
   312  			"mix objects with bool",
   313  			[]cty.Value{
   314  				cty.ObjectVal(map[string]cty.Value{
   315  					"k1": cty.NumberIntVal(1),
   316  				}),
   317  				cty.BoolVal(true),
   318  				cty.ObjectVal(map[string]cty.Value{
   319  					"k3": cty.NumberIntVal(3),
   320  				}),
   321  			},
   322  			"cannot merge primitive value",
   323  		},
   324  		{
   325  			/*
   326  				merge(
   327  					{"k1": 1},
   328  					2,
   329  					{"k3": 3},
   330  				)
   331  			*/
   332  			"mix objects with integer",
   333  			[]cty.Value{
   334  				cty.ObjectVal(map[string]cty.Value{
   335  					"k1": cty.NumberIntVal(1),
   336  				}),
   337  				cty.NumberIntVal(2),
   338  				cty.ObjectVal(map[string]cty.Value{
   339  					"k3": cty.NumberIntVal(3),
   340  				}),
   341  			},
   342  			"cannot merge primitive value",
   343  		},
   344  		{
   345  			/*
   346  				merge(
   347  					{"k1": 1},
   348  					"2",
   349  					{"k3": 3},
   350  				)
   351  			*/
   352  			"mix objects with string",
   353  			[]cty.Value{
   354  				cty.ObjectVal(map[string]cty.Value{
   355  					"k1": cty.NumberIntVal(1),
   356  				}),
   357  				cty.StringVal("2"),
   358  				cty.ObjectVal(map[string]cty.Value{
   359  					"k3": cty.NumberIntVal(3),
   360  				}),
   361  			},
   362  			"cannot merge primitive value",
   363  		},
   364  		{
   365  			/*
   366  				merge(
   367  					["1"],
   368  					true,
   369  					["3"],
   370  				)
   371  			*/
   372  			"mix tuples with bool",
   373  			[]cty.Value{
   374  				cty.TupleVal([]cty.Value{
   375  					cty.StringVal("1"),
   376  				}),
   377  				cty.BoolVal(true),
   378  				cty.TupleVal([]cty.Value{
   379  					cty.StringVal("3"),
   380  				}),
   381  			},
   382  			"cannot merge primitive value",
   383  		},
   384  		{
   385  			/*
   386  				merge(
   387  					["1"],
   388  					2,
   389  					["3"],
   390  				)
   391  			*/
   392  			"mix tuples with integer",
   393  			[]cty.Value{
   394  				cty.TupleVal([]cty.Value{
   395  					cty.StringVal("1"),
   396  				}),
   397  				cty.NumberIntVal(2),
   398  				cty.TupleVal([]cty.Value{
   399  					cty.StringVal("3"),
   400  				}),
   401  			},
   402  			"cannot merge primitive value",
   403  		},
   404  		{
   405  			/*
   406  				merge(
   407  					["1"],
   408  					"2",
   409  					["3"],
   410  				)
   411  			*/
   412  			"mix tuples with string",
   413  			[]cty.Value{
   414  				cty.TupleVal([]cty.Value{
   415  					cty.StringVal("1"),
   416  				}),
   417  				cty.StringVal("2"),
   418  				cty.TupleVal([]cty.Value{
   419  					cty.StringVal("3"),
   420  				}),
   421  			},
   422  			"cannot merge primitive value",
   423  		},
   424  		{
   425  			/*
   426  				merge(
   427  					{"k1": 1},
   428  					["2"],
   429  					{"k3": 3},
   430  				)
   431  			*/
   432  			"mix objects with tuple",
   433  			[]cty.Value{
   434  				cty.ObjectVal(map[string]cty.Value{
   435  					"k1": cty.NumberIntVal(1),
   436  				}),
   437  				cty.TupleVal([]cty.Value{
   438  					cty.StringVal("2"),
   439  				}),
   440  				cty.ObjectVal(map[string]cty.Value{
   441  					"k3": cty.NumberIntVal(3),
   442  				}),
   443  			},
   444  			"type mismatch",
   445  		},
   446  		{
   447  			/*
   448  				merge(
   449  					["1"],
   450  					{"k2": 2},
   451  					["3"],
   452  				)
   453  			*/
   454  			"mix tuples with object",
   455  			[]cty.Value{
   456  				cty.TupleVal([]cty.Value{
   457  					cty.StringVal("1"),
   458  				}),
   459  				cty.ObjectVal(map[string]cty.Value{
   460  					"k2": cty.NumberIntVal(2),
   461  				}),
   462  				cty.TupleVal([]cty.Value{
   463  					cty.StringVal("3"),
   464  				}),
   465  			},
   466  			"type mismatch",
   467  		},
   468  	}
   469  
   470  	hclContext := cf.Context.Value(request.ContextType).(*eval.Context).HCLContext()
   471  
   472  	for _, tt := range tests {
   473  		t.Run(tt.name, func(subT *testing.T) {
   474  			_, err := hclContext.Functions["merge"].Call(tt.args)
   475  			if err == nil {
   476  				subT.Error("Error expected")
   477  			}
   478  			if err != nil && err.Error() != tt.wantErr {
   479  				subT.Errorf("Wrong error message; expected %#v, got: %#v", tt.wantErr, err.Error())
   480  			}
   481  		})
   482  	}
   483  }