Revision control

++ // Copyright (C) 2026 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include "qoaicommonglobal.h"
++
++ #include "../basicSchemas/client/animal.h"
++ #include "../basicSchemas/client/bunny.h"
++ #include "../basicSchemas/client/cat.h"
++ #include "../basicSchemas/client/dog.h"
++ #include "../basicSchemas/client/duck.h"
++ #include "../basicSchemas/client/duck_family.h"
++ #include "../basicSchemas/client/ente.h"
++ #include "../basicSchemas/client/fauna.h"
++ #include "../basicSchemas/client/flora.h"
++ #include "../basicSchemas/client/pflanze.h"
++ #include "../basicSchemas/client/tier.h"
++ #include "../basicSchemas/client/tiere.h"
++ #include "../basicSchemas/client/postaccount_request.h"
++ #include "../basicSchemas/client/postaccount_request_otheraccdata_inner.h"
++ #include "../basicSchemas/client/dataapi.h"
++
++ #include <QtCore/qobject.h>
++ #include <QtTest/qtest.h>
++
++ #include <limits>
++
++ using namespace Qt::StringLiterals;
++ using namespace QtOpenApiCommon;
++
++ class StandardModelsTest : public QObject {
++ Q_OBJECT
++
++ private Q_SLOTS:
++ void testCatJsonConversionMethods_data();
++ void testCatJsonConversionMethods();
++ void testDogJsonConversionMethods_data();
++ void testDogJsonConversionMethods();
++ void testBunnyJsonConversionMethods_data();
++ void testBunnyJsonConversionMethods();
++ void testDuckFamilyJsonConversionMethods_data();
++ void testDuckFamilyJsonConversionMethods();
++ void testDuckJsonConversionMethods_data();
++ void testDuckJsonConversionMethods();
++ void testEnteJsonConversionMethods_data();
++ void testEnteJsonConversionMethods();
++ void testPostAccountRequestOtherAccDataInnerJsonConversionMethods_data();
++ void testPostAccountRequestOtherAccDataInnerJsonConversionMethods();
++ void testPostAccountRequestJsonConversionMethods_data();
++ void testPostAccountRequestJsonConversionMethods();
++ void testAnimalJsonConversionMethods_data();
++ void testAnimalJsonConversionMethods();
++ void testTierJsonConversionMethods_data();
++ void testTierJsonConversionMethods();
++ void testTiereJsonConversionMethods_data();
++ void testTiereJsonConversionMethods();
++ void testPflanzeJsonConversionMethods_data();
++ void testPflanzeJsonConversionMethods();
++ void testFaunaJsonConversionMethods_data();
++ void testFaunaJsonConversionMethods();
++ void testFloraJsonConversionMethods_data();
++ void testFloraJsonConversionMethods();
++ };
++
++ void StandardModelsTest::testCatJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Cat>("cat");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isHuntsSet");
++ QTest::addColumn<bool>("isHuntsValid");
++ QTest::addColumn<bool>("isAgeSet");
++ QTest::addColumn<bool>("isAgeValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Cat model doesn't have required fields.
++ // If no fields are required, then an empty model is a valid case.
++ QTest::newRow("empty") << StandardSchemasModels::Cat{} << QString("{}"_L1)
++ // isHuntsSet isHuntsValid
++ << false << true
++ // isAgeSet isAgeValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ StandardSchemasModels::Cat kitty;
++ kitty.setHunts(false);
++ kitty.setAge(7);
++ QTest::newRow("hunts=false; age=7") << kitty << QString("{\"age\":7,\"hunts\":false}"_L1)
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only the 'age' field set; 'hunts' absent from JSON output.
++ // Note: if fields are not required, they are optional.
++ StandardSchemasModels::Cat ageOnly;
++ ageOnly.setAge(3);
++ QTest::newRow("age=3; hunts not set") << ageOnly << QString("{\"age\":3}"_L1)
++ // isHuntsSet isHuntsValid
++ << false << true
++ // isAgeSet isAgeValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only the optional 'hunts' field set; 'age' absent from JSON output.
++ StandardSchemasModels::Cat huntsOnly;
++ huntsOnly.setHunts(true);
++ QTest::newRow("hunts=true; age not set") << huntsOnly << QString("{\"hunts\":true}"_L1)
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with a wrong type for 'age' (string instead of integer)
++ // NOTE: 'age' should be omitted, because we're trying to set incorrect data type!
++ // The test case for QTBUG-145410
++ // The model stays valid because Cat has no required fields.
++ StandardSchemasModels::Cat stringAgeType("{\"age\":\"seven\",\"hunts\":true}"_L1);
++ QTest::newRow("hunts=true; age (string) dropped")
++ << stringAgeType << QString("{\"hunts\":true}"_L1)
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Let's test double!
++ // NOTE: 'age' should be omitted, because we're trying to set incorrect data type!
++ // The test case for QTBUG-145410
++ // The model stays valid because Cat has no required fields.
++ StandardSchemasModels::Cat doubleAgeType("{\"age\":3.9,\"hunts\":true}"_L1);
++ QTest::newRow("hunts=true; age (double) dropped")
++ << doubleAgeType << QString("{\"hunts\":true}"_L1)
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Let's test a double that can be defined as integer mathematically!
++ // Quote: "JSON Schema defines integers mathematically. This means that
++ // both 1 and 1.0 are equivalent, and are both considered to be integers."
++ // NOTE: 'age' should NOT be omitted, because we're trying to set correct data!
++ // The test case for QTBUG-145410
++ // The model stays valid because Cat has no required fields.
++ StandardSchemasModels::Cat double2AgeType("{\"age\":3.0,\"hunts\":true}"_L1);
++ QTest::newRow("hunts=true; age=3")
++ << double2AgeType << QString("{\"age\":3,\"hunts\":true}"_L1)
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++
++ // Let's test bool!
++ // NOTE: 'age' should be omitted, because we're trying to set incorrect data type!
++ // The test case for QTBUG-145410
++ // The model stays valid because Cat has no required fields.
++ StandardSchemasModels::Cat boolAgeType("{\"age\":true,\"hunts\":true}"_L1);
++ QTest::newRow("hunts=true; age (bool) dropped")
++ << boolAgeType << QString("{\"hunts\":true}"_L1)
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // age is empty. The entire json is dropped, because it's invalid input data.
++ // The model stays valid because Cat has no required fields.
++ StandardSchemasModels::Cat brokenJsonType("{\"age\": ,\"hunts\":true}"_L1);
++ QTest::newRow("Invalid json => age (empty) dropped") << brokenJsonType << QString("{}"_L1)
++ // isHuntsSet isHuntsValid
++ << false << true
++ // isAgeSet isAgeValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Model with a wrong type for 'hunts' (integer instead of boolean):
++ // 'hunts' is dropped, only 'age' survives.
++ StandardSchemasModels::Cat wrongHuntsType("{\"age\":5,\"hunts\":42}"_L1);
++ QTest::newRow("hunts dropped; age=5;") << wrongHuntsType << QString("{\"age\":5}"_L1)
++ // isHuntsSet isHuntsValid
++ << false << true
++ // isAgeSet isAgeValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ const QString testVal = QString("{\"age\":9007199254740993,\"hunts\":true}"_L1);
++ StandardSchemasModels::Cat bigValue(testVal);
++ QTest::newRow("hunts=true; age=9007199254740993;")
++ << bigValue << testVal
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // <long long >::max() (9223372036854775807): maximum value for a signed 64-bit integer.
++ const QString llongMaxVal =
++ QString("{\"age\":%1,\"hunts\":true}"_L1).arg(std::numeric_limits<long long>::max());
++ StandardSchemasModels::Cat llongMaxCat(llongMaxVal);
++ QTest::newRow("hunts=true; age=<long long >::max();")
++ << llongMaxCat << llongMaxVal
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // <long long >::min() (-9223372036854775808): minimum value for a signed 64-bit integer.
++ const QString llongMinVal =
++ QString("{\"age\":%1,\"hunts\":true}"_L1).arg(std::numeric_limits<long long>::min());
++ StandardSchemasModels::Cat llongMinCat(llongMinVal);
++ QTest::newRow("hunts=true; age=LLONG_MIN;")
++ << llongMinCat << llongMinVal
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // ULLONG_MAX (18446744073709551615): maximum value for an unsigned 64-bit integer.
++ // This exceeds the int64 range, so 'age' cannot be represented and must be dropped.
++ StandardSchemasModels::Cat ullongMaxCat(
++ QString("{\"age\":18446744073709551615,\"hunts\":true}"_L1));
++ QTest::newRow("hunts=true; age=ULLONG_MAX (overflow, dropped);")
++ << ullongMaxCat << QString("{\"hunts\":true}"_L1)
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with unknown fields: known fields are parsed,
++ // unknown ones silently ignored.
++ StandardSchemasModels::Cat unknownFields(
++ "{\"age\":2,\"name\":\"Whiskers\",\"hunts\":false,\"color\":\"orange\"}"_L1);
++ QTest::newRow("Additional unknown fields ignored")
++ << unknownFields << QString("{\"age\":2,\"hunts\":false}"_L1)
++ // isHuntsSet isHuntsValid
++ << true << true
++ // isAgeSet isAgeValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ StandardSchemasModels::Cat allUnknownFields;
++ unknownFields.fromJson(
++ "\"name\":\"Whiskers\",\"color\":\"orange\"}"_L1);
++ QTest::newRow("All unknown fields dropped") << allUnknownFields << QString("{}"_L1)
++ // isHuntsSet isHuntsValid
++ << false << true
++ // isAgeSet isAgeValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Model with invalid JSON:
++ // so all fields stay at their initial invalid/unset state.
++ // Cat is still valid (no required fields), but nothing is set.
++ StandardSchemasModels::Cat fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("invalid JSON") << fromInvalidJson << QString("{}"_L1)
++ // isHuntsSet isHuntsValid
++ << false << true
++ // isAgeSet isAgeValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++ }
++
++ void StandardModelsTest::testCatJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Cat, cat);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isHuntsSet);
++ QFETCH(bool, isHuntsValid);
++ QFETCH(bool, isAgeSet);
++ QFETCH(bool, isAgeValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ // Expected model from _data()
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(cat.asJson(), expectedJson);
++ QCOMPARE(cat.asJsonValue(), testValue);
++ QCOMPARE(cat.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(cat.isHuntsValueSet(), isHuntsSet);
++ QCOMPARE(cat.isHuntsValueValid(), isHuntsValid);
++ QCOMPARE(cat.isAgeValueSet(), isAgeSet);
++ QCOMPARE(cat.isAgeValueValid(), isAgeValid);
++ QCOMPARE(cat.isValid(), modelIsValid);
++ QCOMPARE(cat.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Cat fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isHuntsValueSet(), isHuntsSet);
++ QCOMPARE(fromJson.isHuntsValueValid(), isHuntsValid);
++ QCOMPARE(fromJson.isAgeValueSet(), isAgeSet);
++ QCOMPARE(fromJson.isAgeValueValid(), isAgeValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, cat);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Cat fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isHuntsValueSet(), isHuntsSet);
++ QCOMPARE(fromObject.isHuntsValueValid(), isHuntsValid);
++ QCOMPARE(fromObject.isAgeValueSet(), isAgeSet);
++ QCOMPARE(fromObject.isAgeValueValid(), isAgeValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, cat);
++
++ // The attemp to set a new model data from invalid json
++ // (call ::fromJson) should lead to the full model reset.
++ StandardSchemasModels::Cat defaultObject;
++ fromJson.fromJson("{invalid json /e*3 }"_L1);
++ QVERIFY(fromJson.asJson() == "{}"_L1);
++ QVERIFY(fromJson.asJsonValue().toObject().isEmpty());
++ QCOMPARE(fromJson.asJsonValue(), defaultObject.asJsonValue());
++ QCOMPARE(fromJson.isHuntsValueSet(), defaultObject.isHuntsValueSet());
++ QCOMPARE(fromJson.isHuntsValueValid(), defaultObject.isHuntsValueValid());
++ QCOMPARE(fromJson.isAgeValueSet(), defaultObject.isAgeValueSet());
++ QCOMPARE(fromJson.isAgeValueValid(), defaultObject.isAgeValueValid());
++ QCOMPARE(fromJson.isSet(), defaultObject.isSet());
++ QCOMPARE(fromJson.isValid(), defaultObject.isValid());
++ QCOMPARE(fromJson, defaultObject);
++ }
++
++ void StandardModelsTest::testDogJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Dog>("dog");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isBarkSet");
++ QTest::addColumn<bool>("isBarkValid");
++ QTest::addColumn<bool>("isBreedSet");
++ QTest::addColumn<bool>("isBreedValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Dog model has 'bark' as a required field!
++ // An empty Dog is therefore invalid.
++ QTest::newRow("empty") << StandardSchemasModels::Dog{} << QString("{}"_L1)
++ // isBarkSet isBarkValid
++ << false << false
++ // isBreedSet isBreedValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ StandardSchemasModels::Dog hund;
++ hund.setBark(false);
++ hund.setBreed("French Bulldog");
++ QTest::newRow("bark=false; breed=French Bulldog")
++ << hund << QString("{\"bark\":false,\"breed\":\"French Bulldog\"}"_L1)
++ // isBarkSet isBarkValid
++ << true << true
++ // isBreedSet isBreedValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only the required 'bark' field set; 'breed' absent from JSON output.
++ StandardSchemasModels::Dog barkOnly;
++ barkOnly.setBark(true);
++ QTest::newRow("bark=true; breed not set") << barkOnly << QString("{\"bark\":true}"_L1)
++ // isBarkSet isBarkValid
++ << true << true
++ // isBreedSet isBreedValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with a wrong type for 'bark' (string instead of boolean):
++ // fromJsonValue() rejects the value, so 'bark' is dropped and the required
++ // field is missing, so the model becomes invalid.
++ StandardSchemasModels::Dog wrongBarkType("{\"bark\":\"yes\",\"breed\":\"Dingo\"}"_L1);
++ QTest::newRow("breed=Dingo; bark=wrong type => invalid model")
++ << wrongBarkType << QString("{\"breed\":\"Dingo\"}"_L1)
++ // isBarkSet isBarkValid
++ << false << false
++ // isBreedSet isBreedValid
++ << true << true
++ // modelIsValid modelIsSet
++ << false << true; // 'breed' was parsed successfully, so isSet() is true
++
++ // Model with a wrong type for 'breed' (integer instead of string):
++ // 'breed' is dropped
++ // 'bark' (required) is present, so the model stays valid.
++ // The test case for QTBUG-145423
++ StandardSchemasModels::Dog wrongBreedType("{\"bark\":true,\"breed\":42}"_L1);
++ QTest::newRow("bark=true; breed=wrong (int) type => dropped")
++ << wrongBreedType << QString("{\"bark\":true}"_L1)
++ // isBarkSet isBarkValid
++ << true << true
++ // isBreedSet isBreedValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with a wrong type for 'breed' (bool instead of string):
++ // 'breed' is dropped
++ // 'bark' (required) is present, so the model stays valid.
++ // The test case for QTBUG-145423
++ StandardSchemasModels::Dog wrongIntBreedType("{\"bark\":true,\"breed\":true}"_L1);
++ QTest::newRow("bark=true; breed=wrong (bool) type => dropped")
++ << wrongIntBreedType << QString("{\"bark\":true}"_L1)
++ // isBarkSet isBarkValid
++ << true << true
++ // isBreedSet isBreedValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with a wrong type for 'breed' (double instead of string):
++ // 'breed' is dropped
++ // 'bark' (required) is present, so the model stays valid.
++ // The test case for QTBUG-145423
++ StandardSchemasModels::Dog wrongDoubleBreedType("{\"bark\":true,\"breed\":42.99}"_L1);
++ QTest::newRow("bark=true; breed=wrong (double) type => dropped")
++ << wrongDoubleBreedType << QString("{\"bark\":true}"_L1)
++ // isBarkSet isBarkValid
++ << true << true
++ // isBreedSet isBreedValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with a broken 'breed' (empty instead of string):
++ // everything is dropped, so the model is invalid (required field is not set).
++ StandardSchemasModels::Dog brokenBreedType("{\"bark\":true,\"breed\":}"_L1);
++ QTest::newRow("bark=true; breed=broken field => dropped all")
++ << brokenBreedType << QString("{}"_L1)
++ // isBarkSet isBarkValid
++ << false << false
++ // isBreedSet isBreedValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Model with a string type that holds a stringified integer for 'breed':
++ // 'breed' is valid
++ // 'bark' (required) is present, so the model stays valid.
++ StandardSchemasModels::Dog stringifiedIntBreedType("{\"bark\":true,\"breed\":\"42\"}"_L1);
++ QTest::newRow("bark=true; breed=stringified integer")
++ << stringifiedIntBreedType << QString("{\"bark\":true,\"breed\":\"42\"}"_L1)
++ // isBarkSet isBarkValid
++ << true << true
++ // isBreedSet isBreedValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with unknown fields: known fields are parsed, unknown ones silently ignored.
++ StandardSchemasModels::Dog unknownFields(
++ "{\"bark\":false,\"name\":\"Rex\",\"age\":3,\"breed\":\"Husky\"}"_L1);
++ QTest::newRow("unknown fields dropped")
++ << unknownFields << QString("{\"bark\":false,\"breed\":\"Husky\"}"_L1)
++ // isBarkSet isBarkValid
++ << true << true
++ // isBreedSet isBreedValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with invalid JSON
++ // so all fields stay at their initial invalid/unset state.
++ // 'bark' is required but not valid, so the model is invalid.
++ StandardSchemasModels::Dog fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("invalid JSON") << fromInvalidJson << QString("{}"_L1)
++ // isBarkSet isBarkValid
++ << false << false
++ // isBreedSet isBreedValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++ }
++
++ void StandardModelsTest::testDogJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Dog, dog);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isBarkSet);
++ QFETCH(bool, isBarkValid);
++ QFETCH(bool, isBreedSet);
++ QFETCH(bool, isBreedValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue
++ = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(dog.asJson(), expectedJson);
++ QCOMPARE(dog.asJsonValue(), testValue);
++ QCOMPARE(dog.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(dog.isBarkValueSet(), isBarkSet);
++ QCOMPARE(dog.isBarkValueValid(), isBarkValid);
++ QCOMPARE(dog.isBreedValueSet(), isBreedSet);
++ QCOMPARE(dog.isBreedValueValid(), isBreedValid);
++ QCOMPARE(dog.isValid(), modelIsValid);
++ QCOMPARE(dog.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Dog fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isBarkValueSet(), isBarkSet);
++ QCOMPARE(fromJson.isBarkValueValid(), isBarkValid);
++ QCOMPARE(fromJson.isBreedValueSet(), isBreedSet);
++ QCOMPARE(fromJson.isBreedValueValid(), isBreedValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, dog);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Dog fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isBarkValueSet(), isBarkSet);
++ QCOMPARE(fromObject.isBarkValueValid(), isBarkValid);
++ QCOMPARE(fromObject.isBreedValueSet(), isBreedSet);
++ QCOMPARE(fromObject.isBreedValueValid(), isBreedValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, dog);
++ }
++
++ void StandardModelsTest::testBunnyJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Bunny>("bunny");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isWeightSet");
++ QTest::addColumn<bool>("isWeightValid");
++ QTest::addColumn<bool>("isExportingCountriesSet");
++ QTest::addColumn<bool>("isExportingCountriesValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Bunny requires 'exporting-countries'. An empty Bunny is therefore invalid.
++ QTest::newRow("empty") << StandardSchemasModels::Bunny{} << QString("{}"_L1)
++ // isWeightSet isWeightValid
++ << false << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Both fields set, model is valid.
++ StandardSchemasModels::Bunny fullBunny;
++ fullBunny.setWeight(2.5);
++ fullBunny.setExportingCountries({u"Germany"_s, u"France"_s});
++ QTest::newRow("weight=2.5; exportingCountries=[Germany,France]")
++ << fullBunny
++ << QString("{\"exporting-countries\":[\"Germany\",\"France\"],\"weight\":2.5}"_L1)
++ // isWeightSet isWeightValid
++ << true << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only the required 'exporting-countries' field, model is valid.
++ StandardSchemasModels::Bunny countriesOnly;
++ countriesOnly.setExportingCountries({u"Poland"_s});
++ QTest::newRow("exportingCountries=[Poland]; weight not set")
++ << countriesOnly << QString("{\"exporting-countries\":[\"Poland\"]}"_L1)
++ // isWeightSet isWeightValid
++ << false << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only the optional 'weight' field set, but
++ // required 'exporting-countries' absent, so the model is invalid.
++ StandardSchemasModels::Bunny weightOnly;
++ weightOnly.setWeight(1.2);
++ QTest::newRow("weight=1.2; exportingCountries not set")
++ << weightOnly << QString("{\"weight\":1.2}"_L1)
++ // isWeightSet isWeightValid
++ << true << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << true;
++
++ // Model with unknown fields: known fields are parsed, unknown ones silently ignored.
++ // Model has "additionalProperties: true", it means all unknown fields can be added
++ // to the resulting object as additional properties.
++ // But it is not supported yet. Should be done by: QTBUG-143257
++ const QString testString = QString("{\"exporting-countries\":[\"Japan\"],"
++ "\"weight\":3.0,\"color\":\"white\"}"_L1);
++ StandardSchemasModels::Bunny unknownFields(testString);
++ QTest::newRow("Model preserves unknown fields")
++ << unknownFields << testString
++ // isWeightSet isWeightValid
++ << true << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with an empty array for the required field 'exporting-countries':
++ // Per OAS 3.1, an empty array is a valid value and satisfies the required
++ // constraint (the key is present). So isExportingCountriesSet and
++ // isExportingCountriesValid are both true, and isValid() is true.
++ // However, the asJsonObject() omitted the empty arrays with size() > 0,
++ // so the empty arrays were silently dropped on serialization.
++ // Which is a bug and should be fixed.
++ // Note: Sending "exporting-countries": [] clearly signals that the bunny
++ // has no exporting countries.
++ // Omitting could be ambiguously interpreted as “unknown” or “not specified”
++ // depending on server logic.
++ // The test case for QTBUG-145412
++ StandardSchemasModels::Bunny emptyArray("{\"exporting-countries\":[]}"_L1);
++ QTest::newRow("exporting-countries=[]")
++ << emptyArray << QString("{\"exporting-countries\":[]}"_L1)
++ // isWeightSet isWeightValid
++ << false << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // "exporting-countries" is Array of strings. Non-string value is interpreted as an error
++ // The entire array omitted.
++ // The test case for QTBUG-145413
++ StandardSchemasModels::Bunny nonEmptyErrorArray("{\"exporting-countries\":[42]}"_L1);
++ QTest::newRow("exporting-countries=[42]")
++ << nonEmptyErrorArray << QString("{}"_L1)
++ // isWeightSet isWeightValid
++ << false << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // "exporting-countries" is Array of strings. We can set the string value == "42".
++ // The "exporting-countries" array is valid.
++ // The model is valid.
++ StandardSchemasModels::Bunny nonEmptyOkArray("{\"exporting-countries\":[\"42\"]}"_L1);
++ QTest::newRow("exporting-countries=[\"42\"]")
++ << nonEmptyOkArray << QString("{\"exporting-countries\":[\"42\"]}"_L1)
++ // isWeightSet isWeightValid
++ << false << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ StandardSchemasModels::Bunny errorArray("{\"exporting-countries\":[42, \"true\"]}"_L1);
++ QTest::newRow("exporting-countries=[42, \"true\"]")
++ << errorArray << QString("{}"_L1)
++ // isWeightSet isWeightValid
++ << false << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ StandardSchemasModels::Bunny nonEmptyArray("{\"exporting-countries\":[\"42\", \"true\"]}"_L1);
++ QTest::newRow("exporting-countries=[\"42\",\"true\"]")
++ << nonEmptyArray << QString("{\"exporting-countries\":[\"42\",\"true\"]}"_L1)
++ // isWeightSet isWeightValid
++ << false << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with invalid JSON: all fields stay unset/invalid.
++ // 'exporting-countries' is required but missing, so the model is invalid.
++ StandardSchemasModels::Bunny fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("invalid JSON")
++ << fromInvalidJson << QString("{}"_L1)
++ // isWeightSet isWeightValid
++ << false << true
++ // isExportingCountriesSet isExportingCountriesValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++ }
++
++ void StandardModelsTest::testBunnyJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Bunny, bunny);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isWeightSet);
++ QFETCH(bool, isWeightValid);
++ QFETCH(bool, isExportingCountriesSet);
++ QFETCH(bool, isExportingCountriesValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ QEXPECT_FAIL("Model preserves unknown fields",
++ "Known issue, should be fixed: QTBUG-143257", Abort);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(bunny.asJson(), expectedJson);
++ QCOMPARE(bunny.asJsonValue(), testValue);
++ QCOMPARE(bunny.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(bunny.isWeightValueSet(), isWeightSet);
++ QCOMPARE(bunny.isWeightValueValid(), isWeightValid);
++ QCOMPARE(bunny.isExportingCountriesValueSet(), isExportingCountriesSet);
++ QCOMPARE(bunny.isExportingCountriesValueValid(), isExportingCountriesValid);
++ QCOMPARE(bunny.isValid(), modelIsValid);
++ QCOMPARE(bunny.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Bunny fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isWeightValueSet(), isWeightSet);
++ QCOMPARE(fromJson.isWeightValueValid(), isWeightValid);
++ QCOMPARE(fromJson.isExportingCountriesValueSet(), isExportingCountriesSet);
++ QCOMPARE(fromJson.isExportingCountriesValueValid(), isExportingCountriesValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, bunny);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Bunny fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isWeightValueSet(), isWeightSet);
++ QCOMPARE(fromObject.isWeightValueValid(), isWeightValid);
++ QCOMPARE(fromObject.isExportingCountriesValueSet(), isExportingCountriesSet);
++ QCOMPARE(fromObject.isExportingCountriesValueValid(), isExportingCountriesValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, bunny);
++ }
++
++ void StandardModelsTest::testDuckFamilyJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Duck_family>("duckFamily");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isCountryOfOriginSet");
++ QTest::addColumn<bool>("isCountryOfOriginValid");
++ QTest::addColumn<bool>("isCountSet");
++ QTest::addColumn<bool>("isCountValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Duck_family has no required fields; an empty model is valid.
++ QTest::newRow("empty") << StandardSchemasModels::Duck_family{} << QString("{}"_L1)
++ // isCountryOfOriginSet isCountryOfOriginValid
++ << false << true
++ // isCountSet isCountValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // TBD have a look at floats parsing
++ // JSON does not “round” floats automatically
++ // Both fields set.
++ StandardSchemasModels::Duck_family full;
++ full.setCountryOfOrigin(u"Sweden"_s);
++ full.setCount(4.1f);
++ QTest::newRow("countryOfOrigin=Sweden; count=4.1")
++ << full << QString("{\"count\":4.099999904632568,\"countryOfOrigin\":\"Sweden\"}"_L1)
++ // isCountryOfOriginSet isCountryOfOriginValid
++ << true << true
++ // isCountSet isCountValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ full.setCountryOfOrigin(u"Sweden"_s);
++ full.setCount(4.0f);
++ QTest::newRow("countryOfOrigin=Sweden; count=4")
++ << full << QString("{\"count\":4,\"countryOfOrigin\":\"Sweden\"}"_L1)
++ // isCountryOfOriginSet isCountryOfOriginValid
++ << true << true
++ // isCountSet isCountValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++
++ // Only 'countryOfOrigin' set.
++ StandardSchemasModels::Duck_family countryOnly;
++ countryOnly.setCountryOfOrigin(u"Canada"_s);
++ QTest::newRow("countryOfOrigin=Canada; count not set")
++ << countryOnly << QString("{\"countryOfOrigin\":\"Canada\"}"_L1)
++ // isCountryOfOriginSet isCountryOfOriginValid
++ << true << true
++ // isCountSet isCountValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only 'count' set.
++ StandardSchemasModels::Duck_family countOnly;
++ countOnly.setCount(3.5f);
++ QTest::newRow("count=3.5; countryOfOrigin not set")
++ << countOnly << QString("{\"count\":3.5}"_L1)
++ // isCountryOfOriginSet isCountryOfOriginValid
++ << false << true
++ // isCountSet isCountValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with a wrong type for 'count' (string instead of float):
++ // fromJsonValue() rejects the value, so 'count' is dropped.
++ StandardSchemasModels::Duck_family wrongCountType(
++ "{\"countryOfOrigin\":\"Brazil\",\"count\":\"many\"}"_L1);
++ QTest::newRow("count=wrong type; dropped")
++ << wrongCountType << QString("{\"countryOfOrigin\":\"Brazil\"}"_L1)
++ // isCountryOfOriginSet isCountryOfOriginValid
++ << true << true
++ // isCountSet isCountValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // fromJson() with invalid JSON: all fields stay unset.
++ StandardSchemasModels::Duck_family fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("invalid JSON")
++ << fromInvalidJson << QString("{}"_L1)
++ // isCountryOfOriginSet isCountryOfOriginValid
++ << false << true
++ // isCountSet isCountValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++ }
++
++ void StandardModelsTest::testDuckFamilyJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Duck_family, duckFamily);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isCountryOfOriginSet);
++ QFETCH(bool, isCountryOfOriginValid);
++ QFETCH(bool, isCountSet);
++ QFETCH(bool, isCountValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(duckFamily.asJson(), expectedJson);
++ QCOMPARE(duckFamily.asJsonValue(), testValue);
++ QCOMPARE(duckFamily.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(duckFamily.isCountryOfOriginValueSet(), isCountryOfOriginSet);
++ QCOMPARE(duckFamily.isCountryOfOriginValueValid(), isCountryOfOriginValid);
++ QCOMPARE(duckFamily.isCountValueSet(), isCountSet);
++ QCOMPARE(duckFamily.isCountValueValid(), isCountValid);
++ QCOMPARE(duckFamily.isValid(), modelIsValid);
++ QCOMPARE(duckFamily.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Duck_family fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isCountryOfOriginValueSet(), isCountryOfOriginSet);
++ QCOMPARE(fromJson.isCountryOfOriginValueValid(), isCountryOfOriginValid);
++ QCOMPARE(fromJson.isCountValueSet(), isCountSet);
++ QCOMPARE(fromJson.isCountValueValid(), isCountValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, duckFamily);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Duck_family fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isCountryOfOriginValueSet(), isCountryOfOriginSet);
++ QCOMPARE(fromObject.isCountryOfOriginValueValid(), isCountryOfOriginValid);
++ QCOMPARE(fromObject.isCountValueSet(), isCountSet);
++ QCOMPARE(fromObject.isCountValueValid(), isCountValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, duckFamily);
++ }
++
++ void StandardModelsTest::testDuckJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Duck>("duck");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isBitesSet");
++ QTest::addColumn<bool>("isBitesValid");
++ QTest::addColumn<bool>("isFamilySet");
++ QTest::addColumn<bool>("isFamilyValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Duck has no required fields; an empty Duck is valid.
++ QTest::newRow("empty nested objects")
++ << StandardSchemasModels::Duck{} << QString("{}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << false << true // No required fields => family object is true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Both fields set - bites=true and a full family object.
++ StandardSchemasModels::Duck_family family;
++ family.setCountryOfOrigin(u"Australia"_s);
++ family.setCount(12.0f);
++ StandardSchemasModels::Duck fullDuck;
++ fullDuck.setBites(true);
++ fullDuck.setFamily(family);
++ QTest::newRow("bites=true; family={Australia,12}")
++ << fullDuck
++ << QString("{\"bites\":true,\"family\":"
++ "{\"count\":12,\"countryOfOrigin\":\"Australia\"}}"_L1)
++ // isBitesSet isBitesValid
++ << true << true
++ // isFamilySet isFamilyValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only 'bites' set; 'family' absent from JSON.
++ StandardSchemasModels::Duck bitesOnly;
++ bitesOnly.setBites(false);
++ QTest::newRow("bites=false; family not set")
++ << bitesOnly << QString("{\"bites\":false}"_L1)
++ // isBitesSet isBitesValid
++ << true << true
++ // isFamilySet isFamilyValid
++ << false << true // No required fields => family object is true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only 'family' set with a partial family (only countryOfOrigin).
++ StandardSchemasModels::Duck_family partialFamily;
++ partialFamily.setCountryOfOrigin(u"Norway"_s);
++ StandardSchemasModels::Duck familyOnly;
++ familyOnly.setFamily(partialFamily);
++ QTest::newRow("family={Norway}; bites not set")
++ << familyOnly << QString("{\"family\":{\"countryOfOrigin\":\"Norway\"}}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Set 'countryOfOrigin' to empty object, which is incorrect,
++ // because 'countryOfOrigin' is a string type.
++ // The model is invalid.
++ StandardSchemasModels::Duck incorrectFamily("{\"family\":{\"countryOfOrigin\":{}}}"_L1);
++ QTest::newRow("Set incorrect Object to family; bites not set")
++ << incorrectFamily << QString("{}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << false << true // valid because no required fields, so {} is OK.
++ // modelIsValid modelIsSet
++ << true << false;
++
++ StandardSchemasModels::Duck incorrectArrayFamily("{\"family\":{\"countryOfOrigin\":[42]}}"_L1);
++ QTest::newRow("Set incorrect Array to family; bites not set")
++ << incorrectArrayFamily << QString("{}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << false << true // valid because no required fields, so {} is OK.
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Model with a wrong type for 'bites' (integer instead of boolean):
++ // 'bites' is dropped; the model stays valid (no required fields).
++ StandardSchemasModels::Duck wrongBitesType("{\"bites\":1,\"family\":{\"count\":2.0}}"_L1);
++ QTest::newRow("bites=integer => dropped")
++ << wrongBitesType << QString("{\"family\":{\"count\":2}}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // 'family' is set, but empty;
++ StandardSchemasModels::Duck emptyFamily("{\"bites\":false,\"family\":{}}"_L1);
++ QTest::newRow("bites: false, family:{}")
++ << emptyFamily << QString("{\"bites\":false,\"family\":{}}"_L1)
++ // isBitesSet isBitesValid
++ << true << true
++ // isFamilySet isFamilyValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with unknown fields: known fields are parsed, unknown ones ignored.
++ StandardSchemasModels::Duck unknownFields(
++ "{\"bites\":true,\"family\":{\"count\":5.0},\"name\":\"Donald\"}"_L1);
++ QTest::newRow("unknown fields ignored")
++ << unknownFields << QString("{\"bites\":true,\"family\":{\"count\":5}}"_L1)
++ // isBitesSet isBitesValid
++ << true << true
++ // isFamilySet isFamilyValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // fromJson() with invalid JSON: all fields stay unset.
++ StandardSchemasModels::Duck fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("invalid JSON")
++ << fromInvalidJson << QString("{}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << false << true // No required fields => family object is true
++ // modelIsValid modelIsSet
++ << true << false;
++ }
++
++ void StandardModelsTest::testDuckJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Duck, duck);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isBitesSet);
++ QFETCH(bool, isBitesValid);
++ QFETCH(bool, isFamilySet);
++ QFETCH(bool, isFamilyValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(duck.asJson(), expectedJson);
++ QCOMPARE(duck.asJsonValue(), testValue);
++ QCOMPARE(duck.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(duck.isBitesValueSet(), isBitesSet);
++ QCOMPARE(duck.isBitesValueValid(), isBitesValid);
++ QCOMPARE(duck.isFamilyValueSet(), isFamilySet);
++ QCOMPARE(duck.isFamilyValueValid(), isFamilyValid);
++ QCOMPARE(duck.isValid(), modelIsValid);
++ QCOMPARE(duck.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Duck fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isBitesValueSet(), isBitesSet);
++ QCOMPARE(fromJson.isBitesValueValid(), isBitesValid);
++ QCOMPARE(fromJson.isFamilyValueSet(), isFamilySet);
++ QCOMPARE(fromJson.isFamilyValueValid(), isFamilyValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, duck);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Duck fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isBitesValueSet(), isBitesSet);
++ QCOMPARE(fromObject.isBitesValueValid(), isBitesValid);
++ QCOMPARE(fromObject.isFamilyValueSet(), isFamilySet);
++ QCOMPARE(fromObject.isFamilyValueValid(), isFamilyValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, duck);
++ }
++
++ void StandardModelsTest::testEnteJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Ente>("ente");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isBitesSet");
++ QTest::addColumn<bool>("isBitesValid");
++ QTest::addColumn<bool>("isFamilySet");
++ QTest::addColumn<bool>("isFamilyValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Ente has no required fields; an empty Ente is valid.
++ QTest::newRow("Ente: empty")
++ << StandardSchemasModels::Ente{} << QString("{}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << false << true // No required fields => family object is true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Both fields set - bites=true and a full family object (Duck reference).
++ StandardSchemasModels::Duck_family family;
++ family.setCountryOfOrigin(u"Germany"_s);
++ family.setCount(8.0f);
++ StandardSchemasModels::Duck duckFamily;
++ duckFamily.setBites(false);
++ duckFamily.setFamily(family);
++ StandardSchemasModels::Ente fullEnte;
++ fullEnte.setBites(true);
++ fullEnte.setFamily(duckFamily);
++ QTest::newRow("Ente: bites=true; family=Duck{bites:false,family:{Germany,8}}")
++ << fullEnte
++ << QString("{\"bites\":true,\"family\":"
++ "{\"bites\":false,\"family\":{\"count\":8,\"countryOfOrigin\":\"Germany\"}}}"_L1)
++ // isBitesSet isBitesValid
++ << true << true
++ // isFamilySet isFamilyValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only 'bites' set; 'family' absent from JSON.
++ StandardSchemasModels::Ente bitesOnly;
++ bitesOnly.setBites(false);
++ QTest::newRow("Ente: bites=false; family not set")
++ << bitesOnly << QString("{\"bites\":false}"_L1)
++ // isBitesSet isBitesValid
++ << true << true
++ // isFamilySet isFamilyValid
++ << false << true // No required fields => family object is true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only 'family' set with a Duck that has only bites.
++ StandardSchemasModels::Duck partialDuck;
++ partialDuck.setBites(true);
++ StandardSchemasModels::Ente familyOnly;
++ familyOnly.setFamily(partialDuck);
++ QTest::newRow("Ente: family=Duck{bites:true}; bites not set")
++ << familyOnly << QString("{\"family\":{\"bites\":true}}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Set 'family' to incorrect type (string instead of object).
++ // The family field should be dropped.
++ StandardSchemasModels::Ente incorrectFamily("{\"family\":\"not an object\"}"_L1);
++ QTest::newRow("Ente: incorrect string type for family")
++ << incorrectFamily << QString("{}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << false << true // valid because no required fields, so {} is OK.
++ // modelIsValid modelIsSet
++ << true << false;
++
++ StandardSchemasModels::Ente incorrectArrayFamily("{\"family\":[1,2,3]}"_L1);
++ QTest::newRow("Ente: incorrect array type for family")
++ << incorrectArrayFamily << QString("{}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << false << true // valid because no required fields, so {} is OK.
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Model with a wrong type for 'bites' (integer instead of boolean):
++ // 'bites' is dropped; the model stays valid (no required fields).
++ StandardSchemasModels::Ente wrongBitesType(
++ "{\"bites\":42,\"family\":{\"bites\":true}}"_L1);
++ QTest::newRow("Ente: bites=integer (wrong type) => dropped")
++ << wrongBitesType << QString("{\"family\":{\"bites\":true}}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // 'family' is set, but empty Duck object;
++ StandardSchemasModels::Ente emptyFamily("{\"bites\":false,\"family\":{}}"_L1);
++ QTest::newRow("Ente: bites=false, family={}")
++ << emptyFamily << QString("{\"bites\":false,\"family\":{}}"_L1)
++ // isBitesSet isBitesValid
++ << true << true
++ // isFamilySet isFamilyValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with unknown fields: known fields are parsed, unknown ones ignored.
++ StandardSchemasModels::Ente unknownFields(
++ "{\"bites\":true,\"family\":{\"bites\":false},\"color\":\"yellow\"}"_L1);
++ QTest::newRow("Ente: unknown fields ignored")
++ << unknownFields << QString("{\"bites\":true,\"family\":{\"bites\":false}}"_L1)
++ // isBitesSet isBitesValid
++ << true << true
++ // isFamilySet isFamilyValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // fromJson() with invalid JSON: all fields stay unset.
++ StandardSchemasModels::Ente fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("Ente: invalid JSON")
++ << fromInvalidJson << QString("{}"_L1)
++ // isBitesSet isBitesValid
++ << false << true
++ // isFamilySet isFamilyValid
++ << false << true // No required fields => family object is true
++ // modelIsValid modelIsSet
++ << true << false;
++ }
++
++ void StandardModelsTest::testEnteJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Ente, ente);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isBitesSet);
++ QFETCH(bool, isBitesValid);
++ QFETCH(bool, isFamilySet);
++ QFETCH(bool, isFamilyValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(ente.asJson(), expectedJson);
++ QCOMPARE(ente.asJsonValue(), testValue);
++ QCOMPARE(ente.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(ente.isBitesValueSet(), isBitesSet);
++ QCOMPARE(ente.isBitesValueValid(), isBitesValid);
++ QCOMPARE(ente.isFamilyValueSet(), isFamilySet);
++ QCOMPARE(ente.isFamilyValueValid(), isFamilyValid);
++ QCOMPARE(ente.isValid(), modelIsValid);
++ QCOMPARE(ente.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Ente fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isBitesValueSet(), isBitesSet);
++ QCOMPARE(fromJson.isBitesValueValid(), isBitesValid);
++ QCOMPARE(fromJson.isFamilyValueSet(), isFamilySet);
++ QCOMPARE(fromJson.isFamilyValueValid(), isFamilyValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, ente);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Ente fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isBitesValueSet(), isBitesSet);
++ QCOMPARE(fromObject.isBitesValueValid(), isBitesValid);
++ QCOMPARE(fromObject.isFamilyValueSet(), isFamilySet);
++ QCOMPARE(fromObject.isFamilyValueValid(), isFamilyValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, ente);
++ }
++
++ void StandardModelsTest::testPostAccountRequestOtherAccDataInnerJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::PostAccount_request_otherAccData_inner>("inner");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isPayloadSet");
++ QTest::addColumn<bool>("isPayloadValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // No required fields; an empty model is valid.
++ QTest::newRow("empty")
++ << StandardSchemasModels::PostAccount_request_otherAccData_inner{}
++ << QString("{}"_L1)
++ // isPayloadSet isPayloadValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // 'payload' set.
++ StandardSchemasModels::PostAccount_request_otherAccData_inner withPayload;
++ const QList<QList<QString>> fullList = {{"Normal string"_L1}};
++ withPayload.setPayload(fullList);
++ QTest::newRow("{\"payload\":[[\"Normal string\"]]}")
++ << withPayload << QString("{\"payload\":[[\"Normal string\"]]}"_L1)
++ // isPayloadSet isPayloadValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Entire Model should be invalidated, because the array contains an error type:
++ // the array should contain an array of strings: [["bla","bla"]], not a simple string.
++ // The test case for QTBUG-145413
++ StandardSchemasModels::PostAccount_request_otherAccData_inner errorPayload
++ ("{\"payload\":[\"Normal string\"]}"_L1);
++ QTest::newRow("{\"payload\":[\"Normal string\"]} => payload dropped}")
++ << errorPayload << QString("{}"_L1)
++ // isPayloadSet isPayloadValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Entire Model should be invalidated, because the array contains an error type:
++ // the array should contain an array of strings: [["bla","bla"]], not the array of ints.
++ // The test case for QTBUG-145413
++ StandardSchemasModels::PostAccount_request_otherAccData_inner error2Payload
++ ("{\"payload\":[[42]]}"_L1);
++ QTest::newRow("{\"payload\":[[42]]} => payload dropped}")
++ << error2Payload << QString("{}"_L1)
++ // isPayloadSet isPayloadValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Model with a wrong type for 'payload' (string instead of array):
++ // fromJsonValue() rejects the value, so 'payload' is dropped.
++ StandardSchemasModels::PostAccount_request_otherAccData_inner
++ wrongPayloadType("{\"payload\":\"heavy\"}"_L1);
++ QTest::newRow("fromJson payload=string => payload dropped")
++ << wrongPayloadType << QString("{}"_L1)
++ // isPayloadSet isPayloadValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Model with invalid JSON: all fields stay unset.
++ StandardSchemasModels::PostAccount_request_otherAccData_inner fromInvalidJson(
++ "{invalid json}"_L1);
++ QTest::newRow("invalid JSON") << fromInvalidJson << QString("{}"_L1)
++ // isPayloadSet isPayloadValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++ }
++
++ void StandardModelsTest::testPostAccountRequestOtherAccDataInnerJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::PostAccount_request_otherAccData_inner, inner);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isPayloadSet);
++ QFETCH(bool, isPayloadValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(inner.asJson(), expectedJson);
++ QCOMPARE(inner.asJsonValue(), testValue);
++ QCOMPARE(inner.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(inner.isPayloadValueSet(), isPayloadSet);
++ QCOMPARE(inner.isPayloadValueValid(), isPayloadValid);
++ QCOMPARE(inner.isValid(), modelIsValid);
++ QCOMPARE(inner.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::PostAccount_request_otherAccData_inner fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isPayloadValueSet(), isPayloadSet);
++ QCOMPARE(fromJson.isPayloadValueValid(), isPayloadValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, inner);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::PostAccount_request_otherAccData_inner fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isPayloadValueSet(), isPayloadSet);
++ QCOMPARE(fromObject.isPayloadValueValid(), isPayloadValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, inner);
++ }
++
++ // Test for INLINE model => the INLINE model is a model that is declared directly in requestBody
++ void StandardModelsTest::testPostAccountRequestJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::PostAccount_request>("request");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isCardNumberSet");
++ QTest::addColumn<bool>("isCardNumberValid");
++ QTest::addColumn<bool>("isCardDataSet");
++ QTest::addColumn<bool>("isCardDataValid");
++ QTest::addColumn<bool>("isCardAvailabilitySet");
++ QTest::addColumn<bool>("isCardAvailabilityValid");
++ QTest::addColumn<bool>("isCardSecretCodeSet");
++ QTest::addColumn<bool>("isCardSecretCodeValid");
++ QTest::addColumn<bool>("isOtherAccDataSet");
++ QTest::addColumn<bool>("isOtherAccDataValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // 'cardNumber' is required. Empty model is invalid.
++ QTest::newRow("empty") << StandardSchemasModels::PostAccount_request{} << QString("{}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << false << false
++ // isCardDataSet isCardDataValid
++ << false << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Only the required 'cardNumber' set, model is valid.
++ StandardSchemasModels::PostAccount_request cardNumberOnly;
++ cardNumberOnly.setCardNumber(u"1234-5678-9012-3456"_s);
++ QTest::newRow("cardNumber only")
++ << cardNumberOnly << QString("{\"cardNumber\":\"1234-5678-9012-3456\"}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << true << true
++ // isCardDataSet isCardDataValid
++ << false << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // All fields set including a non-empty 'otherAccData' list.
++ StandardSchemasModels::PostAccount_request_otherAccData_inner item;
++ const QList<QList<QString>> fullList = {{"Password"_L1, "1234567890*qwerty"_L1}};
++ item.setPayload(fullList);
++ StandardSchemasModels::PostAccount_request full;
++ full.setCardNumber(u"0000-1111-2222-3333"_s);
++ full.setCardData(42);
++ full.setCardAvailability(true);
++ full.setCardSecretCode(1.5f);
++ full.setOtherAccData({item});
++ QTest::newRow("all fields set")
++ << full << QString("{\"cardAvailability\":true,\"cardData\":42,"
++ "\"cardNumber\":\"0000-1111-2222-3333\","
++ "\"cardSecretCode\":1.5,"
++ "\"otherAccData\":"
++ "[{\"payload\":[[\"Password\",\"1234567890*qwerty\"]]}]}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << true << true
++ // isCardDataSet isCardDataValid
++ << true << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << true << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << true << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with a wrong type for 'cardNumber' (integer instead of string):
++ // 'cardNumber' dropped; model is invalid, because required cardNumber is wrong.
++ // The test case for QTBUG-145423
++ StandardSchemasModels::PostAccount_request wrongCardNumberType("{\"cardNumber\":99}"_L1);
++ QTest::newRow("cardNumber=wrong (int) type; dropped")
++ << wrongCardNumberType << QString("{}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << false << false
++ // isCardDataSet isCardDataValid
++ << false << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Model with a wrong type for 'cardNumber' (array instead of string):
++ // 'cardNumber' dropped; model is invalid, because required cardNumber is wrong.
++ // The test case for QTBUG-145423
++ StandardSchemasModels::PostAccount_request arrayCardNumberType("{\"cardNumber\":[\"99\"]}"_L1);
++ QTest::newRow("arrayCardNumberType=wrong (array) type; dropped")
++ << arrayCardNumberType << QString("{}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << false << false
++ // isCardDataSet isCardDataValid
++ << false << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Model with a wrong type for 'cardNumber' (object instead of string):
++ // 'cardNumber' dropped; model is invalid, because required cardNumber is wrong.
++ // The test case for QTBUG-145423
++ StandardSchemasModels::PostAccount_request objectCardNumberType("{\"cardNumber\":{key:1}}"_L1);
++ QTest::newRow("arrayCardNumberType=wrong (object) type; dropped")
++ << objectCardNumberType << QString("{}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << false << false
++ // isCardDataSet isCardDataValid
++ << false << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Model with a wrong type for 'cardData' (string instead of integer):
++ // NOTE: 'cardData' should be omitted, because we're trying to set incorrect data type!
++ // The test case for QTBUG-145410
++ // 'cardData' is dropped, but required field 'cardNumber' is set correctly,
++ // so model is valid.
++ StandardSchemasModels::PostAccount_request wrongCardDataType(
++ "{\"cardNumber\":\"ABC\",\"cardData\":\"notAnInt\"}"_L1);
++ QTest::newRow("cardData=wrong string type; cardNumber=string")
++ << wrongCardDataType << QString("{\"cardNumber\":\"ABC\"}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << true << true
++ // isCardDataSet isCardDataValid
++ << false << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with a wrong type for 'cardData' (double instead of integer):
++ // NOTE: 'cardData' should be omitted, because we're trying to set incorrect data type!
++ // The test case for QTBUG-145410
++ // 'cardData' is dropped, but required field 'cardNumber' is set correctly,
++ // so model is valid.
++ StandardSchemasModels::PostAccount_request wrongDoubleCardDataType(
++ "{\"cardNumber\":\"ABC\",\"cardData\":8.88}"_L1);
++ QTest::newRow("cardData=wrong double type; cardNumber=string")
++ << wrongDoubleCardDataType << QString("{\"cardNumber\":\"ABC\"}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << true << true
++ // isCardDataSet isCardDataValid
++ << false << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with a wrong type for 'cardData' (array of integers instead of integer):
++ // NOTE: 'cardData' should be omitted, because we're trying to set incorrect data type!
++ // The test case for QTBUG-145410
++ // 'cardData' is dropped, but required field 'cardNumber' is set correctly,
++ // so model is valid.
++ StandardSchemasModels::PostAccount_request arrayCardDataType(
++ "{\"cardNumber\":\"ABC\",\"cardData\":[8, 7]}"_L1);
++ QTest::newRow("cardData=wrong array type; cardNumber=string")
++ << arrayCardDataType << QString("{\"cardNumber\":\"ABC\"}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << true << true
++ // isCardDataSet isCardDataValid
++ << false << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with a wrong type for 'cardData' (Object instead of integer):
++ // NOTE: 'cardData' should be omitted, because we're trying to set incorrect data type!
++ // The test case for QTBUG-145410
++ // 'cardData' is dropped, but required field 'cardNumber' is set correctly,
++ // so model is valid.
++ StandardSchemasModels::PostAccount_request objectCardDataType(
++ "{\"cardNumber\":\"ABC\",\"cardData\":{}}"_L1);
++ QTest::newRow("cardData=wrong Object type; cardNumber=string")
++ << objectCardDataType << QString("{\"cardNumber\":\"ABC\"}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << true << true
++ // isCardDataSet isCardDataValid
++ << false << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // PostAccount_request model has "additionalProperties: true", it means all unknown fields
++ // can be added to the resulting object as additional properties.
++ // But it is not supported yet. Should be done by: QTBUG-143257
++ StandardSchemasModels::PostAccount_request unknownFields(
++ "{\"cardNumber\":\"XYZ\",\"cardData\":7,\"unknownField\":\"ignored\"}"_L1);
++ QTest::newRow("Model preserves unknown fields")
++ << unknownFields
++ << QString("{\"cardNumber\":\"XYZ\",\"cardData\":7,\"unknownField\":\"ignored\"}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << true << true
++ // isCardDataSet isCardDataValid
++ << true << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Model with invalid JSON: all fields stay unset. 'cardNumber' is required
++ // but missing, so the model is invalid.
++ StandardSchemasModels::PostAccount_request fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("invalid JSON") << fromInvalidJson << QString("{}"_L1)
++ // isCardNumberSet isCardNumberValid
++ << false << false
++ // isCardDataSet isCardDataValid
++ << false << true
++ // isCardAvailabilitySet isCardAvailabilityValid
++ << false << true
++ // isCardSecretCodeSet isCardSecretCodeValid
++ << false << true
++ // isOtherAccDataSet isOtherAccDataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++ }
++
++ void StandardModelsTest::testPostAccountRequestJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::PostAccount_request, request);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isCardNumberSet);
++ QFETCH(bool, isCardNumberValid);
++ QFETCH(bool, isCardDataSet);
++ QFETCH(bool, isCardDataValid);
++ QFETCH(bool, isCardAvailabilitySet);
++ QFETCH(bool, isCardAvailabilityValid);
++ QFETCH(bool, isCardSecretCodeSet);
++ QFETCH(bool, isCardSecretCodeValid);
++ QFETCH(bool, isOtherAccDataSet);
++ QFETCH(bool, isOtherAccDataValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ QEXPECT_FAIL("Model preserves unknown fields",
++ "Known issue, should be fixed: QTBUG-143257", Abort);
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(request.asJson(), expectedJson);
++ QCOMPARE(request.asJsonValue(), testValue);
++ QCOMPARE(request.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(request.isCardNumberValueSet(), isCardNumberSet);
++ QCOMPARE(request.isCardNumberValueValid(), isCardNumberValid);
++ QCOMPARE(request.isCardDataValueSet(), isCardDataSet);
++ QCOMPARE(request.isCardDataValueValid(), isCardDataValid);
++ QCOMPARE(request.isCardAvailabilityValueSet(), isCardAvailabilitySet);
++ QCOMPARE(request.isCardAvailabilityValueValid(), isCardAvailabilityValid);
++ QCOMPARE(request.isCardSecretCodeValueSet(), isCardSecretCodeSet);
++ QCOMPARE(request.isCardSecretCodeValueValid(), isCardSecretCodeValid);
++ QCOMPARE(request.isOtherAccDataValueSet(), isOtherAccDataSet);
++ QCOMPARE(request.isOtherAccDataValueValid(), isOtherAccDataValid);
++ QCOMPARE(request.isValid(), modelIsValid);
++ QCOMPARE(request.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::PostAccount_request fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isCardNumberValueSet(), isCardNumberSet);
++ QCOMPARE(fromJson.isCardNumberValueValid(), isCardNumberValid);
++ QCOMPARE(fromJson.isCardDataValueSet(), isCardDataSet);
++ QCOMPARE(fromJson.isCardDataValueValid(), isCardDataValid);
++ QCOMPARE(fromJson.isCardAvailabilityValueSet(), isCardAvailabilitySet);
++ QCOMPARE(fromJson.isCardAvailabilityValueValid(), isCardAvailabilityValid);
++ QCOMPARE(fromJson.isCardSecretCodeValueSet(), isCardSecretCodeSet);
++ QCOMPARE(fromJson.isCardSecretCodeValueValid(), isCardSecretCodeValid);
++ QCOMPARE(fromJson.isOtherAccDataValueSet(), isOtherAccDataSet);
++ QCOMPARE(fromJson.isOtherAccDataValueValid(), isOtherAccDataValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, request);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::PostAccount_request fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isCardNumberValueSet(), isCardNumberSet);
++ QCOMPARE(fromObject.isCardNumberValueValid(), isCardNumberValid);
++ QCOMPARE(fromObject.isCardDataValueSet(), isCardDataSet);
++ QCOMPARE(fromObject.isCardDataValueValid(), isCardDataValid);
++ QCOMPARE(fromObject.isCardAvailabilityValueSet(), isCardAvailabilitySet);
++ QCOMPARE(fromObject.isCardAvailabilityValueValid(), isCardAvailabilityValid);
++ QCOMPARE(fromObject.isCardSecretCodeValueSet(), isCardSecretCodeSet);
++ QCOMPARE(fromObject.isCardSecretCodeValueValid(), isCardSecretCodeValid);
++ QCOMPARE(fromObject.isOtherAccDataValueSet(), isOtherAccDataSet);
++ QCOMPARE(fromObject.isOtherAccDataValueValid(), isOtherAccDataValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, request);
++ }
++
++ void StandardModelsTest::testAnimalJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Animal>("animal");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isNestedMapSet");
++ QTest::addColumn<bool>("isNestedMapValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Animal model has no required fields; an empty model is valid.
++ QTest::newRow("empty") << StandardSchemasModels::Animal{} << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Both keys set via setNestedMap(); the map serializes alphabetically.
++ StandardSchemasModels::Animal full;
++ full.setNestedMap({{u"key1"_s, {{u"a"_s, u"alpha"_s}}},
++ {u"key2"_s, {{u"b"_s, u"beta"_s}}}});
++ QTest::newRow("nestedMap={key1:{a:alpha},key2:{b:beta}}")
++ << full
++ << QString("{\"nestedMap\":{\"key1\":{\"a\":\"alpha\"},\"key2\":{\"b\":\"beta\"}}}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Single-entry map set via setNestedMap().
++ StandardSchemasModels::Animal singleEntry;
++ singleEntry.setNestedMap({{u"outer"_s, {{u"inner"_s, u"value"_s}}}});
++ QTest::newRow("nestedMap={outer:{inner:value}}")
++ << singleEntry
++ << QString("{\"nestedMap\":{\"outer\":{\"inner\":\"value\"}}}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Parsed from JSON: non-empty nestedMap.
++ StandardSchemasModels::Animal fromJsonAnimal(
++ "{\"nestedMap\":{\"k\":{\"x\":\"hello\"}}}"_L1);
++ QTest::newRow("fromJson: nestedMap={k:{x:hello}}")
++ << fromJsonAnimal
++ << QString("{\"nestedMap\":{\"k\":{\"x\":\"hello\"}}}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Parsed from JSON: empty object for nestedMap.
++ StandardSchemasModels::Animal emptyNestedMap("{\"nestedMap\":{}}"_L1);
++ QTest::newRow("fromJson: nestedMap={}")
++ << emptyNestedMap
++ << QString("{\"nestedMap\":{}}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Wrong type for 'nestedMap' (string instead of object): dropped entirely.
++ StandardSchemasModels::Animal wrongStringType("{\"nestedMap\":\"notAnObject\"}"_L1);
++ QTest::newRow("nestedMap=wrong (string) type; dropped")
++ << wrongStringType << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Wrong type for 'nestedMap' (array instead of object): dropped entirely.
++ StandardSchemasModels::Animal wrongArrayType("{\"nestedMap\":[{\"a\":\"b\"}]}"_L1);
++ QTest::newRow("nestedMap=wrong (array) type; dropped")
++ << wrongArrayType << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Wrong type for 'nestedMap' (integer instead of object): dropped entirely.
++ StandardSchemasModels::Animal wrongIntType("{\"nestedMap\":42}"_L1);
++ QTest::newRow("nestedMap=wrong (integer) type; dropped")
++ << wrongIntType << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Wrong inner value type: the inner value should be an object of strings,
++ // not a plain string. The whole nestedMap is dropped.
++ StandardSchemasModels::Animal wrongInnerValue("{\"nestedMap\":{\"k\":\"notAnObject\"}}"_L1);
++ QTest::newRow("nestedMap inner value wrong type; dropped")
++ << wrongInnerValue << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++
++ // Unknown fields are ignored for now.
++ StandardSchemasModels::Animal unknownFields(
++ "{\"nestedMap\":{\"k\":{\"x\":\"v\"}},\"unknownField\":\"ignored\"}"_L1);
++ QTest::newRow("unknown fields ignored")
++ << unknownFields
++ << QString("{\"nestedMap\":{\"k\":{\"x\":\"v\"}}}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Invalid JSON: all fields stay at initial state. No required fields => still valid.
++ StandardSchemasModels::Animal fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("invalid JSON") << fromInvalidJson << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << false;
++ }
++
++ void StandardModelsTest::testAnimalJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Animal, animal);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isNestedMapSet);
++ QFETCH(bool, isNestedMapValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(animal.asJson(), expectedJson);
++ QCOMPARE(animal.asJsonValue(), testValue);
++ QCOMPARE(animal.isNestedMapValueSet(), isNestedMapSet);
++ QCOMPARE(animal.isNestedMapValueValid(), isNestedMapValid);
++ QCOMPARE(animal.isValid(), modelIsValid);
++ QCOMPARE(animal.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Animal fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.isNestedMapValueSet(), isNestedMapSet);
++ QCOMPARE(fromJson.isNestedMapValueValid(), isNestedMapValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, animal);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Animal fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.isNestedMapValueSet(), isNestedMapSet);
++ QCOMPARE(fromObject.isNestedMapValueValid(), isNestedMapValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, animal);
++ }
++
++ void StandardModelsTest::testTierJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Tier>("tier");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isNestedMapSet");
++ QTest::addColumn<bool>("isNestedMapValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Tier: empty model is INVALID because nestedMap is required.
++ QTest::newRow("Tier: empty (invalid - missing required field)")
++ << StandardSchemasModels::Tier{} << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Tier: valid with nestedMap set.
++ StandardSchemasModels::Tier full;
++ full.setNestedMap({{u"key1"_s, {{u"a"_s, u"alpha"_s}}},
++ {u"key2"_s, {{u"b"_s, u"beta"_s}}}});
++ QTest::newRow("Tier: nestedMap={key1:{a:alpha},key2:{b:beta}}")
++ << full
++ << QString("{\"nestedMap\":{\"key1\":{\"a\":\"alpha\"},\"key2\":{\"b\":\"beta\"}}}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Tier: single-entry map via setNestedMap().
++ StandardSchemasModels::Tier singleEntry;
++ singleEntry.setNestedMap({{u"outer"_s, {{u"inner"_s, u"value"_s}}}});
++ QTest::newRow("Tier: nestedMap={outer:{inner:value}}")
++ << singleEntry
++ << QString("{\"nestedMap\":{\"outer\":{\"inner\":\"value\"}}}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Tier: parsed from JSON with valid nestedMap.
++ StandardSchemasModels::Tier fromJsonTier(
++ "{\"nestedMap\":{\"k\":{\"x\":\"hello\"}}}"_L1);
++ QTest::newRow("Tier: fromJson: nestedMap={k:{x:hello}}")
++ << fromJsonTier
++ << QString("{\"nestedMap\":{\"k\":{\"x\":\"hello\"}}}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Tier: empty object for nestedMap is still valid (set but empty).
++ StandardSchemasModels::Tier emptyNestedMap("{\"nestedMap\":{}}"_L1);
++ QTest::newRow("Tier: fromJson: nestedMap={}")
++ << emptyNestedMap
++ << QString("{\"nestedMap\":{}}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Tier: wrong type for 'nestedMap' (string): dropped, model becomes invalid.
++ StandardSchemasModels::Tier wrongStringType("{\"nestedMap\":\"notAnObject\"}"_L1);
++ QTest::newRow("Tier: nestedMap=wrong (string) type; dropped (invalid)")
++ << wrongStringType << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Tier: wrong type for 'nestedMap' (array): dropped, model becomes invalid.
++ StandardSchemasModels::Tier wrongArrayType("{\"nestedMap\":[{\"a\":\"b\"}]}"_L1);
++ QTest::newRow("Tier: nestedMap=wrong (array) type; dropped (invalid)")
++ << wrongArrayType << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Tier: wrong type for 'nestedMap' (integer): dropped, model becomes invalid.
++ StandardSchemasModels::Tier wrongIntType("{\"nestedMap\":42}"_L1);
++ QTest::newRow("Tier: nestedMap=wrong (integer) type; dropped (invalid)")
++ << wrongIntType << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Tier: wrong inner value type - nestedMap dropped, model becomes invalid.
++ StandardSchemasModels::Tier wrongInnerValue("{\"nestedMap\":{\"k\":\"notAnObject\"}}"_L1);
++ QTest::newRow("Tier: nestedMap inner value wrong type; dropped (invalid)")
++ << wrongInnerValue << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Tier: invalid JSON - required field missing, model is invalid.
++ StandardSchemasModels::Tier fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("Tier: invalid JSON")
++ << fromInvalidJson << QString("{}"_L1)
++ // isNestedMapSet isNestedMapValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++ }
++
++ void StandardModelsTest::testTierJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Tier, tier);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isNestedMapSet);
++ QFETCH(bool, isNestedMapValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(tier.asJson(), expectedJson);
++ QCOMPARE(tier.asJsonValue(), testValue);
++ QCOMPARE(tier.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(tier.isNestedMapValueSet(), isNestedMapSet);
++ QCOMPARE(tier.isNestedMapValueValid(), isNestedMapValid);
++ QCOMPARE(tier.isValid(), modelIsValid);
++ QCOMPARE(tier.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Tier fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isNestedMapValueSet(), isNestedMapSet);
++ QCOMPARE(fromJson.isNestedMapValueValid(), isNestedMapValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, tier);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Tier fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue.toObject());
++ QCOMPARE(fromObject.isNestedMapValueSet(), isNestedMapSet);
++ QCOMPARE(fromObject.isNestedMapValueValid(), isNestedMapValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, tier);
++ }
++
++ void StandardModelsTest::testTiereJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Tiere>("tiere");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isNameSet");
++ QTest::addColumn<bool>("isNameValid");
++ QTest::addColumn<bool>("isDeepNestedMapSet");
++ QTest::addColumn<bool>("isDeepNestedMapValid");
++ QTest::addColumn<bool>("isSpeciesListSet");
++ QTest::addColumn<bool>("isSpeciesListValid");
++ QTest::addColumn<bool>("isMetadataSet");
++ QTest::addColumn<bool>("isMetadataValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Tiere: empty model is INVALID (deepNestedMap and speciesList are required).
++ QTest::newRow("Tiere: empty (invalid - missing required fields)")
++ << StandardSchemasModels::Tiere{} << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << false << false
++ // isSpeciesListSet isSpeciesListValid
++ << false << false
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Tiere: fully valid model with all required fields.
++ StandardSchemasModels::Duck duck1;
++ duck1.setBites(true);
++ StandardSchemasModels::Duck_family family1;
++ family1.setCountryOfOrigin(u"Germany"_s);
++ family1.setCount(5.5);
++ duck1.setFamily(family1);
++
++ StandardSchemasModels::Duck duck2;
++ duck2.setBites(false);
++
++ StandardSchemasModels::Ente ente1;
++ ente1.setBites(true);
++ ente1.setFamily(duck1);
++
++ StandardSchemasModels::Tiere full;
++ full.setName(u"European Birds"_s);
++ full.setDeepNestedMap({{u"region1"_s, {{u"species1"_s, duck1}, {u"species2"_s, duck2}}}});
++ full.setSpeciesList({ente1});
++
++ QTest::newRow("Tiere: full model with all fields")
++ << full
++ << QString("{\"deepNestedMap\":{\"region1\":{\"species1\":{\"bites\":true,\"family\":{\"count\":5.5,\"countryOfOrigin\":\"Germany\"}},\"species2\":{\"bites\":false}}},\"name\":\"European Birds\",\"speciesList\":[{\"bites\":true,\"family\":{\"bites\":true,\"family\":{\"count\":5.5,\"countryOfOrigin\":\"Germany\"}}}]}"_L1)
++ // isNameSet isNameValid
++ << true << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << true << true
++ // isSpeciesListSet isSpeciesListValid
++ << true << true
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Tiere: minimal valid - only required fields with empty containers.
++ StandardSchemasModels::Tiere minimal;
++ minimal.setDeepNestedMap({});
++ minimal.setSpeciesList({});
++ QTest::newRow("Tiere: minimal valid (empty required containers)")
++ << minimal
++ << QString("{\"deepNestedMap\":{},\"speciesList\":[]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << true << true
++ // isSpeciesListSet isSpeciesListValid
++ << true << true
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Tiere: parsed from JSON with valid structure.
++ StandardSchemasModels::Tiere fromJson(
++ "{\"name\":\"Birds\",\"deepNestedMap\":{\"r1\":{\"s1\":{\"bites\":true}}},\"speciesList\":[{\"bites\":false}]}"_L1);
++ QTest::newRow("Tiere: fromJson with valid structure")
++ << fromJson
++ << QString("{\"deepNestedMap\":{\"r1\":{\"s1\":{\"bites\":true}}},\"name\":\"Birds\",\"speciesList\":[{\"bites\":false}]}"_L1)
++ // isNameSet isNameValid
++ << true << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << true << true
++ // isSpeciesListSet isSpeciesListValid
++ << true << true
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Tiere: wrong type for deepNestedMap (string) - dropped.
++ StandardSchemasModels::Tiere wrongDeepMapType(
++ "{\"deepNestedMap\":\"notAnObject\",\"speciesList\":[]}"_L1);
++ QTest::newRow("Tiere: deepNestedMap wrong type (string) is dropped (invalid), speciesList: []")
++ << wrongDeepMapType << QString("{\"speciesList\":[]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << false << false
++ // isSpeciesListSet isSpeciesListValid
++ << true << true
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << true;
++
++ // Tiere: wrong type for speciesList (object) is dropped.
++ StandardSchemasModels::Tiere wrongSpeciesListType(
++ "{\"deepNestedMap\":{},\"speciesList\":{}}"_L1);
++ QTest::newRow("Tiere: speciesList wrong type (object) is dropped (invalid), deepNestedMap: {}")
++ << wrongSpeciesListType << QString("{\"deepNestedMap\":{}}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << true << true
++ // isSpeciesListSet isSpeciesListValid
++ << false << false
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << true;
++
++ // Tiere: invalid inner Duck in deepNestedMap - required field with invalid data
++ // makes deepNestedMap model invalid.
++ // speciesList:[] is a valid empty array - it is present and well-formed, so it must
++ // be preserved in the output and reported as set/valid.
++ StandardSchemasModels::Tiere invalidInnerDuck(
++ "{\"deepNestedMap\":{\"r1\":{\"s1\":\"invalidDuck\"}},\"speciesList\":[]}"_L1);
++ QTest::newRow("Tiere: deepNestedMap with invalid inner Duck; field dropped (model invalid)")
++ << invalidInnerDuck << QString("{\"speciesList\":[]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << false << false
++ // isSpeciesListSet isSpeciesListValid
++ << true << true
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << true;
++
++ // Tiere: invalid Ente in speciesList - required array with ANY invalid entries is entirely dropped.
++ StandardSchemasModels::Tiere invalidEnteInList(
++ "{\"deepNestedMap\":{},\"speciesList\":[\"notAnEnte\",{\"bites\":true}]}"_L1);
++ QTest::newRow("Tiere: speciesList with invalid Ente; entire array dropped (model invalid)")
++ << invalidEnteInList << QString("{\"deepNestedMap\":{}}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << true << true
++ // isSpeciesListSet isSpeciesListValid
++ << false << false
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << true;
++
++ // Tiere: with metadata object set.
++ StandardSchemasModels::Tiere withMetadata;
++ withMetadata.setName(u"randomname"_s);
++ withMetadata.setDeepNestedMap({});
++ withMetadata.setSpeciesList({});
++ StandardSchemasModels::Tiere_metadata meta;
++ meta.setRegion(u"Europe"_s);
++ meta.setPopulation(1000000);
++ meta.setEndangered(false);
++ meta.setCategories({u"waterfowl"_s, u"raptors"_s, u"songbirds"_s});
++ withMetadata.setMetadata(meta);
++ QTest::newRow("Tiere: with metadata object")
++ << withMetadata
++ << QString("{\"deepNestedMap\":{},\"metadata\":{\"categories\":[\"waterfowl\",\"raptors\",\"songbirds\"],\"endangered\":false,\"population\":1000000,\"region\":\"Europe\"},\"name\":\"randomname\",\"speciesList\":[]}"_L1)
++ // isNameSet isNameValid
++ << true << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << true << true
++ // isSpeciesListSet isSpeciesListValid
++ << true << true
++ // isMetadataSet isMetadataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Tiere: invalid JSON - all fields invalid.
++ StandardSchemasModels::Tiere fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("Tiere: invalid JSON")
++ << fromInvalidJson << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << false << false
++ // isSpeciesListSet isSpeciesListValid
++ << false << false
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Tiere: missing only deepNestedMap - model invalid.
++ StandardSchemasModels::Tiere missingDeepMap("{\"speciesList\":[]}"_L1);
++ QTest::newRow("Tiere: missing required deepNestedMap")
++ << missingDeepMap << QString("{\"speciesList\":[]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << false << false
++ // isSpeciesListSet isSpeciesListValid
++ << true << true
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << true;
++
++ // Tiere: missing only speciesList - model invalid.
++ StandardSchemasModels::Tiere missingSpeciesList("{\"deepNestedMap\":{}}"_L1);
++ QTest::newRow("Tiere: missing required speciesList")
++ << missingSpeciesList << QString("{\"deepNestedMap\":{}}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepNestedMapSet isDeepNestedMapValid
++ << true << true
++ // isSpeciesListSet isSpeciesListValid
++ << false << false
++ // isMetadataSet isMetadataValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << true;
++ }
++
++ void StandardModelsTest::testTiereJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Tiere, tiere);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isNameSet);
++ QFETCH(bool, isNameValid);
++ QFETCH(bool, isDeepNestedMapSet);
++ QFETCH(bool, isDeepNestedMapValid);
++ QFETCH(bool, isSpeciesListSet);
++ QFETCH(bool, isSpeciesListValid);
++ QFETCH(bool, isMetadataSet);
++ QFETCH(bool, isMetadataValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(tiere.asJson(), expectedJson);
++ QCOMPARE(tiere.asJsonValue(), testValue);
++ QCOMPARE(tiere.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(tiere.isNameValueSet(), isNameSet);
++ QCOMPARE(tiere.isNameValueValid(), isNameValid);
++ QCOMPARE(tiere.isDeepNestedMapValueSet(), isDeepNestedMapSet);
++ QCOMPARE(tiere.isDeepNestedMapValueValid(), isDeepNestedMapValid);
++ QCOMPARE(tiere.isSpeciesListValueSet(), isSpeciesListSet);
++ QCOMPARE(tiere.isSpeciesListValueValid(), isSpeciesListValid);
++ QCOMPARE(tiere.isMetadataValueSet(), isMetadataSet);
++ QCOMPARE(tiere.isMetadataValueValid(), isMetadataValid);
++ QCOMPARE(tiere.isValid(), modelIsValid);
++ QCOMPARE(tiere.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Tiere fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isNameValueSet(), isNameSet);
++ QCOMPARE(fromJson.isNameValueValid(), isNameValid);
++ QCOMPARE(fromJson.isDeepNestedMapValueSet(), isDeepNestedMapSet);
++ QCOMPARE(fromJson.isDeepNestedMapValueValid(), isDeepNestedMapValid);
++ QCOMPARE(fromJson.isSpeciesListValueSet(), isSpeciesListSet);
++ QCOMPARE(fromJson.isSpeciesListValueValid(), isSpeciesListValid);
++ QCOMPARE(fromJson.isMetadataValueSet(), isMetadataSet);
++ QCOMPARE(fromJson.isMetadataValueValid(), isMetadataValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, tiere);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Tiere fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isNameValueSet(), isNameSet);
++ QCOMPARE(fromObject.isNameValueValid(), isNameValid);
++ QCOMPARE(fromObject.isDeepNestedMapValueSet(), isDeepNestedMapSet);
++ QCOMPARE(fromObject.isDeepNestedMapValueValid(), isDeepNestedMapValid);
++ QCOMPARE(fromObject.isSpeciesListValueSet(), isSpeciesListSet);
++ QCOMPARE(fromObject.isSpeciesListValueValid(), isSpeciesListValid);
++ QCOMPARE(fromObject.isMetadataValueSet(), isMetadataSet);
++ QCOMPARE(fromObject.isMetadataValueValid(), isMetadataValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, tiere);
++ }
++
++ void StandardModelsTest::testPflanzeJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Pflanze>("pflanze");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isNameSet");
++ QTest::addColumn<bool>("isNameValid");
++ QTest::addColumn<bool>("isSchoolDataSet");
++ QTest::addColumn<bool>("isSchoolDataValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Pflanze requires 'schoolData'. An empty Pflanze is invalid.
++ QTest::newRow("Pflanze: empty (invalid - missing required field)")
++ << StandardSchemasModels::Pflanze{} << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Both fields set.
++ StandardSchemasModels::Pflanze full;
++ full.setName(u"Rose"_s);
++ full.setSchoolData({{{"biology"_L1, "botany"_L1}, {"science"_L1}}});
++ QTest::newRow("Pflanze: name=Rose; schoolData=[[[biology,botany],[science]]]")
++ << full
++ << QString("{\"name\":\"Rose\",\"schoolData\":[[[\"biology\",\"botany\"],[\"science\"]]]}"_L1)
++ // isNameSet isNameValid
++ << true << true
++ // isSchoolDataSet isSchoolDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only the required 'schoolData' field set; model is valid.
++ StandardSchemasModels::Pflanze schoolDataOnly;
++ schoolDataOnly.setSchoolData({{{"data"_L1}}});
++ QTest::newRow("Pflanze: schoolData=[[[data]]]; name not set")
++ << schoolDataOnly
++ << QString("{\"schoolData\":[[[\"data\"]]]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only the optional 'name' field set; required 'schoolData' absent => invalid.
++ StandardSchemasModels::Pflanze nameOnly;
++ nameOnly.setName(u"Tulip"_s);
++ QTest::newRow("Pflanze: name=Tulip; schoolData not set => invalid")
++ << nameOnly << QString("{\"name\":\"Tulip\"}"_L1)
++ // isNameSet isNameValid
++ << true << true
++ // isSchoolDataSet isSchoolDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << true;
++
++ // Empty outer list for required 'schoolData': set but empty.
++ StandardSchemasModels::Pflanze emptySchoolData;
++ emptySchoolData.setSchoolData({});
++ QTest::newRow("Pflanze: schoolData=[] (empty)")
++ << emptySchoolData
++ << QString("{\"schoolData\":[]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Parsed from JSON: valid triple-nested array.
++ StandardSchemasModels::Pflanze fromJsonPflanze(
++ "{\"name\":\"Lily\",\"schoolData\":[[[\"a\",\"b\"],[\"c\"]],[[\"d\"]]]}"_L1);
++ QTest::newRow("Pflanze: fromJson with valid structure")
++ << fromJsonPflanze
++ << QString("{\"name\":\"Lily\",\"schoolData\":[[[\"a\",\"b\"],[\"c\"]],[[\"d\"]]]}"_L1)
++ // isNameSet isNameValid
++ << true << true
++ // isSchoolDataSet isSchoolDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Wrong type for 'schoolData' (string instead of array): dropped, model invalid.
++ StandardSchemasModels::Pflanze wrongStringType("{\"schoolData\":\"notAnArray\"}"_L1);
++ QTest::newRow("Pflanze: schoolData=wrong (string) type; dropped (invalid)")
++ << wrongStringType << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong type for 'schoolData' (object instead of array): dropped, model invalid.
++ StandardSchemasModels::Pflanze wrongObjectType("{\"schoolData\":{}}"_L1);
++ QTest::newRow("Pflanze: schoolData=wrong (object) type; dropped (invalid)")
++ << wrongObjectType << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong type for 'schoolData' (integer instead of array): dropped, model invalid.
++ StandardSchemasModels::Pflanze wrongIntType("{\"schoolData\":42}"_L1);
++ QTest::newRow("Pflanze: schoolData=wrong (integer) type; dropped (invalid)")
++ << wrongIntType << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong inner type: schoolData should be [[[string]]], not [[int]].
++ // The entire array should be dropped because inner elements are wrong type.
++ StandardSchemasModels::Pflanze wrongInnerType("{\"schoolData\":[[[42]]]}"_L1);
++ QTest::newRow("Pflanze: schoolData=[[[42]]] inner wrong type; dropped (invalid)")
++ << wrongInnerType << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong middle nesting: schoolData should be [[[string]]], not [string].
++ StandardSchemasModels::Pflanze wrongNesting("{\"schoolData\":[\"flat\"]}"_L1);
++ QTest::newRow("Pflanze: schoolData=[\"flat\"] wrong nesting; dropped (invalid)")
++ << wrongNesting << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong type for 'name' (integer instead of string): dropped.
++ // 'schoolData' is valid, so the model is still valid.
++ StandardSchemasModels::Pflanze wrongNameType(
++ "{\"name\":42,\"schoolData\":[[[\"ok\"]]]}"_L1);
++ QTest::newRow("Pflanze: name=wrong (int) type; dropped; schoolData valid")
++ << wrongNameType
++ << QString("{\"schoolData\":[[[\"ok\"]]]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Unknown fields: known fields parsed, unknown ones ignored.
++ StandardSchemasModels::Pflanze unknownFields(
++ "{\"schoolData\":[[[\"x\"]]],\"unknownField\":\"ignored\"}"_L1);
++ QTest::newRow("Pflanze: unknown fields ignored")
++ << unknownFields
++ << QString("{\"schoolData\":[[[\"x\"]]]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Invalid JSON: all fields stay unset. 'schoolData' is required => invalid.
++ StandardSchemasModels::Pflanze fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("Pflanze: invalid JSON")
++ << fromInvalidJson << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isSchoolDataSet isSchoolDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++ }
++
++ void StandardModelsTest::testPflanzeJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Pflanze, pflanze);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isNameSet);
++ QFETCH(bool, isNameValid);
++ QFETCH(bool, isSchoolDataSet);
++ QFETCH(bool, isSchoolDataValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(pflanze.asJson(), expectedJson);
++ QCOMPARE(pflanze.asJsonValue(), testValue);
++ QCOMPARE(pflanze.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(pflanze.isNameValueSet(), isNameSet);
++ QCOMPARE(pflanze.isNameValueValid(), isNameValid);
++ QCOMPARE(pflanze.isSchoolDataValueSet(), isSchoolDataSet);
++ QCOMPARE(pflanze.isSchoolDataValueValid(), isSchoolDataValid);
++ QCOMPARE(pflanze.isValid(), modelIsValid);
++ QCOMPARE(pflanze.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Pflanze fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isNameValueSet(), isNameSet);
++ QCOMPARE(fromJson.isNameValueValid(), isNameValid);
++ QCOMPARE(fromJson.isSchoolDataValueSet(), isSchoolDataSet);
++ QCOMPARE(fromJson.isSchoolDataValueValid(), isSchoolDataValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, pflanze);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Pflanze fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isNameValueSet(), isNameSet);
++ QCOMPARE(fromObject.isNameValueValid(), isNameValid);
++ QCOMPARE(fromObject.isSchoolDataValueSet(), isSchoolDataSet);
++ QCOMPARE(fromObject.isSchoolDataValueValid(), isSchoolDataValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, pflanze);
++ }
++
++ void StandardModelsTest::testFaunaJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Fauna>("fauna");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isNameSet");
++ QTest::addColumn<bool>("isNameValid");
++ QTest::addColumn<bool>("isDeepMapWithListsSet");
++ QTest::addColumn<bool>("isDeepMapWithListsValid");
++ QTest::addColumn<bool>("isHabitatDataSet");
++ QTest::addColumn<bool>("isHabitatDataValid");
++ QTest::addColumn<bool>("isComplexNestingSet");
++ QTest::addColumn<bool>("isComplexNestingValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Fauna requires 'deepMapWithLists'. An empty Fauna is invalid.
++ QTest::newRow("Fauna: empty (invalid - missing required field)")
++ << StandardSchemasModels::Fauna{} << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << false << false
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Only the required 'deepMapWithLists' set with empty map; model is valid.
++ StandardSchemasModels::Fauna emptyRequired;
++ emptyRequired.setDeepMapWithLists({});
++ QTest::newRow("Fauna: deepMapWithLists={} (empty required)")
++ << emptyRequired
++ << QString("{\"deepMapWithLists\":{}}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << true << true
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Full model with all fields set.
++ StandardSchemasModels::Duck duck1;
++ duck1.setBites(true);
++ StandardSchemasModels::Duck duck2;
++ duck2.setBites(false);
++ StandardSchemasModels::Duck_family fam;
++ fam.setCountryOfOrigin(u"Norway"_s);
++ fam.setCount(3.0f);
++ StandardSchemasModels::Duck duck3;
++ duck3.setBites(true);
++ duck3.setFamily(fam);
++
++ StandardSchemasModels::Cat cat1;
++ cat1.setHunts(true);
++ cat1.setAge(5);
++
++ StandardSchemasModels::Fauna full;
++ full.setName(u"European Wildlife"_s);
++ full.setDeepMapWithLists(
++ {{u"region1"_s, {{u"lake"_s, {duck1, duck2}}}}});
++ full.setHabitatData(
++ {{u"continent"_s, {{u"country"_s, {{u"city"_s, {u"forest"_s, u"river"_s}}}}}}});
++ full.setComplexNesting(
++ {{u"group1"_s, {{{u"cats"_s, {cat1}}}}}});
++ QTest::newRow("Fauna: full model with all fields")
++ << full
++ << QString("{\"complexNesting\":{\"group1\":[{\"cats\":[{\"age\":5,\"hunts\":true}]}]},\"deepMapWithLists\":{\"region1\":{\"lake\":[{\"bites\":true},{\"bites\":false}]}},\"habitatData\":{\"continent\":{\"country\":{\"city\":[\"forest\",\"river\"]}}},\"name\":\"European Wildlife\"}"_L1)
++ // isNameSet isNameValid
++ << true << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << true << true
++ // isHabitatDataSet isHabitatDataValid
++ << true << true
++ // isComplexNestingSet isComplexNestingValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // deepMapWithLists with a Duck that has a family.
++ StandardSchemasModels::Fauna withFamily;
++ withFamily.setDeepMapWithLists(
++ {{u"area"_s, {{u"pond"_s, {duck3}}}}});
++ QTest::newRow("Fauna: deepMapWithLists with Duck having family")
++ << withFamily
++ << QString("{\"deepMapWithLists\":{\"area\":{\"pond\":[{\"bites\":true,\"family\":{\"count\":3,\"countryOfOrigin\":\"Norway\"}}]}}}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << true << true
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Parsed from JSON: valid structure.
++ StandardSchemasModels::Fauna fromJsonFauna(
++ "{\"deepMapWithLists\":{\"r1\":{\"s1\":[{\"bites\":true}]}}}"_L1);
++ QTest::newRow("Fauna: fromJson with valid structure")
++ << fromJsonFauna
++ << QString("{\"deepMapWithLists\":{\"r1\":{\"s1\":[{\"bites\":true}]}}}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << true << true
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Wrong type for 'deepMapWithLists' (string): dropped, model invalid.
++ StandardSchemasModels::Fauna wrongStringType("{\"deepMapWithLists\":\"notAnObject\"}"_L1);
++ QTest::newRow("Fauna: deepMapWithLists=wrong (string) type; dropped (invalid)")
++ << wrongStringType << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << false << false
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong type for 'deepMapWithLists' (array): dropped, model invalid.
++ StandardSchemasModels::Fauna wrongArrayType("{\"deepMapWithLists\":[1,2,3]}"_L1);
++ QTest::newRow("Fauna: deepMapWithLists=wrong (array) type; dropped (invalid)")
++ << wrongArrayType << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << false << false
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong inner value in deepMapWithLists: inner value should be object (map of lists),
++ // not a plain string. The whole deepMapWithLists is dropped.
++ StandardSchemasModels::Fauna wrongInnerValue(
++ "{\"deepMapWithLists\":{\"r1\":\"notAnObject\"}}"_L1);
++ QTest::newRow("Fauna: deepMapWithLists inner wrong type; dropped (invalid)")
++ << wrongInnerValue << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << false << false
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong deepest inner value: the innermost list should contain Duck objects (objects),
++ // not strings. The entire deepMapWithLists should be dropped.
++ StandardSchemasModels::Fauna wrongDeepestInner(
++ "{\"deepMapWithLists\":{\"r1\":{\"s1\":[\"notADuck\"]}}}"_L1);
++ QTest::newRow("Fauna: deepMapWithLists deepest inner wrong type; dropped (invalid)")
++ << wrongDeepestInner << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << false << false
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Only optional 'name' set; required 'deepMapWithLists' absent => invalid.
++ StandardSchemasModels::Fauna nameOnly;
++ nameOnly.setName(u"Arctic"_s);
++ QTest::newRow("Fauna: name=Arctic; deepMapWithLists not set => invalid")
++ << nameOnly << QString("{\"name\":\"Arctic\"}"_L1)
++ // isNameSet isNameValid
++ << true << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << false << false
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << true;
++
++ // Unknown fields: known fields parsed, unknown ones ignored.
++ StandardSchemasModels::Fauna unknownFields(
++ "{\"deepMapWithLists\":{},\"unknownField\":\"ignored\"}"_L1);
++ QTest::newRow("Fauna: unknown fields ignored")
++ << unknownFields
++ << QString("{\"deepMapWithLists\":{}}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << true << true
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Invalid JSON: all fields stay unset. 'deepMapWithLists' required => invalid.
++ StandardSchemasModels::Fauna fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("Fauna: invalid JSON")
++ << fromInvalidJson << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isDeepMapWithListsSet isDeepMapWithListsValid
++ << false << false
++ // isHabitatDataSet isHabitatDataValid
++ << false << true
++ // isComplexNestingSet isComplexNestingValid
++ << false << true
++ // modelIsValid modelIsSet
++ << false << false;
++ }
++
++ void StandardModelsTest::testFaunaJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Fauna, fauna);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isNameSet);
++ QFETCH(bool, isNameValid);
++ QFETCH(bool, isDeepMapWithListsSet);
++ QFETCH(bool, isDeepMapWithListsValid);
++ QFETCH(bool, isHabitatDataSet);
++ QFETCH(bool, isHabitatDataValid);
++ QFETCH(bool, isComplexNestingSet);
++ QFETCH(bool, isComplexNestingValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(fauna.asJson(), expectedJson);
++ QCOMPARE(fauna.asJsonValue(), testValue);
++ QCOMPARE(fauna.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fauna.isNameValueSet(), isNameSet);
++ QCOMPARE(fauna.isNameValueValid(), isNameValid);
++ QCOMPARE(fauna.isDeepMapWithListsValueSet(), isDeepMapWithListsSet);
++ QCOMPARE(fauna.isDeepMapWithListsValueValid(), isDeepMapWithListsValid);
++ QCOMPARE(fauna.isHabitatDataValueSet(), isHabitatDataSet);
++ QCOMPARE(fauna.isHabitatDataValueValid(), isHabitatDataValid);
++ QCOMPARE(fauna.isComplexNestingValueSet(), isComplexNestingSet);
++ QCOMPARE(fauna.isComplexNestingValueValid(), isComplexNestingValid);
++ QCOMPARE(fauna.isValid(), modelIsValid);
++ QCOMPARE(fauna.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Fauna fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isNameValueSet(), isNameSet);
++ QCOMPARE(fromJson.isNameValueValid(), isNameValid);
++ QCOMPARE(fromJson.isDeepMapWithListsValueSet(), isDeepMapWithListsSet);
++ QCOMPARE(fromJson.isDeepMapWithListsValueValid(), isDeepMapWithListsValid);
++ QCOMPARE(fromJson.isHabitatDataValueSet(), isHabitatDataSet);
++ QCOMPARE(fromJson.isHabitatDataValueValid(), isHabitatDataValid);
++ QCOMPARE(fromJson.isComplexNestingValueSet(), isComplexNestingSet);
++ QCOMPARE(fromJson.isComplexNestingValueValid(), isComplexNestingValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, fauna);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Fauna fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isNameValueSet(), isNameSet);
++ QCOMPARE(fromObject.isNameValueValid(), isNameValid);
++ QCOMPARE(fromObject.isDeepMapWithListsValueSet(), isDeepMapWithListsSet);
++ QCOMPARE(fromObject.isDeepMapWithListsValueValid(), isDeepMapWithListsValid);
++ QCOMPARE(fromObject.isHabitatDataValueSet(), isHabitatDataSet);
++ QCOMPARE(fromObject.isHabitatDataValueValid(), isHabitatDataValid);
++ QCOMPARE(fromObject.isComplexNestingValueSet(), isComplexNestingSet);
++ QCOMPARE(fromObject.isComplexNestingValueValid(), isComplexNestingValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, fauna);
++ }
++
++ void StandardModelsTest::testFloraJsonConversionMethods_data()
++ {
++ QTest::addColumn<StandardSchemasModels::Flora>("flora");
++ QTest::addColumn<QString>("expectedJson");
++ QTest::addColumn<bool>("isNameSet");
++ QTest::addColumn<bool>("isNameValid");
++ QTest::addColumn<bool>("isPlantDataSet");
++ QTest::addColumn<bool>("isPlantDataValid");
++ QTest::addColumn<bool>("modelIsValid");
++ QTest::addColumn<bool>("modelIsSet");
++
++ // Flora requires 'plantData'. An empty Flora is invalid.
++ QTest::newRow("Flora: empty (invalid - missing required field)")
++ << StandardSchemasModels::Flora{} << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isPlantDataSet isPlantDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Only the required 'plantData' set with empty list; model is valid.
++ StandardSchemasModels::Flora emptyRequired;
++ emptyRequired.setPlantData({});
++ QTest::newRow("Flora: plantData=[] (empty required)")
++ << emptyRequired
++ << QString("{\"plantData\":[]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isPlantDataSet isPlantDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Full model: plantData is QList<QMap<QString, QList<QMap<QString, Pflanze>>>>
++ // Construct a Pflanze for use inside plantData.
++ StandardSchemasModels::Pflanze innerPflanze;
++ innerPflanze.setName(u"Daisy"_s);
++ innerPflanze.setSchoolData({{{"botany"_L1}}});
++
++ StandardSchemasModels::Flora full;
++ full.setName(u"Garden Plants"_s);
++ full.setPlantData({{{u"flowers"_s, {{{u"daisy"_s, innerPflanze}}}}}});
++ QTest::newRow("Flora: full model with Pflanze inside plantData")
++ << full
++ << QString("{\"name\":\"Garden Plants\",\"plantData\":[{\"flowers\":[{\"daisy\":{\"name\":\"Daisy\",\"schoolData\":[[[\"botany\"]]]}}]}]}"_L1)
++ // isNameSet isNameValid
++ << true << true
++ // isPlantDataSet isPlantDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Only optional 'name' set; required 'plantData' absent => invalid.
++ StandardSchemasModels::Flora nameOnly;
++ nameOnly.setName(u"Tropical"_s);
++ QTest::newRow("Flora: name=Tropical; plantData not set => invalid")
++ << nameOnly << QString("{\"name\":\"Tropical\"}"_L1)
++ // isNameSet isNameValid
++ << true << true
++ // isPlantDataSet isPlantDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << true;
++
++ // Wrong type for 'plantData' (string instead of array): dropped, model invalid.
++ StandardSchemasModels::Flora wrongStringType("{\"plantData\":\"notAnArray\"}"_L1);
++ QTest::newRow("Flora: plantData=wrong (string) type; dropped (invalid)")
++ << wrongStringType << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isPlantDataSet isPlantDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong type for 'plantData' (object instead of array): dropped, model invalid.
++ StandardSchemasModels::Flora wrongObjectType("{\"plantData\":{}}"_L1);
++ QTest::newRow("Flora: plantData=wrong (object) type; dropped (invalid)")
++ << wrongObjectType << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isPlantDataSet isPlantDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong type for 'plantData' (integer instead of array): dropped, model invalid.
++ StandardSchemasModels::Flora wrongIntType("{\"plantData\":42}"_L1);
++ QTest::newRow("Flora: plantData=wrong (integer) type; dropped (invalid)")
++ << wrongIntType << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isPlantDataSet isPlantDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong inner type in plantData: plantData is QList<QMap<...>>,
++ // so an element that is a string instead of object should cause the array to be dropped.
++ StandardSchemasModels::Flora wrongInnerType("{\"plantData\":[\"notAnObject\"]}"_L1);
++ QTest::newRow("Flora: plantData=[string] wrong inner type; dropped (invalid)")
++ << wrongInnerType << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isPlantDataSet isPlantDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++
++ // Wrong type for 'name' (integer instead of string): name dropped.
++ // 'plantData' is valid, so the model is still valid.
++ StandardSchemasModels::Flora wrongNameType("{\"name\":42,\"plantData\":[]}"_L1);
++ QTest::newRow("Flora: name=wrong (int) type; dropped; plantData valid")
++ << wrongNameType
++ << QString("{\"plantData\":[]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isPlantDataSet isPlantDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Unknown fields: known fields parsed, unknown ones ignored.
++ StandardSchemasModels::Flora unknownFields(
++ "{\"plantData\":[],\"unknownField\":\"ignored\"}"_L1);
++ QTest::newRow("Flora: unknown fields ignored")
++ << unknownFields
++ << QString("{\"plantData\":[]}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isPlantDataSet isPlantDataValid
++ << true << true
++ // modelIsValid modelIsSet
++ << true << true;
++
++ // Invalid JSON: all fields stay unset. 'plantData' required => invalid.
++ StandardSchemasModels::Flora fromInvalidJson("{invalid json}"_L1);
++ QTest::newRow("Flora: invalid JSON")
++ << fromInvalidJson << QString("{}"_L1)
++ // isNameSet isNameValid
++ << false << true
++ // isPlantDataSet isPlantDataValid
++ << false << false
++ // modelIsValid modelIsSet
++ << false << false;
++ }
++
++ void StandardModelsTest::testFloraJsonConversionMethods()
++ {
++ QFETCH(StandardSchemasModels::Flora, flora);
++ QFETCH(QString, expectedJson);
++ QFETCH(bool, isNameSet);
++ QFETCH(bool, isNameValid);
++ QFETCH(bool, isPlantDataSet);
++ QFETCH(bool, isPlantDataValid);
++ QFETCH(bool, modelIsValid);
++ QFETCH(bool, modelIsSet);
++
++ const QJsonValue testValue = QJsonValue::fromJson(QByteArrayView(expectedJson.toUtf8()));
++ QCOMPARE(flora.asJson(), expectedJson);
++ QCOMPARE(flora.asJsonValue(), testValue);
++ QCOMPARE(flora.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(flora.isNameValueSet(), isNameSet);
++ QCOMPARE(flora.isNameValueValid(), isNameValid);
++ QCOMPARE(flora.isPlantDataValueSet(), isPlantDataSet);
++ QCOMPARE(flora.isPlantDataValueValid(), isPlantDataValid);
++ QCOMPARE(flora.isValid(), modelIsValid);
++ QCOMPARE(flora.isSet(), modelIsSet);
++
++ // Model::fromJson()
++ StandardSchemasModels::Flora fromJson;
++ fromJson.fromJson(expectedJson);
++ QCOMPARE(fromJson.asJson(), expectedJson);
++ QCOMPARE(fromJson.asJsonValue(), testValue);
++ QCOMPARE(fromJson.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromJson.isNameValueSet(), isNameSet);
++ QCOMPARE(fromJson.isNameValueValid(), isNameValid);
++ QCOMPARE(fromJson.isPlantDataValueSet(), isPlantDataSet);
++ QCOMPARE(fromJson.isPlantDataValueValid(), isPlantDataValid);
++ QCOMPARE(fromJson.isSet(), modelIsSet);
++ QCOMPARE(fromJson.isValid(), modelIsValid);
++ QCOMPARE(fromJson, flora);
++
++ // Model::fromJsonValue()
++ StandardSchemasModels::Flora fromObject;
++ fromObject.fromJsonValue(testValue);
++ QCOMPARE(fromObject.asJson(), expectedJson);
++ QCOMPARE(fromObject.asJsonValue(), testValue);
++ QCOMPARE(fromObject.asJsonValue().toObject(), testValue.toObject());
++ QCOMPARE(fromObject.isNameValueSet(), isNameSet);
++ QCOMPARE(fromObject.isNameValueValid(), isNameValid);
++ QCOMPARE(fromObject.isPlantDataValueSet(), isPlantDataSet);
++ QCOMPARE(fromObject.isPlantDataValueValid(), isPlantDataValid);
++ QCOMPARE(fromObject.isSet(), modelIsSet);
++ QCOMPARE(fromObject.isValid(), modelIsValid);
++ QCOMPARE(fromObject, flora);
++ }
++
++ QTEST_MAIN(StandardModelsTest)
++ #include "tst_standardmodels.moc"