HUnitで日本語を出力してみる→成功
こんなテストケース(test.hs)があるとします。
module Main where import Test.HUnit test1 = TestCase (assertEqual "アサーションのラベル" "期待値" "実際の値") tests = TestList [TestLabel "テストのラベル" test1]
これを走らせると:
Prelude> :load test.hs [1 of 1] Compiling Main ( test.hs, interpreted ) Ok, modules loaded: Main. *Main> runTestTT tests Loading package HUnit-1.2.2.1 ... linking ... done. ### Failure in: 0:"\12486\12473\12488\12398\12521\12505\12523" アサーションのラベル expected: "\26399\24453\20516" but got: "\23455\38555\12398\20516" Cases: 1 Tried: 1 Errors: 0 Failures: 1 Counts {cases = 1, tried = 1, errors = 0, failures = 1}
のように表示されてしまいます。「テストのラベル」「期待値」「実際の値」がエスケープされていて、意図通りなのは「アサーションのラベル」だけです。
意図通り表示したいのですが、どうしたものでしょうか。
エスケープの原因
まず、エスケープの原因を探る必要があります。
調べると、下記のリソースが見つかりました。
putStrLnやhPutStrLnではなくprintを日本語文字列の出力に使った場合,文字列が数値を使った表現にエスケープされてしまう点に注意してください。(中略)
エスケープの原因は,printの内部で使われているshow関数にあります。Char型のShowクラスに対するインスタンスでは,文字列をどんな環境でも表示可能にするため,UnicodeでDELよりも後にくる文字をエスケープするよう定義されています(中略)
エスケープされた文字列は,Readクラスのreadメソッドを使うことで元に戻せます。
第39回 一般向けの「Haskell Platform」とインストール・ツールの「cabalコマンド」(5ページ目) | 日経 xTECH(クロステック)
なので、テスト結果出力部分でprint関数なりshow関数なりが呼ばれている可能性が高そうです。
show関数が使われていた
実際にHUnitのコードを追ってみると、予想通りでした。
Test/Text.hs
showPath nodes = foldl1 f (map showNode nodes) where f b a = a ++ ":" ++ b showNode (ListItem n) = show n showNode (Label label) = safe label (show label) safe s ss = if ':' `elem` s || "\"" ++ s ++ "\"" /= ss then ss else s
Test/Base.hs
assertEqual preface expected actual = unless (actual == expected) (assertFailure msg) where msg = (if null preface then "" else preface ++ "\n") ++ "expected: " ++ show expected ++ "\n but got: " ++ show actual
各所でshow関数が使われています。これがエスケープの原因です。
read関数をかます
当該部分にread関数をかまし、ビルド〜インストールし直せば、意図通りに出力できそうです。
実際にやってみます。まず、HUnitのtarボールを展開します。
$ cd ~/.cabal/packages/hackage.haskell.org/HUnit/1.2.2.1 $ tar xzf HUnit-1.2.2.1.tar.gz $ cd HUnit-1.2.2.1
そして、Test/Text.hsとTest/Base.hsを編集します。diffは下記の通りで、read関数をかましているだけです。
Test/Text.hs
$ diff -u Test/HUnit/Text.hs.org Test/HUnit/Text.hs --- Test/HUnit/Text.hs.org 2010-07-22 14:09:01.000000000 +0000 +++ Test/HUnit/Text.hs 2010-07-22 14:10:08.000000000 +0000 @@ -113,7 +113,7 @@ showPath nodes = foldl1 f (map showNode nodes) where f b a = a ++ ":" ++ b showNode (ListItem n) = show n - showNode (Label label) = safe label (show label) + showNode (Label label) = safe label (read (show label)) safe s ss = if ':' `elem` s || "\"" ++ s ++ "\"" /= ss then ss else s
Test/Base.hs
$ diff -u Test/HUnit/Base.hs.org Test/HUnit/Base.hs --- Test/HUnit/Base.hs.org 2010-07-22 14:01:40.000000000 +0000 +++ Test/HUnit/Base.hs 2010-07-22 14:00:36.000000000 +0000 @@ -73,7 +73,7 @@ assertEqual preface expected actual = unless (actual == expected) (assertFailure msg) where msg = (if null preface then "" else preface ++ "\n") ++ - "expected: " ++ show expected ++ "\n but got: " ++ show actual + "expected: " ++ read (show expected) ++ "\n but got: " ++ read (show actual) -- Overloaded `assert` Function
read版をインストール
ビルドの準備ができたので、「cabal install」します。
$ cabal install
問題なくインストールできました。
テスト実行
さて、テストを実行します。意図通り表示されるでしょうか。
Prelude> :load test.hs [1 of 1] Compiling Main ( test.hs, interpreted ) Ok, modules loaded: Main. *Main> runTestTT tests Loading package HUnit-1.2.2.1 ... linking ... done. ### Failure in: 0:テストのラベル アサーションのラベル expected: 期待値 but got: 実際の値 Cases: 1 Tried: 1 Errors: 0 Failures: 1 Counts {cases = 1, tried = 1, errors = 0, failures = 1}
されました!