diff options
author | Alan Conway <aconway@apache.org> | 2015-04-16 19:04:23 +0000 |
---|---|---|
committer | Alan Conway <aconway@apache.org> | 2015-04-16 19:04:23 +0000 |
commit | ea16e50919f21fbab181e20e25b03d1a314634c8 (patch) | |
tree | 59fc8ce516b7ad1e6b46b2f640b418cd9092f10c | |
parent | e7998631f9c479dd659f409f8e38c910e0028858 (diff) | |
download | qpid-python-ea16e50919f21fbab181e20e25b03d1a314634c8.tar.gz |
QPID-6470: Fix float conversion problems.
Previous code would incorrectly convert between float and int types producing nonsense values,
and would not allow legal conversions between float and double types.
Created FixedWidthIntValue and FixedWidthFloatValue template subclasses to correctly
handle conversions. Enabled FieldValue unit tests for float conversions.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1674137 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | qpid/cpp/src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/framing/Endian.cpp | 52 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/framing/Endian.h | 62 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/framing/FieldTable.cpp | 1 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/framing/FieldValue.cpp | 71 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/framing/FieldValue.h | 100 | ||||
-rw-r--r-- | qpid/cpp/src/tests/FieldTable.cpp | 8 | ||||
-rw-r--r-- | qpid/cpp/src/tests/FieldValue.cpp | 35 |
8 files changed, 167 insertions, 163 deletions
diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt index 86606107cc..8e2b5b73e8 100644 --- a/qpid/cpp/src/CMakeLists.txt +++ b/qpid/cpp/src/CMakeLists.txt @@ -777,7 +777,6 @@ set (qpidcommon_SOURCES qpid/framing/AMQHeartbeatBody.cpp qpid/framing/Array.cpp qpid/framing/Buffer.cpp - qpid/framing/Endian.cpp qpid/framing/FieldTable.cpp qpid/framing/FieldValue.cpp qpid/framing/FrameSet.cpp diff --git a/qpid/cpp/src/qpid/framing/Endian.cpp b/qpid/cpp/src/qpid/framing/Endian.cpp deleted file mode 100644 index decfe4b2d9..0000000000 --- a/qpid/cpp/src/qpid/framing/Endian.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -#include "qpid/framing/Endian.h" - -namespace qpid { -namespace framing { - -Endian::Endian() : littleEndian(!testBigEndian()) {} - -bool Endian::testBigEndian() -{ - uint16_t a = 1; - uint16_t b; - uint8_t* p = (uint8_t*) &b; - p[0] = 0xFF & (a >> 8); - p[1] = 0xFF & (a); - return a == b; -} - -uint8_t* Endian::convertIfRequired(uint8_t* octets, int width) -{ - if (instance.littleEndian) { - for (int i = 0; i < (width/2); i++) { - uint8_t temp = octets[i]; - octets[i] = octets[width - (1 + i)]; - octets[width - (1 + i)] = temp; - } - } - return octets; -} - -const Endian Endian::instance; - -}} // namespace qpid::framing diff --git a/qpid/cpp/src/qpid/framing/Endian.h b/qpid/cpp/src/qpid/framing/Endian.h index dea8eaa3b7..faf553fed5 100644 --- a/qpid/cpp/src/qpid/framing/Endian.h +++ b/qpid/cpp/src/qpid/framing/Endian.h @@ -26,21 +26,53 @@ namespace qpid { namespace framing { +namespace endian { -/** - * Conversion utility for little-endian platforms that need to convert - * to and from network ordered octet sequences - */ -class Endian -{ - public: - static uint8_t* convertIfRequired(uint8_t* octets, int width); - private: - const bool littleEndian; - Endian(); - static const Endian instance; - static bool testBigEndian(); -}; -}} // namespace qpid::framing +/** Decode integer from network byte order buffer to type T, buffer must be at least sizeof(T). */ +template <class T> T decodeInt(const uint8_t* buffer) { + T v = buffer[0]; + for (size_t i = 1; i < sizeof(T); ++i) { + v <<= 8; + v |= buffer[i]; + } + return v; +} + +/** Encode integer value to network byte order in buffer, buffer must be at least sizeof(T). */ +template <class T> void encodeInt(uint8_t* buffer, T value) { + for (size_t i = sizeof(T); i > 0; --i) { + buffer[i-1] = value & 0XFF; + value >>= 8; + } +} + +// Compute the int type that can hold a float type. +template <class T> struct IntBox { typedef T Type; }; +template <> struct IntBox<float> { typedef uint32_t Type; }; +template <> struct IntBox<double> { typedef uint64_t Type; }; + +/** Decode floating from network byte order buffer to type T, buffer must be at least sizeof(T). */ +template <class T> T decodeFloat(const uint8_t* buffer) { + typedef typename IntBox<T>::Type Box; + union { T f; Box i; } u; + u.i = decodeInt<Box>(buffer); + return u.f; +} + +/** Encode floating value to network byte order in buffer, buffer must be at least sizeof(T). */ +template <class T> void encodeFloat(uint8_t* buffer, T value) { + typedef typename IntBox<T>::Type Box; + union { T f; Box i; } u; + u.f = value; + encodeInt(buffer, u.i); +} + +}}} // namespace qpid::framing::endian #endif /*!QPID_FRAMING_ENDIAN_H*/ + + + + + + diff --git a/qpid/cpp/src/qpid/framing/FieldTable.cpp b/qpid/cpp/src/qpid/framing/FieldTable.cpp index cd38db1ee8..0b677a6ccb 100644 --- a/qpid/cpp/src/qpid/framing/FieldTable.cpp +++ b/qpid/cpp/src/qpid/framing/FieldTable.cpp @@ -21,7 +21,6 @@ #include "qpid/framing/FieldTable.h" #include "qpid/framing/Array.h" #include "qpid/framing/Buffer.h" -#include "qpid/framing/Endian.h" #include "qpid/framing/FieldValue.h" #include "qpid/Exception.h" #include "qpid/framing/reply_exceptions.h" diff --git a/qpid/cpp/src/qpid/framing/FieldValue.cpp b/qpid/cpp/src/qpid/framing/FieldValue.cpp index 1d39c57edf..227c12e44e 100644 --- a/qpid/cpp/src/qpid/framing/FieldValue.cpp +++ b/qpid/cpp/src/qpid/framing/FieldValue.cpp @@ -21,15 +21,45 @@ #include "qpid/framing/FieldValue.h" #include "qpid/framing/Array.h" #include "qpid/framing/Buffer.h" -#include "qpid/framing/Endian.h" #include "qpid/framing/List.h" #include "qpid/framing/Uuid.h" #include "qpid/framing/reply_exceptions.h" +#include "qpid/framing/Endian.h" #include "qpid/Msg.h" namespace qpid { namespace framing { +// Some template magic for computing types from sizes. +template<int W> struct IntType{}; +template<> struct IntType<1> { typedef int8_t Type; }; +template<> struct IntType<2> { typedef int16_t Type; }; +template<> struct IntType<4> { typedef int32_t Type; }; +template<> struct IntType<8> { typedef int64_t Type; }; + +template<int W> struct UintType{}; +template<> struct UintType<1> { typedef uint8_t Type; }; +template<> struct UintType<2> { typedef uint16_t Type; }; +template<> struct UintType<4> { typedef uint32_t Type; }; +template<> struct UintType<8> { typedef uint64_t Type; }; + +template<int W> struct FloatType{}; +template<> struct FloatType<1> { typedef int8_t Type; }; // Dummy, never used. +template<> struct FloatType<2> { typedef int16_t Type; }; // Dummy, never used. +template<> struct FloatType<4> { typedef float Type; }; +template<> struct FloatType<8> { typedef double Type; }; + +// Construct the right subclass of FixedWidthValue for numeric types using width and kind. +// Kind 1=int, 2=unsigned int, 3=float +template<int W> FixedWidthValue<W>* numericFixedWidthValue(uint8_t kind) { + switch (kind) { + case 1: return new FixedWidthIntValue<typename IntType<W>::Type>(); + case 2: return new FixedWidthIntValue<typename UintType<W>::Type>(); + case 3: return new FixedWidthFloatValue<typename FloatType<W>::Type>(); + default: return new FixedWidthValue<W>(); + } +} + uint8_t FieldValue::getType() const { return typeOctet; @@ -47,20 +77,22 @@ void FieldValue::setType(uint8_t type) } else if (typeOctet == 0x48) { data.reset(new UuidData()); } else { + uint8_t kind = typeOctet & 0xF; uint8_t lenType = typeOctet >> 4; switch(lenType){ case 0: - data.reset(new FixedWidthValue<1>()); + data.reset(numericFixedWidthValue<1>(kind)); break; case 1: - data.reset(new FixedWidthValue<2>()); + data.reset(numericFixedWidthValue<2>(kind)); break; case 2: - data.reset(new FixedWidthValue<4>()); + data.reset(numericFixedWidthValue<4>(kind)); break; case 3: - data.reset(new FixedWidthValue<8>()); + data.reset(numericFixedWidthValue<8>(kind)); break; + // None of the remaining widths can be numeric types so just use new FixedWidthValue case 4: data.reset(new FixedWidthValue<16>()); break; @@ -157,28 +189,28 @@ Struct32Value::Struct32Value(const std::string& v) : {} IntegerValue::IntegerValue(int v) : - FieldValue(0x21, new FixedWidthValue<4>(v)) + FieldValue(0x21, new FixedWidthIntValue<int32_t>(v)) {} FloatValue::FloatValue(float v) : - FieldValue(0x23, new FixedWidthValue<4>(Endian::convertIfRequired(reinterpret_cast<uint8_t*>(&v), 4))) + FieldValue(0x23, new FixedWidthFloatValue<float>(v)) {} DoubleValue::DoubleValue(double v) : - FieldValue(0x33, new FixedWidthValue<8>(Endian::convertIfRequired(reinterpret_cast<uint8_t*>(&v), 8))) + FieldValue(0x33, new FixedWidthFloatValue<double>(v)) {} Integer64Value::Integer64Value(int64_t v) : - FieldValue(0x31, new FixedWidthValue<8>(v)) + FieldValue(0x31, new FixedWidthIntValue<int64_t>(v)) {} Unsigned64Value::Unsigned64Value(uint64_t v) : - FieldValue(0x32, new FixedWidthValue<8>(v)) + FieldValue(0x32, new FixedWidthIntValue<uint64_t>(v)) {} TimeValue::TimeValue(uint64_t v) : - FieldValue(0x38, new FixedWidthValue<8>(v)) + FieldValue(0x38, new FixedWidthIntValue<uint64_t>(v)) { } @@ -197,24 +229,24 @@ ArrayValue::ArrayValue(const Array& a) : FieldValue(0xaa, new EncodedValue<Array VoidValue::VoidValue() : FieldValue(0xf0, new FixedWidthValue<0>()) {} BoolValue::BoolValue(bool b) : - FieldValue(0x08, new FixedWidthValue<1>(b)) + FieldValue(0x08, new FixedWidthIntValue<bool>(b)) {} Unsigned8Value::Unsigned8Value(uint8_t v) : - FieldValue(0x02, new FixedWidthValue<1>(v)) + FieldValue(0x02, new FixedWidthIntValue<uint8_t>(v)) {} Unsigned16Value::Unsigned16Value(uint16_t v) : - FieldValue(0x12, new FixedWidthValue<2>(v)) + FieldValue(0x12, new FixedWidthIntValue<uint16_t>(v)) {} Unsigned32Value::Unsigned32Value(uint32_t v) : - FieldValue(0x22, new FixedWidthValue<4>(v)) + FieldValue(0x22, new FixedWidthIntValue<uint32_t>(v)) {} Integer8Value::Integer8Value(int8_t v) : - FieldValue(0x01, new FixedWidthValue<1>(v)) + FieldValue(0x01, new FixedWidthIntValue<int8_t>(v)) {} Integer16Value::Integer16Value(int16_t v) : - FieldValue(0x11, new FixedWidthValue<2>(v)) + FieldValue(0x11, new FixedWidthIntValue<int16_t>(v)) {} UuidData::UuidData() {} @@ -232,9 +264,4 @@ void FieldValue::print(std::ostream& out) const { out << ')'; } -uint8_t* FieldValue::convertIfRequired(uint8_t* octets, int width) -{ - return Endian::convertIfRequired(octets, width); -} - }} diff --git a/qpid/cpp/src/qpid/framing/FieldValue.h b/qpid/cpp/src/qpid/framing/FieldValue.h index 94126df053..e20244e7c9 100644 --- a/qpid/cpp/src/qpid/framing/FieldValue.h +++ b/qpid/cpp/src/qpid/framing/FieldValue.h @@ -25,6 +25,7 @@ #include "qpid/framing/amqp_types.h" #include "qpid/framing/Buffer.h" #include "qpid/framing/FieldTable.h" +#include "qpid/framing/Endian.h" #include "qpid/CommonImportExport.h" #include <iostream> @@ -66,15 +67,17 @@ class QPID_COMMON_CLASS_EXTERN FieldValue { */ class Data { public: - virtual ~Data() {}; + virtual ~Data() {} virtual uint32_t encodedSize() const = 0; virtual void encode(Buffer& buffer) = 0; virtual void decode(Buffer& buffer) = 0; virtual bool operator==(const Data&) const = 0; virtual bool convertsToInt() const { return false; } + virtual bool convertsToFloat() const { return false; } virtual bool convertsToString() const { return false; } virtual int64_t getInt() const { throw InvalidConversionException();} + virtual double getFloat() const { throw InvalidConversionException();} virtual std::string getString() const { throw InvalidConversionException(); } virtual void print(std::ostream& out) const = 0; @@ -106,8 +109,6 @@ class QPID_COMMON_CLASS_EXTERN FieldValue { protected: FieldValue(uint8_t t, Data* d): typeOctet(t), data(d) {} - QPID_COMMON_EXTERN static uint8_t* convertIfRequired(uint8_t* octets, int width); - private: uint8_t typeOctet; std::auto_ptr<Data> data; @@ -123,12 +124,24 @@ template <> inline bool FieldValue::convertsTo<std::string>() const { return data->convertsToString(); } template <> +inline bool FieldValue::convertsTo<float>() const { return data->convertsToFloat(); } + +template <> +inline bool FieldValue::convertsTo<double>() const { return data->convertsToFloat(); } + +template <> inline int FieldValue::get<int>() const { return static_cast<int>(data->getInt()); } template <> inline int64_t FieldValue::get<int64_t>() const { return data->getInt(); } template <> +inline float FieldValue::get<float>() const { return data->getFloat(); } + +template <> +inline double FieldValue::get<double>() const { return data->getFloat(); } + +template <> inline std::string FieldValue::get<std::string>() const { return data->getString(); } inline std::ostream& operator<<(std::ostream& out, const FieldValue& v) { @@ -138,22 +151,14 @@ inline std::ostream& operator<<(std::ostream& out, const FieldValue& v) { template <int width> class FixedWidthValue : public FieldValue::Data { + protected: uint8_t octets[width]; public: FixedWidthValue() {} FixedWidthValue(const uint8_t (&data)[width]) : octets(data) {} - FixedWidthValue(const uint8_t* const data) - { - for (int i = 0; i < width; i++) octets[i] = data[i]; - } - FixedWidthValue(uint64_t v) - { - for (int i = width; i > 1; --i) { - octets[i-1] = (uint8_t) (0xFF & v); v >>= 8; - } - octets[0] = (uint8_t) (0xFF & v); - } + FixedWidthValue(const uint8_t* const data) { std::copy(data, data + width, octets); } + uint32_t encodedSize() const { return width; } void encode(Buffer& buffer) { buffer.putRawData(octets, width); } void decode(Buffer& buffer) { buffer.getRawData(octets, width); } @@ -162,23 +167,37 @@ class FixedWidthValue : public FieldValue::Data { if (rhs == 0) return false; else return std::equal(&octets[0], &octets[width], &rhs->octets[0]); } - - bool convertsToInt() const { return true; } - int64_t getInt() const - { - int64_t v = 0; - for (int i = 0; i < width-1; ++i) { - v |= octets[i]; v <<= 8; - } - v |= octets[width-1]; - return v; - } uint8_t* rawOctets() { return octets; } const uint8_t* rawOctets() const { return octets; } void print(std::ostream& o) const { o << "F" << width << ":"; }; }; +template <class T> class FixedWidthIntValue : public FixedWidthValue<sizeof(T)> { + public: + FixedWidthIntValue(T v = 0) { endian::encodeInt(this->octets, v); } + bool convertsToInt() const { return true; } + int64_t getInt() const { return endian::decodeInt<T>(this->octets); } + bool convertsToFloat() const { return true; } + double getFloat() const { return getInt(); } +}; + +template <class T> class FixedWidthFloatValue : public FixedWidthValue<sizeof(T)> { + public: + FixedWidthFloatValue(T v = 0) { endian::encodeFloat(this->octets, v); } + bool convertsToFloat() const { return true; } + double getFloat() const { return endian::decodeFloat<T>(this->octets); } +}; + +// Dummy implementations that are never used but needed to avoid compile errors. +template <> class FixedWidthFloatValue<uint8_t> : public FixedWidthValue<1> { + FixedWidthFloatValue() { assert(0); } +}; +template <> class FixedWidthFloatValue<uint16_t> : public FixedWidthValue<2> { + FixedWidthFloatValue() { assert(0); } +}; + + class UuidData : public FixedWidthValue<16> { public: UuidData(); @@ -192,13 +211,7 @@ inline T FieldValue::getIntegerValue() const { FixedWidthValue<W>* const fwv = dynamic_cast< FixedWidthValue<W>* const>(data.get()); if (fwv) { - uint8_t* octets = fwv->rawOctets(); - T v = 0; - for (int i = 0; i < W-1; ++i) { - v |= octets[i]; v <<= 8; - } - v |= octets[W-1]; - return v; + return endian::decodeInt<T>(fwv->rawOctets()); } else { throw InvalidConversionException(); } @@ -218,14 +231,9 @@ inline T FieldValue::getIntegerValue() const template <class T, int W> inline T FieldValue::getFloatingPointValue() const { - const FixedWidthValue<W>* fwv = dynamic_cast<FixedWidthValue<W>*>(data.get()); - if (fwv) { - T value; - uint8_t* target = reinterpret_cast<uint8_t*>(&value); - const uint8_t* octets = fwv->rawOctets(); - std::copy(octets, octets + W, target); - convertIfRequired(target, W); - return value; + const FixedWidthFloatValue<T>* fv = dynamic_cast<FixedWidthFloatValue<T>*>(data.get()); + if (fv) { + return endian::decodeFloat<T>(fv->rawOctets()); } else { throw InvalidConversionException(); } @@ -235,23 +243,13 @@ template <int W> void FieldValue::getFixedWidthValue(unsigned char* value) const { FixedWidthValue<W>* const fwv = dynamic_cast< FixedWidthValue<W>* const>(data.get()); if (fwv) { - for (size_t i = 0; i < W; ++i) value[i] = fwv->rawOctets()[i]; + std::copy(fwv->rawOctets(), fwv->rawOctets() + W, value); } else { throw InvalidConversionException(); } } template <> -inline float FieldValue::get<float>() const { - return getFloatingPointValue<float, 4>(); -} - -template <> -inline double FieldValue::get<double>() const { - return getFloatingPointValue<double, 8>(); -} - -template <> class FixedWidthValue<0> : public FieldValue::Data { public: // Implicit default constructor is fine diff --git a/qpid/cpp/src/tests/FieldTable.cpp b/qpid/cpp/src/tests/FieldTable.cpp index 81372d87c5..c040f1d433 100644 --- a/qpid/cpp/src/tests/FieldTable.cpp +++ b/qpid/cpp/src/tests/FieldTable.cpp @@ -176,19 +176,19 @@ QPID_AUTO_TEST_CASE(testFloatAndDouble) Buffer rbuffer(buff, 100); FieldTable a; rbuffer.get(a); - BOOST_CHECK(string("abc") == a.getAsString("string")); - BOOST_CHECK(5672 == a.getAsInt("int")); + BOOST_CHECK_EQUAL(string("abc"), a.getAsString("string")); + BOOST_CHECK_EQUAL(5672, a.getAsInt("int")); float f2; BOOST_CHECK(!a.getFloat("string", f2)); BOOST_CHECK(!a.getFloat("int", f2)); BOOST_CHECK(a.getFloat("float", f2)); - BOOST_CHECK(f2 == f); + BOOST_CHECK_EQUAL(f2, f); double d2; BOOST_CHECK(!a.getDouble("string", d2)); BOOST_CHECK(!a.getDouble("int", d2)); BOOST_CHECK(a.getDouble("double", d2)); - BOOST_CHECK(d2 == d); + BOOST_CHECK_EQUAL(d2, d); } } diff --git a/qpid/cpp/src/tests/FieldValue.cpp b/qpid/cpp/src/tests/FieldValue.cpp index 3e2a761c38..2182a43e35 100644 --- a/qpid/cpp/src/tests/FieldValue.cpp +++ b/qpid/cpp/src/tests/FieldValue.cpp @@ -53,22 +53,15 @@ QPID_AUTO_TEST_CASE(testIntegerValueEquals) BOOST_CHECK(IntegerValue(5) != i); BOOST_CHECK(i != s); BOOST_CHECK(i.convertsTo<std::string>() == false); - BOOST_CHECK(i.convertsTo<float>() == false); + BOOST_CHECK(i.convertsTo<float>() == true); BOOST_CHECK(i.convertsTo<int>() == true); BOOST_CHECK_THROW(i.get<std::string>(), InvalidConversionException); - - //FIXME aconway 2015-04-03: fails - //BOOST_CHECK_THROW(i.get<float>(), InvalidConversionException); + BOOST_CHECK_EQUAL(i.get<float>(), 42.0); } QPID_AUTO_TEST_CASE(testFloatValueEquals) { - // FIXME aconway 2015-04-03: The commented out tests are bug QPID-6470. - // The basic problems are: - // - allows meaningles conversion between int and float types. - // - does not allow expected conversion between float and double types. - - // BOOST_CHECK(f.convertsTo<float>() == true); + BOOST_CHECK(f.convertsTo<float>() == true); BOOST_CHECK_EQUAL(FloatValue(42.42), f); BOOST_CHECK_CLOSE(f.get<float>(), 42.42, 0.001); // Check twice, regression test for QPID-6470 where the value was corrupted during get. @@ -76,20 +69,28 @@ QPID_AUTO_TEST_CASE(testFloatValueEquals) BOOST_CHECK_CLOSE(f.get<float>(), 42.42, 0.001); // Float to double conversion - // BOOST_CHECK(f.convertsTo<double>() == true); - // BOOST_CHECK_CLOSE(f.get<double>(), 42.42, 0.001); + BOOST_CHECK(f.convertsTo<double>() == true); + BOOST_CHECK_CLOSE(f.get<double>(), 42.42, 0.001); // Double value + BOOST_CHECK(f.convertsTo<float>() == true); + BOOST_CHECK(f.convertsTo<double>() == true); + BOOST_CHECK_CLOSE(df.get<float>(), 123.123, 0.001); BOOST_CHECK_CLOSE(df.get<double>(), 123.123, 0.001); - // BOOST_CHECK(f.convertsTo<float>() == true); - // BOOST_CHECK(f.convertsTo<double>() == true); - // BOOST_CHECK_CLOSE(df.get<float>(), 123.123, 0.001); // Invalid conversions should fail. BOOST_CHECK(!f.convertsTo<std::string>()); - // BOOST_CHECK(!f.convertsTo<int>()); + BOOST_CHECK(!f.convertsTo<int>()); BOOST_CHECK_THROW(f.get<std::string>(), InvalidConversionException); - // BOOST_CHECK_THROW(f.get<int>(), InvalidConversionException); + BOOST_CHECK_THROW(f.get<int>(), InvalidConversionException); + + // getFloatingPointValue: check twice, regression test for QPID-6470 + BOOST_CHECK_CLOSE((f.getFloatingPointValue<float,sizeof(float)>()), 42.42, 0.001); + BOOST_CHECK_CLOSE((f.getFloatingPointValue<float,sizeof(float)>()), 42.42, 0.001); + BOOST_CHECK_CLOSE((df.getFloatingPointValue<double,sizeof(double)>()), 123.123, 0.001); + // getFloatingPointValue should *not* convert float/double, require exact type. + BOOST_CHECK_THROW((f.getFloatingPointValue<double,sizeof(double)>()), InvalidConversionException); + BOOST_CHECK_THROW((df.getFloatingPointValue<float,sizeof(float)>()), InvalidConversionException); } QPID_AUTO_TEST_SUITE_END() |