2013年3月29日金曜日

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

iutest v1.4.0 をリリースしました。

今回は、古いコンパイラへの対応強化と C++11 の機能の取り込みを行なっています。
また、いくつか機能追加もしております。

C++11 の機能の取り込み
initializer_list

::iutest::ValuesIn を初期化リストに対応させました。
このような記述ができるようになります。
IUTEST_INSTANTIATE_TEST_CASE_P(My6, ParamTest
    , ::iutest::ValuesIn({ 3, 2, 1, 0 }));

また、実験的ではありますが、
tr1/iutest_param_direct_tests.hpp
を include することで下記のような記述も可能になります。
IUTEST_INSTANTIATE_TEST_CASE_P(My7, ParamTest
    , { 3, 2, 1, 0 });

::iutest::Values で事足りていると思うので、あまり使いどころはないかもしれません。
IUTEST_INSTANTIATE_TEST_CASE_P(My3, ParamTest
    , ::iutest::Values(3, 2, 1, 0));

extern template

ライブラリビルド向けに extern template を使ってみました。
個人的な勉強のために使ってみた程度です。

random (distribution)

特定範囲の乱数生成に uniform_int_distribution を使うようにしました。
また、::iutest::detail::iuRandom クラスを distribution の要求仕様に対応させました。

テスト関数から random_engine() 関数を呼ぶことで iuRandom を取得可能です。
IUTEST(RandomEngineTest, Test)
{
    IUTEST_ASSERT_LE(
        ::std::uniform_int_distribution<unsigned int>(0, 1)(random_engine()), 1);
}

追加機能
::iutest::RandomValues
パラメータの型が取りうる値をランダムにパラメータとして設定します。
class RandomValuesTest1 : public ::iutest::TestWithParam<int> {};
class RandomValuesTest2 : public ::iutest::TestWithParam<char> {};
class RandomValuesTest3 : public ::iutest::TestWithParam<float> {};

IUTEST_P(RandomValuesTest1, Test)
{
    int v = GetParam();
    IUTEST_SUCCEED() << v;
}
IUTEST_P(RandomValuesTest2, Test)
{
    char v = GetParam();
    IUTEST_SUCCEED() << v;
}
IUTEST_P(RandomValuesTest3, Test)
{
    float v = GetParam();
    IUTEST_ASSERT_GE(1, v);
    IUTEST_ASSERT_LE(0, v);
    IUTEST_SUCCEED() << v;
}

IUTEST_INSTANTIATE_TEST_CASE_P(A, RandomValuesTest1, ::iutest::RandomValues(5));
IUTEST_INSTANTIATE_TEST_CASE_P(A, RandomValuesTest2, ::iutest::RandomValues(5));
IUTEST_INSTANTIATE_TEST_CASE_P(A, RandomValuesTest3, ::iutest::RandomValues(5));


::iutest::ValuesGen
::iutest::RandomValues を作るにあたって汎用的に使えそうだったので、追加しました。
::std::generate のように指定数分、関数オブジェクトを使ってパラメータ設定をします。

struct RandomVMExceptMoneyGenerator
{
    ::iutest::detail::iuRandom engine;
    int operator ()(void)
    {
        for(;;)
        {
            int n =  engine() % 1000;
            if( n != 10 && n != 50 && n != 100 && n != 500 ) return n;
        }
    }
};

IUTEST_INSTANTIATE_TEST_CASE_P(Random03, ValuesGenTest
    , ::iutest::ValuesGen(5, RandomVMExceptMoneyGenerator()));


::iutest::RandomValues もそうですが、::iutest::ValuesGen がなくても同様のパラメータテストは作成できます。
上のテストを書き直すと、このようになります。

struct RandomVMExceptMoneyGenerator
{
    ::iutest::detail::iuRandom engine;
    int operator ()(void)
    {
        for(;;)
        {
            int n =  engine() % 1000;
            if( n != 10 && n != 50 && n != 100 && n != 500 ) return n;
        }
    }
};

::std::vector<int> RandomVMExceptMoneyParams(int n)
{
    ::std::vector<int> v(n);
    ::std::generate(v.begin(), v.end(), RandomVMExceptMoneyGenerator());
    return v;
}

IUTEST_INSTANTIATE_TEST_CASE_P(Random03, ValuesGenTest
    , ::iutest::ValuesIn(RandomVMExceptMoneyParams(5)));


複数の型付けテストに考慮
複数の型を型付けテストでテストしたい場合を考え、修正を加えました。
template<typename T>
class MultiTypedTest : public ::iutest::Test
{
};
typedef ::iutest::Types< ::iutest::Types<int, float>, ::iutest::Types<int, double> > MultiTypedTestTypes;

IUTEST_TYPED_TEST_CASE(MultiTypedTest, MultiTypedTestTypes);

IUTEST_TYPED_TEST(MultiTypedTest, Get)
{
    typedef typename TypeParam:: template get<0>::type  Type1; // 型を取得する get を追加
    typedef typename TypeParam:: template get<1>::type  Type2; // template 引数に何番目の型を指定します
    
    ::iutest::StaticAssertTypeEq< Type1, int >();
    IUTEST_SUCCEED() << ::iutest::detail::GetTypeName< Type1 >();
    IUTEST_SUCCEED() << ::iutest::detail::GetTypeName< Type2 >();
}

複数の型を持った ::iutest::Types をパラメータとして TYPED_TEST を作成します。
各型を ::iutest::Types::get で取得できるようにし、複数の型に対するテストを記述しやすくしました。

次バージョンの予定
実行順序の指定に対応予定です。
あとは、そろそろスレッド周りを見ていこうかなー…という感じです。

2013年3月25日月曜日

[c++] initializer_list: 初期化リストを () で括ったらエラー

c++11 では vector などの初期化が簡単に書けるようになりました。

こちらの機能を利用して iutest のコードを書いていたのですが、
これダメなのか~と思うことがあったのでブログに残しておきます。

こちらがそのコード。
#include <vector>
 
template<typename T>
void f(::std::initializer_list<T>)
{
}
 
int main(int, char**)
{
    f({1,2,3}); // OK
    //f(({1,2,3})); // NG
    ::std::vector<int> a = {1,2,3}; // OK
    //::std::vector<int> b = ({1,2,3}); // NG
    return 0;
}

() でくくったらダメなんですね。

やりたかったこととしては、マクロ引数に初期化リストを渡したかっただけなので、
可変長引数を使うようにしました。

template<typename T>
void f(::std::initializer_list<T>) {}
void f(int) {}

#define HOGE(x) f(x)

void g()
{
    HOGE(0);
    HOGE(({1, 2, 3}));
}



template<typename T>
void f(::std::initializer_list<T>) {}
void f(int) {}

#define HOGE(...) f(__VA_ARGS__)

void g()
{
    HOGE(0);
    HOGE({1, 2, 3});
}


2013年3月23日土曜日

[Jenkins] 最近頻繁に master が落ちると思ったらプラグインのバグだったもよう…

少し前から(何時頃からかは忘れたが) Jenkins のマスターが落ちることが度々発生していました。

ログも出さずに落ちるもんだから、手探り状態で原因を探っておりました。
不要なプラグインを消したり、マシンの構成を変えたり、Java をアップデートしたり、Windows Update したり、Jenkins おじさんにお祈りしたり…

もうわけわからん…

そんなこんなで時が経ち…

ふと、いつものメンテナンス業務をしていると、プラグインの更新があったのでいつもの通り更新履歴を読んでましたら…
Timestamper 1.5.3
•Workaround a bug in Jenkins which causes a VM crash (JENKINS-16528)

あれ、もしかして?
JENKINS-16528: Jenkins master node crashes often when viewing console logs of builds on slaves

うわぁぁぁ…
とりあえず、アップグレードしておきました。
(※直ったかどうかは未確認)

プラグイン更新は慎重にしたほうが良いかも…
git plugin の件もあったし、(Jenkins git plugin 爆死事例集
プラグイン更新はもっと慎重に、そして何かあったら戻すように心がけます。