def test_nested_selectors_in_update_expression_should_fail_at_nesting():
    update_expression = "SET a [  [2] ]. b = 5"
    try:
        UpdateExpressionParser.make(update_expression)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "["
        assert te.near == "[  [2"
def test_expression_tokenizer_set_closing_followed_by_numeric_literal():
    set_action = "SET ) 3"
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == ")"
        assert te.near == "SET ) 3"
def test_expression_tokenizer_only_numeric_literal():
    set_action = "2"
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "2"
        assert te.near == "2"
def test_update_expression_number_in_selector_cannot_be_splite():
    update_expression = "SET a [2 1]. b = 5"
    try:
        UpdateExpressionParser.make(update_expression)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "1"
        assert te.near == "2 1]"
def test_expression_tokenizer_set_closing_round_bracket():
    set_action = "SET )"
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == ")"
        assert te.near == "SET )"
def test_expression_if_not_exists_is_not_valid_in_remove_statement():
    set_action = "REMOVE if_not_exists(a,b)"
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "("
        assert te.near == "if_not_exists(a"
def test_expression_tokenizer_2_different_operators_back_to_back():
    set_action = "SET MyStr = NoExist + - :_val "
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "-"
        assert te.near == "+ - :_val"
def test_expression_tokenizer_numeric_literal_unclosed_square_bracket():
    set_action = "SET MyStr[ 3"
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "<EOF>"
        assert te.near == "3"
def test_update_expression_cannot_have_successive_attributes():
    update_expression = "SET #a a = 5"
    try:
        UpdateExpressionParser.make(update_expression)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "a"
        assert te.near == "#a a ="
def test_expression_tokenizer_multi_number_numeric_literal_in_expression():
    set_action = "SET attrName = 34"
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "34"
        assert te.near == "= 34"
def test_update_expression_add_does_not_allow_attribute_foobar_after_value():
    add_expr = "ADD attr :val foobar"
    try:
        UpdateExpressionParser.make(add_expr)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "foobar"
        assert te.near == ":val foobar"
def test_update_expression_starts_with_keyword_reset_followed_by_identifier():
    update_expression = "RESET NonExistent"
    try:
        UpdateExpressionParser.make(update_expression)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "RESET"
        assert te.near == "RESET NonExistent"
def test_update_expression_with_only_keyword_reset():
    update_expression = "RESET"
    try:
        UpdateExpressionParser.make(update_expression)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "RESET"
        assert te.near == "RESET"
def test_expression_tokenizer_unbalanced_square_brackets_only_closing():
    set_action = "SET MyStr = ]:_val"
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "]"
        assert te.near == "= ]:_val"
def test_expression_tokenizer_unbalanced_round_brackets_multiple_opening():
    set_action = "SET MyStr = (:_val + (:val2"
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "<EOF>"
        assert te.near == ":val2"
def test_update_expression_remove_does_not_allow_operations():
    remove_action = "REMOVE NoExist + "
    try:
        UpdateExpressionParser.make(remove_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "+"
        assert te.near == "NoExist + "
def test_expression_tokenizer_wrong_closing_bracket_with_space():
    set_action = "SET MyStr[3 )"
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == ")"
        assert te.near == "3 )"
def test_update_expression_path_with_both_attribute_and_attribute_name_should_only_fail_at_numeric_value(
):
    update_expression = "SET #a.a = 5"
    try:
        UpdateExpressionParser.make(update_expression)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "5"
        assert te.near == "= 5"
def test_update_expression_parsing_is_not_keyword_aware():
    """path and VALUE are keywords. Yet a token error will be thrown for the numeric literal 1."""
    delete_expr = "SET path = VALUE 1"
    try:
        UpdateExpressionParser.make(delete_expr)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "1"
        assert te.near == "VALUE 1"
def test_update_nested_expression_should_only_fail_parsing_at_numeric_literal_value(
):
    update_expression = "SET a . b = 5"
    try:
        UpdateExpressionParser.make(update_expression)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "5"
        assert te.near == "= 5"
def test_expression_tokenizer_unbalanced_round_brackets_only_closing_followed_by_other_parts(
):
    set_action = "SET MyStr = ):_val + :val2"
    try:
        UpdateExpressionParser.make(set_action)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == ")"
        assert te.near == "= ):_val"
def test_update_expression_delete_does_not_allow_attribute_after_path():
    """value here is not really a value since a value starts with a colon (:)"""
    delete_expr = "DELETE attr val"
    try:
        UpdateExpressionParser.make(delete_expr)
        assert False, "Exception not raised correctly"
    except InvalidTokenException as te:
        assert te.token == "val"
        assert te.near == "attr val"
示例#23
0
def test_cannot_index_into_a_string(table):
    """
    Must error out:
    The document path provided in the update expression is invalid for update'
    """
    try:
        update_expression = "set itemstr[1]=:Item"
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            range_key=None,
            attrs={
                "id": {
                    "S": "foo2"
                },
                "itemstr": {
                    "S": "somestring"
                }
            },
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values={
                ":Item": {
                    "S": "string_update"
                }
            },
            item=item,
            table=table,
        ).validate()
        assert False, "Must raise exception"
    except InvalidUpdateExpressionInvalidDocumentPath:
        assert True
示例#24
0
def test_validation_set_path_does_not_need_to_be_resolvable_but_must_be_creatable_when_setting_a_new_attribute(
    table, ):
    try:
        update_expression = "set d.e=a"
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            range_key=None,
            attrs={
                "id": {
                    "S": "foo2"
                },
                "a": {
                    "N": "3"
                }
            },
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values=None,
            item=item,
            table=table,
        ).validate()
        assert False, "Must raise exception"
    except InvalidUpdateExpressionInvalidDocumentPath:
        assert True
示例#25
0
def test_validation_of_update_expression_with_keyword(table):
    try:
        update_expression = "SET myNum = path + :val"
        update_expression_values = {":val": {"N": "3"}}
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            range_key=None,
            attrs={
                "id": {
                    "S": "1"
                },
                "path": {
                    "N": "3"
                }
            },
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values=update_expression_values,
            item=item,
            table=table,
        ).validate()
        assert False, "No exception raised"
    except AttributeIsReservedKeyword as e:
        assert e.keyword == "path"
示例#26
0
def test_validation_set_path_does_not_need_to_be_resolvable_when_setting_a_new_attribute(
    table, ):
    """If this step just passes we are happy enough"""
    update_expression = "set d=a"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        range_key=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "a": {
                "N": "3"
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=None,
        item=item,
        table=table,
    ).validate()
    dynamo_value = get_set_action_value(validated_ast)
    assert dynamo_value == DynamoType({"N": "3"})
示例#27
0
def test_valid_update_expression(table):
    update_expression = "set forum_desc=:Desc, forum_type=:NewType"
    update_expression_values = {
        ":Desc": {
            "S": "AmazingForum"
        },
        ":NewType": {
            "S": "BASIC"
        },
    }
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "forum_name"}),
        range_key=DynamoType({"S": "forum_type"}),
        attrs={"forum_name": {
            "S": "hello"
        }},
    )
    UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=update_expression_values,
        item=item,
        table=table,
    ).validate()
示例#28
0
def test_validation_of_subraction_operation(table):
    update_expression = "SET ri = :val - :val2"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        range_key=None,
        attrs={
            "id": {
                "S": "1"
            },
            "a": {
                "N": "3"
            },
            "b": {
                "N": "4"
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values={
            ":val": {
                "N": "1"
            },
            ":val2": {
                "N": "3"
            }
        },
        item=item,
        table=table,
    ).validate()
    dynamo_value = get_set_action_value(validated_ast)
    assert dynamo_value == DynamoType({"N": "-2"})
示例#29
0
def test_validation_of_if_not_exists_not_existing_invalid_replace_value(table):
    try:
        update_expression = "SET a = if_not_exists(b, a.c)"
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            range_key=None,
            attrs={
                "id": {
                    "S": "1"
                },
                "a": {
                    "S": "A"
                }
            },
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values=None,
            item=item,
            table=table,
        ).validate()
        assert False, "No exception raised"
    except AttributeDoesNotExist:
        assert True
示例#30
0
def test_validation_of_if_not_exists_with_existing_attribute_should_return_value(
        table):
    update_expression = "SET a = if_not_exists(b, :val)"
    update_expression_values = {":val": {"N": "4"}}
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        range_key=None,
        attrs={
            "id": {
                "S": "1"
            },
            "b": {
                "N": "3"
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=update_expression_values,
        item=item,
        table=table,
    ).validate()
    dynamo_value = get_set_action_value(validated_ast)
    assert dynamo_value == DynamoType({"N": "3"})