Show a patch.

GET /api/patches/26544/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 26544,
    "url": "https://patchwork.libcamera.org/api/patches/26544/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/26544/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20260423230059.3180987-23-laurent.pinchart@ideasonboard.com>",
    "date": "2026-04-23T23:00:44",
    "name": "[v3,22/37] test: yaml-parser: Simplify test",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "8189071ee4d5fbe965ecd197671b86447795f2ab",
    "submitter": {
        "id": 2,
        "url": "https://patchwork.libcamera.org/api/people/2/?format=api",
        "name": "Laurent Pinchart",
        "email": "laurent.pinchart@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/26544/mbox/",
    "series": [
        {
            "id": 5883,
            "url": "https://patchwork.libcamera.org/api/series/5883/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5883",
            "date": "2026-04-23T23:00:22",
            "name": "libcamera: Global configuration file improvements",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/5883/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/26544/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/26544/checks/",
    "tags": {},
    "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 7FEE7BDCB5\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 23 Apr 2026 23:01:48 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EDA1362FD5;\n\tFri, 24 Apr 2026 01:01:47 +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 D856F62FAF\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Apr 2026 01:01:31 +0200 (CEST)",
            "from killaraus.ideasonboard.com\n\t(2001-14ba-703d-e500--2a1.rev.dnainternet.fi\n\t[IPv6:2001:14ba:703d:e500::2a1])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 55088802\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Apr 2026 00:59:52 +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=\"UxayQAlJ\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1776985192;\n\tbh=mG+SiwmyGP1pkyoj5nifYfDoJLIwV8/UWHUkoaNZgPM=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=UxayQAlJwGVAhPSjgPC5Xoh9ZarFlZhlrzmwXN9iMH1srA5r/eJWMzaYIZ+YruvoN\n\t/JOIk1vTkVyKmAa3O9OmMt+9Ko+m6JgTEoNy1DUCp8F17TNbR4VTJr0bB9ucMsS2th\n\tIQzge+nY+uaX62cpeXSSQ2bqL5MW7nvVhPTp3Svs=",
        "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Subject": "[PATCH v3 22/37] test: yaml-parser: Simplify test",
        "Date": "Fri, 24 Apr 2026 02:00:44 +0300",
        "Message-ID": "<20260423230059.3180987-23-laurent.pinchart@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.53.0",
        "In-Reply-To": "<20260423230059.3180987-1-laurent.pinchart@ideasonboard.com>",
        "References": "<20260423230059.3180987-1-laurent.pinchart@ideasonboard.com>",
        "MIME-Version": "1.0",
        "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>"
    },
    "content": "Most of the tests in the YamlParser unit test cover the ValueNode class.\nThey are now implemented in the ValueNode unit test. Drop them, and only\nkeep the tests that related to YAML parsing.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n test/yaml-parser.cpp | 469 +++++--------------------------------------\n 1 file changed, 50 insertions(+), 419 deletions(-)",
    "diff": "diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\nindex 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",
    "prefixes": [
        "v3",
        "22/37"
    ]
}