github.com/zntrio/harp/v2@v2.0.9/pkg/sdk/flags/strvals/parser_test.go (about)

     1  // Licensed to Elasticsearch B.V. under one or more contributor
     2  // license agreements. See the NOTICE file distributed with
     3  // this work for additional information regarding copyright
     4  // ownership. Elasticsearch B.V. licenses this file to you under
     5  // the Apache License, Version 2.0 (the "License"); you may
     6  // not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing,
    12  // software distributed under the License is distributed on an
    13  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14  // KIND, either express or implied.  See the License for the
    15  // specific language governing permissions and limitations
    16  // under the License.
    17  
    18  package strvals
    19  
    20  import (
    21  	"bytes"
    22  	"testing"
    23  
    24  	"sigs.k8s.io/yaml"
    25  )
    26  
    27  func TestSetIndex(t *testing.T) {
    28  	tests := []struct {
    29  		name    string
    30  		initial []interface{}
    31  		expect  []interface{}
    32  		add     int
    33  		val     int
    34  	}{
    35  		{
    36  			name:    "short",
    37  			initial: []interface{}{0, 1},
    38  			expect:  []interface{}{0, 1, 2},
    39  			add:     2,
    40  			val:     2,
    41  		},
    42  		{
    43  			name:    "equal",
    44  			initial: []interface{}{0, 1},
    45  			expect:  []interface{}{0, 2},
    46  			add:     1,
    47  			val:     2,
    48  		},
    49  		{
    50  			name:    "long",
    51  			initial: []interface{}{0, 1, 2, 3, 4, 5},
    52  			expect:  []interface{}{0, 1, 2, 4, 4, 5},
    53  			add:     3,
    54  			val:     4,
    55  		},
    56  	}
    57  
    58  	for _, tt := range tests {
    59  		got := setIndex(tt.initial, tt.add, tt.val)
    60  		if len(got) != len(tt.expect) {
    61  			t.Fatalf("%s: Expected length %d, got %d", tt.name, len(tt.expect), len(got))
    62  		}
    63  
    64  		if gg := got[tt.add].(int); gg != tt.val {
    65  			t.Errorf("%s, Expected value %d, got %d", tt.name, tt.val, gg)
    66  		}
    67  	}
    68  }
    69  
    70  func TestParseSet(t *testing.T) {
    71  	testsString := []struct {
    72  		str    string
    73  		expect map[string]interface{}
    74  		err    bool
    75  	}{
    76  		{
    77  			str:    "long_int_string=1234567890",
    78  			expect: map[string]interface{}{"long_int_string": "1234567890"},
    79  			err:    false,
    80  		},
    81  		{
    82  			str:    "boolean=true",
    83  			expect: map[string]interface{}{"boolean": "true"},
    84  			err:    false,
    85  		},
    86  		{
    87  			str:    "is_null=null",
    88  			expect: map[string]interface{}{"is_null": "null"},
    89  			err:    false,
    90  		},
    91  		{
    92  			str:    "zero=0",
    93  			expect: map[string]interface{}{"zero": "0"},
    94  			err:    false,
    95  		},
    96  	}
    97  	tests := []struct {
    98  		str    string
    99  		expect map[string]interface{}
   100  		err    bool
   101  	}{
   102  		{
   103  			"name1=null,f=false,t=true",
   104  			map[string]interface{}{"name1": nil, "f": false, "t": true},
   105  			false,
   106  		},
   107  		{
   108  			"name1=value1",
   109  			map[string]interface{}{"name1": "value1"},
   110  			false,
   111  		},
   112  		{
   113  			"name1=value1,name2=value2",
   114  			map[string]interface{}{"name1": "value1", "name2": "value2"},
   115  			false,
   116  		},
   117  		{
   118  			"name1=value1,name2=value2,",
   119  			map[string]interface{}{"name1": "value1", "name2": "value2"},
   120  			false,
   121  		},
   122  		{
   123  			str: "name1=value1,,,,name2=value2,",
   124  			err: true,
   125  		},
   126  		{
   127  			str:    "name1=,name2=value2",
   128  			expect: map[string]interface{}{"name1": "", "name2": "value2"},
   129  		},
   130  		{
   131  			str:    "leading_zeros=00009",
   132  			expect: map[string]interface{}{"leading_zeros": "00009"},
   133  		},
   134  		{
   135  			str:    "zero_int=0",
   136  			expect: map[string]interface{}{"zero_int": 0},
   137  		},
   138  		{
   139  			str:    "long_int=1234567890",
   140  			expect: map[string]interface{}{"long_int": 1234567890},
   141  		},
   142  		{
   143  			str:    "boolean=true",
   144  			expect: map[string]interface{}{"boolean": true},
   145  		},
   146  		{
   147  			str:    "is_null=null",
   148  			expect: map[string]interface{}{"is_null": nil},
   149  			err:    false,
   150  		},
   151  		{
   152  			str: "name1,name2=",
   153  			err: true,
   154  		},
   155  		{
   156  			str: "name1,name2=value2",
   157  			err: true,
   158  		},
   159  		{
   160  			str: "name1,name2=value2\\",
   161  			err: true,
   162  		},
   163  		{
   164  			str: "name1,name2",
   165  			err: true,
   166  		},
   167  		{
   168  			"name1=one\\,two,name2=three\\,four",
   169  			map[string]interface{}{"name1": "one,two", "name2": "three,four"},
   170  			false,
   171  		},
   172  		{
   173  			"name1=one\\=two,name2=three\\=four",
   174  			map[string]interface{}{"name1": "one=two", "name2": "three=four"},
   175  			false,
   176  		},
   177  		{
   178  			"name1=one two three,name2=three two one",
   179  			map[string]interface{}{"name1": "one two three", "name2": "three two one"},
   180  			false,
   181  		},
   182  		{
   183  			"outer.inner=value",
   184  			map[string]interface{}{"outer": map[string]interface{}{"inner": "value"}},
   185  			false,
   186  		},
   187  		{
   188  			"outer.middle.inner=value",
   189  			map[string]interface{}{"outer": map[string]interface{}{"middle": map[string]interface{}{"inner": "value"}}},
   190  			false,
   191  		},
   192  		{
   193  			"outer.inner1=value,outer.inner2=value2",
   194  			map[string]interface{}{"outer": map[string]interface{}{"inner1": "value", "inner2": "value2"}},
   195  			false,
   196  		},
   197  		{
   198  			"outer.inner1=value,outer.middle.inner=value",
   199  			map[string]interface{}{
   200  				"outer": map[string]interface{}{
   201  					"inner1": "value",
   202  					"middle": map[string]interface{}{
   203  						"inner": "value",
   204  					},
   205  				},
   206  			},
   207  			false,
   208  		},
   209  		{
   210  			str: "name1.name2",
   211  			err: true,
   212  		},
   213  		{
   214  			str: "name1.name2,name1.name3",
   215  			err: true,
   216  		},
   217  		{
   218  			str:    "name1.name2=",
   219  			expect: map[string]interface{}{"name1": map[string]interface{}{"name2": ""}},
   220  		},
   221  		{
   222  			str: "name1.=name2",
   223  			err: true,
   224  		},
   225  		{
   226  			str: "name1.,name2",
   227  			err: true,
   228  		},
   229  		{
   230  			"name1={value1,value2}",
   231  			map[string]interface{}{"name1": []string{"value1", "value2"}},
   232  			false,
   233  		},
   234  		{
   235  			"name1={value1,value2},name2={value1,value2}",
   236  			map[string]interface{}{
   237  				"name1": []string{"value1", "value2"},
   238  				"name2": []string{"value1", "value2"},
   239  			},
   240  			false,
   241  		},
   242  		{
   243  			"name1={1021,902}",
   244  			map[string]interface{}{"name1": []int{1021, 902}},
   245  			false,
   246  		},
   247  		{
   248  			"name1.name2={value1,value2}",
   249  			map[string]interface{}{"name1": map[string]interface{}{"name2": []string{"value1", "value2"}}},
   250  			false,
   251  		},
   252  		{
   253  			str: "name1={1021,902",
   254  			err: true,
   255  		},
   256  		// List support
   257  		{
   258  			str:    "list[0]=foo",
   259  			expect: map[string]interface{}{"list": []string{"foo"}},
   260  		},
   261  		{
   262  			str: "list[0].foo=bar",
   263  			expect: map[string]interface{}{
   264  				"list": []interface{}{
   265  					map[string]interface{}{"foo": "bar"},
   266  				},
   267  			},
   268  		},
   269  		{
   270  			str: "list[0].foo=bar,list[0].hello=world",
   271  			expect: map[string]interface{}{
   272  				"list": []interface{}{
   273  					map[string]interface{}{"foo": "bar", "hello": "world"},
   274  				},
   275  			},
   276  		},
   277  		{
   278  			str:    "list[0]=foo,list[1]=bar",
   279  			expect: map[string]interface{}{"list": []string{"foo", "bar"}},
   280  		},
   281  		{
   282  			str:    "list[0]=foo,list[1]=bar,",
   283  			expect: map[string]interface{}{"list": []string{"foo", "bar"}},
   284  		},
   285  		{
   286  			str:    "list[0]=foo,list[3]=bar",
   287  			expect: map[string]interface{}{"list": []interface{}{"foo", nil, nil, "bar"}},
   288  		},
   289  		{
   290  			str: "illegal[0]name.foo=bar",
   291  			err: true,
   292  		},
   293  		{
   294  			str:    "noval[0]",
   295  			expect: map[string]interface{}{"noval": []interface{}{}},
   296  		},
   297  		{
   298  			str:    "noval[0]=",
   299  			expect: map[string]interface{}{"noval": []interface{}{""}},
   300  		},
   301  		{
   302  			str:    "nested[0][0]=1",
   303  			expect: map[string]interface{}{"nested": []interface{}{[]interface{}{1}}},
   304  		},
   305  		{
   306  			str:    "nested[1][1]=1",
   307  			expect: map[string]interface{}{"nested": []interface{}{nil, []interface{}{nil, 1}}},
   308  		},
   309  		{
   310  			str: "name1.name2[0].foo=bar,name1.name2[1].foo=bar",
   311  			expect: map[string]interface{}{
   312  				"name1": map[string]interface{}{
   313  					"name2": []map[string]interface{}{{"foo": "bar"}, {"foo": "bar"}},
   314  				},
   315  			},
   316  		},
   317  		{
   318  			str: "name1.name2[1].foo=bar,name1.name2[0].foo=bar",
   319  			expect: map[string]interface{}{
   320  				"name1": map[string]interface{}{
   321  					"name2": []map[string]interface{}{{"foo": "bar"}, {"foo": "bar"}},
   322  				},
   323  			},
   324  		},
   325  		{
   326  			str: "name1.name2[1].foo=bar",
   327  			expect: map[string]interface{}{
   328  				"name1": map[string]interface{}{
   329  					"name2": []map[string]interface{}{nil, {"foo": "bar"}},
   330  				},
   331  			},
   332  		},
   333  	}
   334  
   335  	for _, tt := range tests {
   336  		got, err := Parse(tt.str)
   337  		if err != nil {
   338  			if tt.err {
   339  				continue
   340  			}
   341  			t.Fatalf("%s: %s", tt.str, err)
   342  		}
   343  		if tt.err {
   344  			t.Errorf("%s: Expected error. Got nil", tt.str)
   345  		}
   346  
   347  		y1, err := yaml.Marshal(tt.expect)
   348  		if err != nil {
   349  			t.Fatal(err)
   350  		}
   351  		y2, err := yaml.Marshal(got)
   352  		if err != nil {
   353  			t.Fatalf("Error serializing parsed value: %s", err)
   354  		}
   355  
   356  		if !bytes.Equal(y1, y2) {
   357  			t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2)
   358  		}
   359  	}
   360  	for _, tt := range testsString {
   361  		got, err := ParseString(tt.str)
   362  		if err != nil {
   363  			if tt.err {
   364  				continue
   365  			}
   366  			t.Fatalf("%s: %s", tt.str, err)
   367  		}
   368  		if tt.err {
   369  			t.Errorf("%s: Expected error. Got nil", tt.str)
   370  		}
   371  
   372  		y1, err := yaml.Marshal(tt.expect)
   373  		if err != nil {
   374  			t.Fatal(err)
   375  		}
   376  		y2, err := yaml.Marshal(got)
   377  		if err != nil {
   378  			t.Fatalf("Error serializing parsed value: %s", err)
   379  		}
   380  
   381  		if !bytes.Equal(y1, y2) {
   382  			t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2)
   383  		}
   384  	}
   385  }
   386  
   387  func TestParseInto(t *testing.T) {
   388  	got := map[string]interface{}{
   389  		"outer": map[string]interface{}{
   390  			"inner1": "overwrite",
   391  			"inner2": "value2",
   392  		},
   393  	}
   394  	input := "outer.inner1=value1,outer.inner3=value3,outer.inner4=4"
   395  	expect := map[string]interface{}{
   396  		"outer": map[string]interface{}{
   397  			"inner1": "value1",
   398  			"inner2": "value2",
   399  			"inner3": "value3",
   400  			"inner4": 4,
   401  		},
   402  	}
   403  
   404  	if err := ParseInto(input, got); err != nil {
   405  		t.Fatal(err)
   406  	}
   407  
   408  	y1, err := yaml.Marshal(expect)
   409  	if err != nil {
   410  		t.Fatal(err)
   411  	}
   412  	y2, err := yaml.Marshal(got)
   413  	if err != nil {
   414  		t.Fatalf("Error serializing parsed value: %s", err)
   415  	}
   416  
   417  	if !bytes.Equal(y1, y2) {
   418  		t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2)
   419  	}
   420  }
   421  
   422  func TestParseIntoString(t *testing.T) {
   423  	got := map[string]interface{}{
   424  		"outer": map[string]interface{}{
   425  			"inner1": "overwrite",
   426  			"inner2": "value2",
   427  		},
   428  	}
   429  	input := "outer.inner1=1,outer.inner3=3"
   430  	expect := map[string]interface{}{
   431  		"outer": map[string]interface{}{
   432  			"inner1": "1",
   433  			"inner2": "value2",
   434  			"inner3": "3",
   435  		},
   436  	}
   437  
   438  	if err := ParseIntoString(input, got); err != nil {
   439  		t.Fatal(err)
   440  	}
   441  
   442  	y1, err := yaml.Marshal(expect)
   443  	if err != nil {
   444  		t.Fatal(err)
   445  	}
   446  	y2, err := yaml.Marshal(got)
   447  	if err != nil {
   448  		t.Fatalf("Error serializing parsed value: %s", err)
   449  	}
   450  
   451  	if !bytes.Equal(y1, y2) {
   452  		t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2)
   453  	}
   454  }
   455  
   456  func TestParseFile(t *testing.T) {
   457  	input := "name1=path1"
   458  	expect := map[string]interface{}{
   459  		"name1": "value1",
   460  	}
   461  	rs2v := func(rs []rune) (interface{}, error) {
   462  		v := string(rs)
   463  		if v != "path1" {
   464  			t.Errorf("%s: runesToVal: Expected value path1, got %s", input, v)
   465  			return "", nil
   466  		}
   467  		return "value1", nil
   468  	}
   469  
   470  	got, err := ParseFile(input, rs2v)
   471  	if err != nil {
   472  		t.Fatal(err)
   473  	}
   474  
   475  	y1, err := yaml.Marshal(expect)
   476  	if err != nil {
   477  		t.Fatal(err)
   478  	}
   479  	y2, err := yaml.Marshal(got)
   480  	if err != nil {
   481  		t.Fatalf("Error serializing parsed value: %s", err)
   482  	}
   483  
   484  	if !bytes.Equal(y1, y2) {
   485  		t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2)
   486  	}
   487  }
   488  
   489  func TestParseIntoFile(t *testing.T) {
   490  	got := map[string]interface{}{}
   491  	input := "name1=path1"
   492  	expect := map[string]interface{}{
   493  		"name1": "value1",
   494  	}
   495  	rs2v := func(rs []rune) (interface{}, error) {
   496  		v := string(rs)
   497  		if v != "path1" {
   498  			t.Errorf("%s: runesToVal: Expected value path1, got %s", input, v)
   499  			return "", nil
   500  		}
   501  		return "value1", nil
   502  	}
   503  
   504  	if err := ParseIntoFile(input, got, rs2v); err != nil {
   505  		t.Fatal(err)
   506  	}
   507  
   508  	y1, err := yaml.Marshal(expect)
   509  	if err != nil {
   510  		t.Fatal(err)
   511  	}
   512  	y2, err := yaml.Marshal(got)
   513  	if err != nil {
   514  		t.Fatalf("Error serializing parsed value: %s", err)
   515  	}
   516  
   517  	if !bytes.Equal(y1, y2) {
   518  		t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2)
   519  	}
   520  }
   521  
   522  func TestToYAML(t *testing.T) {
   523  	// The TestParse does the hard part. We just verify that YAML formatting is
   524  	// happening.
   525  	o, err := ToYAML("name=value")
   526  	if err != nil {
   527  		t.Fatal(err)
   528  	}
   529  	expect := "name: value"
   530  	if o != expect {
   531  		t.Errorf("Expected %q, got %q", expect, o)
   532  	}
   533  }