Compare commits

...

6 Commits

Author SHA1 Message Date
gvolfing
78ec129cde Add e2e test 2022-07-01 11:06:01 +02:00
Gabor Volfinger
be29933414 Revert "add e2e test prototype"
This reverts commit 5f2af9050a.
2022-06-29 19:55:40 +02:00
Gabor Volfinger
5f2af9050a add e2e test prototype 2022-06-29 16:31:51 +02:00
Gabor Volfinger
b4f9d4976b remove unnecessary comment 2022-06-29 12:47:16 +02:00
Gabor Volfinger
2302e64e7e refactor unit test 2022-06-29 12:39:12 +02:00
Gabor Volfinger
449fd02b8a prototype implementation 2022-06-29 12:15:11 +02:00
8 changed files with 106 additions and 5 deletions

View File

@@ -398,7 +398,7 @@ cpp<#
,@(loop for op in
'(or-operator xor-operator and-operator addition-operator
subtraction-operator multiplication-operator division-operator
mod-operator not-equal-operator equal-operator less-operator
mod-operator not-equal-operator less-operator
greater-operator less-equal-operator greater-equal-operator
in-list-operator subscript-operator)
collecting
@@ -458,6 +458,33 @@ cpp<#
(:clone))))))
(define-unary-operators))
(lcp:define-class equal-operator (binary-operator)
((isNullCheckRequired "bool" :initval "false" :scope :public))
(:public
#>cpp
DEFVISITABLE(ExpressionVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<void>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
expression1_->Accept(visitor) && expression2_->Accept(visitor);
}
return visitor.PostVisit(*this);
}
cpp<#)
(:protected
#>cpp
using BinaryOperator::BinaryOperator;
EqualOperator(Expression *expression1, Expression *expression2, bool is_nullcheck_required = false)
: BinaryOperator(expression1, expression2), isnullcheckrequired_(is_nullcheck_required) {}
cpp<#)
(:private
#>cpp
friend class AstStorage;
cpp<#)
(:serialize (:slk))
(:clone))
(lcp:define-class aggregation (binary-operator)
((op "Op" :scope :public)
(symbol-pos :int32_t :initval -1 :scope :public

View File

@@ -2267,9 +2267,9 @@ antlrcpp::Any CypherMainVisitor::visitCaseExpression(MemgraphCypher::CaseExpress
Expression *else_expression = ctx->else_expression ? ctx->else_expression->accept(this).as<Expression *>()
: storage_->Create<PrimitiveLiteral>(TypedValue());
for (auto *alternative : alternatives) {
Expression *condition =
test_expression ? storage_->Create<EqualOperator>(test_expression, alternative->when_expression->accept(this))
: alternative->when_expression->accept(this).as<Expression *>();
Expression *condition = test_expression ? storage_->Create<EqualOperator>(
test_expression, alternative->when_expression->accept(this), true)
: alternative->when_expression->accept(this).as<Expression *>();
Expression *then_expression = alternative->then_expression->accept(this);
else_expression = storage_->Create<IfOperator>(condition, then_expression, else_expression);
}

View File

@@ -81,7 +81,6 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
BINARY_OPERATOR_VISITOR(DivisionOperator, /, /);
BINARY_OPERATOR_VISITOR(ModOperator, %, %);
BINARY_OPERATOR_VISITOR(NotEqualOperator, !=, <>);
BINARY_OPERATOR_VISITOR(EqualOperator, ==, =);
BINARY_OPERATOR_VISITOR(LessOperator, <, <);
BINARY_OPERATOR_VISITOR(GreaterOperator, >, >);
BINARY_OPERATOR_VISITOR(LessEqualOperator, <=, <=);
@@ -94,6 +93,21 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
#undef BINARY_OPERATOR_VISITOR
#undef UNARY_OPERATOR_VISITOR
TypedValue Visit(EqualOperator &op) override {
auto val1 = op.expression1_->Accept(*this);
auto val2 = op.expression2_->Accept(*this);
try {
if (op.isnullcheckrequired_ && val2.IsNull()) {
throw QueryRuntimeException("Use the generic form when checking against NULL.");
}
return val1 == val2;
} catch (const TypedValueException &) {
throw QueryRuntimeException("Invalid types: {} and {} for '='.", val1.type(), val2.type());
}
}
TypedValue Visit(AndOperator &op) override {
auto value1 = op.expression1_->Accept(*this);
if (value1.IsBool() && !value1.ValueBool()) {

View File

@@ -40,6 +40,7 @@ add_subdirectory(write_procedures)
add_subdirectory(magic_functions)
add_subdirectory(module_file_manager)
add_subdirectory(monitoring_server)
add_subdirectory(util_e2e)
copy_e2e_python_files(pytest_runner pytest_runner.sh "")
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/memgraph-selfsigned.crt DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

View File

@@ -0,0 +1,5 @@
function(copy_util_e2e_python_files FILE_NAME)
copy_e2e_python_files(util_e2e ${FILE_NAME})
endfunction()
copy_util_e2e_python_files(utility_simple.py)

View File

@@ -0,0 +1,40 @@
# Copyright 2022 Memgraph Ltd.
#
# Use of this software is governed by the Business Source License
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
# License, and you may not use this file except in compliance with the Business Source License.
#
# As of the Change Date specified in that file, in accordance with
# the Business Source License, use of this software will be governed
# by the Apache License, Version 2.0, included in the file
# licenses/APL.txt.
import typing
import mgclient
import sys
import pytest
def test_does_throw_if_null_is_checked_against_in_generic_case():
connection = mgclient.connect(host="localhost", port=7687)
connection.autocommit = True
cursor = connection.cursor()
query = """WITH 2 AS name
RETURN CASE name
WHEN 3 THEN 'works'
WHEN null THEN "doesn't work"
ELSE 'something went wrong'
END"""
with pytest.raises(mgclient.DatabaseError) as err:
cursor.execute(query)
error_msg = err.value.args[0]
assert error_msg == "Use the generic form when checking against NULL."
if __name__ == "__main__":
sys.exit(pytest.main([__file__, "-rA"]))

View File

@@ -0,0 +1,13 @@
template_cluster: &template_cluster
cluster:
main:
args: ["--bolt-port", "7687", "--log-level=TRACE"]
log_file: "util-e2e.log"
setup_queries: []
validation_queries: []
workloads:
- name: "Utility simple"
binary: "tests/e2e/pytest_runner.sh"
args: ["util_e2e/utility_simple.py"]
<<: *template_cluster

View File

@@ -786,6 +786,7 @@ TEST_P(CypherMainVisitorTest, CaseSimpleForm) {
ASSERT_TRUE(condition);
ast_generator.CheckLiteral(condition->expression1_, 5);
ast_generator.CheckLiteral(condition->expression2_, 10);
ASSERT_TRUE(condition->isnullcheckrequired_);
ast_generator.CheckLiteral(if_operator->then_expression_, 1);
ast_generator.CheckLiteral(if_operator->else_expression_, TypedValue());
}