From 5e544a5b7ec431cf75379dafa7f30fd53aa7a145 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Sat, 17 Oct 2020 22:39:01 +1100 Subject: [PATCH] value parse test --- pkg/yqlib/treeops/data_tree_navigator_test.go | 75 ------------------- pkg/yqlib/treeops/operator_assign.go | 27 +++++++ pkg/yqlib/treeops/operator_assign_test.go | 62 +++++++++++++++ pkg/yqlib/treeops/operator_value_test.go | 75 +++++++++++++++++++ pkg/yqlib/treeops/operators.go | 24 ------ pkg/yqlib/treeops/path_tokeniser.go | 17 ++++- pkg/yqlib/value_parser.go | 46 ------------ pkg/yqlib/value_parser_test.go | 65 ---------------- 8 files changed, 179 insertions(+), 212 deletions(-) create mode 100644 pkg/yqlib/treeops/operator_assign.go create mode 100644 pkg/yqlib/treeops/operator_assign_test.go create mode 100644 pkg/yqlib/treeops/operator_value_test.go delete mode 100644 pkg/yqlib/value_parser.go delete mode 100644 pkg/yqlib/value_parser_test.go diff --git a/pkg/yqlib/treeops/data_tree_navigator_test.go b/pkg/yqlib/treeops/data_tree_navigator_test.go index 91117aa..e5349a5 100644 --- a/pkg/yqlib/treeops/data_tree_navigator_test.go +++ b/pkg/yqlib/treeops/data_tree_navigator_test.go @@ -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: diff --git a/pkg/yqlib/treeops/operator_assign.go b/pkg/yqlib/treeops/operator_assign.go new file mode 100644 index 0000000..0dc6090 --- /dev/null +++ b/pkg/yqlib/treeops/operator_assign.go @@ -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 +} diff --git a/pkg/yqlib/treeops/operator_assign_test.go b/pkg/yqlib/treeops/operator_assign_test.go new file mode 100644 index 0000000..979363a --- /dev/null +++ b/pkg/yqlib/treeops/operator_assign_test.go @@ -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) + } +} diff --git a/pkg/yqlib/treeops/operator_value_test.go b/pkg/yqlib/treeops/operator_value_test.go new file mode 100644 index 0000000..b722a4b --- /dev/null +++ b/pkg/yqlib/treeops/operator_value_test.go @@ -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) + } +} diff --git a/pkg/yqlib/treeops/operators.go b/pkg/yqlib/treeops/operators.go index 5b5068d..f09f1c5 100644 --- a/pkg/yqlib/treeops/operators.go +++ b/pkg/yqlib/treeops/operators.go @@ -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 { diff --git a/pkg/yqlib/treeops/path_tokeniser.go b/pkg/yqlib/treeops/path_tokeniser.go index f00651f..5101c19 100644 --- a/pkg/yqlib/treeops/path_tokeniser.go +++ b/pkg/yqlib/treeops/path_tokeniser.go @@ -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)) diff --git a/pkg/yqlib/value_parser.go b/pkg/yqlib/value_parser.go deleted file mode 100644 index 6dee740..0000000 --- a/pkg/yqlib/value_parser.go +++ /dev/null @@ -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} -} diff --git a/pkg/yqlib/value_parser_test.go b/pkg/yqlib/value_parser_test.go deleted file mode 100644 index a21a6ec..0000000 --- a/pkg/yqlib/value_parser_test.go +++ /dev/null @@ -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) -}