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.
これは,Stroustrupのc++本
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, 引き続き便利に使えてます!