2015年12月29日火曜日

2015年最後の下書き供養

さて、2015 年も残りわずかになりましたね。

思いつきで下書きにタイトルを残しておいたものや、ちょっとした文章書いてそれから全く手を付けてないものがかなり溜まってきました。
そこで、今回は「2015年最後の下書き供養」ということで、溜まった下書きを一掃したいと思います。

Jenkins Plugin を作ってみよう - その1(環境構築)

作ってみようと思ってある程度環境構築までしたのですが、結局そこまでで作れていません。
プラグインはホントに作りたいと思ってますが、この下書きはだいぶ古いので捨ててしまいます。

[Jenkins] メール通知をスルーされにくくするためのちょっとした工夫
メール通知の Tips 的な記事としてまとめていて、多少中身ができているのですが、自分自身メール通知がちゃんと運用できていないこともあってまだまだ半端な状態です。
一応残しておきますが、公開できるようになるにはもっと実践する必要があると思います。
(要望があれば、ちょっと頑張ります。)

Haskell はじめました
はじまりませんでした。

Visual Studio Community 2013 でアドインを作る
Community でアドイン(拡張機能)が使えるようになりましたが、使うだけでなく作ることもできるので、簡単にサンプル的なものを作って記事にしようとおもったのですが、VS 2015 Community も出てしまいましたし、完全に旬を過ぎているのでお蔵入りです。

Visual Studio のデバッガ拡張「MIEngine」を使ってみた


便利そうだなと思って少し触って、よくわからなかったので放置してました。
とりあえず今は必要としてないので捨てます。

Perforce を hosting サイトの Assembla を利用して使ってみた
Perforce 使ったことがなかったので、一度使ってみたいな~と思って、どこかホスティングサービスないかというときに見つけたのが Assembla です。

で、Perforce を使おうとしたものの、よくわからなかった・使いこなせなかったので放置。
Perforce 使う機会があればいいのですが、個人的に使おうとしないとそういうことはなさそうなので、これも破棄。

[Arduino] 個人的備忘録
ある程度たまったら、と思っていたのですが、最近は Arduino を弄ってないため全くと言って皆無。
まだしばらくは電子工作から離れてると思います。(たぶん)

[Arduino] コマンドラインでビルドから転送までをする
こっちは書き終わってたんですが、公開するタイミングをうかがっていたら、いつの間にかすっかり忘れていてこの記事を書き始めて気づきました。
気づいた時には既に遅し。だいぶ前に書いたので今はあげるのは…な感じなので、一応保存しておいて次に Arudino を弄る機会があったら、見直して公開することにします。

「C++のためのAPIデザイン」を読んで自作コードを評価してみた


まだ全部読んでない。

2015年に読んだ本
私、本をあまり読まないので、
今年はちょっと本を読もうかなという決意も込めて下書きしていたのですが、
結局読んだのはマンガと
「システムテスト自動化 標準ガイド」と

「マンガでよくわかる 教える技術」くらい。

(それもマンガやろ、というツッコミはなしで)

ギア本もまだ全部読んでないですしね…

というわけで、この記事はボツ。
そして、「2016年に読んだ本」というタイトルに決意を込めて変える!

最後に
今年も残りわずかですね。
もう休みに入られている方も、まだまだ仕事があるよという方もよいお年をお過ごしください。
それでは、また来年~

2015年12月16日水曜日

Boost.Test v3 を使ってみた

この記事は 初心者 C++er Advent Calendar 2015 16 日目の記事です。
<15日目: matsuokah さん「C++初心者ならビルドはBazelでラクしちゃいましょう
>17日目:yumetodo さん「C99からC++14を駆け抜けるC++講座

アドベントカレンダー用に書いてたものじゃないんですが、空いていたので滑り込みました。



Boost 1.59.0がリリースされました - Faith and Brave - C++で遊ぼう

Boost 1.59.0 で Boost.Test v3 になってます。
リンク先にも書かれているように、主な変更点は BOOST_TEST マクロと Data driven test 対応でしょう。
今回はこの2つを試してみました。

Windows + Visual Studio な環境で Boost を即座に使う方法
Boost の Nuget パッケージが公開されているので、それを使います。
NuGet Gallery | boost 1.59.0
既にやり方がまとめてられています。こちらのほうが画像もあって参考になると思います。



BOOST_TEST マクロ
Catch のアサーションのように、式の各値を出力してくれる機能がついたアサーションです。
Catch に関しては以前のブログを参考にしてください。

使い方はこんな感じで
#define BOOST_TEST_MODULE example
#include "boost/test/unit_test.hpp"

int f() { return 42; }

BOOST_AUTO_TEST_CASE(test_op_reportings)
{
 int a = 43, b = 42, c = 0;
 BOOST_TEST(a == b);
 BOOST_TEST(f() == a);
 BOOST_TEST(a < b);
 BOOST_TEST(a - 1 < b);
 BOOST_TEST(b > a - 1);

 BOOST_TEST((f() && c));
}

こんなふうに出力されます。

|| や && は () で囲う必要があります。( () の中身は展開できないようです。)

仕組みとしては、Catch と同様に operator ->* を利用したもののようです。
これはかなり便利な機能が追加されましたね!

Data-driven test
Google Test の値のパラメータ化テストのことです。
Boost.Test でも BOOST_PARAM_TEST_CASE を使うことで出来ていました。これは 2012年のアドベントカレンダーの補足(ブログズミ: Google Test ユーザーが Boost.Test を使ってみた (補足))で書きました。
ちょっと面倒くささがあったのですが、v3 になって Data-driven test に置き換えられました。

基本
まずは簡単な例から
#define BOOST_TEST_MODULE example
#include <boost/test/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#include <boost/test/data/monomorphic.hpp>
#include <iostream>

namespace bdata = boost::unit_test::data;

BOOST_DATA_TEST_CASE(test1, bdata::xrange(5))
{
    std::cout << "test 1: " << sample << std::endl;
    BOOST_TEST((sample <= 4 && sample >= 0));
}
BOOST_DATA_TEST_CASE(test2, bdata::xrange(5), var)
{
    std::cout << "test 2: " << var << std::endl;
    BOOST_TEST((var <= 4 && var >= 0));
}

BOOST_DATA_TEST_CASE の第一引数がテスト名、第二引数がデータセットです。
この例では、0~4 の値でテストが実行されます。
パラメータは何も指定しなければ、「sample」変数で取得できます。(test1)
BOOST_DATA_TEST_CASE マクロの第三引数以降に名前を指定すると、指定した名前で取得できます。(test2)

データセット生成器
データセット生成器は、xrange, random, make の3つが提供されています。 Datasets generators - 1.59.0
xrange は任意の範囲の値を、random はランダムな値を、make は任意の値を指定することができます。

以下は make の例
BOOST_DATA_TEST_CASE(test3, bdata::make(1))
{
    std::cout << "test 3: " << sample << std::endl;
}

struct Hoge
{
    int x, y;
};

//::std::ostream& operator << (::std::ostream& os, const Hoge& hoge)
//{
//  return os << "X:" << hoge.x << " Y:" << hoge.y;
//}

BOOST_TEST_DONT_PRINT_LOG_VALUE(Hoge);

const char* a[] = { "ABC", "DEF", "G", "H" };
Hoge x[4] = { {0,1}, {2,3}, {4,5}, {6,7} };

BOOST_DATA_TEST_CASE(test4, bdata::make(a), v)
{
    std::cout << "test 4: " << a << << std::endl;
}
BOOST_DATA_TEST_CASE(test5, bdata::make(x), v)
{
    std::cout << "test 5: " << v.x << ", " << v.y << std::endl;
}

test3 では単一の値、test4, test5 では配列からデータセットを作成しています。
構造体などを使用する場合は、ostream への operator << を定義するか BOOST_TEST_DONT_PRINT_LOG_VALUE を使う必要があります。


続いて random の例ですが、下記コードだと実行時に例外が投げられます。
BOOST_DATA_TEST_CASE(test6, bdata::random(0, 100))
{
    std::cout << "test 6: " << sample << std::endl;
}
random は要素数の定義がないためです。
random を使うにはデータセットの組み合わせが必要になります。

データセットの組み合わせ
データセットは複数設定することができます。 Operations on dataset - 1.59.0
BOOST_DATA_TEST_CASE の第三引数以降にデータセットを受け取る変数名をパラメータ数分指定してください。

Zips
まずは、random の例として Zips を使います。
BOOST_DATA_TEST_CASE(test7, bdata::xrange(5) ^ bdata::random(0, 100), i, sample)
{
    std::cout << "test 7: " << i << ": " << sample << std::endl;
}

'^' が Zips のオペレーターです。2つのデータセットをペアにします。
上記の例では、0~4 のインデックスと乱数がパラメータとして得られます。


複数のデータセットをまとめることができますが、有限のデータセットの場合は要素数を揃える必要があるので注意。
BOOST_DATA_TEST_CASE(test8, bdata::xrange(5) ^ bdata::xrange(10, 15) ^ bdata::xrange(100, 110, 2)
    , var1, var2, var3)
{
    std::cout << "test 8: " << var1 << ", " << var2 << ", " << var3 << std::endl;
}



Grid (Cartesian products)
次に、データセットから直積のパラメータを生成します。
これは Google Test の Combine と同じ機能になります。
BOOST_DATA_TEST_CASE(test9, bdata::xrange(5) * bdata::xrange(5), var1, var2)
{
    std::cout << "test 9: " << var1 << ", " << var2 << std::endl;
}

'*'Grid (Cartesian products) のオペレーターです。
2つのデータセットのすべての組み合わせがパラメータとして得られます。

Joins
最後になりましたが、データセットは連結することもできます。
BOOST_DATA_TEST_CASE(test10, bdata::xrange(5) + bdata::xrange(10, 15))
{
    std::cout << "test 10: " << sample << std::endl;
}

'+'Joins のオペレーターです。
上記例では 0~4 と 10~14 がパラメータとして得られます。


最後にこれらの組み合わせを使うことで、より複雑なデータセットを作ることもできます。
BOOST_DATA_TEST_CASE(test11, (bdata::xrange(5) + bdata::xrange(10, 15)) ^ bdata::random(0,100), var1, var2)
{
    std::cout << "test 11: " << var1 << ", " << var2 << std::endl;
}


まとめ
Boost.Test v3 になってすごく便利に、そして書きやすくなってました。
個人的にはオペレーターで組み合わせ作れるのがいいなーと思ったので、あとは使う機会があればって感じです。
もし、Boost を業務で使うことがあれば、テスティングフレームワークは Boost.Test を使おうと思います。

2015年12月9日水曜日

[Catch] REQUIRE の式が展開される仕組み

こちらは C++ Advent Calendar 2015 9日目の記事になります。
前の日は plasma_effector さんで「plasma.ADTの紹介 」でした。


ブログズミ: C++ Testing Framework の Catch を使ってみた
以前、Catch を紹介したときに REQUIRE マクロに渡した式が展開されることを書きました。

その仕組について、簡単ではありますが説明しておこうと思います。
(大分昔に書き上げていたものの、アップするタイミングを失っていたのですが、こうしてアドベントカレンダーとして公開することができました。)

#define CATCH_CONFIG_MAIN // main の定義を catch に任せる
#include <catch.hpp>

int f()
{
    return 1;
}

TEST_CASE("Test", "[sample]")
{
    CHECK( f() == 2 );
    REQUIRE( f() <= 0 );
}

-------------------------------------------------------------------------------
Test
-------------------------------------------------------------------------------
main.cpp(9)
...............................................................................

main.cpp(11): FAILED:
  CHECK( f() == 2 )
with expansion:
  1 == 2

main.cpp(12): FAILED:
  REQUIRE( f() <= 0 )
with expansion:
  1 <= 0

===============================================================================
1 test case - failed (2 assertions - both failed)

こちらが「ブログズミ: C++ Testing Framework の Catch を使ってみた」で書いたコードと実行結果です。

REQUIRE および CHECK に渡した式の中の f() が返した値が出力されています。
この仕組を説明します。


マクロを追う
REQUIRE や CHECK マクロがどのような実装になっているのか追っていきます。

まず、REQUIRE や CHECK はこのように書かれています。
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )

どちらも INTERNAL_CATCH_TEST を使っています。
INTERNAL_CATCH_TEST は以下のようになっています。
#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
    do { \
        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
        try { \
            ( __catchResult->*expr ).endExpression(); \
        } \
        catch( ... ) { \
            __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
        } \
        INTERNAL_CATCH_REACT( __catchResult ) \
    } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
(include/internal/catch_capture.hpp)

REQUIRE と CHECK の違いは resultDisposition と macroName の部分です。
macroName はただの名前なので特に気にしなくて OK です。 resultDisposition では続行可能か不可能かを分けています。

さて、ここで重要なのが
( __catchResult->*expr ).endExpression();
のところです。
->* は間接メンバポインタ演算子という演算子で、オーバーロード可能な演算子の1つです。
これが f() の戻り値が表示される仕組みの肝になります。

実際に最初のコードを例に説明をします。

式の分解
最初に示したコードの REQUIRE 文を展開します。

do {
    Catch::ResultBuilder __catchResult( "REQUIRE", CATCH_INTERNAL_LINEINFO, "f() <= 0", Catch::ResultDisposition::Normal );
    try {
        ( __catchResult->*f() <= 0 ).endExpression();
    }
    catch( ... ) {
        __catchResult.useActiveException( Catch::ResultDisposition::Normal );
    }
    INTERNAL_CATCH_REACT( __catchResult )
} while( Catch::isTrue( false && (f() <= 0) ) )

さて、改めて
( __catchResult->*expr ).endExpression();
に注目しましょう。
これは上記の展開されたコードでは、
( __catchResult->*f() <= 0 ).endExpression();
のようになっています。
ここで、
__catchResult->*f() <= 0
はどのような順番で処理されると思いますか?



正解は、
  1. f()
  2. __catchResult->*f()
  3. __catchResult->*f() <= 0
です。
これは演算子の優先順位により、<= よりも ->* が先に評価されるためです。
C++ Operator Precedence - cppreference.com

簡単に挙動確認コードを書きました。気になる方はこちらも参照してください。
[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

というわけで、「f() <= 0」 から 「f()」と「<= 0」とに分解できました。
ResultBuilder(__catchResult) には f() の戻り値が入ってくるので、f() の結果が Catch できるのです^^

分解できたのであとはイイ感じするだけです。ついでなので説明します。

残った式の処理
Catch::ResultBuilder::operator ->* を詳しく見てみましょう。
class ResultBuilder {
public:
    ResultBuilder(  char const* macroName,
                    SourceLineInfo const& lineInfo,
                    char const* capturedExpression,
                    ResultDisposition::Flags resultDisposition );

    template<typename T>
    ExpressionLhs<T const&> operator->* ( T const& operand );
    ExpressionLhs<bool> operator->* ( bool value );

template<typename T>
inline ExpressionLhs<T const&> ResultBuilder::operator->* ( T const& operand ) {
    return ExpressionLhs<T const&>( *this, operand );
}

inline ExpressionLhs<bool> ResultBuilder::operator->* ( bool value ) {
    return ExpressionLhs<bool>( *this, value );
}
(include/internal/catch_result_builder.h)

ResultBuilder::operator->* はなんらかの値を受け取り、ExpressionLhs を返します。
(bool で特殊化されていますがここでは無視します)

ExpressionLhs はこのように定義されています。
template<typename T>
class ExpressionLhs {
    ExpressionLhs& operator = ( ExpressionLhs const& );
#  ifdef CATCH_CPP11_OR_GREATER
    ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
#  endif

public:
    ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
#  ifdef CATCH_CPP11_OR_GREATER
    ExpressionLhs( ExpressionLhs const& ) = default;
    ExpressionLhs( ExpressionLhs && )     = default;
#  endif

    template<typename RhsT>
    ResultBuilder& operator == ( RhsT const& rhs ) {
        return captureExpression<Internal::IsEqualTo>( rhs );
    }

    template<typename RhsT>
    ResultBuilder& operator != ( RhsT const& rhs ) {
        return captureExpression<Internal::IsNotEqualTo>( rhs );
    }

    template<typename RhsT>
    ResultBuilder& operator < ( RhsT const& rhs ) {
        return captureExpression<Internal::IsLessThan>( rhs );
    }

    template<typename RhsT>
    ResultBuilder& operator > ( RhsT const& rhs ) {
        return captureExpression<Internal::IsGreaterThan>( rhs );
    }

    template<typename RhsT>
    ResultBuilder& operator <= ( RhsT const& rhs ) {
        return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
    }

    template<typename RhsT>
    ResultBuilder& operator >= ( RhsT const& rhs ) {
        return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
    }

    ResultBuilder& operator == ( bool rhs ) {
        return captureExpression<Internal::IsEqualTo>( rhs );
    }

    ResultBuilder& operator != ( bool rhs ) {
        return captureExpression<Internal::IsNotEqualTo>( rhs );
    }

    void endExpression() {
        bool value = m_lhs ? true : false;
        m_rb
            .setLhs( Catch::toString( value ) )
            .setResultType( value )
            .endExpression();
    }

    // Only simple binary expressions are allowed on the LHS.
    // If more complex compositions are required then place the sub expression in parentheses
    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );

private:
    template<Internal::Operator Op, typename RhsT>
    ResultBuilder& captureExpression( RhsT const& rhs ) {
        return m_rb
            .setResultType( Internal::compare<Op>( m_lhs, rhs ) )
            .setLhs( Catch::toString( m_lhs ) )
            .setRhs( Catch::toString( rhs ) )
            .setOp( Internal::OperatorTraits<Op>::getName() );
    }

private:
    ResultBuilder& m_rb;
    T m_lhs;
};
(include/internal/catch_expression_lhs.hpp)

長いですが、まずここで注目するのは各種 operator のオーバーロードです。
それぞれ値を受け取り captureExpression 関数を通して ResultBuilder の参照を返しています。

captureExpression では、Internal::compare でオペレーターごとに式の評価が行われ、その結果と左辺・右辺の文字列、オペレーターの文字列が ResultBuilder に設定されます。このように、Catch では operator オーバーロードを利用してそれぞれの情報を集めつつ評価がされていく仕組みになっています。


ちなみに真ん中辺りにある STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& を返すオペレーター(+,-,/,*,&&,||)はこの仕組が使えません。つまり、REQUIRE( a && b ) のような書き方はできませんのでご注意。

他のテスティングフレームワークの対応状況は?
Boost.Test では?
Boost.Test では v1.59 から同様のアサーションが使えるようになってます。
(Catch ではできないオペレーターにも対応しています。)
BOOST_ - 1.59.0
Boost 1.59.0がリリースされました - Faith and Brave - C++で遊ぼう

Google Test では?
Google Test には残念ながらそのようなアサーションはありません。

iutest では?
iutest は私が作っているテスティングフレームワークです。 https://github.com/srz-zumix/iutest
iutest でも同様の記述ができ、これも operator ->* のオーバーロードで実現させています。実装はだいたい似たような感じですが、iutest では Catch では使えないオペレーターにも対応してます。

int f(void)
{
    return 42;
}

IUTEST(ExpressionTest, Test)
{
    IUTEST_EXPECT(f() + f() == 2);
}




最後に
Catch にしろ、Boost.Test にしろ、iutest にしろ、所謂 PowerAssert は便利な機能です。
普段 Google Test をよく使っているので、これがないとテストが書けないわけではありませんが、ASSERT_EQ(a, b) などと書くよりも ASSERT( a == b ) と書けたほうが、より直観的でわかりやすいですよね。

Google Test も(まだまだ開発進んでいるので)対応することを期待しつつ、これで締めたいと思います。
C++ Advent Calendar 2015 10日目は hmito さんで「[C++] csvファイル入出力用のiteratorを作ってみた話 - Qiita」です。

2015年12月8日火曜日

「DevLOVE現場甲子園2015『西日本大会』」に参加してきた

DevLOVE現場甲子園2015『西日本大会』に参加してきました。
参加したセッションは以下。

一回戦【クリスタルファンタジアを支えきった技術と技術だけではどうにもならない話】
内海 恵介
(ゲーム)
二回戦【“ワンフレーズゴール”がもたらしたもの - チーム改善の達成と失敗】
阪田 浩一
(サービス)
三回戦【メンバーの成長を促進する組織マネジメント】
細谷 泰夫
(現場支援)
四回戦【自動化とは何か?ゲーム開発において実践した自動化とは?】
森田 和則
(ゲーム)
五回戦【エンジニアが幸せな人生を過ごすための学び方、関わり方、あり方。】
久保 明
(現場支援)
再演賞【エンジニアが幸せな人生を過ごすための学び方、関わり方、あり方。】
久保 明
(現場支援)

参加した理由
DevLove 甲子園は今回が初参加でした。
参加した理由は、テーマの「受託開発、サービス、ゲーム、現場支援」がどれも興味のあるものだったからというのが一番の理由です。
あとは Twitter でフォローしている人が発表することになっていたので、どんな人か会ってみたかったってのもあります。

熱い内容でした
参加したセッションすべて熱いお話しが聞けました。
自分はゲーム業界の人間ですが、同じ業界も別の業界もどちらもまさに現場の直の声が聞けた、というの良かったです。別の会社、別の業界でどのような仕事をしているのか知る機会というのは本当に少ないのでこういった勉強会はすごく刺激になりました。

総評
個人的な勉強会は久しぶりでしたが、やはりいいですね。
あとやっぱり懇親会で得られる刺激というのも大きくて、特に今回は自分とは全く違う現場の話が聞けたので楽しかったですね。
Diff を知り、自分の現場に活かせるとても良い勉強会、そして交流ができました。
ありがとうございました。

2015年11月30日月曜日

Magnum CI 始めました



つーことで、始めました。Magnum CI
Travis CIDrone.ioShippableWerckerAppveyorCircle CIChodeship、ときて8つ目のサービスです。

Magnum CI の特徴といえば、プライベートリポジトリがいくつでも無料で使える(今のところ)点と、Github や Bitbucket はもちろんのこと独自のリポジトリサーバーでも使える点でしょうか。

まぁ、今回は Python 2.7 系が使える CI サービスならなんでも良かったので、細かいことは省略。


サインアップ
Magnum CI では Github アカウントなど外部アカウントでサインアップできないので、普通に登録します。

プロジェクト作成
プロジェクト作成はこちらを参考にしました。



ポイントとしては、Github への WebHook, Deploy Key 登録です。
このへんは他の CI サービスだと勝手やってくれてたところなので、少し手間に感じましたが、
特に躓くことなく普通に登録するだけで OK でした。
(ここで正常にチェックアウトできるか Test Build しておくといいかもしれません。)

ビルド設定
設定は定番の YAML(.magnum.yml) ファイルに書くか Web 上で設定できます。
今回は Web 上で済ませました。


設定内容は上記サイトとほぼ一緒です。

画像では Build Step の各項目ごとに分けて書いてますが、分け方に特に意味はありません。
sudo apt-get -qq update -y
sudo apt-get -qq install libc6-i386 lib32gcc1 lib32stdc++6 -y unzip

wget http://storage.googleapis.com/nativeclient-mirror/nacl/nacl_sdk/nacl_sdk.zip
unzip nacl_sdk.zip
cd nacl_sdk
./naclsdk list
./naclsdk update
ls
find . -maxdepth 1 -type d -name 'pepper_*'
export NACL_SDK_ROOT="$(find `pwd` -maxdepth 1 -type d -name 'pepper_*')"
echo $NACL_SDK_ROOT
cd ../

cd projects/nacl
make

はじめに必要なものをインストールし、nacl_sdk.zip をダウンロード展開します。
naclsdk の機能を使って環境をインストール。構築された環境から pepper_* のパスを取得して NACL_SDK_ROOT 環境変数にセットします。
iutest の場合、projects/nacl フォルダに NACL 用の Makefile があるので、そこで make をしています。

結果はこんな感じです。
https://magnum-ci.com/public/ad50f16d4e6b5c8a578a/builds

バッジ
最後に CI サービス定番のバッジです。
これはプロジェクトの Stats で確認できます。

今回は以上。では~

2015年11月24日火曜日

Codeship 始めました

先週(ブログズミ: cpplint でコーディングチェック)にも書いたように、またしても CI サービスを使い始めました。
今度は Codeship です。



Codeship の無料プランはこんな感じです。

5 private リポジトリ、100回/月の private ビルド
OSS であればビルド無制限

サポート言語は以下


今回は cpplint.py を実行したいので Python が使えれば OK

プロジェクト作成
Sign Up したらプロジェクトを作ります。
Create a new project を押すと右のようなホスティングサービス選択画面が開きます。
目的のサービスを選択してください。
リポジトリのリストが表示されるので、目的のリポジトリを選択します。

つづいて、右のようなプロジェクト設定が出るので、それぞれ設定をしていきます。

「Select your technology to prepopulate basic commands」でターゲット言語を選択します。
今回は Python を使いたいのでそれを選択しました。

「Setup Commands」で環境のセットアップをします。
通常であれば、cpplint.py を使うためにダウンロードしたりするのですが、 iutest ではテスト用の Makefile で cpplint.py のダウンロードもするようにしているため、ここは空にしています。

「Configure Test Pipelines」でテストパイプラインを設定します。(無料枠だとパイプラインは1つまで、試用はできるみたいです。)
iutest では Makefile で cpplint がかけられるようにしているので、対象のディレクトリに移動して make するだけです。

cd test/cpplint
make

Makefile の中身はこちらから確認できます。
https://github.com/srz-zumix/iutest/blob/master/test/cpplint/Makefile

バッジ
最後に、CI サービス定番のバッジです。
バッジはプロジェクト設定の Notification にあります。


iutest/test/cpplint に貼り付けておきました。

2015年11月16日月曜日

cpplint でコーディングチェック

Google Style Guides のチェックツールとして cpplint.py があります。
今回はこれを使って iutest のコーディングスタイルをチェックしてみました。

cpplint.py の使い方
cpplint.py は github から取得できます。クローンしてもいいですし、cpplint.py だけダウンロードしても OK です。
https://github.com/google/styleguide

iutest の場合



1行の文字数やスペース、改行の入れ方などの報告のほかに、explicit を付けましょうとか const 参照にしましょうなどの報告も出ました。

チェック内容
チェックされる内容は以下のものがあります。

buildclass
c++11
deprecated
endif_comment
explicit_make_pair
forward_decl
header_guard
include
include_alpha
include_order
include_what_you_use
namespaces
printf_format
storage_class
legalcopyright
readabilityalt_tokens
braces
casting
check
constructors
fn_size
function
inheritance
multiline_comment
multiline_string
namespace
nolint
nul
strings
todo
utf8
runtimearrays
casting
explicit
int
init
invalid_increment
member_string_references
memset
indentation_namespace
operator
printf
printf_format
references
string
threadsafe_fn
vlog
whitespaceblank_line
braces
comma
comments
empty_conditional_body
empty_loop_body
end_of_line
ending_newline
forcolon
indent
line_length
newline
operators
parens
semicolon
tab
todo

これらはコマンドラインオプションで有効/無効を設定できます。

警告の除外
該当行にコメントで NOLINT と書いておくと無視してくれます。
using namespace matchers; // NOLINT

それか、--filter コマンドライン引数で無視指定ができます。
警告の末尾に [runtime/explicit] とか [whitespace/end_of_line] とかタグが表示されますので、該当のタグの先頭に '-' を付けると無効にできます。複数指定する場合は、カンマ(,) で区切ります。

cpplint.py --filter=-runtime/explicit,-whitespace/end_of_line

行の長さの設定
1行の長さも --linelength コマンドライン引数で指定できます。

cpplint.py --linelength=150

まとめ
cpplint.py (Google Style Guides)の規則が必ずしも良い、正しいわけではありませんが、1つの指標として役に立つと思いました。iutest でも一通りチェックしてみて、可読性に対してやポータビリティなどに対して改善できました。
というわけで、cpplint を CI で回すようにしています。

来週は cpplint を回している CI サービスの紹介をしたいと思います。
それでは、また来週~




2015年11月11日水曜日

iutest v1.14.0 をリリースしました

C++ テスティングフレームワーク iutest v1.14.0 をリリースしました。
変更点は以下の通りです。

  • 追加
    • 大幅なリファクタリング
  • 修正
    • ::iutest::Range を Enum に対応
    • tools の python 3.x 系対応


今回は細かいバグ修正をして、v1.13.1 としてリリースするつもりでしたが cpplint などの対応をしていたら、影響の大きな変更が入ったため v1.14.0 としてリリースしました。
ですので、今回は新しい機能はありません。

cpplint はまたブログにします。それでは。

2015年11月9日月曜日

Circle CI 始めました

Circle CI については省略。
OSS なら 4 コンテナ無料で使えるようでしたので、iutest でも使ってみました。



したいこと
iutest では既に以下の CI サービスをそれぞれ目的別に使用しています。
CI目的
Travis CIgcc/clang でのテスト
ShippableWandbox で gcc/clang の各バージョンごとの syntax チェック
WerckerWandbox で gcc/clang の各バージョンごとの syntax チェック
Drone.ioコンパイル時間の指標
AppveyorVisual Studio でのテスト、Nuget デプロイ

今回は iutest 付属の python ツールのテスト用として Circle CI を使います。
テスト内容としては、様々なバージョンの python で実行して問題がないかをテストします。

circle.yml
Circle CI も Travis CI などと同じように YAML で設定をします。
今回の利用目的は、様々なバージョンでのテストということで、各バージョンごとにマトリックスを組もうと思ったのですが……そういったことは Circle CI ではできないようです。

rvm - Circle CIで複数Rubyバージョンを平行してテストする - Qiita

ただ、こちらに書かれているようにコンテナをパラレルで起動することで並列にテストすることができます。
それか、単純にバージョンを変更しながら直列に実行するかですね。

幸い github の public プロジェクトならば、4つまで無料でコンテナを使えるので、今回はパラレルで実行してみました。


prallel
まず、使用するコンテナの設定をします。
「Project Settings」 を開き、「Tweaks」 にある 「Adjust Parallelism」を開きます。

下のようにコンテナ設定画面になるので、4x まで選択します。

コンテナの設定は完了です。

次に、circle.yml の test の各処理に対して並列実行であることを追記します。
test:
  - python --version:
    parallel: true
コマンドの末尾に ':' を書いて「parallel: true」を記述します。
これでこのコマンドは各コンテナごとに実行されます。

pyenv
Python のバージョンを変えるのは pyenv で行います。
どのコンテナかどうかは、CIRCLE_NODE_INDEX でわかるのでこれで分岐します。

dependencies:
  pre:
    - |
      case $CIRCLE_NODE_INDEX in
        0) pyenv install -ks 2.7.10; pyenv global 2.7.10; $(pyenv which pip) install requests twilio; ;;
        1) pyenv install -ks 3.5.0;  pyenv global 3.5.0;  $(pyenv which pip) install requests twilio; ;;
        2) pyenv install -ks 3.4.3;  pyenv global 3.4.3;  $(pyenv which pip) install requests twilio; ;;
        3) pyenv install -ks 3.3.3;  pyenv global 3.3.3;  $(pyenv which pip) install requests twilio; ;;
      esac

コマンドの先頭の | は複数行に書くためのものです。

さて、ここでちょっと躓きました。
最初のころは以下のように machine で python version 指定していました。
machine:
  python:
    version: 3.5.0

そうすると、dependencies で pyenv global しても、test に入ったときには machine で指定したバージョンに戻ってしまっていました。
(理由はよくわからないけど、そういうもんだと思って) machine の記述は削除しました。


あとは、test で普通に python を使えば任意のバージョンで実行されます。
https://circleci.com/gh/srz-zumix/iutest

※ コマンドの末尾にコンテナ番号が {} つきで表示されます

まとめ
途中少し(いや割りと…)躓きましたが、複数バージョンでのテストができるようになりました!
Travis CI ほどではありませんが、分かってしまえば簡単でした。

あ、最後に CI サービス定番のバッジですが、
プロジェクト設定の Notifications > Status Badges で取得できます。
いやー Circle CI も便利ですなー

2015年11月2日月曜日

[TortoiseSVN] アイコンオーバーレイが表示されなくて困ったけど一応解決できたよ

TortoiseSVN のアイコンオーバーレイが表示されなくなってしまい、
非常に困っていたのですがなんとか解決できました。

この問題は検索したらたくさん解決方法がヒットします。例えば、

私の環境で起きていた問題も、ShellIconOverlayIdentifiers の数制限が原因でした。

対処方法
  • TortoiseSVN を新しいバージョンに更新する。
    新しいバージョンだと、ShellIconOverlayIdentifiers のプライオリティが上がって TortoiseSVN のアイコンが優先的に表示されるようになりました。
  • ShellIconOverlayIdentifiers レジストリから不要なものを消す。
    仕事のPCでは TortoiseSVN の更新ができない状況だったため、参考URL にもあるように
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers
    から不要なものを削除しました。
    (64bit だと HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node にも同様のキーがある)
    削除したら explorer を再起動。

これでとりあえず、解決できたのですが、
仕事PCの方はいつの間にかまたアイコンが表示されなくなってしまいました。。。
なんでかな?ともう一度レジストリを見ると、消したはずの DropboxExt が元に戻ってるではありませんか!

なんだか勝手に修復するみたいです。なんてヤツだ全く(いや、正しいと思います。でもいらないの。)

今度は、キーを削除しないでキーの既定の文字列を無効な文字列に書き換えてやりました
ただし、デタラメな文字列にしてもダメで、また復元されてしまいました。
上記リンク先にも書いてあるように、GUID を残しつつ無効な文字列にする必要があるようです。
例)MANUALLY_EDITED_{00000000-0000-0000-0000-000000000000}


簡単に DropboxExt のレジストリを書き換えるバッチファイルを書いたので、ご自由にお使いください。
(ただし、使用は自己責任でお願いします。バックアップを取るなりしてください。)
https://gist.github.com/srz-zumix/42121dc8dbabc651dc81


訂正。DropboxExt を書き換えても復元されてしまうので、上記方法は×でした。
なので、TortoiseSVN の方のレジストリキー名を変更して、DropboxExt より優先される名前に(先頭にスペースを2つ追加)しました。



それにしてもアイコンオーバーレイの上限数が少ないですよね。
これってなんとかできないんですかねぇ。根本的な解決ができたらいいのですが…



ともあれ、これでなんとか解決できたので今は良しとしておきます。
それでは。

2015年10月27日火曜日

[Coverity] CEDEC 2015 で出題されたバグクイズ

バグクイズです!(CEDEC 2015 の問題) « Coverity Blog

CEDEC 2015 で出題されたバグクイズ。
私も実際に CEDEC に行って見てきたわけですが、
3日目の問題が直ぐに解けず、なんだか悔しかったのでこの記事を書いてる次第です。
(あーだこーだしているうちに2ヶ月も経ってしまいましたが…)

ちなみに、答えはこちらです。
CEDEC 2015 Tokyo でのバグクイズの正解を発表! « Coverity Blog

Coverity 以外では検出できないのか?

検証の際に実際に使用したソースコードはこちら。
https://github.com/srz-zumix/coverity_test/tree/master/cedec_coverity

Cppcheck v1.70
まずは、フリーで使える C++ 静的解析の定番となっている Cppcheck です。
使用したのは現時点での最新バージョンである 1.7.0 です。

残念ながら、どちらの問題も検出されませんでした。

Visual Studio コード分析
次に Visual Studio です。
Visual Studio にはコード分析機能が付いています。プロジェクトプロパティのコード分析で有効にできます。

これもかなり優秀なんですが…


残念ながら、どちらの問題も検出されませんでした。

gcc/clang
最後はコンパイラーです。
Visual Studio はコード分析のときにビルドしましたが、検出できなかったので既に脱落しております。

それぞれの結果です。


どちらも delete (void*)p の問題は検出されました。

scan-build
おまけです。
scan-build は clang の静的解析ツールです。
cygwin パッケージに入ってたので使ってみました。


結果としては clang コンパイラーと一緒で delete (void*)p の検出だけでした。

まとめ
Coverity すごい!!


2015年10月19日月曜日

[Jenkins] 同じノードで繰り返し実行されないようにする方法

Workflow Plugin を使ったらこれについても制御できるかもしれないですが、
まだ Workflow Plugin 使えてないので、別の方法を紹介します。

Groovy Label Assignment plugin
Groovy Label Assignment plugin を使います。
このプラグインを使うと Groovy を使って、
動的に実行ラベルを設定することができます。

ジョブの設定ページを開くと、
「Groovy スクリプトで実行するノードを制限」があるので有効にし、スクリプトを入力します。
文字列を返すとそれが新しいラベル式になります。なにも返さなかった場合は、もとのラベル式が使われます。


前回実行ノードを除外するときは、こんな感じに書きます。
def label = currentJob.assignedLabel
def last = currentJob.getLastBuild()
if( last == null ) return
def node = last.getBuiltOnStr()
if( node == null || node == "" ) node = "master"
if( node )
  return "${label}&&!" + node 
実行しようとしているジョブは currentJob にバインドされているので、そこからラベルと前回実行時のノード名を取得して新しいラベルを生成します。


さまざまなスレーブでまんべんなく実行したい場合はマトリックスを組むのが良いですが、この方法も覚えておくと便利かもしれません。

2015年10月13日火曜日

5年

このブログを始めて5年になったようです。
まさか、ここまでできるとは思ってませんでした。
5年間いろいろとありましたが、書いてる内容的にこの5年であまり変化がない感じなのも面白いですね。

さて、今から5年後、自分も含めてどうなってるんでしょうね。
それでは今後ともよろしくお願いします。

[Jenkins] Locale Plugin で表示言語を英語にして検索力アップ

Locale Pluginを使うと表示言語を強制的に変更できます。

参考:Jenkins がもっと便利になるおすすめプラグイン 8 つ (フェンリル | デベロッパーズブログ)


Jenkins 関係の調べごとをしていると、日本語表記で検索した場合にヒットしにくいことがあります。
英語表記で検索すればよりたくさんの情報を調べやすくなります。

というわけで、Locale Plugin を使いました。
調べたことはまたこのブログで紹介できると思います。
今回は以上。では。

2015年10月5日月曜日

[Jenkins] Warnings Plugin はとりあえずインストールしておけ

Warnings Plugin は警告ログなどを集計してくれるプラグインです。
デフォルトでたくさんのフォーマットに対応していて、独自定義も自由に作れて、
非常に便利でありがたいプラグインです。

便利なプラグインなので、ここで紹介するまでもなく既に使ってる方が多いのではないかと思います。
が、「とりあえずインストールしておけ」というまでのものかというと、
以前ここでも紹介した Groovy Postbuild Plugin と比べるとそうでもなかもしれません。

ブログズミ: [Jenkins] Groovy postbuild plugin はとりあえずインストールしとけ

ではなぜ、「とりあえずインストールしておけ」というかというと、便利だからという理由とは別の理由があります。

最新バージョンしかないプラグイン
ブログズミ: [Jenkins] プラグインのダウングレード
こちらの記事にも書いてありますが、Jenkins のプラグインは https://updates.jenkins-ci.org/download/plugins/ から古いバージョンをダウンロードしてくることができます。
ここで「すべてのプラグインの古いバージョンがある」と思い込んでいたのですが、
実はそうでもないようで旧バージョンがないプラグインもあるようです。

その1つが Warnings Plugin なのです。
しかし、古いバージョンがダウンロードできないからといって何か困ることがあるのか?
そう思う方も多いでしょう。

なにが困ったか
Jenkins のプラグインには Required Core として Jenkins 本体の要求バージョンというものがあります。
これが使っている Jenkins のバージョンよりも新しいと下のように警告されます。

困ったのはこれです。
とあるプロジェクトでは、 Jenkins が以前から使われていたものの、ほぼ素の状態で使われていました。
とあるタイミングでもっと便利にしたいとなり、Warnings Plugin を使おうとしました。
ところが、使っていた Jenkins はすでにかなり古いバージョンになっており、Warnings Plugin が要求するバージョンよりも古いものでした。

Jenkins のバージョンを上げるのは、結構ストレスです。
経験ある方ならわかると思いますが、バージョン上げた途端動かなくなったり、なんだか挙動がおかしくなったり、めんどくさーい嫌な思い出があるのです。
これが開発初期だったらよかったのですが…
かといって、Required Version を無視して使ってみて動いたらラッキーということもできないでしょう。


結局は Jenkins のバージョン上げて対応をしました。結果としては何も問題なかったです。
ただ正直、最初から Warnings Plugin をインストールしておいてほしかったな、と思いました。
プラグインのバージョンが古くても、少なくとも使えはしますから。


というわけで
旧バージョンが残されていないプラグインは、(便利なものであれば)最初にインストールしておきましょう!

私が使っているプラグインで旧バージョンがないプラグインは2つありました。
Dependency Graph Viewer Plugin
Warnings Plugin

追記
コメントいただきました。ありがとうございます。
Warnings プラグインの旧バージョンはこちらから取得できます。
http://maven.jenkins-ci.org/content/repositories/releases/org/jvnet/hudson/plugins/warnings/

これからは http://maven.jenkins-ci.org/content/repositories/releases/org/jvnet/hudson/plugins/ こっちも確認したいと思います。


2015年9月28日月曜日

Google Mock の Matcher を使ってみた

Google Mock とは Google 製の C++モッキングフレームワークです。
Google Test はよく使っているのですが、Google Mock は存在は知りつつも実用したことは今までありませんでした。
モッキングフレームワークですから、モック作成がメイン機能になりますが、Google Mock は Google Test の機能拡張版として、Google Test の書き方をしつつより便利なアサーションを使うことができます。

今回はその便利なアサーションについてお話しようと思います。

THAT!!
THAT。そうそのアサーションは ASSERT_THAT,EXPECT_THAT という名前で定義されています。
THAT は引数に Matcher を取ります。この Matcher にマッチするかどうかを検証します。
Matcher については日本語ドキュメントに詳しくまとまっているので、そちらを参考にしてください。
Google Mock ドキュメント日本語訳
(v1.6.0 当時のものなので注意)

これらの Matcher は組み合わせて使うこともでき、Google Test の ASSERT_EQ や ASSERT_LE など検証内容が固定のアサーションよりも、統一的な記法でより柔軟にテストを書くことができます。その例を以下に示します。
※以下のコードは適切に using されているものとします。

基本的な比較
Eq,Ne,Le,Lt,Ge,Gt,IsNull,NotNull および浮動小数点数比較など、基本的な比較 Matcher は Google Test でも同等のアサーションがありますので、省きます。

OR 条件
AnyOf Matcher を使用することで OR 条件を表現できます。
TEST(Matcher, AnyOf)
{
   int a=1;
   ASSERT_THAT(a, AnyOf(Eq(1), Eq(10)));
}

これは、「a == 1 || a == 10」であることを検証しています。
Google Test ではスマートに書くことができなかった OR 条件が非常に簡単に書くことができます。

AND 条件
今度は逆に AND 条件をどう書くか、です。
Google Test の場合は以下のように書けました。
TEST(Test, And)
{
    int a=1;
    ASSERT_GT(a, 0);
    ASSERT_LT(10, a);
}
もちろん、Google Mock でも上記のような書き方もできますが、AllOf Matcher が用意されています。
Matcher のメリットは組み合わせができることです。特に理由がない限り AllOf Matcher を使うのがよいでしょう。
TEST(Matcher, AllOf)
{
    int a=1;
    ASSERT_THAT(a, AllOf(Gt(0), Lt(10)));
}

これは、「a > 0 && a < 10」であることを検証しています。

コンテナ
Google Test でコンテナの各要素の検証は、できなくはないですがやや面倒です。
Matcher にはコンテナの要素やクラス・構造体メンバーへのアクセスをするものが用意されています。
これを使うことでかなり簡単に要素チェックができるようになります。

すべての要素が指定条件にマッチする
TEST(Matcher, Each)
{
    int a[3] = {1, 2, 3};
    ::std::vector b { 1, 2, 3};
    ASSERT_THAT(a, Each(Gt(0)) );
    ASSERT_THAT(b, Each(Gt(0)) );
}
Each Matcher はコンテナの要素すべてが指定条件にマッチするかを検証します。
上の例だと、コンテナ a/b の要素がすべて、 0 より大きいことを検証しています。

指定条件にマッチする要素を含む
TEST(Matcher, Contains)
{
    int a[3] = {1, 2, 3};
    ::std::vector b { 1, 2, 3};
    ASSERT_THAT(a, Contains(Eq(1)) );
    ASSERT_THAT(b, Contains(Eq(1)) );
}
Contains Matcher は Each とは違い、指定条件にマッチする要素を含むかどうかを検証します。
上の例だと、コンテナ a/b の要素に、 1 を含むかどうかを検証しています。

キーの検証
次はキーの検証です。map のキーを検証したいときなどに使用します。
TEST(Matcher, Key)
{
    ::std::map m = make_map();
    ASSERT_THAT(m, Key(Lt(10)) );
}

上記コードの場合、キーの値がすべて 10 未満であることを検証しています。

ペアで検証する
map の要素(ペア)を両方検証したい場合は、Pair Matcher を使います。
TEST(Matcher, Key)
{
    ::std::map m = make_map();
    ASSERT_THAT(m, Pair(Lt(10), StrNe("hoge")) );
}
上記コードの場合、m は 10 より小さいキーであり、値の文字列が "hoge" でないことを検証しています。


メンバーの検証
Key と Pair は map の要素に対してのアクセス Matcher でした。
今度は、任意のメンバー変数や関数にアクセスする Matcher です。
struct X {
    int a;
};
TEST(Matcher, Field)
{
    X x = {1};
    ASSERT_THAT(x, Field(&X::a, Eq(1)) );
}
上記コードは、ASSERT_THAT(x.a, Eq(1)); と同じ意味です。
なんの役に立つかは、後述の複雑な組合せでします。

コンテナの各要素それぞれに Matcher を指定する
Each や Contains には各要素に対し1つの Matcher しか指定できませんでした。
しかし、コンテナの先頭は条件X、残りの要素は条件Yで検証したい場合などもあると思います。
そのような場合に使用するのが、ElementsAre Matcher です。
IUTEST(Matcher, ElementsAre)
{
    int a[3] ={ 0, -1, 3 };
    ASSERT_THAT(a, ElementsAre(Ge(0), Lt(0), Gt(0)));
}

こちらは、下記のコードと同じです。
TEST(Matcher, ElementsAre)
{
    int a[3] ={ 0, -1, 3 };
    ASSERT_THAT(a[0], Ge(0))
    ASSERT_THAT(a[1], Lt(0))
    ASSERT_THAT(a[2], Ge(0))
}

また、配列版の ElementsAreArray もあります。
TEST(Matcher, ElementsAreArray)
{
    int a[3] ={ 0, 1, 3 };
    int b[3] ={ 0, 1, 3 };
    EXPECT_THAT(a, ElementsAreArray(b));
}

ワイルドカード
任意の数値にマッチするワイルドカードも用意されています。
この Matcher は常にマッチする Matcher で一部分だけ検証を無視したい場合などに使えます。
ワイルドカードには2種類あり、常にマッチする '_' と 指定の型にマッチする 'A<type>' があります。

TEST(Matcher, Wildcard)
{
    EXPECT_THAT(42, _);
    EXPECT_THAT(42, A<int>());
}

複雑な組合せ
ここまで紹介した Matcher を組み合わせることで、複雑な条件も簡単に記述できるようになります。

struct X { int a, b; }

TEST(Matcher, Member)
{
    std::map<int, X> m;
    for( int i=0; i < 10; ++i )
    {
        m.insert(::std::pair<int, X>(i, X{i, 100}));
    }
    EXPECT_THAT(m, Each(Pair(Le(10), Field(&X::b, Ge(0)))));
}

こちらは、intをキーとする構造体のマップから、各マップ要素の
キーが10以下、構造体のメンバー b が 0 以上であることを検証しています。
これらの検証を1つずつ記述するのは面倒ですが、Each や Pair などを組み合わせることによって上記のように簡潔に記述ができます。

また、ワイルドカードを使えば検証したくない所を無視することができます。
TEST(Matcher, Member)
{
    std::map<int, X> m;
    for( int i=0; i < 10; ++i )
    {
        m.insert(::std::pair<int, X>(i, X{i, 100}));
    }
    EXPECT_THAT(m, Each(Pair(_, Field(&X::b, Ge(0)))));
}

iutest では?
恒例の iutest の対応状況を書いておきます。
iutest は自作の C++ テスティングフレームワークです。
https://github.com/srz-zumix/iutest

iutest でも THAT アサーションと Matcher が使えます。
Matcher は Google Mock v1.7.0 相当のものが使えるようになってます。
詳しくはドキュメントを参照してください。

http://iutest.osdn.jp/doc/html/modules.html
http://iutest.osdn.jp/doc/html/d4/d14/group___m_a_t_c_h_e_r_s.html

最後に
Google Mock はモッキングフレームワークですが、アサーションの拡張としてだけでも使う価値がありそうです。
(iutest ではそれ単体で Matcher が使えますので、こちらもよろしくお願いします)

2015年9月24日木曜日

[iutest] コンパイルエラーになることをテストしてみた

iutest v1.13.0 をリリースしましたが、
iutest v1.12.0 あたりからコンパイルエラーになることをテストするようにしていました。

手法としては、コンパイラ出力を解析してエラーが発生したことを確認するシンプルな方法です。
この解析周りも含め Python で書いてます。
https://github.com/srz-zumix/iutest/blob/master/tools/python/iutest_compile_error_test.py

さて、テストですので期待値を書くことになります。
これはソースコードに直接書ける仕組みにしました。

以下のように書きます。
IUTEST(StaticAssertTypeEqTest, Fail)
{
    IUTEST_TEST_COMPILEERROR("static_assert_typeeq")
    ::iutest::StaticAssertTypeEq<float, int>();
}

IUTEST_TEST_COMPILEERROR の引数にはエラーメッセージを記述します。
このマクロの直後の行にエラーがあり、エラーメッセージに引数の内容が含まれているとテスト成功です。
(エラーメッセージはコンパイラーごとに異なるので注意が必要ですが…)

実際にテストするときは、以下のようにします。
g++ -I../include -g -Wall -Wextra   -std=c++1y -Werror=undef -o static_assertion_failure_tests static_assertion_failure_tests.cpp   2>&1 | python ../tools/python/iutest_compile_error_test.py -c g++
コンパイラーの標準エラー出力を iutest_compile_error_test.py に食わせてあげます。今回は g++ の出力なので、 -c オプションで指定します。
対応しているコンパイラーは g++,clang,cl(Visual Studio) の3つです。
(この機能自体をちゃんとテストしていないので対応できてないケースがあるかもしれませんが…)

実行するとテスト結果が出力されます。
g++ -I../include -g -Wall -Wextra   -std=c++1y -Werror=undef -o static_assertion_failure_tests static_assertion_failure_tests.cpp   2>&1 | python ../tools/python/iutest_compile_error_test.py -c g++
[OK] IUTEST_TEST_COMPILEERROR( "static_assert_typeeq" ): static_assertion_failure_tests.cpp: 24
[OK] IUTEST_TEST_COMPILEERROR( "static_assert_typeeq" ): static_assertion_failure_tests.cpp: 29
[OK] IUTEST_TEST_COMPILEERROR( "static_assert" ): static_assertion_failure_tests.cpp: 35
[OK] IUTEST_TEST_COMPILEERROR( "static_assert" ): static_assertion_failure_tests.cpp: 41

失敗した場合はこんな感じ。
[OK] IUTEST_TEST_COMPILEERROR( "static_assert_typeeq" ): static_assertion_failure_tests.cpp: 24
[OK] IUTEST_TEST_COMPILEERROR( "static_assert_typeeq" ): static_assertion_failure_tests.cpp: 29
[OK] IUTEST_TEST_COMPILEERROR( "static_assert" ): static_assertion_failure_tests.cpp: 35
[NG] IUTEST_TEST_COMPILEERROR( "hogehoge" ): static_assertion_failure_tests.cpp: 41

テストが失敗したときのメッセージとかはまだしっかり作りこめてませんが、これでコンパイルエラーになるべきところをテストできるようになりました。
ライブラリとか作ってると、こういうテストをしたくなると思います。
もっとよさげなツールがあれば使っていきたいところですが…

では。

2015年9月14日月曜日

iutest v1.13.0 をリリースしました

C++ テスティングフレームワーク iutest v1.13.0 をリリースしました。
変更点は以下の通りです。

  • 追加
    • --iutest_flagfile コマンドラインオプションに対応
    • MFC コンテナ対応
    • 値のパラメータ化テストのテスト名指定に対応
    • 型付けテストのテスト名に型名をつけるオプションマクロ (IUTEST_TYPED_TEST_APPEND_TYPENAME) を追加
    • 非ヨーダ記法を提供するヘッダー(iutest_util_no_yoda.hpp)を追加
    • Visual Studio 2015 対応
  • 修正
    • tr1/iutest_vc_unittest.hpp を修正
    • バグ修正

今回は Google Test v1.18.0 におそらく入るであろう機能に一部対応しています。
これに関しては以前ブログに書きましたので、そちらを参考にしてください。

そのほかの変更点としては、MFC のコンテナ(CMap とか CList とか)に対応しました。
MFC のコンテナは書き方に統一感がなくてめんどくさかった…
あとは、アサーションの expected と actual の順番を逆にするユーティリティを追加しました。(iutest_util_no_yoda.hpp)

もう1つ、Visual Studio テストエクスプローラーに対応するための iutest_vc_unittest.hpp がメンテナンスされてなかったのを修正しました。 Visual Studio 2015 対応および TestCase での分類に対応しています。


NuGet パッケージも更新してます。ちゃんと Appvayor で自動アップデートされてました。便利ですねー

今回は以上。それでは。

2015年9月9日水曜日

[Jenkins] 手動実行したビルドを優先実行する

Jenkins Pirority Sorter Plugin を使うことで手動実行した場合のみ、実行優先度を上げることができます。
これによって、メンテナンス用のジョブを走らせたいときなどに優先的に実行することができます。





設定の仕方は、サイドバーの Job Priorites を開き、追加ボタンを押します。
Jobs to include など適切な設定をします。
ここではメンテナンスビューにあるジョブを対象にしました。
(手動実行したいのはたいていメンテナンス系のジョブでしょう)

次に、「Use additional rules when assigning a priority to a Job」にチェックをいれます。
追加ボタンが出るので押すと「Priority Strategy」の選択が出るので、その中から「Job Triggered by a User」を選びます。
あとは優先度を決めます。優先度は数値が小さいほど高くなります。
(デフォルトでは、1-5 の優先度になってますがシステム設定ページで変更することができます)


設定は以上です。
Priority Sorter はバージョンが上がってからあまり見てなかったのですが、設定も一か所にまとまったし、機能も増えたし、かなり便利になったんではないかと思います。

今回はここまで。それでは。

2015年9月3日木曜日

[iutest] Google Test と袂を分かちつつある

Google Test v1.7 がリリースされて、約2年になろうとしています。
v1.7 がリリースされたのが、2013年9月。
v1.6 がリリースされたのが、2011年4月。
v1.8 はいつになるでしょうか。まだその気配はなさそうですが…


ただ、開発は進んでいて、trunk には v1.7 にない機能が、既に幾つか追加されています。
代表的なものとしては、
  • --gtest_flagfile コマンドラインオプション
  • "名前付き"値のパラメータ化テスト
があります。

flagfile は指定したファイルから、コマンドラインオプションを設定する機能です。
コマンドライン引数には文字数制限があるため、--gtest_filter オプションの条件が長くなると収まらない問題の対応として追加されました。

名前付き値のパラメータ化テストは、値のパラメータ化テストのテスト名を任意に設定できる機能です。
以下のように INSTANTIATE_TEST_CASE_P の最後に命名 Functor を指定して使います。
指定しなかった場合は、これまでどおりのインデックスによる命名になります。
class CustomFunctorNamingTest : public TestWithParam<std::string> {};
TEST_P(CustomFunctorNamingTest, CustomTestNames) {}

struct CustomParamNameFunctor {
  std::string operator()(const ::testing::TestParamInfo<std::string>& info) {
    return info.param;
  }
};

INSTANTIATE_TEST_CASE_P(CustomParamNameFunctor,
                        CustomFunctorNamingTest,
                        Values(std::string("FunctorName")),
                        CustomParamNameFunctor());


iutest の実装
さて、これらの機能ですが、iutest では少し違った実装をしています。

フィルターオプションの拡張
まず、flagfile の前に、このフラグが追加された理由である、コマンドライン引数の長さの問題に対して、フィルターオプションをファイルから読み込める方法を追加しました。

test.exe --iutest_filter=@filter.txt

のように、フィルターの先頭に @ を付けてファイルパスを指定します。
フィルターファイルは行頭 # でコメント、改行で条件区切り(; セミコロン)になります。
# iutest_filter_file_tests testdata
*Run*
# comment
*OK*
上記フィルターファイルは、"--iutest_filter=*Run*:*OK*" と同じです。

flagfile
さて、本題の flagfile ですが、もちろん実装しています。
使い方は、Google Test と一緒で

test.exe --iutest_flagfile=flag.txt

のように使います。
ファイルの書き方ですが、一行ごとにオプションを書きます。
また、iutest の場合フィルターファイルと同じように行頭 # でコメントを書けます。
あと、空行は無視されるようになってます。(Google Test も無視してほしいなぁ)

# iutest_flagfile_tests testdata
--iutest_filter=@testdata/filter.txt
--iutest_color=off

上記は iutest のフラグファイルの例です。
先に説明をしたフィルターオプションをファイル指定することもできます。


名前付き値のパラメータ化テスト
Google Test では、INSTANTIATE_TEST_CASE_P に命名 Functor を指定する方式でしたが、iutest ではテストフィクスチャーに MakeTestName 関数を書くことでカスタマイズできます。

class RenameParamTest : public ::iutest::TestWithParam<bool>
{
public:
    template<typename T>
    static const ::std::string MakeTestName(const char* basename, int, const T& param)
    {
        ::std::string name = basename;
        return name + "/" + ::iutest::StreamableToString(param);
    }
};

Google Test の方法だと、インスタンス化の時に命名方法を変えられるので、INSTANTIATE_TEST_CASE_P ごとに名前を変えることが可能です。iutest は実装の容易さから上記方法で実装しました。(INSTANTIATE_TEST_CASE_P ごとに名前を変える必要があるのか、ちょっと想定できなかったので)
と、言っても iutest は Google Test と互換性を持つようにしていますので、そのうち対応することになるとは思います。

最後に
というわけで、iutest の開発も落ち着いてきて独自の機能というのが増えつつあります。
Google Test との互換性のこともあるため、完全に離れてしまうことはないですが、少し窮屈に感じることも出てきました。

そろそろ新しいテスティングフレームワークを出したいなぁーと思ったりもしてますが…
今日はこの辺で!
では。

2015年8月18日火曜日

Visual Studio 2015 で Template 多用しているコードのコンパイルが速くなったらしい

Visual Studio 2015 における Visual C++ の新機能
テンプレートを大量に使用するコードのビルドを高速化するための改善が行われました。

というわけで、試してみました。
検証用にメタメタなコードを探していたら、良さそうなのがあったので以下を使わせて頂きました。

C++TMPを使ってコンパイル時に多倍長フィボナッチ計算。 - 簡潔なQ

実際に使用したコードはこちら。(入力数が大きいとコンパイルエラーになってしまったので、小さくしています。)
https://gist.github.com/srz-zumix/94e3f8b801bd769466e5

結果:
Microsoft(R) C/C++ Optimizing Compiler Version 18.00.40629 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

benchmark.cpp
real 4.49
user 0.00
sys 0.03
Microsoft(R) C/C++ Optimizing Compiler Version 19.00.23026 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

benchmark.cpp
real 3.35
user 0.00
sys 0.03

何回か測定しましたが、何れも VS2015 の方が速い結果になりました。
コンパイルやリンクが速くなるのは嬉しいですね。

2015年8月3日月曜日

Windows 10 にしてん

ノートPC を Windows 10 に更新しました。
自動でなかなか落ちてこなかったので、「メディア作成ツール」を使ってやりました。
特に問題も発生せず、更新できちゃいました。
もともと Windows 8.1 だったのですが、なんかあんまり変わった感じがしませんね。

変わった所といえば、スタートメニューですが、
ちょっと微妙な感じ…ただ、慣れれば問題ないでしょう。
仮想デスクトップとかコマンドプロンプトで Ctrl + V が使えるようになりましたしね。

今週は以上です。では。

2015年7月27日月曜日

[AutoIt] システム情報マクロ

AutoIt を書いていると Windows のバージョン違いによる 挙動・UI の違いが障害になることが多々あります。
AutoIt のコード側で対処する必要がありますが、そんな時に便利なのがシステム情報マクロです。

https://www.autoitscript.com/autoit3/docs/macros/SystemInfo.htm

@OSVersion
名前のまんまの機能です。OS のバージョンを参照できます。
値は、"WIN_81" のように WIN_ + OS名 となってます。詳しくは、上記リンクを参照してください。

これで、OS ごとの差異を場合分けすることができます。

@OSLang
こちらも、名前のまんまの機能です。OS の Locale がこのマクロから参照できます。
https://www.autoitscript.com/autoit3/docs/appendix/OSLangCodes.htm

言語が違うとウィンドウの名前引きに失敗してしまします。
コントロールID 指定でも良いのですが、名前引きの方が柔軟性が高いので、個人的にはこちらを利用することが多いです。




マクロは他にも色々あるので、便利に使えるのではないかと思います。
今回は以上です。それでは。

2015年7月22日水曜日

色のサイト公開

ある日、「背景色」と「文字色」のテストができるツールが欲しいと言われました。
そんなの世の中にいっぱいあるだろーと思ったが、ご所望のものが見つからないとのこと。
個人的に普段やらないことができるし、面白そうだと思ったので作りました。

できたのが、こちら。
http://srz-zumix.github.io/site/colorscheme/#/


作り始めたら、こだわりだしてしまって2週間くらいかかりました。
で、依頼主に見せたんですが、当の本人は既に気移りしていて「あ、そう」って反応でした。
スピードは大事だと学びました。

2015年7月13日月曜日

[Jenkins] ビルドが失敗したときにスレーブをオフラインにする


Offline Node On Failure Plugin を使う
Offline Node On Failure Plugin
その名の通り、ビルドが失敗したらオフラインにするプラグインです。

インストールすると、ビルド後の処理に「Take node offline on failure」が追加されます。
細かい設定などは一切ありません。失敗したらオフラインにします。(master は除く)



失敗かつ特定のログがある/ない場合にオフラインにしたい
さて、Offline Node On Failure Plugin は単純に失敗したらオフラインにするプラグインでした。
ただ、同じ失敗でもオフラインにしたいときもあれば、したくないときもあるでしょう。
その場合は、オフラインにしたくないときはビルドステータスを不安定にすることで実現できます。
それも1つの手です。

しかし、それで終わってはつまらないので、別の方法を紹介します。

Groovy Postbuild Plugin でオフラインにする
Groovy Postbuild Plugin を使います。

オフラインの仕方は以下のようにします。
def com = manager.build.getBuiltOn().toComputer()
  if( com.isOnline() ) {
    com.setTemporarilyOffline(true, new OfflineCause.ByCLI("オフラインメッセージ"))
  }

さらに、特定のログが含まれているかどうかは、
manager.logContains で調べられるので、

if( manager.logContains("致命的な失敗") ) {
    def com = manager.build.getBuiltOn().toComputer()
    if( com.isOnline() ) {
      com.setTemporarilyOffline(true, new OfflineCause.ByCLI("オフラインメッセージ"))
    }
  }

のようにすれば、特定のログ出力に応じてオフラインにできます。


まとめ
プラグインを使えば簡単に実現可能ですが、Groovy を使った方法も覚えておくとより柔軟に制御ができるようになると思います。Groovy Postbuild Plugin で使える Groovy Script を github に上げてますので参考にしてください。(あんまり整理・メンテしてませんが…)
https://github.com/srz-zumix/jgpbc

2015年7月6日月曜日

[C++][静的解析] PVS-Studio を使ってみた



どうやら C++ の静的解析ツールに PVS-Studio があるらしい。ということで、使ってみました。

インストール
PVS-Studio は Visual Studio の拡張機能として使います。(単体でも使用可能
インストーラーのダウンロードはこちらから。
http://www.viva64.com/en/pvs-studio-download/

インストーラーをダウンロードしたら指示にしたがってインストールしてください。

トライアル版を使ってみて
iutest を解析した結果がこちら。
検出数は2つだけ。それもテスト用にわざと書いたコードでした。


よかったよかったと思ったら、これは Level1 の警告で Level2, Level3 の警告がまだありました。

トライアル版では見れない!!
うーん、これは気になる。商売うまいぜ…

ライセンス購入するにはメールを送る必要があるようで、ちょっと敷居が高く感じた。
値段もパッとわからなかったので、今回はここまでとします。

ちなみに、無料の C++ 静的解析ツールといえば Cppcheck が有名ですが、PVS-Studio と Cppcheck との比較資料もありました。
http://www.viva64.com/en/b/0149/