lib/sys/src/font/fixture.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2
3 const Dir = std.Io.Dir;
4
5 /// Sets the `depth_max` value the tree is laid out for, at two, so a test walks
6 /// the fixture tree at this depth to get the counts the layout promises. A walk
7 /// at this bound reaches `nested/deep` and reads it, and stops short of
8 /// `nested/deep/deeper`.
9 pub const visible_depth: u8 = 2;
10
11 /// Records what went into one tree, handed back by the call that made it. A
12 /// test compares the walk's results against it, because the counts depend on
13 /// the host that built the tree.
14 pub const Layout = struct {
15 /// Counts how many font files a walk bounded at `visible_depth` accepts
16 /// from the tree, which a test compares against the catalog's entry count.
17 fonts: u32,
18 /// Holds those files' sizes added together, which a test compares against
19 /// the summed sizes of the admitted entries.
20 bytes: u64,
21 /// Reports whether the directory created with mode zero could still be
22 /// opened, as it can for a privileged test process. A test reads this to
23 /// know whether the directory was unreadable on this host, and the font
24 /// count and the byte total follow this flag because a privileged process
25 /// also admits the font inside that directory.
26 locked_readable: bool,
27 };
28
29 const locked_mode: Dir.Permissions = @fromBackingInt(@intCast(0o000));
30 const open_mode: Dir.Permissions = @fromBackingInt(@intCast(0o755));
31
32 /// Lays the tree out inside `dir` and reports what went in, which a test calls
33 /// once to get a tree that exercises every case the walk has to survive. Inside
34 /// the tree are two levels of subdirectory, one directory below the depth
35 /// bound, a symbolic link pointing back at its own parent, a symbolic link to a
36 /// font file, a `.txt` file, a font named with an uppercase extension, and a
37 /// directory created with mode zero.
38 pub fn create(io: std.Io, dir: Dir) !Layout {
39 try write(io, dir, "Regular.ttf", 64);
40 try write(io, dir, "Italic.OTF", 32);
41 try write(io, dir, "Notes.txt", 8);
42 try dir.symLink(io, "Regular.ttf", "link.ttf", .{});
43 try dir.createDir(io, "nested", open_mode);
44 try write(io, dir, "nested/Bold.otf", 16);
45 try dir.createDir(io, "nested/deep", open_mode);
46 try write(io, dir, "nested/deep/Deep.ttc", 24);
47 try dir.createDir(io, "nested/deep/deeper", open_mode);
48 try write(io, dir, "nested/deep/deeper/TooDeep.ttf", 128);
49 try dir.createDir(io, "loop", open_mode);
50 try write(io, dir, "loop/Loop.pfb", 48);
51 try dir.symLink(io, "../loop", "loop/back", .{ .is_directory = true });
52 try dir.createDir(io, "locked", open_mode);
53 try write(io, dir, "locked/Hidden.ttf", 12);
54 try dir.setFilePermissions(io, "locked", locked_mode, .{});
55 const readable = probe(io, dir);
56 const layout: Layout = .{
57 .fonts = if (readable) 7 else 6,
58 .bytes = if (readable) 260 else 248,
59 .locked_readable = readable,
60 };
61 std.debug.assert(layout.fonts >= 6);
62 std.debug.assert(layout.bytes >= 248);
63 return layout;
64 }
65
66 /// Puts mode 0o755 back on the locked directory, so a test can delete its
67 /// temporary tree afterwards. A failure to restore it is ignored, because the
68 /// caller is already tearing the tree down.
69 pub fn release(io: std.Io, dir: Dir) void {
70 dir.setFilePermissions(io, "locked", open_mode, .{}) catch {};
71 }
72
73 fn probe(io: std.Io, dir: Dir) bool {
74 var opened = dir.openDir(io, "locked", .{ .iterate = true }) catch return false;
75 opened.close(io);
76 return true;
77 }
78
79 fn write(io: std.Io, dir: Dir, sub_path: []const u8, bytes: usize) !void {
80 var content: [128]u8 = @splat('f');
81 std.debug.assert(sub_path.len != 0);
82 std.debug.assert(bytes != 0);
83 std.debug.assert(bytes <= content.len);
84 try dir.writeFile(io, .{ .sub_path = sub_path, .data = content[0..bytes] });
85 }
86
87 /// Creates `directories` subdirectories holding `files` font files apiece, at
88 /// the width a real machine's font directory was measured at, so a benchmark
89 /// can walk a tree the size of a real host font directory. The call returns the
90 /// count of files created, the product of the two arguments.
91 pub fn createCorpus(io: std.Io, dir: Dir, directories: u16, files: u16) !u32 {
92 std.debug.assert(directories != 0);
93 std.debug.assert(files != 0);
94 var directory_name: [32]u8 = undefined;
95 var leaf_name: [64]u8 = undefined;
96 var created: u32 = 0;
97 for (0..directories) |directory| {
98 const sub = try std.fmt.bufPrint(&directory_name, "d{d}", .{directory});
99 try dir.createDir(io, sub, open_mode);
100 for (0..files) |file| {
101 const leaf = try std.fmt.bufPrint(&leaf_name, "{s}/f{d}.ttf", .{ sub, file });
102 try dir.writeFile(io, .{ .sub_path = leaf, .data = "font" });
103 created += 1;
104 }
105 }
106 std.debug.assert(created == @as(u32, directories) * @as(u32, files));
107 return created;
108 }