github.com/solo-io/cue@v0.4.7/cue/decode_test.go (about)

     1  // Copyright 2021 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cue
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  
    21  	"github.com/google/go-cmp/cmp"
    22  )
    23  
    24  func TestDecode(t *testing.T) {
    25  	type Nested struct {
    26  		P *int `json:"P"`
    27  	}
    28  	type fields struct {
    29  		A int `json:"A"`
    30  		B int `json:"B"`
    31  		C int `json:"C"`
    32  		M map[string]interface{}
    33  		*Nested
    34  	}
    35  	one := 1
    36  	intList := func(ints ...int) *[]int {
    37  		ints = append([]int{}, ints...)
    38  		return &ints
    39  	}
    40  	testCases := []struct {
    41  		value string
    42  		dst   interface{}
    43  		want  interface{}
    44  		err   string
    45  	}{{
    46  		// clear pointer
    47  		value: `null`,
    48  		dst:   &[]int{1},
    49  		want:  []int(nil),
    50  	}, {
    51  
    52  		value: `1`,
    53  		err:   "cannot decode into unsettable value",
    54  	}, {
    55  		dst:   new(interface{}),
    56  		value: `_|_`,
    57  		err:   "explicit error (_|_ literal) in source",
    58  	}, {
    59  		// clear pointer
    60  		value: `null`,
    61  		dst:   &[]int{1},
    62  		want:  []int(nil),
    63  	}, {
    64  		// clear pointer
    65  		value: `[null]`,
    66  		dst:   &[]*int{&one},
    67  		want:  []*int{nil},
    68  	}, {
    69  		value: `true`,
    70  		dst:   new(bool),
    71  		want:  true,
    72  	}, {
    73  		value: `false`,
    74  		dst:   new(bool),
    75  		want:  false,
    76  	}, {
    77  		value: `bool`,
    78  		dst:   new(bool),
    79  		err:   "cannot convert non-concrete value bool",
    80  	}, {
    81  		value: `_`,
    82  		dst:   new([]int),
    83  		want:  []int(nil),
    84  	}, {
    85  		value: `"str"`,
    86  		dst:   new(string),
    87  		want:  "str",
    88  	}, {
    89  		value: `"str"`,
    90  		dst:   new(int),
    91  		err:   "cannot use value \"str\" (type string) as int",
    92  	}, {
    93  		value: `'bytes'`,
    94  		dst:   new([]byte),
    95  		want:  []byte("bytes"),
    96  	}, {
    97  		value: `'bytes'`,
    98  		dst:   &[3]byte{},
    99  		want:  [3]byte{0x62, 0x79, 0x74},
   100  	}, {
   101  		value: `1`,
   102  		dst:   new(float32),
   103  		want:  float32(1),
   104  	}, {
   105  		value: `500`,
   106  		dst:   new(uint8),
   107  		err:   "integer 500 overflows uint8",
   108  	}, {
   109  		value: `501`,
   110  		dst:   new(int8),
   111  		err:   "integer 501 overflows int8",
   112  	}, {
   113  		value: `{}`,
   114  		dst:   &fields{},
   115  		want:  fields{},
   116  	}, {
   117  		value: `{A:1,b:2,c:3}`,
   118  		dst:   &fields{},
   119  		want:  fields{A: 1, B: 2, C: 3},
   120  	}, {
   121  		// allocate map
   122  		value: `{a:1,m:{a: 3}}`,
   123  		dst:   &fields{},
   124  		want: fields{A: 1,
   125  			M: map[string]interface{}{"a": int(3)}},
   126  	}, {
   127  		// indirect int
   128  		value: `{p: 1}`,
   129  		dst:   &fields{},
   130  		want:  fields{Nested: &Nested{P: &one}},
   131  	}, {
   132  		value: `{for k, v in y if v > 1 {"\(k)": v} }
   133  		y: {a:1,b:2,c:3}`,
   134  		dst:  &fields{},
   135  		want: fields{B: 2, C: 3},
   136  	}, {
   137  		value: `{a:1,b:2,c:int}`,
   138  		dst:   new(fields),
   139  		err:   "c: cannot convert non-concrete value int",
   140  	}, {
   141  		value: `[]`,
   142  		dst:   intList(),
   143  		want:  *intList(),
   144  	}, {
   145  		value: `[1,2,3]`,
   146  		dst:   intList(),
   147  		want:  *intList(1, 2, 3),
   148  	}, {
   149  		// shorten list
   150  		value: `[1,2,3]`,
   151  		dst:   intList(1, 2, 3, 4),
   152  		want:  *intList(1, 2, 3),
   153  	}, {
   154  		// shorter array
   155  		value: `[1,2,3]`,
   156  		dst:   &[2]int{},
   157  		want:  [2]int{1, 2},
   158  	}, {
   159  		// longer array
   160  		value: `[1,2,3]`,
   161  		dst:   &[4]int{},
   162  		want:  [4]int{1, 2, 3, 0},
   163  	}, {
   164  		value: `[for x in #y if x > 1 { x }]
   165  				#y: [1,2,3]`,
   166  		dst:  intList(),
   167  		want: *intList(2, 3),
   168  	}, {
   169  		value: `[int]`,
   170  		dst:   intList(),
   171  		err:   "0: cannot convert non-concrete value int",
   172  	}, {
   173  		value: `{a: 1, b: 2, c: 3}`,
   174  		dst:   &map[string]int{},
   175  		want:  map[string]int{"a": 1, "b": 2, "c": 3},
   176  	}, {
   177  		value: `{"1": 1, "-2": 2, "3": 3}`,
   178  		dst:   &map[int]int{},
   179  		want:  map[int]int{1: 1, -2: 2, 3: 3},
   180  	}, {
   181  		value: `{"1": 1, "2": 2, "3": 3}`,
   182  		dst:   &map[uint]int{},
   183  		want:  map[uint]int{1: 1, 2: 2, 3: 3},
   184  	}, {
   185  		value: `{a: 1, b: 2, c: true, d: e: 2}`,
   186  		dst:   &map[string]interface{}{},
   187  		want: map[string]interface{}{
   188  			"a": 1, "b": 2, "c": true,
   189  			"d": map[string]interface{}{"e": 2}},
   190  	}, {
   191  		value: `{a: b: *2 | int}`,
   192  		dst:   &map[string]interface{}{},
   193  		want:  map[string]interface{}{"a": map[string]interface{}{"b": int(2)}},
   194  	}, {
   195  		value: `{a: 1, b: 2, c: true}`,
   196  		dst:   &map[string]int{},
   197  		err:   "c: cannot use value true (type bool) as int",
   198  	}, {
   199  		value: `{"300": 3}`,
   200  		dst:   &map[int8]int{},
   201  		err:   "key integer 300 overflows int8",
   202  	}, {
   203  		value: `{"300": 3}`,
   204  		dst:   &map[uint8]int{},
   205  		err:   "key integer 300 overflows uint8",
   206  	}}
   207  	for _, tc := range testCases {
   208  		t.Run(tc.value, func(t *testing.T) {
   209  			err := getInstance(t, tc.value).Value().Decode(tc.dst)
   210  			checkFatal(t, err, tc.err, "init")
   211  
   212  			got := reflect.ValueOf(tc.dst).Elem().Interface()
   213  			if !cmp.Equal(got, tc.want) {
   214  				t.Error(cmp.Diff(got, tc.want))
   215  				t.Errorf("\n%#v\n%#v", got, tc.want)
   216  			}
   217  		})
   218  	}
   219  }