config: theme loading unit tests

This commit is contained in:
Mitchell Hashimoto
2024-11-18 19:19:06 -08:00
parent 04a61e753a
commit df4e616e71
3 changed files with 153 additions and 79 deletions

View File

@ -2675,6 +2675,8 @@ fn loadTheme(self: *Config, theme: []const u8) !void {
self.* = new_config; self.* = new_config;
} }
/// Call this once after you are done setting configuration. This
/// is idempotent but will waste memory if called multiple times.
pub fn finalize(self: *Config) !void { pub fn finalize(self: *Config) !void {
const alloc = self._arena.?.allocator(); const alloc = self._arena.?.allocator();
@ -2720,7 +2722,9 @@ pub fn finalize(self: *Config) !void {
// to look up defaults which is kind of expensive. We only do this // to look up defaults which is kind of expensive. We only do this
// on desktop. // on desktop.
const wd_home = std.mem.eql(u8, "home", wd); const wd_home = std.mem.eql(u8, "home", wd);
if (comptime !builtin.target.isWasm()) { if ((comptime !builtin.target.isWasm()) and
(comptime !builtin.is_test))
{
if (self.command == null or wd_home) command: { if (self.command == null or wd_home) command: {
// First look up the command using the SHELL env var if needed. // First look up the command using the SHELL env var if needed.
// We don't do this in flatpak because SHELL in Flatpak is always // We don't do this in flatpak because SHELL in Flatpak is always
@ -2790,7 +2794,9 @@ pub fn finalize(self: *Config) !void {
if (std.mem.eql(u8, wd, "inherit")) self.@"working-directory" = null; if (std.mem.eql(u8, wd, "inherit")) self.@"working-directory" = null;
// Default our click interval // Default our click interval
if (self.@"click-repeat-interval" == 0) { if (self.@"click-repeat-interval" == 0 and
(comptime !builtin.is_test))
{
self.@"click-repeat-interval" = internal_os.clickInterval() orelse 500; self.@"click-repeat-interval" = internal_os.clickInterval() orelse 500;
} }
@ -3019,82 +3025,6 @@ pub const ChangeIterator = struct {
} }
}; };
const TestIterator = struct {
data: []const []const u8,
i: usize = 0,
pub fn next(self: *TestIterator) ?[]const u8 {
if (self.i >= self.data.len) return null;
const result = self.data[self.i];
self.i += 1;
return result;
}
};
test "parse hook: invalid command" {
const testing = std.testing;
var cfg = try Config.default(testing.allocator);
defer cfg.deinit();
const alloc = cfg._arena.?.allocator();
var it: TestIterator = .{ .data = &.{"foo"} };
try testing.expect(try cfg.parseManuallyHook(alloc, "--command", &it));
try testing.expect(cfg.command == null);
}
test "parse e: command only" {
const testing = std.testing;
var cfg = try Config.default(testing.allocator);
defer cfg.deinit();
const alloc = cfg._arena.?.allocator();
var it: TestIterator = .{ .data = &.{"foo"} };
try testing.expect(!try cfg.parseManuallyHook(alloc, "-e", &it));
try testing.expectEqualStrings("foo", cfg.@"initial-command".?);
}
test "parse e: command and args" {
const testing = std.testing;
var cfg = try Config.default(testing.allocator);
defer cfg.deinit();
const alloc = cfg._arena.?.allocator();
var it: TestIterator = .{ .data = &.{ "echo", "foo", "bar baz" } };
try testing.expect(!try cfg.parseManuallyHook(alloc, "-e", &it));
try testing.expectEqualStrings("echo foo bar baz", cfg.@"initial-command".?);
}
test "clone default" {
const testing = std.testing;
const alloc = testing.allocator;
var source = try Config.default(alloc);
defer source.deinit();
var dest = try source.clone(alloc);
defer dest.deinit();
// Should have no changes
var it = source.changeIterator(&dest);
try testing.expectEqual(@as(?Key, null), it.next());
// I want to do this but this doesn't work (the API doesn't work)
// try testing.expectEqualDeep(dest, source);
}
test "changed" {
const testing = std.testing;
const alloc = testing.allocator;
var source = try Config.default(alloc);
defer source.deinit();
var dest = try source.clone(alloc);
defer dest.deinit();
dest.@"font-thicken" = true;
try testing.expect(source.changed(&dest, .@"font-thicken"));
try testing.expect(!source.changed(&dest, .@"font-size"));
}
/// A config-specific helper to determine if two values of the same /// A config-specific helper to determine if two values of the same
/// type are equal. This isn't the same as std.mem.eql or std.testing.equals /// type are equal. This isn't the same as std.mem.eql or std.testing.equals
/// because we expect structs to implement their own equality. /// because we expect structs to implement their own equality.
@ -5024,3 +4954,146 @@ test "test entryFormatter" {
try p.formatEntry(formatterpkg.entryFormatter("a", buf.writer())); try p.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
try std.testing.expectEqualStrings("a = 584y 49w 23h 34m 33s 709ms 551µs 615ns\n", buf.items); try std.testing.expectEqualStrings("a = 584y 49w 23h 34m 33s 709ms 551µs 615ns\n", buf.items);
} }
const TestIterator = struct {
data: []const []const u8,
i: usize = 0,
pub fn next(self: *TestIterator) ?[]const u8 {
if (self.i >= self.data.len) return null;
const result = self.data[self.i];
self.i += 1;
return result;
}
};
test "parse hook: invalid command" {
const testing = std.testing;
var cfg = try Config.default(testing.allocator);
defer cfg.deinit();
const alloc = cfg._arena.?.allocator();
var it: TestIterator = .{ .data = &.{"foo"} };
try testing.expect(try cfg.parseManuallyHook(alloc, "--command", &it));
try testing.expect(cfg.command == null);
}
test "parse e: command only" {
const testing = std.testing;
var cfg = try Config.default(testing.allocator);
defer cfg.deinit();
const alloc = cfg._arena.?.allocator();
var it: TestIterator = .{ .data = &.{"foo"} };
try testing.expect(!try cfg.parseManuallyHook(alloc, "-e", &it));
try testing.expectEqualStrings("foo", cfg.@"initial-command".?);
}
test "parse e: command and args" {
const testing = std.testing;
var cfg = try Config.default(testing.allocator);
defer cfg.deinit();
const alloc = cfg._arena.?.allocator();
var it: TestIterator = .{ .data = &.{ "echo", "foo", "bar baz" } };
try testing.expect(!try cfg.parseManuallyHook(alloc, "-e", &it));
try testing.expectEqualStrings("echo foo bar baz", cfg.@"initial-command".?);
}
test "clone default" {
const testing = std.testing;
const alloc = testing.allocator;
var source = try Config.default(alloc);
defer source.deinit();
var dest = try source.clone(alloc);
defer dest.deinit();
// Should have no changes
var it = source.changeIterator(&dest);
try testing.expectEqual(@as(?Key, null), it.next());
// I want to do this but this doesn't work (the API doesn't work)
// try testing.expectEqualDeep(dest, source);
}
test "changed" {
const testing = std.testing;
const alloc = testing.allocator;
var source = try Config.default(alloc);
defer source.deinit();
var dest = try source.clone(alloc);
defer dest.deinit();
dest.@"font-thicken" = true;
try testing.expect(source.changed(&dest, .@"font-thicken"));
try testing.expect(!source.changed(&dest, .@"font-size"));
}
test "theme loading" {
const testing = std.testing;
const alloc = testing.allocator;
var arena = ArenaAllocator.init(alloc);
defer arena.deinit();
const alloc_arena = arena.allocator();
// Setup our test theme
var td = try internal_os.TempDir.init();
defer td.deinit();
{
var file = try td.dir.createFile("theme", .{});
defer file.close();
try file.writer().writeAll(@embedFile("testdata/theme_simple"));
}
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
const path = try td.dir.realpath("theme", &path_buf);
var cfg = try Config.default(alloc);
defer cfg.deinit();
var it: TestIterator = .{ .data = &.{
try std.fmt.allocPrint(alloc_arena, "--theme={s}", .{path}),
} };
try cfg.loadIter(alloc, &it);
try cfg.finalize();
try testing.expectEqual(Color{
.r = 0x12,
.g = 0x3A,
.b = 0xBC,
}, cfg.background);
}
test "theme priority is lower than config" {
const testing = std.testing;
const alloc = testing.allocator;
var arena = ArenaAllocator.init(alloc);
defer arena.deinit();
const alloc_arena = arena.allocator();
// Setup our test theme
var td = try internal_os.TempDir.init();
defer td.deinit();
{
var file = try td.dir.createFile("theme", .{});
defer file.close();
try file.writer().writeAll(@embedFile("testdata/theme_simple"));
}
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
const path = try td.dir.realpath("theme", &path_buf);
var cfg = try Config.default(alloc);
defer cfg.deinit();
var it: TestIterator = .{ .data = &.{
"--background=#ABCDEF",
try std.fmt.allocPrint(alloc_arena, "--theme={s}", .{path}),
} };
try cfg.loadIter(alloc, &it);
try cfg.finalize();
try testing.expectEqual(Color{
.r = 0xAB,
.g = 0xCD,
.b = 0xEF,
}, cfg.background);
}

2
src/config/testdata/theme_simple vendored Normal file
View File

@ -0,0 +1,2 @@
# A simple theme
background = #123ABC

View File

@ -112,7 +112,6 @@ pub fn open(
path: []const u8, path: []const u8,
file: std.fs.File, file: std.fs.File,
} { } {
// Absolute themes are loaded a different path. // Absolute themes are loaded a different path.
if (std.fs.path.isAbsolute(theme)) { if (std.fs.path.isAbsolute(theme)) {
const file: std.fs.File = try openAbsolute( const file: std.fs.File = try openAbsolute(