From 792570241817f58bbf406c5b0ece66b115c9f124 Mon Sep 17 00:00:00 2001 From: ruben Date: Wed, 5 Feb 2020 23:36:12 +0000 Subject: [PATCH] New integ test system to avoid code duplication --- include/mysql/impl/prepared_statement.ipp | 14 ++- include/mysql/prepared_statement.hpp | 13 +++ test/integration/execute_statement.cpp | 114 ++++++++++++++----- test/integration/integration_test_common.hpp | 106 +++++++++++++++++ 4 files changed, 219 insertions(+), 28 deletions(-) diff --git a/include/mysql/impl/prepared_statement.ipp b/include/mysql/impl/prepared_statement.ipp index 7e280226..e575143c 100644 --- a/include/mysql/impl/prepared_statement.ipp +++ b/include/mysql/impl/prepared_statement.ipp @@ -42,6 +42,18 @@ mysql::resultset mysql::prepared_statement::execute( return res; } - +template +template +mysql::resultset mysql::prepared_statement::execute( + ForwardIterator params_first, + ForwardIterator params_last +) const +{ + error_code err; + error_info info; + auto res = execute(params_first, params_last, err, info); + detail::check_error_code(err, info); + return res; +} #endif /* INCLUDE_MYSQL_IMPL_PREPARED_STATEMENT_IPP_ */ diff --git a/include/mysql/prepared_statement.hpp b/include/mysql/prepared_statement.hpp index 1b681fd3..1cd960cb 100644 --- a/include/mysql/prepared_statement.hpp +++ b/include/mysql/prepared_statement.hpp @@ -31,10 +31,23 @@ public: return execute(std::begin(params), std::end(params), err, info); } + template + resultset execute(const Collection& params) const + { + return execute(std::begin(params), std::end(params)); + } + + template resultset execute(ForwardIterator params_first, ForwardIterator params_last, error_code&, error_info&) const; + + + template + resultset execute(ForwardIterator params_first, ForwardIterator params_last) const; }; +using tcp_prepared_statement = prepared_statement; + } #include "mysql/impl/prepared_statement.ipp" diff --git a/test/integration/execute_statement.cpp b/test/integration/execute_statement.cpp index b44e0bf5..acac713a 100644 --- a/test/integration/execute_statement.cpp +++ b/test/integration/execute_statement.cpp @@ -10,64 +10,124 @@ using namespace mysql::test; using mysql::value; +using mysql::error_code; +using mysql::error_info; using mysql::Error; +using mysql::tcp_resultset; +using mysql::tcp_prepared_statement; namespace { -struct ExecuteStatementTest : public IntegTestAfterHandshake +// Iterator version +using listit = std::forward_list::const_iterator; +struct ExecuteStatementIteratorTraits { + static tcp_resultset sync_errc(const tcp_prepared_statement& stmt, listit first, listit last, + error_code& errc, error_info& info) + { + return stmt.execute(first, last, errc, info); + } + + static tcp_resultset sync_exc(const tcp_prepared_statement& stmt, listit first, listit last) + { + return stmt.execute(first, last); + } }; -TEST_F(ExecuteStatementTest, IteratorsSyncErrc_OkNoParams) +struct ExecuteStatementIteratorTest : public NetworkTest {}; + +TEST_P(ExecuteStatementIteratorTest, OkNoParams) { std::forward_list params; auto stmt = conn.prepare_statement("SELECT * FROM empty_table"); - auto result = stmt.execute(params.begin(), params.end(), errc, info); - validate_no_error(); - EXPECT_TRUE(result.valid()); + auto result = GetParam().fun(stmt, params.begin(), params.end()); // execute + result.validate_no_error(); + EXPECT_TRUE(result.value.valid()); } -TEST_F(ExecuteStatementTest, IteratorsSyncErrc_OkWithParams) +TEST_P(ExecuteStatementIteratorTest, OkWithParams) { std::forward_list params { value("item"), value(42) }; auto stmt = conn.prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)"); - auto result = stmt.execute(params.begin(), params.end(), errc, info); - validate_no_error(); - EXPECT_TRUE(result.valid()); + auto result = GetParam().fun(stmt, params.begin(), params.end()); + result.validate_no_error(); + EXPECT_TRUE(result.value.valid()); } -TEST_F(ExecuteStatementTest, IteratorsSyncErrc_Error) +TEST_P(ExecuteStatementIteratorTest, MismatchedNumParams) { std::forward_list params { value("item") }; auto stmt = conn.prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)"); - auto result = stmt.execute(params.begin(), params.end(), errc, info); - validate_sync_fail(Error::wrong_num_params, {"param", "2", "1", "statement", "execute"}); - EXPECT_FALSE(result.valid()); + auto result = GetParam().fun(stmt, params.begin(), params.end()); + result.validate_error(Error::wrong_num_params, {"param", "2", "1", "statement", "execute"}); + EXPECT_FALSE(result.value.valid()); } -TEST_F(ExecuteStatementTest, CollectionSyncErrc_OkNoParams) +// TODO: is there any way of making server return an error here? + +MYSQL_NETWORK_TEST_SUITE(ExecuteStatementIteratorTest); + +// Container version +struct ExecuteStatementContainerTraits +{ + static tcp_resultset sync_errc(const tcp_prepared_statement& stmt, const std::vector& v, + error_code& errc, error_info& info) + { + return stmt.execute(v, errc, info); + } + + static tcp_resultset sync_exc(const tcp_prepared_statement& stmt, const std::vector& v) + { + return stmt.execute(v); + } +}; + +struct ExecuteStatementContainerTest : public NetworkTest {}; + +TEST_P(ExecuteStatementContainerTest, OkNoParams) { auto stmt = conn.prepare_statement("SELECT * FROM empty_table"); - auto result = stmt.execute(mysql::no_statement_params, errc, info); - validate_no_error(); + auto result = GetParam().fun(stmt, std::vector()); // execute + result.validate_no_error(); + EXPECT_TRUE(result.value.valid()); +} + +TEST_P(ExecuteStatementContainerTest, OkWithParams) +{ + std::vector params { value("item"), value(42) }; + auto stmt = conn.prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)"); + auto result = GetParam().fun(stmt, params); + result.validate_no_error(); + EXPECT_TRUE(result.value.valid()); +} + +TEST_P(ExecuteStatementContainerTest, MismatchedNumParams) +{ + std::vector params { value("item") }; + auto stmt = conn.prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)"); + auto result = GetParam().fun(stmt, params); + result.validate_error(Error::wrong_num_params, {"param", "2", "1", "statement", "execute"}); + EXPECT_FALSE(result.value.valid()); +} + +MYSQL_NETWORK_TEST_SUITE(ExecuteStatementContainerTest); + +struct ExecuteStatementOtherContainersTest : IntegTestAfterHandshake {}; + +TEST_F(ExecuteStatementOtherContainersTest, NoParams_CanUseNoStatementParamsVariable) +{ + auto stmt = conn.prepare_statement("SELECT * FROM empty_table"); + auto result = stmt.execute(mysql::no_statement_params); EXPECT_TRUE(result.valid()); } -TEST_F(ExecuteStatementTest, CollectionSyncErrc_OkWithParams) +TEST_F(ExecuteStatementOtherContainersTest, CArray) { + value arr [] = { value("hola"), value(10) }; auto stmt = conn.prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)"); - auto result = stmt.execute(makevalues("item", 42), errc, info); - validate_no_error(); + auto result = stmt.execute(arr); EXPECT_TRUE(result.valid()); } -TEST_F(ExecuteStatementTest, CollectionSyncErrc_Error) -{ - auto stmt = conn.prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)"); - auto result = stmt.execute(makevalues("item"), errc, info); - validate_sync_fail(Error::wrong_num_params, {"param", "2", "1", "statement", "execute"}); - EXPECT_FALSE(result.valid()); -} - } diff --git a/test/integration/integration_test_common.hpp b/test/integration/integration_test_common.hpp index d2e7c0aa..9a42e335 100644 --- a/test/integration/integration_test_common.hpp +++ b/test/integration/integration_test_common.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "test_common.hpp" namespace mysql @@ -147,9 +148,114 @@ struct IntegTestAfterHandshake : IntegTest IntegTestAfterHandshake() { handshake(); } }; +template +struct NetworkResult +{ + error_code errc; + error_info info; + T value; + + void validate_no_error() const + { + ASSERT_EQ(errc, error_code()); + EXPECT_EQ(info, error_info()); + } + + void validate_error( + error_code expected_errc, + const std::vector& expected_msg + ) const + { + EXPECT_EQ(errc, expected_errc); + validate_string_contains(info.message(), expected_msg); + } + + void validate_error( + Error expected_errc, + const std::vector& expected_msg + ) const + { + validate_error(detail::make_error_code(expected_errc), expected_msg); + } +}; + +template +struct NetworkFunction : named_param +{ + std::string name; + std::function(Args...)> fun; + + template + NetworkFunction(std::string name, Callable&& cb): + name(std::move(name)), fun(std::forward(cb)) {} +}; + +template +class get_network_function_type +{ + template + static NetworkFunction helper(R(*)(Args...)); +public: + using type = decltype(helper(&TraitsType::sync_exc)); +}; + +template +using traits_network_function = typename get_network_function_type::type; + +template +auto make_network_functions_impl(R(*)(Args...)) +{ + using NetResultType = NetworkResult; + using NetFunType = NetworkFunction; + auto sync_errc = [](Args... args) { + NetResultType res; + res.errc = detail::make_error_code(Error::no); + res.info.set_message("Error info not cleared correctly"); + res.value = TraitsType::sync_errc(std::forward(args)..., res.errc, res.info); + return res; + }; + auto sync_exc = [](Args... args) { + NetResultType res; + try + { + res.value = TraitsType::sync_exc(std::forward(args)...); + } + catch (const boost::system::system_error& err) + { + res.errc = err.code(); + res.info.set_message(err.what()); + } + return res; + }; + return std::vector{ + NetFunType("sync_errc", sync_errc), + NetFunType("sync_exc", sync_exc) + }; +} + +template +std::vector> +make_network_functions() +{ + return make_network_functions_impl(&TraitsType::sync_exc); +} + +template +struct NetworkTest : + public BaseTest, + public testing::WithParamInterface> +{ + using traits_type = TraitsType; +}; + } } +#define MYSQL_NETWORK_TEST_SUITE(TestSuiteName) \ + INSTANTIATE_TEST_SUITE_P(Default, TestSuiteName, testing::ValuesIn( \ + make_network_functions() \ + ), test_name_generator) + #endif /* TEST_INTEGRATION_INTEGRATION_TEST_COMMON_HPP_ */