2022-10-05 17:11:30 +00:00
|
|
|
// Copyright (C) 2022 The Qt Company Ltd.
|
|
|
|
// Copyright (C) 2022 Alexey Edelev <semlanik@gmail.com>, Viktor Kopp <vifactor@gmail.com>
|
2024-03-15 12:04:02 +00:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
2022-10-05 17:11:30 +00:00
|
|
|
|
|
|
|
#include "syntax.qpb.h"
|
|
|
|
|
|
|
|
#include <QMetaProperty>
|
|
|
|
#include <QSignalSpy>
|
2022-10-05 17:31:33 +00:00
|
|
|
#include <QTest>
|
Long live mutable getters
The functionality is desirable by some users, we re-enable it.
New API addresses the core issue that is partially related to
QTBUG-119912, but has wider concequences in blind use in user
projects. We add the 'mut' prefix to all mutable getters to make
the mutable access explicit. Overload approach leads to unwanted
detaches not only whe is used be moc-generated code, but also
in user projects if developers do not pay enough attention to
const modifiers of their variables/references. We declined to
restore it, dispite it was the better looking API, in favor to
the code safety.
This also reveals the code clashing scenario, when the overload
might happen if the message has both 'a' and 'mutA' fields in
its definition. This scenario is kindly forbidden by our generator,
and sanitized at very early stages. We expect that it won't happen
in user projects, but even if it will, the solution is to rename
the field when generating Qt code. The serialization/deserialization
do not depend on field naming directly. json_name attribute also
will help to workaround this.
The undocumented ALLOW_MUTABLE_GETTER_CONFLICTS option allows clashing
the mutable getter names, but its usage currently limited by our
internal code only. The reason unfixed QTBUG-119912 issue in moc.
Once the issue is fixed, the moc version check should get the proper
version, but not '99' as for now and the ALLOW_MUTABLE_GETTER_CONFLICTS
will become public.
Another design solution is the use of overloaded functions that
return pointers, like it's done it the reference protobuf. But this
kind of API leaves the pointer ownership undefined and decided to
not be used.
[ChangeLog][Protobuf] The generated messages now have the mutable
getters for the fiels of the message type. The getters have 'mut'
prefix and implicily allocate the respective fields if needed, so the
use of intermediate message objects is not required.
Task-number: QTBUG-119913
Change-Id: I09b9ee37e1fbbe37b9c3cb501e92442da8ad3e4b
Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
2025-03-14 11:40:54 +00:00
|
|
|
#include <QDebug>
|
2022-10-05 17:11:30 +00:00
|
|
|
|
|
|
|
#include <qtprotobuftestscommon.h>
|
|
|
|
|
|
|
|
class QtProtobufSyntaxTest : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
2024-05-10 13:12:09 +00:00
|
|
|
private Q_SLOTS:
|
2024-05-10 09:18:02 +00:00
|
|
|
void underscoresTest();
|
|
|
|
void upperCaseTest();
|
|
|
|
void reservedTest();
|
|
|
|
void reservedUpperCaseTest();
|
|
|
|
void reservedEnumTest();
|
|
|
|
void lowerCaseEnumTest();
|
|
|
|
void upperCaseEnumTest();
|
Long live mutable getters
The functionality is desirable by some users, we re-enable it.
New API addresses the core issue that is partially related to
QTBUG-119912, but has wider concequences in blind use in user
projects. We add the 'mut' prefix to all mutable getters to make
the mutable access explicit. Overload approach leads to unwanted
detaches not only whe is used be moc-generated code, but also
in user projects if developers do not pay enough attention to
const modifiers of their variables/references. We declined to
restore it, dispite it was the better looking API, in favor to
the code safety.
This also reveals the code clashing scenario, when the overload
might happen if the message has both 'a' and 'mutA' fields in
its definition. This scenario is kindly forbidden by our generator,
and sanitized at very early stages. We expect that it won't happen
in user projects, but even if it will, the solution is to rename
the field when generating Qt code. The serialization/deserialization
do not depend on field naming directly. json_name attribute also
will help to workaround this.
The undocumented ALLOW_MUTABLE_GETTER_CONFLICTS option allows clashing
the mutable getter names, but its usage currently limited by our
internal code only. The reason unfixed QTBUG-119912 issue in moc.
Once the issue is fixed, the moc version check should get the proper
version, but not '99' as for now and the ALLOW_MUTABLE_GETTER_CONFLICTS
will become public.
Another design solution is the use of overloaded functions that
return pointers, like it's done it the reference protobuf. But this
kind of API leaves the pointer ownership undefined and decided to
not be used.
[ChangeLog][Protobuf] The generated messages now have the mutable
getters for the fiels of the message type. The getters have 'mut'
prefix and implicily allocate the respective fields if needed, so the
use of intermediate message objects is not required.
Task-number: QTBUG-119913
Change-Id: I09b9ee37e1fbbe37b9c3cb501e92442da8ad3e4b
Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
2025-03-14 11:40:54 +00:00
|
|
|
|
|
|
|
void mutableGetterConflicts();
|
2022-10-05 17:11:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
using namespace qtprotobufnamespace::tests;
|
|
|
|
|
2024-05-10 09:18:02 +00:00
|
|
|
void QtProtobufSyntaxTest::underscoresTest()
|
2022-10-05 17:11:30 +00:00
|
|
|
{
|
|
|
|
//Sanity compilation checks
|
|
|
|
Message_Uderscore_name msg1;
|
|
|
|
MessageUderscorename msg2;
|
|
|
|
MessageUnderscoreField msg3;
|
|
|
|
PriorMessageUnderscoreField msg4;
|
|
|
|
FollowingMessageUnderscoreField msg5;
|
|
|
|
CombinedMessageUnderscoreField msg6;
|
|
|
|
|
|
|
|
qProtobufAssertMessagePropertyRegistered<MessageUnderscoreField, QtProtobuf::sint32>(1, "QtProtobuf::sint32", "underScoreMessageField");
|
|
|
|
qProtobufAssertMessagePropertyRegistered<PriorMessageUnderscoreField, QtProtobuf::sint32>(1, "QtProtobuf::sint32", "underScoreMessageField");
|
|
|
|
qProtobufAssertMessagePropertyRegistered<PriorMessageUnderscoreField, QtProtobuf::sint32>(1, "QtProtobuf::sint32", "underScoreMessageField");
|
|
|
|
qProtobufAssertMessagePropertyRegistered<FollowingMessageUnderscoreField , QtProtobuf::sint32>(1, "QtProtobuf::sint32", "underScoreMessageField");
|
|
|
|
qProtobufAssertMessagePropertyRegistered<CombinedMessageUnderscoreField , QtProtobuf::sint32>(1, "QtProtobuf::sint32", "underScoreMessageField");
|
|
|
|
}
|
|
|
|
|
2024-05-10 09:18:02 +00:00
|
|
|
void QtProtobufSyntaxTest::upperCaseTest()
|
2022-10-05 17:11:30 +00:00
|
|
|
{
|
|
|
|
qProtobufAssertMessagePropertyRegistered<MessageUpperCase, QtProtobuf::sint32>(1, "QtProtobuf::sint32", "testField");
|
|
|
|
}
|
|
|
|
|
2024-05-10 09:18:02 +00:00
|
|
|
void QtProtobufSyntaxTest::reservedTest()
|
2022-10-05 17:11:30 +00:00
|
|
|
{
|
|
|
|
qProtobufAssertMessagePropertyRegistered<MessageReserved, QtProtobuf::sint32>(1, "QtProtobuf::sint32", "import_proto");
|
|
|
|
qProtobufAssertMessagePropertyRegistered<MessageReserved, QtProtobuf::sint32>(2, "QtProtobuf::sint32", "property_proto");
|
|
|
|
qProtobufAssertMessagePropertyRegistered<MessageReserved, QtProtobuf::sint32>(3, "QtProtobuf::sint32", "id_proto");
|
|
|
|
}
|
|
|
|
|
2024-05-10 09:18:02 +00:00
|
|
|
void QtProtobufSyntaxTest::reservedUpperCaseTest()
|
2022-10-05 17:11:30 +00:00
|
|
|
{
|
|
|
|
qProtobufAssertMessagePropertyRegistered<MessageUpperCaseReserved, QtProtobuf::sint32>(1, "QtProtobuf::sint32", "import_proto");
|
|
|
|
qProtobufAssertMessagePropertyRegistered<MessageUpperCaseReserved, QtProtobuf::sint32>(2, "QtProtobuf::sint32", "property_proto");
|
|
|
|
qProtobufAssertMessagePropertyRegistered<MessageUpperCaseReserved, QtProtobuf::sint32>(3, "QtProtobuf::sint32", "id_proto");
|
|
|
|
}
|
|
|
|
|
2024-05-10 09:18:02 +00:00
|
|
|
void QtProtobufSyntaxTest::reservedEnumTest()
|
2022-10-05 17:11:30 +00:00
|
|
|
{
|
2023-08-05 15:10:53 +00:00
|
|
|
const auto &metaObject = MessageEnumReserved_QtProtobufNested::staticMetaObject;
|
|
|
|
QVERIFY(metaObject.enumeratorCount() > 0);
|
2022-10-05 17:11:30 +00:00
|
|
|
QMetaEnum simpleEnum;
|
2023-08-05 15:10:53 +00:00
|
|
|
for (int i = 0; i < metaObject.enumeratorCount(); i++) {
|
|
|
|
QMetaEnum tmp = metaObject.enumerator(i);
|
2022-10-05 17:11:30 +00:00
|
|
|
if (QString(tmp.name()) == QString("ReservedEnum")) {
|
|
|
|
simpleEnum = tmp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
QVERIFY(simpleEnum.isValid());
|
|
|
|
QCOMPARE(simpleEnum.key(0), "Import");
|
|
|
|
QCOMPARE(simpleEnum.key(1), "Property");
|
|
|
|
QCOMPARE(simpleEnum.key(2), "Id");
|
|
|
|
|
|
|
|
QCOMPARE(simpleEnum.value(0), 0);
|
|
|
|
QCOMPARE(simpleEnum.value(1), 1);
|
|
|
|
QCOMPARE(simpleEnum.value(2), 2);
|
|
|
|
}
|
|
|
|
|
2024-05-10 09:18:02 +00:00
|
|
|
void QtProtobufSyntaxTest::lowerCaseEnumTest()
|
2022-10-05 17:11:30 +00:00
|
|
|
{
|
2023-08-05 15:10:53 +00:00
|
|
|
const auto &metaObject = MessageEnumReserved_QtProtobufNested::staticMetaObject;
|
|
|
|
QVERIFY(metaObject.enumeratorCount() > 0);
|
2022-10-05 17:11:30 +00:00
|
|
|
QMetaEnum simpleEnum;
|
2023-08-05 15:10:53 +00:00
|
|
|
for (int i = 0; i < metaObject.enumeratorCount(); i++) {
|
|
|
|
QMetaEnum tmp = metaObject.enumerator(i);
|
2022-10-05 17:11:30 +00:00
|
|
|
if (QString(tmp.name()) == QString("LowerCaseEnum")) {
|
|
|
|
simpleEnum = tmp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
QVERIFY(simpleEnum.isValid());
|
2023-09-02 10:14:23 +00:00
|
|
|
QCOMPARE(simpleEnum.key(0), "enumValue0");
|
|
|
|
QCOMPARE(simpleEnum.key(1), "enumValue1");
|
|
|
|
QCOMPARE(simpleEnum.key(2), "enumValue2");
|
|
|
|
}
|
|
|
|
|
2024-05-10 09:18:02 +00:00
|
|
|
void QtProtobufSyntaxTest::upperCaseEnumTest()
|
2023-09-02 10:14:23 +00:00
|
|
|
{
|
|
|
|
const auto &metaObject = MessageEnumReserved_QtProtobufNested::staticMetaObject;
|
|
|
|
QVERIFY(metaObject.enumeratorCount() > 0);
|
|
|
|
QMetaEnum simpleEnum;
|
|
|
|
for (int i = 0; i < metaObject.enumeratorCount(); i++) {
|
|
|
|
QMetaEnum tmp = metaObject.enumerator(i);
|
|
|
|
if (QString(tmp.name()) == QString("UpperCaseEnum")) {
|
|
|
|
simpleEnum = tmp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
QVERIFY(simpleEnum.isValid());
|
2022-10-05 17:11:30 +00:00
|
|
|
QCOMPARE(simpleEnum.key(0), "EnumValue0");
|
|
|
|
QCOMPARE(simpleEnum.key(1), "EnumValue1");
|
|
|
|
QCOMPARE(simpleEnum.key(2), "EnumValue2");
|
|
|
|
}
|
|
|
|
|
Long live mutable getters
The functionality is desirable by some users, we re-enable it.
New API addresses the core issue that is partially related to
QTBUG-119912, but has wider concequences in blind use in user
projects. We add the 'mut' prefix to all mutable getters to make
the mutable access explicit. Overload approach leads to unwanted
detaches not only whe is used be moc-generated code, but also
in user projects if developers do not pay enough attention to
const modifiers of their variables/references. We declined to
restore it, dispite it was the better looking API, in favor to
the code safety.
This also reveals the code clashing scenario, when the overload
might happen if the message has both 'a' and 'mutA' fields in
its definition. This scenario is kindly forbidden by our generator,
and sanitized at very early stages. We expect that it won't happen
in user projects, but even if it will, the solution is to rename
the field when generating Qt code. The serialization/deserialization
do not depend on field naming directly. json_name attribute also
will help to workaround this.
The undocumented ALLOW_MUTABLE_GETTER_CONFLICTS option allows clashing
the mutable getter names, but its usage currently limited by our
internal code only. The reason unfixed QTBUG-119912 issue in moc.
Once the issue is fixed, the moc version check should get the proper
version, but not '99' as for now and the ALLOW_MUTABLE_GETTER_CONFLICTS
will become public.
Another design solution is the use of overloaded functions that
return pointers, like it's done it the reference protobuf. But this
kind of API leaves the pointer ownership undefined and decided to
not be used.
[ChangeLog][Protobuf] The generated messages now have the mutable
getters for the fiels of the message type. The getters have 'mut'
prefix and implicily allocate the respective fields if needed, so the
use of intermediate message objects is not required.
Task-number: QTBUG-119913
Change-Id: I09b9ee37e1fbbe37b9c3cb501e92442da8ad3e4b
Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
2025-03-14 11:40:54 +00:00
|
|
|
void QtProtobufSyntaxTest::mutableGetterConflicts()
|
|
|
|
{
|
|
|
|
NameClashingMutableGetters msg;
|
|
|
|
// Set 'data' field for the 'field' field using the mutable getter
|
|
|
|
msg.mutField().setData(1);
|
|
|
|
|
|
|
|
// Set 'data' field for the 'mutField' field using the mutable getter
|
|
|
|
msg.mutMutField().setData(2);
|
|
|
|
|
|
|
|
// Access the immutable 'field' field
|
|
|
|
QVERIFY(msg.field().data() == 1);
|
|
|
|
// Access the mutable 'field' field
|
|
|
|
QVERIFY(msg.mutField().data() == 1);
|
|
|
|
|
|
|
|
// Access the immutable 'mutField' field
|
|
|
|
QVERIFY(std::as_const(msg).mutField().data() == 2);
|
|
|
|
|
|
|
|
// Ensure we use the correct value in serialization
|
|
|
|
QVERIFY(!msg.property("mutField_p").isNull());
|
|
|
|
QVERIFY(msg.property("mutField_p").value<MutFieldMessage *>()->data() == 2);
|
|
|
|
}
|
|
|
|
|
2022-10-05 17:11:30 +00:00
|
|
|
QTEST_MAIN(QtProtobufSyntaxTest)
|
|
|
|
#include "tst_protobuf_syntax.moc"
|