Fix conversion of QVariant() in QJsonArrays and Objects (through CBOR)

When I wrote the QCborValue to QJsonValue conversion, I used
QJsonValue::Undefined because it allowed to keep some level of
compatibility in CBOR, despite the function documentation saying that
CBOR undefineds became JSON nulls. Which they did.

But when we converted QJson{Array,Object} to be backed by CBOR classes,
that Undefined meant the insertion into the array/object actually
deleted the entry.

[ChangeLog][JSON] Fixed a regression from 5.14 that caused values of
default-constructed QVariants in QVariantLists, QVariantMaps and
QVariantHashes to disappear when converting to JSON via
fromVariant{,List,Map,Hash}.

Fixes: QTBUG-84610
Pick-to: 5.15
Change-Id: Ic0987177fe463f352db9bd84993f116e2bdacc75
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Thiago Macieira 2020-06-11 11:33:24 -07:00 committed by Ulf Hermann
parent bdc2493096
commit cb1c66bd20
3 changed files with 49 additions and 10 deletions

View File

@ -280,11 +280,9 @@ QJsonValue qt_convertToJson(QCborContainerPrivate *d, qsizetype idx)
return qt_convertToJson(e.flags & Element::IsContainer ? e.container : nullptr, -e.type);
case QCborValue::Null:
return QJsonValue();
case QCborValue::Undefined:
case QCborValue::Invalid:
return QJsonValue::Undefined;
return QJsonValue();
case QCborValue::False:
return false;
@ -375,6 +373,8 @@ QJsonValue QCborValue::toJsonValue() const
return true;
case Null:
case Undefined:
case Invalid:
return QJsonValue();
case Double:
@ -383,10 +383,6 @@ QJsonValue QCborValue::toJsonValue() const
case SimpleType:
break;
case Undefined:
case Invalid:
return QJsonValue::Undefined;
case ByteArray:
case String:
// empty strings

View File

@ -1346,6 +1346,7 @@ void tst_QtJson::fromVariant_data()
variantList.append(stringValue);
variantList.append(stringList);
variantList.append(QVariant::fromValue(nullptr));
variantList.append(QVariant());
QJsonArray jsonArray_variant;
jsonArray_variant.append(boolValue);
jsonArray_variant.append(floatValue);
@ -1353,23 +1354,31 @@ void tst_QtJson::fromVariant_data()
jsonArray_variant.append(stringValue);
jsonArray_variant.append(jsonArray_string);
jsonArray_variant.append(QJsonValue(QJsonValue::Null));
jsonArray_variant.append(QJsonValue());
QVariantMap variantMap;
variantMap["bool"] = boolValue;
variantMap["float"] = floatValue;
variantMap["string"] = stringValue;
variantMap["array"] = variantList;
variantMap["null"] = QVariant::fromValue(nullptr);
variantMap["default"] = QVariant();
QVariantHash variantHash;
variantHash["bool"] = boolValue;
variantHash["float"] = floatValue;
variantHash["string"] = stringValue;
variantHash["array"] = variantList;
variantHash["null"] = QVariant::fromValue(nullptr);
variantHash["default"] = QVariant();
QJsonObject jsonObject;
jsonObject["bool"] = boolValue;
jsonObject["float"] = floatValue;
jsonObject["string"] = stringValue;
jsonObject["array"] = jsonArray_variant;
jsonObject["null"] = QJsonValue::Null;
jsonObject["default"] = QJsonValue();
QTest::newRow("default") << QVariant() << QJsonValue(QJsonValue::Null);
QTest::newRow("nullptr") << QVariant::fromValue(nullptr) << QJsonValue(QJsonValue::Null);
QTest::newRow("bool") << QVariant(boolValue) << QJsonValue(boolValue);
QTest::newRow("int") << QVariant(intValue) << QJsonValue(intValue);
@ -1385,13 +1394,47 @@ void tst_QtJson::fromVariant_data()
QTest::newRow("variantHash") << QVariant(variantHash) << QJsonValue(jsonObject);
}
// replaces QVariant() with QVariant(nullptr)
static QVariant normalizedVariant(const QVariant &v)
{
switch (v.userType()) {
case QMetaType::UnknownType:
return QVariant::fromValue(nullptr);
case QMetaType::QVariantList: {
const QVariantList in = v.toList();
QVariantList out;
out.reserve(in.size());
for (const QVariant &v : in)
out << normalizedVariant(v);
return out;
}
case QMetaType::QVariantMap: {
const QVariantMap in = v.toMap();
QVariantMap out;
for (auto it = in.begin(); it != in.end(); ++it)
out.insert(it.key(), normalizedVariant(it.value()));
return out;
}
case QMetaType::QVariantHash: {
const QVariantHash in = v.toHash();
QVariantHash out;
for (auto it = in.begin(); it != in.end(); ++it)
out.insert(it.key(), normalizedVariant(it.value()));
return out;
}
default:
return v;
}
}
void tst_QtJson::fromVariant()
{
QFETCH( QVariant, variant );
QFETCH( QJsonValue, jsonvalue );
QCOMPARE(QJsonValue::fromVariant(variant), jsonvalue);
QCOMPARE(variant.toJsonValue(), jsonvalue);
QCOMPARE(normalizedVariant(variant).toJsonValue(), jsonvalue);
}
void tst_QtJson::fromVariantSpecial_data()
@ -1424,7 +1467,7 @@ void tst_QtJson::toVariant()
QFETCH( QVariant, variant );
QFETCH( QJsonValue, jsonvalue );
QCOMPARE(jsonvalue.toVariant(), variant);
QCOMPARE(jsonvalue.toVariant(), normalizedVariant(variant));
}
void tst_QtJson::fromVariantMap()

View File

@ -89,7 +89,7 @@ void tst_QCborValue_Json::toVariant_data()
};
// good JSON matching:
add(QCborValue(), QVariant(), QJsonValue::Undefined);
add(QCborValue(), QVariant(), QJsonValue::Null);
add(nullptr, QVariant::fromValue(nullptr), QJsonValue::Null);
add(false, false, false);
add(true, true, true);