Closed7

C++テストフレームワーク: catch2をZigから使う試み

ktz_aliasktz_alias

C++のユニットテストを探して、Wikipediaを舐め回してたところ、catch2が目につく。

  • スター数も多いので良さそうな予感
ktz_aliasktz_alias

以下のように書いたら、ビルドは通った・・・通ったんだが、実行がブロックされてメソッドから抜け出てくれん。

#include <catch2/catch_session.hpp>

extern "C" {

auto run_catch2_test() -> void {
    Catch::Session().run();
}

}
ktz_aliasktz_alias

Zigのインサイドコードテストからよばせた場合は、ブロックされるが、通常の実行ファイルから呼ばせた場合は問題なく終了した。

標準入力か、標準エラーのロックを握られてるくさい?
↑コマンドラインオプションとして-o filenameを付与するよう指示したら、呼び出しから戻ってきた

ktz_aliasktz_alias

標準出力の衝突を回避した上で、Session::run()を実行し、戻り値(exit code)をみて、判定するのが現実的そう。

標準出力の衝突を回避は以下のいずれか

  • "-o filename"を指定する
  • Session::run()前に標準出力をファイルにリダイレクトし、実行後元の状態に戻す

後者のコードはChatGPT先生曰く、以下のように書けば良いとのこと

auto run_catch2_test() -> int {
    // 標準出力をファイルにリダイレクト
    std::ofstream out("output.txt");
    std::streambuf* coutbuf = std::cout.rdbuf(); // 標準出力のバッファを保存
    std::cout.rdbuf(out.rdbuf()); // 標準出力をリダイレクト

    int argc = 2;
    const char* argv[] = { "your_program_name", "--success" };

    Catch::Session session;

    // Apply the command line arguments
    int returnCode = session.applyCommandLine(argc, argv);
    if (returnCode != 0) { // Indicates a command line error
        std::cout << "Error parsing command line arguments\n";
        return -1;
    }

    // Run the tests and capture the result
    int result = session.run();
    
    std::cout.rdbuf(coutbuf); // 標準出力を元に戻す
    return result;
}

戻り値

  • 0 - テスト成功なら
  • 1 - テスト失敗
  • 2 - 対象テストなし

zig側で以下のように書けば良さそう(ChatGPT先生のコードを改変)

test "call catch2 test" {
    const allocator = std.testing.allocator;

    const err = run_catch2_test();
    
    if (err > 0) {
        // ファイルからCatch2の結果を読み取る
        const file = try std.fs.cwd().openFile("output.txt", .{});
        defer file.close();

        const meta = try file.metadata();
        const data = try file.readToEndAlloc(allocator, meta.size());
        defer allocator.free(data);

        std.debug.print("Catch2 output:\n{s}\n", .{data}); 
    }

    try testing.expectEqual(0, err);
}
このスクラップは5ヶ月前にクローズされました