{"id":12084,"url":"https://patchwork.libcamera.org/api/patches/12084/?format=json","web_url":"https://patchwork.libcamera.org/patch/12084/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20210422210609.425987-3-nfraprado@collabora.com>","date":"2021-04-22T21:06:09","name":"[libcamera-devel,RFC,2/2] lc-compliance: Refactor using Googletest","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"8e4c485b726687bc40a6255e10a82c5b42e5cada","submitter":{"id":84,"url":"https://patchwork.libcamera.org/api/people/84/?format=json","name":"Nícolas F. R. A. Prado","email":"nfraprado@collabora.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/12084/mbox/","series":[{"id":1965,"url":"https://patchwork.libcamera.org/api/series/1965/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=1965","date":"2021-04-22T21:06:07","name":"lc-compliance: Refactor using Googletest","version":1,"mbox":"https://patchwork.libcamera.org/series/1965/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/12084/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/12084/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 304B7BDB1A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 22 Apr 2021 21:06:56 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id ED06F68865;\n\tThu, 22 Apr 2021 23:06:55 +0200 (CEST)","from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2D8E268857\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 22 Apr 2021 23:06:54 +0200 (CEST)","from [127.0.0.1] (localhost [127.0.0.1])\n\t(Authenticated sender: nfraprado) with ESMTPSA id 1C32B1F43738"],"From":"=?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= <nfraprado@collabora.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Thu, 22 Apr 2021 18:06:09 -0300","Message-Id":"<20210422210609.425987-3-nfraprado@collabora.com>","X-Mailer":"git-send-email 2.31.1","In-Reply-To":"<20210422210609.425987-1-nfraprado@collabora.com>","References":"<20210422210609.425987-1-nfraprado@collabora.com>","MIME-Version":"1.0","Subject":"[libcamera-devel] [RFC PATCH 2/2] 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>","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"base64","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>\n---\n src/lc-compliance/main.cpp           |  60 +++++------\n src/lc-compliance/meson.build        |   3 +\n src/lc-compliance/simple_capture.cpp |  73 +++++---------\n src/lc-compliance/simple_capture.h   |   8 +-\n src/lc-compliance/single_stream.cpp  | 142 ++++++++++++++-------------\n 5 files changed, 132 insertions(+), 154 deletions(-)","diff":"diff --git a/src/lc-compliance/main.cpp b/src/lc-compliance/main.cpp\nindex 54cee54aa978..04cd0732ee3d 100644\n--- a/src/lc-compliance/main.cpp\n+++ b/src/lc-compliance/main.cpp\n@@ -14,8 +14,12 @@\n #include \"../cam/options.h\"\n #include \"tests.h\"\n \n+#include \"gtest/gtest.h\"\n+\n using namespace libcamera;\n \n+std::shared_ptr<Camera> cam;\n+\n enum {\n \tOptCamera = 'c',\n \tOptHelp = 'h',\n@@ -28,14 +32,13 @@ public:\n \t~Harness();\n \n \tint exec();\n+\tint init();\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 };\n \n Harness::Harness(const OptionsParser::Options &options)\n@@ -46,33 +49,14 @@ Harness::Harness(const OptionsParser::Options &options)\n \n Harness::~Harness()\n {\n-\tif (camera_) {\n-\t\tcamera_->release();\n-\t\tcamera_.reset();\n+\tif (cam) {\n+\t\tcam->release();\n+\t\tcam.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 \tint ret = cm_->start();\n@@ -89,14 +73,14 @@ int Harness::init()\n \t}\n \n \tconst std::string &cameraId = options_[OptCamera];\n-\tcamera_ = cm_->get(cameraId);\n-\tif (!camera_) {\n+\tcam = cm_->get(cameraId);\n+\tif (!cam) {\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+\tif (cam->acquire()) {\n \t\tstd::cout << \"Failed to acquire camera\" << std::endl;\n \t\treturn -EINVAL;\n \t}\n@@ -108,8 +92,8 @@ int Harness::init()\n \n void Harness::listCameras()\n {\n-\tfor (const std::shared_ptr<Camera> &cam : cm_->cameras())\n-\t\tstd::cout << \"- \" << cam.get()->id() << std::endl;\n+\tfor (const std::shared_ptr<Camera> &c : cm_->cameras())\n+\t\tstd::cout << \"- \" << c.get()->id() << std::endl;\n }\n \n static int parseOptions(int argc, char **argv, OptionsParser::Options *options)\n@@ -133,6 +117,17 @@ static int parseOptions(int argc, char **argv, OptionsParser::Options *options)\n \treturn 0;\n }\n \n+/* Make asserts act like exceptions, otherwise they only fail (or skip) the\n+ * current function */\n+class ThrowListener : public testing::EmptyTestEventListener {\n+  void OnTestPartResult(const testing::TestPartResult& result) override {\n+    if (result.type() == testing::TestPartResult::kFatalFailure\n+\t\t    || result.type() == testing::TestPartResult::kSkip) {\n+      throw testing::AssertionException(result);\n+    }\n+  }\n+};\n+\n int main(int argc, char **argv)\n {\n \tOptionsParser::Options options;\n@@ -143,6 +138,11 @@ 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+\t::testing::InitGoogleTest(&argc, argv);\n+\ttesting::UnitTest::GetInstance()->listeners().Append(new ThrowListener);\n+\treturn RUN_ALL_TESTS();\n }\ndiff --git a/src/lc-compliance/meson.build b/src/lc-compliance/meson.build\nindex a2bfcceb1259..4c41ce6da43a 100644\n--- a/src/lc-compliance/meson.build\n+++ b/src/lc-compliance/meson.build\n@@ -18,10 +18,13 @@ lc_compliance_sources = files([\n     'single_stream.cpp',\n ])\n \n+gtest_dep = dependency('gtest', main: true)\n+\n lc_compliance  = executable('lc-compliance', lc_compliance_sources,\n                             dependencies : [\n                                 libatomic,\n                                 libcamera_dep,\n                                 libevent,\n+                                gtest_dep\n                             ],\n                             install : true)\ndiff --git a/src/lc-compliance/simple_capture.cpp b/src/lc-compliance/simple_capture.cpp\nindex e6715ac07f12..24abbff138a3 100644\n--- a/src/lc-compliance/simple_capture.cpp\n+++ b/src/lc-compliance/simple_capture.cpp\n@@ -6,6 +6,7 @@\n  */\n \n #include \"simple_capture.h\"\n+#include \"gtest/gtest.h\"\n \n using namespace libcamera;\n \n@@ -20,35 +21,29 @@ 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_->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@@ -73,22 +68,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@@ -99,17 +91,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\t}\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\t}\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\t}\n+\t\tASSERT_GE(queueRequest(request.get()), 0) << \"Failed to queue request\";\n \n \t\trequests.push_back(std::move(request));\n \t}\n@@ -120,12 +106,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@@ -157,11 +138,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@@ -173,17 +152,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\t}\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\t}\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\t}\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@@ -194,7 +167,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..0f8465083456 100644\n--- a/src/lc-compliance/simple_capture.h\n+++ b/src/lc-compliance/simple_capture.h\n@@ -17,13 +17,13 @@\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 +40,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 +56,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..18830cd9bce5 100644\n--- a/src/lc-compliance/single_stream.cpp\n+++ b/src/lc-compliance/single_stream.cpp\n@@ -6,92 +6,94 @@\n  */\n \n #include <iostream>\n+#include <sstream>\n \n #include \"simple_capture.h\"\n #include \"tests.h\"\n+#include \"gtest/gtest.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+extern std::shared_ptr<Camera> cam;\n+\n+std::vector<int> NUMREQUESTS = {1, 2, 3, 5, 8, 13, 21, 34, 55, 89};\n+\n+class FixedRequestsTest :\n+    public testing::TestWithParam<std::tuple<StreamRole, int>> {\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-\tSimpleCaptureBalanced capture(camera);\n+\tauto [role, numRequests] = GetParam();\n \n-\tResults::Result ret = capture.configure(role);\n-\tif (ret.first != Results::Pass)\n-\t\treturn ret;\n+\tSimpleCaptureBalanced capture(cam);\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+\tcapture.configure(role);\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+\tcapture.capture(numRequests);\n }\n \n-Results::Result testRequestUnbalance(std::shared_ptr<Camera> camera,\n-\t\t\t\t     StreamRole role, unsigned int numRequests)\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-\tSimpleCaptureUnbalanced capture(camera);\n+\tauto [role, numRequests] = GetParam();\n+\tunsigned int numRepeats = 3;\n \n-\tResults::Result ret = capture.configure(role);\n-\tif (ret.first != Results::Pass)\n-\t\treturn ret;\n+\tSimpleCaptureBalanced capture(cam);\n \n-\treturn capture.capture(numRequests);\n+\tcapture.configure(role);\n+\n+\tfor (unsigned int starts = 0; starts < numRepeats; starts++)\n+\t\tcapture.capture(numRequests);\n }\n \n-Results testSingleStream(std::shared_ptr<Camera> camera)\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-\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+\tauto [role, numRequests] = GetParam();\n+\n+\tSimpleCaptureUnbalanced capture(cam);\n+\n+\tcapture.configure(role);\n+\n+\tcapture.capture(numRequests);\n }\n+\n+INSTANTIATE_TEST_SUITE_P(Raw,\n+                         FixedRequestsTest,\n+                         testing::Combine(testing::Values(Raw),\n+\t\t\t\t\ttesting::ValuesIn(NUMREQUESTS)));\n+\n+INSTANTIATE_TEST_SUITE_P(StillCapture,\n+                         FixedRequestsTest,\n+                         testing::Combine(testing::Values(StillCapture),\n+\t\t\t\t\ttesting::ValuesIn(NUMREQUESTS)));\n+\n+INSTANTIATE_TEST_SUITE_P(VideoRecording,\n+                         FixedRequestsTest,\n+                         testing::Combine(testing::Values(VideoRecording),\n+\t\t\t\t\ttesting::ValuesIn(NUMREQUESTS)));\n+\n+INSTANTIATE_TEST_SUITE_P(Viewfinder,\n+                         FixedRequestsTest,\n+                         testing::Combine(testing::Values(Viewfinder),\n+\t\t\t\t\ttesting::ValuesIn(NUMREQUESTS)));\n","prefixes":["libcamera-devel","RFC","2/2"]}