simulator: expose sometimes assertions via the simulator object
This commit is contained in:
@@ -7,9 +7,30 @@ const Trace = @import("trace.zig").Trace;
|
|||||||
const Scheduler = @import("scheduler.zig");
|
const Scheduler = @import("scheduler.zig");
|
||||||
const Network = @import("network.zig");
|
const Network = @import("network.zig");
|
||||||
const Node = @import("node.zig");
|
const Node = @import("node.zig");
|
||||||
|
const Sometimes = @import("sometimes.zig").Sometimes;
|
||||||
|
|
||||||
pub const EntryPoint = Scheduler.MainEntryPoint;
|
pub const EntryPoint = Scheduler.MainEntryPoint;
|
||||||
|
|
||||||
|
// Process-global pointer to the active simulation's sometimes-assertion
|
||||||
|
// registry. Programs under test only receive an `std.Io` and have no handle to
|
||||||
|
// the Simulator, so assertSometimes() reaches the registry through this global.
|
||||||
|
// Everything runs single-threaded in userspace, so a plain global is
|
||||||
|
// deterministic. It is set in init() and cleared in deinit(), giving each
|
||||||
|
// simulation a fresh, per-run registry.
|
||||||
|
var g_sometimes: ?*Sometimes = null;
|
||||||
|
|
||||||
|
// Records that `cond` was observed at this point of the simulation. The call
|
||||||
|
// site (@src()) is the identity; `label` is an optional human-readable name
|
||||||
|
// shown in the end-of-simulation report. Pass null when no label is wanted:
|
||||||
|
// assertSometimes(x > 0, @src(), null);
|
||||||
|
//
|
||||||
|
// This never changes the behaviour of the program under test: if no simulation
|
||||||
|
// is active the call is a no-op.
|
||||||
|
pub fn assertSometimes(cond: bool, src: std.builtin.SourceLocation, label: ?[]const u8) void {
|
||||||
|
const registry = g_sometimes orelse return;
|
||||||
|
registry.record(cond, src, label);
|
||||||
|
}
|
||||||
|
|
||||||
const SpawnOptions = struct {
|
const SpawnOptions = struct {
|
||||||
stack_size: usize = 64 * 1024,
|
stack_size: usize = 64 * 1024,
|
||||||
addresses: []const u32 = &[0]u32 {}, // TODO: How do I make an empty slice?
|
addresses: []const u32 = &[0]u32 {}, // TODO: How do I make an empty slice?
|
||||||
@@ -34,6 +55,7 @@ nodes: std.ArrayList(*Node),
|
|||||||
executables: std.ArrayList(ExecutableName),
|
executables: std.ArrayList(ExecutableName),
|
||||||
real_io: std.Io,
|
real_io: std.Io,
|
||||||
next_node_id: u32,
|
next_node_id: u32,
|
||||||
|
sometimes: Sometimes,
|
||||||
|
|
||||||
pub fn init(self: *Simulator, gpa: Allocator, real_io: std.Io, seed: u64) void {
|
pub fn init(self: *Simulator, gpa: Allocator, real_io: std.Io, seed: u64) void {
|
||||||
self.gpa = gpa;
|
self.gpa = gpa;
|
||||||
@@ -45,9 +67,18 @@ pub fn init(self: *Simulator, gpa: Allocator, real_io: std.Io, seed: u64) void {
|
|||||||
self.executables = .empty;
|
self.executables = .empty;
|
||||||
self.real_io = real_io;
|
self.real_io = real_io;
|
||||||
self.next_node_id = 0;
|
self.next_node_id = 0;
|
||||||
|
self.sometimes.init(gpa);
|
||||||
|
g_sometimes = &self.sometimes;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Simulator) void {
|
pub fn deinit(self: *Simulator) void {
|
||||||
|
// Print the end-of-simulation coverage report unless the caller already
|
||||||
|
// asked for it explicitly via reportSometimes().
|
||||||
|
if (!self.sometimes.reported)
|
||||||
|
self.sometimes.report();
|
||||||
|
g_sometimes = null;
|
||||||
|
self.sometimes.deinit();
|
||||||
|
|
||||||
for (self.nodes.items) |node| {
|
for (self.nodes.items) |node| {
|
||||||
node.deinit();
|
node.deinit();
|
||||||
self.gpa.destroy(node);
|
self.gpa.destroy(node);
|
||||||
@@ -59,6 +90,13 @@ pub fn deinit(self: *Simulator) void {
|
|||||||
self.trace.deinit();
|
self.trace.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prints which sometimes-assertions were taken (✓) and which were reached
|
||||||
|
// but never satisfied (✗). Called automatically by deinit(); expose it so
|
||||||
|
// callers can choose exactly when the report is emitted.
|
||||||
|
pub fn reportSometimes(self: *Simulator) void {
|
||||||
|
self.sometimes.report();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setTraceOutputFile(self: *Simulator, path: []const u8) !void {
|
pub fn setTraceOutputFile(self: *Simulator, path: []const u8) !void {
|
||||||
try self.trace.setOutputFile(path);
|
try self.trace.setOutputFile(path);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user