1

最近Zigを習い始めました。小さなプロジェクトとして、ランダム化されたテストを作成するための小さな QuickCheck [1] スタイルのヘルパー ライブラリを実装したいと考えていました。

ただし、任意の数の引数で関数を呼び出す一般的な方法を記述する方法がわかりません。

2 つの引数で関数をテストできる簡略化されたバージョンを次に示します。

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.
  • 適切な引数タプル呼び出しを返す汎用関数を記述します。サポートしたいアリティごとに 1 つの関数が必要なので、これはあまり好きではありません。antypeただし、有効な戻り値の型ではないため、とにかく機能しないようです。

私は Zig 0.9.1 を使用しています。

任意の洞察をいただければ幸いです。

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

4

1 に答える 1