Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

157 Zeilen
5.3 KiB

  1. %% -------------------------------------------------------------------
  2. %%
  3. %% trunc_io_eqc: QuickCheck test for trunc_io:format with maxlen
  4. %%
  5. %% Copyright (c) 2007-2011 Basho Technologies, Inc. All Rights Reserved.
  6. %%
  7. %% This file is provided to you under the Apache License,
  8. %% Version 2.0 (the "License"); you may not use this file
  9. %% except in compliance with the License. You may obtain
  10. %% a copy of the License at
  11. %%
  12. %% http://www.apache.org/licenses/LICENSE-2.0
  13. %%
  14. %% Unless required by applicable law or agreed to in writing,
  15. %% software distributed under the License is distributed on an
  16. %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17. %% KIND, either express or implied. See the License for the
  18. %% specific language governing permissions and limitations
  19. %% under the License.
  20. %%
  21. %% -------------------------------------------------------------------
  22. -module(trunc_io_eqc).
  23. -ifdef(TEST).
  24. -ifdef(EQC).
  25. -export([test/0, test/1, check/0]).
  26. -include_lib("eqc/include/eqc.hrl").
  27. -include_lib("eunit/include/eunit.hrl").
  28. -define(QC_OUT(P),
  29. eqc:on_output(fun(Str, Args) -> io:format(user, Str, Args) end, P)).
  30. %%====================================================================
  31. %% eunit test
  32. %%====================================================================
  33. eqc_test_() ->
  34. {spawn,
  35. [?_assertEqual(true, quickcheck(numtests(500, ?QC_OUT(prop_format()))))]
  36. }.
  37. %%====================================================================
  38. %% Shell helpers
  39. %%====================================================================
  40. test() ->
  41. test(100).
  42. test(N) ->
  43. quickcheck(numtests(N, prop_format())).
  44. check() ->
  45. check(prop_format(), current_counterexample()).
  46. %%====================================================================
  47. %% Generators
  48. %%====================================================================
  49. gen_fmt_args() ->
  50. list(oneof([gen_print_str(),
  51. {"~p", gen_any(5)},
  52. {"~w", gen_any(5)},
  53. {"~s", gen_print_str()}
  54. ])).
  55. %% Generates a printable string
  56. gen_print_str() ->
  57. ?LET(Xs, list(char()), [X || X <- Xs, io_lib:printable_list([X]), X /= $~]).
  58. gen_any(MaxDepth) ->
  59. oneof([largeint(),
  60. gen_atom(),
  61. nat(),
  62. binary(),
  63. gen_pid(),
  64. gen_port(),
  65. gen_ref(),
  66. gen_fun()] ++
  67. [?LAZY(list(gen_any(MaxDepth - 1))) || MaxDepth /= 0] ++
  68. [?LAZY(gen_tuple(gen_any(MaxDepth - 1))) || MaxDepth /= 0]).
  69. gen_atom() ->
  70. elements([abc, def, ghi]).
  71. gen_tuple(Gen) ->
  72. ?LET(Xs, list(Gen), list_to_tuple(Xs)).
  73. gen_max_len() -> %% Generate length from 3 to whatever. Needs space for ... in output
  74. ?LET(Xs, int(), 3 + abs(Xs)).
  75. gen_pid() ->
  76. ?LAZY(spawn(fun() -> ok end)).
  77. gen_port() ->
  78. ?LAZY(begin
  79. Port = erlang:open_port({spawn, "true"}, []),
  80. erlang:port_close(Port),
  81. Port
  82. end).
  83. gen_ref() ->
  84. ?LAZY(make_ref()).
  85. gen_fun() ->
  86. ?LAZY(fun() -> ok end).
  87. %%====================================================================
  88. %% Property
  89. %%====================================================================
  90. %% Checks that trunc_io:format produces output less than or equal to MaxLen
  91. prop_format() ->
  92. ?FORALL({FmtArgs, MaxLen}, {gen_fmt_args(), gen_max_len()},
  93. begin
  94. {FmtStr, Args} = build_fmt_args(FmtArgs),
  95. try
  96. Str = lists:flatten(trunc_io:format(FmtStr, Args, MaxLen)),
  97. ?WHENFAIL(begin
  98. io:format("FmtStr: ~p\n", [FmtStr]),
  99. io:format("Args: ~p\n", [Args]),
  100. io:format("MaxLen: ~p\n", [MaxLen]),
  101. io:format("ActLen: ~p\n", [length(Str)]),
  102. io:format("Str: ~p\n", [Str])
  103. end,
  104. %% Make sure the result is a printable list
  105. %% and if the format string is less than the length,
  106. %% the result string is less than the length.
  107. conjunction([{printable, Str == "" orelse
  108. io_lib:printable_list(Str)},
  109. {length, length(FmtStr) > MaxLen orelse
  110. length(Str) =< MaxLen}]))
  111. catch
  112. _:Err ->
  113. io:format(user, "\nException: ~p\n", [Err]),
  114. io:format("FmtStr: ~p\n", [FmtStr]),
  115. io:format("Args: ~p\n", [Args]),
  116. false
  117. end
  118. end).
  119. %%====================================================================
  120. %% Internal helpers
  121. %%====================================================================
  122. %% Build a tuple of {Fmt, Args} from a gen_fmt_args() return
  123. build_fmt_args(FmtArgs) ->
  124. F = fun({Fmt, Arg}, {FmtStr0, Args0}) ->
  125. {FmtStr0 ++ Fmt, Args0 ++ [Arg]};
  126. (Str, {FmtStr0, Args0}) ->
  127. {FmtStr0 ++ Str, Args0}
  128. end,
  129. lists:foldl(F, {"", []}, FmtArgs).
  130. -endif. % (TEST).
  131. -endif. % (EQC).