krestenkrab / triq

Trifork QuickCheck
http://krestenkrab.github.com/triq/
Apache License 2.0
281 stars 54 forks source link

Limit list() length #39

Closed essen closed 9 years ago

essen commented 9 years ago

Me again,

I was looking today at how to limit generated list length, and it seems the current answer is "I can't". This is problematic, as I end up generating input data that is much much larger than I expect the function to take (due to limits defined elsewhere), and this makes some tests take forever. I can use ?SUCHTHAT to limit the length, but it ends up being slower because Triq just generates until it finds a value that matches.

The other issue with list length is that to generate a string of 1 to 8 characters I ended up writing this:

language_tag() ->
    oneof([
        [alpha()],
        [alpha(), alpha()],
        [alpha(), alpha(), alpha()],
        [alpha(), alpha(), alpha(), alpha()],
        [alpha(), alpha(), alpha(), alpha(), alpha()],
        [alpha(), alpha(), alpha(), alpha(), alpha(), alpha()],
        [alpha(), alpha(), alpha(), alpha(), alpha(), alpha(), alpha()],
        [alpha(), alpha(), alpha(), alpha(), alpha(), alpha(), alpha(), alpha()]
    ]).

What I would like to write is something like:

language_tag() ->
    non_empty(list(alpha(), 8)).

Or:

language_tag() ->
    list(alpha(), 1, 8).

Thoughts?

krestenkrab commented 9 years ago

You should be able to use ?SIZED(8, int() ) to get an int value no bigger than 8.

essen commented 9 years ago

I tried something like this:

alpha_chars() -> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".
alpha() -> oneof(alpha_chars()).

prop_language_tag() ->
    ?FORALL(T, ?SIZED(8, list(alpha())), begin io:format("~p~n", [T]), true end).

But I get a crash:

{"init terminating in do_boot",{function_clause,[{cow_http_hd,'-prop_language_tag/0-fun-0-',[2],[{file,"src/cow_http_hd.erl"},{line,671}]},{triq_dom,'-sized/1-fun-0-',2,[{file,"src/triq_dom.erl"},{line,1045}]},{triq,check_forall,6,[{file,"src/triq.erl"},{line,251}]},{triq,check,3,[{file,"src/triq.erl"},{line,335}]},{triq,all,2,[{file,"src/triq.erl"},{line,273}]},{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,657}]},{erl_eval,eval_lc1,6,[{file,"erl_eval.erl"},{line,683}]},{erl_eval,eval_generate,7,[{file,"erl_eval.erl"},{line,712}]}]}}

I get the same crash if I try alpha() instead of list(alpha()) so I assumed I just didn't understand how ?SIZED worked. (And I probably don't; the one test with ?SIZED is also confusing me.)

essen commented 9 years ago

Trying the following property based on your previous comment:

prop_sized_int() ->
    ?FORALL(I, ?SIZED(8, int()), begin io:format("~p~n", [I]), true end).

And I get the following result:

triq_tests: run_property_testing_test_...*failed*
in function triq_tests:'-prop_sized_int/0-fun-0-'/1 (test/triq_tests.erl, line 106)
  called as '-prop_sized_int/0-fun-0-'(2)
in call from triq_dom:'-sized/1-fun-0-'/2 (src/triq_dom.erl, line 1045)
in call from triq:check_forall/6 (src/triq.erl, line 247)
in call from triq:check/3 (src/triq.erl, line 331)
in call from triq:all/2 (src/triq.erl, line 269)
in call from triq_tests:run_property_testing_case/0 (test/triq_tests.erl, line 241)
**error:function_clause

Also tried a ?SIZED(S, int(S)) which works but doesn't allow me to limit the size like I want.

It seems to me like ?SIZED is made to allow determining a size when generating custom data structures, and not to allow limiting to a maximum size.

essen commented 9 years ago

I suppose it is possible with a recursive function like (pseudo-code):

prop_char_list() -> ?FORALL(I, ?SIZED(S, char_list(min(S, 255))), ...
char_list(0) -> [];
char_list(N) -> [char()|char_list(N - 1)].

But it would be nicer if I could just do a list(char(), 255) directly.

essen commented 9 years ago

Ah, it looks like I was looking for the vector/2 generator. I will try, close the ticket and apologize for all the noise if this is it. :-)

essen commented 9 years ago

Yep looks like the following does exactly what I want:

vector(Min, Max, Dom) ->
    ?LET(N, choose(Min, Max), vector(N, Dom)).

So sorry about all the noise, but thanks as I learnt quite a bunch there. :-)

Closing!