C/C++単体テストツールCutterにハマる(2)

前回,ハマったのはこんなサンプルプログラムでした.

/**** lib/Calc.cc ****/
#ifndef __CALC_H
#define __CALC_H
#include <iostream>
using namespace std;

class Calc
{
public:
  Calc();
  ~Calc();
  int add(int a, int b);
};
#endif

/**** lib/Calc.cc ****/
#include <Calc.h>

Calc::Calc()
{
  cout<<"Calc constructor"<<endl;
}
Calc::~Calc()
{
  cout<<"Calc destructor"<<endl;
}
int Calc::add(int a, int b)
{
  return(a+b);
}

そしてテストプログラム.ちょっと綺麗に改編.

/**** test/test_Calc.cc ****/
#include <cppcutter.h>
#include <Calc.h>

namespace testCacl
{
  void test_Calc()
  {
    Calc calc;
    cppcut_assert_equal(3, calc.add(1,2));
  }
}

共有ライブラリを作成.前回,酔っ払ってarを使ってスタティックライブラリを作っていたので,コマンドを修正.

> g++ -o lib/libCalc.so lib/Calc.cc -Ilib -I/usr/local/include/cutter -shared -fPIC

テストコードの共有ライブラリ化.

> g++ -o test/test_Calc.so test/test_Calc.cc -Llib -lCalc -L/usr/local/lib -lcppcutter -lcutter -Ilib -I/usr/local/include/cutter -shared -fPIC

実行!

> env LD_LIBRARY_PATH=./lib cutter -v v test/
testCacl:
  testCacl::test_Calc:                                  Calc constructor
Calc destructor
.: (0.000241)

Finished in 0.001482 seconds (total: 0.000241 seconds)

1 test(s), 1 assertion(s), 0 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s)
100% passed

今回ハマったのは,テンプレートの導入です.
テストプログラムを微妙に書き換えてみます.

/**** test/test_Calc.cc ****/
#include <cppcutter.h>
#include <Calc.h>

namespace testCacl
{
  void test_Calc()
  {
    Calc calc;
    cppcut_assert_equal(4.0, calc.add(1.5,2.5));
  }
}

実行!

> env LD_LIBRARY_PATH=./lib cutter -v v test/
testCacl:
  testCacl::test_Calc:                                  Calc constructor
F: (0.000582)

1) Failure: testCacl::test_Calc
<4.0 == calc.add(1.5,2.5)>
expected: <4>
  actual: <3>
test/test_Calc.cc:9: void testCacl::test_Calc()(): cppcut_assert_equal(4.0, calc.add(1.5,2.5), )

Finished in 0.001993 seconds (total: 0.000582 seconds)

1 test(s), 0 assertion(s), 1 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s)
0% passed

1.5+2.5=4を期待したけど,切捨てられて1+2=3になったのでテスト失敗です!当たり前!
そこで,intじゃなくてdoubleも気軽に対応したいと,ライブラリを書き換えます.

/**** lib/Calc.h ****/
#ifndef __CALC_H
#define __CALC_H
#include <iostream>
using namespace std;

template<class C> class Calc
{
public:
  Calc();
  ~Calc();
  C add(C a, C b);
};
#endif

/**** lib/Calc.cc ****/
#include <Calc.h>
template<class C> Calc<C>::Calc()
{
  cout<<"Calc constructor"<<endl;
}
template<class C> Calc<C>::~Calc()
{
  cout<<"Calc destructor"<<endl;
}
template<class C> C Calc<C>::add(C a, C b)
{
  return(a+b);
}

テストコードもちょっとだけ変更.

/**** test/test_Calc.cc ****/
#include <cutter.h>
#include <Calc.h>

namespace testCacl
{
  void test_Calc()
  {
    Calc<double> calc;
    cut_assert_equal_double(4.0, 0.1, calc.add(1.5,2.5));
  }
}

テスト実行!

> env LD_LIBRARY_PATH=./lib cutter -v v test/                                   testCacl:
  testCacl::test_Calc:                                  /libexec/ld-elf.so.1: test/test_Calc.so: Undefined symbol "_ZN4CalcIdEC1Ev"

へ?

> nm lib/libCalc.so |grep _ZN4CalcIdEC1Ev
>

確かにありません.
悩んだあげく,ライブラリのソースを微妙に書き換えました.

/**** lib/Calc.cc ****/
#include <Calc.h>

template<class C> Calc<C>::Calc()
{
  cout<<"Calc constructor"<<endl;
}
template<class C> Calc<C>::~Calc()
{
  cout<<"Calc destructor"<<endl;
}
template<class C> C Calc<C>::add(C a, C b)
{
  return(a+b);
}

template class Calc<double>;

すると,

> nm lib/libCalc.so |grep _ZN4CalcIdEC1Ev
 00000cb0 W _ZN4CalcIdEC1Ev

あるじゃないですか,今度は.テスト実行!

> env LD_LIBRARY_PATH=./lib cutter -v v test/                                   testCacl:
  testCacl::test_Calc:                                  Calc constructor
Calc destructor
.: (0.000225)

Finished in 0.001446 seconds (total: 0.000225 seconds)

1 test(s), 1 assertion(s), 0 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s)
100% passed
>

Ok.

これは,Stroustrupc++
http://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9EC-%E3%82%A2%E3%82%B9%E3%82%AD%E3%83%BC%E3%82%A2%E3%82%B8%E3%82%BD%E3%83%B3%E3%82%A6%E3%82%A7%E3%82%B9%E3%83%AC%E3%82%A4%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA%E2%80%95Ascii-Addison-Wesley-programming/dp/475611895X
の最後の方に書かれてあった,「明示的なインスタンス生成」がうまくいったようです.

Cutter, 引き続き便利に使えてます!