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 を知り、自分の現場に活かせるとても良い勉強会、そして交流ができました。
ありがとうございました。