MLton(+SML/NJ)のためのユニットテスト環境
前回(SML/NJでのUnitTest環境の構築)で構築した
ユニットテスト環境をSMLコンパイラである MLton で使えるようにします.
.cmファイル(SML/NJ用のmakefile)と.mlb(MLton用のmakefile)から同様に使えるようにするため,
SML/NJ用の環境も少し変更したので両方の環境構築方法を紹介します.
いずれの場合にも既に以下のようにチェックアウトが済んでいるとして説明します.
svn checkout http://sml-ext.googlecode.com/svn/trunk/ sml-ext-read-only
MLton用の環境構築
チェックアウトしたファイルを一部修正します.
無理やりコメントアウト(^^;;
--- sources.mlb (revision 648) +++ sources.mlb (working copy) @@ -16,10 +16,11 @@ util/sources.mlb timing/$(TIMING).mlb word/sources.mlb - +(* opt/cfsqp/cfsqp.mlb opt/knitro/knitro.mlb - +*) basis/list-ext-test.sml basis/real-ext-test.sml test/sml-ext-test.sml
今度は構文エラーを真面目に修正. (どーせショボイregexpなので使わないんですが…)
--- regexp/simple-regexp.sml (revision 648) +++ regexp/simple-regexp.sml (working copy) @@ -27,11 +27,10 @@ case matches of NONE => false | SOME (tree,_) => - (case MatchTree.nth(tree,0) of - NONE => raise Impossible - | SOME {len,pos=_} => len = n) + let val {len,...} = MatchTree.nth(tree,0) + in len = n + end end - end
あとは適切に.mlbファイルを記述してコンパイルすれば使うことが出来ます.
以下が .mlb ファイルのサンプルです
$ cat test.mlb local $(SML_LIB)/basis/basis.mlb $(SML_EXT)/sources.mlb (* sml-extを指定 *) test.sml (* テストを書いてあるファイル *) in structure Test (* テストする対象のstructure *) end
これをコンパイルすれば実行ファイルが出来上がります. (多分もっと良い方法があるはずだけど…)
$ mlton -mlb-path-map /path/to/sml-ext-read-only/sml-ext.map \ -mlb-path-var 'SML_EXT /path/to/sml-ext-read-only' test.mlb
テストの書き方は以下のようになります. 前回とほぼ同じですが, openするstructureの名前が変わっています.
$ cat test.sml structure Test = struct open UnitTests (* 前回はSmlExt.UnitTestsだった *) open Ops fun test () = $ ("Test" (* 全体に名前付ける *) , &[ % (fn()=> assertEqualEq (0, 0)) (* 0==0 *) , % (fn()=> assertEqualEq (0, 1)) (* 0==1 *) , % (fn()=> assertEqualEq (0, 2)) , % (fn()=> assertEqualInt (1, 0)) (* ケースに名前を付ける *) , $ ("1==1", % (fn()=> assertEqualInt (1, 1))) , % (fn()=> assertEqualInt (1, 2)) , % (fn()=> assertEqualReal (2.0, 0.0)) (* 特殊化された比較アサート *) , % (fn()=> assertEqualReal (2.1, 2.1)) , % (fn()=> assertEqualReal (2.2, 2.19999)) , % (fn()=> assertEqualReal (3.14, 3.14159)) , % (fn()=> ? (6 = foldr op+ 0 [1,2,3])) , $ ("sum[1..10]=55", (* ちょっと実際的?なケース *) % (fn()=> ? (55 = foldr op+ 0 (List.tabulate(10,fn i=> i))))) ]) end val _ = UnitTests.runTest(Test.test()); (* 即テスト実行 *)
前回の方法では SmlExt がグローバルに公開され, 必要なものはその中にネストして定義されていました.
今回の方法では SmlExt は提供されず, sml-extライブラリが提供するstructureがそれぞれトップレベルに公開されます. *1
sml-ext.cm(とそこから読み込まれるファイル全部)に対応する.mlbファイルを書けば, 前回と同じように使えるハズ.
SML/NJ用の環境構築
- vi sml-ext
そのままコンパイルするとエラーが出るため修正します(これは前回と同様)
signature SmlExt'ORD_SET_EXT ↓ signature SmlExt'SmlNjLib'ORD_SET_EXT
- 前回と違うファイルを指定してコンパイルします
$ cd sml-ext-read-only/ # 前回 $ echo 'CM.stabilize true "sml-ext.cm";' | sml # 今回 $ echo 'CM.stabilize true "sources.cm";' | sml
- CM(コンパイルマネージャ)のパスを登録
# 前回 $ echo "sml-ext.cm sml-ext.cm" >> $SMLNJ_HOME/lib/pathconfig # 今回 $ echo "sml-ext sml-ext" >> $SMLNJ_HOME/lib/pathconfig
- ファイルを移動. CMの性質上, 一段深いディレクトリに置く必要があります.
# 前回 $ mv sml-ext-read-only $SMLNJ_HOME/lib/sml-ext.cm # 今回 $ mv sml-ext-read-only $SMLNJ_HOME/lib/sml-ext/sml-ext
- 完了!
以下が.cmファイルのサンプルです. 上で説明しているように, structureの公開されるレベルが変わったので
それに合わせて明示的にUnitTests structureを指定します.
Library structure UnitTests (* 前回は SmlExt *) structure Test is $/basis.cm $/sml-ext/sources.cm (* 前回は $/sml-ext.cm *) test.sml
cm2mlb
.cmファイルから.mlbを作成するツールはMLtonにより提供されています…
# なぜこんなところにある…w $ cd /usr/share/doc/mlton/cm2mlb/ && make
が, コレが吐いたファイルは謎の番号が振られたstructureの羅列なのであんまりうれしくは無いですorz
まとめ
- SML/NJとMLtonで同じユニットテストが実行できるようになりました!
- cm2mlbは罠
- CMのpathconfig設定は直感的じゃない><