authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-28 18:13:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:52-07:00
loga45cafb7f0d182be9d2652229583297e55eac5c1
tree871375801e207e4954a1f1b974535fe8ac43b645
parentc40204a3e521b82094fb44b2ce412f47d05964b2

std.Io: add unit test for select


2 files changed, 46 insertions(+), 19 deletions(-)

lib/std/Io.zig+2-2
...@@ -1632,7 +1632,7 @@ pub fn SelectUnion(S: type) type {...@@ -1632,7 +1632,7 @@ pub fn SelectUnion(S: type) type {
16321632
1633/// `s` is a struct with every field a `*Future(T)`, where `T` can be any type,1633/// `s` is a struct with every field a `*Future(T)`, where `T` can be any type,
1634/// and can be different for each field.1634/// and can be different for each field.
1635pub fn select(io: Io, s: anytype) SelectUnion(@TypeOf(s)) {1635pub fn select(io: Io, s: anytype) Cancelable!SelectUnion(@TypeOf(s)) {
1636 const U = SelectUnion(@TypeOf(s));1636 const U = SelectUnion(@TypeOf(s));
1637 const S = @TypeOf(s);1637 const S = @TypeOf(s);
1638 const fields = @typeInfo(S).@"struct".fields;1638 const fields = @typeInfo(S).@"struct".fields;
...@@ -1641,7 +1641,7 @@ pub fn select(io: Io, s: anytype) SelectUnion(@TypeOf(s)) {...@@ -1641,7 +1641,7 @@ pub fn select(io: Io, s: anytype) SelectUnion(@TypeOf(s)) {
1641 const future = @field(s, field.name);1641 const future = @field(s, field.name);
1642 any_future.* = future.any_future orelse return @unionInit(U, field.name, future.result);1642 any_future.* = future.any_future orelse return @unionInit(U, field.name, future.result);
1643 }1643 }
1644 switch (io.vtable.select(io.userdata, &futures)) {1644 switch (try io.vtable.select(io.userdata, &futures)) {
1645 inline 0...(fields.len - 1) => |selected_index| {1645 inline 0...(fields.len - 1) => |selected_index| {
1646 const field_name = fields[selected_index].name;1646 const field_name = fields[selected_index].name;
1647 return @unionInit(U, field_name, @field(s, field_name).await(io));1647 return @unionInit(U, field_name, @field(s, field_name).await(io));
lib/std/Io/test.zig+44-17
...@@ -3,24 +3,26 @@ const native_endian = builtin.cpu.arch.endian();...@@ -3,24 +3,26 @@ const native_endian = builtin.cpu.arch.endian();
33
4const std = @import("std");4const std = @import("std");
5const Io = std.Io;5const Io = std.Io;
6const DefaultPrng = std.Random.DefaultPrng;6const testing = std.testing;
7const expect = std.testing.expect;7const expect = std.testing.expect;
8const expectEqual = std.testing.expectEqual;8const expectEqual = std.testing.expectEqual;
9const expectError = std.testing.expectError;9const expectError = std.testing.expectError;
10const DefaultPrng = std.Random.DefaultPrng;
10const mem = std.mem;11const mem = std.mem;
11const fs = std.fs;12const fs = std.fs;
12const File = std.fs.File;13const File = std.fs.File;
14const assert = std.debug.assert;
1315
14const tmpDir = std.testing.tmpDir;16const tmpDir = std.testing.tmpDir;
1517
16test "write a file, read it, then delete it" {18test "write a file, read it, then delete it" {
17 const io = std.testing.io;19 const io = testing.io;
1820
19 var tmp = tmpDir(.{});21 var tmp = tmpDir(.{});
20 defer tmp.cleanup();22 defer tmp.cleanup();
2123
22 var data: [1024]u8 = undefined;24 var data: [1024]u8 = undefined;
23 var prng = DefaultPrng.init(std.testing.random_seed);25 var prng = DefaultPrng.init(testing.random_seed);
24 const random = prng.random();26 const random = prng.random();
25 random.bytes(data[0..]);27 random.bytes(data[0..]);
26 const tmp_file_name = "temp_test_file.txt";28 const tmp_file_name = "temp_test_file.txt";
...@@ -51,8 +53,8 @@ test "write a file, read it, then delete it" {...@@ -51,8 +53,8 @@ test "write a file, read it, then delete it" {
5153
52 var file_buffer: [1024]u8 = undefined;54 var file_buffer: [1024]u8 = undefined;
53 var file_reader = file.reader(io, &file_buffer);55 var file_reader = file.reader(io, &file_buffer);
54 const contents = try file_reader.interface.allocRemaining(std.testing.allocator, .limited(2 * 1024));56 const contents = try file_reader.interface.allocRemaining(testing.allocator, .limited(2 * 1024));
55 defer std.testing.allocator.free(contents);57 defer testing.allocator.free(contents);
5658
57 try expect(mem.eql(u8, contents[0.."begin".len], "begin"));59 try expect(mem.eql(u8, contents[0.."begin".len], "begin"));
58 try expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], &data));60 try expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], &data));
...@@ -94,18 +96,18 @@ test "setEndPos" {...@@ -94,18 +96,18 @@ test "setEndPos" {
94 defer file.close();96 defer file.close();
9597
96 // Verify that the file size changes and the file offset is not moved98 // Verify that the file size changes and the file offset is not moved
97 try std.testing.expect((try file.getEndPos()) == 0);99 try expect((try file.getEndPos()) == 0);
98 try std.testing.expect((try file.getPos()) == 0);100 try expect((try file.getPos()) == 0);
99 try file.setEndPos(8192);101 try file.setEndPos(8192);
100 try std.testing.expect((try file.getEndPos()) == 8192);102 try expect((try file.getEndPos()) == 8192);
101 try std.testing.expect((try file.getPos()) == 0);103 try expect((try file.getPos()) == 0);
102 try file.seekTo(100);104 try file.seekTo(100);
103 try file.setEndPos(4096);105 try file.setEndPos(4096);
104 try std.testing.expect((try file.getEndPos()) == 4096);106 try expect((try file.getEndPos()) == 4096);
105 try std.testing.expect((try file.getPos()) == 100);107 try expect((try file.getPos()) == 100);
106 try file.setEndPos(0);108 try file.setEndPos(0);
107 try std.testing.expect((try file.getEndPos()) == 0);109 try expect((try file.getEndPos()) == 0);
108 try std.testing.expect((try file.getPos()) == 100);110 try expect((try file.getPos()) == 100);
109}111}
110112
111test "updateTimes" {113test "updateTimes" {
...@@ -128,7 +130,7 @@ test "updateTimes" {...@@ -128,7 +130,7 @@ test "updateTimes" {
128}130}
129131
130test "Group" {132test "Group" {
131 const io = std.testing.io;133 const io = testing.io;
132134
133 var group: Io.Group = .init;135 var group: Io.Group = .init;
134 var results: [2]usize = undefined;136 var results: [2]usize = undefined;
...@@ -138,7 +140,7 @@ test "Group" {...@@ -138,7 +140,7 @@ test "Group" {
138140
139 group.wait(io);141 group.wait(io);
140142
141 try std.testing.expectEqualSlices(usize, &.{ 45, 245 }, &results);143 try testing.expectEqualSlices(usize, &.{ 45, 245 }, &results);
142}144}
143145
144fn count(a: usize, b: usize, result: *usize) void {146fn count(a: usize, b: usize, result: *usize) void {
...@@ -150,7 +152,7 @@ fn count(a: usize, b: usize, result: *usize) void {...@@ -150,7 +152,7 @@ fn count(a: usize, b: usize, result: *usize) void {
150}152}
151153
152test "Group cancellation" {154test "Group cancellation" {
153 const io = std.testing.io;155 const io = testing.io;
154156
155 var group: Io.Group = .init;157 var group: Io.Group = .init;
156 var results: [2]usize = undefined;158 var results: [2]usize = undefined;
...@@ -160,7 +162,7 @@ test "Group cancellation" {...@@ -160,7 +162,7 @@ test "Group cancellation" {
160162
161 group.cancel(io);163 group.cancel(io);
162164
163 try std.testing.expectEqualSlices(usize, &.{ 1, 1 }, &results);165 try testing.expectEqualSlices(usize, &.{ 1, 1 }, &results);
164}166}
165167
166fn sleep(io: Io, result: *usize) void {168fn sleep(io: Io, result: *usize) void {
...@@ -169,3 +171,28 @@ fn sleep(io: Io, result: *usize) void {...@@ -169,3 +171,28 @@ fn sleep(io: Io, result: *usize) void {
169 io.sleep(.fromMilliseconds(1), .awake) catch {};171 io.sleep(.fromMilliseconds(1), .awake) catch {};
170 result.* = 1;172 result.* = 1;
171}173}
174
175test "select" {
176 const io = testing.io;
177
178 var queue: Io.Queue(u8) = .init(&.{});
179
180 var get_a = try io.concurrent(Io.Queue(u8).getOne, .{ &queue, io });
181 defer if (get_a.cancel(io)) |_| @panic("fail") else |err| assert(err == error.Canceled);
182
183 var get_b = try io.concurrent(Io.Queue(u8).getOne, .{ &queue, io });
184 defer if (get_b.cancel(io)) |_| @panic("fail") else |err| assert(err == error.Canceled);
185
186 var timeout = io.async(Io.sleep, .{ io, .fromMilliseconds(1), .awake });
187 defer timeout.cancel(io) catch {};
188
189 switch (try io.select(.{
190 .get_a = &get_a,
191 .get_b = &get_b,
192 .timeout = &timeout,
193 })) {
194 .get_a => return error.TestFailure,
195 .get_b => return error.TestFailure,
196 .timeout => {},
197 }
198}