ros_comm
ros_comm copied to clipboard
Fix printing XmlRpcValue with GTest
The following GTest call currently ends in XmlRpcException("type error: expected a struct")
being thrown:
EXPECT_EQ(XmlRpc::XmlRpcValue(false), XmlRpc::XmlRpcValue(0));
That is because GTest tries to print all XmlRpcValues as "containers". Here is the code how GTest determines whether a value is a container:
typedef int IsContainer;
template <class C>
IsContainer IsContainerTest(int /* dummy */,
typename C::iterator* /* it */ = NULL,
typename C::const_iterator* /* const_it */ = NULL) {
return 0;
}
XmlRpcValue contains the iterator
and const_iterator
typedefs, so it satisifies the GTest condition to be treated as a container.
Further in GTest code:
template <typename C>
void DefaultPrintTo(IsContainer /* dummy */,
false_type /* is not a pointer */,
const C& container, ::std::ostream* os) {
const size_t kMaxCount = 32; // The maximum number of elements to print.
*os << '{';
size_t count = 0;
for (typename C::const_iterator it = container.begin();
it != container.end(); ++it, ++count) {
if (count > 0) {
*os << ',';
if (count == kMaxCount) { // Enough has been printed.
*os << " ...";
break;
}
}
*os << ' ';
// We cannot call PrintTo(*it, os) here as PrintTo() doesn't
// handle *it being a native array.
internal::UniversalPrint(*it, os);
}
if (count > 0) {
*os << ' ';
}
*os << '}';
}
This function calls container.begin()
, which in case of XmlRpcValue results in assertStruct()
being called. And that throws the exception for non-struct values.
The fix is simple - GTest looks for a PrintTo()
method and if it finds it, it uses this method to print values and skips the default printer which is problematic.
I chose to print the toXml()
value instead of calling write()
so that the GTest output is more explicit about what kind of values failed to compare.
I get this output with this PR:
Failure
Expected: XmlRpc::XmlRpcValue(false)
Which is: <value><boolean>0</boolean></value>
To be equal to: XmlRpc::XmlRpcValue(0)
Which is: <value><i4>0</i4></value>