Skip to content

Commit

Permalink
Merge pull request #195 from CppMicroServices/181-improve-BadAnyCastE…
Browse files Browse the repository at this point in the history
…xception

Improve BadAnyCastException message
  • Loading branch information
saschazelzer committed May 18, 2017
2 parents cd078e8 + 6a6f093 commit cad87f9
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 7 deletions.
38 changes: 33 additions & 5 deletions framework/include/cppmicroservices/Any.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,22 @@ class BadAnyCastException : public std::bad_cast
std::string _msg;
};


namespace detail
{
/**
*
* A utility function used to throw a BadAnyCastException object
* containing an exception message containing the source and target type names.
*
* \param funcName The throwing function's name.
* \param anyTypeName A string representing the Any object's underlying type.
* \throws cppmicroservices::BadAnyCastException
*/
US_Framework_EXPORT void ThrowBadAnyCastException(const std::string& funcName, const std::type_info& source, const std::type_info& target);

}

/**
* \ingroup gr_any
*
Expand All @@ -469,7 +485,7 @@ ValueType* any_cast(Any* operand)
{
return operand && operand->Type() == typeid(ValueType)
? &static_cast<Any::Holder<ValueType>*>(operand->_content.get())->_held
: 0;
: nullptr;
}

/**
Expand Down Expand Up @@ -510,7 +526,10 @@ template <typename ValueType>
ValueType any_cast(const Any& operand)
{
ValueType* result = any_cast<ValueType>(const_cast<Any*>(&operand));
if (!result) throw BadAnyCastException("Failed to convert between const Any types");
if (!result)
{
detail::ThrowBadAnyCastException(std::string("any_cast"), operand.Type(), typeid(ValueType));
}
return *result;
}

Expand All @@ -534,7 +553,10 @@ template <typename ValueType>
ValueType any_cast(Any& operand)
{
ValueType* result = any_cast<ValueType>(&operand);
if (!result) throw BadAnyCastException("Failed to convert between Any types");
if (!result)
{
detail::ThrowBadAnyCastException(std::string("any_cast"), operand.Type(), typeid(ValueType));
}
return *result;
}

Expand All @@ -554,7 +576,10 @@ template <typename ValueType>
const ValueType& ref_any_cast(const Any & operand)
{
ValueType* result = any_cast<ValueType>(const_cast<Any*>(&operand));
if (!result) throw BadAnyCastException("RefAnyCast: Failed to convert between const Any types");
if (!result)
{
detail::ThrowBadAnyCastException(std::string("ref_any_cast"), operand.Type(), typeid(ValueType));
}
return *result;
}

Expand All @@ -574,7 +599,10 @@ template <typename ValueType>
ValueType& ref_any_cast(Any& operand)
{
ValueType* result = any_cast<ValueType>(&operand);
if (!result) throw BadAnyCastException("RefAnyCast: Failed to convert between Any types");
if (!result)
{
detail::ThrowBadAnyCastException(std::string("ref_any_cast"), operand.Type(), typeid(ValueType));
}
return *result;
}

Expand Down
14 changes: 14 additions & 0 deletions framework/src/util/Any.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,25 @@
=============================================================================*/

#include "cppmicroservices/Any.h"
#include "Utils.h"

#include <stdexcept>

namespace cppmicroservices {

namespace detail {

void ThrowBadAnyCastException(const std::string& funcName, const std::type_info& source, const std::type_info& target)
{
std::string msg("cppmicroservices::BadAnyCastException: ");
std::string targetTypeName(GetDemangledName(target));
std::string sourceTypeName(GetDemangledName(source));
msg += funcName + ": Failed to convert from cppmicroservices::Any type " + sourceTypeName + " to target type " + targetTypeName;
throw BadAnyCastException(msg);
}

}

std::ostream& any_value_to_string(std::ostream& os, const Any& any)
{
os << any.ToString();
Expand Down
7 changes: 5 additions & 2 deletions framework/src/util/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,11 @@ void TerminateForDebug(const std::exception_ptr ex)
#endif
}

US_Framework_EXPORT ::std::string detail::GetDemangledName(const ::std::type_info& typeInfo)
namespace detail
{
::std::string result;
std::string GetDemangledName(const std::type_info& typeInfo)
{
std::string result;
#ifdef US_HAVE_CXXABI_H
int status = 0;
char* demangled = abi::__cxa_demangle(typeInfo.name(), 0, 0, &status);
Expand Down Expand Up @@ -493,6 +495,7 @@ US_Framework_EXPORT ::std::string detail::GetDemangledName(const ::std::type_inf
#endif
return result;
}
}

US_MSVC_PUSH_DISABLE_WARNING(4715) // 'function' : not all control paths return a value
std::string GetExceptionStr(const std::exception_ptr& exc)
Expand Down
4 changes: 4 additions & 0 deletions framework/src/util/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ std::string GetCurrentWorkingDirectory();

void TerminateForDebug(const std::exception_ptr ex);

namespace detail {
US_Framework_EXPORT std::string GetDemangledName(const std::type_info& typeInfo);
}

//-------------------------------------------------------------------
// Error handling
//-------------------------------------------------------------------
Expand Down
39 changes: 39 additions & 0 deletions framework/test/AnyTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,45 @@ int AnyTest(int /*argc*/, char* /*argv*/[])
US_TEST_CONDITION(anyMap3.Type() == typeid(std::map<std::string, Any>), "Any[std::map<std::string,Any>].Type()")
US_TEST_CONDITION(anyMap3.ToString() == "{map : {1 : 0.3, 3 : bye}, number : 5, vector : [9,8,7]}", "Any[std::map<std::string,Any>].ToString()")
US_TEST_CONDITION(anyMap3.ToJSON() == "{\"map\" : {\"1\" : 0.3, \"3\" : \"bye\"}, \"number\" : 5, \"vector\" : [9,8,7]}", "Any[std::map<std::string,Any>].ToJSON()")

// Test BadAnyCastException exceptions
const Any uncastableConstAny(0.0);
Any uncastableAny(0.0);

US_TEST_FOR_EXCEPTION(cppmicroservices::BadAnyCastException, any_cast<std::string>(uncastableConstAny))

try
{
(void)any_cast<std::string>(uncastableConstAny);
}
catch (const cppmicroservices::BadAnyCastException& ex) { US_TEST_OUTPUT(<< ex.what()) }


US_TEST_FOR_EXCEPTION(cppmicroservices::BadAnyCastException, any_cast<std::string>(uncastableAny))

try
{
(void)any_cast<std::string>(uncastableAny);
}
catch (const cppmicroservices::BadAnyCastException& ex) { US_TEST_OUTPUT(<< ex.what()) }


US_TEST_FOR_EXCEPTION(cppmicroservices::BadAnyCastException, ref_any_cast<std::string>(uncastableConstAny))

try
{
(void)ref_any_cast<std::string>(uncastableConstAny);
}
catch (const cppmicroservices::BadAnyCastException& ex) { US_TEST_OUTPUT(<< ex.what()) }


US_TEST_FOR_EXCEPTION(cppmicroservices::BadAnyCastException, ref_any_cast<std::string>(uncastableAny))

try
{
(void)ref_any_cast<std::string>(uncastableAny);
}
catch (const cppmicroservices::BadAnyCastException& ex) { US_TEST_OUTPUT(<< ex.what()) }

US_TEST_END()
}

0 comments on commit cad87f9

Please sign in to comment.