Erlang Central

Generate Unique Values

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Generating Unique Values

How to write a generator that produces unique values?

Normally, if you need unique values, there is some notion of 'state', only when there is state, it is important that a value differs from a previous value. For example, if you send a sequence of messages to a server and each message needs a unique tag, different from previous tags. The server 'remembers' the state and if you want to perform positive testing, you may not want to send the same tag twice.

It may be worth considering to just create a deterministic list and take consequtive values from that list.

```unique() ->
lists:seq(0,100).
```

More advanced, if you do not use integers as values, you could create the list and filter out the values that occur more than once.

```unique(Generator) ->
?LET(Values,list(Generator),
here_you_filter_function(Values)).
```

Note that efficiency is no issue in test value generation!

What if one wants to create a fixed amount of unique values, say a vector of length N. Once again, you may be happy with lists:seq(1,N), if you have are happy with integers. You can even write a function from integers to your actual value that generates a unique value depending on your input.

Other approach is to define a recursive generator.

```uvector(0,Gen) ->
[];
uvector(N,Gen) ->
?LET(Values,uvector(N-1,Gen),
?LET(Value,?SUCHTHAT(V,Gen, not lists:member(V,Values)),
[Value|Values])).
```

A simple use of this generator could be to create unique integers or to fail on a unique vector of booleans.

```9> eqc_gen:sample(example:uvector(16,eqc_gen:int())).
[-9,9,-7,-8,8,-5,2,-3,0,4,-6,6,10,-1,5,1]
[9,12,3,1,0,7,2,-9,-11,4,-2,11,-10,8,-3,10]
[13,-11,5,12,-1,10,-2,0,-10,-6,-7,3,-3,6,9,11]
[-10,9,-4,-13,1,-12,10,13,-6,-7,-14,6,-8,-11,2,-1]
[8,-2,9,-1,-11,-13,6,-8,3,15,4,-14,-7,-5,2,-3]
[-4,16,3,2,1,-13,5,0,-10,6,4,9,14,-8,-1,12]
[16,7,-5,14,-16,5,9,-10,-15,11,3,10,-2,-8,-6,-12]
[9,17,-9,-16,-3,3,-12,-13,8,7,-15,2,-5,15,13,-8]
[6,-7,18,-12,-16,-3,-17,-5,2,-6,16,4,3,11,-13,14]
[-6,18,19,20,-17,9,-14,1,15,-1,-4,-11,2,5,-18,8]
[-18,7,-7,-21,10,19,-16,-3,4,-11,3,-15,-12,-5,15,-2]
ok
10> eqc_gen:sample(example:uvector(4,eqc_gen:bool())).
** exception exit: "?SUCHTHAT failed to find a value within 100 attempts."
in function  eqc_gen:sample/1
```