...

Source file src/cuelang.org/go/internal/core/convert/go_test.go

Documentation: cuelang.org/go/internal/core/convert

     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  }
   401  

View as plain text