1

我最近开始学习 Zig。作为一个小项目,我想实现一个用于编写随机测试的小型 QuickCheck [1] 样式帮助程序库。

但是,我不知道如何编写通用方法来调用具有任意数量参数的函数。

这是一个简化版本,可以使用两个参数测试函数:

const std    = @import("std");
const Prng   = std.rand.DefaultPrng;
const Random = std.rand.Random;
const expect = std.testing.expect;

// the thing we want to test
fn some_property(a: u64, b: u64) !void {
    var tmp: u64 = undefined;
    var c1 = @addWithOverflow(u64, a, b, &tmp);
    var c2 = @addWithOverflow(u64, a, b, &tmp);

    expect(c1 == c2);
}

// helper for generating random arguments for the function under test
fn gen(comptime T: ?type, rnd: Random) (T orelse undefined) {
    switch (T orelse undefined) {
        u64  => return rnd.int(u64),
        f64  => return rnd.float(f64),
        else => @compileError("unsupported type"),
    }
}

/// tests if 'property' holds.
fn for_all(property: anytype) !void {
  var rnd = Prng.init(0);

  const arg_types = @typeInfo(@TypeOf(property)).Fn.args;

  var i: usize = 0;
  while (i < 100) {
    var a = gen(arg_types[0].arg_type, rnd.random());
    var b = gen(arg_types[1].arg_type, rnd.random());

    var args = .{a, b}; // <-- how do I build args for functions with any number of arguments?

    try @call(.{}, property, args);

    i += 1;
  }
}

test "test" {
  try for_all(some_property);
}

我尝试了一些不同的方法,但我不知道如何让上述代码适用于具有任意数量参数的函数。

我尝试过的事情:

  • 制作args一个数组并用inline for循环填充它。不起作用,因为[]anytype不是有效类型。
  • 使用一点 comptime 魔法来构建一个结构类型,其字段包含@call. 这在编译器中遇到了一个 TODO:error: TODO: struct args.
  • 编写返回适当参数元组调用的通用函数。我真的不喜欢这个,因为你需要一个函数来支持你想要支持的每一个 arity。但它似乎无论如何都不起作用,因为antype它不是有效的返回类型。

我在 Zig 0.9.1。

任何见解将不胜感激。

[1] https://hackage.haskell.org/package/QuickCheck

4

1 回答 1

0

这可以通过(在zig 标准库的这个文件std.meta.ArgsTuple中定义)来完成

    const Args = std.meta.ArgsTuple(@TypeOf(property));

    var i: usize = 0;
    while (i < 1000) : (i += 1) {
        var args: Args = undefined;
        inline for (std.meta.fields(Args)) |field, index| {
            args[index] = gen(field.field_type, rnd.random());
        }

        try @call(.{}, property, args);
    }

这在内部工作的方式是它构造一个带有@Type(). 然后我们可以用值填充它并使用它来调用函数。

于 2022-02-23T23:26:25.537 回答