4

裏話

QuickCheckユニットテストフレームワークをCに移植しています( GitHubの作業コードを参照してください)。構文は次のようになります。

for_all(property, gen1, gen2, gen3 ...);

propertyたとえば、テストする関数はどこにありますかbool is_odd(int)gen1gen2などは、の入力値を生成する関数ですproperty。整数を生成するもの、文字を生成するもの、文字列を生成するものなどがあります。

for_all任意の入力(任意の数の引数、任意のタイプの引数)を持つ関数を受け入れます。for_allジェネレーターを実行し、プロパティ関数に渡すテスト値を作成します。たとえば、プロパティis_oddはタイプが。の関数bool f(int)です。for_all生成物を使用して100個のテストケースを作成します。プロパティがそれらのいずれかに対してfalseを返す場合for_all、問題のあるテストケース値を出力します。それ以外の場合は、for_allを出力します"SUCCESS"

したがって、ジェネレータにアクセスするにfor_allはを使用する必要があります。va_listジェネレーター関数を呼び出したら、それらをプロパティ関数に渡すにはどうすればよいですか?

is_oddタイプがの場合、次の構文を持つbool f(int)関数をどのように実装しますか?apply()

apply(is_odd, generated_values);

二次問題

SOを参照してください。

失敗したテストケースの任意の値をインテリジェントに印刷するにはどうすればよいですか?テストケースは、単一の整数、2文字、文字列、または上記の組み合わせの場合がありますか?使用するかどうかは事前にわかりません。

  • printf("%d %d %d\n", some_int, some_int, some_int);
  • printf("%c\n" a_character);
  • printf("%s%s\n", a_string, a_struct_requiring_its_own_printf_function);
4

1 に答える 1

3

C 言語は静的型付け言語です。他の言語にある実行時リフレクションの機能はありません。また、ランタイムが提供する型から任意の関数呼び出しを構築する方法も提供しません。is_odd関数の署名が何であるか、それが受け入れるパラメーターの数、およびそれらのパラメーターの型が何であるかを知る方法が必要です。...引数リストの最後にいつ到達したかさえわかりません。明示的なターミネータが必要です。

enum function_signature {
    returns_bool_accepts_int,
    returns_bool_accepts_float,
    returns_bool_accepts_int_int,
};

typedef bool (*function_returning_bool_accepting_int)(int);
typedef int (*function_generates_int)();

void for_all(function_signature signature, ...)
{
    va_list ap;
    va_start(ap, signature);
    switch (function_signature)
    {
    case returns_bool_accepts_int:
        {
            function_returning_bool_accepting_int fn = va_arg(ap, function_returning_bool_accepting_int);
            function_generates_int generator;
            do {
                generator = va_arg(ap, function_generates_int);
                if (generator) fn(generator());
            } while (generator);
        }
        break;
    ... etc ...
    }
}

あなたの問題は、QuickCheck が JavaScript の高度な動的プログラミング機能を利用するように設計されていることです。これは、C には欠けているものです。

更新任意の関数シグネチャを許可する場合は、呼び出し元に適切なアダプターを提供させるなどして、再度静的にする方法が必要です。

typedef void (*function_pointer)();
typedef bool (*function_applicator)(function_pointer, function_pointer);

void for_all(function_applicator apply, ...)
{
    va_list ap;
    va_start(ap, apply);
    function_pointer target = va_arg(ap, function_pointer);
    function_pointer generator;
    do {
        generator = va_arg(ap, function_pointer);
        if (generator) apply(target, generator);
    } while (generator);
}

// sample caller
typedef bool (*function_returning_bool_accepting_int)(int);
typedef int (*function_returning_int)();
bool apply_one_int(function_pointer target_, function_pointer generator_)
{
    function_returning_bool_accepting_int target = (function_returning_bool_accepting_int)target_;
    function_returning_int generator = (function_returning_int)generator_;
    return target(generator());
}

for_all(apply_one_int, is_odd, generated_values1, generated_values2, (function_pointer)0);



}
于 2011-09-23T01:04:46.747 に答える