DynamicAny conversion limits

This commit is contained in:
Aleksandar Fabijanic 2007-04-25 01:11:49 +00:00
parent 109a6f47bd
commit f29f7cda53
4 changed files with 394 additions and 105 deletions

View File

@ -49,15 +49,30 @@ namespace Poco {
class Foundation_API DynamicAny
/// A DynamicAny allows to store data of different types and to convert between these types transparently.
/// It's the reponsibility of the programmer to ensure that conversions are meaningful.
/// For example: it is possible to convert between string and character. An empty string gets converted to
/// the char '\0', a non-empty string gets truncated to the very first character. Numeric values are truncated,
/// no overflow/underflow errors are checked. A string value "false" can be converted to a boolean value false,
/// any other string not "false" (not case sensitive) or "0" to true (e.g: "hi" -> true).
/// DynamicAny allows to store data of different types and to convert between these types transparently.
/// DynamicAny puts forth the best effort to provide intuitive and reasonable conversion semantics and prevent
/// unexpected data loss, particularly when performing narrowing or signedness conversions of numeric data types.
///
/// A DynamicAny can be created from a value of any type for which a
/// specialization of DynamicAnyHolderImpl is available.
/// Loss of signedness is not allowed for numeric values. This means that if an attempt is made to convert
/// the internal value which is a negative signed integer to an unsigned integer type storage, a RangeException is thrown.
/// Overflow is not allowed, so if the internal value is a larger number than the target numeric type size can accomodate,
/// a RangeException is thrown.
///
/// Precision loss, such as in conversion from floating-point types to integers or from double to float on platforms
/// where they differ in size (provided internal actual value fits in float min/max range), is allowed.
///
/// String truncation is allowed - it is possible to convert between string and character when string length is
/// greater than 1. An empty string gets converted to the char '\0', a non-empty string is truncated to the first character.
///
/// Bolean conversion are performed as follows:
///
/// A string value "false" (not case sensitive) or "0" can be converted to a boolean value false, any other string
/// not being false by the above criteria evaluates to true (e.g: "hi" -> true).
/// Integer 0 values are false, everything else is true.
/// Floating point values equal to the minimal FP representation on a given platform are false, everything else is true.
///
/// A DynamicAny can be created from and converted to a value of any type for which a specialization of
/// DynamicAnyHolderImpl is available. For supported types, see DynamicAnyHolder documentation.
{
public:
DynamicAny();

View File

@ -46,15 +46,46 @@
#include "Poco/String.h"
#include "Poco/Exception.h"
#include <typeinfo>
#include <limits>
///BEGIN ported from boost
/// following macros were ported from boost to help the DynamicAnyHolder development
/// for complete multi-platform code, see static_assert.hpp in boost libraries
// Helper macro POCO_JOIN:
// The following piece of macro magic joins the two
// arguments together, even when one of the arguments is
// itself a macro (see 16.3.1 in C++ standard). The key
// is that macro expansion of macro arguments does not
// occur in POCO_DO_JOIN2 but does in POCO_DO_JOIN.
//
#define POCO_JOIN(X, Y) POCO_DO_JOIN( X, Y )
#define POCO_DO_JOIN(X, Y) POCO_DO_JOIN2(X,Y)
#define POCO_DO_JOIN2(X, Y) X##Y
template <bool x> struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
template<int x> struct static_assert_test{};
#if defined(__GNUC__) && (__GNUC__ == 3) && ((__GNUC_MINOR__ == 3) || (__GNUC_MINOR__ == 4))
# define poco_static_assert( B ) \
typedef char POCO_JOIN(poco_static_assert_typedef_, __LINE__) \
[ STATIC_ASSERTION_FAILURE< (bool)(B) >::value ]
#else
# define poco_static_assert(B) \
typedef static_assert_test<sizeof(STATIC_ASSERTION_FAILURE<(bool)(B)>)> poco_static_assert_typedef_
#endif
///END ported from boost
namespace Poco {
class Foundation_API DynamicAnyHolder
/// Interface for a data holder used by the DynamicAny class. Provides methods to convert between data types.
/// Interface for a data holder used by the DynamicAny class.
/// Provides methods to convert between data types.
/// Only data types for which a convert method exists are supported, which are
/// all C++ built-in types, along with std::string.
/// all C++ built-in types with addition of std::string.
{
public:
DynamicAnyHolder();
@ -88,6 +119,91 @@ public:
virtual void convert(double& val) const = 0;
virtual void convert(char& val) const = 0;
virtual void convert(std::string& val) const = 0;
protected:
template <typename F, typename T>
void convertToSmaller(const F& from, T& to) const
/// This function is meant to convert signed integral values from
/// larger to smaller type. It checks the upper and lower bound and
/// if from value is within limits of type T (i.e. check calls do not throw),
/// it is converted.
{
poco_static_assert (std::numeric_limits<F>::is_specialized);
poco_static_assert (std::numeric_limits<T>::is_specialized);
poco_static_assert (std::numeric_limits<F>::is_signed);
poco_static_assert (std::numeric_limits<T>::is_signed);
checkUpperLimit(from, to);
checkLowerLimit(from, to);
to = static_cast<T>(from);
}
template <typename F, typename T>
void convertToSmallerUnsigned(const F& from, T& to) const
/// This function is meant for converting unsigned integral data types,
/// from larger to smaller type. Since lower limit is always 0 for unigned types,
/// only the upper limit is checked, thus saving some cycles compared to the signed
/// version of the function. If the value to be converted is smaller than
/// the maximum value for the target type, the conversion is performed.
{
poco_static_assert (std::numeric_limits<F>::is_specialized);
poco_static_assert (std::numeric_limits<T>::is_specialized);
poco_static_assert (!std::numeric_limits<F>::is_signed);
poco_static_assert (!std::numeric_limits<T>::is_signed);
checkUpperLimit(from, to);
to = static_cast<T>(from);
}
template <typename F, typename T>
void convertSignedToUnsigned(const F& from, T& to) const
/// This function is meant for converting signed integral data types to
/// unsigned data types. Negative values can not be converted and if one is
/// encountered, RangeException is thrown.
/// If uper limit is within the target data type limits, the converiosn is performed.
{
poco_static_assert (std::numeric_limits<F>::is_specialized);
poco_static_assert (std::numeric_limits<T>::is_specialized);
poco_static_assert (std::numeric_limits<F>::is_signed);
poco_static_assert (!std::numeric_limits<T>::is_signed);
if (from < 0)
throw RangeException("Value too small.");
checkUpperLimit(from, to);
to = static_cast<T>(from);
}
template <typename F, typename T>
void convertUnsignedToSigned(const F& from, T& to) const
/// This function is meant for converting unsigned integral data types to
/// unsigned data types. Negative values can not be converted and if one is
/// encountered, RangeException is thrown.
/// If uper limit is within the target data type limits, the converiosn is performed.
{
poco_static_assert (std::numeric_limits<F>::is_specialized);
poco_static_assert (std::numeric_limits<T>::is_specialized);
poco_static_assert (!std::numeric_limits<F>::is_signed);
poco_static_assert (std::numeric_limits<T>::is_signed);
checkUpperLimit(from, to);
to = static_cast<T>(from);
}
private:
template <typename F, typename T>
void checkUpperLimit(const F& from, T& to) const
{
if (from > std::numeric_limits<T>::max())
throw RangeException("Value too large.");
}
template <typename F, typename T>
void checkLowerLimit(const F& from, T& to) const
{
if (from < std::numeric_limits<T>::min())
throw RangeException("Value too small.");
}
};
@ -119,6 +235,11 @@ class DynamicAnyHolderImpl: public DynamicAnyHolder
///
/// DynamicAny can be used for any type for which a specialization for
/// DynamicAnyHolderImpl is available.
///
/// DynamicAnyHolderImpl throws following exceptions:
/// NotImplementedException (if the specialization for a type does not exist)
/// RangeException (if an attempt is made to assign a numeric value outside of the target min/max limits
/// SyntaxException (if an attempt is made to convert a string containing non-numeric characters to number)
{
DynamicAnyHolderImpl()
{
@ -245,22 +366,22 @@ public:
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt32& val) const
{
val = static_cast<UInt32>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt64& val) const
{
val = static_cast<UInt64>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(bool& val) const
@ -318,7 +439,7 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertToSmaller(_val, val);
}
void convert(Int16& val) const
@ -338,22 +459,22 @@ public:
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt32& val) const
{
val = static_cast<UInt32>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt64& val) const
{
val = static_cast<UInt64>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(bool& val) const
@ -373,7 +494,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertToSmaller(_val, val);
}
void convert(std::string& val) const
@ -410,12 +531,12 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertToSmaller(_val, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(_val);
convertToSmaller(_val, val);
}
void convert(Int32& val) const
@ -430,22 +551,22 @@ public:
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt32& val) const
{
val = static_cast<UInt32>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt64& val) const
{
val = static_cast<UInt64>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(bool& val) const
@ -465,7 +586,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertToSmaller(_val, val);
}
void convert(std::string& val) const
@ -502,17 +623,17 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertToSmaller(_val, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(_val);
convertToSmaller(_val, val);
}
void convert(Int32& val) const
{
val = static_cast<Int32>(_val);
convertToSmaller(_val, val);
}
void convert(Int64& val) const
@ -522,22 +643,22 @@ public:
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt32& val) const
{
val = static_cast<UInt32>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt64& val) const
{
val = static_cast<UInt64>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(bool& val) const
@ -557,7 +678,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertToSmaller(_val, val);
}
void convert(std::string& val) const
@ -594,12 +715,12 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int32& val) const
@ -649,7 +770,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(std::string& val) const
@ -686,17 +807,17 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int32& val) const
{
val = static_cast<Int32>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int64& val) const
@ -706,7 +827,7 @@ public:
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertToSmallerUnsigned(_val, val);
}
void convert(UInt16& val) const
@ -741,7 +862,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(std::string& val) const
@ -778,32 +899,32 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int32& val) const
{
val = static_cast<Int32>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int64& val) const
{
val = static_cast<Int64>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertToSmallerUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertToSmallerUnsigned(_val, val);
}
void convert(UInt32& val) const
@ -833,7 +954,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(std::string& val) const
@ -870,37 +991,37 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int32& val) const
{
val = static_cast<Int32>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int64& val) const
{
val = static_cast<Int64>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertToSmallerUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertToSmallerUnsigned(_val, val);
}
void convert(UInt32& val) const
{
val = static_cast<UInt32>(_val);
convertToSmallerUnsigned(_val, val);
}
void convert(UInt64& val) const
@ -925,7 +1046,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(std::string& val) const
@ -1054,47 +1175,48 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertToSmaller(_val, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(_val);
convertToSmaller(_val, val);
}
void convert(Int32& val) const
{
val = static_cast<Int32>(_val);
convertToSmaller(_val, val);
}
void convert(Int64& val) const
{
val = static_cast<Int64>(_val);
convertToSmaller(_val, val);
}
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt32& val) const
{
val = static_cast<UInt32>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt64& val) const
{
val = static_cast<UInt64>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(bool& val) const
{
val = !(_val < 0.0001f && _val > -0.0001f);
val = !(_val <= std::numeric_limits<float>::min() &&
_val >= -1 * std::numeric_limits<float>::min());
}
void convert(float& val) const
@ -1109,7 +1231,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertToSmaller(_val, val);
}
void convert(std::string& val) const
@ -1146,51 +1268,58 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertToSmaller(_val, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(_val);
convertToSmaller(_val, val);
}
void convert(Int32& val) const
{
val = static_cast<Int32>(_val);
convertToSmaller(_val, val);
}
void convert(Int64& val) const
{
val = static_cast<Int64>(_val);
convertToSmaller(_val, val);
}
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt32& val) const
{
val = static_cast<UInt32>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt64& val) const
{
val = static_cast<UInt64>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(bool& val) const
{
val = !(_val < 0.0001 && _val > -0.0001);
val = !(_val <= std::numeric_limits<double>::min() &&
_val >= -1 * std::numeric_limits<double>::min());
}
void convert(float& val) const
{
double fMin = -1 * std::numeric_limits<float>::max();
double fMax = std::numeric_limits<float>::max();
if (_val < fMin) throw RangeException("Value too small.");
if (_val > fMax) throw RangeException("Value too large.");
val = static_cast<float>(_val);
}
@ -1201,7 +1330,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertToSmaller(_val, val);
}
void convert(std::string& val) const
@ -1258,22 +1387,22 @@ public:
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt32& val) const
{
val = static_cast<UInt32>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt64& val) const
{
val = static_cast<UInt64>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(bool& val) const
@ -1334,12 +1463,14 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(NumberParser::parse(_val));
int v = NumberParser::parse(_val);
convertToSmaller(v, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(NumberParser::parse(_val));
int v = NumberParser::parse(_val);
convertToSmaller(v, val);
}
void convert(Int32& val) const
@ -1354,12 +1485,14 @@ public:
void convert(UInt8& val) const
{
val = static_cast<UInt8>(NumberParser::parseUnsigned(_val));
unsigned int v = NumberParser::parseUnsigned(_val);
convertToSmallerUnsigned(v, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(NumberParser::parseUnsigned(_val));
unsigned int v = NumberParser::parseUnsigned(_val);
convertToSmallerUnsigned(v, val);
}
void convert(UInt32& val) const
@ -1385,7 +1518,8 @@ public:
void convert(float& val) const
{
val = static_cast<float>(NumberParser::parseFloat(_val));
double v = NumberParser::parseFloat(_val);
convertToSmaller(v, val);
}
void convert(double& val) const
@ -1438,12 +1572,12 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertToSmaller(_val, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(_val);
convertToSmaller(_val, val);
}
void convert(Int32& val) const
@ -1458,22 +1592,22 @@ public:
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt32& val) const
{
val = static_cast<UInt32>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(UInt64& val) const
{
val = static_cast<UInt64>(_val);
convertSignedToUnsigned(_val, val);
}
void convert(bool& val) const
@ -1493,7 +1627,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertToSmaller(_val, val);
}
void convert(std::string& val) const
@ -1530,37 +1664,37 @@ public:
void convert(Int8& val) const
{
val = static_cast<Int8>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int16& val) const
{
val = static_cast<Int16>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int32& val) const
{
val = static_cast<Int32>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(Int64& val) const
{
val = static_cast<Int64>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(UInt8& val) const
{
val = static_cast<UInt8>(_val);
convertToSmallerUnsigned(_val, val);
}
void convert(UInt16& val) const
{
val = static_cast<UInt16>(_val);
convertToSmallerUnsigned(_val, val);
}
void convert(UInt32& val) const
{
val = static_cast<UInt32>(_val);
convertToSmallerUnsigned(_val, val);
}
void convert(UInt64& val) const
@ -1585,7 +1719,7 @@ public:
void convert(char& val) const
{
val = static_cast<char>(_val);
convertUnsignedToSigned(_val, val);
}
void convert(std::string& val) const

View File

@ -38,7 +38,6 @@
#include "Poco/Bugcheck.h"
using namespace Poco;
@ -940,11 +939,91 @@ void DynamicAnyTest::testConversionOperator()
assert (i == 42);
any = 123;
std::string s(any);
std::string s = any;//'s(any)' bombs on gcc 3.4.4
assert (s == "123");
}
void DynamicAnyTest::testLimitsInt()
{
testLimitsSigned<Int16, Int8>();
testLimitsSigned<Int32, Int8>();
testLimitsSigned<Int64, Int8>();
testLimitsFloatToInt<float, Int8>();
testLimitsFloatToInt<double, Int8>();
testLimitsSigned<Int16, char>();
testLimitsSigned<Int32, char>();
testLimitsSigned<Int64, char>();
testLimitsFloatToInt<float, char>();
testLimitsFloatToInt<double, char>();
testLimitsSigned<Int32, Int16>();
testLimitsSigned<Int64, Int16>();
testLimitsFloatToInt<float, Int16>();
testLimitsFloatToInt<double, Int16>();
testLimitsSigned<Int64, Int32>();
testLimitsFloatToInt<float, Int32>();
testLimitsFloatToInt<double, Int32>();
testLimitsSignedUnsigned<Int8, UInt8>();
testLimitsSignedUnsigned<Int16, UInt8>();
testLimitsSignedUnsigned<Int32, UInt8>();
testLimitsSignedUnsigned<Int64, UInt8>();
testLimitsFloatToInt<float, UInt8>();
testLimitsFloatToInt<double, UInt8>();
testLimitsSignedUnsigned<Int8, UInt16>();
testLimitsSignedUnsigned<Int16, UInt16>();
testLimitsSignedUnsigned<Int32, UInt16>();
testLimitsSignedUnsigned<Int64, UInt16>();
testLimitsFloatToInt<float, UInt16>();
testLimitsFloatToInt<double, UInt16>();
testLimitsSignedUnsigned<Int8, UInt32>();
testLimitsSignedUnsigned<Int16, UInt32>();
testLimitsSignedUnsigned<Int32, UInt32>();
testLimitsSignedUnsigned<Int64, UInt32>();
testLimitsFloatToInt<float, UInt32>();
testLimitsFloatToInt<double, UInt32>();
testLimitsSignedUnsigned<Int8, UInt64>();
testLimitsSignedUnsigned<Int16, UInt64>();
testLimitsSignedUnsigned<Int32, UInt64>();
testLimitsSignedUnsigned<Int64, UInt64>();
testLimitsFloatToInt<float, UInt64>();
testLimitsFloatToInt<double, UInt64>();
testLimitsUnsigned<UInt16, UInt8>();
testLimitsUnsigned<UInt32, UInt8>();
testLimitsUnsigned<UInt64, UInt8>();
testLimitsUnsigned<UInt32, UInt16>();
testLimitsUnsigned<UInt64, UInt16>();
testLimitsUnsigned<UInt64, UInt32>();
}
void DynamicAnyTest::testLimitsFloat()
{
if (std::numeric_limits<double>::max() != std::numeric_limits<float>::max())
{
double iMin = -1 * std::numeric_limits<float>::max();
DynamicAny da = iMin * 10;
try { float f; f = da; fail("must fail"); }
catch (RangeException&) {}
double iMax = std::numeric_limits<float>::max();
da = iMax * 10;
try { float f; f = da; fail("must fail"); }
catch (RangeException&) {}
}
}
void DynamicAnyTest::setUp()
{
}
@ -975,6 +1054,8 @@ CppUnit::Test* DynamicAnyTest::suite()
CppUnit_addTest(pSuite, DynamicAnyTest, testLong);
CppUnit_addTest(pSuite, DynamicAnyTest, testULong);
CppUnit_addTest(pSuite, DynamicAnyTest, testConversionOperator);
CppUnit_addTest(pSuite, DynamicAnyTest, testLimitsInt);
CppUnit_addTest(pSuite, DynamicAnyTest, testLimitsFloat);
return pSuite;
}

View File

@ -36,6 +36,8 @@
#include "Poco/Foundation.h"
#include "Poco/DynamicAny.h"
#include "Poco/Exception.h"
#include "CppUnit/TestCase.h"
@ -61,10 +63,67 @@ public:
void testULong();
void testString();
void testConversionOperator();
void testLimitsInt();
void testLimitsFloat();
void setUp();
void tearDown();
static CppUnit::Test* suite();
private:
template<typename TL, typename TS>
void testLimitsSigned()
{
TL iMin = std::numeric_limits<TS>::min();
Poco::DynamicAny da = iMin - 1;
try { TS i; i = da; fail("must fail"); }
catch (Poco::RangeException&) {}
TL iMax = std::numeric_limits<TS>::max();
da = iMax + 1;
try { TS i; i = da; fail("must fail"); }
catch (Poco::RangeException&) {}
}
template<typename TL, typename TS>
void testLimitsFloatToInt()
{
Poco::DynamicAny da;
if (std::numeric_limits<TS>::is_signed)
{
TL iMin = static_cast<TL>(std::numeric_limits<TS>::min());
da = iMin * 10;
try { TS i; i = da; fail("must fail"); }
catch (Poco::RangeException&) {}
}
TL iMax = static_cast<TL>(std::numeric_limits<TS>::max());
da = iMax * 10;
try { TS i; i = da; fail("must fail"); }
catch (Poco::RangeException&) {}
}
template<typename TS, typename TU>
void testLimitsSignedUnsigned()
{
assert (std::numeric_limits<TS>::is_signed);
assert (!std::numeric_limits<TU>::is_signed);
TS iMin = std::numeric_limits<TS>::min();
Poco::DynamicAny da = iMin;
try { TU i; i = da; fail("must fail"); }
catch (Poco::RangeException&) {}
}
template<typename TL, typename TS>
void testLimitsUnsigned()
{
TL iMax = std::numeric_limits<TS>::max();
Poco::DynamicAny da = iMax + 1;
try { TS i; i = da; fail("must fail"); }
catch (Poco::RangeException&) {}
}
};