mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-12 13:48:06 +00:00
value parse test
This commit is contained in:
parent
60511f5f92
commit
5e544a5b7e
@ -628,81 +628,6 @@ func TestDataTreeNavigatorArraySimple(t *testing.T) {
|
||||
test.AssertResult(t, expected, resultsToString(results))
|
||||
}
|
||||
|
||||
func TestDataTreeNavigatorSimpleAssignCmd(t *testing.T) {
|
||||
|
||||
nodes := readDoc(t, `a:
|
||||
b: apple`)
|
||||
|
||||
path, errPath := treeCreator.ParsePath(`.a.b |= "frog"`)
|
||||
if errPath != nil {
|
||||
t.Error(errPath)
|
||||
}
|
||||
results, errNav := treeNavigator.GetMatchingNodes(nodes, path)
|
||||
|
||||
if errNav != nil {
|
||||
t.Error(errNav)
|
||||
}
|
||||
|
||||
expected := `
|
||||
-- Node --
|
||||
Document 0, path: [a b]
|
||||
Tag: !!str, Kind: ScalarNode, Anchor:
|
||||
frog
|
||||
`
|
||||
|
||||
test.AssertResult(t, expected, resultsToString(results))
|
||||
}
|
||||
|
||||
func TestDataTreeNavigatorSimpleAssignNumberCmd(t *testing.T) {
|
||||
|
||||
nodes := readDoc(t, `a:
|
||||
b: apple`)
|
||||
|
||||
path, errPath := treeCreator.ParsePath(`.a.b |= 5`)
|
||||
if errPath != nil {
|
||||
t.Error(errPath)
|
||||
}
|
||||
results, errNav := treeNavigator.GetMatchingNodes(nodes, path)
|
||||
|
||||
if errNav != nil {
|
||||
t.Error(errNav)
|
||||
}
|
||||
|
||||
expected := `
|
||||
-- Node --
|
||||
Document 0, path: [a b]
|
||||
Tag: !!int, Kind: ScalarNode, Anchor:
|
||||
5
|
||||
`
|
||||
|
||||
test.AssertResult(t, expected, resultsToString(results))
|
||||
}
|
||||
|
||||
func TestDataTreeNavigatorSimpleAssignFloatCmd(t *testing.T) {
|
||||
|
||||
nodes := readDoc(t, `a:
|
||||
b: apple`)
|
||||
|
||||
path, errPath := treeCreator.ParsePath(`.a.b |= 3.142`)
|
||||
if errPath != nil {
|
||||
t.Error(errPath)
|
||||
}
|
||||
results, errNav := treeNavigator.GetMatchingNodes(nodes, path)
|
||||
|
||||
if errNav != nil {
|
||||
t.Error(errNav)
|
||||
}
|
||||
|
||||
expected := `
|
||||
-- Node --
|
||||
Document 0, path: [a b]
|
||||
Tag: !!float, Kind: ScalarNode, Anchor:
|
||||
3.142
|
||||
`
|
||||
|
||||
test.AssertResult(t, expected, resultsToString(results))
|
||||
}
|
||||
|
||||
func TestDataTreeNavigatorSimpleAssignBooleanCmd(t *testing.T) {
|
||||
|
||||
nodes := readDoc(t, `a:
|
||||
|
27
pkg/yqlib/treeops/operator_assign.go
Normal file
27
pkg/yqlib/treeops/operator_assign.go
Normal file
@ -0,0 +1,27 @@
|
||||
package treeops
|
||||
|
||||
import "github.com/elliotchance/orderedmap"
|
||||
|
||||
func AssignOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
|
||||
rhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// grab the first value
|
||||
first := rhs.Front()
|
||||
|
||||
if first != nil {
|
||||
candidate.UpdateFrom(first.Value.(*CandidateNode))
|
||||
}
|
||||
}
|
||||
return matchingNodes, nil
|
||||
}
|
62
pkg/yqlib/treeops/operator_assign_test.go
Normal file
62
pkg/yqlib/treeops/operator_assign_test.go
Normal file
@ -0,0 +1,62 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var assignOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `.a.b |= "frog"`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {b: frog}}\n",
|
||||
},
|
||||
}, {
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `.a.b | (. |= "frog")`,
|
||||
expected: []string{
|
||||
"D0, P[a b], (!!str)::frog\n",
|
||||
},
|
||||
}, {
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `.a.b |= 5`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {b: 5}}\n",
|
||||
},
|
||||
}, {
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `.a.b |= 3.142`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {b: 3.142}}\n",
|
||||
},
|
||||
// document: `{}`,
|
||||
// expression: `["cat", "dog"]`,
|
||||
// expected: []string{
|
||||
// "D0, P[], (!!seq)::- cat\n- dog\n",
|
||||
// },
|
||||
// }, {
|
||||
// document: `{}`,
|
||||
// expression: `1 | collect`,
|
||||
// expected: []string{
|
||||
// "D0, P[], (!!seq)::- 1\n",
|
||||
// },
|
||||
// }, {
|
||||
// document: `[1,2,3]`,
|
||||
// expression: `[.[]]`,
|
||||
// expected: []string{
|
||||
// "D0, P[], (!!seq)::- 1\n- 2\n- 3\n",
|
||||
// },
|
||||
// }, {
|
||||
// document: `a: {b: [1,2,3]}`,
|
||||
// expression: `[.a.b[]]`,
|
||||
// expected: []string{
|
||||
// "D0, P[a b], (!!seq)::- 1\n- 2\n- 3\n",
|
||||
// },
|
||||
},
|
||||
}
|
||||
|
||||
func TestAssignOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range assignOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
}
|
75
pkg/yqlib/treeops/operator_value_test.go
Normal file
75
pkg/yqlib/treeops/operator_value_test.go
Normal file
@ -0,0 +1,75 @@
|
||||
package treeops
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var valueOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
document: ``,
|
||||
expression: `1`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!int)::1\n",
|
||||
},
|
||||
}, {
|
||||
document: ``,
|
||||
expression: `-1`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!int)::-1\n",
|
||||
},
|
||||
}, {
|
||||
document: ``,
|
||||
expression: `1.2`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!float)::1.2\n",
|
||||
},
|
||||
}, {
|
||||
document: ``,
|
||||
expression: `-5.2e11`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!float)::-5.2e11\n",
|
||||
},
|
||||
}, {
|
||||
document: ``,
|
||||
expression: `5e-10`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!float)::5e-10\n",
|
||||
},
|
||||
}, {
|
||||
document: ``,
|
||||
expression: `"cat"`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!str)::cat\n",
|
||||
},
|
||||
}, {
|
||||
document: ``,
|
||||
expression: `"1.3"`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!str)::\"1.3\"\n",
|
||||
},
|
||||
}, {
|
||||
document: ``,
|
||||
expression: `"true"`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!str)::\"true\"\n",
|
||||
},
|
||||
}, {
|
||||
document: ``,
|
||||
expression: `true`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!bool)::true\n",
|
||||
},
|
||||
}, {
|
||||
document: ``,
|
||||
expression: `false`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!bool)::false\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestValueOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range valueOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
}
|
@ -32,30 +32,6 @@ func nodeToMap(candidate *CandidateNode) *orderedmap.OrderedMap {
|
||||
return elMap
|
||||
}
|
||||
|
||||
func AssignOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
|
||||
rhs, err := d.getMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// grab the first value
|
||||
first := rhs.Front()
|
||||
|
||||
if first != nil {
|
||||
candidate.UpdateFrom(first.Value.(*CandidateNode))
|
||||
}
|
||||
}
|
||||
return lhs, nil
|
||||
}
|
||||
|
||||
func IntersectionOperator(d *dataTreeNavigator, matchingNodes *orderedmap.OrderedMap, pathNode *PathTreeNode) (*orderedmap.OrderedMap, error) {
|
||||
lhs, err := d.getMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
|
@ -76,6 +76,17 @@ func numberValue() lex.Action {
|
||||
}
|
||||
}
|
||||
|
||||
func floatValue() lex.Action {
|
||||
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||
var numberString = string(m.Bytes)
|
||||
var number, errParsingInt = strconv.ParseFloat(numberString, 64) // nolint
|
||||
if errParsingInt != nil {
|
||||
return nil, errParsingInt
|
||||
}
|
||||
return &Token{PathElementType: Value, OperationType: None, Value: number, StringValue: numberString}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func booleanValue(val bool) lex.Action {
|
||||
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||
return &Token{PathElementType: Value, OperationType: None, Value: val, StringValue: string(m.Bytes)}, nil
|
||||
@ -111,7 +122,7 @@ func initLexer() (*lex.Lexer, error) {
|
||||
lexer.Add([]byte(`length`), opToken(Length))
|
||||
lexer.Add([]byte(`select`), opToken(Select))
|
||||
lexer.Add([]byte(`or`), opToken(Or))
|
||||
lexer.Add([]byte(`and`), opToken(And))
|
||||
// lexer.Add([]byte(`and`), opToken())
|
||||
lexer.Add([]byte(`collect`), opToken(Collect))
|
||||
|
||||
lexer.Add([]byte(`\s*==\s*`), opToken(Equals))
|
||||
@ -131,7 +142,9 @@ func initLexer() (*lex.Lexer, error) {
|
||||
|
||||
lexer.Add([]byte(`\|`), opToken(Pipe))
|
||||
|
||||
lexer.Add([]byte(`-?[0-9]+`), numberValue())
|
||||
lexer.Add([]byte(`-?\d+(\.\d+)`), floatValue())
|
||||
lexer.Add([]byte(`-?[1-9](\.\d+)?[Ee][-+]?\d+`), floatValue())
|
||||
lexer.Add([]byte(`-?\d+`), numberValue())
|
||||
|
||||
lexer.Add([]byte(`[Tt][Rr][Uu][Ee]`), booleanValue(true))
|
||||
lexer.Add([]byte(`[Ff][Aa][Ll][Ss][Ee]`), booleanValue(false))
|
||||
|
@ -1,46 +0,0 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type ValueParser interface {
|
||||
Parse(argument string, customTag string, customStyle string, anchorName string, createAlias bool) *yaml.Node
|
||||
}
|
||||
|
||||
type valueParser struct {
|
||||
}
|
||||
|
||||
func NewValueParser() ValueParser {
|
||||
return &valueParser{}
|
||||
}
|
||||
|
||||
func (v *valueParser) Parse(argument string, customTag string, customStyle string, anchorName string, createAlias bool) *yaml.Node {
|
||||
var style yaml.Style
|
||||
if customStyle == "tagged" {
|
||||
style = yaml.TaggedStyle
|
||||
} else if customStyle == "double" {
|
||||
style = yaml.DoubleQuotedStyle
|
||||
} else if customStyle == "single" {
|
||||
style = yaml.SingleQuotedStyle
|
||||
} else if customStyle == "literal" {
|
||||
style = yaml.LiteralStyle
|
||||
} else if customStyle == "folded" {
|
||||
style = yaml.FoldedStyle
|
||||
} else if customStyle == "flow" {
|
||||
style = yaml.FlowStyle
|
||||
} else if customStyle != "" {
|
||||
log.Error("Unknown style %v, ignoring", customStyle)
|
||||
}
|
||||
if argument == "[]" {
|
||||
return &yaml.Node{Tag: "!!seq", Kind: yaml.SequenceNode, Style: style}
|
||||
}
|
||||
|
||||
kind := yaml.ScalarNode
|
||||
|
||||
if createAlias {
|
||||
kind = yaml.AliasNode
|
||||
}
|
||||
|
||||
return &yaml.Node{Value: argument, Tag: customTag, Kind: kind, Style: style, Anchor: anchorName}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v3/test"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var parseStyleTests = []struct {
|
||||
customStyle string
|
||||
expectedStyle yaml.Style
|
||||
}{
|
||||
{"", 0},
|
||||
{"tagged", yaml.TaggedStyle},
|
||||
{"double", yaml.DoubleQuotedStyle},
|
||||
{"single", yaml.SingleQuotedStyle},
|
||||
{"folded", yaml.FoldedStyle},
|
||||
{"flow", yaml.FlowStyle},
|
||||
{"literal", yaml.LiteralStyle},
|
||||
}
|
||||
|
||||
func TestValueParserStyleTag(t *testing.T) {
|
||||
for _, tt := range parseStyleTests {
|
||||
actual := NewValueParser().Parse("cat", "", tt.customStyle, "", false)
|
||||
test.AssertResultWithContext(t, tt.expectedStyle, actual.Style, tt.customStyle)
|
||||
}
|
||||
}
|
||||
|
||||
var parseValueTests = []struct {
|
||||
argument string
|
||||
customTag string
|
||||
expectedTag string
|
||||
testDescription string
|
||||
}{
|
||||
{"true", "!!str", "!!str", "boolean forced as string"},
|
||||
{"3", "!!int", "!!int", "int"},
|
||||
{"cat", "", "", "default"},
|
||||
}
|
||||
|
||||
func TestValueParserParse(t *testing.T) {
|
||||
for _, tt := range parseValueTests {
|
||||
actual := NewValueParser().Parse(tt.argument, tt.customTag, "", "", false)
|
||||
test.AssertResultWithContext(t, tt.argument, actual.Value, tt.testDescription)
|
||||
test.AssertResultWithContext(t, tt.expectedTag, actual.Tag, tt.testDescription)
|
||||
test.AssertResult(t, yaml.ScalarNode, actual.Kind)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueParserParseEmptyArray(t *testing.T) {
|
||||
actual := NewValueParser().Parse("[]", "", "", "", false)
|
||||
test.AssertResult(t, "!!seq", actual.Tag)
|
||||
test.AssertResult(t, yaml.SequenceNode, actual.Kind)
|
||||
}
|
||||
|
||||
func TestValueParserParseAlias(t *testing.T) {
|
||||
actual := NewValueParser().Parse("bob", "", "", "", true)
|
||||
test.AssertResult(t, "bob", actual.Value)
|
||||
test.AssertResult(t, yaml.AliasNode, actual.Kind)
|
||||
}
|
||||
|
||||
func TestValueParserAnchorname(t *testing.T) {
|
||||
actual := NewValueParser().Parse("caterpillar", "", "", "foo", false)
|
||||
test.AssertResult(t, "foo", actual.Anchor)
|
||||
}
|
Loading…
Reference in New Issue
Block a user