ソフトな忘却力(17) VSCodeでgtest、テンプレートライブラリ使用csvパーサ

Joseph Halfmoon

今回は実用的なテンプレート・ライブラリ libfccp を呼び出しているコードにGoogleTest(gtest)を適用してみたいと思います。libfccp はC++用のCSVファイル読み取り用のパーサです。CSVはテキストなので自分でも読み込み簡単な気がしますが、既にライブラリがあるのなら利用させていただいた方が確実でお楽。

今回は、WindowsPC上のVSCodeから、Raspberry Pi 4機にSSH接続してサンプルプログラムを作成、実行しています。ビルドツールは例によって CMakeです。

今回利用させていただくライブラリのホームページは以下です。

Fast C++ CSV Parser

Raspberry Pi OS上では、デフォルトではlibfccpはインストールされていないと思いますが、以下の apt コマンドでインストール可能です。

sudo apt install libfccp-dev

libfccpはテンプレートライブラリです。インストールされる実体は、以下のヘッダファイルが一つだけのようです。

/usr/include/libfccp/csv.h

特にライブラリ・ファイルを呼び出すわけでないので、以下を除けばビルド時に特別な設定は要らないようです。しかし、libfccpのデフォルトでは pthread を使用するようになってました。pthread使用の場合はビルドにオプション設定を追加する必要が出てくると思います。今回はごく小規模なテストをするだけだったので、pthread使わないようにlibfccpにお願いするマクロをソースの中で定義しています。

gtest用のテストのサンプル

testディレクトリ配下に置いた test_csvparser.cppの全文が以下です。サンプルのCSVファイル一つ(2列、10000行、ヘッダありのデータファイルです。)を読み取って、vector型のオブジェクトに格納し、読み取った個数を確かめるだけのテストです。内容については何もチェックしていない、手抜きのもの。

//test_csvparser.csp
#define CSV_IO_NO_THREAD
#include <gtest/gtest.h>
#include <libfccp/csv.h>
#include <vector>

using namespace std;

vector<int> idx;
vector<double> dat;

TEST(test_libfccp, readTest) {
    io::CSVReader<2> in("t.csv");
    in.read_header(io::ignore_extra_column, "index", "data");
    int tempIndex;
    double tempData;
    while (in.read_row(tempIndex, tempData)) {
        idx.push_back(tempIndex);
        dat.push_back(tempData);
    }
    EXPECT_EQ( idx.size(), 10000); //GOOD
    EXPECT_EQ( dat.size(), 10000);  //GOOD
}

このtestディレクトリ配下をビルドするために配置した CMakeLists.txt ファイルが以下です。前回まで Raspberry Pi 3 機を使っていたのですが、今回は Raspberry Pi 4機に変えています。Pi 4上はどこを探しても GoogleTestのソースは無い筈ですが、以下のCMakeLists.txtで、CMakeが良きに計らってローカルにセットアップしてくれます。良い仕組みだな~。

test/CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(test_csvparser)
set(CMAKE_CXX_STANDARD 11)

include(FetchContent)
FetchContent_Declare(
    googletest
    URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

enable_testing()

add_executable(
    test_csvparser
    test_csvparser.cpp
)

target_link_libraries(
    test_csvparser
    gtest_main
)

include(GoogleTest)
gtest_discover_tests(test_csvparser)
形ばかりだけれどもmain関数

先ほどのテストプログラムを「小さく」した感じで形ばかりのプログラムソースをプロジェクトルートに置きました。単にテスト用のCSVの内容を標準出力に送るだけのもの。

//main.cpp
#define CSV_IO_NO_THREAD
#include <iostream>
#include <libfccp/csv.h>
using namespace std;

int main() {
    io::CSVReader<2> in("test/t.csv");
    in.read_header(io::ignore_extra_column, "index", "data");
    int index;
    double data;
    while (in.read_row(index, data)) {
        cout << "index=" << index << " data=" << data << endl;
    }
}

そして以下がプロジェクトルートに配置した、CMakeLists.txt。

cmake_minimum_required(VERSION 3.0.0)
project(csvparser VERSION 0.1.0)

include(CTest)
enable_testing()

add_executable(csvparser main.cpp)
add_subdirectory(test)

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

VSCodeからbuildした後の様子。ツマラナイ画面ですが。

csvparser_gtest

実行結果

実際に読み込んだテスト用のCSVファイルは以下です。

index,data
1,10.0511541945054
2,23.9891861011839
3,58.4443380698546
~途中略~
9997,9.91486664553604
9998,51.0844663720918
9999,43.3297881458661
10000,35.4664663926697

そして上記を読み取った gtest の結果が冒頭のアイキャッチ画像に。PASSです。あたりまえか。

まあ、テンプレート・ライブラリなのでビルド的には何もしなくても gtestはOKっと。CSVファイルの読み取りは後で別件の実験に使用予定であります。

ソフトな忘却力(16) VSCodeでctest+gtestその2、Classのテスト へ戻る

ソフトな忘却力(18) 偶数個のときの median、浮動小数の gtest へ進む