コード網羅ツールは、コードのどの部分が実際に実行され、どの部分が一回も呼ばれなかったかを、プログラマが判断できるようにする。GHCには計器付きコードを生成するオプションがあり、生成されたコードはHaskell Program Coverage(HPC)ツールキット(GHCに付属している)の一員としてコード網羅率を記録する。このコード網羅率情報は、HPCツールを使って人間が理解できる形式に変換することができる。
正しい計器付きコードは二種類の網羅率情報を供給する。ソース網羅率と真偽値制御網羅率である。ソース網羅率は、プログラムがどれくらい隅々まで使われたかの度合いで、三つの水準、すなわち宣言(最上位のものと局所的なものの両方)、分岐(複数の等式やcaseの枝からの選択)、式(あらゆる深さのもの)で測られる。真偽値網羅率は、構文的に真偽値が要求される全ての場所(ガード、条件、qualifier(訳者: qualifierって何?))について、どれくらいTrueとFalseの両方が得られたかである。
HPCは、この両方の種類の情報を、二つの主要な方法で表示する。一つは、統計要約の付いたテキスト形式の報告書(hpc report
)であり、もう一つはソースの色付きマークアップ(hpc markup
)である。真偽値網羅については、それぞれのガード、条件、qualifierについて、四つの結果があり得る。TrueとFalseの両方が起こった、Trueだけ、Falseだけ、一回も評価されなかった、である。hpcマークアップの出力において、黄色の背景による強調はプログラムのその部分が一回も評価されなかったことを示し、緑の背景は常にTrueだったことを、赤い背景は常にFalseだったことを示す。
例として、Recip.hs
という、逆数の正確な十進表現を計算するプログラムを使おう。小数の循環部分は括弧に入れて示すことにする。
reciprocal :: Int -> (String, Int) reciprocal n | n > 1 = ('0' : '.' : digits, recur) | otherwise = error "attempting to compute reciprocal of number <= 1" where (digits, recur) = divide n 1 [] divide :: Int -> Int -> [Int] -> (String, Int) divide n c cs | c `elem` cs = ([], position c cs) | r == 0 = (show q, 0) | r /= 0 = (show q ++ digits, recur) where (q, r) = (c*10) `quotRem` n (digits, recur) = divide n r (c:cs) position :: Int -> [Int] -> Int position n (x:xs) | n==x = 1 | otherwise = 1 + position n xs showRecip :: Int -> String showRecip n = "1/" ++ show n ++ " = " ++ if r==0 then d else take p d ++ "(" ++ drop p d ++ ")" where p = length d - r (d, r) = reciprocal n main = do number <- readLn putStrLn (showRecip number) main
HPCの計器付与は-fhpcフラグで有効になる。
$ ghc -fhpc Recip.hs
GHCはカレントディレクトリに.hpc
サブディレクトリを作成し、HPCインデックス(.mix
)ファイルを、コンパイルするモジュール一つにつき一個そこに置く。これらのファイルについて心配する必要はない。これらは、プログラムが実行された後にhpc
ツールがコンパイルされたモジュールの網羅率データを生成するのに必要な情報を含んでいる。
$ ./Recip 1/3 = 0.(3)
プログラムを実行すると接尾辞.tix
を持つファイル、この例ではRecip.tix
が生成される。これはプログラムの今回の実行の網羅率データを含んでいる。プログラムは(たとえば違うテストデータで)複数回走らせることができ、そうすると別々の実行の網羅率データがこの.tix
に蓄積される。網羅率データをリセットしてやりなおすには、単に.tix
ファイルを削除すれば良い。
プログラムを走らせたので、テキスト形式で網羅率の要約を生成することができる。
$ hpc report Recip 80% expressions used (81/101) 12% boolean coverage (1/8) 14% guards (1/7), 3 always True, 1 always False, 2 unevaluated 0% 'if' conditions (0/1), 1 always False 100% qualifiers (0/0) 55% alternatives used (5/9) 100% local declarations used (9/9) 100% top-level declarations used (5/5)
マークアップされたソースを生成することもできる。
$ hpc markup Recip writing Recip.hs.html
これによって、Haskellモジュール一つにつき一つのファイルと、四つのインデックスファイル(hpc_index.html、hpc_index_alt.html、hpc_index_exp.html、hpc_index_fun.html)が生成される。
-fhpc
現在のモジュール、またはコンパイルされているモジュール群に対するコード網羅率の計測を有効にする。
このオプションを使ってコンパイルされたモジュールは、これなしでコンパイルされたモジュールと自由に混ぜて構わない。実際、大部分のライブタリは典型的には-fhpc
なしでコンパイルされるだろう。プログラムが実行されるとき、網羅率データは-fhpc
付きでコンパイルされたモジュールについてのみ生成され、hpc
はそれらのモジュールについての情報のみを示す。
hpcコマンドにはいくつかサブコマンドがある。
$ hpc Usage: hpc COMMAND ... Commands: help Display help for hpc or a single command Reporting Coverage: report Output textual report about program coverage markup Markup Haskell source with program coverage Processing Coverage files: sum Sum multiple .tix files in a single .tix file combine Combine two .tix files in a single .tix file map Map a function over a single .tix file Coverage Overlays: overlay Generate a .tix file from an overlay file draft Generate draft overlay that provides 100% coverage Others: show Show .tix file in readable, verbose format version Display version for hpc
一般的に言って、これらのオプションは、計器付きバイナリが生成した後の.tixファイルに対して動作する。
hpcツールは、アプリケーションをビルドした場所の最上位ディレクトリに居て、その同じ最上位ディレクトリに.tix
ファイルがあることを前提とする。別のディレクトリに対してhpc
を使うには--srcdir
フラグを使うことができる。また、複数の場所でコンパイルされたプログラム(パッケージでは普通のことである)を分析する場合は、--srcdir
を複数回使えばよい。
ここからは、hpcのメジャーモードについて詳しく説明する。
hpc report
は、網羅率のテキスト形式の報告書を与える。デフォルトで、includeやexcludeが使われない限り、報告書を生成する上ですべてのモジュールとパッケージが考慮に入る。--per-module
フラグが使われない限り、報告書は要約である。--xml-output
オプションは、hpcを使って網羅率を収集するツールのためにある。
$ hpc help report Usage: hpc report [OPTION] .. <TIX_FILE> [<MODULE> [<MODULE> ..]] Options: --per-module show module level detail --decl-list show unused decls --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --srcdir=DIR path to source directory of .hs files multi-use of srcdir possible --hpcdir=DIR append sub-directory that contains .mix files default .hpc [rarely used] --reset-hpcdirs empty the list of hpcdir's [rarely used] --xml-output show output in XML
hpc markup
はソースファイルをマークアップして色付きhtmlにする。
$ hpc help markup Usage: hpc markup [OPTION] .. <TIX_FILE> [<MODULE> [<MODULE> ..]] Options: --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --srcdir=DIR path to source directory of .hs files multi-use of srcdir possible --hpcdir=DIR append sub-directory that contains .mix files default .hpc [rarely used] --reset-hpcdirs empty the list of hpcdir's [rarely used] --fun-entry-count show top-level function entry counts --highlight-covered highlight covered code, rather that code gaps --destdir=DIR path to write output to
hpc sum
は任意の個数の.tix
ファイルを足し合わせて、単一の.tix
ファイルにする。hpc sum
は元の.tix
ファイルを変更せず、新しい.tix
ファイルを作る。
$ hpc help sum Usage: hpc sum [OPTION] .. <TIX_FILE> [<TIX_FILE> [<TIX_FILE> ..]] Sum multiple .tix files in a single .tix file Options: --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --output=FILE output FILE --union use the union of the module namespace (default is intersection)
hpc combine
はhpc
のスイスアーミーナイフである。.tix
ファイルの差(difference)をとること、ある.tix
ファイルから別の.tix
ファイルを引く(subtract)こと、二つの.tix
ファイルを足す(add)ことができる。hpc combineは元の.tix
ファイルを変更せず、新しい.tix
ファイルを生成する。
$ hpc help combine Usage: hpc combine [OPTION] .. <TIX_FILE> <TIX_FILE> Combine two .tix files in a single .tix file Options: --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --output=FILE output FILE --function=FUNCTION combine .tix files with join function, default = ADD FUNCTION = ADD | DIFF | SUB --union use the union of the module namespace (default is intersection)
hpc mapは.tix
ファイルを反転(invert)したり零化(zero)したりする。hpc mapは元の.tix
ファイルを変更せず、新しい.tix
ファイルを生成する。
$ hpc help map Usage: hpc map [OPTION] .. <TIX_FILE> Map a function over a single .tix file Options: --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --output=FILE output FILE --function=FUNCTION apply function to .tix files, default = ID FUNCTION = ID | INV | ZERO --union use the union of the module namespace (default is intersection)
overlayはHPCの実験的機能で、網羅率のテキスト記述である。hpc draftは.tixファイルからdraft overlayを作るのに使われ、hpc overlayはoverlayから.tixファイルを生成する。
% hpc help overlay Usage: hpc overlay [OPTION] .. <OVERLAY_FILE> [<OVERLAY_FILE> [...]] Options: --srcdir=DIR path to source directory of .hs files multi-use of srcdir possible --hpcdir=DIR append sub-directory that contains .mix files default .hpc [rarely used] --reset-hpcdirs empty the list of hpcdir's [rarely used] --output=FILE output FILE % hpc help draft Usage: hpc draft [OPTION] .. <TIX_FILE> Options: --exclude=[PACKAGE:][MODULE] exclude MODULE and/or PACKAGE --include=[PACKAGE:][MODULE] include MODULE and/or PACKAGE --srcdir=DIR path to source directory of .hs files multi-use of srcdir possible --hpcdir=DIR append sub-directory that contains .mix files default .hpc [rarely used] --reset-hpcdirs empty the list of hpcdir's [rarely used] --output=FILE output FILE
HPCは.tix
ファイルをロックしようとしないので、同じディレクトリでバイナリを並行に実行すると競合条件が現れるだろう。バイナリの名前を変更する以外に、生成される.tix
ファイルの名前を変えるすべはない。HPCはGHCiでは動作しない。