Migrated case to portable static assert and added static tests

This commit is contained in:
rbock
2015-12-24 21:11:00 +01:00
parent 899c868f5e
commit 02f4dd1793
9 changed files with 219 additions and 49 deletions

View File

@@ -34,22 +34,29 @@
namespace sqlpp
{
namespace detail
{
template <typename When>
using valid_when_t =
logic::all_t<is_boolean_t<wrap_operand_t<When>>::value, is_expression_t<wrap_operand_t<When>>::value>;
SQLPP_PORTABLE_STATIC_ASSERT(assert_case_else_expression_t, "argument is not a value expression in else()");
SQLPP_PORTABLE_STATIC_ASSERT(assert_case_then_else_same_type_t,
"argument of then() and else() are not of the same type");
template <typename Then>
using valid_then_t = is_expression_t<wrap_operand_t<Then>>;
template <typename Then, typename Else>
using check_case_else_t = static_combined_check_t<
static_check_t<is_expression_t<wrap_operand_t<Else>>::value, assert_case_else_expression_t>,
static_check_t<logic::any_t<is_sql_null_t<Then>::value,
is_sql_null_t<wrap_operand_t<Else>>::value,
std::is_same<value_type_of<Then>, value_type_of<wrap_operand_t<Else>>>::value>::value,
assert_case_then_else_same_type_t>>;
template <typename Then, typename Else>
using valid_else_t = logic::all_t<
is_expression_t<wrap_operand_t<Else>>::value,
logic::any_t<is_sql_null_t<Then>::value,
is_sql_null_t<wrap_operand_t<Else>>::value,
std::is_same<value_type_of<Then>, value_type_of<wrap_operand_t<Else>>>::value>::value>;
}
SQLPP_PORTABLE_STATIC_ASSERT(assert_case_then_expression_t, "argument is not a value expression in then()");
template <typename Then>
using check_case_then_t =
static_check_t<logic::all_t<is_expression_t<wrap_operand_t<Then>>::value>::value, assert_case_then_expression_t>;
SQLPP_PORTABLE_STATIC_ASSERT(assert_case_when_boolean_expression_t,
"argument is not a boolean expression in case_when()");
template <typename When>
using check_case_when_t = static_check_t<
logic::all_t<is_boolean_t<wrap_operand_t<When>>::value, is_expression_t<wrap_operand_t<When>>::value>::value,
assert_case_when_boolean_expression_t>;
template <typename When, typename Then, typename Else>
struct case_t
@@ -100,11 +107,10 @@ namespace sqlpp
~case_then_t() = default;
template <typename Else>
auto else_(Else else_) -> decltype(this->_else_impl(detail::valid_else_t<Then, Else>{}, else_))
auto else_(Else else_) -> decltype(this->_else_impl(check_case_else_t<Then, Else>{}, else_))
{
static_assert(detail::valid_else_t<Then, Else>::value,
"arguments of then and else must be expressions of the same type (or null)");
return _else_impl(detail::valid_else_t<Then, Else>{}, else_);
check_case_else_t<Then, Else>::_();
return _else_impl(check_case_else_t<Then, Else>{}, else_);
}
private:
@@ -136,10 +142,10 @@ namespace sqlpp
~case_when_t() = default;
template <typename Then>
auto then(Then t) -> decltype(this->_then_impl(detail::valid_then_t<Then>{}, t))
auto then(Then t) -> decltype(this->_then_impl(check_case_then_t<Then>{}, t))
{
static_assert(detail::valid_then_t<Then>::value, "then argument must be a value expression");
return _then_impl(detail::valid_then_t<Then>{}, t);
check_case_then_t<Then>::_();
return _then_impl(check_case_then_t<Then>{}, t);
}
private:
@@ -178,11 +184,11 @@ namespace sqlpp
}
template <typename When>
auto case_when(When when) -> decltype(detail::case_when_impl(detail::valid_when_t<When>{}, when))
auto case_when(When when) -> decltype(detail::case_when_impl(check_case_when_t<When>{}, when))
{
static_assert(detail::valid_when_t<When>::value, "case_when condition must be a boolean expression");
check_case_when_t<When>::_();
return detail::case_when_impl(detail::valid_when_t<When>{}, when);
return detail::case_when_impl(typename check_case_when_t<When>::type{}, when);
}
}

View File

@@ -31,7 +31,7 @@
namespace sqlpp
{
struct consistent_t
struct consistent_t : std::true_type
{
static constexpr bool value = true;
using type = std::true_type;

View File

@@ -438,7 +438,7 @@ namespace sqlpp
using Check = check_insert_static_set_t<Assignments...>;
Check{}._();
return _set_impl<void>(typename Check::type{}, assignments...);
return _set_impl<void>(Check{}, assignments...);
}
template <typename... Assignments>
@@ -449,7 +449,7 @@ namespace sqlpp
using Check = check_insert_dynamic_set_t<_database_t, Assignments...>;
Check{}._();
return _set_impl<_database_t>(typename Check::type{}, assignments...);
return _set_impl<_database_t>(Check{}, assignments...);
}
private:

View File

@@ -30,9 +30,8 @@
namespace sqlpp
{
#define SQLPP_PORTABLE_STATIC_ASSERT(name, message) \
struct name \
struct name : std::false_type \
{ \
static constexpr bool value = false; \
using type = std::false_type; \
\
template <typename T = void> \

View File

@@ -296,7 +296,7 @@ namespace sqlpp
using Check = check_where_static_t<Expressions...>;
Check{}._();
return _where_impl<void>(typename Check::type{}, expressions...);
return _where_impl<void>(Check{}, expressions...);
}
template <typename... Expressions>
@@ -306,7 +306,7 @@ namespace sqlpp
using Check = check_where_dynamic_t<_database_t, Expressions...>;
Check{}._();
return _where_impl<_database_t>(typename Check::type{}, expressions...);
return _where_impl<_database_t>(Check{}, expressions...);
}
private:

View File

@@ -29,6 +29,7 @@ function(test_compile name)
endfunction()
test_compile(aggregates)
test_compile(case)
test_compile(where)
test_compile(insert)
test_compile(date)

View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) 2015-2015, Roland Bock
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <iostream>
#include "MockDb.h"
#include "Sample.h"
#include <sqlpp11/sqlpp11.h>
namespace
{
constexpr auto t = test::TabBar{};
constexpr auto f = test::TabFoo{};
template <typename T>
void print_type_on_error(std::true_type)
{
}
template <typename T>
void print_type_on_error(std::false_type)
{
T::_print_me_;
}
template <typename Assert, typename When>
void when_check(const When& when)
{
using CheckResult = sqlpp::check_case_when_t<When>;
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
print_type_on_error<CheckResult>(ExpectedCheckResult{});
static_assert(ExpectedCheckResult::value, "Unexpected check result");
using ReturnType = decltype(sqlpp::case_when(when));
using ExpectedReturnType = sqlpp::logic::all_t<Assert::value xor std::is_same<ReturnType, void>::value>;
print_type_on_error<ReturnType>(ExpectedReturnType{});
static_assert(ExpectedReturnType::value, "Unexpected return type");
}
template <typename Assert, typename When, typename Then>
void then_check(const When& when, const Then& then)
{
using CheckResult = sqlpp::check_case_then_t<Then>;
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
print_type_on_error<CheckResult>(ExpectedCheckResult{});
static_assert(ExpectedCheckResult::value, "Unexpected check result");
using ReturnType = decltype(sqlpp::case_when(when).then(then));
using ExpectedReturnType = sqlpp::logic::all_t<Assert::value xor std::is_same<ReturnType, void>::value>;
print_type_on_error<ReturnType>(ExpectedReturnType{});
static_assert(ExpectedReturnType::value, "Unexpected return type");
}
template <typename Assert, typename When, typename Then, typename Else>
void else_check(const When& when, const Then& then, const Else& else_)
{
using CheckResult = sqlpp::check_case_else_t<sqlpp::wrap_operand_t<Then>, Else>;
using ExpectedCheckResult = std::is_same<CheckResult, Assert>;
print_type_on_error<CheckResult>(ExpectedCheckResult{});
static_assert(ExpectedCheckResult::value, "Unexpected check result");
using ReturnType = decltype(sqlpp::case_when(when).then(then).else_(else_));
using ExpectedReturnType = sqlpp::logic::all_t<Assert::value xor std::is_same<ReturnType, void>::value>;
print_type_on_error<ReturnType>(ExpectedReturnType{});
static_assert(ExpectedReturnType::value, "Unexpected return type");
}
void when()
{
// OK
when_check<sqlpp::consistent_t>(t.gamma);
when_check<sqlpp::consistent_t>(t.gamma == true);
when_check<sqlpp::consistent_t>(count(t.alpha) > 0);
// Try assignment as "when"
when_check<sqlpp::assert_case_when_boolean_expression_t>(t.gamma = true);
// Try non-boolean expression as "when"
when_check<sqlpp::assert_case_when_boolean_expression_t>(t.alpha);
// Try some other types as "when"
when_check<sqlpp::assert_case_when_boolean_expression_t>("true");
when_check<sqlpp::assert_case_when_boolean_expression_t>(42);
when_check<sqlpp::assert_case_when_boolean_expression_t>('c');
when_check<sqlpp::assert_case_when_boolean_expression_t>(nullptr);
// Try to use a table as "when"
when_check<sqlpp::assert_case_when_boolean_expression_t>(t);
// Try to use an alias as "when"
when_check<sqlpp::assert_case_when_boolean_expression_t>(t.gamma.as(t.beta));
}
void then()
{
// OK
then_check<sqlpp::consistent_t>(t.gamma, t.gamma);
then_check<sqlpp::consistent_t>(t.gamma, t.gamma == true);
then_check<sqlpp::consistent_t>(t.gamma, count(t.alpha) > 0);
then_check<sqlpp::consistent_t>(t.gamma, t.alpha);
then_check<sqlpp::consistent_t>(t.gamma, "true");
then_check<sqlpp::consistent_t>(t.gamma, 42);
then_check<sqlpp::consistent_t>(t.gamma, 'c');
then_check<sqlpp::consistent_t>(t.gamma, nullptr);
// Try to use an assignment as "then"
then_check<sqlpp::assert_case_then_expression_t>(t.gamma, t.gamma = true);
// Try to use a table as "then"
then_check<sqlpp::assert_case_then_expression_t>(t.gamma, t);
// Try to use an alias as "then"
then_check<sqlpp::assert_case_then_expression_t>(t.gamma, t.alpha.as(t.beta));
}
void else_()
{
// OK
else_check<sqlpp::consistent_t>(t.gamma, t.gamma, t.gamma);
else_check<sqlpp::consistent_t>(t.gamma, t.alpha, 42);
else_check<sqlpp::consistent_t>(t.gamma, t.beta, "twentyseven");
// Try to use an assignment as "else"
else_check<sqlpp::assert_case_else_expression_t>(t.gamma, t.alpha, t.alpha = 7);
// Try to use a table as "else"
else_check<sqlpp::assert_case_else_expression_t>(t.gamma, t.alpha, t);
// Try to use an alias as "else"
else_check<sqlpp::assert_case_else_expression_t>(t.gamma, t.alpha, t.alpha.as(t.beta));
}
}
int main(int, char**)
{
when();
then();
else_();
}

View File

@@ -60,7 +60,7 @@ namespace
}
template <typename Assert, typename... Expressions>
void set_dynamic_check(const Expressions&... expressions)
void where_dynamic_check(const Expressions&... expressions)
{
static auto db = MockDb{};
using CheckResult = sqlpp::check_where_dynamic_t<decltype(db), Expressions...>;
@@ -95,35 +95,40 @@ namespace
where_static_check<sqlpp::assert_where_expressions_t>(17);
where_static_check<sqlpp::assert_where_expressions_t>('c');
where_static_check<sqlpp::assert_where_expressions_t>(nullptr);
where_static_check<sqlpp::assert_where_expressions_t>(t.alpha.as(t.beta));
// Try using aggregate functions in where
where_static_check<sqlpp::assert_where_no_aggregate_functions_t>(count(t.alpha) > 0);
where_static_check<sqlpp::assert_where_no_aggregate_functions_t>(t.gamma and count(t.alpha) > 0);
where_static_check<sqlpp::assert_where_no_aggregate_functions_t>(
case_when(count(t.alpha) > 0).then(t.gamma).else_(not t.gamma));
}
// column alpha is not allowed, column gamma is required
void dynamic_where()
{
// OK
set_dynamic_check<sqlpp::consistent_t>();
where_static_check<sqlpp::consistent_t>(t.gamma);
where_static_check<sqlpp::consistent_t>(t.gamma == true);
where_dynamic_check<sqlpp::consistent_t>();
where_dynamic_check<sqlpp::consistent_t>(t.gamma);
where_dynamic_check<sqlpp::consistent_t>(t.gamma == true);
// Try assignment as condition
where_static_check<sqlpp::assert_where_expressions_t>(t.gamma = true);
where_dynamic_check<sqlpp::assert_where_expressions_t>(t.gamma = true);
// Try non-boolean expression
where_static_check<sqlpp::assert_where_boolean_t>(t.alpha);
where_dynamic_check<sqlpp::assert_where_boolean_t>(t.alpha);
// Try some other types as expressions
where_static_check<sqlpp::assert_where_expressions_t>("true");
where_static_check<sqlpp::assert_where_expressions_t>(17);
where_static_check<sqlpp::assert_where_expressions_t>('c');
where_static_check<sqlpp::assert_where_expressions_t>(nullptr);
where_dynamic_check<sqlpp::assert_where_expressions_t>("true");
where_dynamic_check<sqlpp::assert_where_expressions_t>(17);
where_dynamic_check<sqlpp::assert_where_expressions_t>('c');
where_dynamic_check<sqlpp::assert_where_expressions_t>(nullptr);
where_dynamic_check<sqlpp::assert_where_expressions_t>(t.alpha.as(t.beta));
// Try using aggregate functions in where
where_static_check<sqlpp::assert_where_no_aggregate_functions_t>(count(t.alpha) > 0);
where_static_check<sqlpp::assert_where_no_aggregate_functions_t>(t.gamma and count(t.alpha) > 0);
where_dynamic_check<sqlpp::assert_where_no_aggregate_functions_t>(count(t.alpha) > 0);
where_dynamic_check<sqlpp::assert_where_no_aggregate_functions_t>(t.gamma and count(t.alpha) > 0);
where_dynamic_check<sqlpp::assert_where_no_aggregate_functions_t>(
case_when(count(t.alpha) > 0).then(t.gamma).else_(not t.gamma));
// Try dynamic_where on a non-dynamic remove
using CheckResult = sqlpp::check_where_dynamic_t<void>;

View File

@@ -120,10 +120,10 @@ struct MockDbT : public sqlpp::connection
auto _run(const T& t, const std::false_type&) -> void;
template <typename T>
auto operator()(const T& t) -> decltype(this->_run(t, typename sqlpp::run_check_t<_serializer_context_t, T>::type{}))
auto operator()(const T& t) -> decltype(this->_run(t, sqlpp::run_check_t<_serializer_context_t, T>{}))
{
sqlpp::run_check_t<_serializer_context_t, T>::_();
return _run(t, typename sqlpp::run_check_t<_serializer_context_t, T>::type{});
return _run(t, sqlpp::run_check_t<_serializer_context_t, T>{});
}
size_t execute(const std::string&)
@@ -191,11 +191,10 @@ struct MockDbT : public sqlpp::connection
auto _prepare(const T& t, const std::false_type&) -> void;
template <typename T>
auto prepare(const T& t)
-> decltype(this->_prepare(t, typename sqlpp::prepare_check_t<_serializer_context_t, T>::type{}))
auto prepare(const T& t) -> decltype(this->_prepare(t, sqlpp::prepare_check_t<_serializer_context_t, T>{}))
{
sqlpp::prepare_check_t<_serializer_context_t, T>::_();
return _prepare(t, typename sqlpp::prepare_check_t<_serializer_context_t, T>::type{});
return _prepare(t, sqlpp::prepare_check_t<_serializer_context_t, T>{});
}
template <typename Statement>