blob: c35c9bb395404f5f0f6a510f3ebee018f716dfc5 [file] [log] [blame]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001// Copyright 2018 The 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
15package cue
16
17import (
Marcel van Lohuizen7b5d2fd2018-12-11 16:34:56 +010018 "fmt"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010019 "math/big"
20 "reflect"
Marcel van Lohuizen7b5d2fd2018-12-11 16:34:56 +010021 "strings"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010022 "testing"
23
24 "cuelang.org/go/cue/ast"
25 "cuelang.org/go/cue/errors"
26)
27
28func TestConvert(t *testing.T) {
29 i34 := big.NewInt(34)
30 d34 := mkBigInt(34)
31 f34 := big.NewFloat(34.0000)
32 testCases := []struct {
33 goVal interface{}
34 want string
35 }{{
36 nil, "null",
37 }, {
38 true, "true",
39 }, {
40 false, "false",
41 }, {
42 errors.New("oh noes"), "_|_(oh noes)",
43 }, {
44 "foo", `"foo"`,
45 }, {
46 3, "3",
47 }, {
48 uint(3), "3",
49 }, {
50 uint8(3), "3",
51 }, {
52 uint16(3), "3",
53 }, {
54 uint32(3), "3",
55 }, {
56 uint64(3), "3",
57 }, {
58 int8(-3), "-3",
59 }, {
60 int16(-3), "-3",
61 }, {
62 int32(-3), "-3",
63 }, {
64 int64(-3), "-3",
65 }, {
66 float64(3.1), "3.1",
67 }, {
68 &i34, "34",
69 }, {
70 &f34, "34",
71 }, {
72 &d34, "34",
73 }, {
74 []int{1, 2, 3, 4}, "[1,2,3,4]",
75 }, {
76 []interface{}{}, "[]",
77 }, {
78 map[string][]int{
79 "a": []int{1},
80 "b": []int{3, 4},
81 }, "<0>{a: [1], b: [3,4]}",
82 }, {
83 map[int]int{}, "_|_(builtin map key not a string, but unsupported type int)",
84 }, {
85 map[int]int{1: 2}, "_|_(builtin map key not a string, but unsupported type int)",
86 }, {
87 struct {
88 a int
89 b int
90 }{3, 4},
91 "<0>{}",
92 }, {
93 struct {
94 A int
95 B int
96 }{3, 4},
97 "<0>{A: 3, B: 4}",
98 }, {
99 struct {
100 A int `json:"a"`
101 B int `cue:"b"`
102 }{3, 4},
103 "<0>{a: 3, b: 4}",
104 }, {
105 struct {
106 A int `json:",bb" cue:"" protobuf:"aa"`
107 B int `json:"cc" cue:"bb" protobuf:"aa"`
108 }{3, 4},
109 "<0>{aa: 3, bb: 4}",
110 }, {
111 &struct{ A int }{3}, "<0>{A: 3}",
112 }, {
113 (*struct{ A int })(nil), "null",
114 }, {
115 reflect.ValueOf(3), "3",
116 }}
117 inst := getInstance(t, "foo")
118 b := ast.NewIdent("dummy")
119 for _, tc := range testCases {
120 ctx := inst.newContext()
121 t.Run("", func(t *testing.T) {
122 v := convert(ctx, newNode(b), tc.goVal)
123 got := debugStr(ctx, v)
124 if got != tc.want {
125 t.Errorf("got %q; want %q", got, tc.want)
126 }
127 })
128 }
129}
Marcel van Lohuizen7b5d2fd2018-12-11 16:34:56 +0100130
131func TestBuiltins(t *testing.T) {
132 test := func(pkg, expr string) []*bimport {
133 return []*bimport{&bimport{"",
134 []string{fmt.Sprintf("import %q\n(%s)", pkg, expr)},
135 }}
136 }
137 testExpr := func(expr string) []*bimport {
138 return []*bimport{&bimport{"",
139 []string{fmt.Sprintf("(%s)", expr)},
140 }}
141 }
142 testCases := []struct {
143 instances []*bimport
144 emit string
145 }{{
146 test("math", "math.Pi"),
147 `3.14159265358979323846264338327950288419716939937510582097494459`,
148 }, {
149 test("math", "math.Floor(math.Pi)"),
150 `3`,
151 }, {
152 test("math", "math.Pi(3)"),
153 `_|_(<0>.Pi:cannot call non-function 3.14159265358979323846264338327950288419716939937510582097494459 (type float))`,
154 }, {
155 test("math", "math.Floor(3, 5)"),
156 `_|_(<0>.Floor (3,5):number of arguments does not match (1 vs 2))`,
157 }, {
158 test("math", `math.Floor("foo")`),
159 `_|_(<0>.Floor ("foo"):argument 1 requires type number, found string)`,
160 }, {
161 test("encoding/hex", `hex.Encode("foo")`),
162 `"666f6f"`,
163 }, {
164 test("encoding/hex", `hex.Decode(hex.Encode("foo"))`),
165 `'foo'`,
166 }, {
167 test("encoding/hex", `hex.Decode("foo")`),
168 `_|_(<0>.Decode ("foo"):call error: encoding/hex: invalid byte: U+006F 'o')`,
169 }, {
170 test("strconv", `strconv.FormatUint(64, 16)`),
171 `"40"`,
172 }, {
173 // Find a better alternative, as this call should go.
174 test("strconv", `strconv.FormatFloat(3.02, 300, 4, 64)`),
175 `_|_(<0>.FormatFloat (3.02,300,4,64):argument 1 out of range: has 9 > 8 bits)`,
176 }, {
177 // Find a better alternative, as this call should go.
178 test("strconv", `strconv.FormatFloat(3.02, -1, 4, 64)`),
179 `_|_(<0>.FormatFloat (3.02,-1,4,64):argument 1 must be a positive integer)`,
180 }, {
181 // Find a better alternative, as this call should go.
182 test("strconv", `strconv.FormatFloat(3.02, 1.0, 4, 64)`),
183 `_|_(<0>.FormatFloat (3.02,1.0,4,64):argument 2 requires type int, found float)`,
184 }, {
185 // Panics
186 test("math", `math.Jacobi(1000, 2000)`),
187 `_|_(<0>.Jacobi (1000,2000):call error: big: invalid 2nd argument to Int.Jacobi: need odd integer but got 2000)`,
188 }, {
189 test("math", `math.Jacobi(1000, 201)`),
190 `1`,
191 }, {
192 test("math", `math.Asin(2.0e400)`),
193 `_|_(<0>.Asin (2.0e+400):invalid argument 0: cue: value was rounded up)`,
194 }, {
195 test("encoding/csv", `csv.Decode("1,2,3\n4,5,6")`),
196 `[["1","2","3"],["4","5","6"]]`,
197 }, {
198 test("strconv", `strconv.FormatBool(true)`),
199 `"true"`,
200 }, {
201 test("strings", `strings.Join(["Hello", "World!"], " ")`),
202 `"Hello World!"`,
203 }, {
204 test("strings", `strings.Join([1, 2], " ")`),
205 `_|_(<0>.Join ([1,2]," "):list element 1: not of right kind (number vs string))`,
206 }, {
207 test("math/bits", `bits.Or(0x8, 0x1)`),
208 `9`,
209 }, {
210 testExpr(`len({})`),
211 `0`,
212 }, {
213 testExpr(`len({a: 1, b: 2, <foo>: int, _c: 3})`),
214 `2`,
215 }, {
216 testExpr(`len([1, 2, 3])`),
217 `3`,
218 }, {
219 testExpr(`len("foo")`),
220 `3`,
221 }, {
222 testExpr(`len('f\x20\x20')`),
223 `3`,
224 }}
225 for _, tc := range testCases {
226 t.Run("", func(t *testing.T) {
227 insts := Build(makeInstances(tc.instances))
228 if err := insts[0].Err; err != nil {
229 t.Fatal(err)
230 }
231 got := strings.TrimSpace(fmt.Sprintf("%s\n", insts[0].Value()))
232 if got != tc.emit {
233 t.Errorf("\n got: %s\nwant: %s", got, tc.emit)
234 }
235 })
236 }
237}