blob: 6ad69053858372a5c4692f5d3ff48847a11b2537 [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 (
18 "fmt"
19 "math/big"
20 "testing"
21
22 "cuelang.org/go/cue/ast"
23 "github.com/cockroachdb/apd"
24 "github.com/google/go-cmp/cmp"
25 "github.com/google/go-cmp/cmp/cmpopts"
26)
27
Marcel van Lohuizen4a360992019-05-11 18:18:31 +020028var defIntBase = newNumBase(&ast.BasicLit{}, newNumInfo(intKind, 0, 10, false))
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010029var defRatBase = newNumBase(&ast.BasicLit{}, newNumInfo(floatKind, 0, 10, false))
30
31func mkInt(a int64) *numLit {
32 x := &numLit{numBase: defIntBase}
33 x.v.SetInt64(a)
34 return x
35}
36func mkIntString(a string) *numLit {
37 x := &numLit{numBase: defIntBase}
38 x.v.SetString(a)
39 return x
40}
41func mkFloat(a string) *numLit {
42 x := &numLit{numBase: defRatBase}
43 x.v.SetString(a)
44 return x
45}
46func mkBigInt(a int64) (v apd.Decimal) { v.SetInt64(a); return }
47
48func mkBigFloat(a string) (v apd.Decimal) { v.SetString(a); return }
49
50var diffOpts = []cmp.Option{
51 cmp.Comparer(func(x, y big.Rat) bool {
52 return x.String() == y.String()
53 }),
54 cmp.Comparer(func(x, y big.Int) bool {
55 return x.String() == y.String()
56 }),
57 cmp.AllowUnexported(
58 nullLit{},
59 boolLit{},
60 stringLit{},
61 bytesLit{},
62 numLit{},
63 numBase{},
64 numInfo{},
65 ),
66 cmpopts.IgnoreUnexported(
67 bottom{},
68 baseValue{},
69 baseValue{},
70 ),
71}
72
73var (
74 nullSentinel = &nullLit{}
75 trueSentinel = &boolLit{b: true}
76 falseSentinel = &boolLit{b: false}
77)
78
79func TestLiterals(t *testing.T) {
80 mkMul := func(x int64, m multiplier, base int) *numLit {
81 return &numLit{
Marcel van Lohuizen4a360992019-05-11 18:18:31 +020082 newNumBase(&ast.BasicLit{}, newNumInfo(intKind, m, base, false)),
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010083 mkBigInt(x),
84 }
85 }
86 hk := &numLit{
Marcel van Lohuizen4a360992019-05-11 18:18:31 +020087 newNumBase(&ast.BasicLit{}, newNumInfo(intKind, 0, 10, true)),
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010088 mkBigInt(100000),
89 }
90 testCases := []struct {
91 lit string
92 node value
93 }{
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +010094 {"0", mkInt(0)},
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010095 {"null", nullSentinel},
96 {"true", trueSentinel},
97 {"false", falseSentinel},
98 {"fls", &bottom{}},
99 {`"foo"`, &stringLit{str: "foo"}},
100 {`"\"foo\""`, &stringLit{str: `"foo"`}},
101 {`"foo\u0032"`, &stringLit{str: `foo2`}},
102 {`"foo\U00000033"`, &stringLit{str: `foo3`}},
103 {`"foo\U0001f499"`, &stringLit{str: `foo💙`}},
104 {`"\a\b\f\n\r\t\v"`, &stringLit{str: "\a\b\f\n\r\t\v"}},
105 {`"""
106 """`, &stringLit{str: ""}},
107 {`"""
108 abc
109 """`, &stringLit{str: "abc"}},
110 {`"""
111 abc
112 def
113 """`, &stringLit{str: "abc\ndef"}},
114 {`"""
115 abc
116 def
117 """`, &stringLit{str: "abc\n\tdef"}},
118 {`'\xff'`, &bytesLit{b: []byte("\xff")}},
119 {"1", mkInt(1)},
120 {"100_000", hk},
121 {"1.", mkFloat("1")},
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +0100122 {"0.0", mkFloat("0.0")},
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100123 {".0", mkFloat(".0")},
124 {"1K", mkMul(1000, mulK, 10)},
125 {"1Mi", mkMul(1024*1024, mulMi, 10)},
126 {"1.5Mi", mkMul((1024+512)*1024, mulMi, 10)},
127 {"1.3Mi", &bottom{}}, // Cannot be accurately represented.
128 {"1.3G", mkMul(1300000000, mulG, 10)},
129 {"1.3e+20", mkFloat("1.3e+20")},
130 {"1.3e20", mkFloat("1.3e+20")},
131 {"1.3e-5", mkFloat("1.3e-5")},
132 {"0x1234", mkMul(0x1234, 0, 16)},
133 {"0xABCD", mkMul(0xABCD, 0, 16)},
134 {"0b11001000", mkMul(0xc8, 0, 2)},
135 {"0b1", mkMul(1, 0, 2)},
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +0100136 {"0o755", mkMul(0755, 0, 8)},
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100137 }
138 p := litParser{
139 ctx: &context{Context: &apd.BaseContext},
140 }
141 for i, tc := range testCases {
142 t.Run(fmt.Sprintf("%d/%+q", i, tc.lit), func(t *testing.T) {
143 got := p.parse(&ast.BasicLit{Value: tc.lit})
144 if !cmp.Equal(got, tc.node, diffOpts...) {
145 t.Error(cmp.Diff(got, tc.node, diffOpts...))
146 t.Errorf("%#v, %#v\n", got, tc.node)
147 }
148 })
149 }
150}
151
152func TestLiteralErrors(t *testing.T) {
153 testCases := []struct {
154 lit string
155 }{
156 {`"foo\u"`},
157 {`"foo\u003"`},
158 {`"foo\U1234567"`},
159 {`"foo\U12345678"`},
160 {`"foo\Ug"`},
161 {`"\xff"`},
162 // not allowed in string literal, only binary
163 {`"foo\x00"`},
164 {`0x`},
Marcel van Lohuizenfc6303c2019-02-07 17:49:04 +0100165 {`0o`},
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100166 {`0_`},
167 {``},
168 {`"`},
169 {`"a`},
170 // wrong indentation
171 {`"""
172 abc
173 def
174 """`},
175 // non-matching quotes
176 {`"""
177 abc
178 '''`},
179 {`"""
180 abc
181 "`},
182 {`"abc \( foo "`},
183 }
184 p := litParser{
185 ctx: &context{Context: &apd.BaseContext},
186 }
187 for _, tc := range testCases {
188 t.Run(fmt.Sprintf("%+q", tc.lit), func(t *testing.T) {
189 got := p.parse(&ast.BasicLit{Value: tc.lit})
190 if _, ok := got.(*bottom); !ok {
191 t.Fatalf("expected error but found none")
192 }
193 })
194 }
195}