Module proper_types

Type manipulation functions and predefined types.

Copyright © 2010-2021 Manolis Papadakis, Eirini Arvaniti, and Kostis Sagonas

Version: May 19 2021 06:40:23

Authors: Manolis Papadakis.

Description

Type manipulation functions and predefined types.

Basic types

This module defines all the basic types of the PropEr type system as functions. See the function index for an overview.

Types can be combined in tuples or lists to produce other types. Exact values (such as exact numbers, atoms, binaries and strings) can be combined with types inside such structures, like in this example of the type of a tagged tuple: {'result', integer()}.

When including the PropEr header file, all API functions of this module are automatically imported, unless PROPER_NO_IMPORTS is defined.

Customized types

The following operators can be applied to basic types in order to produce new ones:

?LET(<Xs>, <Xs_type>, <In>)
To produce an instance of this type, all appearances of the variables in <Xs> are replaced inside <In> by their corresponding values in a randomly generated instance of <Xs_type>. It's OK for the <In> part to evaluate to a type - in that case, an instance of the inner type is generated recursively.
?SUCHTHAT(<X>, <Type>, <Condition>)
This produces a specialization of <Type>, which only includes those members of <Type> that satisfy the constraint <Condition> - that is, those members for which the function fun(<X>) -> <Condition> end returns true. If the constraint is very strict - that is, only a small percentage of instances of <Type> pass the test - it will take a lot of tries for the instance generation subsystem to randomly produce a valid instance. This will result in slower testing, and testing may even be stopped short, in case the constraint_tries limit is reached (see the "Options" section in the documentation of the proper module). If this is the case, it would be more appropriate to generate valid instances of the specialized type using the ?LET macro. Also make sure that even small instances can satisfy the constraint, since PropEr will only try small instances at the start of testing. If this is not possible, you can instruct PropEr to start at a larger size, by supplying a suitable value for the start_size option (see the "Options" section in the documentation of the proper module).
?SUCHTHATMAYBE(<X>, <Type>, <Condition>)
Equivalent to the ?SUCHTHAT macro, but the constraint <Condition> is considered non-strict: if the constraint_tries limit is reached, the generator will just return an instance of <Type> instead of failing, even if that instance doesn't satisfy the constraint.
?SHRINK(<Generator>, <List_of_alt_gens>)
This creates a type whose instances are generated by evaluating the statement block <Generator> (this may evaluate to a type, which will then be generated recursively). If an instance of such a type is to be shrunk, the generators in <List_of_alt_gens> are first run to produce hopefully simpler instances of the type. Thus, the generators in the second argument should be simpler than the default. The simplest ones should be at the front of the list, since those are the generators preferred by the shrinking subsystem. Like the main <Generator>, the alternatives may also evaluate to a type, which is generated recursively.
?LETSHRINK(<List_of_variables>, <List_of_types>, <Generator>)
This is created by combining a ?LET and a ?SHRINK macro. Instances are generated by applying a randomly generated list of values inside <Generator> (just like a ?LET, with the added constraint that the variables and types must be provided in a list - alternatively, <List_of_types> may be a list or vector type). When shrinking instances of such a type, the sub-instances that were combined to produce it are first tried in place of the failing instance.
?LAZY(<Generator>)
This construct returns a type whose only purpose is to delay the evaluation of <Generator> (<Generator> can return a type, which will be generated recursively). Using this, you can simulate the lazy generation of instances:
         stream() -> ?LAZY(frequency([ {1,[]}, {3,[0|stream()]} ])).
The above type produces lists of zeroes with an average length of 3. Note that, had we not enclosed the generator with a ?LAZY macro, the evaluation would continue indefinitely, due to the eager evaluation of the Erlang language.
non_empty(<List_or_binary_type>)
See the documentation for non_empty/1.
noshrink(<Type>)
See the documentation for noshrink/1.
default(<Default_value>, <Type>)
See the documentation for default/2.
with_parameter(<Parameter>, <Value>, <Type>)
See the documentation for with_parameter/3.
with_parameters(<Param_value_pairs>, <Type>)
See the documentation for with_parameters/2.

Size manipulation

The following operators are related to the size parameter, which controls the maximum size of produced instances. The actual size of a produced instance is chosen randomly, but can never exceed the value of the size parameter at the moment of generation. A more accurate definition is the following: the maximum instance of size S can never be smaller than the maximum instance of size S-1. The actual size of an instance is measured differently for each type: the actual size of a list is its length, while the actual size of a tree may be the number of its internal nodes. Some types, e.g. unions, have no notion of size, thus their generation is not influenced by the value of size. The size parameter starts at 1 and grows automatically during testing.

?SIZED(<S>, <Generator>)
Creates a new type, whose instances are produced by replacing all appearances of the <S> parameter inside the statement block <Generator> with the value of the size parameter. It's OK for the <Generator> to return a type - in that case, an instance of the inner type is generated recursively.
resize(<New_size>, <Type>)
See the documentation for resize/2.

Data Types

extint()

extint() = integer() | inf

extnum()

extnum() = number() | inf

frequency()

frequency() = non_neg_integer()

length()

length() = non_neg_integer()

loose_tuple()

loose_tuple(T) = {} | {T} | {T, T} | {T, T, T} | {T, T, T, T} | {T, T, T, T, T} | {T, T, T, T, T, T} | {T, T, T, T, T, T, T} | {T, T, T, T, T, T, T, T} | {T, T, T, T, T, T, T, T, T} | {T, T, T, T, T, T, T, T, T, T} | tuple()

raw_type()

raw_type() = type() | [raw_type()] | loose_tuple(raw_type()) | term()

You can consider this as an equivalent of type().

type()

abstract datatype: type()

A type of the PropEr type system

type_prop_name()

type_prop_name() = kind | generator | reverse_gen | parts_type | combine | alt_gens | shrink_to_parts | size_transform | is_instance | shrinkers | noshrink | internal_type | internal_types | get_length | split | join | get_indices | remove | retrieve | update | constraints | parameters | env | subenv | user_nf | is_user_nf | matcher

type_prop_value()

type_prop_value() = term()

value()

value() = term()

Function Index

add_prop/3
any/0All Erlang terms (that PropEr can produce).
arity/0Equivalent to integer(0, 255).
atom/0All atoms.
binary/0All binaries.
binary/1All binaries with a byte size of Len.
bitstring/0All bitstrings.
bitstring/1All bitstrings with a bit size of Len.
bool/0Equivalent to boolean().
boolean/0The atoms true and false.
byte/0Equivalent to integer(0, 255).
char/0Equivalent to integer(0, 1114111).
choose/2Equivalent to integer(Low, High).
default/2Adds a default value, Default, to Type.
elements/1Equivalent to union(Choices).
exactly/1Singleton type consisting only of E.
fixed_list/1All lists whose i-th element is an instance of the type at index i of ListOfTypes.
float/0Equivalent to float(inf, inf).
float/2All floats between Low and High, bounds included.
frequency/1Equivalent to weighted_union(Choices).
function/2All pure functions that map instances of ArgTypes to instances of RetType.
function0/1Equivalent to function(0, RetType).
function1/1Equivalent to function(1, RetType).
function2/1Equivalent to function(2, RetType).
function3/1Equivalent to function(3, RetType).
function4/1Equivalent to function(4, RetType).
int/0Small integers (bound by the current value of the size parameter).
integer/0Equivalent to integer(inf, inf).
integer/2All integers between Low and High, bounds included.
largeint/0Equivalent to integer().
list/0Equivalent to list(any()).
list/1All lists containing elements of type ElemType.
loose_tuple/1Tuples whose elements are all of type ElemType.
map/0A map associating keys and values of unspecified types (of any term()).
map/2A map whose keys are defined by the generator K and values by the generator V.
nat/0Small non-negative integers (bound by the current value of the size parameter).
neg_integer/0Equivalent to integer(inf, -1).
nil/0Equivalent to exactly([]).
non_empty/1This is a predefined constraint that can be applied to random-length list and binary types to ensure that the produced values are never empty.
non_neg_float/0Equivalent to float(0.0, inf).
non_neg_integer/0Equivalent to integer(0, inf).
noshrink/1Creates a new type which is equivalent to Type, but whose instances are never shrunk by the shrinking subsystem.
number/0Equivalent to union([integer(), float()]).
oneof/1Equivalent to union(Choices).
orderedlist/1All sorted lists containing elements of type ElemType.
parameter/1Equivalent to parameter(Parameter, undefined).
parameter/2Returns the value associated with Parameter, or Default in case Parameter is not associated with any value.
pos_integer/0Equivalent to integer(1, inf).
range/2Equivalent to integer(Low, High).
real/0Equivalent to float().
resize/2Overrides the size parameter used when generating instances of Type with NewSize.
return/1Equivalent to exactly(E).
shrink_list/1A type that generates exactly the list List.
string/0Equivalent to list(char()).
term/0Equivalent to any().
timeout/0Equivalent to union([non_neg_integer() | infinity]).
tuple/0Equivalent to loose_tuple(any()).
tuple/1All tuples whose i-th element is an instance of the type at index i of ListOfTypes.
union/1The union of all types in ListOfTypes.
vector/2All lists of length Len containing elements of type ElemType.
weighted_default/2A specialization of default/2, where Default and Type are assigned weights to be considered by the random instance generator.
weighted_union/1A specialization of union/1, where each type in ListOfTypes is assigned a frequency.
with_parameter/3Associates the atom key Parameter with the value Value while generating instances of Type.
with_parameters/2Similar to with_parameter/3, but accepts a list of {Parameter, Value} pairs.
wunion/1Equivalent to weighted_union(FreqChoices).

Function Details

add_prop/3

add_prop(PropName::type_prop_name(), Value::type_prop_value(), X3::proper_types:type()) -> proper_types:type()

any/0

any() -> proper_types:type()

All Erlang terms (that PropEr can produce). For reasons of efficiency, functions are never produced as instances of this type.
CAUTION: Instances of this type are expensive to produce, shrink and instance- check, both in terms of processing time and consumed memory. Only use this type if you are certain that you need it.

arity/0

arity() -> proper_types:type()

Equivalent to integer(0, 255).

atom/0

atom() -> proper_types:type()

All atoms. All atoms used internally by PropEr start with a '$', so such atoms will never be produced as instances of this type. You should also refrain from using such atoms in your code, to avoid a potential clash. Instances shrink towards the empty atom, ''.

binary/0

binary() -> proper_types:type()

All binaries. Instances shrink towards the empty binary, <<>>.

binary/1

binary(Len::length()) -> proper_types:type()

All binaries with a byte size of Len. Len must be an Erlang expression that evaluates to a non-negative integer. Instances shrink towards binaries of zeroes.

bitstring/0

bitstring() -> proper_types:type()

All bitstrings. Instances shrink towards the empty bitstring, <<>>.

bitstring/1

bitstring(Len::length()) -> proper_types:type()

All bitstrings with a bit size of Len. Len must be an Erlang expression that evaluates to a non-negative integer. Instances shrink towards bitstrings of zeroes

bool/0

bool() -> proper_types:type()

Equivalent to boolean().

boolean/0

boolean() -> proper_types:type()

The atoms true and false. Instances shrink towards false.

byte/0

byte() -> proper_types:type()

Equivalent to integer(0, 255).

char/0

char() -> proper_types:type()

Equivalent to integer(0, 1114111).

choose/2

choose(Low::extint(), High::extint()) -> proper_types:type()

Equivalent to integer(Low, High).

default/2

default(Default::raw_type(), Type::raw_type()) -> proper_types:type()

Adds a default value, Default, to Type. The default serves as a primary shrinking target for instances, while it is also chosen by the random instance generation subsystem half the time.

elements/1

elements(Choices::[raw_type(), ...]) -> proper_types:type()

Equivalent to union(Choices).

exactly/1

exactly(E::term()) -> proper_types:type()

Singleton type consisting only of E. E must be an evaluated term. Also written simply as E.

fixed_list/1

fixed_list(ListOfTypes::maybe_improper_list(raw_type(), raw_type() | [])) -> proper_types:type()

All lists whose i-th element is an instance of the type at index i of ListOfTypes. Also written simply as a list of types.

float/0

float() -> proper_types:type()

Equivalent to float(inf, inf).

float/2

float(Low::extnum(), High::extnum()) -> proper_types:type()

All floats between Low and High, bounds included. Low and High must be Erlang expressions that evaluate to floats, with Low =< High. Additionally, Low and High may have the value inf, in which case they represent minus infinity and plus infinity respectively. Instances shrink towards 0.0 if Low =< 0.0 =< High, or towards the bound with the smallest absolute value otherwise.

frequency/1

frequency(FreqChoices::[{frequency(), raw_type()}, ...]) -> proper_types:type()

Equivalent to weighted_union(Choices).

function/2

function(ArgTypes::[raw_type()] | arity(), RetType::raw_type()) -> proper_types:type()

All pure functions that map instances of ArgTypes to instances of RetType. The syntax function(Arity, RetType) is also acceptable.

function0/1

function0(RetType::raw_type()) -> proper_types:type()

Equivalent to function(0, RetType).

function1/1

function1(RetType::raw_type()) -> proper_types:type()

Equivalent to function(1, RetType).

function2/1

function2(RetType::raw_type()) -> proper_types:type()

Equivalent to function(2, RetType).

function3/1

function3(RetType::raw_type()) -> proper_types:type()

Equivalent to function(3, RetType).

function4/1

function4(RetType::raw_type()) -> proper_types:type()

Equivalent to function(4, RetType).

int/0

int() -> proper_types:type()

Small integers (bound by the current value of the size parameter). Instances shrink towards 0.

integer/0

integer() -> proper_types:type()

Equivalent to integer(inf, inf).

integer/2

integer(Low::extint(), High::extint()) -> proper_types:type()

All integers between Low and High, bounds included. Low and High must be Erlang expressions that evaluate to integers, with Low =< High. Additionally, Low and High may have the value inf, in which case they represent minus infinity and plus infinity respectively. Instances shrink towards 0 if Low =< 0 =< High, or towards the bound with the smallest absolute value otherwise.

largeint/0

largeint() -> proper_types:type()

Equivalent to integer().

list/0

list() -> proper_types:type()

Equivalent to list(any()).

list/1

list(ElemType::raw_type()) -> proper_types:type()

All lists containing elements of type ElemType. Instances shrink towards the empty list, [].

loose_tuple/1

loose_tuple(ElemType::raw_type()) -> proper_types:type()

Tuples whose elements are all of type ElemType. Instances shrink towards the 0-size tuple, {}.

map/0

map() -> proper_types:type()

A map associating keys and values of unspecified types (of any term()).

map/2

map(K::raw_type(), V::raw_type()) -> proper_types:type()

A map whose keys are defined by the generator K and values by the generator V.

nat/0

nat() -> proper_types:type()

Small non-negative integers (bound by the current value of the size parameter). Instances shrink towards 0.

neg_integer/0

neg_integer() -> proper_types:type()

Equivalent to integer(inf, -1).

nil/0

nil() -> proper_types:type()

Equivalent to exactly([]).

non_empty/1

non_empty(ListType::raw_type()) -> proper_types:type()

This is a predefined constraint that can be applied to random-length list and binary types to ensure that the produced values are never empty.

e.g. list/0, string/0, binary/0)

non_neg_float/0

non_neg_float() -> proper_types:type()

Equivalent to float(0.0, inf).

non_neg_integer/0

non_neg_integer() -> proper_types:type()

Equivalent to integer(0, inf).

noshrink/1

noshrink(Type::raw_type()) -> proper_types:type()

Creates a new type which is equivalent to Type, but whose instances are never shrunk by the shrinking subsystem.

number/0

number() -> proper_types:type()

Equivalent to union([integer(), float()]).

oneof/1

oneof(Choices::[raw_type(), ...]) -> proper_types:type()

Equivalent to union(Choices).

orderedlist/1

orderedlist(ElemType::raw_type()) -> proper_types:type()

All sorted lists containing elements of type ElemType. Instances shrink towards the empty list, [].

parameter/1

parameter(Parameter::atom()) -> value()

Equivalent to parameter(Parameter, undefined).

parameter/2

parameter(Parameter::atom(), Default::value()) -> value()

Returns the value associated with Parameter, or Default in case Parameter is not associated with any value.

pos_integer/0

pos_integer() -> proper_types:type()

Equivalent to integer(1, inf).

range/2

range(Low::extint(), High::extint()) -> proper_types:type()

Equivalent to integer(Low, High).

real/0

real() -> proper_types:type()

Equivalent to float().

resize/2

resize(NewSize::proper_gen:size(), Type::raw_type()) -> proper_types:type()

Overrides the size parameter used when generating instances of Type with NewSize. Has no effect on size-less types, such as unions. Also, this will not affect the generation of any internal types contained in Type, such as the elements of a list - those will still be generated using the test-wide value of size. One use of this function is to modify types to produce instances that grow faster or slower, like so:

     ?SIZED(Size, resize(Size * 2, list(integer()))
The above specifies a list type that grows twice as fast as normal lists.

return/1

return(E::term()) -> proper_types:type()

Equivalent to exactly(E).

shrink_list/1

shrink_list(List::[term()]) -> proper_types:type()

A type that generates exactly the list List. Instances shrink towards shorter sublists of the original list.

string/0

string() -> proper_types:type()

Equivalent to list(char()).

term/0

term() -> proper_types:type()

Equivalent to any().

timeout/0

timeout() -> proper_types:type()

Equivalent to union([non_neg_integer() | infinity]).

tuple/0

tuple() -> proper_types:type()

Equivalent to loose_tuple(any()).

tuple/1

tuple(ListOfTypes::[raw_type()]) -> proper_types:type()

All tuples whose i-th element is an instance of the type at index i of ListOfTypes. Also written simply as a tuple of types.

union/1

union(ListOfTypes::[raw_type(), ...]) -> proper_types:type()

The union of all types in ListOfTypes. ListOfTypes can't be empty. The random instance generator is equally likely to choose any one of the types in ListOfTypes. The shrinking subsystem will always try to shrink an instance of a type union to an instance of the first type in ListOfTypes, thus you should write the simplest case first.

vector/2

vector(Len::length(), ElemType::raw_type()) -> proper_types:type()

All lists of length Len containing elements of type ElemType. Len must be an Erlang expression that evaluates to a non-negative integer.

weighted_default/2

weighted_default(Default::{frequency(), raw_type()}, Type::{frequency(), raw_type()}) -> proper_types:type()

A specialization of default/2, where Default and Type are assigned weights to be considered by the random instance generator. The shrinking subsystem will ignore the weights and try to shrink using the default value.

weighted_union/1

weighted_union(ListOfTypes::[{frequency(), raw_type()}, ...]) -> proper_types:type()

A specialization of union/1, where each type in ListOfTypes is assigned a frequency. Frequencies must be Erlang expressions that evaluate to non-negative integers. Types with larger frequencies are more likely to be chosen by the random instance generator. The shrinking subsystem will ignore the frequencies and try to shrink towards the first type in the list with a non-zero frequency.

with_parameter/3

with_parameter(Parameter::atom(), Value::value(), Type::raw_type()) -> proper_types:type()

Associates the atom key Parameter with the value Value while generating instances of Type.

with_parameters/2

with_parameters(PVlist::[{atom(), value()}], Type::raw_type()) -> proper_types:type()

Similar to with_parameter/3, but accepts a list of {Parameter, Value} pairs.

wunion/1

wunion(FreqChoices::[{frequency(), raw_type()}, ...]) -> proper_types:type()

Equivalent to weighted_union(FreqChoices).


Generated by EDoc