/*
* Copyright © 2016 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors:
* Ted Gould
*/
#include
#include
#include
#include
class EventuallyFixture : public ::testing::Test
{
protected:
std::chrono::milliseconds _eventuallyTime = std::chrono::minutes{1};
std::once_flag checkEventuallyEnv_;
static gboolean timeout_cb(gpointer user_data)
{
auto loop = static_cast(user_data);
g_main_loop_quit(loop);
return G_SOURCE_REMOVE;
}
void pause(unsigned int ms = 0)
{
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_timeout_add(ms, timeout_cb, loop);
g_main_loop_run(loop);
g_main_loop_unref(loop);
}
testing::AssertionResult eventuallyLoop(std::function &testfunc)
{
std::call_once(checkEventuallyEnv_, [this]() {
auto eventuallyenv = getenv("EVENTUALLY_TIMEOUT");
if (eventuallyenv != nullptr)
{
_eventuallyTime = std::chrono::seconds{std::atoi(eventuallyenv)};
}
});
auto loop = std::shared_ptr(g_main_loop_new(nullptr, FALSE),
[](GMainLoop *loop) { g_clear_pointer(&loop, g_main_loop_unref); });
std::promise retpromise;
auto retfuture = retpromise.get_future();
auto start = std::chrono::steady_clock::now();
/* The core of the idle function as an object so we can use the C++-isms
of attaching the variables and make this code reasonably readable */
std::function idlefunc = [&loop, &retpromise, &testfunc, &start, this]() -> gboolean {
auto result = testfunc();
auto elapsed = std::chrono::steady_clock::now() - start;
if (result == false)
{
if (_eventuallyTime > elapsed)
{
return G_SOURCE_CONTINUE;
}
g_warning("Eventually time out after: %d ms",
int(std::chrono::duration_cast(elapsed).count()));
}
retpromise.set_value(result);
g_main_loop_quit(loop.get());
return G_SOURCE_REMOVE;
};
g_idle_add(
[](gpointer data) -> gboolean {
auto func = reinterpret_cast *>(data);
return (*func)();
},
&idlefunc);
g_main_loop_run(loop.get());
return retfuture.get();
}
/* Eventually Helpers */
#define _EVENTUALLY_HELPER(oper) \
template \
testing::AssertionResult eventuallyHelper##oper(Args &&... args) \
{ \
std::function func = [&]() { \
return testing::internal::CmpHelper##oper(std::forward(args)...); \
}; \
return eventuallyLoop(func); \
}
#define _EVENTUALLY_FUNC_HELPER(oper) \
template \
testing::AssertionResult eventuallyFuncHelper##oper(const char *desca, const char *descb, comptype expected, \
std::function checker) \
{ \
std::function func = [&]() { \
auto newval = checker(); \
return testing::internal::CmpHelper##oper(desca, descb, expected, newval); \
}; \
return eventuallyLoop(func); \
}
_EVENTUALLY_HELPER(EQ);
_EVENTUALLY_HELPER(NE);
_EVENTUALLY_HELPER(LT);
_EVENTUALLY_HELPER(GT);
_EVENTUALLY_HELPER(STREQ);
_EVENTUALLY_HELPER(STRNE);
_EVENTUALLY_FUNC_HELPER(EQ);
_EVENTUALLY_FUNC_HELPER(NE);
_EVENTUALLY_FUNC_HELPER(LT);
_EVENTUALLY_FUNC_HELPER(GT);
_EVENTUALLY_FUNC_HELPER(STREQ);
_EVENTUALLY_FUNC_HELPER(STRNE);
#undef _EVENTUALLY_HELPER
#undef _EVENTUALLY_FUNC_HELPER
};
/* Helpers */
#define EXPECT_EVENTUALLY_EQ(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperEQ, expected, actual)
#define EXPECT_EVENTUALLY_NE(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperNE, expected, actual)
#define EXPECT_EVENTUALLY_LT(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperLT, expected, actual)
#define EXPECT_EVENTUALLY_GT(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperGT, expected, actual)
#define EXPECT_EVENTUALLY_STREQ(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperSTREQ, expected, actual)
#define EXPECT_EVENTUALLY_STRNE(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperSTRNE, expected, actual)
#define ASSERT_EVENTUALLY_EQ(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperEQ, expected, actual)
#define ASSERT_EVENTUALLY_NE(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperNE, expected, actual)
#define ASSERT_EVENTUALLY_LT(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperLT, expected, actual)
#define ASSERT_EVENTUALLY_GT(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperGT, expected, actual)
#define ASSERT_EVENTUALLY_STREQ(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperSTREQ, expected, actual)
#define ASSERT_EVENTUALLY_STRNE(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyHelperSTRNE, expected, actual)
/* Func Helpers */
#define EXPECT_EVENTUALLY_FUNC_EQ(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperEQ, expected, actual)
#define EXPECT_EVENTUALLY_FUNC_NE(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperNE, expected, actual)
#define EXPECT_EVENTUALLY_FUNC_LT(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperLT, expected, actual)
#define EXPECT_EVENTUALLY_FUNC_GT(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperGT, expected, actual)
#define EXPECT_EVENTUALLY_FUNC_STREQ(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperSTREQ, expected, actual)
#define EXPECT_EVENTUALLY_FUNC_STRNE(expected, actual) \
EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperSTRNE, expected, actual)
#define ASSERT_EVENTUALLY_FUNC_EQ(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperEQ, expected, actual)
#define ASSERT_EVENTUALLY_FUNC_NE(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperNE, expected, actual)
#define ASSERT_EVENTUALLY_FUNC_LT(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperLT, expected, actual)
#define ASSERT_EVENTUALLY_FUNC_GT(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperGT, expected, actual)
#define ASSERT_EVENTUALLY_FUNC_STREQ(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperSTREQ, expected, actual)
#define ASSERT_EVENTUALLY_FUNC_STRNE(expected, actual) \
ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperSTRNE, expected, actual)