2014年2月27日木曜日

[C++] Jenkins でカバレッジ計測結果を表示する

最近のマイブーム、カバレッジ計測です。
前回([C++] Coveralls でコードカバレッジ)、
前々回([C++] Coveralls でコードカバレッジ - その2
Travis CI + Covarlls でカバレッジ計測をしましたが、今回は Jenkins でやります。

なぜ、Jenkins かというと社内の CI ツールが Jenkins だからというだけです。
(最近は Travis CI とか Coveralls とかの方が楽で便利だなと思っているのですが、仕事では Jenkins が手放せません。)

やり方については以下の記事を参考にしました。

gcovr のインストール
まず最初に gcovr をインストールします。
公式サイトからダウンロードしても良いですが、今回は easy_install でインストールしました。
やることは簡単で、以下のコマンドを実行するだけです。
easy_install gcovr

gcovr で xml 出力
gcc でカバレッジを出力する手順は省きます。
gcovr で xml 出力するには --xml オプションをつけて実行します。
gcovr --xml --output=gcovr_result.xml ./test
--output には出力ファイル名を指定し、解析対象のフォルダパスを渡します。

Jenkins の設定
Jenkins の設定も特に難しいことはありません。
まずは、プラグインの管理で「Cobertura Plugin」をインストールします。

次に、プロジェクトの設定を開き、「ビルド後の処理の追加」から「Cobertura カバレッジ・レポートの集計」を選択します。続いて、「Cobertura XMLレポート パターン」に gcovr が出力した xml ファイルのパスを指定します。


以上で設定は終わりです。
これを実行すると、以下のようにカバレッジが表示されます。


(条件のカバレッジ率が低いですね:-<)


かなり雑に説明しましたが、とくに躓くポイントはないと思います。
視覚化すると見えてくるものもあると思うので、導入できる環境であれば是非。
(仕事で jenkins が…といいつつ実はまだ導入してない)
それでは、皆様よい開発を~。

2014年2月21日金曜日

[C++] va_list を再利用してはいけない

最近ハマったので備忘録。

C++ で可変長引数を扱うときに va_list を使うと思いますが、これって再利用してはダメなんですね。知りませんでした。

#include <stdarg.h>
#include <iostream>

void f(const char* fmt, ...)
{
    va_list va, va2;
    va_start(va, fmt);
    va_copy(va2, va);
    
    // OK
    char buf[256];
    vsprintf(buf, fmt, va);
    ::std::cout << buf;
    
    // OK
    char buf2[256];
    vsprintf(buf2, fmt, va2);
    ::std::cout << buf2;

    // NG
    char buf3[256];
    vsprintf(buf3, fmt, va);
    ::std::cout << buf3;

    va_end(va);
    va_end(va2);
}

int main(void)
{
    f("%d %d %d\r\n", 1, 2, 3);
    return 0;
}

1 2 3
1 2 3
4198192 812910400 0

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

va_copy というのも初めて知りました。
Visual Studio だと va_copy は 2012 以前だとないようです。2013 では使えます。

ちなみに、Visual Studio だと上記コードでも問題なく動いたので環境依存ってことなんでしょうかね。

2014年2月17日月曜日

[C++] Coveralls でコードカバレッジ - その2

Travis CI + Coveralls でカバレッジ計測を使い始めたのですが、自分が思ってた以上にカバレッジ率が低くて 恥ずかしい/// って感じだったのですが、どうやら通っているはずのコードが通っていないと判断されているようでした。

原因は gcov のバージョンが古いことのようで、Travis でデフォルトで使える gcov は version 4.6.3 なのですが、
以下のログからも分かるように、同じファイルでも相対パスの経路が違うと別ファイルとして認識されるようです。

File '../include/internal/../internal/../iutest_env.hpp'
Lines executed:85.59% of 111
../include/internal/../internal/../iutest_env.hpp:creating 'iutest_env.hpp.gcov'

File '../include/gtest/../internal/../internal/../iutest_env.hpp'
Lines executed:63.54% of 96
../include/gtest/../internal/../internal/../iutest_env.hpp:creating 'iutest_env.hpp.gcov'

そして、出力する .gcov ファイル名は同じなため上書き保存されてしまっていました。
※ Coveralls で表示されるパーセンテージと異なる場合がありますが、それは cpp-coveralls が positive failure に対応しているためです。(これに気づかず Coveralls や cpp-coveralls 側を疑ってしまい時間がかかってしまった…)

-p オプションや -l オプション使えば上書きされることはないですが、後でマージする必要があります。
マージツールもあるようですが、今回はストレートに新しいバージョンの gcov を使うことで対応しました。

.travis.yml に以下を追加。
install:
  # gcc 4.8
  - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
  - sudo apt-get -qq update
  - if [ "${CXX}" = 'g++' ]; then sudo apt-get -qq install g++-4.8; fi
  - if [ "${CXX}" = 'g++' ]; then sudo update-alternatives --install /usr/bin/gcc  gcc  /usr/bin/gcc-4.8 90; fi
  - if [ "${CXX}" = 'g++' ]; then sudo update-alternatives --install /usr/bin/g++  g++  /usr/bin/g++-4.8 90; fi
  - if [ "${CXX}" = 'g++' ]; then sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-4.8 90;  fi

この修正とテスト追加により、iutestカバレッジが 91% にまでなりました。
バッチがみどりになった~

そして、カバレッジ上げようとテストを見なおしていたらバグを結構潰せました。
いや~やっといてよかった~

※ 執筆時点でのカバレッジ結果なので将来的にパーセンテージが変化することがあります。
最新の情報は github へ > https://github.com/srz-zumix/iutest