authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-03-27 11:14:02+01:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-04-17 12:10:37+02:00
log7ea8f842bc65cdaf046483b2bfe7948ebad16516
tree59efc2b3a0dea8ee5bc2070110d95f85bae8a64c
parent3e1e625814165d9d9282f3cd89bc117cf1b6d61c
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

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>

21 files changed, 530 insertions(+), 430 deletions(-)

build.zig+16-16
...@@ -526,16 +526,16 @@ pub fn build(b: *std.Build) !void {...@@ -526,16 +526,16 @@ pub fn build(b: *std.Build) !void {
526 .test_filters = test_filters,526 .test_filters = test_filters,
527 .test_target_filters = test_target_filters,527 .test_target_filters = test_target_filters,
528 .test_extra_targets = test_extra_targets,528 .test_extra_targets = test_extra_targets,
529 .root_src = "lib/c.zig",529 .root_src = "lib/std/std.zig",
530 .name = "zigc",530 .name = "std",
531 .desc = "Run the zig libc implementation unit tests",531 .desc = "Run the standard library tests",
532 .optimize_modes = optimization_modes,532 .optimize_modes = optimization_modes,
533 .include_paths = &.{},533 .include_paths = &.{},
534 .sanitize_thread = sanitize_thread,534 .sanitize_thread = sanitize_thread,
535 .skip_single_threaded = true,535 .skip_single_threaded = skip_single_threaded,
536 .skip_non_native = skip_non_native,536 .skip_non_native = skip_non_native,
537 .test_only = test_only,537 .test_only = test_only,
538 .skip_spirv = skip_spirv,538 .skip_spirv = true,
539 .skip_wasm = skip_wasm,539 .skip_wasm = skip_wasm,
540 .skip_freebsd = skip_freebsd,540 .skip_freebsd = skip_freebsd,
541 .skip_netbsd = skip_netbsd,541 .skip_netbsd = skip_netbsd,
...@@ -544,25 +544,24 @@ pub fn build(b: *std.Build) !void {...@@ -544,25 +544,24 @@ pub fn build(b: *std.Build) !void {
544 .skip_darwin = skip_darwin,544 .skip_darwin = skip_darwin,
545 .skip_linux = skip_linux,545 .skip_linux = skip_linux,
546 .skip_llvm = skip_llvm,546 .skip_llvm = skip_llvm,
547 .skip_libc = true,547 .skip_libc = skip_libc,
548 .no_builtin = true,548 .max_rss = 9_300_000_000,
549 .max_rss = 4_000_000_000,
550 }));549 }));
551550
552 test_modules_step.dependOn(tests.addModuleTests(b, .{551 test_modules_step.dependOn(tests.addModuleTests(b, .{
553 .test_filters = test_filters,552 .test_filters = test_filters,
554 .test_target_filters = test_target_filters,553 .test_target_filters = test_target_filters,
555 .test_extra_targets = test_extra_targets,554 .test_extra_targets = test_extra_targets,
556 .root_src = "lib/std/std.zig",555 .root_src = "test/c.zig",
557 .name = "std",556 .name = "libc",
558 .desc = "Run the standard library tests",557 .desc = "Run the libc API tests",
559 .optimize_modes = optimization_modes,558 .optimize_modes = optimization_modes,
560 .include_paths = &.{},559 .include_paths = &.{},
561 .sanitize_thread = sanitize_thread,560 .sanitize_thread = sanitize_thread,
562 .skip_single_threaded = skip_single_threaded,561 .skip_single_threaded = true,
563 .skip_non_native = skip_non_native,562 .skip_non_native = skip_non_native,
564 .test_only = test_only,563 .test_only = test_only,
565 .skip_spirv = skip_spirv,564 .skip_spirv = true,
566 .skip_wasm = skip_wasm,565 .skip_wasm = skip_wasm,
567 .skip_freebsd = skip_freebsd,566 .skip_freebsd = skip_freebsd,
568 .skip_netbsd = skip_netbsd,567 .skip_netbsd = skip_netbsd,
...@@ -572,7 +571,8 @@ pub fn build(b: *std.Build) !void {...@@ -572,7 +571,8 @@ pub fn build(b: *std.Build) !void {
572 .skip_linux = skip_linux,571 .skip_linux = skip_linux,
573 .skip_llvm = skip_llvm,572 .skip_llvm = skip_llvm,
574 .skip_libc = skip_libc,573 .skip_libc = skip_libc,
575 .max_rss = 9_300_000_000,574 .no_builtin = true,
575 .max_rss = 4_000_000_000,
576 }));576 }));
577577
578 const unit_tests_step = b.step("test-unit", "Run the compiler source unit tests");578 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 {...@@ -662,13 +662,13 @@ pub fn build(b: *std.Build) !void {
662 try tests.addIncrementalTests(b, test_incremental_step, test_filters);662 try tests.addIncrementalTests(b, test_incremental_step, test_filters);
663 if (!skip_test_incremental) test_step.dependOn(test_incremental_step);663 if (!skip_test_incremental) test_step.dependOn(test_incremental_step);
664664
665 if (tests.addLibcTests(b, .{665 if (tests.addLibcTestNszTests(b, .{
666 .optimize_modes = optimization_modes,666 .optimize_modes = optimization_modes,
667 .test_filters = test_filters,667 .test_filters = test_filters,
668 .test_target_filters = test_target_filters,668 .test_target_filters = test_target_filters,
669 .skip_wasm = skip_wasm,669 .skip_wasm = skip_wasm,
670 .max_rss = 3_500_000_000,670 .max_rss = 3_500_000_000,
671 })) |test_libc_step| test_step.dependOn(test_libc_step);671 })) |test_libc_nsz_step| test_step.dependOn(test_libc_nsz_step);
672}672}
673673
674fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {674fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
lib/c.zig+1-2
...@@ -2,8 +2,7 @@...@@ -2,8 +2,7 @@
2//! bundled libcs.2//! bundled libcs.
3//!3//!
4//! mingw-w64 libc is not fully statically linked, so some symbols don't need4//! mingw-w64 libc is not fully statically linked, so some symbols don't need
5//! to be exported. However, a future enhancement could be eliminating Zig's5//! to be exported.
6//! dependency on msvcrt dll even when linking libc and targeting Windows.
76
8const builtin = @import("builtin");7const builtin = @import("builtin");
9const std = @import("std");8const std = @import("std");
lib/c/inttypes.zig-10
...@@ -24,13 +24,3 @@ fn imaxdiv(a: intmax_t, b: intmax_t) callconv(.c) imaxdiv_t {...@@ -24,13 +24,3 @@ fn imaxdiv(a: intmax_t, b: intmax_t) callconv(.c) imaxdiv_t {
24 .rem = @rem(a, b),24 .rem = @rem(a, b),
25 };25 };
26}26}
27
28test imaxabs {
29 const val: intmax_t = -10;
30 try std.testing.expectEqual(10, imaxabs(val));
31}
32
33test imaxdiv {
34 const expected: imaxdiv_t = .{ .quot = 9, .rem = 0 };
35 try std.testing.expectEqual(expected, imaxdiv(9, 1));
36}
lib/c/math.zig-100
...@@ -2,10 +2,6 @@ const builtin = @import("builtin");...@@ -2,10 +2,6 @@ const builtin = @import("builtin");
22
3const std = @import("std");3const std = @import("std");
4const math = std.math;4const math = std.math;
5const expect = std.testing.expect;
6const expectEqual = std.testing.expectEqual;
7const expectApproxEqAbs = std.testing.expectApproxEqAbs;
8const expectApproxEqRel = std.testing.expectApproxEqRel;
95
10const symbol = @import("../c.zig").symbol;6const symbol = @import("../c.zig").symbol;
117
...@@ -304,59 +300,6 @@ fn modfl(x: c_longdouble, iptr: *c_longdouble) callconv(.c) c_longdouble {...@@ -304,59 +300,6 @@ fn modfl(x: c_longdouble, iptr: *c_longdouble) callconv(.c) c_longdouble {
304 };300 };
305}301}
306302
307fn testModf(comptime T: type) !void {
308 // Choose the appropriate `modf` impl to test based on type
309 const f = switch (T) {
310 f32 => modff,
311 f64 => modf,
312 c_longdouble => modfl,
313 else => @compileError("modf not implemented for " ++ @typeName(T)),
314 };
315
316 var int: T = undefined;
317 const iptr = &int;
318 const eps_val: comptime_float = @max(1e-6, math.floatEps(T));
319
320 const normal_frac = f(@as(T, 1234.567), iptr);
321 // Account for precision error
322 const expected = 1234.567 - @as(T, 1234);
323 try expectApproxEqAbs(expected, normal_frac, eps_val);
324 try expectApproxEqRel(@as(T, 1234.0), iptr.*, eps_val);
325
326 // When `x` is a NaN, NaN is returned and `*iptr` is set to NaN
327 const nan_frac = f(math.nan(T), iptr);
328 try expect(math.isNan(nan_frac));
329 try expect(math.isNan(iptr.*));
330
331 // When `x` is positive infinity, +0 is returned and `*iptr` is set to
332 // positive infinity
333 const pos_zero_frac = f(math.inf(T), iptr);
334 try expect(math.isPositiveZero(pos_zero_frac));
335 try expect(math.isPositiveInf(iptr.*));
336
337 // When `x` is negative infinity, -0 is returned and `*iptr` is set to
338 // negative infinity
339 const neg_zero_frac = f(-math.inf(T), iptr);
340 try expect(math.isNegativeZero(neg_zero_frac));
341 try expect(math.isNegativeInf(iptr.*));
342
343 // Return -0 when `x` is a negative integer
344 const nz_frac = f(@as(T, -1000.0), iptr);
345 try expect(math.isNegativeZero(nz_frac));
346 try expectEqual(@as(T, -1000.0), iptr.*);
347
348 // Return +0 when `x` is a positive integer
349 const pz_frac = f(@as(T, 1000.0), iptr);
350 try expect(math.isPositiveZero(pz_frac));
351 try expectEqual(@as(T, 1000.0), iptr.*);
352}
353
354test "modf" {
355 try testModf(f32);
356 try testModf(f64);
357 try testModf(c_longdouble);
358}
359
360fn nan(_: [*:0]const c_char) callconv(.c) f64 {303fn nan(_: [*:0]const c_char) callconv(.c) f64 {
361 return math.nan(f64);304 return math.nan(f64);
362}305}
...@@ -421,49 +364,6 @@ fn rintf(x: f32) callconv(.c) f32 {...@@ -421,49 +364,6 @@ fn rintf(x: f32) callconv(.c) f32 {
421 return y;364 return y;
422}365}
423366
424fn testRint(comptime T: type) !void {
425 const f = switch (T) {
426 f32 => rintf,
427 f64 => rint,
428 else => @compileError("rint not implemented for" ++ @typeName(T)),
429 };
430
431 // Positive numbers round correctly
432 try expectEqual(@as(T, 42.0), f(42.2));
433 try expectEqual(@as(T, 42.0), f(41.8));
434
435 // Negative numbers round correctly
436 try expectEqual(@as(T, -6.0), f(-5.9));
437 try expectEqual(@as(T, -6.0), f(-6.1));
438
439 // No rounding needed test
440 try expectEqual(@as(T, 5.0), f(5.0));
441 try expectEqual(@as(T, -10.0), f(-10.0));
442 try expectEqual(@as(T, 0.0), f(0.0));
443
444 // Very large numbers return unchanged
445 const large: T = 9007199254740992.0; // 2^53
446 try expectEqual(large, f(large));
447 try expectEqual(-large, f(-large));
448
449 // Small positive numbers round to zero
450 const pos_result = f(0.3);
451 try expect(math.isPositiveZero(pos_result));
452
453 // Small negative numbers round to negative zero
454 const neg_result = f(-0.3);
455 try expect(math.isNegativeZero(neg_result));
456
457 // Exact half rounds to nearest even (banker's rounding)
458 try expectEqual(@as(T, 2.0), f(2.5));
459 try expectEqual(@as(T, 4.0), f(3.5));
460}
461
462test "rint" {
463 try testRint(f32);
464 try testRint(f64);
465}
466
467fn tanh(x: f64) callconv(.c) f64 {367fn tanh(x: f64) callconv(.c) f64 {
468 return math.tanh(x);368 return math.tanh(x);
469}369}
lib/c/search.zig+1-27
...@@ -9,6 +9,7 @@ comptime {...@@ -9,6 +9,7 @@ comptime {
9 }9 }
10}10}
1111
12/// Not defined in `std.c` because C headers don't either.
12const Node = extern struct {13const Node = extern struct {
13 next: ?*Node,14 next: ?*Node,
14 prev: ?*Node,15 prev: ?*Node,
...@@ -38,30 +39,3 @@ fn remque(element: *anyopaque) callconv(.c) void {...@@ -38,30 +39,3 @@ fn remque(element: *anyopaque) callconv(.c) void {
38 if (e.next) |next| next.prev = e.prev;39 if (e.next) |next| next.prev = e.prev;
39 if (e.prev) |prev| prev.next = e.next;40 if (e.prev) |prev| prev.next = e.next;
40}41}
41
42test "insque and remque" {
43 var first = Node{ .next = null, .prev = null };
44 var second = Node{ .next = null, .prev = null };
45 var third = Node{ .next = null, .prev = null };
46
47 insque(&first, null);
48 try std.testing.expectEqual(@as(?*Node, null), first.next);
49 try std.testing.expectEqual(@as(?*Node, null), first.prev);
50
51 insque(&second, &first);
52 try std.testing.expectEqual(@as(?*Node, &second), first.next);
53 try std.testing.expectEqual(@as(?*Node, &first), second.prev);
54
55 insque(&third, &first);
56 try std.testing.expectEqual(@as(?*Node, &third), first.next);
57 try std.testing.expectEqual(@as(?*Node, &second), third.next);
58 try std.testing.expectEqual(@as(?*Node, &first), third.prev);
59 try std.testing.expectEqual(@as(?*Node, &third), second.prev);
60
61 remque(&third);
62 try std.testing.expectEqual(@as(?*Node, &second), first.next);
63 try std.testing.expectEqual(@as(?*Node, &first), second.prev);
64
65 remque(&second);
66 try std.testing.expectEqual(@as(?*Node, null), first.next);
67}
lib/c/stdlib.zig-100
...@@ -294,103 +294,3 @@ fn bsearch(key: *const anyopaque, base: *const anyopaque, n: usize, size: usize,...@@ -294,103 +294,3 @@ fn bsearch(key: *const anyopaque, base: *const anyopaque, n: usize, size: usize,
294 }294 }
295 return null;295 return null;
296}296}
297
298test abs {
299 const val: c_int = -10;
300 try std.testing.expectEqual(10, abs(val));
301}
302
303test labs {
304 const val: c_long = -10;
305 try std.testing.expectEqual(10, labs(val));
306}
307
308test llabs {
309 const val: c_longlong = -10;
310 try std.testing.expectEqual(10, llabs(val));
311}
312
313test div {
314 const expected: div_t = .{ .quot = 5, .rem = 5 };
315 try std.testing.expectEqual(expected, div(55, 10));
316}
317
318test ldiv {
319 const expected: ldiv_t = .{ .quot = -6, .rem = 2 };
320 try std.testing.expectEqual(expected, ldiv(38, -6));
321}
322
323test lldiv {
324 const expected: lldiv_t = .{ .quot = 1, .rem = 2 };
325 try std.testing.expectEqual(expected, lldiv(5, 3));
326}
327
328test atoi {
329 try std.testing.expectEqual(0, atoi(@ptrCast("stop42true")));
330 try std.testing.expectEqual(42, atoi(@ptrCast("42true")));
331 try std.testing.expectEqual(-1, atoi(@ptrCast("-01")));
332 try std.testing.expectEqual(1, atoi(@ptrCast("+001")));
333 try std.testing.expectEqual(100, atoi(@ptrCast(" 100")));
334 try std.testing.expectEqual(500, atoi(@ptrCast("000000000000500")));
335 try std.testing.expectEqual(1111, atoi(@ptrCast("0000000000001111_0000")));
336 try std.testing.expectEqual(0, atoi(@ptrCast("0xAA")));
337 try std.testing.expectEqual(700, atoi(@ptrCast("700B")));
338 try std.testing.expectEqual(32453, atoi(@ptrCast("+32453more")));
339 try std.testing.expectEqual(std.math.maxInt(c_int), atoi(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.maxInt(c_int)}))));
340 try std.testing.expectEqual(std.math.minInt(c_int), atoi(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.minInt(c_int)}))));
341}
342
343test atol {
344 try std.testing.expectEqual(0, atol(@ptrCast("stop42true")));
345 try std.testing.expectEqual(42, atol(@ptrCast("42true")));
346 try std.testing.expectEqual(-1, atol(@ptrCast("-01")));
347 try std.testing.expectEqual(1, atol(@ptrCast("+001")));
348 try std.testing.expectEqual(100, atol(@ptrCast(" 100")));
349 try std.testing.expectEqual(500, atol(@ptrCast("000000000000500")));
350 try std.testing.expectEqual(1111, atol(@ptrCast("0000000000001111_0000")));
351 try std.testing.expectEqual(0, atol(@ptrCast("0xAA")));
352 try std.testing.expectEqual(700, atol(@ptrCast("700B")));
353 try std.testing.expectEqual(32453, atol(@ptrCast("+32453more")));
354 try std.testing.expectEqual(std.math.maxInt(c_long), atol(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.maxInt(c_long)}))));
355 try std.testing.expectEqual(std.math.minInt(c_long), atol(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.minInt(c_long)}))));
356}
357
358test atoll {
359 try std.testing.expectEqual(0, atoll(@ptrCast("stop42true")));
360 try std.testing.expectEqual(42, atoll(@ptrCast("42true")));
361 try std.testing.expectEqual(-1, atoll(@ptrCast("-01")));
362 try std.testing.expectEqual(1, atoll(@ptrCast("+001")));
363 try std.testing.expectEqual(100, atoll(@ptrCast(" 100")));
364 try std.testing.expectEqual(500, atoll(@ptrCast("000000000000500")));
365 try std.testing.expectEqual(1111, atoll(@ptrCast("0000000000001111_0000")));
366 try std.testing.expectEqual(0, atoll(@ptrCast("0xAA")));
367 try std.testing.expectEqual(700, atoll(@ptrCast("700B")));
368 try std.testing.expectEqual(32453, atoll(@ptrCast(" +32453more")));
369 try std.testing.expectEqual(std.math.maxInt(c_longlong), atoll(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.maxInt(c_longlong)}))));
370 try std.testing.expectEqual(std.math.minInt(c_longlong), atoll(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.minInt(c_longlong)}))));
371}
372
373// FIXME: We cannot test strtol, strtoll, strtoul, etc.. here as it must modify errno and libc is not linked in tests
374
375test bsearch {
376 const Comparison = struct {
377 pub fn compare(a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int {
378 const a_u16: *const u16 = @ptrCast(@alignCast(a));
379 const b_u16: *const u16 = @ptrCast(@alignCast(b));
380
381 return switch (std.math.order(a_u16.*, b_u16.*)) {
382 .gt => 1,
383 .eq => 0,
384 .lt => -1,
385 };
386 }
387 };
388
389 const items: []const u16 = &.{ 0, 5, 7, 9, 10, 200, 512, 768 };
390
391 try std.testing.expectEqual(@as(?*anyopaque, null), bsearch(&@as(u16, 2000), items.ptr, items.len, @sizeOf(u16), Comparison.compare));
392
393 for (items) |*value| {
394 try std.testing.expectEqual(@as(*const anyopaque, value), bsearch(value, items.ptr, items.len, @sizeOf(u16), Comparison.compare));
395 }
396}
lib/c/stdlib/drand48.zig-57
...@@ -90,60 +90,3 @@ fn srand48(seedval: c_long) callconv(.c) void {...@@ -90,60 +90,3 @@ fn srand48(seedval: c_long) callconv(.c) void {
90 const xi = (@as(u32, @truncate(@as(c_ulong, @bitCast(seedval)))) << 16) | 0x330E;90 const xi = (@as(u32, @truncate(@as(c_ulong, @bitCast(seedval)))) << 16) | 0x330E;
91 lcg = .init(xi, default_multiplier, default_addend);91 lcg = .init(xi, default_multiplier, default_addend);
92}92}
93
94test erand48 {
95 var xsubi: [3]c_ushort = .{ 37174, 64810, 11603 };
96
97 try std.testing.expectApproxEqAbs(0.8965, erand48(&xsubi), 0.0005);
98 try std.testing.expectEqualSlices(c_ushort, &.{ 22537, 47966, 58735 }, &xsubi);
99
100 try std.testing.expectApproxEqAbs(0.3375, erand48(&xsubi), 0.0005);
101 try std.testing.expectEqualSlices(c_ushort, &.{ 37344, 32911, 22119 }, &xsubi);
102
103 try std.testing.expectApproxEqAbs(0.6475, erand48(&xsubi), 0.0005);
104 try std.testing.expectEqualSlices(c_ushort, &.{ 23659, 29872, 42445 }, &xsubi);
105
106 try std.testing.expectApproxEqAbs(0.5005, erand48(&xsubi), 0.0005);
107 try std.testing.expectEqualSlices(c_ushort, &.{ 31642, 7875, 32802 }, &xsubi);
108
109 try std.testing.expectApproxEqAbs(0.5065, erand48(&xsubi), 0.0005);
110 try std.testing.expectEqualSlices(c_ushort, &.{ 64669, 14399, 33170 }, &xsubi);
111}
112
113test jrand48 {
114 var xsubi: [3]c_ushort = .{ 25175, 11052, 45015 };
115
116 try std.testing.expectEqual(1699503220, jrand48(&xsubi));
117 try std.testing.expectEqualSlices(c_ushort, &.{ 2326, 23668, 25932 }, &xsubi);
118
119 try std.testing.expectEqual(-992276007, jrand48(&xsubi));
120 try std.testing.expectEqualSlices(c_ushort, &.{ 41577, 4569, 50395 }, &xsubi);
121
122 try std.testing.expectEqual(-19535776, jrand48(&xsubi));
123 try std.testing.expectEqualSlices(c_ushort, &.{ 31936, 59488, 65237 }, &xsubi);
124
125 try std.testing.expectEqual(79438377, jrand48(&xsubi));
126 try std.testing.expectEqualSlices(c_ushort, &.{ 40395, 8745, 1212 }, &xsubi);
127
128 try std.testing.expectEqual(-1258917728, jrand48(&xsubi));
129 try std.testing.expectEqualSlices(c_ushort, &.{ 37242, 28832, 46326 }, &xsubi);
130}
131
132test nrand48 {
133 var xsubi: [3]c_ushort = .{ 546, 33817, 23389 };
134
135 try std.testing.expectEqual(914920692, nrand48(&xsubi));
136 try std.testing.expectEqualSlices(c_ushort, &.{ 29829, 10728, 27921 }, &xsubi);
137
138 try std.testing.expectEqual(754104482, nrand48(&xsubi));
139 try std.testing.expectEqualSlices(c_ushort, &.{ 6828, 28997, 23013 }, &xsubi);
140
141 try std.testing.expectEqual(609453945, nrand48(&xsubi));
142 try std.testing.expectEqualSlices(c_ushort, &.{ 58183, 3826, 18599 }, &xsubi);
143
144 try std.testing.expectEqual(1878644360, nrand48(&xsubi));
145 try std.testing.expectEqualSlices(c_ushort, &.{ 36678, 44304, 57331 }, &xsubi);
146
147 try std.testing.expectEqual(2114923686, nrand48(&xsubi));
148 try std.testing.expectEqualSlices(c_ushort, &.{ 58585, 22861, 64542 }, &xsubi);
149}
lib/c/string.zig-7
...@@ -290,10 +290,3 @@ fn mempcpy(noalias dst: *anyopaque, noalias src: *const anyopaque, len: usize) c...@@ -290,10 +290,3 @@ fn mempcpy(noalias dst: *anyopaque, noalias src: *const anyopaque, len: usize) c
290 @memcpy(dst_bytes[0..len], src_bytes[0..len]);290 @memcpy(dst_bytes[0..len], src_bytes[0..len]);
291 return dst_bytes + len;291 return dst_bytes + len;
292}292}
293
294test strncmp {
295 try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
296 try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("c"), 1) < 0);
297 try std.testing.expect(strncmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
298 try std.testing.expect(strncmp(@ptrCast("\xff"), @ptrCast("\x02"), 1) > 0);
299}
lib/c/strings.zig-38
...@@ -81,41 +81,3 @@ fn __strncasecmp_l(a: [*:0]const c_char, b: [*:0]const c_char, n: usize, locale:...@@ -81,41 +81,3 @@ fn __strncasecmp_l(a: [*:0]const c_char, b: [*:0]const c_char, n: usize, locale:
81 _ = locale;81 _ = locale;
82 return strncasecmp(a, b, n);82 return strncasecmp(a, b, n);
83}83}
84
85test bzero {
86 var array: [10]u8 = [_]u8{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
87 var a = std.mem.zeroes([array.len]u8);
88 a[9] = '0';
89 bzero(&array[0], 9);
90 try std.testing.expect(std.mem.eql(u8, &array, &a));
91}
92
93test firstBitSet {
94 try std.testing.expectEqual(0, firstBitSet(usize, 0));
95
96 for (0..@bitSizeOf(usize)) |i| {
97 const bit = @as(usize, 1) << @intCast(i);
98
99 try std.testing.expectEqual(i + 1, firstBitSet(usize, bit));
100 }
101}
102
103test strcasecmp {
104 try std.testing.expect(strcasecmp(@ptrCast("a"), @ptrCast("b")) < 0);
105 try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("a")) > 0);
106 try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("b")) < 0);
107 try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("A")) > 0);
108 try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("A")) == 0);
109 try std.testing.expect(strcasecmp(@ptrCast("B"), @ptrCast("b")) == 0);
110 try std.testing.expect(strcasecmp(@ptrCast("bb"), @ptrCast("AA")) > 0);
111}
112
113test strncasecmp {
114 try std.testing.expect(strncasecmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
115 try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
116 try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("b"), 1) < 0);
117 try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("A"), 1) > 0);
118 try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("A"), 1) == 0);
119 try std.testing.expect(strncasecmp(@ptrCast("B"), @ptrCast("b"), 1) == 0);
120 try std.testing.expect(strncasecmp(@ptrCast("bb"), @ptrCast("AA"), 2) > 0);
121}
lib/c/unistd.zig-26
...@@ -206,32 +206,6 @@ fn swab(noalias src_ptr: *const anyopaque, noalias dest_ptr: *anyopaque, n: isiz...@@ -206,32 +206,6 @@ fn swab(noalias src_ptr: *const anyopaque, noalias dest_ptr: *anyopaque, n: isiz
206 }206 }
207}207}
208208
209test swab {
210 var a: [4]u8 = undefined;
211 @memset(a[0..], '\x00');
212 swab("abcd", &a, 4);
213 try std.testing.expectEqualSlices(u8, "badc", &a);
214
215 // Partial copy
216 @memset(a[0..], '\x00');
217 swab("abcd", &a, 2);
218 try std.testing.expectEqualSlices(u8, "ba\x00\x00", &a);
219
220 // n < 1
221 @memset(a[0..], '\x00');
222 swab("abcd", &a, 0);
223 try std.testing.expectEqualSlices(u8, "\x00" ** 4, &a);
224 swab("abcd", &a, -1);
225 try std.testing.expectEqualSlices(u8, "\x00" ** 4, &a);
226
227 // Odd n
228 @memset(a[0..], '\x00');
229 swab("abcd", &a, 1);
230 try std.testing.expectEqualSlices(u8, "\x00" ** 4, &a);
231 swab("abcd", &a, 3);
232 try std.testing.expectEqualSlices(u8, "ba\x00\x00", &a);
233}
234
235fn close(fd: std.c.fd_t) callconv(.c) c_int {209fn close(fd: std.c.fd_t) callconv(.c) c_int {
236 const signed: isize = @bitCast(linux.close(fd));210 const signed: isize = @bitCast(linux.close(fd));
237 if (signed < 0) {211 if (signed < 0) {
lib/std/c.zig+53-6
...@@ -11102,13 +11102,60 @@ pub const ioctl = switch (native_os) {...@@ -11102,13 +11102,60 @@ pub const ioctl = switch (native_os) {
11102 else => private.ioctl,11102 else => private.ioctl,
11103};11103};
1110411104
11105pub extern "c" fn bzero(s: *anyopaque, n: usize) void;
11106
11107pub extern "c" fn swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void;
11108
11109pub extern "c" fn strncmp(a: [*:0]const c_char, b: [*:0]const c_char, max: usize) c_int;
11110pub extern "c" fn strcasecmp(a: [*:0]const c_char, b: [*:0]const c_char) c_int;
11111pub extern "c" fn strncasecmp(a: [*:0]const c_char, b: [*:0]const c_char, max: usize) c_int;
11112
11113pub extern "c" fn ffs(i: c_int) c_int;
11114pub extern "c" fn ffsl(i: c_long) c_long;
11115pub extern "c" fn ffsll(i: c_longlong) c_longlong;
11116
11117pub extern "c" fn erand48(xsubi: *[3]c_ushort) f64;
11118pub extern "c" fn jrand48(xsubi: *[3]c_ushort) c_long;
11119pub extern "c" fn nrand48(xsubi: *[3]c_ushort) c_long;
11120
11121pub extern "c" fn insque(element: *anyopaque, pred: ?*anyopaque) void;
11122pub extern "c" fn remque(element: *anyopaque) void;
11123
11124pub extern "c" fn imaxabs(a: intmax_t) intmax_t;
11125pub extern "c" fn imaxdiv(a: intmax_t, b: intmax_t) imaxdiv_t;
11126
11127pub extern "c" fn abs(a: c_int) c_int;
11128pub extern "c" fn labs(a: c_long) c_long;
11129pub extern "c" fn llabs(a: c_longlong) c_longlong;
11130
11131pub extern "c" fn div(a: c_int, b: c_int) div_t;
11132pub extern "c" fn ldiv(a: c_long, b: c_long) ldiv_t;
11133pub extern "c" fn lldiv(a: c_longlong, b: c_longlong) lldiv_t;
11134
11135pub extern "c" fn atoi(str: [*:0]const c_char) c_int;
11136pub extern "c" fn atol(str: [*:0]const c_char) c_long;
11137pub extern "c" fn atoll(str: [*:0]const c_char) c_longlong;
11138
11139pub extern "c" fn bsearch(
11140 key: *const anyopaque,
11141 base: *const anyopaque,
11142 n: usize,
11143 size: usize,
11144 compare: *const fn (a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int,
11145) ?*anyopaque;
11146
11105// Math11147// Math
11106pub extern "c" fn atan(x: f64) callconv(.c) f64;11148pub extern "c" fn atan(x: f64) f64;
11107pub extern "c" fn copysign(x: f64, y: f64) callconv(.c) f64;11149pub extern "c" fn copysign(x: f64, y: f64) f64;
11108pub extern "c" fn fdim(x: f64, y: f64) callconv(.c) f64;11150pub extern "c" fn fdim(x: f64, y: f64) f64;
11109pub extern "c" fn frexp(x: f64, e: *c_int) callconv(.c) f64;11151pub extern "c" fn frexp(x: f64, e: *c_int) f64;
11110pub extern "c" fn hypot(x: f64, y: f64) callconv(.c) f64;11152pub extern "c" fn hypot(x: f64, y: f64) f64;
11111pub extern "c" fn modf(x: f64, iptr: *f64) callconv(.c) f64;11153pub extern "c" fn modff(x: f32, iptr: *f32) f32;
11154pub extern "c" fn modf(x: f64, iptr: *f64) f64;
11155pub extern "c" fn modfl(x: c_longdouble, iptr: *c_longdouble) c_longdouble;
11156pub extern "c" fn rintf(x: f32) f32;
11157pub extern "c" fn rint(x: f64) f64;
11158pub extern "c" fn rintl(x: c_longdouble) c_longdouble;
1111211159
11113// OS-specific bits. These are protected from being used on the wrong OS by11160// OS-specific bits. These are protected from being used on the wrong OS by
11114// comptime assertions inside each OS-specific file.11161// comptime assertions inside each OS-specific file.
test/c.zig created+12
...@@ -0,0 +1,12 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4test {
5 _ = @import("c/inttypes.zig");
6 _ = @import("c/math.zig");
7 _ = @import("c/search.zig");
8 _ = @import("c/stdlib.zig");
9 _ = @import("c/string.zig");
10 _ = @import("c/strings.zig");
11 _ = @import("c/unistd.zig");
12}
test/c/inttypes.zig created+15
...@@ -0,0 +1,15 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const testing = std.testing;
6
7test "imaxabs" {
8 const val: c.intmax_t = -10;
9 try testing.expectEqual(10, c.imaxabs(val));
10}
11
12test "imaxdiv" {
13 const expected: c.imaxdiv_t = .{ .quot = 9, .rem = 0 };
14 try testing.expectEqual(expected, c.imaxdiv(9, 1));
15}
test/c/math.zig created+101
...@@ -0,0 +1,101 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const math = std.math;
6const testing = std.testing;
7
8fn testModf(comptime T: type) !void {
9 const f = switch (T) {
10 f32 => c.modff,
11 f64 => c.modf,
12 c_longdouble => c.modfl,
13 else => unreachable,
14 };
15
16 var int: T = undefined;
17 const iptr = &int;
18 const eps_val: comptime_float = @max(1e-6, math.floatEps(T));
19
20 const normal_frac = f(@as(T, 1234.567), iptr);
21 // Account for precision error
22 const expected = 1234.567 - @as(T, 1234);
23 try testing.expectApproxEqAbs(expected, normal_frac, eps_val);
24 try testing.expectApproxEqRel(@as(T, 1234.0), iptr.*, eps_val);
25
26 // When `x` is a NaN, NaN is returned and `*iptr` is set to NaN
27 const nan_frac = f(math.nan(T), iptr);
28 try testing.expect(math.isNan(nan_frac));
29 try testing.expect(math.isNan(iptr.*));
30
31 // When `x` is positive infinity, +0 is returned and `*iptr` is set to
32 // positive infinity
33 const pos_zero_frac = f(math.inf(T), iptr);
34 try testing.expect(math.isPositiveZero(pos_zero_frac));
35 try testing.expect(math.isPositiveInf(iptr.*));
36
37 // When `x` is negative infinity, -0 is returned and `*iptr` is set to
38 // negative infinity
39 const neg_zero_frac = f(-math.inf(T), iptr);
40 try testing.expect(math.isNegativeZero(neg_zero_frac));
41 try testing.expect(math.isNegativeInf(iptr.*));
42
43 // Return -0 when `x` is a negative integer
44 const nz_frac = f(@as(T, -1000.0), iptr);
45 try testing.expect(math.isNegativeZero(nz_frac));
46 try testing.expectEqual(@as(T, -1000.0), iptr.*);
47
48 // Return +0 when `x` is a positive integer
49 const pz_frac = f(@as(T, 1000.0), iptr);
50 try testing.expect(math.isPositiveZero(pz_frac));
51 try testing.expectEqual(@as(T, 1000.0), iptr.*);
52}
53
54test "modf" {
55 try testModf(f32);
56 try testModf(f64);
57 try testModf(c_longdouble);
58}
59
60fn testRint(comptime T: type) !void {
61 const f = switch (T) {
62 f32 => c.rintf,
63 f64 => c.rint,
64 else => @compileError("rint not implemented for" ++ @typeName(T)),
65 };
66
67 // Positive numbers round correctly
68 try testing.expectEqual(@as(T, 42.0), f(42.2));
69 try testing.expectEqual(@as(T, 42.0), f(41.8));
70
71 // Negative numbers round correctly
72 try testing.expectEqual(@as(T, -6.0), f(-5.9));
73 try testing.expectEqual(@as(T, -6.0), f(-6.1));
74
75 // No rounding needed test
76 try testing.expectEqual(@as(T, 5.0), f(5.0));
77 try testing.expectEqual(@as(T, -10.0), f(-10.0));
78 try testing.expectEqual(@as(T, 0.0), f(0.0));
79
80 // Very large numbers return unchanged
81 const large: T = 9007199254740992.0; // 2^53
82 try testing.expectEqual(large, f(large));
83 try testing.expectEqual(-large, f(-large));
84
85 // Small positive numbers round to zero
86 const pos_result = f(0.3);
87 try testing.expect(math.isPositiveZero(pos_result));
88
89 // Small negative numbers round to negative zero
90 const neg_result = f(-0.3);
91 try testing.expect(math.isNegativeZero(neg_result));
92
93 // Exact half rounds to nearest even (banker's rounding)
94 try testing.expectEqual(@as(T, 2.0), f(2.5));
95 try testing.expectEqual(@as(T, 4.0), f(3.5));
96}
97
98test "rint" {
99 try testRint(f32);
100 try testRint(f64);
101}
test/c/search.zig created+38
...@@ -0,0 +1,38 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const testing = std.testing;
6
7/// Not defined in `std.c` because C headers don't either.
8const Node = extern struct {
9 next: ?*Node,
10 prev: ?*Node,
11};
12
13test "insque and remque" {
14 var first: Node = .{ .next = null, .prev = null };
15 var second: Node = .{ .next = null, .prev = null };
16 var third: Node = .{ .next = null, .prev = null };
17
18 c.insque(&first, null);
19 try testing.expectEqual(@as(?*Node, null), first.next);
20 try testing.expectEqual(@as(?*Node, null), first.prev);
21
22 c.insque(&second, &first);
23 try testing.expectEqual(@as(?*Node, &second), first.next);
24 try testing.expectEqual(@as(?*Node, &first), second.prev);
25
26 c.insque(&third, &first);
27 try testing.expectEqual(@as(?*Node, &third), first.next);
28 try testing.expectEqual(@as(?*Node, &second), third.next);
29 try testing.expectEqual(@as(?*Node, &first), third.prev);
30 try testing.expectEqual(@as(?*Node, &third), second.prev);
31
32 c.remque(&third);
33 try testing.expectEqual(@as(?*Node, &second), first.next);
34 try testing.expectEqual(@as(?*Node, &first), second.prev);
35
36 c.remque(&second);
37 try testing.expectEqual(@as(?*Node, null), first.next);
38}
test/c/stdlib.zig created+109
...@@ -0,0 +1,109 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const fmt = std.fmt;
6const math = std.math;
7const testing = std.testing;
8
9test "abs" {
10 const val: c_int = -10;
11 try testing.expectEqual(10, c.abs(val));
12}
13
14test "labs" {
15 const val: c_long = -10;
16 try testing.expectEqual(10, c.labs(val));
17}
18
19test "llabs" {
20 const val: c_longlong = -10;
21 try testing.expectEqual(10, c.llabs(val));
22}
23
24test "div" {
25 const expected: c.div_t = .{ .quot = 5, .rem = 5 };
26 try testing.expectEqual(expected, c.div(55, 10));
27}
28
29test "ldiv" {
30 const expected: c.ldiv_t = .{ .quot = -6, .rem = 2 };
31 try testing.expectEqual(expected, c.ldiv(38, -6));
32}
33
34test "lldiv" {
35 const expected: c.lldiv_t = .{ .quot = 1, .rem = 2 };
36 try testing.expectEqual(expected, c.lldiv(5, 3));
37}
38
39test "atoi" {
40 try testing.expectEqual(0, c.atoi(@ptrCast("stop42true")));
41 try testing.expectEqual(42, c.atoi(@ptrCast("42true")));
42 try testing.expectEqual(-1, c.atoi(@ptrCast("-01")));
43 try testing.expectEqual(1, c.atoi(@ptrCast("+001")));
44 try testing.expectEqual(100, c.atoi(@ptrCast(" 100")));
45 try testing.expectEqual(500, c.atoi(@ptrCast("000000000000500")));
46 try testing.expectEqual(1111, c.atoi(@ptrCast("0000000000001111_0000")));
47 try testing.expectEqual(0, c.atoi(@ptrCast("0xAA")));
48 try testing.expectEqual(700, c.atoi(@ptrCast("700B")));
49 try testing.expectEqual(32453, c.atoi(@ptrCast("+32453more")));
50 try testing.expectEqual(math.maxInt(c_int), c.atoi(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_int)}))));
51 try testing.expectEqual(math.minInt(c_int), c.atoi(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_int)}))));
52}
53
54test "atol" {
55 try testing.expectEqual(0, c.atol(@ptrCast("stop42true")));
56 try testing.expectEqual(42, c.atol(@ptrCast("42true")));
57 try testing.expectEqual(-1, c.atol(@ptrCast("-01")));
58 try testing.expectEqual(1, c.atol(@ptrCast("+001")));
59 try testing.expectEqual(100, c.atol(@ptrCast(" 100")));
60 try testing.expectEqual(500, c.atol(@ptrCast("000000000000500")));
61 try testing.expectEqual(1111, c.atol(@ptrCast("0000000000001111_0000")));
62 try testing.expectEqual(0, c.atol(@ptrCast("0xAA")));
63 try testing.expectEqual(700, c.atol(@ptrCast("700B")));
64 try testing.expectEqual(32453, c.atol(@ptrCast("+32453more")));
65 try testing.expectEqual(math.maxInt(c_long), c.atol(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_long)}))));
66 try testing.expectEqual(math.minInt(c_long), c.atol(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_long)}))));
67}
68
69test "atoll" {
70 try testing.expectEqual(0, c.atoll(@ptrCast("stop42true")));
71 try testing.expectEqual(42, c.atoll(@ptrCast("42true")));
72 try testing.expectEqual(-1, c.atoll(@ptrCast("-01")));
73 try testing.expectEqual(1, c.atoll(@ptrCast("+001")));
74 try testing.expectEqual(100, c.atoll(@ptrCast(" 100")));
75 try testing.expectEqual(500, c.atoll(@ptrCast("000000000000500")));
76 try testing.expectEqual(1111, c.atoll(@ptrCast("0000000000001111_0000")));
77 try testing.expectEqual(0, c.atoll(@ptrCast("0xAA")));
78 try testing.expectEqual(700, c.atoll(@ptrCast("700B")));
79 try testing.expectEqual(32453, c.atoll(@ptrCast(" +32453more")));
80 try testing.expectEqual(math.maxInt(c_longlong), c.atoll(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_longlong)}))));
81 try testing.expectEqual(math.minInt(c_longlong), c.atoll(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_longlong)}))));
82}
83
84test "bsearch" {
85 const Comparison = struct {
86 pub fn compare(a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int {
87 const a_u16: *const u16 = @ptrCast(@alignCast(a));
88 const b_u16: *const u16 = @ptrCast(@alignCast(b));
89
90 return switch (math.order(a_u16.*, b_u16.*)) {
91 .gt => 1,
92 .eq => 0,
93 .lt => -1,
94 };
95 }
96 };
97
98 const items: []const u16 = &.{ 0, 5, 7, 9, 10, 200, 512, 768 };
99
100 try testing.expectEqual(@as(?*anyopaque, null), c.bsearch(&@as(u16, 2000), items.ptr, items.len, @sizeOf(u16), Comparison.compare));
101
102 for (items) |*value| {
103 try testing.expectEqual(@as(*const anyopaque, value), c.bsearch(value, items.ptr, items.len, @sizeOf(u16), Comparison.compare));
104 }
105}
106
107test {
108 _ = @import("stdlib/drand48.zig");
109}
test/c/stdlib/drand48.zig created+62
...@@ -0,0 +1,62 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const testing = std.testing;
6
7test "erand48" {
8 var xsubi: [3]c_ushort = .{ 37174, 64810, 11603 };
9
10 try testing.expectApproxEqAbs(0.8965, c.erand48(&xsubi), 0.0005);
11 try testing.expectEqualSlices(c_ushort, &.{ 22537, 47966, 58735 }, &xsubi);
12
13 try testing.expectApproxEqAbs(0.3375, c.erand48(&xsubi), 0.0005);
14 try testing.expectEqualSlices(c_ushort, &.{ 37344, 32911, 22119 }, &xsubi);
15
16 try testing.expectApproxEqAbs(0.6475, c.erand48(&xsubi), 0.0005);
17 try testing.expectEqualSlices(c_ushort, &.{ 23659, 29872, 42445 }, &xsubi);
18
19 try testing.expectApproxEqAbs(0.5005, c.erand48(&xsubi), 0.0005);
20 try testing.expectEqualSlices(c_ushort, &.{ 31642, 7875, 32802 }, &xsubi);
21
22 try testing.expectApproxEqAbs(0.5065, c.erand48(&xsubi), 0.0005);
23 try testing.expectEqualSlices(c_ushort, &.{ 64669, 14399, 33170 }, &xsubi);
24}
25
26test "jrand48" {
27 var xsubi: [3]c_ushort = .{ 25175, 11052, 45015 };
28
29 try testing.expectEqual(1699503220, c.jrand48(&xsubi));
30 try testing.expectEqualSlices(c_ushort, &.{ 2326, 23668, 25932 }, &xsubi);
31
32 try testing.expectEqual(-992276007, c.jrand48(&xsubi));
33 try testing.expectEqualSlices(c_ushort, &.{ 41577, 4569, 50395 }, &xsubi);
34
35 try testing.expectEqual(-19535776, c.jrand48(&xsubi));
36 try testing.expectEqualSlices(c_ushort, &.{ 31936, 59488, 65237 }, &xsubi);
37
38 try testing.expectEqual(79438377, c.jrand48(&xsubi));
39 try testing.expectEqualSlices(c_ushort, &.{ 40395, 8745, 1212 }, &xsubi);
40
41 try testing.expectEqual(-1258917728, c.jrand48(&xsubi));
42 try testing.expectEqualSlices(c_ushort, &.{ 37242, 28832, 46326 }, &xsubi);
43}
44
45test "nrand48" {
46 var xsubi: [3]c_ushort = .{ 546, 33817, 23389 };
47
48 try testing.expectEqual(914920692, c.nrand48(&xsubi));
49 try testing.expectEqualSlices(c_ushort, &.{ 29829, 10728, 27921 }, &xsubi);
50
51 try testing.expectEqual(754104482, c.nrand48(&xsubi));
52 try testing.expectEqualSlices(c_ushort, &.{ 6828, 28997, 23013 }, &xsubi);
53
54 try testing.expectEqual(609453945, c.nrand48(&xsubi));
55 try testing.expectEqualSlices(c_ushort, &.{ 58183, 3826, 18599 }, &xsubi);
56
57 try testing.expectEqual(1878644360, c.nrand48(&xsubi));
58 try testing.expectEqualSlices(c_ushort, &.{ 36678, 44304, 57331 }, &xsubi);
59
60 try testing.expectEqual(2114923686, c.nrand48(&xsubi));
61 try testing.expectEqualSlices(c_ushort, &.{ 58585, 22861, 64542 }, &xsubi);
62}
test/c/string.zig created+12
...@@ -0,0 +1,12 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const testing = std.testing;
6
7test "strncmp" {
8 try testing.expect(c.strncmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
9 try testing.expect(c.strncmp(@ptrCast("a"), @ptrCast("c"), 1) < 0);
10 try testing.expect(c.strncmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
11 try testing.expect(c.strncmp(@ptrCast("\xff"), @ptrCast("\x02"), 1) > 0);
12}
test/c/strings.zig created+57
...@@ -0,0 +1,57 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const mem = std.mem;
6const testing = std.testing;
7
8test "bzero" {
9 var array: [10]u8 = [_]u8{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
10 var a = mem.zeroes([array.len]u8);
11 a[9] = '0';
12 c.bzero(&array[0], 9);
13 try testing.expect(mem.eql(u8, &array, &a));
14}
15
16fn testFfs(comptime T: type) !void {
17 const ffs = switch (T) {
18 c_int => c.ffs,
19 c_long => c.ffsl,
20 c_longlong => c.ffsll,
21 else => unreachable,
22 };
23
24 try testing.expectEqual(0, ffs(0));
25
26 for (0..@bitSizeOf(T)) |i| {
27 const bit = @as(T, 1) << @intCast(i);
28
29 try testing.expectEqual(@as(T, @intCast(i + 1)), ffs(bit));
30 }
31}
32
33test "ffs" {
34 try testFfs(c_int);
35 try testFfs(c_long);
36 try testFfs(c_longlong);
37}
38
39test "strcasecmp" {
40 try testing.expect(c.strcasecmp(@ptrCast("a"), @ptrCast("b")) < 0);
41 try testing.expect(c.strcasecmp(@ptrCast("b"), @ptrCast("a")) > 0);
42 try testing.expect(c.strcasecmp(@ptrCast("A"), @ptrCast("b")) < 0);
43 try testing.expect(c.strcasecmp(@ptrCast("b"), @ptrCast("A")) > 0);
44 try testing.expect(c.strcasecmp(@ptrCast("A"), @ptrCast("A")) == 0);
45 try testing.expect(c.strcasecmp(@ptrCast("B"), @ptrCast("b")) == 0);
46 try testing.expect(c.strcasecmp(@ptrCast("bb"), @ptrCast("AA")) > 0);
47}
48
49test "strncasecmp" {
50 try testing.expect(c.strncasecmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
51 try testing.expect(c.strncasecmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
52 try testing.expect(c.strncasecmp(@ptrCast("A"), @ptrCast("b"), 1) < 0);
53 try testing.expect(c.strncasecmp(@ptrCast("b"), @ptrCast("A"), 1) > 0);
54 try testing.expect(c.strncasecmp(@ptrCast("A"), @ptrCast("A"), 1) == 0);
55 try testing.expect(c.strncasecmp(@ptrCast("B"), @ptrCast("b"), 1) == 0);
56 try testing.expect(c.strncasecmp(@ptrCast("bb"), @ptrCast("AA"), 2) > 0);
57}
test/c/unistd.zig created+31
...@@ -0,0 +1,31 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const testing = std.testing;
6
7test "swab" {
8 var a: [4]u8 = undefined;
9 @memset(a[0..], '\x00');
10 c.swab("abcd", &a, 4);
11 try testing.expectEqualSlices(u8, "badc", &a);
12
13 // Partial copy
14 @memset(a[0..], '\x00');
15 c.swab("abcd", &a, 2);
16 try testing.expectEqualSlices(u8, "ba\x00\x00", &a);
17
18 // n < 1
19 @memset(a[0..], '\x00');
20 c.swab("abcd", &a, 0);
21 try testing.expectEqualSlices(u8, "\x00" ** 4, &a);
22 c.swab("abcd", &a, -1);
23 try testing.expectEqualSlices(u8, "\x00" ** 4, &a);
24
25 // Odd n
26 @memset(a[0..], '\x00');
27 c.swab("abcd", &a, 1);
28 try testing.expectEqualSlices(u8, "\x00" ** 4, &a);
29 c.swab("abcd", &a, 3);
30 try testing.expectEqualSlices(u8, "ba\x00\x00", &a);
31}
test/tests.zig+22-41
...@@ -18,7 +18,7 @@ pub const DebuggerContext = @import("src/Debugger.zig");...@@ -18,7 +18,7 @@ pub const DebuggerContext = @import("src/Debugger.zig");
18pub const LlvmIrContext = @import("src/LlvmIr.zig");18pub const LlvmIrContext = @import("src/LlvmIr.zig");
19pub const LibcContext = @import("src/Libc.zig");19pub const LibcContext = @import("src/Libc.zig");
2020
21const TestTarget = struct {21const ModuleTestTarget = struct {
22 linkage: ?std.builtin.LinkMode = null,22 linkage: ?std.builtin.LinkMode = null,
23 target: std.Target.Query = .{},23 target: std.Target.Query = .{},
24 optimize_mode: std.builtin.OptimizeMode = .Debug,24 optimize_mode: std.builtin.OptimizeMode = .Debug,
...@@ -36,33 +36,14 @@ const TestTarget = struct {...@@ -36,33 +36,14 @@ const TestTarget = struct {
36 // invocation. This could be because of a slow backend, requiring a newer LLVM version, being36 // invocation. This could be because of a slow backend, requiring a newer LLVM version, being
37 // too niche, etc.37 // too niche, etc.
38 extra_target: bool = false,38 extra_target: bool = false,
39
40 pub fn supportsModule(
41 self: *const TestTarget,
42 target: *const std.Build.ResolvedTarget,
43 name: []const u8,
44 ) bool {
45 if (mem.eql(u8, name, "zigc")) {
46 if (target.result.isMuslLibC()) return self.linkage == .static or (self.linkage == null and !target.query.isNative());
47 if (target.result.isMinGW()) return true;
48 if (target.result.isWasiLibC()) return true;
49 return false;
50 }
51 if (mem.eql(u8, name, "std")) {
52 if (target.result.cpu.arch.isSpirV()) return false;
53 return true;
54 }
55
56 return true;
57 }
58};39};
5940
60const test_targets = blk: {41const module_test_targets = blk: {
61 // getBaselineCpuFeatures calls populateDependencies which has a O(N ^ 2) algorithm42 // getBaselineCpuFeatures calls populateDependencies which has a O(N ^ 2) algorithm
62 // (where N is roughly 160, which technically makes it O(1), but it adds up to a43 // (where N is roughly 160, which technically makes it O(1), but it adds up to a
63 // lot of branches)44 // lot of branches)
64 @setEvalBranchQuota(80_000);45 @setEvalBranchQuota(80_000);
65 break :blk [_]TestTarget{46 break :blk [_]ModuleTestTarget{
66 // Native Targets47 // Native Targets
6748
68 .{}, // 0 index must be all defaults49 .{}, // 0 index must be all defaults
...@@ -2475,24 +2456,21 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2475,24 +2456,21 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2475 const step = b.step(b.fmt("test-{s}", .{options.name}), options.desc);2456 const step = b.step(b.fmt("test-{s}", .{options.name}), options.desc);
24762457
2477 if (options.test_only) |test_only| {2458 if (options.test_only) |test_only| {
2478 const test_target: TestTarget = switch (test_only) {2459 const test_target: ModuleTestTarget = switch (test_only) {
2479 .default => test_targets[0],2460 .default => module_test_targets[0],
2480 .fuzz => |optimize| .{2461 .fuzz => |optimize| .{
2481 .optimize_mode = optimize,2462 .optimize_mode = optimize,
2482 .use_llvm = true,2463 .use_llvm = true,
2483 },2464 },
2484 };2465 };
2485 const resolved_target = b.resolveTargetQuery(test_target.target);2466 const resolved_target = b.resolveTargetQuery(test_target.target);
24862467 const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM");
2487 if (test_target.supportsModule(&resolved_target, options.name)) {2468 addOneModuleTest(b, step, test_target, &resolved_target, triple_txt, options);
2488 const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM");
2489 addOneModuleTest(b, step, test_target, &resolved_target, triple_txt, options);
2490 }
24912469
2492 return step;2470 return step;
2493 }2471 }
24942472
2495 for_targets: for (test_targets) |test_target| {2473 for_targets: for (module_test_targets) |test_target| {
2496 if (test_target.skip_modules.len > 0) {2474 if (test_target.skip_modules.len > 0) {
2497 for (test_target.skip_modules) |skip_mod| {2475 for (test_target.skip_modules) |skip_mod| {
2498 if (std.mem.eql(u8, options.name, skip_mod)) continue :for_targets;2476 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 {...@@ -2501,8 +2479,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
25012479
2502 const resolved_target = b.resolveTargetQuery(test_target.target);2480 const resolved_target = b.resolveTargetQuery(test_target.target);
25032481
2504 if (!test_target.supportsModule(&resolved_target, options.name)) continue;
2505
2506 if (!options.test_extra_targets and test_target.extra_target) continue;2482 if (!options.test_extra_targets and test_target.extra_target) continue;
25072483
2508 if (options.skip_non_native and !test_target.target.isNative())2484 if (options.skip_non_native and !test_target.target.isNative())
...@@ -2510,6 +2486,13 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2510,6 +2486,13 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
25102486
2511 const target = &resolved_target.result;2487 const target = &resolved_target.result;
25122488
2489 if (std.mem.eql(u8, options.name, "libc")) {
2490 // The libc API tests obviously need to link libc. So for test
2491 // target entries where we wouldn't link libc by default, skip the
2492 // libc API tests.
2493 if (test_target.link_libc == null and !std.os.targetRequiresLibC(target)) continue;
2494 }
2495
2513 if (options.skip_spirv and target.cpu.arch.isSpirV()) continue;2496 if (options.skip_spirv and target.cpu.arch.isSpirV()) continue;
2514 if (options.skip_wasm and target.cpu.arch.isWasm()) continue;2497 if (options.skip_wasm and target.cpu.arch.isWasm()) continue;
25152498
...@@ -2544,8 +2527,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2544,8 +2527,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2544 if (!would_use_llvm and target.cpu.arch == .aarch64) {2527 if (!would_use_llvm and target.cpu.arch == .aarch64) {
2545 // TODO get std tests passing for the aarch64 self-hosted backend.2528 // TODO get std tests passing for the aarch64 self-hosted backend.
2546 if (mem.eql(u8, options.name, "std")) continue;2529 if (mem.eql(u8, options.name, "std")) continue;
2547 // TODO get zigc tests passing for the aarch64 self-hosted backend.
2548 if (mem.eql(u8, options.name, "zigc")) continue;
2549 }2530 }
25502531
2551 const want_this_mode = for (options.optimize_modes) |m| {2532 const want_this_mode = for (options.optimize_modes) |m| {
...@@ -2561,7 +2542,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2561,7 +2542,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2561fn addOneModuleTest(2542fn addOneModuleTest(
2562 b: *std.Build,2543 b: *std.Build,
2563 step: *Step,2544 step: *Step,
2564 test_target: TestTarget,2545 test_target: ModuleTestTarget,
2565 resolved_target: *const std.Build.ResolvedTarget,2546 resolved_target: *const std.Build.ResolvedTarget,
2566 triple_txt: []const u8,2547 triple_txt: []const u8,
2567 options: ModuleTestOptions,2548 options: ModuleTestOptions,
...@@ -2598,11 +2579,11 @@ fn addOneModuleTest(...@@ -2598,11 +2579,11 @@ fn addOneModuleTest(
2598 });2579 });
2599 these_tests.linkage = test_target.linkage;2580 these_tests.linkage = test_target.linkage;
2600 // https://codeberg.org/ziglang/zig/issues/317012581 // https://codeberg.org/ziglang/zig/issues/31701
2601 if (!(mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "zigc"))) {2582 if (!(mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "libc"))) {
2602 if (options.no_builtin) these_tests.root_module.no_builtin = true;2583 if (options.no_builtin) these_tests.root_module.no_builtin = true;
2603 }2584 }
2604 // https://codeberg.org/ziglang/zig/issues/317022585 // https://codeberg.org/ziglang/zig/issues/31702
2605 if (mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "zigc")) {2586 if (mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "libc")) {
2606 these_tests.root_module.stack_protector = false;2587 these_tests.root_module.stack_protector = false;
2607 }2588 }
2608 if (options.build_options) |build_options| {2589 if (options.build_options) |build_options| {
...@@ -2992,7 +2973,7 @@ pub fn addLlvmIrTests(b: *std.Build, options: LlvmIrContext.Options) ?*Step {...@@ -2992,7 +2973,7 @@ pub fn addLlvmIrTests(b: *std.Build, options: LlvmIrContext.Options) ?*Step {
2992 return step;2973 return step;
2993}2974}
29942975
2995const libc_targets: []const std.Target.Query = &.{2976const libc_test_nsz_targets: []const std.Target.Query = &.{
2996 .{2977 .{
2997 .cpu_arch = .arm,2978 .cpu_arch = .arm,
2998 .os_tag = .linux,2979 .os_tag = .linux,
...@@ -3155,8 +3136,8 @@ const libc_targets: []const std.Target.Query = &.{...@@ -3155,8 +3136,8 @@ const libc_targets: []const std.Target.Query = &.{
3155 },3136 },
3156};3137};
31573138
3158pub fn addLibcTests(b: *std.Build, options: LibcContext.Options) ?*Step {3139pub fn addLibcTestNszTests(b: *std.Build, options: LibcContext.Options) ?*Step {
3159 const step = b.step("test-libc", "Run libc-test test cases");3140 const step = b.step("test-libc-nsz", "Run external libc-test test cases");
3160 const opt_libc_test_path = b.option(std.Build.LazyPath, "libc-test-path", "path to libc-test source directory");3141 const opt_libc_test_path = b.option(std.Build.LazyPath, "libc-test-path", "path to libc-test source directory");
3161 if (opt_libc_test_path) |libc_test_path| {3142 if (opt_libc_test_path) |libc_test_path| {
3162 var context: LibcContext = .{3143 var context: LibcContext = .{
...@@ -3168,7 +3149,7 @@ pub fn addLibcTests(b: *std.Build, options: LibcContext.Options) ?*Step {...@@ -3168,7 +3149,7 @@ pub fn addLibcTests(b: *std.Build, options: LibcContext.Options) ?*Step {
31683149
3169 libc.addCases(&context);3150 libc.addCases(&context);
31703151
3171 for (libc_targets) |target_query| {3152 for (libc_test_nsz_targets) |target_query| {
3172 const target = b.resolveTargetQuery(target_query);3153 const target = b.resolveTargetQuery(target_query);
3173 context.addTarget(target);3154 context.addTarget(target);
3174 }3155 }