mirror of https://github.com/goccy/go-json.git
196 lines
3.4 KiB
Go
196 lines
3.4 KiB
Go
// Copyright 2011 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package json_test
|
|
|
|
import (
|
|
"regexp"
|
|
"testing"
|
|
|
|
"github.com/goccy/go-json"
|
|
)
|
|
|
|
func TestNumberIsValid(t *testing.T) {
|
|
// From: https://stackoverflow.com/a/13340826
|
|
var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`)
|
|
|
|
validTests := []string{
|
|
"0",
|
|
"-0",
|
|
"1",
|
|
"-1",
|
|
"0.1",
|
|
"-0.1",
|
|
"1234",
|
|
"-1234",
|
|
"12.34",
|
|
"-12.34",
|
|
"12E0",
|
|
"12E1",
|
|
"12e34",
|
|
"12E-0",
|
|
"12e+1",
|
|
"12e-34",
|
|
"-12E0",
|
|
"-12E1",
|
|
"-12e34",
|
|
"-12E-0",
|
|
"-12e+1",
|
|
"-12e-34",
|
|
"1.2E0",
|
|
"1.2E1",
|
|
"1.2e34",
|
|
"1.2E-0",
|
|
"1.2e+1",
|
|
"1.2e-34",
|
|
"-1.2E0",
|
|
"-1.2E1",
|
|
"-1.2e34",
|
|
"-1.2E-0",
|
|
"-1.2e+1",
|
|
"-1.2e-34",
|
|
"0E0",
|
|
"0E1",
|
|
"0e34",
|
|
"0E-0",
|
|
"0e+1",
|
|
"0e-34",
|
|
"-0E0",
|
|
"-0E1",
|
|
"-0e34",
|
|
"-0E-0",
|
|
"-0e+1",
|
|
"-0e-34",
|
|
}
|
|
|
|
for i, test := range validTests {
|
|
if !isValidNumber(test) {
|
|
t.Errorf("%d: %s should be valid", i, test)
|
|
}
|
|
|
|
var f float64
|
|
if err := json.Unmarshal([]byte(test), &f); err != nil {
|
|
t.Errorf("%d: %s should be valid but Unmarshal failed: %v", i, test, err)
|
|
}
|
|
|
|
if !jsonNumberRegexp.MatchString(test) {
|
|
t.Errorf("%d: %s should be valid but regexp does not match", i, test)
|
|
}
|
|
}
|
|
|
|
invalidTests := []string{
|
|
"",
|
|
"invalid",
|
|
"1.0.1",
|
|
"1..1",
|
|
"-1-2",
|
|
"012a42",
|
|
//"01.2",
|
|
//"012",
|
|
"12E12.12",
|
|
"1e2e3",
|
|
"1e+-2",
|
|
"1e--23",
|
|
"1e",
|
|
"e1",
|
|
"1e+",
|
|
"1ea",
|
|
"1a",
|
|
"1.a",
|
|
//"1.",
|
|
//"01",
|
|
//"1.e1",
|
|
}
|
|
|
|
for i, test := range invalidTests {
|
|
if isValidNumber(test) {
|
|
t.Errorf("%d: %s should be invalid", i, test)
|
|
}
|
|
|
|
var f float64
|
|
if err := json.Unmarshal([]byte(test), &f); err == nil {
|
|
t.Errorf("%d: %s should be invalid but unmarshal wrote %v", i, test, f)
|
|
}
|
|
|
|
if jsonNumberRegexp.MatchString(test) {
|
|
t.Errorf("%d: %s should be invalid but matches regexp", i, test)
|
|
}
|
|
}
|
|
}
|
|
|
|
// isValidNumber reports whether s is a valid JSON number literal.
|
|
func isValidNumber(s string) bool {
|
|
// This function implements the JSON numbers grammar.
|
|
// See https://tools.ietf.org/html/rfc7159#section-6
|
|
// and https://www.json.org/img/number.png
|
|
|
|
if s == "" {
|
|
return false
|
|
}
|
|
|
|
// Optional -
|
|
if s[0] == '-' {
|
|
s = s[1:]
|
|
if s == "" {
|
|
return false
|
|
}
|
|
}
|
|
|
|
// Digits
|
|
switch {
|
|
default:
|
|
return false
|
|
|
|
case s[0] == '0':
|
|
s = s[1:]
|
|
|
|
case '1' <= s[0] && s[0] <= '9':
|
|
s = s[1:]
|
|
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
|
|
s = s[1:]
|
|
}
|
|
}
|
|
|
|
// . followed by 1 or more digits.
|
|
if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
|
|
s = s[2:]
|
|
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
|
|
s = s[1:]
|
|
}
|
|
}
|
|
|
|
// e or E followed by an optional - or + and
|
|
// 1 or more digits.
|
|
if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
|
|
s = s[1:]
|
|
if s[0] == '+' || s[0] == '-' {
|
|
s = s[1:]
|
|
if s == "" {
|
|
return false
|
|
}
|
|
}
|
|
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
|
|
s = s[1:]
|
|
}
|
|
}
|
|
|
|
// Make sure we are at the end.
|
|
return s == ""
|
|
}
|
|
|
|
func BenchmarkNumberIsValid(b *testing.B) {
|
|
s := "-61657.61667E+61673"
|
|
for i := 0; i < b.N; i++ {
|
|
isValidNumber(s)
|
|
}
|
|
}
|
|
|
|
func BenchmarkNumberIsValidRegexp(b *testing.B) {
|
|
var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`)
|
|
s := "-61657.61667E+61673"
|
|
for i := 0; i < b.N; i++ {
|
|
jsonNumberRegexp.MatchString(s)
|
|
}
|
|
}
|