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 }