Add make_enum macros and a unit test, also add to project files
This commit is contained in:
parent
e8266ba932
commit
215de94390
8 changed files with 427 additions and 3 deletions
|
@ -163,8 +163,6 @@
|
|||
<Unit filename="../../src/attack_prediction_display.hpp" />
|
||||
<Unit filename="../../src/boilerplate-header.cpp" />
|
||||
<Unit filename="../../src/buffered_istream.hpp" />
|
||||
<Unit filename="../../src/terrain_builder.cpp" />
|
||||
<Unit filename="../../src/terrain_builder.hpp" />
|
||||
<Unit filename="../../src/callable_objects.cpp" />
|
||||
<Unit filename="../../src/callable_objects.hpp" />
|
||||
<Unit filename="../../src/campaign_server/campaign_server.cpp" />
|
||||
|
@ -753,6 +751,7 @@
|
|||
<Unit filename="../../src/lua/lzio.h" />
|
||||
<Unit filename="../../src/lua_jailbreak_exception.cpp" />
|
||||
<Unit filename="../../src/lua_jailbreak_exception.hpp" />
|
||||
<Unit filename="../../src/make_enum.hpp" />
|
||||
<Unit filename="../../src/map.cpp" />
|
||||
<Unit filename="../../src/map.hpp" />
|
||||
<Unit filename="../../src/map_exception.hpp" />
|
||||
|
@ -948,6 +947,8 @@
|
|||
<Unit filename="../../src/team.hpp" />
|
||||
<Unit filename="../../src/terrain.cpp" />
|
||||
<Unit filename="../../src/terrain.hpp" />
|
||||
<Unit filename="../../src/terrain_builder.cpp" />
|
||||
<Unit filename="../../src/terrain_builder.hpp" />
|
||||
<Unit filename="../../src/terrain_filter.cpp" />
|
||||
<Unit filename="../../src/terrain_filter.hpp" />
|
||||
<Unit filename="../../src/terrain_translation.cpp" />
|
||||
|
|
|
@ -788,6 +788,7 @@
|
|||
<Unit filename="..\..\src\lua\lzio.h" />
|
||||
<Unit filename="..\..\src\lua_jailbreak_exception.cpp" />
|
||||
<Unit filename="..\..\src\lua_jailbreak_exception.hpp" />
|
||||
<Unit filename="..\..\src\make_enum.hpp" />
|
||||
<Unit filename="..\..\src\map.cpp" />
|
||||
<Unit filename="..\..\src\map.hpp" />
|
||||
<Unit filename="..\..\src\map_exception.hpp" />
|
||||
|
|
|
@ -3384,7 +3384,8 @@
|
|||
<File Name="../../src/tests/test_config.cpp"/>
|
||||
<File Name="../../src/tests/test_config_cache.cpp"/>
|
||||
<File Name="../../src/tests/test_lexical_cast.cpp"/>
|
||||
<File Name="../../src/tests/map_location.cpp"/>
|
||||
<File Name="../../src/tests/test_make_enum.cpp"/>
|
||||
<File Name="../../src/tests/test_map_location.cpp"/>
|
||||
<File Name="../../src/tests/test_mp_connect.cpp"/>
|
||||
<File Name="../../src/tests/test_network_worker.cpp"/>
|
||||
<File Name="../../src/tests/test_sdl_utils.hpp"/>
|
||||
|
@ -4424,6 +4425,7 @@
|
|||
<File Name="../../src/terrain_translation.hpp"/>
|
||||
<File Name="../../src/game_errors.hpp"/>
|
||||
<File Name="../../src/cavegen.cpp"/>
|
||||
<File Name="../../src/make_enum.hpp"/>
|
||||
<File Name="../../src/map.cpp"/>
|
||||
<File Name="../../src/preferences_display.hpp"/>
|
||||
<File Name="../../src/statistics_dialog.hpp"/>
|
||||
|
|
|
@ -16555,6 +16555,62 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\tests\test_make_enum.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\Tests\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\Tests\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug_with_VLD|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\Tests\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Test_Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\Tests\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Test_Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\Tests\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="ReleaseDEBUG|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\Tests\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\tests\test_map_location.cpp"
|
||||
>
|
||||
|
@ -20182,6 +20238,10 @@
|
|||
RelativePath="..\..\src\lua_jailbreak_exception.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\make_enum.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\map.cpp"
|
||||
>
|
||||
|
|
|
@ -1257,6 +1257,7 @@ if(ENABLE_TESTS)
|
|||
tests/test_image_modifications.cpp
|
||||
tests/test_lexical_cast.cpp
|
||||
tests/test_map_location.cpp
|
||||
tests/test_make_enum.cpp
|
||||
tests/test_mp_connect.cpp
|
||||
tests/test_network_worker.cpp
|
||||
tests/test_sdl_utils.cpp
|
||||
|
|
|
@ -663,6 +663,7 @@ test_sources = Split("""
|
|||
tests/test_image_modifications.cpp
|
||||
tests/test_lexical_cast.cpp
|
||||
tests/test_map_location.cpp
|
||||
tests/test_make_enum.cpp
|
||||
tests/test_mp_connect.cpp
|
||||
tests/test_network_worker.cpp
|
||||
tests/test_sdl_utils.cpp
|
||||
|
|
212
src/make_enum.hpp
Normal file
212
src/make_enum.hpp
Normal file
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
Copyright (C) 2014 by Chris Beck <render787@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
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.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
// Defines the MAKE_ENUM macro,
|
||||
// and companion macro MAKE_ENUM_STREAM_OPS, which also enables lexical_cast
|
||||
// Currently this has 1 argument and 2 argument variety.
|
||||
|
||||
/**
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
namespace foo {
|
||||
|
||||
MAKE_ENUM(enumname,
|
||||
(con1, name1)
|
||||
(con2, name2)
|
||||
(con3, name3)
|
||||
)
|
||||
|
||||
MAKE_ENUM_STREAM_OPS1(enumname)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class bar {
|
||||
public:
|
||||
|
||||
MAKE_ENUM(another,
|
||||
(val1, name1)
|
||||
(val2, name2)
|
||||
(val3, name3)
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
MAKE_ENUM_STREAM_OPS2(bar , another)
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* What it does:
|
||||
*
|
||||
* generates an enum foo::enumname, with functions to convert to and from string
|
||||
*
|
||||
*
|
||||
* foo::string_to_enumname(std::string); //throws bad_enum_cast
|
||||
* foo::string_to_enumname(std::string, foo::enumname default); //no throw
|
||||
* foo::enumname_to_string(foo::enumname); //no throw
|
||||
*
|
||||
* The stream ops define
|
||||
* std::ostream & operator<< (std::ostream &, foo::enumname)
|
||||
* std::istream & operator>> (std::istream &, foo::enumname &)
|
||||
*
|
||||
* In case of a bad string -> enum conversion from istream output,
|
||||
* the istream will have its fail bit set.
|
||||
* This means that lexical_casts will throw a bad_lexical_cast,
|
||||
* in the similar scenario.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* For example code, see src/tests/test_make_enum.cpp
|
||||
*
|
||||
**/
|
||||
|
||||
#ifndef MAKE_ENUM_HPP
|
||||
#define MAKE_ENUM_HPP
|
||||
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
|
||||
class bad_enum_cast : public std::exception
|
||||
{
|
||||
public:
|
||||
bad_enum_cast(const std::string& enumname, const std::string str)
|
||||
: message("Failed to convert String \"" + str + "\" to type " + enumname)
|
||||
{}
|
||||
|
||||
virtual ~bad_enum_cast() throw() {}
|
||||
|
||||
const char * what() const throw()
|
||||
{
|
||||
return message.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string message;
|
||||
};
|
||||
|
||||
|
||||
#define CAT2( A, B ) A ## B
|
||||
#define CAT3( A, B, C ) A ## B ## C
|
||||
|
||||
//Clang apparently doesn't support __VA_ARGS__ with --C98 (???)
|
||||
//Can try this again when we upgrade
|
||||
/*
|
||||
#define GET_COUNT(_1, _2, _3, _4, _5, COUNT, ...) COUNT
|
||||
#define VA_SIZE(...) GET_COUNT(__VA_ARGS__, 5, 4, 3, 2, 1)
|
||||
|
||||
#define VA_SELECT(MNAME, ...) CAT2(MNAME, VA_SIZE(__VA_ARGS__) )(__VA_ARGS__)
|
||||
*/
|
||||
|
||||
|
||||
#define EXPANDENUMVALUE( a, b ) a ,
|
||||
#define EXPANDENUMTYPE( r, data, elem ) EXPANDENUMVALUE elem
|
||||
|
||||
#define EXPANDENUMFUNCTIONRETURN( a, b ) if ( str == b ) return a;
|
||||
#define EXPANDENUMFUNCTION( r, data, elem ) EXPANDENUMFUNCTIONRETURN elem
|
||||
|
||||
#define EXPANDENUMFUNCTIONREVRETURN( a, b ) if ( val == a ) return b;
|
||||
#define EXPANDENUMFUNCTIONREV( r, data, elem ) EXPANDENUMFUNCTIONREVRETURN elem
|
||||
|
||||
#define ADD_PAREN_1( A, B ) ((A, B)) ADD_PAREN_2
|
||||
#define ADD_PAREN_2( A, B ) ((A, B)) ADD_PAREN_1
|
||||
#define ADD_PAREN_1_END
|
||||
#define ADD_PAREN_2_END
|
||||
#define MAKEPAIRS( INPUT ) BOOST_PP_CAT(ADD_PAREN_1 INPUT,_END)
|
||||
|
||||
#define MAKEENUMTYPE( NAME, CONTENT ) \
|
||||
enum NAME { \
|
||||
BOOST_PP_SEQ_FOR_EACH(EXPANDENUMTYPE, , MAKEPAIRS(CONTENT)) \
|
||||
}; \
|
||||
|
||||
|
||||
#define MAKEENUMCAST( NAME, PREFIX, CONTENT ) \
|
||||
PREFIX NAME CAT3(string_to_, NAME, _default) (const std::string& str, NAME def) \
|
||||
{ \
|
||||
BOOST_PP_SEQ_FOR_EACH(EXPANDENUMFUNCTION, , MAKEPAIRS(CONTENT)) \
|
||||
return def; \
|
||||
} \
|
||||
PREFIX NAME CAT2(string_to_,NAME) (const std::string& str) \
|
||||
{ \
|
||||
BOOST_PP_SEQ_FOR_EACH(EXPANDENUMFUNCTION, , MAKEPAIRS(CONTENT)) \
|
||||
throw bad_enum_cast( #NAME , str); \
|
||||
} \
|
||||
PREFIX std::string CAT2(NAME,_to_string) (NAME val) \
|
||||
{ \
|
||||
BOOST_PP_SEQ_FOR_EACH(EXPANDENUMFUNCTIONREV, , MAKEPAIRS(CONTENT)) \
|
||||
assert(false); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define MAKE_ENUM( NAME, CONTENT ) \
|
||||
MAKEENUMTYPE( NAME, CONTENT ) \
|
||||
MAKEENUMCAST( NAME, static , CONTENT )
|
||||
|
||||
#define MAKE_ENUM_STREAM_OPS1( NAME ) \
|
||||
inline std::ostream& operator<< (std::ostream & os, NAME val) \
|
||||
{ \
|
||||
os << CAT2(NAME,_to_string) ( val ); \
|
||||
return os; \
|
||||
} \
|
||||
inline std::istream& operator>> (std::istream & is, NAME & val) \
|
||||
{ \
|
||||
std::istream::sentry s(is, true); \
|
||||
if(!s) return is; \
|
||||
std::string temp; \
|
||||
is >> temp; \
|
||||
try { \
|
||||
val = CAT2(string_to_, NAME) ( temp ); \
|
||||
} catch (bad_enum_cast & e) { \
|
||||
is.setstate(std::ios::failbit); \
|
||||
} \
|
||||
return is; \
|
||||
} \
|
||||
|
||||
|
||||
#define MAKE_ENUM_STREAM_OPS2( NAMESPACE, NAME ) \
|
||||
inline std::ostream& operator<< (std::ostream & os, NAMESPACE::NAME val) \
|
||||
{ \
|
||||
os << CAT2(NAMESPACE::NAME,_to_string) ( val ); \
|
||||
return os; \
|
||||
} \
|
||||
inline std::istream& operator>> (std::istream & is, NAMESPACE::NAME & val) \
|
||||
{ \
|
||||
std::istream::sentry s(is, true); \
|
||||
if(!s) return is; \
|
||||
std::string temp; \
|
||||
is >> temp; \
|
||||
try { \
|
||||
val = CAT2(NAMESPACE::string_to_,NAME) ( temp ); \
|
||||
} catch (bad_enum_cast & e) {\
|
||||
is.setstate(std::ios::failbit); \
|
||||
} \
|
||||
return is; \
|
||||
} \
|
||||
|
||||
//Clang apparently doesn't support __VA_ARGS__ with --C98 (???)
|
||||
//Can try this again when we upgrade
|
||||
//#define MAKE_ENUM_STREAM_OPS VA_SELECT(MAKE_ENUM_STREAM_OPS, __VA_ARGS__)
|
||||
|
||||
|
||||
#endif
|
146
src/tests/test_make_enum.cpp
Normal file
146
src/tests/test_make_enum.cpp
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
Copyright (C) 2014 by Chris Beck <render787@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
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.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-test"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "make_enum.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace foo {
|
||||
|
||||
MAKE_ENUM(enumname,
|
||||
(con1, "name1")
|
||||
(con2, "name2")
|
||||
(con3, "name3")
|
||||
)
|
||||
|
||||
MAKE_ENUM_STREAM_OPS1(enumname)
|
||||
}
|
||||
|
||||
|
||||
//generates an enum foo::enumname with lexical casts
|
||||
/*
|
||||
namespace foo {
|
||||
enum enumname {con1, con2 ,con3}
|
||||
}
|
||||
|
||||
foo::enumname lexical_cast<std::string> ( std::string str ) throws bad_lexical_cast
|
||||
{
|
||||
...
|
||||
}
|
||||
*/
|
||||
|
||||
class bar {
|
||||
public:
|
||||
|
||||
MAKE_ENUM(another,
|
||||
(val1, "name1")
|
||||
(val2, "name2")
|
||||
(val3, "name3")
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
MAKE_ENUM_STREAM_OPS2(bar,another)
|
||||
|
||||
/** Tests begin **/
|
||||
|
||||
BOOST_AUTO_TEST_SUITE ( test_make_enum )
|
||||
|
||||
BOOST_AUTO_TEST_CASE ( test_make_enum_namespace )
|
||||
{
|
||||
foo::enumname e = foo::string_to_enumname_default("name2", foo::con1); //returns con2
|
||||
|
||||
BOOST_CHECK_EQUAL ( e, foo::con2 );
|
||||
|
||||
std::string str = foo::enumname_to_string(foo::con1); //returns "name1"
|
||||
|
||||
BOOST_CHECK_EQUAL ( str, "name1" );
|
||||
|
||||
std::string str2 = lexical_cast<std::string> (e); //returns "name2" since e is con2
|
||||
|
||||
BOOST_CHECK_EQUAL ( str2, "name2" );
|
||||
|
||||
bool threw_exception_when_it_wasnt_supposed_to = false;
|
||||
|
||||
try {
|
||||
e = lexical_cast<foo::enumname> ("name3"); //returns con3
|
||||
} catch (bad_lexical_cast & e) {
|
||||
//std::cerr << "enum lexical cast didn't work!" << std::endl;
|
||||
threw_exception_when_it_wasnt_supposed_to = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( !threw_exception_when_it_wasnt_supposed_to );
|
||||
|
||||
bool threw_exception_when_it_was_supposed_to = false;
|
||||
|
||||
try {
|
||||
e = lexical_cast<foo::enumname> ("name4"); //throw bad_lexical_cast
|
||||
} catch (bad_lexical_cast & e) {
|
||||
//std::cerr << "enum lexical cast worked!" << std::endl;
|
||||
threw_exception_when_it_was_supposed_to = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( threw_exception_when_it_was_supposed_to );
|
||||
|
||||
std::stringstream ss;
|
||||
ss << e;
|
||||
BOOST_CHECK_EQUAL (ss.str(), "name3");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE ( test_make_enum_class )
|
||||
{
|
||||
bar::another e = bar::string_to_another_default("name2", bar::val1); //returns val2
|
||||
|
||||
BOOST_CHECK_EQUAL ( e, bar::val2 );
|
||||
|
||||
std::string str = bar::another_to_string(bar::val1); //returns "name1"
|
||||
|
||||
BOOST_CHECK_EQUAL ( str, "name1" );
|
||||
|
||||
std::string str2 = lexical_cast<std::string> (e); //returns "name2" since e is val2
|
||||
|
||||
BOOST_CHECK_EQUAL ( str2, "name2" );
|
||||
|
||||
bool threw_exception_when_it_wasnt_supposed_to = false;
|
||||
|
||||
try {
|
||||
e = lexical_cast<bar::another> ("name3"); //returns val3
|
||||
} catch (bad_lexical_cast & e) {
|
||||
//std::cerr << "enum lexical cast didn't work!" << std::endl;
|
||||
threw_exception_when_it_wasnt_supposed_to = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( !threw_exception_when_it_wasnt_supposed_to );
|
||||
|
||||
bool threw_exception_when_it_was_supposed_to = false;
|
||||
|
||||
try {
|
||||
e = lexical_cast<bar::another> ("name4"); //throw bad_lexical_cast
|
||||
} catch (bad_lexical_cast & e) {
|
||||
//std::cerr << "enum lexical cast worked!" << std::endl;
|
||||
threw_exception_when_it_was_supposed_to = true;
|
||||
}
|
||||
|
||||
BOOST_CHECK( threw_exception_when_it_was_supposed_to );
|
||||
|
||||
std::stringstream ss;
|
||||
ss << e;
|
||||
BOOST_CHECK_EQUAL (ss.str(), "name3");
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Add table
Reference in a new issue