ros_comm icon indicating copy to clipboard operation
ros_comm copied to clipboard

Fix printing XmlRpcValue with GTest

Open peci1 opened this issue 2 years ago • 0 comments

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>

peci1 avatar Jan 20 '22 11:01 peci1