2011年05月22日

型の擬似的な上書き ――BOOST_AUTO_TEST_CASE_FIXTUREの仕組みより――

個人的に目から鱗だったのでメモ。

Boost.Testsetup/teardown的な物を書くにはどうすれば良いのかなーとググって、IT戦記のコメント欄経由でBOOST_FIXTURE_TEST_SUITE()の存在を知る。
で、ふと該当部分のコードがどうなってるのか気になったので覗いてみた。

以下引用コードは全てBoost 1.45.0のunit_test_suite.hppから。

#define BOOST_FIXTURE_TEST_SUITE( suite_name, F )					   \
BOOST_AUTO_TEST_SUITE( suite_name )									 \
typedef F BOOST_AUTO_TEST_CASE_FIXTURE;								 \
/**/

53~56行、BOOST_FIXTURE_TEST_SUITE()マクロの定義部分。このマクロの第2引数に指定したクラスがfixture実装クラスとなり、コンストラクタがsetup処理、デストラクタがteardown処理になる。利用法は上に挙げたメモの日々(2009-05-26)を参照。

さて、このコードを見ると、fixtureを使わない場合に使用するBOOST_AUTO_TEST_SUITE()を内部で利用している。BOOST_AUTO_TEST_SUITE()は44~47行にて定義されており、次のようになっている。

#define BOOST_AUTO_TEST_SUITE( suite_name )							 \
namespace suite_name {												  \
BOOST_AUTO_TU_REGISTRAR( suite_name )( BOOST_STRINGIZE( suite_name ) ); \
/**/

で、実際のテストケースを記述するBOOST_AUTO_TEST_CASE()マクロは次のように定義されている。114~116行。

#define BOOST_AUTO_TEST_CASE( test_name )							   \
BOOST_FIXTURE_TEST_CASE( test_name, BOOST_AUTO_TEST_CASE_FIXTURE )
/**/

BOOST_FIXTURE_TEST_SUITE()の定義内にてtypedefされているBOOST_AUTO_TEST_CASE_FIXTUREが此処で利用されている。
……あれ?でもこれってBOOST_AUTO_TEST_SUITE()利用時には定義されていない筈だよな?一体どうなってるんだろう?

"BOOST_AUTO_TEST_CASE_FIXTURE"でコード内を検索すると、以下の記述が見つかる。193~202行。

namespace boost { namespace unit_test { namespace ut_detail {

struct nil_t {};

} // namespace ut_detail
} // unit_test
} // namespace boost

// Intentionally is in global namespace, so that FIXURE_TEST_SUITE can reset it in user code.
typedef ::boost::unit_test::ut_detail::nil_t BOOST_AUTO_TEST_CASE_FIXTURE;

グローバルスコープにて全く同じ名前の型がtypedefされている。

つまり、BOOST_AUTO_TEST_SUITE()使用時は、

typedef ::boost::unit_test::ut_detail::nil_t BOOST_AUTO_TEST_CASE_FIXTURE;

namespace test_suite_name {
// 略
BOOST_FIXTURE_TEST_CASE(test_case_name, BOOST_AUTO_TEST_CASE_FIXTURE); // グローバルの物が使われる
// 略

……のように展開され、グローバルスコープに定義されたBOOST_AUTO_TEST_CASE_FIXTUREが利用される。

が、対してBOOST_FIXTURE_TEST_SUITE()使用時は、

typedef ::boost::unit_test::ut_detail::nil_t BOOST_AUTO_TEST_CASE_FIXTURE;

namespace test_suite_name {
typedef fixture_class_name BOOST_AUTO_TEST_CASE_FIXTURE;
// 略
BOOST_FIXTURE_TEST_CASE(test_case_name, BOOST_AUTO_TEST_CASE_FIXTURE); // 同じ名前空間内の物が使われる
// 略

……のように展開され、名前空間内のtypedefに因ってグローバルスコープのBOOST_AUTO_TEST_CASE_FIXTUREが隠蔽されるようになっているのである。

確かに、このような場合には、より内側の物で外側が隠蔽されると入門書で読んだ記憶があるが、実際に使われているコードを見るのは初めてかも。

目から鱗というか、盲点だったというか。

setup/teardown
それぞれ、テスト開始時に必ず行う処理、テスト終了時に必ず行う処理
Boost 1.45.0
2011年5月22日現在、最新のバージョンは1.46.1だが、ものぐさこいてアップデートしてなかった……
ラベル:C++ boost Boost.Test
posted by 天井冴太 at 04:05| Comment(0) | TrackBack(0) | Hack | 更新情報をチェックする

2011年05月14日

Visual C++ 2010で生じる、warning C4819を退治する

何らかの理由によりVC++のエディタ画面以外でコードを編集したいと言う事はよく有る。そういった時、いざVC++でコンパイルしようとした時に警告が発生する事がある。

例えば以下のようなコードを何らかのテキストエディタで記述し、UTF-8で保存する。

#include <iostream>
using namespace std;

int main()
{
	cout << "このプログラムには日本語の文字列が含まれています。" << endl;
}

で、これをコンパイルすると、以下のような警告/エラーが発生する事が有る。

test.cpp : warning C4819: ファイルは、現在のコード ページ (932) で表示できない文字を含んでいます。データの損失を防ぐために、ファイルを Unicode 形式で保存してください。
test.cpp(6) : error C2001: 定数が 2 行目に続いています。
test.cpp(7) : error C2143: 構文エラー : ';' が '}' の前にありません。

しかし、全く同じコードをVC++IDEにて作成した場合はエラーとならない。

何故か。

どうやら、VC++UTF-8なソースコードをコンパイルしようと思ったら、BOMが必要となるらしい。
エラーメッセージの現在のコード ページ (932)という記述から推察するに、BOMが無ければCP932として処理しているのだろう。

IDE上で文字化けする訳でもないのに、不思議な話である。

[VC++ 2010にてファイルの文字コードを変更するには、"ファイル"メニューの"名前を付けて (ファイル名) を保存"から保存し直せば良い。この時、"名前を付けてファイルを保存"ダイアログの"保存"ボタン右の下向き三角形をクリックし、"エンコード付きで保存"を使う必要が有る。

ただ単に警告が出るだけであれば、無視するなり、#pragma warning(disable: 4819)を指定するなりしても良いのだが、恐ろしい事に、他のエラーや警告を同時発生させる事がある。上に挙げたコードが正にその例となっており、文字コード誤判断の結果、error C2001とerror C2143が発生しているのが分かる。
warning C4819が発生している状態で、なおかつ原因の分からないコンパイルエラーが発生しているのであれば、コードの文字コードに注意を払う必要が有るだろう。

謝辞

THX @cpp_akira!!

何らかの理由により
コーディングにはVim使いたいとか。
VC++でコンパイル
VC++付属のclコマンドも含む。
BOM
UTF-8でのそれは、正確には"Byte Order Mark"という訳ではないが。
posted by 天井冴太 at 20:37| Comment(0) | TrackBack(0) | Tool | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

この広告は180日以上新しい記事の投稿がないブログに表示されております。