blob: 1701706fe73bff3dfe83ca68cd471a97badc0573 [file]
// Copyright 2026 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "iree/async/address.h"
#include <string>
#include "iree/base/api.h"
#include "iree/testing/gtest.h"
#include "iree/testing/status_matchers.h"
namespace {
// Helper: format an address to a std::string for easy comparison.
static std::string FormatAddress(const iree_async_address_t& address) {
char buffer[IREE_ASYNC_ADDRESS_MAX_FORMAT_LENGTH];
iree_string_view_t value = iree_string_view_empty();
iree_status_t status =
iree_async_address_format(&address, sizeof(buffer), buffer, &value);
if (!iree_status_is_ok(status)) {
iree_status_ignore(status);
return "<format failed>";
}
return std::string(value.data, value.size);
}
// Helper: parse IPv4 and return the address (or fail the test).
static iree_async_address_t ParseIPv4(const char* host, uint16_t port) {
iree_async_address_t address;
iree_string_view_t host_view =
host ? iree_make_cstring_view(host) : iree_string_view_empty();
iree_status_t status =
iree_async_address_from_ipv4(host_view, port, &address);
IREE_EXPECT_OK(status);
return address;
}
// Helper: parse IPv6 and return the address (or fail the test).
static iree_async_address_t ParseIPv6(const char* host, uint16_t port) {
iree_async_address_t address;
iree_string_view_t host_view =
host ? iree_make_cstring_view(host) : iree_string_view_empty();
iree_status_t status =
iree_async_address_from_ipv6(host_view, port, &address);
IREE_EXPECT_OK(status);
return address;
}
//===----------------------------------------------------------------------===//
// IPv4 Parsing — Valid Cases
//===----------------------------------------------------------------------===//
TEST(AddressFromIpv4, EmptyHostIsAny) {
iree_async_address_t address;
IREE_EXPECT_OK(
iree_async_address_from_ipv4(iree_string_view_empty(), 8080, &address));
EXPECT_EQ(FormatAddress(address), "0.0.0.0:8080");
}
TEST(AddressFromIpv4, Loopback) {
auto address = ParseIPv4("127.0.0.1", 80);
EXPECT_EQ(FormatAddress(address), "127.0.0.1:80");
}
TEST(AddressFromIpv4, AllZeros) {
auto address = ParseIPv4("0.0.0.0", 0);
EXPECT_EQ(FormatAddress(address), "0.0.0.0:0");
}
TEST(AddressFromIpv4, MaxOctets) {
auto address = ParseIPv4("255.255.255.255", 65535);
EXPECT_EQ(FormatAddress(address), "255.255.255.255:65535");
}
TEST(AddressFromIpv4, EphemeralPort) {
auto address = ParseIPv4("192.168.1.1", 0);
EXPECT_EQ(FormatAddress(address), "192.168.1.1:0");
}
TEST(AddressFromIpv4, TypicalServerPort) {
auto address = ParseIPv4("10.0.0.1", 443);
EXPECT_EQ(FormatAddress(address), "10.0.0.1:443");
}
TEST(AddressFromIpv4, SingleDigitOctets) {
auto address = ParseIPv4("1.2.3.4", 5);
EXPECT_EQ(FormatAddress(address), "1.2.3.4:5");
}
//===----------------------------------------------------------------------===//
// IPv4 Parsing — Error Cases
//===----------------------------------------------------------------------===//
TEST(AddressFromIpv4, OctetOverflow) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(
iree_make_cstring_view("256.0.0.1"), 80, &address));
}
TEST(AddressFromIpv4, OctetOverflowLarge) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(
iree_make_cstring_view("999.0.0.1"), 80, &address));
}
TEST(AddressFromIpv4, TooFewDots) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(
iree_make_cstring_view("1.2.3"), 80, &address));
}
TEST(AddressFromIpv4, TooManyDots) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(
iree_make_cstring_view("1.2.3.4.5"), 80, &address));
}
TEST(AddressFromIpv4, LeadingZeros) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(iree_make_cstring_view("01.02.03.04"), 80,
&address));
}
TEST(AddressFromIpv4, LeadingZeroSingle) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(
iree_make_cstring_view("1.02.3.4"), 80, &address));
}
TEST(AddressFromIpv4, TrailingGarbage) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(iree_make_cstring_view("1.2.3.4xyz"), 80,
&address));
}
TEST(AddressFromIpv4, WhitespaceLeading) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(
iree_make_cstring_view(" 1.2.3.4"), 80, &address));
}
TEST(AddressFromIpv4, WhitespaceTrailing) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(
iree_make_cstring_view("1.2.3.4 "), 80, &address));
}
TEST(AddressFromIpv4, EmptyOctet) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(
iree_make_cstring_view("1..3.4"), 80, &address));
}
TEST(AddressFromIpv4, HexRejected) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(iree_make_cstring_view("0x7f.0.0.1"), 80,
&address));
}
TEST(AddressFromIpv4, JustDots) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(
iree_make_cstring_view("..."), 80, &address));
}
TEST(AddressFromIpv4, NegativeRejected) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(
iree_make_cstring_view("-1.0.0.0"), 80, &address));
}
TEST(AddressFromIpv4, VeryLongDigitString) {
// Digits that overflow a uint32 accumulator (exceeds 255 check).
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(iree_make_cstring_view("9999999999.0.0.1"),
80, &address));
}
TEST(AddressFromIpv4, EmbeddedNul) {
// string_view with embedded NUL byte — not a valid digit.
iree_string_view_t host = {("1.2\0.3.4"), 8};
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv4(host, 80, &address));
}
//===----------------------------------------------------------------------===//
// IPv6 Parsing — Valid Cases
//===----------------------------------------------------------------------===//
TEST(AddressFromIpv6, EmptyHostIsAny) {
iree_async_address_t address;
IREE_EXPECT_OK(
iree_async_address_from_ipv6(iree_string_view_empty(), 80, &address));
EXPECT_EQ(FormatAddress(address), "[::]:80");
}
TEST(AddressFromIpv6, Loopback) {
auto address = ParseIPv6("::1", 80);
EXPECT_EQ(FormatAddress(address), "[::1]:80");
}
TEST(AddressFromIpv6, FullForm) {
auto address = ParseIPv6("2001:0db8:0000:0000:0000:0000:0000:0001", 443);
EXPECT_EQ(FormatAddress(address), "[2001:db8::1]:443");
}
TEST(AddressFromIpv6, CompressionMiddle) {
auto address = ParseIPv6("2001:db8::1", 80);
EXPECT_EQ(FormatAddress(address), "[2001:db8::1]:80");
}
TEST(AddressFromIpv6, CompressionStart) {
auto address = ParseIPv6("::1", 80);
EXPECT_EQ(FormatAddress(address), "[::1]:80");
}
TEST(AddressFromIpv6, CompressionEnd) {
auto address = ParseIPv6("2001:db8::", 80);
EXPECT_EQ(FormatAddress(address), "[2001:db8::]:80");
}
TEST(AddressFromIpv6, AllZeros) {
auto address = ParseIPv6("::", 0);
EXPECT_EQ(FormatAddress(address), "[::]:0");
}
TEST(AddressFromIpv6, AllOnes) {
auto address = ParseIPv6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 1);
EXPECT_EQ(FormatAddress(address),
"[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:1");
}
TEST(AddressFromIpv6, LinkLocal) {
auto address = ParseIPv6("fe80::1", 0);
EXPECT_EQ(FormatAddress(address), "[fe80::1]:0");
}
TEST(AddressFromIpv6, MixedCase) {
auto address = ParseIPv6("2001:DB8::ABCD", 80);
// Output is always lowercase per RFC 5952.
EXPECT_EQ(FormatAddress(address), "[2001:db8::abcd]:80");
}
TEST(AddressFromIpv6, SingleZeroGroupNotCompressed) {
// RFC 5952: single zero group is NOT compressed.
auto address = ParseIPv6("2001:db8:0:1:0:0:0:1", 80);
// The run of 3 zeros at positions 4-6 gets compressed, not the single at 2.
EXPECT_EQ(FormatAddress(address), "[2001:db8:0:1::1]:80");
}
TEST(AddressFromIpv6, LongestRunWins) {
// Two runs of zeros: positions 2-3 (length 2) and 5-7 (length 3).
auto address = ParseIPv6("1:1:0:0:1:0:0:0", 80);
EXPECT_EQ(FormatAddress(address), "[1:1:0:0:1::]:80");
}
TEST(AddressFromIpv6, LeftmostTiebreak) {
// Two runs of equal length: positions 1-2 and 5-6.
auto address = ParseIPv6("1:0:0:1:1:0:0:1", 80);
EXPECT_EQ(FormatAddress(address), "[1::1:1:0:0:1]:80");
}
TEST(AddressFromIpv6, Ipv4Mapped) {
auto address = ParseIPv6("::ffff:192.168.1.1", 8080);
EXPECT_EQ(FormatAddress(address), "[::ffff:192.168.1.1]:8080");
}
TEST(AddressFromIpv6, Ipv4MappedLoopback) {
auto address = ParseIPv6("::ffff:127.0.0.1", 80);
EXPECT_EQ(FormatAddress(address), "[::ffff:127.0.0.1]:80");
}
TEST(AddressFromIpv6, LeadingZerosInGroup) {
// Leading zeros in groups are valid input.
auto address = ParseIPv6("2001:0db8:0000:0000:0000:0000:0000:0001", 80);
EXPECT_EQ(FormatAddress(address), "[2001:db8::1]:80");
}
TEST(AddressFromIpv6, MaxPort) {
auto address = ParseIPv6("::1", 65535);
EXPECT_EQ(FormatAddress(address), "[::1]:65535");
}
//===----------------------------------------------------------------------===//
// IPv6 Parsing — Error Cases
//===----------------------------------------------------------------------===//
TEST(AddressFromIpv6, DoubleCompressionRejected) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(iree_make_cstring_view("2001::db8::1"), 80,
&address));
}
TEST(AddressFromIpv6, TooManyGroups) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(iree_make_cstring_view("1:2:3:4:5:6:7:8:9"),
80, &address));
}
TEST(AddressFromIpv6, TooFewGroupsNoCompression) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(iree_make_cstring_view("1:2:3:4:5:6:7"), 80,
&address));
}
TEST(AddressFromIpv6, GroupTooLong) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(iree_make_cstring_view("2001:dbbbb::1"), 80,
&address));
}
TEST(AddressFromIpv6, InvalidHexChar) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(iree_make_cstring_view("2001:xyzw::1"), 80,
&address));
}
TEST(AddressFromIpv6, TrailingColon) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(iree_make_cstring_view("2001:db8:1:"), 80,
&address));
}
TEST(AddressFromIpv6, LeadingSingleColon) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(iree_make_cstring_view(":1"), 80, &address));
}
TEST(AddressFromIpv6, TooManyGroupsWithCompression) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(iree_make_cstring_view("1:2:3:4:5::6:7:8"),
80, &address));
}
TEST(AddressFromIpv6, Ipv4MappedOctetOverflow) {
// IPv4-mapped form with an octet exceeding 255.
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(iree_make_cstring_view("::ffff:256.1.1.1"),
80, &address));
}
TEST(AddressFromIpv6, Ipv4MappedTooFewOctets) {
// IPv4-mapped form with fewer than 4 octets.
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(iree_make_cstring_view("::ffff:1.2.3"), 80,
&address));
}
TEST(AddressFromIpv6, SixGroupsPlusIpv4Suffix) {
// 6 hex groups + IPv4 suffix = 8 total 16-bit groups (valid).
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_ipv6(
iree_make_cstring_view("1:2:3:4:5:6:1.2.3.4"), 80, &address));
}
TEST(AddressFromIpv6, CompressionPlusIpv4TooManyGroups) {
// Compression + hex groups + IPv4 suffix would exceed 8 total groups.
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(
iree_make_cstring_view("::1:2:3:4:5:6:1.2.3.4"), 80, &address));
}
TEST(AddressFromIpv6, ZoneIdNumeric) {
// Numeric zone ID maps directly to sin6_scope_id.
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_ipv6(
iree_make_cstring_view("fe80::1%3"), 80, &address));
EXPECT_EQ(FormatAddress(address), "[fe80::1%3]:80");
}
TEST(AddressFromIpv6, ZoneIdZeroNotFormatted) {
// No zone suffix → scope_id is 0 → no % in output.
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_ipv6(iree_make_cstring_view("fe80::1"),
80, &address));
EXPECT_EQ(FormatAddress(address), "[fe80::1]:80");
}
TEST(AddressFromIpv6, ZoneIdEmpty) {
// Trailing % with no zone ID is invalid.
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(
iree_make_cstring_view("fe80::1%"), 80, &address));
}
TEST(AddressFromIpv6, ZoneIdLargeNumeric) {
// Large numeric scope_id.
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_ipv6(
iree_make_cstring_view("fe80::1%42"), 80, &address));
EXPECT_EQ(FormatAddress(address), "[fe80::1%42]:80");
}
#if defined(IREE_PLATFORM_LINUX)
TEST(AddressFromIpv6, ZoneIdInterfaceName) {
// "lo" exists on all Linux systems — resolves to a non-zero interface index.
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_ipv6(
iree_make_cstring_view("fe80::1%lo"), 80, &address));
// The formatted output uses the numeric index, not the name.
std::string formatted = FormatAddress(address);
// Should start with [fe80::1% and end with ]:80.
EXPECT_TRUE(formatted.find("[fe80::1%") == 0);
EXPECT_TRUE(formatted.find("]:80") != std::string::npos);
}
TEST(AddressFromIpv6, ZoneIdUnknownInterface) {
// Non-existent interface name (must be < IF_NAMESIZE = 16 chars).
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_NOT_FOUND,
iree_async_address_from_ipv6(iree_make_cstring_view("fe80::1%noif0"), 80,
&address));
}
TEST(AddressFromIpv6, ZoneIdInterfaceNameTooLong) {
// Interface name exceeding IF_NAMESIZE (16 bytes on Linux).
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_ipv6(
iree_make_cstring_view("fe80::1%this_name_is_way_too_long"), 80,
&address));
}
#endif // IREE_PLATFORM_LINUX
//===----------------------------------------------------------------------===//
// Unix Socket Parsing
//===----------------------------------------------------------------------===//
#if !defined(IREE_PLATFORM_GENERIC) && !defined(IREE_PLATFORM_WASM)
TEST(AddressFromUnix, SimplePath) {
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_unix(
iree_make_cstring_view("/tmp/socket.sock"), &address));
EXPECT_EQ(FormatAddress(address), "unix:/tmp/socket.sock");
}
TEST(AddressFromUnix, RelativePath) {
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_unix(
iree_make_cstring_view("./relative.sock"), &address));
EXPECT_EQ(FormatAddress(address), "unix:./relative.sock");
}
TEST(AddressFromUnix, EmptyPathRejected) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_unix(iree_string_view_empty(), &address));
}
TEST(AddressFromUnix, PathTooLong) {
// sun_path is typically 104 (macOS) or 108 (Linux) bytes.
// A 200-byte path should exceed the limit on all platforms.
std::string long_path(200, 'x');
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_unix(
iree_make_string_view(long_path.data(), long_path.size()), &address));
}
TEST(AddressFromUnix, MaxLengthPath) {
// Create a path that is exactly the maximum length (sizeof(sun_path) - 1).
// We test with 103 bytes which fits on both Linux (107 max) and macOS (103
// max).
std::string max_path(103, 'a');
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_unix(
iree_make_string_view(max_path.data(), max_path.size()), &address));
EXPECT_EQ(FormatAddress(address), "unix:" + max_path);
}
#if defined(IREE_PLATFORM_LINUX) || defined(IREE_PLATFORM_ANDROID)
TEST(AddressFromUnix, AbstractNamespace) {
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_unix(
iree_make_cstring_view("@my-abstract-socket"), &address));
EXPECT_EQ(FormatAddress(address), "unix:@my-abstract-socket");
}
TEST(AddressFromUnix, AbstractNamespaceEmpty) {
// "@" alone means abstract namespace with an empty name (just the NUL byte).
iree_async_address_t address;
IREE_EXPECT_OK(
iree_async_address_from_unix(iree_make_cstring_view("@"), &address));
EXPECT_EQ(FormatAddress(address), "unix:@");
}
#else // !IREE_PLATFORM_LINUX && !IREE_PLATFORM_ANDROID
TEST(AddressFromUnix, AbstractNamespaceUnavailable) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_UNAVAILABLE,
iree_async_address_from_unix(
iree_make_cstring_view("@abstract"), &address));
}
#endif // IREE_PLATFORM_LINUX || IREE_PLATFORM_ANDROID
TEST(AddressFormat, UnixPathWithoutTrailingNulInLength) {
// Construct a valid Unix address via the normal API, then simulate what
// getsockname() returns: the socklen_t may not include the trailing NUL byte.
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_unix(
iree_make_cstring_view("/tmp/test.sock"), &address));
// Subtract 1 from the stored length (drop the NUL from the count).
address.length -= 1;
// Format should still produce the correct path.
EXPECT_EQ(FormatAddress(address), "unix:/tmp/test.sock");
}
#endif // !IREE_PLATFORM_GENERIC && !IREE_PLATFORM_WASM
//===----------------------------------------------------------------------===//
// Format — Buffer Capacity
//===----------------------------------------------------------------------===//
TEST(AddressFormat, BufferExactSize) {
auto address = ParseIPv4("1.2.3.4", 80);
// "1.2.3.4:80" = 10 chars.
char buffer[10];
iree_string_view_t value = iree_string_view_empty();
IREE_EXPECT_OK(
iree_async_address_format(&address, sizeof(buffer), buffer, &value));
EXPECT_EQ(std::string(value.data, value.size), "1.2.3.4:80");
}
TEST(AddressFormat, BufferTooSmall) {
auto address = ParseIPv4("127.0.0.1", 8080);
// "127.0.0.1:8080" = 14 chars. Provide only 5.
char buffer[5];
iree_string_view_t value = iree_string_view_empty();
IREE_EXPECT_STATUS_IS(
IREE_STATUS_OUT_OF_RANGE,
iree_async_address_format(&address, sizeof(buffer), buffer, &value));
}
TEST(AddressFormat, BufferCapacityZero) {
auto address = ParseIPv4("1.2.3.4", 80);
iree_string_view_t value = iree_string_view_empty();
IREE_EXPECT_STATUS_IS(IREE_STATUS_OUT_OF_RANGE,
iree_async_address_format(&address, 0, NULL, &value));
}
TEST(AddressFormat, OversizedBuffer) {
auto address = ParseIPv4("10.0.0.1", 443);
char buffer[256];
iree_string_view_t value = iree_string_view_empty();
IREE_EXPECT_OK(
iree_async_address_format(&address, sizeof(buffer), buffer, &value));
EXPECT_EQ(std::string(value.data, value.size), "10.0.0.1:443");
// Value points into the buffer.
EXPECT_EQ(value.data, buffer);
}
TEST(AddressFormat, OutValueNull) {
auto address = ParseIPv4("1.2.3.4", 80);
char buffer[64];
// out_value is NULL — should still succeed without writing the view.
IREE_EXPECT_OK(iree_async_address_format(&address, sizeof(buffer), buffer,
/*out_value=*/NULL));
}
TEST(AddressFormat, EmptyAddress) {
iree_async_address_t address;
memset(&address, 0, sizeof(address));
char buffer[64];
iree_string_view_t value = iree_string_view_empty();
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_format(&address, sizeof(buffer), buffer, &value));
}
//===----------------------------------------------------------------------===//
// Format — IPv6 Specific
//===----------------------------------------------------------------------===//
TEST(AddressFormat, Ipv6Loopback) {
auto address = ParseIPv6("::1", 80);
char buffer[64];
iree_string_view_t value = iree_string_view_empty();
IREE_EXPECT_OK(
iree_async_address_format(&address, sizeof(buffer), buffer, &value));
EXPECT_EQ(std::string(value.data, value.size), "[::1]:80");
}
TEST(AddressFormat, Ipv6Any) {
auto address = ParseIPv6("::", 0);
char buffer[64];
iree_string_view_t value = iree_string_view_empty();
IREE_EXPECT_OK(
iree_async_address_format(&address, sizeof(buffer), buffer, &value));
EXPECT_EQ(std::string(value.data, value.size), "[::]:0");
}
TEST(AddressFormat, Ipv6Mapped) {
auto address = ParseIPv6("::ffff:10.0.0.1", 9090);
char buffer[64];
iree_string_view_t value = iree_string_view_empty();
IREE_EXPECT_OK(
iree_async_address_format(&address, sizeof(buffer), buffer, &value));
EXPECT_EQ(std::string(value.data, value.size), "[::ffff:10.0.0.1]:9090");
}
TEST(AddressFormat, TruncatedLengthTooShort) {
// Address with length=1 is too short for any valid sockaddr family header.
iree_async_address_t address;
memset(&address, 0, sizeof(address));
address.length = 1;
char buffer[IREE_ASYNC_ADDRESS_MAX_FORMAT_LENGTH];
iree_string_view_t formatted = iree_string_view_empty();
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_format(&address, sizeof(buffer), buffer, &formatted));
}
//===----------------------------------------------------------------------===//
// Round-Trip Tests
//===----------------------------------------------------------------------===//
TEST(AddressRoundTrip, Ipv4Loopback) {
auto address = ParseIPv4("127.0.0.1", 8080);
EXPECT_EQ(FormatAddress(address), "127.0.0.1:8080");
}
TEST(AddressRoundTrip, Ipv4Any) {
iree_async_address_t address;
IREE_EXPECT_OK(
iree_async_address_from_ipv4(iree_string_view_empty(), 0, &address));
EXPECT_EQ(FormatAddress(address), "0.0.0.0:0");
}
TEST(AddressRoundTrip, Ipv6Compressed) {
auto address = ParseIPv6("2001:db8::1", 443);
EXPECT_EQ(FormatAddress(address), "[2001:db8::1]:443");
}
TEST(AddressRoundTrip, Ipv6Full) {
auto address = ParseIPv6("2001:db8:85a3:0:0:8a2e:370:7334", 80);
EXPECT_EQ(FormatAddress(address), "[2001:db8:85a3::8a2e:370:7334]:80");
}
TEST(AddressRoundTrip, Ipv6AllOnes) {
auto address = ParseIPv6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 1);
EXPECT_EQ(FormatAddress(address),
"[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:1");
}
#if !defined(IREE_PLATFORM_GENERIC) && !defined(IREE_PLATFORM_WASM)
TEST(AddressRoundTrip, UnixFilesystem) {
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_unix(
iree_make_cstring_view("/var/run/daemon.sock"), &address));
EXPECT_EQ(FormatAddress(address), "unix:/var/run/daemon.sock");
}
#endif // !IREE_PLATFORM_GENERIC && !IREE_PLATFORM_WASM
//===----------------------------------------------------------------------===//
// AddressFromString — Valid IPv4
//===----------------------------------------------------------------------===//
// Helper: parse from string and return the address (or fail the test).
static iree_async_address_t ParseFromString(const char* address_str) {
iree_async_address_t address;
IREE_EXPECT_OK(iree_async_address_from_string(
iree_make_cstring_view(address_str), &address));
return address;
}
TEST(AddressFromString, Ipv4Loopback) {
auto address = ParseFromString("127.0.0.1:80");
EXPECT_EQ(FormatAddress(address), "127.0.0.1:80");
}
TEST(AddressFromString, Ipv4AllZeros) {
auto address = ParseFromString("0.0.0.0:0");
EXPECT_EQ(FormatAddress(address), "0.0.0.0:0");
}
TEST(AddressFromString, Ipv4MaxValues) {
auto address = ParseFromString("255.255.255.255:65535");
EXPECT_EQ(FormatAddress(address), "255.255.255.255:65535");
}
TEST(AddressFromString, Ipv4EmptyHostIsAny) {
auto address = ParseFromString(":8080");
EXPECT_EQ(FormatAddress(address), "0.0.0.0:8080");
}
TEST(AddressFromString, Ipv4TypicalServer) {
auto address = ParseFromString("10.0.0.1:443");
EXPECT_EQ(FormatAddress(address), "10.0.0.1:443");
}
TEST(AddressFromString, Ipv4EphemeralPort) {
auto address = ParseFromString("192.168.1.1:0");
EXPECT_EQ(FormatAddress(address), "192.168.1.1:0");
}
//===----------------------------------------------------------------------===//
// AddressFromString — Valid IPv6
//===----------------------------------------------------------------------===//
TEST(AddressFromString, Ipv6Loopback) {
auto address = ParseFromString("[::1]:80");
EXPECT_EQ(FormatAddress(address), "[::1]:80");
}
TEST(AddressFromString, Ipv6Any) {
auto address = ParseFromString("[::]:0");
EXPECT_EQ(FormatAddress(address), "[::]:0");
}
TEST(AddressFromString, Ipv6Compressed) {
auto address = ParseFromString("[2001:db8::1]:443");
EXPECT_EQ(FormatAddress(address), "[2001:db8::1]:443");
}
TEST(AddressFromString, Ipv6Ipv4Mapped) {
auto address = ParseFromString("[::ffff:192.168.1.1]:8080");
EXPECT_EQ(FormatAddress(address), "[::ffff:192.168.1.1]:8080");
}
TEST(AddressFromString, Ipv6ZoneId) {
auto address = ParseFromString("[fe80::1%3]:80");
EXPECT_EQ(FormatAddress(address), "[fe80::1%3]:80");
}
TEST(AddressFromString, Ipv6NonCanonicalInput) {
// Leading zeros in groups are accepted but not preserved in output.
auto address = ParseFromString("[2001:0db8::1]:80");
EXPECT_EQ(FormatAddress(address), "[2001:db8::1]:80");
}
TEST(AddressFromString, Ipv6Full) {
auto address = ParseFromString("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:1");
EXPECT_EQ(FormatAddress(address),
"[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:1");
}
TEST(AddressFromString, Ipv6MaxPort) {
auto address = ParseFromString("[::1]:65535");
EXPECT_EQ(FormatAddress(address), "[::1]:65535");
}
TEST(AddressFromString, Ipv6EmptyBrackets) {
// Empty brackets with port — from_ipv6 treats empty host as in6addr_any.
auto address = ParseFromString("[]:0");
EXPECT_EQ(FormatAddress(address), "[::]:0");
}
//===----------------------------------------------------------------------===//
// AddressFromString — Valid Unix
//===----------------------------------------------------------------------===//
#if !defined(IREE_PLATFORM_GENERIC) && !defined(IREE_PLATFORM_WASM)
TEST(AddressFromString, UnixFilesystem) {
auto address = ParseFromString("unix:/tmp/socket.sock");
EXPECT_EQ(FormatAddress(address), "unix:/tmp/socket.sock");
}
TEST(AddressFromString, UnixRelativePath) {
auto address = ParseFromString("unix:./relative.sock");
EXPECT_EQ(FormatAddress(address), "unix:./relative.sock");
}
#if defined(IREE_PLATFORM_LINUX) || defined(IREE_PLATFORM_ANDROID)
TEST(AddressFromString, UnixAbstract) {
auto address = ParseFromString("unix:@my-socket");
EXPECT_EQ(FormatAddress(address), "unix:@my-socket");
}
#endif // IREE_PLATFORM_LINUX || IREE_PLATFORM_ANDROID
#endif // !IREE_PLATFORM_GENERIC && !IREE_PLATFORM_WASM
//===----------------------------------------------------------------------===//
// AddressFromString — Error Cases
//===----------------------------------------------------------------------===//
TEST(AddressFromString, Empty) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(iree_string_view_empty(), &address));
}
TEST(AddressFromString, Ipv4MissingPort) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("127.0.0.1"), &address));
}
TEST(AddressFromString, Ipv4EmptyPort) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("127.0.0.1:"), &address));
}
TEST(AddressFromString, Ipv4NonNumericPort) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("127.0.0.1:abc"), &address));
}
TEST(AddressFromString, Ipv4PortOverflow) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(iree_make_cstring_view("127.0.0.1:99999"),
&address));
}
TEST(AddressFromString, Ipv4PortLeadingZeros) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("127.0.0.1:080"), &address));
}
TEST(AddressFromString, Ipv4PortLeadingZeroDouble) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("127.0.0.1:00"), &address));
}
TEST(AddressFromString, NoColonAtAll) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("just_a_word"), &address));
}
TEST(AddressFromString, Ipv6MissingCloseBracket) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(iree_make_cstring_view("[::1"), &address));
}
TEST(AddressFromString, Ipv6NoPortAfterBracket) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("[::1]"), &address));
}
TEST(AddressFromString, Ipv6MissingColonAfterBracket) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("[::1]80"), &address));
}
TEST(AddressFromString, Ipv6EmptyPort) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("[::1]:"), &address));
}
TEST(AddressFromString, Ipv6NonNumericPort) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("[::1]:abc"), &address));
}
TEST(AddressFromString, Ipv6PortOverflow) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("[::1]:99999"), &address));
}
TEST(AddressFromString, Ipv6PortLeadingZeros) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("[::1]:080"), &address));
}
#if !defined(IREE_PLATFORM_GENERIC) && !defined(IREE_PLATFORM_WASM)
TEST(AddressFromString, UnixEmptyPath) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("unix:"), &address));
}
#endif // !IREE_PLATFORM_GENERIC && !IREE_PLATFORM_WASM
TEST(AddressFromString, Ipv4BadHost) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("1.2.3.4.5:80"), &address));
}
TEST(AddressFromString, Ipv6BadHost) {
iree_async_address_t address;
IREE_EXPECT_STATUS_IS(
IREE_STATUS_INVALID_ARGUMENT,
iree_async_address_from_string(
iree_make_cstring_view("[2001::db8::1]:80"), &address));
}
//===----------------------------------------------------------------------===//
// AddressFromString — Round-Trip Tests
//===----------------------------------------------------------------------===//
// Helper: parse → format → parse → format, verify the two formatted strings
// match. This validates that the canonical form is stable.
static void VerifyRoundTrip(const char* input) {
iree_async_address_t address1;
IREE_ASSERT_OK(
iree_async_address_from_string(iree_make_cstring_view(input), &address1));
std::string formatted1 = FormatAddress(address1);
ASSERT_NE(formatted1, "<format failed>") << "First format failed";
iree_async_address_t address2;
IREE_ASSERT_OK(iree_async_address_from_string(
iree_make_string_view(formatted1.data(), formatted1.size()), &address2));
std::string formatted2 = FormatAddress(address2);
EXPECT_EQ(formatted1, formatted2)
<< "Round-trip failed for input '" << input << "'";
}
TEST(AddressFromStringRoundTrip, Ipv4Loopback) {
VerifyRoundTrip("127.0.0.1:8080");
}
TEST(AddressFromStringRoundTrip, Ipv4Any) { VerifyRoundTrip(":0"); }
TEST(AddressFromStringRoundTrip, Ipv4Max) {
VerifyRoundTrip("255.255.255.255:65535");
}
TEST(AddressFromStringRoundTrip, Ipv6Loopback) { VerifyRoundTrip("[::1]:80"); }
TEST(AddressFromStringRoundTrip, Ipv6Compressed) {
VerifyRoundTrip("[2001:db8::1]:443");
}
TEST(AddressFromStringRoundTrip, Ipv6Full) {
VerifyRoundTrip("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:1");
}
TEST(AddressFromStringRoundTrip, Ipv6Mapped) {
VerifyRoundTrip("[::ffff:10.0.0.1]:9090");
}
TEST(AddressFromStringRoundTrip, Ipv6ZoneId) {
VerifyRoundTrip("[fe80::1%42]:80");
}
#if !defined(IREE_PLATFORM_GENERIC) && !defined(IREE_PLATFORM_WASM)
TEST(AddressFromStringRoundTrip, UnixPath) {
VerifyRoundTrip("unix:/var/run/daemon.sock");
}
#if defined(IREE_PLATFORM_LINUX) || defined(IREE_PLATFORM_ANDROID)
TEST(AddressFromStringRoundTrip, UnixAbstract) {
VerifyRoundTrip("unix:@my-abstract-socket");
}
#endif // IREE_PLATFORM_LINUX || IREE_PLATFORM_ANDROID
#endif // !IREE_PLATFORM_GENERIC && !IREE_PLATFORM_WASM
} // namespace