/* * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2.0, * as published by the Free Software Foundation. * * This program is also distributed with certain software (including * but not limited to OpenSSL) that is licensed under separate terms, * as designated in a particular file or component or in included license * documentation. The authors of MySQL hereby grant you an additional * permission to link the program and your derivative works with the * separately licensed software that they have included with MySQL. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License, version 2.0, for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "plugin/x/src/prepare_param_handler.h" #include "plugin/x/src/xpl_error.h" #include "unittest/gunit/xplugin/xpl/assert_error_code.h" #include "unittest/gunit/xplugin/xpl/mock/session.h" #include "unittest/gunit/xplugin/xpl/mysqlx_pb_wrapper.h" namespace xpl { namespace test { using Arg_list = Prepare_param_handler::Arg_list; using Param_list = Prepare_param_handler::Param_list; using Placeholder_list = Prepare_param_handler::Placeholder_list; using Param_value_list = Prepare_param_handler::Param_value_list; using Param_svalue_list = Prepare_param_handler::Param_svalue_list; class Prepare_param_handler_base_test : public testing::Test { public: Placeholder_list m_placeholders; Prepare_param_handler m_handler{m_placeholders}; }; struct Param_check_argument_placeholder_consistency { int expect_error_code; std::size_t args_size; Placeholder_list phs; }; Param_check_argument_placeholder_consistency check_argument_placeholder_consistency_param[] = { {ER_X_SUCCESS, 0, {}}, {ER_X_SUCCESS, 1, {0}}, {ER_X_SUCCESS, 1, {0, 0, 0}}, {ER_X_SUCCESS, 2, {1, 0, 1}}, {ER_X_SUCCESS, 3, {0, 1, 2}}, {ER_X_SUCCESS, 3, {1, 2, 0}}, {ER_X_SUCCESS, 3, {2, 1, 0}}, {ER_X_SUCCESS, 3, {2, 0, 1}}, {ER_X_SUCCESS, 3, {1, 0, 2}}, {ER_X_SUCCESS, 3, {0, 2, 1}}, {ER_X_PREPARED_EXECUTE_ARGUMENT_CONSISTENCY, 0, {0}}, {ER_X_PREPARED_EXECUTE_ARGUMENT_CONSISTENCY, 1, {2}}, }; class Prepare_param_handler_argument_consistency_test : public Prepare_param_handler_base_test, public testing::WithParamInterface< Param_check_argument_placeholder_consistency> {}; TEST_P(Prepare_param_handler_argument_consistency_test, check_argument_placeholder_consistency) { const Param_check_argument_placeholder_consistency ¶m = GetParam(); m_placeholders = param.phs; ASSERT_ERROR_CODE( param.expect_error_code, m_handler.check_argument_placeholder_consistency(param.args_size, 0)); } INSTANTIATE_TEST_CASE_P( Prepare_command_handler, Prepare_param_handler_argument_consistency_test, testing::ValuesIn(check_argument_placeholder_consistency_param)); namespace { class Value { public: Value() {} explicit Value(const unsigned v) { int8store(buf.data(), static_cast(v)); } explicit Value(const int v) { int8store(buf.data(), static_cast(v)); } explicit Value(const double v) { float8store(buf.data(), v); } explicit Value(const float v) { float4store(buf.data(), v); } explicit Value(const bool v) { buf[0] = v ? 1 : 0; } operator const Param_value_list::value_type &() const { return buf; } private: Param_value_list::value_type buf{{0}}; }; } // namespace struct Param_prepare_parameters { int expect_error_code; Param_list expect_params; Param_value_list expect_param_values; Param_svalue_list expect_param_svalues; Arg_list args; Placeholder_list phs; }; #define NLL \ { true, MYSQL_TYPE_NULL, false, nullptr, 0ul } #define SIN \ { false, MYSQL_TYPE_LONGLONG, false, nullptr, sizeof(int64_t) } #define UIN \ { false, MYSQL_TYPE_LONGLONG, true, nullptr, sizeof(uint64_t) } #define STR(len) \ { false, MYSQL_TYPE_STRING, false, nullptr, len } #define DBL \ { false, MYSQL_TYPE_DOUBLE, false, nullptr, sizeof(double) } #define FLT \ { false, MYSQL_TYPE_FLOAT, false, nullptr, sizeof(float) } #define BOL \ { false, MYSQL_TYPE_TINY, false, nullptr, 1ul } #define RAW(id) \ { id, Placeholder_info::Type::k_raw } #define JSN(id) \ { id, Placeholder_info::Type::k_json } using Octets = Scalar::Octets; using String = Scalar::String; Param_prepare_parameters prepare_parameters_param[] = { {ER_X_SUCCESS, {}, {}, {}, {}, {}}, {ER_X_SUCCESS, {NLL}, {}, {}, Any_list{Scalar::Null()}, {RAW(0)}}, {ER_X_SUCCESS, {STR(4)}, {}, {"null"}, Any_list{Scalar::Null()}, {JSN(0)}}, {ER_X_SUCCESS, {SIN}, {Value(-1)}, {}, Any_list{Scalar(-1)}, {RAW(0)}}, {ER_X_SUCCESS, {SIN}, {Value(-1)}, {}, Any_list{Scalar(-1)}, {JSN(0)}}, {ER_X_SUCCESS, {UIN}, {Value(1u)}, {}, Any_list{Scalar(1u)}, {RAW(0)}}, {ER_X_SUCCESS, {UIN}, {Value(1u)}, {}, Any_list{Scalar(1u)}, {JSN(0)}}, {ER_X_SUCCESS, {STR(3)}, {}, {}, Any_list{String("abc")}, {RAW(0)}}, {ER_X_SUCCESS, {STR(5)}, {}, {"\"abc\""}, Any_list{String("abc")}, {JSN(0)}}, {ER_X_SUCCESS, {STR(3)}, {}, {}, Any_list{Octets("abc")}, {RAW(0)}}, {ER_X_SUCCESS, {STR(3)}, {}, {}, Any_list{Octets("abc", Octets::Content_type::k_json)}, {RAW(0)}}, {ER_X_SUCCESS, {STR(5)}, {}, {"\"abc\""}, Any_list{Octets("abc")}, {JSN(0)}}, {ER_X_SUCCESS, {STR(3)}, {}, {"abc"}, Any_list{Octets("abc", Octets::Content_type::k_json)}, {JSN(0)}}, {ER_X_SUCCESS, {DBL}, {Value(1.1)}, {}, Any_list{Scalar(1.1)}, {RAW(0)}}, {ER_X_SUCCESS, {DBL}, {Value(1.1)}, {}, Any_list{Scalar(1.1)}, {JSN(0)}}, {ER_X_SUCCESS, {FLT}, {Value(1.1f)}, {}, Any_list{Scalar(1.1f)}, {RAW(0)}}, {ER_X_SUCCESS, {FLT}, {Value(1.1f)}, {}, Any_list{Scalar(1.1f)}, {JSN(0)}}, {ER_X_SUCCESS, {BOL}, {Value(true)}, {}, Any_list{Scalar(true)}, {RAW(0)}}, {ER_X_SUCCESS, {BOL}, {Value(false)}, {}, Any_list{Scalar(false)}, {RAW(0)}}, {ER_X_SUCCESS, {STR(4)}, {}, {"true"}, Any_list{Scalar(true)}, {JSN(0)}}, {ER_X_SUCCESS, {STR(5)}, {}, {"false"}, Any_list{Scalar(false)}, {JSN(0)}}, {ER_X_SUCCESS, {UIN, SIN}, {Value(2u), Value(1)}, {}, Any_list{Scalar(2u), Scalar(1)}, {RAW(0), RAW(1)}}, {ER_X_SUCCESS, {SIN, UIN}, {Value(1), Value(2u)}, {}, Any_list{Scalar(2u), Scalar(1)}, {RAW(1), RAW(0)}}, {ER_X_SUCCESS, {SIN, SIN, SIN}, {Value(1), Value(1), Value(1)}, {}, Any_list{Scalar(1)}, {RAW(0), RAW(0), RAW(0)}}, {ER_X_SUCCESS, {NLL, SIN, NLL}, {Value(1)}, {}, Any_list{Scalar::Null(), Scalar(1)}, {RAW(0), RAW(1), RAW(0)}}, {ER_X_SUCCESS, {NLL, STR(2), STR(3)}, {}, {}, Any_list{Scalar::String("ab"), Scalar::Octets("abc"), Scalar::Null()}, {RAW(2), RAW(0), RAW(1)}}, {ER_X_PREPARED_EXECUTE_ARGUMENT_NOT_SUPPORTED, {}, {}, {}, Any_list{Any::Object()}, {RAW(0)}}, {ER_X_PREPARED_EXECUTE_ARGUMENT_NOT_SUPPORTED, {}, {}, {}, Any_list{Any::Array()}, {RAW(0)}}, {ER_X_SUCCESS, {SIN}, {Value(1)}, {}, Any_list{Scalar(1), Any::Array()}, {RAW(0)}}, {ER_X_SUCCESS, {BOL, STR(4)}, {Value(true)}, {"true"}, Any_list{Scalar(true)}, {RAW(0), JSN(0)}}, }; class Prepare_command_handler_prepare_parameters_test : public Prepare_param_handler_base_test, public testing::WithParamInterface {}; MATCHER(Eq_param, "") { using ::testing::get; // intentionally skip comparison of "value" value; return get<0>(arg).null_bit == get<1>(arg).null_bit && get<0>(arg).type == get<1>(arg).type && get<0>(arg).unsigned_type == get<1>(arg).unsigned_type && get<0>(arg).length == get<1>(arg).length; } TEST_P(Prepare_command_handler_prepare_parameters_test, prepare_parameters) { const auto ¶m = GetParam(); m_placeholders = param.phs; ASSERT_ERROR_CODE(param.expect_error_code, m_handler.prepare_parameters(param.args)); EXPECT_THAT(m_handler.get_params(), testing::Pointwise(Eq_param(), param.expect_params)); EXPECT_EQ(param.expect_param_svalues, m_handler.get_string_values()); EXPECT_EQ(param.expect_param_values, m_handler.get_values()); } INSTANTIATE_TEST_CASE_P(Prepare_command_handler, Prepare_command_handler_prepare_parameters_test, testing::ValuesIn(prepare_parameters_param)); } // namespace test } // namespace xpl