authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-04-17 22:31:35+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-04-17 22:31:35+02:00
log6e987a1d04e5d9eb41a10110a5343384f0a9a57b
treef82b5fe8e3e17c50628ae0b9a3c46ecdfca6e2ae
parentb0ef8d3610ab18eb499eb351e302ecc3ab5aea78
parent6612e7cdb26a761392f129525872bd00758095c2

Merge pull request 'libzigc: move all unit tests from `lib/c/` to `test/c/`' (#31923) from alexrp/zig:libc-test-refactor into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31923 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

24 files changed, 621 insertions(+), 445 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.
lib/std/os.zig+41
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std.zig");
2const native_os = builtin.os.tag;3const native_os = builtin.os.tag;
34
4pub const linux = @import("os/linux.zig");5pub const linux = @import("os/linux.zig");
...@@ -8,6 +9,46 @@ pub const wasi = @import("os/wasi.zig");...@@ -8,6 +9,46 @@ pub const wasi = @import("os/wasi.zig");
8pub const emscripten = @import("os/emscripten.zig");9pub const emscripten = @import("os/emscripten.zig");
9pub const windows = @import("os/windows.zig");10pub const windows = @import("os/windows.zig");
1011
12/// Returns whether the Zig standard library requires libc in order to interface
13/// with the operating system on the given target.
14pub fn targetRequiresLibC(target: *const std.Target) bool {
15 if (target.requiresLibC()) return true;
16 return switch (target.os.tag) {
17 .linux => switch (target.cpu.arch) {
18 // https://codeberg.org/ziglang/zig/issues/30940
19 .alpha,
20 // https://codeberg.org/ziglang/zig/issues/30942
21 .csky,
22 // https://codeberg.org/ziglang/zig/issues/30943
23 .hppa,
24 .hppa64,
25 // https://codeberg.org/ziglang/zig/issues/30944
26 .microblaze,
27 .microblazeel,
28 // https://codeberg.org/ziglang/zig/issues/30946
29 .sh,
30 .sheb,
31 // https://codeberg.org/ziglang/zig/issues/30945
32 .sparc,
33 // https://codeberg.org/ziglang/zig/issues/30947
34 .xtensa,
35 .xtensaeb,
36 => true,
37 else => false,
38 },
39 .freebsd => true, // https://codeberg.org/ziglang/zig/issues/30981
40 .netbsd => true, // https://codeberg.org/ziglang/zig/issues/30980
41 .openbsd => true, // https://codeberg.org/ziglang/zig/issues/30982
42 else => false,
43 };
44}
45
46/// Returns whether the Zig standard library requires libc in order to interface
47/// with the operating system on the current target.
48pub fn requiresLibC() bool {
49 return targetRequiresLibC(&builtin.target);
50}
51
11test {52test {
12 _ = linux;53 _ = linux;
13 if (native_os == .uefi) _ = uefi;54 if (native_os == .uefi) _ = uefi;
src/Compilation/Config.zig+1-10
...@@ -234,19 +234,10 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -234,19 +234,10 @@ pub fn resolve(options: Options) ResolveError!Config {
234 break :b true;234 break :b true;
235 }235 }
236 if (options.link_libc) |x| break :b x;236 if (options.link_libc) |x| break :b x;
237 switch (target.os.tag) {
238 // These targets don't require libc, but we don't yet have a syscall layer for them,
239 // so we default to linking libc for now.
240 .freebsd,
241 .netbsd,
242 .openbsd,
243 => break :b true,
244 else => {},
245 }
246 if (options.ensure_libc_on_non_freestanding and target.os.tag != .freestanding)237 if (options.ensure_libc_on_non_freestanding and target.os.tag != .freestanding)
247 break :b true;238 break :b true;
248239
249 break :b target.requiresLibC();240 break :b std.os.targetRequiresLibC(target);
250 };241 };
251242
252 const link_mode = b: {243 const link_mode = b: {
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+18
...@@ -0,0 +1,18 @@
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 if (builtin.target.cpu.arch.isPowerPC32()) return error.SkipZigTest; // TODO
14 if (builtin.target.cpu.arch == .s390x) return error.SkipZigTest; // TODO
15
16 const expected: c.imaxdiv_t = .{ .quot = 9, .rem = 0 };
17 try testing.expectEqual(expected, c.imaxdiv(9, 1));
18}
test/c/math.zig created+104
...@@ -0,0 +1,104 @@
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
58 if (builtin.target.cpu.arch.isPowerPC()) return error.SkipZigTest; // TODO
59
60 try testModf(c_longdouble);
61}
62
63fn testRint(comptime T: type) !void {
64 const f = switch (T) {
65 f32 => c.rintf,
66 f64 => c.rint,
67 else => @compileError("rint not implemented for" ++ @typeName(T)),
68 };
69
70 // Positive numbers round correctly
71 try testing.expectEqual(@as(T, 42.0), f(42.2));
72 try testing.expectEqual(@as(T, 42.0), f(41.8));
73
74 // Negative numbers round correctly
75 try testing.expectEqual(@as(T, -6.0), f(-5.9));
76 try testing.expectEqual(@as(T, -6.0), f(-6.1));
77
78 // No rounding needed test
79 try testing.expectEqual(@as(T, 5.0), f(5.0));
80 try testing.expectEqual(@as(T, -10.0), f(-10.0));
81 try testing.expectEqual(@as(T, 0.0), f(0.0));
82
83 // Very large numbers return unchanged
84 const large: T = 9007199254740992.0; // 2^53
85 try testing.expectEqual(large, f(large));
86 try testing.expectEqual(-large, f(-large));
87
88 // Small positive numbers round to zero
89 const pos_result = f(0.3);
90 try testing.expect(math.isPositiveZero(pos_result));
91
92 // Small negative numbers round to negative zero
93 const neg_result = f(-0.3);
94 try testing.expect(math.isNegativeZero(neg_result));
95
96 // Exact half rounds to nearest even (banker's rounding)
97 try testing.expectEqual(@as(T, 2.0), f(2.5));
98 try testing.expectEqual(@as(T, 4.0), f(3.5));
99}
100
101test "rint" {
102 try testRint(f32);
103 try testRint(f64);
104}
test/c/search.zig created+40
...@@ -0,0 +1,40 @@
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 if (builtin.target.os.tag == .windows) return; // no insque/remque
15
16 var first: Node = .{ .next = null, .prev = null };
17 var second: Node = .{ .next = null, .prev = null };
18 var third: Node = .{ .next = null, .prev = null };
19
20 c.insque(&first, null);
21 try testing.expectEqual(@as(?*Node, null), first.next);
22 try testing.expectEqual(@as(?*Node, null), first.prev);
23
24 c.insque(&second, &first);
25 try testing.expectEqual(@as(?*Node, &second), first.next);
26 try testing.expectEqual(@as(?*Node, &first), second.prev);
27
28 c.insque(&third, &first);
29 try testing.expectEqual(@as(?*Node, &third), first.next);
30 try testing.expectEqual(@as(?*Node, &second), third.next);
31 try testing.expectEqual(@as(?*Node, &first), third.prev);
32 try testing.expectEqual(@as(?*Node, &third), second.prev);
33
34 c.remque(&third);
35 try testing.expectEqual(@as(?*Node, &second), first.next);
36 try testing.expectEqual(@as(?*Node, &first), second.prev);
37
38 c.remque(&second);
39 try testing.expectEqual(@as(?*Node, null), first.next);
40}
test/c/stdlib.zig created+125
...@@ -0,0 +1,125 @@
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 if (builtin.target.cpu.arch.isMIPS64()) return error.SkipZigTest; // TODO
11
12 const val: c_int = -10;
13 try testing.expectEqual(10, c.abs(val));
14}
15
16test "labs" {
17 if (builtin.target.cpu.arch.isMIPS64() and @sizeOf(usize) == 4) return error.SkipZigTest; // TODO
18
19 const val: c_long = -10;
20 try testing.expectEqual(10, c.labs(val));
21}
22
23test "llabs" {
24 const val: c_longlong = -10;
25 try testing.expectEqual(10, c.llabs(val));
26}
27
28test "div" {
29 if (builtin.target.cpu.arch.isLoongArch()) return error.SkipZigTest; // TODO
30 if (builtin.target.cpu.arch.isMIPS64()) return error.SkipZigTest; // TODO
31 if (builtin.target.cpu.arch.isPowerPC()) return error.SkipZigTest; // TODO
32 if (builtin.target.cpu.arch == .s390x) return error.SkipZigTest; // TODO
33
34 const expected: c.div_t = .{ .quot = 5, .rem = 5 };
35 try testing.expectEqual(expected, c.div(55, 10));
36}
37
38test "ldiv" {
39 if (builtin.target.cpu.arch.isMIPS64() and @sizeOf(usize) == 4) return error.SkipZigTest; // TODO
40 if (builtin.target.cpu.arch.isPowerPC32()) return error.SkipZigTest; // TODO
41 if (builtin.target.cpu.arch == .s390x) return error.SkipZigTest; // TODO
42
43 const expected: c.ldiv_t = .{ .quot = -6, .rem = 2 };
44 try testing.expectEqual(expected, c.ldiv(38, -6));
45}
46
47test "lldiv" {
48 if (builtin.target.cpu.arch.isPowerPC32()) return error.SkipZigTest; // TODO
49 if (builtin.target.cpu.arch == .s390x) return error.SkipZigTest; // TODO
50
51 const expected: c.lldiv_t = .{ .quot = 1, .rem = 2 };
52 try testing.expectEqual(expected, c.lldiv(5, 3));
53}
54
55test "atoi" {
56 try testing.expectEqual(0, c.atoi(@ptrCast("stop42true")));
57 try testing.expectEqual(42, c.atoi(@ptrCast("42true")));
58 try testing.expectEqual(-1, c.atoi(@ptrCast("-01")));
59 try testing.expectEqual(1, c.atoi(@ptrCast("+001")));
60 try testing.expectEqual(100, c.atoi(@ptrCast(" 100")));
61 try testing.expectEqual(500, c.atoi(@ptrCast("000000000000500")));
62 try testing.expectEqual(1111, c.atoi(@ptrCast("0000000000001111_0000")));
63 try testing.expectEqual(0, c.atoi(@ptrCast("0xAA")));
64 try testing.expectEqual(700, c.atoi(@ptrCast("700B")));
65 try testing.expectEqual(32453, c.atoi(@ptrCast("+32453more")));
66 try testing.expectEqual(math.maxInt(c_int), c.atoi(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_int)}))));
67 try testing.expectEqual(math.minInt(c_int), c.atoi(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_int)}))));
68}
69
70test "atol" {
71 try testing.expectEqual(0, c.atol(@ptrCast("stop42true")));
72 try testing.expectEqual(42, c.atol(@ptrCast("42true")));
73 try testing.expectEqual(-1, c.atol(@ptrCast("-01")));
74 try testing.expectEqual(1, c.atol(@ptrCast("+001")));
75 try testing.expectEqual(100, c.atol(@ptrCast(" 100")));
76 try testing.expectEqual(500, c.atol(@ptrCast("000000000000500")));
77 try testing.expectEqual(1111, c.atol(@ptrCast("0000000000001111_0000")));
78 try testing.expectEqual(0, c.atol(@ptrCast("0xAA")));
79 try testing.expectEqual(700, c.atol(@ptrCast("700B")));
80 try testing.expectEqual(32453, c.atol(@ptrCast("+32453more")));
81 try testing.expectEqual(math.maxInt(c_long), c.atol(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_long)}))));
82 try testing.expectEqual(math.minInt(c_long), c.atol(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_long)}))));
83}
84
85test "atoll" {
86 try testing.expectEqual(0, c.atoll(@ptrCast("stop42true")));
87 try testing.expectEqual(42, c.atoll(@ptrCast("42true")));
88 try testing.expectEqual(-1, c.atoll(@ptrCast("-01")));
89 try testing.expectEqual(1, c.atoll(@ptrCast("+001")));
90 try testing.expectEqual(100, c.atoll(@ptrCast(" 100")));
91 try testing.expectEqual(500, c.atoll(@ptrCast("000000000000500")));
92 try testing.expectEqual(1111, c.atoll(@ptrCast("0000000000001111_0000")));
93 try testing.expectEqual(0, c.atoll(@ptrCast("0xAA")));
94 try testing.expectEqual(700, c.atoll(@ptrCast("700B")));
95 try testing.expectEqual(32453, c.atoll(@ptrCast(" +32453more")));
96 try testing.expectEqual(math.maxInt(c_longlong), c.atoll(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_longlong)}))));
97 try testing.expectEqual(math.minInt(c_longlong), c.atoll(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_longlong)}))));
98}
99
100test "bsearch" {
101 const Comparison = struct {
102 pub fn compare(a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int {
103 const a_u16: *const u16 = @ptrCast(@alignCast(a));
104 const b_u16: *const u16 = @ptrCast(@alignCast(b));
105
106 return switch (math.order(a_u16.*, b_u16.*)) {
107 .gt => 1,
108 .eq => 0,
109 .lt => -1,
110 };
111 }
112 };
113
114 const items: []const u16 = &.{ 0, 5, 7, 9, 10, 200, 512, 768 };
115
116 try testing.expectEqual(@as(?*anyopaque, null), c.bsearch(&@as(u16, 2000), items.ptr, items.len, @sizeOf(u16), Comparison.compare));
117
118 for (items) |*value| {
119 try testing.expectEqual(@as(*const anyopaque, value), c.bsearch(value, items.ptr, items.len, @sizeOf(u16), Comparison.compare));
120 }
121}
122
123test {
124 _ = @import("stdlib/drand48.zig");
125}
test/c/stdlib/drand48.zig created+70
...@@ -0,0 +1,70 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const testing = std.testing;
6
7test "erand48" {
8 if (builtin.target.os.tag == .windows) return; // no erand48
9
10 var xsubi: [3]c_ushort = .{ 37174, 64810, 11603 };
11
12 try testing.expectApproxEqAbs(0.8965, c.erand48(&xsubi), 0.0005);
13 try testing.expectEqualSlices(c_ushort, &.{ 22537, 47966, 58735 }, &xsubi);
14
15 try testing.expectApproxEqAbs(0.3375, c.erand48(&xsubi), 0.0005);
16 try testing.expectEqualSlices(c_ushort, &.{ 37344, 32911, 22119 }, &xsubi);
17
18 try testing.expectApproxEqAbs(0.6475, c.erand48(&xsubi), 0.0005);
19 try testing.expectEqualSlices(c_ushort, &.{ 23659, 29872, 42445 }, &xsubi);
20
21 try testing.expectApproxEqAbs(0.5005, c.erand48(&xsubi), 0.0005);
22 try testing.expectEqualSlices(c_ushort, &.{ 31642, 7875, 32802 }, &xsubi);
23
24 try testing.expectApproxEqAbs(0.5065, c.erand48(&xsubi), 0.0005);
25 try testing.expectEqualSlices(c_ushort, &.{ 64669, 14399, 33170 }, &xsubi);
26}
27
28test "jrand48" {
29 if (builtin.target.os.tag == .windows) return; // no jrand48
30
31 if (builtin.target.os.tag == .openbsd) return error.SkipZigTest; // TODO
32
33 var xsubi: [3]c_ushort = .{ 25175, 11052, 45015 };
34
35 try testing.expectEqual(1699503220, c.jrand48(&xsubi));
36 try testing.expectEqualSlices(c_ushort, &.{ 2326, 23668, 25932 }, &xsubi);
37
38 try testing.expectEqual(-992276007, c.jrand48(&xsubi));
39 try testing.expectEqualSlices(c_ushort, &.{ 41577, 4569, 50395 }, &xsubi);
40
41 try testing.expectEqual(-19535776, c.jrand48(&xsubi));
42 try testing.expectEqualSlices(c_ushort, &.{ 31936, 59488, 65237 }, &xsubi);
43
44 try testing.expectEqual(79438377, c.jrand48(&xsubi));
45 try testing.expectEqualSlices(c_ushort, &.{ 40395, 8745, 1212 }, &xsubi);
46
47 try testing.expectEqual(-1258917728, c.jrand48(&xsubi));
48 try testing.expectEqualSlices(c_ushort, &.{ 37242, 28832, 46326 }, &xsubi);
49}
50
51test "nrand48" {
52 if (builtin.target.os.tag == .windows) return; // no nrand48
53
54 var xsubi: [3]c_ushort = .{ 546, 33817, 23389 };
55
56 try testing.expectEqual(914920692, c.nrand48(&xsubi));
57 try testing.expectEqualSlices(c_ushort, &.{ 29829, 10728, 27921 }, &xsubi);
58
59 try testing.expectEqual(754104482, c.nrand48(&xsubi));
60 try testing.expectEqualSlices(c_ushort, &.{ 6828, 28997, 23013 }, &xsubi);
61
62 try testing.expectEqual(609453945, c.nrand48(&xsubi));
63 try testing.expectEqualSlices(c_ushort, &.{ 58183, 3826, 18599 }, &xsubi);
64
65 try testing.expectEqual(1878644360, c.nrand48(&xsubi));
66 try testing.expectEqualSlices(c_ushort, &.{ 36678, 44304, 57331 }, &xsubi);
67
68 try testing.expectEqual(2114923686, c.nrand48(&xsubi));
69 try testing.expectEqualSlices(c_ushort, &.{ 58585, 22861, 64542 }, &xsubi);
70}
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+68
...@@ -0,0 +1,68 @@
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 if (builtin.target.os.tag == .windows) return; // no bzero
10
11 var array: [10]u8 = [_]u8{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
12 var a = mem.zeroes([array.len]u8);
13 a[9] = '0';
14 c.bzero(&array[0], 9);
15 try testing.expect(mem.eql(u8, &array, &a));
16}
17
18fn testFfs(comptime T: type) !void {
19 const ffs = switch (T) {
20 c_int => c.ffs,
21 c_long => c.ffsl,
22 c_longlong => c.ffsll,
23 else => unreachable,
24 };
25
26 try testing.expectEqual(0, ffs(0));
27
28 for (0..@bitSizeOf(T)) |i| {
29 const bit = @as(T, 1) << @intCast(i);
30
31 try testing.expectEqual(@as(T, @intCast(i + 1)), ffs(bit));
32 }
33}
34
35test "ffs" {
36 if (builtin.target.os.tag == .openbsd) return; // no ffsl/ffsll
37 if (builtin.target.os.tag == .windows) return; // no ffs
38
39 try testFfs(c_int);
40
41 if (builtin.target.os.tag == .netbsd) return; // no ffsl/ffsll until 11
42
43 try testFfs(c_long);
44
45 if (@sizeOf(usize) == 4) return error.SkipZigTest; // TODO
46
47 try testFfs(c_longlong);
48}
49
50test "strcasecmp" {
51 try testing.expect(c.strcasecmp(@ptrCast("a"), @ptrCast("b")) < 0);
52 try testing.expect(c.strcasecmp(@ptrCast("b"), @ptrCast("a")) > 0);
53 try testing.expect(c.strcasecmp(@ptrCast("A"), @ptrCast("b")) < 0);
54 try testing.expect(c.strcasecmp(@ptrCast("b"), @ptrCast("A")) > 0);
55 try testing.expect(c.strcasecmp(@ptrCast("A"), @ptrCast("A")) == 0);
56 try testing.expect(c.strcasecmp(@ptrCast("B"), @ptrCast("b")) == 0);
57 try testing.expect(c.strcasecmp(@ptrCast("bb"), @ptrCast("AA")) > 0);
58}
59
60test "strncasecmp" {
61 try testing.expect(c.strncasecmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
62 try testing.expect(c.strncasecmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
63 try testing.expect(c.strncasecmp(@ptrCast("A"), @ptrCast("b"), 1) < 0);
64 try testing.expect(c.strncasecmp(@ptrCast("b"), @ptrCast("A"), 1) > 0);
65 try testing.expect(c.strncasecmp(@ptrCast("A"), @ptrCast("A"), 1) == 0);
66 try testing.expect(c.strncasecmp(@ptrCast("B"), @ptrCast("b"), 1) == 0);
67 try testing.expect(c.strncasecmp(@ptrCast("bb"), @ptrCast("AA"), 2) > 0);
68}
test/c/unistd.zig created+35
...@@ -0,0 +1,35 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const c = std.c;
5const testing = std.testing;
6
7test "swab" {
8 if (builtin.target.cpu.arch.isMIPS64() and @sizeOf(usize) == 4) return error.SkipZigTest; // TODO
9 if (builtin.target.cpu.arch == .x86_64 and @sizeOf(usize) == 4) return error.SkipZigTest; // TODO
10 if (builtin.target.os.tag == .netbsd) return error.SkipZigTest; // TODO
11
12 var a: [4]u8 = undefined;
13 @memset(a[0..], '\x00');
14 c.swab("abcd", &a, 4);
15 try testing.expectEqualSlices(u8, "badc", &a);
16
17 // Partial copy
18 @memset(a[0..], '\x00');
19 c.swab("abcd", &a, 2);
20 try testing.expectEqualSlices(u8, "ba\x00\x00", &a);
21
22 // n < 1
23 @memset(a[0..], '\x00');
24 c.swab("abcd", &a, 0);
25 try testing.expectEqualSlices(u8, "\x00" ** 4, &a);
26 c.swab("abcd", &a, -1);
27 try testing.expectEqualSlices(u8, "\x00" ** 4, &a);
28
29 // Odd n
30 @memset(a[0..], '\x00');
31 c.swab("abcd", &a, 1);
32 try testing.expectEqualSlices(u8, "\x00" ** 4, &a);
33 c.swab("abcd", &a, 3);
34 try testing.expectEqualSlices(u8, "ba\x00\x00", &a);
35}
test/src/StackTrace.zig+1-4
...@@ -58,10 +58,7 @@ fn addCaseTarget(...@@ -58,10 +58,7 @@ fn addCaseTarget(
58 .fuchsia => false,58 .fuchsia => false,
59 else => true,59 else => true,
60 };60 };
61 const both_libc = switch (target.result.os.tag) {61 const both_libc = !std.os.targetRequiresLibC(&target.result);
62 .freebsd, .netbsd, .openbsd => false,
63 else => !target.result.requiresLibC(),
64 };
6562
66 // See `std.debug.StackIterator.fp_usability` logic.63 // See `std.debug.StackIterator.fp_usability` logic.
67 const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.result.cpu.arch) {64 const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.result.cpu.arch) {
test/tests.zig+23-42
...@@ -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
...@@ -2531,7 +2514,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2531,7 +2514,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2531 } else continue;2514 } else continue;
2532 }2515 }
25332516
2534 if (options.skip_libc and test_target.link_libc == true)2517 if (options.skip_libc and (test_target.link_libc == true or std.os.targetRequiresLibC(target)))
2535 continue;2518 continue;
25362519
2537 // We can't provide MSVC libc when cross-compiling.2520 // We can't provide MSVC libc when cross-compiling.
...@@ -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 }