blob: 7b1c815b399efe1af7c8e35975ced1800fa8d667 [file] [log] [blame]
// Copyright 2020 CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package literal
import (
"fmt"
"math/big"
"strconv"
"testing"
"cuelang.org/go/cue/token"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)
func mkInt(i int) NumInfo {
return NumInfo{
base: 10,
neg: i < 0,
buf: []byte(strconv.Itoa(i)),
}
}
func mkFloat(a string) NumInfo {
return NumInfo{
base: 10,
buf: []byte(a),
neg: a[0] == '-',
isFloat: true,
}
}
func mkMul(i string, m Multiplier, base byte) NumInfo {
return NumInfo{
base: base,
mul: m,
neg: i[0] == '-',
buf: []byte(i),
}
}
func TestNumbers(t *testing.T) {
// hk := newInt(testBase, newRepresentation(0, 10, true)).setInt64(100000)
testCases := []struct {
lit string
norm string
n NumInfo
}{
{"0", "0", mkInt(0)},
{"1", "1", mkInt(1)},
{"-1", "-1", mkInt(-1)},
{"100_000", "100000", NumInfo{UseSep: true, base: 10, buf: []byte("100000")}},
{"1.", "1.", mkFloat("1.")},
{"0.", "0.", mkFloat("0.")},
{".0", "0.0", mkFloat("0.0")},
{"012.34", "12.34", mkFloat("12.34")},
{".01", "0.01", mkFloat("0.01")},
{".01e2", "0.01e2", mkFloat("0.01e2")},
{"0.", "0.", mkFloat("0.")},
{"1K", "1000", mkMul("1", K, 10)},
{".5K", "500", mkMul("0.5", K, 10)},
{"1Mi", "1048576", mkMul("1", Mi, 10)},
{"1.5Mi", "1572864", mkMul("1.5", Mi, 10)},
// {"1.3Mi", &bottom{}}, // Cannot be accurately represented.
{"1.3G", "1300000000", mkMul("1.3", G, 10)},
{"1.3e+20", "1.3e+20", mkFloat("1.3e+20")},
{"1.3e20", "1.3e20", mkFloat("1.3e20")},
{"1.3e-5", "1.3e-5", mkFloat("1.3e-5")},
{".3e-1", "0.3e-1", mkFloat("0.3e-1")},
{"0e-5", "0e-5", mkFloat("0e-5")},
{"0E-5", "0e-5", mkFloat("0e-5")},
{"5e-5", "5e-5", mkFloat("5e-5")},
{"5E-5", "5e-5", mkFloat("5e-5")},
{"0x1234", "4660", mkMul("1234", 0, 16)},
{"0xABCD", "43981", mkMul("ABCD", 0, 16)},
{"-0xABCD", "-43981", mkMul("-ABCD", 0, 16)},
{"0b11001000", "200", mkMul("11001000", 0, 2)},
{"0b1", "1", mkMul("1", 0, 2)},
{"0o755", "493", mkMul("755", 0, 8)},
{"0755", "493", mkMul("755", 0, 8)},
}
n := NumInfo{}
for i, tc := range testCases {
t.Run(fmt.Sprintf("%d/%+q", i, tc.lit), func(t *testing.T) {
if err := ParseNum(tc.lit, &n); err != nil {
t.Fatal(err)
}
n.src = ""
n.p = 0
n.ch = 0
if !cmp.Equal(n, tc.n, diffOpts...) {
t.Error(cmp.Diff(n, tc.n, diffOpts...))
t.Errorf("%#v, %#v\n", n, tc.n)
}
if n.String() != tc.norm {
t.Errorf("got %v; want %v", n.String(), tc.norm)
}
})
}
}
var diffOpts = []cmp.Option{
cmp.Comparer(func(x, y big.Rat) bool {
return x.String() == y.String()
}),
cmp.Comparer(func(x, y big.Int) bool {
return x.String() == y.String()
}),
cmp.AllowUnexported(
NumInfo{},
),
cmpopts.IgnoreUnexported(
token.Pos{},
),
cmpopts.EquateEmpty(),
}
func TestNumErrors(t *testing.T) {
testCases := []string{
`0x`,
`0o`,
`0b`,
`0_`,
"0128",
"e+100",
".p",
``,
`"`,
`"a`,
`23.34e`,
`23.34e33pp`,
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%+q", tc), func(t *testing.T) {
n := &NumInfo{}
err := ParseNum(tc, n)
if err == nil {
t.Fatalf("expected error but found none")
}
})
}
}