module: improve parameter injection, fix tests
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
aa33896935
commit
0fc3bf6545
1 changed files with 66 additions and 64 deletions
130
src/module.zig
130
src/module.zig
|
|
@ -291,14 +291,8 @@ inline fn injectArgs(
|
||||||
var args: std.meta.ArgsTuple(Function) = undefined;
|
var args: std.meta.ArgsTuple(Function) = undefined;
|
||||||
comptime var std_args_index = 0;
|
comptime var std_args_index = 0;
|
||||||
outer: inline for (@typeInfo(std.meta.ArgsTuple(Function)).Struct.fields) |arg| {
|
outer: inline for (@typeInfo(std.meta.ArgsTuple(Function)).Struct.fields) |arg| {
|
||||||
// Injected arguments always go first, then standard (non-injected) arguments.
|
// Is this a Struct or *Struct, with a `pub const IsInjectedArgument = void;` decl? If so,
|
||||||
if (std_args_index > 0) {
|
// it is considered an injected argument.
|
||||||
@field(args, arg.name) = std_args[std_args_index];
|
|
||||||
std_args_index += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this argument matching the type of an argument we could inject?
|
|
||||||
inline for (@typeInfo(Injectable).Struct.fields) |inject_field| {
|
inline for (@typeInfo(Injectable).Struct.fields) |inject_field| {
|
||||||
if (inject_field.type == arg.type and @alignOf(inject_field.type) == @alignOf(arg.type)) {
|
if (inject_field.type == arg.type and @alignOf(inject_field.type) == @alignOf(arg.type)) {
|
||||||
// Inject argument
|
// Inject argument
|
||||||
|
|
@ -322,11 +316,8 @@ fn UninjectedArgsTuple(
|
||||||
) type {
|
) type {
|
||||||
var std_args: []const type = &[0]type{};
|
var std_args: []const type = &[0]type{};
|
||||||
inline for (@typeInfo(std.meta.ArgsTuple(Function)).Struct.fields) |arg| {
|
inline for (@typeInfo(std.meta.ArgsTuple(Function)).Struct.fields) |arg| {
|
||||||
// Injected arguments always go first, then standard (non-injected) arguments.
|
// Is this a Struct or *Struct, with a `pub const IsInjectedArgument = void;` decl? If so,
|
||||||
if (std_args.len > 0) {
|
// it is considered an injected argument.
|
||||||
std_args = std_args ++ [_]type{arg.type};
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const is_injected = blk: {
|
const is_injected = blk: {
|
||||||
switch (@typeInfo(arg.type)) {
|
switch (@typeInfo(arg.type)) {
|
||||||
.Struct => break :blk @hasDecl(arg.type, "IsInjectedArgument"),
|
.Struct => break :blk @hasDecl(arg.type, "IsInjectedArgument"),
|
||||||
|
|
@ -529,12 +520,11 @@ test Modules {
|
||||||
pub const name = .engine_sprite2d;
|
pub const name = .engine_sprite2d;
|
||||||
});
|
});
|
||||||
|
|
||||||
const Injectable = struct {};
|
|
||||||
var modules: Modules(.{
|
var modules: Modules(.{
|
||||||
Physics,
|
Physics,
|
||||||
Renderer,
|
Renderer,
|
||||||
Sprite2D,
|
Sprite2D,
|
||||||
}, Injectable) = undefined;
|
}) = undefined;
|
||||||
try modules.init(testing.allocator);
|
try modules.init(testing.allocator);
|
||||||
defer modules.deinit(testing.allocator);
|
defer modules.deinit(testing.allocator);
|
||||||
testing.refAllDeclsRecursive(Physics);
|
testing.refAllDeclsRecursive(Physics);
|
||||||
|
|
@ -577,12 +567,11 @@ test EventName {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const Injectable = struct {};
|
|
||||||
const Mods = Modules(.{
|
const Mods = Modules(.{
|
||||||
Physics,
|
Physics,
|
||||||
Renderer,
|
Renderer,
|
||||||
Sprite2D,
|
Sprite2D,
|
||||||
}, Injectable);
|
});
|
||||||
const info = @typeInfo(EventName(Mods.modules)).Enum;
|
const info = @typeInfo(EventName(Mods.modules)).Enum;
|
||||||
|
|
||||||
try testing.expect(type, u3).eql(info.tag_type);
|
try testing.expect(type, u3).eql(info.tag_type);
|
||||||
|
|
@ -616,12 +605,11 @@ test ModuleName {
|
||||||
const Sprite2D = Module(struct {
|
const Sprite2D = Module(struct {
|
||||||
pub const name = .engine_sprite2d;
|
pub const name = .engine_sprite2d;
|
||||||
});
|
});
|
||||||
const Injectable = struct {};
|
|
||||||
const Mods = Modules(.{
|
const Mods = Modules(.{
|
||||||
Physics,
|
Physics,
|
||||||
Renderer,
|
Renderer,
|
||||||
Sprite2D,
|
Sprite2D,
|
||||||
}, Injectable);
|
});
|
||||||
const info = @typeInfo(ModuleName(Mods.modules)).Enum;
|
const info = @typeInfo(ModuleName(Mods.modules)).Enum;
|
||||||
|
|
||||||
try testing.expect(type, u2).eql(info.tag_type);
|
try testing.expect(type, u2).eql(info.tag_type);
|
||||||
|
|
@ -631,6 +619,7 @@ test ModuleName {
|
||||||
try testing.expect([]const u8, "engine_sprite2d").eql(info.fields[2].name);
|
try testing.expect([]const u8, "engine_sprite2d").eql(info.fields[2].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove this in favor of testing.expect
|
||||||
const TupleTester = struct {
|
const TupleTester = struct {
|
||||||
fn assertTypeEqual(comptime Expected: type, comptime Actual: type) void {
|
fn assertTypeEqual(comptime Expected: type, comptime Actual: type) void {
|
||||||
if (Expected != Actual) @compileError("Expected type " ++ @typeName(Expected) ++ ", but got type " ++ @typeName(Actual));
|
if (Expected != Actual) @compileError("Expected type " ++ @typeName(Expected) ++ ", but got type " ++ @typeName(Actual));
|
||||||
|
|
@ -655,17 +644,28 @@ const TupleTester = struct {
|
||||||
test injectArgs {
|
test injectArgs {
|
||||||
// Injected arguments should generally be *struct types to avoid conflicts with any user-passed
|
// Injected arguments should generally be *struct types to avoid conflicts with any user-passed
|
||||||
// parameters, though we do not require it - so we test with other types here.
|
// parameters, though we do not require it - so we test with other types here.
|
||||||
var i: i32 = 1234;
|
const Foo = struct {
|
||||||
const i32_ptr: *i32 = &i;
|
foo: f32,
|
||||||
var f: f32 = 0.1234;
|
pub const IsInjectedArgument = void;
|
||||||
const f32_ptr: *f32 = &f;
|
};
|
||||||
const Foo = struct { foo: f32 };
|
const Bar = struct {
|
||||||
var foo: Foo = .{ .foo = 1234 };
|
bar: i32,
|
||||||
const foo_ptr: *Foo = &foo;
|
pub const IsInjectedArgument = void;
|
||||||
|
};
|
||||||
|
const Baz = struct {
|
||||||
|
baz: bool,
|
||||||
|
pub const IsInjectedArgument = void;
|
||||||
|
};
|
||||||
|
var foo = Foo{ .foo = 0.1234 };
|
||||||
|
var bar = Bar{ .bar = 1234 };
|
||||||
|
var baz = Baz{ .baz = true };
|
||||||
|
const foo_ptr = &foo;
|
||||||
|
const bar_ptr = &bar;
|
||||||
|
const baz_ptr = &baz;
|
||||||
|
|
||||||
// No standard, no injected
|
// No standard, no injected
|
||||||
try testing.expect(struct {}, .{}).eql(injectArgs(fn () void, @TypeOf(.{}), .{}, .{}));
|
try testing.expect(struct {}, .{}).eql(injectArgs(fn () void, @TypeOf(.{}), .{}, .{}));
|
||||||
const injectable = .{ i32_ptr, f32_ptr, foo_ptr };
|
const injectable = .{ foo_ptr, bar_ptr, baz_ptr };
|
||||||
try testing.expect(struct {}, .{}).eql(injectArgs(fn () void, @TypeOf(injectable), injectable, .{}));
|
try testing.expect(struct {}, .{}).eql(injectArgs(fn () void, @TypeOf(injectable), injectable, .{}));
|
||||||
|
|
||||||
// Standard parameters only, no injected
|
// Standard parameters only, no injected
|
||||||
|
|
@ -673,26 +673,23 @@ test injectArgs {
|
||||||
try testing.expect(std.meta.Tuple(&.{ i32, f32 }), .{ 1, 0.5 }).eql(injectArgs(fn (a: i32, b: f32) void, @TypeOf(injectable), injectable, .{ 1, 0.5 }));
|
try testing.expect(std.meta.Tuple(&.{ i32, f32 }), .{ 1, 0.5 }).eql(injectArgs(fn (a: i32, b: f32) void, @TypeOf(injectable), injectable, .{ 1, 0.5 }));
|
||||||
|
|
||||||
// Injected parameters only, no standard
|
// Injected parameters only, no standard
|
||||||
try testing.expect(std.meta.Tuple(&.{*i32}), .{i32_ptr}).eql(injectArgs(fn (a: *i32) void, @TypeOf(injectable), injectable, .{}));
|
|
||||||
try testing.expect(std.meta.Tuple(&.{*f32}), .{f32_ptr}).eql(injectArgs(fn (a: *f32) void, @TypeOf(injectable), injectable, .{}));
|
|
||||||
try testing.expect(std.meta.Tuple(&.{*Foo}), .{foo_ptr}).eql(injectArgs(fn (a: *Foo) void, @TypeOf(injectable), injectable, .{}));
|
try testing.expect(std.meta.Tuple(&.{*Foo}), .{foo_ptr}).eql(injectArgs(fn (a: *Foo) void, @TypeOf(injectable), injectable, .{}));
|
||||||
try testing.expect(std.meta.Tuple(&.{ *i32, *f32, *Foo }), .{ i32_ptr, f32_ptr, foo_ptr }).eql(injectArgs(fn (a: *i32, b: *f32, c: *Foo) void, @TypeOf(injectable), injectable, .{}));
|
try testing.expect(std.meta.Tuple(&.{ *Foo, *Bar }), .{ foo_ptr, bar_ptr }).eql(injectArgs(fn (a: *Foo, b: *Bar) void, @TypeOf(injectable), injectable, .{}));
|
||||||
|
try testing.expect(std.meta.Tuple(&.{ *Foo, *Bar, *Baz }), .{ foo_ptr, bar_ptr, baz_ptr }).eql(injectArgs(fn (a: *Foo, b: *Bar, c: *Baz) void, @TypeOf(injectable), injectable, .{}));
|
||||||
|
try testing.expect(std.meta.Tuple(&.{ *Bar, *Baz, *Foo }), .{ bar_ptr, baz_ptr, foo_ptr }).eql(injectArgs(fn (a: *Bar, b: *Baz, c: *Foo) void, @TypeOf(injectable), injectable, .{}));
|
||||||
|
try testing.expect(std.meta.Tuple(&.{ *Foo, *Foo, *Baz }), .{ foo_ptr, foo_ptr, baz_ptr }).eql(injectArgs(fn (a: *Foo, b: *Foo, c: *Baz) void, @TypeOf(injectable), injectable, .{}));
|
||||||
|
|
||||||
// Once a standard parameter is encountered, all parameters after that are considered standard
|
// As long as the argument is a Struct or *Struct with an IsInjectedArgument decl, it is
|
||||||
// and not injected.
|
// considered an injected argument.
|
||||||
var my_f32: f32 = 0.1337;
|
// try testing.expect(std.meta.Tuple(&.{*const Foo}), .{foo_ptr}).eql(injectArgs(fn (a: *const Foo) void, @TypeOf(injectable), injectable, .{}));
|
||||||
var my_i32: i32 = 1337;
|
const injectable2 = .{ foo, foo_ptr, bar_ptr, baz_ptr };
|
||||||
try testing.expect(std.meta.Tuple(&.{f32}), .{1234}).eql(injectArgs(fn (a: f32) void, @TypeOf(injectable), injectable, .{1234}));
|
try testing.expect(std.meta.Tuple(&.{Foo}), .{foo_ptr.*}).eql(injectArgs(fn (a: Foo) void, @TypeOf(injectable2), injectable2, .{}));
|
||||||
try testing.expect(std.meta.Tuple(&.{ i32, *f32 }), .{ 1234, &my_f32 }).eql(injectArgs(fn (a: i32, b: *f32) void, @TypeOf(injectable), injectable, .{ 1234, &my_f32 }));
|
|
||||||
try testing.expect(std.meta.Tuple(&.{ i32, *i32, *f32 }), .{ 1234, &my_i32, &my_f32 }).eql(injectArgs(fn (a: i32, b: *i32, c: *f32) void, @TypeOf(injectable), injectable, .{ 1234, &my_i32, &my_f32 }));
|
|
||||||
|
|
||||||
// First parameter (*f32) matches an injectable parameter type, so it is injected.
|
// Order doesn't matter, injected arguments can be placed inbetween any standard arguments, etc.
|
||||||
try testing.expect(std.meta.Tuple(&.{ *f32, i32, *i32, *f32 }), .{ f32_ptr, 1234, &my_i32, &my_f32 }).eql(injectArgs(fn (a: *f32, b: i32, c: *i32, d: *f32) void, @TypeOf(injectable), injectable, .{ 1234, &my_i32, &my_f32 }));
|
try testing.expect(std.meta.Tuple(&.{ i32, *Foo, *Foo, *Baz }), .{ 1337, foo_ptr, foo_ptr, baz_ptr }).eql(injectArgs(fn (z: i32, a: *Foo, b: *Foo, c: *Baz) void, @TypeOf(injectable), injectable, .{1337}));
|
||||||
|
try testing.expect(std.meta.Tuple(&.{ i32, *Foo, f32, *Foo, *Baz }), .{ 1337, foo_ptr, 1.337, foo_ptr, baz_ptr }).eql(injectArgs(fn (z: i32, a: *Foo, w: f32, b: *Foo, c: *Baz) void, @TypeOf(injectable), injectable, .{ 1337, 1.337 }));
|
||||||
// First parameter (*f32) matches an injectable parameter type, so it is injected. 2nd
|
try testing.expect(std.meta.Tuple(&.{ i32, f32, *Foo, *Foo, *Baz }), .{ 1337, 1.337, foo_ptr, foo_ptr, baz_ptr }).eql(injectArgs(fn (z: i32, w: f32, a: *Foo, b: *Foo, c: *Baz) void, @TypeOf(injectable), injectable, .{ 1337, 1.337 }));
|
||||||
// parameter is not injectable, so all remaining parameters are not injected.
|
try testing.expect(std.meta.Tuple(&.{ *Foo, *Foo, *Baz, i32, f32 }), .{ foo_ptr, foo_ptr, baz_ptr, 1337, 1.337 }).eql(injectArgs(fn (az: *Foo, b: *Foo, c: *Baz, z: i32, w: f32) void, @TypeOf(injectable), injectable, .{ 1337, 1.337 }));
|
||||||
var my_foo = foo;
|
|
||||||
try testing.expect(std.meta.Tuple(&.{ *f32, i32, *Foo, *i32, *f32 }), .{ f32_ptr, 1234, &my_foo, &my_i32, &my_f32 }).eql(injectArgs(fn (a: *f32, b: i32, c: *Foo, d: *i32, e: *f32) void, @TypeOf(injectable), injectable, .{ 1234, &my_foo, &my_i32, &my_f32 }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test UninjectedArgsTuple {
|
test UninjectedArgsTuple {
|
||||||
|
|
@ -700,6 +697,10 @@ test UninjectedArgsTuple {
|
||||||
foo: f32,
|
foo: f32,
|
||||||
pub const IsInjectedArgument = void;
|
pub const IsInjectedArgument = void;
|
||||||
};
|
};
|
||||||
|
const Bar = struct {
|
||||||
|
bar: bool,
|
||||||
|
pub const IsInjectedArgument = void;
|
||||||
|
};
|
||||||
|
|
||||||
// No standard, no injected
|
// No standard, no injected
|
||||||
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn () void));
|
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn () void));
|
||||||
|
|
@ -710,23 +711,24 @@ test UninjectedArgsTuple {
|
||||||
TupleTester.assertTuple(.{ i32, f32 }, UninjectedArgsTuple(std.meta.Tuple, fn (a: i32, b: f32) void));
|
TupleTester.assertTuple(.{ i32, f32 }, UninjectedArgsTuple(std.meta.Tuple, fn (a: i32, b: f32) void));
|
||||||
|
|
||||||
// Injected parameters only, no standard
|
// Injected parameters only, no standard
|
||||||
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *i32) void));
|
|
||||||
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *f32) void));
|
|
||||||
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *Foo) void));
|
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *Foo) void));
|
||||||
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *f32, b: *Foo, c: *i32) void));
|
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *Bar) void));
|
||||||
|
|
||||||
// Once a standard parameter is encountered, all parameters after that are considered standard
|
// As long as the argument is a Struct or *Struct with an IsInjectedArgument decl, it is
|
||||||
// and not injected.
|
// considered an injected argument.
|
||||||
TupleTester.assertTuple(.{f32}, UninjectedArgsTuple(std.meta.Tuple, fn (a: f32) void));
|
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *Foo, b: *Bar, c: Foo, d: Bar) void));
|
||||||
TupleTester.assertTuple(.{ i32, *f32 }, UninjectedArgsTuple(std.meta.Tuple, fn (a: i32, b: *f32) void));
|
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: Foo) void));
|
||||||
TupleTester.assertTuple(.{ i32, *i32, *f32 }, UninjectedArgsTuple(std.meta.Tuple, fn (a: i32, b: *i32, c: *f32) void));
|
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: Bar) void));
|
||||||
|
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *const Foo) void));
|
||||||
|
TupleTester.assertTuple(.{}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *const Bar) void));
|
||||||
|
|
||||||
// First parameter (*f32) matches an injectable parameter type, so it is injected.
|
// Order doesn't matter, injected arguments can be placed inbetween any standard arguments, etc.
|
||||||
TupleTester.assertTuple(.{ i32, *i32, *f32 }, UninjectedArgsTuple(std.meta.Tuple, fn (a: *f32, b: i32, c: *i32, d: *f32) void));
|
TupleTester.assertTuple(.{ f32, bool }, UninjectedArgsTuple(std.meta.Tuple, fn (i: f32, a: *Foo, k: bool, b: *Bar, c: Foo, d: Bar) void));
|
||||||
|
TupleTester.assertTuple(.{f32}, UninjectedArgsTuple(std.meta.Tuple, fn (i: f32, a: *Foo, b: *Bar, c: Foo, d: Bar) void));
|
||||||
// First parameter (*f32) matches an injectable parameter type, so it is injected. 2nd
|
TupleTester.assertTuple(.{f32}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *Foo, i: f32, b: *Bar, c: Foo, d: Bar) void));
|
||||||
// parameter is not injectable, so all remaining parameters are not injected.
|
TupleTester.assertTuple(.{f32}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *Foo, b: *Bar, i: f32, c: Foo, d: Bar) void));
|
||||||
TupleTester.assertTuple(.{ i32, *Foo, *i32, *f32 }, UninjectedArgsTuple(std.meta.Tuple, fn (a: *f32, b: i32, c: *Foo, d: *i32, e: *f32) void));
|
TupleTester.assertTuple(.{f32}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *Foo, b: *Bar, c: Foo, i: f32, d: Bar) void));
|
||||||
|
TupleTester.assertTuple(.{f32}, UninjectedArgsTuple(std.meta.Tuple, fn (a: *Foo, b: *Bar, c: Foo, d: Bar, i: f32) void));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "event name calling" {
|
test "event name calling" {
|
||||||
|
|
@ -770,11 +772,10 @@ test "event name calling" {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const Injectable = struct {};
|
|
||||||
var modules: Modules(.{
|
var modules: Modules(.{
|
||||||
Physics,
|
Physics,
|
||||||
Renderer,
|
Renderer,
|
||||||
}, Injectable) = undefined;
|
}) = undefined;
|
||||||
try modules.init(testing.allocator);
|
try modules.init(testing.allocator);
|
||||||
defer modules.deinit(testing.allocator);
|
defer modules.deinit(testing.allocator);
|
||||||
|
|
||||||
|
|
@ -840,6 +841,8 @@ test "dispatch" {
|
||||||
};
|
};
|
||||||
var foo = struct {
|
var foo = struct {
|
||||||
injected_args_sum: usize = 0,
|
injected_args_sum: usize = 0,
|
||||||
|
|
||||||
|
pub const IsInjectedArgument = void;
|
||||||
}{};
|
}{};
|
||||||
const Minimal = Module(struct {
|
const Minimal = Module(struct {
|
||||||
pub const name = .engine_minimal;
|
pub const name = .engine_minimal;
|
||||||
|
|
@ -887,12 +890,11 @@ test "dispatch" {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const injectable = .{&foo};
|
|
||||||
var modules: Modules(.{
|
var modules: Modules(.{
|
||||||
Minimal,
|
Minimal,
|
||||||
Physics,
|
Physics,
|
||||||
Renderer,
|
Renderer,
|
||||||
}, @TypeOf(injectable)) = undefined;
|
}) = undefined;
|
||||||
try modules.init(testing.allocator);
|
try modules.init(testing.allocator);
|
||||||
defer modules.deinit(testing.allocator);
|
defer modules.deinit(testing.allocator);
|
||||||
|
|
||||||
|
|
@ -934,8 +936,8 @@ test "dispatch" {
|
||||||
try testing.expect(usize, 1).eql(global.physics_calc);
|
try testing.expect(usize, 1).eql(global.physics_calc);
|
||||||
|
|
||||||
// Local events
|
// Local events
|
||||||
modules.sendToModule(.engine_renderer, .basicArgs, .{ @as(u32, 1), @as(u32, 2) }); // TODO: match arguments against fn ArgsTuple, for correctness and type inference
|
modules.sendToModule(.engine_renderer, .basicArgs, .{ .@"0" = @as(u32, 1), .@"1" = @as(u32, 2) }); // TODO: match arguments against fn ArgsTuple, for correctness and type inference
|
||||||
modules.sendToModule(.engine_renderer, .injectedArgs, .{ @as(u32, 1), @as(u32, 2) });
|
modules.sendToModule(.engine_renderer, .injectedArgs, .{ .@"0" = @as(u32, 1), .@"1" = @as(u32, 2) });
|
||||||
try modules.dispatch(.{&foo});
|
try modules.dispatch(.{&foo});
|
||||||
try testing.expect(usize, 3).eql(global.basic_args_sum);
|
try testing.expect(usize, 3).eql(global.basic_args_sum);
|
||||||
try testing.expect(usize, 3).eql(foo.injected_args_sum);
|
try testing.expect(usize, 3).eql(foo.injected_args_sum);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue