commit 7ea8f842bc65cdaf046483b2bfe7948ebad16516 (tree)
parent 3e1e625814165d9d9282f3cd89bc117cf1b6d61c
Author: Alex Rønne Petersen <alex@alexrp.com>
Date: Fri, 27 Mar 2026 11:14:02 +0100
libzigc: move all unit tests from lib/c/ to test/c/
Before:
* test-zigc: run libzigc unit tests (part of test-modules)
* test-libc: run libc-test cases
Now:
* test-libc: run libc API unit tests (part of test-modules)
* test-libc-nsz: run libc-test cases
libc API unit tests (previously referred to as libzigc unit tests) now run for
all supported targets, even those we don't provide libzigc for. The idea is that
this will help us catch bad assumptions in the unit tests, as well as bugs in
other libcs.
I considered this setup:
* test-c: run libc API unit tests (part of test-modules)
* test-libc-nsz: run libc-test cases
* test-libc: both of the above
However, I do not like it because it gives a false sense of security; the full
module and C ABI test suites are still liable to catch libzigc bugs that test-c
and test-libc-nsz might not. So contributors should just run the test steps
outlined in https://codeberg.org/ziglang/zig/issues/30978.
Co-authored-by: rpkak <rpkak@noreply.codeberg.org>
Diffstat:
21 files changed, 530 insertions(+), 430 deletions(-)
diff --git a/build.zig b/build.zig
@@ -526,16 +526,16 @@ pub fn build(b: *std.Build) !void {
.test_filters = test_filters,
.test_target_filters = test_target_filters,
.test_extra_targets = test_extra_targets,
- .root_src = "lib/c.zig",
- .name = "zigc",
- .desc = "Run the zig libc implementation unit tests",
+ .root_src = "lib/std/std.zig",
+ .name = "std",
+ .desc = "Run the standard library tests",
.optimize_modes = optimization_modes,
.include_paths = &.{},
.sanitize_thread = sanitize_thread,
- .skip_single_threaded = true,
+ .skip_single_threaded = skip_single_threaded,
.skip_non_native = skip_non_native,
.test_only = test_only,
- .skip_spirv = skip_spirv,
+ .skip_spirv = true,
.skip_wasm = skip_wasm,
.skip_freebsd = skip_freebsd,
.skip_netbsd = skip_netbsd,
@@ -544,25 +544,24 @@ pub fn build(b: *std.Build) !void {
.skip_darwin = skip_darwin,
.skip_linux = skip_linux,
.skip_llvm = skip_llvm,
- .skip_libc = true,
- .no_builtin = true,
- .max_rss = 4_000_000_000,
+ .skip_libc = skip_libc,
+ .max_rss = 9_300_000_000,
}));
test_modules_step.dependOn(tests.addModuleTests(b, .{
.test_filters = test_filters,
.test_target_filters = test_target_filters,
.test_extra_targets = test_extra_targets,
- .root_src = "lib/std/std.zig",
- .name = "std",
- .desc = "Run the standard library tests",
+ .root_src = "test/c.zig",
+ .name = "libc",
+ .desc = "Run the libc API tests",
.optimize_modes = optimization_modes,
.include_paths = &.{},
.sanitize_thread = sanitize_thread,
- .skip_single_threaded = skip_single_threaded,
+ .skip_single_threaded = true,
.skip_non_native = skip_non_native,
.test_only = test_only,
- .skip_spirv = skip_spirv,
+ .skip_spirv = true,
.skip_wasm = skip_wasm,
.skip_freebsd = skip_freebsd,
.skip_netbsd = skip_netbsd,
@@ -572,7 +571,8 @@ pub fn build(b: *std.Build) !void {
.skip_linux = skip_linux,
.skip_llvm = skip_llvm,
.skip_libc = skip_libc,
- .max_rss = 9_300_000_000,
+ .no_builtin = true,
+ .max_rss = 4_000_000_000,
}));
const unit_tests_step = b.step("test-unit", "Run the compiler source unit tests");
@@ -662,13 +662,13 @@ pub fn build(b: *std.Build) !void {
try tests.addIncrementalTests(b, test_incremental_step, test_filters);
if (!skip_test_incremental) test_step.dependOn(test_incremental_step);
- if (tests.addLibcTests(b, .{
+ if (tests.addLibcTestNszTests(b, .{
.optimize_modes = optimization_modes,
.test_filters = test_filters,
.test_target_filters = test_target_filters,
.skip_wasm = skip_wasm,
.max_rss = 3_500_000_000,
- })) |test_libc_step| test_step.dependOn(test_libc_step);
+ })) |test_libc_nsz_step| test_step.dependOn(test_libc_nsz_step);
}
fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
diff --git a/lib/c.zig b/lib/c.zig
@@ -2,8 +2,7 @@
//! bundled libcs.
//!
//! mingw-w64 libc is not fully statically linked, so some symbols don't need
-//! to be exported. However, a future enhancement could be eliminating Zig's
-//! dependency on msvcrt dll even when linking libc and targeting Windows.
+//! to be exported.
const builtin = @import("builtin");
const std = @import("std");
diff --git a/lib/c/inttypes.zig b/lib/c/inttypes.zig
@@ -24,13 +24,3 @@ fn imaxdiv(a: intmax_t, b: intmax_t) callconv(.c) imaxdiv_t {
.rem = @rem(a, b),
};
}
-
-test imaxabs {
- const val: intmax_t = -10;
- try std.testing.expectEqual(10, imaxabs(val));
-}
-
-test imaxdiv {
- const expected: imaxdiv_t = .{ .quot = 9, .rem = 0 };
- try std.testing.expectEqual(expected, imaxdiv(9, 1));
-}
diff --git a/lib/c/math.zig b/lib/c/math.zig
@@ -2,10 +2,6 @@ const builtin = @import("builtin");
const std = @import("std");
const math = std.math;
-const expect = std.testing.expect;
-const expectEqual = std.testing.expectEqual;
-const expectApproxEqAbs = std.testing.expectApproxEqAbs;
-const expectApproxEqRel = std.testing.expectApproxEqRel;
const symbol = @import("../c.zig").symbol;
@@ -304,59 +300,6 @@ fn modfl(x: c_longdouble, iptr: *c_longdouble) callconv(.c) c_longdouble {
};
}
-fn testModf(comptime T: type) !void {
- // Choose the appropriate `modf` impl to test based on type
- const f = switch (T) {
- f32 => modff,
- f64 => modf,
- c_longdouble => modfl,
- else => @compileError("modf not implemented for " ++ @typeName(T)),
- };
-
- var int: T = undefined;
- const iptr = ∫
- const eps_val: comptime_float = @max(1e-6, math.floatEps(T));
-
- const normal_frac = f(@as(T, 1234.567), iptr);
- // Account for precision error
- const expected = 1234.567 - @as(T, 1234);
- try expectApproxEqAbs(expected, normal_frac, eps_val);
- try expectApproxEqRel(@as(T, 1234.0), iptr.*, eps_val);
-
- // When `x` is a NaN, NaN is returned and `*iptr` is set to NaN
- const nan_frac = f(math.nan(T), iptr);
- try expect(math.isNan(nan_frac));
- try expect(math.isNan(iptr.*));
-
- // When `x` is positive infinity, +0 is returned and `*iptr` is set to
- // positive infinity
- const pos_zero_frac = f(math.inf(T), iptr);
- try expect(math.isPositiveZero(pos_zero_frac));
- try expect(math.isPositiveInf(iptr.*));
-
- // When `x` is negative infinity, -0 is returned and `*iptr` is set to
- // negative infinity
- const neg_zero_frac = f(-math.inf(T), iptr);
- try expect(math.isNegativeZero(neg_zero_frac));
- try expect(math.isNegativeInf(iptr.*));
-
- // Return -0 when `x` is a negative integer
- const nz_frac = f(@as(T, -1000.0), iptr);
- try expect(math.isNegativeZero(nz_frac));
- try expectEqual(@as(T, -1000.0), iptr.*);
-
- // Return +0 when `x` is a positive integer
- const pz_frac = f(@as(T, 1000.0), iptr);
- try expect(math.isPositiveZero(pz_frac));
- try expectEqual(@as(T, 1000.0), iptr.*);
-}
-
-test "modf" {
- try testModf(f32);
- try testModf(f64);
- try testModf(c_longdouble);
-}
-
fn nan(_: [*:0]const c_char) callconv(.c) f64 {
return math.nan(f64);
}
@@ -421,49 +364,6 @@ fn rintf(x: f32) callconv(.c) f32 {
return y;
}
-fn testRint(comptime T: type) !void {
- const f = switch (T) {
- f32 => rintf,
- f64 => rint,
- else => @compileError("rint not implemented for" ++ @typeName(T)),
- };
-
- // Positive numbers round correctly
- try expectEqual(@as(T, 42.0), f(42.2));
- try expectEqual(@as(T, 42.0), f(41.8));
-
- // Negative numbers round correctly
- try expectEqual(@as(T, -6.0), f(-5.9));
- try expectEqual(@as(T, -6.0), f(-6.1));
-
- // No rounding needed test
- try expectEqual(@as(T, 5.0), f(5.0));
- try expectEqual(@as(T, -10.0), f(-10.0));
- try expectEqual(@as(T, 0.0), f(0.0));
-
- // Very large numbers return unchanged
- const large: T = 9007199254740992.0; // 2^53
- try expectEqual(large, f(large));
- try expectEqual(-large, f(-large));
-
- // Small positive numbers round to zero
- const pos_result = f(0.3);
- try expect(math.isPositiveZero(pos_result));
-
- // Small negative numbers round to negative zero
- const neg_result = f(-0.3);
- try expect(math.isNegativeZero(neg_result));
-
- // Exact half rounds to nearest even (banker's rounding)
- try expectEqual(@as(T, 2.0), f(2.5));
- try expectEqual(@as(T, 4.0), f(3.5));
-}
-
-test "rint" {
- try testRint(f32);
- try testRint(f64);
-}
-
fn tanh(x: f64) callconv(.c) f64 {
return math.tanh(x);
}
diff --git a/lib/c/search.zig b/lib/c/search.zig
@@ -9,6 +9,7 @@ comptime {
}
}
+/// Not defined in `std.c` because C headers don't either.
const Node = extern struct {
next: ?*Node,
prev: ?*Node,
@@ -38,30 +39,3 @@ fn remque(element: *anyopaque) callconv(.c) void {
if (e.next) |next| next.prev = e.prev;
if (e.prev) |prev| prev.next = e.next;
}
-
-test "insque and remque" {
- var first = Node{ .next = null, .prev = null };
- var second = Node{ .next = null, .prev = null };
- var third = Node{ .next = null, .prev = null };
-
- insque(&first, null);
- try std.testing.expectEqual(@as(?*Node, null), first.next);
- try std.testing.expectEqual(@as(?*Node, null), first.prev);
-
- insque(&second, &first);
- try std.testing.expectEqual(@as(?*Node, &second), first.next);
- try std.testing.expectEqual(@as(?*Node, &first), second.prev);
-
- insque(&third, &first);
- try std.testing.expectEqual(@as(?*Node, &third), first.next);
- try std.testing.expectEqual(@as(?*Node, &second), third.next);
- try std.testing.expectEqual(@as(?*Node, &first), third.prev);
- try std.testing.expectEqual(@as(?*Node, &third), second.prev);
-
- remque(&third);
- try std.testing.expectEqual(@as(?*Node, &second), first.next);
- try std.testing.expectEqual(@as(?*Node, &first), second.prev);
-
- remque(&second);
- try std.testing.expectEqual(@as(?*Node, null), first.next);
-}
diff --git a/lib/c/stdlib.zig b/lib/c/stdlib.zig
@@ -294,103 +294,3 @@ fn bsearch(key: *const anyopaque, base: *const anyopaque, n: usize, size: usize,
}
return null;
}
-
-test abs {
- const val: c_int = -10;
- try std.testing.expectEqual(10, abs(val));
-}
-
-test labs {
- const val: c_long = -10;
- try std.testing.expectEqual(10, labs(val));
-}
-
-test llabs {
- const val: c_longlong = -10;
- try std.testing.expectEqual(10, llabs(val));
-}
-
-test div {
- const expected: div_t = .{ .quot = 5, .rem = 5 };
- try std.testing.expectEqual(expected, div(55, 10));
-}
-
-test ldiv {
- const expected: ldiv_t = .{ .quot = -6, .rem = 2 };
- try std.testing.expectEqual(expected, ldiv(38, -6));
-}
-
-test lldiv {
- const expected: lldiv_t = .{ .quot = 1, .rem = 2 };
- try std.testing.expectEqual(expected, lldiv(5, 3));
-}
-
-test atoi {
- try std.testing.expectEqual(0, atoi(@ptrCast("stop42true")));
- try std.testing.expectEqual(42, atoi(@ptrCast("42true")));
- try std.testing.expectEqual(-1, atoi(@ptrCast("-01")));
- try std.testing.expectEqual(1, atoi(@ptrCast("+001")));
- try std.testing.expectEqual(100, atoi(@ptrCast(" 100")));
- try std.testing.expectEqual(500, atoi(@ptrCast("000000000000500")));
- try std.testing.expectEqual(1111, atoi(@ptrCast("0000000000001111_0000")));
- try std.testing.expectEqual(0, atoi(@ptrCast("0xAA")));
- try std.testing.expectEqual(700, atoi(@ptrCast("700B")));
- try std.testing.expectEqual(32453, atoi(@ptrCast("+32453more")));
- try std.testing.expectEqual(std.math.maxInt(c_int), atoi(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.maxInt(c_int)}))));
- try std.testing.expectEqual(std.math.minInt(c_int), atoi(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.minInt(c_int)}))));
-}
-
-test atol {
- try std.testing.expectEqual(0, atol(@ptrCast("stop42true")));
- try std.testing.expectEqual(42, atol(@ptrCast("42true")));
- try std.testing.expectEqual(-1, atol(@ptrCast("-01")));
- try std.testing.expectEqual(1, atol(@ptrCast("+001")));
- try std.testing.expectEqual(100, atol(@ptrCast(" 100")));
- try std.testing.expectEqual(500, atol(@ptrCast("000000000000500")));
- try std.testing.expectEqual(1111, atol(@ptrCast("0000000000001111_0000")));
- try std.testing.expectEqual(0, atol(@ptrCast("0xAA")));
- try std.testing.expectEqual(700, atol(@ptrCast("700B")));
- try std.testing.expectEqual(32453, atol(@ptrCast("+32453more")));
- try std.testing.expectEqual(std.math.maxInt(c_long), atol(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.maxInt(c_long)}))));
- try std.testing.expectEqual(std.math.minInt(c_long), atol(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.minInt(c_long)}))));
-}
-
-test atoll {
- try std.testing.expectEqual(0, atoll(@ptrCast("stop42true")));
- try std.testing.expectEqual(42, atoll(@ptrCast("42true")));
- try std.testing.expectEqual(-1, atoll(@ptrCast("-01")));
- try std.testing.expectEqual(1, atoll(@ptrCast("+001")));
- try std.testing.expectEqual(100, atoll(@ptrCast(" 100")));
- try std.testing.expectEqual(500, atoll(@ptrCast("000000000000500")));
- try std.testing.expectEqual(1111, atoll(@ptrCast("0000000000001111_0000")));
- try std.testing.expectEqual(0, atoll(@ptrCast("0xAA")));
- try std.testing.expectEqual(700, atoll(@ptrCast("700B")));
- try std.testing.expectEqual(32453, atoll(@ptrCast(" +32453more")));
- try std.testing.expectEqual(std.math.maxInt(c_longlong), atoll(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.maxInt(c_longlong)}))));
- try std.testing.expectEqual(std.math.minInt(c_longlong), atoll(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.minInt(c_longlong)}))));
-}
-
-// FIXME: We cannot test strtol, strtoll, strtoul, etc.. here as it must modify errno and libc is not linked in tests
-
-test bsearch {
- const Comparison = struct {
- pub fn compare(a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int {
- const a_u16: *const u16 = @ptrCast(@alignCast(a));
- const b_u16: *const u16 = @ptrCast(@alignCast(b));
-
- return switch (std.math.order(a_u16.*, b_u16.*)) {
- .gt => 1,
- .eq => 0,
- .lt => -1,
- };
- }
- };
-
- const items: []const u16 = &.{ 0, 5, 7, 9, 10, 200, 512, 768 };
-
- try std.testing.expectEqual(@as(?*anyopaque, null), bsearch(&@as(u16, 2000), items.ptr, items.len, @sizeOf(u16), Comparison.compare));
-
- for (items) |*value| {
- try std.testing.expectEqual(@as(*const anyopaque, value), bsearch(value, items.ptr, items.len, @sizeOf(u16), Comparison.compare));
- }
-}
diff --git a/lib/c/stdlib/drand48.zig b/lib/c/stdlib/drand48.zig
@@ -90,60 +90,3 @@ fn srand48(seedval: c_long) callconv(.c) void {
const xi = (@as(u32, @truncate(@as(c_ulong, @bitCast(seedval)))) << 16) | 0x330E;
lcg = .init(xi, default_multiplier, default_addend);
}
-
-test erand48 {
- var xsubi: [3]c_ushort = .{ 37174, 64810, 11603 };
-
- try std.testing.expectApproxEqAbs(0.8965, erand48(&xsubi), 0.0005);
- try std.testing.expectEqualSlices(c_ushort, &.{ 22537, 47966, 58735 }, &xsubi);
-
- try std.testing.expectApproxEqAbs(0.3375, erand48(&xsubi), 0.0005);
- try std.testing.expectEqualSlices(c_ushort, &.{ 37344, 32911, 22119 }, &xsubi);
-
- try std.testing.expectApproxEqAbs(0.6475, erand48(&xsubi), 0.0005);
- try std.testing.expectEqualSlices(c_ushort, &.{ 23659, 29872, 42445 }, &xsubi);
-
- try std.testing.expectApproxEqAbs(0.5005, erand48(&xsubi), 0.0005);
- try std.testing.expectEqualSlices(c_ushort, &.{ 31642, 7875, 32802 }, &xsubi);
-
- try std.testing.expectApproxEqAbs(0.5065, erand48(&xsubi), 0.0005);
- try std.testing.expectEqualSlices(c_ushort, &.{ 64669, 14399, 33170 }, &xsubi);
-}
-
-test jrand48 {
- var xsubi: [3]c_ushort = .{ 25175, 11052, 45015 };
-
- try std.testing.expectEqual(1699503220, jrand48(&xsubi));
- try std.testing.expectEqualSlices(c_ushort, &.{ 2326, 23668, 25932 }, &xsubi);
-
- try std.testing.expectEqual(-992276007, jrand48(&xsubi));
- try std.testing.expectEqualSlices(c_ushort, &.{ 41577, 4569, 50395 }, &xsubi);
-
- try std.testing.expectEqual(-19535776, jrand48(&xsubi));
- try std.testing.expectEqualSlices(c_ushort, &.{ 31936, 59488, 65237 }, &xsubi);
-
- try std.testing.expectEqual(79438377, jrand48(&xsubi));
- try std.testing.expectEqualSlices(c_ushort, &.{ 40395, 8745, 1212 }, &xsubi);
-
- try std.testing.expectEqual(-1258917728, jrand48(&xsubi));
- try std.testing.expectEqualSlices(c_ushort, &.{ 37242, 28832, 46326 }, &xsubi);
-}
-
-test nrand48 {
- var xsubi: [3]c_ushort = .{ 546, 33817, 23389 };
-
- try std.testing.expectEqual(914920692, nrand48(&xsubi));
- try std.testing.expectEqualSlices(c_ushort, &.{ 29829, 10728, 27921 }, &xsubi);
-
- try std.testing.expectEqual(754104482, nrand48(&xsubi));
- try std.testing.expectEqualSlices(c_ushort, &.{ 6828, 28997, 23013 }, &xsubi);
-
- try std.testing.expectEqual(609453945, nrand48(&xsubi));
- try std.testing.expectEqualSlices(c_ushort, &.{ 58183, 3826, 18599 }, &xsubi);
-
- try std.testing.expectEqual(1878644360, nrand48(&xsubi));
- try std.testing.expectEqualSlices(c_ushort, &.{ 36678, 44304, 57331 }, &xsubi);
-
- try std.testing.expectEqual(2114923686, nrand48(&xsubi));
- try std.testing.expectEqualSlices(c_ushort, &.{ 58585, 22861, 64542 }, &xsubi);
-}
diff --git a/lib/c/string.zig b/lib/c/string.zig
@@ -290,10 +290,3 @@ fn mempcpy(noalias dst: *anyopaque, noalias src: *const anyopaque, len: usize) c
@memcpy(dst_bytes[0..len], src_bytes[0..len]);
return dst_bytes + len;
}
-
-test strncmp {
- try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
- try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("c"), 1) < 0);
- try std.testing.expect(strncmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
- try std.testing.expect(strncmp(@ptrCast("\xff"), @ptrCast("\x02"), 1) > 0);
-}
diff --git a/lib/c/strings.zig b/lib/c/strings.zig
@@ -81,41 +81,3 @@ fn __strncasecmp_l(a: [*:0]const c_char, b: [*:0]const c_char, n: usize, locale:
_ = locale;
return strncasecmp(a, b, n);
}
-
-test bzero {
- var array: [10]u8 = [_]u8{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
- var a = std.mem.zeroes([array.len]u8);
- a[9] = '0';
- bzero(&array[0], 9);
- try std.testing.expect(std.mem.eql(u8, &array, &a));
-}
-
-test firstBitSet {
- try std.testing.expectEqual(0, firstBitSet(usize, 0));
-
- for (0..@bitSizeOf(usize)) |i| {
- const bit = @as(usize, 1) << @intCast(i);
-
- try std.testing.expectEqual(i + 1, firstBitSet(usize, bit));
- }
-}
-
-test strcasecmp {
- try std.testing.expect(strcasecmp(@ptrCast("a"), @ptrCast("b")) < 0);
- try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("a")) > 0);
- try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("b")) < 0);
- try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("A")) > 0);
- try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("A")) == 0);
- try std.testing.expect(strcasecmp(@ptrCast("B"), @ptrCast("b")) == 0);
- try std.testing.expect(strcasecmp(@ptrCast("bb"), @ptrCast("AA")) > 0);
-}
-
-test strncasecmp {
- try std.testing.expect(strncasecmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
- try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
- try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("b"), 1) < 0);
- try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("A"), 1) > 0);
- try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("A"), 1) == 0);
- try std.testing.expect(strncasecmp(@ptrCast("B"), @ptrCast("b"), 1) == 0);
- try std.testing.expect(strncasecmp(@ptrCast("bb"), @ptrCast("AA"), 2) > 0);
-}
diff --git a/lib/c/unistd.zig b/lib/c/unistd.zig
@@ -206,32 +206,6 @@ fn swab(noalias src_ptr: *const anyopaque, noalias dest_ptr: *anyopaque, n: isiz
}
}
-test swab {
- var a: [4]u8 = undefined;
- @memset(a[0..], '\x00');
- swab("abcd", &a, 4);
- try std.testing.expectEqualSlices(u8, "badc", &a);
-
- // Partial copy
- @memset(a[0..], '\x00');
- swab("abcd", &a, 2);
- try std.testing.expectEqualSlices(u8, "ba\x00\x00", &a);
-
- // n < 1
- @memset(a[0..], '\x00');
- swab("abcd", &a, 0);
- try std.testing.expectEqualSlices(u8, "\x00" ** 4, &a);
- swab("abcd", &a, -1);
- try std.testing.expectEqualSlices(u8, "\x00" ** 4, &a);
-
- // Odd n
- @memset(a[0..], '\x00');
- swab("abcd", &a, 1);
- try std.testing.expectEqualSlices(u8, "\x00" ** 4, &a);
- swab("abcd", &a, 3);
- try std.testing.expectEqualSlices(u8, "ba\x00\x00", &a);
-}
-
fn close(fd: std.c.fd_t) callconv(.c) c_int {
const signed: isize = @bitCast(linux.close(fd));
if (signed < 0) {
diff --git a/lib/std/c.zig b/lib/std/c.zig
@@ -11102,13 +11102,60 @@ pub const ioctl = switch (native_os) {
else => private.ioctl,
};
+pub extern "c" fn bzero(s: *anyopaque, n: usize) void;
+
+pub extern "c" fn swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void;
+
+pub extern "c" fn strncmp(a: [*:0]const c_char, b: [*:0]const c_char, max: usize) c_int;
+pub extern "c" fn strcasecmp(a: [*:0]const c_char, b: [*:0]const c_char) c_int;
+pub extern "c" fn strncasecmp(a: [*:0]const c_char, b: [*:0]const c_char, max: usize) c_int;
+
+pub extern "c" fn ffs(i: c_int) c_int;
+pub extern "c" fn ffsl(i: c_long) c_long;
+pub extern "c" fn ffsll(i: c_longlong) c_longlong;
+
+pub extern "c" fn erand48(xsubi: *[3]c_ushort) f64;
+pub extern "c" fn jrand48(xsubi: *[3]c_ushort) c_long;
+pub extern "c" fn nrand48(xsubi: *[3]c_ushort) c_long;
+
+pub extern "c" fn insque(element: *anyopaque, pred: ?*anyopaque) void;
+pub extern "c" fn remque(element: *anyopaque) void;
+
+pub extern "c" fn imaxabs(a: intmax_t) intmax_t;
+pub extern "c" fn imaxdiv(a: intmax_t, b: intmax_t) imaxdiv_t;
+
+pub extern "c" fn abs(a: c_int) c_int;
+pub extern "c" fn labs(a: c_long) c_long;
+pub extern "c" fn llabs(a: c_longlong) c_longlong;
+
+pub extern "c" fn div(a: c_int, b: c_int) div_t;
+pub extern "c" fn ldiv(a: c_long, b: c_long) ldiv_t;
+pub extern "c" fn lldiv(a: c_longlong, b: c_longlong) lldiv_t;
+
+pub extern "c" fn atoi(str: [*:0]const c_char) c_int;
+pub extern "c" fn atol(str: [*:0]const c_char) c_long;
+pub extern "c" fn atoll(str: [*:0]const c_char) c_longlong;
+
+pub extern "c" fn bsearch(
+ key: *const anyopaque,
+ base: *const anyopaque,
+ n: usize,
+ size: usize,
+ compare: *const fn (a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int,
+) ?*anyopaque;
+
// Math
-pub extern "c" fn atan(x: f64) callconv(.c) f64;
-pub extern "c" fn copysign(x: f64, y: f64) callconv(.c) f64;
-pub extern "c" fn fdim(x: f64, y: f64) callconv(.c) f64;
-pub extern "c" fn frexp(x: f64, e: *c_int) callconv(.c) f64;
-pub extern "c" fn hypot(x: f64, y: f64) callconv(.c) f64;
-pub extern "c" fn modf(x: f64, iptr: *f64) callconv(.c) f64;
+pub extern "c" fn atan(x: f64) f64;
+pub extern "c" fn copysign(x: f64, y: f64) f64;
+pub extern "c" fn fdim(x: f64, y: f64) f64;
+pub extern "c" fn frexp(x: f64, e: *c_int) f64;
+pub extern "c" fn hypot(x: f64, y: f64) f64;
+pub extern "c" fn modff(x: f32, iptr: *f32) f32;
+pub extern "c" fn modf(x: f64, iptr: *f64) f64;
+pub extern "c" fn modfl(x: c_longdouble, iptr: *c_longdouble) c_longdouble;
+pub extern "c" fn rintf(x: f32) f32;
+pub extern "c" fn rint(x: f64) f64;
+pub extern "c" fn rintl(x: c_longdouble) c_longdouble;
// OS-specific bits. These are protected from being used on the wrong OS by
// comptime assertions inside each OS-specific file.
diff --git a/test/c.zig b/test/c.zig
@@ -0,0 +1,12 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+test {
+ _ = @import("c/inttypes.zig");
+ _ = @import("c/math.zig");
+ _ = @import("c/search.zig");
+ _ = @import("c/stdlib.zig");
+ _ = @import("c/string.zig");
+ _ = @import("c/strings.zig");
+ _ = @import("c/unistd.zig");
+}
diff --git a/test/c/inttypes.zig b/test/c/inttypes.zig
@@ -0,0 +1,15 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+const c = std.c;
+const testing = std.testing;
+
+test "imaxabs" {
+ const val: c.intmax_t = -10;
+ try testing.expectEqual(10, c.imaxabs(val));
+}
+
+test "imaxdiv" {
+ const expected: c.imaxdiv_t = .{ .quot = 9, .rem = 0 };
+ try testing.expectEqual(expected, c.imaxdiv(9, 1));
+}
diff --git a/test/c/math.zig b/test/c/math.zig
@@ -0,0 +1,101 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+const c = std.c;
+const math = std.math;
+const testing = std.testing;
+
+fn testModf(comptime T: type) !void {
+ const f = switch (T) {
+ f32 => c.modff,
+ f64 => c.modf,
+ c_longdouble => c.modfl,
+ else => unreachable,
+ };
+
+ var int: T = undefined;
+ const iptr = ∫
+ const eps_val: comptime_float = @max(1e-6, math.floatEps(T));
+
+ const normal_frac = f(@as(T, 1234.567), iptr);
+ // Account for precision error
+ const expected = 1234.567 - @as(T, 1234);
+ try testing.expectApproxEqAbs(expected, normal_frac, eps_val);
+ try testing.expectApproxEqRel(@as(T, 1234.0), iptr.*, eps_val);
+
+ // When `x` is a NaN, NaN is returned and `*iptr` is set to NaN
+ const nan_frac = f(math.nan(T), iptr);
+ try testing.expect(math.isNan(nan_frac));
+ try testing.expect(math.isNan(iptr.*));
+
+ // When `x` is positive infinity, +0 is returned and `*iptr` is set to
+ // positive infinity
+ const pos_zero_frac = f(math.inf(T), iptr);
+ try testing.expect(math.isPositiveZero(pos_zero_frac));
+ try testing.expect(math.isPositiveInf(iptr.*));
+
+ // When `x` is negative infinity, -0 is returned and `*iptr` is set to
+ // negative infinity
+ const neg_zero_frac = f(-math.inf(T), iptr);
+ try testing.expect(math.isNegativeZero(neg_zero_frac));
+ try testing.expect(math.isNegativeInf(iptr.*));
+
+ // Return -0 when `x` is a negative integer
+ const nz_frac = f(@as(T, -1000.0), iptr);
+ try testing.expect(math.isNegativeZero(nz_frac));
+ try testing.expectEqual(@as(T, -1000.0), iptr.*);
+
+ // Return +0 when `x` is a positive integer
+ const pz_frac = f(@as(T, 1000.0), iptr);
+ try testing.expect(math.isPositiveZero(pz_frac));
+ try testing.expectEqual(@as(T, 1000.0), iptr.*);
+}
+
+test "modf" {
+ try testModf(f32);
+ try testModf(f64);
+ try testModf(c_longdouble);
+}
+
+fn testRint(comptime T: type) !void {
+ const f = switch (T) {
+ f32 => c.rintf,
+ f64 => c.rint,
+ else => @compileError("rint not implemented for" ++ @typeName(T)),
+ };
+
+ // Positive numbers round correctly
+ try testing.expectEqual(@as(T, 42.0), f(42.2));
+ try testing.expectEqual(@as(T, 42.0), f(41.8));
+
+ // Negative numbers round correctly
+ try testing.expectEqual(@as(T, -6.0), f(-5.9));
+ try testing.expectEqual(@as(T, -6.0), f(-6.1));
+
+ // No rounding needed test
+ try testing.expectEqual(@as(T, 5.0), f(5.0));
+ try testing.expectEqual(@as(T, -10.0), f(-10.0));
+ try testing.expectEqual(@as(T, 0.0), f(0.0));
+
+ // Very large numbers return unchanged
+ const large: T = 9007199254740992.0; // 2^53
+ try testing.expectEqual(large, f(large));
+ try testing.expectEqual(-large, f(-large));
+
+ // Small positive numbers round to zero
+ const pos_result = f(0.3);
+ try testing.expect(math.isPositiveZero(pos_result));
+
+ // Small negative numbers round to negative zero
+ const neg_result = f(-0.3);
+ try testing.expect(math.isNegativeZero(neg_result));
+
+ // Exact half rounds to nearest even (banker's rounding)
+ try testing.expectEqual(@as(T, 2.0), f(2.5));
+ try testing.expectEqual(@as(T, 4.0), f(3.5));
+}
+
+test "rint" {
+ try testRint(f32);
+ try testRint(f64);
+}
diff --git a/test/c/search.zig b/test/c/search.zig
@@ -0,0 +1,38 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+const c = std.c;
+const testing = std.testing;
+
+/// Not defined in `std.c` because C headers don't either.
+const Node = extern struct {
+ next: ?*Node,
+ prev: ?*Node,
+};
+
+test "insque and remque" {
+ var first: Node = .{ .next = null, .prev = null };
+ var second: Node = .{ .next = null, .prev = null };
+ var third: Node = .{ .next = null, .prev = null };
+
+ c.insque(&first, null);
+ try testing.expectEqual(@as(?*Node, null), first.next);
+ try testing.expectEqual(@as(?*Node, null), first.prev);
+
+ c.insque(&second, &first);
+ try testing.expectEqual(@as(?*Node, &second), first.next);
+ try testing.expectEqual(@as(?*Node, &first), second.prev);
+
+ c.insque(&third, &first);
+ try testing.expectEqual(@as(?*Node, &third), first.next);
+ try testing.expectEqual(@as(?*Node, &second), third.next);
+ try testing.expectEqual(@as(?*Node, &first), third.prev);
+ try testing.expectEqual(@as(?*Node, &third), second.prev);
+
+ c.remque(&third);
+ try testing.expectEqual(@as(?*Node, &second), first.next);
+ try testing.expectEqual(@as(?*Node, &first), second.prev);
+
+ c.remque(&second);
+ try testing.expectEqual(@as(?*Node, null), first.next);
+}
diff --git a/test/c/stdlib.zig b/test/c/stdlib.zig
@@ -0,0 +1,109 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+const c = std.c;
+const fmt = std.fmt;
+const math = std.math;
+const testing = std.testing;
+
+test "abs" {
+ const val: c_int = -10;
+ try testing.expectEqual(10, c.abs(val));
+}
+
+test "labs" {
+ const val: c_long = -10;
+ try testing.expectEqual(10, c.labs(val));
+}
+
+test "llabs" {
+ const val: c_longlong = -10;
+ try testing.expectEqual(10, c.llabs(val));
+}
+
+test "div" {
+ const expected: c.div_t = .{ .quot = 5, .rem = 5 };
+ try testing.expectEqual(expected, c.div(55, 10));
+}
+
+test "ldiv" {
+ const expected: c.ldiv_t = .{ .quot = -6, .rem = 2 };
+ try testing.expectEqual(expected, c.ldiv(38, -6));
+}
+
+test "lldiv" {
+ const expected: c.lldiv_t = .{ .quot = 1, .rem = 2 };
+ try testing.expectEqual(expected, c.lldiv(5, 3));
+}
+
+test "atoi" {
+ try testing.expectEqual(0, c.atoi(@ptrCast("stop42true")));
+ try testing.expectEqual(42, c.atoi(@ptrCast("42true")));
+ try testing.expectEqual(-1, c.atoi(@ptrCast("-01")));
+ try testing.expectEqual(1, c.atoi(@ptrCast("+001")));
+ try testing.expectEqual(100, c.atoi(@ptrCast(" 100")));
+ try testing.expectEqual(500, c.atoi(@ptrCast("000000000000500")));
+ try testing.expectEqual(1111, c.atoi(@ptrCast("0000000000001111_0000")));
+ try testing.expectEqual(0, c.atoi(@ptrCast("0xAA")));
+ try testing.expectEqual(700, c.atoi(@ptrCast("700B")));
+ try testing.expectEqual(32453, c.atoi(@ptrCast("+32453more")));
+ try testing.expectEqual(math.maxInt(c_int), c.atoi(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_int)}))));
+ try testing.expectEqual(math.minInt(c_int), c.atoi(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_int)}))));
+}
+
+test "atol" {
+ try testing.expectEqual(0, c.atol(@ptrCast("stop42true")));
+ try testing.expectEqual(42, c.atol(@ptrCast("42true")));
+ try testing.expectEqual(-1, c.atol(@ptrCast("-01")));
+ try testing.expectEqual(1, c.atol(@ptrCast("+001")));
+ try testing.expectEqual(100, c.atol(@ptrCast(" 100")));
+ try testing.expectEqual(500, c.atol(@ptrCast("000000000000500")));
+ try testing.expectEqual(1111, c.atol(@ptrCast("0000000000001111_0000")));
+ try testing.expectEqual(0, c.atol(@ptrCast("0xAA")));
+ try testing.expectEqual(700, c.atol(@ptrCast("700B")));
+ try testing.expectEqual(32453, c.atol(@ptrCast("+32453more")));
+ try testing.expectEqual(math.maxInt(c_long), c.atol(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_long)}))));
+ try testing.expectEqual(math.minInt(c_long), c.atol(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_long)}))));
+}
+
+test "atoll" {
+ try testing.expectEqual(0, c.atoll(@ptrCast("stop42true")));
+ try testing.expectEqual(42, c.atoll(@ptrCast("42true")));
+ try testing.expectEqual(-1, c.atoll(@ptrCast("-01")));
+ try testing.expectEqual(1, c.atoll(@ptrCast("+001")));
+ try testing.expectEqual(100, c.atoll(@ptrCast(" 100")));
+ try testing.expectEqual(500, c.atoll(@ptrCast("000000000000500")));
+ try testing.expectEqual(1111, c.atoll(@ptrCast("0000000000001111_0000")));
+ try testing.expectEqual(0, c.atoll(@ptrCast("0xAA")));
+ try testing.expectEqual(700, c.atoll(@ptrCast("700B")));
+ try testing.expectEqual(32453, c.atoll(@ptrCast(" +32453more")));
+ try testing.expectEqual(math.maxInt(c_longlong), c.atoll(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_longlong)}))));
+ try testing.expectEqual(math.minInt(c_longlong), c.atoll(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_longlong)}))));
+}
+
+test "bsearch" {
+ const Comparison = struct {
+ pub fn compare(a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int {
+ const a_u16: *const u16 = @ptrCast(@alignCast(a));
+ const b_u16: *const u16 = @ptrCast(@alignCast(b));
+
+ return switch (math.order(a_u16.*, b_u16.*)) {
+ .gt => 1,
+ .eq => 0,
+ .lt => -1,
+ };
+ }
+ };
+
+ const items: []const u16 = &.{ 0, 5, 7, 9, 10, 200, 512, 768 };
+
+ try testing.expectEqual(@as(?*anyopaque, null), c.bsearch(&@as(u16, 2000), items.ptr, items.len, @sizeOf(u16), Comparison.compare));
+
+ for (items) |*value| {
+ try testing.expectEqual(@as(*const anyopaque, value), c.bsearch(value, items.ptr, items.len, @sizeOf(u16), Comparison.compare));
+ }
+}
+
+test {
+ _ = @import("stdlib/drand48.zig");
+}
diff --git a/test/c/stdlib/drand48.zig b/test/c/stdlib/drand48.zig
@@ -0,0 +1,62 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+const c = std.c;
+const testing = std.testing;
+
+test "erand48" {
+ var xsubi: [3]c_ushort = .{ 37174, 64810, 11603 };
+
+ try testing.expectApproxEqAbs(0.8965, c.erand48(&xsubi), 0.0005);
+ try testing.expectEqualSlices(c_ushort, &.{ 22537, 47966, 58735 }, &xsubi);
+
+ try testing.expectApproxEqAbs(0.3375, c.erand48(&xsubi), 0.0005);
+ try testing.expectEqualSlices(c_ushort, &.{ 37344, 32911, 22119 }, &xsubi);
+
+ try testing.expectApproxEqAbs(0.6475, c.erand48(&xsubi), 0.0005);
+ try testing.expectEqualSlices(c_ushort, &.{ 23659, 29872, 42445 }, &xsubi);
+
+ try testing.expectApproxEqAbs(0.5005, c.erand48(&xsubi), 0.0005);
+ try testing.expectEqualSlices(c_ushort, &.{ 31642, 7875, 32802 }, &xsubi);
+
+ try testing.expectApproxEqAbs(0.5065, c.erand48(&xsubi), 0.0005);
+ try testing.expectEqualSlices(c_ushort, &.{ 64669, 14399, 33170 }, &xsubi);
+}
+
+test "jrand48" {
+ var xsubi: [3]c_ushort = .{ 25175, 11052, 45015 };
+
+ try testing.expectEqual(1699503220, c.jrand48(&xsubi));
+ try testing.expectEqualSlices(c_ushort, &.{ 2326, 23668, 25932 }, &xsubi);
+
+ try testing.expectEqual(-992276007, c.jrand48(&xsubi));
+ try testing.expectEqualSlices(c_ushort, &.{ 41577, 4569, 50395 }, &xsubi);
+
+ try testing.expectEqual(-19535776, c.jrand48(&xsubi));
+ try testing.expectEqualSlices(c_ushort, &.{ 31936, 59488, 65237 }, &xsubi);
+
+ try testing.expectEqual(79438377, c.jrand48(&xsubi));
+ try testing.expectEqualSlices(c_ushort, &.{ 40395, 8745, 1212 }, &xsubi);
+
+ try testing.expectEqual(-1258917728, c.jrand48(&xsubi));
+ try testing.expectEqualSlices(c_ushort, &.{ 37242, 28832, 46326 }, &xsubi);
+}
+
+test "nrand48" {
+ var xsubi: [3]c_ushort = .{ 546, 33817, 23389 };
+
+ try testing.expectEqual(914920692, c.nrand48(&xsubi));
+ try testing.expectEqualSlices(c_ushort, &.{ 29829, 10728, 27921 }, &xsubi);
+
+ try testing.expectEqual(754104482, c.nrand48(&xsubi));
+ try testing.expectEqualSlices(c_ushort, &.{ 6828, 28997, 23013 }, &xsubi);
+
+ try testing.expectEqual(609453945, c.nrand48(&xsubi));
+ try testing.expectEqualSlices(c_ushort, &.{ 58183, 3826, 18599 }, &xsubi);
+
+ try testing.expectEqual(1878644360, c.nrand48(&xsubi));
+ try testing.expectEqualSlices(c_ushort, &.{ 36678, 44304, 57331 }, &xsubi);
+
+ try testing.expectEqual(2114923686, c.nrand48(&xsubi));
+ try testing.expectEqualSlices(c_ushort, &.{ 58585, 22861, 64542 }, &xsubi);
+}
diff --git a/test/c/string.zig b/test/c/string.zig
@@ -0,0 +1,12 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+const c = std.c;
+const testing = std.testing;
+
+test "strncmp" {
+ try testing.expect(c.strncmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
+ try testing.expect(c.strncmp(@ptrCast("a"), @ptrCast("c"), 1) < 0);
+ try testing.expect(c.strncmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
+ try testing.expect(c.strncmp(@ptrCast("\xff"), @ptrCast("\x02"), 1) > 0);
+}
diff --git a/test/c/strings.zig b/test/c/strings.zig
@@ -0,0 +1,57 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+const c = std.c;
+const mem = std.mem;
+const testing = std.testing;
+
+test "bzero" {
+ var array: [10]u8 = [_]u8{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
+ var a = mem.zeroes([array.len]u8);
+ a[9] = '0';
+ c.bzero(&array[0], 9);
+ try testing.expect(mem.eql(u8, &array, &a));
+}
+
+fn testFfs(comptime T: type) !void {
+ const ffs = switch (T) {
+ c_int => c.ffs,
+ c_long => c.ffsl,
+ c_longlong => c.ffsll,
+ else => unreachable,
+ };
+
+ try testing.expectEqual(0, ffs(0));
+
+ for (0..@bitSizeOf(T)) |i| {
+ const bit = @as(T, 1) << @intCast(i);
+
+ try testing.expectEqual(@as(T, @intCast(i + 1)), ffs(bit));
+ }
+}
+
+test "ffs" {
+ try testFfs(c_int);
+ try testFfs(c_long);
+ try testFfs(c_longlong);
+}
+
+test "strcasecmp" {
+ try testing.expect(c.strcasecmp(@ptrCast("a"), @ptrCast("b")) < 0);
+ try testing.expect(c.strcasecmp(@ptrCast("b"), @ptrCast("a")) > 0);
+ try testing.expect(c.strcasecmp(@ptrCast("A"), @ptrCast("b")) < 0);
+ try testing.expect(c.strcasecmp(@ptrCast("b"), @ptrCast("A")) > 0);
+ try testing.expect(c.strcasecmp(@ptrCast("A"), @ptrCast("A")) == 0);
+ try testing.expect(c.strcasecmp(@ptrCast("B"), @ptrCast("b")) == 0);
+ try testing.expect(c.strcasecmp(@ptrCast("bb"), @ptrCast("AA")) > 0);
+}
+
+test "strncasecmp" {
+ try testing.expect(c.strncasecmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
+ try testing.expect(c.strncasecmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
+ try testing.expect(c.strncasecmp(@ptrCast("A"), @ptrCast("b"), 1) < 0);
+ try testing.expect(c.strncasecmp(@ptrCast("b"), @ptrCast("A"), 1) > 0);
+ try testing.expect(c.strncasecmp(@ptrCast("A"), @ptrCast("A"), 1) == 0);
+ try testing.expect(c.strncasecmp(@ptrCast("B"), @ptrCast("b"), 1) == 0);
+ try testing.expect(c.strncasecmp(@ptrCast("bb"), @ptrCast("AA"), 2) > 0);
+}
diff --git a/test/c/unistd.zig b/test/c/unistd.zig
@@ -0,0 +1,31 @@
+const builtin = @import("builtin");
+const std = @import("std");
+
+const c = std.c;
+const testing = std.testing;
+
+test "swab" {
+ var a: [4]u8 = undefined;
+ @memset(a[0..], '\x00');
+ c.swab("abcd", &a, 4);
+ try testing.expectEqualSlices(u8, "badc", &a);
+
+ // Partial copy
+ @memset(a[0..], '\x00');
+ c.swab("abcd", &a, 2);
+ try testing.expectEqualSlices(u8, "ba\x00\x00", &a);
+
+ // n < 1
+ @memset(a[0..], '\x00');
+ c.swab("abcd", &a, 0);
+ try testing.expectEqualSlices(u8, "\x00" ** 4, &a);
+ c.swab("abcd", &a, -1);
+ try testing.expectEqualSlices(u8, "\x00" ** 4, &a);
+
+ // Odd n
+ @memset(a[0..], '\x00');
+ c.swab("abcd", &a, 1);
+ try testing.expectEqualSlices(u8, "\x00" ** 4, &a);
+ c.swab("abcd", &a, 3);
+ try testing.expectEqualSlices(u8, "ba\x00\x00", &a);
+}
diff --git a/test/tests.zig b/test/tests.zig
@@ -18,7 +18,7 @@ pub const DebuggerContext = @import("src/Debugger.zig");
pub const LlvmIrContext = @import("src/LlvmIr.zig");
pub const LibcContext = @import("src/Libc.zig");
-const TestTarget = struct {
+const ModuleTestTarget = struct {
linkage: ?std.builtin.LinkMode = null,
target: std.Target.Query = .{},
optimize_mode: std.builtin.OptimizeMode = .Debug,
@@ -36,33 +36,14 @@ const TestTarget = struct {
// invocation. This could be because of a slow backend, requiring a newer LLVM version, being
// too niche, etc.
extra_target: bool = false,
-
- pub fn supportsModule(
- self: *const TestTarget,
- target: *const std.Build.ResolvedTarget,
- name: []const u8,
- ) bool {
- if (mem.eql(u8, name, "zigc")) {
- if (target.result.isMuslLibC()) return self.linkage == .static or (self.linkage == null and !target.query.isNative());
- if (target.result.isMinGW()) return true;
- if (target.result.isWasiLibC()) return true;
- return false;
- }
- if (mem.eql(u8, name, "std")) {
- if (target.result.cpu.arch.isSpirV()) return false;
- return true;
- }
-
- return true;
- }
};
-const test_targets = blk: {
+const module_test_targets = blk: {
// getBaselineCpuFeatures calls populateDependencies which has a O(N ^ 2) algorithm
// (where N is roughly 160, which technically makes it O(1), but it adds up to a
// lot of branches)
@setEvalBranchQuota(80_000);
- break :blk [_]TestTarget{
+ break :blk [_]ModuleTestTarget{
// Native Targets
.{}, // 0 index must be all defaults
@@ -2475,24 +2456,21 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
const step = b.step(b.fmt("test-{s}", .{options.name}), options.desc);
if (options.test_only) |test_only| {
- const test_target: TestTarget = switch (test_only) {
- .default => test_targets[0],
+ const test_target: ModuleTestTarget = switch (test_only) {
+ .default => module_test_targets[0],
.fuzz => |optimize| .{
.optimize_mode = optimize,
.use_llvm = true,
},
};
const resolved_target = b.resolveTargetQuery(test_target.target);
-
- if (test_target.supportsModule(&resolved_target, options.name)) {
- const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM");
- addOneModuleTest(b, step, test_target, &resolved_target, triple_txt, options);
- }
+ const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM");
+ addOneModuleTest(b, step, test_target, &resolved_target, triple_txt, options);
return step;
}
- for_targets: for (test_targets) |test_target| {
+ for_targets: for (module_test_targets) |test_target| {
if (test_target.skip_modules.len > 0) {
for (test_target.skip_modules) |skip_mod| {
if (std.mem.eql(u8, options.name, skip_mod)) continue :for_targets;
@@ -2501,8 +2479,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
const resolved_target = b.resolveTargetQuery(test_target.target);
- if (!test_target.supportsModule(&resolved_target, options.name)) continue;
-
if (!options.test_extra_targets and test_target.extra_target) continue;
if (options.skip_non_native and !test_target.target.isNative())
@@ -2510,6 +2486,13 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
const target = &resolved_target.result;
+ if (std.mem.eql(u8, options.name, "libc")) {
+ // The libc API tests obviously need to link libc. So for test
+ // target entries where we wouldn't link libc by default, skip the
+ // libc API tests.
+ if (test_target.link_libc == null and !std.os.targetRequiresLibC(target)) continue;
+ }
+
if (options.skip_spirv and target.cpu.arch.isSpirV()) continue;
if (options.skip_wasm and target.cpu.arch.isWasm()) continue;
@@ -2544,8 +2527,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
if (!would_use_llvm and target.cpu.arch == .aarch64) {
// TODO get std tests passing for the aarch64 self-hosted backend.
if (mem.eql(u8, options.name, "std")) continue;
- // TODO get zigc tests passing for the aarch64 self-hosted backend.
- if (mem.eql(u8, options.name, "zigc")) continue;
}
const want_this_mode = for (options.optimize_modes) |m| {
@@ -2561,7 +2542,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
fn addOneModuleTest(
b: *std.Build,
step: *Step,
- test_target: TestTarget,
+ test_target: ModuleTestTarget,
resolved_target: *const std.Build.ResolvedTarget,
triple_txt: []const u8,
options: ModuleTestOptions,
@@ -2598,11 +2579,11 @@ fn addOneModuleTest(
});
these_tests.linkage = test_target.linkage;
// https://codeberg.org/ziglang/zig/issues/31701
- if (!(mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "zigc"))) {
+ if (!(mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "libc"))) {
if (options.no_builtin) these_tests.root_module.no_builtin = true;
}
// https://codeberg.org/ziglang/zig/issues/31702
- if (mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "zigc")) {
+ if (mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "libc")) {
these_tests.root_module.stack_protector = false;
}
if (options.build_options) |build_options| {
@@ -2992,7 +2973,7 @@ pub fn addLlvmIrTests(b: *std.Build, options: LlvmIrContext.Options) ?*Step {
return step;
}
-const libc_targets: []const std.Target.Query = &.{
+const libc_test_nsz_targets: []const std.Target.Query = &.{
.{
.cpu_arch = .arm,
.os_tag = .linux,
@@ -3155,8 +3136,8 @@ const libc_targets: []const std.Target.Query = &.{
},
};
-pub fn addLibcTests(b: *std.Build, options: LibcContext.Options) ?*Step {
- const step = b.step("test-libc", "Run libc-test test cases");
+pub fn addLibcTestNszTests(b: *std.Build, options: LibcContext.Options) ?*Step {
+ const step = b.step("test-libc-nsz", "Run external libc-test test cases");
const opt_libc_test_path = b.option(std.Build.LazyPath, "libc-test-path", "path to libc-test source directory");
if (opt_libc_test_path) |libc_test_path| {
var context: LibcContext = .{
@@ -3168,7 +3149,7 @@ pub fn addLibcTests(b: *std.Build, options: LibcContext.Options) ?*Step {
libc.addCases(&context);
- for (libc_targets) |target_query| {
+ for (libc_test_nsz_targets) |target_query| {
const target = b.resolveTargetQuery(target_query);
context.addTarget(target);
}