You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2016/05/31 17:42:47 UTC
qpid-proton git commit: PROTON-1216: c++: proton::coerce should
convert binary to string.
Repository: qpid-proton
Updated Branches:
refs/heads/master fc82f55b8 -> 8d0c5afd0
PROTON-1216: c++: proton::coerce should convert binary to string.
Make scalar and value coerce<> consistent with C++ implicit conversions and each other.
- No source api change (still have deprecated functions)
- Better test coverage, consistent tests for value and scalar where applicable.
- Fixed unknown integer type conversions for scalar.
- Fixed examples using deprecated APIs (deprecated APIs are still in place)
- Consistent printing of scalar values, repect the std::ios::boolalpha flag for printing bool.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/8d0c5afd
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/8d0c5afd
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/8d0c5afd
Branch: refs/heads/master
Commit: 8d0c5afd081a4732c0cb3a1ccd6a0cbcba7187ee
Parents: fc82f55
Author: Alan Conway <ac...@redhat.com>
Authored: Tue May 31 13:11:30 2016 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue May 31 13:11:30 2016 -0400
----------------------------------------------------------------------
examples/cpp/encode_decode.cpp | 1 +
examples/cpp/simple_recv.cpp | 2 +-
.../cpp/include/proton/annotation_key.hpp | 6 +-
proton-c/bindings/cpp/include/proton/error.hpp | 3 -
.../cpp/include/proton/internal/scalar_base.hpp | 29 ++-
.../cpp/include/proton/internal/type_traits.hpp | 21 +-
.../bindings/cpp/include/proton/message_id.hpp | 2 +-
proton-c/bindings/cpp/include/proton/scalar.hpp | 3 +-
.../bindings/cpp/include/proton/scalar_base.cpp | 151 ++++++++++++++
proton-c/bindings/cpp/include/proton/value.hpp | 18 +-
proton-c/bindings/cpp/src/interop_test.cpp | 6 +-
proton-c/bindings/cpp/src/scalar_base.cpp | 30 ++-
proton-c/bindings/cpp/src/scalar_test.cpp | 100 +--------
proton-c/bindings/cpp/src/scalar_test.hpp | 209 +++++++++++++++++++
proton-c/bindings/cpp/src/test_bits.hpp | 4 +-
proton-c/bindings/cpp/src/value.cpp | 4 +-
proton-c/bindings/cpp/src/value_test.cpp | 150 ++-----------
17 files changed, 485 insertions(+), 254 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/examples/cpp/encode_decode.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/encode_decode.cpp b/examples/cpp/encode_decode.cpp
index 67fb0fc..17971d9 100644
--- a/examples/cpp/encode_decode.cpp
+++ b/examples/cpp/encode_decode.cpp
@@ -243,6 +243,7 @@ static void print_next(proton::codec::decoder& d) {
void print(proton::value& v) {
proton::codec::decoder d(v);
d.rewind();
+ std::cout << std::boolalpha; // Print boolean as true/false.
while (d.more()) {
print_next(d);
if (d.more()) std::cout << ", ";
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/examples/cpp/simple_recv.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/simple_recv.cpp b/examples/cpp/simple_recv.cpp
index 2495a28..7621941 100644
--- a/examples/cpp/simple_recv.cpp
+++ b/examples/cpp/simple_recv.cpp
@@ -50,7 +50,7 @@ class simple_recv : public proton::messaging_handler {
}
void on_message(proton::delivery &d, proton::message &msg) OVERRIDE {
- if (msg.id().get<uint64_t>() < received) {
+ if (proton::get<uint64_t>(msg.id()) < received) {
return; // Ignore duplicate
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/include/proton/annotation_key.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/annotation_key.hpp b/proton-c/bindings/cpp/include/proton/annotation_key.hpp
index 019e3d3..c0c8ca6 100644
--- a/proton-c/bindings/cpp/include/proton/annotation_key.hpp
+++ b/proton-c/bindings/cpp/include/proton/annotation_key.hpp
@@ -59,12 +59,12 @@ class annotation_key : public internal::scalar_base {
};
/// @cond INTERNAL
-/// XXX Document this?
+/// Primary template for get<T>(message_id), specialized for legal types.
template <class T> T get(const annotation_key& x);
/// @endcond
/// Get the uint64_t value or throw conversion_error.
-///
+///
/// @related annotation_key
template<> inline uint64_t get<uint64_t>(const annotation_key& x) { return internal::get<uint64_t>(x); }
@@ -74,7 +74,7 @@ template<> inline uint64_t get<uint64_t>(const annotation_key& x) { return inter
template<> inline symbol get<symbol>(const annotation_key& x) { return internal::get<symbol>(x); }
/// Get the @ref binary value or throw conversion_error.
-///
+///
/// @copydoc scalar::coerce
/// @related annotation_key
template<class T> T coerce(const annotation_key& x) { return internal::coerce<T>(x); }
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/include/proton/error.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/error.hpp b/proton-c/bindings/cpp/include/proton/error.hpp
index 1dbbc9b..6896620 100644
--- a/proton-c/bindings/cpp/include/proton/error.hpp
+++ b/proton-c/bindings/cpp/include/proton/error.hpp
@@ -24,15 +24,12 @@
#include "./internal/config.hpp"
#include "./internal/export.hpp"
-#include "./value.hpp"
#include <stdexcept>
#include <string>
namespace proton {
-class value;
-
/// The base Proton error.
///
/// All exceptions thrown from functions in the proton namespace are
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/include/proton/internal/scalar_base.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/internal/scalar_base.hpp b/proton-c/bindings/cpp/include/proton/internal/scalar_base.hpp
index 8f57cb6..bcd0410 100644
--- a/proton-c/bindings/cpp/include/proton/internal/scalar_base.hpp
+++ b/proton-c/bindings/cpp/include/proton/internal/scalar_base.hpp
@@ -36,6 +36,7 @@
#include <iosfwd>
#include <string>
+#include <typeinfo>
namespace proton {
class message;
@@ -47,6 +48,9 @@ class encoder;
namespace internal {
+class scalar_base;
+template<class T> T get(const scalar_base& s);
+
/// Base class for scalar types.
class scalar_base : private comparable<scalar_base> {
public:
@@ -97,6 +101,9 @@ class scalar_base : private comparable<scalar_base> {
PN_CPP_EXTERN void put_(const char* s); ///< Treated as an AMQP string
PN_CPP_EXTERN void put_(const null&);
+ template<class T> void put(const T& x) { putter<T>::put(*this, x); }
+
+ private:
PN_CPP_EXTERN void get_(bool&) const;
PN_CPP_EXTERN void get_(uint8_t&) const;
PN_CPP_EXTERN void get_(int8_t&) const;
@@ -119,7 +126,20 @@ class scalar_base : private comparable<scalar_base> {
PN_CPP_EXTERN void get_(binary&) const;
PN_CPP_EXTERN void get_(null&) const;
- private:
+ // use template structs, functions cannot be partially specialized.
+ template <class T, class Enable=void> struct putter {
+ static void put(scalar_base& s, const T& x) { s.put_(x); }
+ };
+ template <class T> struct putter<T, typename enable_if<is_unknown_integer<T>::value>::type> {
+ static void put(scalar_base& s, const T& x) { s.put_(static_cast<typename known_integer<T>::type>(x)); }
+ };
+ template <class T, class Enable=void> struct getter {
+ static T get(const scalar_base& s) { T x; s.get_(x); return x; }
+ };
+ template <class T> struct getter<T, typename enable_if<is_unknown_integer<T>::value>::type> {
+ static T get(const scalar_base& s) { typename known_integer<T>::type x; s.get_(x); return x; }
+ };
+
void ok(pn_type_t) const;
void set(const pn_atom_t&);
void set(const binary& x, pn_type_t t);
@@ -131,11 +151,10 @@ class scalar_base : private comparable<scalar_base> {
friend class proton::message;
friend class codec::encoder;
friend class codec::decoder;
+ template<class T> friend T get(const scalar_base& s) { return scalar_base::getter<T>::get(s); }
/// @endcond
};
-template<class T> T get(const scalar_base& s) { T x; s.get(x); return x; }
-
template <class R, class F> R visit(const scalar_base& s, F f) {
switch(s.type()) {
case BOOLEAN: return f(s.get<bool>());
@@ -162,6 +181,8 @@ template <class R, class F> R visit(const scalar_base& s, F f) {
}
}
+PN_CPP_EXTERN conversion_error make_coercion_error(const char* cpp_type, type_id amqp_type);
+
template<class T> struct coerce_op {
template <class U>
typename enable_if<is_convertible<U, T>::value, T>::type operator()(const U& x) {
@@ -169,7 +190,7 @@ template<class T> struct coerce_op {
}
template <class U>
typename enable_if<!is_convertible<U, T>::value, T>::type operator()(const U&) {
- throw conversion_error("cannot coerce from " + type_name(type_id_of<U>::value));
+ throw make_coercion_error(typeid(T).name(), type_id_of<U>::value);
}
};
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp b/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp
index 999b321..0490823 100644
--- a/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp
+++ b/proton-c/bindings/cpp/include/proton/internal/type_traits.hpp
@@ -117,7 +117,20 @@ template<> struct type_id_of<binary> : public type_id_constant<BINARY, binary> {
template <class T, class Enable=void> struct has_type_id : public false_type {};
template <class T> struct has_type_id<T, typename type_id_of<T>::type> : public true_type {};
-// Map arbitrary integral types to known AMQP integral types.
+// The known/unknown integer type magic is required because the C++ standard is
+// vague a about the equivalence of integral types for overloading. E.g. char is
+// sometimes equivalent to signed char, sometimes unsigned char, sometimes
+// neither. int8_t or uint8_t may or may not be equivalent to a char type.
+// int64_t may or may not be equivalent to long long etc. C++ compilers are also
+// allowed to add their own non-standard integer types like __int64, which may
+// or may not be equivalent to any of the standard integer types.
+//
+// The solution is to use a fixed, standard set of integer types that are
+// guaranteed to be distinct for overloading (see type_id_of) and to use template
+// specialization to convert other integer types to a known integer type with the
+// same sizeof and is_signed.
+
+// Map arbitrary integral types to known integral types.
template<size_t SIZE, bool IS_SIGNED> struct integer_type;
template<> struct integer_type<1, true> { typedef int8_t type; };
template<> struct integer_type<2, true> { typedef int16_t type; };
@@ -133,7 +146,11 @@ template <class T> struct is_unknown_integer {
static const bool value = !has_type_id<T>::value && is_integral<T>::value;
};
-// Helper base for SFINAE test templates.
+template<class T, class = typename enable_if<is_unknown_integer<T>::value>::type>
+struct known_integer : public integer_type<sizeof(T), is_signed<T>::value> {};
+
+
+// Helper base for SFINAE templates.
struct sfinae {
typedef char yes;
typedef double no;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/include/proton/message_id.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message_id.hpp b/proton-c/bindings/cpp/include/proton/message_id.hpp
index a37198e..84f8ab0 100644
--- a/proton-c/bindings/cpp/include/proton/message_id.hpp
+++ b/proton-c/bindings/cpp/include/proton/message_id.hpp
@@ -68,7 +68,7 @@ class message_id : public internal::scalar_base {
};
/// @cond INTERNAL
-// XXX Document this?
+/// Base template for get(message_id), specialized for legal message_id types.
template <class T> T get(const message_id& x);
/// @endcond
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/include/proton/scalar.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/scalar.hpp b/proton-c/bindings/cpp/include/proton/scalar.hpp
index 4fd6dd9..eed5255 100644
--- a/proton-c/bindings/cpp/include/proton/scalar.hpp
+++ b/proton-c/bindings/cpp/include/proton/scalar.hpp
@@ -41,7 +41,7 @@ class scalar : public internal::scalar_base {
template <class T> scalar(const T& x) { *this = x; }
/// Assign from any scalar type.
- template <class T> scalar& operator=(const T& x) { put_(x); return *this; }
+ template <class T> scalar& operator=(const T& x) { put(x); return *this; }
/// True if type() == NULL_TYPE.
bool empty() const { return type() == NULL_TYPE; }
@@ -71,6 +71,7 @@ template<class T> T get(const scalar& s) { return internal::get<T>(s); }
/// according to `std::is_convertible`
/// @related scalar
template<class T> T coerce(const scalar& x) { return internal::coerce<T>(x); }
+template<class T> T coerce(scalar& x) { return internal::coerce<T>(x); }
} // proton
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/include/proton/scalar_base.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/scalar_base.cpp b/proton-c/bindings/cpp/include/proton/scalar_base.cpp
new file mode 100644
index 0000000..20694db
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/scalar_base.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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 "msg.hpp"
+#include "types_internal.hpp"
+
+#include "proton/binary.hpp"
+#include "proton/decimal.hpp"
+#include "proton/internal/scalar_base.hpp"
+#include "proton/internal/type_traits.hpp"
+#include "proton/symbol.hpp"
+#include "proton/timestamp.hpp"
+#include "proton/uuid.hpp"
+
+#include <ostream>
+
+namespace proton {
+namespace internal {
+
+scalar_base::scalar_base() { atom_.type = PN_NULL; }
+scalar_base::scalar_base(const pn_atom_t& a) { set(a); }
+scalar_base::scalar_base(const scalar_base& x) { set(x.atom_); }
+
+scalar_base& scalar_base::operator=(const scalar_base& x) {
+ if (this != &x)
+ set(x.atom_);
+ return *this;
+}
+
+type_id scalar_base::type() const { return type_id(atom_.type); }
+
+void scalar_base::set(const binary& x, pn_type_t t) {
+ atom_.type = t;
+ bytes_ = x;
+ atom_.u.as_bytes = pn_bytes(bytes_);
+}
+
+void scalar_base::set(const pn_atom_t& atom) {
+ if (type_id_is_string_like(type_id(atom.type))) {
+ set(bin(atom.u.as_bytes), atom.type);
+ } else {
+ atom_ = atom;
+ bytes_.clear();
+ }
+}
+
+void scalar_base::put_(bool x) { atom_.u.as_bool = x; atom_.type = PN_BOOL; }
+void scalar_base::put_(uint8_t x) { atom_.u.as_ubyte = x; atom_.type = PN_UBYTE; }
+void scalar_base::put_(int8_t x) { atom_.u.as_byte = x; atom_.type = PN_BYTE; }
+void scalar_base::put_(uint16_t x) { atom_.u.as_ushort = x; atom_.type = PN_USHORT; }
+void scalar_base::put_(int16_t x) { atom_.u.as_short = x; atom_.type = PN_SHORT; }
+void scalar_base::put_(uint32_t x) { atom_.u.as_uint = x; atom_.type = PN_UINT; }
+void scalar_base::put_(int32_t x) { atom_.u.as_int = x; atom_.type = PN_INT; }
+void scalar_base::put_(uint64_t x) { atom_.u.as_ulong = x; atom_.type = PN_ULONG; }
+void scalar_base::put_(int64_t x) { atom_.u.as_long = x; atom_.type = PN_LONG; }
+void scalar_base::put_(wchar_t x) { atom_.u.as_char = x; atom_.type = PN_CHAR; }
+void scalar_base::put_(float x) { atom_.u.as_float = x; atom_.type = PN_FLOAT; }
+void scalar_base::put_(double x) { atom_.u.as_double = x; atom_.type = PN_DOUBLE; }
+void scalar_base::put_(timestamp x) { atom_.u.as_timestamp = x.milliseconds(); atom_.type = PN_TIMESTAMP; }
+void scalar_base::put_(const decimal32& x) { byte_copy(atom_.u.as_decimal32, x); atom_.type = PN_DECIMAL32;; }
+void scalar_base::put_(const decimal64& x) { byte_copy(atom_.u.as_decimal64, x); atom_.type = PN_DECIMAL64; }
+void scalar_base::put_(const decimal128& x) { byte_copy(atom_.u.as_decimal128, x); atom_.type = PN_DECIMAL128; }
+void scalar_base::put_(const uuid& x) { byte_copy(atom_.u.as_uuid, x); atom_.type = PN_UUID; }
+void scalar_base::put_(const std::string& x) { set(binary(x), PN_STRING); }
+void scalar_base::put_(const symbol& x) { set(binary(x), PN_SYMBOL); }
+void scalar_base::put_(const binary& x) { set(x, PN_BINARY); }
+void scalar_base::put_(const char* x) { set(binary(std::string(x)), PN_STRING); }
+void scalar_base::put_(const null&) { atom_.type = PN_NULL; }
+
+void scalar_base::ok(pn_type_t t) const {
+ if (atom_.type != t) throw make_conversion_error(type_id(t), type());
+}
+
+void scalar_base::get_(bool& x) const { ok(PN_BOOL); x = atom_.u.as_bool; }
+void scalar_base::get_(uint8_t& x) const { ok(PN_UBYTE); x = atom_.u.as_ubyte; }
+void scalar_base::get_(int8_t& x) const { ok(PN_BYTE); x = atom_.u.as_byte; }
+void scalar_base::get_(uint16_t& x) const { ok(PN_USHORT); x = atom_.u.as_ushort; }
+void scalar_base::get_(int16_t& x) const { ok(PN_SHORT); x = atom_.u.as_short; }
+void scalar_base::get_(uint32_t& x) const { ok(PN_UINT); x = atom_.u.as_uint; }
+void scalar_base::get_(int32_t& x) const { ok(PN_INT); x = atom_.u.as_int; }
+void scalar_base::get_(wchar_t& x) const { ok(PN_CHAR); x = wchar_t(atom_.u.as_char); }
+void scalar_base::get_(uint64_t& x) const { ok(PN_ULONG); x = atom_.u.as_ulong; }
+void scalar_base::get_(int64_t& x) const { ok(PN_LONG); x = atom_.u.as_long; }
+void scalar_base::get_(timestamp& x) const { ok(PN_TIMESTAMP); x = atom_.u.as_timestamp; }
+void scalar_base::get_(float& x) const { ok(PN_FLOAT); x = atom_.u.as_float; }
+void scalar_base::get_(double& x) const { ok(PN_DOUBLE); x = atom_.u.as_double; }
+void scalar_base::get_(decimal32& x) const { ok(PN_DECIMAL32); byte_copy(x, atom_.u.as_decimal32); }
+void scalar_base::get_(decimal64& x) const { ok(PN_DECIMAL64); byte_copy(x, atom_.u.as_decimal64); }
+void scalar_base::get_(decimal128& x) const { ok(PN_DECIMAL128); byte_copy(x, atom_.u.as_decimal128); }
+void scalar_base::get_(uuid& x) const { ok(PN_UUID); byte_copy(x, atom_.u.as_uuid); }
+void scalar_base::get_(std::string& x) const { ok(PN_STRING); x = std::string(bytes_.begin(), bytes_.end()); }
+void scalar_base::get_(symbol& x) const { ok(PN_SYMBOL); x = symbol(bytes_.begin(), bytes_.end()); }
+void scalar_base::get_(binary& x) const { ok(PN_BINARY); x = bytes_; }
+void scalar_base::get_(null&) const { ok(PN_NULL); }
+
+namespace {
+
+struct equal_op {
+ const scalar_base& x;
+ equal_op(const scalar_base& s) : x(s) {}
+ template<class T> bool operator()(const T& y) { return (x.get<T>() == y); }
+};
+
+struct less_op {
+ const scalar_base& x;
+ less_op(const scalar_base& s) : x(s) {}
+ template<class T> bool operator()(const T& y) { return (y < x.get<T>()); }
+};
+
+struct ostream_op {
+ std::ostream& o;
+ ostream_op(std::ostream& o_) : o(o_) {}
+ template<class T> std::ostream& operator()(const T& x) { return o << x; }
+};
+
+} // namespace
+
+bool operator==(const scalar_base& x, const scalar_base& y) {
+ if (x.type() != y.type()) return false;
+ if (x.type() == NULL_TYPE) return true;
+ return internal::visit<bool>(x, equal_op(y));
+}
+
+bool operator<(const scalar_base& x, const scalar_base& y) {
+ if (x.type() != y.type()) return x.type() < y.type();
+ if (x.type() == NULL_TYPE) return false;
+ return internal::visit<bool>(x, less_op(y));
+}
+
+std::ostream& operator<<(std::ostream& o, const scalar_base& s) {
+ if (s.type() == NULL_TYPE) return o << "<null>";
+ return internal::visit<std::ostream&>(s, ostream_op(o));
+}
+
+}} // namespaces
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/include/proton/value.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/value.hpp b/proton-c/bindings/cpp/include/proton/value.hpp
index 2e8b302..4149f60 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -25,6 +25,7 @@
#include "./codec/encoder.hpp"
#include "./codec/decoder.hpp"
#include "./internal/type_traits.hpp"
+#include "./scalar.hpp"
#include "./types_fwd.hpp"
#include <iosfwd>
@@ -129,7 +130,7 @@ template<class T> T get(const value& v) { T x; get(v, x); return x; }
/// Like get(const value&) but assigns the value to a reference
/// instead of returning it. May be more efficient for complex values
/// (arrays, maps, etc.)
-///
+///
/// @related proton::value
template<class T> void get(const value& v, T& x) { codec::decoder d(v, true); d >> x; }
@@ -142,10 +143,21 @@ template<class T> T coerce(const value& v) { T x; coerce(v, x); return x; }
/// (arrays, maps, etc.)
///
/// @related proton::value
-template<class T> void coerce(const value& v, T& x) { codec::decoder d(v, false); d >> x; }
+template<class T> void coerce(const value& v, T& x) {
+ codec::decoder d(v, false);
+ if (type_id_is_scalar(v.type())) {
+ scalar s;
+ d >> s;
+ x = internal::coerce<T>(s);
+ } else {
+ d >> x;
+ }
+}
-/// @cond INTERNAL
+/// Special case for get<null>(), just checks that value contains NULL.
template<> inline void get<null>(const value& v, null&) { assert_type_equal(NULL_TYPE, v.type()); }
+
+/// @cond INTERNAL
template<class T> void value::get(T &x) const { x = proton::get<T>(*this); }
template<class T> T value::get() const { return proton::get<T>(*this); }
inline int64_t value::as_int() const { return proton::coerce<int64_t>(*this); }
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/src/interop_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/interop_test.cpp b/proton-c/bindings/cpp/src/interop_test.cpp
index 22581f0..45f6a0d 100644
--- a/proton-c/bindings/cpp/src/interop_test.cpp
+++ b/proton-c/bindings/cpp/src/interop_test.cpp
@@ -46,10 +46,10 @@ string read(string filename) {
// Test data ostream operator
void test_data_ostream() {
- value dv;
- decoder d(dv);
+ data dt(data::create());
+ decoder d(dt);
d.decode(read("primitives"));
- ASSERT_EQUAL("true, false, 42, 42, -42, 12345, -12345, 12345, -12345, 0.125, 0.125", str(dv));
+ ASSERT_EQUAL("true, false, 42, 42, -42, 12345, -12345, 12345, -12345, 0.125, 0.125", str(dt));
}
// Test extracting to exact AMQP types works corectly, extrating to invalid types fails.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/src/scalar_base.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar_base.cpp b/proton-c/bindings/cpp/src/scalar_base.cpp
index 20694db..c94bc34 100644
--- a/proton-c/bindings/cpp/src/scalar_base.cpp
+++ b/proton-c/bindings/cpp/src/scalar_base.cpp
@@ -30,6 +30,11 @@
#include <ostream>
+#if PN_CPP_HAS_CPP11
+#include <cxxabi.h>
+#include <memory>
+#endif
+
namespace proton {
namespace internal {
@@ -114,13 +119,13 @@ namespace {
struct equal_op {
const scalar_base& x;
equal_op(const scalar_base& s) : x(s) {}
- template<class T> bool operator()(const T& y) { return (x.get<T>() == y); }
+ template<class T> bool operator()(const T& y) { return (get<T>(x) == y); }
};
struct less_op {
const scalar_base& x;
less_op(const scalar_base& s) : x(s) {}
- template<class T> bool operator()(const T& y) { return (y < x.get<T>()); }
+ template<class T> bool operator()(const T& y) { return (y < get<T>(x)); }
};
struct ostream_op {
@@ -144,8 +149,25 @@ bool operator<(const scalar_base& x, const scalar_base& y) {
}
std::ostream& operator<<(std::ostream& o, const scalar_base& s) {
- if (s.type() == NULL_TYPE) return o << "<null>";
- return internal::visit<std::ostream&>(s, ostream_op(o));
+ switch (s.type()) {
+ case NULL_TYPE: return o << "<null>";
+ // Print byte types as integer, not char.
+ case BYTE: return o << static_cast<int>(get<int8_t>(s));
+ case UBYTE: return o << static_cast<unsigned int>(get<uint8_t>(s));
+ // Other types printed using normal C++ operator <<
+ default: return internal::visit<std::ostream&>(s, ostream_op(o));
+ }
+}
+
+conversion_error make_coercion_error(const char* cpp_mangled, type_id amqp) {
+#if PN_CPP_HAS_CPP11
+ std::unique_ptr<char, decltype(&::free)> demangled(
+ abi::__cxa_demangle(cpp_mangled, NULL, NULL, NULL), ::free);
+ std::string cpp_name = demangled ? demangled.get() : cpp_mangled;
+#else
+ std::string cpp_name = cpp_mangled;
+#endif
+ return conversion_error("invalid proton::coerce<" + cpp_name + ">(" + type_name(amqp) + ")");
}
}} // namespaces
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/src/scalar_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar_test.cpp b/proton-c/bindings/cpp/src/scalar_test.cpp
index f6df832..3d6d6de 100644
--- a/proton-c/bindings/cpp/src/scalar_test.cpp
+++ b/proton-c/bindings/cpp/src/scalar_test.cpp
@@ -17,19 +17,7 @@
* under the License.
*/
-#include "test_bits.hpp"
-
-#include "proton/binary.hpp"
-#include "proton/error.hpp"
-#include "proton/internal/type_traits.hpp"
-
-#include "proton/scalar.hpp"
-#include "proton/value.hpp"
-#include "proton/message_id.hpp"
-#include "proton/annotation_key.hpp"
-#include "proton/decimal.hpp"
-
-#include <sstream>
+#include "scalar_test.hpp"
namespace {
@@ -37,59 +25,7 @@ using namespace std;
using namespace proton;
using namespace test;
-// Inserting and extracting simple C++ values.
-template <class T> void type_test(T x, type_id tid, T y) {
- scalar s(x);
- ASSERT_EQUAL(tid, s.type());
- ASSERT(!s.empty());
- ASSERT_EQUAL(x, s.get<T>());
-
- scalar v2;
- ASSERT(v2.type() == NULL_TYPE);
- v2 = x;
- ASSERT_EQUAL(tid, v2.type());
- ASSERT_EQUAL(x, v2.get<T>());
- ASSERT_EQUAL(s, v2);
- ASSERT_EQUAL(str(x), str(s));
-
- v2 = y;
- ASSERT(s != v2);
- ASSERT(s < v2);
- ASSERT(v2 > s);
-}
-
-#define ASSERT_MISMATCH(EXPR, WANT, GOT) \
- try { \
- (void)(EXPR); \
- FAIL("expected conversion_error: " #EXPR); \
- } catch (const conversion_error&) {}
-
-void coerce_test() {
- scalar a;
- ASSERT_EQUAL(NULL_TYPE, a.type());
- ASSERT(a.empty());
- ASSERT_MISMATCH(a.get<float>(), FLOAT, NULL_TYPE);
-
- a = binary("foo");
- ASSERT_MISMATCH(a.get<int16_t>(), SHORT, BINARY);
- ASSERT_MISMATCH(coerce<int64_t>(a), LONG, BINARY);
- ASSERT_MISMATCH(coerce<double>(a), DOUBLE, BINARY);
- ASSERT_MISMATCH(a.get<std::string>(), STRING, BINARY); // No strict conversion
- ASSERT_EQUAL(coerce<std::string>(a), std::string("foo")); // OK string-like conversion
-
- a = int16_t(42);
- ASSERT_MISMATCH(a.get<std::string>(), STRING, SHORT);
- ASSERT_MISMATCH(a.get<timestamp>(), TIMESTAMP, SHORT);
- ASSERT_MISMATCH(coerce<std::string>(a), STRING, SHORT);
- ASSERT_EQUAL(coerce<int64_t>(a), 42);
- ASSERT_EQUAL(coerce<uint64_t>(a), 42u);
- ASSERT_EQUAL(coerce<double>(a), 42);
-
- a = int16_t(-42);
- ASSERT_EQUAL(coerce<int64_t>(a), -42);
- ASSERT_EQUAL(coerce<uint64_t>(a), uint64_t(-42));
- ASSERT_EQUAL(coerce<double>(a), -42);
-}
+// NOTE: proton::coerce<> and bad proton::get() are tested in value_test to avoid redundant test code.
void encode_decode_test() {
value v;
@@ -98,23 +34,23 @@ void encode_decode_test() {
ASSERT_EQUAL(v, a);
ASSERT_EQUAL(std::string("foo"), get<std::string>(v));
scalar a2 = get<scalar>(v);
- ASSERT_EQUAL(std::string("foo"), a2.get<std::string>());
+ ASSERT_EQUAL(std::string("foo"), get<std::string>(a2));
}
void message_id_test() {
ASSERT_EQUAL(23, coerce<int64_t>(message_id(23)));
- ASSERT_EQUAL(23u, message_id(23).get<uint64_t>());
+ ASSERT_EQUAL(23u, get<uint64_t>(message_id(23)));
ASSERT(message_id("foo") != message_id(binary("foo")));
ASSERT_EQUAL(scalar("foo"), message_id("foo"));
ASSERT_EQUAL("foo", coerce<std::string>(message_id("foo")));
ASSERT(message_id("a") < message_id("z"));
uuid r = uuid::random();
- ASSERT_EQUAL(r, message_id(r).get<uuid>());
+ ASSERT_EQUAL(r, get<uuid>(message_id(r)));
}
void annotation_key_test() {
ASSERT_EQUAL(23, coerce<int64_t>(annotation_key(23)));
- ASSERT_EQUAL(23u, annotation_key(23).get<uint64_t>());
+ ASSERT_EQUAL(23u, get<uint64_t>(annotation_key(23)));
ASSERT_EQUAL("foo", coerce<std::string>(annotation_key("foo")));
ASSERT_EQUAL(scalar(symbol("foo")), annotation_key("foo"));
}
@@ -125,30 +61,10 @@ template <class T> T make(const char c) { T x; std::fill(x.begin(), x.end(), c);
int main(int, char**) {
int failed = 0;
- RUN_TEST(failed, type_test(false, BOOLEAN, true));
- RUN_TEST(failed, type_test(uint8_t(42), UBYTE, uint8_t(50)));
- RUN_TEST(failed, type_test(int8_t('x'), BYTE, int8_t('y')));
- RUN_TEST(failed, type_test(uint16_t(4242), USHORT, uint16_t(5252)));
- RUN_TEST(failed, type_test(int16_t(-4242), SHORT, int16_t(3)));
- RUN_TEST(failed, type_test(uint32_t(4242), UINT, uint32_t(5252)));
- RUN_TEST(failed, type_test(int32_t(-4242), INT, int32_t(3)));
- RUN_TEST(failed, type_test(uint64_t(4242), ULONG, uint64_t(5252)));
- RUN_TEST(failed, type_test(int64_t(-4242), LONG, int64_t(3)));
- RUN_TEST(failed, type_test(wchar_t(23), CHAR, wchar_t(24)));
- RUN_TEST(failed, type_test(float(1.234), FLOAT, float(2.345)));
- RUN_TEST(failed, type_test(double(11.2233), DOUBLE, double(12)));
- RUN_TEST(failed, type_test(timestamp(0), TIMESTAMP, timestamp(1)));
- RUN_TEST(failed, type_test(make<decimal32>(0), DECIMAL32, make<decimal32>(1)));
- RUN_TEST(failed, type_test(make<decimal64>(0), DECIMAL64, make<decimal64>(1)));
- RUN_TEST(failed, type_test(make<decimal128>(0), DECIMAL128, make<decimal128>(1)));
- RUN_TEST(failed, type_test(uuid::copy("a"), UUID, uuid::copy("x")));
- RUN_TEST(failed, type_test(std::string("aaa"), STRING, std::string("aaaa")));
- RUN_TEST(failed, type_test(symbol("aaa"), SYMBOL, symbol("aaaa")));
- RUN_TEST(failed, type_test(binary("aaa"), BINARY, binary("aaaa")));
- RUN_TEST(failed, type_test(std::string("xxx"), STRING, std::string("yyy")));
+ scalar_test_group<scalar>(failed);
+
RUN_TEST(failed, encode_decode_test());
RUN_TEST(failed, message_id_test());
RUN_TEST(failed, annotation_key_test());
- RUN_TEST(failed, coerce_test());
return failed;
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/src/scalar_test.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/scalar_test.hpp b/proton-c/bindings/cpp/src/scalar_test.hpp
new file mode 100644
index 0000000..87a529c
--- /dev/null
+++ b/proton-c/bindings/cpp/src/scalar_test.hpp
@@ -0,0 +1,209 @@
+#ifndef SCALAR_TEST_HPP
+#define SCALAR_TEST_HPP
+
+/*
+ * 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.
+ */
+
+// Template tests used by both scalar_test.cpp and value_test.hpp to test conversion
+// of scalar values via a proton::scalar or a proton::value.
+
+#include "test_bits.hpp"
+
+#include "proton/types.hpp"
+#include "proton/error.hpp"
+
+#include <sstream>
+
+
+namespace test {
+
+using namespace proton;
+
+// Inserting and extracting simple C++ values using same-type get<T> and coerce<T>
+template <class V, class T> void simple_type_test(T x, type_id tid, const std::string& s, T y) {
+ V vx(x); // Construct from C++ value
+ ASSERT_EQUAL(tid, vx.type());
+ ASSERT(!vx.empty());
+ ASSERT_EQUAL(x, get<T>(vx));
+ ASSERT_EQUAL(x, coerce<T>(vx));
+
+ V vxa = x; // Assign from C++ value
+ ASSERT_EQUAL(tid, vxa.type());
+ ASSERT(!vx.empty());
+ ASSERT_EQUAL(vx, vxa);
+ ASSERT_EQUAL(x, get<T>(vxa));
+ ASSERT_EQUAL(x, coerce<T>(vxa));
+
+ V v2; // Default construct
+ ASSERT(v2.type() == NULL_TYPE);
+ ASSERT(v2.empty());
+ v2 = x; // Assign from C++ value
+ ASSERT_EQUAL(tid, v2.type());
+ ASSERT_EQUAL(vx, v2);
+ ASSERT_EQUAL(x, get<T>(v2));
+ ASSERT_EQUAL(x, coerce<T>(v2));
+
+ V v3(vx); // Copy construct
+ ASSERT_EQUAL(tid, v3.type());
+ ASSERT_EQUAL(vx, v3);
+ ASSERT_EQUAL(x, get<T>(v3));
+ ASSERT_EQUAL(x, coerce<T>(v3));
+
+ V v4 = vx; // Copy assign
+ ASSERT_EQUAL(tid, v4.type());
+ ASSERT_EQUAL(x, get<T>(v4));
+ ASSERT_EQUAL(x, coerce<T>(v4));
+
+ ASSERT_EQUAL(s, str(vx)); // Stringify
+ V vy(y);
+ ASSERT(vx != vy); // Compare
+ ASSERT(vx < vy);
+ ASSERT(vy > vx);
+}
+
+// Test native C/C++ integer types via their mapped integer type ([u]int_x_t)
+template <class V, class T> void simple_integral_test() {
+ typedef typename internal::integer_type<sizeof(T), internal::is_signed<T>::value>::type int_type;
+ simple_type_test<V>(T(3), internal::type_id_of<int_type>::value, "3", T(4));
+}
+
+// Test invalid gets, valid same-type get<T> is tested by simple_type_test
+// Templated to test both scalar and value.
+template<class V> void bad_get_test() {
+ try { get<bool>(V(int8_t(1))); FAIL("byte as bool"); } catch (conversion_error) {}
+ try { get<uint8_t>(V(true)); FAIL("bool as uint8_t"); } catch (conversion_error) {}
+ try { get<uint8_t>(V(int8_t(1))); FAIL("int8 as uint8"); } catch (conversion_error) {}
+ try { get<int16_t>(V(uint16_t(1))); FAIL("uint16 as int16"); } catch (conversion_error) {}
+ try { get<int16_t>(V(int32_t(1))); FAIL("int32 as int16"); } catch (conversion_error) {}
+ try { get<symbol>(V(std::string())); FAIL("string as symbol"); } catch (conversion_error) {}
+ try { get<std::string>(V(binary())); FAIL("binary as string"); } catch (conversion_error) {}
+ try { get<binary>(V(symbol())); FAIL("symbol as binary"); } catch (conversion_error) {}
+ try { get<binary>(V(timestamp())); FAIL("timestamp as binary"); } catch (conversion_error) {}
+ try { get<int>(V(timestamp())); FAIL("timestamp as int"); } catch (conversion_error) {}
+ try { get<timestamp>(V(0)); FAIL("int as timestamp"); } catch (conversion_error) {}
+ try { get<timestamp>(V(std::string())); FAIL("string as timestamp"); } catch (conversion_error) {}
+}
+
+// Test some valid coercions and some bad ones with mixed types.
+// Templated to test both scalar and value.
+template<class V> void coerce_test() {
+ // Valid C++ conversions should work with coerce.
+ ASSERT_EQUAL(false, coerce<bool>(V(0)));
+ ASSERT_EQUAL(true, coerce<bool>(V(-1)));
+ ASSERT_EQUAL(true, coerce<bool>(V(int64_t(0xFFFF0000))));
+
+ ASSERT_EQUAL(1, coerce<uint8_t>(V(uint64_t(1)))); // In range.
+ ASSERT_EQUAL(1, coerce<uint8_t>(V(uint32_t(0xFF01)))); // int truncate.
+ ASSERT_EQUAL(0xFFFF, coerce<uint16_t>(V(int8_t(-1)))); // Sign extend.
+ ASSERT_EQUAL(-1, coerce<int32_t>(V(uint64_t(0xFFFFFFFFul)))); // 2s complement
+
+ ASSERT_EQUALISH(1.2, coerce<float>(V(double(1.2))), 0.001);
+ ASSERT_EQUALISH(3.4, coerce<double>(V(float(3.4))), 0.001);
+ ASSERT_EQUALISH(23.0, coerce<double>(V(uint64_t(23))), 0.001); // int to double.
+ ASSERT_EQUAL(-1945, coerce<int>(V(float(-1945.123)))); // round to int.
+
+ // String-like conversions.
+ ASSERT_EQUAL(std::string("foo"), coerce<std::string>(V(symbol("foo"))));
+ ASSERT_EQUAL(std::string("foo"), coerce<std::string>(V(binary("foo"))));
+
+ // Bad coercions, types are not `is_convertible`
+ V s("foo");
+ try { coerce<bool>(s); FAIL("string as bool"); } catch (conversion_error) {}
+ try { coerce<int>(s); FAIL("string as int"); } catch (conversion_error) {}
+ try { coerce<double>(s); FAIL("string as double"); } catch (conversion_error) {}
+
+ try { coerce<std::string>(V(0)); FAIL("int as string"); } catch (conversion_error) {}
+ try { coerce<symbol>(V(true)); FAIL("bool as symbol"); } catch (conversion_error) {}
+ try { coerce<binary>(V(0.0)); FAIL("double as binary"); } catch (conversion_error) {}
+ try { coerce<symbol>(V(binary())); FAIL("binary as symbol"); } catch (conversion_error) {}
+ try { coerce<binary>(V(symbol())); FAIL("symbol as binary"); } catch (conversion_error) {}
+ try { coerce<binary>(s); } catch (conversion_error) {}
+ try { coerce<symbol>(s); } catch (conversion_error) {}
+}
+
+template <class V> void null_test() {
+ V v;
+ ASSERT(v.empty());
+ ASSERT_EQUAL(NULL_TYPE, v.type());
+ get<null>(v);
+ null n;
+ get(v, n);
+ V v2(n);
+ ASSERT(v.empty());
+ ASSERT_EQUAL(NULL_TYPE, v.type());
+ v = "foo";
+ ASSERT_EQUAL(STRING, v.type());
+ try { get<null>(v); FAIL("Expected conversion_error"); } catch (conversion_error) {}
+ v = null();
+ get<null>(v);
+}
+
+// Nasty hack for uninterpreted decimal<> types.
+template <class T> T make(const char c) { T x; std::fill(x.begin(), x.end(), c); return x; }
+
+template <class V> void scalar_test_group(int& failed) {
+ // Direct AMQP-mapped types.
+ RUN_TEST(failed, simple_type_test<V>(false, BOOLEAN, "false", true));
+ RUN_TEST(failed, simple_type_test<V>(uint8_t(42), UBYTE, "42", uint8_t(50)));
+ RUN_TEST(failed, simple_type_test<V>(int8_t(-42), BYTE, "-42", int8_t(-40)));
+ RUN_TEST(failed, simple_type_test<V>(uint16_t(4242), USHORT, "4242", uint16_t(5252)));
+ RUN_TEST(failed, simple_type_test<V>(int16_t(-4242), SHORT, "-4242", int16_t(3)));
+ RUN_TEST(failed, simple_type_test<V>(uint32_t(4242), UINT, "4242", uint32_t(5252)));
+ RUN_TEST(failed, simple_type_test<V>(int32_t(-4242), INT, "-4242", int32_t(3)));
+ RUN_TEST(failed, simple_type_test<V>(uint64_t(4242), ULONG, "4242", uint64_t(5252)));
+ RUN_TEST(failed, simple_type_test<V>(int64_t(-4242), LONG, "-4242", int64_t(3)));
+ RUN_TEST(failed, simple_type_test<V>(wchar_t('X'), CHAR, "88", wchar_t('Y')));
+ RUN_TEST(failed, simple_type_test<V>(float(1.234), FLOAT, "1.234", float(2.345)));
+ RUN_TEST(failed, simple_type_test<V>(double(11.2233), DOUBLE, "11.2233", double(12)));
+ RUN_TEST(failed, simple_type_test<V>(timestamp(1234), TIMESTAMP, "1234", timestamp(12345)));
+ RUN_TEST(failed, simple_type_test<V>(make<decimal32>(1), DECIMAL32, "decimal32(0x01010101)", make<decimal32>(2)));
+ RUN_TEST(failed, simple_type_test<V>(make<decimal64>(3), DECIMAL64, "decimal64(0x0303030303030303)", make<decimal64>(4)));
+ RUN_TEST(failed, simple_type_test<V>(make<decimal128>(5), DECIMAL128, "decimal128(0x05050505050505050505050505050505)", make<decimal128>(6)));
+ RUN_TEST(failed, simple_type_test<V>(
+ uuid::copy("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"),
+ UUID, "00112233-4455-6677-8899-aabbccddeeff",
+ uuid::copy("\xff\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff")));
+ RUN_TEST(failed, simple_type_test<V>(std::string("xxx"), STRING, "xxx", std::string("yyy")));
+ RUN_TEST(failed, simple_type_test<V>(symbol("aaa"), SYMBOL, "aaa", symbol("aaaa")));
+ RUN_TEST(failed, simple_type_test<V>(binary("\010aaa"), BINARY, "b\"\\x08aaa\"", binary("aaaa")));
+
+ // Test native C++ integral types.
+ RUN_TEST(failed, (simple_integral_test<V, char>()));
+ RUN_TEST(failed, (simple_integral_test<V, signed char>()));
+ RUN_TEST(failed, (simple_integral_test<V, unsigned char>()));
+ RUN_TEST(failed, (simple_integral_test<V, short>()));
+ RUN_TEST(failed, (simple_integral_test<V, int>()));
+ RUN_TEST(failed, (simple_integral_test<V, long>()));
+ RUN_TEST(failed, (simple_integral_test<V, unsigned short>()));
+ RUN_TEST(failed, (simple_integral_test<V, unsigned int>()));
+ RUN_TEST(failed, (simple_integral_test<V, unsigned long>()));
+#if PN_CPP_HAS_LONG_LONG
+ RUN_TEST(failed, (simple_integral_test<V, long long>()));
+ RUN_TEST(failed, (simple_integral_test<V, unsigned long long>()));
+#endif
+
+
+ RUN_TEST(failed, (coerce_test<V>()));
+ RUN_TEST(failed, (null_test<V>()));
+ RUN_TEST(failed, (bad_get_test<V>()));
+}
+
+}
+
+#endif // SCALAR_TEST_HPP
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/src/test_bits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/test_bits.hpp b/proton-c/bindings/cpp/src/test_bits.hpp
index 6dc629d..6486e48 100644
--- a/proton-c/bindings/cpp/src/test_bits.hpp
+++ b/proton-c/bindings/cpp/src/test_bits.hpp
@@ -67,7 +67,9 @@ inline void assert_equalish(double want, double got, double delta, const std::st
++BAD_COUNT; \
} while(0)
-template<class T> std::string str(const T& x) { std::ostringstream s; s << x; return s.str(); }
+template<class T> std::string str(const T& x) {
+ std::ostringstream s; s << std::boolalpha << x; return s.str();
+}
// A way to easily create literal collections that can be compared to std:: collections
// and to print std collections
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/src/value.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/value.cpp b/proton-c/bindings/cpp/src/value.cpp
index dd4f108..c5c71a0 100644
--- a/proton-c/bindings/cpp/src/value.cpp
+++ b/proton-c/bindings/cpp/src/value.cpp
@@ -176,8 +176,9 @@ std::ostream& operator<<(std::ostream& o, const internal::value_base& x) {
if (x.empty())
return o << "<null>";
proton::decoder d(x);
- // Print std::string and proton::foo types using their own operator << consistent with C++.
+ // Print the following types with operator<<() consistent with C++.
switch (d.next_type()) {
+ case BOOLEAN: return o << get<bool>(d); // Respect std::boolalpha settings.
case STRING: return o << get<std::string>(d);
case SYMBOL: return o << get<symbol>(d);
case DECIMAL32: return o << get<decimal32>(d);
@@ -185,6 +186,7 @@ std::ostream& operator<<(std::ostream& o, const internal::value_base& x) {
case DECIMAL128: return o << get<decimal128>(d);
case UUID: return o << get<uuid>(d);
case TIMESTAMP: return o << get<timestamp>(d);
+ case CHAR: return o << get<wchar_t>(d);
default:
// Use pn_inspect for other types.
return o << d;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8d0c5afd/proton-c/bindings/cpp/src/value_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/value_test.cpp b/proton-c/bindings/cpp/src/value_test.cpp
index e37b792..966f415 100644
--- a/proton-c/bindings/cpp/src/value_test.cpp
+++ b/proton-c/bindings/cpp/src/value_test.cpp
@@ -17,10 +17,7 @@
* under the License.
*/
-#include "test_bits.hpp"
-
-#include "proton/types.hpp"
-#include "proton/error.hpp"
+#include "scalar_test.hpp"
namespace {
@@ -28,55 +25,29 @@ using namespace std;
using namespace proton;
using namespace test;
-// Inserting and extracting simple C++ values.
-template <class T> void simple_type_test(T x, type_id tid, const std::string& s, T y) {
- value vx(x);
- ASSERT_EQUAL(tid, vx.type());
- ASSERT_EQUAL(x, get<T>(vx));
-
- value vxa = x;
- ASSERT_EQUAL(tid, vxa.type());
- ASSERT_EQUAL(x, get<T>(vxa));
-
- value v2;
- v2 = x;
- ASSERT_EQUAL(tid, v2.type());
- ASSERT_EQUAL(x, get<T>(v2));
-
- value v3(vx);
- ASSERT_EQUAL(tid, v3.type());
- ASSERT_EQUAL(x, get<T>(v3));
-
- value v4 = vx;
- ASSERT_EQUAL(tid, v4.type());
- ASSERT_EQUAL(x, get<T>(v4));
-
-
- ASSERT_EQUAL(vx, v2);
- ASSERT_EQUAL(s, str(vx));
- value vy(y);
- ASSERT(vx != vy);
- ASSERT(vx < vy);
- ASSERT(vy > vx);
-}
-
-template <class T> void simple_integral_test() {
- typedef typename internal::integer_type<sizeof(T), internal::is_signed<T>::value>::type int_type;
- simple_type_test(T(3), internal::type_id_of<int_type>::value, "3", T(4));
-}
-
// Inserting and extracting arrays from a container T of type U
template <class T> void sequence_test(type_id tid, const many<typename T::value_type>& values) {
T x(values.begin(), values.end());
- value vx(x); // construt
+ value vx(x); // construct
ASSERT_EQUAL(tid, vx.type());
ASSERT_EQUAL(x, get<T>(vx));
-
+ ASSERT_EQUAL(x, coerce<T>(vx));
+ {
+ T y;
+ get(vx, y); // Two argument get.
+ ASSERT_EQUAL(x, y);
+ }
+ {
+ T y;
+ coerce(vx, y); // Two argument coerce.
+ ASSERT_EQUAL(x, y);
+ }
value v2; // assign
v2 = x;
ASSERT_EQUAL(tid, v2.type());
ASSERT_EQUAL(x, get<T>(v2));
+ ASSERT_EQUAL(x, coerce<T>(v2));
ASSERT_EQUAL(vx, v2);
T y(x);
@@ -96,99 +67,11 @@ template <class T, class U> void map_test(const U& values) {
ASSERT_EQUAL(m, m2);
}
-template <class T> T make(const char c) {
- T x; std::fill(x.begin(), x.end(), c); return x;
-}
-
-void null_test() {
- value v;
- ASSERT(v.empty());
- ASSERT_EQUAL(NULL_TYPE, v.type());
- get<null>(v);
- null n;
- get(v, n);
- value v2(n);
- ASSERT(v.empty());
- ASSERT_EQUAL(NULL_TYPE, v.type());
- v = "foo";
- ASSERT_EQUAL(STRING, v.type());
- try { get<null>(v); FAIL("Expected conversion_error"); } catch (conversion_error) {}
- v = null();
- get<null>(v);
-}
-
-void get_coerce_test() {
- // Valid conversions
- ASSERT_EQUAL(true, coerce<bool>(value(true)));
-
- ASSERT_EQUAL(1, coerce<uint8_t>(value(uint8_t(1))));
- ASSERT_EQUAL(-1, coerce<int8_t>(value(int8_t(-1))));
-
- ASSERT_EQUAL(2, coerce<uint16_t>(value(uint8_t(2))));
- ASSERT_EQUAL(-2, coerce<int16_t>(value(int8_t(-2))));
-
- ASSERT_EQUAL(3u, coerce<uint32_t>(value(uint16_t(3))));
- ASSERT_EQUAL(-3, coerce<int32_t>(value(int16_t(-3))));
-
- ASSERT_EQUAL(4u, coerce<uint64_t>(value(uint32_t(4))));
- ASSERT_EQUAL(-4, coerce<int64_t>(value(int32_t(-4))));
-
- ASSERT_EQUALISH(1.2, coerce<float>(value(double(1.2))), 0.001);
- ASSERT_EQUALISH(3.4, coerce<double>(value(float(3.4))), 0.001);
-
- ASSERT_EQUAL(std::string("foo"), coerce<std::string>(value(symbol("foo"))));
-
- // Bad conversions
- try { get<bool>(value(int8_t(1))); FAIL("byte as bool"); } catch (conversion_error) {}
- try { get<uint8_t>(value(true)); FAIL("bool as uint8_t"); } catch (conversion_error) {}
- try { get<uint8_t>(value(int8_t(1))); FAIL("int8 as uint8"); } catch (conversion_error) {}
- try { get<int16_t>(value(uint16_t(1))); FAIL("uint16 as int16"); } catch (conversion_error) {}
- try { get<int16_t>(value(int32_t(1))); FAIL("int32 as int16"); } catch (conversion_error) {}
- try { get<symbol>(value(std::string())); FAIL("string as symbol"); } catch (conversion_error) {}
-}
-
}
int main(int, char**) {
int failed = 0;
- RUN_TEST(failed, simple_type_test(false, BOOLEAN, "false", true));
- RUN_TEST(failed, simple_type_test(uint8_t(42), UBYTE, "42", uint8_t(50)));
- RUN_TEST(failed, simple_type_test(int8_t(-42), BYTE, "-42", int8_t(-40)));
- RUN_TEST(failed, simple_type_test(uint16_t(4242), USHORT, "4242", uint16_t(5252)));
- RUN_TEST(failed, simple_type_test(int16_t(-4242), SHORT, "-4242", int16_t(3)));
- RUN_TEST(failed, simple_type_test(uint32_t(4242), UINT, "4242", uint32_t(5252)));
- RUN_TEST(failed, simple_type_test(int32_t(-4242), INT, "-4242", int32_t(3)));
- RUN_TEST(failed, simple_type_test(uint64_t(4242), ULONG, "4242", uint64_t(5252)));
- RUN_TEST(failed, simple_type_test(int64_t(-4242), LONG, "-4242", int64_t(3)));
- RUN_TEST(failed, simple_type_test(wchar_t('X'), CHAR, "X", wchar_t('Y')));
- RUN_TEST(failed, simple_type_test(float(1.234), FLOAT, "1.234", float(2.345)));
- RUN_TEST(failed, simple_type_test(double(11.2233), DOUBLE, "11.2233", double(12)));
- RUN_TEST(failed, simple_type_test(timestamp(1234), TIMESTAMP, "1234", timestamp(12345)));
- RUN_TEST(failed, simple_type_test(make<decimal32>(1), DECIMAL32, "decimal32(0x01010101)", make<decimal32>(2)));
- RUN_TEST(failed, simple_type_test(make<decimal64>(3), DECIMAL64, "decimal64(0x0303030303030303)", make<decimal64>(4)));
- RUN_TEST(failed, simple_type_test(make<decimal128>(5), DECIMAL128, "decimal128(0x05050505050505050505050505050505)", make<decimal128>(6)));
- RUN_TEST(failed, simple_type_test(
- uuid::copy("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"),
- UUID, "00112233-4455-6677-8899-aabbccddeeff",
- uuid::copy("\xff\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff")));
- RUN_TEST(failed, simple_type_test(std::string("xxx"), STRING, "xxx", std::string("yyy")));
- RUN_TEST(failed, simple_type_test(symbol("aaa"), SYMBOL, "aaa", symbol("aaaa")));
- RUN_TEST(failed, simple_type_test(binary("\010aaa"), BINARY, "b\"\\x08aaa\"", binary("aaaa")));
-
- // Test native C++ integral types.
- RUN_TEST(failed, simple_integral_test<char>());
- RUN_TEST(failed, simple_integral_test<signed char>());
- RUN_TEST(failed, simple_integral_test<unsigned char>());
- RUN_TEST(failed, simple_integral_test<short>());
- RUN_TEST(failed, simple_integral_test<int>());
- RUN_TEST(failed, simple_integral_test<long>());
- RUN_TEST(failed, simple_integral_test<unsigned short>());
- RUN_TEST(failed, simple_integral_test<unsigned int>());
- RUN_TEST(failed, simple_integral_test<unsigned long>());
-#if PN_CPP_HAS_LONG_LONG
- RUN_TEST(failed, simple_integral_test<long long>());
- RUN_TEST(failed, simple_integral_test<unsigned long long>());
-#endif
+ scalar_test_group<value>(failed);
// Sequence tests
RUN_TEST(failed, sequence_test<std::list<bool> >(ARRAY, many<bool>() + false + true));
@@ -221,8 +104,5 @@ int main(int, char**) {
RUN_TEST(failed, sequence_test<std::forward_list<binary> >(ARRAY, many<binary>() + binary("xx") + binary("yy")));
RUN_TEST(failed, (map_test<std::unordered_map<std::string, uint64_t> >(pairs)));
#endif
-
- RUN_TEST(failed, get_coerce_test());
- RUN_TEST(failed, null_test());
return failed;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org