srfi.252 - プロパティテスト ¶プロパティテストは、テストしたいコンポーネントにランダムな入力を供給して 満たすべき属性(プロパティ)が満たされるかをテストする方法です。 HaskellのQuickCheckによってポピュラーになりました。
このモジュールでは、プロパティテストを実行するためのAPI群と、 ランダムな入力を生成するためのAPI群のふたつを提供します。
テスト手続きはgauche.testと統合されています
(gauche.test - 単体テスト参照)。また、このSRFIはSRFI-64と併せて使えるように
設計されており、GaucheでもSRFI-64と併用することができます
(srfi.64 - SchemeテストスイートAPI参照)。
ランダムな入力を生成するジェネレータはdata.randomの上に
構築されています (data.random - ランダムデータの生成参照)。
これは簡便のために提供されています。必要なら、独自にジェネレータを作っても構いません。
[SRFI-252]{srfi.252}
generator-listにあるジェネレータが生成した値を引数として、
property-checkを呼びます。それをruns回繰り返します。
property-checkは手続きに評価される式で、プロパティが満たされたら#tを、
そうでなければ#fを返します。
引数はgenerator-listにリストされた各ジェネレータが生成します。
generator-listはproperty-checkが受け取る引数と
同数のジェネレータから構成されていなければなりません。
省略可能なruns引数は非負の整数で、property-checkを何回呼び出すかを 指定します。省略された場合はシステムのデフォルトが使われます (Gaucheでは今のところ30。但し将来変わる可能性はあります)。
test-propertyが最も基本的なもので、全てのproperty-checkの呼び出しが
成功であれば成功します。
test-property-expect-failは逆に、全てのproperyt-check
の呼び出しが失敗した場合に成功します (つまり、失敗することを期待したチェックです)。
test-property-skipはproperty-checkは呼び出さず、
runs回のテストをスキップしたということだけを記録します。
最後に、test-property-errorとtest-property-error-typeは
property-checkが常にエラーを投げることを期待します。
test-property-error-typeはそれに加え、投げられるエラーが
error-typeコンディションタイプであることを期待します。
SRFIではこれらのテストはSRFI-64のフレームワーク上で実行されることを
想定していますが、srfi.64をロードせずにgauche.testのテストの
一環として実行することも可能です。
[SRFI-252]{srfi.252}
プロパティテストのための、SRFI-64 テストランナーオブジェクトを返します。
Gaucheではこれは単にSRFI-64 simple runnerを返しますが、
他の実装では機能を追加したランナーが返されるかもしれません。
ポータブルなコードを書いている時は、
このテストランナーを使ってプロパティテストを行うと良いでしょう。
以下の手続きは特定の型のオブジェクトを生成するジェネレータを作ります。
data.random(data.random - ランダムデータの生成参照)や
srfi.194(srfi.194 - ランダムデータジェネレータ (SRFI)参照)にも
似たような手続きがありますが、このモジュールのジェネレータ作成手続きで
作られるジェネレータには、プロパティテストに適した特性があります。
それは、ランダムな値を生成する前に、決められた一連の値(典型的な値および
境界値)を生成するということです。
以下の手続きで作られるジェネレータは、作成時の
random-data-random-sourceパラメータの値を取り込みます
(data.random - ランダムデータの生成参照)。
テストを再現可能にしたい場合は、自前のランダムソースを使うことができます。
[SRFI-252]{srfi.252}
#t、#f、そしてそれに続いて二つの真偽値を等確率でランダムに
生成するジェネレータを作って返します。
data.randomのbooleans$も参照
(data.random - ランダムデータの生成)。
[SRFI-252]{srfi.252}
まず空のバイトベクタ #u8() を生成し、続いて
ランダムな長さでランダムな内容を持つバイトベクタを生成するジェネレータを作って返します。
Gaucheではこの手続きは、sequences-ofとintegers$を
使って次のとおり実装されています(data.random - ランダムデータの生成参照)。
定数sequence-max-sizeは今の所33ですが、将来変更されるかもしれません。
(gcons* '#u8()
(sequences-of <u8vector>
(integers$ sequence-max-size)
(integers$ 256))))
[SRFI-252]{srfi.252}
最初に#\nullを、その後はランダムな文字を返すジェネレータを
作って返します。
今のところ、経験的に重み付けしたサンプリングを使っていて、 ASCII文字が出やすくなっていますが、全てのUnicode文字が生成される 可能性があります。
data.randomのchars$も参照してください
(data.random - ランダムデータの生成)。
[SRFI-252]{srfi.252}
まず空文字列、その後はランダムな長さのランダムな文字列を生成する
ジェネレータを作って返します。
Gaucheの実装は、次のコードと実質的に等価です
(strings-ofとintegers$についてはdata.random - ランダムデータの生成参照)。
定数sequence-max-sizeは今の所33ですが変更されるかもしれません。
(gcons* ""
(strings-of (integers$ sequence-max-size)
(rlet1 g (char-generator)
(g)))) ; discard initial #\null
[SRFI-252]{srfi.252}
まず空の名前のシンボル(||)、続いてランダムな長さのランダムな名前を持つ
シンボルを生成するジェネレータを作って返します。
基本的には(gmap string->symbol (string-generator))と考えて良いです。
[SRFI-252]{srfi.252}
以下の複素数を順に生成し、続いてランダムな複素数を生成するジェネレータを
作って返します。
0.0 -0.0 0.5 -0.5 1.0 -1.0 0.0+1.0i 0.0-1.0i -0.0+1.0i -0.0-1.0i 0.5+0.5i 0.5-0.5i -0.5+0.5i -0.5-0.5i 1.0+1.0i 1.0-1.0i -1.0+1.0i -1.0-1.0i +inf.0+inf.0i +inf.0-inf.0i -inf.0+inf.0i -inf.0-inf.0i +nan.0+nan.0i +inf.0 -inf.0 +nan.0
註: SRFIでは、complex-generatorが作るジェネレータは
実装がサポートしていれば正確な複素数と非正確な複素数のどちらも返すと
されています。Gaucheは正確な複素数を持っていないので、
これはinexact-complex-generatorと同じです。
Gaucheの実装では、ランダムな複素数は、実部と虚部をそれぞれ
有限浮動小数点数の集合から一様にサンプリングして作っています。
「一様にサンプリングした有限浮動小数点数」は、
「一様にサンプリングした実数」とは異なることに注意してください。
詳しくはdata.randomのfinite-flonums$を参照
(data.random - ランダムデータの生成)。
[SRFI-252]{srfi.252}
Gaucheは正確な複素数をサポートしていないので、
これらの手続きは呼ばれたらエラーを投げます。
[SRFI-252]{srfi.252}
整数、正確な整数、非正確な整数をそれぞれ生成するジェネレータを作って返します。
正確な整数のジェネレータは、まず0、1、-1を
順に生成してから、続いてランダムな整数を生成します。
非正確な整数のジェネレータは、まず0.0、-0.0、
1.0、-1.0を
順に生成してから、続いてランダムな整数を生成します。
integer-generatorが返す一般の整数のジェネレータは、
正確な整数のジェネレータと不正確な整数のジェネレータから当確率で
ランダムにサンプリングします。
正確な整数の範囲はメモリの許す限り大きくできるので、 可能な値の範囲から一様サンプリングするのは現実的ではありません。 ほとんど全てのサンプルは非常に大きな整数になってしまうでしょう。 かわりにGaucheでは、整数の範囲を3つに区切りました。 比較的小さな整数、fixnum、そしてbignumです。 小さな整数とfixnumは範囲内で一様サンプリングされます。 bignumはべき乗則によってサンプリングされます。 従って、生成されるbignumの多くはfixnumに近いレンジになり、 時折非常に大きな整数が混ざるという感じになります。
[SRFI-252]{srfi.252}
それぞれ、有理数、正確な有理数、そして不正確な有理数を生成するジェネレータを
作って返します。
正確な有理数ジェネレータは、最初に
0、1、-1、1/2、-1/2を順に生成し、
その後はexact-integer-generatorと同じ分布で生成した
正確な整数a、bを使って(/ a b)を生成します
(bから0は除外します)。
非正確な有理数ジェネレータは、最初に
0.0、-0.0、0.5、=0.5、1.0、-1.0
を順に生成し、その後は非正確な有理数をランダムに生成します。
Gaucheでは非正確な有理数は有限な浮動小数点数で表されるので、
可能な有限浮動小数点数から一様サンプリングした値を使います
(これは表現可能な実数範囲からの一様サンプリングではありません)。
詳しくはdata.random - ランダムデータの生成のfinite-flonums$
を参照してください。
rational-generatorが返す一般の有理数ジェネレータは、
正確な有理数ジェネレータと非正確な有理数ジェネレータから等確率で
サンプリングします。
[SRFI-252]{srfi.252}
それぞれ、実数、正確な実数、そして不正確な実数を生成するジェネレータを
作って返します。
Gaucheでは、正確な実数の集合は正確な有理数の集合と一致します
(無限大およびNaNは非正確だからです)。
従って、exact-real-generatorは
exact-rational-generatorと同じです。
非正確な実数のジェネレータは、まず
0.0、-0.0、0.5、-0.5,
1.0、-1.0、+inf.0、-inf.0、+nan.0を
順に生成し、以降は可能な有限浮動小数点数から一様サンプリングした値を使います
(これは表現可能な実数範囲からの一様サンプリングではありません)。
詳しくはdata.random - ランダムデータの生成のfinite-flonums$
を参照してください。
real-generatorが返す一般の実数ジェネレータは、
正確な実数ジェネレータと非正確な実数ジェネレータから等確率で
サンプリングします。
[SRFI-252]{srfi.252}
Gaucheでは、正確な数の集合は(正確な複素数を持ってないので)
正確な有理数の集合と等しく、非正確な数の集合は
非正確な複素数の集合と等しいです。
従って、exact-number-generatorは
exact-rational-generatorと同じ、
inexact-number-generatorは
inexact-complex-generatorと同じです。
number-generatorが返す一般の数ジェネレータは、
正確な数ジェネレータと非正確な数ジェネレータから等確率で
サンプリングします。
[SRFI-252]{srfi.252}
最初に空リスト/空ベクタを、以降はmax-lengthを最大長とする
ランダムな長さのリストおよびベクタを
それぞれ生成するジェネレータを作って返します。
返されるリストやベクタの要素は、ジェネレータelt-generatorで
作られます。
data.randomのlists-of/vectors-ofと似ています。
max-lengthが省略された場合は、lists-of/vectors-ofの
デフォルトに任せます。それはdata.randomのパラメータ
default-sizerで制御されます。
詳しくはdata.random - ランダムデータの生成を参照してください。
[SRFI-252]{srfi.252}
ペアを生成するジェネレータを作って返します。
cdr-generatorが指定された場合、各ペアのcarは
car-generator、cdrはcdr-generatorで生成します。
cdr-generatorが省略された場合、carとcdr両方にcar-generatorを
使います。
[SRFI-252]{srfi.252}
手続きを生成するジェネレータを作って返します。
各手続きは任意個の引数を取り、value-generatorが生成する
値を戻り値とします。