Browse Source

Fix comparing of repeated types

- Fix the way how repeated types are compared. Since protobuf doesn't
  strict the order of repeated types we should avoid dummy comparing
  of QList, but look for the items. This causes higher lookup
  complexity but better work.
- QList containing QSharedPointer returns tru only if the pointer
  values of QSharedPointer are the same but not actual values in the
  structures. This is critical issue since lists containing the same
  values return faulty false values

Fixes #229
Alexey Edelev 3 năm trước cách đây
mục cha
commit
c6d7977a54

+ 2 - 0
src/generator/messagedefinitionprinter.cpp

@@ -333,6 +333,8 @@ void MessageDefinitionPrinter::printComparisonOperators()
         }
         if (common::isPureMessage(field)) {
             mPrinter->Print(propertyMap, Templates::EqualOperatorMessagePropertyTemplate);
+        } else if (field->type() == FieldDescriptor::TYPE_MESSAGE && field->is_repeated()) {
+            mPrinter->Print(propertyMap, Templates::EqualOperatorRepeatedPropertyTemplate);
         } else {
             mPrinter->Print(propertyMap, Templates::EqualOperatorPropertyTemplate);
         }

+ 3 - 1
src/generator/templates.cpp

@@ -166,7 +166,9 @@ const char *Templates::EmptyEqualOperatorDefinitionTemplate = "bool $classname$:
                                                               "    return true;\n"
                                                               "}\n\n";
 const char *Templates::EqualOperatorPropertyTemplate = "m_$property_name$ == other.m_$property_name$";
-const char *Templates::EqualOperatorMessagePropertyTemplate = "m_$property_name$ == other.m_$property_name$\n";
+const char *Templates::EqualOperatorMessagePropertyTemplate = "(m_$property_name$ == other.m_$property_name$\n"
+                                                              "    || *m_$property_name$ == *other.m_$property_name$)\n";
+const char *Templates::EqualOperatorRepeatedPropertyTemplate = "QtProtobuf::repeatedValueCompare(m_$property_name$, other.m_$property_name$)";
 
 const char *Templates::NotEqualOperatorDeclarationTemplate = "bool operator !=(const $classname$ &other) const;\n";
 const char *Templates::NotEqualOperatorDefinitionTemplate = "bool $classname$::operator !=(const $classname$ &other) const\n{\n"

+ 1 - 0
src/generator/templates.h

@@ -126,6 +126,7 @@ public:
     static const char *EmptyEqualOperatorDefinitionTemplate;
     static const char *EqualOperatorPropertyTemplate;
     static const char *EqualOperatorMessagePropertyTemplate;
+    static const char *EqualOperatorRepeatedPropertyTemplate;
     static const char *NotEqualOperatorDeclarationTemplate;
     static const char *NotEqualOperatorDefinitionTemplate;
     static const char *GetterPrivateMessageDeclarationTemplate;

+ 41 - 0
src/protobuf/qtprotobuftypes.h

@@ -28,6 +28,7 @@
 #include "qtprotobufglobal.h"
 
 #include <QList>
+#include <QMap>
 #include <QMetaType>
 
 #include <unordered_map>
@@ -274,6 +275,45 @@ struct ProtoTypeRegistrar {
     }
 };
 
+template<typename T>
+bool repeatedValueCompare(const QList<QSharedPointer<T>>& a, const QList<QSharedPointer<T>>& b) {
+    if (a.size() != b.size()) {
+        return false;
+    }
+    auto itA = std::begin(a);
+    auto itB = std::begin(b);
+    while (itA != std::end(a) && itB != std::end(b)) {
+        if (*itA != *itB && *(*itA) != *(*itB)) {
+            return false;
+        }
+        ++itA;
+        ++itB;
+    }
+
+    return true;
+}
+
+template<typename K, typename V>
+bool repeatedValueCompare(const QMap<K, V>& a, const QMap<K, V>& b) {
+    return a == b;
+}
+
+template<typename K, typename V>
+bool repeatedValueCompare(const QMap<K, QSharedPointer<V>>& a, const QMap<K, QSharedPointer<V>>& b) {
+    if (a.size() != b.size()) {
+        return false;
+    }
+
+    for (auto itA = a.keyValueBegin(); itA != a.keyValueEnd(); ++itA) {
+        if (b.value((*itA).first) != (*itA).second
+                && *(b.value((*itA).first)) != *((*itA).second)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 }
 
 Q_DECLARE_METATYPE(QtProtobuf::int32)
@@ -366,4 +406,5 @@ template<> struct hash<QString> {
     }
 };
 #endif
+
 }

+ 31 - 0
tests/test_protobuf/simpletest.cpp.inc

@@ -945,5 +945,36 @@ TEST_F(SimpleTest, NoPackageMessageTest)
     ASSERT_EQ(test.property(propertyName).value<SimpleIntMessageExt*>()->testFieldInt(), 42);
     ASSERT_EQ(test.testField().testFieldInt(), 42);
 }
+
+TEST_F(SimpleTest, RepeatedComplexMessageCompareTest)
+{
+    QSharedPointer<ComplexMessage> msg1(new ComplexMessage(10, {"qwerty"}));
+    QSharedPointer<ComplexMessage> msg2(new ComplexMessage(20, {"ytrewq"}));
+
+    QSharedPointer<ComplexMessage> msg3(new ComplexMessage(10, {"qwerty"}));
+    QSharedPointer<ComplexMessage> msg4(new ComplexMessage(20, {"ytrewq"}));
+
+    ASSERT_TRUE(*msg1 == *msg3);
+    ASSERT_TRUE(*msg2 == *msg4);
+
+    RepeatedComplexMessage test1 = RepeatedComplexMessage({msg1, msg2});
+    RepeatedComplexMessage test2 = RepeatedComplexMessage({msg3, msg4});
+    RepeatedComplexMessage test3 = RepeatedComplexMessage({msg4, msg3});
+    ASSERT_TRUE(test1 == test2);
+    ASSERT_FALSE(test3 == test2);
+}
+
+TEST_F(SimpleTest, SimpleInt32ComplexMessageMapMessageCompareTest)
+{
+    QSharedPointer<ComplexMessage> msg1(new ComplexMessage(10, {"qwerty"}));
+    QSharedPointer<ComplexMessage> msg2(new ComplexMessage(20, {"ytrewq"}));
+
+    QSharedPointer<ComplexMessage> msg3(new ComplexMessage(10, {"qwerty"}));
+    QSharedPointer<ComplexMessage> msg4(new ComplexMessage(20, {"ytrewq"}));
+
+    SimpleInt32ComplexMessageMapMessage test1 = SimpleInt32ComplexMessageMapMessage({{20, msg1}, {30, msg2}});
+    SimpleInt32ComplexMessageMapMessage test2 = SimpleInt32ComplexMessageMapMessage({{20, msg3}, {30, msg4}});
+    ASSERT_TRUE(test1 == test2);
+}
 } // tests
 } // qtprotobuf

+ 1 - 0
tests/test_protobuf_multifile/simpletest.cpp

@@ -86,6 +86,7 @@
 #include "qtprotobufnamespace/tests/lowercasemessagename.h"
 #include "qtprotobufnamespace/tests/lowercasefieldmessagename.h"
 #include "qtprotobufnamespace/tests/messageuppercase.h"
+#include "qtprotobufnamespace/tests/simpleint32complexmessagemapmessage.h"
 #include "emptymessage.h"
 #include "simpleintmessage.h"
 #include "nopackageexternalmessage.h"