Added missing closing bracket error check

This commit is contained in:
Mike Farah 2021-09-05 11:39:11 +10:00
parent 25ba763b08
commit 1cfbbde796
3 changed files with 62 additions and 7 deletions

View File

@ -6,37 +6,66 @@ import (
"github.com/mikefarah/yq/v4/test" "github.com/mikefarah/yq/v4/test"
) )
func TestPathTreeNoArgsForTwoArgOp(t *testing.T) { func TestParserNoMatchingCloseCollect(t *testing.T) {
_, err := NewExpressionParser().ParseExpression("[1,2")
test.AssertResultComplex(t, "Bad expression, could not find matching `]`", err.Error())
}
func TestParserNoMatchingCloseObjectInCollect(t *testing.T) {
_, err := NewExpressionParser().ParseExpression(`[{"b": "c"]`)
test.AssertResultComplex(t, "Bad expression, could not find matching `}`", err.Error())
}
func TestParserNoMatchingCloseInCollect(t *testing.T) {
_, err := NewExpressionParser().ParseExpression(`[(.a]`)
test.AssertResultComplex(t, "Bad expression, could not find matching `)`", err.Error())
}
func TestParserNoMatchingCloseCollectObject(t *testing.T) {
_, err := NewExpressionParser().ParseExpression(`{"a": "b"`)
test.AssertResultComplex(t, "Bad expression, could not find matching `}`", err.Error())
}
func TestParserNoMatchingCloseCollectInCollectObject(t *testing.T) {
_, err := NewExpressionParser().ParseExpression(`{"b": [1}`)
test.AssertResultComplex(t, "Bad expression, could not find matching `]`", err.Error())
}
func TestParserNoMatchingCloseBracketInCollectObject(t *testing.T) {
_, err := NewExpressionParser().ParseExpression(`{"b": (1}`)
test.AssertResultComplex(t, "Bad expression, could not find matching `)`", err.Error())
}
func TestParserNoArgsForTwoArgOp(t *testing.T) {
_, err := NewExpressionParser().ParseExpression("=") _, err := NewExpressionParser().ParseExpression("=")
test.AssertResultComplex(t, "'=' expects 2 args but there is 0", err.Error()) test.AssertResultComplex(t, "'=' expects 2 args but there is 0", err.Error())
} }
func TestPathTreeOneLhsArgsForTwoArgOp(t *testing.T) { func TestParserOneLhsArgsForTwoArgOp(t *testing.T) {
_, err := NewExpressionParser().ParseExpression(".a =") _, err := NewExpressionParser().ParseExpression(".a =")
test.AssertResultComplex(t, "'=' expects 2 args but there is 1", err.Error()) test.AssertResultComplex(t, "'=' expects 2 args but there is 1", err.Error())
} }
func TestPathTreeOneRhsArgsForTwoArgOp(t *testing.T) { func TestParserOneRhsArgsForTwoArgOp(t *testing.T) {
_, err := NewExpressionParser().ParseExpression("= .a") _, err := NewExpressionParser().ParseExpression("= .a")
test.AssertResultComplex(t, "'=' expects 2 args but there is 1", err.Error()) test.AssertResultComplex(t, "'=' expects 2 args but there is 1", err.Error())
} }
func TestPathTreeTwoArgsForTwoArgOp(t *testing.T) { func TestParserTwoArgsForTwoArgOp(t *testing.T) {
_, err := NewExpressionParser().ParseExpression(".a = .b") _, err := NewExpressionParser().ParseExpression(".a = .b")
test.AssertResultComplex(t, nil, err) test.AssertResultComplex(t, nil, err)
} }
func TestPathTreeNoArgsForOneArgOp(t *testing.T) { func TestParserNoArgsForOneArgOp(t *testing.T) {
_, err := NewExpressionParser().ParseExpression("explode") _, err := NewExpressionParser().ParseExpression("explode")
test.AssertResultComplex(t, "'explode' expects 1 arg but received none", err.Error()) test.AssertResultComplex(t, "'explode' expects 1 arg but received none", err.Error())
} }
func TestPathTreeOneArgForOneArgOp(t *testing.T) { func TestParserOneArgForOneArgOp(t *testing.T) {
_, err := NewExpressionParser().ParseExpression("explode(.)") _, err := NewExpressionParser().ParseExpression("explode(.)")
test.AssertResultComplex(t, nil, err) test.AssertResultComplex(t, nil, err)
} }
func TestPathTreeExtraArgs(t *testing.T) { func TestParserExtraArgs(t *testing.T) {
_, err := NewExpressionParser().ParseExpression("sortKeys(.) explode(.)") _, err := NewExpressionParser().ParseExpression("sortKeys(.) explode(.)")
test.AssertResultComplex(t, "Bad expression, please check expression syntax", err.Error()) test.AssertResultComplex(t, "Bad expression, please check expression syntax", err.Error())
} }

View File

@ -2,6 +2,7 @@ package yqlib
import ( import (
"errors" "errors"
"fmt"
logging "gopkg.in/op/go-logging.v1" logging "gopkg.in/op/go-logging.v1"
) )
@ -24,6 +25,17 @@ func popOpToResult(opStack []*token, result []*Operation) ([]*token, []*Operatio
return opStack, append(result, newOp.Operation) return opStack, append(result, newOp.Operation)
} }
func validateNoOpenTokens(token *token) error {
if token.TokenType == openCollect {
return fmt.Errorf(("Bad expression, could not find matching `]`"))
} else if token.TokenType == openCollectObject {
return fmt.Errorf(("Bad expression, could not find matching `}`"))
} else if token.TokenType == openBracket {
return fmt.Errorf(("Bad expression, could not find matching `)`"))
}
return nil
}
func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Operation, error) { func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Operation, error) {
var result []*Operation var result []*Operation
// surround the whole thing with brackets // surround the whole thing with brackets
@ -45,6 +57,10 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope
} }
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != opener { for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != opener {
missingClosingTokenErr := validateNoOpenTokens(opStack[len(opStack)-1])
if missingClosingTokenErr != nil {
return nil, missingClosingTokenErr
}
opStack, result = popOpToResult(opStack, result) opStack, result = popOpToResult(opStack, result)
} }
if len(opStack) == 0 { if len(opStack) == 0 {
@ -76,6 +92,11 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope
case closeBracket: case closeBracket:
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != openBracket { for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != openBracket {
missingClosingTokenErr := validateNoOpenTokens(opStack[len(opStack)-1])
if missingClosingTokenErr != nil {
return nil, missingClosingTokenErr
}
opStack, result = popOpToResult(opStack, result) opStack, result = popOpToResult(opStack, result)
} }
if len(opStack) == 0 { if len(opStack) == 0 {
@ -98,6 +119,8 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope
} }
} }
log.Debugf("opstackLen: %v", len(opStack))
if log.IsEnabledFor(logging.DEBUG) { if log.IsEnabledFor(logging.DEBUG) {
log.Debugf("PostFix Result:") log.Debugf("PostFix Result:")
for _, currentToken := range result { for _, currentToken := range result {

View File

@ -162,6 +162,9 @@ func createValueOperation(value interface{}, stringValue string) *Operation {
// debugging purposes only // debugging purposes only
func (p *Operation) toString() string { func (p *Operation) toString() string {
if p == nil {
return "OP IS NIL"
}
if p.OperationType == traversePathOpType { if p.OperationType == traversePathOpType {
return fmt.Sprintf("%v", p.Value) return fmt.Sprintf("%v", p.Value)
} else if p.OperationType == selfReferenceOpType { } else if p.OperationType == selfReferenceOpType {