|
|
@ -0,0 +1,157 @@ |
|
|
|
%% ------------------------------------------------------------------- |
|
|
|
%% |
|
|
|
%% trunc_io_eqc: QuickCheck test for trunc_io:format with maxlen |
|
|
|
%% |
|
|
|
%% Copyright (c) 2007-2011 Basho Technologies, Inc. All Rights Reserved. |
|
|
|
%% |
|
|
|
%% This file is provided to you under the Apache License, |
|
|
|
%% Version 2.0 (the "License"); you may not use this file |
|
|
|
%% except in compliance with the License. You may obtain |
|
|
|
%% a copy of the License at |
|
|
|
%% |
|
|
|
%% http://www.apache.org/licenses/LICENSE-2.0 |
|
|
|
%% |
|
|
|
%% Unless required by applicable law or agreed to in writing, |
|
|
|
%% software distributed under the License is distributed on an |
|
|
|
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
|
|
|
%% KIND, either express or implied. See the License for the |
|
|
|
%% specific language governing permissions and limitations |
|
|
|
%% under the License. |
|
|
|
%% |
|
|
|
%% ------------------------------------------------------------------- |
|
|
|
-module(trunc_io_eqc). |
|
|
|
|
|
|
|
-ifdef(TEST). |
|
|
|
-ifdef(EQC). |
|
|
|
-export([test/0, test/1, check/0]). |
|
|
|
|
|
|
|
-include_lib("eqc/include/eqc.hrl"). |
|
|
|
-include_lib("eunit/include/eunit.hrl"). |
|
|
|
|
|
|
|
-define(QC_OUT(P), |
|
|
|
eqc:on_output(fun(Str, Args) -> io:format(user, Str, Args) end, P)). |
|
|
|
|
|
|
|
%%==================================================================== |
|
|
|
%% eunit test |
|
|
|
%%==================================================================== |
|
|
|
|
|
|
|
eqc_test_() -> |
|
|
|
{spawn, |
|
|
|
[?_assertEqual(true, quickcheck(numtests(500, ?QC_OUT(prop_format()))))] |
|
|
|
}. |
|
|
|
|
|
|
|
%%==================================================================== |
|
|
|
%% Shell helpers |
|
|
|
%%==================================================================== |
|
|
|
|
|
|
|
test() -> |
|
|
|
test(100). |
|
|
|
|
|
|
|
test(N) -> |
|
|
|
quickcheck(numtests(N, prop_format())). |
|
|
|
|
|
|
|
check() -> |
|
|
|
check(prop_format(), current_counterexample()). |
|
|
|
|
|
|
|
%%==================================================================== |
|
|
|
%% Generators |
|
|
|
%%==================================================================== |
|
|
|
|
|
|
|
gen_fmt_args() -> |
|
|
|
list(oneof([gen_print_str(), |
|
|
|
{"~p", gen_any(5)}, |
|
|
|
{"~w", gen_any(5)}, |
|
|
|
{"~s", gen_print_str()} |
|
|
|
])). |
|
|
|
|
|
|
|
|
|
|
|
%% Generates a printable string |
|
|
|
gen_print_str() -> |
|
|
|
?LET(Xs, list(char()), [X || X <- Xs, io_lib:printable_list([X]), X /= $~]). |
|
|
|
|
|
|
|
gen_any(MaxDepth) -> |
|
|
|
oneof([largeint(), |
|
|
|
gen_atom(), |
|
|
|
nat(), |
|
|
|
binary(), |
|
|
|
gen_pid(), |
|
|
|
gen_port(), |
|
|
|
gen_ref(), |
|
|
|
gen_fun()] ++ |
|
|
|
[?LAZY(list(gen_any(MaxDepth - 1))) || MaxDepth /= 0] ++ |
|
|
|
[?LAZY(gen_tuple(gen_any(MaxDepth - 1))) || MaxDepth /= 0]). |
|
|
|
|
|
|
|
gen_atom() -> |
|
|
|
elements([abc, def, ghi]). |
|
|
|
|
|
|
|
gen_tuple(Gen) -> |
|
|
|
?LET(Xs, list(Gen), list_to_tuple(Xs)). |
|
|
|
|
|
|
|
gen_max_len() -> %% Generate length from 3 to whatever. Needs space for ... in output |
|
|
|
?LET(Xs, int(), 3 + abs(Xs)). |
|
|
|
|
|
|
|
gen_pid() -> |
|
|
|
?LAZY(spawn(fun() -> ok end)). |
|
|
|
|
|
|
|
gen_port() -> |
|
|
|
?LAZY(begin |
|
|
|
Port = erlang:open_port({spawn, "true"}, []), |
|
|
|
erlang:port_close(Port), |
|
|
|
Port |
|
|
|
end). |
|
|
|
|
|
|
|
gen_ref() -> |
|
|
|
?LAZY(make_ref()). |
|
|
|
|
|
|
|
gen_fun() -> |
|
|
|
?LAZY(fun() -> ok end). |
|
|
|
|
|
|
|
%%==================================================================== |
|
|
|
%% Property |
|
|
|
%%==================================================================== |
|
|
|
|
|
|
|
%% Checks that trunc_io:format produces output less than or equal to MaxLen |
|
|
|
prop_format() -> |
|
|
|
?FORALL({FmtArgs, MaxLen}, {gen_fmt_args(), gen_max_len()}, |
|
|
|
begin |
|
|
|
{FmtStr, Args} = build_fmt_args(FmtArgs), |
|
|
|
try |
|
|
|
Str = lists:flatten(trunc_io:format(FmtStr, Args, MaxLen)), |
|
|
|
?WHENFAIL(begin |
|
|
|
io:format("FmtStr: ~p\n", [FmtStr]), |
|
|
|
io:format("Args: ~p\n", [Args]), |
|
|
|
io:format("MaxLen: ~p\n", [MaxLen]), |
|
|
|
io:format("ActLen: ~p\n", [length(Str)]), |
|
|
|
io:format("Str: ~p\n", [Str]) |
|
|
|
end, |
|
|
|
%% Make sure the result is a printable list |
|
|
|
%% and if the format string is less than the length, |
|
|
|
%% the result string is less than the length. |
|
|
|
conjunction([{printable, Str == "" orelse |
|
|
|
io_lib:printable_list(Str)}, |
|
|
|
{length, length(FmtStr) > MaxLen orelse |
|
|
|
length(Str) =< MaxLen}])) |
|
|
|
catch |
|
|
|
_:Err -> |
|
|
|
io:format(user, "\nException: ~p\n", [Err]), |
|
|
|
io:format("FmtStr: ~p\n", [FmtStr]), |
|
|
|
io:format("Args: ~p\n", [Args]), |
|
|
|
false |
|
|
|
end |
|
|
|
end). |
|
|
|
|
|
|
|
%%==================================================================== |
|
|
|
%% Internal helpers |
|
|
|
%%==================================================================== |
|
|
|
|
|
|
|
%% Build a tuple of {Fmt, Args} from a gen_fmt_args() return |
|
|
|
build_fmt_args(FmtArgs) -> |
|
|
|
F = fun({Fmt, Arg}, {FmtStr0, Args0}) -> |
|
|
|
{FmtStr0 ++ Fmt, Args0 ++ [Arg]}; |
|
|
|
(Str, {FmtStr0, Args0}) -> |
|
|
|
{FmtStr0 ++ Str, Args0} |
|
|
|
end, |
|
|
|
lists:foldl(F, {"", []}, FmtArgs). |
|
|
|
|
|
|
|
-endif. % (TEST). |
|
|
|
-endif. % (EQC). |