Patch Detail
Show a patch.
GET /api/patches/12507/?format=api
{ "id": 12507, "url": "https://patchwork.libcamera.org/api/patches/12507/?format=api", "web_url": "https://patchwork.libcamera.org/patch/12507/", "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": "<20210607181506.51711-5-nfraprado@collabora.com>", "date": "2021-06-07T18:15:05", "name": "[libcamera-devel,v6,4/5] lc-compliance: Refactor using Googletest", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "a71e5657a20ccc73c19849d35c542c55c3037eb3", "submitter": { "id": 84, "url": "https://patchwork.libcamera.org/api/people/84/?format=api", "name": "Nícolas F. R. A. Prado", "email": "nfraprado@collabora.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/12507/mbox/", "series": [ { "id": 2108, "url": "https://patchwork.libcamera.org/api/series/2108/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=2108", "date": "2021-06-07T18:15:01", "name": "lc-compliance: Refactor using Googletest", "version": 6, "mbox": "https://patchwork.libcamera.org/series/2108/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/12507/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/12507/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 64D8EC320B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 7 Jun 2021 18:16:15 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2E4DF6892E;\n\tMon, 7 Jun 2021 20:16:15 +0200 (CEST)", "from bhuna.collabora.co.uk (bhuna.collabora.co.uk\n\t[IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D13EC602A7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 7 Jun 2021 20:16:13 +0200 (CEST)", "from localhost.localdomain (unknown\n\t[IPv6:2804:14c:1a9:2978:d3df:ab8:a31a:aacc])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128\n\tbits))\n\t(No client certificate requested) (Authenticated sender: nfraprado)\n\tby bhuna.collabora.co.uk (Postfix) with ESMTPSA id 639531F422E0;\n\tMon, 7 Jun 2021 19:16:11 +0100 (BST)" ], "From": "=?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= <nfraprado@collabora.com>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Mon, 7 Jun 2021 15:15:05 -0300", "Message-Id": "<20210607181506.51711-5-nfraprado@collabora.com>", "X-Mailer": "git-send-email 2.31.1", "In-Reply-To": "<20210607181506.51711-1-nfraprado@collabora.com>", "References": "<20210607181506.51711-1-nfraprado@collabora.com>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v6 4/5] lc-compliance: Refactor using\n\tGoogletest", "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>", "Cc": "kernel@collabora.com, =?utf-8?q?Andr=C3=A9_Almeida?=\n\t<andrealmeid@collabora.com>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Refactor lc-compliance using Googletest as the test framework.\n\nSigned-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\nNo changes in v6\n\nChanges in v5:\n- Thanks to Laurent:\n - Fixed style issues\n - Added SetUp and TearDown functions to acquire and release the camera for\n each test\n\nChanges in v4:\n- Removed old lc-compliance results classes\n- Thanks to Niklas:\n - Improved naming of tests\n\nChanges in v3:\n- Thanks to Niklas:\n - Went back to static test registration, and created a Singleton Environment\n class to store the camera global variable\n- Added a nameParameters() function to give meaningful names to the test\n parameters, removing the need to register each test suite for every role\n\n src/lc-compliance/main.cpp | 77 ++++++------\n src/lc-compliance/meson.build | 4 +-\n src/lc-compliance/results.cpp | 75 ------------\n src/lc-compliance/results.h | 47 --------\n src/lc-compliance/simple_capture.cpp | 74 +++++-------\n src/lc-compliance/simple_capture.h | 9 +-\n src/lc-compliance/single_stream.cpp | 174 ++++++++++++++++-----------\n src/lc-compliance/tests.h | 16 ---\n 8 files changed, 177 insertions(+), 299 deletions(-)\n delete mode 100644 src/lc-compliance/results.cpp\n delete mode 100644 src/lc-compliance/results.h\n delete mode 100644 src/lc-compliance/tests.h", "diff": "diff --git a/src/lc-compliance/main.cpp b/src/lc-compliance/main.cpp\nindex 54cee54aa978..27503372d0eb 100644\n--- a/src/lc-compliance/main.cpp\n+++ b/src/lc-compliance/main.cpp\n@@ -9,10 +9,12 @@\n #include <iostream>\n #include <string.h>\n \n+#include <gtest/gtest.h>\n+\n #include <libcamera/libcamera.h>\n \n+#include \"environment.h\"\n #include \"../cam/options.h\"\n-#include \"tests.h\"\n \n using namespace libcamera;\n \n@@ -21,60 +23,52 @@ enum {\n \tOptHelp = 'h',\n };\n \n+/*\n+ * Make asserts act like exceptions, otherwise they only fail (or skip) the\n+ * current function. From gtest documentation:\n+ * https://google.github.io/googletest/advanced.html#asserting-on-subroutines-with-an-exception\n+ */\n+class ThrowListener : public testing::EmptyTestEventListener\n+{\n+\tvoid OnTestPartResult(const testing::TestPartResult &result) override\n+\t{\n+\t\tif (result.type() == testing::TestPartResult::kFatalFailure ||\n+\t\t result.type() == testing::TestPartResult::kSkip)\n+\t\t\tthrow testing::AssertionException(result);\n+\t}\n+};\n+\n class Harness\n {\n public:\n \tHarness(const OptionsParser::Options &options);\n \t~Harness();\n \n-\tint exec();\n+\tint init();\n+\tint run(int argc, char **argv);\n \n private:\n-\tint init();\n \tvoid listCameras();\n \n \tOptionsParser::Options options_;\n-\tstd::unique_ptr<CameraManager> cm_;\n-\tstd::shared_ptr<Camera> camera_;\n+\tstd::shared_ptr<CameraManager> cm_;\n };\n \n Harness::Harness(const OptionsParser::Options &options)\n \t: options_(options)\n {\n-\tcm_ = std::make_unique<CameraManager>();\n+\tcm_ = std::make_shared<CameraManager>();\n }\n \n Harness::~Harness()\n {\n-\tif (camera_) {\n-\t\tcamera_->release();\n-\t\tcamera_.reset();\n-\t}\n-\n \tcm_->stop();\n }\n \n-int Harness::exec()\n-{\n-\tint ret = init();\n-\tif (ret)\n-\t\treturn ret;\n-\n-\tstd::vector<Results> results;\n-\n-\tresults.push_back(testSingleStream(camera_));\n-\n-\tfor (const Results &result : results) {\n-\t\tret = result.summary();\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\t}\n-\n-\treturn 0;\n-}\n-\n int Harness::init()\n {\n+\tstd::shared_ptr<Camera> camera;\n+\n \tint ret = cm_->start();\n \tif (ret) {\n \t\tstd::cout << \"Failed to start camera manager: \"\n@@ -89,23 +83,29 @@ int Harness::init()\n \t}\n \n \tconst std::string &cameraId = options_[OptCamera];\n-\tcamera_ = cm_->get(cameraId);\n-\tif (!camera_) {\n+\tcamera = cm_->get(cameraId);\n+\tif (!camera) {\n \t\tstd::cout << \"Camera \" << cameraId << \" not found, available cameras:\" << std::endl;\n \t\tlistCameras();\n \t\treturn -ENODEV;\n \t}\n \n-\tif (camera_->acquire()) {\n-\t\tstd::cout << \"Failed to acquire camera\" << std::endl;\n-\t\treturn -EINVAL;\n-\t}\n+\tEnvironment::get()->setup(cm_, cameraId);\n \n \tstd::cout << \"Using camera \" << cameraId << std::endl;\n \n \treturn 0;\n }\n \n+int Harness::run(int argc, char **argv)\n+{\n+\t::testing::InitGoogleTest(&argc, argv);\n+\n+\ttesting::UnitTest::GetInstance()->listeners().Append(new ThrowListener);\n+\n+\treturn RUN_ALL_TESTS();\n+}\n+\n void Harness::listCameras()\n {\n \tfor (const std::shared_ptr<Camera> &cam : cm_->cameras())\n@@ -143,6 +143,9 @@ int main(int argc, char **argv)\n \t\treturn EXIT_FAILURE;\n \n \tHarness harness(options);\n+\tret = harness.init();\n+\tif (ret)\n+\t\treturn ret;\n \n-\treturn harness.exec() ? EXIT_FAILURE : EXIT_SUCCESS;\n+\treturn harness.run(argc, argv);\n }\ndiff --git a/src/lc-compliance/meson.build b/src/lc-compliance/meson.build\nindex 6dd49085569f..156b938ee9ad 100644\n--- a/src/lc-compliance/meson.build\n+++ b/src/lc-compliance/meson.build\n@@ -14,15 +14,17 @@ lc_compliance_sources = files([\n '../cam/options.cpp',\n 'environment.cpp',\n 'main.cpp',\n- 'results.cpp',\n 'simple_capture.cpp',\n 'single_stream.cpp',\n ])\n \n+libgtest = dependency('gtest')\n+\n lc_compliance = executable('lc-compliance', lc_compliance_sources,\n dependencies : [\n libatomic,\n libcamera_dep,\n libevent,\n+ libgtest,\n ],\n install : true)\ndiff --git a/src/lc-compliance/results.cpp b/src/lc-compliance/results.cpp\ndeleted file mode 100644\nindex f149f7859e28..000000000000\n--- a/src/lc-compliance/results.cpp\n+++ /dev/null\n@@ -1,75 +0,0 @@\n-/* SPDX-License-Identifier: GPL-2.0-or-later */\n-/*\n- * Copyright (C) 2020, Google Inc.\n- *\n- * results.cpp - Test result aggregator\n- */\n-\n-#include \"results.h\"\n-\n-#include <iostream>\n-\n-void Results::add(const Result &result)\n-{\n-\tif (result.first == Pass)\n-\t\tpassed_++;\n-\telse if (result.first == Fail)\n-\t\tfailed_++;\n-\telse if (result.first == Skip)\n-\t\tskipped_++;\n-\n-\tprintResult(result);\n-}\n-\n-void Results::add(Status status, const std::string &message)\n-{\n-\tadd({ status, message });\n-}\n-\n-void Results::fail(const std::string &message)\n-{\n-\tadd(Fail, message);\n-}\n-\n-void Results::pass(const std::string &message)\n-{\n-\tadd(Pass, message);\n-}\n-\n-void Results::skip(const std::string &message)\n-{\n-\tadd(Skip, message);\n-}\n-\n-int Results::summary() const\n-{\n-\tif (failed_ + passed_ + skipped_ != planned_) {\n-\t\tstd::cout << \"Planned and executed number of tests differ \"\n-\t\t\t << failed_ + passed_ + skipped_ << \" executed \"\n-\t\t\t << planned_ << \" planned\" << std::endl;\n-\n-\t\treturn -EINVAL;\n-\t}\n-\n-\tstd::cout << planned_ << \" tests executed, \"\n-\t\t << passed_ << \" tests passed, \"\n-\t\t << skipped_ << \" tests skipped and \"\n-\t\t << failed_ << \" tests failed \" << std::endl;\n-\n-\treturn 0;\n-}\n-\n-void Results::printResult(const Result &result)\n-{\n-\tstd::string prefix;\n-\n-\t/* \\todo Make parsable as TAP. */\n-\tif (result.first == Pass)\n-\t\tprefix = \"PASS\";\n-\telse if (result.first == Fail)\n-\t\tprefix = \"FAIL\";\n-\telse if (result.first == Skip)\n-\t\tprefix = \"SKIP\";\n-\n-\tstd::cout << \"- \" << prefix << \": \" << result.second << std::endl;\n-}\ndiff --git a/src/lc-compliance/results.h b/src/lc-compliance/results.h\ndeleted file mode 100644\nindex 2a3722b841a6..000000000000\n--- a/src/lc-compliance/results.h\n+++ /dev/null\n@@ -1,47 +0,0 @@\n-/* SPDX-License-Identifier: GPL-2.0-or-later */\n-/*\n- * Copyright (C) 2020, Google Inc.\n- *\n- * results.h - Test result aggregator\n- */\n-#ifndef __LC_COMPLIANCE_RESULTS_H__\n-#define __LC_COMPLIANCE_RESULTS_H__\n-\n-#include <string>\n-#include <utility>\n-\n-/* \\todo Check if result aggregator can be shared with self tests in test/ */\n-class Results\n-{\n-public:\n-\tenum Status {\n-\t\tFail,\n-\t\tPass,\n-\t\tSkip,\n-\t};\n-\n-\tusing Result = std::pair<Status, std::string>;\n-\n-\tResults(unsigned int planned)\n-\t\t: planned_(planned), passed_(0), failed_(0), skipped_(0)\n-\t{\n-\t}\n-\n-\tvoid add(const Result &result);\n-\tvoid add(Status status, const std::string &message);\n-\tvoid fail(const std::string &message);\n-\tvoid pass(const std::string &message);\n-\tvoid skip(const std::string &message);\n-\n-\tint summary() const;\n-\n-private:\n-\tvoid printResult(const Result &result);\n-\n-\tunsigned int planned_;\n-\tunsigned int passed_;\n-\tunsigned int failed_;\n-\tunsigned int skipped_;\n-};\n-\n-#endif /* __LC_COMPLIANCE_RESULTS_H__ */\ndiff --git a/src/lc-compliance/simple_capture.cpp b/src/lc-compliance/simple_capture.cpp\nindex f90fe6d0f9aa..7731eb16f8c2 100644\n--- a/src/lc-compliance/simple_capture.cpp\n+++ b/src/lc-compliance/simple_capture.cpp\n@@ -5,6 +5,8 @@\n * simple_capture.cpp - Simple capture helper\n */\n \n+#include <gtest/gtest.h>\n+\n #include \"simple_capture.h\"\n \n using namespace libcamera;\n@@ -20,38 +22,34 @@ SimpleCapture::~SimpleCapture()\n \tstop();\n }\n \n-Results::Result SimpleCapture::configure(StreamRole role)\n+void SimpleCapture::configure(StreamRole role)\n {\n \tconfig_ = camera_->generateConfiguration({ role });\n \n-\tif (!config_)\n-\t\treturn { Results::Skip, \"Role not supported by camera\" };\n+\tif (!config_) {\n+\t\tstd::cout << \"Role not supported by camera\" << std::endl;\n+\t\tGTEST_SKIP();\n+\t}\n \n \tif (config_->validate() != CameraConfiguration::Valid) {\n \t\tconfig_.reset();\n-\t\treturn { Results::Fail, \"Configuration not valid\" };\n+\t\tFAIL() << \"Configuration not valid\";\n \t}\n \n \tif (camera_->configure(config_.get())) {\n \t\tconfig_.reset();\n-\t\treturn { Results::Fail, \"Failed to configure camera\" };\n+\t\tFAIL() << \"Failed to configure camera\";\n \t}\n-\n-\treturn { Results::Pass, \"Configure camera\" };\n }\n \n-Results::Result SimpleCapture::start()\n+void SimpleCapture::start()\n {\n \tStream *stream = config_->at(0).stream();\n-\tif (allocator_->allocate(stream) < 0)\n-\t\treturn { Results::Fail, \"Failed to allocate buffers\" };\n+\tASSERT_GE(allocator_->allocate(stream), 0) << \"Failed to allocate buffers\";\n \n-\tif (camera_->start())\n-\t\treturn { Results::Fail, \"Failed to start camera\" };\n+\tASSERT_TRUE(!camera_->start()) << \"Failed to start camera\";\n \n \tcamera_->requestCompleted.connect(this, &SimpleCapture::requestComplete);\n-\n-\treturn { Results::Pass, \"Started camera\" };\n }\n \n void SimpleCapture::stop()\n@@ -77,22 +75,19 @@ SimpleCaptureBalanced::SimpleCaptureBalanced(std::shared_ptr<Camera> camera)\n {\n }\n \n-Results::Result SimpleCaptureBalanced::capture(unsigned int numRequests)\n+void SimpleCaptureBalanced::capture(unsigned int numRequests)\n {\n-\tResults::Result ret = start();\n-\tif (ret.first != Results::Pass)\n-\t\treturn ret;\n+\tstart();\n \n \tStream *stream = config_->at(0).stream();\n \tconst std::vector<std::unique_ptr<FrameBuffer>> &buffers = allocator_->buffers(stream);\n \n \t/* No point in testing less requests then the camera depth. */\n \tif (buffers.size() > numRequests) {\n-\t\t/* Cache buffers.size() before we destroy it in stop() */\n-\t\tint buffers_size = buffers.size();\n-\n-\t\treturn { Results::Skip, \"Camera needs \" + std::to_string(buffers_size)\n-\t\t\t+ \" requests, can't test only \" + std::to_string(numRequests) };\n+\t\tstd::cout << \"Camera needs \" + std::to_string(buffers.size())\n+\t\t\t+ \" requests, can't test only \"\n+\t\t\t+ std::to_string(numRequests) << std::endl;\n+\t\tGTEST_SKIP();\n \t}\n \n \tqueueCount_ = 0;\n@@ -103,14 +98,11 @@ Results::Result SimpleCaptureBalanced::capture(unsigned int numRequests)\n \tstd::vector<std::unique_ptr<libcamera::Request>> requests;\n \tfor (const std::unique_ptr<FrameBuffer> &buffer : buffers) {\n \t\tstd::unique_ptr<Request> request = camera_->createRequest();\n-\t\tif (!request)\n-\t\t\treturn { Results::Fail, \"Can't create request\" };\n+\t\tASSERT_TRUE(request) << \"Can't create request\";\n \n-\t\tif (request->addBuffer(stream, buffer.get()))\n-\t\t\treturn { Results::Fail, \"Can't set buffer for request\" };\n+\t\tASSERT_FALSE(request->addBuffer(stream, buffer.get())) << \"Can't set buffer for request\";\n \n-\t\tif (queueRequest(request.get()) < 0)\n-\t\t\treturn { Results::Fail, \"Failed to queue request\" };\n+\t\tASSERT_GE(queueRequest(request.get()), 0) << \"Failed to queue request\";\n \n \t\trequests.push_back(std::move(request));\n \t}\n@@ -121,12 +113,7 @@ Results::Result SimpleCaptureBalanced::capture(unsigned int numRequests)\n \tstop();\n \tdelete loop_;\n \n-\tif (captureCount_ != captureLimit_)\n-\t\treturn { Results::Fail, \"Got \" + std::to_string(captureCount_) +\n-\t\t\t\" request, wanted \" + std::to_string(captureLimit_) };\n-\n-\treturn { Results::Pass, \"Balanced capture of \" +\n-\t\tstd::to_string(numRequests) + \" requests\" };\n+\tASSERT_EQ(captureCount_, captureLimit_);\n }\n \n int SimpleCaptureBalanced::queueRequest(Request *request)\n@@ -158,11 +145,9 @@ SimpleCaptureUnbalanced::SimpleCaptureUnbalanced(std::shared_ptr<Camera> camera)\n {\n }\n \n-Results::Result SimpleCaptureUnbalanced::capture(unsigned int numRequests)\n+void SimpleCaptureUnbalanced::capture(unsigned int numRequests)\n {\n-\tResults::Result ret = start();\n-\tif (ret.first != Results::Pass)\n-\t\treturn ret;\n+\tstart();\n \n \tStream *stream = config_->at(0).stream();\n \tconst std::vector<std::unique_ptr<FrameBuffer>> &buffers = allocator_->buffers(stream);\n@@ -174,14 +159,11 @@ Results::Result SimpleCaptureUnbalanced::capture(unsigned int numRequests)\n \tstd::vector<std::unique_ptr<libcamera::Request>> requests;\n \tfor (const std::unique_ptr<FrameBuffer> &buffer : buffers) {\n \t\tstd::unique_ptr<Request> request = camera_->createRequest();\n-\t\tif (!request)\n-\t\t\treturn { Results::Fail, \"Can't create request\" };\n+\t\tASSERT_TRUE(request) << \"Can't create request\";\n \n-\t\tif (request->addBuffer(stream, buffer.get()))\n-\t\t\treturn { Results::Fail, \"Can't set buffer for request\" };\n+\t\tASSERT_FALSE(request->addBuffer(stream, buffer.get())) << \"Can't set buffer for request\";\n \n-\t\tif (camera_->queueRequest(request.get()) < 0)\n-\t\t\treturn { Results::Fail, \"Failed to queue request\" };\n+\t\tASSERT_GE(camera_->queueRequest(request.get()), 0) << \"Failed to queue request\";\n \n \t\trequests.push_back(std::move(request));\n \t}\n@@ -192,7 +174,7 @@ Results::Result SimpleCaptureUnbalanced::capture(unsigned int numRequests)\n \tstop();\n \tdelete loop_;\n \n-\treturn { status ? Results::Fail : Results::Pass, \"Unbalanced capture of \" + std::to_string(numRequests) + \" requests\" };\n+\tASSERT_FALSE(status);\n }\n \n void SimpleCaptureUnbalanced::requestComplete(Request *request)\ndiff --git a/src/lc-compliance/simple_capture.h b/src/lc-compliance/simple_capture.h\nindex d9de53fb63a3..62984243a1fa 100644\n--- a/src/lc-compliance/simple_capture.h\n+++ b/src/lc-compliance/simple_capture.h\n@@ -12,18 +12,17 @@\n #include <libcamera/libcamera.h>\n \n #include \"../cam/event_loop.h\"\n-#include \"results.h\"\n \n class SimpleCapture\n {\n public:\n-\tResults::Result configure(libcamera::StreamRole role);\n+\tvoid configure(libcamera::StreamRole role);\n \n protected:\n \tSimpleCapture(std::shared_ptr<libcamera::Camera> camera);\n \tvirtual ~SimpleCapture();\n \n-\tResults::Result start();\n+\tvoid start();\n \tvoid stop();\n \n \tvirtual void requestComplete(libcamera::Request *request) = 0;\n@@ -40,7 +39,7 @@ class SimpleCaptureBalanced : public SimpleCapture\n public:\n \tSimpleCaptureBalanced(std::shared_ptr<libcamera::Camera> camera);\n \n-\tResults::Result capture(unsigned int numRequests);\n+\tvoid capture(unsigned int numRequests);\n \n private:\n \tint queueRequest(libcamera::Request *request);\n@@ -56,7 +55,7 @@ class SimpleCaptureUnbalanced : public SimpleCapture\n public:\n \tSimpleCaptureUnbalanced(std::shared_ptr<libcamera::Camera> camera);\n \n-\tResults::Result capture(unsigned int numRequests);\n+\tvoid capture(unsigned int numRequests);\n \n private:\n \tvoid requestComplete(libcamera::Request *request) override;\ndiff --git a/src/lc-compliance/single_stream.cpp b/src/lc-compliance/single_stream.cpp\nindex 8318b42f42d6..837e17a1c189 100644\n--- a/src/lc-compliance/single_stream.cpp\n+++ b/src/lc-compliance/single_stream.cpp\n@@ -7,91 +7,121 @@\n \n #include <iostream>\n \n+#include <gtest/gtest.h>\n+\n+#include \"environment.h\"\n #include \"simple_capture.h\"\n-#include \"tests.h\"\n \n using namespace libcamera;\n \n-Results::Result testRequestBalance(std::shared_ptr<Camera> camera,\n-\t\t\t\t StreamRole role, unsigned int startCycles,\n-\t\t\t\t unsigned int numRequests)\n+const std::vector<int> NUMREQUESTS = { 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };\n+const std::vector<StreamRole> ROLES = { Raw, StillCapture, VideoRecording, Viewfinder };\n+\n+class FixedRequestsTest : public testing::TestWithParam<std::tuple<StreamRole, int>>\n {\n-\tSimpleCaptureBalanced capture(camera);\n+public:\n+\tstatic std::string nameParameters(const testing::TestParamInfo<FixedRequestsTest::ParamType> &info);\n \n-\tResults::Result ret = capture.configure(role);\n-\tif (ret.first != Results::Pass)\n-\t\treturn ret;\n+protected:\n+\tvoid SetUp() override;\n+\tvoid TearDown() override;\n \n-\tfor (unsigned int starts = 0; starts < startCycles; starts++) {\n-\t\tret = capture.capture(numRequests);\n-\t\tif (ret.first != Results::Pass)\n-\t\t\treturn ret;\n-\t}\n+\tstd::shared_ptr<Camera> camera_;\n+};\n \n-\treturn { Results::Pass, \"Balanced capture of \" +\n-\t\tstd::to_string(numRequests) + \" requests with \" +\n-\t\tstd::to_string(startCycles) + \" start cycles\" };\n+/*\n+ * We use gtest's SetUp() and TearDown() instead of constructor and destructor\n+ * in order to be able to assert on them.\n+ */\n+void FixedRequestsTest::SetUp()\n+{\n+\tEnvironment *env = Environment::get();\n+\n+\tcamera_ = env->cm()->get(env->cameraId());\n+\n+\tASSERT_FALSE(camera_->acquire());\n }\n \n-Results::Result testRequestUnbalance(std::shared_ptr<Camera> camera,\n-\t\t\t\t StreamRole role, unsigned int numRequests)\n+void FixedRequestsTest::TearDown()\n {\n-\tSimpleCaptureUnbalanced capture(camera);\n+\tif (!camera_)\n+\t\treturn;\n \n-\tResults::Result ret = capture.configure(role);\n-\tif (ret.first != Results::Pass)\n-\t\treturn ret;\n-\n-\treturn capture.capture(numRequests);\n+\tcamera_->release();\n+\tcamera_.reset();\n }\n \n-Results testSingleStream(std::shared_ptr<Camera> camera)\n+std::string FixedRequestsTest::nameParameters(const testing::TestParamInfo<FixedRequestsTest::ParamType> &info)\n {\n-\tstatic const std::vector<std::pair<std::string, StreamRole>> roles = {\n-\t\t{ \"raw\", Raw },\n-\t\t{ \"still\", StillCapture },\n-\t\t{ \"video\", VideoRecording },\n-\t\t{ \"viewfinder\", Viewfinder },\n-\t};\n-\tstatic const std::vector<unsigned int> numRequests = { 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };\n-\n-\tResults results(numRequests.size() * roles.size() * 3);\n-\n-\tfor (const auto &role : roles) {\n-\t\tstd::cout << \"= Test role \" << role.first << std::endl;\n-\t\t/*\n-\t\t * Test single capture cycles\n-\t\t *\n-\t\t * Makes sure the camera completes the exact number of requests queued.\n-\t\t * Example failure is a camera that needs N+M requests queued to\n-\t\t * complete N requests to the application.\n-\t\t */\n-\t\tstd::cout << \"* Test single capture cycles\" << std::endl;\n-\t\tfor (unsigned int num : numRequests)\n-\t\t\tresults.add(testRequestBalance(camera, role.second, 1, num));\n-\n-\t\t/*\n-\t\t * Test multiple start/stop cycles\n-\t\t *\n-\t\t * Makes sure the camera supports multiple start/stop cycles.\n-\t\t * Example failure is a camera that does not clean up correctly in its\n-\t\t * error path but is only tested by single-capture applications.\n-\t\t */\n-\t\tstd::cout << \"* Test multiple start/stop cycles\" << std::endl;\n-\t\tfor (unsigned int num : numRequests)\n-\t\t\tresults.add(testRequestBalance(camera, role.second, 3, num));\n-\n-\t\t/*\n-\t\t * Test unbalanced stop\n-\t\t *\n-\t\t * Makes sure the camera supports a stop with requests queued.\n-\t\t * Example failure is a camera that does not handle cancelation\n-\t\t * of buffers coming back from the video device while stopping.\n-\t\t */\n-\t\tstd::cout << \"* Test unbalanced stop\" << std::endl;\n-\t\tfor (unsigned int num : numRequests)\n-\t\t\tresults.add(testRequestUnbalance(camera, role.second, num));\n-\t}\n-\n-\treturn results;\n+\tstd::map<StreamRole, std::string> rolesMap = { { Raw, \"Raw\" },\n+\t\t\t\t\t\t { StillCapture, \"StillCapture\" },\n+\t\t\t\t\t\t { VideoRecording, \"VideoRecording\" },\n+\t\t\t\t\t\t { Viewfinder, \"Viewfinder\" } };\n+\n+\tstd::string roleName = rolesMap[std::get<0>(info.param)];\n+\tstd::string numRequestsName = std::to_string(std::get<1>(info.param));\n+\n+\treturn roleName + \"_\" + numRequestsName;\n }\n+\n+/*\n+ * Test single capture cycles\n+ *\n+ * Makes sure the camera completes the exact number of requests queued. Example\n+ * failure is a camera that needs N+M requests queued to complete N requests to\n+ * the application.\n+ */\n+TEST_P(FixedRequestsTest, BalancedSingleCycle)\n+{\n+\tauto [role, numRequests] = GetParam();\n+\n+\tSimpleCaptureBalanced capture(camera_);\n+\n+\tcapture.configure(role);\n+\n+\tcapture.capture(numRequests);\n+};\n+\n+/*\n+ * Test multiple start/stop cycles\n+ *\n+ * Makes sure the camera supports multiple start/stop cycles. Example failure is\n+ * a camera that does not clean up correctly in its error path but is only\n+ * tested by single-capture applications.\n+ */\n+TEST_P(FixedRequestsTest, BalancedMultiCycle)\n+{\n+\tauto [role, numRequests] = GetParam();\n+\tunsigned int numRepeats = 3;\n+\n+\tSimpleCaptureBalanced capture(camera_);\n+\n+\tcapture.configure(role);\n+\n+\tfor (unsigned int starts = 0; starts < numRepeats; starts++)\n+\t\tcapture.capture(numRequests);\n+};\n+\n+/*\n+ * Test unbalanced stop\n+ *\n+ * Makes sure the camera supports a stop with requests queued. Example failure\n+ * is a camera that does not handle cancelation of buffers coming back from the\n+ * video device while stopping.\n+ */\n+TEST_P(FixedRequestsTest, Unbalanced)\n+{\n+\tauto [role, numRequests] = GetParam();\n+\n+\tSimpleCaptureUnbalanced capture(camera_);\n+\n+\tcapture.configure(role);\n+\n+\tcapture.capture(numRequests);\n+};\n+\n+INSTANTIATE_TEST_SUITE_P(RolesAndRequests,\n+\t\t\t FixedRequestsTest,\n+\t\t\t testing::Combine(testing::ValuesIn(ROLES),\n+\t\t\t\t\t testing::ValuesIn(NUMREQUESTS)),\n+\t\t\t FixedRequestsTest::nameParameters);\ndiff --git a/src/lc-compliance/tests.h b/src/lc-compliance/tests.h\ndeleted file mode 100644\nindex 396605214e4b..000000000000\n--- a/src/lc-compliance/tests.h\n+++ /dev/null\n@@ -1,16 +0,0 @@\n-/* SPDX-License-Identifier: GPL-2.0-or-later */\n-/*\n- * Copyright (C) 2020, Google Inc.\n- *\n- * tests.h - Test modules\n- */\n-#ifndef __LC_COMPLIANCE_TESTS_H__\n-#define __LC_COMPLIANCE_TESTS_H__\n-\n-#include <libcamera/libcamera.h>\n-\n-#include \"results.h\"\n-\n-Results testSingleStream(std::shared_ptr<libcamera::Camera> camera);\n-\n-#endif /* __LC_COMPLIANCE_TESTS_H__ */\n", "prefixes": [ "libcamera-devel", "v6", "4/5" ] }