Format files before working on them

gjson_test.go was formatted with gofumpt
This commit is contained in:
ccoVeille 2024-04-23 13:35:22 +02:00
parent 2ba56cc086
commit 0b9aa79774
No known key found for this signature in database
4 changed files with 159 additions and 118 deletions

View File

@ -1,12 +1,12 @@
<p align="center"> <p align="center">
<img <img
src="logo.png" src="logo.png"
width="240" height="78" border="0" alt="GJSON"> width="240" height="78" border="0" alt="GJSON">
<br> <br>
<a href="https://godoc.org/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a> <a href="https://godoc.org/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
<a href="https://tidwall.com/gjson-play"><img src="https://img.shields.io/badge/%F0%9F%8F%90-playground-9900cc.svg?style=flat-square" alt="GJSON Playground"></a> <a href="https://tidwall.com/gjson-play"><img src="https://img.shields.io/badge/%F0%9F%8F%90-playground-9900cc.svg?style=flat-square" alt="GJSON Playground"></a>
<a href="SYNTAX.md"><img src="https://img.shields.io/badge/{}-syntax-33aa33.svg?style=flat-square" alt="GJSON Syntax"></a> <a href="SYNTAX.md"><img src="https://img.shields.io/badge/{}-syntax-33aa33.svg?style=flat-square" alt="GJSON Syntax"></a>
</p> </p>
<p align="center">get json values quickly</a></p> <p align="center">get json values quickly</a></p>
@ -34,7 +34,7 @@ $ go get -u github.com/tidwall/gjson
This will retrieve the library. This will retrieve the library.
## Get a value ## Get a value
Get searches json for the specified path. A path is in dot syntax, such as "name.last" or "age". When the value is found it's returned immediately. Get searches json for the specified path. A path is in dot syntax, such as "name.last" or "age". When the value is found it's returned immediately.
```go ```go
package main package main
@ -93,9 +93,9 @@ The dot and wildcard characters can be escaped with '\\'.
"friends.1.last" >> "Craig" "friends.1.last" >> "Craig"
``` ```
You can also query an array for the first match by using `#(...)`, or find all You can also query an array for the first match by using `#(...)`, or find all
matches with `#(...)#`. Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` matches with `#(...)#`. Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=`
comparison operators and the simple pattern matching `%` (like) and `!%` comparison operators and the simple pattern matching `%` (like) and `!%`
(not like) operators. (not like) operators.
``` ```
@ -109,13 +109,13 @@ friends.#(nets.#(=="fb"))#.first >> ["Dale","Roger"]
*Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was *Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was
changed in v1.3.0 as to avoid confusion with the new changed in v1.3.0 as to avoid confusion with the new
[multipath](SYNTAX.md#multipaths) syntax. For backwards compatibility, [multipath](SYNTAX.md#multipaths) syntax. For backwards compatibility,
`#[...]` will continue to work until the next major release.* `#[...]` will continue to work until the next major release.*
## Result Type ## Result Type
GJSON supports the json types `string`, `number`, `bool`, and `null`. GJSON supports the json types `string`, `number`, `bool`, and `null`.
Arrays and Objects are returned as their raw json types. Arrays and Objects are returned as their raw json types.
The `Result` type holds one of these: The `Result` type holds one of these:
@ -179,14 +179,14 @@ result.Int() int64 // -9223372036854775808 to 9223372036854775807
result.Uint() uint64 // 0 to 18446744073709551615 result.Uint() uint64 // 0 to 18446744073709551615
``` ```
## Modifiers and path chaining ## Modifiers and path chaining
New in version 1.2 is support for modifier functions and path chaining. New in version 1.2 is support for modifier functions and path chaining.
A modifier is a path component that performs custom processing on the A modifier is a path component that performs custom processing on the
json. json.
Multiple paths can be "chained" together using the pipe character. Multiple paths can be "chained" together using the pipe character.
This is useful for getting results from a modified query. This is useful for getting results from a modified query.
For example, using the built-in `@reverse` modifier on the above json document, For example, using the built-in `@reverse` modifier on the above json document,
@ -215,13 +215,13 @@ There are currently the following built-in modifiers:
### Modifier arguments ### Modifier arguments
A modifier may accept an optional argument. The argument can be a valid JSON A modifier may accept an optional argument. The argument can be a valid JSON
document or just characters. document or just characters.
For example, the `@pretty` modifier takes a json object as its argument. For example, the `@pretty` modifier takes a json object as its argument.
``` ```
@pretty:{"sortKeys":true} @pretty:{"sortKeys":true}
``` ```
Which makes the json pretty and orders all of its keys. Which makes the json pretty and orders all of its keys.
@ -240,7 +240,7 @@ Which makes the json pretty and orders all of its keys.
} }
``` ```
*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`. *The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`.
Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.* Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
### Custom modifiers ### Custom modifiers
@ -269,7 +269,7 @@ gjson.AddModifier("case", func(json, arg string) string {
## JSON Lines ## JSON Lines
There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array. There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array.
For example: For example:
@ -305,14 +305,14 @@ Suppose you want all the last names from the following json:
{ {
"programmers": [ "programmers": [
{ {
"firstName": "Janet", "firstName": "Janet",
"lastName": "McLaughlin", "lastName": "McLaughlin",
}, { }, {
"firstName": "Elliotte", "firstName": "Elliotte",
"lastName": "Hunter", "lastName": "Hunter",
}, { }, {
"firstName": "Jason", "firstName": "Jason",
"lastName": "Harold", "lastName": "Harold",
} }
] ]
} }
@ -336,7 +336,7 @@ println(name.String()) // prints "Elliotte"
## Iterate through an object or array ## Iterate through an object or array
The `ForEach` function allows for quickly iterating through an object or array. The `ForEach` function allows for quickly iterating through an object or array.
The key and value are passed to the iterator function for objects. The key and value are passed to the iterator function for objects.
Only the value is passed for arrays. Only the value is passed for arrays.
Returning `false` from an iterator will stop iteration. Returning `false` from an iterator will stop iteration.
@ -344,7 +344,7 @@ Returning `false` from an iterator will stop iteration.
```go ```go
result := gjson.Get(json, "programmers") result := gjson.Get(json, "programmers")
result.ForEach(func(key, value gjson.Result) bool { result.ForEach(func(key, value gjson.Result) bool {
println(value.String()) println(value.String())
return true // keep iterating return true // keep iterating
}) })
``` ```
@ -363,7 +363,7 @@ gjson.Get(json, "name.last")
## Check for the existence of a value ## Check for the existence of a value
Sometimes you just want to know if a value exists. Sometimes you just want to know if a value exists.
```go ```go
value := gjson.Get(json, "name.last") value := gjson.Get(json, "name.last")
@ -429,8 +429,8 @@ This is a best-effort no allocation sub slice of the original json. This method
## Performance ## Performance
Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/), Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/),
[ffjson](https://github.com/pquerna/ffjson), [ffjson](https://github.com/pquerna/ffjson),
[EasyJSON](https://github.com/mailru/easyjson), [EasyJSON](https://github.com/mailru/easyjson),
[jsonparser](https://github.com/buger/jsonparser), [jsonparser](https://github.com/buger/jsonparser),
and [json-iterator](https://github.com/json-iterator/go) and [json-iterator](https://github.com/json-iterator/go)
@ -459,7 +459,7 @@ JSON document used:
"width": 500, "width": 500,
"height": 500 "height": 500
}, },
"image": { "image": {
"src": "Images/Sun.png", "src": "Images/Sun.png",
"hOffset": 250, "hOffset": 250,
"vOffset": 250, "vOffset": 250,
@ -474,7 +474,7 @@ JSON document used:
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
} }
} }
} }
``` ```
Each operation was rotated through one of the following search paths: Each operation was rotated through one of the following search paths:

View File

@ -15,12 +15,12 @@ This document is designed to explain the structure of a GJSON Path through examp
- [Multipaths](#multipaths) - [Multipaths](#multipaths)
- [Literals](#literals) - [Literals](#literals)
The definitive implementation is [github.com/tidwall/gjson](https://github.com/tidwall/gjson). The definitive implementation is [github.com/tidwall/gjson](https://github.com/tidwall/gjson).
Use the [GJSON Playground](https://gjson.dev) to experiment with the syntax online. Use the [GJSON Playground](https://gjson.dev) to experiment with the syntax online.
## Path structure ## Path structure
A GJSON Path is intended to be easily expressed as a series of components separated by a `.` character. A GJSON Path is intended to be easily expressed as a series of components separated by a `.` character.
Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, `!`, and `?`. Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, `!`, and `?`.
@ -44,7 +44,7 @@ Given this JSON
The following GJSON Paths evaluate to the accompanying values. The following GJSON Paths evaluate to the accompanying values.
### Basic ### Basic
In many cases you'll just want to retrieve values by object name or array index. In many cases you'll just want to retrieve values by object name or array index.
@ -61,7 +61,7 @@ friends.1.first "Roger"
### Wildcards ### Wildcards
A key may contain the special wildcard characters `*` and `?`. A key may contain the special wildcard characters `*` and `?`.
The `*` will match on any zero+ characters, and `?` matches on any one character. The `*` will match on any zero+ characters, and `?` matches on any one character.
```go ```go
@ -71,7 +71,7 @@ c?ildren.0 "Sara"
### Escape character ### Escape character
Special purpose characters, such as `.`, `*`, and `?` can be escaped with `\`. Special purpose characters, such as `.`, `*`, and `?` can be escaped with `\`.
```go ```go
fav\.movie "Deer Hunter" fav\.movie "Deer Hunter"
@ -82,13 +82,13 @@ You'll also need to make sure that the `\` character is correctly escaped when h
```go ```go
// Go // Go
val := gjson.Get(json, "fav\\.movie") // must escape the slash val := gjson.Get(json, "fav\\.movie") // must escape the slash
val := gjson.Get(json, `fav\.movie`) // no need to escape the slash val := gjson.Get(json, `fav\.movie`) // no need to escape the slash
``` ```
```rust ```rust
// Rust // Rust
let val = gjson::get(json, "fav\\.movie") // must escape the slash let val = gjson::get(json, "fav\\.movie") // must escape the slash
let val = gjson::get(json, r#"fav\.movie"#) // no need to escape the slash let val = gjson::get(json, r#"fav\.movie"#) // no need to escape the slash
``` ```
@ -105,8 +105,8 @@ friends.#.age [44,68,47]
### Queries ### Queries
You can also query an array for the first match by using `#(...)`, or find all matches with `#(...)#`. You can also query an array for the first match by using `#(...)`, or find all matches with `#(...)#`.
Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators, Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators,
and the simple pattern matching `%` (like) and `!%` (not like) operators. and the simple pattern matching `%` (like) and `!%` (not like) operators.
```go ```go
@ -131,7 +131,7 @@ friends.#(nets.#(=="fb"))#.first >> ["Dale","Roger"]
``` ```
*Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was *Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was
changed in v1.3.0 as to avoid confusion with the new [multipath](#multipaths) changed in v1.3.0 as to avoid confusion with the new [multipath](#multipaths)
syntax. For backwards compatibility, `#[...]` will continue to work until the syntax. For backwards compatibility, `#[...]` will continue to work until the
next major release.* next major release.*
@ -185,9 +185,9 @@ vals.#(b!=~*)#.a >> [11]
### Dot vs Pipe ### Dot vs Pipe
The `.` is standard separator, but it's also possible to use a `|`. The `.` is standard separator, but it's also possible to use a `|`.
In most cases they both end up returning the same results. In most cases they both end up returning the same results.
The cases where`|` differs from `.` is when it's used after the `#` for [Arrays](#arrays) and [Queries](#queries). The cases where`|` differs from `.` is when it's used after the `#` for [Arrays](#arrays) and [Queries](#queries).
Here are some examples Here are some examples
@ -221,8 +221,8 @@ The `.first` suffix will process the `first` path on each array element *before*
["Dale","Jane"] ["Dale","Jane"]
``` ```
But the `|first` suffix actually processes the `first` path *after* the previous result. But the `|first` suffix actually processes the `first` path *after* the previous result.
Since the previous result is an array, not an object, it's not possible to process Since the previous result is an array, not an object, it's not possible to process
because `first` does not exist. because `first` does not exist.
Yet, `|0` suffix returns Yet, `|0` suffix returns
@ -286,12 +286,12 @@ Which makes the json pretty and orders all of its keys.
} }
``` ```
*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`. *The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`.
Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.* Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
#### Custom modifiers #### Custom modifiers
You can also add custom modifiers. You can also add custom modifiers.
For example, here we create a modifier which makes the entire JSON payload upper or lower case. For example, here we create a modifier which makes the entire JSON payload upper or lower case.
@ -323,11 +323,11 @@ For example, using the given multipath:
{name.first,age,"the_murphys":friends.#(last="Murphy")#.first} {name.first,age,"the_murphys":friends.#(last="Murphy")#.first}
``` ```
Here we selected the first name, age, and the first name for friends with the Here we selected the first name, age, and the first name for friends with the
last name "Murphy". last name "Murphy".
You'll notice that an optional key can be provided, in this case You'll notice that an optional key can be provided, in this case
"the_murphys", to force assign a key to a value. Otherwise, the name of the "the_murphys", to force assign a key to a value. Otherwise, the name of the
actual field will be used, in this case "first". If a name cannot be actual field will be used, in this case "first". If a name cannot be
determined, then "_" is used. determined, then "_" is used.
@ -339,9 +339,9 @@ This results in
### Literals ### Literals
Starting with v1.12.0, GJSON added support of json literals, which provides a way for constructing static blocks of json. This is can be particularly useful when constructing a new json document using [multipaths](#multipaths). Starting with v1.12.0, GJSON added support of json literals, which provides a way for constructing static blocks of json. This is can be particularly useful when constructing a new json document using [multipaths](#multipaths).
A json literal begins with the '!' declaration character. A json literal begins with the '!' declaration character.
For example, using the given multipath: For example, using the given multipath:
@ -351,7 +351,7 @@ For example, using the given multipath:
Here we selected the first name and age. Then add two new fields, "company" and "employed". Here we selected the first name and age. Then add two new fields, "company" and "employed".
This results in This results in
```json ```json
{"first":"Tom","age":37,"company":"Happysoft","employed":true} {"first":"Tom","age":37,"company":"Happysoft","employed":true}

View File

@ -334,7 +334,7 @@ type arrayOrMapResult struct {
} }
func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) { func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
var json = t.Raw json := t.Raw
var i int var i int
var value Result var value Result
var count int var count int
@ -686,7 +686,7 @@ func (t Result) Value() interface{} {
} }
func parseString(json string, i int) (int, string, bool, bool) { func parseString(json string, i int) (int, string, bool, bool) {
var s = i s := i
for ; i < len(json); i++ { for ; i < len(json); i++ {
if json[i] > '\\' { if json[i] > '\\' {
continue continue
@ -724,7 +724,7 @@ func parseString(json string, i int) (int, string, bool, bool) {
} }
func parseNumber(json string, i int) (int, string) { func parseNumber(json string, i int) (int, string) {
var s = i s := i
i++ i++
for ; i < len(json); i++ { for ; i < len(json); i++ {
if json[i] <= ' ' || json[i] == ',' || json[i] == ']' || if json[i] <= ' ' || json[i] == ',' || json[i] == ']' ||
@ -736,7 +736,7 @@ func parseNumber(json string, i int) (int, string) {
} }
func parseLiteral(json string, i int) (int, string) { func parseLiteral(json string, i int) (int, string) {
var s = i s := i
i++ i++
for ; i < len(json); i++ { for ; i < len(json); i++ {
if json[i] < 'a' || json[i] > 'z' { if json[i] < 'a' || json[i] > 'z' {
@ -793,8 +793,7 @@ func parseArrayPath(path string) (r arrayPathResult) {
} else if path[1] == '[' || path[1] == '(' { } else if path[1] == '[' || path[1] == '(' {
// query // query
r.query.on = true r.query.on = true
qpath, op, value, _, fi, vesc, ok := qpath, op, value, _, fi, vesc, ok := parseQuery(path[i:])
parseQuery(path[i:])
if !ok { if !ok {
// bad query, end now // bad query, end now
break break
@ -1103,7 +1102,7 @@ func parseObject(c *parseContext, i int, path string) (int, bool) {
// this is slightly different from getting s string value // this is slightly different from getting s string value
// because we don't need the outer quotes. // because we don't need the outer quotes.
i++ i++
var s = i s := i
for ; i < len(c.json); i++ { for ; i < len(c.json); i++ {
if c.json[i] > '\\' { if c.json[i] > '\\' {
continue continue
@ -1400,6 +1399,7 @@ func queryMatches(rp *arrayPathResult, value Result) bool {
} }
return false return false
} }
func parseArray(c *parseContext, i int, path string) (int, bool) { func parseArray(c *parseContext, i int, path string) (int, bool) {
var pmatch, vesc, ok, hit bool var pmatch, vesc, ok, hit bool
var val string var val string
@ -1619,8 +1619,8 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
c.pipe = right c.pipe = right
c.piped = true c.piped = true
} }
var indexes = make([]int, 0, 64) indexes := make([]int, 0, 64)
var jsons = make([]byte, 0, 64) jsons := make([]byte, 0, 64)
jsons = append(jsons, '[') jsons = append(jsons, '[')
for j, k := 0, 0; j < len(alog); j++ { for j, k := 0, 0; j < len(alog); j++ {
idx := alog[j] idx := alog[j]
@ -2095,7 +2095,7 @@ func Get(json, path string) Result {
} }
} }
var i int var i int
var c = &parseContext{json: json} c := &parseContext{json: json}
if len(path) >= 2 && path[0] == '.' && path[1] == '.' { if len(path) >= 2 && path[0] == '.' && path[1] == '.' {
c.lines = true c.lines = true
parseArray(c, 0, path[2:]) parseArray(c, 0, path[2:])
@ -2136,7 +2136,7 @@ func runeit(json string) rune {
// unescape unescapes a string // unescape unescapes a string
func unescape(json string) string { func unescape(json string) string {
var str = make([]byte, 0, len(json)) str := make([]byte, 0, len(json))
for i := 0; i < len(json); i++ { for i := 0; i < len(json); i++ {
switch { switch {
default: default:
@ -2377,6 +2377,7 @@ func validpayload(data []byte, i int) (outi int, ok bool) {
} }
return i, false return i, false
} }
func validany(data []byte, i int) (outi int, ok bool) { func validany(data []byte, i int) (outi int, ok bool) {
for ; i < len(data); i++ { for ; i < len(data); i++ {
switch data[i] { switch data[i] {
@ -2402,6 +2403,7 @@ func validany(data []byte, i int) (outi int, ok bool) {
} }
return i, false return i, false
} }
func validobject(data []byte, i int) (outi int, ok bool) { func validobject(data []byte, i int) (outi int, ok bool) {
for ; i < len(data); i++ { for ; i < len(data); i++ {
switch data[i] { switch data[i] {
@ -2444,6 +2446,7 @@ func validobject(data []byte, i int) (outi int, ok bool) {
} }
return i, false return i, false
} }
func validcolon(data []byte, i int) (outi int, ok bool) { func validcolon(data []byte, i int) (outi int, ok bool) {
for ; i < len(data); i++ { for ; i < len(data); i++ {
switch data[i] { switch data[i] {
@ -2457,6 +2460,7 @@ func validcolon(data []byte, i int) (outi int, ok bool) {
} }
return i, false return i, false
} }
func validcomma(data []byte, i int, end byte) (outi int, ok bool) { func validcomma(data []byte, i int, end byte) (outi int, ok bool) {
for ; i < len(data); i++ { for ; i < len(data); i++ {
switch data[i] { switch data[i] {
@ -2472,6 +2476,7 @@ func validcomma(data []byte, i int, end byte) (outi int, ok bool) {
} }
return i, false return i, false
} }
func validarray(data []byte, i int) (outi int, ok bool) { func validarray(data []byte, i int) (outi int, ok bool) {
for ; i < len(data); i++ { for ; i < len(data); i++ {
switch data[i] { switch data[i] {
@ -2495,6 +2500,7 @@ func validarray(data []byte, i int) (outi int, ok bool) {
} }
return i, false return i, false
} }
func validstring(data []byte, i int) (outi int, ok bool) { func validstring(data []byte, i int) (outi int, ok bool) {
for ; i < len(data); i++ { for ; i < len(data); i++ {
if data[i] < ' ' { if data[i] < ' ' {
@ -2527,6 +2533,7 @@ func validstring(data []byte, i int) (outi int, ok bool) {
} }
return i, false return i, false
} }
func validnumber(data []byte, i int) (outi int, ok bool) { func validnumber(data []byte, i int) (outi int, ok bool) {
i-- i--
// sign // sign
@ -2609,6 +2616,7 @@ func validtrue(data []byte, i int) (outi int, ok bool) {
} }
return i, false return i, false
} }
func validfalse(data []byte, i int) (outi int, ok bool) { func validfalse(data []byte, i int) (outi int, ok bool) {
if i+4 <= len(data) && data[i] == 'a' && data[i+1] == 'l' && if i+4 <= len(data) && data[i] == 'a' && data[i+1] == 'l' &&
data[i+2] == 's' && data[i+3] == 'e' { data[i+2] == 's' && data[i+3] == 'e' {
@ -2616,6 +2624,7 @@ func validfalse(data []byte, i int) (outi int, ok bool) {
} }
return i, false return i, false
} }
func validnull(data []byte, i int) (outi int, ok bool) { func validnull(data []byte, i int) (outi int, ok bool) {
if i+3 <= len(data) && data[i] == 'u' && data[i+1] == 'l' && if i+3 <= len(data) && data[i] == 'u' && data[i+1] == 'l' &&
data[i+2] == 'l' { data[i+2] == 'l' {

View File

@ -199,7 +199,6 @@ func TestPath(t *testing.T) {
get("loggy.programmers.2.email") get("loggy.programmers.2.email")
get("lastly.end\\.\\.\\.ing") get("lastly.end\\.\\.\\.ing")
get("lastly.yay") get("lastly.yay")
} }
func TestTimeResult(t *testing.T) { func TestTimeResult(t *testing.T) {
@ -216,8 +215,10 @@ func TestParseAny(t *testing.T) {
func TestManyVariousPathCounts(t *testing.T) { func TestManyVariousPathCounts(t *testing.T) {
json := `{"a":"a","b":"b","c":"c"}` json := `{"a":"a","b":"b","c":"c"}`
counts := []int{3, 4, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127, counts := []int{
128, 129, 255, 256, 257, 511, 512, 513} 3, 4, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127,
128, 129, 255, 256, 257, 511, 512, 513,
}
paths := []string{"a", "b", "c"} paths := []string{"a", "b", "c"}
expects := []string{"a", "b", "c"} expects := []string{"a", "b", "c"}
for _, count := range counts { for _, count := range counts {
@ -238,6 +239,7 @@ func TestManyVariousPathCounts(t *testing.T) {
} }
} }
} }
func TestManyRecursion(t *testing.T) { func TestManyRecursion(t *testing.T) {
var json string var json string
var path string var path string
@ -252,6 +254,7 @@ func TestManyRecursion(t *testing.T) {
path = path[1:] path = path[1:]
assert(t, GetMany(json, path)[0].String() == "b") assert(t, GetMany(json, path)[0].String() == "b")
} }
func TestByteSafety(t *testing.T) { func TestByteSafety(t *testing.T) {
jsonb := []byte(`{"name":"Janet","age":38}`) jsonb := []byte(`{"name":"Janet","age":38}`)
mtok := GetBytes(jsonb, "name") mtok := GetBytes(jsonb, "name")
@ -348,6 +351,7 @@ func TestPlus53BitInts(t *testing.T) {
// flip the number to the negative sign. // flip the number to the negative sign.
assert(t, Get(json, "overflow_int64").Int() == -9223372036854775808) assert(t, Get(json, "overflow_int64").Int() == -9223372036854775808)
} }
func TestIssue38(t *testing.T) { func TestIssue38(t *testing.T) {
// These should not fail, even though the unicode is invalid. // These should not fail, even though the unicode is invalid.
Get(`["S3O PEDRO DO BUTI\udf93"]`, "0") Get(`["S3O PEDRO DO BUTI\udf93"]`, "0")
@ -359,6 +363,7 @@ func TestIssue38(t *testing.T) {
Get(`["S3O PEDRO DO BUTI\udf93\u1345"]`, "0") Get(`["S3O PEDRO DO BUTI\udf93\u1345"]`, "0")
Get(`["S3O PEDRO DO BUTI\udf93\u1345asd"]`, "0") Get(`["S3O PEDRO DO BUTI\udf93\u1345asd"]`, "0")
} }
func TestTypes(t *testing.T) { func TestTypes(t *testing.T) {
assert(t, (Result{Type: String}).Type.String() == "String") assert(t, (Result{Type: String}).Type.String() == "String")
assert(t, (Result{Type: Number}).Type.String() == "Number") assert(t, (Result{Type: Number}).Type.String() == "Number")
@ -404,6 +409,7 @@ func TestTypes(t *testing.T) {
assert(t, (Result{Type: False}).Float() == 0) assert(t, (Result{Type: False}).Float() == 0)
assert(t, (Result{Type: Number, Num: 1}).Float() == 1) assert(t, (Result{Type: Number, Num: 1}).Float() == 1)
} }
func TestForEach(t *testing.T) { func TestForEach(t *testing.T) {
Result{}.ForEach(nil) Result{}.ForEach(nil)
Result{Type: String, Str: "Hello"}.ForEach(func(_, value Result) bool { Result{Type: String, Str: "Hello"}.ForEach(func(_, value Result) bool {
@ -423,6 +429,7 @@ func TestForEach(t *testing.T) {
ParseBytes([]byte(`{"bad`)).ForEach(nil) ParseBytes([]byte(`{"bad`)).ForEach(nil)
ParseBytes([]byte(`{"ok":"bad`)).ForEach(nil) ParseBytes([]byte(`{"ok":"bad`)).ForEach(nil)
} }
func TestMap(t *testing.T) { func TestMap(t *testing.T) {
assert(t, len(ParseBytes([]byte(`"asdf"`)).Map()) == 0) assert(t, len(ParseBytes([]byte(`"asdf"`)).Map()) == 0)
assert(t, ParseBytes([]byte(`{"asdf":"ghjk"`)).Map()["asdf"].String() == assert(t, ParseBytes([]byte(`{"asdf":"ghjk"`)).Map()["asdf"].String() ==
@ -431,6 +438,7 @@ func TestMap(t *testing.T) {
assert(t, Result{Type: JSON, Raw: "**invalid**"}.Value() == nil) assert(t, Result{Type: JSON, Raw: "**invalid**"}.Value() == nil)
assert(t, Result{Type: JSON, Raw: "{"}.Map() != nil) assert(t, Result{Type: JSON, Raw: "{"}.Map() != nil)
} }
func TestBasic1(t *testing.T) { func TestBasic1(t *testing.T) {
mtok := get(basicJSON, `loggy.programmers`) mtok := get(basicJSON, `loggy.programmers`)
var count int var count int
@ -474,6 +482,7 @@ func TestBasic1(t *testing.T) {
t.Fatalf("expected %v, got %v", 3, count) t.Fatalf("expected %v, got %v", 3, count)
} }
} }
func TestBasic2(t *testing.T) { func TestBasic2(t *testing.T) {
mtok := get(basicJSON, `loggy.programmers.#[age=101].firstName`) mtok := get(basicJSON, `loggy.programmers.#[age=101].firstName`)
if mtok.String() != "1002.3" { if mtok.String() != "1002.3" {
@ -509,6 +518,7 @@ func TestBasic2(t *testing.T) {
mtok.Map()["programmers"].Array()[1].Map()["firstName"].Str) mtok.Map()["programmers"].Array()[1].Map()["firstName"].Str)
} }
} }
func TestBasic3(t *testing.T) { func TestBasic3(t *testing.T) {
var mtok Result var mtok Result
if Parse(basicJSON).Get("loggy.programmers").Get("1"). if Parse(basicJSON).Get("loggy.programmers").Get("1").
@ -549,6 +559,7 @@ func TestBasic3(t *testing.T) {
t.Fatalf("expected 0, got %v", len(mtok.Array())) t.Fatalf("expected 0, got %v", len(mtok.Array()))
} }
} }
func TestBasic4(t *testing.T) { func TestBasic4(t *testing.T) {
if get(basicJSON, "items.3.tags.#").Num != 3 { if get(basicJSON, "items.3.tags.#").Num != 3 {
t.Fatalf("expected 3, got %v", get(basicJSON, "items.3.tags.#").Num) t.Fatalf("expected 3, got %v", get(basicJSON, "items.3.tags.#").Num)
@ -593,6 +604,7 @@ func TestBasic4(t *testing.T) {
t.Fatal("should be nil") t.Fatal("should be nil")
} }
} }
func TestBasic5(t *testing.T) { func TestBasic5(t *testing.T) {
token := get(basicJSON, "age") token := get(basicJSON, "age")
if token.String() != "100" { if token.String() != "100" {
@ -630,8 +642,9 @@ func TestBasic5(t *testing.T) {
t.Fatalf("expecting %v, got %v", "Jason", fn) t.Fatalf("expecting %v, got %v", "Jason", fn)
} }
} }
func TestUnicode(t *testing.T) { func TestUnicode(t *testing.T) {
var json = `{"key":0,"的情况下解":{"key":1,"的情况":2}}` json := `{"key":0,"的情况下解":{"key":1,"的情况":2}}`
if Get(json, "的情况下解.key").Num != 1 { if Get(json, "的情况下解.key").Num != 1 {
t.Fatal("fail") t.Fatal("fail")
} }
@ -659,11 +672,13 @@ func TestUnescape(t *testing.T) {
unescape(string([]byte{'\\', '\\', 0})) unescape(string([]byte{'\\', '\\', 0}))
unescape(string([]byte{'\\', '/', '\\', 'b', '\\', 'f'})) unescape(string([]byte{'\\', '/', '\\', 'b', '\\', 'f'}))
} }
func assert(t testing.TB, cond bool) { func assert(t testing.TB, cond bool) {
if !cond { if !cond {
panic("assert failed") panic("assert failed")
} }
} }
func TestLess(t *testing.T) { func TestLess(t *testing.T) {
assert(t, !Result{Type: Null}.Less(Result{Type: Null}, true)) assert(t, !Result{Type: Null}.Less(Result{Type: Null}, true))
assert(t, Result{Type: Null}.Less(Result{Type: False}, true)) assert(t, Result{Type: Null}.Less(Result{Type: False}, true))
@ -673,18 +688,30 @@ func TestLess(t *testing.T) {
assert(t, Result{Type: Null}.Less(Result{Type: String}, true)) assert(t, Result{Type: Null}.Less(Result{Type: String}, true))
assert(t, !Result{Type: False}.Less(Result{Type: Null}, true)) assert(t, !Result{Type: False}.Less(Result{Type: Null}, true))
assert(t, Result{Type: False}.Less(Result{Type: True}, true)) assert(t, Result{Type: False}.Less(Result{Type: True}, true))
assert(t, Result{Type: String, Str: "abc"}.Less(Result{Type: String, assert(t, Result{Type: String, Str: "abc"}.Less(Result{
Str: "bcd"}, true)) Type: String,
assert(t, Result{Type: String, Str: "ABC"}.Less(Result{Type: String, Str: "bcd",
Str: "abc"}, true)) }, true))
assert(t, !Result{Type: String, Str: "ABC"}.Less(Result{Type: String, assert(t, Result{Type: String, Str: "ABC"}.Less(Result{
Str: "abc"}, false)) Type: String,
assert(t, Result{Type: Number, Num: 123}.Less(Result{Type: Number, Str: "abc",
Num: 456}, true)) }, true))
assert(t, !Result{Type: Number, Num: 456}.Less(Result{Type: Number, assert(t, !Result{Type: String, Str: "ABC"}.Less(Result{
Num: 123}, true)) Type: String,
assert(t, !Result{Type: Number, Num: 456}.Less(Result{Type: Number, Str: "abc",
Num: 456}, true)) }, false))
assert(t, Result{Type: Number, Num: 123}.Less(Result{
Type: Number,
Num: 456,
}, true))
assert(t, !Result{Type: Number, Num: 456}.Less(Result{
Type: Number,
Num: 123,
}, true))
assert(t, !Result{Type: Number, Num: 456}.Less(Result{
Type: Number,
Num: 456,
}, true))
assert(t, stringLessInsensitive("abcde", "BBCDE")) assert(t, stringLessInsensitive("abcde", "BBCDE"))
assert(t, stringLessInsensitive("abcde", "bBCDE")) assert(t, stringLessInsensitive("abcde", "bBCDE"))
assert(t, stringLessInsensitive("Abcde", "BBCDE")) assert(t, stringLessInsensitive("Abcde", "BBCDE"))
@ -776,7 +803,7 @@ var exampleJSON = `{
}` }`
func TestUnmarshalMap(t *testing.T) { func TestUnmarshalMap(t *testing.T) {
var m1 = Parse(exampleJSON).Value().(map[string]interface{}) m1 := Parse(exampleJSON).Value().(map[string]interface{})
var m2 map[string]interface{} var m2 map[string]interface{}
if err := json.Unmarshal([]byte(exampleJSON), &m2); err != nil { if err := json.Unmarshal([]byte(exampleJSON), &m2); err != nil {
t.Fatal(err) t.Fatal(err)
@ -795,9 +822,9 @@ func TestUnmarshalMap(t *testing.T) {
} }
func TestSingleArrayValue(t *testing.T) { func TestSingleArrayValue(t *testing.T) {
var json = `{"key": "value","key2":[1,2,3,4,"A"]}` json := `{"key": "value","key2":[1,2,3,4,"A"]}`
var result = Get(json, "key") result := Get(json, "key")
var array = result.Array() array := result.Array()
if len(array) != 1 { if len(array) != 1 {
t.Fatal("array is empty") t.Fatal("array is empty")
} }
@ -814,7 +841,6 @@ func TestSingleArrayValue(t *testing.T) {
if len(array) != 0 { if len(array) != 0 {
t.Fatalf("got '%v', expected '%v'", len(array), 0) t.Fatalf("got '%v', expected '%v'", len(array), 0)
} }
} }
var manyJSON = ` { var manyJSON = ` {
@ -867,12 +893,15 @@ func TestManyBasic(t *testing.T) {
testMany(true, `[Cat Nancy]`, "name\\.first", "name.first") testMany(true, `[Cat Nancy]`, "name\\.first", "name.first")
testMany(true, `[world]`, strings.Repeat("a.", 70)+"hello") testMany(true, `[world]`, strings.Repeat("a.", 70)+"hello")
} }
func testMany(t *testing.T, json string, paths, expected []string) { func testMany(t *testing.T, json string, paths, expected []string) {
testManyAny(t, json, paths, expected, true) testManyAny(t, json, paths, expected, true)
testManyAny(t, json, paths, expected, false) testManyAny(t, json, paths, expected, false)
} }
func testManyAny(t *testing.T, json string, paths, expected []string, func testManyAny(t *testing.T, json string, paths, expected []string,
bytes bool) { bytes bool,
) {
var result []Result var result []Result
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
var which string var which string
@ -902,6 +931,7 @@ func testManyAny(t *testing.T, json string, paths, expected []string,
} }
} }
} }
func TestIssue20(t *testing.T) { func TestIssue20(t *testing.T) {
json := `{ "name": "FirstName", "name1": "FirstName1", ` + json := `{ "name": "FirstName", "name1": "FirstName1", ` +
`"address": "address1", "addressDetails": "address2", }` `"address": "address1", "addressDetails": "address2", }`
@ -918,10 +948,14 @@ func TestIssue21(t *testing.T) {
"Level1Field4":4, "Level1Field4":4,
"Level1Field2":{ "Level2Field1":[ "value1", "value2" ], "Level1Field2":{ "Level2Field1":[ "value1", "value2" ],
"Level2Field2":{ "Level3Field1":[ { "key1":"value1" } ] } } }` "Level2Field2":{ "Level3Field1":[ { "key1":"value1" } ] } } }`
paths := []string{"Level1Field1", "Level1Field2.Level2Field1", paths := []string{
"Level1Field2.Level2Field2.Level3Field1", "Level1Field4"} "Level1Field1", "Level1Field2.Level2Field1",
expected := []string{"3", `[ "value1", "value2" ]`, "Level1Field2.Level2Field2.Level3Field1", "Level1Field4",
`[ { "key1":"value1" } ]`, "4"} }
expected := []string{
"3", `[ "value1", "value2" ]`,
`[ { "key1":"value1" } ]`, "4",
}
t.Run("SingleMany", func(t *testing.T) { t.Run("SingleMany", func(t *testing.T) {
testMany(t, json, paths, testMany(t, json, paths,
expected) expected)
@ -1097,8 +1131,10 @@ func TestValidBasic(t *testing.T) {
testvalid(t, "[-.123]", false) testvalid(t, "[-.123]", false)
} }
var jsonchars = []string{"{", "[", ",", ":", "}", "]", "1", "0", "true", var jsonchars = []string{
"false", "null", `""`, `"\""`, `"a"`} "{", "[", ",", ":", "}", "]", "1", "0", "true",
"false", "null", `""`, `"\""`, `"a"`,
}
func makeRandomJSONChars(b []byte) { func makeRandomJSONChars(b []byte) {
var bb []byte var bb []byte
@ -1217,6 +1253,7 @@ func TestIssue55(t *testing.T) {
} }
} }
} }
func TestIssue58(t *testing.T) { func TestIssue58(t *testing.T) {
json := `{"data":[{"uid": 1},{"uid": 2}]}` json := `{"data":[{"uid": 1},{"uid": 2}]}`
res := Get(json, `data.#[uid!=1]`).Raw res := Get(json, `data.#[uid!=1]`).Raw
@ -1279,11 +1316,10 @@ null
if i != 4 { if i != 4 {
t.Fatalf("expected '%v', got '%v'", 4, i) t.Fatalf("expected '%v', got '%v'", 4, i)
} }
} }
func TestNumUint64String(t *testing.T) { func TestNumUint64String(t *testing.T) {
var i int64 = 9007199254740993 //2^53 + 1 var i int64 = 9007199254740993 // 2^53 + 1
j := fmt.Sprintf(`{"data": [ %d, "hello" ] }`, i) j := fmt.Sprintf(`{"data": [ %d, "hello" ] }`, i)
res := Get(j, "data.0") res := Get(j, "data.0")
if res.String() != "9007199254740993" { if res.String() != "9007199254740993" {
@ -1312,7 +1348,7 @@ func TestNumBigString(t *testing.T) {
func TestNumFloatString(t *testing.T) { func TestNumFloatString(t *testing.T) {
var i int64 = -9007199254740993 var i int64 = -9007199254740993
j := fmt.Sprintf(`{"data":[ "hello", %d ]}`, i) //No quotes around value!! j := fmt.Sprintf(`{"data":[ "hello", %d ]}`, i) // No quotes around value!!
res := Get(j, "data.1") res := Get(j, "data.1")
if res.String() != "-9007199254740993" { if res.String() != "-9007199254740993" {
t.Fatalf("expected '%v', got '%v'", "-9007199254740993", res.String()) t.Fatalf("expected '%v', got '%v'", "-9007199254740993", res.String())
@ -1321,7 +1357,7 @@ func TestNumFloatString(t *testing.T) {
func TestDuplicateKeys(t *testing.T) { func TestDuplicateKeys(t *testing.T) {
// this is valid json according to the JSON spec // this is valid json according to the JSON spec
var json = `{"name": "Alex","name": "Peter"}` json := `{"name": "Alex","name": "Peter"}`
if Parse(json).Get("name").String() != if Parse(json).Get("name").String() !=
Parse(json).Map()["name"].String() { Parse(json).Map()["name"].String() {
t.Fatalf("expected '%v', got '%v'", t.Fatalf("expected '%v', got '%v'",
@ -1335,7 +1371,7 @@ func TestDuplicateKeys(t *testing.T) {
} }
func TestArrayValues(t *testing.T) { func TestArrayValues(t *testing.T) {
var json = `{"array": ["PERSON1","PERSON2",0],}` json := `{"array": ["PERSON1","PERSON2",0],}`
values := Get(json, "array").Array() values := Get(json, "array").Array()
var output string var output string
for i, val := range values { for i, val := range values {
@ -1354,7 +1390,6 @@ func TestArrayValues(t *testing.T) {
if output != expect { if output != expect {
t.Fatalf("expected '%v', got '%v'", expect, output) t.Fatalf("expected '%v', got '%v'", expect, output)
} }
} }
func BenchmarkValid(b *testing.B) { func BenchmarkValid(b *testing.B) {
@ -1459,7 +1494,6 @@ func TestSplitPipe(t *testing.T) {
split(t, `hello.#[a|1="asdf\"|1324"]#|that.more|yikes`, split(t, `hello.#[a|1="asdf\"|1324"]#|that.more|yikes`,
`hello.#[a|1="asdf\"|1324"]#`, "that.more|yikes", true) `hello.#[a|1="asdf\"|1324"]#`, "that.more|yikes", true)
split(t, `a.#[]#\|b`, "", "", false) split(t, `a.#[]#\|b`, "", "", false)
} }
func TestArrayEx(t *testing.T) { func TestArrayEx(t *testing.T) {
@ -1705,7 +1739,6 @@ func TestQueries(t *testing.T) {
assert(t, Get(json, `i*.f*.#[cust1>=true].first`).Exists()) assert(t, Get(json, `i*.f*.#[cust1>=true].first`).Exists())
assert(t, !Get(json, `i*.f*.#[cust2<false].first`).Exists()) assert(t, !Get(json, `i*.f*.#[cust2<false].first`).Exists())
assert(t, Get(json, `i*.f*.#[cust2<=false].first`).Exists()) assert(t, Get(json, `i*.f*.#[cust2<=false].first`).Exists())
} }
func TestQueryArrayValues(t *testing.T) { func TestQueryArrayValues(t *testing.T) {
@ -1797,8 +1830,7 @@ func TestParseQuery(t *testing.T) {
var path, op, value, remain string var path, op, value, remain string
var ok bool var ok bool
path, op, value, remain, _, _, ok = path, op, value, remain, _, _, ok = parseQuery(`#(service_roles.#(=="one").()==asdf).cap`)
parseQuery(`#(service_roles.#(=="one").()==asdf).cap`)
assert(t, ok && assert(t, ok &&
path == `service_roles.#(=="one").()` && path == `service_roles.#(=="one").()` &&
op == "=" && op == "=" &&
@ -1826,8 +1858,7 @@ func TestParseQuery(t *testing.T) {
value == `` && value == `` &&
remain == ``) remain == ``)
path, op, value, remain, _, _, ok = path, op, value, remain, _, _, ok = parseQuery(`#(a\("\"(".#(=="o\"(ne")%"ab\")").remain`)
parseQuery(`#(a\("\"(".#(=="o\"(ne")%"ab\")").remain`)
assert(t, ok && assert(t, ok &&
path == `a\("\"(".#(=="o\"(ne")` && path == `a\("\"(".#(=="o\"(ne")` &&
op == "%" && op == "%" &&
@ -1836,7 +1867,7 @@ func TestParseQuery(t *testing.T) {
} }
func TestParentSubQuery(t *testing.T) { func TestParentSubQuery(t *testing.T) {
var json = `{ json := `{
"topology": { "topology": {
"instances": [ "instances": [
{ {
@ -1863,7 +1894,7 @@ func TestParentSubQuery(t *testing.T) {
} }
func TestSingleModifier(t *testing.T) { func TestSingleModifier(t *testing.T) {
var data = `{"@key": "value"}` data := `{"@key": "value"}`
assert(t, Get(data, "@key").String() == "value") assert(t, Get(data, "@key").String() == "value")
assert(t, Get(data, "\\@key").String() == "value") assert(t, Get(data, "\\@key").String() == "value")
} }
@ -1945,7 +1976,7 @@ func TestValid(t *testing.T) {
// https://github.com/tidwall/gjson/issues/152 // https://github.com/tidwall/gjson/issues/152
func TestJoin152(t *testing.T) { func TestJoin152(t *testing.T) {
var json = `{ json := `{
"distance": 1374.0, "distance": 1374.0,
"validFrom": "2005-11-14", "validFrom": "2005-11-14",
"historical": { "historical": {
@ -2086,7 +2117,6 @@ func TestVariousFuzz(t *testing.T) {
testJSON1 := `["*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,,,,,,"]` testJSON1 := `["*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,,,,,,"]`
testJSON2 := `#[%"*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,,,,,,""*,*"]` testJSON2 := `#[%"*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,,,,,,""*,*"]`
Get(testJSON1, testJSON2) Get(testJSON1, testJSON2)
} }
func TestSubpathsWithMultipaths(t *testing.T) { func TestSubpathsWithMultipaths(t *testing.T) {
@ -2227,11 +2257,10 @@ func TestModifierDoubleQuotes(t *testing.T) {
`{"name":"Product P4","value":"{\"productId\":\"1cc3\",\"vendorId\":\"20de\"}"},`+ `{"name":"Product P4","value":"{\"productId\":\"1cc3\",\"vendorId\":\"20de\"}"},`+
`{"name":"Product P4","value":"{\"productId\":\"1dd3\",\"vendorId\":\"30de\"}"}`+ `{"name":"Product P4","value":"{\"productId\":\"1dd3\",\"vendorId\":\"30de\"}"}`+
`]`) `]`)
} }
func TestIndexes(t *testing.T) { func TestIndexes(t *testing.T) {
var exampleJSON = `{ exampleJSON := `{
"vals": [ "vals": [
[1,66,{test: 3}], [1,66,{test: 3}],
[4,5,[6]] [4,5,[6]]
@ -2276,7 +2305,7 @@ func TestIndexes(t *testing.T) {
} }
func TestIndexesMatchesRaw(t *testing.T) { func TestIndexesMatchesRaw(t *testing.T) {
var exampleJSON = `{ exampleJSON := `{
"objectArray":[ "objectArray":[
{"first": "Jason", "age": 41}, {"first": "Jason", "age": 41},
{"first": "Dale", "age": 44}, {"first": "Dale", "age": 44},
@ -2312,7 +2341,7 @@ func TestIssue240(t *testing.T) {
} }
func TestKeysValuesModifier(t *testing.T) { func TestKeysValuesModifier(t *testing.T) {
var json = `{ json := `{
"1300014": { "1300014": {
"code": "1300014", "code": "1300014",
"price": 59.18, "price": 59.18,
@ -2341,11 +2370,15 @@ func TestKeysValuesModifier(t *testing.T) {
func TestNaNInf(t *testing.T) { func TestNaNInf(t *testing.T) {
json := `[+Inf,-Inf,Inf,iNF,-iNF,+iNF,NaN,nan,nAn,-0,+0]` json := `[+Inf,-Inf,Inf,iNF,-iNF,+iNF,NaN,nan,nAn,-0,+0]`
raws := []string{"+Inf", "-Inf", "Inf", "iNF", "-iNF", "+iNF", "NaN", "nan", raws := []string{
"nAn", "-0", "+0"} "+Inf", "-Inf", "Inf", "iNF", "-iNF", "+iNF", "NaN", "nan",
nums := []float64{math.Inf(+1), math.Inf(-1), math.Inf(0), math.Inf(0), "nAn", "-0", "+0",
}
nums := []float64{
math.Inf(+1), math.Inf(-1), math.Inf(0), math.Inf(0),
math.Inf(-1), math.Inf(+1), math.NaN(), math.NaN(), math.NaN(), math.Inf(-1), math.Inf(+1), math.NaN(), math.NaN(), math.NaN(),
math.Copysign(0, -1), 0} math.Copysign(0, -1), 0,
}
assert(t, int(Get(json, `#`).Int()) == len(raws)) assert(t, int(Get(json, `#`).Int()) == len(raws))
for i := 0; i < len(raws); i++ { for i := 0; i < len(raws); i++ {
@ -2579,7 +2612,7 @@ func TestJSONString(t *testing.T) {
testJSONString(t, "R\xfd\xfc\a!\x82eO\x16?_\x0f\x9ab\x1dr") testJSONString(t, "R\xfd\xfc\a!\x82eO\x16?_\x0f\x9ab\x1dr")
testJSONString(t, "_\xb9\v\xad\xb3|X!\xb6\xd9U&\xa4\x1a\x95\x04") testJSONString(t, "_\xb9\v\xad\xb3|X!\xb6\xd9U&\xa4\x1a\x95\x04")
data, _ := json.Marshal("\b\f") data, _ := json.Marshal("\b\f")
if (string(data) == "\"\\b\\f\"") { if string(data) == "\"\\b\\f\"" {
// Go version 1.22+ encodes "\b" and "\f" correctly. // Go version 1.22+ encodes "\b" and "\f" correctly.
testJSONString(t, "\b\f") testJSONString(t, "\b\f")
rng := rand.New(rand.NewSource(time.Now().UnixNano())) rng := rand.New(rand.NewSource(time.Now().UnixNano()))
@ -2639,7 +2672,6 @@ func TestIssue301(t *testing.T) {
assert(t, Get(json, `fav\.movie.[0]`).String() == `["Deer Hunter"]`) assert(t, Get(json, `fav\.movie.[0]`).String() == `["Deer Hunter"]`)
assert(t, Get(json, `fav\.movie.1`).String() == "") assert(t, Get(json, `fav\.movie.1`).String() == "")
assert(t, Get(json, `fav\.movie.[1]`).String() == "[]") assert(t, Get(json, `fav\.movie.[1]`).String() == "[]")
} }
func TestModDig(t *testing.T) { func TestModDig(t *testing.T) {