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 }