For Development HEAD DRAFTSearch (procedure/syntax/module):

11.69 srfi.252 - Property testing

Module: srfi.252

Property testing is to feed random input to a component to be tested and see if it satisfies certain properties hold. The method was made popular with Haskell’s QuickCheck.

This module provides two groups of APIs; one for running property tests, and another for generating random input.

The test procedures are integrated with gauche.test (see gauche.test - Unit Testing). The SRFI is designed to be used with SRFI-64 (see srfi.64 - A Scheme API for test suites); in Gauche, you can run them with either of modules.

The random input generators are built on top of data.random (see data.random - Random data generators). They are provided for the convenience; you can use any generator to create input feed.

Testing forms

Macro: test-property property-check generator-list :optional runs
Macro: test-property-expect-fail property-check generator-list :optional runs
Macro: test-property-skip property-check generator-list :optional runs
Macro: test-property-error property-check generator-list :optional runs
Macro: test-property-error-type error-type property-check generator-list :optional runs

[SRFI-252]{srfi.252} Calls property-check over the arguments generated by the generators in generator-list as many times as runs.

property-check is an expression that evaluates to a procedure accepts input, and returns #t if the property is satisfied, #f if not. The input is fed from generators listed in generator-list; it must have as many generators as the number of arguments property-check accepts.

The optional argument runs must be a nonnegative exact integer to specify how many times property-check should be run. If omitted, the system default is used, which is 30 in Gauche. The default runs may be changed in future.

Test-property is the basic one; the test passes when every property-check invocation returns true. Test-property-expect-fail, on the other hand, passes when every property-check returns false (thus, expected failure). Test-property-skip does not run property-check, just counts runs attempts as skipped tests. Test-property-error expects all invocations of property-check raises an error. Finally, test-property-error and test-property-error-type expect all property-check invocations raise an error. Additionally, test-property-error-type expects the raised error is of type error-type, which should be a condition type.

This SRFI is designed to be used with SRFI-64, but you can use these directly with gauche.test without loading srfi.64.

Function: property-test-runner

[SRFI-252]{srfi.252} Returns a SRFI-64 test runner object specialized for property testing. In Gauche, this simply returns SRFI-64 simple runner, but other implementations may have some additional features. It is recommended that portable code sets the runner created with this procedure before calling property test procedures.

Generators

These are procedures that create generators of specific types. You can find similar generator procedurs in data.random (see data.random - Random data generators) and srfi.194 (see srfi.194 - Random data generators (SRFI)), but the procedures here creates generators with one specific property suitable for testing: They start generating certain pre-defined values–typical, or boundary values–before generating random values.

All created generators captures the value of parameter random-data-random-source (see data.random - Random data generators) when created. If you want to have reproducible results, you can provide your own random source.

Function: boolean-generator

[SRFI-252]{srfi.252} Returns a generator that yields #t and #f, then a random boolean values in equal probability.

See also booleans$ in data.random (see data.random - Random data generators).

Function: bytevector-generator

[SRFI-252]{srfi.252} Returns a generator that yields an empty bytevector #u8() first, then bytevectors of random length and random content subsequently.

In Gauche, it is realized as follows (see data.random - Random data generators, for sequences-of and integers$). The constant sequence-max-size is currently 33 but may be changed.

(gcons* '#u8()
        (sequences-of <u8vector>
                      (integers$ sequence-max-size)
                      (integers$ 256))))
Function: char-generator

[SRFI-252]{srfi.252} Returns a character generator that yields #\null, then random characters subsequently. Currently we sample charactres uniformly from the entire Unicode range, but that causes most of the characters to be very infrequently used ones. We might change it in future.

See also chars$ in data.random (see data.random - Random data generators).

Function: string-generator

[SRFI-252]{srfi.252} Returns a string generator that yields an empty string "", then strings of random length and random content subsequently.

In Gauche, it is realized as follows (see data.random - Random data generators, for strings-of and integers$). The constant sequence-max-size is currently 33 but may be changed.

(gcons* ""
  (strings-of (integers$ sequence-max-size) (chars$ char-set:full)))

Note that the chracters are sampled uniformly from the entire Unicode range, which causes almost all strings to consist of very infrequently used characters. We might address this in future.

Function: symbol-generator

[SRFI-252]{srfi.252} Returns a symbol generator that yields a symbol whose name is empty (||), then symbols of random length and random content subsequently. It is basically (gmap string->symbol (string-generator)).

Note that the chracters are sampled uniformly from the entire Unicode range, which causes almost all symbols to consist of very infrequently used characters. We might address this in future.

Function: complex-generator
Function: inexact-complex-generator

[SRFI-252]{srfi.252} Returns a generator that yields the following inexact complex numbers, followed by random complex numbers.

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

Note: SRFI specifies complex-generator to return both exact and inexact complex numbers if the implementation supports them. Gauche doesn’t have exact complex numbers, so it is the same as inexact-complex-generator.

In Gauche, a random complex number is created by uniformly sampled finite flonums for real and imaginary parts. Note that “uniformly sampled finite flonums” are not the same as “uniformly sampled real numbers”; See finite-flonums$ for the details (see data.random - Random data generators).

Function: exact-complex-generator
Function: exact-integer-complex-generator

[SRFI-252]{srfi.252} Gauche does not support exact complex numbers, and these procedures raise an error when called.

Function: integer-generator
Function: exact-integer-generator
Function: inexact-integer-generator

[SRFI-252]{srfi.252} Return generators that yields integers, exact integers, and inexact integers, respectively.

The exact integer generator always yield 0, 1, and -1 at the beginning, then random integers follow.

The inexact integer generator always yield 0.0, -0.0, 1.0, and -1.0 at the beginning, then random integers follow.

The general integer generator created by integer-generator samples evenly from an exact integer genratgor and an inexact integer generator.

Since the range of exact integers is only bounded by the memory, uniform sampling from the entire possible range is infeasible; almost all samples would become a huge integer. Instead, we split integer range into 3: relatively small integers, fixnums, and bignums, and sample evenly from these three generators. Small integers and fixnums are sampled uniformly within its range, and bignums are sampled according to the power law; so, we see a lot more bignums closer to fixnum range, with occasional really big numbers sprinkled in.

Function: rational-generator
Function: exact-rational-generator
Function: inexact-rational-generator

[SRFI-252]{srfi.252} Return generators that yields rational numbers, exact rational numbers, and inexact rational numbers, respectively.

The exact rational number generator yields 0, 1, -1, 1/2, and -1/2 at the beginning, then generate (/ a b) where a, b are generated in the same way as exact-integer-generator’s distribution, except 0 is excluded from b.

The inexact rational number generator yields 0.0, -0.0, 0.5, =0.5, 1.0, and -1.0 at the beginning, then proceed to generate random inexact rational numbers. In Gauche, inexact rational numbers are finite flonums, and we uniformly samples from all possible finite flonums (which is not the same as uniform sample from a range of real numbers). See finite-flonums$ in data.random - Random data generators.

The general rational number generator created by rational-generator evenly samples from an exact rational number generator and an inexact rational number generator.

Function: real-generator
Function: exact-real-generator
Function: inexact-real-generator

[SRFI-252]{srfi.252} Return generators that yields real numbers, exact real numbers, and inexact real numbers, respectively.

In Gauche, the set of exact real numbers are exactly the same as the set of exact rational numbers (infinites and NaNs are inexact), so exact-real-generator is the same as exact-rational-generator.

The inexact real number generator yields 0.0, -0.0, 0.5, -0.5, 1.0, -1.0, +inf.0, -inf.0, and +nan.0 at the beginning, followed by inexact real numbers uniformly sampled from all possible finite flonums (which is not the same as uniform sample from a range of real numbers). See finite-flonums$ in data.random - Random data generators.

The general real number generator created by real-generator evenly samples from an exact real number generator and an inexact real number generator.

Function: number-generator
Function: exact-number-generator
Function: inexact-number-generator

[SRFI-252]{srfi.252} In Gauche, the set of exact numbers is the same as the set of exact rational numbers (we don’t have exact complex), and the set of inexact numbers is the same as the set of inexact complex numbers. Thus exact-number-generator is the same as exact-rational-generator, and inexact-number-generator is the same as inexact-complex-generator.

The general number generator created by number-generator evenly samples from an exact number generator and an inexact number generator.

Function: list-generator-of elt-generator :optional max-length
Function: vector-generator-of elt-generator :optional mex-length

[SRFI-252]{srfi.252} Return generators that yield a list/vector of random length up to max-length, and elements generated by elt-generator, respectively. Similar to lists-of/vectors-of in data.random.

When max-length is omitted, we leave the length to the default of lists-of/vectors-of, which is determined by the parameter default-sizer in data.random. See data.random - Random data generators, for the details.

Function: pair-generator-of car-generator :optional cdr-generator

[SRFI-252]{srfi.252} Returns a generator that yields pairs, whose car is generated with car-generator and whose cdr is generated with cdr-generator. If cdr-generator is omitted, car-generator is used.

Function: procedure-generator-of value-generator

[SRFI-252]{srfi.252} Returns a generator that yields procedures, which accepts any number of arguments and returns a value generated with value-generator.



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT