diff --git a/.travis.yml b/.travis.yml index b00c1fe..4cf8b4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,8 +7,6 @@ language: go # You don't need to test on very old version of the Go compiler. It's the user's # responsibility to keep their compilers up to date. go: - - 1.11.x - - 1.12.x - 1.13.x - 1.14.x - 1.15.x diff --git a/README.md b/README.md index e6fa8c2..571acf6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Abstract JSON +# Abstract JSON (v1) [![Build Status](https://travis-ci.com/spyzhov/ajson.svg?branch=master)](https://travis-ci.com/spyzhov/ajson) [![Go Report Card](https://goreportcard.com/badge/github.com/spyzhov/ajson)](https://goreportcard.com/report/github.com/spyzhov/ajson) @@ -15,7 +15,7 @@ Method `Marshal` will serialize current `Node` object to JSON structure. Each `Node` has its own type and calculated value, which will be calculated on demand. Calculated value saves in `atomic.Value`, so it's thread safe. -Method `JSONPath` will returns slice of found elements in current JSON data, by [JSONPath](http://goessner.net/articles/JsonPath/) request. +Method `JSONPath` will return a slice of found elements in current JSON data, by [JSONPath](http://goessner.net/articles/JsonPath/) request. ## Compare with other solutions @@ -23,14 +23,14 @@ Check the [cburgmer/json-path-comparison](https://cburgmer.github.io/json-path-c # Usage -[Playground](https://play.golang.com/p/iIxkktxN0SK) +[Playground](https://play.golang.com/) ```go package main import ( "fmt" - "github.com/spyzhov/ajson" + "github.com/spyzhov/ajson/v1" ) func main() { @@ -40,7 +40,7 @@ func main() { nodes, _ := root.JSONPath("$..price") for _, node := range nodes { node.SetNumeric(node.MustNumeric() * 1.25) - node.Parent().AppendObject("currency", ajson.StringNode("", "EUR")) + node.Parent().AppendObject("currency", ajson.NewString("EUR")) } result, _ := ajson.Marshal(root) @@ -146,7 +146,7 @@ Package has several predefined constants. You are free to add new one with function `AddConstant`: ```go - AddConstant("c", NumericNode("speed of light in vacuum", 299_792_458)) + AddConstant("c", NewNumeric(299_792_458)) ``` #### Examples @@ -154,7 +154,7 @@ You are free to add new one with function `AddConstant`:
Using `true` in path -[Playground](https://play.golang.org/p/h0oFLaE11Tn) +[Playground](https://play.golang.org/) ```go package main @@ -162,7 +162,7 @@ package main import ( "fmt" - "github.com/spyzhov/ajson" + "github.com/spyzhov/ajson/v1" ) func main() { @@ -179,7 +179,7 @@ Count of `true` values: 3
Using `null` in eval -[Playground](https://play.golang.org/p/wpqh1Fw5vWE) +[Playground](https://play.golang.org/) ```go package main @@ -187,7 +187,7 @@ package main import ( "fmt" - "github.com/spyzhov/ajson" + "github.com/spyzhov/ajson/v1" ) func main() { @@ -249,7 +249,7 @@ You are free to add new one with function `AddOperation`: if err != nil { return nil, err } - return BoolNode("neq", !result), nil + return NewBool(!result), nil }) ``` @@ -258,7 +258,7 @@ You are free to add new one with function `AddOperation`:
Using `regex` operator -[Playground](https://play.golang.org/p/Lm_F4OGTMWl) +[Playground](https://play.golang.org/) ```go package main @@ -266,7 +266,7 @@ package main import ( "fmt" - "github.com/spyzhov/ajson" + "github.com/spyzhov/ajson/v1" ) func main() { @@ -342,7 +342,7 @@ You are free to add new one with function `AddFunction`: ```go AddFunction("trim", func(node *ajson.Node) (result *Node, err error) { if node.IsString() { - return StringNode("trim", strings.TrimSpace(node.MustString())), nil + return NewString(strings.TrimSpace(node.MustString())), nil } return }) @@ -353,7 +353,7 @@ You are free to add new one with function `AddFunction`:
Using `avg` for array -[Playground](https://play.golang.org/p/cM66hTE-CX1) +[Playground](https://play.golang.org/) ```go package main @@ -361,7 +361,7 @@ package main import ( "fmt" - "github.com/spyzhov/ajson" + "github.com/spyzhov/ajson/v1" ) func main() { @@ -385,6 +385,23 @@ Avg price: 5.5 ```
+# `Node` structure + +`ajson` works with the structures of `Node` type only. +`Node` is the container to be able to store any suitable value. +The value is stored as the `atomic.Value` object, so it has thread-safe value mutations. + +`Node` structure can contain different type of value, such as: + +* `Null` type with the internal representation as `nil.(interface{})`; +* `Numeric` type with the internal representation as `float64`; +* `String` type with the internal representation as `string`; +* `Bool` type with the internal representation as `bool`; +* `Array` type with the internal representation as `[]*Node`; +* `Object` type with the internal representation as `map[string]*Node`. + +Each type has its own constructor (e.g. `NewNull`, `NewArray`, etc.) and list of applicable methods. + # Examples Calculating `AVG(price)` when object is heterogeneous. @@ -431,13 +448,14 @@ Calculating `AVG(price)` when object is heterogeneous. ## Unmarshal -[Playground](https://play.golang.org/p/xny93dzjZCK) +[Playground](https://play.golang.org/) + ```go package main import ( "fmt" - "github.com/spyzhov/ajson" + "github.com/spyzhov/ajson/v1" ) func main() { @@ -479,13 +497,14 @@ func main() { ## JSONPath: -[Playground](https://play.golang.org/p/7twZHOd6dbT) +[Playground](https://play.golang.org/) + ```go package main import ( "fmt" - "github.com/spyzhov/ajson" + "github.com/spyzhov/ajson/v1" ) func main() { @@ -517,13 +536,14 @@ func main() { ## Eval -[Playground](https://play.golang.org/p/lTXnlRU3sgR) +[Playground](https://play.golang.org/) + ```go package main import ( "fmt" - "github.com/spyzhov/ajson" + "github.com/spyzhov/ajson/v1" ) func main() { @@ -547,13 +567,14 @@ func main() { ## Marshal -[Playground](https://play.golang.org/p/i4gXXcA2VLU) +[Playground](https://play.golang.org/) + ```go package main import ( "fmt" - "github.com/spyzhov/ajson" + "github.com/spyzhov/ajson/v1" ) func main() { diff --git a/buffer.go b/buffer.go index 7392957..0609035 100644 --- a/buffer.go +++ b/buffer.go @@ -4,31 +4,30 @@ import ( "io" "strings" - . "github.com/spyzhov/ajson/internal" + . "github.com/spyzhov/ajson/v1/internal" ) -type buffer struct { - data []byte - length int - index int - - last States - state States - class Classes -} - const __ = -1 const ( + // uSpace is a code for symbol `Space` (taken from www.json.org) + uSpace byte = '\u0020' + // uNewLine is a code for symbol `New Line` or `\n` (taken from www.json.org) + uNewLine byte = '\u000A' + // uCarriageReturn is a code for symbol `Carriage Return` or `\r` (taken from www.json.org) + uCarriageReturn byte = '\u000D' + // uTab is a code for symbol `Tab` or `\t` (taken from www.json.org) + uTab byte = '\u0009' + quotes byte = '"' quote byte = '\'' coma byte = ',' colon byte = ':' backslash byte = '\\' - skipS byte = ' ' - skipN byte = '\n' - skipR byte = '\r' - skipT byte = '\t' + skipS = uSpace + skipN = uNewLine + skipR = uCarriageReturn + skipT = uTab bracketL byte = '[' bracketR byte = ']' bracesL byte = '{' @@ -52,6 +51,23 @@ const ( question byte = '?' ) +type buffer struct { + data []byte + length int + index int + + last State + state State + class Class + + table sst +} + +type sst interface { + GetState(state State, class Class) State + GetClass(index byte) Class +} + type ( rpn []string tokens []string @@ -63,12 +79,20 @@ var ( _false = []byte("false") ) +var ( + _quoteState = map[byte]Class{ + quote: C_QUOTE, + quotes: C_ETC, + } +) + func newBuffer(body []byte) (b *buffer) { b = &buffer{ length: len(body), data: body, last: GO, state: GO, + table: StateTransitionTable, } return } @@ -158,7 +182,7 @@ func (b *buffer) numeric(token bool) error { if b.class == __ { return b.errorSymbol() } - b.state = StateTransitionTable[b.last][b.class] + b.state = b.table.GetState(b.last, b.class) if b.state == __ { if token { break @@ -179,23 +203,25 @@ func (b *buffer) numeric(token bool) error { return nil } -func (b *buffer) getClasses(search byte) Classes { +func (b *buffer) getClasses(search byte) Class { if b.data[b.index] >= 128 { return C_ETC } - if search == quote { - return QuoteAsciiClasses[b.data[b.index]] + if search == quote { // HACK for single quote + if result, ok := _quoteState[b.data[b.index]]; ok { + return result + } } - return AsciiClasses[b.data[b.index]] + return b.table.GetClass(b.data[b.index]) } -func (b *buffer) getState() States { +func (b *buffer) getState() State { b.last = b.state b.class = b.getClasses(quotes) if b.class == __ { return __ } - b.state = StateTransitionTable[b.last][b.class] + b.state = b.table.GetState(b.last, b.class) return b.state } @@ -209,7 +235,7 @@ func (b *buffer) string(search byte, token bool) error { if b.class == __ { return b.errorSymbol() } - b.state = StateTransitionTable[b.last][b.class] + b.state = b.table.GetState(b.last, b.class) if b.state == __ { return b.errorSymbol() } diff --git a/buffer_test.go b/buffer_test.go index a24cde9..b816beb 100644 --- a/buffer_test.go +++ b/buffer_test.go @@ -86,7 +86,7 @@ func TestBuffer_RPN_long_operations_name(t *testing.T) { expected := []string{"@.key", "1", "!@#$%^&*"} AddOperation(`!@#$%^&*`, 3, false, func(left *Node, right *Node) (result *Node, err error) { - return NullNode(""), nil + return NewNull(), nil }) result, err := newBuffer([]byte(jsonpath)).rpn() if err != nil { diff --git a/cmd/ajson/main.go b/cmd/ajson/main.go index 8b3cad1..237429a 100644 --- a/cmd/ajson/main.go +++ b/cmd/ajson/main.go @@ -9,7 +9,7 @@ import ( "os" "strings" - "github.com/spyzhov/ajson" + "github.com/spyzhov/ajson/v1" ) var version = "v0.7.1" @@ -66,7 +66,7 @@ func main() { var nodes []*ajson.Node nodes, err = root.JSONPath(path) - result = ajson.ArrayNode("", nodes) + result = ajson.NewArray(nodes) if err != nil { result, err = ajson.Eval(root, path) } diff --git a/decode.go b/decode.go index 0af1d2a..2f7564b 100644 --- a/decode.go +++ b/decode.go @@ -1,7 +1,7 @@ package ajson import ( - . "github.com/spyzhov/ajson/internal" + . "github.com/spyzhov/ajson/v1/internal" ) /* @@ -9,14 +9,14 @@ import ( Copy from `internal/state.go:144` */ const ( - cl States = -2 /* colon */ - cm States = -3 /* comma */ - //qt States = -4 /* quote */ - bo States = -5 /* bracket open */ - co States = -6 /* curly br. open */ - bc States = -7 /* bracket close */ - cc States = -8 /* curly br. close */ - ec States = -9 /* curly br. empty */ + cl State = -2 /* colon */ + cm State = -3 /* comma */ + //qt State = -4 /* quote */ + bo State = -5 /* bracket open */ + co State = -6 /* curly br. open */ + bc State = -7 /* bracket close */ + cc State = -8 /* curly br. close */ + ec State = -9 /* curly br. empty */ ) // Unmarshal parses the JSON-encoded data and return the root node of struct. @@ -25,7 +25,7 @@ const ( func Unmarshal(data []byte) (root *Node, err error) { buf := newBuffer(data) var ( - state States + state State key *string current *Node ) diff --git a/encode_test.go b/encode_test.go index 4fc613f..68a9838 100644 --- a/encode_test.go +++ b/encode_test.go @@ -11,7 +11,7 @@ func ExampleMarshal() { locations, _ := root.JSONPath("$..[?(@.latitude && @.longitude)]") for _, location := range locations { name := fmt.Sprintf("At [%v, %v]", location.MustKey("latitude").MustNumeric(), location.MustKey("longitude").MustNumeric()) - _ = location.AppendObject("name", StringNode("", name)) + _ = location.AppendObject("name", NewString(name)) } result, _ := Marshal(root) fmt.Printf("%s", result) @@ -43,48 +43,48 @@ func TestMarshal_Primitive(t *testing.T) { }{ { name: "null", - node: NullNode(""), + node: NewNull(), }, { name: "true", - node: BoolNode("", true), + node: NewBool(true), }, { name: "false", - node: BoolNode("", false), + node: NewBool(false), }, { name: `"string"`, - node: StringNode("", "string"), + node: NewString("string"), }, { name: `"one \"encoded\" string"`, - node: StringNode("", `one "encoded" string`), + node: NewString(`one "encoded" string`), }, { name: `"spec.symbols: \r\n\t; UTF-8: 😹; \u2028 \u0000"`, - node: StringNode("", "spec.symbols: \r\n\t; UTF-8: 😹; \u2028 \000"), + node: NewString("spec.symbols: \r\n\t; UTF-8: 😹; \u2028 \000"), }, { name: "100500", - node: NumericNode("", 100500), + node: NewNumeric(100500), }, { name: "100.5", - node: NumericNode("", 100.5), + node: NewNumeric(100.5), }, { name: "[1,2,3]", - node: ArrayNode("", []*Node{ - NumericNode("0", 1), - NumericNode("2", 2), - NumericNode("3", 3), + node: NewArray([]*Node{ + NewNumeric(1), + NewNumeric(2), + NewNumeric(3), }), }, { name: `{"foo":"bar"}`, - node: ObjectNode("", map[string]*Node{ - "foo": StringNode("foo", "bar"), + node: NewObject(map[string]*Node{ + "foo": NewString("bar"), }), }, } @@ -165,21 +165,21 @@ func TestMarshal_Errors(t *testing.T) { { name: "Array_1", node: func() (node *Node) { - node = ArrayNode("", nil) - node.children["1"] = NullNode("1") + node = NewArray(nil) + node.children["1"] = withKey(NewNull(), "1") return }, }, { name: "Array_2", node: func() (node *Node) { - return ArrayNode("", []*Node{valueNode(nil, "", Bool, 1)}) + return NewArray([]*Node{valueNode(nil, "", Bool, 1)}) }, }, { name: "Object", node: func() (node *Node) { - return ObjectNode("", map[string]*Node{"key": valueNode(nil, "key", Bool, 1)}) + return NewObject(map[string]*Node{"key": valueNode(nil, "key", Bool, 1)}) }, }, } diff --git a/go.mod b/go.mod index 1959fae..a164083 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module github.com/spyzhov/ajson +module github.com/spyzhov/ajson/v1 -go 1.12 +go 1.13 diff --git a/internal/state.go b/internal/state.go index 9116c5c..5f37d78 100644 --- a/internal/state.go +++ b/internal/state.go @@ -1,53 +1,53 @@ -/* -Copy from https://github.com/freddierice/php_source/blob/467ed5d6edff72219afd3e644516f131118ef48e/ext/json/JSON_parser.c -Base code: Copyright (c) 2005 JSON.org -*/ +// Package internal +// Copy from https://github.com/freddierice/php_source/blob/467ed5d6edff72219afd3e644516f131118ef48e/ext/json/JSON_parser.c +// Base code: Copyright (c) 2005 JSON.org package internal type ( - States int8 - Classes int8 + State int8 + Class int8 + States [31][31]State ) const __ = -1 // enum classes const ( - C_SPACE Classes = iota /* space */ - C_WHITE /* other whitespace */ - C_LCURB /* { */ - C_RCURB /* } */ - C_LSQRB /* [ */ - C_RSQRB /* ] */ - C_COLON /* : */ - C_COMMA /* , */ - C_QUOTE /* " */ - C_BACKS /* \ */ - C_SLASH /* / */ - C_PLUS /* + */ - C_MINUS /* - */ - C_POINT /* . */ - C_ZERO /* 0 */ - C_DIGIT /* 123456789 */ - C_LOW_A /* a */ - C_LOW_B /* b */ - C_LOW_C /* c */ - C_LOW_D /* d */ - C_LOW_E /* e */ - C_LOW_F /* f */ - C_LOW_L /* l */ - C_LOW_N /* n */ - C_LOW_R /* r */ - C_LOW_S /* s */ - C_LOW_T /* t */ - C_LOW_U /* u */ - C_ABCDF /* ABCDF */ - C_E /* E */ - C_ETC /* everything else */ + C_SPACE Class = iota /* space */ + C_WHITE /* other whitespace */ + C_LCURB /* { */ + C_RCURB /* } */ + C_LSQRB /* [ */ + C_RSQRB /* ] */ + C_COLON /* : */ + C_COMMA /* , */ + C_QUOTE /* " */ + C_BACKS /* \ */ + C_SLASH /* / */ + C_PLUS /* + */ + C_MINUS /* - */ + C_POINT /* . */ + C_ZERO /* 0 */ + C_DIGIT /* 123456789 */ + C_LOW_A /* a */ + C_LOW_B /* b */ + C_LOW_C /* c */ + C_LOW_D /* d */ + C_LOW_E /* e */ + C_LOW_F /* f */ + C_LOW_L /* l */ + C_LOW_N /* n */ + C_LOW_R /* r */ + C_LOW_S /* s */ + C_LOW_T /* t */ + C_LOW_U /* u */ + C_ABCDF /* ABCDF */ + C_E /* E */ + C_ETC /* everything else */ ) // AsciiClasses array maps the 128 ASCII characters into character classes. -var AsciiClasses = [128]Classes{ +var AsciiClasses = [128]Class{ /* This array maps the 128 ASCII characters into character classes. The remaining Unicode characters should be mapped to C_ETC. @@ -74,89 +74,61 @@ var AsciiClasses = [128]Classes{ C_ETC, C_ETC, C_ETC, C_LCURB, C_ETC, C_RCURB, C_ETC, C_ETC, } -// QuoteAsciiClasses is a HACK for single quote from AsciiClasses -var QuoteAsciiClasses = [128]Classes{ - /* - This array maps the 128 ASCII characters into character classes. - The remaining Unicode characters should be mapped to C_ETC. - Non-whitespace control characters are errors. - */ - __, __, __, __, __, __, __, __, - __, C_WHITE, C_WHITE, __, __, C_WHITE, __, __, - __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, - - C_SPACE, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_QUOTE, - C_ETC, C_ETC, C_ETC, C_PLUS, C_COMMA, C_MINUS, C_POINT, C_SLASH, - C_ZERO, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, - C_DIGIT, C_DIGIT, C_COLON, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, - - C_ETC, C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E, C_ABCDF, C_ETC, - C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, - C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, - C_ETC, C_ETC, C_ETC, C_LSQRB, C_BACKS, C_RSQRB, C_ETC, C_ETC, - - C_ETC, C_LOW_A, C_LOW_B, C_LOW_C, C_LOW_D, C_LOW_E, C_LOW_F, C_ETC, - C_ETC, C_ETC, C_ETC, C_ETC, C_LOW_L, C_ETC, C_LOW_N, C_ETC, - C_ETC, C_ETC, C_LOW_R, C_LOW_S, C_LOW_T, C_LOW_U, C_ETC, C_ETC, - C_ETC, C_ETC, C_ETC, C_LCURB, C_ETC, C_RCURB, C_ETC, C_ETC, -} - /* The state codes. */ const ( - GO States = iota /* start */ - OK /* ok */ - OB /* object */ - KE /* key */ - CO /* colon */ - VA /* value */ - AR /* array */ - ST /* string */ - ES /* escape */ - U1 /* u1 */ - U2 /* u2 */ - U3 /* u3 */ - U4 /* u4 */ - MI /* minus */ - ZE /* zero */ - IN /* integer */ - DT /* dot */ - FR /* fraction */ - E1 /* e */ - E2 /* ex */ - E3 /* exp */ - T1 /* tr */ - T2 /* tru */ - T3 /* true */ - F1 /* fa */ - F2 /* fal */ - F3 /* fals */ - F4 /* false */ - N1 /* nu */ - N2 /* nul */ - N3 /* null */ + GO State = iota /* start */ + OK /* ok */ + OB /* object */ + KE /* key */ + CO /* colon */ + VA /* value */ + AR /* array */ + ST /* string */ + ES /* escape */ + U1 /* u1 */ + U2 /* u2 */ + U3 /* u3 */ + U4 /* u4 */ + MI /* minus */ + ZE /* zero */ + IN /* integer */ + DT /* dot */ + FR /* fraction */ + E1 /* e */ + E2 /* ex */ + E3 /* exp */ + T1 /* tr */ + T2 /* tru */ + T3 /* true */ + F1 /* fa */ + F2 /* fal */ + F3 /* fals */ + F4 /* false */ + N1 /* nu */ + N2 /* nul */ + N3 /* null */ ) /* The action codes */ const ( - cl States = -2 /* colon */ - cm States = -3 /* comma */ - qt States = -4 /* quote */ - bo States = -5 /* bracket open */ - co States = -6 /* curly br. open */ - bc States = -7 /* bracket close */ - cc States = -8 /* curly br. close */ - ec States = -9 /* curly br. empty */ + cl State = -2 /* colon */ + cm State = -3 /* comma */ + qt State = -4 /* quote */ + bo State = -5 /* bracket open */ + co State = -6 /* curly br. open */ + bc State = -7 /* bracket close */ + cc State = -8 /* curly br. close */ + ec State = -9 /* curly br. empty */ ) // StateTransitionTable is the state transition table takes the current state and the current symbol, and returns either // a new state or an action. An action is represented as a negative number. A JSON text is accepted if at the end of the // text the state is OK and if the mode is DONE. -var StateTransitionTable = [31][31]States{ +var StateTransitionTable = States{ /* The state transition table takes the current state and the current symbol, and returns either a new state or an action. An action is represented as a @@ -196,3 +168,15 @@ var StateTransitionTable = [31][31]States{ /*nul N2*/ {__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, N3, __, __, __, __, __, __, __, __}, /*null N3*/ {__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, OK, __, __, __, __, __, __, __, __}, } + +// GetState provides an ability to hide the base StateTransitionTable type and use interface declaration to get value. +func (s States) GetState(state State, class Class) State { + return s[state][class] +} + +func (s States) GetClass(index byte) Class { + if index > 128 { + return C_ETC + } + return AsciiClasses[index] +} diff --git a/jsonpath.go b/jsonpath.go index 7f81b14..a6c5837 100644 --- a/jsonpath.go +++ b/jsonpath.go @@ -600,7 +600,7 @@ func eval(node *Node, expression rpn, cmd string) (result *Node, err error) { ok bool size int commands []string - bstr []byte + bytestr []byte ) for _, exp := range expression { size = len(stack) @@ -632,26 +632,25 @@ func eval(node *Node, expression rpn, cmd string) (result *Node, err error) { return } if len(slice) > 1 { // array given - stack = append(stack, ArrayNode("", slice)) + stack = append(stack, NewArray(slice)) } else if len(slice) == 1 { stack = append(stack, slice[0]) } else { // no data found - // stack = append(stack, NullNode("")) - return NullNode(""), nil + return NewNull(), nil } } else if constant, ok := constants[strings.ToLower(exp)]; ok { stack = append(stack, constant) } else { - bstr = []byte(exp) - size = len(bstr) - if size >= 2 && bstr[0] == quote && bstr[size-1] == quote { - if sstr, ok := unquote(bstr, quote); ok { - temp = StringNode("", sstr) + bytestr = []byte(exp) + size = len(bytestr) + if size >= 2 && bytestr[0] == quote && bytestr[size-1] == quote { + if strval, ok := unquote(bytestr, quote); ok { + temp = NewString(strval) } else { err = errorRequest("wrong request: %s", cmd) } } else { - temp, err = Unmarshal(bstr) + temp, err = Unmarshal(bytestr) } if err != nil { return @@ -666,7 +665,7 @@ func eval(node *Node, expression rpn, cmd string) (result *Node, err error) { return stack[0], nil } if len(stack) == 0 { - return NullNode(""), nil + return NewNull(), nil } return nil, errorRequest("wrong request: %s", cmd) } diff --git a/jsonpath_test.go b/jsonpath_test.go index a623288..aada80f 100644 --- a/jsonpath_test.go +++ b/jsonpath_test.go @@ -562,7 +562,7 @@ func ExampleJSONPath_array() { if err != nil { panic(err) } - result, err := Marshal(ArrayNode("", authors)) + result, err := Marshal(NewArray(authors)) if err != nil { panic(err) } @@ -663,7 +663,7 @@ func TestEval(t *testing.T) { name: "avg($..price)", root: Must(Unmarshal(json)), eval: "avg($..price)", - expected: NumericNode("", 14.774000000000001), + expected: NewNumeric(14.774000000000001), wantErr: false, }, { @@ -684,7 +684,7 @@ func TestEval(t *testing.T) { name: "round(avg($..price)+pi)", root: Must(Unmarshal(json)), eval: "round(avg($..price)+pi)", - expected: NumericNode("", 18), + expected: NewNumeric(18), wantErr: false, }, { @@ -1418,12 +1418,13 @@ func TestJSONPath_special_requests(t *testing.T) { } func TestApplyJSONPath(t *testing.T) { - node1 := NumericNode("", 1.) - node2 := NumericNode("", 2.) - cpy := func(n Node) *Node { - return &n + node1 := NewNumeric(1.) + node2 := NewNumeric(2.) + _copy := func(node *Node) *Node { + another := *node + return &another } - array := ArrayNode("", []*Node{cpy(*node1), cpy(*node2)}) + array := NewArray([]*Node{_copy(node1), _copy(node2)}) type args struct { node *Node diff --git a/math_test.go b/math_test.go index 7eb8a02..2e7ccd7 100644 --- a/math_test.go +++ b/math_test.go @@ -28,7 +28,7 @@ func ExampleAddFunction() { } sum += num } - return NumericNode("array_sum", sum), nil + return NewNumeric(sum), nil } return }) @@ -50,7 +50,7 @@ func ExampleAddFunction_usage() { } func ExampleAddConstant() { - AddConstant("SqrtPi", NumericNode("SqrtPi", math.SqrtPi)) + AddConstant("SqrtPi", NewNumeric(math.SqrtPi)) } func ExampleAddConstant_using() { @@ -85,7 +85,7 @@ func ExampleAddOperation() { if err != nil { return nil, err } - return BoolNode("neq", !res), nil + return NewBool(!res), nil }) } @@ -111,38 +111,38 @@ type operationTest struct { func testNumOperation(operator string, results [3]float64) []*operationTest { return []*operationTest{ - {name: "2" + operator + "2", operation: operator, left: NumericNode("", 2), right: NumericNode("", 2), result: NumericNode("", results[0])}, - {name: "3" + operator + "3", operation: operator, left: NumericNode("", 3), right: NumericNode("", 3), result: NumericNode("", results[1])}, - {name: "10" + operator + "3", operation: operator, left: NumericNode("", 10), right: NumericNode("", 3), result: NumericNode("", results[2])}, - {name: "X" + operator + "2", operation: operator, left: StringNode("", "X"), right: NumericNode("", 2), fail: true}, - {name: "2" + operator + "Y", operation: operator, left: NumericNode("", 2), right: StringNode("", "Y"), fail: true}, + {name: "2" + operator + "2", operation: operator, left: NewNumeric(2), right: NewNumeric(2), result: NewNumeric(results[0])}, + {name: "3" + operator + "3", operation: operator, left: NewNumeric(3), right: NewNumeric(3), result: NewNumeric(results[1])}, + {name: "10" + operator + "3", operation: operator, left: NewNumeric(10), right: NewNumeric(3), result: NewNumeric(results[2])}, + {name: "X" + operator + "2", operation: operator, left: NewString("X"), right: NewNumeric(2), fail: true}, + {name: "2" + operator + "Y", operation: operator, left: NewNumeric(2), right: NewString("Y"), fail: true}, } } func testBoolOperation(operator string, results [4]bool) []*operationTest { return []*operationTest{ - {name: "2" + operator + "2", operation: operator, left: NumericNode("", 2), right: NumericNode("", 2), result: BoolNode("", results[0])}, - {name: "3" + operator + "3", operation: operator, left: NumericNode("", 3), right: NumericNode("", 3), result: BoolNode("", results[1])}, - {name: "10" + operator + "0", operation: operator, left: NumericNode("", 10), right: NumericNode("", 0), result: BoolNode("", results[2])}, - {name: "0" + operator + "10", operation: operator, left: NumericNode("", 0), right: NumericNode("", 10), result: BoolNode("", results[3])}, - {name: "left error: " + operator, operation: operator, left: valueNode(nil, "", Numeric, "foo"), right: NumericNode("", 10), fail: true}, - {name: "right error: " + operator, operation: operator, left: NumericNode("", 10), right: valueNode(nil, "", Numeric, "foo"), fail: true}, + {name: "2" + operator + "2", operation: operator, left: NewNumeric(2), right: NewNumeric(2), result: NewBool(results[0])}, + {name: "3" + operator + "3", operation: operator, left: NewNumeric(3), right: NewNumeric(3), result: NewBool(results[1])}, + {name: "10" + operator + "0", operation: operator, left: NewNumeric(10), right: NewNumeric(0), result: NewBool(results[2])}, + {name: "0" + operator + "10", operation: operator, left: NewNumeric(0), right: NewNumeric(10), result: NewBool(results[3])}, + {name: "left error: " + operator, operation: operator, left: valueNode(nil, "", Numeric, "foo"), right: NewNumeric(10), fail: true}, + {name: "right error: " + operator, operation: operator, left: NewNumeric(10), right: valueNode(nil, "", Numeric, "foo"), fail: true}, } } func testBooleanOperation(operator string, results [4]bool) []*operationTest { return []*operationTest{ - {name: "2" + operator + "2", operation: operator, left: NumericNode("", 2), right: NumericNode("", 2), result: BoolNode("", results[0])}, - {name: "3" + operator + "3", operation: operator, left: NumericNode("", 3), right: NumericNode("", 3), result: BoolNode("", results[1])}, - {name: "10" + operator + "0", operation: operator, left: NumericNode("", 10), right: NumericNode("", 0), result: BoolNode("", results[2])}, - {name: "0" + operator + "10", operation: operator, left: NumericNode("", 0), right: NumericNode("", 10), result: BoolNode("", results[3])}, + {name: "2" + operator + "2", operation: operator, left: NewNumeric(2), right: NewNumeric(2), result: NewBool(results[0])}, + {name: "3" + operator + "3", operation: operator, left: NewNumeric(3), right: NewNumeric(3), result: NewBool(results[1])}, + {name: "10" + operator + "0", operation: operator, left: NewNumeric(10), right: NewNumeric(0), result: NewBool(results[2])}, + {name: "0" + operator + "10", operation: operator, left: NewNumeric(0), right: NewNumeric(10), result: NewBool(results[3])}, } } func TestOperations(t *testing.T) { tests := []*operationTest{ - {name: "0/0", operation: "/", left: NumericNode("", 0), right: NumericNode("", 0), fail: true}, - {name: "1/0", operation: "/", left: NumericNode("", 1), right: NumericNode("", 0), fail: true}, - {name: "X+Y", operation: "+", left: StringNode("", "X"), right: StringNode("", "Y"), result: StringNode("", "XY")}, + {name: "0/0", operation: "/", left: NewNumeric(0), right: NewNumeric(0), fail: true}, + {name: "1/0", operation: "/", left: NewNumeric(1), right: NewNumeric(0), fail: true}, + {name: "X+Y", operation: "+", left: NewString("X"), right: NewString("Y"), result: NewString("XY")}, } tests = append(tests, testNumOperation("**", [3]float64{4, 27, 1000})...) @@ -170,10 +170,11 @@ func TestOperations(t *testing.T) { tests = append(tests, testBooleanOperation("||", [4]bool{true, true, true, true})...) _e := valueNode(nil, "", Numeric, "foo") - _t := NumericNode("", 1) - _f := NumericNode("", 0) - _false := BoolNode("", false) - _true := BoolNode("", true) + _t := NewNumeric(1) + _f := NewNumeric(0) + _false := NewBool(false) + _true := NewBool(true) + _null := NewNull() tests = append( tests, &operationTest{name: "error && true", operation: "&&", left: _e, right: _t, fail: true}, @@ -181,25 +182,27 @@ func TestOperations(t *testing.T) { &operationTest{name: "error && false", operation: "&&", left: _e, right: _f, fail: true}, &operationTest{name: "false && error", operation: "&&", left: _f, right: _e, result: _false}, &operationTest{name: "true && error", operation: "&&", left: _t, right: _e, fail: true}, + &operationTest{name: "true && null", operation: "&&", left: _t, right: _null, result: _false}, + &operationTest{name: "null && true", operation: "&&", left: _null, right: _t, result: _false}, &operationTest{ name: "[] && {} == false", operation: "&&", - left: ArrayNode("", []*Node{}), - right: ObjectNode("", map[string]*Node{}), + left: NewArray([]*Node{}), + right: NewObject(map[string]*Node{}), result: _false, }, &operationTest{ name: "{} || [] == false", operation: "||", - left: ObjectNode("", map[string]*Node{}), - right: ArrayNode("", []*Node{}), + left: NewObject(map[string]*Node{}), + right: NewArray([]*Node{}), result: _false, }, &operationTest{ name: `{"foo":"bar"} || [1] == true`, operation: "&&", - left: ObjectNode("", map[string]*Node{"foo": StringNode("foo", "bar")}), - right: ArrayNode("", []*Node{NumericNode("0", 1)}), + left: NewObject(map[string]*Node{"foo": NewString("bar")}), + right: NewArray([]*Node{NewNumeric(1)}), result: _true, }, @@ -209,11 +212,11 @@ func TestOperations(t *testing.T) { &operationTest{name: "false || error", operation: "||", left: _f, right: _e, fail: true}, &operationTest{name: "true || error", operation: "||", left: _t, right: _e, result: _true}, - &operationTest{name: "regexp true", operation: "=~", left: StringNode("", `123`), right: StringNode("", `\d+`), result: _true}, - &operationTest{name: "regexp false", operation: "=~", left: StringNode("", `1 2 3`), right: StringNode("", `^\d+$`), result: _false}, - &operationTest{name: "regexp pattern error", operation: "=~", left: StringNode("", `2`), right: StringNode("", `\2`), fail: true}, - &operationTest{name: "regexp error 1", operation: "=~", left: _f, right: StringNode("", `123`), fail: true}, - &operationTest{name: "regexp error 2", operation: "=~", left: StringNode("", `\d+`), right: _f, fail: true}, + &operationTest{name: "regexp true", operation: "=~", left: NewString(`123`), right: NewString(`\d+`), result: _true}, + &operationTest{name: "regexp false", operation: "=~", left: NewString(`1 2 3`), right: NewString(`^\d+$`), result: _false}, + &operationTest{name: "regexp pattern error", operation: "=~", left: NewString(`2`), right: NewString(`\2`), fail: true}, + &operationTest{name: "regexp error 1", operation: "=~", left: _f, right: NewString(`123`), fail: true}, + &operationTest{name: "regexp error 2", operation: "=~", left: NewString(`\d+`), right: _f, fail: true}, ) for _, test := range tests { @@ -240,7 +243,7 @@ func TestAddConstant(t *testing.T) { if _, ok := constants[name]; ok { t.Error("test constant already exists") } - AddConstant(name, NumericNode(name, 3.14)) + AddConstant(name, NewNumeric(3.14)) if _, ok := constants[name]; !ok { t.Error("test constant was not added") } @@ -253,18 +256,18 @@ func TestAddOperation(t *testing.T) { return } AddOperation(name, 1, true, func(left *Node, right *Node) (result *Node, err error) { - return NumericNode("example", 1), nil + return NewNumeric(1), nil }) if _, ok := operations[name]; !ok { t.Error("test operation was not added") return } - result, err := Eval(NullNode(""), `@ _one_to_rule_them_all_ 100500`) + result, err := Eval(NewNull(), `@ _one_to_rule_them_all_ 100500`) if err != nil { t.Errorf("Unexpected error: %s", err.Error()) return } - if ok, err := result.Eq(NumericNode("", 1)); err != nil { + if ok, err := result.Eq(NewNumeric(1)); err != nil { t.Errorf("Unexpected error: %s", err.Error()) } else if !ok { t.Errorf("Should be one") @@ -277,7 +280,7 @@ func TestAddFunction(t *testing.T) { t.Error("test constant already exists") } AddFunction(name, func(node *Node) (result *Node, err error) { - return NumericNode("example", 2), nil + return NewNumeric(2), nil }) if _, ok := functions[name]; !ok { t.Error("test function was not added") @@ -365,15 +368,15 @@ func TestFunctions(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - node := NumericNode(test.name, test.value) + node := NewNumeric(test.value) var expected *Node switch test.result.(type) { case int: - expected = NumericNode(test.fname, float64(test.result.(int))) + expected = NewNumeric(float64(test.result.(int))) case float64: - expected = NumericNode(test.fname, test.result.(float64)) + expected = NewNumeric(test.result.(float64)) case bool: - expected = BoolNode(test.fname, test.result.(bool)) + expected = NewBool(test.result.(bool)) default: panic("wrong type") } @@ -403,74 +406,74 @@ func TestFunctions2(t *testing.T) { {name: "pow10 error", fname: "pow10", value: _e, fail: true}, {name: "factorial error", fname: "factorial", value: _e, fail: true}, {name: "abs error 1", fname: "abs", value: _e, fail: true}, - {name: "abs error 2", fname: "abs", value: StringNode("", ""), fail: true}, + {name: "abs error 2", fname: "abs", value: NewString(""), fail: true}, - {name: "length array", fname: "length", value: ArrayNode("test", []*Node{ + {name: "length array", fname: "length", value: NewArray([]*Node{ valueNode(nil, "", Numeric, "foo"), valueNode(nil, "", Numeric, "foo"), valueNode(nil, "", Numeric, "foo"), - }), result: NumericNode("", 3)}, - {name: "length blank array", fname: "length", value: ArrayNode("test", []*Node{}), result: NumericNode("", 0)}, - {name: "length object", fname: "length", value: ObjectNode("test", map[string]*Node{ - "foo": NumericNode("foo", 1), - "bar": NumericNode("bar", 1), - }), result: NumericNode("", 2)}, - {name: "length string", fname: "length", value: StringNode("", "foo_bar"), result: NumericNode("", 7)}, + }), result: NewNumeric(3)}, + {name: "length blank array", fname: "length", value: NewArray([]*Node{}), result: NewNumeric(0)}, + {name: "length object", fname: "length", value: NewObject(map[string]*Node{ + "foo": NewNumeric(1), + "bar": NewNumeric(1), + }), result: NewNumeric(2)}, + {name: "length string", fname: "length", value: NewString("foo_bar"), result: NewNumeric(7)}, {name: "length string error", fname: "length", value: _s, fail: true}, - {name: "length numeric", fname: "length", value: NumericNode("", 123), result: NumericNode("", 1)}, - {name: "length bool", fname: "length", value: BoolNode("", false), result: NumericNode("", 1)}, - {name: "length null", fname: "length", value: NullNode(""), result: NumericNode("", 1)}, + {name: "length numeric", fname: "length", value: NewNumeric(123), result: NewNumeric(1)}, + {name: "length bool", fname: "length", value: NewBool(false), result: NewNumeric(1)}, + {name: "length null", fname: "length", value: NewNull(), result: NewNumeric(1)}, - {name: "avg error 1", fname: "avg", value: ArrayNode("test", []*Node{ + {name: "avg error 1", fname: "avg", value: NewArray([]*Node{ valueNode(nil, "", Numeric, "foo"), valueNode(nil, "", Numeric, "foo"), valueNode(nil, "", Numeric, "foo"), }), fail: true}, - {name: "avg error 2", fname: "avg", value: _e, fail: false, result: NullNode("")}, - {name: "avg array 1", fname: "avg", value: ArrayNode("test", []*Node{ - NumericNode("", 1), - NumericNode("", 1), - NumericNode("", 1), - NumericNode("", 1), - }), result: NumericNode("", 1)}, - {name: "avg array 2", fname: "avg", value: ArrayNode("test", []*Node{ - NumericNode("", 1), - NumericNode("", 2), - NumericNode("", 3), - }), result: NumericNode("", 2)}, - {name: "avg object", fname: "avg", value: ObjectNode("test", map[string]*Node{ - "q": NumericNode("", 1), - "w": NumericNode("", 2), - "e": NumericNode("", 3), - }), result: NumericNode("", 2)}, - {name: "avg array blank", fname: "avg", value: ArrayNode("test", []*Node{}), result: NumericNode("", 0)}, - - {name: "sum error 1", fname: "sum", value: ArrayNode("test", []*Node{ + {name: "avg error 2", fname: "avg", value: _e, fail: false, result: NewNull()}, + {name: "avg array 1", fname: "avg", value: NewArray([]*Node{ + NewNumeric(1), + NewNumeric(1), + NewNumeric(1), + NewNumeric(1), + }), result: NewNumeric(1)}, + {name: "avg array 2", fname: "avg", value: NewArray([]*Node{ + NewNumeric(1), + NewNumeric(2), + NewNumeric(3), + }), result: NewNumeric(2)}, + {name: "avg object", fname: "avg", value: NewObject(map[string]*Node{ + "q": NewNumeric(1), + "w": NewNumeric(2), + "e": NewNumeric(3), + }), result: NewNumeric(2)}, + {name: "avg array blank", fname: "avg", value: NewArray([]*Node{}), result: NewNumeric(0)}, + + {name: "sum error 1", fname: "sum", value: NewArray([]*Node{ valueNode(nil, "", Numeric, "foo"), valueNode(nil, "", Numeric, "foo"), valueNode(nil, "", Numeric, "foo"), }), fail: true}, - {name: "sum error 2", fname: "sum", value: _e, fail: false, result: NullNode("")}, - {name: "sum array 1", fname: "sum", value: ArrayNode("test", []*Node{ - NumericNode("", 1), - NumericNode("", 1), - NumericNode("", 1), - NumericNode("", 1), - }), result: NumericNode("", 4)}, - {name: "sum array 2", fname: "sum", value: ArrayNode("test", []*Node{ - NumericNode("", 1), - NumericNode("", 2), - NumericNode("", 3), - }), result: NumericNode("", 6)}, - {name: "sum object", fname: "sum", value: ObjectNode("test", map[string]*Node{ - "q": NumericNode("", 1), - "w": NumericNode("", 2), - "e": NumericNode("", 3), - }), result: NumericNode("", 6)}, - {name: "sum array blank", fname: "sum", value: ArrayNode("test", []*Node{}), result: NumericNode("", 0)}, - - {name: "rand", fname: "rand", value: StringNode("test", "test"), fail: true}, - {name: "randint", fname: "randint", value: StringNode("test", "test"), fail: true}, + {name: "sum error 2", fname: "sum", value: _e, fail: false, result: NewNull()}, + {name: "sum array 1", fname: "sum", value: NewArray([]*Node{ + NewNumeric(1), + NewNumeric(1), + NewNumeric(1), + NewNumeric(1), + }), result: NewNumeric(4)}, + {name: "sum array 2", fname: "sum", value: NewArray([]*Node{ + NewNumeric(1), + NewNumeric(2), + NewNumeric(3), + }), result: NewNumeric(6)}, + {name: "sum object", fname: "sum", value: NewObject(map[string]*Node{ + "q": NewNumeric(1), + "w": NewNumeric(2), + "e": NewNumeric(3), + }), result: NewNumeric(6)}, + {name: "sum array blank", fname: "sum", value: NewArray([]*Node{}), result: NewNumeric(0)}, + + {name: "rand", fname: "rand", value: NewString("test"), fail: true}, + {name: "randint", fname: "randint", value: NewString("test"), fail: true}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -496,23 +499,23 @@ func TestConstants(t *testing.T) { name string expected *Node }{ - {name: "e", expected: NumericNode("e", float64(math.E))}, - {name: "pi", expected: NumericNode("pi", float64(math.Pi))}, - {name: "phi", expected: NumericNode("phi", float64(math.Phi))}, - - {name: "sqrt2", expected: NumericNode("sqrt2", float64(math.Sqrt2))}, - {name: "sqrte", expected: NumericNode("sqrte", float64(math.SqrtE))}, - {name: "sqrtpi", expected: NumericNode("sqrtpi", float64(math.SqrtPi))}, - {name: "sqrtphi", expected: NumericNode("sqrtphi", float64(math.SqrtPhi))}, - - {name: "ln2", expected: NumericNode("ln2", float64(math.Ln2))}, - {name: "log2e", expected: NumericNode("log2e", float64(math.Log2E))}, - {name: "ln10", expected: NumericNode("ln10", float64(math.Ln10))}, - {name: "log10e", expected: NumericNode("log10e", float64(math.Log10E))}, - - {name: "true", expected: BoolNode("true", true)}, - {name: "false", expected: BoolNode("false", false)}, - {name: "null", expected: NullNode("null")}, + {name: "e", expected: NewNumeric(float64(math.E))}, + {name: "pi", expected: NewNumeric(float64(math.Pi))}, + {name: "phi", expected: NewNumeric(float64(math.Phi))}, + + {name: "sqrt2", expected: NewNumeric(float64(math.Sqrt2))}, + {name: "sqrte", expected: NewNumeric(float64(math.SqrtE))}, + {name: "sqrtpi", expected: NewNumeric(float64(math.SqrtPi))}, + {name: "sqrtphi", expected: NewNumeric(float64(math.SqrtPhi))}, + + {name: "ln2", expected: NewNumeric(float64(math.Ln2))}, + {name: "log2e", expected: NewNumeric(float64(math.Log2E))}, + {name: "ln10", expected: NewNumeric(float64(math.Ln10))}, + {name: "log10e", expected: NewNumeric(float64(math.Log10E))}, + + {name: "true", expected: NewBool(true)}, + {name: "false", expected: NewBool(false)}, + {name: "null", expected: NewNull()}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { diff --git a/node.go b/node.go index 310cf64..4e40bda 100644 --- a/node.go +++ b/node.go @@ -60,82 +60,76 @@ const ( Object ) -// NullNode is constructor for Node with Null value -func NullNode(key string) *Node { +// NewNull is constructor for Node with Null value +func NewNull() *Node { return &Node{ _type: Null, - key: &key, dirty: true, } } -// NumericNode is constructor for Node with a Numeric value -func NumericNode(key string, value float64) (current *Node) { +// NewNumeric is constructor for Node with a Numeric value +func NewNumeric(value float64) (current *Node) { current = &Node{ _type: Numeric, - key: &key, dirty: true, } current.value.Store(value) return } -// StringNode is constructor for Node with a String value -func StringNode(key string, value string) (current *Node) { +// NewString is constructor for Node with a String value +func NewString(value string) (current *Node) { current = &Node{ _type: String, - key: &key, dirty: true, } current.value.Store(value) return } -// BoolNode is constructor for Node with a Bool value -func BoolNode(key string, value bool) (current *Node) { +// NewBool is constructor for Node with a Bool value +func NewBool(value bool) (current *Node) { current = &Node{ _type: Bool, - key: &key, dirty: true, } current.value.Store(value) return } -// ArrayNode is constructor for Node with an Array value -func ArrayNode(key string, value []*Node) (current *Node) { +// NewArray is constructor for Node with an Array value +func NewArray(values []*Node) (current *Node) { current = &Node{ data: nil, _type: Array, - key: &key, dirty: true, } - current.children = make(map[string]*Node, len(value)) - if value != nil { - current.value.Store(value) - for i, val := range value { + current.children = make(map[string]*Node, len(values)) + if values != nil { + current.value.Store(values) + for i, value := range values { var index = i - current.children[strconv.Itoa(i)] = val - val.parent = current - val.index = &index + current.children[strconv.Itoa(i)] = value + value.parent = current + value.index = &index } } return } -// ObjectNode is constructor for Node with an Object value -func ObjectNode(key string, value map[string]*Node) (current *Node) { +// NewObject is constructor for Node with an Object value +func NewObject(values map[string]*Node) (current *Node) { current = &Node{ _type: Object, - key: &key, - children: value, + children: values, dirty: true, } - if value != nil { - current.value.Store(value) - for key, val := range value { - val.parent = current - val.key = &key + if values != nil { + current.value.Store(values) + for key, value := range values { + value.parent = current + value.key = &key } } else { current.children = make(map[string]*Node) @@ -143,6 +137,27 @@ func ObjectNode(key string, value map[string]*Node) (current *Node) { return } +// NewNode is constructor for any suitable type/value. +// List of applicable types: +// +// Result NodeType Underlying value type(s) +// Null nil.(interface{}) +// Numeric float64, float32, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64 +// String string +// Bool bool +// Array []*Node +// Object map[string]*Node +// +// Returns an error for any other value. +func NewNode(value interface{}) (node *Node, err error) { + node = NewNull() + err = node.Set(value) + if err != nil { + return nil, err + } + return +} + func newNode(parent *Node, buf *buffer, _type NodeType, key **string) (current *Node, err error) { current = &Node{ parent: parent, @@ -947,3 +962,11 @@ func (n *Node) root() (node *Node) { } return node } + +func strptr(value string) *string { + return &value +} + +func intptr(value int) *int { + return &value +} diff --git a/node_mutations.go b/node_mutations.go index 786e1ac..a5feb8c 100644 --- a/node_mutations.go +++ b/node_mutations.go @@ -276,7 +276,7 @@ func (n *Node) remove(value *Node) error { if n.IsArray() { delete(n.children, strconv.Itoa(*value.index)) n.dropindex(*value.index) - } else { + } else if value.key != nil { delete(n.children, *value.key) } value.parent = nil @@ -366,8 +366,11 @@ func (n *Node) setReference(parent *Node, key *string, index *int) { if key == nil { n.key = nil } else { - temp := *key - n.key = &temp + n.key = strptr(*key) + } + if index == nil { + n.index = nil + } else { + n.index = intptr(*index) } - n.index = index } diff --git a/node_mutations_test.go b/node_mutations_test.go index 47b11c7..db2ad88 100644 --- a/node_mutations_test.go +++ b/node_mutations_test.go @@ -22,7 +22,7 @@ func TestNode_SetNull(t *testing.T) { }{ { name: "Null", - node: NullNode(""), + node: NewNull(), }, { name: "parsed Null", @@ -30,7 +30,7 @@ func TestNode_SetNull(t *testing.T) { }, { name: "Bool", - node: BoolNode("", false), + node: NewBool(false), }, { name: "parsed Bool", @@ -38,7 +38,7 @@ func TestNode_SetNull(t *testing.T) { }, { name: "String", - node: StringNode("", "String value"), + node: NewString("String value"), }, { name: "parsed String", @@ -46,7 +46,7 @@ func TestNode_SetNull(t *testing.T) { }, { name: "Numeric", - node: NumericNode("", 123.456), + node: NewNumeric(123.456), }, { name: "parsed Numeric", @@ -54,10 +54,10 @@ func TestNode_SetNull(t *testing.T) { }, { name: "Array", - node: ArrayNode("", []*Node{ - NumericNode("0", 123.456), - BoolNode("1", false), - NullNode("2"), + node: NewArray([]*Node{ + NewNumeric(123.456), + NewBool(false), + NewNull(), }), }, { @@ -66,10 +66,10 @@ func TestNode_SetNull(t *testing.T) { }, { name: "Object", - node: ObjectNode("", map[string]*Node{ - "foo": NumericNode("foo", 123.456), - "bar": BoolNode("bar", false), - "baz": NullNode("baz"), + node: NewObject(map[string]*Node{ + "foo": NewNumeric(123.456), + "bar": NewBool(false), + "baz": NewNull(), }), }, { @@ -108,7 +108,7 @@ func TestNode_SetNumeric(t *testing.T) { }{ { name: "Null", - node: NullNode(""), + node: NewNull(), }, { name: "parsed Null", @@ -116,7 +116,7 @@ func TestNode_SetNumeric(t *testing.T) { }, { name: "Bool", - node: BoolNode("", false), + node: NewBool(false), }, { name: "parsed Bool", @@ -124,7 +124,7 @@ func TestNode_SetNumeric(t *testing.T) { }, { name: "String", - node: StringNode("", "String value"), + node: NewString("String value"), }, { name: "parsed String", @@ -132,7 +132,7 @@ func TestNode_SetNumeric(t *testing.T) { }, { name: "Numeric", - node: NumericNode("", 123.456), + node: NewNumeric(123.456), }, { name: "parsed Numeric", @@ -140,10 +140,10 @@ func TestNode_SetNumeric(t *testing.T) { }, { name: "Array", - node: ArrayNode("", []*Node{ - NumericNode("0", 123.456), - BoolNode("1", false), - NullNode("2"), + node: NewArray([]*Node{ + NewNumeric(123.456), + NewBool(false), + NewNull(), }), }, { @@ -152,10 +152,10 @@ func TestNode_SetNumeric(t *testing.T) { }, { name: "Object", - node: ObjectNode("", map[string]*Node{ - "foo": NumericNode("foo", 123.456), - "bar": BoolNode("bar", false), - "baz": NullNode("baz"), + node: NewObject(map[string]*Node{ + "foo": NewNumeric(123.456), + "bar": NewBool(false), + "baz": NewNull(), }), }, { @@ -194,7 +194,7 @@ func TestNode_SetString(t *testing.T) { }{ { name: "Null", - node: NullNode(""), + node: NewNull(), }, { name: "parsed Null", @@ -202,7 +202,7 @@ func TestNode_SetString(t *testing.T) { }, { name: "Bool", - node: BoolNode("", false), + node: NewBool(false), }, { name: "parsed Bool", @@ -210,7 +210,7 @@ func TestNode_SetString(t *testing.T) { }, { name: "String", - node: StringNode("", "String value"), + node: NewString("String value"), }, { name: "parsed String", @@ -218,7 +218,7 @@ func TestNode_SetString(t *testing.T) { }, { name: "Numeric", - node: NumericNode("", 123.456), + node: NewNumeric(123.456), }, { name: "parsed Numeric", @@ -226,10 +226,10 @@ func TestNode_SetString(t *testing.T) { }, { name: "Array", - node: ArrayNode("", []*Node{ - NumericNode("0", 123.456), - BoolNode("1", false), - NullNode("2"), + node: NewArray([]*Node{ + NewNumeric(123.456), + NewBool(false), + NewNull(), }), }, { @@ -238,10 +238,10 @@ func TestNode_SetString(t *testing.T) { }, { name: "Object", - node: ObjectNode("", map[string]*Node{ - "foo": NumericNode("foo", 123.456), - "bar": BoolNode("bar", false), - "baz": NullNode("baz"), + node: NewObject(map[string]*Node{ + "foo": NewNumeric(123.456), + "bar": NewBool(false), + "baz": NewNull(), }), }, { @@ -280,7 +280,7 @@ func TestNode_SetBool(t *testing.T) { }{ { name: "Null", - node: NullNode(""), + node: NewNull(), }, { name: "parsed Null", @@ -288,7 +288,7 @@ func TestNode_SetBool(t *testing.T) { }, { name: "Bool", - node: BoolNode("", false), + node: NewBool(false), }, { name: "parsed Bool", @@ -296,7 +296,7 @@ func TestNode_SetBool(t *testing.T) { }, { name: "String", - node: StringNode("", "String value"), + node: NewString("String value"), }, { name: "parsed String", @@ -304,7 +304,7 @@ func TestNode_SetBool(t *testing.T) { }, { name: "Numeric", - node: NumericNode("", 123.456), + node: NewNumeric(123.456), }, { name: "parsed Numeric", @@ -312,10 +312,10 @@ func TestNode_SetBool(t *testing.T) { }, { name: "Array", - node: ArrayNode("", []*Node{ - NumericNode("0", 123.456), - BoolNode("1", false), - NullNode("2"), + node: NewArray([]*Node{ + NewNumeric(123.456), + NewBool(false), + NewNull(), }), }, { @@ -324,10 +324,10 @@ func TestNode_SetBool(t *testing.T) { }, { name: "Object", - node: ObjectNode("", map[string]*Node{ - "foo": NumericNode("foo", 123.456), - "bar": BoolNode("bar", false), - "baz": NullNode("baz"), + node: NewObject(map[string]*Node{ + "foo": NewNumeric(123.456), + "bar": NewBool(false), + "baz": NewNull(), }), }, { @@ -360,10 +360,10 @@ func TestNode_SetBool(t *testing.T) { func TestNode_SetArray(t *testing.T) { expected := []*Node{ - NullNode("0"), - BoolNode("1", false), - StringNode("2", "Foo"), - NumericNode("3", 1), + withKey(NewNull(), "0"), + NewBool(false), + withKey(NewString("Foo"), "2"), + withKey(NewNumeric(1), "3"), } tests := []struct { name string @@ -371,7 +371,7 @@ func TestNode_SetArray(t *testing.T) { }{ { name: "Null", - node: NullNode(""), + node: NewNull(), }, { name: "parsed Null", @@ -379,7 +379,7 @@ func TestNode_SetArray(t *testing.T) { }, { name: "Bool", - node: BoolNode("", false), + node: NewBool(false), }, { name: "parsed Bool", @@ -387,7 +387,7 @@ func TestNode_SetArray(t *testing.T) { }, { name: "String", - node: StringNode("", "String value"), + node: NewString("String value"), }, { name: "parsed String", @@ -395,7 +395,7 @@ func TestNode_SetArray(t *testing.T) { }, { name: "Numeric", - node: NumericNode("", 123.456), + node: NewNumeric(123.456), }, { name: "parsed Numeric", @@ -403,10 +403,10 @@ func TestNode_SetArray(t *testing.T) { }, { name: "Array", - node: ArrayNode("", []*Node{ - NumericNode("0", 123.456), - BoolNode("1", false), - NullNode("2"), + node: NewArray([]*Node{ + NewNumeric(123.456), + NewBool(false), + NewNull(), }), }, { @@ -415,10 +415,10 @@ func TestNode_SetArray(t *testing.T) { }, { name: "Object", - node: ObjectNode("", map[string]*Node{ - "foo": NumericNode("foo", 123.456), - "bar": BoolNode("bar", false), - "baz": NullNode("baz"), + node: NewObject(map[string]*Node{ + "foo": NewNumeric(123.456), + "bar": NewBool(false), + "baz": NewNull(), }), }, { @@ -448,8 +448,8 @@ func TestNode_SetArray(t *testing.T) { func TestNode_SetObject(t *testing.T) { expected := map[string]*Node{ - "foo": NullNode("foo"), - "bar": BoolNode("bar", false), + "foo": NewNull(), + "bar": NewBool(false), } tests := []struct { name string @@ -457,7 +457,7 @@ func TestNode_SetObject(t *testing.T) { }{ { name: "Null", - node: NullNode(""), + node: NewNull(), }, { name: "parsed Null", @@ -465,7 +465,7 @@ func TestNode_SetObject(t *testing.T) { }, { name: "Bool", - node: BoolNode("", false), + node: NewBool(false), }, { name: "parsed Bool", @@ -473,7 +473,7 @@ func TestNode_SetObject(t *testing.T) { }, { name: "String", - node: StringNode("", "String value"), + node: NewString("String value"), }, { name: "parsed String", @@ -481,7 +481,7 @@ func TestNode_SetObject(t *testing.T) { }, { name: "Numeric", - node: NumericNode("", 123.456), + node: NewNumeric(123.456), }, { name: "parsed Numeric", @@ -489,10 +489,10 @@ func TestNode_SetObject(t *testing.T) { }, { name: "Array", - node: ArrayNode("", []*Node{ - NumericNode("0", 123.456), - BoolNode("1", false), - NullNode("2"), + node: NewArray([]*Node{ + NewNumeric(123.456), + NewBool(false), + NewNull(), }), }, { @@ -501,10 +501,10 @@ func TestNode_SetObject(t *testing.T) { }, { name: "Object", - node: ObjectNode("", map[string]*Node{ - "foo": NumericNode("foo", 123.456), - "bar": BoolNode("bar", false), - "baz": NullNode("baz"), + node: NewObject(map[string]*Node{ + "foo": NewNumeric(123.456), + "bar": NewBool(false), + "baz": NewNull(), }), }, { @@ -584,13 +584,13 @@ func TestNode_mutations(t *testing.T) { } func TestNode_AppendArray(t *testing.T) { - if err := Must(Unmarshal([]byte(`[{"foo":"bar"}]`))).AppendArray(NullNode("")); err != nil { + if err := Must(Unmarshal([]byte(`[{"foo":"bar"}]`))).AppendArray(NewNull()); err != nil { t.Errorf("AppendArray should return error") } root := Must(Unmarshal([]byte(`[{"foo":"bar"}]`))) - if err := root.AppendArray(NullNode("")); err != nil { + if err := root.AppendArray(NewNull()); err != nil { t.Errorf("AppendArray returns error: %v", err) } if value, err := Marshal(root); err != nil { @@ -600,8 +600,8 @@ func TestNode_AppendArray(t *testing.T) { } if err := root.AppendArray( - NumericNode("", 1), - StringNode("", "foo"), + NewNumeric(1), + NewString("foo"), Must(Unmarshal([]byte(`[0,1,null,true,"example"]`))), Must(Unmarshal([]byte(`{"foo": true, "bar": null, "baz": 123}`))), ); err != nil { @@ -620,7 +620,7 @@ func TestNode_AppendArray_self(t *testing.T) { if err := root.AppendArray(root); err == nil { t.Errorf("AppendArray must returns error") } - if err := root.MustIndex(0).AppendArray(NullNode("")); err == nil { + if err := root.MustIndex(0).AppendArray(NewNull()); err == nil { t.Errorf("AppendArray must returns error") } @@ -655,7 +655,7 @@ func TestNode_AppendArray_self(t *testing.T) { t.Errorf("Marshal returns wrong value: %s", string(value)) } - err = root.AppendArray(ArrayNode("", nil)) + err = root.AppendArray(NewArray(nil)) if err != nil { t.Errorf("AppendArray returns error: %s", err) } @@ -695,13 +695,13 @@ func TestNode_AppendArray_self(t *testing.T) { } func TestNode_AppendObject(t *testing.T) { - if err := Must(Unmarshal([]byte(`{"foo":"bar","baz":null}`))).AppendObject("biz", NullNode("")); err != nil { + if err := Must(Unmarshal([]byte(`{"foo":"bar","baz":null}`))).AppendObject("biz", NewNull()); err != nil { t.Errorf("AppendArray should return error") } root := Must(Unmarshal([]byte(`{"foo":"bar"}`))) - if err := root.AppendObject("biz", NullNode("")); err != nil { + if err := root.AppendObject("biz", NewNull()); err != nil { t.Errorf("AppendArray returns error: %v", err) } if value, err := Marshal(root); err != nil { @@ -710,7 +710,7 @@ func TestNode_AppendObject(t *testing.T) { t.Errorf("Marshal returns wrong value: %s", string(value)) } - if err := root.AppendObject("foo", NumericNode("", 1)); err != nil { + if err := root.AppendObject("foo", NewNumeric(1)); err != nil { t.Errorf("AppendArray returns error: %v", err) } if value, err := Marshal(root); err != nil { @@ -726,7 +726,7 @@ func TestNode_AppendObject_self(t *testing.T) { if err := root.AppendObject("foo", root); err == nil { t.Errorf("AppendArray must returns error") } - if err := root.MustKey("fiz").AppendObject("fiz", NullNode("")); err == nil { + if err := root.MustKey("fiz").AppendObject("fiz", NewNull()); err == nil { t.Errorf("AppendArray must returns error: not object") } @@ -1009,10 +1009,10 @@ func TestNode_DeleteNode(t *testing.T) { initial := `{"foo":{"bar":["baz",1,null]},"biz":"zip"}` root := Must(Unmarshal([]byte(initial))) - if err := root.DeleteNode(NullNode("")); err == nil { + if err := root.DeleteNode(NewNull()); err == nil { t.Errorf("Expected error") } - if err := root.DeleteNode(StringNode("biz", "zip")); err == nil { + if err := root.DeleteNode(withKey(NewString("zip"), "biz")); err == nil { t.Errorf("Expected error") } if err := root.MustKey("biz").DeleteNode(root.MustKey("biz")); err == nil { @@ -1022,7 +1022,7 @@ func TestNode_DeleteNode(t *testing.T) { t.Errorf("Expected error") } - node := NullNode("") + node := NewNull() if err := root.AppendObject("key", node); err != nil { t.Errorf("UnExpected error: %v", err) } @@ -1041,7 +1041,7 @@ func TestNode_DeleteNode(t *testing.T) { func TestIssue22_SetArray_not_working(t *testing.T) { data := []byte(`{"key": [1, 2, 3]}`) - node := NumericNode("", 4) + node := NewNumeric(4) expected := `{"key":[1,2,4]}` root := Must(Unmarshal(data)) @@ -1083,7 +1083,7 @@ func TestNode_SetArray1(t *testing.T) { name: "null -> [1,2,3]", json: `null`, path: `$`, - value: []*Node{NumericNode("", 1), NumericNode("", 2), NumericNode("", 3)}, + value: []*Node{NewNumeric(1), NewNumeric(2), NewNumeric(3)}, wantErr: false, expected: `[1,2,3]`, }, @@ -1091,7 +1091,7 @@ func TestNode_SetArray1(t *testing.T) { name: `{"key": null} -> {"key": [1,2,3]}`, json: `{"key": null}`, path: `$.key`, - value: []*Node{NumericNode("", 1), NumericNode("", 2), NumericNode("", 3)}, + value: []*Node{NewNumeric(1), NewNumeric(2), NewNumeric(3)}, wantErr: false, expected: `{"key":[1,2,3]}`, }, @@ -1099,7 +1099,7 @@ func TestNode_SetArray1(t *testing.T) { name: `{"key": [1,2,3]} -> {"key": [1,4,3]}`, json: `{"key": [1,2,3]}`, path: `$.key`, - value: []*Node{NumericNode("", 1), NumericNode("", 4), NumericNode("", 3)}, + value: []*Node{NewNumeric(1), NewNumeric(4), NewNumeric(3)}, wantErr: false, expected: `{"key":[1,4,3]}`, }, @@ -1107,7 +1107,7 @@ func TestNode_SetArray1(t *testing.T) { name: `{"key": [[1,2,3],2,3]} -> {"key": [[4,5,6],2,3]}`, json: `{"key": [[1,2,3],2,3]}`, path: `$.key[0]`, - value: []*Node{NumericNode("", 4), NumericNode("", 5), NumericNode("", 6)}, + value: []*Node{NewNumeric(4), NewNumeric(5), NewNumeric(6)}, wantErr: false, expected: `{"key":[[4,5,6],2,3]}`, }, @@ -1161,7 +1161,7 @@ func TestNode_SetObject1(t *testing.T) { name: `null -> {"foo": "bar"}`, json: `null`, path: `$`, - value: map[string]*Node{"foo": StringNode("foo", "bar")}, + value: map[string]*Node{"foo": NewString("bar")}, wantErr: false, expected: `{"foo":"bar"}`, }, @@ -1169,7 +1169,7 @@ func TestNode_SetObject1(t *testing.T) { name: `{"key": null} -> {"key": {"foo": "bar"}}`, json: `{"key": null}`, path: `$.key`, - value: map[string]*Node{"foo": StringNode("foo", "bar")}, + value: map[string]*Node{"foo": NewString("bar")}, wantErr: false, expected: `{"key":{"foo":"bar"}}`, }, @@ -1177,7 +1177,7 @@ func TestNode_SetObject1(t *testing.T) { name: `{"key": [1,2,3]} -> {"key": {"foo":"bar"}}`, json: `{"key": [1,2,3]}`, path: `$.key`, - value: map[string]*Node{"foo": StringNode("foo", "bar")}, + value: map[string]*Node{"foo": NewString("bar")}, wantErr: false, expected: `{"key":{"foo":"bar"}}`, }, @@ -1185,7 +1185,7 @@ func TestNode_SetObject1(t *testing.T) { name: `{"key": [[1,2,3],2,3]} -> {"key": [{"foo":"bar"},2,3]}`, json: `{"key": [[1,2,3],2,3]}`, path: `$.key[0]`, - value: map[string]*Node{"foo": StringNode("foo", "bar")}, + value: map[string]*Node{"foo": NewString("bar")}, wantErr: false, expected: `{"key":[{"foo":"bar"},2,3]}`, }, @@ -1193,7 +1193,7 @@ func TestNode_SetObject1(t *testing.T) { name: `{"key": {"baz": [null]}} -> {"key": {"baz": [{"foo":"bar"}]}}`, json: `{"key": {"baz": [null]}}`, path: `$.key.baz[0]`, - value: map[string]*Node{"foo": StringNode("foo", "bar")}, + value: map[string]*Node{"foo": NewString("bar")}, wantErr: false, expected: `{"key":{"baz":[{"foo":"bar"}]}}`, }, @@ -1351,7 +1351,7 @@ func TestNode_update(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - node := NullNode("") + node := NewNull() if err := node.update(tt.args._type, tt.args.value); (err != nil) != tt.wantErr { t.Errorf("update() error = %v, wantErr %v", err, tt.wantErr) } @@ -1361,9 +1361,9 @@ func TestNode_update(t *testing.T) { func TestNode_update_fail(t *testing.T) { i0 := 0 - node := NullNode("") - parent := NullNode("") - broken := NullNode("0") + node := NewNull() + parent := NewNull() + broken := NewNull() broken.index = &i0 broken.parent = parent @@ -1376,10 +1376,10 @@ func TestNode_update_fail(t *testing.T) { } func TestNode_Clone(t *testing.T) { - node := NumericNode("", 1.1) - null := NullNode("") - array := ArrayNode("", []*Node{node, null}) - object := ObjectNode("", map[string]*Node{"array": array}) + node := NewNumeric(1.1) + null := NewNull() + array := NewArray([]*Node{node, null}) + object := NewObject(map[string]*Node{"array": array}) tests := []struct { name string @@ -1438,7 +1438,7 @@ func ExampleNode_Clone() { nodes[i] = node.Clone() } - result, _ := Marshal(ArrayNode("", nodes)) + result, _ := Marshal(NewArray(nodes)) fmt.Printf("Array: %s\n", result) result, _ = Marshal(root) @@ -1483,9 +1483,9 @@ func ExampleNode_Clone() { func TestNode_SetNode(t *testing.T) { iValue := `{"foo": [{"bar":"baz"}]}` idempotent := Must(Unmarshal([]byte(iValue))) - child := StringNode("", "example") - parent := ArrayNode("", []*Node{child}) - array := ArrayNode("", []*Node{}) + child := NewString("example") + parent := NewArray([]*Node{child}) + array := NewArray([]*Node{}) proxy := func(root *Node) *Node { return root } @@ -1501,15 +1501,15 @@ func TestNode_SetNode(t *testing.T) { }{ { name: "Null->Numeric(1)", - root: NullNode(""), + root: NewNull(), getter: proxy, - value: NumericNode("", 1), + value: NewNumeric(1), result: `1`, wantErr: false, }, { name: "Null->Object", - root: NullNode(""), + root: NewNull(), getter: proxy, value: Must(Unmarshal([]byte(`{"bar":"baz"}`))), result: `{"bar":"baz"}`, @@ -1517,7 +1517,7 @@ func TestNode_SetNode(t *testing.T) { }, { name: "Null->Object(ref)", - root: NullNode(""), + root: NewNull(), getter: proxy, value: idempotent.MustObject()["foo"].MustArray()[0], result: `{"bar":"baz"}`, diff --git a/node_test.go b/node_test.go index 281043d..de9f107 100644 --- a/node_test.go +++ b/node_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "math" "reflect" + "sync/atomic" "testing" ) @@ -171,10 +172,10 @@ func TestNode_GetArray(t *testing.T) { t.Errorf("root.GetArray() is corrupted") } - root = NullNode("") + root = NewNull() _, err = root.GetArray() if err == nil { - t.Errorf("Error on root.GetArray(): NullNode") + t.Errorf("Error on root.GetArray(): NewNull") } if _, err := (*Node)(nil).GetArray(); err == nil { t.Errorf("(nil).GetArray() should be an error") @@ -207,10 +208,10 @@ func TestNode_GetBool(t *testing.T) { t.Errorf("root.GetBool() is corrupted") } - root = NullNode("") + root = NewNull() _, err = root.GetBool() if err == nil { - t.Errorf("Error on root.GetBool(): NullNode") + t.Errorf("Error on root.GetBool(): NewNull") } if _, err := (*Node)(nil).GetBool(); err == nil { t.Errorf("(nil).GetBool() should be an error") @@ -319,10 +320,10 @@ func TestNode_GetNull(t *testing.T) { t.Errorf("root.GetNull() is corrupted") } - root = NumericNode("", 1) + root = NewNumeric(1) _, err = root.GetNull() if err == nil { - t.Errorf("Error expected on root.GetNull() using NumericNode") + t.Errorf("Error expected on root.GetNull() using NewNumeric") } if _, err := (*Node)(nil).GetNull(); err == nil { t.Errorf("(nil).GetNull() should be an error") @@ -355,10 +356,10 @@ func TestNode_GetNumeric(t *testing.T) { t.Errorf("root.GetNumeric() is corrupted") } - root = StringNode("", "") + root = NewString("") _, err = root.GetNumeric() if err == nil { - t.Errorf("Error on root.GetNumeric() using StringNode") + t.Errorf("Error on root.GetNumeric() using NewString") } root = valueNode(nil, "", Numeric, "foo") @@ -400,10 +401,10 @@ func TestNode_GetObject(t *testing.T) { t.Errorf("root.GetObject() is corrupted: bar") } - root = NullNode("") + root = NewNull() _, err = root.GetObject() if err == nil { - t.Errorf("Error on root.GetArray(): NullNode") + t.Errorf("Error on root.GetArray(): NewNull") } if _, err := (*Node)(nil).GetObject(); err == nil { t.Errorf("(nil).GetObject() should be an error") @@ -439,10 +440,10 @@ func TestNode_GetString(t *testing.T) { t.Errorf("root.GetString() is corrupted") } - root = NumericNode("", 1) + root = NewNumeric(1) _, err = root.GetString() if err == nil { - t.Errorf("Error on root.GetString(): NumericNode") + t.Errorf("Error on root.GetString(): NewNumeric") } if _, err := (*Node)(nil).GetString(); err == nil { t.Errorf("(nil).GetString() should be an error") @@ -476,10 +477,10 @@ func TestNode_Index(t *testing.T) { if (*Node)(nil).Index() != -1 { t.Errorf("Wrong value for (*Node)(nil).Index()") } - if NullNode("").Index() != -1 { + if NewNull().Index() != -1 { t.Errorf("Wrong value for Null.Index()") } - if ObjectNode("", nil).Index() != -1 { + if NewObject(nil).Index() != -1 { t.Errorf("Wrong value for Null.Index()") } } @@ -759,16 +760,16 @@ func TestNode_String(t *testing.T) { t.Errorf("Wrong (Unmarshal) root.String()") } - root = StringNode("", "foo") + root = NewString("foo") value = root.String() if value != `"foo"` { - t.Errorf("Wrong (StringNode) root.String()") + t.Errorf("Wrong (NewString) root.String()") } - root = NullNode("") + root = NewNull() value = root.String() if value != "null" { - t.Errorf("Wrong (NullNode) root.String()") + t.Errorf("Wrong (NewNull) root.String()") } if (*Node)(nil).String() != "" { t.Errorf("Wrong value for (*Node)(nil).String()") @@ -913,68 +914,68 @@ func TestNode_Eq(t *testing.T) { }, { name: "filled maps", - left: valueNode(nil, "{}", Object, map[string]*Node{"foo": StringNode("foo", "bar")}), - right: valueNode(nil, "{}", Object, map[string]*Node{"foo": StringNode("foo", "bar")}), + left: valueNode(nil, "{}", Object, map[string]*Node{"foo": NewString("bar")}), + right: valueNode(nil, "{}", Object, map[string]*Node{"foo": NewString("bar")}), expected: true, }, { name: "filled arrays", - left: valueNode(nil, "[]", Array, []*Node{NumericNode("0", 1)}), - right: valueNode(nil, "[]", Array, []*Node{NumericNode("0", 1)}), + left: valueNode(nil, "[]", Array, []*Node{NewNumeric(1)}), + right: valueNode(nil, "[]", Array, []*Node{NewNumeric(1)}), expected: true, }, { name: "filled maps: different", - left: valueNode(nil, "{}", Object, map[string]*Node{"foo": StringNode("foo", "bar")}), - right: valueNode(nil, "{}", Object, map[string]*Node{"foo": StringNode("foo", "baz")}), + left: valueNode(nil, "{}", Object, map[string]*Node{"foo": NewString("bar")}), + right: valueNode(nil, "{}", Object, map[string]*Node{"foo": NewString("baz")}), expected: false, }, { name: "filled maps: different keys", - left: valueNode(nil, "{}", Object, map[string]*Node{"foo": StringNode("foo", "bar")}), - right: valueNode(nil, "{}", Object, map[string]*Node{"baz": StringNode("baz", "bar")}), + left: valueNode(nil, "{}", Object, map[string]*Node{"foo": NewString("bar")}), + right: valueNode(nil, "{}", Object, map[string]*Node{"baz": NewString("bar")}), expected: false, }, { name: "filled arrays: different", - left: valueNode(nil, "[]", Array, []*Node{NumericNode("0", 1)}), - right: valueNode(nil, "[]", Array, []*Node{NumericNode("0", 2)}), + left: valueNode(nil, "[]", Array, []*Node{NewNumeric(1)}), + right: valueNode(nil, "[]", Array, []*Node{NewNumeric(2)}), expected: false, }, { name: "filled maps: errors", - left: valueNode(nil, "{}", Object, map[string]*Node{"foo": StringNode("foo", "bar")}), + left: valueNode(nil, "{}", Object, map[string]*Node{"foo": NewString("bar")}), right: valueNode(nil, "{}", Object, map[string]*Node{"foo": valueNode(nil, "", String, 123)}), error: true, }, { name: "filled arrays: errors", - left: valueNode(nil, "[]", Array, []*Node{NumericNode("0", 1)}), + left: valueNode(nil, "[]", Array, []*Node{NewNumeric(1)}), right: valueNode(nil, "[]", Array, []*Node{valueNode(nil, "", Numeric, "foo")}), error: true, }, { name: "floats 1", - left: NumericNode("", 1.1), - right: NumericNode("", 1.2), + left: NewNumeric(1.1), + right: NewNumeric(1.2), expected: false, }, { name: "floats 2", - left: NumericNode("", -1), - right: NumericNode("", 1), + left: NewNumeric(-1), + right: NewNumeric(1), expected: false, }, { name: "floats 3", - left: NumericNode("", 1.0001), - right: NumericNode("", 1.00011), + left: NewNumeric(1.0001), + right: NewNumeric(1.00011), expected: false, }, { name: "error 1", left: valueNode(nil, "", Numeric, "foo"), - right: NumericNode("", 1.00011), + right: NewNumeric(1.00011), error: true, }, { @@ -1010,12 +1011,12 @@ func TestNode_Eq(t *testing.T) { { name: "nil/value", left: nil, - right: StringNode("", "foo"), + right: NewString("foo"), error: true, }, { name: "value/nil", - left: StringNode("", "foo"), + left: NewString("foo"), right: nil, error: true, }, @@ -1081,31 +1082,31 @@ func TestNode_Neq(t *testing.T) { }, { name: "floats 1", - left: NumericNode("", 1.1), - right: NumericNode("", 1.2), + left: NewNumeric(1.1), + right: NewNumeric(1.2), expected: true, }, { name: "floats 2", - left: NumericNode("", -1), - right: NumericNode("", 1), + left: NewNumeric(-1), + right: NewNumeric(1), expected: true, }, { name: "floats 3", - left: NumericNode("", 1.0001), - right: NumericNode("", 1.00011), + left: NewNumeric(1.0001), + right: NewNumeric(1.00011), expected: true, }, { name: "nil/value", left: nil, - right: StringNode("", "foo"), + right: NewString("foo"), error: true, }, { name: "value/nil", - left: StringNode("", "foo"), + left: NewString("foo"), right: nil, error: true, }, @@ -1135,97 +1136,97 @@ func TestNode_Ge(t *testing.T) { }{ { name: "null", - left: NullNode(""), - right: NullNode(""), + left: NewNull(), + right: NewNull(), error: true, }, { name: "array", - left: ArrayNode("", nil), - right: ArrayNode("", nil), + left: NewArray(nil), + right: NewArray(nil), error: true, }, { name: "object", - left: ObjectNode("", nil), - right: ObjectNode("", nil), + left: NewObject(nil), + right: NewObject(nil), error: true, }, { name: "float 1", - left: NumericNode("", 3.1), - right: NumericNode("", 3), + left: NewNumeric(3.1), + right: NewNumeric(3), expected: true, }, { name: "float 2", - left: NumericNode("", 0), - right: NumericNode("", -3), + left: NewNumeric(0), + right: NewNumeric(-3), expected: true, }, { name: "float 3", - left: NumericNode("", 0), - right: NumericNode("", 0), + left: NewNumeric(0), + right: NewNumeric(0), expected: false, }, { name: "float 4", - left: NumericNode("", math.MaxFloat64), - right: NumericNode("", math.SmallestNonzeroFloat64), + left: NewNumeric(math.MaxFloat64), + right: NewNumeric(math.SmallestNonzeroFloat64), expected: true, }, { name: "float 5", - left: NumericNode("", math.SmallestNonzeroFloat64), - right: NumericNode("", math.MaxFloat64), + left: NewNumeric(math.SmallestNonzeroFloat64), + right: NewNumeric(math.MaxFloat64), expected: false, }, { name: "string 1", - left: StringNode("", "z"), - right: StringNode("", "a"), + left: NewString("z"), + right: NewString("a"), expected: true, }, { name: "string 2", - left: StringNode("", "a"), - right: StringNode("", "a"), + left: NewString("a"), + right: NewString("a"), expected: false, }, { name: "wrong type 1", - left: StringNode("", "z"), - right: NumericNode("", math.MaxFloat64), + left: NewString("z"), + right: NewNumeric(math.MaxFloat64), expected: false, }, { name: "wrong type 2", - left: NumericNode("", math.MaxFloat64), - right: StringNode("", "z"), + left: NewNumeric(math.MaxFloat64), + right: NewString("z"), expected: false, }, { name: "error 1", left: valueNode(nil, "e1", Numeric, string("e1")), - right: NumericNode("", 1), + right: NewNumeric(1), error: true, }, { name: "error 2", left: valueNode(nil, "e1", String, float64(1)), - right: StringNode("", "foo"), + right: NewString("foo"), error: true, }, { name: "nil/value", left: nil, - right: StringNode("", "foo"), + right: NewString("foo"), error: true, }, { name: "value/nil", - left: StringNode("", "foo"), + left: NewString("foo"), right: nil, error: true, }, @@ -1253,97 +1254,97 @@ func TestNode_Geq(t *testing.T) { }{ { name: "null", - left: NullNode(""), - right: NullNode(""), + left: NewNull(), + right: NewNull(), error: true, }, { name: "array", - left: ArrayNode("", nil), - right: ArrayNode("", nil), + left: NewArray(nil), + right: NewArray(nil), error: true, }, { name: "object", - left: ObjectNode("", nil), - right: ObjectNode("", nil), + left: NewObject(nil), + right: NewObject(nil), error: true, }, { name: "float 1", - left: NumericNode("", 3.1), - right: NumericNode("", 3), + left: NewNumeric(3.1), + right: NewNumeric(3), expected: true, }, { name: "float 2", - left: NumericNode("", 0), - right: NumericNode("", -3), + left: NewNumeric(0), + right: NewNumeric(-3), expected: true, }, { name: "float 3", - left: NumericNode("", 0), - right: NumericNode("", 0), + left: NewNumeric(0), + right: NewNumeric(0), expected: true, }, { name: "float 4", - left: NumericNode("", math.MaxFloat64), - right: NumericNode("", math.SmallestNonzeroFloat64), + left: NewNumeric(math.MaxFloat64), + right: NewNumeric(math.SmallestNonzeroFloat64), expected: true, }, { name: "float 5", - left: NumericNode("", math.SmallestNonzeroFloat64), - right: NumericNode("", math.MaxFloat64), + left: NewNumeric(math.SmallestNonzeroFloat64), + right: NewNumeric(math.MaxFloat64), expected: false, }, { name: "string 1", - left: StringNode("", "z"), - right: StringNode("", "a"), + left: NewString("z"), + right: NewString("a"), expected: true, }, { name: "string 2", - left: StringNode("", "a"), - right: StringNode("", "a"), + left: NewString("a"), + right: NewString("a"), expected: true, }, { name: "wrong type 1", - left: StringNode("", "z"), - right: NumericNode("", math.MaxFloat64), + left: NewString("z"), + right: NewNumeric(math.MaxFloat64), expected: false, }, { name: "wrong type 2", - left: NumericNode("", math.MaxFloat64), - right: StringNode("", "z"), + left: NewNumeric(math.MaxFloat64), + right: NewString("z"), expected: false, }, { name: "error 1", left: valueNode(nil, "e1", Numeric, string("e1")), - right: NumericNode("", 1), + right: NewNumeric(1), error: true, }, { name: "error 2", left: valueNode(nil, "e1", String, float64(1)), - right: StringNode("", "foo"), + right: NewString("foo"), error: true, }, { name: "nil/value", left: nil, - right: StringNode("", "foo"), + right: NewString("foo"), error: true, }, { name: "value/nil", - left: StringNode("", "foo"), + left: NewString("foo"), right: nil, error: true, }, @@ -1372,97 +1373,97 @@ func TestNode_Le(t *testing.T) { }{ { name: "null", - left: NullNode(""), - right: NullNode(""), + left: NewNull(), + right: NewNull(), error: true, }, { name: "array", - left: ArrayNode("", nil), - right: ArrayNode("", nil), + left: NewArray(nil), + right: NewArray(nil), error: true, }, { name: "object", - left: ObjectNode("", nil), - right: ObjectNode("", nil), + left: NewObject(nil), + right: NewObject(nil), error: true, }, { name: "float 1", - left: NumericNode("", 3.1), - right: NumericNode("", 3), + left: NewNumeric(3.1), + right: NewNumeric(3), expected: false, }, { name: "float 2", - left: NumericNode("", 0), - right: NumericNode("", -3), + left: NewNumeric(0), + right: NewNumeric(-3), expected: false, }, { name: "float 3", - left: NumericNode("", 0), - right: NumericNode("", 0), + left: NewNumeric(0), + right: NewNumeric(0), expected: false, }, { name: "float 4", - left: NumericNode("", math.MaxFloat64), - right: NumericNode("", math.SmallestNonzeroFloat64), + left: NewNumeric(math.MaxFloat64), + right: NewNumeric(math.SmallestNonzeroFloat64), expected: false, }, { name: "float 5", - left: NumericNode("", math.SmallestNonzeroFloat64), - right: NumericNode("", math.MaxFloat64), + left: NewNumeric(math.SmallestNonzeroFloat64), + right: NewNumeric(math.MaxFloat64), expected: true, }, { name: "string 1", - left: StringNode("", "z"), - right: StringNode("", "a"), + left: NewString("z"), + right: NewString("a"), expected: false, }, { name: "string 2", - left: StringNode("", "a"), - right: StringNode("", "a"), + left: NewString("a"), + right: NewString("a"), expected: false, }, { name: "wrong type 1", - left: StringNode("", "z"), - right: NumericNode("", math.MaxFloat64), + left: NewString("z"), + right: NewNumeric(math.MaxFloat64), expected: false, }, { name: "wrong type 2", - left: NumericNode("", math.MaxFloat64), - right: StringNode("", "z"), + left: NewNumeric(math.MaxFloat64), + right: NewString("z"), expected: false, }, { name: "error 1", left: valueNode(nil, "e1", Numeric, string("e1")), - right: NumericNode("", 1), + right: NewNumeric(1), error: true, }, { name: "error 2", left: valueNode(nil, "e1", String, float64(1)), - right: StringNode("", "foo"), + right: NewString("foo"), error: true, }, { name: "nil/value", left: nil, - right: StringNode("", "foo"), + right: NewString("foo"), error: true, }, { name: "value/nil", - left: StringNode("", "foo"), + left: NewString("foo"), right: nil, error: true, }, @@ -1491,97 +1492,97 @@ func TestNode_Leq(t *testing.T) { }{ { name: "null", - left: NullNode(""), - right: NullNode(""), + left: NewNull(), + right: NewNull(), error: true, }, { name: "array", - left: ArrayNode("", nil), - right: ArrayNode("", nil), + left: NewArray(nil), + right: NewArray(nil), error: true, }, { name: "object", - left: ObjectNode("", nil), - right: ObjectNode("", nil), + left: NewObject(nil), + right: NewObject(nil), error: true, }, { name: "float 1", - left: NumericNode("", 3.1), - right: NumericNode("", 3), + left: NewNumeric(3.1), + right: NewNumeric(3), expected: false, }, { name: "float 2", - left: NumericNode("", 0), - right: NumericNode("", -3), + left: NewNumeric(0), + right: NewNumeric(-3), expected: false, }, { name: "float 3", - left: NumericNode("", 0), - right: NumericNode("", 0), + left: NewNumeric(0), + right: NewNumeric(0), expected: true, }, { name: "float 4", - left: NumericNode("", math.MaxFloat64), - right: NumericNode("", math.SmallestNonzeroFloat64), + left: NewNumeric(math.MaxFloat64), + right: NewNumeric(math.SmallestNonzeroFloat64), expected: false, }, { name: "float 5", - left: NumericNode("", math.SmallestNonzeroFloat64), - right: NumericNode("", math.MaxFloat64), + left: NewNumeric(math.SmallestNonzeroFloat64), + right: NewNumeric(math.MaxFloat64), expected: true, }, { name: "string 1", - left: StringNode("", "z"), - right: StringNode("", "a"), + left: NewString("z"), + right: NewString("a"), expected: false, }, { name: "string 2", - left: StringNode("", "a"), - right: StringNode("", "a"), + left: NewString("a"), + right: NewString("a"), expected: true, }, { name: "wrong type 1", - left: StringNode("", "z"), - right: NumericNode("", math.MaxFloat64), + left: NewString("z"), + right: NewNumeric(math.MaxFloat64), expected: false, }, { name: "wrong type 2", - left: NumericNode("", math.MaxFloat64), - right: StringNode("", "z"), + left: NewNumeric(math.MaxFloat64), + right: NewString("z"), expected: false, }, { name: "error 1", left: valueNode(nil, "e1", Numeric, string("e1")), - right: NumericNode("", 1), + right: NewNumeric(1), error: true, }, { name: "error 2", left: valueNode(nil, "e1", String, float64(1)), - right: StringNode("", "foo"), + right: NewString("foo"), error: true, }, { name: "nil/value", left: nil, - right: StringNode("", "foo"), + right: NewString("foo"), error: true, }, { name: "value/nil", - left: StringNode("", "foo"), + left: NewString("foo"), right: nil, error: true, }, @@ -1602,28 +1603,28 @@ func TestNode_Leq(t *testing.T) { } func TestNullNode(t *testing.T) { - node := NullNode("test") + node := NewNull() if node.MustNull() != nil { t.Errorf("Failed") } } func TestNumericNode(t *testing.T) { - node := NumericNode("test", 1.5) + node := NewNumeric(1.5) if node.MustNumeric() != 1.5 { t.Errorf("Failed") } } func TestStringNode(t *testing.T) { - node := StringNode("test", "check") + node := NewString("check") if node.MustString() != "check" { t.Errorf("Failed") } } func TestBoolNode(t *testing.T) { - node := BoolNode("test", true) + node := NewBool(true) if !node.MustBool() { t.Errorf("Failed") } @@ -1631,11 +1632,11 @@ func TestBoolNode(t *testing.T) { func TestArrayNode(t *testing.T) { array := []*Node{ - NullNode("0"), - NumericNode("1", 1), - StringNode("str", "foo"), + NewNull(), + NewNumeric(1), + NewString("foo"), } - node := ArrayNode("test", array) + node := NewArray(array) result := node.MustArray() if len(result) != len(array) { t.Errorf("Failed: length") @@ -1652,11 +1653,11 @@ func TestArrayNode(t *testing.T) { func TestObjectNode(t *testing.T) { objects := map[string]*Node{ - "zero": NullNode("0"), - "foo": NumericNode("1", 1), - "bar": StringNode("str", "foo"), + "zero": NewNull(), + "foo": NewNumeric(1), + "bar": NewString("foo"), } - node := ObjectNode("test", objects) + node := NewObject(objects) result := node.MustObject() if len(result) != len(objects) { t.Errorf("Failed: length") @@ -1679,28 +1680,28 @@ func TestNode_Inheritors(t *testing.T) { }{ { name: "object", - node: ObjectNode("", map[string]*Node{ - "zero": NullNode("0"), - "foo": NumericNode("1", 1), - "bar": StringNode("str", "foo"), + node: NewObject(map[string]*Node{ + "zero": NewNull(), + "foo": NewNumeric(1), + "bar": NewString("foo"), }), expected: []*Node{ - StringNode("str", "foo"), - NumericNode("1", 1), - NullNode("0"), + NewString("foo"), + NewNumeric(1), + withKey(NewNull(), "0"), }, }, { name: "array", - node: ArrayNode("", []*Node{ - NullNode("0"), - NumericNode("1", 1), - StringNode("str", "foo"), + node: NewArray([]*Node{ + NewNull(), + NewNumeric(1), + NewString("foo"), }), expected: []*Node{ - NullNode("0"), - NumericNode("1", 1), - StringNode("str", "foo"), + withKey(NewNull(), "0"), + NewNumeric(1), + NewString("foo"), }, }, } @@ -1787,28 +1788,28 @@ func TestNode_IsDirty(t *testing.T) { expected: true, }, { - name: "NumericNode", - node: NumericNode("", 1.1), + name: "NewNumeric", + node: NewNumeric(1.1), expected: true, }, { - name: "NullNode", - node: NullNode(""), + name: "NewNull", + node: NewNull(), expected: true, }, { - name: "ArrayNode", - node: ArrayNode("", nil), + name: "NewArray", + node: NewArray(nil), expected: true, }, { - name: "StringNode", - node: StringNode("", ""), + name: "NewString", + node: NewString(""), expected: true, }, { - name: "BoolNode", - node: BoolNode("", false), + name: "NewBool", + node: NewBool(false), expected: true, }, { @@ -1845,7 +1846,7 @@ func Test_newNode(t *testing.T) { { name: "blank key for Object", args: args{ - parent: ObjectNode("", make(map[string]*Node)), + parent: NewObject(make(map[string]*Node)), buf: newBuffer(make([]byte, 10)), _type: Bool, key: &nilKey, @@ -1856,7 +1857,7 @@ func Test_newNode(t *testing.T) { { name: "child for non Object/Array", args: args{ - parent: BoolNode("", true), + parent: NewBool(true), buf: newBuffer(make([]byte, 10)), _type: Bool, key: &relFillKey, @@ -1883,13 +1884,13 @@ func Test_newNode(t *testing.T) { } func TestNode_Value(t *testing.T) { - array := ArrayNode("", []*Node{ - NumericNode("0", 0), - StringNode("1", "bar"), + array := NewArray([]*Node{ + NewNumeric(0), + NewString("bar"), }) - object := ObjectNode("", map[string]*Node{ - "foo": NumericNode("foo", 0), - "bar": StringNode("bar", "bar"), + object := NewObject(map[string]*Node{ + "foo": NewNumeric(0), + "bar": NewString("bar"), }) tests := []struct { name string @@ -1899,13 +1900,13 @@ func TestNode_Value(t *testing.T) { }{ { name: "null", - node: NullNode(""), + node: NewNull(), wantValue: nil, wantErr: false, }, { name: "string", - node: StringNode("", "foo"), + node: NewString("foo"), wantValue: "foo", wantErr: false, }, @@ -1917,7 +1918,7 @@ func TestNode_Value(t *testing.T) { }, { name: "numeric", - node: NumericNode("", 1e3), + node: NewNumeric(1e3), wantValue: float64(1000), wantErr: false, }, @@ -1929,7 +1930,7 @@ func TestNode_Value(t *testing.T) { }, { name: "bool", - node: BoolNode("", true), + node: NewBool(true), wantValue: true, wantErr: false, }, @@ -1997,3 +1998,125 @@ func TestNode_Value(t *testing.T) { }) } } + +func withKey(node *Node, key string) *Node { + node.key = &key + return node +} + +func TestNewNode(t *testing.T) { + tests := []struct { + name string + value interface{} + wantNode *Node + wantErr bool + }{ + { + name: "null", + value: nil, + wantNode: NewNull(), + wantErr: false, + }, + { + name: "numeric(0)", + value: 0, + wantNode: NewNumeric(0), + wantErr: false, + }, + { + name: "numeric(1)", + value: uint8(78), + wantNode: NewNumeric(78), + wantErr: false, + }, + { + name: "string(0)", + value: "", + wantNode: NewString(""), + wantErr: false, + }, + { + name: "string(1)", + value: "foo-bar", + wantNode: NewString("foo-bar"), + wantErr: false, + }, + { + name: "bool(true)", + value: true, + wantNode: NewBool(true), + wantErr: false, + }, + { + name: "bool(false)", + value: false, + wantNode: NewBool(false), + wantErr: false, + }, + { + name: "array(blank)", + value: []*Node{}, + wantNode: NewArray([]*Node{}), + wantErr: false, + }, + { + name: "array(nil, true)", + value: []*Node{NewNull(), NewBool(true)}, + wantNode: NewArray([]*Node{NewNull(), NewBool(true)}), + wantErr: false, + }, + { + name: "object(blank)", + value: map[string]*Node{}, + wantNode: NewObject(map[string]*Node{}), + wantErr: false, + }, + { + name: "object(foo:bar)", + value: map[string]*Node{"foo": NewString("bar")}, + wantNode: NewObject(map[string]*Node{"foo": NewString("bar")}), + wantErr: false, + }, + { + name: "*Node", + value: NewString("foo/bar"), + wantNode: NewString("foo/bar"), + wantErr: false, + }, + { + name: "*Node", + value: NewString("foo/bar"), + wantNode: NewString("foo/bar"), + wantErr: false, + }, + { + name: "error#1", + value: struct{}{}, + wantNode: nil, + wantErr: true, + }, + { + name: "error#2", + value: atomic.Value{}, + wantNode: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotNode, err := NewNode(tt.value) + if (err != nil) != tt.wantErr { + t.Errorf("NewNode() error = %v, wantErr %v", err, tt.wantErr) + return + } + if tt.wantErr { + return + } + if result, err := gotNode.Eq(tt.wantNode); err != nil { + t.Errorf("Node.Eq() unexpected error = %v", err) + } else if !result { + t.Errorf("NewNode() gotNode = %s, want %s", gotNode, tt.wantNode) + } + }) + } +}