PranitInitial commit439f83c3 months agoHistory
186 lines · 6.5 KB · Zig
RawDownload
const std = @import("std");const hooks = @import("../hooks/hooks.zig");const notification_contract = @import("../notifications/notification_contract.zig"); pub const Preferences = notification_contract.Preferences;pub const Notification = notification_contract.Notification;const Kind = notification_contract.Kind;const Cue = notification_contract.Cue;const Provider = notification_contract.Provider; pub fn Runtime(    comptime App: type,    comptime provider: Provider,) type {    return struct {        pub fn configure(app: *App) notification_contract.ConfigureError!void {            try provider.configure(app);        }         pub fn setPreferences(app: *App, next: Preferences) void {            provider.set_preferences(app, next);        }         pub fn preferences(app: *const App) Preferences {            return provider.preferences(app);        }         pub fn maxEnabled(app: *const App) bool {            return provider.max_enabled(app);        }         pub fn queue(app: *App, notification: Notification) void {            provider.queue(app, notification);        }         pub fn presentationFinished(app: *App) void {            provider.presentation_finished(app);        }         pub fn flush(app: *App) void {            provider.flush(app);        }         pub fn playCue(app: *App, cue: Cue) void {            provider.play_cue(app, cue);        }         pub fn playMaxCue(app: *App, cue: Cue) void {            provider.play_max_cue(app, cue);        }         pub fn dispatchAttentionRequired(            app: *App,            turn_id: u64,            kind: hooks.AttentionKind,        ) void {            provider.dispatch_attention_required(app, turn_id, kind);        }    };} test "notification runtime routes the full contract through its provider" {    const FakeApp = struct {        configure_fails: bool = false,        configure_count: usize = 0,        preferences_value: Preferences = .{},        max_enabled_value: bool = false,        queued: ?Notification = null,        presentation_finished_count: usize = 0,        flush_count: usize = 0,        played_cue: ?Cue = null,        played_max_cue: ?Cue = null,        attention_turn_id: ?u64 = null,        attention_kind: ?hooks.AttentionKind = null,         const provider = Provider{            .configure = configureProvider,            .set_preferences = setPreferencesProvider,            .preferences = preferencesProvider,            .max_enabled = maxEnabledProvider,            .queue = queueProvider,            .presentation_finished = presentationFinishedProvider,            .flush = flushProvider,            .play_cue = playCueProvider,            .play_max_cue = playMaxCueProvider,            .dispatch_attention_required = dispatchAttentionRequiredProvider,        };         fn configureProvider(raw: *anyopaque) notification_contract.ConfigureError!void {            const self: *@This() = @ptrCast(@alignCast(raw));            if (self.configure_fails) return error.RuntimeFrozen;            self.configure_count += 1;        }         fn setPreferencesProvider(raw: *anyopaque, preferences_value: Preferences) void {            const self: *@This() = @ptrCast(@alignCast(raw));            self.preferences_value = preferences_value;        }         fn preferencesProvider(raw: *const anyopaque) Preferences {            const self: *const @This() = @ptrCast(@alignCast(raw));            return self.preferences_value;        }         fn maxEnabledProvider(raw: *const anyopaque) bool {            const self: *const @This() = @ptrCast(@alignCast(raw));            return self.max_enabled_value;        }         fn queueProvider(raw: *anyopaque, notification: Notification) void {            const self: *@This() = @ptrCast(@alignCast(raw));            self.queued = notification;        }         fn presentationFinishedProvider(raw: *anyopaque) void {            const self: *@This() = @ptrCast(@alignCast(raw));            self.presentation_finished_count += 1;        }         fn flushProvider(raw: *anyopaque) void {            const self: *@This() = @ptrCast(@alignCast(raw));            self.flush_count += 1;        }         fn playCueProvider(raw: *anyopaque, cue: Cue) void {            const self: *@This() = @ptrCast(@alignCast(raw));            self.played_cue = cue;        }         fn playMaxCueProvider(raw: *anyopaque, cue: Cue) void {            const self: *@This() = @ptrCast(@alignCast(raw));            self.played_max_cue = cue;        }         fn dispatchAttentionRequiredProvider(            raw: *anyopaque,            turn_id: u64,            kind: hooks.AttentionKind,        ) void {            const self: *@This() = @ptrCast(@alignCast(raw));            self.attention_turn_id = turn_id;            self.attention_kind = kind;        }    };     const TestRuntime = Runtime(FakeApp, FakeApp.provider);    var app = FakeApp{};     app.configure_fails = true;    try std.testing.expectError(error.RuntimeFrozen, TestRuntime.configure(&app));    app.configure_fails = false;    try TestRuntime.configure(&app);    try std.testing.expectEqual(@as(usize, 1), app.configure_count);     const preferences_value = Preferences{        .turn_end = true,        .attention_required = true,        .max = true,    };    TestRuntime.setPreferences(&app, preferences_value);    const captured_preferences = TestRuntime.preferences(&app);    try std.testing.expect(captured_preferences.turn_end);    try std.testing.expect(captured_preferences.attention_required);    try std.testing.expect(captured_preferences.max);     app.max_enabled_value = true;    try std.testing.expect(TestRuntime.maxEnabled(&app));     TestRuntime.queue(&app, .{ .kind = .turn_end, .cue = .@"error" });    try std.testing.expectEqual(Kind.turn_end, app.queued.?.kind);    try std.testing.expectEqual(Cue.@"error", app.queued.?.cue);     TestRuntime.presentationFinished(&app);    TestRuntime.flush(&app);    try std.testing.expectEqual(@as(usize, 1), app.presentation_finished_count);    try std.testing.expectEqual(@as(usize, 1), app.flush_count);     TestRuntime.playCue(&app, .bloom);    TestRuntime.playMaxCue(&app, .toggle);    try std.testing.expectEqual(Cue.bloom, app.played_cue.?);    try std.testing.expectEqual(Cue.toggle, app.played_max_cue.?);     TestRuntime.dispatchAttentionRequired(&app, 42, .permission);    try std.testing.expectEqual(@as(u64, 42), app.attention_turn_id.?);    try std.testing.expectEqual(hooks.AttentionKind.permission, app.attention_kind.?);}