[{"id":22803,"web_url":"https://patchwork.libcamera.org/comment/22803/","msgid":"<YmiaJ0iAhJjCkJRu@pendragon.ideasonboard.com>","date":"2022-04-27T01:19:35","subject":"Re: [libcamera-devel] [PATCH v5 2/3] test: Add YamlParser test","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Han-Lin,\n\nThank you for the patch.\n\nOn Mon, Apr 25, 2022 at 10:46:16PM +0800, Han-Lin Chen via libcamera-devel wrote:\n> Add a unit test to exercise the API of the YamlParser class.\n> \n> Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>\n> ---\n>  test/meson.build     |   1 +\n>  test/yaml-parser.cpp | 496 +++++++++++++++++++++++++++++++++++++++++++\n>  2 files changed, 497 insertions(+)\n>  create mode 100644 test/yaml-parser.cpp\n> \n> diff --git a/test/meson.build b/test/meson.build\n> index fd4c5ca0..9c68fae1 100644\n> --- a/test/meson.build\n> +++ b/test/meson.build\n> @@ -54,6 +54,7 @@ internal_tests = [\n>      ['timer-thread',                    'timer-thread.cpp'],\n>      ['unique-fd',                       'unique-fd.cpp'],\n>      ['utils',                           'utils.cpp'],\n> +    ['yaml-parser',                     'yaml-parser.cpp'],\n>  ]\n>  \n>  internal_non_parallel_tests = [\n> diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> new file mode 100644\n> index 00000000..b9122287\n> --- /dev/null\n> +++ b/test/yaml-parser.cpp\n> @@ -0,0 +1,496 @@\n> +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> +/*\n> + * Copyright (C) 2022, Google Inc.\n> + *\n> + * yaml-parser.cpp - YAML parser operations tests\n> + */\n> +\n> +#include <iostream>\n> +#include <string>\n> +#include <unistd.h>\n> +\n> +#include <libcamera/internal/yaml_parser.h>\n> +\n> +#include \"test.h\"\n> +\n> +using namespace std;\n> +using namespace libcamera;\n\nAlphabetically sorted please.\n\n> +\n> +static const string testYaml =\n> +\t\"string: libcamera\\n\"\n> +\t\"double: 3.14159\\n\"\n> +\t\"uint32_t: 100\\n\"\n> +\t\"int32_t: -100\\n\"\n> +\t\"size: [1920, 1080]\\n\"\n> +\t\"list:\\n\"\n> +\t\"  - James\\n\"\n> +\t\"  - Mary\\n\"\n> +\t\"dictionary:\\n\"\n> +\t\"  a: 1\\n\"\n> +\t\"  b: 2\\n\"\n> +\t\"  c: 3\\n\"\n> +\t\"level1:\\n\"\n> +\t\"  level2:\\n\"\n> +\t\"    - [1, 2]\\n\"\n> +\t\"    - {one: 1, two: 2}\\n\";\n> +\n> +static const string invalidYaml =\n> +\t\"Invalid : - YAML : - Content\";\n> +\n> +class YamlParserTest : public Test\n> +{\n> +protected:\n> +\tbool createFile(const string &content, string &filename)\n> +\t{\n> +\t\tfilename = \"/tmp/libcamera.test.XXXXXX\";\n> +\t\tint fd = mkstemp(&filename.front());\n> +\t\tif (fd == -1)\n> +\t\t\treturn false;\n> +\n> +\t\tFILE *fh = fdopen(fd, \"w\");\n> +\t\tfputs(content.c_str(), fh);\n> +\n> +\t\tfclose(fh);\n> +\n> +\t\treturn true;\n> +\t}\n> +\n> +\tint init()\n> +\t{\n> +\t\tif (!createFile(testYaml, testYamlFile_))\n> +\t\t\treturn TestFail;\n> +\n> +\t\tif (!createFile(invalidYaml, invalidYamlFile_))\n> +\t\t\treturn TestFail;\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +\tint run()\n> +\t{\n> +\t\t/* Test invalid YAML file */\n> +\t\tFILE *fh = fopen(invalidYamlFile_.c_str(), \"r\");\n> +\t\tif (!fh) {\n> +\t\t\tcerr << \"Fail to open invalid YAML file\";\n\nMissing std::endl at the end of the line. Same below.\n\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tstd::unique_ptr<YamlObject> root = YamlParser::parse(fh);\n> +\n> +\t\tif (root) {\n> +\t\t\tcerr << \"Invalid YAML file parse successfully\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tfclose(fh);\n\nYou can move this right after parse(). Same below.\n\n> +\n> +\t\t/* Test YAML file */\n> +\t\tfh = fopen(testYamlFile_.c_str(), \"r\");\n> +\t\tif (!fh) {\n> +\t\t\tcerr << \"Fail to open test YAML file\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\troot = YamlParser::parse(fh);\n> +\n> +\t\tif (!root) {\n> +\t\t\tcerr << \"Fail to parse test YAML file: \";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tfclose(fh);\n> +\n> +\t\tif (!(*root).isDictionary()) {\n\n\t\tif (!root->isDictionary()) {\n\nis more readable. Same below.\n\n> +\t\t\tcerr << \"YAML root is not dictionary\";\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\";\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\";\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\";\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\";\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\";\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\";\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\";\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\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Test string object */\n> +\t\tbool ok;\n> +\t\tauto &strObj = (*root)[\"string\"];\n> +\n> +\t\tif (strObj.isDictionary()) {\n> +\t\t\tcerr << \"String object parse as Dictionary\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (strObj.isList()) {\n> +\t\t\tcerr << \"String object parse as List\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> +\t\t\tcerr << \"String object parse as wrong content\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\t\tcerr << \"String object parse as integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\t\tcerr << \"String object parse as unsigned integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\t\tcerr << \"String object parse as double\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\t\tcerr << \"String object parse as Size\";\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\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (int32Obj.isList()) {\n> +\t\t\tcerr << \"Integer object parse as Integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n> +\t\t\tcerr << \"Integer object parse as wrong value\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n> +\t\t\tcerr << \"Integer object fail to parse as string\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n> +\t\t\tcerr << \"Integer object fail to parse as double\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\t\tcerr << \"Negative integer object parse as unsigned integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\t\tcerr << \"Integer object parse as Size\";\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\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (uint32Obj.isList()) {\n> +\t\t\tcerr << \"Unsigned integer object parse as List\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n> +\t\t\tcerr << \"Unsigned integer object fail to parse as integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n> +\t\t\tcerr << \"Unsigned integer object fail to parse as string\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n> +\t\t\tcerr << \"Unsigned integer object fail to parse as double\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n> +\t\t\tcerr << \"Unsigned integer object parsed as wrong value\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\t\tcerr << \"Unsigned integer object parsed as Size\";\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\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (doubleObj.isList()) {\n> +\t\t\tcerr << \"Double object parse as List\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n> +\t\t\tcerr << \"Double object fail to parse as string\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n> +\t\t\tcerr << \"Double object parse as wrong value\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\t\tcerr << \"Double object parse as integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\t\tcerr << \"Double object parse as unsigned integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\t\tcerr << \"Double object parse as Size\";\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\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (!sizeObj.isList()) {\n> +\t\t\tcerr << \"Size object parse as List\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n> +\t\t\tcerr << \"Size object parse as string\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\t\tcerr << \"Size object parse as double\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\t\tcerr << \"Size object parse as integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\t\tcerr << \"Size object parse as unsigned integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n> +\t\t\tcerr << \"Size object parse as wrong value\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\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\";\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\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n> +\t\t\tcerr << \"List object parse as string\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\t\tcerr << \"List object parse as double\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\t\tcerr << \"List object parse as integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\t\tcerr << \"List object parse as unsigne integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\t\tcerr << \"String list object parse as Size\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (listObj.size() > 2) {\n> +\t\t\tcerr << \"List object parse with wrong size\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (listObj[0].get<string>(\"\") != \"James\" ||\n> +\t\t    listObj[1].get<string>(\"\") != \"Mary\") {\n> +\t\t\tcerr << \"List object parse as wrong value\";\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 (!dictObj.isDictionary()) {\n> +\t\t\tcerr << \"Dictionary object fail to parse as Dictionary\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (dictObj.isList()) {\n> +\t\t\tcerr << \"Dictionary object parse as List\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n> +\t\t\tcerr << \"Dictionary object parse as string\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\t\tcerr << \"Dictionary object parse as double\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\t\tcerr << \"Dictionary object parse as integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\t\tcerr << \"Dictionary object parse as unsigned integer\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\t\tcerr << \"Dictionary object parse as Size\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tauto memeberNames = dictObj.getMemberNames();\n> +\t\tsort(memeberNames.begin(), memeberNames.end());\n> +\n> +\t\tif (memeberNames.size() != 3) {\n> +\t\t\tcerr << \"Dictionary object fail to extra member names\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (memeberNames[0] != \"a\" ||\n> +\t\t    memeberNames[1] != \"b\" ||\n> +\t\t    memeberNames[2] != \"c\") {\n> +\t\t\tcerr << \"Dictionary object fail to parse member names\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (dictObj[\"a\"].get<int32_t>(0) != 1 ||\n> +\t\t    dictObj[\"b\"].get<int32_t>(0) != 2 ||\n> +\t\t    dictObj[\"c\"].get<int32_t>(0) != 3) {\n> +\t\t\tcerr << \"Dictionary object fail to parse member value\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Test leveled objects */\n> +\t\tauto &level1Obj = (*root)[\"level1\"];\n> +\n> +\t\tif (!level1Obj.isDictionary()) {\n> +\t\t\tcerr << \"level1 object fail to parse as Dictionary\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\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\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tauto &firstElement = level2Obj[0];\n> +\t\tif (!firstElement.isList() ||\n> +\t\t    firstElement.size() != 2 ||\n> +\t\t    firstElement[0].get<int32_t>(0) != 1 ||\n> +\t\t    firstElement[1].get<int32_t>(0) != 2) {\n> +\t\t\tcerr << \"The first element of level2 object fail to pars as integer list\";\n\ns/pars/parse/\n\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tauto &secondElement = level2Obj[1];\n> +\t\tif (!secondElement.isDictionary() ||\n> +\t\t    !secondElement.contains(\"one\") ||\n> +\t\t    !secondElement.contains(\"two\") ||\n> +\t\t    secondElement[\"one\"].get<int32_t>(0) != 1 ||\n> +\t\t    secondElement[\"two\"].get<int32_t>(0) != 2) {\n> +\t\t\tcerr << \"The second element of level2 object fail to pases as dictionary\";\n\ns/pases/parse/\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +\tvoid cleanup()\n> +\t{\n> +\t\tunlink(testYamlFile_.c_str());\n> +\t\tunlink(invalidYamlFile_.c_str());\n> +\t}\n> +\n> +private:\n> +\tstd::string testYamlFile_;\n> +\tstd::string invalidYamlFile_;\n> +};\n> +\n> +TEST_REGISTER(YamlParserTest)","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 D8D3BC3256\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 27 Apr 2022 01:19:38 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 43FB865645;\n\tWed, 27 Apr 2022 03:19:38 +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 C6F01604A6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Apr 2022 03:19:36 +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 0BFEE30B;\n\tWed, 27 Apr 2022 03:19:35 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1651022378;\n\tbh=a86hcIaUvQi0dDkfs+945Vh+yZJDhdSmetS4Roh09aQ=;\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=Txu9y7kpJidd3UlTVI29jiQKVIYgZ3ZiK/W26hb4E2ccbhXf40atTs8mby7nxuEsF\n\trBcRPVvBEGCiQVBq+mZZ6Pss6OSWmsfsUonulhIpr+ALohMAwlfbqZdcoP0KJDPE4A\n\t3HBu7lcQSOf35Awo9gLiErtW8IHDpxDNit7SaYbBrv+B5skf8mQKA1h3rx6EvpPMRS\n\tpZcEs0FzeVJRHd4ylRNWIjg7FK8UBfFSGtE48kHyfM7tS757QSXBneow7LPHO/zxAg\n\tf/ljoRF8H18P4llJsjYK+iRsP0m1539QQDe0+z+mXv+hqYKq64glyK1WfC/JqUYU2U\n\tOl5nHQVRmrO7A==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1651022376;\n\tbh=a86hcIaUvQi0dDkfs+945Vh+yZJDhdSmetS4Roh09aQ=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=YNduSMLPvrL2/2XGLpyupFUMJgOIF0Wrd3/oydBg6J1lGvd1Y5dH8TUK8qYpuX2cO\n\t8A0p6ci4LUw0nW4V2oM7zU+8W4QzlUb+2oqvioPW2F6DY/YFr82uEs5k2/CMRaj5NN\n\t4a5hql8WoQE9dY6fxV+9x+gZZPIUIad4/8vKP1Js="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"YNduSMLP\"; dkim-atps=neutral","Date":"Wed, 27 Apr 2022 04:19:35 +0300","To":"Han-Lin Chen <hanlinchen@chromium.org>","Message-ID":"<YmiaJ0iAhJjCkJRu@pendragon.ideasonboard.com>","References":"<20220425144617.2549778-1-hanlinchen@chromium.org>\n\t<20220425144617.2549778-3-hanlinchen@chromium.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20220425144617.2549778-3-hanlinchen@chromium.org>","Subject":"Re: [libcamera-devel] [PATCH v5 2/3] test: Add YamlParser test","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>"}}]