Skip to content

v0.2.53..v0.2.54 changeset OsmApiChangesetElement.cpp

Garret Voltz edited this page Mar 31, 2020 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangesetElement.cpp b/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangesetElement.cpp
index 1d74420..7ed42cc 100644
--- a/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangesetElement.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangesetElement.cpp
@@ -22,7 +22,7 @@
  * This will properly maintain the copyright information. DigitalGlobe
  * copyrights will be updated automatically.
  *
- * @copyright Copyright (C) 2018, 2019 DigitalGlobe (http://www.digitalglobe.com/)
+ * @copyright Copyright (C) 2018, 2019, 2020 DigitalGlobe (http://www.digitalglobe.com/)
  */
 
 #include "OsmApiChangesetElement.h"
@@ -30,9 +30,6 @@
 #include <hoot/core/util/HootException.h>
 #include <hoot/core/visitors/ApiTagTruncateVisitor.h>
 
-//  Qt
-#include <QTextStream>
-
 namespace hoot
 {
 
@@ -52,7 +49,11 @@ ChangesetElement::ChangesetElement(const XmlObject& object, ElementIdToIdMap* id
     _status(ChangesetElement::Available)
 {
   for (QXmlStreamAttributes::const_iterator it = object.second.begin(); it != object.second.end(); ++it)
-    _object.push_back(std::make_pair(it->name().toString(), it->value().toString()));
+  {
+    //  Ignore the changeset attribute because it will be replaced later even if it does exist
+    if (it->name().compare(QString("changeset")) != 0)
+      _object.push_back(std::make_pair(it->name().toString(), it->value().toString()));
+  }
 }
 
 ChangesetElement::ChangesetElement(const ChangesetElement& element)
@@ -162,6 +163,99 @@ QString ChangesetElement::toTagString(const ElementTag& tag) const
   return ts.readAll();
 }
 
+bool ChangesetElement::diffElement(const ChangesetElement* element, QTextStream& ts1, QTextStream& ts2) const
+{
+  bool success = true;
+  //  Compare the IDs
+  if (_id != element->_id)
+  {
+    ts1 << "< id = " << _id << "\n";
+    ts2 << "> id = " << element->_id << "\n";
+    success = false;
+  }
+  //  Compare the attributes
+  if (!diffAttributes(element->_object, ts1, ts2))
+    success = false;
+  //  Compare the tags
+  if (!diffTags(element->_tags, ts1, ts2))
+    success = false;
+  return success;
+}
+
+bool ChangesetElement::diffAttributes(const ElementAttributes& attributes, QTextStream& ts1, QTextStream& ts2) const
+{
+  bool success = true;
+  //  Compare the attributes by count first
+  if (_object.size() != attributes.size())
+  {
+    ts1 << "< attribute count = " << _object.size() << "\n";
+    for (size_t index = 0; index < _object.size(); ++index)
+      ts1 << "< " << _object[index].first << " = " << _object[index].second << "\n";
+    ts2 << "> attribute count = " << attributes.size() << "\n";
+    for (size_t index = 0; index < attributes.size(); ++index)
+      ts2 << "> " << attributes[index].first << " = " << attributes[index].second << "\n";
+    success = false;
+  }
+  else
+  {
+    //  Compare attributes one by one
+    for (size_t index = 0; index < _object.size(); ++index)
+    {
+      QString name1 = _object[index].first;
+      QString value1 = _object[index].second;
+      QString name2 = attributes[index].first;
+      QString value2 = attributes[index].second;
+      //  Some attributes can have different values and still be equivalent
+      if (name1 == "action" || name1 == "version" || name1 == "changeset")
+        continue;
+      //  Compare names and values
+      if (name1 != name2 && value1 != value2)
+      {
+        ts1 << "< " << name1 << " = " << value1 << "\n";
+        ts2 << "> " << name2 << " = " << value2 << "\n";
+        success = false;
+      }
+    }
+  }
+  return success;
+}
+
+bool ChangesetElement::diffTags(const ElementTags& tags,  QTextStream& ts1, QTextStream& ts2) const
+{
+  bool success = true;
+  //  Compare the tags by count first
+  if (_tags.size() != tags.size())
+  {
+    ts1 << "< tag count = " << _tags.size() << "\n";
+    for (size_t index = 0; index < _tags.size(); ++index)
+      ts1 << "< " << _tags[index].first << " = " << _tags[index].second << "\n";
+    ts2 << "> tag count = " << tags.size() << "\n";
+    for (size_t index = 0; index < tags.size(); ++index)
+      ts2 << "> " << tags[index].first << " = " << tags[index].second << "\n";
+    success = false;
+  }
+  else
+  {
+    //  Compare tags one by one
+    for (size_t index = 0; index < _tags.size(); ++index)
+    {
+      QString key1 = _tags[index].first;
+      QString value1 = _tags[index].second;
+      QString key2 = tags[index].first;
+      QString value2 = tags[index].second;
+      //  Ignore any tags here?
+      //  Compare keys and values
+      if (key1 != key2 && value1 != value2)
+      {
+        ts1 << "< " << key1 << " = " << value1 << "\n";
+        ts2 << "> " << key2 << " = " << value2 << "\n";
+        success = false;
+      }
+    }
+  }
+  return success;
+}
+
 ChangesetNode::ChangesetNode(const XmlObject& node, ElementIdToIdMap* idMap)
   : ChangesetElement(node, idMap)
 {
@@ -192,6 +286,28 @@ QString ChangesetNode::toString(long changesetId) const
   return ts.readAll();
 }
 
+bool ChangesetNode::diff(const ChangesetNode& node, QString& diffOutput) const
+{
+  bool success = true;
+  QString buffer1;
+  QTextStream ts1(&buffer1);
+  ts1.setCodec("UTF-8");
+  QString buffer2;
+  QTextStream ts2(&buffer2);
+  ts2.setCodec("UTF-8");
+  //  Compare the common element data
+  if (!diffElement(&node, ts1, ts2))
+    success = false;
+  //  Create the diff when the two nodes are different
+  if (!success)
+  {
+    ts1 << "--------------------\n" << ts2.readAll();
+    diffOutput = ts1.readAll();
+  }
+  //  Return success variable
+  return success;
+}
+
 ChangesetWay::ChangesetWay(const XmlObject& way, ElementIdToIdMap* idMap)
   : ChangesetElement(way, idMap)
 {
@@ -231,6 +347,60 @@ QString ChangesetWay::toString(long changesetId) const
   return ts.readAll();
 }
 
+bool ChangesetWay::diff(const ChangesetWay& way, QString& diffOutput) const
+{
+  bool success = true;
+  QString buffer1;
+  QTextStream ts1(&buffer1);
+  ts1.setCodec("UTF-8");
+  QString buffer2;
+  QTextStream ts2(&buffer2);
+  ts2.setCodec("UTF-8");
+  //  Compare the common element data
+  if (!diffElement(&way, ts1, ts2))
+    success = false;
+  //  Compare the way nodes
+  if (_nodes.size() != way._nodes.size())
+  {
+    ts1 << "< node count = " << _nodes.size() << "\n";
+    for (int index = 0; index < _nodes.size(); ++index)
+      ts1 << "< " << _nodes[index] << "\n";
+    ts2 << "> node count = " << way._nodes.size() << "\n";
+    for (int index = 0; index < way._nodes.size(); ++index)
+      ts2 << "> " << way._nodes[index] << "\n";
+    success = false;
+  }
+  else
+  {
+    //  Compare node IDs one by one
+    for (int index = 0; index < _nodes.size(); ++index)
+    {
+      //  Node IDs
+      if (_nodes[index] != way._nodes[index] && _nodes[index] != way._idMap->getId(ElementType::Node, way._nodes[index]))
+      {
+        ts1 << "< nodes = ";
+        for (QVector<long>::const_iterator it = _nodes.begin(); it != _nodes.end(); ++it)
+          ts1 << *it << " ";
+        ts1 << "\n";
+        ts2 << "> nodes = ";
+        for (QVector<long>::const_iterator it = way._nodes.begin(); it != way._nodes.end(); ++it)
+          ts2 << *it << " ";
+        ts2 << "\n";
+        success = false;
+        break;
+      }
+    }
+  }
+  //  Create the diff when the two nodes are different
+  if (!success)
+  {
+    ts1 << "--------------------\n" << ts2.readAll();
+    diffOutput = ts1.readAll();
+  }
+  //  Return success variable
+  return success;
+}
+
 ChangesetRelation::ChangesetRelation(const XmlObject& relation, ElementIdToIdMap* idMap)
   : ChangesetElement(relation, idMap)
 {
@@ -290,6 +460,44 @@ QString ChangesetRelation::toString(long changesetId) const
   return ts.readAll();
 }
 
+bool ChangesetRelation::diff(const ChangesetRelation& relation, QString& diffOutput) const
+{
+  bool success = true;
+  QString buffer1;
+  QTextStream ts1(&buffer1);
+  ts1.setCodec("UTF-8");
+  QString buffer2;
+  QTextStream ts2(&buffer2);
+  ts2.setCodec("UTF-8");
+  //  Compare the common element data
+  if (!diffElement(&relation, ts1, ts2))
+    success = false;
+  //  Compare the members
+  if (_members.size() != relation._members.size())
+  {
+    ts1 << "< member count = " << _members.size() << "\n";
+    ts2 << "> member count = " << relation._members.size() << "\n";
+    success = false;
+  }
+  else
+  {
+    //  Compare members one by one
+    for (int index = 0; index < _members.size(); ++index)
+    {
+      if (!_members[index].diff(relation._members[index], ts1, ts2))
+        success = false;
+    }
+  }
+  //  Create the diff when the two nodes are different
+  if (!success)
+  {
+    ts1 << "--------------------\n" << ts2.readAll();
+    diffOutput = ts1.readAll();
+  }
+  //  Return success variable
+  return success;
+}
+
 ChangesetRelationMember::ChangesetRelationMember(const QXmlStreamAttributes& member, ElementIdToIdMap* idMap)
   : _type(ElementType::fromString(member.value("type").toString().toLower())),
     _ref(member.value("ref").toString().toLong()),
@@ -309,4 +517,31 @@ QString ChangesetRelationMember::toString() const
   return ts.readAll();
 }
 
+bool ChangesetRelationMember::diff(const ChangesetRelationMember& member, QTextStream& ts1, QTextStream& ts2) const
+{
+  bool success = true;
+  //  Compare the ref IDs
+  if (_ref != member._ref && _ref != member._idMap->getId(member._type, member._ref))
+  {
+    ts1 << "< ref = " << _ref << "\n";
+    ts2 << "> ref = " << member._ref << "\n";
+    success = false;
+  }
+  //  Compare the member type
+  if (_type != member._type)
+  {
+    ts1 << "< type = " << _type << "\n";
+    ts2 << "> type = " << member._type << "\n";
+    success = false;
+  }
+  //  Compare the member role
+  if (_role != member._role)
+  {
+    ts1 << "< role = " << _role << "\n";
+    ts2 << "> role = " << member._role << "\n";
+    success = false;
+  }
+  return success;
+}
+
 }
Clone this wiki locally