summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Conway <aconway@apache.org>2015-04-16 19:04:23 +0000
committerAlan Conway <aconway@apache.org>2015-04-16 19:04:23 +0000
commitea16e50919f21fbab181e20e25b03d1a314634c8 (patch)
tree59fc8ce516b7ad1e6b46b2f640b418cd9092f10c
parente7998631f9c479dd659f409f8e38c910e0028858 (diff)
downloadqpid-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.txt1
-rw-r--r--qpid/cpp/src/qpid/framing/Endian.cpp52
-rw-r--r--qpid/cpp/src/qpid/framing/Endian.h62
-rw-r--r--qpid/cpp/src/qpid/framing/FieldTable.cpp1
-rw-r--r--qpid/cpp/src/qpid/framing/FieldValue.cpp71
-rw-r--r--qpid/cpp/src/qpid/framing/FieldValue.h100
-rw-r--r--qpid/cpp/src/tests/FieldTable.cpp8
-rw-r--r--qpid/cpp/src/tests/FieldValue.cpp35
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()