First commit of STRINGIFY_ENUM

This commit is contained in:
Phil nash
2019-04-04 15:55:46 +01:00
parent 08147a23f9
commit 43428c6093
16 changed files with 587 additions and 8 deletions

View File

@@ -0,0 +1,68 @@
/*
* Created by Phil on 4/4/2019.
* Copyright 2019 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_enum_values_registry.h"
#include "catch_string_manip.h"
#include "catch_stream.h"
#include <map>
namespace Catch {
IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {}
IEnumInfo::~IEnumInfo() {}
namespace Detail {
std::vector<std::string> parseEnums( StringRef enums ) {
auto enumValues = splitString( enums, ',' );
std::vector<std::string> parsed;
parsed.reserve( enumValues.size() );
for( auto const& enumValue : enumValues ) {
auto identifiers = splitString( enumValue, ':' );
parsed.push_back( Catch::trim( identifiers.back() ) );
}
return parsed;
}
struct EnumInfo : IEnumInfo {
std::string m_name;
std::map<int, std::string> m_values;
~EnumInfo();
std::string lookup( int value ) const override {
auto it = m_values.find( value );
if( it == m_values.end() ) {
ReusableStringStream rss;
rss << "{** unexpected value for " << m_name << ": " << value << "**}";
return rss.str();
}
return it->second;
}
};
EnumInfo::~EnumInfo() {}
IEnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
std::unique_ptr<EnumInfo> enumInfo( new EnumInfo );
enumInfo->m_name = enumName;
const auto valueNames = Catch::Detail::parseEnums( allValueNames );
assert( valueNames.size() == values.size() );
std::size_t i = 0;
for( auto value : values )
enumInfo->m_values.insert({ value, valueNames[i++] });
EnumInfo* raw = enumInfo.get();
m_enumInfos.push_back( std::move( enumInfo ) );
return *raw;
}
} // Detail
} // Catch

View File

@@ -0,0 +1,32 @@
/*
* Created by Phil on 4/4/2019.
* Copyright 2019 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_ENUMVALUESREGISTRY_H_INCLUDED
#define TWOBLUECUBES_CATCH_ENUMVALUESREGISTRY_H_INCLUDED
#include "catch_interfaces_enum_values_registry.h"
#include <vector>
namespace Catch {
namespace Detail {
class EnumValuesRegistry : public IMutableEnumValuesRegistry {
std::vector<std::unique_ptr<IEnumInfo>> m_enumInfos;
IEnumInfo const& registerEnum(StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;
};
std::vector<std::string> parseEnums( StringRef enums );
} // Detail
} // Catch
#endif //TWOBLUECUBES_CATCH_ENUMVALUESREGISTRY_H_INCLUDED

View File

@@ -0,0 +1,40 @@
/*
* Created by Phil on 4/4/2019.
* Copyright 2019 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_INTERFACESENUMVALUESREGISTRY_H_INCLUDED
#define TWOBLUECUBES_CATCH_INTERFACESENUMVALUESREGISTRY_H_INCLUDED
#include "catch_stringref.h"
#include <vector>
namespace Catch {
struct IEnumInfo {
virtual ~IEnumInfo();
virtual std::string lookup( int value ) const = 0;
};
struct IMutableEnumValuesRegistry {
virtual ~IMutableEnumValuesRegistry();
virtual IEnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
template<typename E>
IEnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
std::vector<int> intValues;
intValues.reserve( values.size() );
for( auto enumValue : values )
intValues.push_back( static_cast<int>( enumValue ) );
return registerEnum( enumName, allEnums, intValues );
}
};
} // Catch
#endif //TWOBLUECUBES_CATCH_INTERFACESENUMVALUESREGISTRY_H_INCLUDED

View File

@@ -22,6 +22,8 @@ namespace Catch {
struct IReporterRegistry;
struct IReporterFactory;
struct ITagAliasRegistry;
struct IMutableEnumValuesRegistry;
class StartupExceptionRegistry;
using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
@@ -32,7 +34,6 @@ namespace Catch {
virtual IReporterRegistry const& getReporterRegistry() const = 0;
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
@@ -47,6 +48,7 @@ namespace Catch {
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
virtual void registerStartupException() noexcept = 0;
virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
};
IRegistryHub const& getRegistryHub();

View File

@@ -15,6 +15,7 @@
#include "catch_tag_alias_registry.h"
#include "catch_startup_exception_registry.h"
#include "catch_singletons.hpp"
#include "catch_enum_values_registry.h"
namespace Catch {
@@ -60,6 +61,9 @@ namespace Catch {
void registerStartupException() noexcept override {
m_exceptionRegistry.add(std::current_exception());
}
IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
return m_enumValuesRegistry;
}
private:
TestRegistry m_testCaseRegistry;
@@ -67,6 +71,7 @@ namespace Catch {
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
TagAliasRegistry m_tagAliasRegistry;
StartupExceptionRegistry m_exceptionRegistry;
Detail::EnumValuesRegistry m_enumValuesRegistry;
};
}

View File

@@ -6,11 +6,13 @@
*/
#include "catch_string_manip.h"
#include "catch_stringref.h"
#include <algorithm>
#include <ostream>
#include <cstring>
#include <cctype>
#include <vector>
namespace Catch {
@@ -65,6 +67,21 @@ namespace Catch {
return replaced;
}
std::vector<std::string> splitString( StringRef str, char delimiter ) {
std::vector<std::string> subStrings;
std::size_t start = 0;
for(std::size_t pos = 0; pos < str.size(); ++pos ) {
if( str[pos] == delimiter ) {
if( pos - start > 1 )
subStrings.push_back( str.substr( start, pos-start ) );
start = pos+1;
}
}
if( start < str.size() )
subStrings.push_back( str.substr( start, str.size()-start ) );
return subStrings;
}
pluralise::pluralise( std::size_t count, std::string const& label )
: m_count( count ),
m_label( label )

View File

@@ -12,6 +12,8 @@
namespace Catch {
class StringRef;
bool startsWith( std::string const& s, std::string const& prefix );
bool startsWith( std::string const& s, char prefix );
bool endsWith( std::string const& s, std::string const& suffix );
@@ -21,6 +23,7 @@ namespace Catch {
std::string toLower( std::string const& s );
std::string trim( std::string const& str );
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
std::vector<std::string> splitString( StringRef str, char delimiter );
struct pluralise {
pluralise( std::size_t count, std::string const& label );

View File

@@ -15,6 +15,7 @@
#include <string>
#include "catch_compiler_capabilities.h"
#include "catch_stream.h"
#include "catch_interfaces_enum_values_registry.h"
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
#include <string_view>
@@ -639,6 +640,19 @@ struct ratio_string<std::milli> {
}
#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
#define INTERNAL_CATCH_STRINGIFY_ENUM( enumName, ... ) \
template<> struct ::Catch::StringMaker<enumName> { \
static std::string convert( enumName value ) { \
static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
return enumInfo.lookup( static_cast<int>( value ) ); \
} \
};
#ifdef CATCH_CONFIG_PREFIX_ALL
# define CATCH_STRINGIFY_ENUM( enumName, ... ) INTERNAL_CATCH_STRINGIFY_ENUM( enumName, __VA_ARGS__ )
#else
# define STRINGIFY_ENUM( enumName, ... ) INTERNAL_CATCH_STRINGIFY_ENUM( enumName, __VA_ARGS__ )
#endif
#ifdef _MSC_VER
#pragma warning(pop)