cmake: allow building tests in unity mode

Makes building tests noticeably faster.

Apply changes/fixes/workarounds to make Unity work:
- rename test variables to avoid collisions or shadowing each other when
  combined into single units.
- add workaround to avoid applying `lib/memdebug.h` overrides to system
  headers declaring/defining `getaddrinfo()`/`freeaddrinfo()` for
  `tests/server/resolve.c`. This replaces a previous workaround that
  worked for that specific source.
- rename test macro `CTRL` clashing with Cygwin `sys/ioctl.h`.
- add include guard to `test.h`.

Also:
- exclude `tests/http/clients` which are all single-source. (like
  `docs/examples`.)

Build time improvements for tests:
- AppVeyor CI:
  - MSVC 2008, 2010: 1 minute faster (4m8s -> 2m56s, 3m19s -> 2m24s)
  - MSVC 2022 arm64: 3.5 minutes faster (10m18s -> 6m48s)
  before: https://ci.appveyor.com/project/curlorg/curl/builds/50522785
  after: https://ci.appveyor.com/project/curlorg/curl/builds/50522942
- GHA:
  - Cygwin: 1.5 minutes faster (3m13s -> 1m43s)
    before: https://github.com/curl/curl/actions/runs/10681535327/job/29605384398
    after: https://github.com/curl/curl/actions/runs/10680818726/job/29603130637
  - Windows:
    before: https://github.com/curl/curl/actions/runs/10680818713
    after: https://github.com/curl/curl/actions/runs/10683850187
    - MSYS2, mingw-w64: 1 minute faster
    - MSVC: 30 seconds faster (3m17s -> 2m48s)
  - macOS: double speed (39s -> 18s)
    before: https://github.com/curl/curl/actions/runs/10680818753/job/29603133447
    after: https://github.com/curl/curl/actions/runs/10683850174/job/29612914515
  - Linux: almost double speed (30/31s -> 18s)
    before: https://github.com/curl/curl/actions/runs/10681535311/job/29605387156
    after: https://github.com/curl/curl/actions/runs/10680818721/job/29603133976
  - non-native: no obvious effect.
    before: https://github.com/curl/curl/actions/runs/10680818722
    after: https://github.com/curl/curl/actions/runs/10683850187
  - Old Linux: Unity mode not supported by old CMake, no effect.

Closes #14765
This commit is contained in:
Viktor Szakats 2024-09-03 00:26:26 +02:00
parent aa1a153910
commit 3efba94f77
No known key found for this signature in database
GPG Key ID: B5ABD165E2AEF201
13 changed files with 77 additions and 61 deletions

View File

@ -84,6 +84,7 @@
#undef socketpair #undef socketpair
#endif #endif
#ifndef CURL_NO_GETADDRINFO_OVERRIDE
#ifdef HAVE_GETADDRINFO #ifdef HAVE_GETADDRINFO
#if defined(getaddrinfo) && defined(__osf__) #if defined(getaddrinfo) && defined(__osf__)
#undef ogetaddrinfo #undef ogetaddrinfo
@ -95,6 +96,7 @@
#ifdef HAVE_FREEADDRINFO #ifdef HAVE_FREEADDRINFO
#undef freeaddrinfo #undef freeaddrinfo
#endif /* HAVE_FREEADDRINFO */ #endif /* HAVE_FREEADDRINFO */
#endif /* CURL_NO_GETADDRINFO_OVERRIDE */
/* sclose is probably already defined, redefine it! */ /* sclose is probably already defined, redefine it! */
#undef sclose #undef sclose

View File

@ -153,6 +153,7 @@ CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
__LINE__, __FILE__) __LINE__, __FILE__)
#endif #endif
#ifndef CURL_NO_GETADDRINFO_OVERRIDE
#ifdef HAVE_GETADDRINFO #ifdef HAVE_GETADDRINFO
#if defined(getaddrinfo) && defined(__osf__) #if defined(getaddrinfo) && defined(__osf__)
/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define /* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define
@ -172,6 +173,7 @@ CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
#define freeaddrinfo(data) \ #define freeaddrinfo(data) \
curl_dbg_freeaddrinfo(data, __LINE__, __FILE__) curl_dbg_freeaddrinfo(data, __LINE__, __FILE__)
#endif /* HAVE_FREEADDRINFO */ #endif /* HAVE_FREEADDRINFO */
#endif /* CURL_NO_GETADDRINFO_OVERRIDE */
/* sclose is probably already defined, redefine it! */ /* sclose is probably already defined, redefine it! */
#undef sclose #undef sclose

View File

@ -21,8 +21,6 @@
# SPDX-License-Identifier: curl # SPDX-License-Identifier: curl
# #
########################################################################### ###########################################################################
set(CMAKE_UNITY_BUILD OFF)
find_program(TEST_NGHTTPX "nghttpx") find_program(TEST_NGHTTPX "nghttpx")
if(NOT TEST_NGHTTPX) if(NOT TEST_NGHTTPX)
set(TEST_NGHTTPX "nghttpx") set(TEST_NGHTTPX "nghttpx")

View File

@ -26,6 +26,8 @@
transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
set_source_files_properties("../../lib/curl_multibyte.c" PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
foreach(_target IN LISTS noinst_PROGRAMS) foreach(_target IN LISTS noinst_PROGRAMS)
if(DEFINED ${_target}_SOURCES) if(DEFINED ${_target}_SOURCES)
set(_sources ${${_target}_SOURCES}) set(_sources ${${_target}_SOURCES})

View File

@ -120,7 +120,7 @@ static void memory_tracking_init(void)
#endif #endif
/* returns a hexdump in a static memory area */ /* returns a hexdump in a static memory area */
char *hexdump(const unsigned char *buffer, size_t len) char *hexdump(const unsigned char *buf, size_t len)
{ {
static char dump[200 * 3 + 1]; static char dump[200 * 3 + 1];
char *p = dump; char *p = dump;
@ -128,7 +128,7 @@ char *hexdump(const unsigned char *buffer, size_t len)
if(len > 200) if(len > 200)
return NULL; return NULL;
for(i = 0; i < len; i++, p += 3) for(i = 0; i < len; i++, p += 3)
msnprintf(p, 4, "%02x ", buffer[i]); msnprintf(p, 4, "%02x ", buf[i]);
return dump; return dump;
} }

View File

@ -55,7 +55,7 @@ static size_t myreadfunc(char *ptr, size_t size, size_t nmemb, void *stream)
#define NUM_HEADERS 8 #define NUM_HEADERS 8
#define SIZE_HEADERS 5000 #define SIZE_HEADERS 5000
static char buf[SIZE_HEADERS + 100]; static char testbuf[SIZE_HEADERS + 100];
CURLcode test(char *URL) CURLcode test(char *URL)
{ {
@ -77,10 +77,10 @@ CURLcode test(char *URL)
} }
for(i = 0; i < NUM_HEADERS; i++) { for(i = 0; i < NUM_HEADERS; i++) {
int len = msnprintf(buf, sizeof(buf), "Header%d: ", i); int len = msnprintf(testbuf, sizeof(testbuf), "Header%d: ", i);
memset(&buf[len], 'A', SIZE_HEADERS); memset(&testbuf[len], 'A', SIZE_HEADERS);
buf[len + SIZE_HEADERS] = 0; /* null-terminate */ testbuf[len + SIZE_HEADERS] = 0; /* null-terminate */
hl = curl_slist_append(headerlist, buf); hl = curl_slist_append(headerlist, testbuf);
if(!hl) if(!hl)
goto test_cleanup; goto test_cleanup;
headerlist = hl; headerlist = hl;

View File

@ -28,7 +28,7 @@
#include "memdebug.h" #include "memdebug.h"
static const char cmd[] = "A1 IDLE\r\n"; static const char cmd[] = "A1 IDLE\r\n";
static char buf[1024]; static char testbuf[1024];
CURLcode test(char *URL) CURLcode test(char *URL)
{ {
@ -101,9 +101,9 @@ CURLcode test(char *URL)
pos = 0; pos = 0;
} }
} }
else if(pos < (ssize_t)sizeof(buf)) { else if(pos < (ssize_t)sizeof(testbuf)) {
CURLcode ec; CURLcode ec;
ec = curl_easy_recv(curl, buf + pos, sizeof(buf) - pos, &len); ec = curl_easy_recv(curl, testbuf + pos, sizeof(testbuf) - pos, &len);
if(ec == CURLE_AGAIN) { if(ec == CURLE_AGAIN) {
continue; continue;
} }
@ -122,7 +122,7 @@ CURLcode test(char *URL)
} }
if(state) { if(state) {
fwrite(buf, pos, 1, stdout); fwrite(testbuf, pos, 1, stdout);
putchar('\n'); putchar('\n');
} }

View File

@ -1,3 +1,5 @@
#ifndef HEADER_CURL_TEST_H
#define HEADER_CURL_TEST_H
/*************************************************************************** /***************************************************************************
* _ _ ____ _ * _ _ ____ _
* Project ___| | | | _ \| | * Project ___| | | | _ \| |
@ -498,3 +500,5 @@ extern int unitfail;
} }
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
#endif /* HEADER_CURL_TEST_H */

View File

@ -26,6 +26,8 @@
transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
set_source_files_properties("../../lib/memdebug.c" "../../lib/curl_multibyte.c" PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
foreach(_target IN LISTS noinst_PROGRAMS) foreach(_target IN LISTS noinst_PROGRAMS)
set(_target_name "${_target}") set(_target_name "${_target}")
add_executable(${_target_name} EXCLUDE_FROM_ALL ${${_target}_SOURCES}) add_executable(${_target_name} EXCLUDE_FROM_ALL ${${_target}_SOURCES})
@ -45,6 +47,10 @@ foreach(_target IN LISTS noinst_PROGRAMS)
if(WIN32) if(WIN32)
set_property(TARGET ${_target_name} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB") set_property(TARGET ${_target_name} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
endif() endif()
# getaddrinfo/freeaddrinfo overrides break UNITY build by overriding them
# before including system headers. Server code doesn't need these overrides,
# so it's safe to disable them globally.
set_property(TARGET ${_target_name} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_NO_GETADDRINFO_OVERRIDE")
set_target_properties(${_target_name} PROPERTIES set_target_properties(${_target_name} PROPERTIES
OUTPUT_NAME "${_target}" OUTPUT_NAME "${_target}"
PROJECT_LABEL "Test server ${_target}") PROJECT_LABEL "Test server ${_target}")

View File

@ -45,6 +45,7 @@ LIBS = $(BLANK_AT_MAKETIME)
if DOING_NATIVE_WINDOWS if DOING_NATIVE_WINDOWS
AM_CPPFLAGS += -DCURL_STATICLIB AM_CPPFLAGS += -DCURL_STATICLIB
endif endif
AM_CPPFLAGS += -DCURL_NO_GETADDRINFO_OVERRIDE
# Makefile.inc provides neat definitions # Makefile.inc provides neat definitions
include Makefile.inc include Makefile.inc

View File

@ -21,6 +21,10 @@
* SPDX-License-Identifier: curl * SPDX-License-Identifier: curl
* *
***************************************************************************/ ***************************************************************************/
#ifndef CURL_NO_GETADDRINFO_OVERRIDE
#define CURL_NO_GETADDRINFO_OVERRIDE
#endif
#include "server_setup.h" #include "server_setup.h"
/* Purpose /* Purpose
@ -125,11 +129,9 @@ int main(int argc, char *argv[])
hints.ai_family = use_ipv6 ? PF_INET6 : PF_INET; hints.ai_family = use_ipv6 ? PF_INET6 : PF_INET;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0; hints.ai_flags = 0;
/* Use parenthesis around functions to stop them from being replaced by rc = getaddrinfo(host, "80", &hints, &ai);
the macro in memdebug.h */
rc = (getaddrinfo)(host, "80", &hints, &ai);
if(rc == 0) if(rc == 0)
(freeaddrinfo)(ai); freeaddrinfo(ai);
} }
#else #else
if(use_ipv6) { if(use_ipv6) {

View File

@ -1433,8 +1433,8 @@ success:
#define data_or_ctrl(x) ((x)?"DATA":"CTRL") #define data_or_ctrl(x) ((x)?"DATA":"CTRL")
#define CTRL 0 #define SWS_CTRL 0
#define DATA 1 #define SWS_DATA 1
static void http_connect(curl_socket_t *infdp, static void http_connect(curl_socket_t *infdp,
curl_socket_t rootfd, curl_socket_t rootfd,
@ -1454,13 +1454,13 @@ static void http_connect(curl_socket_t *infdp,
bool poll_server_wr[2] = { TRUE, TRUE }; bool poll_server_wr[2] = { TRUE, TRUE };
bool primary = FALSE; bool primary = FALSE;
bool secondary = FALSE; bool secondary = FALSE;
int max_tunnel_idx; /* CTRL or DATA */ int max_tunnel_idx; /* SWS_CTRL or SWS_DATA */
int loop; int loop;
int i; int i;
int timeout_count = 0; int timeout_count = 0;
/* primary tunnel client endpoint already connected */ /* primary tunnel client endpoint already connected */
clientfd[CTRL] = *infdp; clientfd[SWS_CTRL] = *infdp;
/* Sleep here to make sure the client reads CONNECT response's /* Sleep here to make sure the client reads CONNECT response's
'end of headers' separate from the server data that follows. 'end of headers' separate from the server data that follows.
@ -1470,8 +1470,8 @@ static void http_connect(curl_socket_t *infdp,
if(got_exit_signal) if(got_exit_signal)
goto http_connect_cleanup; goto http_connect_cleanup;
serverfd[CTRL] = connect_to(ipaddr, ipport); serverfd[SWS_CTRL] = connect_to(ipaddr, ipport);
if(serverfd[CTRL] == CURL_SOCKET_BAD) if(serverfd[SWS_CTRL] == CURL_SOCKET_BAD)
goto http_connect_cleanup; goto http_connect_cleanup;
/* Primary tunnel socket endpoints are now connected. Tunnel data back and /* Primary tunnel socket endpoints are now connected. Tunnel data back and
@ -1479,7 +1479,7 @@ static void http_connect(curl_socket_t *infdp,
tunnel, simultaneously allowing establishment, operation and teardown of tunnel, simultaneously allowing establishment, operation and teardown of
a secondary tunnel that may be used for passive FTP data connection. */ a secondary tunnel that may be used for passive FTP data connection. */
max_tunnel_idx = CTRL; max_tunnel_idx = SWS_CTRL;
primary = TRUE; primary = TRUE;
while(!got_exit_signal) { while(!got_exit_signal) {
@ -1493,10 +1493,10 @@ static void http_connect(curl_socket_t *infdp,
FD_ZERO(&input); FD_ZERO(&input);
FD_ZERO(&output); FD_ZERO(&output);
if((clientfd[DATA] == CURL_SOCKET_BAD) && if((clientfd[SWS_DATA] == CURL_SOCKET_BAD) &&
(serverfd[DATA] == CURL_SOCKET_BAD) && (serverfd[SWS_DATA] == CURL_SOCKET_BAD) &&
poll_client_rd[CTRL] && poll_client_wr[CTRL] && poll_client_rd[SWS_CTRL] && poll_client_wr[SWS_CTRL] &&
poll_server_rd[CTRL] && poll_server_wr[CTRL]) { poll_server_rd[SWS_CTRL] && poll_server_wr[SWS_CTRL]) {
/* listener socket is monitored to allow client to establish /* listener socket is monitored to allow client to establish
secondary tunnel only when this tunnel is not established secondary tunnel only when this tunnel is not established
and primary one is fully operational */ and primary one is fully operational */
@ -1557,8 +1557,8 @@ static void http_connect(curl_socket_t *infdp,
/* ---------------------------------------------------------- */ /* ---------------------------------------------------------- */
/* passive mode FTP may establish a secondary tunnel */ /* passive mode FTP may establish a secondary tunnel */
if((clientfd[DATA] == CURL_SOCKET_BAD) && if((clientfd[SWS_DATA] == CURL_SOCKET_BAD) &&
(serverfd[DATA] == CURL_SOCKET_BAD) && FD_ISSET(rootfd, &input)) { (serverfd[SWS_DATA] == CURL_SOCKET_BAD) && FD_ISSET(rootfd, &input)) {
/* a new connection on listener socket (most likely from client) */ /* a new connection on listener socket (most likely from client) */
curl_socket_t datafd = accept(rootfd, NULL, NULL); curl_socket_t datafd = accept(rootfd, NULL, NULL);
if(datafd != CURL_SOCKET_BAD) { if(datafd != CURL_SOCKET_BAD) {
@ -1598,19 +1598,19 @@ static void http_connect(curl_socket_t *infdp,
wait_ms(250); wait_ms(250);
if(!got_exit_signal) { if(!got_exit_signal) {
/* connect to the server */ /* connect to the server */
serverfd[DATA] = connect_to(ipaddr, req2->connect_port); serverfd[SWS_DATA] = connect_to(ipaddr, req2->connect_port);
if(serverfd[DATA] != CURL_SOCKET_BAD) { if(serverfd[SWS_DATA] != CURL_SOCKET_BAD) {
/* secondary tunnel established, now we have two /* secondary tunnel established, now we have two
connections */ connections */
poll_client_rd[DATA] = TRUE; poll_client_rd[SWS_DATA] = TRUE;
poll_client_wr[DATA] = TRUE; poll_client_wr[SWS_DATA] = TRUE;
poll_server_rd[DATA] = TRUE; poll_server_rd[SWS_DATA] = TRUE;
poll_server_wr[DATA] = TRUE; poll_server_wr[SWS_DATA] = TRUE;
max_tunnel_idx = DATA; max_tunnel_idx = SWS_DATA;
secondary = TRUE; secondary = TRUE;
toc[DATA] = 0; toc[SWS_DATA] = 0;
tos[DATA] = 0; tos[SWS_DATA] = 0;
clientfd[DATA] = datafd; clientfd[SWS_DATA] = datafd;
datafd = CURL_SOCKET_BAD; datafd = CURL_SOCKET_BAD;
} }
} }
@ -1761,7 +1761,7 @@ static void http_connect(curl_socket_t *infdp,
clientfd[i] = CURL_SOCKET_BAD; clientfd[i] = CURL_SOCKET_BAD;
if(serverfd[i] == CURL_SOCKET_BAD) { if(serverfd[i] == CURL_SOCKET_BAD) {
logmsg("[%s] ENDING", data_or_ctrl(i)); logmsg("[%s] ENDING", data_or_ctrl(i));
if(i == DATA) if(i == SWS_DATA)
secondary = FALSE; secondary = FALSE;
else else
primary = FALSE; primary = FALSE;
@ -1775,7 +1775,7 @@ static void http_connect(curl_socket_t *infdp,
serverfd[i] = CURL_SOCKET_BAD; serverfd[i] = CURL_SOCKET_BAD;
if(clientfd[i] == CURL_SOCKET_BAD) { if(clientfd[i] == CURL_SOCKET_BAD) {
logmsg("[%s] ENDING", data_or_ctrl(i)); logmsg("[%s] ENDING", data_or_ctrl(i));
if(i == DATA) if(i == SWS_DATA)
secondary = FALSE; secondary = FALSE;
else else
primary = FALSE; primary = FALSE;
@ -1787,7 +1787,7 @@ static void http_connect(curl_socket_t *infdp,
/* ---------------------------------------------------------- */ /* ---------------------------------------------------------- */
max_tunnel_idx = secondary ? DATA : CTRL; max_tunnel_idx = secondary ? SWS_DATA : SWS_CTRL;
if(!primary) if(!primary)
/* exit loop upon primary tunnel teardown */ /* exit loop upon primary tunnel teardown */
@ -1805,7 +1805,7 @@ static void http_connect(curl_socket_t *infdp,
http_connect_cleanup: http_connect_cleanup:
for(i = DATA; i >= CTRL; i--) { for(i = SWS_DATA; i >= SWS_CTRL; i--) {
if(serverfd[i] != CURL_SOCKET_BAD) { if(serverfd[i] != CURL_SOCKET_BAD) {
logmsg("[%s] CLOSING server socket (cleanup)", data_or_ctrl(i)); logmsg("[%s] CLOSING server socket (cleanup)", data_or_ctrl(i));
shutdown(serverfd[i], SHUT_RDWR); shutdown(serverfd[i], SHUT_RDWR);

View File

@ -37,7 +37,7 @@
static struct Curl_easy *data; static struct Curl_easy *data;
static char input[4096]; static char input[4096];
static char result[4096]; static char output[4096];
int debugf_cb(CURL *handle, curl_infotype type, char *buf, size_t size, int debugf_cb(CURL *handle, curl_infotype type, char *buf, size_t size,
void *userptr); void *userptr);
@ -55,8 +55,8 @@ debugf_cb(CURL *handle, curl_infotype type, char *buf, size_t size,
(void)type; (void)type;
(void)userptr; (void)userptr;
memset(result, '\0', sizeof(result)); memset(output, '\0', sizeof(output));
memcpy(result, buf, size); memcpy(output, buf, size);
return 0; return 0;
} }
@ -97,47 +97,46 @@ UNITTEST_START
/* Injecting a simple short string via a format */ /* Injecting a simple short string via a format */
msnprintf(input, sizeof(input), "Simple Test"); msnprintf(input, sizeof(input), "Simple Test");
Curl_infof(data, "%s", input); Curl_infof(data, "%s", input);
fail_unless(verify(result, input) == 0, "Simple string test"); fail_unless(verify(output, input) == 0, "Simple string test");
/* Injecting a few different variables with a format */ /* Injecting a few different variables with a format */
Curl_infof(data, "%s %u testing %lu", input, 42, 43L); Curl_infof(data, "%s %u testing %lu", input, 42, 43L);
fail_unless(verify(result, "Simple Test 42 testing 43\n") == 0, fail_unless(verify(output, "Simple Test 42 testing 43\n") == 0,
"Format string"); "Format string");
/* Variations of empty strings */ /* Variations of empty strings */
Curl_infof(data, ""); Curl_infof(data, "");
fail_unless(strlen(result) == 1, "Empty string"); fail_unless(strlen(output) == 1, "Empty string");
Curl_infof(data, "%s", (char *)NULL); Curl_infof(data, "%s", (char *)NULL);
fail_unless(verify(result, "(nil)") == 0, "Passing NULL as string"); fail_unless(verify(output, "(nil)") == 0, "Passing NULL as string");
/* A string just long enough to not be truncated */ /* A string just long enough to not be truncated */
memset(input, '\0', sizeof(input)); memset(input, '\0', sizeof(input));
memset(input, 'A', 2047); memset(input, 'A', 2047);
Curl_infof(data, "%s", input); Curl_infof(data, "%s", input);
fail_unless(strlen(result) == 2048, "No truncation of infof input"); fail_unless(strlen(output) == 2048, "No truncation of infof input");
fail_unless(verify(result, input) == 0, "No truncation of infof input"); fail_unless(verify(output, input) == 0, "No truncation of infof input");
fail_unless(result[sizeof(result) - 1] == '\0', fail_unless(output[sizeof(output) - 1] == '\0',
"No truncation of infof input"); "No truncation of infof input");
/* Just over the limit without newline for truncation via '...' */ /* Just over the limit without newline for truncation via '...' */
memset(input + 2047, 'A', 4); memset(input + 2047, 'A', 4);
Curl_infof(data, "%s", input); Curl_infof(data, "%s", input);
fail_unless(strlen(result) == 2051, "Truncation of infof input 1"); fail_unless(strlen(output) == 2051, "Truncation of infof input 1");
fail_unless(result[sizeof(result) - 1] == '\0', "Truncation of infof input 1"); fail_unless(output[sizeof(output) - 1] == '\0', "Truncation of infof input 1");
/* Just over the limit with newline for truncation via '...' */ /* Just over the limit with newline for truncation via '...' */
memset(input + 2047, 'A', 4); memset(input + 2047, 'A', 4);
memset(input + 2047 + 4, '\n', 1); memset(input + 2047 + 4, '\n', 1);
Curl_infof(data, "%s", input); Curl_infof(data, "%s", input);
fail_unless(strlen(result) == 2051, "Truncation of infof input 2"); fail_unless(strlen(output) == 2051, "Truncation of infof input 2");
fail_unless(result[sizeof(result) - 1] == '\0', "Truncation of infof input 2"); fail_unless(output[sizeof(output) - 1] == '\0', "Truncation of infof input 2");
/* Way over the limit for truncation via '...' */ /* Way over the limit for truncation via '...' */
memset(input, '\0', sizeof(input)); memset(input, '\0', sizeof(input));
memset(input, 'A', sizeof(input) - 1); memset(input, 'A', sizeof(input) - 1);
Curl_infof(data, "%s", input); Curl_infof(data, "%s", input);
fail_unless(strlen(result) == 2051, "Truncation of infof input 3"); fail_unless(strlen(output) == 2051, "Truncation of infof input 3");
fail_unless(result[sizeof(result) - 1] == '\0', "Truncation of infof input 3"); fail_unless(output[sizeof(output) - 1] == '\0', "Truncation of infof input 3");
UNITTEST_STOP UNITTEST_STOP