From patchwork Tue Sep 3 09:14:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788323 Received: from pfout3-smtp.messagingengine.com (fout3-smtp.messagingengine.com [103.168.172.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 26CFF19F43B for ; Tue, 3 Sep 2024 09:14:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354882; cv=none; b=Btl0QXtk/ipfQCSwd9JXd224ejuduvPWyo5eAxxrhnGVaUxZXMP3zhMqctYuAZzs2iWbuLjL0JPD/sKmQdSre0tpI4Lt/CoCiFnc5drS8hw32nittnDN/0G0dXjv/IJCpVDyBvsTM6DJ0SzVjf7AVvTaAko3tIH/rJ6FcHHOnng= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354882; c=relaxed/simple; bh=axVoeBeO3+G1i8CjNEGnZ3LQIvmMNw0SOha9RctPyTo=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=jKMuO2jTHCYUrZVWH6jSwLraCQCy7rUQ3Tc6MWl0/7THIMCH8gjw7Z4GXoBEsVbFs3abnRaN9iv92zMre5CH2yXJKulWPwvHVCN9TOLMww+QTWYPMP53xfacppDHcjeAJIInN/YXG7iQtpErSrw8iCsY3kcCbmCDfd2emeUIyAs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=O/tcF9hw; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=g9oEiDDl; arc=none smtp.client-ip=103.168.172.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="O/tcF9hw"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="g9oEiDDl" Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfout.phl.internal (Postfix) with ESMTP id 0EFC6138037F; Tue, 3 Sep 2024 05:14:39 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-05.internal (MEProxy); Tue, 03 Sep 2024 05:14:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354879; x=1725441279; bh=vE2Bw3zlWz 0JKf5giy+Bb5ybj8Rkmr9xJz4acHe1lSs=; b=O/tcF9hwDy6L2BpANelqULwBjf XIJum0Y/+T2xgWkLku0pFlSc+E7QrcZ82TExyQXz5/GxCK7XimCMg3Y8MHCc4oVE fs86cMNfgPx0nt55CnXlCq45J9bJIbVT5p2PpjHkEffkaXhf5pxc8tg/OEqbaXY5 vFvhO3T6YkBoR1e/WnkMLh+itr8fX1+SqxwkF1DBqdZb4LYauQsZi0GiNqWXnTmU jtm5ZKUZOzCMazdEjPmkAWZCRYdZOBeruxJ6JveOvfXjKBYcAzpstI6V67aCuTWK 8ug6IDDBcLDLb46XGkrQ8wufLvMRxRZM7mRJwp3elXPEYHAViu40jinwxM2w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354879; x=1725441279; bh=vE2Bw3zlWz0JKf5giy+Bb5ybj8Rk mr9xJz4acHe1lSs=; b=g9oEiDDlgAO10U9Wgmu+HeAxI9YtyMP6DvdfHA6/c/H2 iw4U1RDiNOstcooOt5y93LeRduoWuwgqjcAziyOE9WloVVp+XWPttlNcLU4tAnZ9 X9kt77PL+DBeKny3lBUVlW29EtwIjC9X2PNSPLekCr934Ky0OdBLGNL2yymtL06V +PkVzZPM1ckMXZEqnWdlyoAj3tXn0JJTpeXEmK6qaEvzwgwUAr+00Fi8jzL8l5Je v2Vc72diiDeQ3ASAGXjHJ/F2VWZWirKx/AgSfoIXHN4NJR1NtHQWfwlR+tZZRQVP T7X8/mN6sN7SV4y6cyB1YmOGItIJYqMiWf20s/0Wsw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtohepghhithesvhhgvghrrdhkvghrnhgvlhdrohhrghdprh gtphhtthhopegvthhhohhmshhonhesvggufigrrhguthhhohhmshhonhdrtghomhdprhgt phhtthhopehsphgvtghtrhgrlhesghhoohhglhgvrdgtohhmpdhrtghpthhtohepshhtvg grughmohhnsehgohhoghhlvgdrtghomhdprhgtphhtthhopehphhhilhhlihhprdifohho ugesughunhgvlhhmrdhorhhgrdhukhdprhgtphhtthhopehjohhhrghnnhgvshdrshgthh hinhguvghlihhnsehgmhigrdguvgdprhgtphhtthhopehgihhtshhtvghrsehpohgsohig rdgtohhmpdhrtghpthhtoheprhhssggvtghkvghrsehnvgigsghrihgughgvrdgtohhmpd hrtghpthhtoheplhdrshdrrhesfigvsgdruggv X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:14:37 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 7ce3ad88 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:14:29 +0000 (UTC) Date: Tue, 3 Sep 2024 11:14:34 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 01/14] t: do not pass GIT_TEST_OPTS to unit tests with prove Message-ID: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: When using the prove target, we append GIT_TEST_OPTS to the arguments that we execute each of the tests with. This doesn't only include the intended test scripts, but also ends up passing the arguments to our unit tests. This is unintentional though as they do not even know to interpret those arguments, and is inconsistent with how we execute unit tests without prove. This isn't much of an issue because our current set of unit tests mostly ignore their arguments anyway. With the introduction of clar-based unit tests this is about to become an issue though, as these do parse their command line argument to alter behaviour. Prepare for this by passing GIT_TEST_OPTS to "run-test.sh" via an environment variable. Like this, we can conditionally forward it to our test scripts, only. Signed-off-by: Patrick Steinhardt --- t/Makefile | 3 ++- t/run-test.sh | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/t/Makefile b/t/Makefile index 4c30e7c06fb..d2212de0b78 100644 --- a/t/Makefile +++ b/t/Makefile @@ -68,7 +68,8 @@ failed: test -z "$$failed" || $(MAKE) $$failed prove: pre-clean check-chainlint $(TEST_LINT) - @echo "*** prove (shell & unit tests) ***"; $(CHAINLINTSUPPRESS) TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS) :: $(GIT_TEST_OPTS) + @echo "*** prove (shell & unit tests) ***" + @$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS) $(MAKE) clean-except-prove-cache $(T): diff --git a/t/run-test.sh b/t/run-test.sh index 13c353b91b4..63328ac630c 100755 --- a/t/run-test.sh +++ b/t/run-test.sh @@ -10,7 +10,7 @@ case "$1" in echo >&2 "ERROR: TEST_SHELL_PATH is empty or not set" exit 1 fi - exec "${TEST_SHELL_PATH}" "$@" + exec "${TEST_SHELL_PATH}" "$@" ${TEST_OPTIONS} ;; *) exec "$@" From patchwork Tue Sep 3 09:14:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788325 Received: from pfout3-smtp.messagingengine.com (fout3-smtp.messagingengine.com [103.168.172.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 468171A3058 for ; Tue, 3 Sep 2024 09:14:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354886; cv=none; b=mtkNd+rwWySLGNZ3s/N6OnES6tdc4FUbCN7/qx88x3B8aXknOZyck7z15w6AbaOHiTj6RA6QHYHOu2IqmFjUNgKT/6bYaJgODluUw6xKPyMgiV2IIVl+yZTj81X7+SBiQvORqB4Bu2IC9Qe+eXq2E5+d/FiqJngNh5Z4BQehMBY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354886; c=relaxed/simple; bh=V6kPrK8J6bSI9Tx/qkRzha5UclPn7d1E/J8DGm+WxA8=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=PL6j3T1I/RjcYirUEce3x4WSZUPzshOHqYQ778mgfgOfrZ3aLhnTff8CErU/1UFT6dY5Le3eClZ+w0ldno2ncsTVUcJnaIYs7TIOXgiSoRDMVCYUOTYQZPgdsJYzjv88i0+M+7IO+lxRxzu0XWzHfhKAhhaj8kc1sOSckOOhptA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=NCUYa7Bo; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=K3ahmX36; arc=none smtp.client-ip=103.168.172.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="NCUYa7Bo"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="K3ahmX36" Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfout.phl.internal (Postfix) with ESMTP id 43251138038C; Tue, 3 Sep 2024 05:14:41 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-05.internal (MEProxy); Tue, 03 Sep 2024 05:14:41 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-transfer-encoding:content-type:content-type:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm1; t=1725354881; x=1725441281; bh=PbYGEXFhczFtdctLWlQIWvpnwxLR6Qe5nDQQBnOOHeI=; b= NCUYa7BofpECiJv8T80ySPgiJip7NL091RYUnyTV0F6b55mcZFf/o9O5ISmhHfmI K0EkiFFq5p3K1IqqU/LtUhhZzatRRnvaEsrtK5KJizN55DC7fGyzHQDxZt0HKgGj GDzehI4sunXh5hyTTFi6jS3lg4QSMiwZ62fQmSsxJPbJWexpXkMckX0UHg/Ia1Dj YRoWe4HsUupKivgjZJJ/AwidM8RIpQVA9YJL2pnbsqpsuxHoFRThyyOVe/jk1qWx ljFpkL7FkRymgonjy+hxcTlN4d1rQM7kce2Pq2+9DfZGybXdU4xMy9n98nF4rlUs zKgTvwGug6H5kWKQH/0+8g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1725354881; x= 1725441281; bh=PbYGEXFhczFtdctLWlQIWvpnwxLR6Qe5nDQQBnOOHeI=; b=K 3ahmX363dFnG8PDruMjgMkF97rXQuR4lhKcCxgvuMp5yuaZKYcShrtldH0z8aTUa GOGRyzFThJ8rbAJ8ql6fxIQc2V4H5cDUW50omnercH8HX1kg6XoH5HU+R4CG7wYZ j4RmS48zRCs2GnUN8h9cwWoBimtVERIsjoZATN87bSuKkbNY1jUh7YeFBnMbB8Qt 4gUWDQs6cpqFBXeANGFC5Yq8KLQco1Xadh4kSxSwYsXxI+DfLP91sUAw5AHqJC7X zohRDA68jPiom5+AUQneupLD5lYXLMt1lGvbsUwB7MEBUeUT6Lx5oVp6E5nAN3Jg NYQVn/eI3FebPoghkpAQg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnegoufhushhpvggtthffohhmrghinhculdegledmnecujfgurhep fffhvfevuffkfhggtggugfgjsehtkeertddttdejnecuhfhrohhmpefrrghtrhhitghkuc futhgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucggtffrrghtthgvrhhnpeeu heeivddtuddvudffleeuvdeuveehffduheehuefhhfegveeuffdvleeugfelgeenucffoh hmrghinhepghhithhhuhgsrdgtohhmpdhgihhthhhusgdrihhopdhtfihithhtvghrrdgt ohhmpdhmohguuhhlvgdrnhgrmhgvnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrg hmpehmrghilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhho uggvpehsmhhtphhouhhtpdhrtghpthhtohepghhithhsthgvrhesphhosghogidrtghomh dprhgtphhtthhopehlrdhsrdhrseifvggsrdguvgdprhgtphhtthhopehgihhtsehvghgv rhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepshhpvggtthhrrghlsehgohhoghhlvg drtghomhdprhgtphhtthhopegvthhhohhmshhonhesvggufigrrhguthhhohhmshhonhdr tghomhdprhgtphhtthhopehjohhhrghnnhgvshdrshgthhhinhguvghlihhnsehgmhigrd guvgdprhgtphhtthhopehrshgsvggtkhgvrhesnhgvgigsrhhiughgvgdrtghomhdprhgt phhtthhopehsthgvrggumhhonhesghhoohhglhgvrdgtohhmpdhrtghpthhtohepphhhih hllhhiphdrfihoohguseguuhhnvghlmhdrohhrghdruhhk X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:14:39 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 74308ff2 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:14:32 +0000 (UTC) Date: Tue, 3 Sep 2024 11:14:37 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 02/14] t: import the clar unit testing framework Message-ID: <55a9b46e65f2072ca7994b042dfe24d1c153c334.1725349234.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Our unit testing framework is a homegrown solution. While it supports most of our needs, it is likely that the volume of unit tests will grow quite a bit in the future such that we can exercise low-level subsystems directly. This surfaces several shortcomings that the current solution has: - There is no way to run only one specific tests. While some of our unit tests wire this up manually, others don't. In general, it requires quite a bit of boilerplate to get this set up correctly. - Failures do not cause a test to stop execution directly. Instead, the test author needs to return manually whenever an assertion fails. This is rather verbose and is not done correctly in most of our unit tests. - Wiring up a new testcase requires both implementing the test function and calling it in the respective test suite's main function, which is creating code duplication. We can of course fix all of these issues ourselves, but that feels rather pointless when there are already so many unit testing frameworks out there that have those features. We line out some requirements for any unit testing framework in "Documentation/technical/unit-tests.txt". The "clar" unit testing framework, which isn't listed in that table yet, ticks many of the boxes: - It is licensed under ISC, which is compatible. - It is easily vendorable because it is rather tiny at around 1200 lines of code. - It is easily hackable due to the same reason. - It has TAP support. - It has skippable tests. - It preprocesses test files in order to extract test functions, which then get wired up automatically. While it's not perfect, the fact that clar originates from the libgit2 project means that it should be rather easy for us to collaborate with upstream to plug any gaps. Import the clar unit testing framework at commit 1516124 (Merge pull request #97 from pks-t/pks-whitespace-fixes, 2024-08-15). The framework will be wired up in subsequent commits. Signed-off-by: Patrick Steinhardt --- Documentation/technical/unit-tests.txt | 2 + Makefile | 4 +- t/unit-tests/clar/.github/workflows/ci.yml | 23 + t/unit-tests/clar/COPYING | 15 + t/unit-tests/clar/README.md | 329 ++++++++ t/unit-tests/clar/clar.c | 842 +++++++++++++++++++++ t/unit-tests/clar/clar.h | 173 +++++ t/unit-tests/clar/clar/fixtures.h | 50 ++ t/unit-tests/clar/clar/fs.h | 522 +++++++++++++ t/unit-tests/clar/clar/print.h | 211 ++++++ t/unit-tests/clar/clar/sandbox.h | 153 ++++ t/unit-tests/clar/clar/summary.h | 143 ++++ t/unit-tests/clar/generate.py | 266 +++++++ t/unit-tests/clar/test/.gitignore | 4 + t/unit-tests/clar/test/Makefile | 39 + t/unit-tests/clar/test/clar_test.h | 16 + t/unit-tests/clar/test/main.c | 40 + t/unit-tests/clar/test/main.c.sample | 27 + t/unit-tests/clar/test/resources/test/file | 1 + t/unit-tests/clar/test/sample.c | 84 ++ 20 files changed, 2943 insertions(+), 1 deletion(-) create mode 100644 t/unit-tests/clar/.github/workflows/ci.yml create mode 100644 t/unit-tests/clar/COPYING create mode 100644 t/unit-tests/clar/README.md create mode 100644 t/unit-tests/clar/clar.c create mode 100644 t/unit-tests/clar/clar.h create mode 100644 t/unit-tests/clar/clar/fixtures.h create mode 100644 t/unit-tests/clar/clar/fs.h create mode 100644 t/unit-tests/clar/clar/print.h create mode 100644 t/unit-tests/clar/clar/sandbox.h create mode 100644 t/unit-tests/clar/clar/summary.h create mode 100755 t/unit-tests/clar/generate.py create mode 100644 t/unit-tests/clar/test/.gitignore create mode 100644 t/unit-tests/clar/test/Makefile create mode 100644 t/unit-tests/clar/test/clar_test.h create mode 100644 t/unit-tests/clar/test/main.c create mode 100644 t/unit-tests/clar/test/main.c.sample create mode 100644 t/unit-tests/clar/test/resources/test/file create mode 100644 t/unit-tests/clar/test/sample.c diff --git a/Documentation/technical/unit-tests.txt b/Documentation/technical/unit-tests.txt index 206037ffb19..5a432b7b29c 100644 --- a/Documentation/technical/unit-tests.txt +++ b/Documentation/technical/unit-tests.txt @@ -203,6 +203,7 @@ GitHub / GitLab stars to estimate this. :criterion: https://github.com/Snaipe/Criterion[Criterion] :c-tap: https://github.com/rra/c-tap-harness/[C TAP] :check: https://libcheck.github.io/check/[Check] +:clar: https://github.com/clar-test/clar[Clar] [format="csv",options="header",width="33%",subs="specialcharacters,attributes,quotes,macros"] |===== @@ -212,6 +213,7 @@ Framework,"<>","< _Historical note_ +> +> Originally the clar project was named "clay" because the word "test" has its +> roots in the latin word *"testum"*, meaning "earthen pot", and *"testa"*, +> meaning "piece of burned clay"? +> +> This is because historically, testing implied melting metal in a pot to +> check its quality. Clay is what tests are made of. + +## Quick Usage Overview + +Clar is a minimal C unit testing framework. It's been written to replace the +old framework in [libgit2][libgit2], but it's both very versatile and +straightforward to use. + +Can you count to funk? + +- **Zero: Initialize test directory** + + ~~~~ sh + $ mkdir tests + $ cp -r $CLAR_ROOT/clar* tests + $ cp $CLAR_ROOT/test/clar_test.h tests + $ cp $CLAR_ROOT/test/main.c.sample tests/main.c + ~~~~ + +- **One: Write some tests** + + File: tests/adding.c: + + ~~~~ c + /* adding.c for the "Adding" suite */ + #include "clar.h" + + static int *answer; + + void test_adding__initialize(void) + { + answer = malloc(sizeof(int)); + cl_assert_(answer != NULL, "No memory left?"); + *answer = 42; + } + + void test_adding__cleanup(void) + { + free(answer); + } + + void test_adding__make_sure_math_still_works(void) + { + cl_assert_(5 > 3, "Five should probably be greater than three"); + cl_assert_(-5 < 2, "Negative numbers are small, I think"); + cl_assert_(*answer == 42, "The universe is doing OK. And the initializer too."); + } + ~~~~~ + +- **Two: Build the test executable** + + ~~~~ sh + $ cd tests + $ $CLAR_PATH/generate.py . + Written `clar.suite` (1 suites) + $ gcc -I. clar.c main.c adding.c -o testit + ~~~~ + +- **Funk: Funk it.** + + ~~~~ sh + $ ./testit + ~~~~ + +## The Clar Test Suite + +Writing a test suite is pretty straightforward. Each test suite is a `*.c` +file with a descriptive name: this encourages modularity. + +Each test suite has optional initialize and cleanup methods. These methods +will be called before and after running **each** test in the suite, even if +such test fails. As a rule of thumb, if a test needs a different initializer +or cleanup method than another test in the same module, that means it +doesn't belong in that module. Keep that in mind when grouping tests +together. + +The `initialize` and `cleanup` methods have the following syntax, with +`suitename` being the current suite name, e.g. `adding` for the `adding.c` +suite. + +~~~~ c +void test_suitename__initialize(void) +{ + /* init */ +} + +void test_suitename__cleanup(void) +{ + /* cleanup */ +} +~~~~ + +These methods are encouraged to use static, global variables to store the state +that will be used by all tests inside the suite. + +~~~~ c +static git_repository *_repository; + +void test_status__initialize(void) +{ + create_tmp_repo(STATUS_REPO); + git_repository_open(_repository, STATUS_REPO); +} + +void test_status__cleanup(void) +{ + git_repository_close(_repository); + git_path_rm(STATUS_REPO); +} + +void test_status__simple_test(void) +{ + /* do something with _repository */ +} +~~~~ + +Writing the actual tests is just as straightforward. Tests have the +`void test_suitename__test_name(void)` signature, and they should **not** +be static. Clar will automatically detect and list them. + +Tests are run as they appear on their original suites: they have no return +value. A test is considered "passed" if it doesn't raise any errors. Check +the "Clar API" section to see the various helper functions to check and +raise errors during test execution. + +__Caution:__ If you use assertions inside of `test_suitename__initialize`, +make sure that you do not rely on `__initialize` being completely run +inside your `test_suitename__cleanup` function. Otherwise you might +encounter ressource cleanup twice. + +## How does Clar work? + +To use Clar: + +1. copy the Clar boilerplate to your test directory +2. copy (and probably modify) the sample `main.c` (from + `$CLAR_PATH/test/main.c.sample`) +3. run the Clar mixer (a.k.a. `generate.py`) to scan your test directory and + write out the test suite metadata. +4. compile your test files and the Clar boilerplate into a single test + executable +5. run the executable to test! + +The Clar boilerplate gives you a set of useful test assertions and features +(like accessing or making sandbox copies of fixture data). It consists of +the `clar.c` and `clar.h` files, plus the code in the `clar/` subdirectory. +You should not need to edit these files. + +The sample `main.c` (i.e. `$CLAR_PATH/test/main.c.sample`) file invokes +`clar_test(argc, argv)` to run the tests. Usually, you will edit this file +to perform any framework specific initialization and teardown that you need. + +The Clar mixer (`generate.py`) recursively scans your test directory for +any `.c` files, parses them, and writes the `clar.suite` file with all of +the metadata about your tests. When you build, the `clar.suite` file is +included into `clar.c`. + +The mixer can be run with **Python 2.5, 2.6, 2.7, 3.0, 3.1, 3.2 and PyPy 1.6**. + +Commandline usage of the mixer is as follows: + + $ ./generate.py . + +Where `.` is the folder where all the test suites can be found. The mixer +will automatically locate all the relevant source files and build the +testing metadata. The metadata will be written to `clar.suite`, in the same +folder as all the test suites. This file is included by `clar.c` and so +must be accessible via `#include` when building the test executable. + + $ gcc -I. clar.c main.c suite1.c test2.c -o run_tests + +**Note that the Clar mixer only needs to be ran when adding new tests to a +suite, in order to regenerate the metadata**. As a result, the `clar.suite` +file can be checked into version control if you wish to be able to build +your test suite without having to re-run the mixer. + +This is handy when e.g. generating tests in a local computer, and then +building and testing them on an embedded device or a platform where Python +is not available. + +### Fixtures + +Clar can create sandboxed fixtures for you to use in your test. You'll need to compile *clar.c* with an additional `CFLAG`, `-DCLAR_FIXTURE_PATH`. This should be an absolute path to your fixtures directory. + +Once that's done, you can use the fixture API as defined below. + +## The Clar API + +Clar makes the following methods available from all functions in a test +suite. + +- `cl_must_pass(call)`, `cl_must_pass_(call, message)`: Verify that the given + function call passes, in the POSIX sense (returns a value greater or equal + to 0). + +- `cl_must_fail(call)`, `cl_must_fail_(call, message)`: Verify that the given + function call fails, in the POSIX sense (returns a value less than 0). + +- `cl_assert(expr)`, `cl_assert_(expr, message)`: Verify that `expr` is true. + +- `cl_check_pass(call)`, `cl_check_pass_(call, message)`: Verify that the + given function call passes, in the POSIX sense (returns a value greater or + equal to 0). If the function call doesn't succeed, a test failure will be + logged but the test's execution will continue. + +- `cl_check_fail(call)`, `cl_check_fail_(call, message)`: Verify that the + given function call fails, in the POSIX sense (returns a value less than + 0). If the function call doesn't fail, a test failure will be logged but + the test's execution will continue. + +- `cl_check(expr)`: Verify that `expr` is true. If `expr` is not + true, a test failure will be logged but the test's execution will continue. + +- `cl_fail(message)`: Fail the current test with the given message. + +- `cl_warning(message)`: Issue a warning. This warning will be + logged as a test failure but the test's execution will continue. + +- `cl_set_cleanup(void (*cleanup)(void *), void *opaque)`: Set the cleanup + method for a single test. This method will be called with `opaque` as its + argument before the test returns (even if the test has failed). + If a global cleanup method is also available, the local cleanup will be + called first, and then the global. + +- `cl_assert_equal_i(int,int)`: Verify that two integer values are equal. + The advantage of this over a simple `cl_assert` is that it will format + a much nicer error report if the values are not equal. + +- `cl_assert_equal_s(const char *,const char *)`: Verify that two strings + are equal. The expected value can also be NULL and this will correctly + test for that. + +- `cl_fixture_sandbox(const char *)`: Sets up a sandbox for a fixture + so that you can mutate the file directly. + +- `cl_fixture_cleanup(const char *)`: Tears down the previous fixture + sandbox. + +- `cl_fixture(const char *)`: Gets the full path to a fixture file. + +Please do note that these methods are *always* available whilst running a +test, even when calling auxiliary/static functions inside the same file. + +It's strongly encouraged to perform test assertions in auxiliary methods, +instead of returning error values. This is considered good Clar style. + +Style Example: + +~~~~ c +/* + * Bad style: auxiliary functions return an error code + */ + +static int check_string(const char *str) +{ + const char *aux = process_string(str); + + if (aux == NULL) + return -1; + + return strcmp(my_function(aux), str) == 0 ? 0 : -1; +} + +void test_example__a_test_with_auxiliary_methods(void) +{ + cl_must_pass_( + check_string("foo"), + "String differs after processing" + ); + + cl_must_pass_( + check_string("bar"), + "String differs after processing" + ); +} +~~~~ + +~~~~ c +/* + * Good style: auxiliary functions perform assertions + */ + +static void check_string(const char *str) +{ + const char *aux = process_string(str); + + cl_assert_( + aux != NULL, + "String processing failed" + ); + + cl_assert_( + strcmp(my_function(aux), str) == 0, + "String differs after processing" + ); +} + +void test_example__a_test_with_auxiliary_methods(void) +{ + check_string("foo"); + check_string("bar"); +} +~~~~ + +About Clar +========== + +Clar has been written from scratch by [Vicent Martí](https://github.com/vmg), +to replace the old testing framework in [libgit2][libgit2]. + +Do you know what languages are *in* on the SF startup scene? Node.js *and* +Latin. Follow [@vmg](https://www.twitter.com/vmg) on Twitter to +receive more lessons on word etymology. You can be hip too. + + +[libgit2]: https://github.com/libgit2/libgit2 diff --git a/t/unit-tests/clar/clar.c b/t/unit-tests/clar/clar.c new file mode 100644 index 00000000000..3fc2c768158 --- /dev/null +++ b/t/unit-tests/clar/clar.c @@ -0,0 +1,842 @@ +/* + * Copyright (c) Vicent Marti. All rights reserved. + * + * This file is part of clar, distributed under the ISC license. + * For full terms see the included COPYING file. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* required for sandboxing */ +#include +#include + +#ifdef _WIN32 +# include +# include +# include +# include + +# define _MAIN_CC __cdecl + +# ifndef stat +# define stat(path, st) _stat(path, st) +# endif +# ifndef mkdir +# define mkdir(path, mode) _mkdir(path) +# endif +# ifndef chdir +# define chdir(path) _chdir(path) +# endif +# ifndef access +# define access(path, mode) _access(path, mode) +# endif +# ifndef strdup +# define strdup(str) _strdup(str) +# endif +# ifndef strcasecmp +# define strcasecmp(a,b) _stricmp(a,b) +# endif + +# ifndef __MINGW32__ +# pragma comment(lib, "shell32") +# ifndef strncpy +# define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE) +# endif +# ifndef W_OK +# define W_OK 02 +# endif +# ifndef S_ISDIR +# define S_ISDIR(x) ((x & _S_IFDIR) != 0) +# endif +# define p_snprintf(buf,sz,fmt,...) _snprintf_s(buf,sz,_TRUNCATE,fmt,__VA_ARGS__) +# else +# define p_snprintf snprintf +# endif + +# ifndef PRIuZ +# define PRIuZ "Iu" +# endif +# ifndef PRIxZ +# define PRIxZ "Ix" +# endif + +# if defined(_MSC_VER) || defined(__MINGW32__) + typedef struct stat STAT_T; +# else + typedef struct _stat STAT_T; +# endif +#else +# include /* waitpid(2) */ +# include +# define _MAIN_CC +# define p_snprintf snprintf +# ifndef PRIuZ +# define PRIuZ "zu" +# endif +# ifndef PRIxZ +# define PRIxZ "zx" +# endif + typedef struct stat STAT_T; +#endif + +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) + +#include "clar.h" + +static void fs_rm(const char *_source); +static void fs_copy(const char *_source, const char *dest); + +#ifdef CLAR_FIXTURE_PATH +static const char * +fixture_path(const char *base, const char *fixture_name); +#endif + +struct clar_error { + const char *file; + const char *function; + size_t line_number; + const char *error_msg; + char *description; + + struct clar_error *next; +}; + +struct clar_explicit { + size_t suite_idx; + const char *filter; + + struct clar_explicit *next; +}; + +struct clar_report { + const char *test; + int test_number; + const char *suite; + + enum cl_test_status status; + time_t start; + double elapsed; + + struct clar_error *errors; + struct clar_error *last_error; + + struct clar_report *next; +}; + +struct clar_summary { + const char *filename; + FILE *fp; +}; + +static struct { + enum cl_test_status test_status; + + const char *active_test; + const char *active_suite; + + int total_skipped; + int total_errors; + + int tests_ran; + int suites_ran; + + enum cl_output_format output_format; + + int report_errors_only; + int exit_on_error; + int verbosity; + + int write_summary; + char *summary_filename; + struct clar_summary *summary; + + struct clar_explicit *explicit; + struct clar_explicit *last_explicit; + + struct clar_report *reports; + struct clar_report *last_report; + + void (*local_cleanup)(void *); + void *local_cleanup_payload; + + jmp_buf trampoline; + int trampoline_enabled; + + cl_trace_cb *pfn_trace_cb; + void *trace_payload; + +} _clar; + +struct clar_func { + const char *name; + void (*ptr)(void); +}; + +struct clar_suite { + const char *name; + struct clar_func initialize; + struct clar_func cleanup; + const struct clar_func *tests; + size_t test_count; + int enabled; +}; + +/* From clar_print_*.c */ +static void clar_print_init(int test_count, int suite_count, const char *suite_names); +static void clar_print_shutdown(int test_count, int suite_count, int error_count); +static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error); +static void clar_print_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status failed); +static void clar_print_onsuite(const char *suite_name, int suite_index); +static void clar_print_onabort(const char *msg, ...); + +/* From clar_sandbox.c */ +static void clar_unsandbox(void); +static int clar_sandbox(void); + +/* From summary.h */ +static struct clar_summary *clar_summary_init(const char *filename); +static int clar_summary_shutdown(struct clar_summary *fp); + +/* Load the declarations for the test suite */ +#include "clar.suite" + + +#define CL_TRACE(ev) \ + do { \ + if (_clar.pfn_trace_cb) \ + _clar.pfn_trace_cb(ev, \ + _clar.active_suite, \ + _clar.active_test, \ + _clar.trace_payload); \ + } while (0) + +void cl_trace_register(cl_trace_cb *cb, void *payload) +{ + _clar.pfn_trace_cb = cb; + _clar.trace_payload = payload; +} + + +/* Core test functions */ +static void +clar_report_errors(struct clar_report *report) +{ + struct clar_error *error; + int i = 1; + + for (error = report->errors; error; error = error->next) + clar_print_error(i++, _clar.last_report, error); +} + +static void +clar_report_all(void) +{ + struct clar_report *report; + struct clar_error *error; + int i = 1; + + for (report = _clar.reports; report; report = report->next) { + if (report->status != CL_TEST_FAILURE) + continue; + + for (error = report->errors; error; error = error->next) + clar_print_error(i++, report, error); + } +} + +#ifdef WIN32 +# define clar_time DWORD + +static void clar_time_now(clar_time *out) +{ + *out = GetTickCount(); +} + +static double clar_time_diff(clar_time *start, clar_time *end) +{ + return ((double)*end - (double)*start) / 1000; +} +#else +# include + +# define clar_time struct timeval + +static void clar_time_now(clar_time *out) +{ + struct timezone tz; + + gettimeofday(out, &tz); +} + +static double clar_time_diff(clar_time *start, clar_time *end) +{ + return ((double)end->tv_sec + (double)end->tv_usec / 1.0E6) - + ((double)start->tv_sec + (double)start->tv_usec / 1.0E6); +} +#endif + +static void +clar_run_test( + const struct clar_suite *suite, + const struct clar_func *test, + const struct clar_func *initialize, + const struct clar_func *cleanup) +{ + clar_time start, end; + + _clar.trampoline_enabled = 1; + + CL_TRACE(CL_TRACE__TEST__BEGIN); + + _clar.last_report->start = time(NULL); + clar_time_now(&start); + + if (setjmp(_clar.trampoline) == 0) { + if (initialize->ptr != NULL) + initialize->ptr(); + + CL_TRACE(CL_TRACE__TEST__RUN_BEGIN); + test->ptr(); + CL_TRACE(CL_TRACE__TEST__RUN_END); + } + + clar_time_now(&end); + + _clar.trampoline_enabled = 0; + + if (_clar.last_report->status == CL_TEST_NOTRUN) + _clar.last_report->status = CL_TEST_OK; + + _clar.last_report->elapsed = clar_time_diff(&start, &end); + + if (_clar.local_cleanup != NULL) + _clar.local_cleanup(_clar.local_cleanup_payload); + + if (cleanup->ptr != NULL) + cleanup->ptr(); + + CL_TRACE(CL_TRACE__TEST__END); + + _clar.tests_ran++; + + /* remove any local-set cleanup methods */ + _clar.local_cleanup = NULL; + _clar.local_cleanup_payload = NULL; + + if (_clar.report_errors_only) { + clar_report_errors(_clar.last_report); + } else { + clar_print_ontest(suite->name, test->name, _clar.tests_ran, _clar.last_report->status); + } +} + +static void +clar_run_suite(const struct clar_suite *suite, const char *filter) +{ + const struct clar_func *test = suite->tests; + size_t i, matchlen; + struct clar_report *report; + int exact = 0; + + if (!suite->enabled) + return; + + if (_clar.exit_on_error && _clar.total_errors) + return; + + if (!_clar.report_errors_only) + clar_print_onsuite(suite->name, ++_clar.suites_ran); + + _clar.active_suite = suite->name; + _clar.active_test = NULL; + CL_TRACE(CL_TRACE__SUITE_BEGIN); + + if (filter) { + size_t suitelen = strlen(suite->name); + matchlen = strlen(filter); + if (matchlen <= suitelen) { + filter = NULL; + } else { + filter += suitelen; + while (*filter == ':') + ++filter; + matchlen = strlen(filter); + + if (matchlen && filter[matchlen - 1] == '$') { + exact = 1; + matchlen--; + } + } + } + + for (i = 0; i < suite->test_count; ++i) { + if (filter && strncmp(test[i].name, filter, matchlen)) + continue; + + if (exact && strlen(test[i].name) != matchlen) + continue; + + _clar.active_test = test[i].name; + + report = calloc(1, sizeof(struct clar_report)); + report->suite = _clar.active_suite; + report->test = _clar.active_test; + report->test_number = _clar.tests_ran; + report->status = CL_TEST_NOTRUN; + + if (_clar.reports == NULL) + _clar.reports = report; + + if (_clar.last_report != NULL) + _clar.last_report->next = report; + + _clar.last_report = report; + + clar_run_test(suite, &test[i], &suite->initialize, &suite->cleanup); + + if (_clar.exit_on_error && _clar.total_errors) + return; + } + + _clar.active_test = NULL; + CL_TRACE(CL_TRACE__SUITE_END); +} + +static void +clar_usage(const char *arg) +{ + printf("Usage: %s [options]\n\n", arg); + printf("Options:\n"); + printf(" -sname Run only the suite with `name` (can go to individual test name)\n"); + printf(" -iname Include the suite with `name`\n"); + printf(" -xname Exclude the suite with `name`\n"); + printf(" -v Increase verbosity (show suite names)\n"); + printf(" -q Only report tests that had an error\n"); + printf(" -Q Quit as soon as a test fails\n"); + printf(" -t Display results in tap format\n"); + printf(" -l Print suite names\n"); + printf(" -r[filename] Write summary file (to the optional filename)\n"); + exit(-1); +} + +static void +clar_parse_args(int argc, char **argv) +{ + int i; + + /* Verify options before execute */ + for (i = 1; i < argc; ++i) { + char *argument = argv[i]; + + if (argument[0] != '-' || argument[1] == '\0' + || strchr("sixvqQtlr", argument[1]) == NULL) { + clar_usage(argv[0]); + } + } + + for (i = 1; i < argc; ++i) { + char *argument = argv[i]; + + switch (argument[1]) { + case 's': + case 'i': + case 'x': { /* given suite name */ + int offset = (argument[2] == '=') ? 3 : 2, found = 0; + char action = argument[1]; + size_t j, arglen, suitelen, cmplen; + + argument += offset; + arglen = strlen(argument); + + if (arglen == 0) + clar_usage(argv[0]); + + for (j = 0; j < _clar_suite_count; ++j) { + suitelen = strlen(_clar_suites[j].name); + cmplen = (arglen < suitelen) ? arglen : suitelen; + + if (strncmp(argument, _clar_suites[j].name, cmplen) == 0) { + int exact = (arglen >= suitelen); + + /* Do we have a real suite prefix separated by a + * trailing '::' or just a matching substring? */ + if (arglen > suitelen && (argument[suitelen] != ':' + || argument[suitelen + 1] != ':')) + continue; + + ++found; + + if (!exact) + _clar.verbosity = MAX(_clar.verbosity, 1); + + switch (action) { + case 's': { + struct clar_explicit *explicit = + calloc(1, sizeof(struct clar_explicit)); + assert(explicit); + + explicit->suite_idx = j; + explicit->filter = argument; + + if (_clar.explicit == NULL) + _clar.explicit = explicit; + + if (_clar.last_explicit != NULL) + _clar.last_explicit->next = explicit; + + _clar_suites[j].enabled = 1; + _clar.last_explicit = explicit; + break; + } + case 'i': _clar_suites[j].enabled = 1; break; + case 'x': _clar_suites[j].enabled = 0; break; + } + + if (exact) + break; + } + } + + if (!found) { + clar_print_onabort("No suite matching '%s' found.\n", argument); + exit(-1); + } + break; + } + + case 'q': + _clar.report_errors_only = 1; + break; + + case 'Q': + _clar.exit_on_error = 1; + break; + + case 't': + _clar.output_format = CL_OUTPUT_TAP; + break; + + case 'l': { + size_t j; + printf("Test suites (use -s to run just one):\n"); + for (j = 0; j < _clar_suite_count; ++j) + printf(" %3d: %s\n", (int)j, _clar_suites[j].name); + + exit(0); + } + + case 'v': + _clar.verbosity++; + break; + + case 'r': + _clar.write_summary = 1; + free(_clar.summary_filename); + _clar.summary_filename = *(argument + 2) ? strdup(argument + 2) : NULL; + break; + + default: + assert(!"Unexpected commandline argument!"); + } + } +} + +void +clar_test_init(int argc, char **argv) +{ + const char *summary_env; + + if (argc > 1) + clar_parse_args(argc, argv); + + clar_print_init( + (int)_clar_callback_count, + (int)_clar_suite_count, + "" + ); + + if (!_clar.summary_filename && + (summary_env = getenv("CLAR_SUMMARY")) != NULL) { + _clar.write_summary = 1; + _clar.summary_filename = strdup(summary_env); + } + + if (_clar.write_summary && !_clar.summary_filename) + _clar.summary_filename = strdup("summary.xml"); + + if (_clar.write_summary && + !(_clar.summary = clar_summary_init(_clar.summary_filename))) { + clar_print_onabort("Failed to open the summary file\n"); + exit(-1); + } + + if (clar_sandbox() < 0) { + clar_print_onabort("Failed to sandbox the test runner.\n"); + exit(-1); + } +} + +int +clar_test_run(void) +{ + size_t i; + struct clar_explicit *explicit; + + if (_clar.explicit) { + for (explicit = _clar.explicit; explicit; explicit = explicit->next) + clar_run_suite(&_clar_suites[explicit->suite_idx], explicit->filter); + } else { + for (i = 0; i < _clar_suite_count; ++i) + clar_run_suite(&_clar_suites[i], NULL); + } + + return _clar.total_errors; +} + +void +clar_test_shutdown(void) +{ + struct clar_explicit *explicit, *explicit_next; + struct clar_report *report, *report_next; + + clar_print_shutdown( + _clar.tests_ran, + (int)_clar_suite_count, + _clar.total_errors + ); + + clar_unsandbox(); + + if (_clar.write_summary && clar_summary_shutdown(_clar.summary) < 0) { + clar_print_onabort("Failed to write the summary file\n"); + exit(-1); + } + + for (explicit = _clar.explicit; explicit; explicit = explicit_next) { + explicit_next = explicit->next; + free(explicit); + } + + for (report = _clar.reports; report; report = report_next) { + report_next = report->next; + free(report); + } + + free(_clar.summary_filename); +} + +int +clar_test(int argc, char **argv) +{ + int errors; + + clar_test_init(argc, argv); + errors = clar_test_run(); + clar_test_shutdown(); + + return errors; +} + +static void abort_test(void) +{ + if (!_clar.trampoline_enabled) { + clar_print_onabort( + "Fatal error: a cleanup method raised an exception."); + clar_report_errors(_clar.last_report); + exit(-1); + } + + CL_TRACE(CL_TRACE__TEST__LONGJMP); + longjmp(_clar.trampoline, -1); +} + +void clar__skip(void) +{ + _clar.last_report->status = CL_TEST_SKIP; + _clar.total_skipped++; + abort_test(); +} + +void clar__fail( + const char *file, + const char *function, + size_t line, + const char *error_msg, + const char *description, + int should_abort) +{ + struct clar_error *error = calloc(1, sizeof(struct clar_error)); + + if (_clar.last_report->errors == NULL) + _clar.last_report->errors = error; + + if (_clar.last_report->last_error != NULL) + _clar.last_report->last_error->next = error; + + _clar.last_report->last_error = error; + + error->file = file; + error->function = function; + error->line_number = line; + error->error_msg = error_msg; + + if (description != NULL) + error->description = strdup(description); + + _clar.total_errors++; + _clar.last_report->status = CL_TEST_FAILURE; + + if (should_abort) + abort_test(); +} + +void clar__assert( + int condition, + const char *file, + const char *function, + size_t line, + const char *error_msg, + const char *description, + int should_abort) +{ + if (condition) + return; + + clar__fail(file, function, line, error_msg, description, should_abort); +} + +void clar__assert_equal( + const char *file, + const char *function, + size_t line, + const char *err, + int should_abort, + const char *fmt, + ...) +{ + va_list args; + char buf[4096]; + int is_equal = 1; + + va_start(args, fmt); + + if (!strcmp("%s", fmt)) { + const char *s1 = va_arg(args, const char *); + const char *s2 = va_arg(args, const char *); + is_equal = (!s1 || !s2) ? (s1 == s2) : !strcmp(s1, s2); + + if (!is_equal) { + if (s1 && s2) { + int pos; + for (pos = 0; s1[pos] == s2[pos] && s1[pos] && s2[pos]; ++pos) + /* find differing byte offset */; + p_snprintf(buf, sizeof(buf), "'%s' != '%s' (at byte %d)", + s1, s2, pos); + } else { + p_snprintf(buf, sizeof(buf), "'%s' != '%s'", s1, s2); + } + } + } + else if(!strcmp("%.*s", fmt)) { + const char *s1 = va_arg(args, const char *); + const char *s2 = va_arg(args, const char *); + int len = va_arg(args, int); + is_equal = (!s1 || !s2) ? (s1 == s2) : !strncmp(s1, s2, len); + + if (!is_equal) { + if (s1 && s2) { + int pos; + for (pos = 0; s1[pos] == s2[pos] && pos < len; ++pos) + /* find differing byte offset */; + p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s' (at byte %d)", + len, s1, len, s2, pos); + } else { + p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s'", len, s1, len, s2); + } + } + } + else if (!strcmp("%ls", fmt)) { + const wchar_t *wcs1 = va_arg(args, const wchar_t *); + const wchar_t *wcs2 = va_arg(args, const wchar_t *); + is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcscmp(wcs1, wcs2); + + if (!is_equal) { + if (wcs1 && wcs2) { + int pos; + for (pos = 0; wcs1[pos] == wcs2[pos] && wcs1[pos] && wcs2[pos]; ++pos) + /* find differing byte offset */; + p_snprintf(buf, sizeof(buf), "'%ls' != '%ls' (at byte %d)", + wcs1, wcs2, pos); + } else { + p_snprintf(buf, sizeof(buf), "'%ls' != '%ls'", wcs1, wcs2); + } + } + } + else if(!strcmp("%.*ls", fmt)) { + const wchar_t *wcs1 = va_arg(args, const wchar_t *); + const wchar_t *wcs2 = va_arg(args, const wchar_t *); + int len = va_arg(args, int); + is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcsncmp(wcs1, wcs2, len); + + if (!is_equal) { + if (wcs1 && wcs2) { + int pos; + for (pos = 0; wcs1[pos] == wcs2[pos] && pos < len; ++pos) + /* find differing byte offset */; + p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls' (at byte %d)", + len, wcs1, len, wcs2, pos); + } else { + p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls'", len, wcs1, len, wcs2); + } + } + } + else if (!strcmp("%"PRIuZ, fmt) || !strcmp("%"PRIxZ, fmt)) { + size_t sz1 = va_arg(args, size_t), sz2 = va_arg(args, size_t); + is_equal = (sz1 == sz2); + if (!is_equal) { + int offset = p_snprintf(buf, sizeof(buf), fmt, sz1); + strncat(buf, " != ", sizeof(buf) - offset); + p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, sz2); + } + } + else if (!strcmp("%p", fmt)) { + void *p1 = va_arg(args, void *), *p2 = va_arg(args, void *); + is_equal = (p1 == p2); + if (!is_equal) + p_snprintf(buf, sizeof(buf), "%p != %p", p1, p2); + } + else { + int i1 = va_arg(args, int), i2 = va_arg(args, int); + is_equal = (i1 == i2); + if (!is_equal) { + int offset = p_snprintf(buf, sizeof(buf), fmt, i1); + strncat(buf, " != ", sizeof(buf) - offset); + p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, i2); + } + } + + va_end(args); + + if (!is_equal) + clar__fail(file, function, line, err, buf, should_abort); +} + +void cl_set_cleanup(void (*cleanup)(void *), void *opaque) +{ + _clar.local_cleanup = cleanup; + _clar.local_cleanup_payload = opaque; +} + +#include "clar/sandbox.h" +#include "clar/fixtures.h" +#include "clar/fs.h" +#include "clar/print.h" +#include "clar/summary.h" diff --git a/t/unit-tests/clar/clar.h b/t/unit-tests/clar/clar.h new file mode 100644 index 00000000000..8c22382bd56 --- /dev/null +++ b/t/unit-tests/clar/clar.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) Vicent Marti. All rights reserved. + * + * This file is part of clar, distributed under the ISC license. + * For full terms see the included COPYING file. + */ +#ifndef __CLAR_TEST_H__ +#define __CLAR_TEST_H__ + +#include + +enum cl_test_status { + CL_TEST_OK, + CL_TEST_FAILURE, + CL_TEST_SKIP, + CL_TEST_NOTRUN, +}; + +enum cl_output_format { + CL_OUTPUT_CLAP, + CL_OUTPUT_TAP, +}; + +/** Setup clar environment */ +void clar_test_init(int argc, char *argv[]); +int clar_test_run(void); +void clar_test_shutdown(void); + +/** One shot setup & run */ +int clar_test(int argc, char *argv[]); + +const char *clar_sandbox_path(void); + +void cl_set_cleanup(void (*cleanup)(void *), void *opaque); +void cl_fs_cleanup(void); + +/** + * cl_trace_* is a hook to provide a simple global tracing + * mechanism. + * + * The goal here is to let main() provide clar-proper + * with a callback to optionally write log info for + * test operations into the same stream used by their + * actual tests. This would let them print test names + * and maybe performance data as they choose. + * + * The goal is NOT to alter the flow of control or to + * override test selection/skipping. (So the callback + * does not return a value.) + * + * The goal is NOT to duplicate the existing + * pass/fail/skip reporting. (So the callback + * does not accept a status/errorcode argument.) + * + */ +typedef enum cl_trace_event { + CL_TRACE__SUITE_BEGIN, + CL_TRACE__SUITE_END, + CL_TRACE__TEST__BEGIN, + CL_TRACE__TEST__END, + CL_TRACE__TEST__RUN_BEGIN, + CL_TRACE__TEST__RUN_END, + CL_TRACE__TEST__LONGJMP, +} cl_trace_event; + +typedef void (cl_trace_cb)( + cl_trace_event ev, + const char *suite_name, + const char *test_name, + void *payload); + +/** + * Register a callback into CLAR to send global trace events. + * Pass NULL to disable. + */ +void cl_trace_register(cl_trace_cb *cb, void *payload); + + +#ifdef CLAR_FIXTURE_PATH +const char *cl_fixture(const char *fixture_name); +void cl_fixture_sandbox(const char *fixture_name); +void cl_fixture_cleanup(const char *fixture_name); +const char *cl_fixture_basename(const char *fixture_name); +#endif + +/** + * Assertion macros with explicit error message + */ +#define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 1) +#define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 1) +#define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 1) + +/** + * Check macros with explicit error message + */ +#define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 0) +#define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 0) +#define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 0) + +/** + * Assertion macros with no error message + */ +#define cl_must_pass(expr) cl_must_pass_(expr, NULL) +#define cl_must_fail(expr) cl_must_fail_(expr, NULL) +#define cl_assert(expr) cl_assert_(expr, NULL) + +/** + * Check macros with no error message + */ +#define cl_check_pass(expr) cl_check_pass_(expr, NULL) +#define cl_check_fail(expr) cl_check_fail_(expr, NULL) +#define cl_check(expr) cl_check_(expr, NULL) + +/** + * Forced failure/warning + */ +#define cl_fail(desc) clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1) +#define cl_warning(desc) clar__fail(__FILE__, __func__, __LINE__, "Warning during test execution:", desc, 0) + +#define cl_skip() clar__skip() + +/** + * Typed assertion macros + */ +#define cl_assert_equal_s(s1,s2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2)) +#define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2)) + +#define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2)) +#define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2)) + +#define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len)) +#define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len)) + +#define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len)) +#define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len)) + +#define cl_assert_equal_i(i1,i2) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2)) +#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2)) +#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2)) + +#define cl_assert_equal_b(b1,b2) clar__assert_equal(__FILE__,__func__,__LINE__,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0)) + +#define cl_assert_equal_p(p1,p2) clar__assert_equal(__FILE__,__func__,__LINE__,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2)) + +void clar__skip(void); + +void clar__fail( + const char *file, + const char *func, + size_t line, + const char *error, + const char *description, + int should_abort); + +void clar__assert( + int condition, + const char *file, + const char *func, + size_t line, + const char *error, + const char *description, + int should_abort); + +void clar__assert_equal( + const char *file, + const char *func, + size_t line, + const char *err, + int should_abort, + const char *fmt, + ...); + +#endif diff --git a/t/unit-tests/clar/clar/fixtures.h b/t/unit-tests/clar/clar/fixtures.h new file mode 100644 index 00000000000..6ec6423484d --- /dev/null +++ b/t/unit-tests/clar/clar/fixtures.h @@ -0,0 +1,50 @@ +#ifdef CLAR_FIXTURE_PATH +static const char * +fixture_path(const char *base, const char *fixture_name) +{ + static char _path[4096]; + size_t root_len; + + root_len = strlen(base); + strncpy(_path, base, sizeof(_path)); + + if (_path[root_len - 1] != '/') + _path[root_len++] = '/'; + + if (fixture_name[0] == '/') + fixture_name++; + + strncpy(_path + root_len, + fixture_name, + sizeof(_path) - root_len); + + return _path; +} + +const char *cl_fixture(const char *fixture_name) +{ + return fixture_path(CLAR_FIXTURE_PATH, fixture_name); +} + +void cl_fixture_sandbox(const char *fixture_name) +{ + fs_copy(cl_fixture(fixture_name), _clar_path); +} + +const char *cl_fixture_basename(const char *fixture_name) +{ + const char *p; + + for (p = fixture_name; *p; p++) { + if (p[0] == '/' && p[1] && p[1] != '/') + fixture_name = p+1; + } + + return fixture_name; +} + +void cl_fixture_cleanup(const char *fixture_name) +{ + fs_rm(fixture_path(_clar_path, cl_fixture_basename(fixture_name))); +} +#endif diff --git a/t/unit-tests/clar/clar/fs.h b/t/unit-tests/clar/clar/fs.h new file mode 100644 index 00000000000..3e39890bd3e --- /dev/null +++ b/t/unit-tests/clar/clar/fs.h @@ -0,0 +1,522 @@ +/* + * By default, use a read/write loop to copy files on POSIX systems. + * On Linux, use sendfile by default as it's slightly faster. On + * macOS, we avoid fcopyfile by default because it's slightly slower. + */ +#undef USE_FCOPYFILE +#define USE_SENDFILE 1 + +#ifdef _WIN32 + +#ifdef CLAR_WIN32_LONGPATHS +# define CLAR_MAX_PATH 4096 +#else +# define CLAR_MAX_PATH MAX_PATH +#endif + +#define RM_RETRY_COUNT 5 +#define RM_RETRY_DELAY 10 + +#ifdef __MINGW32__ + +/* These security-enhanced functions are not available + * in MinGW, so just use the vanilla ones */ +#define wcscpy_s(a, b, c) wcscpy((a), (c)) +#define wcscat_s(a, b, c) wcscat((a), (c)) + +#endif /* __MINGW32__ */ + +static int +fs__dotordotdot(WCHAR *_tocheck) +{ + return _tocheck[0] == '.' && + (_tocheck[1] == '\0' || + (_tocheck[1] == '.' && _tocheck[2] == '\0')); +} + +static int +fs_rmdir_rmdir(WCHAR *_wpath) +{ + unsigned retries = 1; + + while (!RemoveDirectoryW(_wpath)) { + /* Only retry when we have retries remaining, and the + * error was ERROR_DIR_NOT_EMPTY. */ + if (retries++ > RM_RETRY_COUNT || + ERROR_DIR_NOT_EMPTY != GetLastError()) + return -1; + + /* Give whatever has a handle to a child item some time + * to release it before trying again */ + Sleep(RM_RETRY_DELAY * retries * retries); + } + + return 0; +} + +static void translate_path(WCHAR *path, size_t path_size) +{ + size_t path_len, i; + + if (wcsncmp(path, L"\\\\?\\", 4) == 0) + return; + + path_len = wcslen(path); + cl_assert(path_size > path_len + 4); + + for (i = path_len; i > 0; i--) { + WCHAR c = path[i - 1]; + + if (c == L'/') + path[i + 3] = L'\\'; + else + path[i + 3] = path[i - 1]; + } + + path[0] = L'\\'; + path[1] = L'\\'; + path[2] = L'?'; + path[3] = L'\\'; + path[path_len + 4] = L'\0'; +} + +static void +fs_rmdir_helper(WCHAR *_wsource) +{ + WCHAR buffer[CLAR_MAX_PATH]; + HANDLE find_handle; + WIN32_FIND_DATAW find_data; + size_t buffer_prefix_len; + + /* Set up the buffer and capture the length */ + wcscpy_s(buffer, CLAR_MAX_PATH, _wsource); + translate_path(buffer, CLAR_MAX_PATH); + wcscat_s(buffer, CLAR_MAX_PATH, L"\\"); + buffer_prefix_len = wcslen(buffer); + + /* FindFirstFile needs a wildcard to match multiple items */ + wcscat_s(buffer, CLAR_MAX_PATH, L"*"); + find_handle = FindFirstFileW(buffer, &find_data); + cl_assert(INVALID_HANDLE_VALUE != find_handle); + + do { + /* FindFirstFile/FindNextFile gives back . and .. + * entries at the beginning */ + if (fs__dotordotdot(find_data.cFileName)) + continue; + + wcscpy_s(buffer + buffer_prefix_len, CLAR_MAX_PATH - buffer_prefix_len, find_data.cFileName); + + if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes) + fs_rmdir_helper(buffer); + else { + /* If set, the +R bit must be cleared before deleting */ + if (FILE_ATTRIBUTE_READONLY & find_data.dwFileAttributes) + cl_assert(SetFileAttributesW(buffer, find_data.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)); + + cl_assert(DeleteFileW(buffer)); + } + } + while (FindNextFileW(find_handle, &find_data)); + + /* Ensure that we successfully completed the enumeration */ + cl_assert(ERROR_NO_MORE_FILES == GetLastError()); + + /* Close the find handle */ + FindClose(find_handle); + + /* Now that the directory is empty, remove it */ + cl_assert(0 == fs_rmdir_rmdir(_wsource)); +} + +static int +fs_rm_wait(WCHAR *_wpath) +{ + unsigned retries = 1; + DWORD last_error; + + do { + if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(_wpath)) + last_error = GetLastError(); + else + last_error = ERROR_SUCCESS; + + /* Is the item gone? */ + if (ERROR_FILE_NOT_FOUND == last_error || + ERROR_PATH_NOT_FOUND == last_error) + return 0; + + Sleep(RM_RETRY_DELAY * retries * retries); + } + while (retries++ <= RM_RETRY_COUNT); + + return -1; +} + +static void +fs_rm(const char *_source) +{ + WCHAR wsource[CLAR_MAX_PATH]; + DWORD attrs; + + /* The input path is UTF-8. Convert it to wide characters + * for use with the Windows API */ + cl_assert(MultiByteToWideChar(CP_UTF8, + MB_ERR_INVALID_CHARS, + _source, + -1, /* Indicates NULL termination */ + wsource, + CLAR_MAX_PATH)); + + translate_path(wsource, CLAR_MAX_PATH); + + /* Does the item exist? If not, we have no work to do */ + attrs = GetFileAttributesW(wsource); + + if (INVALID_FILE_ATTRIBUTES == attrs) + return; + + if (FILE_ATTRIBUTE_DIRECTORY & attrs) + fs_rmdir_helper(wsource); + else { + /* The item is a file. Strip the +R bit */ + if (FILE_ATTRIBUTE_READONLY & attrs) + cl_assert(SetFileAttributesW(wsource, attrs & ~FILE_ATTRIBUTE_READONLY)); + + cl_assert(DeleteFileW(wsource)); + } + + /* Wait for the DeleteFile or RemoveDirectory call to complete */ + cl_assert(0 == fs_rm_wait(wsource)); +} + +static void +fs_copydir_helper(WCHAR *_wsource, WCHAR *_wdest) +{ + WCHAR buf_source[CLAR_MAX_PATH], buf_dest[CLAR_MAX_PATH]; + HANDLE find_handle; + WIN32_FIND_DATAW find_data; + size_t buf_source_prefix_len, buf_dest_prefix_len; + + wcscpy_s(buf_source, CLAR_MAX_PATH, _wsource); + wcscat_s(buf_source, CLAR_MAX_PATH, L"\\"); + translate_path(buf_source, CLAR_MAX_PATH); + buf_source_prefix_len = wcslen(buf_source); + + wcscpy_s(buf_dest, CLAR_MAX_PATH, _wdest); + wcscat_s(buf_dest, CLAR_MAX_PATH, L"\\"); + translate_path(buf_dest, CLAR_MAX_PATH); + buf_dest_prefix_len = wcslen(buf_dest); + + /* Get an enumerator for the items in the source. */ + wcscat_s(buf_source, CLAR_MAX_PATH, L"*"); + find_handle = FindFirstFileW(buf_source, &find_data); + cl_assert(INVALID_HANDLE_VALUE != find_handle); + + /* Create the target directory. */ + cl_assert(CreateDirectoryW(_wdest, NULL)); + + do { + /* FindFirstFile/FindNextFile gives back . and .. + * entries at the beginning */ + if (fs__dotordotdot(find_data.cFileName)) + continue; + + wcscpy_s(buf_source + buf_source_prefix_len, CLAR_MAX_PATH - buf_source_prefix_len, find_data.cFileName); + wcscpy_s(buf_dest + buf_dest_prefix_len, CLAR_MAX_PATH - buf_dest_prefix_len, find_data.cFileName); + + if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes) + fs_copydir_helper(buf_source, buf_dest); + else + cl_assert(CopyFileW(buf_source, buf_dest, TRUE)); + } + while (FindNextFileW(find_handle, &find_data)); + + /* Ensure that we successfully completed the enumeration */ + cl_assert(ERROR_NO_MORE_FILES == GetLastError()); + + /* Close the find handle */ + FindClose(find_handle); +} + +static void +fs_copy(const char *_source, const char *_dest) +{ + WCHAR wsource[CLAR_MAX_PATH], wdest[CLAR_MAX_PATH]; + DWORD source_attrs, dest_attrs; + HANDLE find_handle; + WIN32_FIND_DATAW find_data; + + /* The input paths are UTF-8. Convert them to wide characters + * for use with the Windows API. */ + cl_assert(MultiByteToWideChar(CP_UTF8, + MB_ERR_INVALID_CHARS, + _source, + -1, + wsource, + CLAR_MAX_PATH)); + + cl_assert(MultiByteToWideChar(CP_UTF8, + MB_ERR_INVALID_CHARS, + _dest, + -1, + wdest, + CLAR_MAX_PATH)); + + translate_path(wsource, CLAR_MAX_PATH); + translate_path(wdest, CLAR_MAX_PATH); + + /* Check the source for existence */ + source_attrs = GetFileAttributesW(wsource); + cl_assert(INVALID_FILE_ATTRIBUTES != source_attrs); + + /* Check the target for existence */ + dest_attrs = GetFileAttributesW(wdest); + + if (INVALID_FILE_ATTRIBUTES != dest_attrs) { + /* Target exists; append last path part of source to target. + * Use FindFirstFile to parse the path */ + find_handle = FindFirstFileW(wsource, &find_data); + cl_assert(INVALID_HANDLE_VALUE != find_handle); + wcscat_s(wdest, CLAR_MAX_PATH, L"\\"); + wcscat_s(wdest, CLAR_MAX_PATH, find_data.cFileName); + FindClose(find_handle); + + /* Check the new target for existence */ + cl_assert(INVALID_FILE_ATTRIBUTES == GetFileAttributesW(wdest)); + } + + if (FILE_ATTRIBUTE_DIRECTORY & source_attrs) + fs_copydir_helper(wsource, wdest); + else + cl_assert(CopyFileW(wsource, wdest, TRUE)); +} + +void +cl_fs_cleanup(void) +{ +#ifdef CLAR_FIXTURE_PATH + fs_rm(fixture_path(_clar_path, "*")); +#endif +} + +#else + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) +# include +#endif + +#if defined(__APPLE__) +# include +#endif + +static void basename_r(const char **out, int *out_len, const char *in) +{ + size_t in_len = strlen(in), start_pos; + + for (in_len = strlen(in); in_len; in_len--) { + if (in[in_len - 1] != '/') + break; + } + + for (start_pos = in_len; start_pos; start_pos--) { + if (in[start_pos - 1] == '/') + break; + } + + cl_assert(in_len - start_pos < INT_MAX); + + if (in_len - start_pos > 0) { + *out = &in[start_pos]; + *out_len = (in_len - start_pos); + } else { + *out = "/"; + *out_len = 1; + } +} + +static char *joinpath(const char *dir, const char *base, int base_len) +{ + char *out; + int len; + + if (base_len == -1) { + size_t bl = strlen(base); + + cl_assert(bl < INT_MAX); + base_len = (int)bl; + } + + len = strlen(dir) + base_len + 2; + cl_assert(len > 0); + + cl_assert(out = malloc(len)); + cl_assert(snprintf(out, len, "%s/%.*s", dir, base_len, base) < len); + + return out; +} + +static void +fs_copydir_helper(const char *source, const char *dest, int dest_mode) +{ + DIR *source_dir; + struct dirent *d; + + mkdir(dest, dest_mode); + + cl_assert_(source_dir = opendir(source), "Could not open source dir"); + while ((d = (errno = 0, readdir(source_dir))) != NULL) { + char *child; + + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + + child = joinpath(source, d->d_name, -1); + fs_copy(child, dest); + free(child); + } + + cl_assert_(errno == 0, "Failed to iterate source dir"); + + closedir(source_dir); +} + +static void +fs_copyfile_helper(const char *source, size_t source_len, const char *dest, int dest_mode) +{ + int in, out; + + cl_must_pass((in = open(source, O_RDONLY))); + cl_must_pass((out = open(dest, O_WRONLY|O_CREAT|O_TRUNC, dest_mode))); + +#if USE_FCOPYFILE && defined(__APPLE__) + ((void)(source_len)); /* unused */ + cl_must_pass(fcopyfile(in, out, 0, COPYFILE_DATA)); +#elif USE_SENDFILE && defined(__linux__) + { + ssize_t ret = 0; + + while (source_len && (ret = sendfile(out, in, NULL, source_len)) > 0) { + source_len -= (size_t)ret; + } + cl_assert(ret >= 0); + } +#else + { + char buf[131072]; + ssize_t ret; + + ((void)(source_len)); /* unused */ + + while ((ret = read(in, buf, sizeof(buf))) > 0) { + size_t len = (size_t)ret; + + while (len && (ret = write(out, buf, len)) > 0) { + cl_assert(ret <= (ssize_t)len); + len -= ret; + } + cl_assert(ret >= 0); + } + cl_assert(ret == 0); + } +#endif + + close(in); + close(out); +} + +static void +fs_copy(const char *source, const char *_dest) +{ + char *dbuf = NULL; + const char *dest = NULL; + struct stat source_st, dest_st; + + cl_must_pass_(lstat(source, &source_st), "Failed to stat copy source"); + + if (lstat(_dest, &dest_st) == 0) { + const char *base; + int base_len; + + /* Target exists and is directory; append basename */ + cl_assert(S_ISDIR(dest_st.st_mode)); + + basename_r(&base, &base_len, source); + cl_assert(base_len < INT_MAX); + + dbuf = joinpath(_dest, base, base_len); + dest = dbuf; + } else if (errno != ENOENT) { + cl_fail("Cannot copy; cannot stat destination"); + } else { + dest = _dest; + } + + if (S_ISDIR(source_st.st_mode)) { + fs_copydir_helper(source, dest, source_st.st_mode); + } else { + fs_copyfile_helper(source, source_st.st_size, dest, source_st.st_mode); + } + + free(dbuf); +} + +static void +fs_rmdir_helper(const char *path) +{ + DIR *dir; + struct dirent *d; + + cl_assert_(dir = opendir(path), "Could not open dir"); + while ((d = (errno = 0, readdir(dir))) != NULL) { + char *child; + + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + + child = joinpath(path, d->d_name, -1); + fs_rm(child); + free(child); + } + + cl_assert_(errno == 0, "Failed to iterate source dir"); + closedir(dir); + + cl_must_pass_(rmdir(path), "Could not remove directory"); +} + +static void +fs_rm(const char *path) +{ + struct stat st; + + if (lstat(path, &st)) { + if (errno == ENOENT) + return; + + cl_fail("Cannot copy; cannot stat destination"); + } + + if (S_ISDIR(st.st_mode)) { + fs_rmdir_helper(path); + } else { + cl_must_pass(unlink(path)); + } +} + +void +cl_fs_cleanup(void) +{ + clar_unsandbox(); + clar_sandbox(); +} +#endif diff --git a/t/unit-tests/clar/clar/print.h b/t/unit-tests/clar/clar/print.h new file mode 100644 index 00000000000..c17e2f693bd --- /dev/null +++ b/t/unit-tests/clar/clar/print.h @@ -0,0 +1,211 @@ +/* clap: clar protocol, the traditional clar output format */ + +static void clar_print_clap_init(int test_count, int suite_count, const char *suite_names) +{ + (void)test_count; + printf("Loaded %d suites: %s\n", (int)suite_count, suite_names); + printf("Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')\n"); +} + +static void clar_print_clap_shutdown(int test_count, int suite_count, int error_count) +{ + (void)test_count; + (void)suite_count; + (void)error_count; + + printf("\n\n"); + clar_report_all(); +} + +static void clar_print_clap_error(int num, const struct clar_report *report, const struct clar_error *error) +{ + printf(" %d) Failure:\n", num); + + printf("%s::%s [%s:%"PRIuZ"]\n", + report->suite, + report->test, + error->file, + error->line_number); + + printf(" %s\n", error->error_msg); + + if (error->description != NULL) + printf(" %s\n", error->description); + + printf("\n"); + fflush(stdout); +} + +static void clar_print_clap_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status status) +{ + (void)test_name; + (void)test_number; + + if (_clar.verbosity > 1) { + printf("%s::%s: ", suite_name, test_name); + + switch (status) { + case CL_TEST_OK: printf("ok\n"); break; + case CL_TEST_FAILURE: printf("fail\n"); break; + case CL_TEST_SKIP: printf("skipped"); break; + case CL_TEST_NOTRUN: printf("notrun"); break; + } + } else { + switch (status) { + case CL_TEST_OK: printf("."); break; + case CL_TEST_FAILURE: printf("F"); break; + case CL_TEST_SKIP: printf("S"); break; + case CL_TEST_NOTRUN: printf("N"); break; + } + + fflush(stdout); + } +} + +static void clar_print_clap_onsuite(const char *suite_name, int suite_index) +{ + if (_clar.verbosity == 1) + printf("\n%s", suite_name); + + (void)suite_index; +} + +static void clar_print_clap_onabort(const char *fmt, va_list arg) +{ + vfprintf(stderr, fmt, arg); +} + +/* tap: test anywhere protocol format */ + +static void clar_print_tap_init(int test_count, int suite_count, const char *suite_names) +{ + (void)test_count; + (void)suite_count; + (void)suite_names; + printf("TAP version 13\n"); +} + +static void clar_print_tap_shutdown(int test_count, int suite_count, int error_count) +{ + (void)suite_count; + (void)error_count; + + printf("1..%d\n", test_count); +} + +static void clar_print_tap_error(int num, const struct clar_report *report, const struct clar_error *error) +{ + (void)num; + (void)report; + (void)error; +} + +static void print_escaped(const char *str) +{ + char *c; + + while ((c = strchr(str, '\'')) != NULL) { + printf("%.*s", (int)(c - str), str); + printf("''"); + str = c + 1; + } + + printf("%s", str); +} + +static void clar_print_tap_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status status) +{ + const struct clar_error *error = _clar.last_report->errors; + + (void)test_name; + (void)test_number; + + switch(status) { + case CL_TEST_OK: + printf("ok %d - %s::%s\n", test_number, suite_name, test_name); + break; + case CL_TEST_FAILURE: + printf("not ok %d - %s::%s\n", test_number, suite_name, test_name); + + printf(" ---\n"); + printf(" reason: |\n"); + printf(" %s\n", error->error_msg); + + if (error->description) + printf(" %s\n", error->description); + + printf(" at:\n"); + printf(" file: '"); print_escaped(error->file); printf("'\n"); + printf(" line: %" PRIuZ "\n", error->line_number); + printf(" function: '%s'\n", error->function); + printf(" ---\n"); + + break; + case CL_TEST_SKIP: + case CL_TEST_NOTRUN: + printf("ok %d - # SKIP %s::%s\n", test_number, suite_name, test_name); + break; + } + + fflush(stdout); +} + +static void clar_print_tap_onsuite(const char *suite_name, int suite_index) +{ + printf("# start of suite %d: %s\n", suite_index, suite_name); +} + +static void clar_print_tap_onabort(const char *fmt, va_list arg) +{ + printf("Bail out! "); + vprintf(fmt, arg); + fflush(stdout); +} + +/* indirection between protocol output selection */ + +#define PRINT(FN, ...) do { \ + switch (_clar.output_format) { \ + case CL_OUTPUT_CLAP: \ + clar_print_clap_##FN (__VA_ARGS__); \ + break; \ + case CL_OUTPUT_TAP: \ + clar_print_tap_##FN (__VA_ARGS__); \ + break; \ + default: \ + abort(); \ + } \ + } while (0) + +static void clar_print_init(int test_count, int suite_count, const char *suite_names) +{ + PRINT(init, test_count, suite_count, suite_names); +} + +static void clar_print_shutdown(int test_count, int suite_count, int error_count) +{ + PRINT(shutdown, test_count, suite_count, error_count); +} + +static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error) +{ + PRINT(error, num, report, error); +} + +static void clar_print_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status status) +{ + PRINT(ontest, suite_name, test_name, test_number, status); +} + +static void clar_print_onsuite(const char *suite_name, int suite_index) +{ + PRINT(onsuite, suite_name, suite_index); +} + +static void clar_print_onabort(const char *msg, ...) +{ + va_list argp; + va_start(argp, msg); + PRINT(onabort, msg, argp); + va_end(argp); +} diff --git a/t/unit-tests/clar/clar/sandbox.h b/t/unit-tests/clar/clar/sandbox.h new file mode 100644 index 00000000000..7c177f35258 --- /dev/null +++ b/t/unit-tests/clar/clar/sandbox.h @@ -0,0 +1,153 @@ +#ifdef __APPLE__ +#include +#endif + +static char _clar_path[4096 + 1]; + +static int +is_valid_tmp_path(const char *path) +{ + STAT_T st; + + if (stat(path, &st) != 0) + return 0; + + if (!S_ISDIR(st.st_mode)) + return 0; + + return (access(path, W_OK) == 0); +} + +static int +find_tmp_path(char *buffer, size_t length) +{ +#ifndef _WIN32 + static const size_t var_count = 5; + static const char *env_vars[] = { + "CLAR_TMP", "TMPDIR", "TMP", "TEMP", "USERPROFILE" + }; + + size_t i; + + for (i = 0; i < var_count; ++i) { + const char *env = getenv(env_vars[i]); + if (!env) + continue; + + if (is_valid_tmp_path(env)) { +#ifdef __APPLE__ + if (length >= PATH_MAX && realpath(env, buffer) != NULL) + return 0; +#endif + strncpy(buffer, env, length - 1); + buffer[length - 1] = '\0'; + return 0; + } + } + + /* If the environment doesn't say anything, try to use /tmp */ + if (is_valid_tmp_path("/tmp")) { +#ifdef __APPLE__ + if (length >= PATH_MAX && realpath("/tmp", buffer) != NULL) + return 0; +#endif + strncpy(buffer, "/tmp", length - 1); + buffer[length - 1] = '\0'; + return 0; + } + +#else + DWORD env_len = GetEnvironmentVariable("CLAR_TMP", buffer, (DWORD)length); + if (env_len > 0 && env_len < (DWORD)length) + return 0; + + if (GetTempPath((DWORD)length, buffer)) + return 0; +#endif + + /* This system doesn't like us, try to use the current directory */ + if (is_valid_tmp_path(".")) { + strncpy(buffer, ".", length - 1); + buffer[length - 1] = '\0'; + return 0; + } + + return -1; +} + +static void clar_unsandbox(void) +{ + if (_clar_path[0] == '\0') + return; + + cl_must_pass(chdir("..")); + + fs_rm(_clar_path); +} + +static int build_sandbox_path(void) +{ +#ifdef CLAR_TMPDIR + const char path_tail[] = CLAR_TMPDIR "_XXXXXX"; +#else + const char path_tail[] = "clar_tmp_XXXXXX"; +#endif + + size_t len; + + if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0) + return -1; + + len = strlen(_clar_path); + +#ifdef _WIN32 + { /* normalize path to POSIX forward slashes */ + size_t i; + for (i = 0; i < len; ++i) { + if (_clar_path[i] == '\\') + _clar_path[i] = '/'; + } + } +#endif + + if (_clar_path[len - 1] != '/') { + _clar_path[len++] = '/'; + } + + strncpy(_clar_path + len, path_tail, sizeof(_clar_path) - len); + +#if defined(__MINGW32__) + if (_mktemp(_clar_path) == NULL) + return -1; + + if (mkdir(_clar_path, 0700) != 0) + return -1; +#elif defined(_WIN32) + if (_mktemp_s(_clar_path, sizeof(_clar_path)) != 0) + return -1; + + if (mkdir(_clar_path, 0700) != 0) + return -1; +#else + if (mkdtemp(_clar_path) == NULL) + return -1; +#endif + + return 0; +} + +static int clar_sandbox(void) +{ + if (_clar_path[0] == '\0' && build_sandbox_path() < 0) + return -1; + + if (chdir(_clar_path) != 0) + return -1; + + return 0; +} + +const char *clar_sandbox_path(void) +{ + return _clar_path; +} diff --git a/t/unit-tests/clar/clar/summary.h b/t/unit-tests/clar/clar/summary.h new file mode 100644 index 00000000000..4dd352e28b8 --- /dev/null +++ b/t/unit-tests/clar/clar/summary.h @@ -0,0 +1,143 @@ + +#include +#include + +static int clar_summary_close_tag( + struct clar_summary *summary, const char *tag, int indent) +{ + const char *indt; + + if (indent == 0) indt = ""; + else if (indent == 1) indt = "\t"; + else indt = "\t\t"; + + return fprintf(summary->fp, "%s\n", indt, tag); +} + +static int clar_summary_testsuites(struct clar_summary *summary) +{ + return fprintf(summary->fp, "\n"); +} + +static int clar_summary_testsuite(struct clar_summary *summary, + int idn, const char *name, time_t timestamp, + int test_count, int fail_count, int error_count) +{ + struct tm *tm = localtime(×tamp); + char iso_dt[20]; + + if (strftime(iso_dt, sizeof(iso_dt), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return -1; + + return fprintf(summary->fp, "\t\n", + idn, name, iso_dt, test_count, fail_count, error_count); +} + +static int clar_summary_testcase(struct clar_summary *summary, + const char *name, const char *classname, double elapsed) +{ + return fprintf(summary->fp, + "\t\t\n", + name, classname, elapsed); +} + +static int clar_summary_failure(struct clar_summary *summary, + const char *type, const char *message, const char *desc) +{ + return fprintf(summary->fp, + "\t\t\t\n", + type, message, desc); +} + +static int clar_summary_skipped(struct clar_summary *summary) +{ + return fprintf(summary->fp, "\t\t\t\n"); +} + +struct clar_summary *clar_summary_init(const char *filename) +{ + struct clar_summary *summary; + FILE *fp; + + if ((fp = fopen(filename, "w")) == NULL) { + perror("fopen"); + return NULL; + } + + if ((summary = malloc(sizeof(struct clar_summary))) == NULL) { + perror("malloc"); + fclose(fp); + return NULL; + } + + summary->filename = filename; + summary->fp = fp; + + return summary; +} + +int clar_summary_shutdown(struct clar_summary *summary) +{ + struct clar_report *report; + const char *last_suite = NULL; + + if (clar_summary_testsuites(summary) < 0) + goto on_error; + + report = _clar.reports; + while (report != NULL) { + struct clar_error *error = report->errors; + + if (last_suite == NULL || strcmp(last_suite, report->suite) != 0) { + if (clar_summary_testsuite(summary, 0, report->suite, + report->start, _clar.tests_ran, _clar.total_errors, 0) < 0) + goto on_error; + } + + last_suite = report->suite; + + clar_summary_testcase(summary, report->test, report->suite, report->elapsed); + + while (error != NULL) { + if (clar_summary_failure(summary, "assert", + error->error_msg, error->description) < 0) + goto on_error; + + error = error->next; + } + + if (report->status == CL_TEST_SKIP) + clar_summary_skipped(summary); + + if (clar_summary_close_tag(summary, "testcase", 2) < 0) + goto on_error; + + report = report->next; + + if (!report || strcmp(last_suite, report->suite) != 0) { + if (clar_summary_close_tag(summary, "testsuite", 1) < 0) + goto on_error; + } + } + + if (clar_summary_close_tag(summary, "testsuites", 0) < 0 || + fclose(summary->fp) != 0) + goto on_error; + + printf("written summary file to %s\n", summary->filename); + + free(summary); + return 0; + +on_error: + fclose(summary->fp); + free(summary); + return -1; +} diff --git a/t/unit-tests/clar/generate.py b/t/unit-tests/clar/generate.py new file mode 100755 index 00000000000..80996ac3e71 --- /dev/null +++ b/t/unit-tests/clar/generate.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python +# +# Copyright (c) Vicent Marti. All rights reserved. +# +# This file is part of clar, distributed under the ISC license. +# For full terms see the included COPYING file. +# + +from __future__ import with_statement +from string import Template +import re, fnmatch, os, sys, codecs, pickle + +class Module(object): + class Template(object): + def __init__(self, module): + self.module = module + + def _render_callback(self, cb): + if not cb: + return ' { NULL, NULL }' + return ' { "%s", &%s }' % (cb['short_name'], cb['symbol']) + + class DeclarationTemplate(Template): + def render(self): + out = "\n".join("extern %s;" % cb['declaration'] for cb in self.module.callbacks) + "\n" + + for initializer in self.module.initializers: + out += "extern %s;\n" % initializer['declaration'] + + if self.module.cleanup: + out += "extern %s;\n" % self.module.cleanup['declaration'] + + return out + + class CallbacksTemplate(Template): + def render(self): + out = "static const struct clar_func _clar_cb_%s[] = {\n" % self.module.name + out += ",\n".join(self._render_callback(cb) for cb in self.module.callbacks) + out += "\n};\n" + return out + + class InfoTemplate(Template): + def render(self): + templates = [] + + initializers = self.module.initializers + if len(initializers) == 0: + initializers = [ None ] + + for initializer in initializers: + name = self.module.clean_name() + if initializer and initializer['short_name'].startswith('initialize_'): + variant = initializer['short_name'][len('initialize_'):] + name += " (%s)" % variant.replace('_', ' ') + + template = Template( + r""" + { + "${clean_name}", + ${initialize}, + ${cleanup}, + ${cb_ptr}, ${cb_count}, ${enabled} + }""" + ).substitute( + clean_name = name, + initialize = self._render_callback(initializer), + cleanup = self._render_callback(self.module.cleanup), + cb_ptr = "_clar_cb_%s" % self.module.name, + cb_count = len(self.module.callbacks), + enabled = int(self.module.enabled) + ) + templates.append(template) + + return ','.join(templates) + + def __init__(self, name): + self.name = name + + self.mtime = None + self.enabled = True + self.modified = False + + def clean_name(self): + return self.name.replace("_", "::") + + def _skip_comments(self, text): + SKIP_COMMENTS_REGEX = re.compile( + r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', + re.DOTALL | re.MULTILINE) + + def _replacer(match): + s = match.group(0) + return "" if s.startswith('/') else s + + return re.sub(SKIP_COMMENTS_REGEX, _replacer, text) + + def parse(self, contents): + TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\s*\(\s*void\s*\))\s*\{" + + contents = self._skip_comments(contents) + regex = re.compile(TEST_FUNC_REGEX % self.name, re.MULTILINE) + + self.callbacks = [] + self.initializers = [] + self.cleanup = None + + for (declaration, symbol, short_name) in regex.findall(contents): + data = { + "short_name" : short_name, + "declaration" : declaration, + "symbol" : symbol + } + + if short_name.startswith('initialize'): + self.initializers.append(data) + elif short_name == 'cleanup': + self.cleanup = data + else: + self.callbacks.append(data) + + return self.callbacks != [] + + def refresh(self, path): + self.modified = False + + try: + st = os.stat(path) + + # Not modified + if st.st_mtime == self.mtime: + return True + + self.modified = True + self.mtime = st.st_mtime + + with codecs.open(path, encoding='utf-8') as fp: + raw_content = fp.read() + + except IOError: + return False + + return self.parse(raw_content) + +class TestSuite(object): + + def __init__(self, path, output): + self.path = path + self.output = output + + def should_generate(self, path): + if not os.path.isfile(path): + return True + + if any(module.modified for module in self.modules.values()): + return True + + return False + + def find_modules(self): + modules = [] + for root, _, files in os.walk(self.path): + module_root = root[len(self.path):] + module_root = [c for c in module_root.split(os.sep) if c] + + tests_in_module = fnmatch.filter(files, "*.c") + + for test_file in tests_in_module: + full_path = os.path.join(root, test_file) + module_name = "_".join(module_root + [test_file[:-2]]).replace("-", "_") + + modules.append((full_path, module_name)) + + return modules + + def load_cache(self): + path = os.path.join(self.output, '.clarcache') + cache = {} + + try: + fp = open(path, 'rb') + cache = pickle.load(fp) + fp.close() + except (IOError, ValueError): + pass + + return cache + + def save_cache(self): + path = os.path.join(self.output, '.clarcache') + with open(path, 'wb') as cache: + pickle.dump(self.modules, cache) + + def load(self, force = False): + module_data = self.find_modules() + self.modules = {} if force else self.load_cache() + + for path, name in module_data: + if name not in self.modules: + self.modules[name] = Module(name) + + if not self.modules[name].refresh(path): + del self.modules[name] + + def disable(self, excluded): + for exclude in excluded: + for module in self.modules.values(): + name = module.clean_name() + if name.startswith(exclude): + module.enabled = False + module.modified = True + + def suite_count(self): + return sum(max(1, len(m.initializers)) for m in self.modules.values()) + + def callback_count(self): + return sum(len(module.callbacks) for module in self.modules.values()) + + def write(self): + output = os.path.join(self.output, 'clar.suite') + + if not self.should_generate(output): + return False + + with open(output, 'w') as data: + modules = sorted(self.modules.values(), key=lambda module: module.name) + + for module in modules: + t = Module.DeclarationTemplate(module) + data.write(t.render()) + + for module in modules: + t = Module.CallbacksTemplate(module) + data.write(t.render()) + + suites = "static struct clar_suite _clar_suites[] = {" + ','.join( + Module.InfoTemplate(module).render() for module in modules + ) + "\n};\n" + + data.write(suites) + + data.write("static const size_t _clar_suite_count = %d;\n" % self.suite_count()) + data.write("static const size_t _clar_callback_count = %d;\n" % self.callback_count()) + + self.save_cache() + return True + +if __name__ == '__main__': + from optparse import OptionParser + + parser = OptionParser() + parser.add_option('-f', '--force', action="store_true", dest='force', default=False) + parser.add_option('-x', '--exclude', dest='excluded', action='append', default=[]) + parser.add_option('-o', '--output', dest='output') + + options, args = parser.parse_args() + if len(args) > 1: + print("More than one path given") + sys.exit(1) + + path = args.pop() if args else '.' + output = options.output or path + suite = TestSuite(path, output) + suite.load(options.force) + suite.disable(options.excluded) + if suite.write(): + print("Written `clar.suite` (%d tests in %d suites)" % (suite.callback_count(), suite.suite_count())) diff --git a/t/unit-tests/clar/test/.gitignore b/t/unit-tests/clar/test/.gitignore new file mode 100644 index 00000000000..a477d0c40ca --- /dev/null +++ b/t/unit-tests/clar/test/.gitignore @@ -0,0 +1,4 @@ +clar.suite +.clarcache +clar_test +*.o diff --git a/t/unit-tests/clar/test/Makefile b/t/unit-tests/clar/test/Makefile new file mode 100644 index 00000000000..93c6b2ad32c --- /dev/null +++ b/t/unit-tests/clar/test/Makefile @@ -0,0 +1,39 @@ +# +# Copyright (c) Vicent Marti. All rights reserved. +# +# This file is part of clar, distributed under the ISC license. +# For full terms see the included COPYING file. +# + +# +# Set up the path to the clar sources and to the fixtures directory +# +# The fixture path needs to be an absolute path so it can be used +# even after we have chdir'ed into the test directory while testing. +# +CURRENT_MAKEFILE := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) +TEST_DIRECTORY := $(abspath $(dir $(CURRENT_MAKEFILE))) +CLAR_PATH := $(dir $(TEST_DIRECTORY)) +CLAR_FIXTURE_PATH := $(TEST_DIRECTORY)/resources/ + +CFLAGS=-g -I.. -I. -Wall -DCLAR_FIXTURE_PATH=\"$(CLAR_FIXTURE_PATH)\" + +.PHONY: clean + +# list the objects that go into our test +objects = main.o sample.o + +# build the test executable itself +clar_test: $(objects) clar_test.h clar.suite $(CLAR_PATH)clar.c + $(CC) $(CFLAGS) -o $@ "$(CLAR_PATH)clar.c" $(objects) + +# test object files depend on clar macros +$(objects) : $(CLAR_PATH)clar.h + +# build the clar.suite file of test metadata +clar.suite: + python "$(CLAR_PATH)generate.py" . + +# remove all generated files +clean: + $(RM) -rf *.o clar.suite .clarcache clar_test clar_test.dSYM diff --git a/t/unit-tests/clar/test/clar_test.h b/t/unit-tests/clar/test/clar_test.h new file mode 100644 index 00000000000..0fcaa639aa8 --- /dev/null +++ b/t/unit-tests/clar/test/clar_test.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Vicent Marti. All rights reserved. + * + * This file is part of clar, distributed under the ISC license. + * For full terms see the included COPYING file. + */ +#ifndef __CLAR_TEST__ +#define __CLAR_TEST__ + +/* Import the standard clar helper functions */ +#include "clar.h" + +/* Your custom shared includes / defines here */ +extern int global_test_counter; + +#endif diff --git a/t/unit-tests/clar/test/main.c b/t/unit-tests/clar/test/main.c new file mode 100644 index 00000000000..59e56ad255b --- /dev/null +++ b/t/unit-tests/clar/test/main.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) Vicent Marti. All rights reserved. + * + * This file is part of clar, distributed under the ISC license. + * For full terms see the included COPYING file. + */ + +#include "clar_test.h" + +/* + * Sample main() for clar tests. + * + * You should write your own main routine for clar tests that does specific + * setup and teardown as necessary for your application. The only required + * line is the call to `clar_test(argc, argv)`, which will execute the test + * suite. If you want to check the return value of the test application, + * your main() should return the same value returned by clar_test(). + */ + +int global_test_counter = 0; + +#ifdef _WIN32 +int __cdecl main(int argc, char *argv[]) +#else +int main(int argc, char *argv[]) +#endif +{ + int ret; + + /* Your custom initialization here */ + global_test_counter = 0; + + /* Run the test suite */ + ret = clar_test(argc, argv); + + /* Your custom cleanup here */ + cl_assert_equal_i(8, global_test_counter); + + return ret; +} diff --git a/t/unit-tests/clar/test/main.c.sample b/t/unit-tests/clar/test/main.c.sample new file mode 100644 index 00000000000..a4d91b72fa8 --- /dev/null +++ b/t/unit-tests/clar/test/main.c.sample @@ -0,0 +1,27 @@ +/* + * Copyright (c) Vicent Marti. All rights reserved. + * + * This file is part of clar, distributed under the ISC license. + * For full terms see the included COPYING file. + */ + +#include "clar_test.h" + +/* + * Minimal main() for clar tests. + * + * Modify this with any application specific setup or teardown that you need. + * The only required line is the call to `clar_test(argc, argv)`, which will + * execute the test suite. If you want to check the return value of the test + * application, main() should return the same value returned by clar_test(). + */ + +#ifdef _WIN32 +int __cdecl main(int argc, char *argv[]) +#else +int main(int argc, char *argv[]) +#endif +{ + /* Run the test suite */ + return clar_test(argc, argv); +} diff --git a/t/unit-tests/clar/test/resources/test/file b/t/unit-tests/clar/test/resources/test/file new file mode 100644 index 00000000000..220f4aa98a7 --- /dev/null +++ b/t/unit-tests/clar/test/resources/test/file @@ -0,0 +1 @@ +File diff --git a/t/unit-tests/clar/test/sample.c b/t/unit-tests/clar/test/sample.c new file mode 100644 index 00000000000..faa1209262f --- /dev/null +++ b/t/unit-tests/clar/test/sample.c @@ -0,0 +1,84 @@ +#include "clar_test.h" +#include + +static int file_size(const char *filename) +{ + struct stat st; + + if (stat(filename, &st) == 0) + return (int)st.st_size; + return -1; +} + +void test_sample__initialize(void) +{ + global_test_counter++; +} + +void test_sample__cleanup(void) +{ + cl_fixture_cleanup("test"); + + cl_assert(file_size("test/file") == -1); +} + +void test_sample__1(void) +{ + cl_assert(1); + cl_must_pass(0); /* 0 == success */ + cl_must_fail(-1); /* <0 == failure */ + cl_must_pass(-1); /* demonstrate a failing call */ +} + +void test_sample__2(void) +{ + cl_fixture_sandbox("test"); + + cl_assert(file_size("test/nonexistent") == -1); + cl_assert(file_size("test/file") > 0); + cl_assert(100 == 101); +} + +void test_sample__strings(void) +{ + const char *actual = "expected"; + cl_assert_equal_s("expected", actual); + cl_assert_equal_s_("expected", actual, "second try with annotation"); + cl_assert_equal_s_("mismatched", actual, "this one fails"); +} + +void test_sample__strings_with_length(void) +{ + const char *actual = "expected"; + cl_assert_equal_strn("expected_", actual, 8); + cl_assert_equal_strn("exactly", actual, 2); + cl_assert_equal_strn_("expected_", actual, 8, "with annotation"); + cl_assert_equal_strn_("exactly", actual, 3, "this one fails"); +} + +void test_sample__int(void) +{ + int value = 100; + cl_assert_equal_i(100, value); + cl_assert_equal_i_(101, value, "extra note on failing test"); +} + +void test_sample__int_fmt(void) +{ + int value = 100; + cl_assert_equal_i_fmt(022, value, "%04o"); +} + +void test_sample__bool(void) +{ + int value = 100; + cl_assert_equal_b(1, value); /* test equality as booleans */ + cl_assert_equal_b(0, value); +} + +void test_sample__ptr(void) +{ + const char *actual = "expected"; + cl_assert_equal_p(actual, actual); /* pointers to same object */ + cl_assert_equal_p(&actual, actual); +} From patchwork Tue Sep 3 09:14:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788324 Received: from pfout3-smtp.messagingengine.com (fout3-smtp.messagingengine.com [103.168.172.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E5FB11A3040 for ; Tue, 3 Sep 2024 09:14:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354886; cv=none; b=Znq5c4PqavMfCWQ2WcLVfu9s7//zxYmt0ez+vg6QC2OZH6lMW+sd44JgmzCPvQ37Ob7yFYl1EaeDI7JGgYhqy8EO7yJkG+8phqGQYpFfgUM3i/R36lgbJuvQEirx3Muve1+q3ocmV+IgoWKylu9KK2ZbwNqVs6OX3U/FMp/aHZM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354886; c=relaxed/simple; bh=FXXuxYSoXXTmOqCu9/JOoPLs0iWFrFY9QF3f1J0O1fw=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=VMEqD0+A3Gkk0wn3UbxgcNcM5kEt5GYfSnKezulgXGiPSQAT22jRLIgWnkrRXZ2CB2GVBXj6dpzWwoPHzpRLO3B8hM7W+456SUe0NKj1Eb/AE03Lzg1nfmV1F/IeCLAqfhIt1wvM3YmC9LHbO6M8tdkkWbjYi5kMOtCLP6BIpRs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=liQGfK6+; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=DG/LexWS; arc=none smtp.client-ip=103.168.172.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="liQGfK6+"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="DG/LexWS" Received: from phl-compute-08.internal (phl-compute-08.phl.internal [10.202.2.48]) by mailfout.phl.internal (Postfix) with ESMTP id 317AA138039B; Tue, 3 Sep 2024 05:14:44 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-08.internal (MEProxy); Tue, 03 Sep 2024 05:14:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354884; x=1725441284; bh=ouoo1eOQI2 +EdVuymWTaQ7zhb6dQtN6siuE9pR2GCGY=; b=liQGfK6+ErFnMwjQW8/Ukp+8Wa o/1oRVeWwysem7qv+CeVavHp/X13y2dTyZuSMarj3+K5m8lR/C9ual3Qx/kZlTGP ofR0U9xDMwBYCM65SY+tNNGAYDUPkZz/6UCfcKyPjfk0+D+aU4J9yZWXHn8bUIqB /nseJDMJJJV8GPxGSZZFyDsAF5lVilFEdirziJKyo03Z9Ek9iB3FZoEkkcUhIwy0 wF4htBhK9685bxe7RQSKGXTFDXcE/EHq+avVl2JnoHoFNqIGrf0VIKzq30egWksZ 6kNvCF1ur4l8FQNKRRGH6CloYi8aJTiKF4DxfDpNvkROudQQs2vSXsKRO4dA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354884; x=1725441284; bh=ouoo1eOQI2+EdVuymWTaQ7zhb6dQ tN6siuE9pR2GCGY=; b=DG/LexWSmI8aRkuDRtdzMs50mi/U1JttzytKOtXv45KW RBKXcFpM/+bcF92cN+UFE/yYSNFmV/PeAFQoz5D/h55LmOakb4glp/4hTd2sVYlq XzIxFYEMcLIp68/iBqrG+RJgrv7Bo+7kNi+bBP5myONNWJXCnCZE75Jm/GwIPzB6 yRjCTGc+fXjyS06b8zmQYLYNJXYATaEKvvsPs3pehPi9gaU2+DDoVcOeCrd7bgsB i0d9m7jy0ApfiCIgORbGbgQdNPDdjhtBLbsjGdbp4M/LpzzZKDEPoYTAco2mCFCc GRq3KsXpyBQ85YkSCL9uvbLhXxM62jo9VX73oXDsnA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhephfeigfdvffdvtdeuhfelgfelhefgfeevueetffdugfeh tefgveelhfeuueevuedvnecuffhomhgrihhnpehgihhthhhusgdrtghomhenucevlhhush htvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm pdhnsggprhgtphhtthhopeelpdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehgih htshhtvghrsehpohgsohigrdgtohhmpdhrtghpthhtohepshhpvggtthhrrghlsehgohho ghhlvgdrtghomhdprhgtphhtthhopehsthgvrggumhhonhesghhoohhglhgvrdgtohhmpd hrtghpthhtoheprhhssggvtghkvghrsehnvgigsghrihgughgvrdgtohhmpdhrtghpthht ohepjhhohhgrnhhnvghsrdhstghhihhnuggvlhhinhesghhmgidruggvpdhrtghpthhtoh epvghthhhomhhsohhnsegvugifrghrughthhhomhhsohhnrdgtohhmpdhrtghpthhtohep ghhithesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehphhhilhhlihhprd ifohhougesughunhgvlhhmrdhorhhgrdhukhdprhgtphhtthhopehlrdhsrdhrseifvggs rdguvg X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:14:42 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 38e0b857 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:14:35 +0000 (UTC) Date: Tue, 3 Sep 2024 11:14:41 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 03/14] t/clar: fix compatibility with NonStop Message-ID: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The NonStop platform does not have `mkdtemp()` available, which we rely on in `build_sandbox_path()`. Fix this issue by using `mktemp()` and `mkdir()` instead on this platform. This has been cherry-picked from the upstream pull request at [1]. [1]: https://github.com/clar-test/clar/pull/96 Signed-off-by: Patrick Steinhardt --- t/unit-tests/clar/clar/sandbox.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/t/unit-tests/clar/clar/sandbox.h b/t/unit-tests/clar/clar/sandbox.h index 7c177f35258..e25057b7c49 100644 --- a/t/unit-tests/clar/clar/sandbox.h +++ b/t/unit-tests/clar/clar/sandbox.h @@ -120,6 +120,12 @@ static int build_sandbox_path(void) if (_mktemp(_clar_path) == NULL) return -1; + if (mkdir(_clar_path, 0700) != 0) + return -1; +#elif defined(__TANDEM) + if (mktemp(_clar_path) == NULL) + return -1; + if (mkdir(_clar_path, 0700) != 0) return -1; #elif defined(_WIN32) From patchwork Tue Sep 3 09:14:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788326 Received: from pfhigh7-smtp.messagingengine.com (fhigh7-smtp.messagingengine.com [103.168.172.158]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 20F601A3AA4 for ; Tue, 3 Sep 2024 09:14:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.158 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354891; cv=none; b=UWvU1GukH3X5mKdJTb9x6F78Niz1eLW7oKZvBlb7Fbkb+u5LeXPOn8im0Ch6YVAOnb8N+QyxC3kWk5nvfHvsgn6mZRGDDoLvCLMprApZNUZRShG4lzS9TisX4JUfAmhN6e1hIzDvidrPo6zgZop72SGjYKGMM1UPEHu98xEOucQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354891; c=relaxed/simple; bh=0fyQvM2FEPi3i3CG2dpJM7QRyfkiVX5/0CaO1OY8+Hc=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=cJXj74nYmczoYUDmDHq6CDbo2vhWTJVJxv/VFZWjMVF9UuXi7f3Ql9hPV0ql+kFtMVATXTGDNpFHitn0YTYfjHjXYM4FMqLR42ou3y2BcDHC6qw27z2RUN6cywqkzzi6S0cpgKcS6qaVInwz6qU9rc69jRMZQBg+7u/az9KHZqY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=rYSmopzl; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=gIgBXT0w; arc=none smtp.client-ip=103.168.172.158 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="rYSmopzl"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="gIgBXT0w" Received: from phl-compute-06.internal (phl-compute-06.phl.internal [10.202.2.46]) by mailfhigh.phl.internal (Postfix) with ESMTP id 0D47B11402DD; Tue, 3 Sep 2024 05:14:49 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-06.internal (MEProxy); Tue, 03 Sep 2024 05:14:49 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354889; x=1725441289; bh=+2XmeVreAq Puhzif37oJpaNSKtzjS2WxILwJTxj0W38=; b=rYSmopzlktfcCG8ngl06mkPbUA xznP3lDV5Wjm3UJbZjpU1OtqqnX92ml3Gejz5YCXhBq70lJFCltH76qtVvgpkhBT UkLp0oCwDPPF1s/gT0aGlnfFrnozpinyEL5h9tECwK4yYRON8SacO3HgcLjJpkPo 8tFbLCRLhyVYGl7SoEXdmD/l8gFEEIEjDvNCmx5Io8rCBk+Oz8J/bO34QvdoPOxA MQwLKnJwF4pRSHcp7Nz8oJyGJrpH5d7G6is+6r2OqNqdDLZEzQGkEEjVwgfNsNt5 OoFvYgtgLggFcDvcutVbPhFyMXVAvs660DYMSao+j/vdbC9GwNsd1aP8jaiA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354889; x=1725441289; bh=+2XmeVreAqPuhzif37oJpaNSKtzj S2WxILwJTxj0W38=; b=gIgBXT0wAi/wD9rEXPYsqxUEgg4nJr78+Hs1+AqnPJP1 kMr979rqKUQs7Sihncc/Z8RwjhGN1e3ycc5AdNFclCGbhDGQLspduGx7OVLL6w4q 71qIEcrpK3/wQnwgwpTZoPPn1FCRAbEUHo1Y7qM5aFz44fNZrfZntdyKb/gDoeTE gKas7mg/26Bgcf4IbhUCFU9QFuKiK+OV3E7zIL3nHaEYKV3n5YXK9XS1QXbGTkJR RgEe342nrw6YcWW+DTRiW6hdahdVsHQIu2chTCI2FR7NjgezF6heDKZexhsWc+Z9 MEAgy7a4c8hZkBza4nJNRp4KLjiMIjLfVF5T358gCQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedgudefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtoheplhdrshdrrhesfigvsgdruggvpdhrtghpthhtohepvg hthhhomhhsohhnsegvugifrghrughthhhomhhsohhnrdgtohhmpdhrtghpthhtohepshhp vggtthhrrghlsehgohhoghhlvgdrtghomhdprhgtphhtthhopehgihhtshhtvghrsehpoh gsohigrdgtohhmpdhrtghpthhtohepshhtvggrughmohhnsehgohhoghhlvgdrtghomhdp rhgtphhtthhopehphhhilhhlihhprdifohhougesughunhgvlhhmrdhorhhgrdhukhdprh gtphhtthhopehjohhhrghnnhgvshdrshgthhhinhguvghlihhnsehgmhigrdguvgdprhgt phhtthhopehgihhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprhhssg gvtghkvghrsehnvgigsghrihgughgvrdgtohhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:14:47 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id e4766d17 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:14:40 +0000 (UTC) Date: Tue, 3 Sep 2024 11:14:43 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 04/14] clar: avoid compile error with mingw-w64 Message-ID: <658a601c5411f38457007ed961582b5d898f813a.1725349234.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: From: Johannes Schindelin When using mingw-w64 to compile the code, and using `_stat()`, it is necessary to use `struct _stat`, too, and not `struct stat` (as the latter is incompatible with the "dashed" version because it is limited to 32-bit time types for backwards compatibility). Signed-off-by: Johannes Schindelin Signed-off-by: Patrick Steinhardt --- t/unit-tests/clar/clar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/unit-tests/clar/clar.c b/t/unit-tests/clar/clar.c index 3fc2c768158..e2ebe551d38 100644 --- a/t/unit-tests/clar/clar.c +++ b/t/unit-tests/clar/clar.c @@ -68,7 +68,7 @@ # define PRIxZ "Ix" # endif -# if defined(_MSC_VER) || defined(__MINGW32__) +# if defined(_MSC_VER) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) typedef struct stat STAT_T; # else typedef struct _stat STAT_T; From patchwork Tue Sep 3 09:14:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788327 Received: from pfout3-smtp.messagingengine.com (fout3-smtp.messagingengine.com [103.168.172.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E522D1A3AA9 for ; Tue, 3 Sep 2024 09:14:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354894; cv=none; b=A1psFEt3eHRauo6x1EARnhILZDvqddFIKdnOEsKFseOE3VhDFadUN7B8rHyLk6NF00BqOWEgZ7KB7tItrlSwyxFRPIGI7KuYSMBP2Xy3o1dzadVPmlsEVtWf9dzpL+4g2oxP/gtNDoKPx4xBwOzr+S9jwL3RQ3S2Az1BYcyWnHE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354894; c=relaxed/simple; bh=eB4UC0bgdMASHojoF191UVs+lqf7Rf6MI20f9mr6sAI=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=HlomXu8bap8rG4+0jk9dRwcE7x6O8l/PIyvggldlf854zVbXIrEWsmzNmoV90frQAX3o9DR4FPVRVqdvPMwNjT3DbnpjZclJqY+B6Ccvs5gWqPPqqb0HmE2YFU9DjJt2+s7W3AZr/YfrOIl7hrlt2eeFHG+7kDUE7aQKOGul6Ss= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=og7nQkNQ; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=iCQLlYi4; arc=none smtp.client-ip=103.168.172.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="og7nQkNQ"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="iCQLlYi4" Received: from phl-compute-04.internal (phl-compute-04.phl.internal [10.202.2.44]) by mailfout.phl.internal (Postfix) with ESMTP id 0C7FE138038C; Tue, 3 Sep 2024 05:14:52 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-04.internal (MEProxy); Tue, 03 Sep 2024 05:14:52 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354892; x=1725441292; bh=QPyjDuWhrm km+ZsnKWZD+9wcElTU2nl+IcjDBLgAKRk=; b=og7nQkNQZouq2AcJCb/o99gb7f cP+MEF/acXBDsu7v7qjOpi68NwdaXFbrZwO3RwYe6Jt+1682boC99aDW24RLUdaX gbX7KC+ja+orVoSfzbeYm88RhoJAxYHolrqeCl2W7r3WrvgB1UxFlwDwsbdAu0Sm sLIo4k9dnKkPVYdi4B8q5xlP+GxeVMDlciSD2BueA9xGUUK6TnB6UcUaG/jDcR4v tEcpM9kfwryOXdVFE497xF99lysfgXnMMm9hXUQUu4ZyeOs/mmDjH9a79pwW7jnX XL4WIb1wHnTTXIM9vmBGt4+Zf3gIFc+TXa9RXNZY6z0bfBQRRNy+jgZNVQ8A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354892; x=1725441292; bh=QPyjDuWhrmkm+ZsnKWZD+9wcElTU 2nl+IcjDBLgAKRk=; b=iCQLlYi4I6DfHnCt9ZDFZZQKm/WWl4Fm1z2iqC8ASwmj weXC66ZY4t/9JHxO6Gy65F6Nc3qXLkOXKNxopl2KOL85JN9GqCH+0hZZaXy0DRdx yPYnRpZOUWiilXs3/+VdPtzBLnFmdCOGcldt9XHlkrJX5ZPnCsj5WLShSpBCMJds x1sepQiLqjDLgKl8+ainO5bvzizLPl9hhEDYedo9w3OO6Fj4zaEVCLnwWoLc1KuA KwmXjHbUIaT90W8LnM7sNWgm1yAYpp6yboelCxAX0yFLm5YgX4i30bHLjQ70sPe7 gF3EcOHkd9WImm7mp24XfkpyuMq5VxoBTItTgn6I8w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtohepphhhihhllhhiphdrfihoohguseguuhhnvghlmhdroh hrghdruhhkpdhrtghpthhtohepghhithhsthgvrhesphhosghogidrtghomhdprhgtphht thhopehrshgsvggtkhgvrhesnhgvgigsrhhiughgvgdrtghomhdprhgtphhtthhopehsph gvtghtrhgrlhesghhoohhglhgvrdgtohhmpdhrtghpthhtohepvghthhhomhhsohhnsegv ugifrghrughthhhomhhsohhnrdgtohhmpdhrtghpthhtohepshhtvggrughmohhnsehgoh hoghhlvgdrtghomhdprhgtphhtthhopehjohhhrghnnhgvshdrshgthhhinhguvghlihhn sehgmhigrdguvgdprhgtphhtthhopehgihhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpd hrtghpthhtoheplhdrshdrrhesfigvsgdruggv X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:14:50 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 6751d2e4 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:14:43 +0000 (UTC) Date: Tue, 3 Sep 2024 11:14:48 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 05/14] clar(win32): avoid compile error due to unused `fs_copy()` Message-ID: <0b8a6ac5fedf95e3d5328bf1fef75710e26ee3c3.1725349234.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: From: Johannes Schindelin When CLAR_FIXTURE_PATH is unset, the `fs_copy()` function seems not to be used. But it is declared as `static`, and GCC does not like that, complaining that it should not be declared/defined to begin with. We could mark this function as (potentially) unused by following the `MAYBE_UNUSED` pattern from Git's `git-compat-util.h`. However, this is a GCC-only construct that is not understood by Visual C. Besides, `clar` does not use that pattern at all. Instead, let's use the `((void)SYMBOL);` pattern that `clar` already uses elsewhere; This avoids the compile error by sorta kinda make the function used after a fashion. Note: GCC 14.x (which Git for Windows' SDK already uses) is able to figure out that this function is unused even though there are recursive calls between `fs_copy()` and `fs_copydir_helper()`; Earlier GCC versions do not detect that, and therefore the issue has been hidden from the regular Linux CI builds (where GCC 14.x is not yet used). That is the reason why this change is only made in the Windows-specific portion of `t/unit-tests/clar/clar/fs.h`. Signed-off-by: Johannes Schindelin Signed-off-by: Patrick Steinhardt --- t/unit-tests/clar/clar/fs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/unit-tests/clar/clar/fs.h b/t/unit-tests/clar/clar/fs.h index 3e39890bd3e..8b206179fc4 100644 --- a/t/unit-tests/clar/clar/fs.h +++ b/t/unit-tests/clar/clar/fs.h @@ -297,6 +297,8 @@ cl_fs_cleanup(void) { #ifdef CLAR_FIXTURE_PATH fs_rm(fixture_path(_clar_path, "*")); +#else + ((void)fs_copy); /* unused */ #endif } From patchwork Tue Sep 3 09:14:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788328 Received: from pfhigh7-smtp.messagingengine.com (fhigh7-smtp.messagingengine.com [103.168.172.158]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF17E1AD249 for ; Tue, 3 Sep 2024 09:14:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.158 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354897; cv=none; b=aU2BRiNa9jWsCGUcbLBmu0hXfiCaPDGNvNsySs77vdoMVD6Nm/TsYkrhPJhzIymbRDyZp/0lSRrqAJ9clNcJi9YBmVH3M9QAlw6z8rzfO4PZE0C3N6oE5qcaqPNHttzWJvWoH4c8Mo0Xpmkv0VIQPAWxnsHBsf4cxI8zZwj1gvk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354897; c=relaxed/simple; bh=elt6OztjLWNA785lG+uQt+uYcY3TvhS3V6bCtJDMj6o=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=BBeiNyCdYcnUoT8glRdEzHYpLBvceCGvCtybwYUHkSyERHGLV/HVDi9p4bl2EEtUvw5hJKyiklcT0sNRFADWmsX1u3bLH381GW3JpgD+zyDG/mQd2ko9rLkIevTw1TzeQTTkIqdNgMZt7B2230h69HoosXXdyikdbUsdEL4Mvx8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=jJ6a3/mq; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=K3SrAjfT; arc=none smtp.client-ip=103.168.172.158 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="jJ6a3/mq"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="K3SrAjfT" Received: from phl-compute-02.internal (phl-compute-02.phl.internal [10.202.2.42]) by mailfhigh.phl.internal (Postfix) with ESMTP id F3A9711402E3; Tue, 3 Sep 2024 05:14:54 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-02.internal (MEProxy); Tue, 03 Sep 2024 05:14:54 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354894; x=1725441294; bh=ZE5XUuGZ46 Crv+NZ1+Ywoca9QPuQ/dphbASL7tc8nM0=; b=jJ6a3/mqJ53lIQLqgVf6TlYMle NR2CdnJLAsQHPE6Di2IlH5AA+fUY+yLxZaBn+IAZ0TcHd4oayfUQu07PH8GelF6G WB4ZXf3Cg6cH3ppxPf4q7FKo6QpnzynX0Fr/xCT+BLloQ+lzp030lXt2LP+lxa78 S7qhFz0f3morU/Y3lOnDO0+tEiwlF5VZe0QkRBEWQKH46t0kUhIpEJmonx9B1ZGq XzStTn9B5H7oh8kWSaau6/Ij8sOJ06VRpPKkSIqus2hm6wps8j3Ux+scWk64g/MX A0cCYfuNE2jEgdQ2qOQjRZVdNfK6lwvcocPrMMVGghAR7GADqV2His7s3ZIA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354894; x=1725441294; bh=ZE5XUuGZ46Crv+NZ1+Ywoca9QPuQ /dphbASL7tc8nM0=; b=K3SrAjfTPEAXvCnAIMnKeuBOK18h2pf/b3C/z1Xr/ZmH vx/bCYbVf4iTwUSNrwnP4XC/A6DJxKg6h4TgGVRCuPTIG+P1nsNCSqpASYuP++2z i4Pcqk5dz2cV8FJYXagwb7v8UTHS88WvvKnO2MBsr5gN5tqs/I8aZGgrNgkliiKk j+fqM6sGaBqq8o5Ye8encINyAlTBuPilBtuyhWoMBSx3DvGNQcDnmBQ7E7cThpfk mgvObK80l7kftjjW8qjd5boWi/nOFv516sLME7tSoxxkEUVcPwDCUNeeibJgLLB3 Ae/bVKGV80MQbePdawumBIPpQt4msy2GeiereAd/sg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhephfeigfdvffdvtdeuhfelgfelhefgfeevueetffdugfeh tefgveelhfeuueevuedvnecuffhomhgrihhnpehgihhthhhusgdrtghomhenucevlhhush htvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehpshesphhkshdrihhm pdhnsggprhgtphhtthhopeelpdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehrsh gsvggtkhgvrhesnhgvgigsrhhiughgvgdrtghomhdprhgtphhtthhopehlrdhsrdhrseif vggsrdguvgdprhgtphhtthhopehsphgvtghtrhgrlhesghhoohhglhgvrdgtohhmpdhrtg hpthhtohepphhhihhllhhiphdrfihoohguseguuhhnvghlmhdrohhrghdruhhkpdhrtghp thhtohepvghthhhomhhsohhnsegvugifrghrughthhhomhhsohhnrdgtohhmpdhrtghpth htohepghhithesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehsthgvrggu mhhonhesghhoohhglhgvrdgtohhmpdhrtghpthhtohepjhhohhgrnhhnvghsrdhstghhih hnuggvlhhinhesghhmgidruggvpdhrtghpthhtohepghhithhsthgvrhesphhosghogidr tghomh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:14:53 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 66d175a5 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:14:46 +0000 (UTC) Date: Tue, 3 Sep 2024 11:14:51 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 06/14] clar: stop including `shellapi.h` unnecessarily Message-ID: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: From: Johannes Schindelin The `shellapi.h` header was included as of https://github.com/clar-test/clar/commit/136e763211aa, to have `SHFileOperation()` declared so that it could be called. However, https://github.com/clar-test/clar/commit/5ce31b69b525 removed that call, and therefore that `#include ` is unnecessary. It is also unwanted in Git because this project uses a subset of Git for Windows' SDK in its CI builds that (for bandwidth reasons) excludes tons of header files, including `shellapi.h`. So let's remove it. Note: Since the `windows.h` header would include `shellapi.h` anyway, we also define `WIN32_LEAN_AND_MEAN` to avoid this and similar other unnecessary includes before including `windows.h`. Signed-off-by: Johannes Schindelin Signed-off-by: Patrick Steinhardt --- t/unit-tests/clar/clar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/unit-tests/clar/clar.c b/t/unit-tests/clar/clar.c index e2ebe551d38..cef0f023c24 100644 --- a/t/unit-tests/clar/clar.c +++ b/t/unit-tests/clar/clar.c @@ -19,9 +19,9 @@ #include #ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN # include # include -# include # include # define _MAIN_CC __cdecl From patchwork Tue Sep 3 09:14:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788329 Received: from pfhigh7-smtp.messagingengine.com (fhigh7-smtp.messagingengine.com [103.168.172.158]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 65E671A4E96 for ; Tue, 3 Sep 2024 09:14:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.158 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354900; cv=none; b=iWOTIPFEVZD39Lb7V0DtBrCgpKhbQxz6oEHWqZF4PLkM1Mh/fGp4nGIp36Ufzkr7UghrToW6ouEW6pQ9AElGrbU3a+ersYJZOshCWGohnAuRxQOLkUvxL6kV+OFRuGGPAQ9+Qe+dBV0BEZzoP7Kbb+pzbc5SGtpTlqVAHZeW9RE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354900; c=relaxed/simple; bh=N1iuBAmXm96AHC9Av99fPm2lzo8XJiR8jvzCPunq2JM=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=QqGyZGAmljnzvZKXJzYF7BGi2OieZSX6hypcwZomDTber/vXBP5Ak7P7ooEKmWb4gAL9T+rporadc9bHmqGt6fN9/UnR0PQgCMF+ElEJeywV/R7Gnx3JNWnWnLEY8NP6F068BIkMTlFp3ULFHlfVDpZog1610BNocn0W708kxSo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=PSQ90Y3A; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=H1jP+Ibu; arc=none smtp.client-ip=103.168.172.158 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="PSQ90Y3A"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="H1jP+Ibu" Received: from phl-compute-06.internal (phl-compute-06.phl.internal [10.202.2.46]) by mailfhigh.phl.internal (Postfix) with ESMTP id 5B9B81140297; Tue, 3 Sep 2024 05:14:58 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-06.internal (MEProxy); Tue, 03 Sep 2024 05:14:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354898; x=1725441298; bh=Rx2HvSsWxg 4VXxW0K1EJ+rcAzPv7jAfJYUAhdmtjFdc=; b=PSQ90Y3AmZcpP6xN0xLUeBs9ad kl79VhkUOVeuN12S8ZB4nSNqdKxsK8K6cKvRrGITCQyzpjmVfizRROsYjVI485Vx 6Xl0xT4M1IxSi8/qkZ+HdYPmrpW+RvJIKx9z5HF7FHgXsecwNhtW2Kw4yOz8+HN8 G71cn+IDzqfqq5KgULpugEZFRHCW+k5PLq99ajovNcbn/zPRnqi6WYJBsrOkFg7g o4GKLEfSeJvRfjOvStMvdAKx2uCLVhvxkwWrZ3PD9FmT4C2xOxxG7+LHwjlo6xLD AONNKFPExO3EFbvaytZl5qDi755ZXyFARYnj/nWqUVKz0bcIpz8wUKwiS8vg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354898; x=1725441298; bh=Rx2HvSsWxg4VXxW0K1EJ+rcAzPv7 jAfJYUAhdmtjFdc=; b=H1jP+IbuKROYswrs2Q5rQvNEuHmVlhlJ8ZyT79u/TN1+ ou9tZqlHfIL5nWWFoceErWt8hDFMvPJDEarqF0P5VHIh4g78iezfRDTe7/Nn5ysn coKyWUCyPndjTJSFbyu8y10M6ywJ1Zg5HfV/YMLytS7uYuumAM789NdQJgWGcJaJ mMnIxBo+77R3RsQEnzIigrC8mv8zy1Z/QS+E+hToV5YVW9iEE8TbEWksxhbskgO3 EqiP4giqYGhKGdZ4lMg/J6/oyEJGt6OY56fX921s+/+Hrbt0CbygUF2arkvP7WoD GFNj7PjtvZ/attPEjz24gPGzj6xPJWDrMGSuMDRsUA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedgudefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgepvdenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtohepghhithhsthgvrhesphhosghogidrtghomhdprhgtph htthhopehrshgsvggtkhgvrhesnhgvgigsrhhiughgvgdrtghomhdprhgtphhtthhopehj ohhhrghnnhgvshdrshgthhhinhguvghlihhnsehgmhigrdguvgdprhgtphhtthhopehphh hilhhlihhprdifohhougesughunhgvlhhmrdhorhhgrdhukhdprhgtphhtthhopehlrdhs rdhrseifvggsrdguvgdprhgtphhtthhopegvthhhohhmshhonhesvggufigrrhguthhhoh hmshhonhdrtghomhdprhgtphhtthhopehsphgvtghtrhgrlhesghhoohhglhgvrdgtohhm pdhrtghpthhtohepshhtvggrughmohhnsehgohhoghhlvgdrtghomhdprhgtphhtthhope hgihhtsehvghgvrhdrkhgvrhhnvghlrdhorhhg X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:14:56 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 35838468 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:14:49 +0000 (UTC) Date: Tue, 3 Sep 2024 11:14:54 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 07/14] Makefile: fix sparse dependency on GENERATED_H Message-ID: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The "check" Makefile target is essentially an alias around the "sparse" target. The one difference though is that it will tell users to instead run the "test" target in case they do not have sparse(1) installed, as chances are high that they wanted to execute the test suite rather than doing semantic checks. But even though the "check" target ultimately just ends up executing `make sparse`, it still depends on our generated headers. This does not make any sense though: they are irrelevant for the "test" target advice, and if these headers are required for the "sparse" target they must be declared as a dependency on the aliased target, not the alias. But even moving the dependency to the "sparse" target is wrong, as concurrent builds may then end up generating the headers and running sparse concurrently. Instead, we make them a dependency of the specific objects. While that is overly broad, it does ensure correct ordering. The alternative, specifying which file depends on what generated header explicitly, feels rather unmaintainable. Signed-off-by: Patrick Steinhardt --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 28742a60964..efd305ab358 100644 --- a/Makefile +++ b/Makefile @@ -3254,7 +3254,7 @@ check-sha1:: t/helper/test-tool$X SP_OBJ = $(patsubst %.o,%.sp,$(OBJECTS)) -$(SP_OBJ): %.sp: %.c %.o +$(SP_OBJ): %.sp: %.c %.o $(GENERATED_H) $(QUIET_SP)cgcc -no-compile $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) \ -Wsparse-error \ $(SPARSE_FLAGS) $(SP_EXTRA_FLAGS) $< && \ @@ -3295,7 +3295,7 @@ style: git clang-format --style file --diff --extensions c,h .PHONY: check -check: $(GENERATED_H) +check: @if sparse; \ then \ echo >&2 "Use 'make sparse' instead"; \ From patchwork Tue Sep 3 09:14:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788330 Received: from pfhigh7-smtp.messagingengine.com (fhigh7-smtp.messagingengine.com [103.168.172.158]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4D6A81A4E9D for ; Tue, 3 Sep 2024 09:15:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.158 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354902; cv=none; b=cIQ7MWTuRe9PYADbjSRvAO0QwDwTEhkijCVuGUVbb9k9hvEwrua6k7ciz3JJhDLUtuhHVML9veEWZPeaWsdzWcpQT6xkOypbN8wtLNJdiTcOdb5yx8ktmlkftozsmUbnHEgjBgSBqjeFVaQNaY877YKFanXsww8/zqxKjYPjkRI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354902; c=relaxed/simple; bh=zVqsPlib8PMvr6ODTBec02rNDMQoOxe2VgGGMCYr7Kw=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=ObUY44RJYGWYNYSXK8b7lcZwJ17NB1UCihm0JaEdPsS5JwKB8Ueb0w/bQ9/CjENtJlEQM9VJoH6IAUBZDLscI6lt9drTUKwo9C+rNHFrjaTpUOMebi8WwbmxZmL95yQh9GdzsrO/RhdlYEdPjX/1MlMAryP5HjdEpm9cip/NBH8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=hKiFtQuJ; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=XH1d2UbR; arc=none smtp.client-ip=103.168.172.158 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="hKiFtQuJ"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="XH1d2UbR" Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfhigh.phl.internal (Postfix) with ESMTP id 45F4411402E4; Tue, 3 Sep 2024 05:15:00 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-05.internal (MEProxy); Tue, 03 Sep 2024 05:15:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354900; x=1725441300; bh=Kpi7ujAAof vmC0k8soQrOCXibyRPAb5PmzEemCzlapw=; b=hKiFtQuJsULw5xGrh6b2mvwDOz ztYMJNn7OoMza8l2TNyXZx5JpjEUVOYA3MP+PF54XqZRc0V6ax/8D5HpyqC1l3So rBwat12ec8b1i6zS6AebEchfxCE+E61599wd4BQ2E1AyX5AyZHNWrTzAIdaDACyR fHP6ZgLA9VWyVS9JnKmSVrNLnvpF5Gbs3wz5JBg+kITwQEMSR2f1eGIE1joQVv9A mypp7lXuju+m26k5p3qOdJR9tLpv9aGaR4g0JH96vLwAjcu9+kaaMmTR8RG8VGpb 55+B4p45uJ/aMApniObgFb4ktAxx9KhnAZlBmEObrTB/CWpU7IYJpwxr9awg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354900; x=1725441300; bh=Kpi7ujAAofvmC0k8soQrOCXibyRP Ab5PmzEemCzlapw=; b=XH1d2UbRG+OMNPLutF/Tx8Wfj2R1nFEaf12OelbnPEqN mvuVwkWirLa26fFoyBHvNi5DNdJ/k8qdaT0tdaoImAPeeAWRPbWwCFvaODrPPSt9 2vgUXcpk3AHRgQxuzio0Lu1es2ZCbGnspi7So3mBXZX/Ip0ztdWGUz+/dPRKLseU 6G5/O7gaECJ6Awm5dfoime3vwwnjp5xjD2ZfxYoJR1u1sy8kUXXO4hvZzLBl+j0Y tfoZ8geXkOSIAhzQjv/XRNRLLotD6GHAFeTCU6kMbW4TBdAPm71oDwi9b2DRls8E 7hQSKUgjXvH9buVNjg3Y77WN8w9chB2ENvFbzrGAAA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtohepshhpvggtthhrrghlsehgohhoghhlvgdrtghomhdprh gtphhtthhopehgihhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepghhi thhsthgvrhesphhosghogidrtghomhdprhgtphhtthhopegvthhhohhmshhonhesvggufi grrhguthhhohhmshhonhdrtghomhdprhgtphhtthhopehphhhilhhlihhprdifohhouges ughunhgvlhhmrdhorhhgrdhukhdprhgtphhtthhopehsthgvrggumhhonhesghhoohhglh gvrdgtohhmpdhrtghpthhtoheprhhssggvtghkvghrsehnvgigsghrihgughgvrdgtohhm pdhrtghpthhtohepjhhohhgrnhhnvghsrdhstghhihhnuggvlhhinhesghhmgidruggvpd hrtghpthhtoheplhdrshdrrhesfigvsgdruggv X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:14:58 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 9271de2e (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:14:51 +0000 (UTC) Date: Tue, 3 Sep 2024 11:14:57 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 08/14] Makefile: make hdr-check depend on generated headers Message-ID: <3d3fe443b9a3f368287efa709cd744583da358e1.1725349234.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The "hdr-check" Makefile target compiles each of our headers as a standalone code unit to ensure that they are not missing any type declarations and can be included standalone. With the next commit we will wire up the clar unit testing framework, which will have the effect that some headers start depending on generated ones. While we could declare that dependency explicitly, it does not really feel very maintainable in the future. Instead, we do the same as in the preceding commit and have the objects depend on all of our generated headers. While again overly broad, it is easy to maintain and generating headers is not an expensive thing to do anyway. Signed-off-by: Patrick Steinhardt --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index efd305ab358..8c4487dd0c6 100644 --- a/Makefile +++ b/Makefile @@ -3284,7 +3284,7 @@ HCC = $(HCO:hco=hcc) @echo '#include "git-compat-util.h"' >$@ @echo '#include "$<"' >>$@ -$(HCO): %.hco: %.hcc FORCE +$(HCO): %.hco: %.hcc $(GENERATED_H) FORCE $(QUIET_HDR)$(CC) $(ALL_CFLAGS) -o /dev/null -c -xc $< .PHONY: hdr-check $(HCO) From patchwork Tue Sep 3 09:15:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788331 Received: from pfout3-smtp.messagingengine.com (fout3-smtp.messagingengine.com [103.168.172.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5B2761AD270 for ; Tue, 3 Sep 2024 09:15:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354905; cv=none; b=YWAEQUj1qMoqseSs0OLrJ6GnRaQU0TDYGeiDMysx904+yuQp6lgcNcunnMZqGeej42PJnnLYn653TQSQAj7o/OdpHUFtvvjl7xguOUiqaWv0hPJ+rPvBlhgfpaPSFgQ3xhNYxjURsVCj6ZoU5rpBOQjqPI8LEHtJisvVPfF4pvI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354905; c=relaxed/simple; bh=9XP0vs65LiszYU0sLs9vKvp/bRjlHKjOHzyyAaWwKv0=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=NOSpyHdTdhOR13meO4S1mkTXQ3+RsX+wTygmvqiqKucbRCPJZ3e6lSYLpLLK3U5Is/gT5KOtAvL8hQFuxnR4HkvsgY6drRMIcjfe3yXt2vSI6iXEe9Go3IfdhTRCYDydKkjYXlvGRWsozFTjnSAa3zkmJiuDIOq3wNkMK9e4Ha8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=nJMeZvqG; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=e2KVUpof; arc=none smtp.client-ip=103.168.172.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="nJMeZvqG"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="e2KVUpof" Received: from phl-compute-07.internal (phl-compute-07.phl.internal [10.202.2.47]) by mailfout.phl.internal (Postfix) with ESMTP id 407A2138039B; Tue, 3 Sep 2024 05:15:03 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-07.internal (MEProxy); Tue, 03 Sep 2024 05:15:03 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354903; x=1725441303; bh=18qPGIFS3f njLyb+wgq72v/rvEgh6NPfU6ZJ8d8Xx4o=; b=nJMeZvqGa9F7FlOU6eRi4pSrHN LRJf8rBZIqkOGJ1fU2r23HMexo9bOxzhdp4HflDKZ1Cb/3TXdu2hlU9l96EYdr6S e32cjqZNJPjhr+SbXcahWbllkkTg7vmkHMy4Hon2jpIdEtIGeZAQBJfC1sUIsjoY /y5G0PhqQ5y88efXHFeNhGlvueSgxUxDL5amc+rum+ZA/Jq4RtrvYLrwfyH+yQXF Zd/dkfRmTQO72p9QLvKPkLq3/ofh7cnDD+VeEnKyCjr5XdouANNQZUWejdV3VDG7 Gx5pGS3j3NEFscq//MDUUTuePiMDBhX6hdCKWP50S4iZNcFcnTXsNrlt+48g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354903; x=1725441303; bh=18qPGIFS3fnjLyb+wgq72v/rvEgh 6NPfU6ZJ8d8Xx4o=; b=e2KVUpofaZzVIgWUbszY7Mc9Z3PQa5Snx75JxUpa9U/i a1b7W3LkUzbXFqgADTCcuVGYp1jcxU9DuMB0rnp4k4CNJ4ujQarKIyZbl0dov1Ub R3vDhjdOk7G+tPuxL6g5Cc30S8ZroGHYwtptjynTftFOesUbSh5tqu+SZXx3E4+Q /Yf8h6GblPKMbucie7oQ7WzGbyFXsu+U3wr7v0g1OZKi6G3igVfLReP8s/RsCoze G3ru/EP1Gt6bGHMcUon7eNX7pvP4yOXeYyBbC9wXCssbznP5Npip9/iqjITqZzbC 4dBnSLajw54mUBL0DA6hyXtPfPY4s4IgCND1v85vMw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtohepshhtvggrughmohhnsehgohhoghhlvgdrtghomhdprh gtphhtthhopehphhhilhhlihhprdifohhougesughunhgvlhhmrdhorhhgrdhukhdprhgt phhtthhopehjohhhrghnnhgvshdrshgthhhinhguvghlihhnsehgmhigrdguvgdprhgtph htthhopehgihhtshhtvghrsehpohgsohigrdgtohhmpdhrtghpthhtohepshhpvggtthhr rghlsehgohhoghhlvgdrtghomhdprhgtphhtthhopegvthhhohhmshhonhesvggufigrrh guthhhohhmshhonhdrtghomhdprhgtphhtthhopehlrdhsrdhrseifvggsrdguvgdprhgt phhtthhopehgihhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprhhssg gvtghkvghrsehnvgigsghrihgughgvrdgtohhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:15:01 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 5551cb73 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:14:54 +0000 (UTC) Date: Tue, 3 Sep 2024 11:15:00 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 09/14] Makefile: do not use sparse on third-party sources Message-ID: <7d0f494850a48e5285e8823ff9252fdcf531439e.1725349234.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: We have several third-party sources in our codebase that we have imported from upstream projects. These sources are mostly excluded from our static analysis, for example when running Coccinelle. Do the same for our "sparse" target by filtering them out. Signed-off-by: Patrick Steinhardt --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8c4487dd0c6..81a47b61327 100644 --- a/Makefile +++ b/Makefile @@ -3252,7 +3252,8 @@ t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) $(REFTABLE_TEST_LIB) check-sha1:: t/helper/test-tool$X t/helper/test-sha1.sh -SP_OBJ = $(patsubst %.o,%.sp,$(OBJECTS)) +SP_SRC = $(filter-out $(THIRD_PARTY_SOURCES),$(patsubst %.o,%.c,$(OBJECTS))) +SP_OBJ = $(patsubst %.c,%.sp,$(SP_SRC)) $(SP_OBJ): %.sp: %.c %.o $(GENERATED_H) $(QUIET_SP)cgcc -no-compile $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) \ From patchwork Tue Sep 3 09:15:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788332 Received: from pfhigh7-smtp.messagingengine.com (fhigh7-smtp.messagingengine.com [103.168.172.158]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2F0A419F439 for ; Tue, 3 Sep 2024 09:15:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.158 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354911; cv=none; b=KPK2D85E+4sECDs1zhOyal+Kwux/mE5AWnyks3lKX1vfN7Dm0UtDPd3BwRmTnCjrDm2TXnfOAmKbjCQb/d5NGzOHKd8XtdHDZJH1ThUUQIxfvu5SHg8TUbeMFdTyRFUAQ9K2epVgRXOdW6oLWu4aBPRiqFE4/v7/eRAFcIlNVQw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354911; c=relaxed/simple; bh=qG/GPwVH2LeuJUn1r2gIFUjikw8GvbaB4tnoMuizN/Y=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=r/Wv30zymY8EROcBuwSSHF+5CpmYneu2/wVY8RuTXRXxz8nFOLVru9wvLyIYc26hIIGhBJtXENprQmirAGNKAeQzPEK48RlHe0pGMLY3IoiMNnsuAInCHNnzJ7eczo6X7MK+2u4RtTtaBmK0tWL1BvmuD7jQ3ZSWgTGurhfr4K0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=GrIneEQx; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=bUYtbylz; arc=none smtp.client-ip=103.168.172.158 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="GrIneEQx"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="bUYtbylz" Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfhigh.phl.internal (Postfix) with ESMTP id 352B711402E4; Tue, 3 Sep 2024 05:15:08 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-01.internal (MEProxy); Tue, 03 Sep 2024 05:15:08 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354908; x=1725441308; bh=fKrB79yUX/ zmu79uawav3SlSmoTeM530Dtq33jWLKyg=; b=GrIneEQxyJxbuJI77OBtNxyNob AuFmh8/SnzkeHI56W5Ylz/f9U2wYa61Km75+Q8ZRm1BLFuv9+w2kzifpntB/u3c/ JWt+a61IUlmU1/R96XvOoOFIKbdwSOnS7vwVEMKg2PRfIi1uVaXUA4gYCrZdeI+o vsEbRen+opTOPp0QdXibelp9XTwCVcu+RI2fzyccwwKeTwAyYYPf08ptYpSw5oNO ilwtWv5OTWpZOESongbmPRc8rk405Rh9YExHDvqkeJqprwPaQlpZPWaXNHeDW1// dTUZB3uSjvH9JrpWsElSrPkwntUOqFKLd7M8sCml4bNiqdFYTHMG+drfSgNw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354908; x=1725441308; bh=fKrB79yUX/zmu79uawav3SlSmoTe M530Dtq33jWLKyg=; b=bUYtbylzmPQZprycnmjNwlcKiJhC54k3vpAiU6WZ1wGA fmtz8LKpEP2DCjR/alCO2xkHqcxg3TqK6PPyBzSchRfxrzDi7p3V6luI2nCVV5ow /tcvqgk52YbWp805yOjXVMbvJyYzZOvaXXqa8danjbGNkIOPcpDZr8D8i7x4iNzw 3EwZXT7/561whUaE1JuOmd8mH4muR9XgTTHieqE3TfZLKif7UPhid+dc8V+eDHVU 1L9utNv8ej2Ix2EnIZGecVYra5ciH7qFyVmtWYOja8sOG0du7XU3vTmw2UrkE2rH T8zwf6gUj3lTUng0QeNQlHMI7FJAP2eJ4sFk3VcDjQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedgudefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtohepjhhohhgrnhhnvghsrdhstghhihhnuggvlhhinhesgh hmgidruggvpdhrtghpthhtohepshhtvggrughmohhnsehgohhoghhlvgdrtghomhdprhgt phhtthhopehrshgsvggtkhgvrhesnhgvgigsrhhiughgvgdrtghomhdprhgtphhtthhope hlrdhsrdhrseifvggsrdguvgdprhgtphhtthhopehgihhtshhtvghrsehpohgsohigrdgt ohhmpdhrtghpthhtohepghhithesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtth hopegvthhhohhmshhonhesvggufigrrhguthhhohhmshhonhdrtghomhdprhgtphhtthho pehphhhilhhlihhprdifohhougesughunhgvlhhmrdhorhhgrdhukhdprhgtphhtthhope hsphgvtghtrhgrlhesghhoohhglhgvrdgtohhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:15:06 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 07ec01d2 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:14:59 +0000 (UTC) Date: Tue, 3 Sep 2024 11:15:02 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 10/14] Makefile: wire up the clar unit testing framework Message-ID: <9c74c5ae01989659c0347d2742f820d2161d274b.1725349234.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Wire up the clar unit testing framework by introducing a new "unit-tests" executable. In contrast to the existing framework, this will result in a single executable for all test suites. The ability to pick specific tests to execute is retained via functionality built into the clar itself. Note that we need to be a bit careful about how we need to invalidate our Makefile rules. While we obviously have to regenerate the clar suite when our test suites change, we also have to invalidate it in case any of the test suites gets removed. We do so by using our typical pattern of creating a `GIT-TEST-SUITES` file that gets updated whenever the set of test suites changes, so that we can easily depend on that file. Another specialty is that we generate a "clar-decls.h" file. The test functions are neither static, nor do they have external declarations. This is because they are getting parsed via "generate.py", which then creates the external generations that get populated into an array. These declarations are only seen by the main function though. The consequence is that we will get a bunch of "missing prototypes" errors from our compiler for each of these test functions. To fix those errors, we extract the `extern` declarations from "clar.suite" and put them into a standalone header that then gets included by each of our unit tests. This gets rid of compiler warnings for every function which has been extracted by "generate.py". More importantly though, it does _not_ get rid of warnings in case a function really isn't being used by anything. Thus, it would cause a compiler error if a function name was mistyped and thus not picked up by "generate.py". The test driver "unit-test.c" is an empty stub for now. It will get implemented in the next commit. Signed-off-by: Patrick Steinhardt --- .gitignore | 1 + Makefile | 36 +++++++++++++++++++++--- t/Makefile | 1 + t/unit-tests/.gitignore | 2 ++ t/unit-tests/clar-generate.awk | 50 ++++++++++++++++++++++++++++++++++ t/unit-tests/unit-test.c | 6 ++++ t/unit-tests/unit-test.h | 3 ++ 7 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 t/unit-tests/clar-generate.awk create mode 100644 t/unit-tests/unit-test.c create mode 100644 t/unit-tests/unit-test.h diff --git a/.gitignore b/.gitignore index 8caf3700c23..6687bd6db4c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ /GIT-PYTHON-VARS /GIT-SCRIPT-DEFINES /GIT-SPATCH-DEFINES +/GIT-TEST-SUITES /GIT-USER-AGENT /GIT-VERSION-FILE /bin-wrappers/ diff --git a/Makefile b/Makefile index 81a47b61327..e38146b5eb0 100644 --- a/Makefile +++ b/Makefile @@ -914,6 +914,8 @@ REFTABLE_TEST_LIB = reftable/libreftable_test.a GENERATED_H += command-list.h GENERATED_H += config-list.h GENERATED_H += hook-list.h +GENERATED_H += $(UNIT_TEST_DIR)/clar-decls.h +GENERATED_H += $(UNIT_TEST_DIR)/clar.suite .PHONY: generated-hdrs generated-hdrs: $(GENERATED_H) @@ -1334,6 +1336,11 @@ THIRD_PARTY_SOURCES += sha1dc/% THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/% THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/% +UNIT_TESTS_PROG = $(UNIT_TEST_BIN)/unit-tests$(X) +UNIT_TESTS_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TESTS_SUITES)) +UNIT_TESTS_OBJS += $(UNIT_TEST_DIR)/clar/clar.o +UNIT_TESTS_OBJS += $(UNIT_TEST_DIR)/unit-test.o + UNIT_TEST_PROGRAMS += t-ctype UNIT_TEST_PROGRAMS += t-example-decorate UNIT_TEST_PROGRAMS += t-hash @@ -2714,6 +2721,7 @@ OBJECTS += $(XDIFF_OBJS) OBJECTS += $(FUZZ_OBJS) OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS) OBJECTS += $(UNIT_TEST_OBJS) +OBJECTS += $(UNIT_TESTS_OBJS) ifndef NO_CURL OBJECTS += http.o http-walker.o remote-curl.o @@ -3216,7 +3224,7 @@ endif test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X)) -all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) +all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) $(UNIT_TESTS_PROG) bin-wrappers/%: wrap-for-bin.sh $(call mkdir_p_parent_template) @@ -3648,7 +3656,7 @@ endif artifacts-tar:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) \ GIT-BUILD-OPTIONS $(TEST_PROGRAMS) $(test_bindir_programs) \ - $(UNIT_TEST_PROGS) $(MOFILES) + $(UNIT_TEST_PROGS) $(UNIT_TESTS_PROG) $(MOFILES) $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) \ SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)' test -n "$(ARTIFACTS_DIRECTORY)" @@ -3704,6 +3712,7 @@ cocciclean: clean: profile-clean coverage-clean cocciclean $(RM) -r .build $(UNIT_TEST_BIN) + $(RM) GIT-TEST-SUITES $(RM) po/git.pot po/git-core.pot $(RM) git.res $(RM) $(OBJECTS) @@ -3863,7 +3872,26 @@ $(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o \ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \ $(filter %.o,$^) $(filter %.a,$^) $(LIBS) +GIT-TEST-SUITES: FORCE + @FLAGS='$(UNIT_TESTS_SUITES)'; \ + if test x"$$FLAGS" != x"`cat GIT-TEST-SUITES 2>/dev/null`" ; then \ + echo >&2 " * new test suites"; \ + echo "$$FLAGS" >GIT-TEST-SUITES; \ + fi + +$(UNIT_TEST_DIR)/clar-decls.h: $(patsubst %,$(UNIT_TEST_DIR)/%.c,$(UNIT_TESTS_SUITES)) GIT-TEST-SUITES + $(QUIET_GEN)for suite in $(UNIT_TESTS_SUITES); do \ + sed -ne "s/^\(void test_$${suite}__[a-zA-Z_0-9][a-zA-Z_0-9]*(void)$$\)/extern \1;/p" $(UNIT_TEST_DIR)/$$suite.c; \ + done >$@ +$(UNIT_TEST_DIR)/clar.suite: $(UNIT_TEST_DIR)/clar-decls.h + $(QUIET_GEN)awk -f $(UNIT_TEST_DIR)/clar-generate.awk $< >$(UNIT_TEST_DIR)/clar.suite +$(UNIT_TESTS_OBJS): $(UNIT_TEST_DIR)/clar-decls.h +$(UNIT_TESTS_OBJS): EXTRA_CPPFLAGS = -I$(UNIT_TEST_DIR) +$(UNIT_TESTS_PROG): $(UNIT_TEST_DIR)/clar.suite $(UNIT_TESTS_OBJS) $(GITLIBS) GIT-LDFLAGS + $(call mkdir_p_parent_template) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) + .PHONY: build-unit-tests unit-tests -build-unit-tests: $(UNIT_TEST_PROGS) -unit-tests: $(UNIT_TEST_PROGS) t/helper/test-tool$X +build-unit-tests: $(UNIT_TEST_PROGS) $(UNIT_TESTS_PROG) +unit-tests: $(UNIT_TEST_PROGS) $(UNIT_TESTS_PROG) t/helper/test-tool$X $(MAKE) -C t/ unit-tests diff --git a/t/Makefile b/t/Makefile index d2212de0b78..131ffd778fe 100644 --- a/t/Makefile +++ b/t/Makefile @@ -48,6 +48,7 @@ CHAINLINTTESTS = $(sort $(patsubst chainlint/%.test,%,$(wildcard chainlint/*.tes CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl UNIT_TEST_SOURCES = $(wildcard unit-tests/t-*.c) UNIT_TEST_PROGRAMS = $(patsubst unit-tests/%.c,unit-tests/bin/%$(X),$(UNIT_TEST_SOURCES)) +UNIT_TEST_PROGRAMS += unit-tests/bin/unit-tests$(X) UNIT_TESTS = $(sort $(UNIT_TEST_PROGRAMS)) UNIT_TESTS_NO_DIR = $(notdir $(UNIT_TESTS)) diff --git a/t/unit-tests/.gitignore b/t/unit-tests/.gitignore index 5e56e040ec0..d0632ec7f9e 100644 --- a/t/unit-tests/.gitignore +++ b/t/unit-tests/.gitignore @@ -1 +1,3 @@ /bin +/clar.suite +/clar-decls.h diff --git a/t/unit-tests/clar-generate.awk b/t/unit-tests/clar-generate.awk new file mode 100644 index 00000000000..ab71ce6c9fc --- /dev/null +++ b/t/unit-tests/clar-generate.awk @@ -0,0 +1,50 @@ +function add_suite(suite, initialize, cleanup, count) { + if (!suite) return + suite_count++ + callback_count += count + suites = suites " {\n" + suites = suites " \"" suite "\",\n" + suites = suites " " initialize ",\n" + suites = suites " " cleanup ",\n" + suites = suites " _clar_cb_" suite ", " count ", 1\n" + suites = suites " },\n" +} + +BEGIN { + suites = "static struct clar_suite _clar_suites[] = {\n" +} + +{ + print + name = $3; sub(/\(.*$/, "", name) + suite = name; sub(/^test_/, "", suite); sub(/__.*$/, "", suite) + short_name = name; sub(/^.*__/, "", short_name) + cb = "{ \"" short_name "\", &" name " }" + if (suite != prev_suite) { + add_suite(prev_suite, initialize, cleanup, count) + if (callbacks) callbacks = callbacks "};\n" + callbacks = callbacks "static const struct clar_func _clar_cb_" suite "[] = {\n" + initialize = "{ NULL, NULL }" + cleanup = "{ NULL, NULL }" + count = 0 + prev_suite = suite + } + if (short_name == "initialize") { + initialize = cb + } else if (short_name == "cleanup") { + cleanup = cb + } else { + callbacks = callbacks " " cb ",\n" + count++ + } +} + +END { + add_suite(suite, initialize, cleanup, count) + suites = suites "};" + if (callbacks) callbacks = callbacks "};" + print callbacks + print suites + print "static const size_t _clar_suite_count = " suite_count ";" + print "static const size_t _clar_callback_count = " callback_count ";" +} diff --git a/t/unit-tests/unit-test.c b/t/unit-tests/unit-test.c new file mode 100644 index 00000000000..3d12cde6dae --- /dev/null +++ b/t/unit-tests/unit-test.c @@ -0,0 +1,6 @@ +#include "unit-test.h" + +int cmd_main(int argc UNUSED, const char **argv UNUSED) +{ + return 0; +} diff --git a/t/unit-tests/unit-test.h b/t/unit-tests/unit-test.h new file mode 100644 index 00000000000..66ec2387cc6 --- /dev/null +++ b/t/unit-tests/unit-test.h @@ -0,0 +1,3 @@ +#include "git-compat-util.h" +#include "clar/clar.h" +#include "clar-decls.h" From patchwork Tue Sep 3 09:15:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788333 Received: from pfout3-smtp.messagingengine.com (fout3-smtp.messagingengine.com [103.168.172.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5258D1A4E84 for ; Tue, 3 Sep 2024 09:15:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354913; cv=none; b=qDaWPHkJMPuUogUPThxvvoF1BRH5YeYqIq6fuuRS9ueQYt+ZZJem4z/mEALdjVpdrThOqW7T6VIxO7hIGWOuKBJSwuKHk2qQAh+dBSiewUR3KNS9FkGmkkI8ByidwcuIggFYE/iOQ17W/3dGUI2o0VMhaWC8KjekvGyGBcftUxI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354913; c=relaxed/simple; bh=6Yo4t7T8tMGPfD5/7GuVm6Qu351ugaTrN+0WIx1qZrQ=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=eeWoOmcxbmCE8MJN2vulz6uLyo7PLRHN2zSN5sKHFbQyY4UP1Hu52Kx4PM/w0063EuFZDu4sEjeuWCMQuxc87r4Nb+hbiuqSFkuPmVUQ0reKmaOF5ImPIxikByLH7UafMMUtm3QoIkCkzvKOKOHwMI+eZ4p/pK3n/8wiH9jHClU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=BrQlBu8d; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=U8l4G+fU; arc=none smtp.client-ip=103.168.172.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="BrQlBu8d"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="U8l4G+fU" Received: from phl-compute-08.internal (phl-compute-08.phl.internal [10.202.2.48]) by mailfout.phl.internal (Postfix) with ESMTP id 27721138039B; Tue, 3 Sep 2024 05:15:11 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-08.internal (MEProxy); Tue, 03 Sep 2024 05:15:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354911; x=1725441311; bh=ySSHlaLZoG gsdS4kmZH5RddeQPoSTlVVhMDFh7zZo8c=; b=BrQlBu8d2vdwzwKmY4ME+A0fGc ds3RKkBsj+wiGO+GglTydHXdO7JUlbKujGEwnqCblAjY97xrtIvQapjCKNVtIVLU S1KWZVx1sF3KRAiGMTK3Yo0eyZ2Mf+JqOErGb+GaztfXarKEWNCf3iioUgq+UZm2 pSyjF/1yf4hXU0bniCQFImIqyxHH57I50OVf1YQ7su4u7lr+zfqj56IZu5otUTQ4 1biS+16VuLaG7Dcs+seEnCb3FfXmgvjRzEScsQpwqYJCM7sfAJnOnWUOcHlu2+kr HNAQefJuZi0PgImVURVeoIb5xdXDUtoDbnynWRMj8+vCXYipv8NHxb/OqxbA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354911; x=1725441311; bh=ySSHlaLZoGgsdS4kmZH5RddeQPoS TlVVhMDFh7zZo8c=; b=U8l4G+fUXIrWMmIy46/cndIdBdU5mQBZfHl2wzCWlGhG zvmeOddc9o0uRzkhEwcknEikkkUBOIbEyRGNwhQU6B6dUpZMYrHiv9XmS5U6Z8vd Ni6g0ROHgV9YCyxFEf0nkLA4ufgQDbF+DQqqGfFMJRwquAcUMCtFBx853FCFydw1 HRoI9q6yKztdCtZ/E6dxfrNXCcpbbGV2J/b9dc7NtJacLBy/ILD3OLB4b3lGRO8s qRRDJJs79hed5FkAmb+FeNofQQpoKcdN5UM+dX90c7hXYjzJ6v52L731+HGNexsW 7FRcNFtVLvrG3MS7gPFSlOHOeXqKmn2OMMg7tb1LIQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtoheplhdrshdrrhesfigvsgdruggvpdhrtghpthhtohepgh hithesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehsthgvrggumhhonhes ghhoohhglhgvrdgtohhmpdhrtghpthhtoheprhhssggvtghkvghrsehnvgigsghrihgugh gvrdgtohhmpdhrtghpthhtohepjhhohhgrnhhnvghsrdhstghhihhnuggvlhhinhesghhm gidruggvpdhrtghpthhtohepvghthhhomhhsohhnsegvugifrghrughthhhomhhsohhnrd gtohhmpdhrtghpthhtohepphhhihhllhhiphdrfihoohguseguuhhnvghlmhdrohhrghdr uhhkpdhrtghpthhtohepshhpvggtthhrrghlsehgohhoghhlvgdrtghomhdprhgtphhtth hopehgihhtshhtvghrsehpohgsohigrdgtohhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:15:09 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 5d3a1ae9 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:15:02 +0000 (UTC) Date: Tue, 3 Sep 2024 11:15:07 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 11/14] t/unit-tests: implement test driver Message-ID: <8bd5b3e2b2989a30b597da2103eb8d9699cf3d7f.1725349234.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The test driver in "unit-test.c" is responsible for setting up our unit tests and eventually running them. As such, it is also responsible for parsing the command line arguments. The clar unit testing framework provides function `clar_test()` that parses command line arguments and then executes the tests for us. In theory that would already be sufficient. We have the special requirement to always generate TAP-formatted output though, so we'd have to always pass the "-t" argument to clar. Furthermore, some of the options exposed by clar are ineffective when "-t" is used, but they would still be shown when the user passes the "-h" parameter to have the clar show its usage. Implement our own option handling instead of using the one provided by clar, which gives us greater flexibility in how exactly we set things up. We would ideally not use any "normal" code of ours for this such that the unit testing framework doesn't depend on it working correctly. But it is somewhat dubious whether we really want to reimplement all of the option parsing. So for now, let's be pragmatic and reuse it until we find a good reason in the future why we'd really want to avoid it. Signed-off-by: Patrick Steinhardt --- t/unit-tests/unit-test.c | 43 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/t/unit-tests/unit-test.c b/t/unit-tests/unit-test.c index 3d12cde6dae..96fa64de71d 100644 --- a/t/unit-tests/unit-test.c +++ b/t/unit-tests/unit-test.c @@ -1,6 +1,45 @@ #include "unit-test.h" +#include "parse-options.h" +#include "string-list.h" +#include "strvec.h" -int cmd_main(int argc UNUSED, const char **argv UNUSED) +static const char * const unit_test_usage[] = { + N_("unit-test []"), + NULL, +}; + +int cmd_main(int argc, const char **argv) { - return 0; + struct string_list run_args = STRING_LIST_INIT_NODUP; + struct string_list exclude_args = STRING_LIST_INIT_NODUP; + int immediate = 0; + struct option options[] = { + OPT_BOOL('i', "--immediate", &immediate, + N_("immediately exit upon the first failed test")), + OPT_STRING_LIST('r', "run", &run_args, N_("name"), + N_("run only test suite or individual test ")), + OPT_STRING_LIST('x', "exclude", &exclude_args, N_("name"), + N_("exclude test suite ")), + OPT_END(), + }; + struct strvec args = STRVEC_INIT; + int ret; + + argc = parse_options(argc, argv, NULL, options, + unit_test_usage, PARSE_OPT_KEEP_ARGV0); + if (argc > 1) + usagef(_("extra command line parameter '%s'"), argv[0]); + + strvec_push(&args, argv[0]); + strvec_push(&args, "-t"); + for (size_t i = 0; i < run_args.nr; i++) + strvec_pushf(&args, "-s%s", run_args.items[i].string); + for (size_t i = 0; i < exclude_args.nr; i++) + strvec_pushf(&args, "-x%s", exclude_args.items[i].string); + + ret = clar_test(args.nr, (char **) args.v); + + string_list_clear(&run_args, 0); + strvec_clear(&args); + return ret; } From patchwork Tue Sep 3 09:15:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788334 Received: from pfout3-smtp.messagingengine.com (fout3-smtp.messagingengine.com [103.168.172.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0675A1A4E80 for ; Tue, 3 Sep 2024 09:15:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354915; cv=none; b=ltFS3P4T5aEcoV3ubluIF+4mb55M+6dmxSbhG4qxnY9wMHfWeZTQJOkH/NLII8dYLgpBqZZLAgOV/lBD7EY/V59gCTElHxJlEDctIq7G0fie971cvlAaNWz3jIcyucxUP/uRfJj/N/XaE8RV0BNooj9dN2WFOTrFq+iAvVpFRw8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354915; c=relaxed/simple; bh=lNlgOPpzOgO/u4gCgguqjwoMja4/zM8s2KTFhTM+WIA=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=EvkgRzKFPyvbMYV1s61Q62oV0Q8/dfJITA4gcDO6Q/CaBuHNU0Mu4xVdqWNfWJ39TWdDPtdKAKicAjD2Fxk9ffrly5BHOLA9eHyUm6P8CYF8cpX0j9r7rXEpEPpb0Wekj/BPRa+N/gZM9oBuDLoOsH3Xux3qFJDDhXtSAvMiYcA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=p+CMYZu8; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=SOyROd3S; arc=none smtp.client-ip=103.168.172.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="p+CMYZu8"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="SOyROd3S" Received: from phl-compute-07.internal (phl-compute-07.phl.internal [10.202.2.47]) by mailfout.phl.internal (Postfix) with ESMTP id 0FD731380409; Tue, 3 Sep 2024 05:15:13 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-07.internal (MEProxy); Tue, 03 Sep 2024 05:15:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354913; x=1725441313; bh=DqHh6f3TXV xvIVqbz3W52tttlLqyNi3TJ/82CGB8I+k=; b=p+CMYZu8xQzr2JEvDOkHL4w6ik ZDfUh3kJFuW7Zh8iLIZM/18F9x/DFu4U16ZpAd0ziDgWTTZ0JnpBE79Oo0sLjG5f 6raEFxhYL0trMvjLROJ53+idTFdBPcEvRggvWyEoiWKxC05v/oF7ewsnMyxnVjPI qNcQMgr5pJyjjbZBrpyrY6XhfFHbnoxRAD/MjAlQscSNDyrxMJuiMCTkPImQ9yDn ea7GlXPWGfuUUYfxUDEAXRuINeoqPtYju0F9sQuNSEc4zbfCJNwEHCo5rlA+hXzj GzOjo/3q04Jk+BHKmm5UBu+I2lDRBRiUXdtYjvNR682EAq8pNkjW0E9KtutQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354913; x=1725441313; bh=DqHh6f3TXVxvIVqbz3W52tttlLqy Ni3TJ/82CGB8I+k=; b=SOyROd3StrwwsnxlWrO2vA6ArtabRAz1mCshcek2wi+o p+nQEXcd+5Rkz13HSjkhrAk/vahvx++BsWTpe3fqiQR2x2sfKWSzQma/MV2ggG0E 9pUqg3bGmZgu9SctkP0T+ntElgFZQkKtd8AqrAelAK7Je4cr7kaWebmD4EnWxF8+ 8/eRL5vIE7dbwhJKns04gOyXAEk78UP97DAMYAcXPWOLpBjnMRqSSJh5HGdrmRD0 X+p9mzxbLV5jlfxqQhbwLN+ncVfWPMVcmFJ58htOTyPNbTxXdkM9FEHsCyzJDqS1 DKGwzc5A/peY5zNF1h5hqHsKwpyxcnlN/G7aKmQ+FQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgepudenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtoheplhdrshdrrhesfigvsgdruggvpdhrtghpthhtoheprh hssggvtghkvghrsehnvgigsghrihgughgvrdgtohhmpdhrtghpthhtohepghhithhsthgv rhesphhosghogidrtghomhdprhgtphhtthhopehgihhtsehvghgvrhdrkhgvrhhnvghlrd horhhgpdhrtghpthhtohepphhhihhllhhiphdrfihoohguseguuhhnvghlmhdrohhrghdr uhhkpdhrtghpthhtohepshhtvggrughmohhnsehgohhoghhlvgdrtghomhdprhgtphhtth hopehsphgvtghtrhgrlhesghhoohhglhgvrdgtohhmpdhrtghpthhtohepjhhohhgrnhhn vghsrdhstghhihhnuggvlhhinhesghhmgidruggvpdhrtghpthhtohepvghthhhomhhsoh hnsegvugifrghrughthhhomhhsohhnrdgtohhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:15:11 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 947220d5 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:15:04 +0000 (UTC) Date: Tue, 3 Sep 2024 11:15:10 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 12/14] t/unit-tests: convert strvec tests to use clar Message-ID: <3c3b9eacdfb5c5410b1ce868869564bcd4256013.1725349234.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Convert the strvec tests to use the new clar unit testing framework. This is a first test balloon that demonstrates how the testing infra for clar-based tests looks like. The tests are part of the "t/unit-tests/bin/unit-tests" binary. When running that binary with an injected error, it generates TAP output: # ./t/unit-tests/bin/unit-tests TAP version 13 # start of suite 1: strvec ok 1 - strvec::init ok 2 - strvec::dynamic_init ok 3 - strvec::clear not ok 4 - strvec::push --- reason: | String mismatch: (&vec)->v[i] != expect[i] 'foo' != 'fo' (at byte 2) at: file: 't/unit-tests/strvec.c' line: 48 function: 'test_strvec__push' --- ok 5 - strvec::pushf ok 6 - strvec::pushl ok 7 - strvec::pushv ok 8 - strvec::replace_at_head ok 9 - strvec::replace_at_tail ok 10 - strvec::replace_in_between ok 11 - strvec::replace_with_substring ok 12 - strvec::remove_at_head ok 13 - strvec::remove_at_tail ok 14 - strvec::remove_in_between ok 15 - strvec::pop_empty_array ok 16 - strvec::pop_non_empty_array ok 17 - strvec::split_empty_string ok 18 - strvec::split_single_item ok 19 - strvec::split_multiple_items ok 20 - strvec::split_whitespace_only ok 21 - strvec::split_multiple_consecutive_whitespaces ok 22 - strvec::detach 1..22 The binary also supports some parameters that allow us to run only a subset of unit tests or alter the output: $ ./t/unit-tests/bin/unit-tests -h Usage: ./t/unit-tests/bin/unit-tests [options] Options: -sname Run only the suite with `name` (can go to individual test name) -iname Include the suite with `name` -xname Exclude the suite with `name` -v Increase verbosity (show suite names) -q Only report tests that had an error -Q Quit as soon as a test fails -t Display results in tap format -l Print suite names -r[filename] Write summary file (to the optional filename) Furthermore, running `make unit-tests` runs the binary along with all the other unit tests we have. Signed-off-by: Patrick Steinhardt --- Makefile | 2 +- t/unit-tests/strvec.c | 241 ++++++++++++++++++++++++++++++++++++++++ t/unit-tests/t-strvec.c | 211 ----------------------------------- 3 files changed, 242 insertions(+), 212 deletions(-) create mode 100644 t/unit-tests/strvec.c delete mode 100644 t/unit-tests/t-strvec.c diff --git a/Makefile b/Makefile index e38146b5eb0..56ce6c00e44 100644 --- a/Makefile +++ b/Makefile @@ -1336,6 +1336,7 @@ THIRD_PARTY_SOURCES += sha1dc/% THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/% THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/% +UNIT_TESTS_SUITES += strvec UNIT_TESTS_PROG = $(UNIT_TEST_BIN)/unit-tests$(X) UNIT_TESTS_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TESTS_SUITES)) UNIT_TESTS_OBJS += $(UNIT_TEST_DIR)/clar/clar.o @@ -1356,7 +1357,6 @@ UNIT_TEST_PROGRAMS += t-reftable-record UNIT_TEST_PROGRAMS += t-reftable-tree UNIT_TEST_PROGRAMS += t-strbuf UNIT_TEST_PROGRAMS += t-strcmp-offset -UNIT_TEST_PROGRAMS += t-strvec UNIT_TEST_PROGRAMS += t-trailer UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS)) UNIT_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS)) diff --git a/t/unit-tests/strvec.c b/t/unit-tests/strvec.c new file mode 100644 index 00000000000..bf4c0cb172e --- /dev/null +++ b/t/unit-tests/strvec.c @@ -0,0 +1,241 @@ +#include "unit-test.h" +#include "strbuf.h" +#include "strvec.h" + +#define check_strvec(vec, ...) \ + do { \ + const char *expect[] = { __VA_ARGS__ }; \ + size_t expect_len = ARRAY_SIZE(expect); \ + cl_assert(expect_len > 0); \ + cl_assert_equal_p(expect[expect_len - 1], NULL); \ + cl_assert_equal_i((vec)->nr, expect_len - 1); \ + cl_assert((vec)->nr <= (vec)->alloc); \ + for (size_t i = 0; i < expect_len; i++) \ + cl_assert_equal_s((vec)->v[i], expect[i]); \ + } while (0) + +void test_strvec__init(void) +{ + struct strvec vec = STRVEC_INIT; + + cl_assert_equal_p(vec.v, empty_strvec); + cl_assert_equal_i(vec.nr, 0); + cl_assert_equal_i(vec.alloc, 0); +} + +void test_strvec__dynamic_init(void) +{ + struct strvec vec; + + strvec_init(&vec); + cl_assert_equal_p(vec.v, empty_strvec); + cl_assert_equal_i(vec.nr, 0); + cl_assert_equal_i(vec.alloc, 0); +} + +void test_strvec__clear(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_push(&vec, "foo"); + strvec_clear(&vec); + cl_assert_equal_p(vec.v, empty_strvec); + cl_assert_equal_i(vec.nr, 0); + cl_assert_equal_i(vec.alloc, 0); +} + +void test_strvec__push(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_push(&vec, "foo"); + check_strvec(&vec, "foo", NULL); + + strvec_push(&vec, "bar"); + check_strvec(&vec, "foo", "bar", NULL); + + strvec_clear(&vec); +} + +void test_strvec__pushf(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushf(&vec, "foo: %d", 1); + check_strvec(&vec, "foo: 1", NULL); + strvec_clear(&vec); +} + +void test_strvec__pushl(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + check_strvec(&vec, "foo", "bar", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__pushv(void) +{ + const char *strings[] = { + "foo", "bar", "baz", NULL, + }; + struct strvec vec = STRVEC_INIT; + + strvec_pushv(&vec, strings); + check_strvec(&vec, "foo", "bar", "baz", NULL); + + strvec_clear(&vec); +} + +void test_strvec__replace_at_head(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 0, "replaced"); + check_strvec(&vec, "replaced", "bar", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__replace_at_tail(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 2, "replaced"); + check_strvec(&vec, "foo", "bar", "replaced", NULL); + strvec_clear(&vec); +} + +void test_strvec__replace_in_between(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 1, "replaced"); + check_strvec(&vec, "foo", "replaced", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__replace_with_substring(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", NULL); + strvec_replace(&vec, 0, vec.v[0] + 1); + check_strvec(&vec, "oo", NULL); + strvec_clear(&vec); +} + +void test_strvec__remove_at_head(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 0); + check_strvec(&vec, "bar", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__remove_at_tail(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 2); + check_strvec(&vec, "foo", "bar", NULL); + strvec_clear(&vec); +} + +void test_strvec__remove_in_between(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 1); + check_strvec(&vec, "foo", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__pop_empty_array(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pop(&vec); + check_strvec(&vec, NULL); + strvec_clear(&vec); +} + +void test_strvec__pop_non_empty_array(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_pop(&vec); + check_strvec(&vec, "foo", "bar", NULL); + strvec_clear(&vec); +} + +void test_strvec__split_empty_string(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_split(&vec, ""); + check_strvec(&vec, NULL); + strvec_clear(&vec); +} + +void test_strvec__split_single_item(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_split(&vec, "foo"); + check_strvec(&vec, "foo", NULL); + strvec_clear(&vec); +} + +void test_strvec__split_multiple_items(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_split(&vec, "foo bar baz"); + check_strvec(&vec, "foo", "bar", "baz", NULL); + strvec_clear(&vec); +} + +void test_strvec__split_whitespace_only(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_split(&vec, " \t\n"); + check_strvec(&vec, NULL); + strvec_clear(&vec); +} + +void test_strvec__split_multiple_consecutive_whitespaces(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_split(&vec, "foo\n\t bar"); + check_strvec(&vec, "foo", "bar", NULL); + strvec_clear(&vec); +} + +void test_strvec__detach(void) +{ + struct strvec vec = STRVEC_INIT; + const char **detached; + + strvec_push(&vec, "foo"); + + detached = strvec_detach(&vec); + cl_assert_equal_s(detached[0], "foo"); + cl_assert_equal_p(detached[1], NULL); + + cl_assert_equal_p(vec.v, empty_strvec); + cl_assert_equal_i(vec.nr, 0); + cl_assert_equal_i(vec.alloc, 0); + + free((char *) detached[0]); + free(detached); +} diff --git a/t/unit-tests/t-strvec.c b/t/unit-tests/t-strvec.c deleted file mode 100644 index c4bac8fc91b..00000000000 --- a/t/unit-tests/t-strvec.c +++ /dev/null @@ -1,211 +0,0 @@ -#include "test-lib.h" -#include "strbuf.h" -#include "strvec.h" - -#define check_strvec(vec, ...) \ - do { \ - const char *expect[] = { __VA_ARGS__ }; \ - if (check_uint(ARRAY_SIZE(expect), >, 0) && \ - check_pointer_eq(expect[ARRAY_SIZE(expect) - 1], NULL) && \ - check_uint((vec)->nr, ==, ARRAY_SIZE(expect) - 1) && \ - check_uint((vec)->nr, <=, (vec)->alloc)) { \ - for (size_t i = 0; i < ARRAY_SIZE(expect); i++) { \ - if (!check_str((vec)->v[i], expect[i])) { \ - test_msg(" i: %"PRIuMAX, \ - (uintmax_t)i); \ - break; \ - } \ - } \ - } \ - } while (0) - -int cmd_main(int argc, const char **argv) -{ - if_test ("static initialization") { - struct strvec vec = STRVEC_INIT; - check_pointer_eq(vec.v, empty_strvec); - check_uint(vec.nr, ==, 0); - check_uint(vec.alloc, ==, 0); - } - - if_test ("dynamic initialization") { - struct strvec vec; - strvec_init(&vec); - check_pointer_eq(vec.v, empty_strvec); - check_uint(vec.nr, ==, 0); - check_uint(vec.alloc, ==, 0); - } - - if_test ("clear") { - struct strvec vec = STRVEC_INIT; - strvec_push(&vec, "foo"); - strvec_clear(&vec); - check_pointer_eq(vec.v, empty_strvec); - check_uint(vec.nr, ==, 0); - check_uint(vec.alloc, ==, 0); - } - - if_test ("push") { - struct strvec vec = STRVEC_INIT; - - strvec_push(&vec, "foo"); - check_strvec(&vec, "foo", NULL); - - strvec_push(&vec, "bar"); - check_strvec(&vec, "foo", "bar", NULL); - - strvec_clear(&vec); - } - - if_test ("pushf") { - struct strvec vec = STRVEC_INIT; - strvec_pushf(&vec, "foo: %d", 1); - check_strvec(&vec, "foo: 1", NULL); - strvec_clear(&vec); - } - - if_test ("pushl") { - struct strvec vec = STRVEC_INIT; - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - check_strvec(&vec, "foo", "bar", "baz", NULL); - strvec_clear(&vec); - } - - if_test ("pushv") { - const char *strings[] = { - "foo", "bar", "baz", NULL, - }; - struct strvec vec = STRVEC_INIT; - - strvec_pushv(&vec, strings); - check_strvec(&vec, "foo", "bar", "baz", NULL); - - strvec_clear(&vec); - } - - if_test ("replace at head") { - struct strvec vec = STRVEC_INIT; - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_replace(&vec, 0, "replaced"); - check_strvec(&vec, "replaced", "bar", "baz", NULL); - strvec_clear(&vec); - } - - if_test ("replace at tail") { - struct strvec vec = STRVEC_INIT; - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_replace(&vec, 2, "replaced"); - check_strvec(&vec, "foo", "bar", "replaced", NULL); - strvec_clear(&vec); - } - - if_test ("replace in between") { - struct strvec vec = STRVEC_INIT; - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_replace(&vec, 1, "replaced"); - check_strvec(&vec, "foo", "replaced", "baz", NULL); - strvec_clear(&vec); - } - - if_test ("replace with substring") { - struct strvec vec = STRVEC_INIT; - strvec_pushl(&vec, "foo", NULL); - strvec_replace(&vec, 0, vec.v[0] + 1); - check_strvec(&vec, "oo", NULL); - strvec_clear(&vec); - } - - if_test ("remove at head") { - struct strvec vec = STRVEC_INIT; - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_remove(&vec, 0); - check_strvec(&vec, "bar", "baz", NULL); - strvec_clear(&vec); - } - - if_test ("remove at tail") { - struct strvec vec = STRVEC_INIT; - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_remove(&vec, 2); - check_strvec(&vec, "foo", "bar", NULL); - strvec_clear(&vec); - } - - if_test ("remove in between") { - struct strvec vec = STRVEC_INIT; - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_remove(&vec, 1); - check_strvec(&vec, "foo", "baz", NULL); - strvec_clear(&vec); - } - - if_test ("pop with empty array") { - struct strvec vec = STRVEC_INIT; - strvec_pop(&vec); - check_strvec(&vec, NULL); - strvec_clear(&vec); - } - - if_test ("pop with non-empty array") { - struct strvec vec = STRVEC_INIT; - strvec_pushl(&vec, "foo", "bar", "baz", NULL); - strvec_pop(&vec); - check_strvec(&vec, "foo", "bar", NULL); - strvec_clear(&vec); - } - - if_test ("split empty string") { - struct strvec vec = STRVEC_INIT; - strvec_split(&vec, ""); - check_strvec(&vec, NULL); - strvec_clear(&vec); - } - - if_test ("split single item") { - struct strvec vec = STRVEC_INIT; - strvec_split(&vec, "foo"); - check_strvec(&vec, "foo", NULL); - strvec_clear(&vec); - } - - if_test ("split multiple items") { - struct strvec vec = STRVEC_INIT; - strvec_split(&vec, "foo bar baz"); - check_strvec(&vec, "foo", "bar", "baz", NULL); - strvec_clear(&vec); - } - - if_test ("split whitespace only") { - struct strvec vec = STRVEC_INIT; - strvec_split(&vec, " \t\n"); - check_strvec(&vec, NULL); - strvec_clear(&vec); - } - - if_test ("split multiple consecutive whitespaces") { - struct strvec vec = STRVEC_INIT; - strvec_split(&vec, "foo\n\t bar"); - check_strvec(&vec, "foo", "bar", NULL); - strvec_clear(&vec); - } - - if_test ("detach") { - struct strvec vec = STRVEC_INIT; - const char **detached; - - strvec_push(&vec, "foo"); - - detached = strvec_detach(&vec); - check_str(detached[0], "foo"); - check_pointer_eq(detached[1], NULL); - - check_pointer_eq(vec.v, empty_strvec); - check_uint(vec.nr, ==, 0); - check_uint(vec.alloc, ==, 0); - - free((char *) detached[0]); - free(detached); - } - - return test_done(); -} From patchwork Tue Sep 3 09:15:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788335 Received: from pfout3-smtp.messagingengine.com (fout3-smtp.messagingengine.com [103.168.172.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B94351AD248 for ; Tue, 3 Sep 2024 09:15:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354918; cv=none; b=vDPuw4gOX5WvBcsq3nSrVloia7bLkqwe02xFQ9T9teAiVFBlhqv5yThVARC2HddwU1ikktsV/V6Ejy0VsHBTRFPwjIxktTdXRftbRrz3T/OmEO9h7TSipqNZISbaTNnAegIZYRWkcG4V2mWeHUgalfMvdFfqlikFyva4ODuCYDM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354918; c=relaxed/simple; bh=o8AvCYwdX4wfPRnqvqq7AeJ4cCZ4DL0EMdedHCki+WM=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=dHd7jdVGQaJ4qa1M7eEV76WpJsRnrHxEgjpXRYKVtwyQhXE86k9Ulda4/ikPLrtlxjmhZAZGOgnOOmyMh7hUr4dykJre5oNLGLkvIltLhBQ+EpimOLFw1lzKdLpPx//LUtbc5xQyjoY5IsvL9UQ0MSrWeoBS80eNQZHTXRS4I8Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=nA4fkj2i; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=BruDZLlp; arc=none smtp.client-ip=103.168.172.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="nA4fkj2i"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="BruDZLlp" Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfout.phl.internal (Postfix) with ESMTP id DCE4C1380407; Tue, 3 Sep 2024 05:15:15 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-05.internal (MEProxy); Tue, 03 Sep 2024 05:15:15 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354915; x=1725441315; bh=KAAxfKJS18 jrKgJEhHgipsfQrRvdndevq+kMqC1nqCQ=; b=nA4fkj2iCmc1kDtA1G2KzE/mD6 Nz8XeRtNnTbTTJ8+WW6emL4JUVU/5tT+JNBZaMzbM6nqDL1Bdi/Lg1E1D43NRCwb JkUZYvx14vz0SPkcQQtq5FIWUCddE2P60nmn08qDN+Vm7eTAiOYjQyI5eKGv+KtP lwg2ALIzZVmDYQAsB17xfvwclzwX63r6z61TLdTPS9RHxf3f7AzpvlXKMNOPGye5 bi45YbbT22Sw14UaCJH5hzfqH9/eZvb6OAIQyJ//cVK2qqnSZMTaZ8kIIwkmx70c 85vV+DvCUrXyVB9497gUKqYdzbGiUdp8CMeltCXD82oshqphAnJVGHmFchoA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354915; x=1725441315; bh=KAAxfKJS18jrKgJEhHgipsfQrRvd ndevq+kMqC1nqCQ=; b=BruDZLlpBXDlIg8888hebP8HuCZ8450BabKHi1r1jNVj pRZD7AHfW+Lg5diofZn8x0jkm5lqgOFt7D0KQPYeiZzjU/41tg9UMG14UDDdrLSW La0JilM4QNwwqGh62RuqgLIKLiNRHLrA7eSCXBX4C01/5crTmdj0uXwyesQRcj/r X5PxzYAJYrA/clb62JM4Qa3SYKwzpZJHT9MpQmWwyQ6qa3TrYjsh7FchHe02iakT gxS0rbQjxI13nD6wvmwFsu4vsZbxgy1y/h6i08mgcPN3gHj4IoH+5oZPeHt/0qDN aWOFGQwxkTMZlbL5NOJZQ9mg1CoyMP0w7UkhdcVPFQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgepvdenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtohepvghthhhomhhsohhnsegvugifrghrughthhhomhhsoh hnrdgtohhmpdhrtghpthhtohepjhhohhgrnhhnvghsrdhstghhihhnuggvlhhinhesghhm gidruggvpdhrtghpthhtohepshhpvggtthhrrghlsehgohhoghhlvgdrtghomhdprhgtph htthhopehlrdhsrdhrseifvggsrdguvgdprhgtphhtthhopehgihhtshhtvghrsehpohgs ohigrdgtohhmpdhrtghpthhtoheprhhssggvtghkvghrsehnvgigsghrihgughgvrdgtoh hmpdhrtghpthhtohepghhithesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthho pehsthgvrggumhhonhesghhoohhglhgvrdgtohhmpdhrtghpthhtohepphhhihhllhhiph drfihoohguseguuhhnvghlmhdrohhrghdruhhk X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:15:14 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 6c660519 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:15:07 +0000 (UTC) Date: Tue, 3 Sep 2024 11:15:12 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 13/14] t/unit-tests: convert ctype tests to use clar Message-ID: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Convert the ctype tests to use the new clar unit testing framework. Introduce a new function `cl_failf()` that allows us to print a formatted error message, which we can use to point out which of the characters was classified incorrectly. This results in output like this on failure: # start of suite 1: ctype not ok 1 - ctype::isspace --- reason: | Test failed. 0x0d is classified incorrectly: expected 0, got 1 at: file: 't/unit-tests/ctype.c' line: 36 function: 'test_ctype__isspace' --- ok 2 - ctype::isdigit ok 3 - ctype::isalpha ok 4 - ctype::isalnum ok 5 - ctype::is_glob_special ok 6 - ctype::is_regex_special ok 7 - ctype::is_pathspec_magic ok 8 - ctype::isascii ok 9 - ctype::islower ok 10 - ctype::isupper ok 11 - ctype::iscntrl ok 12 - ctype::ispunct ok 13 - ctype::isxdigit ok 14 - ctype::isprint Signed-off-by: Patrick Steinhardt --- Makefile | 2 +- t/unit-tests/{t-ctype.c => ctype.c} | 71 +++++++++++++++++++++++++---- t/unit-tests/unit-test.h | 7 +++ 3 files changed, 69 insertions(+), 11 deletions(-) rename t/unit-tests/{t-ctype.c => ctype.c} (68%) diff --git a/Makefile b/Makefile index 56ce6c00e44..c841cf70063 100644 --- a/Makefile +++ b/Makefile @@ -1336,13 +1336,13 @@ THIRD_PARTY_SOURCES += sha1dc/% THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/% THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/% +UNIT_TESTS_SUITES += ctype UNIT_TESTS_SUITES += strvec UNIT_TESTS_PROG = $(UNIT_TEST_BIN)/unit-tests$(X) UNIT_TESTS_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TESTS_SUITES)) UNIT_TESTS_OBJS += $(UNIT_TEST_DIR)/clar/clar.o UNIT_TESTS_OBJS += $(UNIT_TEST_DIR)/unit-test.o -UNIT_TEST_PROGRAMS += t-ctype UNIT_TEST_PROGRAMS += t-example-decorate UNIT_TEST_PROGRAMS += t-hash UNIT_TEST_PROGRAMS += t-hashmap diff --git a/t/unit-tests/t-ctype.c b/t/unit-tests/ctype.c similarity index 68% rename from t/unit-tests/t-ctype.c rename to t/unit-tests/ctype.c index e28a7f50f9a..32e65867cdc 100644 --- a/t/unit-tests/t-ctype.c +++ b/t/unit-tests/ctype.c @@ -1,16 +1,16 @@ -#include "test-lib.h" +#include "unit-test.h" #define TEST_CHAR_CLASS(class, string) do { \ size_t len = ARRAY_SIZE(string) - 1 + \ BUILD_ASSERT_OR_ZERO(ARRAY_SIZE(string) > 0) + \ BUILD_ASSERT_OR_ZERO(sizeof(string[0]) == sizeof(char)); \ - if_test (#class " works") { \ - for (int i = 0; i < 256; i++) { \ - if (!check_int(class(i), ==, !!memchr(string, i, len)))\ - test_msg(" i: 0x%02x", i); \ - } \ - check(!class(EOF)); \ + for (int i = 0; i < 256; i++) { \ + int actual = class(i), expect = !!memchr(string, i, len); \ + if (actual != expect) \ + cl_failf("0x%02x is classified incorrectly: expected %d, got %d", \ + i, expect, actual); \ } \ + cl_assert(!class(EOF)); \ } while (0) #define DIGIT "0123456789" @@ -31,21 +31,72 @@ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ "\x7f" -int cmd_main(int argc, const char **argv) { +void test_ctype__isspace(void) +{ TEST_CHAR_CLASS(isspace, " \n\r\t"); +} + +void test_ctype__isdigit(void) +{ TEST_CHAR_CLASS(isdigit, DIGIT); +} + +void test_ctype__isalpha(void) +{ TEST_CHAR_CLASS(isalpha, LOWER UPPER); +} + +void test_ctype__isalnum(void) +{ TEST_CHAR_CLASS(isalnum, LOWER UPPER DIGIT); +} + +void test_ctype__is_glob_special(void) +{ TEST_CHAR_CLASS(is_glob_special, "*?[\\"); +} + +void test_ctype__is_regex_special(void) +{ TEST_CHAR_CLASS(is_regex_special, "$()*+.?[\\^{|"); +} + +void test_ctype__is_pathspec_magic(void) +{ TEST_CHAR_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~"); +} + +void test_ctype__isascii(void) +{ TEST_CHAR_CLASS(isascii, ASCII); +} + +void test_ctype__islower(void) +{ TEST_CHAR_CLASS(islower, LOWER); +} + +void test_ctype__isupper(void) +{ TEST_CHAR_CLASS(isupper, UPPER); +} + +void test_ctype__iscntrl(void) +{ TEST_CHAR_CLASS(iscntrl, CNTRL); +} + +void test_ctype__ispunct(void) +{ TEST_CHAR_CLASS(ispunct, PUNCT); +} + +void test_ctype__isxdigit(void) +{ TEST_CHAR_CLASS(isxdigit, DIGIT "abcdefABCDEF"); - TEST_CHAR_CLASS(isprint, LOWER UPPER DIGIT PUNCT " "); +} - return test_done(); +void test_ctype__isprint(void) +{ + TEST_CHAR_CLASS(isprint, LOWER UPPER DIGIT PUNCT " "); } diff --git a/t/unit-tests/unit-test.h b/t/unit-tests/unit-test.h index 66ec2387cc6..85e5d6a948a 100644 --- a/t/unit-tests/unit-test.h +++ b/t/unit-tests/unit-test.h @@ -1,3 +1,10 @@ #include "git-compat-util.h" #include "clar/clar.h" #include "clar-decls.h" +#include "strbuf.h" + +#define cl_failf(fmt, ...) do { \ + char desc[4096]; \ + snprintf(desc, sizeof(desc), fmt, __VA_ARGS__); \ + clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1); \ +} while (0) From patchwork Tue Sep 3 09:15:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13788336 Received: from pfhigh7-smtp.messagingengine.com (fhigh7-smtp.messagingengine.com [103.168.172.158]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9CA3B1AD250 for ; Tue, 3 Sep 2024 09:15:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.158 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354921; cv=none; b=S5dusHIjlPGAzwmFZIIj4fi2nNQeBbma2KdMQSGrpcqXvFsEvkqn7GoCYJolghWa/YfF7a42so/OKU2z936kMmImc3DnGR71X82pWuaCWTdtLq73kksLiXmadQEimezDAsgluz+jySV70+8CNI0MxCMw+iLwExwNukqzIInlcwY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725354921; c=relaxed/simple; bh=GYikfNQ7yWqaozdcScET35JZjw6jit6Wp7EIhOTyjTM=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=lIdpVqHnd5lnKpEBooKl7OPX0w4UAnLfM/E4diGcUm+rMMk+JkVyorkPIMzCyylmRLR/Slq81vGUFeWqWv1gaZ0sHMvHpjVrc50rCeBurZxk0LSBzJYNOE7Ci5JtvTqVYZ/93uYW0NmWdeqUfSNraRSIJ/k9P7W1mIFdj85mtdk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im; spf=pass smtp.mailfrom=pks.im; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b=UH4rhlzp; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=IxV0S23A; arc=none smtp.client-ip=103.168.172.158 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="UH4rhlzp"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="IxV0S23A" Received: from phl-compute-03.internal (phl-compute-03.phl.internal [10.202.2.43]) by mailfhigh.phl.internal (Postfix) with ESMTP id D123E11402DE; Tue, 3 Sep 2024 05:15:18 -0400 (EDT) Received: from phl-mailfrontend-02 ([10.202.2.163]) by phl-compute-03.internal (MEProxy); Tue, 03 Sep 2024 05:15:18 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1725354918; x=1725441318; bh=9+01RIOplL 3MejPA2j7JjS2DT7phb0RTErJSwO/FFpM=; b=UH4rhlzp7nM5G6PxVGKpj//ofF p89uBbD+0kX6EI0nVMOT4B87lto1Dxowwpi8shafcocP/Q+XMH1Ds54j8qZeL5yW UmF+8LE69ikohwxVBe3jtsk8DnHGtIqCLQqy3J0nUGByrf0cVY+8MzUMEY+8ZR+I qYv0w/ujObk/qL8PUMijYHBwHVkNu4wAfaxnxlWkD6ymMEbdrCtq/VqwZdM8Hcle sgugBl8tRJaXkNDMUqXvMA37+q8garn/JoPqH10gScYxPlsX3C+PtVkNVeEVl6Je MRXO9J3Vysxp3Cs4W4lc2tEifmTit/dYXGmwlmLe17+VkeOsI/0fzAvw3FJQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; t=1725354918; x=1725441318; bh=9+01RIOplL3MejPA2j7JjS2DT7ph b0RTErJSwO/FFpM=; b=IxV0S23AkyrM/fE17kdb6QkCtmpiSF9kKR9zlLptj9ks s+ZAkQJW6vwaJ4E3ZFZ16q2+09r1hH/40iNEd8NNTAKZch6968CdhhlMRGJe0rvD DckDtcOpgLmr1S6qwaVd+MDBV8Kk1T6Rh47l9CIawNZmHHOvrYLz/X6FfwrThMV7 aSjzMppRCkJaa/212Yflb9/ggah1zZWPVYJ+elGnWOX0839EC3ThARN6uj6CkS5z lQno5YF1rK4lS+rfCLL4g2h2KRmSsKvkduPJl9bopowpDOE5fxMhN7nJJHwTdCqA aAcKPh/JejV81TpMGhbm3pZS75BktGM3EHnFS7ZlZA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrudehhedguddvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnecujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvden ucfhrhhomheprfgrthhrihgtkhcuufhtvghinhhhrghrughtuceophhssehpkhhsrdhimh eqnecuggftrfgrthhtvghrnhepveekkeffhfeitdeludeigfejtdetvdelvdduhefgueeg udfghfeukefhjedvkedtnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrg hilhhfrhhomhepphhssehpkhhsrdhimhdpnhgspghrtghpthhtohepledpmhhouggvpehs mhhtphhouhhtpdhrtghpthhtohepshhpvggtthhrrghlsehgohhoghhlvgdrtghomhdprh gtphhtthhopehsthgvrggumhhonhesghhoohhglhgvrdgtohhmpdhrtghpthhtohepghhi thesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopegvthhhohhmshhonhesvg gufigrrhguthhhohhmshhonhdrtghomhdprhgtphhtthhopehgihhtshhtvghrsehpohgs ohigrdgtohhmpdhrtghpthhtohepphhhihhllhhiphdrfihoohguseguuhhnvghlmhdroh hrghdruhhkpdhrtghpthhtoheplhdrshdrrhesfigvsgdruggvpdhrtghpthhtohepjhho hhgrnhhnvghsrdhstghhihhnuggvlhhinhesghhmgidruggvpdhrtghpthhtoheprhhssg gvtghkvghrsehnvgigsghrihgughgvrdgtohhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 3 Sep 2024 05:15:17 -0400 (EDT) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 023f4953 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Tue, 3 Sep 2024 09:15:10 +0000 (UTC) Date: Tue, 3 Sep 2024 11:15:15 +0200 From: Patrick Steinhardt To: git@vger.kernel.org Cc: =?utf-8?b?UmVuw6k=?= Scharfe , Junio C Hamano , Kyle Lippincott , Phillip Wood , Josh Steadmon , rsbecker@nexbridge.com, Edward Thomson , Johannes Schindelin Subject: [PATCH v7 14/14] clar: add CMake support Message-ID: References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: From: Johannes Schindelin Now that we're using `clar` as powerful test framework, we have to adjust the Visual C build (read: the CMake definition) to be able to handle that, too. Signed-off-by: Johannes Schindelin Signed-off-by: Patrick Steinhardt --- contrib/buildsystems/CMakeLists.txt | 53 +++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 832f46b316b..608fd3fe709 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -1004,6 +1004,59 @@ foreach(unit_test ${unit_test_PROGRAMS}) endif() endforeach() +parse_makefile_for_scripts(unit_tests_SUITES "UNIT_TESTS_SUITES" "") + +set(clar_decls "") +set(clar_cbs "") +set(clar_cbs_count 0) +set(clar_suites "static struct clar_suite _clar_suites[] = {\n") +list(LENGTH unit_tests_SUITES clar_suites_count) +foreach(suite ${unit_tests_SUITES}) + file(STRINGS "${CMAKE_SOURCE_DIR}/t/unit-tests/${suite}.c" decls + REGEX "^void test_${suite}__[a-zA-Z_0-9][a-zA-Z_0-9]*\\(void\\)$") + + list(LENGTH decls decls_count) + string(REGEX REPLACE "void (test_${suite}__([a-zA-Z_0-9]*))\\(void\\)" " { \"\\2\", &\\1 },\n" cbs ${decls}) + string(JOIN "" cbs ${cbs}) + list(TRANSFORM decls PREPEND "extern ") + string(JOIN ";\n" decls ${decls}) + + string(APPEND clar_decls "${decls};\n") + string(APPEND clar_cbs + "static const struct clar_func _clar_cb_${suite}[] = {\n" + ${cbs} + "};\n") + string(APPEND clar_suites + " {\n" + " \"${suite}\",\n" + " { NULL, NULL },\n" + " { NULL, NULL },\n" + " _clar_cb_${suite}, ${decls_count}, 1\n" + " },\n") + math(EXPR clar_cbs_count "${clar_cbs_count}+${decls_count}") +endforeach() +string(APPEND clar_suites + "};\n" + "static const size_t _clar_suite_count = ${clar_suites_count};\n" + "static const size_t _clar_callback_count = ${clar_cbs_count};\n") +file(WRITE "${CMAKE_BINARY_DIR}/t/unit-tests/clar-decls.h" "${clar_decls}") +file(WRITE "${CMAKE_BINARY_DIR}/t/unit-tests/clar.suite" "${clar_decls}" "${clar_cbs}" "${clar_suites}") + +list(TRANSFORM unit_tests_SUITES PREPEND "${CMAKE_SOURCE_DIR}/t/unit-tests/") +list(TRANSFORM unit_tests_SUITES APPEND ".c") +add_library(unit-tests-lib ${unit_tests_SUITES} "${CMAKE_SOURCE_DIR}/t/unit-tests/clar/clar.c") +target_include_directories(unit-tests-lib PRIVATE "${CMAKE_SOURCE_DIR}/t/unit-tests") +add_executable(unit-tests "${CMAKE_SOURCE_DIR}/t/unit-tests/unit-test.c") +target_link_libraries(unit-tests unit-tests-lib common-main) +set_target_properties(unit-tests + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin) +if(MSVC) + set_target_properties(unit-tests + PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/t/unit-tests/bin) + set_target_properties(unit-tests + PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/t/unit-tests/bin) +endif() + #test-tool parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS") add_library(test-lib OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/test-lib.c)