[{"id":24628,"web_url":"https://patchwork.libcamera.org/comment/24628/","msgid":"<20220818120342.GD2412817@pyrite.rasen.tech>","date":"2022-08-18T12:03:42","subject":"Re: [libcamera-devel] [PATCH v4 1/9] test: yaml-parser: Simplify\n\tcode by centralizing parse error checks","submitter":{"id":97,"url":"https://patchwork.libcamera.org/api/people/97/","name":"Nicolas Dufresne via libcamera-devel","email":"libcamera-devel@lists.libcamera.org"},"content":"On Tue, Aug 16, 2022 at 04:54:06AM +0300, Laurent Pinchart via libcamera-devel wrote:\n> Centralize most parse failure checks in a single function to avoid a\n> larger number of copies of nearly identical checks.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nReviewed-by: Paul Elder <paul.elder@ideasboard.com>\n\n> ---\n>  test/yaml-parser.cpp | 309 +++++++++++++------------------------------\n>  1 file changed, 95 insertions(+), 214 deletions(-)\n> \n> diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> index 93ba88b8bcd5..6729e1bd430e 100644\n> --- a/test/yaml-parser.cpp\n> +++ b/test/yaml-parser.cpp\n> @@ -72,6 +72,83 @@ protected:\n>  \t\treturn TestPass;\n>  \t}\n>  \n> +\tenum class Type {\n> +\t\tString,\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 YamlObject &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 isInteger = type == Type::Int32 || type == Type::UInt32;\n> +\t\tbool isSigned = 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 (!isInteger && 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 ((!isInteger || 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 (!isInteger && 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 run()\n>  \t{\n>  \t\t/* Test invalid YAML file */\n> @@ -107,58 +184,24 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>  \n> -\t\tif (!root->contains(\"string\")) {\n> -\t\t\tcerr << \"Missing string object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"double\")) {\n> -\t\t\tcerr << \"Missing double object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"int32_t\")) {\n> -\t\t\tcerr << \"Missing int32_t object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"uint32_t\")) {\n> -\t\t\tcerr << \"Missing uint32_t object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"size\")) {\n> -\t\t\tcerr << \"Missing Size object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"list\")) {\n> -\t\t\tcerr << \"Missing list object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"dictionary\")) {\n> -\t\t\tcerr << \"Missing dictionary object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"level1\")) {\n> -\t\t\tcerr << \"Missing leveled object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> +\t\tstd::vector<const char *> rootElemNames = {\n> +\t\t\t\"string\", \"double\", \"int32_t\", \"uint32_t\", \"size\",\n> +\t\t\t\"list\", \"dictionary\", \"level1\",\n> +\t\t};\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\t\t\treturn TestFail;\n> +\t\t\t}\n>  \t\t}\n>  \n>  \t\t/* Test string object */\n>  \t\tauto &strObj = (*root)[\"string\"];\n>  \n> -\t\tif (strObj.isDictionary()) {\n> -\t\t\tcerr << \"String object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(strObj, \"string\", Type::String) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (strObj.isList()) {\n> -\t\t\tcerr << \"String object parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>  \n>  \t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\" ||\n>  \t\t    strObj.get<string>(\"\") != \"libcamera\") {\n> @@ -166,38 +209,11 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>  \n> -\t\tif (strObj.get<int32_t>()) {\n> -\t\t\tcerr << \"String object parse as integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (strObj.get<uint32_t>()) {\n> -\t\t\tcerr << \"String object parse as unsigned integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (strObj.get<double>()) {\n> -\t\t\tcerr << \"String object parse as double\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (strObj.get<Size>()) {\n> -\t\t\tcerr << \"String object parse as Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n>  \t\t/* Test int32_t object */\n>  \t\tauto &int32Obj = (*root)[\"int32_t\"];\n>  \n> -\t\tif (int32Obj.isDictionary()) {\n> -\t\t\tcerr << \"Integer object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(int32Obj, \"int32_t\", Type::Int32) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (int32Obj.isList()) {\n> -\t\t\tcerr << \"Integer object parse as Integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>  \n>  \t\tif (int32Obj.get<int32_t>().value_or(0) != -100 ||\n>  \t\t    int32Obj.get<int32_t>(0) != -100) {\n> @@ -217,28 +233,11 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>  \n> -\t\tif (int32Obj.get<uint32_t>()) {\n> -\t\t\tcerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (int32Obj.get<Size>()) {\n> -\t\t\tcerr << \"Integer object parse as Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n>  \t\t/* Test uint32_t object */\n>  \t\tauto &uint32Obj = (*root)[\"uint32_t\"];\n>  \n> -\t\tif (uint32Obj.isDictionary()) {\n> -\t\t\tcerr << \"Unsigned integer object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(uint32Obj, \"uint32_t\", Type::UInt32) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (uint32Obj.isList()) {\n> -\t\t\tcerr << \"Unsigned integer object parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>  \n>  \t\tif (uint32Obj.get<int32_t>().value_or(0) != 100 ||\n>  \t\t    uint32Obj.get<int32_t>(0) != 100) {\n> @@ -264,23 +263,11 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>  \n> -\t\tif (uint32Obj.get<Size>()) {\n> -\t\t\tcerr << \"Unsigned integer object parsed as Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n>  \t\t/* Test double value */\n>  \t\tauto &doubleObj = (*root)[\"double\"];\n>  \n> -\t\tif (doubleObj.isDictionary()) {\n> -\t\t\tcerr << \"Double object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(doubleObj, \"double\", Type::Double) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (doubleObj.isList()) {\n> -\t\t\tcerr << \"Double object parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>  \n>  \t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\" ||\n>  \t\t    doubleObj.get<string>(\"\") != \"3.14159\") {\n> @@ -294,53 +281,11 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>  \n> -\t\tif (doubleObj.get<int32_t>()) {\n> -\t\t\tcerr << \"Double object parse as integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (doubleObj.get<uint32_t>()) {\n> -\t\t\tcerr << \"Double object parse as unsigned integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (doubleObj.get<Size>()) {\n> -\t\t\tcerr << \"Double object parse as Size\" << 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 (sizeObj.isDictionary()) {\n> -\t\t\tcerr << \"Size object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(sizeObj, \"size\", Type::Size) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!sizeObj.isList()) {\n> -\t\t\tcerr << \"Size object parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (sizeObj.get<string>()) {\n> -\t\t\tcerr << \"Size object parse as string\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (sizeObj.get<double>()) {\n> -\t\t\tcerr << \"Size object parse as double\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (sizeObj.get<int32_t>()) {\n> -\t\t\tcerr << \"Size object parse as integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (sizeObj.get<uint32_t>()) {\n> -\t\t\tcerr << \"Size object parse as unsigned integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\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> @@ -351,40 +296,8 @@ protected:\n>  \t\t/* Test list object */\n>  \t\tauto &listObj = (*root)[\"list\"];\n>  \n> -\t\tif (listObj.isDictionary()) {\n> -\t\t\tcerr << \"List object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(listObj, \"list\", Type::List) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!listObj.isList()) {\n> -\t\t\tcerr << \"List object fail to parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (listObj.get<string>()) {\n> -\t\t\tcerr << \"List object parse as string\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (listObj.get<double>()) {\n> -\t\t\tcerr << \"List object parse as double\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (listObj.get<int32_t>()) {\n> -\t\t\tcerr << \"List object parse as integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (listObj.get<uint32_t>()) {\n> -\t\t\tcerr << \"List object parse as unsigne integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (listObj.get<Size>()) {\n> -\t\t\tcerr << \"String list object parse as Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>  \n>  \t\tstatic constexpr std::array<const char *, 2> listValues{\n>  \t\t\t\"James\",\n> @@ -424,40 +337,8 @@ protected:\n>  \t\t/* Test dictionary object */\n>  \t\tauto &dictObj = (*root)[\"dictionary\"];\n>  \n> -\t\tif (!dictObj.isDictionary()) {\n> -\t\t\tcerr << \"Dictionary object fail to parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(dictObj, \"dictionary\", Type::Dictionary) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.isList()) {\n> -\t\t\tcerr << \"Dictionary object parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.get<string>()) {\n> -\t\t\tcerr << \"Dictionary object parse as string\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.get<double>()) {\n> -\t\t\tcerr << \"Dictionary object parse as double\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.get<int32_t>()) {\n> -\t\t\tcerr << \"Dictionary object parse as integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.get<uint32_t>()) {\n> -\t\t\tcerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.get<Size>()) {\n> -\t\t\tcerr << \"Dictionary object parse as Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>  \n>  \t\tstatic constexpr std::array<std::pair<const char *, int>, 3> dictValues{ {\n>  \t\t\t{ \"a\", 1 },\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 C9D0ABE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 18 Aug 2022 12:03:52 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1AA0561FC0;\n\tThu, 18 Aug 2022 14:03:52 +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 3286F61FA7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Aug 2022 14:03:51 +0200 (CEST)","from pyrite.rasen.tech (KD027085204050.au-net.ne.jp [27.85.204.50])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A1EED8B;\n\tThu, 18 Aug 2022 14:03:49 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1660824232;\n\tbh=ft9PLxpOxsnpHKBdU3iBykMnedlvC//nd9ByOjsZ1S8=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=ICoURgTf/ALx4fMmxmzSKZ6rh1aUCw6Sr6Wia6hnbIdBHsUgMbZN6CCPUPHUqVQYj\n\tspXDWxpAc6kstwyTo0+/ifvaNYXzp/mOHDqsEzBOJMqH9Ju/7q3Tts0ECtXcebirB2\n\tmPpWjY/rTe6oR2HaCevU+xN4D4WHro0hdBG2GJkCCLfHTkPXxLa3w4GhfpQF5xcBgi\n\ty+9k+oWP4vNjOsCtwlkeXrp4j8TeP0e3lYNJ7D23vc9V9/t+oWYT0Z7GAs4CajjoBh\n\tBDM2lFnWUBAp1fod7gc54iyyIpGBSJtAxoeX2ye59BHewuL+PQ1NAzXKFNUFQto1gX\n\tCXFDCxw2+pUkw==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1660824230;\n\tbh=ft9PLxpOxsnpHKBdU3iBykMnedlvC//nd9ByOjsZ1S8=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=KwkB0n/Jjro78jPVOa4+T2Efshz062zp5ahAztL78AM44QjAybc7qlBFcuXLDlKMu\n\t/zw4l63w9OoIOiUYJgnN/N35+CYR4wRZvUfGMv7C+fIuHbTkzldZx1CusUr0Tp16Ge\n\tU9GXKC/ri8mMdcJAzAtHhY9TcB/cWLkveVuhKQSo="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"KwkB0n/J\"; dkim-atps=neutral","Date":"Thu, 18 Aug 2022 21:03:42 +0900","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20220818120342.GD2412817@pyrite.rasen.tech>","References":"<20220816015414.7462-1-laurent.pinchart@ideasonboard.com>\n\t<20220816015414.7462-2-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20220816015414.7462-2-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v4 1/9] test: yaml-parser: Simplify\n\tcode by centralizing parse error checks","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>","From":"Paul Elder via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"paul.elder@ideasonboard.com","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24634,"web_url":"https://patchwork.libcamera.org/comment/24634/","msgid":"<20220818124713.gm4ckukrupk4xju7@uno.localdomain>","date":"2022-08-18T12:47:13","subject":"Re: [libcamera-devel] [PATCH v4 1/9] test: yaml-parser: Simplify\n\tcode by centralizing parse error checks","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent,\n\nOn Tue, Aug 16, 2022 at 04:54:06AM +0300, Laurent Pinchart via libcamera-devel wrote:\n> Centralize most parse failure checks in a single function to avoid a\n> larger number of copies of nearly identical checks.\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nThis saves a lot of boilerplate indeed!\n\n> ---\n>  test/yaml-parser.cpp | 309 +++++++++++++------------------------------\n>  1 file changed, 95 insertions(+), 214 deletions(-)\n>\n> diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> index 93ba88b8bcd5..6729e1bd430e 100644\n> --- a/test/yaml-parser.cpp\n> +++ b/test/yaml-parser.cpp\n> @@ -72,6 +72,83 @@ protected:\n>  \t\treturn TestPass;\n>  \t}\n>\n> +\tenum class Type {\n> +\t\tString,\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 YamlObject &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 isInteger = type == Type::Int32 || type == Type::UInt32;\n> +\t\tbool isSigned = type == Type::Int32;\n\nAren't double signed too ?\n\nAnyway,\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\n\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 (!isInteger && 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 ((!isInteger || 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 (!isInteger && 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 run()\n>  \t{\n>  \t\t/* Test invalid YAML file */\n> @@ -107,58 +184,24 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (!root->contains(\"string\")) {\n> -\t\t\tcerr << \"Missing string object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"double\")) {\n> -\t\t\tcerr << \"Missing double object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"int32_t\")) {\n> -\t\t\tcerr << \"Missing int32_t object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"uint32_t\")) {\n> -\t\t\tcerr << \"Missing uint32_t object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"size\")) {\n> -\t\t\tcerr << \"Missing Size object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"list\")) {\n> -\t\t\tcerr << \"Missing list object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"dictionary\")) {\n> -\t\t\tcerr << \"Missing dictionary object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!root->contains(\"level1\")) {\n> -\t\t\tcerr << \"Missing leveled object in YAML root\" << std::endl;\n> -\t\t\treturn TestFail;\n> +\t\tstd::vector<const char *> rootElemNames = {\n> +\t\t\t\"string\", \"double\", \"int32_t\", \"uint32_t\", \"size\",\n> +\t\t\t\"list\", \"dictionary\", \"level1\",\n> +\t\t};\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\t\t\treturn TestFail;\n> +\t\t\t}\n>  \t\t}\n>\n>  \t\t/* Test string object */\n>  \t\tauto &strObj = (*root)[\"string\"];\n>\n> -\t\tif (strObj.isDictionary()) {\n> -\t\t\tcerr << \"String object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(strObj, \"string\", Type::String) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (strObj.isList()) {\n> -\t\t\tcerr << \"String object parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>\n>  \t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\" ||\n>  \t\t    strObj.get<string>(\"\") != \"libcamera\") {\n> @@ -166,38 +209,11 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<int32_t>()) {\n> -\t\t\tcerr << \"String object parse as integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (strObj.get<uint32_t>()) {\n> -\t\t\tcerr << \"String object parse as unsigned integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (strObj.get<double>()) {\n> -\t\t\tcerr << \"String object parse as double\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (strObj.get<Size>()) {\n> -\t\t\tcerr << \"String object parse as Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n>  \t\t/* Test int32_t object */\n>  \t\tauto &int32Obj = (*root)[\"int32_t\"];\n>\n> -\t\tif (int32Obj.isDictionary()) {\n> -\t\t\tcerr << \"Integer object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(int32Obj, \"int32_t\", Type::Int32) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (int32Obj.isList()) {\n> -\t\t\tcerr << \"Integer object parse as Integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>\n>  \t\tif (int32Obj.get<int32_t>().value_or(0) != -100 ||\n>  \t\t    int32Obj.get<int32_t>(0) != -100) {\n> @@ -217,28 +233,11 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<uint32_t>()) {\n> -\t\t\tcerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (int32Obj.get<Size>()) {\n> -\t\t\tcerr << \"Integer object parse as Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n>  \t\t/* Test uint32_t object */\n>  \t\tauto &uint32Obj = (*root)[\"uint32_t\"];\n>\n> -\t\tif (uint32Obj.isDictionary()) {\n> -\t\t\tcerr << \"Unsigned integer object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(uint32Obj, \"uint32_t\", Type::UInt32) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (uint32Obj.isList()) {\n> -\t\t\tcerr << \"Unsigned integer object parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>\n>  \t\tif (uint32Obj.get<int32_t>().value_or(0) != 100 ||\n>  \t\t    uint32Obj.get<int32_t>(0) != 100) {\n> @@ -264,23 +263,11 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<Size>()) {\n> -\t\t\tcerr << \"Unsigned integer object parsed as Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n>  \t\t/* Test double value */\n>  \t\tauto &doubleObj = (*root)[\"double\"];\n>\n> -\t\tif (doubleObj.isDictionary()) {\n> -\t\t\tcerr << \"Double object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(doubleObj, \"double\", Type::Double) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (doubleObj.isList()) {\n> -\t\t\tcerr << \"Double object parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>\n>  \t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\" ||\n>  \t\t    doubleObj.get<string>(\"\") != \"3.14159\") {\n> @@ -294,53 +281,11 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<int32_t>()) {\n> -\t\t\tcerr << \"Double object parse as integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (doubleObj.get<uint32_t>()) {\n> -\t\t\tcerr << \"Double object parse as unsigned integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (doubleObj.get<Size>()) {\n> -\t\t\tcerr << \"Double object parse as Size\" << 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 (sizeObj.isDictionary()) {\n> -\t\t\tcerr << \"Size object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(sizeObj, \"size\", Type::Size) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!sizeObj.isList()) {\n> -\t\t\tcerr << \"Size object parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (sizeObj.get<string>()) {\n> -\t\t\tcerr << \"Size object parse as string\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (sizeObj.get<double>()) {\n> -\t\t\tcerr << \"Size object parse as double\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (sizeObj.get<int32_t>()) {\n> -\t\t\tcerr << \"Size object parse as integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (sizeObj.get<uint32_t>()) {\n> -\t\t\tcerr << \"Size object parse as unsigned integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\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> @@ -351,40 +296,8 @@ protected:\n>  \t\t/* Test list object */\n>  \t\tauto &listObj = (*root)[\"list\"];\n>\n> -\t\tif (listObj.isDictionary()) {\n> -\t\t\tcerr << \"List object parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(listObj, \"list\", Type::List) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (!listObj.isList()) {\n> -\t\t\tcerr << \"List object fail to parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (listObj.get<string>()) {\n> -\t\t\tcerr << \"List object parse as string\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (listObj.get<double>()) {\n> -\t\t\tcerr << \"List object parse as double\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (listObj.get<int32_t>()) {\n> -\t\t\tcerr << \"List object parse as integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (listObj.get<uint32_t>()) {\n> -\t\t\tcerr << \"List object parse as unsigne integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (listObj.get<Size>()) {\n> -\t\t\tcerr << \"String list object parse as Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>\n>  \t\tstatic constexpr std::array<const char *, 2> listValues{\n>  \t\t\t\"James\",\n> @@ -424,40 +337,8 @@ protected:\n>  \t\t/* Test dictionary object */\n>  \t\tauto &dictObj = (*root)[\"dictionary\"];\n>\n> -\t\tif (!dictObj.isDictionary()) {\n> -\t\t\tcerr << \"Dictionary object fail to parse as Dictionary\" << std::endl;\n> +\t\tif (testObjectType(dictObj, \"dictionary\", Type::Dictionary) != TestPass)\n>  \t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.isList()) {\n> -\t\t\tcerr << \"Dictionary object parse as List\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.get<string>()) {\n> -\t\t\tcerr << \"Dictionary object parse as string\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.get<double>()) {\n> -\t\t\tcerr << \"Dictionary object parse as double\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.get<int32_t>()) {\n> -\t\t\tcerr << \"Dictionary object parse as integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.get<uint32_t>()) {\n> -\t\t\tcerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n> -\n> -\t\tif (dictObj.get<Size>()) {\n> -\t\t\tcerr << \"Dictionary object parse as Size\" << std::endl;\n> -\t\t\treturn TestFail;\n> -\t\t}\n>\n>  \t\tstatic constexpr std::array<std::pair<const char *, int>, 3> dictValues{ {\n>  \t\t\t{ \"a\", 1 },\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 221BEC3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 18 Aug 2022 12:47:18 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5C34861FC0;\n\tThu, 18 Aug 2022 14:47:17 +0200 (CEST)","from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net\n\t[IPv6:2001:4b98:dc4:8::222])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4B90161FA7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Aug 2022 14:47:16 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id A065240003;\n\tThu, 18 Aug 2022 12:47:15 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1660826837;\n\tbh=yeCIahsi/eltYIrOd7OTaOgxljls5OsjyXXNRD4FVHE=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=K8YyBmcFeBsZZ4gLtz4dNxqzIFOZepLVq1zmavEFCSP5tvWoSD1qbOohSH3poKfn+\n\twnnfBkJpzy9Vvah2lTM/g6Zi2Wg75Bgq00GtJSFvqIyklCfe3fcpFhLIR5rjftGYb8\n\tdgP9SHpZSlna5jPLnqEEVkkySUufEO/cDKhvCAdgM1xV3ZRatTZFE4Jh1g9jNTFbIT\n\tcSmHalzwesMeqUKiq6+vA2d3RI5J6sieHvXCavIhPAUKT6ceB/TfEZHQLHMzWJI2q/\n\tN0IoPysAtM+VdTJ7ULnE/a0HaSRkG3eP6XnVHiHAT18AAwGq38tph9LtWFeCb97kl9\n\tmz9EfviCTE+0w==","Date":"Thu, 18 Aug 2022 14:47:13 +0200","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20220818124713.gm4ckukrupk4xju7@uno.localdomain>","References":"<20220816015414.7462-1-laurent.pinchart@ideasonboard.com>\n\t<20220816015414.7462-2-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20220816015414.7462-2-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v4 1/9] test: yaml-parser: Simplify\n\tcode by centralizing parse error checks","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>","From":"Jacopo Mondi via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24662,"web_url":"https://patchwork.libcamera.org/comment/24662/","msgid":"<Yv5UjjhOTO+j4HLv@pendragon.ideasonboard.com>","date":"2022-08-18T15:02:38","subject":"Re: [libcamera-devel] [PATCH v4 1/9] test: yaml-parser: Simplify\n\tcode by centralizing parse error checks","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Thu, Aug 18, 2022 at 02:47:13PM +0200, Jacopo Mondi wrote:\n> On Tue, Aug 16, 2022 at 04:54:06AM +0300, Laurent Pinchart via libcamera-devel wrote:\n> > Centralize most parse failure checks in a single function to avoid a\n> > larger number of copies of nearly identical checks.\n> >\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> \n> This saves a lot of boilerplate indeed!\n> \n> > ---\n> >  test/yaml-parser.cpp | 309 +++++++++++++------------------------------\n> >  1 file changed, 95 insertions(+), 214 deletions(-)\n> >\n> > diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> > index 93ba88b8bcd5..6729e1bd430e 100644\n> > --- a/test/yaml-parser.cpp\n> > +++ b/test/yaml-parser.cpp\n> > @@ -72,6 +72,83 @@ protected:\n> >  \t\treturn TestPass;\n> >  \t}\n> >\n> > +\tenum class Type {\n> > +\t\tString,\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 YamlObject &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 isInteger = type == Type::Int32 || type == Type::UInt32;\n> > +\t\tbool isSigned = type == Type::Int32;\n> \n> Aren't double signed too ?\n\nIndeed. I could rename the variable to isSignedInteger if you want.\n\n> Anyway,\n> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> \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 (!isInteger && 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 ((!isInteger || 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 (!isInteger && 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 run()\n> >  \t{\n> >  \t\t/* Test invalid YAML file */\n> > @@ -107,58 +184,24 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (!root->contains(\"string\")) {\n> > -\t\t\tcerr << \"Missing string object in YAML root\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (!root->contains(\"double\")) {\n> > -\t\t\tcerr << \"Missing double object in YAML root\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (!root->contains(\"int32_t\")) {\n> > -\t\t\tcerr << \"Missing int32_t object in YAML root\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (!root->contains(\"uint32_t\")) {\n> > -\t\t\tcerr << \"Missing uint32_t object in YAML root\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (!root->contains(\"size\")) {\n> > -\t\t\tcerr << \"Missing Size object in YAML root\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (!root->contains(\"list\")) {\n> > -\t\t\tcerr << \"Missing list object in YAML root\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (!root->contains(\"dictionary\")) {\n> > -\t\t\tcerr << \"Missing dictionary object in YAML root\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (!root->contains(\"level1\")) {\n> > -\t\t\tcerr << \"Missing leveled object in YAML root\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > +\t\tstd::vector<const char *> rootElemNames = {\n> > +\t\t\t\"string\", \"double\", \"int32_t\", \"uint32_t\", \"size\",\n> > +\t\t\t\"list\", \"dictionary\", \"level1\",\n> > +\t\t};\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\t\t\treturn TestFail;\n> > +\t\t\t}\n> >  \t\t}\n> >\n> >  \t\t/* Test string object */\n> >  \t\tauto &strObj = (*root)[\"string\"];\n> >\n> > -\t\tif (strObj.isDictionary()) {\n> > -\t\t\tcerr << \"String object parse as Dictionary\" << std::endl;\n> > +\t\tif (testObjectType(strObj, \"string\", Type::String) != TestPass)\n> >  \t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (strObj.isList()) {\n> > -\t\t\tcerr << \"String object parse as List\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> >\n> >  \t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\" ||\n> >  \t\t    strObj.get<string>(\"\") != \"libcamera\") {\n> > @@ -166,38 +209,11 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (strObj.get<int32_t>()) {\n> > -\t\t\tcerr << \"String object parse as integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (strObj.get<uint32_t>()) {\n> > -\t\t\tcerr << \"String object parse as unsigned integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (strObj.get<double>()) {\n> > -\t\t\tcerr << \"String object parse as double\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (strObj.get<Size>()) {\n> > -\t\t\tcerr << \"String object parse as Size\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> >  \t\t/* Test int32_t object */\n> >  \t\tauto &int32Obj = (*root)[\"int32_t\"];\n> >\n> > -\t\tif (int32Obj.isDictionary()) {\n> > -\t\t\tcerr << \"Integer object parse as Dictionary\" << std::endl;\n> > +\t\tif (testObjectType(int32Obj, \"int32_t\", Type::Int32) != TestPass)\n> >  \t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (int32Obj.isList()) {\n> > -\t\t\tcerr << \"Integer object parse as Integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> >\n> >  \t\tif (int32Obj.get<int32_t>().value_or(0) != -100 ||\n> >  \t\t    int32Obj.get<int32_t>(0) != -100) {\n> > @@ -217,28 +233,11 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (int32Obj.get<uint32_t>()) {\n> > -\t\t\tcerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (int32Obj.get<Size>()) {\n> > -\t\t\tcerr << \"Integer object parse as Size\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> >  \t\t/* Test uint32_t object */\n> >  \t\tauto &uint32Obj = (*root)[\"uint32_t\"];\n> >\n> > -\t\tif (uint32Obj.isDictionary()) {\n> > -\t\t\tcerr << \"Unsigned integer object parse as Dictionary\" << std::endl;\n> > +\t\tif (testObjectType(uint32Obj, \"uint32_t\", Type::UInt32) != TestPass)\n> >  \t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (uint32Obj.isList()) {\n> > -\t\t\tcerr << \"Unsigned integer object parse as List\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> >\n> >  \t\tif (uint32Obj.get<int32_t>().value_or(0) != 100 ||\n> >  \t\t    uint32Obj.get<int32_t>(0) != 100) {\n> > @@ -264,23 +263,11 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (uint32Obj.get<Size>()) {\n> > -\t\t\tcerr << \"Unsigned integer object parsed as Size\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> >  \t\t/* Test double value */\n> >  \t\tauto &doubleObj = (*root)[\"double\"];\n> >\n> > -\t\tif (doubleObj.isDictionary()) {\n> > -\t\t\tcerr << \"Double object parse as Dictionary\" << std::endl;\n> > +\t\tif (testObjectType(doubleObj, \"double\", Type::Double) != TestPass)\n> >  \t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (doubleObj.isList()) {\n> > -\t\t\tcerr << \"Double object parse as List\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> >\n> >  \t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\" ||\n> >  \t\t    doubleObj.get<string>(\"\") != \"3.14159\") {\n> > @@ -294,53 +281,11 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (doubleObj.get<int32_t>()) {\n> > -\t\t\tcerr << \"Double object parse as integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (doubleObj.get<uint32_t>()) {\n> > -\t\t\tcerr << \"Double object parse as unsigned integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (doubleObj.get<Size>()) {\n> > -\t\t\tcerr << \"Double object parse as Size\" << 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 (sizeObj.isDictionary()) {\n> > -\t\t\tcerr << \"Size object parse as Dictionary\" << std::endl;\n> > +\t\tif (testObjectType(sizeObj, \"size\", Type::Size) != TestPass)\n> >  \t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (!sizeObj.isList()) {\n> > -\t\t\tcerr << \"Size object parse as List\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (sizeObj.get<string>()) {\n> > -\t\t\tcerr << \"Size object parse as string\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (sizeObj.get<double>()) {\n> > -\t\t\tcerr << \"Size object parse as double\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (sizeObj.get<int32_t>()) {\n> > -\t\t\tcerr << \"Size object parse as integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (sizeObj.get<uint32_t>()) {\n> > -\t\t\tcerr << \"Size object parse as unsigned integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\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> > @@ -351,40 +296,8 @@ protected:\n> >  \t\t/* Test list object */\n> >  \t\tauto &listObj = (*root)[\"list\"];\n> >\n> > -\t\tif (listObj.isDictionary()) {\n> > -\t\t\tcerr << \"List object parse as Dictionary\" << std::endl;\n> > +\t\tif (testObjectType(listObj, \"list\", Type::List) != TestPass)\n> >  \t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (!listObj.isList()) {\n> > -\t\t\tcerr << \"List object fail to parse as List\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (listObj.get<string>()) {\n> > -\t\t\tcerr << \"List object parse as string\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (listObj.get<double>()) {\n> > -\t\t\tcerr << \"List object parse as double\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (listObj.get<int32_t>()) {\n> > -\t\t\tcerr << \"List object parse as integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (listObj.get<uint32_t>()) {\n> > -\t\t\tcerr << \"List object parse as unsigne integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (listObj.get<Size>()) {\n> > -\t\t\tcerr << \"String list object parse as Size\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> >\n> >  \t\tstatic constexpr std::array<const char *, 2> listValues{\n> >  \t\t\t\"James\",\n> > @@ -424,40 +337,8 @@ protected:\n> >  \t\t/* Test dictionary object */\n> >  \t\tauto &dictObj = (*root)[\"dictionary\"];\n> >\n> > -\t\tif (!dictObj.isDictionary()) {\n> > -\t\t\tcerr << \"Dictionary object fail to parse as Dictionary\" << std::endl;\n> > +\t\tif (testObjectType(dictObj, \"dictionary\", Type::Dictionary) != TestPass)\n> >  \t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (dictObj.isList()) {\n> > -\t\t\tcerr << \"Dictionary object parse as List\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (dictObj.get<string>()) {\n> > -\t\t\tcerr << \"Dictionary object parse as string\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (dictObj.get<double>()) {\n> > -\t\t\tcerr << \"Dictionary object parse as double\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (dictObj.get<int32_t>()) {\n> > -\t\t\tcerr << \"Dictionary object parse as integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (dictObj.get<uint32_t>()) {\n> > -\t\t\tcerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> > -\n> > -\t\tif (dictObj.get<Size>()) {\n> > -\t\t\tcerr << \"Dictionary object parse as Size\" << std::endl;\n> > -\t\t\treturn TestFail;\n> > -\t\t}\n> >\n> >  \t\tstatic constexpr std::array<std::pair<const char *, int>, 3> dictValues{ {\n> >  \t\t\t{ \"a\", 1 },","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 480F6C3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 18 Aug 2022 15:02:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1232561FC0;\n\tThu, 18 Aug 2022 17:02:43 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id EDCBD61FA7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Aug 2022 17:02:41 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 73FFE8B;\n\tThu, 18 Aug 2022 17:02:41 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1660834963;\n\tbh=bEyCtzoo5eYKySPCAeXad4pafeqdvwNHMgmrySyGzdw=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=1sHrzdNAnCHFsdB+76ER5ykZgSjsWI7TDLfTz7wjD0MKqikj7Nu0qyqjPemCGpTur\n\taN0JqXQ1AjgbzviKuOjvcD4jCqzo+Ikm8nCaWIlmgd/c3yeiOC+VXtTcOEhsV8ooN9\n\tAlUyo0+ucFbjquvYh6gVIYsN7SjLM8SPXLBDPDSOY2RFWJ+bixKvwslPPATxIKkzpW\n\tQuFBMta2itRFm2ydlpSCzdPkG6XIRSMWbPD0ymvA8q5rpMucXwC9daI3mS2Qe7A234\n\t5I/reW/tDhIdupQ+dViQs3WROxoduABiIEVNkUXkHswSLbKawKaVFgZwILES4eBul1\n\tdA1xo+CpevYBg==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1660834961;\n\tbh=bEyCtzoo5eYKySPCAeXad4pafeqdvwNHMgmrySyGzdw=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=CMdpYlrQekR11ktUTPZFuiaof+w/ibVCUmrsD4Y8H5T1DsIaq6h2PUYfQLxiFXg2U\n\t9JsyaXW4uOZXxzKS8rjm6k5i88FsXBZEPzcQCZaQUhecUFx2APkiKe/1hAzd5MTB4Q\n\tHtl2N/yRP+EIsVKf9ottM52RLxoxNk2IsST/EyQI="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"CMdpYlrQ\"; dkim-atps=neutral","Date":"Thu, 18 Aug 2022 18:02:38 +0300","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<Yv5UjjhOTO+j4HLv@pendragon.ideasonboard.com>","References":"<20220816015414.7462-1-laurent.pinchart@ideasonboard.com>\n\t<20220816015414.7462-2-laurent.pinchart@ideasonboard.com>\n\t<20220818124713.gm4ckukrupk4xju7@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20220818124713.gm4ckukrupk4xju7@uno.localdomain>","Subject":"Re: [libcamera-devel] [PATCH v4 1/9] test: yaml-parser: Simplify\n\tcode by centralizing parse error checks","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24665,"web_url":"https://patchwork.libcamera.org/comment/24665/","msgid":"<20220818150638.uza56fsnhk3pjgwk@uno.localdomain>","date":"2022-08-18T15:06:38","subject":"Re: [libcamera-devel] [PATCH v4 1/9] test: yaml-parser: Simplify\n\tcode by centralizing parse error checks","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent\n\nOn Thu, Aug 18, 2022 at 06:02:38PM +0300, Laurent Pinchart wrote:\n> Hi Jacopo,\n>\n> On Thu, Aug 18, 2022 at 02:47:13PM +0200, Jacopo Mondi wrote:\n> > On Tue, Aug 16, 2022 at 04:54:06AM +0300, Laurent Pinchart via libcamera-devel wrote:\n> > > Centralize most parse failure checks in a single function to avoid a\n> > > larger number of copies of nearly identical checks.\n> > >\n> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> >\n> > This saves a lot of boilerplate indeed!\n> >\n> > > ---\n> > >  test/yaml-parser.cpp | 309 +++++++++++++------------------------------\n> > >  1 file changed, 95 insertions(+), 214 deletions(-)\n> > >\n> > > diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> > > index 93ba88b8bcd5..6729e1bd430e 100644\n> > > --- a/test/yaml-parser.cpp\n> > > +++ b/test/yaml-parser.cpp\n> > > @@ -72,6 +72,83 @@ protected:\n> > >  \t\treturn TestPass;\n> > >  \t}\n> > >\n> > > +\tenum class Type {\n> > > +\t\tString,\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 YamlObject &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 isInteger = type == Type::Int32 || type == Type::UInt32;\n> > > +\t\tbool isSigned = type == Type::Int32;\n> >\n> > Aren't double signed too ?\n>\n> Indeed. I could rename the variable to isSignedInteger if you want.\n>\n\nNo need for a rename, I was just making sure you were not leaving\ndouble unhandled.\n\n> > Anyway,\n> > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> >\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 (!isInteger && 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 ((!isInteger || 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 (!isInteger && 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 run()\n> > >  \t{\n> > >  \t\t/* Test invalid YAML file */\n> > > @@ -107,58 +184,24 @@ protected:\n> > >  \t\t\treturn TestFail;\n> > >  \t\t}\n> > >\n> > > -\t\tif (!root->contains(\"string\")) {\n> > > -\t\t\tcerr << \"Missing string object in YAML root\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (!root->contains(\"double\")) {\n> > > -\t\t\tcerr << \"Missing double object in YAML root\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (!root->contains(\"int32_t\")) {\n> > > -\t\t\tcerr << \"Missing int32_t object in YAML root\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (!root->contains(\"uint32_t\")) {\n> > > -\t\t\tcerr << \"Missing uint32_t object in YAML root\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (!root->contains(\"size\")) {\n> > > -\t\t\tcerr << \"Missing Size object in YAML root\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (!root->contains(\"list\")) {\n> > > -\t\t\tcerr << \"Missing list object in YAML root\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (!root->contains(\"dictionary\")) {\n> > > -\t\t\tcerr << \"Missing dictionary object in YAML root\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (!root->contains(\"level1\")) {\n> > > -\t\t\tcerr << \"Missing leveled object in YAML root\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > +\t\tstd::vector<const char *> rootElemNames = {\n> > > +\t\t\t\"string\", \"double\", \"int32_t\", \"uint32_t\", \"size\",\n> > > +\t\t\t\"list\", \"dictionary\", \"level1\",\n> > > +\t\t};\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\t\t\treturn TestFail;\n> > > +\t\t\t}\n> > >  \t\t}\n> > >\n> > >  \t\t/* Test string object */\n> > >  \t\tauto &strObj = (*root)[\"string\"];\n> > >\n> > > -\t\tif (strObj.isDictionary()) {\n> > > -\t\t\tcerr << \"String object parse as Dictionary\" << std::endl;\n> > > +\t\tif (testObjectType(strObj, \"string\", Type::String) != TestPass)\n> > >  \t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (strObj.isList()) {\n> > > -\t\t\tcerr << \"String object parse as List\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > >\n> > >  \t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\" ||\n> > >  \t\t    strObj.get<string>(\"\") != \"libcamera\") {\n> > > @@ -166,38 +209,11 @@ protected:\n> > >  \t\t\treturn TestFail;\n> > >  \t\t}\n> > >\n> > > -\t\tif (strObj.get<int32_t>()) {\n> > > -\t\t\tcerr << \"String object parse as integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (strObj.get<uint32_t>()) {\n> > > -\t\t\tcerr << \"String object parse as unsigned integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (strObj.get<double>()) {\n> > > -\t\t\tcerr << \"String object parse as double\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (strObj.get<Size>()) {\n> > > -\t\t\tcerr << \"String object parse as Size\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > >  \t\t/* Test int32_t object */\n> > >  \t\tauto &int32Obj = (*root)[\"int32_t\"];\n> > >\n> > > -\t\tif (int32Obj.isDictionary()) {\n> > > -\t\t\tcerr << \"Integer object parse as Dictionary\" << std::endl;\n> > > +\t\tif (testObjectType(int32Obj, \"int32_t\", Type::Int32) != TestPass)\n> > >  \t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (int32Obj.isList()) {\n> > > -\t\t\tcerr << \"Integer object parse as Integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > >\n> > >  \t\tif (int32Obj.get<int32_t>().value_or(0) != -100 ||\n> > >  \t\t    int32Obj.get<int32_t>(0) != -100) {\n> > > @@ -217,28 +233,11 @@ protected:\n> > >  \t\t\treturn TestFail;\n> > >  \t\t}\n> > >\n> > > -\t\tif (int32Obj.get<uint32_t>()) {\n> > > -\t\t\tcerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (int32Obj.get<Size>()) {\n> > > -\t\t\tcerr << \"Integer object parse as Size\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > >  \t\t/* Test uint32_t object */\n> > >  \t\tauto &uint32Obj = (*root)[\"uint32_t\"];\n> > >\n> > > -\t\tif (uint32Obj.isDictionary()) {\n> > > -\t\t\tcerr << \"Unsigned integer object parse as Dictionary\" << std::endl;\n> > > +\t\tif (testObjectType(uint32Obj, \"uint32_t\", Type::UInt32) != TestPass)\n> > >  \t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (uint32Obj.isList()) {\n> > > -\t\t\tcerr << \"Unsigned integer object parse as List\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > >\n> > >  \t\tif (uint32Obj.get<int32_t>().value_or(0) != 100 ||\n> > >  \t\t    uint32Obj.get<int32_t>(0) != 100) {\n> > > @@ -264,23 +263,11 @@ protected:\n> > >  \t\t\treturn TestFail;\n> > >  \t\t}\n> > >\n> > > -\t\tif (uint32Obj.get<Size>()) {\n> > > -\t\t\tcerr << \"Unsigned integer object parsed as Size\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > >  \t\t/* Test double value */\n> > >  \t\tauto &doubleObj = (*root)[\"double\"];\n> > >\n> > > -\t\tif (doubleObj.isDictionary()) {\n> > > -\t\t\tcerr << \"Double object parse as Dictionary\" << std::endl;\n> > > +\t\tif (testObjectType(doubleObj, \"double\", Type::Double) != TestPass)\n> > >  \t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (doubleObj.isList()) {\n> > > -\t\t\tcerr << \"Double object parse as List\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > >\n> > >  \t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\" ||\n> > >  \t\t    doubleObj.get<string>(\"\") != \"3.14159\") {\n> > > @@ -294,53 +281,11 @@ protected:\n> > >  \t\t\treturn TestFail;\n> > >  \t\t}\n> > >\n> > > -\t\tif (doubleObj.get<int32_t>()) {\n> > > -\t\t\tcerr << \"Double object parse as integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (doubleObj.get<uint32_t>()) {\n> > > -\t\t\tcerr << \"Double object parse as unsigned integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (doubleObj.get<Size>()) {\n> > > -\t\t\tcerr << \"Double object parse as Size\" << 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 (sizeObj.isDictionary()) {\n> > > -\t\t\tcerr << \"Size object parse as Dictionary\" << std::endl;\n> > > +\t\tif (testObjectType(sizeObj, \"size\", Type::Size) != TestPass)\n> > >  \t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (!sizeObj.isList()) {\n> > > -\t\t\tcerr << \"Size object parse as List\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (sizeObj.get<string>()) {\n> > > -\t\t\tcerr << \"Size object parse as string\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (sizeObj.get<double>()) {\n> > > -\t\t\tcerr << \"Size object parse as double\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (sizeObj.get<int32_t>()) {\n> > > -\t\t\tcerr << \"Size object parse as integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (sizeObj.get<uint32_t>()) {\n> > > -\t\t\tcerr << \"Size object parse as unsigned integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\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> > > @@ -351,40 +296,8 @@ protected:\n> > >  \t\t/* Test list object */\n> > >  \t\tauto &listObj = (*root)[\"list\"];\n> > >\n> > > -\t\tif (listObj.isDictionary()) {\n> > > -\t\t\tcerr << \"List object parse as Dictionary\" << std::endl;\n> > > +\t\tif (testObjectType(listObj, \"list\", Type::List) != TestPass)\n> > >  \t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (!listObj.isList()) {\n> > > -\t\t\tcerr << \"List object fail to parse as List\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (listObj.get<string>()) {\n> > > -\t\t\tcerr << \"List object parse as string\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (listObj.get<double>()) {\n> > > -\t\t\tcerr << \"List object parse as double\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (listObj.get<int32_t>()) {\n> > > -\t\t\tcerr << \"List object parse as integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (listObj.get<uint32_t>()) {\n> > > -\t\t\tcerr << \"List object parse as unsigne integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (listObj.get<Size>()) {\n> > > -\t\t\tcerr << \"String list object parse as Size\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > >\n> > >  \t\tstatic constexpr std::array<const char *, 2> listValues{\n> > >  \t\t\t\"James\",\n> > > @@ -424,40 +337,8 @@ protected:\n> > >  \t\t/* Test dictionary object */\n> > >  \t\tauto &dictObj = (*root)[\"dictionary\"];\n> > >\n> > > -\t\tif (!dictObj.isDictionary()) {\n> > > -\t\t\tcerr << \"Dictionary object fail to parse as Dictionary\" << std::endl;\n> > > +\t\tif (testObjectType(dictObj, \"dictionary\", Type::Dictionary) != TestPass)\n> > >  \t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (dictObj.isList()) {\n> > > -\t\t\tcerr << \"Dictionary object parse as List\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (dictObj.get<string>()) {\n> > > -\t\t\tcerr << \"Dictionary object parse as string\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (dictObj.get<double>()) {\n> > > -\t\t\tcerr << \"Dictionary object parse as double\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (dictObj.get<int32_t>()) {\n> > > -\t\t\tcerr << \"Dictionary object parse as integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (dictObj.get<uint32_t>()) {\n> > > -\t\t\tcerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > > -\n> > > -\t\tif (dictObj.get<Size>()) {\n> > > -\t\t\tcerr << \"Dictionary object parse as Size\" << std::endl;\n> > > -\t\t\treturn TestFail;\n> > > -\t\t}\n> > >\n> > >  \t\tstatic constexpr std::array<std::pair<const char *, int>, 3> dictValues{ {\n> > >  \t\t\t{ \"a\", 1 },\n>\n> --\n> Regards,\n>\n> Laurent Pinchart","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 78A9EBE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 18 Aug 2022 15:06:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2843861FBC;\n\tThu, 18 Aug 2022 17:06:43 +0200 (CEST)","from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net\n\t[217.70.183.196])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8FDFC61FA7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Aug 2022 17:06:41 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id C703CE0005;\n\tThu, 18 Aug 2022 15:06:40 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1660835203;\n\tbh=Jw//Wdpb98jcEehiOSNtj4E4me6scEhR2xbGRegW5LY=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=FmlRGuByOnsQlX+Z7nnW42BP0f5wKEH4rJgbPoW6SCPLHbC9pf9TNuvrxzcXvbAu3\n\tOS3a0wJvpGvjcjsbAebFohLqxoyYIqtU5ZzmO5NGdxxQuBaQXnStATCICQdVgrOnOL\n\t4QhWAVL2yEq2fnGUbjF/vxpUw48rqzCbWruoiaVCA8GBpuUcSr9i4RDNKGCM7+MWOW\n\tQSg4TErTnrbh8SShNgRy56SzJKCCNglMmT3BTvGQaaPwEdxUIV39HOH3VxmLpxaX2F\n\tcMynuZ9ZVFfa7Ra/z7ZSOnQ7noJ4e1CCMWt0nNiCrSDaLSnmsfAuzO8aWGzNLq9kWL\n\txe0JYaNbNrSFA==","Date":"Thu, 18 Aug 2022 17:06:38 +0200","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20220818150638.uza56fsnhk3pjgwk@uno.localdomain>","References":"<20220816015414.7462-1-laurent.pinchart@ideasonboard.com>\n\t<20220816015414.7462-2-laurent.pinchart@ideasonboard.com>\n\t<20220818124713.gm4ckukrupk4xju7@uno.localdomain>\n\t<Yv5UjjhOTO+j4HLv@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<Yv5UjjhOTO+j4HLv@pendragon.ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v4 1/9] test: yaml-parser: Simplify\n\tcode by centralizing parse error checks","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>","From":"Jacopo Mondi via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]