mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-05 08:10:50 +00:00
There are subtle inconsistencies, like "01" being a valid decimal but not a valid integer, which vaguely bug me. Cleaning this up, and the corresponding parser logic. A number can't have leading spaces because the grammar doesn't put spaces in them in the first place, so stop accepting them in the number syntax. This should never have any impact on anything, it's just simpler. Update a couple of test cases to reflect this -- no longer testing that trailing spaces are okay, now testing that they're not, for instance.
262 lines
10 KiB
Go
262 lines
10 KiB
Go
// Copyright 2017 Pilosa Corp.
|
|
//
|
|
// 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 pql_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/pilosa/pilosa/v2/pql"
|
|
)
|
|
|
|
// Ensure call can be converted into a string.
|
|
func TestDecimal(t *testing.T) {
|
|
t.Run("Parse", func(t *testing.T) {
|
|
tests := []struct {
|
|
s string
|
|
exp pql.Decimal
|
|
expErr string
|
|
}{
|
|
{"0", pql.Decimal{0, 0}, ""},
|
|
{"-0", pql.Decimal{0, 0}, ""},
|
|
{"0.0", pql.Decimal{0, 0}, ""},
|
|
{"0.", pql.Decimal{0, 0}, ""},
|
|
{"-0.00", pql.Decimal{0, 0}, ""},
|
|
{"123.4567", pql.Decimal{1234567, 4}, ""},
|
|
{"123.456700", pql.Decimal{1234567, 4}, ""},
|
|
{"00123.4567", pql.Decimal{1234567, 4}, ""},
|
|
{"+123.4567", pql.Decimal{1234567, 4}, ""},
|
|
{"-123.4567", pql.Decimal{-1234567, 4}, ""},
|
|
{"-00123.4567", pql.Decimal{-1234567, 4}, ""},
|
|
{"-12.25", pql.Decimal{-1225, 2}, ""},
|
|
|
|
{"123", pql.Decimal{123, 0}, ""},
|
|
{"-12300", pql.Decimal{-123, -2}, ""},
|
|
{"+012300", pql.Decimal{123, -2}, ""},
|
|
{"12300", pql.Decimal{123, -2}, ""},
|
|
{"12300.", pql.Decimal{123, -2}, ""},
|
|
{"12300.0", pql.Decimal{123, -2}, ""},
|
|
{"123.0", pql.Decimal{123, 0}, ""},
|
|
|
|
{".123", pql.Decimal{123, 3}, ""},
|
|
{"0.123", pql.Decimal{123, 3}, ""},
|
|
{"0.001230", pql.Decimal{123, 5}, ""},
|
|
{"-0.001230", pql.Decimal{-123, 5}, ""},
|
|
|
|
// int64 edges.
|
|
{".000009223372036854775807", pql.Decimal{9223372036854775807, 24}, ""},
|
|
{"-.000009223372036854775808", pql.Decimal{-9223372036854775808, 24}, ""},
|
|
{"92233720368547.75807", pql.Decimal{9223372036854775807, 5}, ""},
|
|
{"-92233720368547.75807", pql.Decimal{-9223372036854775807, 5}, ""},
|
|
{"9223372036854775807000", pql.Decimal{9223372036854775807, -3}, ""},
|
|
{"-9223372036854775807000", pql.Decimal{-9223372036854775807, -3}, ""},
|
|
|
|
// precision adjustment
|
|
{"2.666666666666666667", pql.Decimal{2666666666666666667, 18}, ""},
|
|
{"2.6666666666666666667", pql.Decimal{2666666666666666666, 18}, ""},
|
|
{"2.6666666666666666666667", pql.Decimal{2666666666666666666, 18}, ""},
|
|
{"-9.223372036854775808", pql.Decimal{-9223372036854775808, 18}, ""},
|
|
{"-9.223372036854775809", pql.Decimal{-922337203685477580, 17}, ""},
|
|
{"9.223372036854775807", pql.Decimal{9223372036854775807, 18}, ""},
|
|
{"9.223372036854775808", pql.Decimal{922337203685477580, 17}, ""},
|
|
|
|
// Error cases.
|
|
{"", pql.Decimal{}, "decimal string is empty"},
|
|
{"-", pql.Decimal{}, "decimal string is empty"},
|
|
{"*0.123", pql.Decimal{}, "invalid syntax"},
|
|
{"abc", pql.Decimal{}, "invalid syntax"},
|
|
{"0.12.3", pql.Decimal{}, "invalid decimal string"},
|
|
{"--12300", pql.Decimal{}, "invalid syntax"},
|
|
{" 123.4567 ", pql.Decimal{}, "invalid syntax"},
|
|
{" 123.4567", pql.Decimal{}, "invalid syntax"},
|
|
{"123.4567 ", pql.Decimal{}, "invalid syntax"},
|
|
{"0.a", pql.Decimal{}, "invalid syntax"},
|
|
|
|
// These are no longer error cases since we introduced precision adjustment.
|
|
//{"922337203685477580.9", pql.Decimal{}, "value out of range"},
|
|
//{"-922337203685477580.9", pql.Decimal{}, "value out of range"},
|
|
{"9223372036854775808000", pql.Decimal{}, "value out of range"},
|
|
{"-9223372036854775809000", pql.Decimal{}, "value out of range"},
|
|
}
|
|
for i, test := range tests {
|
|
dec, err := pql.ParseDecimal(test.s)
|
|
if test.expErr != "" {
|
|
if err == nil || !strings.Contains(err.Error(), test.expErr) {
|
|
t.Fatalf("test %d parsing string `%s`: expected error to contain: %s, but got: %v", i, test.s, test.expErr, err)
|
|
}
|
|
} else if err != nil {
|
|
t.Fatalf("test %d parsing string `%s`: %s", i, test.s, err)
|
|
} else if dec != test.exp {
|
|
t.Fatalf("test %d parsing string `%s`: expected: %v, but got: %v", i, test.s, test.exp, dec)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("ToInt64", func(t *testing.T) {
|
|
tests := []struct {
|
|
dec pql.Decimal
|
|
scale int64
|
|
exp int64
|
|
}{
|
|
{pql.Decimal{0, 0}, 0, 0}, // 0 : 0
|
|
{pql.Decimal{0, 0}, 1, 0}, // 0 : 0.0
|
|
{pql.Decimal{0, 0}, -1, 0}, // 0 : 0
|
|
|
|
{pql.Decimal{1234567, 4}, 5, 12345670}, // 123.4567 : 123.45670
|
|
{pql.Decimal{1234567, 4}, 4, 1234567}, // 123.4567 : 123.4567
|
|
{pql.Decimal{1234567, 4}, 3, 123456}, // 123.4567 : 123.456
|
|
|
|
{pql.Decimal{-1234567, 4}, 5, -12345670}, // -123.4567 : -123.45670
|
|
{pql.Decimal{-1234567, 4}, 4, -1234567}, // -123.4567 : -123.4567
|
|
{pql.Decimal{-1234567, 4}, 3, -123456}, // -123.4567 : -123.456
|
|
|
|
{pql.Decimal{123, -2}, 5, 1230000000}, // 12300 : 12300.00000
|
|
{pql.Decimal{123, -2}, -1, 1230}, // 12300 : 1230
|
|
{pql.Decimal{123, 1}, -1, 1}, // 12.3 : 1
|
|
{pql.Decimal{123, 1}, -2, 0}, // 12.3 : 0
|
|
}
|
|
for i, test := range tests {
|
|
v := test.dec.ToInt64(test.scale)
|
|
if v != test.exp {
|
|
t.Fatalf("test %d expected: %d, but got: %d", i, test.exp, v)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("String", func(t *testing.T) {
|
|
tests := []struct {
|
|
s string
|
|
exp string
|
|
}{
|
|
{"123.4567", "123.4567"},
|
|
{"123.456700", "123.4567"},
|
|
{"00123.4567", "123.4567"},
|
|
{"+123.4567", "123.4567"},
|
|
{"-123.4567", "-123.4567"},
|
|
{"-00123.4567", "-123.4567"},
|
|
{"-12.25", "-12.25"},
|
|
|
|
{"123", "123"},
|
|
{"-12300", "-12300"},
|
|
{"+012300", "12300"},
|
|
{"12300", "12300"},
|
|
|
|
{"12300.", "12300"},
|
|
{"12300.0", "12300"},
|
|
{"123.0", "123"},
|
|
|
|
{"0.123", "0.123"},
|
|
{"0.001230", "0.00123"},
|
|
{"+0.001230", "0.00123"},
|
|
{"-0.001230", "-0.00123"},
|
|
}
|
|
for i, test := range tests {
|
|
dec, err := pql.ParseDecimal(test.s)
|
|
if err != nil {
|
|
t.Fatalf("parsing string `%s`: %s", test.s, err)
|
|
}
|
|
if str := dec.String(); str != test.exp {
|
|
t.Fatalf("test %d expected: %s, but got: %s", i, test.exp, str)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Comparisons", func(t *testing.T) {
|
|
tests := []struct {
|
|
d1 pql.Decimal
|
|
d2 pql.Decimal
|
|
expLT bool
|
|
expLTE bool
|
|
expGT bool
|
|
expGTE bool
|
|
expEQ bool
|
|
}{
|
|
{pql.NewDecimal(0, 0), pql.NewDecimal(0, 0), false, true, false, true, true},
|
|
{pql.NewDecimal(0, 0), pql.NewDecimal(10, 0), true, true, false, false, false},
|
|
{pql.NewDecimal(10, 0), pql.NewDecimal(0, 0), false, false, true, true, false},
|
|
{pql.NewDecimal(123456, 3), pql.NewDecimal(123456, 3), false, true, false, true, true},
|
|
{pql.NewDecimal(123456, 3), pql.NewDecimal(123456, 4), false, false, true, true, false},
|
|
{pql.NewDecimal(123456, 4), pql.NewDecimal(123456, 3), true, true, false, false, false},
|
|
{pql.NewDecimal(1233456, 4), pql.NewDecimal(123456, 3), true, true, false, false, false},
|
|
|
|
{pql.NewDecimal(0, 0), pql.NewDecimal(-10, 0), false, false, true, true, false},
|
|
{pql.NewDecimal(-10, 0), pql.NewDecimal(0, 0), true, true, false, false, false},
|
|
{pql.NewDecimal(-123456, 3), pql.NewDecimal(-123456, 3), false, true, false, true, true},
|
|
{pql.NewDecimal(-123456, 3), pql.NewDecimal(-123456, 4), true, true, false, false, false},
|
|
{pql.NewDecimal(-123456, 4), pql.NewDecimal(-123456, 3), false, false, true, true, false},
|
|
{pql.NewDecimal(-1233456, 4), pql.NewDecimal(-123456, 3), false, false, true, true, false},
|
|
|
|
{pql.NewDecimal(10, 0), pql.NewDecimal(-10, 0), false, false, true, true, false},
|
|
{pql.NewDecimal(-10, 0), pql.NewDecimal(10, 0), true, true, false, false, false},
|
|
{pql.NewDecimal(-123456, 3), pql.NewDecimal(123456, 3), true, true, false, false, false},
|
|
{pql.NewDecimal(123456, 3), pql.NewDecimal(-123456, 3), false, false, true, true, false},
|
|
{pql.NewDecimal(-123456, 3), pql.NewDecimal(123456, 4), true, true, false, false, false},
|
|
{pql.NewDecimal(123456, 3), pql.NewDecimal(-123456, 4), false, false, true, true, false},
|
|
{pql.NewDecimal(-123456, 4), pql.NewDecimal(123456, 3), true, true, false, false, false},
|
|
{pql.NewDecimal(123456, 4), pql.NewDecimal(-123456, 3), false, false, true, true, false},
|
|
{pql.NewDecimal(-1233456, 4), pql.NewDecimal(123456, 3), true, true, false, false, false},
|
|
{pql.NewDecimal(1233456, 4), pql.NewDecimal(-123456, 3), false, false, true, true, false},
|
|
|
|
{pql.NewDecimal(9223372036854775807, 0), pql.NewDecimal(9223372036854775807, 0), false, true, false, true, true},
|
|
{pql.NewDecimal(9223372036854775807, 2), pql.NewDecimal(9223372036854775807, 0), true, true, false, false, false},
|
|
{pql.NewDecimal(9223372036854775807, 19), pql.NewDecimal(9223372036854775807, 0), true, true, false, false, false},
|
|
|
|
{pql.NewDecimal(-9223372036854775808, 0), pql.NewDecimal(-9223372036854775808, 0), false, true, false, true, true},
|
|
{pql.NewDecimal(-9223372036854775808, 0), pql.NewDecimal(-9223372036854775807, 0), true, true, false, false, false},
|
|
{pql.NewDecimal(-9223372036854775808, 2), pql.NewDecimal(-9223372036854775808, 0), false, false, true, true, false},
|
|
{pql.NewDecimal(-9223372036854775808, 19), pql.NewDecimal(-9223372036854775807, 0), false, false, true, true, false},
|
|
}
|
|
for i, test := range tests {
|
|
if got := test.d1.LessThan(test.d2); got != test.expLT {
|
|
t.Fatalf("test LT %d expected %s < %s to be %v, but got: %v", i, test.d1, test.d2, test.expLT, got)
|
|
}
|
|
if got := test.d1.LessThanOrEqualTo(test.d2); got != test.expLTE {
|
|
t.Fatalf("test LTE %d expected %s <= %s to be %v, but got: %v", i, test.d1, test.d2, test.expLTE, got)
|
|
}
|
|
if got := test.d1.GreaterThan(test.d2); got != test.expGT {
|
|
t.Fatalf("test GT %d expected %s > %s to be %v, but got: %v", i, test.d1, test.d2, test.expGT, got)
|
|
}
|
|
if got := test.d1.GreaterThanOrEqualTo(test.d2); got != test.expGTE {
|
|
t.Fatalf("test GTE %d expected %s >= %s to be %v, but got: %v", i, test.d1, test.d2, test.expGTE, got)
|
|
}
|
|
if got := test.d1.EqualTo(test.d2); got != test.expEQ {
|
|
t.Fatalf("test EQ %d expected %s == %s to be %v, but got: %v", i, test.d1, test.d2, test.expEQ, got)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("JSON", func(t *testing.T) {
|
|
t.Run("Unmarshal", func(t *testing.T) {
|
|
tests := []struct {
|
|
json string
|
|
exp pql.Decimal
|
|
}{
|
|
{"1234.56", pql.NewDecimal(123456, 2)},
|
|
}
|
|
for i, test := range tests {
|
|
b := []byte(test.json)
|
|
dec := &pql.Decimal{}
|
|
if err := json.Unmarshal(b, &dec); err != nil {
|
|
panic(err)
|
|
}
|
|
if !reflect.DeepEqual(*dec, test.exp) {
|
|
t.Fatalf("test %d expected: %T, but got: %T", i, test.exp, dec)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|