mirror of
https://github.com/open-goal/jak-project
synced 2026-08-26 16:16:36 -04:00
5d5e35fb9b
## Problem Windows builds break with a current local toolchain (Scoop LLVM 22.1.8, CMake 4.4.0, VS 2026), in two independent ways: 1. The build stops at curl's deliberate guard: `#error "no non-blocking method was found/used/set"` in `third-party/curl/lib/nonblock.c`. 2. From the second configure onward, `cmake --build` re-runs CMake in an endless loop (observed 42 consecutive reconfigure cycles in a single build). Likely the same mechanism behind the "endlessly building" VS 2026 note in `docs/setup/dev/vs.md`. ## Root cause 1. `third-party/curl/CMake/CurlTests.c` passes `int *` to `ioctlsocket()`, whose third parameter is `u_long *`. Clang 22 promotes `-Wincompatible-pointer-types` to a hard error in C, so the `HAVE_IOCTLSOCKET_FIONBIO` try_compile silently fails and `curl_config.h` never defines it. Upstream CI does not see this because the windows-2022 runner image ships an older LLVM. GCC 14 promotes the same warning to a hard error, which is very likely the `CurlTests.c.obj` failure reported from MSYS2 in open-goal/jak-project#3551. Upstream curl hit the identical problem with GCC 14 and fixed the probe in curl 8.8.0 (curl/curl#13578). 2. The root CMakeLists copies the build tree's `compile_commands.json` into `<src>/build/` for clangd using `configure_file()`, which registers its input as a configure dependency. CMake rewrites `compile_commands.json` late in every generation, after `CTestTestfile.cmake` and `cmake_install.cmake` (outputs of the same Ninja regen rule), so once the dependency is registered the rule is deterministically dirty and every `ninja` invocation re-runs CMake. A pristine first configure is safe (the file does not exist yet, so the `if(EXISTS ...)` guard skips the copy), which is why the loop looks machine- or IDE-specific. ## Fix 1. Per review, re-vendor `third-party/curl` at the `curl-8_21_0` tag (previously `curl-8_3_0`), which carries the upstream probe fix plus two years of upstream development; `vendor.yaml` updated to match. Adjustments the version jump forced: - curl 8.15 removed the native macOS Secure Transport backend (`CURL_USE_SECTRANSP`), so macOS now builds curl against OpenSSL like Linux. The two macOS workflows install Homebrew `openssl@3` and export `OPENSSL_ROOT_DIR` (keg-only), and the macOS setup docs gained the same two lines. - `CURL_BROTLI` / `CURL_ZSTD` switched to AUTO-detection in curl 8.10; pinned OFF to keep the previous no-compression behavior and avoid silently linking whatever the CI images happen to have. - curl's new top-level `BUILD_EXAMPLES` cache option (default ON) leaked into discord-rpc's identically named option and broke configure at a nonexistent `examples/send-presence` directory; pinned OFF ahead of the third-party subdirectories. The diff is dominated by the mechanical tag-tree swap under `third-party/curl` (linguist-vendored, collapsed in review). The hand-written changes are `CMakeLists.txt`, the two macOS workflows, `docs/setup/system/macos.md`, and `vendor.yaml`. 2. Swap `configure_file()` for `file(COPY ...)`: the same clangd copy with no configure dependency registered. (`file(COPY_FILE ... ONLY_IF_DIFFERENT)` would be cleaner still but requires CMake 3.21, above the declared `cmake_minimum_required(VERSION 3.10)`.) ## Test plan - [x] Fresh `cmake --preset Release-windows-clang` (LLVM 22, no cache seeding) completes and logs `Enabled SSL backends: Schannel`; the FIONBIO probe passes without the previous `#error` - [x] Full Windows Release build from scratch in the branch worktree (all 1422 targets) - [x] goalc-test suite: 1509 passed, 0 failed - [x] Second consecutive configure with `compile_commands.json` present: the regen rule in `build.ninja` has no `compile_commands.json` input; `<src>/build/compile_commands.json` is still refreshed for clangd - [x] Repeated `ninja` invocations after a full build no longer re-run CMake - [x] macOS Intel and ARM CI green (first exercise of the OpenSSL backend switch) --- I work off a self-hosted forge, so this GitHub account is quiet; the configure logs and ninja dirty-node traces from the investigation are available if anyone wants the raw data. (AI-assisted)
444 lines
15 KiB
C
Vendored
Generated
444 lines
15 KiB
C
Vendored
Generated
/***************************************************************************
|
|
* _ _ ____ _
|
|
* 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
|
|
*
|
|
***************************************************************************/
|
|
#include "unitcheck.h"
|
|
#include "urlapi-int.h"
|
|
#include "curlx/dynbuf.h"
|
|
|
|
static CURLcode test_unit1675(const char *arg)
|
|
{
|
|
UNITTEST_BEGIN_SIMPLE
|
|
|
|
/* Test ipv4_normalize */
|
|
{
|
|
struct dynbuf host;
|
|
int fails = 0;
|
|
unsigned int i;
|
|
struct ipv4_test {
|
|
const char *in;
|
|
const char *out;
|
|
};
|
|
const struct ipv4_test tests[] = {
|
|
{ "0x.0x.0x.0x", NULL }, /* invalid hex */
|
|
{ "0x.0x.0x", NULL }, /* invalid hex */
|
|
{ "0x.0x", NULL }, /* invalid hex */
|
|
{ "0x", NULL }, /* invalid hex */
|
|
{ "0", "0.0.0.0" },
|
|
{ "00", "0.0.0.0" },
|
|
{ "00000000000", "0.0.0.0" },
|
|
{ "127.0.0.1", "127.0.0.1" },
|
|
{ "0177.0.0.1", "127.0.0.1" },
|
|
{ "00177.0.0.1", "127.0.0.1" },
|
|
{ "0x7f.0.0.1", "127.0.0.1" },
|
|
{ "0x07f.0.0.1", "127.0.0.1" },
|
|
{ "1", "0.0.0.1" },
|
|
{ "010", "0.0.0.8" },
|
|
{ "001", "0.0.0.1" },
|
|
{ "127", "0.0.0.127" },
|
|
{ "127.1", "127.0.0.1" },
|
|
{ "127.0.1", "127.0.0.1" },
|
|
{ "1.16777215", "1.255.255.255" },
|
|
{ "1.16777216", NULL }, /* overflow */
|
|
{ "1.1.65535", "1.1.255.255" },
|
|
{ "1.1.65536", NULL }, /* overflow */
|
|
{ "0x7f000001", "127.0.0.1" },
|
|
{ "0x7F000001", "127.0.0.1" },
|
|
{ "0x7g000001", NULL }, /* bad hex */
|
|
{ "2130706433", "127.0.0.1" },
|
|
{ "017700000001", "127.0.0.1" },
|
|
{ "000000000017700000001", "127.0.0.1" },
|
|
{ "192.168.0.1", "192.168.0.1" },
|
|
{ "0300.0250.0000.0001", "192.168.0.1" },
|
|
{ "0xc0.0xa8.0.1", "192.168.0.1" },
|
|
{ "0xc0a80001", "192.168.0.1" },
|
|
{ "3232235521", "192.168.0.1" },
|
|
{ "4294967294", "255.255.255.254" },
|
|
{ "4294967295", "255.255.255.255" },
|
|
{ "037777777777", "255.255.255.255" },
|
|
{ "0xFFFFFFFF", "255.255.255.255" },
|
|
{ "0xFFFFFfff", "255.255.255.255" },
|
|
{ "1.2.3.4.5", NULL }, /* too many parts */
|
|
{ "256.0.0.1", NULL }, /* overflow */
|
|
{ "1.256.0.1", NULL }, /* overflow */
|
|
{ "1.1.256.1", NULL }, /* overflow */
|
|
{ "1.0.0.256", NULL }, /* overflow */
|
|
{ "0x100.0.0.1", NULL }, /* overflow */
|
|
{ "1.0x100.0.1", NULL }, /* overflow */
|
|
{ "1.1.0x100.1", NULL }, /* overflow */
|
|
{ "1.1.1.0x100", NULL }, /* overflow */
|
|
{ "0400.0.0.1", NULL }, /* overflow */
|
|
{ "4.0400.0.1", NULL }, /* overflow */
|
|
{ "4.4.0400.1", NULL }, /* overflow */
|
|
{ "4.4.4.0400", NULL }, /* overflow */
|
|
{ "4294967296", NULL }, /* overflow */
|
|
{ "040000000000", NULL }, /* overflow */
|
|
{ "0x100000000", NULL }, /* overflow */
|
|
{ "1.2.3.-4", NULL }, /* negative */
|
|
{ "1.2.-3.4", NULL }, /* negative */
|
|
{ "1.-2.3.4", NULL }, /* negative */
|
|
{ "-1.2.3.4", NULL }, /* negative */
|
|
{ "-12", NULL }, /* negative */
|
|
{ "-12.1", NULL }, /* negative */
|
|
{ "-12.2.3", NULL }, /* negative */
|
|
{ " 1.2.3.4", NULL }, /* space */
|
|
{ "1. 2.3.4", NULL }, /* space */
|
|
{ "1.2. 3.4", NULL }, /* space */
|
|
{ "1.2.3. 4", NULL }, /* space */
|
|
};
|
|
|
|
curlx_dyn_init(&host, 256);
|
|
for(i = 0; i < CURL_ARRAYSIZE(tests); i++) {
|
|
int rc;
|
|
curlx_dyn_reset(&host);
|
|
if(curlx_dyn_add(&host, tests[i].in)) {
|
|
curlx_dyn_free(&host);
|
|
return CURLE_OUT_OF_MEMORY;
|
|
}
|
|
rc = ipv4_normalize(&host);
|
|
if(tests[i].out) {
|
|
if((rc != HOST_IPV4) ||
|
|
strcmp(curlx_dyn_ptr(&host), tests[i].out)) {
|
|
curl_mfprintf(stderr, "ipv4_normalize('%s') failed: "
|
|
"expected '%s', got '%s'\n",
|
|
tests[i].in, tests[i].out, curlx_dyn_ptr(&host));
|
|
fails++;
|
|
}
|
|
}
|
|
else if(rc == HOST_IPV4) {
|
|
curl_mfprintf(stderr, "ipv4_normalize('%s') succeeded unexpectedly:"
|
|
" got '%s'\n",
|
|
tests[i].in, curlx_dyn_ptr(&host));
|
|
fails++;
|
|
}
|
|
}
|
|
curlx_dyn_free(&host);
|
|
abort_if(fails, "ipv4_normalize tests failed");
|
|
}
|
|
|
|
/* Test urlencode_str */
|
|
{
|
|
struct dynbuf out;
|
|
int fails = 0;
|
|
unsigned int i;
|
|
struct urlencode_test {
|
|
const char *in;
|
|
bool relative;
|
|
unsigned int query;
|
|
const char *out;
|
|
};
|
|
const struct urlencode_test tests[] = {
|
|
{ "http://leave\x01/hello\x01world", FALSE, QUERY_NO,
|
|
"http://leave\x01/hello%01world" },
|
|
{ "http://leave/hello\x01world", FALSE, QUERY_NO,
|
|
"http://leave/hello%01world" },
|
|
{ "http://le ave/hello\x01world", FALSE, QUERY_NO,
|
|
"http://le ave/hello%01world" },
|
|
{ "hello\x01world", TRUE, QUERY_NO, "hello%01world" },
|
|
{ "hello\xf0world", TRUE, QUERY_NO, "hello%F0world" },
|
|
{ "hello world", TRUE, QUERY_NO, "hello%20world" },
|
|
{ "hello%20world", TRUE, QUERY_NO, "hello%20world" },
|
|
{ "hello world", TRUE, QUERY_YES, "hello+world" },
|
|
{ "a+b c", TRUE, QUERY_NO, "a+b%20c" },
|
|
{ "a%20b%20c", TRUE, QUERY_NO, "a%20b%20c" },
|
|
{ "a%aab%aac", TRUE, QUERY_NO, "a%AAb%AAc" },
|
|
{ "a%aab%AAc", TRUE, QUERY_NO, "a%AAb%AAc" },
|
|
{ "w%w%x", TRUE, QUERY_NO, "w%w%x" },
|
|
{ "w%wf%xf", TRUE, QUERY_NO, "w%wf%xf" },
|
|
{ "w%fw%fw", TRUE, QUERY_NO, "w%fw%fw" },
|
|
{ "a+b c", TRUE, QUERY_YES, "a+b+c" },
|
|
{ "/foo/bar", TRUE, QUERY_NO, "/foo/bar" },
|
|
{ "/foo/bar", TRUE, QUERY_YES, "/foo/bar" },
|
|
{ "/foo/ bar", TRUE, QUERY_NO, "/foo/%20bar" },
|
|
{ "/foo/ bar", TRUE, QUERY_YES, "/foo/+bar" },
|
|
{ "~-._", TRUE, QUERY_NO, "~-._" },
|
|
{ "~-._", TRUE, QUERY_YES, "~-._" },
|
|
{ "foo bar?foo bar", TRUE, QUERY_NO, "foo%20bar?foo%20bar" },
|
|
{ "foo bar?foo bar", TRUE, QUERY_NOT_YET, "foo%20bar?foo+bar" },
|
|
};
|
|
|
|
curlx_dyn_init(&out, 256);
|
|
for(i = 0; i < CURL_ARRAYSIZE(tests); i++) {
|
|
CURLUcode uc;
|
|
curlx_dyn_reset(&out);
|
|
uc = urlencode_str(&out, tests[i].in, strlen(tests[i].in),
|
|
tests[i].relative, tests[i].query);
|
|
if(uc || strcmp(curlx_dyn_ptr(&out), tests[i].out)) {
|
|
curl_mfprintf(stderr, "urlencode_str('%s', query=%u) failed:"
|
|
" expected '%s', got '%s'\n",
|
|
tests[i].in, tests[i].query, tests[i].out,
|
|
uc ? "error" : curlx_dyn_ptr(&out));
|
|
fails++;
|
|
}
|
|
}
|
|
curlx_dyn_free(&out);
|
|
abort_if(fails, "urlencode_str tests failed");
|
|
}
|
|
|
|
/* Test ipv6_parse */
|
|
{
|
|
struct Curl_URL u;
|
|
int fails = 0;
|
|
unsigned int i;
|
|
struct ipv6_test {
|
|
const char *in;
|
|
const char *out_host;
|
|
const char *out_zone;
|
|
};
|
|
const struct ipv6_test tests[] = {
|
|
{ "[::1]", "[::1]", NULL },
|
|
{ "[fe80::1%eth0]", "[fe80::1]", "eth0" },
|
|
{ "[fe80::1%25eth0]", "[fe80::1]", "eth0" },
|
|
{ "[::1", NULL, NULL }, /* missing bracket */
|
|
{ "[]", NULL, NULL }, /* empty */
|
|
};
|
|
|
|
for(i = 0; i < CURL_ARRAYSIZE(tests); i++) {
|
|
CURLUcode uc;
|
|
char hostname[256];
|
|
memset(&u, 0, sizeof(u));
|
|
curlx_strcopy(hostname, sizeof(hostname),
|
|
tests[i].in, strlen(tests[i].in));
|
|
uc = ipv6_parse(&u, hostname, strlen(hostname));
|
|
if(tests[i].out_host) {
|
|
if(uc || strcmp(hostname, tests[i].out_host)) {
|
|
curl_mfprintf(stderr, "ipv6_parse('%s') host failed:"
|
|
" expected '%s', got '%s'\n",
|
|
tests[i].in, tests[i].out_host,
|
|
uc ? "error" : hostname);
|
|
fails++;
|
|
}
|
|
if(!uc && tests[i].out_zone) {
|
|
if(!u.zoneid || strcmp(u.zoneid, tests[i].out_zone)) {
|
|
curl_mfprintf(stderr, "ipv6_parse('%s') zone failed:"
|
|
" expected '%s', got '%s'\n",
|
|
tests[i].in, tests[i].out_zone,
|
|
u.zoneid ? u.zoneid : "(null)");
|
|
fails++;
|
|
}
|
|
}
|
|
}
|
|
else if(!uc) {
|
|
curl_mfprintf(stderr, "ipv6_parse('%s') succeeded unexpectedly\n",
|
|
tests[i].in);
|
|
fails++;
|
|
}
|
|
curlx_free(u.host);
|
|
curlx_free(u.zoneid);
|
|
}
|
|
abort_if(fails, "ipv6_parse tests failed");
|
|
}
|
|
|
|
/* Test parse_file */
|
|
{
|
|
CURLU *u;
|
|
const char *path;
|
|
size_t pathlen;
|
|
int fails = 0;
|
|
unsigned int i;
|
|
struct file_test {
|
|
const char *in;
|
|
const char *out_path;
|
|
bool fine;
|
|
};
|
|
const struct file_test tests[] = {
|
|
{ "file:///etc/hosts", "/etc/hosts", TRUE },
|
|
{ "file://localhost/etc/hosts", "/etc/hosts", TRUE },
|
|
{ "file://apple/etc/hosts", "/etc/hosts", FALSE },
|
|
{ "file:foo", NULL, FALSE },
|
|
{ "file:./", NULL, FALSE },
|
|
{ "file:?q", NULL, FALSE },
|
|
{ "file:#f", NULL, FALSE },
|
|
#ifdef _WIN32
|
|
{ "file:///c:/windows/system32", "c:/windows/system32", TRUE },
|
|
{ "file://localhost/c:/windows/system32", "c:/windows/system32", TRUE },
|
|
#endif
|
|
};
|
|
|
|
for(i = 0; i < CURL_ARRAYSIZE(tests); i++) {
|
|
CURLUcode uc;
|
|
u = curl_url();
|
|
if(!u)
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
|
uc = parse_file(tests[i].in, strlen(tests[i].in), u, &path, &pathlen);
|
|
if(!tests[i].fine && !uc) {
|
|
curl_mfprintf(stderr, "Unexpectedly fine for input '%s'\n",
|
|
tests[i].in);
|
|
fails++;
|
|
}
|
|
if(tests[i].fine &&
|
|
(uc ||
|
|
strncmp(path, tests[i].out_path, pathlen) ||
|
|
strlen(tests[i].out_path) != pathlen)) {
|
|
curl_mfprintf(stderr, "parse_file('%s') failed:"
|
|
" expected path '%s'; got path '%.*s'\n",
|
|
tests[i].in, tests[i].out_path,
|
|
(int)pathlen, path);
|
|
fails++;
|
|
}
|
|
curl_url_cleanup(u);
|
|
}
|
|
abort_if(fails, "parse_file tests failed");
|
|
}
|
|
|
|
/* Test same origin check. For now, we can only do that when
|
|
* schemes are supported by libcurl. */
|
|
#ifndef CURL_DISABLE_HTTP
|
|
{
|
|
CURLU *base, *href;
|
|
int fails = 0;
|
|
unsigned int i;
|
|
bool match;
|
|
struct origin_test {
|
|
const char *base;
|
|
const char *scheme;
|
|
const char *host;
|
|
const char *port;
|
|
const char *path;
|
|
bool expect_match;
|
|
};
|
|
const struct origin_test tests[] = {
|
|
{ "http://host:123/x", "http", "host", "123", "/y", TRUE },
|
|
{ "http://host:123/x", NULL, "host", "123", "/y", TRUE },
|
|
{ "http://host:123/x", NULL, NULL, NULL, "/y", TRUE },
|
|
{ "http://host:80/x", "http", "host", "123", "/y", FALSE },
|
|
{ "http://host:80/x", "http", "host", NULL, "/y", TRUE },
|
|
{ "http://host/x", "http", "host", "80", "/y", TRUE },
|
|
#ifdef USE_SSL
|
|
{ "http://host:123/x", "https", "host", "123", "/y", FALSE },
|
|
{ "https://host/x", "http", "host", "443", "/y", FALSE },
|
|
{ "https://host/x", "https", "host", "443", "/y", TRUE },
|
|
#endif
|
|
};
|
|
|
|
for(i = 0; i < CURL_ARRAYSIZE(tests); i++) {
|
|
CURLUcode uc;
|
|
base = curl_url();
|
|
href = curl_url();
|
|
if(!base || !href) {
|
|
curl_mfprintf(stderr, "%u: failed to allocate memory\n", i);
|
|
fails++;
|
|
goto loop_end;
|
|
}
|
|
uc = curl_url_set(base, CURLUPART_URL, tests[i].base, 0);
|
|
if(uc) {
|
|
curl_mfprintf(stderr, "failed to parse %u base %s -> %d\n", i,
|
|
tests[i].base, (int)uc);
|
|
fails++;
|
|
goto loop_end;
|
|
}
|
|
if(tests[i].scheme)
|
|
uc = curl_url_set(href, CURLUPART_SCHEME, tests[i].scheme, 0);
|
|
if(!uc && tests[i].host)
|
|
uc = curl_url_set(href, CURLUPART_HOST, tests[i].host, 0);
|
|
if(!uc && tests[i].port)
|
|
uc = curl_url_set(href, CURLUPART_PORT, tests[i].port, 0);
|
|
if(!uc && tests[i].path)
|
|
uc = curl_url_set(href, CURLUPART_PATH, tests[i].path, 0);
|
|
if(uc) {
|
|
curl_mfprintf(stderr, "failed to parse %u href %s://%s:%s%s -> %d\n",
|
|
i, tests[i].scheme, tests[i].host, tests[i].port,
|
|
tests[i].path, (int)uc);
|
|
fails++;
|
|
goto loop_end;
|
|
}
|
|
|
|
match = Curl_url_same_origin(base, href);
|
|
if(match != tests[i].expect_match) {
|
|
curl_mfprintf(stderr, "ERROR: %u base %s and href %s://%s:%s%s %s\n",
|
|
i, tests[i].base, tests[i].scheme, tests[i].host,
|
|
tests[i].port, tests[i].path,
|
|
match ? "matched" : "did not match");
|
|
fails++;
|
|
}
|
|
|
|
loop_end:
|
|
curl_url_cleanup(base);
|
|
curl_url_cleanup(href);
|
|
}
|
|
abort_if(fails, "same_origin tests failed");
|
|
}
|
|
#endif /* !CURL_DISABLE_HTTP */
|
|
|
|
/* Test parse_hostname_login */
|
|
{
|
|
struct Curl_URL u;
|
|
int fails = 0;
|
|
unsigned int i;
|
|
struct test {
|
|
CURLUcode uc;
|
|
const char *in;
|
|
const char *scheme;
|
|
unsigned int flags;
|
|
const char *user;
|
|
const char *password;
|
|
const char *options;
|
|
size_t offset;
|
|
};
|
|
const struct test tests[] = {
|
|
{ CURLUE_OK, "foo:bar@host", NULL, 0, "foo", "bar", "o", 8 },
|
|
{ CURLUE_OK, "foo:bar;abc@host", "imap", 0, "foo", "bar", "abc", 12 },
|
|
{ CURLUE_OK, "foo:bar;abc@host", NULL, 0, "foo", "bar;abc", "o", 12 },
|
|
{ CURLUE_USER_NOT_ALLOWED, "foo:bar@host", NULL, CURLU_DISALLOW_USER,
|
|
NULL, NULL, NULL, 0 },
|
|
{ CURLUE_OK, "host", NULL, 0, NULL, NULL, NULL, 0 },
|
|
};
|
|
|
|
for(i = 0; i < CURL_ARRAYSIZE(tests); i++) {
|
|
CURLUcode uc;
|
|
size_t offset = 0;
|
|
memset(&u, 0, sizeof(u));
|
|
u.scheme = CURL_UNCONST(tests[i].scheme);
|
|
u.user = curlx_strdup("u");
|
|
u.password = curlx_strdup("p");
|
|
u.options = curlx_strdup("o");
|
|
uc = parse_hostname_login(&u, tests[i].in, strlen(tests[i].in),
|
|
tests[i].flags, &offset);
|
|
if(uc != tests[i].uc ||
|
|
!!u.user != !!tests[i].user ||
|
|
(u.user && tests[i].user &&
|
|
strcmp(u.user, tests[i].user)) ||
|
|
!!u.password != !!tests[i].password ||
|
|
(u.password && tests[i].password &&
|
|
strcmp(u.password, tests[i].password)) ||
|
|
!!u.options != !!tests[i].options ||
|
|
(u.options && tests[i].options &&
|
|
strcmp(u.options, tests[i].options)) ||
|
|
offset != tests[i].offset) {
|
|
curl_mfprintf(stderr, "%u: parse_hostname_login('%s') host failed:"
|
|
" expected '%d/%s/%s/%s/%zu', got '%d/%s/%s/%s/%zu'\n",
|
|
i, tests[i].in, (int)tests[i].uc, tests[i].user,
|
|
tests[i].password, tests[i].options, tests[i].offset,
|
|
(int)uc, u.user, u.password, u.options, offset);
|
|
fails++;
|
|
}
|
|
curlx_safefree(u.user);
|
|
curlx_safefree(u.password);
|
|
curlx_safefree(u.options);
|
|
}
|
|
abort_if(fails, "parse_hostname_login tests failed");
|
|
}
|
|
|
|
UNITTEST_END_SIMPLE
|
|
}
|