value parse test

This commit is contained in:
Mike Farah 2020-10-17 22:39:01 +11:00
parent 60511f5f92
commit 5e544a5b7e
8 changed files with 179 additions and 212 deletions

View File

@ -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:

View 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
}

View 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)
}
}

View 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)
}
}

View File

@ -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 {

View File

@ -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))

View File

@ -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}
}

View File

@ -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)
}