Browse Source

Improve enum types generation

- Fix issues related to include generation
- Fix enum types namespace detection
- Add and update tests
Alexey Edelev 6 years ago
parent
commit
183224a3ec

+ 1 - 1
src/generator/classsourcegeneratorbase.cpp

@@ -46,7 +46,7 @@ void ClassSourceGeneratorBase::printClassHeaderInclude()
 {
     std::string includeFileName = mClassName;
     utils::tolower(includeFileName);
-    mPrinter.Print({{"type_lower", includeFileName}}, Templates::InternalIncludeTemplate);
+    mPrinter.Print({{"include", includeFileName}}, Templates::InternalIncludeTemplate);
 }
 
 void ClassSourceGeneratorBase::printUsingNamespaces(const std::unordered_set<std::string> &namespaces)

+ 1 - 1
src/generator/clientgenerator.cpp

@@ -66,6 +66,6 @@ void ClientGenerator::printClientIncludes()
     includeSet.insert("abstractclient");
     includeSet.insert("asyncreply");
     for(auto type : includeSet) {
-        mPrinter.Print({{"type_lower", type}}, Templates::InternalIncludeTemplate);
+        mPrinter.Print({{"include", type}}, Templates::InternalIncludeTemplate);
     }
 }

+ 1 - 1
src/generator/globalenumsgenerator.cpp

@@ -33,7 +33,7 @@ using namespace ::google::protobuf::io;
 using namespace ::google::protobuf::compiler;
 
 GlobalEnumsGenerator::GlobalEnumsGenerator(const PackagesList &packageList, std::unique_ptr<io::ZeroCopyOutputStream> out) :
-    ClassGeneratorBase(Templates::EnumClassNameTemplate, std::move(out))
+    ClassGeneratorBase(Templates::GlobalEnumClassNameTemplate, std::move(out))
   , mPackageList(packageList) {}
 
 void GlobalEnumsGenerator::startEnum(const std::vector<std::string>& namespaces) {

+ 55 - 59
src/generator/protobufclassgenerator.cpp

@@ -156,49 +156,51 @@ void ProtobufClassGenerator::printIncludes()
 
     mPrinter.Print(Templates::DefaultProtobufIncludesTemplate);
 
-    PropertyMap properties;
     std::set<std::string> existingIncludes;
     std::string newInclude;
     const char* includeTemplate;
     for (int i = 0; i < mMessage->field_count(); i++) {
         const FieldDescriptor* field = mMessage->field(i);
-        if (producePropertyMap(field, properties)) {
-            switch (field->type()) {
-            case FieldDescriptor::TYPE_MESSAGE:
-                if (field->is_repeated()) {
-                    //Repeated field includes are similar to non-repeated
-                    properties["type_lower"] = properties["type_nonlist_lower"];
-                }
-                newInclude = properties["type_lower"];
+        switch (field->type()) {
+        case FieldDescriptor::TYPE_MESSAGE: {
+            std::string typeName = field->message_type()->name();
+            utils::tolower(typeName);
+            newInclude = typeName;
+            includeTemplate = Templates::InternalIncludeTemplate;
+        }
+            break;
+        case FieldDescriptor::TYPE_BYTES:
+            newInclude = "QByteArray";
+            includeTemplate = Templates::ExternalIncludeTemplate;
+            break;
+        case FieldDescriptor::TYPE_STRING:
+            newInclude = "QString";
+            includeTemplate = Templates::ExternalIncludeTemplate;
+            break;
+        case FieldDescriptor::TYPE_ENUM: {
+            EnumVisibility enumVisibily = getEnumVisibility(field);
+            if (enumVisibily == GLOBAL_ENUM) {
+                includeTemplate = Templates::GlobalEnumIncludeTemplate;
+            } else if (enumVisibily == NEIGHBOUR_ENUM){
                 includeTemplate = Templates::InternalIncludeTemplate;
-                break;
-            case FieldDescriptor::TYPE_BYTES:
-            case FieldDescriptor::TYPE_STRING:
-                includeTemplate = Templates::ExternalIncludeTemplate;
-                break;
-            case FieldDescriptor::TYPE_ENUM: {
-                EnumVisibility enumVisibily = getEnumVisibility(field);
-                if (enumVisibily == GLOBAL_ENUM) {
-                    includeTemplate = Templates::GlobalEnumIncludeTemplate;
-                } else {
-                    includeTemplate = Templates::InternalIncludeTemplate;
-                    std::string fullEnumName = field->enum_type()->full_name();
-                    std::vector<std::string> fullEnumNameParts;
-                    utils::split(fullEnumName, fullEnumNameParts, '.');
-                    std::string enumTypeOwner = fullEnumNameParts.at(fullEnumNameParts.size() - 2);
-                    utils::tolower(enumTypeOwner);
-                    properties["type_lower"] = enumTypeOwner;
-                }
-            }
-                break;
-            default:
+                std::string fullEnumName = field->enum_type()->full_name();
+                std::vector<std::string> fullEnumNameParts;
+                utils::split(fullEnumName, fullEnumNameParts, '.');
+                std::string enumTypeOwner = fullEnumNameParts.at(fullEnumNameParts.size() - 2);
+                utils::tolower(enumTypeOwner);
+                newInclude = enumTypeOwner;
+            } else {
                 continue;
             }
+        }
+            break;
+        default:
+            continue;
+        }
 
-            if (existingIncludes.find(newInclude) == std::end(existingIncludes)) {
-                mPrinter.Print(properties, includeTemplate);
-                existingIncludes.insert(newInclude);
-            }
+        if (existingIncludes.find(newInclude) == std::end(existingIncludes)) {
+            mPrinter.Print({{"include", newInclude}}, includeTemplate);
+            existingIncludes.insert(newInclude);
         }
     }
 }
@@ -250,23 +252,24 @@ std::string ProtobufClassGenerator::getTypeName(const FieldDescriptor *field)
     std::vector<std::string> typeNamespace;
 
     if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
-        namespaceTypeName = getNamespacesList(field->message_type(), typeNamespace);
-    } else if (field->type() == FieldDescriptor::TYPE_ENUM) {
-        namespaceTypeName = getNamespacesList(field->enum_type(), typeNamespace);
-    }
-
-    if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
-        typeName = namespaceTypeName.append(field->message_type()->name());
+        const Descriptor *msg = field->message_type();
+        namespaceTypeName = getNamespacesList(msg, typeNamespace);
+        typeName = namespaceTypeName.append(msg->name());
 
         if (field->is_repeated()) {
             return namespaceTypeName.append("List");
         }
     } else if (field->type() == FieldDescriptor::TYPE_ENUM) {
-        if (getEnumVisibility(field) == GLOBAL_ENUM) {
-            std::string globEnum(Templates::EnumClassNameTemplate);
-            typeName = namespaceTypeName.append(globEnum.append("::").append(field->enum_type()->name()));
+        const EnumDescriptor *enumType = field->enum_type();
+        namespaceTypeName = getNamespacesList(enumType, typeNamespace);
+        EnumVisibility visibility = getEnumVisibility(field);
+        if (visibility == LOCAL_ENUM) {
+            typeName = typeName.append(enumType->name());
+        } else if(visibility == GLOBAL_ENUM) {
+            typeName = namespaceTypeName.append(Templates::GlobalEnumClassNameTemplate)
+                    .append("::").append(enumType->name());
         } else {
-            typeName = typeName.append(field->enum_type()->name());
+            typeName = namespaceTypeName.append(enumType->name());
         }
         if (field->is_repeated()) {
             return typeName.append("List");
@@ -317,18 +320,8 @@ bool ProtobufClassGenerator::producePropertyMap(const FieldDescriptor *field, Pr
     std::string capProperty = field->camelcase_name();
     capProperty[0] = ::toupper(capProperty[0]);
 
-    std::string typeNameNonList = typeName;
-    if (field->is_repeated()) {
-        auto pos = typeNameNonList.rfind("List");
-        typeNameNonList = typeNameNonList.erase(pos, 4);
-    }
-    std::string typeNameNonListLower(typeNameNonList);
-    utils::tolower(typeNameNonListLower);
-
     propertyMap = {{"type", typeName},
-                   {"type_nonlist", typeNameNonList},
                    {"type_lower", typeNameLower},
-                   {"type_nonlist_lower", typeNameNonListLower},
                    {"property_name", field->camelcase_name()},
                    {"property_name_cap", capProperty}};
     return true;
@@ -435,13 +428,16 @@ ProtobufClassGenerator::EnumVisibility ProtobufClassGenerator::getEnumVisibility
     const EnumDescriptor *enumType = field->enum_type();
     const FileDescriptor *enumFile = field->enum_type()->file();
 
-    for (int i = 0; i < enumFile->enum_type_count(); i++) {
-        if (enumType->full_name() == enumFile->enum_type(i)->full_name()) {
-            return GLOBAL_ENUM;
+    for (int i = 0; i < enumFile->message_type_count(); i++) {
+        const Descriptor* msg = enumFile->message_type(i);
+        for(int j = 0; j < msg->enum_type_count(); j++) {
+            if (enumType->full_name() == msg->enum_type(j)->full_name()) {
+                return NEIGHBOUR_ENUM;
+            }
         }
     }
 
-    return NEIGHBOUR_ENUM;
+    return GLOBAL_ENUM;
 }
 
 bool ProtobufClassGenerator::isLocalMessageEnum(const ::google::protobuf::FieldDescriptor *field)

+ 0 - 1
src/generator/protobufclassgenerator.h

@@ -81,7 +81,6 @@ private:
     static bool isComplexType(const ::google::protobuf::FieldDescriptor *field);
     static bool isListType(const ::google::protobuf::FieldDescriptor *field);
 
-private:
     template<typename T>
     std::string getNamespacesList(const T *message, std::vector<std::string> &container);
 };

+ 1 - 1
src/generator/servicegeneratorbase.cpp

@@ -63,7 +63,7 @@ void ServiceGeneratorBase::printIncludes()
     }
 
     for(auto type : includeSet) {
-        mPrinter.Print({{"type_lower", type}}, Templates::InternalIncludeTemplate);
+        mPrinter.Print({{"include", type}}, Templates::InternalIncludeTemplate);
     }
 }
 

+ 3 - 3
src/generator/templates.cpp

@@ -32,14 +32,14 @@ const char *Templates::DefaultProtobufIncludesTemplate = "#include <QMetaType>\n
                                                          "#include <protobufobject.h>\n"
                                                          "#include <unordered_map>\n\n";
 
-const char *Templates::EnumClassNameTemplate = "GlobalEnums";
+const char *Templates::GlobalEnumClassNameTemplate = "GlobalEnums";
 
 const char *Templates::PreambleTemplate = "/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */\n\n"
                                       "#pragma once\n\n"
                                       "#include <QObject>\n";
 
-const char *Templates::InternalIncludeTemplate =  "#include \"$type_lower$.h\"\n";
-const char *Templates::ExternalIncludeTemplate = "#include <$type$>\n";
+const char *Templates::InternalIncludeTemplate =  "#include \"$include$.h\"\n";
+const char *Templates::ExternalIncludeTemplate = "#include <$include$>\n";
 const char *Templates::GlobalEnumIncludeTemplate = "#include <globalenums.h>\n";
 
 const char *Templates::UsingQtProtobufNamespaceTemplate = "\nusing namespace qtprotobuf;\n";

+ 1 - 1
src/generator/templates.h

@@ -35,7 +35,7 @@ namespace generator {
 class Templates {
 public:
     static const char *DefaultProtobufIncludesTemplate;
-    static const char *EnumClassNameTemplate;
+    static const char *GlobalEnumClassNameTemplate;
     static const char *PreambleTemplate;
     static const char *InternalIncludeTemplate;
     static const char *ExternalIncludeTemplate;

+ 4 - 4
tests/proto/simpletest.proto

@@ -21,10 +21,10 @@ message SimpleFileEnumMessage {
   repeated TestEnum globalEnumList = 2;
 }
 
-//message StepChildEnumMessage {
-//  SimpleEnumMessage.LocalEnum localStepChildEnum = 1;
-//  repeated SimpleEnumMessage.LocalEnum localStepChildList = 2;
-//}
+message StepChildEnumMessage {
+  SimpleEnumMessage.LocalEnum localStepChildEnum = 1;
+  repeated SimpleEnumMessage.LocalEnum localStepChildList = 2;
+}
 
 message SimpleExternalEnumMessage {
     qtprotobufnamespace1.externaltests.ExternalTestEnum externalEnum = 1;

+ 65 - 28
tests/simpletest.cpp

@@ -25,7 +25,7 @@
 
 #include "simpletest.h"
 
-//#include "stepchildenummessage.h"
+#include "stepchildenummessage.h"
 #include "simpleboolmessage.h"
 #include "simpleintmessage.h"
 #include "simplesintmessage.h"
@@ -261,31 +261,39 @@ TEST_F(SimpleTest, SimpleLocalEnumsTest)
     ASSERT_EQ(simpleEnum.value(1), 1);
     ASSERT_EQ(simpleEnum.value(2), 2);
     ASSERT_EQ(simpleEnum.value(3), 3);
+
+    const char* propertyName = "localEnumList";
+    SimpleEnumMessage test;
+    int propertyNumber = SimpleEnumMessage::propertyOrdering.at(2); //See simpletest.proto
+    ASSERT_STREQ(SimpleEnumMessage::staticMetaObject.property(propertyNumber).typeName(), "LocalEnumList");
+    ASSERT_EQ(SimpleEnumMessage::staticMetaObject.property(propertyNumber).userType(), qMetaTypeId<SimpleEnumMessage::LocalEnumList>());
+    ASSERT_STREQ(SimpleEnumMessage::staticMetaObject.property(propertyNumber).name(), propertyName);
+    ASSERT_TRUE(test.setProperty(propertyName, QVariant::fromValue<SimpleEnumMessage::LocalEnumList>({SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                                      SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                                      SimpleEnumMessage::LOCAL_ENUM_VALUE1,
+                                                                                                      SimpleEnumMessage::LOCAL_ENUM_VALUE3})));
+    ASSERT_TRUE(test.property(propertyName).value<SimpleEnumMessage::LocalEnum>() == QVariant::fromValue<SimpleEnumMessage::LocalEnumList>({SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                                                                            SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                                                                            SimpleEnumMessage::LOCAL_ENUM_VALUE1,
+                                                                                                                                            SimpleEnumMessage::LOCAL_ENUM_VALUE3}));
+    ASSERT_TRUE(test.localEnumList() == SimpleEnumMessage::LocalEnumList({SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                SimpleEnumMessage::LOCAL_ENUM_VALUE1,
+                                                                                SimpleEnumMessage::LOCAL_ENUM_VALUE3}));
 }
 
-TEST_F(SimpleTest, SimpleExternalEnumMessage)
+TEST_F(SimpleTest, SimpleExternalEnumMessageTest)
 {
-    ASSERT_GT(SimpleExternalEnumMessage::staticMetaObject.enumeratorCount(), 0);
-    QMetaEnum simpleExternalEnum;
-    for (int i = 0; i < SimpleExternalEnumMessage::staticMetaObject.enumeratorCount(); i++) {
-        QMetaEnum tmp = SimpleExternalEnumMessage::staticMetaObject.enumerator(i);
-        if (QString(tmp.name()) == QString("ExternalTestEnum")) {
-            simpleExternalEnum = tmp;
-            break;
-        }
-    }
-    ASSERT_TRUE(simpleExternalEnum.isValid());
-    ASSERT_STREQ(simpleExternalEnum.key(0), "EXTERNAL_TEST_ENUM_VALUE0");
-    ASSERT_STREQ(simpleExternalEnum.key(1), "EXTERNAL_TEST_ENUM_VALUE1");
-    ASSERT_STREQ(simpleExternalEnum.key(2), "EXTERNAL_TEST_ENUM_VALUE2");
-    ASSERT_STREQ(simpleExternalEnum.key(3), "EXTERNAL_TEST_ENUM_VALUE3");
-    ASSERT_STREQ(simpleExternalEnum.key(4), "EXTERNAL_TEST_ENUM_VALUE4");
-
-    ASSERT_EQ(simpleExternalEnum.value(0), 0);
-    ASSERT_EQ(simpleExternalEnum.value(1), 1);
-    ASSERT_EQ(simpleExternalEnum.value(2), 2);
-    ASSERT_EQ(simpleExternalEnum.value(3), 3);
-    ASSERT_EQ(simpleExternalEnum.value(4), 4);
+    const char* propertyName = "externalEnum";
+    using ExternalGlobalEnums = qtprotobufnamespace1::externaltests::GlobalEnums;
+    SimpleExternalEnumMessage test;
+    int propertyNumber = SimpleExternalEnumMessage::propertyOrdering.at(1); //See externalpackagetest.proto
+    ASSERT_STREQ(SimpleExternalEnumMessage::staticMetaObject.property(propertyNumber).typeName(), "qtprotobufnamespace1::externaltests::GlobalEnums::ExternalTestEnum");
+    ASSERT_EQ(SimpleExternalEnumMessage::staticMetaObject.property(propertyNumber).userType(), qMetaTypeId<ExternalGlobalEnums::ExternalTestEnum>());
+    ASSERT_STREQ(SimpleExternalEnumMessage::staticMetaObject.property(propertyNumber).name(), propertyName);
+    ASSERT_TRUE(test.setProperty(propertyName, QVariant::fromValue<ExternalGlobalEnums::ExternalTestEnum>(ExternalGlobalEnums::EXTERNAL_TEST_ENUM_VALUE4)));
+    ASSERT_TRUE(test.property(propertyName).value<ExternalGlobalEnums::ExternalTestEnum>() == QVariant::fromValue<ExternalGlobalEnums::ExternalTestEnum>(ExternalGlobalEnums::EXTERNAL_TEST_ENUM_VALUE4));
+    ASSERT_TRUE(test.externalEnum() == QVariant::fromValue<ExternalGlobalEnums::ExternalTestEnum>(ExternalGlobalEnums::EXTERNAL_TEST_ENUM_VALUE4));
 }
 
 TEST_F(SimpleTest, SimpleEnumsTest)
@@ -356,8 +364,37 @@ TEST_F(SimpleTest, RepeatedIntMessageTest)
     ASSERT_TRUE(test.testRepeatedInt() == sint32List({1, 2, 3, 4, 5}));
 }
 
-//Enable this test once required change will be done for EnumMessages generation
-//TEST_F(SimpleTest, StepChildEnumMessageTest)
-//{
-//    StepChildEnumMessage  message;
-//}
+TEST_F(SimpleTest, StepChildEnumMessageTest)
+{
+    const char* propertyName = "localStepChildEnum";
+    StepChildEnumMessage test;
+    int propertyNumber = StepChildEnumMessage::propertyOrdering.at(1); //See simpletest.proto
+    ASSERT_STREQ(StepChildEnumMessage::staticMetaObject.property(propertyNumber).typeName(), "qtprotobufnamespace::tests::SimpleEnumMessage::LocalEnum");
+    ASSERT_EQ(StepChildEnumMessage::staticMetaObject.property(propertyNumber).userType(), qMetaTypeId<SimpleEnumMessage::LocalEnum>());
+    ASSERT_STREQ(StepChildEnumMessage::staticMetaObject.property(propertyNumber).name(), propertyName);
+    ASSERT_TRUE(test.setProperty(propertyName, QVariant::fromValue<qtprotobufnamespace::tests::SimpleEnumMessage::LocalEnum>(SimpleEnumMessage::LOCAL_ENUM_VALUE2)));
+    ASSERT_TRUE(test.property(propertyName).value<SimpleEnumMessage::LocalEnum>() == SimpleEnumMessage::LOCAL_ENUM_VALUE2);
+    ASSERT_TRUE(test.localStepChildEnum() == SimpleEnumMessage::LOCAL_ENUM_VALUE2);
+}
+
+TEST_F(SimpleTest, StepChildEnumListMessageTest)
+{
+    const char* propertyName = "localStepChildList";
+    StepChildEnumMessage test;
+    int propertyNumber = StepChildEnumMessage::propertyOrdering.at(2); //See simpletest.proto
+    ASSERT_STREQ(StepChildEnumMessage::staticMetaObject.property(propertyNumber).typeName(), "qtprotobufnamespace::tests::SimpleEnumMessage::LocalEnumList");
+    ASSERT_EQ(StepChildEnumMessage::staticMetaObject.property(propertyNumber).userType(), qMetaTypeId<SimpleEnumMessage::LocalEnumList>());
+    ASSERT_STREQ(StepChildEnumMessage::staticMetaObject.property(propertyNumber).name(), propertyName);
+    ASSERT_TRUE(test.setProperty(propertyName, QVariant::fromValue<SimpleEnumMessage::LocalEnumList>({SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                                      SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                                      SimpleEnumMessage::LOCAL_ENUM_VALUE1,
+                                                                                                      SimpleEnumMessage::LOCAL_ENUM_VALUE3})));
+    ASSERT_TRUE(test.property(propertyName).value<SimpleEnumMessage::LocalEnum>() == QVariant::fromValue<SimpleEnumMessage::LocalEnumList>({SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                                                                            SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                                                                            SimpleEnumMessage::LOCAL_ENUM_VALUE1,
+                                                                                                                                            SimpleEnumMessage::LOCAL_ENUM_VALUE3}));
+    ASSERT_TRUE(test.localStepChildList() == SimpleEnumMessage::LocalEnumList({SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                SimpleEnumMessage::LOCAL_ENUM_VALUE2,
+                                                                                SimpleEnumMessage::LOCAL_ENUM_VALUE1,
+                                                                                SimpleEnumMessage::LOCAL_ENUM_VALUE3}));
+}