]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
unit tests: extract "private" prototypes at build time
authorDaniel Stenberg <daniel@haxx.se>
Sun, 29 Jun 2025 12:33:13 +0000 (14:33 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 30 Jun 2025 21:16:40 +0000 (23:16 +0200)
In order to do unit tests for private functions, functions that are
marked UNITTEST but without a global scope in the library, functions
that do not have prototypes in their corresponding header file, unit
tests previously brought their own private prototype *copy* into the
unit test.

This was error-prone when the internal function changes but the change
might be missed in the unit test which then uses an outdated prototype
copy for testing.

This change removes the private prototypes from unit tests and instead
introduces a C file parser that parses the specific C files and extracts
the necessary unit test prototypes into a generated header file for unit
tests to use. This geneated lib/unitprotos.h header is then included by
unit tests that need private prototypes.

Assisted-by: Viktor Szakats
Closes #17750

lib/.gitignore
lib/CMakeLists.txt
lib/Makefile.am
scripts/Makefile.am
scripts/extract-unit-protos [new file with mode: 0755]
tests/unit/CMakeLists.txt
tests/unit/unit1300.c
tests/unit/unit1395.c
tests/unit/unit3212.c
tests/unit/unit3213.c

index e776bc899dc3b2a6db50d1582be99ccd2732f69f..0f0bcd646535f8647f3eae8918520aa98ac7d68c 100644 (file)
@@ -7,3 +7,4 @@ curl_config.h
 curl_config.h.in
 libcurl.vers
 libcurl_unity.c
+unitprotos.h
index 19db59f9e60eae8515e658328f2fa6452748e960..9b0fda54092f3c9a8ac5790211b358ce63df1778 100644 (file)
@@ -49,6 +49,14 @@ if(CURL_BUILD_TESTING)
   # There is plenty of parallelism when building the testdeps target.
   # Override the curlu batch size with the maximum to optimize performance.
   set_target_properties(curlu PROPERTIES UNITY_BUILD_BATCH_SIZE 0 C_CLANG_TIDY "")
+
+  add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+    COMMAND ${PERL_EXECUTABLE} "${PROJECT_SOURCE_DIR}/scripts/extract-unit-protos"
+      ${CSOURCES} > "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h"
+    DEPENDS "${PROJECT_SOURCE_DIR}/scripts/extract-unit-protos" ${CSOURCES}
+    VERBATIM)
+  add_custom_target(curlu-unitprotos ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h")
 endif()
 
 ## Library definition
index d43d54979a39f9e6543552c32832aba1b85bd0f8..75fbbdf4b93d3d357a8839d1d2567c9286339ec2 100644 (file)
@@ -39,6 +39,10 @@ lib_LTLIBRARIES = libcurl.la
 
 if BUILD_UNITTESTS
 noinst_LTLIBRARIES = libcurlu.la
+
+# generate a file with "private" prototypes for unit testing
+UNITPROTOS = unitprotos.h
+
 else
 noinst_LTLIBRARIES =
 endif
@@ -88,8 +92,11 @@ CLEANFILES = libcurl_unity.c
 else
 libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS)
 libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS)
+CLEANFILES =
 endif
 
+CLEANFILES += $(UNITPROTOS)
+
 libcurl_la_CPPFLAGS_EXTRA =
 libcurl_la_LDFLAGS_EXTRA =
 libcurl_la_CFLAGS_EXTRA =
@@ -151,10 +158,21 @@ checksrc:
 if NOT_CURL_CI
 if DEBUGBUILD
 # for debug builds, we scan the sources on all regular make invokes
-all-local: checksrc
+CHECKSOURCES = checksrc
 endif
 endif
 
+all-local: $(CHECKSOURCES) $(UNITPROTOS)
+
+UNIT_V = $(UNITV_$(V))
+UNITV_0 = @echo "  UNITPR  " $@;
+UNITV_1 =
+UNITV_ = $(UNITV_0)
+
+# UNITPROTOS depends on every C file in the lib/ dir
+$(UNITPROTOS): $(CSOURCES)
+       $(UNIT_V)(cd $(srcdir) && @PERL@ ../scripts/extract-unit-protos $(CSOURCES) > $(top_builddir)/lib/$(UNITPROTOS))
+
 # disable the tests that are mostly causing false positives
 TIDYFLAGS := -checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling -quiet
 if CURL_WERROR
index 0b278e62b01fc7415448c555ce75e62f68b348a8..b4e3c0757b9403d99208a60c10694004c11e6753 100644 (file)
@@ -25,7 +25,7 @@
 EXTRA_DIST = coverage.sh completion.pl firefox-db2pem.sh checksrc.pl checksrc-all.sh \
   mk-ca-bundle.pl mk-unity.pl schemetable.c cd2nroff nroff2cd cdall cd2cd managen    \
   dmaketgz maketgz release-tools.sh verify-release cmakelint.sh mdlinkcheck          \
-  CMakeLists.txt pythonlint.sh randdisable wcurl top-complexity
+  CMakeLists.txt pythonlint.sh randdisable wcurl top-complexity extract-unit-protos
 
 dist_bin_SCRIPTS = wcurl
 
diff --git a/scripts/extract-unit-protos b/scripts/extract-unit-protos
new file mode 100755 (executable)
index 0000000..9fc6c1b
--- /dev/null
@@ -0,0 +1,90 @@
+#!/usr/bin/env perl
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# SPDX-License-Identifier: curl
+#
+###########################################################################
+
+sub scanfile {
+    my ($file) = @_;
+    open(F, "<$file") || die "$file failed";
+    while(<F>) {
+        if($_ =~ /^UNITTEST .*\);/) {
+            push @proto, $_;
+            $inc{$file} = 1;
+        }
+    }
+    close(F);
+}
+
+foreach my $f (@ARGV) {
+    scanfile($f);
+}
+
+print <<HEAD
+#ifndef UNITTESTPROTOS_H
+#define UNITTESTPROTOS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \\| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \\___|\\___/|_| \\_\\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ * Generated-by: extract-unit-protos
+ *
+ ***************************************************************************/
+HEAD
+    ;
+
+for my $f (sort keys %inc) {
+    # convert to suitable header file
+    $f =~ s/\.c/.h/; # .h extension
+
+    if(-f $f) {
+        $f =~ s/.*\///; # cut the path off
+        print "#include \"$f\"\n";
+    }
+}
+
+for my $p (@proto) {
+    print $p;
+}
+
+print <<FOOT
+#endif /* UNITTESTPROTOS_H */
+FOOT
+    ;
index f1585f4dda5352a0878f2278e38234c2fcf9b66d..6ae9c171889d9099864c90eaec9c37b6a761166f 100644 (file)
@@ -35,10 +35,11 @@ add_custom_command(OUTPUT "${BUNDLE}.c"
   VERBATIM)
 
 add_executable(${BUNDLE} EXCLUDE_FROM_ALL "${BUNDLE}.c")
+add_dependencies(${BUNDLE} curlu-unitprotos)
 add_dependencies(testdeps ${BUNDLE})
 target_link_libraries(${BUNDLE} curlu)
 target_include_directories(${BUNDLE} PRIVATE
-  "${PROJECT_BINARY_DIR}/lib"            # for "curl_config.h"
+  "${PROJECT_BINARY_DIR}/lib"            # for "curl_config.h", "unitprotos.h"
   "${PROJECT_SOURCE_DIR}/lib"            # for "curl_setup.h", curlx
   "${PROJECT_SOURCE_DIR}/tests/libtest"  # for "first.h"
   "${CMAKE_CURRENT_SOURCE_DIR}"          # for the generated bundle source to find included test sources
index d86fac54d58033018b799490f3c7db252630fd7f..bdc6b0162bfd1d8348e3b35ff21ae2cee17aefa5 100644 (file)
@@ -24,8 +24,7 @@
 #include "curlcheck.h"
 
 #include "llist.h"
-
-UNITTEST void Curl_node_uremove(struct Curl_llist_node *, void *);
+#include "unitprotos.h"
 
 static void test_Curl_llist_dtor(void *key, void *value)
 {
index abb22a4370ebb9ded0b5029a0973cfcf15e818de..7c09b3b78a87913516c7ae6221d24da62627b8ab 100644 (file)
  *
  ***************************************************************************/
 #include "curlcheck.h"
-
-/* copied from urlapi.c */
-extern int dedotdotify(const char *input, size_t clen, char **out);
-
 #include "memdebug.h"
+#include "unitprotos.h"
 
 static CURLcode test_unit1395(char *arg)
 {
index f53c1d6c15dfeb31d693ba239336f21220080d42..1226a6b6fa0c1b8daf6ef8741a3b4232b26bfe28 100644 (file)
@@ -26,8 +26,7 @@
 #include "urldata.h"
 #include "uint-table.h"
 #include "curl_trc.h"
-
-UNITTEST void Curl_uint_tbl_clear(struct uint_tbl *tbl);
+#include "unitprotos.h"
 
 #define TBL_SIZE    100
 
index bb5738d2fb21e0dcbdc98de0865f848b07e1fe09..f59ad5a9cf1b085dea8a12260108616c7134f024 100644 (file)
@@ -26,8 +26,7 @@
 #include "urldata.h"
 #include "uint-spbset.h"
 #include "curl_trc.h"
-
-UNITTEST void Curl_uint_spbset_clear(struct uint_spbset *bset);
+#include "unitprotos.h"
 
 static void check_spbset(const char *name, const unsigned int *s, size_t slen)
 {