[{"id":38641,"web_url":"https://patchwork.libcamera.org/comment/38641/","msgid":"<05317d55-2b42-42e5-a207-9e9068934082@ideasonboard.com>","date":"2026-04-24T07:54:14","subject":"Re: [PATCH v3 22/37] test: yaml-parser: Simplify test","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2026. 04. 24. 1:00 keltezéssel, Laurent Pinchart írta:\n> Most of the tests in the YamlParser unit test cover the ValueNode class.\n> They are now implemented in the ValueNode unit test. Drop them, and only\n> keep the tests that related to YAML parsing.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n\nReviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n\n\n>   test/yaml-parser.cpp | 469 +++++--------------------------------------\n>   1 file changed, 50 insertions(+), 419 deletions(-)\n> \n> diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> index 8c5826f4885b..0bbda3af8ea9 100644\n> --- a/test/yaml-parser.cpp\n> +++ b/test/yaml-parser.cpp\n> @@ -12,7 +12,6 @@\n>   #include <unistd.h>\n> \n>   #include <libcamera/base/file.h>\n> -#include <libcamera/base/utils.h>\n> \n>   #include <libcamera/geometry.h>\n> \n> @@ -24,24 +23,12 @@ using namespace libcamera;\n>   using namespace std;\n> \n>   static const string testYaml =\n> -\t\"string: libcamera\\n\"\n> -\t\"double: 3.14159\\n\"\n> -\t\"int8_t: -100\\n\"\n> -\t\"uint8_t: 100\\n\"\n> -\t\"int16_t: -1000\\n\"\n> -\t\"uint16_t: 1000\\n\"\n> -\t\"int32_t: -100000\\n\"\n> -\t\"uint32_t: 100000\\n\"\n> -\t\"size: [1920, 1080]\\n\"\n> +\t\"empty:\\n\"\n> +\t\"value: 42\\n\"\n>   \t\"list:\\n\"\n> -\t\"  - James\\n\"\n> -\t\"  - Mary\\n\"\n> +\t\"  - libcamera\\n\"\n> +\t\"  - linux\\n\"\n>   \t\"  - \\n\"\n> -\t\"dictionary:\\n\"\n> -\t\"  a: 1\\n\"\n> -\t\"  c: 3\\n\"\n> -\t\"  b: 2\\n\"\n> -\t\"  empty:\\n\"\n>   \t\"level1:\\n\"\n>   \t\"  level2:\\n\"\n>   \t\"    - [1, 2]\\n\"\n> @@ -80,212 +67,9 @@ protected:\n>   \t\treturn TestPass;\n>   \t}\n> \n> -\tenum class Type {\n> -\t\tString,\n> -\t\tInt8,\n> -\t\tUInt8,\n> -\t\tInt16,\n> -\t\tUInt16,\n> -\t\tInt32,\n> -\t\tUInt32,\n> -\t\tDouble,\n> -\t\tSize,\n> -\t\tList,\n> -\t\tDictionary,\n> -\t};\n> -\n> -\tint testObjectType(const ValueNode &obj, const char *name, Type type)\n> -\t{\n> -\t\tbool isList = type == Type::List || type == Type::Size;\n> -\t\tbool isScalar = !isList && type != Type::Dictionary;\n> -\t\tbool isInteger8 = type == Type::Int8 || type == Type::UInt8;\n> -\t\tbool isInteger16 = type == Type::Int16 || type == Type::UInt16;\n> -\t\tbool isInteger32 = type == Type::Int32 || type == Type::UInt32;\n> -\t\tbool isIntegerUpTo16 = isInteger8 || isInteger16;\n> -\t\tbool isIntegerUpTo32 = isIntegerUpTo16 || isInteger32;\n> -\t\tbool isSigned = type == Type::Int8 || type == Type::Int16 ||\n> -\t\t\t        type == Type::Int32;\n> -\n> -\t\tif ((isScalar && !obj.isValue()) || (!isScalar && obj.isValue())) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" type mismatch when compared to \"\n> -\t\t\t\t<< \"value\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif ((isList && !obj.isList()) || (!isList && obj.isList())) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" type mismatch when compared to \"\n> -\t\t\t\t<< \"list\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif ((type == Type::Dictionary && !obj.isDictionary()) ||\n> -\t\t    (type != Type::Dictionary && obj.isDictionary())) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" type mismatch when compared to \"\n> -\t\t\t\t<< \"dictionary\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!isScalar && obj.get<std::string>()) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" didn't fail to parse as \"\n> -\t\t\t\t<< \"string\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!isInteger8 && obj.get<int8_t>()) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" didn't fail to parse as \"\n> -\t\t\t\t<< \"int8_t\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif ((!isInteger8 || isSigned) && obj.get<uint8_t>()) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" didn't fail to parse as \"\n> -\t\t\t\t<< \"uint8_t\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!isIntegerUpTo16 && obj.get<int16_t>()) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" didn't fail to parse as \"\n> -\t\t\t\t<< \"int16_t\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif ((!isIntegerUpTo16 || isSigned) && obj.get<uint16_t>()) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" didn't fail to parse as \"\n> -\t\t\t\t<< \"uint16_t\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!isIntegerUpTo32 && obj.get<int32_t>()) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" didn't fail to parse as \"\n> -\t\t\t\t<< \"int32_t\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif ((!isIntegerUpTo32 || isSigned) && obj.get<uint32_t>()) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" didn't fail to parse as \"\n> -\t\t\t\t<< \"uint32_t\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!isIntegerUpTo32 && type != Type::Double && obj.get<double>()) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" didn't fail to parse as \"\n> -\t\t\t\t<< \"double\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (type != Type::Size && obj.get<Size>()) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" didn't fail to parse as \"\n> -\t\t\t\t<< \"Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\treturn TestPass;\n> -\t}\n> -\n> -\tint testIntegerObject(const ValueNode &obj, const char *name, Type type,\n> -\t\t\t      int64_t value)\n> -\t{\n> -\t\tuint64_t unsignedValue = static_cast<uint64_t>(value);\n> -\t\tstd::string strValue = std::to_string(value);\n> -\t\tbool isInteger8 = type == Type::Int8 || type == Type::UInt8;\n> -\t\tbool isInteger16 = type == Type::Int16 || type == Type::UInt16;\n> -\t\tbool isSigned = type == Type::Int8 || type == Type::Int16 ||\n> -\t\t\t\ttype == Type::Int32;\n> -\n> -\t\t/* All integers can be parsed as strings or double. */\n> -\n> -\t\tif (obj.get<string>().value_or(\"\") != strValue ||\n> -\t\t    obj.get<string>(\"\") != strValue) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" failed to parse as \"\n> -\t\t\t\t<< \"string\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (obj.get<double>().value_or(0.0) != value ||\n> -\t\t    obj.get<double>(0.0) != value) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" failed to parse as \"\n> -\t\t\t\t<< \"double\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (isInteger8) {\n> -\t\t\tif (obj.get<int8_t>().value_or(0) != value ||\n> -\t\t\t    obj.get<int8_t>(0) != value) {\n> -\t\t\t\tstd::cerr\n> -\t\t\t\t\t<< \"Object \" << name << \" failed to parse as \"\n> -\t\t\t\t\t<< \"int8_t\" << std::endl;\n> -\t\t\t\treturn TestFail;\n> -\t\t\t}\n> -\t\t}\n> -\n> -\t\tif (isInteger8 && !isSigned) {\n> -\t\t\tif (obj.get<uint8_t>().value_or(0) != unsignedValue ||\n> -\t\t\t    obj.get<uint8_t>(0) != unsignedValue) {\n> -\t\t\t\tstd::cerr\n> -\t\t\t\t\t<< \"Object \" << name << \" failed to parse as \"\n> -\t\t\t\t\t<< \"uint8_t\" << std::endl;\n> -\t\t\t\treturn TestFail;\n> -\t\t\t}\n> -\t\t}\n> -\n> -\t\tif (isInteger8 || isInteger16) {\n> -\t\t\tif (obj.get<int16_t>().value_or(0) != value ||\n> -\t\t\t    obj.get<int16_t>(0) != value) {\n> -\t\t\t\tstd::cerr\n> -\t\t\t\t\t<< \"Object \" << name << \" failed to parse as \"\n> -\t\t\t\t\t<< \"int16_t\" << std::endl;\n> -\t\t\t\treturn TestFail;\n> -\t\t\t}\n> -\t\t}\n> -\n> -\t\tif ((isInteger8 || isInteger16) && !isSigned) {\n> -\t\t\tif (obj.get<uint16_t>().value_or(0) != unsignedValue ||\n> -\t\t\t    obj.get<uint16_t>(0) != unsignedValue) {\n> -\t\t\t\tstd::cerr\n> -\t\t\t\t\t<< \"Object \" << name << \" failed to parse as \"\n> -\t\t\t\t\t<< \"uint16_t\" << std::endl;\n> -\t\t\t\treturn TestFail;\n> -\t\t\t}\n> -\t\t}\n> -\n> -\t\tif (obj.get<int32_t>().value_or(0) != value ||\n> -\t\t    obj.get<int32_t>(0) != value) {\n> -\t\t\tstd::cerr\n> -\t\t\t\t<< \"Object \" << name << \" failed to parse as \"\n> -\t\t\t\t<< \"int32_t\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!isSigned) {\n> -\t\t\tif (obj.get<uint32_t>().value_or(0) != unsignedValue ||\n> -\t\t\t    obj.get<uint32_t>(0) != unsignedValue) {\n> -\t\t\t\tstd::cerr\n> -\t\t\t\t\t<< \"Object \" << name << \" failed to parse as \"\n> -\t\t\t\t\t<< \"uint32_t\" << std::endl;\n> -\t\t\t\treturn TestFail;\n> -\t\t\t}\n> -\t\t}\n> -\n> -\t\treturn TestPass;\n> -\t}\n> -\n>   \tint run()\n>   \t{\n> -\t\t/* Test invalid YAML file */\n> +\t\t/* Test parsing invalid YAML file. */\n>   \t\tFile file{ invalidYamlFile_ };\n>   \t\tif (!file.open(File::OpenModeFlag::ReadOnly)) {\n>   \t\t\tcerr << \"Fail to open invalid YAML file\" << std::endl;\n> @@ -298,7 +82,7 @@ protected:\n>   \t\t\treturn TestFail;\n>   \t\t}\n> \n> -\t\t/* Test YAML file */\n> +\t\t/* Test parsing valid YAML file. */\n>   \t\tfile.close();\n>   \t\tfile.setFileName(testYamlFile_);\n>   \t\tif (!file.open(File::OpenModeFlag::ReadOnly)) {\n> @@ -313,130 +97,66 @@ protected:\n>   \t\t\treturn TestFail;\n>   \t\t}\n> \n> +\t\t/* Test that the root dictionary node has been parsed correctly. */\n>   \t\tif (!root->isDictionary()) {\n> -\t\t\tcerr << \"YAML root is not dictionary\" << std::endl;\n> +\t\t\tcerr << \"Dictionary node has wrong type\" << std::endl;\n>   \t\t\treturn TestFail;\n>   \t\t}\n> \n> -\t\tstd::vector<const char *> rootElemNames = {\n> -\t\t\t\"string\", \"double\", \"int8_t\", \"uint8_t\", \"int16_t\",\n> -\t\t\t\"uint16_t\", \"int32_t\", \"uint32_t\", \"size\", \"list\",\n> -\t\t\t\"dictionary\", \"level1\",\n> -\t\t};\n> +\t\tusing NodeFunc = bool (ValueNode::*)() const;\n> \n> -\t\tfor (const char *name : rootElemNames) {\n> -\t\t\tif (!root->contains(name)) {\n> -\t\t\t\tcerr << \"Missing \" << name << \" object in YAML root\"\n> -\t\t\t\t     << std::endl;\n> +\t\tstd::map<std::string, NodeFunc> topLevelNodes = { {\n> +\t\t\t{ \"empty\", &ValueNode::isValue },\n> +\t\t\t{ \"value\", &ValueNode::isValue },\n> +\t\t\t{ \"list\", &ValueNode::isList },\n> +\t\t\t{ \"level1\", &ValueNode::isDictionary },\n> +\t\t} };\n> +\n> +\t\tif (root->size() != topLevelNodes.size()) {\n> +\t\t\tstd::cerr << \"Dictionary node has wrong size\" << std::endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tfor (const auto &[key, value] : root->asDict()) {\n> +\t\t\tconst auto iter = topLevelNodes.find(key);\n> +\t\t\tif (iter == topLevelNodes.end()) {\n> +\t\t\t\tstd::cerr << \"Dictionary key '\" << key << \"' unknown\"\n> +\t\t\t\t\t  << std::endl;\n>   \t\t\t\treturn TestFail;\n>   \t\t\t}\n> +\n> +\t\t\tconst auto &func = iter->second;\n> +\t\t\tif (!(value.*func)()) {\n> +\t\t\t\tstd::cerr << \"Node '\" << key << \"' has wrong type\"\n> +\t\t\t\t\t  << std::endl;\n> +\t\t\t\treturn TestFail;\n> +\t\t\t}\n> +\n> +\t\t\ttopLevelNodes.erase(iter);\n>   \t\t}\n> \n> -\t\t/* Test string object */\n> -\t\tauto &strObj = (*root)[\"string\"];\n> +\t\t/* Test empty node. */\n> +\t\tauto &emptyNode = (*root)[\"empty\"];\n> \n> -\t\tif (testObjectType(strObj, \"string\", Type::String) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\" ||\n> -\t\t    strObj.get<string>(\"\") != \"libcamera\") {\n> -\t\t\tcerr << \"String object parse as wrong content\" << std::endl;\n> +\t\tif (emptyNode.get<string>(\"-\") != \"\") {\n> +\t\t\tstd::cerr << \"Empty node has incorrect content\" << std::endl;\n>   \t\t\treturn TestFail;\n>   \t\t}\n> \n> -\t\t/* Test int8_t object */\n> -\t\tauto &int8Obj = (*root)[\"int8_t\"];\n> +\t\t/* Test value node. */\n> +\t\tauto &valueNode = (*root)[\"value\"];\n> \n> -\t\tif (testObjectType(int8Obj, \"int8_t\", Type::Int8) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\tif (testIntegerObject(int8Obj, \"int8_t\", Type::Int8, -100) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\t/* Test uint8_t object */\n> -\t\tauto &uint8Obj = (*root)[\"uint8_t\"];\n> -\n> -\t\tif (testObjectType(uint8Obj, \"uint8_t\", Type::UInt8) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\tif (testIntegerObject(uint8Obj, \"uint8_t\", Type::UInt8, 100) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\t/* Test int16_t object */\n> -\t\tauto &int16Obj = (*root)[\"int16_t\"];\n> -\n> -\t\tif (testObjectType(int16Obj, \"int16_t\", Type::Int16) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\tif (testIntegerObject(int16Obj, \"int16_t\", Type::Int16, -1000) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\t/* Test uint16_t object */\n> -\t\tauto &uint16Obj = (*root)[\"uint16_t\"];\n> -\n> -\t\tif (testObjectType(uint16Obj, \"uint16_t\", Type::UInt16) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\tif (testIntegerObject(uint16Obj, \"uint16_t\", Type::UInt16, 1000) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\t/* Test int32_t object */\n> -\t\tauto &int32Obj = (*root)[\"int32_t\"];\n> -\n> -\t\tif (testObjectType(int32Obj, \"int32_t\", Type::Int32) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\tif (testIntegerObject(int32Obj, \"int32_t\", Type::Int32, -100000) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\t/* Test uint32_t object */\n> -\t\tauto &uint32Obj = (*root)[\"uint32_t\"];\n> -\n> -\t\tif (testObjectType(uint32Obj, \"uint32_t\", Type::UInt32) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\tif (testIntegerObject(uint32Obj, \"uint32_t\", Type::UInt32, 100000) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\t/* Test double value */\n> -\t\tauto &doubleObj = (*root)[\"double\"];\n> -\n> -\t\tif (testObjectType(doubleObj, \"double\", Type::Double) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\" ||\n> -\t\t    doubleObj.get<string>(\"\") != \"3.14159\") {\n> -\t\t\tcerr << \"Double object fail to parse as string\" << std::endl;\n> +\t\tif (valueNode.get<string>(\"\") != \"42\") {\n> +\t\t\tstd::cerr << \"Value node has incorrect content\" << std::endl;\n>   \t\t\treturn TestFail;\n>   \t\t}\n> \n> -\t\tif (doubleObj.get<double>().value_or(0.0) != 3.14159 ||\n> -\t\t    doubleObj.get<double>(0.0) != 3.14159) {\n> -\t\t\tcerr << \"Double object parse as wrong value\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\t/* Test Size value */\n> -\t\tauto &sizeObj = (*root)[\"size\"];\n> -\n> -\t\tif (testObjectType(sizeObj, \"size\", Type::Size) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\tif (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080) ||\n> -\t\t    sizeObj.get<Size>(Size(0, 0)) != Size(1920, 1080)) {\n> -\t\t\tcerr << \"Size object parse as wrong value\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\t/* Test list object */\n> +\t\t/* Test list node. */\n>   \t\tauto &listObj = (*root)[\"list\"];\n> \n> -\t\tif (testObjectType(listObj, \"list\", Type::List) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n>   \t\tstatic constexpr std::array<const char *, 3> listValues{\n> -\t\t\t\"James\",\n> -\t\t\t\"Mary\",\n> +\t\t\t\"libcamera\",\n> +\t\t\t\"linux\",\n>   \t\t\t\"\",\n>   \t\t};\n> \n> @@ -470,102 +190,13 @@ protected:\n>   \t\t\ti++;\n>   \t\t}\n> \n> -\t\t/* Ensure that empty objects get parsed as empty strings. */\n> +\t\t/* Ensure that empty list elements get parsed as empty strings. */\n>   \t\tif (!listObj[2].isValue()) {\n> -\t\t\tcerr << \"Empty object is not a value\" << std::endl;\n> +\t\t\tcerr << \"Empty list element is not a value\" << std::endl;\n>   \t\t\treturn TestFail;\n>   \t\t}\n> \n> -\t\t/* Test dictionary object */\n> -\t\tauto &dictObj = (*root)[\"dictionary\"];\n> -\n> -\t\tif (testObjectType(dictObj, \"dictionary\", Type::Dictionary) != TestPass)\n> -\t\t\treturn TestFail;\n> -\n> -\t\tstatic constexpr std::array<std::pair<const char *, int>, 4> dictValues{ {\n> -\t\t\t{ \"a\", 1 },\n> -\t\t\t{ \"c\", 3 },\n> -\t\t\t{ \"b\", 2 },\n> -\t\t\t{ \"empty\", -100 },\n> -\t\t} };\n> -\n> -\t\tsize_t dictSize = dictValues.size();\n> -\n> -\t\tif (dictObj.size() != dictSize) {\n> -\t\t\tcerr << \"Dictionary object has wrong size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\ti = 0;\n> -\t\tfor (const auto &[key, elem] : dictObj.asDict()) {\n> -\t\t\tif (i >= dictSize) {\n> -\t\t\t\tstd::cerr << \"Too many elements in dictionary during iteration\"\n> -\t\t\t\t\t  << std::endl;\n> -\t\t\t\treturn TestFail;\n> -\t\t\t}\n> -\n> -\t\t\tconst auto &item = dictValues[i];\n> -\t\t\tif (item.first != key) {\n> -\t\t\t\tstd::cerr << \"Dictionary key \" << i << \" has wrong value\"\n> -\t\t\t\t\t  << std::endl;\n> -\t\t\t\treturn TestFail;\n> -\t\t\t}\n> -\n> -\t\t\tif (&elem != &dictObj[key]) {\n> -\t\t\t\tstd::cerr << \"Dictionary element \" << i << \" has wrong address\"\n> -\t\t\t\t\t  << std::endl;\n> -\t\t\t\treturn TestFail;\n> -\t\t\t}\n> -\n> -\t\t\tif (elem.get<int32_t>(-100) != item.second) {\n> -\t\t\t\tstd::cerr << \"Dictionary element \" << i << \" has wrong value\"\n> -\t\t\t\t\t  << std::endl;\n> -\t\t\t\treturn TestFail;\n> -\t\t\t}\n> -\n> -\t\t\ti++;\n> -\t\t}\n> -\n> -\t\t/* Ensure that empty objects get parsed as empty strings. */\n> -\t\tif (!dictObj[\"empty\"].isValue()) {\n> -\t\t\tcerr << \"Empty object is not of type value\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\t/* Ensure that keys without values are added to a dict. */\n> -\t\tif (!dictObj.contains(\"empty\")) {\n> -\t\t\tcerr << \"Empty element is missing in dict\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\t/* Test access to nonexistent member. */\n> -\t\tif (dictObj[\"nonexistent\"].get<std::string>(\"default\") != \"default\") {\n> -\t\t\tcerr << \"Accessing nonexistent dict entry fails to return default\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\t/* Test nonexistent object has value type empty. */\n> -\t\tif (!dictObj[\"nonexistent\"].isEmpty()) {\n> -\t\t\tcerr << \"Accessing nonexistent object returns non-empty object\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\t/* Test explicit cast to bool on an empty object returns true. */\n> -\t\tif (!!dictObj[\"empty\"] != true) {\n> -\t\t\tcerr << \"Casting empty entry to bool returns false\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\t/* Test explicit cast to bool on nonexistent object returns false. */\n> -\t\tif (!!dictObj[\"nonexistent\"] != false) {\n> -\t\t\tcerr << \"Casting nonexistent dict entry to bool returns true\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\t/* Make sure utils::map_keys() works on the adapter. */\n> -\t\t(void)utils::map_keys(dictObj.asDict());\n> -\n> -\t\t/* Test leveled objects */\n> +\t\t/* Test nested nodes. */\n>   \t\tauto &level1Obj = (*root)[\"level1\"];\n> \n>   \t\tif (!level1Obj.isDictionary()) {\n> @@ -576,7 +207,7 @@ protected:\n>   \t\tauto &level2Obj = level1Obj[\"level2\"];\n> \n>   \t\tif (!level2Obj.isList() || level2Obj.size() != 2) {\n> -\t\t\tcerr << \"level2 object should be 2 element list\" << std::endl;\n> +\t\t\tcerr << \"level2 object should be a 2 elements list\" << std::endl;\n>   \t\t\treturn TestFail;\n>   \t\t}\n> \n> --\n> Regards,\n> \n> Laurent Pinchart\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id C3734BDCB5\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 24 Apr 2026 07:54:18 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7B0A662F6E;\n\tFri, 24 Apr 2026 09:54:18 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A4D0062F67\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Apr 2026 09:54:17 +0200 (CEST)","from [192.168.33.62] (185.221.140.120.nat.pool.zt.hu\n\t[185.221.140.120])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E497A802;\n\tFri, 24 Apr 2026 09:52:37 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"OXLrw0Xc\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1777017158;\n\tbh=wdQCAlvrhGZZz4i8FyduMUmW2JEzT/1a6Ju1dkHNb2Y=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=OXLrw0XcCZKHMoWSUeYF2L3n9pRXArO0Uq1yOMhL/qpSkQsE5TKRgOyZmpGNIvVrI\n\tXxRyib1acQCdvEx1ltxDGR2HsQonCE0gzUWQYS8niVe7teP7tqziRcvGYr7Nzn8m7S\n\tamvAZbPZ5HBYUjDOWOVkDEwXCoi3bwjbg/qyb+Ow=","Message-ID":"<05317d55-2b42-42e5-a207-9e9068934082@ideasonboard.com>","Date":"Fri, 24 Apr 2026 09:54:14 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v3 22/37] test: yaml-parser: Simplify test","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20260423230059.3180987-1-laurent.pinchart@ideasonboard.com>\n\t<5k6-uG4Qdq1bAHRqdzOduJI5Ix0AsmMjZ-v6Grb2SMmZkvPCC9_bY1QTJ7ZXN-j0GVN-aoL6Yq0nR1V05Lvppg==@protonmail.internalid>\n\t<20260423230059.3180987-23-laurent.pinchart@ideasonboard.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20260423230059.3180987-23-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]