tangled
alpha
login
or
join now
brookjeynes.dev
/
jido
7
fork
atom
地圖 (Jido) is a lightweight Unix TUI file explorer designed for speed and simplicity.
7
fork
atom
overview
issues
pulls
pipelines
feat: add tests
brookjeynes.dev
2 months ago
15b8f69d
c25fc4e9
+552
-2
8 changed files
expand all
collapse all
unified
split
build.zig
src
circ_stack.zig
commands.zig
directories.zig
list.zig
test_file_operations.zig
test_helpers.zig
test_navigation.zig
+44
-1
build.zig
···
50
50
build_options.addOption(std.SemanticVersion, "version", version);
51
51
const build_options_module = build_options.createModule();
52
52
53
53
-
// Building targets for release.
54
53
const build_all = b.option(bool, "all-targets", "Build all targets in ReleaseSafe mode.") orelse false;
55
54
if (build_all) {
56
55
try buildTargets(b, build_options_module);
···
67
66
}
68
67
const run_step = b.step("run", "Run the app");
69
68
run_step.dependOn(&run_cmd.step);
69
69
+
70
70
+
const libvaxis = b.dependency("vaxis", .{ .target = target, .optimize = optimize }).module("vaxis");
71
71
+
const fuzzig = b.dependency("fuzzig", .{ .target = target, .optimize = optimize }).module("fuzzig");
72
72
+
const zuid = b.dependency("zuid", .{ .target = target, .optimize = optimize }).module("zuid");
73
73
+
const zeit = b.dependency("zeit", .{ .target = target, .optimize = optimize }).module("zeit");
74
74
+
const test_step = b.step("test", "Run unit tests");
75
75
+
const unit_tests = b.addTest(.{
76
76
+
.root_module = b.createModule(.{
77
77
+
.root_source_file = b.path("src/main.zig"),
78
78
+
.target = target,
79
79
+
.optimize = optimize,
80
80
+
}),
81
81
+
});
82
82
+
unit_tests.root_module.addImport("options", build_options_module);
83
83
+
unit_tests.root_module.addImport("vaxis", libvaxis);
84
84
+
unit_tests.root_module.addImport("fuzzig", fuzzig);
85
85
+
unit_tests.root_module.addImport("zeit", zeit);
86
86
+
unit_tests.root_module.addImport("zuid", zuid);
87
87
+
88
88
+
const run_unit_tests = b.addRunArtifact(unit_tests);
89
89
+
test_step.dependOn(&run_unit_tests.step);
90
90
+
91
91
+
const integration_tests = &[_][]const u8{
92
92
+
"src/test_navigation.zig",
93
93
+
"src/test_file_operations.zig",
94
94
+
};
95
95
+
96
96
+
for (integration_tests) |test_file| {
97
97
+
const test_exe = b.addTest(.{
98
98
+
.root_module = b.createModule(.{
99
99
+
.root_source_file = b.path(test_file),
100
100
+
.target = target,
101
101
+
.optimize = optimize,
102
102
+
}),
103
103
+
});
104
104
+
test_exe.root_module.addImport("vaxis", libvaxis);
105
105
+
test_exe.root_module.addImport("fuzzig", fuzzig);
106
106
+
test_exe.root_module.addImport("zuid", zuid);
107
107
+
test_exe.root_module.addImport("zeit", zeit);
108
108
+
test_exe.root_module.addImport("options", build_options_module);
109
109
+
110
110
+
const run_test = b.addRunArtifact(test_exe);
111
111
+
test_step.dependOn(&run_test.step);
112
112
+
}
70
113
}
71
114
72
115
fn buildTargets(b: *std.Build, build_options: *std.Build.Module) !void {
+44
-1
src/circ_stack.zig
···
30
30
pub fn pop(self: *Self) ?T {
31
31
if (self.count == 0) return null;
32
32
33
33
-
self.head = (self.head - 1) % capacity;
33
33
+
self.head = if (self.head == 0) capacity - 1 else self.head - 1;
34
34
const value = self.buf[self.head];
35
35
self.count -= 1;
36
36
return value;
37
37
}
38
38
};
39
39
}
40
40
+
41
41
+
const testing = std.testing;
42
42
+
43
43
+
test "CircularStack: push and pop basic operations" {
44
44
+
var stack = CircularStack(u32, 5).init();
45
45
+
46
46
+
_ = stack.push(1);
47
47
+
_ = stack.push(2);
48
48
+
_ = stack.push(3);
49
49
+
50
50
+
try testing.expectEqual(@as(?u32, 3), stack.pop());
51
51
+
try testing.expectEqual(@as(?u32, 2), stack.pop());
52
52
+
try testing.expectEqual(@as(?u32, 1), stack.pop());
53
53
+
try testing.expectEqual(@as(?u32, null), stack.pop());
54
54
+
}
55
55
+
56
56
+
test "CircularStack: wraparound behavior at capacity" {
57
57
+
var stack = CircularStack(u32, 3).init();
58
58
+
59
59
+
_ = stack.push(1);
60
60
+
_ = stack.push(2);
61
61
+
_ = stack.push(3);
62
62
+
63
63
+
const evicted = stack.push(4);
64
64
+
try testing.expectEqual(@as(?u32, 1), evicted);
65
65
+
66
66
+
try testing.expectEqual(@as(?u32, 4), stack.pop());
67
67
+
try testing.expectEqual(@as(?u32, 3), stack.pop());
68
68
+
try testing.expectEqual(@as(?u32, 2), stack.pop());
69
69
+
}
70
70
+
71
71
+
test "CircularStack: reset clears all entries" {
72
72
+
var stack = CircularStack(u32, 5).init();
73
73
+
74
74
+
_ = stack.push(1);
75
75
+
_ = stack.push(2);
76
76
+
_ = stack.push(3);
77
77
+
78
78
+
stack.reset();
79
79
+
80
80
+
try testing.expectEqual(@as(?u32, null), stack.pop());
81
81
+
try testing.expectEqual(@as(usize, 0), stack.count);
82
82
+
}
+50
src/commands.zig
···
172
172
try app.repopulateDirectory("");
173
173
app.directories.history.reset();
174
174
}
175
175
+
176
176
+
const testing = std.testing;
177
177
+
178
178
+
test "CommandHistory: add and retrieve commands" {
179
179
+
var history = CommandHistory{};
180
180
+
defer history.deinit(testing.allocator);
181
181
+
182
182
+
try history.add(":cd /tmp", testing.allocator);
183
183
+
try history.add(":config", testing.allocator);
184
184
+
185
185
+
try testing.expectEqual(@as(usize, 2), history.count);
186
186
+
}
187
187
+
188
188
+
test "CommandHistory: previous/next navigation" {
189
189
+
var history = CommandHistory{};
190
190
+
defer history.deinit(testing.allocator);
191
191
+
192
192
+
try history.add(":cmd1", testing.allocator);
193
193
+
try history.add(":cmd2", testing.allocator);
194
194
+
try history.add(":cmd3", testing.allocator);
195
195
+
196
196
+
const cmd3 = history.previous();
197
197
+
try testing.expectEqualStrings(":cmd3", cmd3.?);
198
198
+
199
199
+
const cmd2 = history.previous();
200
200
+
try testing.expectEqualStrings(":cmd2", cmd2.?);
201
201
+
202
202
+
const cmd3_again = history.next();
203
203
+
try testing.expectEqualStrings(":cmd3", cmd3_again.?);
204
204
+
205
205
+
const at_end = history.next();
206
206
+
try testing.expect(at_end == null);
207
207
+
}
208
208
+
209
209
+
test "CommandHistory: wraparound at capacity" {
210
210
+
var history = CommandHistory{};
211
211
+
defer history.deinit(testing.allocator);
212
212
+
213
213
+
var i: u32 = 0;
214
214
+
while (i < 15) : (i += 1) {
215
215
+
const cmd = try std.fmt.allocPrint(testing.allocator, ":cmd{}", .{i});
216
216
+
defer testing.allocator.free(cmd);
217
217
+
try history.add(cmd, testing.allocator);
218
218
+
}
219
219
+
220
220
+
try testing.expectEqual(@as(usize, 10), history.count);
221
221
+
222
222
+
const recent = history.previous();
223
223
+
try testing.expectEqualStrings(":cmd14", recent.?);
224
224
+
}
+88
src/directories.zig
···
167
167
}
168
168
self.child_entries.clear();
169
169
}
170
170
+
171
171
+
const testing = std.testing;
172
172
+
173
173
+
test "Directories: populateEntries respects show_hidden config" {
174
174
+
const local_config = &@import("./config.zig").config;
175
175
+
176
176
+
var tmp = testing.tmpDir(.{});
177
177
+
defer tmp.cleanup();
178
178
+
179
179
+
{
180
180
+
const visible = try tmp.dir.createFile("visible.txt", .{});
181
181
+
visible.close();
182
182
+
const hidden = try tmp.dir.createFile(".hidden.txt", .{});
183
183
+
hidden.close();
184
184
+
}
185
185
+
186
186
+
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
187
187
+
const tmp_path = try tmp.dir.realpath(".", &path_buf);
188
188
+
const iter_dir = try std.fs.openDirAbsolute(tmp_path, .{ .iterate = true });
189
189
+
190
190
+
var dirs = try Self.init(testing.allocator, null);
191
191
+
defer {
192
192
+
dirs.clearEntries();
193
193
+
dirs.clearChildEntries();
194
194
+
dirs.entries.deinit();
195
195
+
dirs.child_entries.deinit();
196
196
+
dirs.searcher.deinit();
197
197
+
}
198
198
+
dirs.dir.close();
199
199
+
dirs.dir = iter_dir;
200
200
+
201
201
+
local_config.show_hidden = false;
202
202
+
try dirs.populateEntries("");
203
203
+
try testing.expectEqual(@as(usize, 1), dirs.entries.len());
204
204
+
205
205
+
dirs.clearEntries();
206
206
+
local_config.show_hidden = true;
207
207
+
try dirs.populateEntries("");
208
208
+
try testing.expectEqual(@as(usize, 2), dirs.entries.len());
209
209
+
}
210
210
+
211
211
+
test "Directories: fuzzy search filters entries" {
212
212
+
var tmp = testing.tmpDir(.{});
213
213
+
defer tmp.cleanup();
214
214
+
215
215
+
{
216
216
+
const f1 = try tmp.dir.createFile("test_file.txt", .{});
217
217
+
f1.close();
218
218
+
const f2 = try tmp.dir.createFile("other.txt", .{});
219
219
+
f2.close();
220
220
+
const f3 = try tmp.dir.createFile("test_another.txt", .{});
221
221
+
f3.close();
222
222
+
}
223
223
+
224
224
+
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
225
225
+
const tmp_path = try tmp.dir.realpath(".", &path_buf);
226
226
+
const iter_dir = try std.fs.openDirAbsolute(tmp_path, .{ .iterate = true });
227
227
+
228
228
+
var dirs = try Self.init(testing.allocator, null);
229
229
+
defer {
230
230
+
dirs.clearEntries();
231
231
+
dirs.clearChildEntries();
232
232
+
dirs.entries.deinit();
233
233
+
dirs.child_entries.deinit();
234
234
+
dirs.searcher.deinit();
235
235
+
}
236
236
+
dirs.dir.close();
237
237
+
dirs.dir = iter_dir;
238
238
+
239
239
+
try dirs.populateEntries("test");
240
240
+
// Should match test_*
241
241
+
try testing.expect(dirs.entries.len() >= 2);
242
242
+
243
243
+
// Verify all entries contain "test"
244
244
+
for (dirs.entries.all()) |entry| {
245
245
+
try testing.expect(std.mem.indexOf(u8, entry.name, "test") != null);
246
246
+
}
247
247
+
}
248
248
+
249
249
+
test "Directories: fullPath resolves relative paths" {
250
250
+
var dirs = try Self.init(testing.allocator, ".");
251
251
+
defer dirs.deinit();
252
252
+
253
253
+
const path = try dirs.fullPath(".");
254
254
+
try testing.expect(path.len > 0);
255
255
+
// Should be absolute
256
256
+
try testing.expect(std.mem.indexOf(u8, path, "/") != null);
257
257
+
}
+67
src/list.zig
···
85
85
}
86
86
};
87
87
}
88
88
+
89
89
+
const testing = std.testing;
90
90
+
91
91
+
test "List: navigation respects bounds" {
92
92
+
var list = List(u32).init(testing.allocator);
93
93
+
defer list.deinit();
94
94
+
95
95
+
try list.append(1);
96
96
+
try list.append(2);
97
97
+
try list.append(3);
98
98
+
99
99
+
try testing.expectEqual(@as(usize, 0), list.selected);
100
100
+
101
101
+
list.next();
102
102
+
try testing.expectEqual(@as(usize, 1), list.selected);
103
103
+
104
104
+
list.next();
105
105
+
list.next();
106
106
+
// Try to go past end
107
107
+
list.next();
108
108
+
// Should stay at last
109
109
+
try testing.expectEqual(@as(usize, 2), list.selected);
110
110
+
111
111
+
list.previous();
112
112
+
try testing.expectEqual(@as(usize, 1), list.selected);
113
113
+
114
114
+
list.previous();
115
115
+
// Try to go before start
116
116
+
list.previous();
117
117
+
// Should stay at first
118
118
+
try testing.expectEqual(@as(usize, 0), list.selected);
119
119
+
}
120
120
+
121
121
+
test "List: getSelected handles empty list" {
122
122
+
var list = List(u32).init(testing.allocator);
123
123
+
defer list.deinit();
124
124
+
125
125
+
const result = try list.getSelected();
126
126
+
try testing.expect(result == null);
127
127
+
}
128
128
+
129
129
+
test "List: append and get operations" {
130
130
+
var list = List(u32).init(testing.allocator);
131
131
+
defer list.deinit();
132
132
+
133
133
+
try list.append(42);
134
134
+
try list.append(84);
135
135
+
136
136
+
try testing.expectEqual(@as(usize, 2), list.len());
137
137
+
try testing.expectEqual(@as(u32, 42), try list.get(0));
138
138
+
try testing.expectEqual(@as(u32, 84), try list.get(1));
139
139
+
}
140
140
+
141
141
+
test "List: selectFirst and selectLast" {
142
142
+
var list = List(u32).init(testing.allocator);
143
143
+
defer list.deinit();
144
144
+
145
145
+
try list.append(1);
146
146
+
try list.append(2);
147
147
+
try list.append(3);
148
148
+
149
149
+
list.selectLast();
150
150
+
try testing.expectEqual(@as(usize, 2), list.selected);
151
151
+
152
152
+
list.selectFirst();
153
153
+
try testing.expectEqual(@as(usize, 0), list.selected);
154
154
+
}
+84
src/test_file_operations.zig
···
1
1
+
const std = @import("std");
2
2
+
const testing = std.testing;
3
3
+
const TestEnv = @import("test_helpers.zig").TestEnv;
4
4
+
const Directories = @import("directories.zig");
5
5
+
const environment = @import("environment.zig");
6
6
+
7
7
+
test "FileOps: create new directory" {
8
8
+
var env = try TestEnv.init(testing.allocator);
9
9
+
defer env.deinit();
10
10
+
11
11
+
var dirs = try Directories.init(testing.allocator, env.tmp_path);
12
12
+
defer dirs.deinit();
13
13
+
14
14
+
try dirs.dir.makeDir("testdir");
15
15
+
16
16
+
var test_dir = dirs.dir.openDir("testdir", .{}) catch |err| {
17
17
+
std.debug.print("Failed to open created directory: {}\n", .{err});
18
18
+
return err;
19
19
+
};
20
20
+
test_dir.close();
21
21
+
22
22
+
try dirs.populateEntries("");
23
23
+
var found = false;
24
24
+
for (dirs.entries.all()) |entry| {
25
25
+
if (std.mem.eql(u8, entry.name, "testdir")) {
26
26
+
found = true;
27
27
+
try testing.expectEqual(std.fs.Dir.Entry.Kind.directory, entry.kind);
28
28
+
}
29
29
+
}
30
30
+
try testing.expect(found);
31
31
+
}
32
32
+
33
33
+
test "FileOps: create new file" {
34
34
+
var env = try TestEnv.init(testing.allocator);
35
35
+
defer env.deinit();
36
36
+
37
37
+
var dirs = try Directories.init(testing.allocator, env.tmp_path);
38
38
+
defer dirs.deinit();
39
39
+
40
40
+
const file = try dirs.dir.createFile("testfile.txt", .{});
41
41
+
file.close();
42
42
+
43
43
+
try testing.expect(environment.fileExists(dirs.dir, "testfile.txt"));
44
44
+
45
45
+
try dirs.populateEntries("");
46
46
+
var found = false;
47
47
+
for (dirs.entries.all()) |entry| {
48
48
+
if (std.mem.eql(u8, entry.name, "testfile.txt")) {
49
49
+
found = true;
50
50
+
try testing.expectEqual(std.fs.Dir.Entry.Kind.file, entry.kind);
51
51
+
}
52
52
+
}
53
53
+
try testing.expect(found);
54
54
+
}
55
55
+
56
56
+
test "FileOps: rename file" {
57
57
+
var env = try TestEnv.init(testing.allocator);
58
58
+
defer env.deinit();
59
59
+
60
60
+
try env.createFiles(&.{"oldname.txt"});
61
61
+
62
62
+
var dirs = try Directories.init(testing.allocator, env.tmp_path);
63
63
+
defer dirs.deinit();
64
64
+
65
65
+
try dirs.populateEntries("");
66
66
+
67
67
+
try testing.expect(environment.fileExists(dirs.dir, "oldname.txt"));
68
68
+
try dirs.dir.rename("oldname.txt", "newname.txt");
69
69
+
try testing.expect(!environment.fileExists(dirs.dir, "oldname.txt"));
70
70
+
try testing.expect(environment.fileExists(dirs.dir, "newname.txt"));
71
71
+
72
72
+
dirs.clearEntries();
73
73
+
try dirs.populateEntries("");
74
74
+
75
75
+
var found_old = false;
76
76
+
var found_new = false;
77
77
+
for (dirs.entries.all()) |entry| {
78
78
+
if (std.mem.eql(u8, entry.name, "oldname.txt")) found_old = true;
79
79
+
if (std.mem.eql(u8, entry.name, "newname.txt")) found_new = true;
80
80
+
}
81
81
+
82
82
+
try testing.expect(!found_old);
83
83
+
try testing.expect(found_new);
84
84
+
}
+61
src/test_helpers.zig
···
1
1
+
const std = @import("std");
2
2
+
3
3
+
pub const TestEnv = struct {
4
4
+
allocator: std.mem.Allocator,
5
5
+
tmp_dir: std.testing.TmpDir,
6
6
+
tmp_path: []const u8,
7
7
+
8
8
+
pub fn init(allocator: std.mem.Allocator) !TestEnv {
9
9
+
var tmp_dir = std.testing.tmpDir(.{});
10
10
+
const real_path = try tmp_dir.dir.realpathAlloc(allocator, ".");
11
11
+
12
12
+
return TestEnv{
13
13
+
.allocator = allocator,
14
14
+
.tmp_dir = tmp_dir,
15
15
+
.tmp_path = real_path,
16
16
+
};
17
17
+
}
18
18
+
19
19
+
pub fn deinit(self: *TestEnv) void {
20
20
+
self.allocator.free(self.tmp_path);
21
21
+
self.tmp_dir.cleanup();
22
22
+
}
23
23
+
24
24
+
pub fn createFiles(self: *TestEnv, names: []const []const u8) !void {
25
25
+
for (names) |name| {
26
26
+
const file = try self.tmp_dir.dir.createFile(name, .{});
27
27
+
file.close();
28
28
+
}
29
29
+
}
30
30
+
31
31
+
pub const DirNode = struct {
32
32
+
name: []const u8,
33
33
+
children: ?[]const DirNode,
34
34
+
};
35
35
+
36
36
+
pub fn createDirStructure(self: *TestEnv, nodes: []const DirNode) !void {
37
37
+
for (nodes) |node| {
38
38
+
if (node.children) |children| {
39
39
+
try self.tmp_dir.dir.makeDir(node.name);
40
40
+
var subdir = try self.tmp_dir.dir.openDir(node.name, .{});
41
41
+
defer subdir.close();
42
42
+
43
43
+
for (children) |child| {
44
44
+
if (child.children) |_| {
45
45
+
try subdir.makeDir(child.name);
46
46
+
} else {
47
47
+
const file = try subdir.createFile(child.name, .{});
48
48
+
file.close();
49
49
+
}
50
50
+
}
51
51
+
} else {
52
52
+
const file = try self.tmp_dir.dir.createFile(node.name, .{});
53
53
+
file.close();
54
54
+
}
55
55
+
}
56
56
+
}
57
57
+
58
58
+
pub fn path(self: *TestEnv, relative: []const u8) ![]const u8 {
59
59
+
return try std.fs.path.join(self.allocator, &.{ self.tmp_path, relative });
60
60
+
}
61
61
+
};
+114
src/test_navigation.zig
···
1
1
+
const std = @import("std");
2
2
+
const testing = std.testing;
3
3
+
const TestEnv = @import("test_helpers.zig").TestEnv;
4
4
+
const Directories = @import("directories.zig");
5
5
+
const events = @import("events.zig");
6
6
+
const App = @import("app.zig");
7
7
+
8
8
+
test "Navigation: traverse left to parent directory" {
9
9
+
var env = try TestEnv.init(testing.allocator);
10
10
+
defer env.deinit();
11
11
+
12
12
+
try env.createDirStructure(&.{
13
13
+
.{ .name = "parent", .children = &.{
14
14
+
.{ .name = "child", .children = &.{} },
15
15
+
.{ .name = "sibling.txt", .children = null },
16
16
+
} },
17
17
+
});
18
18
+
19
19
+
const child_path = try env.path("parent/child");
20
20
+
defer testing.allocator.free(child_path);
21
21
+
22
22
+
var dirs = try Directories.init(testing.allocator, child_path);
23
23
+
defer dirs.deinit();
24
24
+
25
25
+
const before_path = try dirs.fullPath(".");
26
26
+
try testing.expect(std.mem.endsWith(u8, before_path, "child"));
27
27
+
28
28
+
const parent_dir = try dirs.dir.openDir("../", .{ .iterate = true });
29
29
+
dirs.dir.close();
30
30
+
dirs.dir = parent_dir;
31
31
+
32
32
+
const after_path = try dirs.fullPath(".");
33
33
+
try testing.expect(std.mem.endsWith(u8, after_path, "parent"));
34
34
+
35
35
+
try dirs.populateEntries("");
36
36
+
var found_child = false;
37
37
+
for (dirs.entries.all()) |entry| {
38
38
+
if (std.mem.eql(u8, entry.name, "child")) {
39
39
+
found_child = true;
40
40
+
try testing.expectEqual(std.fs.Dir.Entry.Kind.directory, entry.kind);
41
41
+
}
42
42
+
}
43
43
+
try testing.expect(found_child);
44
44
+
}
45
45
+
46
46
+
test "Navigation: traverse right into directory" {
47
47
+
var env = try TestEnv.init(testing.allocator);
48
48
+
defer env.deinit();
49
49
+
50
50
+
try env.createDirStructure(&.{
51
51
+
.{ .name = "subdir", .children = &.{
52
52
+
.{ .name = "inner.txt", .children = null },
53
53
+
} },
54
54
+
.{ .name = "file.txt", .children = null },
55
55
+
});
56
56
+
57
57
+
var dirs = try Directories.init(testing.allocator, env.tmp_path);
58
58
+
defer dirs.deinit();
59
59
+
60
60
+
try dirs.populateEntries("");
61
61
+
62
62
+
for (dirs.entries.all(), 0..) |entry, i| {
63
63
+
if (std.mem.eql(u8, entry.name, "subdir")) {
64
64
+
dirs.entries.selected = i;
65
65
+
break;
66
66
+
}
67
67
+
}
68
68
+
69
69
+
const selected = try dirs.getSelected();
70
70
+
try testing.expect(selected != null);
71
71
+
try testing.expectEqualStrings("subdir", selected.?.name);
72
72
+
73
73
+
const subdir = try dirs.dir.openDir("subdir", .{ .iterate = true });
74
74
+
dirs.dir.close();
75
75
+
dirs.dir = subdir;
76
76
+
77
77
+
const current_path = try dirs.fullPath(".");
78
78
+
try testing.expect(std.mem.endsWith(u8, current_path, "subdir"));
79
79
+
80
80
+
dirs.clearEntries();
81
81
+
try dirs.populateEntries("");
82
82
+
try testing.expectEqual(@as(usize, 1), dirs.entries.len());
83
83
+
84
84
+
const inner = try dirs.entries.get(0);
85
85
+
try testing.expectEqualStrings("inner.txt", inner.name);
86
86
+
}
87
87
+
88
88
+
test "Navigation: move selection with next and previous" {
89
89
+
var env = try TestEnv.init(testing.allocator);
90
90
+
defer env.deinit();
91
91
+
92
92
+
try env.createFiles(&.{ "file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt" });
93
93
+
94
94
+
var dirs = try Directories.init(testing.allocator, env.tmp_path);
95
95
+
defer dirs.deinit();
96
96
+
97
97
+
try dirs.populateEntries("");
98
98
+
try testing.expectEqual(@as(usize, 5), dirs.entries.len());
99
99
+
try testing.expectEqual(@as(usize, 0), dirs.entries.selected);
100
100
+
101
101
+
dirs.entries.next();
102
102
+
dirs.entries.next();
103
103
+
dirs.entries.next();
104
104
+
try testing.expectEqual(@as(usize, 3), dirs.entries.selected);
105
105
+
106
106
+
dirs.entries.previous();
107
107
+
try testing.expectEqual(@as(usize, 2), dirs.entries.selected);
108
108
+
109
109
+
dirs.entries.selectLast();
110
110
+
try testing.expectEqual(@as(usize, 4), dirs.entries.selected);
111
111
+
112
112
+
dirs.entries.selectFirst();
113
113
+
try testing.expectEqual(@as(usize, 0), dirs.entries.selected);
114
114
+
}