summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@qt.io>2023-03-17 17:37:28 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-03-21 17:40:07 +0000
commitaf6151f2f34fb44ef4631d9c4de874b7dd13d7c6 (patch)
treec4bd6a40db6d91030a1603ee6e8bb161a89651ec
parentab249a81bbf4b32882ee5c2289191f1f0d106f13 (diff)
downloadqtapplicationmanager-6.4.tar.gz
yaml: missing values are actually null/~, not empty strings6.4
Change-Id: I6ca98e219bf4c3de9a1eaaae5ddeb7e7cfa27107 Reviewed-by: Dominik Holland <dominik.holland@qt.io> (cherry picked from commit 0ae6d0a3637075fe8005361177eae3142eee0a77) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/common-lib/qtyaml.cpp144
-rw-r--r--tests/auto/yaml/data/test.yaml1
-rw-r--r--tests/auto/yaml/tst_yaml.cpp2
3 files changed, 77 insertions, 70 deletions
diff --git a/src/common-lib/qtyaml.cpp b/src/common-lib/qtyaml.cpp
index e0ff3d1b..2d64a3c9 100644
--- a/src/common-lib/qtyaml.cpp
+++ b/src/common-lib/qtyaml.cpp
@@ -290,9 +290,8 @@ QVariant YamlParser::parseScalar() const
{
QString scalar = parseString();
- if (scalar.isEmpty()
- || d->event.data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE
- || d->event.data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE) {
+ if (d->event.data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE
+ || d->event.data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE) {
return scalar;
}
@@ -537,79 +536,84 @@ QStringList YamlParser::parseStringOrStringList()
}
}
-void YamlParser::parseFields(const std::vector<Field> &fields)
+static QString mapEventNames(const QVector<yaml_event_type_t> &events)
{
- if (!isMap())
- throw YamlParserException(this, "Expected a map (type %1) to parse fields from, but got type %2")
- .arg(YAML_MAPPING_START_EVENT).arg(d->event.type);
+ static const QHash<yaml_event_type_t, const char *> eventNames = {
+ { YAML_NO_EVENT, "nothing" },
+ { YAML_STREAM_START_EVENT, "stream start" },
+ { YAML_STREAM_END_EVENT, "stream end" },
+ { YAML_DOCUMENT_START_EVENT, "document start" },
+ { YAML_DOCUMENT_END_EVENT, "document end" },
+ { YAML_ALIAS_EVENT, "alias" },
+ { YAML_SCALAR_EVENT, "scalar" },
+ { YAML_SEQUENCE_START_EVENT, "sequence start" },
+ { YAML_SEQUENCE_END_EVENT, "sequence end" },
+ { YAML_MAPPING_START_EVENT, "mapping start" },
+ { YAML_MAPPING_END_EVENT, "mapping end" }
+ };
+ QString names;
+ for (int i = 0; i < events.size(); ++i) {
+ if (i)
+ names.append(i == (events.size() - 1) ? qL1S(" or ") : qL1S(", "));
+ names.append(qL1S(eventNames.value(events.at(i), "<unknown>")));
+ }
+ return names;
+};
+void YamlParser::parseFields(const std::vector<Field> &fields)
+{
QVector<QString> fieldsFound;
- while (true) {
- nextEvent(); // read key
- if (d->event.type == YAML_MAPPING_END_EVENT)
- break;
- QString key = parseMapKey();
- if (fieldsFound.contains(key))
- throw YamlParserException(this, "Found duplicate key '%1' in mapping").arg(key);
-
- auto field = fields.cbegin();
- for (; field != fields.cend(); ++field) {
- if (key == qL1S(field->name))
- break;
- }
- if (field == fields.cend())
- throw YamlParserException(this, "Field '%1' is not valid in this context").arg(key);
- fieldsFound << key;
-
- nextEvent(); // read value
- QVector<yaml_event_type_t> allowedEvents;
- if (field->types & YamlParser::Scalar)
- allowedEvents.append(YAML_SCALAR_EVENT);
- if (field->types & YamlParser::Map)
- allowedEvents.append(YAML_MAPPING_START_EVENT);
- if (field->types & YamlParser::List)
- allowedEvents.append(YAML_SEQUENCE_START_EVENT);
-
- if (!allowedEvents.contains(d->event.type)) { // ALIASES MISSING HERE!
- auto mapEventNames = [](const QVector<yaml_event_type_t> &events) -> QString {
- static const QHash<yaml_event_type_t, const char *> eventNames = {
- { YAML_NO_EVENT, "nothing" },
- { YAML_STREAM_START_EVENT, "stream start" },
- { YAML_STREAM_END_EVENT, "stream end" },
- { YAML_DOCUMENT_START_EVENT, "document start" },
- { YAML_DOCUMENT_END_EVENT, "document end" },
- { YAML_ALIAS_EVENT, "alias" },
- { YAML_SCALAR_EVENT, "scalar" },
- { YAML_SEQUENCE_START_EVENT, "sequence start" },
- { YAML_SEQUENCE_END_EVENT, "sequence end" },
- { YAML_MAPPING_START_EVENT, "mapping start" },
- { YAML_MAPPING_END_EVENT, "mapping end" }
- };
- QString names;
- for (int i = 0; i < events.size(); ++i) {
- if (i)
- names.append(i == (events.size() - 1) ? qL1S(" or ") : qL1S(", "));
- names.append(qL1S(eventNames.value(events.at(i), "<unknown>")));
- }
- return names;
- };
-
- throw YamlParserException(this, "Field '%1' expected to be of type '%2', but got '%3'")
- .arg(field->name).arg(mapEventNames(allowedEvents)).arg(mapEventNames({ d->event.type }));
+ if (!isMap()) {
+ // an empty document is ok - we just have to check for required fields below
+ if (!isScalar() || (parseScalar() != QVariant::fromValue(nullptr))) {
+ throw YamlParserException(this, "Expected a map (type '%1') to parse fields from, but got type '%2'")
+ .arg(mapEventNames({ YAML_MAPPING_START_EVENT })).arg(mapEventNames({ d->event.type }));
}
+ } else {
+ while (true) {
+ nextEvent(); // read key
+ if (d->event.type == YAML_MAPPING_END_EVENT)
+ break;
+ QString key = parseMapKey();
+ if (fieldsFound.contains(key))
+ throw YamlParserException(this, "Found duplicate key '%1' in mapping").arg(key);
+
+ auto field = fields.cbegin();
+ for (; field != fields.cend(); ++field) {
+ if (key == qL1S(field->name))
+ break;
+ }
+ if (field == fields.cend())
+ throw YamlParserException(this, "Field '%1' is not valid in this context").arg(key);
+ fieldsFound << key;
+
+ nextEvent(); // read value
+ QVector<yaml_event_type_t> allowedEvents;
+ if (field->types & YamlParser::Scalar)
+ allowedEvents.append(YAML_SCALAR_EVENT);
+ if (field->types & YamlParser::Map)
+ allowedEvents.append(YAML_MAPPING_START_EVENT);
+ if (field->types & YamlParser::List)
+ allowedEvents.append(YAML_SEQUENCE_START_EVENT);
+
+ if (!allowedEvents.contains(d->event.type)) { // ALIASES MISSING HERE!
+ throw YamlParserException(this, "Field '%1' expected to be of type '%2', but got '%3'")
+ .arg(field->name).arg(mapEventNames(allowedEvents)).arg(mapEventNames({ d->event.type }));
+ }
- yaml_event_type_t typeBefore = d->event.type;
- yaml_event_type_t typeAfter;
- switch (typeBefore) {
- case YAML_MAPPING_START_EVENT: typeAfter = YAML_MAPPING_END_EVENT; break;
- case YAML_SEQUENCE_START_EVENT: typeAfter = YAML_SEQUENCE_END_EVENT; break;
- default: typeAfter = typeBefore; break;
- }
- field->callback(this);
- if (d->event.type != typeAfter) {
- throw YamlParserException(this, "Invalid YAML event state after field callback for '%3': expected %1, but got %2")
- .arg(typeAfter).arg(d->event.type).arg(key);
+ yaml_event_type_t typeBefore = d->event.type;
+ yaml_event_type_t typeAfter;
+ switch (typeBefore) {
+ case YAML_MAPPING_START_EVENT: typeAfter = YAML_MAPPING_END_EVENT; break;
+ case YAML_SEQUENCE_START_EVENT: typeAfter = YAML_SEQUENCE_END_EVENT; break;
+ default: typeAfter = typeBefore; break;
+ }
+ field->callback(this);
+ if (d->event.type != typeAfter) {
+ throw YamlParserException(this, "Invalid YAML event state after field callback for '%3': expected %1, but got %2")
+ .arg(typeAfter).arg(d->event.type).arg(key);
+ }
}
}
QStringList fieldsMissing;
diff --git a/tests/auto/yaml/data/test.yaml b/tests/auto/yaml/data/test.yaml
index b16e3d39..7b2e5e84 100644
--- a/tests/auto/yaml/data/test.yaml
+++ b/tests/auto/yaml/data/test.yaml
@@ -15,6 +15,7 @@ bool-false: false
bool-no: no
null-literal: null
null-tilde: ~
+null-empty:
string-unquoted: unquoted
string-singlequoted: 'singlequoted'
string-doublequoted: "doublequoted"
diff --git a/tests/auto/yaml/tst_yaml.cpp b/tests/auto/yaml/tst_yaml.cpp
index 344f0d15..c9f3394c 100644
--- a/tests/auto/yaml/tst_yaml.cpp
+++ b/tests/auto/yaml/tst_yaml.cpp
@@ -52,6 +52,7 @@ void tst_Yaml::parser()
{ "bool-no", false },
{ "null-literal", vnull },
{ "null-tilde", vnull },
+ { "null-empty", vnull },
{ "string-unquoted", QVariant::fromValue<QString>(qSL("unquoted")) },
{ "string-singlequoted", QVariant::fromValue<QString>(qSL("singlequoted")) },
{ "string-doublequoted", QVariant::fromValue<QString>(qSL("doublequoted")) },
@@ -176,6 +177,7 @@ static const QVariantMap testMainDoc = {
{ qSL("bool-no"), false },
{ qSL("null-literal"), vnull },
{ qSL("null-tilde"), vnull },
+ { qSL("null-empty"), vnull },
{ qSL("string-unquoted"), qSL("unquoted") },
{ qSL("string-singlequoted"), qSL("singlequoted") },
{ qSL("string-doublequoted"), qSL("doublequoted") },