cuelang.org/go@v0.10.1/internal/core/convert/go_test.go (about) 1 // Copyright 2019 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 convert_test 16 17 // TODO: generate tests from Go's json encoder. 18 19 import ( 20 "encoding" 21 "math/big" 22 "reflect" 23 "testing" 24 "time" 25 26 "github.com/cockroachdb/apd/v3" 27 "github.com/google/go-cmp/cmp" 28 29 "cuelang.org/go/cue/errors" 30 "cuelang.org/go/internal/core/adt" 31 "cuelang.org/go/internal/core/convert" 32 "cuelang.org/go/internal/core/debug" 33 "cuelang.org/go/internal/core/runtime" 34 ) 35 36 func mkBigInt(a int64) (v apd.Decimal) { v.SetInt64(a); return } 37 38 type textMarshaller struct { 39 b string 40 } 41 42 func (t *textMarshaller) MarshalText() (b []byte, err error) { 43 return []byte(t.b), nil 44 } 45 46 var _ encoding.TextMarshaler = &textMarshaller{} 47 48 func TestConvert(t *testing.T) { 49 type key struct { 50 a int 51 } 52 type stringType string 53 i34 := big.NewInt(34) 54 d35 := mkBigInt(35) 55 n36 := mkBigInt(-36) 56 f37 := big.NewFloat(37.0000) 57 testCases := []struct { 58 goVal interface{} 59 want string 60 }{{ 61 nil, "(_){ _ }", 62 }, { 63 true, "(bool){ true }", 64 }, { 65 false, "(bool){ false }", 66 }, { 67 errors.New("oh noes"), "(_|_){\n // [eval] oh noes\n}", 68 }, { 69 "foo", `(string){ "foo" }`, 70 }, { 71 "\x80", `(string){ "�" }`, 72 }, { 73 3, "(int){ 3 }", 74 }, { 75 uint(3), "(int){ 3 }", 76 }, { 77 uint8(3), "(int){ 3 }", 78 }, { 79 uint16(3), "(int){ 3 }", 80 }, { 81 uint32(3), "(int){ 3 }", 82 }, { 83 uint64(3), "(int){ 3 }", 84 }, { 85 int8(-3), "(int){ -3 }", 86 }, { 87 int16(-3), "(int){ -3 }", 88 }, { 89 int32(-3), "(int){ -3 }", 90 }, { 91 int64(-3), "(int){ -3 }", 92 }, { 93 float64(3), "(float){ 3 }", 94 }, { 95 float64(3.1), "(float){ 3.1 }", 96 }, { 97 float32(3.1), "(float){ 3.1 }", 98 }, { 99 uintptr(3), "(int){ 3 }", 100 }, { 101 &i34, "(int){ 34 }", 102 }, { 103 &f37, "(float){ 37 }", 104 }, { 105 &d35, "(int){ 35 }", 106 }, { 107 &n36, "(int){ -36 }", 108 }, { 109 []int{1, 2, 3, 4}, `(#list){ 110 0: (int){ 1 } 111 1: (int){ 2 } 112 2: (int){ 3 } 113 3: (int){ 4 } 114 }`, 115 }, { 116 struct { 117 A int 118 B *int 119 }{3, nil}, 120 "(struct){\n A: (int){ 3 }\n}", 121 }, { 122 []interface{}{}, "(#list){\n}", 123 }, { 124 []interface{}{nil}, "(#list){\n 0: (_){ _ }\n}", 125 }, { 126 map[string]interface{}{"a": 1, "x": nil}, `(struct){ 127 a: (int){ 1 } 128 x: (_){ _ } 129 }`, 130 }, { 131 map[string][]int{ 132 "a": {1}, 133 "b": {3, 4}, 134 }, `(struct){ 135 a: (#list){ 136 0: (int){ 1 } 137 } 138 b: (#list){ 139 0: (int){ 3 } 140 1: (int){ 4 } 141 } 142 }`, 143 }, { 144 map[bool]int{}, "(_|_){\n // [eval] unsupported Go type for map key (bool)\n}", 145 }, { 146 map[struct{}]int{{}: 2}, "(_|_){\n // [eval] unsupported Go type for map key (struct {})\n}", 147 }, { 148 map[int]int{1: 2}, `(struct){ 149 "1": (int){ 2 } 150 }`, 151 }, { 152 struct { 153 a int 154 b int 155 }{3, 4}, 156 "(struct){\n}", 157 }, { 158 struct { 159 A int 160 B int `json:"-"` 161 C int `json:",omitempty"` 162 }{3, 4, 0}, 163 `(struct){ 164 A: (int){ 3 } 165 }`, 166 }, { 167 struct { 168 A int 169 B int 170 }{3, 4}, 171 `(struct){ 172 A: (int){ 3 } 173 B: (int){ 4 } 174 }`, 175 }, { 176 struct { 177 A int `json:"a"` 178 B int `yaml:"b"` 179 }{3, 4}, 180 `(struct){ 181 a: (int){ 3 } 182 b: (int){ 4 } 183 }`, 184 }, { 185 struct { 186 A int `json:"" yaml:"" protobuf:"aa"` 187 B int `yaml:"cc" json:"bb" protobuf:"aa"` 188 }{3, 4}, 189 `(struct){ 190 aa: (int){ 3 } 191 bb: (int){ 4 } 192 }`, 193 }, { 194 &struct{ A int }{3}, `(struct){ 195 A: (int){ 3 } 196 }`, 197 }, { 198 (*struct{ A int })(nil), "(_){ _ }", 199 }, { 200 reflect.ValueOf(3), "(int){ 3 }", 201 }, { 202 time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC), `(string){ "2019-04-01T00:00:00Z" }`, 203 }, { 204 func() interface{} { 205 type T struct { 206 B int 207 } 208 type S struct { 209 A string 210 T 211 } 212 return S{} 213 }(), 214 `(struct){ 215 A: (string){ "" } 216 B: (int){ 0 } 217 }`, 218 }, 219 {map[key]string{{a: 1}: "foo"}, 220 "(_|_){\n // [eval] unsupported Go type for map key (convert_test.key)\n}"}, 221 {map[*textMarshaller]string{{b: "bar"}: "foo"}, 222 "(struct){\n \"&{bar}\": (string){ \"foo\" }\n}"}, 223 {map[int]string{1: "foo"}, 224 "(struct){\n \"1\": (string){ \"foo\" }\n}"}, 225 {map[string]encoding.TextMarshaler{"foo": nil}, 226 "(struct){\n foo: (_){ _ }\n}"}, 227 {make(chan int), 228 "(_|_){\n // [eval] unsupported Go type (chan int)\n}"}, 229 {[]interface{}{func() {}}, 230 "(_|_){\n // [eval] unsupported Go type (func())\n}"}, 231 {stringType("\x80"), `(string){ "�" }`}, 232 } 233 r := runtime.New() 234 for _, tc := range testCases { 235 ctx := adt.NewContext(r, &adt.Vertex{}) 236 t.Run("", func(t *testing.T) { 237 v := convert.GoValueToValue(ctx, tc.goVal, true) 238 n, ok := v.(*adt.Vertex) 239 if !ok { 240 n = &adt.Vertex{BaseValue: v} 241 } 242 got := debug.NodeString(ctx, n, nil) 243 if got != tc.want { 244 t.Error(cmp.Diff(got, tc.want)) 245 } 246 }) 247 } 248 } 249 250 func TestX(t *testing.T) { 251 t.Skip() 252 253 x := []string{} 254 255 r := runtime.New() 256 ctx := adt.NewContext(r, &adt.Vertex{}) 257 258 v := convert.GoValueToValue(ctx, x, false) 259 // if err != nil { 260 // t.Fatal(err) 261 // } 262 got := debug.NodeString(ctx, v, nil) 263 t.Error(got) 264 } 265 266 func TestConvertType(t *testing.T) { 267 testCases := []struct { 268 goTyp interface{} 269 want string 270 }{{ 271 struct { 272 A int `cue:">=0&<100"` 273 B *big.Int `cue:">=0"` 274 C *big.Int 275 D big.Int 276 F *big.Float 277 }{}, 278 // TODO: indicate that B is explicitly an int only. 279 `{ 280 A: (((int & >=-9223372036854775808) & <=9223372036854775807) & (>=0 & <100)) 281 B: (int & >=0) 282 C?: int 283 D: int 284 F?: number 285 }`, 286 }, { 287 &struct { 288 A int16 `cue:">=0&<100"` 289 B error `json:"b,"` 290 C string 291 D bool 292 F float64 293 L []byte 294 T time.Time 295 G func() 296 }{}, 297 `(*null|{ 298 A: (((int & >=-32768) & <=32767) & (>=0 & <100)) 299 b: null 300 C: string 301 D: bool 302 F: number 303 L?: (*null|bytes) 304 T: _ 305 })`, 306 }, { 307 struct { 308 A int `cue:"<"` // invalid 309 }{}, 310 "_|_(invalid tag \"<\" for field \"A\": expected operand, found 'EOF' (and 1 more errors))", 311 }, { 312 struct { 313 A int `json:"-"` // skip 314 D *apd.Decimal 315 P ***apd.Decimal 316 I interface{ Foo() } 317 T string `cue:""` // allowed 318 h int 319 }{}, 320 `{ 321 D?: number 322 P?: (*null|number) 323 I?: _ 324 T: (string & _) 325 }`, 326 }, { 327 struct { 328 A int8 `cue:"C-B"` 329 B int8 `cue:"C-A,opt"` 330 C int8 `cue:"A+B"` 331 }{}, 332 // TODO: should B be marked as optional? 333 `{ 334 A: (((int & >=-128) & <=127) & (〈0;C〉 - 〈0;B〉)) 335 B?: (((int & >=-128) & <=127) & (〈0;C〉 - 〈0;A〉)) 336 C: (((int & >=-128) & <=127) & (〈0;A〉 + 〈0;B〉)) 337 }`, 338 }, { 339 []string{}, 340 `(*null|[ 341 ...string, 342 ])`, 343 }, { 344 [4]string{}, 345 `(4 * [ 346 string, 347 ])`, 348 }, { 349 []func(){}, 350 "_|_(unsupported Go type (func()))", 351 }, { 352 map[string]struct{ A map[string]uint }{}, 353 `(*null|{ 354 [string]: { 355 A?: (*null|{ 356 [string]: ((int & >=0) & <=18446744073709551615) 357 }) 358 } 359 })`, 360 }, { 361 map[float32]int{}, 362 `_|_(unsupported Go type for map key (float32))`, 363 }, { 364 map[int]map[float32]int{}, 365 `_|_(unsupported Go type for map key (float32))`, 366 }, { 367 map[int]func(){}, 368 `_|_(unsupported Go type (func()))`, 369 }, { 370 time.Now, // a function 371 "_|_(unsupported Go type (func() time.Time))", 372 }, { 373 struct { 374 Foobar string `cue:"\"foo,bar\",opt"` 375 }{}, 376 `{ 377 Foobar?: (string & "foo,bar") 378 }`, 379 }, { 380 struct { 381 Foobar string `cue:"\"foo,opt,bar\""` 382 }{}, 383 `{ 384 Foobar: (string & "foo,opt,bar") 385 }`, 386 }} 387 388 r := runtime.New() 389 390 for _, tc := range testCases { 391 t.Run("", func(t *testing.T) { 392 ctx := adt.NewContext(r, &adt.Vertex{}) 393 v, _ := convert.GoTypeToExpr(ctx, tc.goTyp) 394 got := debug.NodeString(ctx, v, nil) 395 if got != tc.want { 396 t.Errorf("\n got %q;\nwant %q", got, tc.want) 397 } 398 }) 399 } 400 }