Fixing readonly ops not to modify context when paths dont exist

This commit is contained in:
Mike Farah 2021-05-16 14:17:13 +10:00
parent 3f51a44596
commit 0b71a40797
10 changed files with 88 additions and 26 deletions

View File

@ -60,3 +60,9 @@ func (n *Context) Clone() Context {
}
return clone
}
func (n *Context) ReadOnlyClone() Context {
clone := n.Clone()
clone.DontAutoCreate = true
return clone
}

View File

@ -12,7 +12,7 @@ func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode *
aliasName := ""
if !expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs)
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs)
if err != nil {
return Context{}, err
}
@ -32,7 +32,7 @@ func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode *
log.Debugf("Setting aliasName : %v", candidate.GetKey())
if expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.Rhs)
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs)
if err != nil {
return Context{}, err
}
@ -41,9 +41,11 @@ func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode *
}
}
if aliasName != "" {
candidate.Node.Kind = yaml.AliasNode
candidate.Node.Value = aliasName
}
}
return context, nil
}
@ -66,7 +68,7 @@ func assignAnchorOperator(d *dataTreeNavigator, context Context, expressionNode
anchorName := ""
if !expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs)
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs)
if err != nil {
return Context{}, err
}
@ -87,7 +89,7 @@ func assignAnchorOperator(d *dataTreeNavigator, context Context, expressionNode
log.Debugf("Setting anchorName of : %v", candidate.GetKey())
if expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.Rhs)
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs)
if err != nil {
return Context{}, err
}

View File

@ -58,6 +58,22 @@ var anchorOperatorScenarios = []expressionScenario{
"D0, P[], (doc)::a: &cat {b: cat}\n",
},
},
{
skipDoc: true,
document: `a: {c: cat}`,
expression: `.a anchor |= .b`,
expected: []string{
"D0, P[], (doc)::a: {c: cat}\n",
},
},
{
skipDoc: true,
document: `a: {c: cat}`,
expression: `.a anchor = .b`,
expected: []string{
"D0, P[], (doc)::a: {c: cat}\n",
},
},
{
description: "Get alias",
document: `{b: &billyBob meow, a: *billyBob}`,
@ -74,6 +90,22 @@ var anchorOperatorScenarios = []expressionScenario{
"D0, P[], (doc)::{b: &meow purr, a: *meow}\n",
},
},
{
skipDoc: true,
document: `{b: &meow purr, a: cat}`,
expression: `.a alias = .c`,
expected: []string{
"D0, P[], (doc)::{b: &meow purr, a: cat}\n",
},
},
{
skipDoc: true,
document: `{b: &meow purr, a: cat}`,
expression: `.a alias |= .c`,
expected: []string{
"D0, P[], (doc)::{b: &meow purr, a: cat}\n",
},
},
{
description: "Set alias relatively using assign-update",
document: `{b: &meow purr, a: {f: meow}}`,
@ -159,7 +191,7 @@ foobar:
},
}
func TestAnchorAliaseOperatorScenarios(t *testing.T) {
func TestAnchorAliasOperatorScenarios(t *testing.T) {
for _, tt := range anchorOperatorScenarios {
testScenario(t, &tt)
}

View File

@ -134,7 +134,7 @@ func anyOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi
func orOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("-- orOp")
return crossFunction(d, context, expressionNode, performBoolOp(
return crossFunction(d, context.ReadOnlyClone(), expressionNode, performBoolOp(
func(b1 bool, b2 bool) bool {
log.Debugf("-- peformingOrOp with %v and %v", b1, b2)
return b1 || b2
@ -143,7 +143,7 @@ func orOperator(d *dataTreeNavigator, context Context, expressionNode *Expressio
func andOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("-- AndOp")
return crossFunction(d, context, expressionNode, performBoolOp(
return crossFunction(d, context.ReadOnlyClone(), expressionNode, performBoolOp(
func(b1 bool, b2 bool) bool {
return b1 && b2
}), true)

View File

@ -141,6 +141,22 @@ var booleanOperatorScenarios = []expressionScenario{
"D0, P[b], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: `{}`,
expression: `(.a.b or .c) as $x`,
expected: []string{
"D0, P[], (doc)::{}\n",
},
},
{
skipDoc: true,
document: `{}`,
expression: `(.a.b and .c) as $x`,
expected: []string{
"D0, P[], (doc)::{}\n",
},
},
{
description: "Not true is false",
expression: `true | not`,

View File

@ -27,7 +27,7 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod
comment := ""
if !expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs)
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs)
if err != nil {
return Context{}, err
}
@ -41,7 +41,7 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod
candidate := el.Value.(*CandidateNode)
if expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.Rhs)
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs)
if err != nil {
return Context{}, err
}

View File

@ -62,6 +62,22 @@ var commentOperatorScenarios = []expressionScenario{
"D0, P[], (doc)::a: cat\n\n# cat\n",
},
},
{
skipDoc: true,
document: `a: cat`,
expression: `. footComment=.b.d`,
expected: []string{
"D0, P[], (doc)::a: cat\n",
},
},
{
skipDoc: true,
document: `a: cat`,
expression: `. footComment|=.b.d`,
expected: []string{
"D0, P[], (doc)::a: cat\n",
},
},
{
description: "Remove comment",
document: "a: cat # comment\nb: dog # leave this",

View File

@ -7,9 +7,7 @@ import (
)
func deleteChildOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
contextToUse := context.Clone()
contextToUse.DontAutoCreate = true
nodesToDelete, err := d.GetMatchingNodes(contextToUse, expressionNode.Rhs)
nodesToDelete, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs)
if err != nil {
return Context{}, err

View File

@ -12,9 +12,7 @@ func hasOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi
log.Debugf("-- hasOperation")
var results = list.New()
readonlyContext := context.Clone()
readonlyContext.DontAutoCreate = true
rhs, err := d.GetMatchingNodes(readonlyContext, expressionNode.Rhs)
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs)
if err != nil {
return Context{}, err

View File

@ -13,9 +13,7 @@ func getSubstituteParameters(d *dataTreeNavigator, block *ExpressionNode, contex
regEx := ""
replacementText := ""
readonlyContext := context.Clone()
readonlyContext.DontAutoCreate = true
regExNodes, err := d.GetMatchingNodes(readonlyContext, block.Lhs)
regExNodes, err := d.GetMatchingNodes(context.ReadOnlyClone(), block.Lhs)
if err != nil {
return "", "", err
}
@ -80,9 +78,7 @@ func joinStringOperator(d *dataTreeNavigator, context Context, expressionNode *E
log.Debugf("-- joinStringOperator")
joinStr := ""
readonlyContext := context.Clone()
readonlyContext.DontAutoCreate = true
rhs, err := d.GetMatchingNodes(readonlyContext, expressionNode.Rhs)
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs)
if err != nil {
return Context{}, err
}
@ -123,9 +119,7 @@ func splitStringOperator(d *dataTreeNavigator, context Context, expressionNode *
log.Debugf("-- splitStringOperator")
splitStr := ""
readonlyContext := context.Clone()
readonlyContext.DontAutoCreate = true
rhs, err := d.GetMatchingNodes(readonlyContext, expressionNode.Rhs)
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs)
if err != nil {
return Context{}, err
}