QA: Add coroutine unit test

This adds a simple unit test to qa_common to check coroutines
produce expected events in the right order.

This is an automated analogue to the user-facing tool in
qa/common_tools.
This commit is contained in:
John Beard 2019-01-23 12:31:53 +00:00 committed by Wayne Stambaugh
parent 6729842441
commit b690658972
3 changed files with 185 additions and 0 deletions

View File

@ -37,6 +37,7 @@ set( common_srcs
../../common/observable.cpp ../../common/observable.cpp
test_color4d.cpp test_color4d.cpp
test_coroutine.cpp
test_format_units.cpp test_format_units.cpp
test_hotkey_store.cpp test_hotkey_store.cpp
test_title_block.cpp test_title_block.cpp

View File

@ -0,0 +1,177 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 KiCad Developers, see CHANGELOG.TXT for contributors.
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file test_coroutine.cpp
* Test suite for coroutines.
*
* See also the coroutine utility in qa/common_tools for a command line
* test utility.
*/
#include <unit_test_utils/unit_test_utils.h>
#include <tool/coroutine.h>
#include <common.h>
/**
* An event in a simple coroutine harness.
*/
struct COROUTINE_TEST_EVENT
{
enum class TYPE
{
START,
CALL,
YIELD,
RETURNED,
END,
};
TYPE m_type;
int m_value;
bool operator==( const COROUTINE_TEST_EVENT& aOther ) const
{
return m_type == aOther.m_type && m_value == aOther.m_value;
}
bool operator!=( const COROUTINE_TEST_EVENT& aOther ) const
{
return !operator==( aOther );
}
};
/**
* Define a stream function for logging this type.
*
* TODO: convert to boost_test_print_type when Boost minver > 1.64
*/
std::ostream& operator<<( std::ostream& os, const COROUTINE_TEST_EVENT& aObj )
{
os << "COROUTINE_TEST_EVENT[ type: " << (int) aObj.m_type << ", value: " << aObj.m_value
<< " ]";
return os;
}
/**
* Simple coroutine harness that runs a coroutine that increments a number up
* to a pre-set limit, spitting out coroutine events as it goes.
*
* This can then be used to ensure the events are occurring as expected.
*/
class COROUTINE_INCREMENTING_HARNESS
{
public:
/**
* The coroutine test take ints and returns them
*/
using TEST_COROUTINE = COROUTINE<int, int>;
using EVT_HANDLER = std::function<void( const COROUTINE_TEST_EVENT& )>;
COROUTINE_INCREMENTING_HARNESS( EVT_HANDLER aHandler, int aCount )
: m_handler( aHandler ), m_count( aCount )
{
}
int CountTo( int n )
{
m_handler( { COROUTINE_TEST_EVENT::TYPE::START, 0 } );
for( int i = 1; i <= n; i++ )
{
m_handler( { COROUTINE_TEST_EVENT::TYPE::YIELD, i } );
m_cofunc->KiYield( i );
}
return 0;
}
void Run()
{
m_cofunc =
std::make_unique<TEST_COROUTINE>( this, &COROUTINE_INCREMENTING_HARNESS::CountTo );
m_handler( { COROUTINE_TEST_EVENT::TYPE::CALL, m_count } );
m_cofunc->Call( m_count );
int ret_val = 0;
while( m_cofunc->Running() )
{
ret_val = m_cofunc->ReturnValue();
m_handler( { COROUTINE_TEST_EVENT::TYPE::RETURNED, ret_val } );
m_cofunc->Resume();
}
m_handler( { COROUTINE_TEST_EVENT::TYPE::END, ret_val } );
}
EVT_HANDLER m_handler;
std::unique_ptr<TEST_COROUTINE> m_cofunc;
int m_count;
};
/**
* Declare the test suite
*/
BOOST_AUTO_TEST_SUITE( Coroutine )
/**
* A basic test to repeatedly call a coroutine and check that it yields
* values as expected.
*/
BOOST_AUTO_TEST_CASE( Increment )
{
const int count = 2;
const std::vector<COROUTINE_TEST_EVENT> exp_events = {
{ COROUTINE_TEST_EVENT::TYPE::CALL, count },
{ COROUTINE_TEST_EVENT::TYPE::START, 0 },
{ COROUTINE_TEST_EVENT::TYPE::YIELD, 1 },
{ COROUTINE_TEST_EVENT::TYPE::RETURNED, 1 },
{ COROUTINE_TEST_EVENT::TYPE::YIELD, 2 },
{ COROUTINE_TEST_EVENT::TYPE::RETURNED, 2 },
{ COROUTINE_TEST_EVENT::TYPE::END, 2 },
};
std::vector<COROUTINE_TEST_EVENT> received_events;
auto handler = [&]( const COROUTINE_TEST_EVENT& aEvent ) {
received_events.push_back( aEvent );
};
COROUTINE_INCREMENTING_HARNESS harness( handler, count );
harness.Run();
BOOST_CHECK_EQUAL_COLLECTIONS(
received_events.begin(), received_events.end(), exp_events.begin(), exp_events.end() );
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -35,6 +35,13 @@
typedef COROUTINE<int, int> MyCoroutine; typedef COROUTINE<int, int> MyCoroutine;
/**
* A simple harness that counts to a preset value in a couroutine, yielding
* each value.
*
* This is a user-facing version of the "Increment" unit test in the "Coroutine"
* suite, in qa_common.
*/
class CoroutineExample class CoroutineExample
{ {
public: public: