Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 502 lines (441 sloc) 20.784 kB
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
1 %% ``The contents of this file are subject to the Erlang Public License,
2 %% Version 1.1, (the "License"); you may not use this file except in
3 %% compliance with the License. You should have received a copy of the
4 %% Erlang Public License along with your Erlang distribution. If not, it can be
5 %% retrieved via the world wide web at http://www.erlang.org/.
6 %%
7 %% Software distributed under the License is distributed on an "AS IS"
8 %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9 %% the License for the specific language governing rights and limitations
10 %% under the License.
11 %%
12 %% The Initial Developer of the Original Code is Corelatus AB.
13 %% Portions created by Corelatus are Copyright 2003, Corelatus
14 %% AB. All Rights Reserved.''
15 %%
16 %% @doc Module to print out terms for logging. Limits by length rather than depth.
17 %%
18 %% The resulting string may be slightly larger than the limit; the intention
19 %% is to provide predictable CPU and memory consumption for formatting
20 %% terms, not produce precise string lengths.
21 %%
22 %% Typical use:
23 %%
24 %% trunc_io:print(Term, 500).
25 %%
26 %% Source license: Erlang Public License.
27 %% Original author: Matthias Lang, <tt>matthias@corelatus.se</tt>
4ac0137 @Vagabond Rename trunc_io to lager_trunc_io to prevent clashes
Vagabond authored
28 %%
29 %% Various changes to this module, most notably the format/3 implementation
6a8403f @Vagabond Fix edoc generation
Vagabond authored
30 %% were added by Andrew Thompson `<andrew@basho.com>'. The module has been renamed
4ac0137 @Vagabond Rename trunc_io to lager_trunc_io to prevent clashes
Vagabond authored
31 %% to avoid conflicts with the vanilla module.
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
32
4ac0137 @Vagabond Rename trunc_io to lager_trunc_io to prevent clashes
Vagabond authored
33 -module(lager_trunc_io).
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
34 -author('matthias@corelatus.se').
35 %% And thanks to Chris Newcombe for a bug fix
3311702 @Vagabond Add builtin chomping to lager_format
Vagabond authored
36 -export([format/3, format/4, print/2, print/3, fprint/2, fprint/3, safe/2]). % interface functions
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
37 -version("$Id: trunc_io.erl,v 1.11 2009-02-23 12:01:06 matthias Exp $").
38
03d3fa1 @Vagabond Fixes and tests for deep-list handling in trunc_io:format
Vagabond authored
39 -ifdef(TEST).
40 -export([perf/0, perf/3, perf1/0, test/0, test/2]). % testing functions
41 -include_lib("eunit/include/eunit.hrl").
42 -endif.
43
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
44 -record(print_options, {
45 %% negative depth means no depth limiting
46 depth = -1 :: integer(),
47 %% whether to print lists as strings, if possible
31d9529 @Vagabond Default to treating lists as strings, (and set it false for ~w)
Vagabond authored
48 lists_as_strings = true :: boolean(),
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
49 %% force strings, or binaries to be printed as a string,
50 %% even if they're not printable
51 force_strings = false :: boolean()
52 }).
53
e45d5bc @Vagabond Implement an alternative and much faster lager_trunc_io:format/3
Vagabond authored
54 format(Fmt, Args, Max) ->
3311702 @Vagabond Add builtin chomping to lager_format
Vagabond authored
55 format(Fmt, Args, Max, []).
56
57 format(Fmt, Args, Max, Options) ->
58 try lager_format:format(Fmt, Args, Max, Options) of
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
59 Result -> Result
60 catch
61 _:_ ->
62 erlang:error(badarg, [Fmt, Args])
63 end.
37f190f @Vagabond Try to give more equal allocations to large terms
Vagabond authored
64
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
65 %% @doc Returns an flattened list containing the ASCII representation of the given
66 %% term.
67 -spec fprint(term(), pos_integer()) -> string().
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
68 fprint(Term, Max) ->
69 fprint(Term, Max, []).
70
71
72 %% @doc Returns an flattened list containing the ASCII representation of the given
73 %% term.
74 -spec fprint(term(), pos_integer(), #print_options{}) -> string().
75 fprint(T, Max, Options) ->
76 {L, _} = print(T, Max, prepare_options(Options, #print_options{})),
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
77 lists:flatten(L).
78
79 %% @doc Same as print, but never crashes.
80 %%
81 %% This is a tradeoff. Print might conceivably crash if it's asked to
82 %% print something it doesn't understand, for example some new data
83 %% type in a future version of Erlang. If print crashes, we fall back
84 %% to io_lib to format the term, but then the formatting is
85 %% depth-limited instead of length limited, so you might run out
86 %% memory printing it. Out of the frying pan and into the fire.
87 %%
88 -spec safe(term(), pos_integer()) -> {string(), pos_integer()} | {string()}.
89 safe(What, Len) ->
90 case catch print(What, Len) of
91 {L, Used} when is_list(L) -> {L, Used};
92 _ -> {"unable to print" ++ io_lib:write(What, 99)}
93 end.
94
95 %% @doc Returns {List, Length}
96 -spec print(term(), pos_integer()) -> {iolist(), pos_integer()}.
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
97 print(Term, Max) ->
98 print(Term, Max, []).
99
100 %% @doc Returns {List, Length}
101 -spec print(term(), pos_integer(), #print_options{}) -> {iolist(), pos_integer()}.
102 print(Term, Max, Options) when is_list(Options) ->
103 %% need to convert the proplist to a record
104 print(Term, Max, prepare_options(Options, #print_options{}));
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
105
106 print(Term, _Max, #print_options{force_strings=true}) when not is_list(Term), not is_binary(Term), not is_atom(Term) ->
107 erlang:error(badarg);
108
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
109 print(_, Max, _Options) when Max < 0 -> {"...", 3};
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
110 print(_, _, #print_options{depth=0}) -> {"...", 3};
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
111
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
112 print(Tuple, Max, Options) when is_tuple(Tuple) ->
113 {TC, Len} = tuple_contents(Tuple, Max-2, Options),
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
114 {[${, TC, $}], Len + 2};
115
116 %% @doc We assume atoms, floats, funs, integers, PIDs, ports and refs never need
117 %% to be truncated. This isn't strictly true, someone could make an
118 %% arbitrarily long bignum. Let's assume that won't happen unless someone
119 %% is being malicious.
120 %%
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
121 print(Atom, _Max, #print_options{force_strings=NoQuote}) when is_atom(Atom) ->
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
122 L = atom_to_list(Atom),
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
123 R = case atom_needs_quoting_start(L) andalso not NoQuote of
3babca1 @Vagabond Make sure atoms needing quoting are quoted.
Vagabond authored
124 true -> lists:flatten([$', L, $']);
125 false -> L
126 end,
127 {R, length(R)};
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
128
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
129 print(<<>>, _Max, _Options) ->
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
130 {"<<>>", 4};
131
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
132 print(Binary, 0, _Options) when is_binary(Binary) ->
71fae1b @Vagabond Truncator for funs; special case binary truncation when max is 0
Vagabond authored
133 {"<<..>>", 6};
134
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
135 print(Binary, Max, Options) when is_binary(Binary) ->
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
136 B = binary_to_list(Binary, 1, lists:min([Max, size(Binary)])),
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
137 {L, Len} = case Options#print_options.lists_as_strings orelse
138 Options#print_options.force_strings of
139 true ->
140 alist_start(B, Max-4, Options);
141 _ ->
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
142 list_body(B, Max-4, Options, false)
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
143 end,
7e9da64 @Vagabond Several fixes for printing binaries, improve quote stripping
Vagabond authored
144 {Res, Length} = case L of
145 [91, X, 93] ->
146 {X, Len - 2};
147 X ->
148 {X, Len}
149 end,
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
150 case Options#print_options.force_strings of
151 true ->
152 {Res, Length};
153 _ ->
154 {["<<", Res, ">>"], Length+4}
155 end;
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
156
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
157 print(Float, _Max, _Options) when is_float(Float) ->
9a577df @Vagabond Use the io_lib_format:fwrite_g function to print floats
Vagabond authored
158 %% use the same function io_lib:format uses to print floats
159 %% float_to_list is way too verbose.
160 L = io_lib_format:fwrite_g(Float),
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
161 {L, length(L)};
162
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
163 print(Fun, Max, _Options) when is_function(Fun) ->
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
164 L = erlang:fun_to_list(Fun),
71fae1b @Vagabond Truncator for funs; special case binary truncation when max is 0
Vagabond authored
165 case length(L) > Max of
166 true ->
167 S = erlang:max(5, Max),
168 Res = string:substr(L, 1, S) ++ "..>",
169 {Res, length(Res)};
170 _ ->
171 {L, length(L)}
172 end;
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
173
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
174 print(Integer, _Max, _Options) when is_integer(Integer) ->
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
175 L = integer_to_list(Integer),
176 {L, length(L)};
177
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
178 print(Pid, _Max, _Options) when is_pid(Pid) ->
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
179 L = pid_to_list(Pid),
180 {L, length(L)};
181
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
182 print(Ref, _Max, _Options) when is_reference(Ref) ->
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
183 L = erlang:ref_to_list(Ref),
184 {L, length(L)};
185
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
186 print(Port, _Max, _Options) when is_port(Port) ->
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
187 L = erlang:port_to_list(Port),
188 {L, length(L)};
189
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
190 print(List, Max, Options) when is_list(List) ->
9c6ce62 @Vagabond Fix some more formatting bugs
Vagabond authored
191 case Options#print_options.lists_as_strings orelse
192 Options#print_options.force_strings of
193 true ->
194 alist_start(List, Max, dec_depth(Options));
195 _ ->
196 {R, Len} = list_body(List, Max, dec_depth(Options), false),
197 {[$[, R, $]], Len + 2}
198 end.
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
199
200 %% Returns {List, Length}
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
201 tuple_contents(Tuple, Max, Options) ->
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
202 L = tuple_to_list(Tuple),
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
203 list_body(L, Max, dec_depth(Options), true).
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
204
205 %% Format the inside of a list, i.e. do not add a leading [ or trailing ].
206 %% Returns {List, Length}
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
207 list_body([], _Max, _Options, _Tuple) -> {[], 0};
208 list_body(_, Max, _Options, _Tuple) when Max < 4 -> {"...", 3};
209 list_body(_, _Max, #print_options{depth=0}, _Tuple) -> {"...", 3};
210 list_body([H|T], Max, Options, Tuple) ->
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
211 {List, Len} = print(H, Max, Options),
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
212 {Final, FLen} = list_bodyc(T, Max - Len, Options, Tuple),
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
213 {[List|Final], FLen + Len};
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
214 list_body(X, Max, Options, _Tuple) -> %% improper list
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
215 {List, Len} = print(X, Max - 1, Options),
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
216 {[$|,List], Len + 1}.
217
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
218 list_bodyc([], _Max, _Options, _Tuple) -> {[], 0};
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
219 list_bodyc(_, Max, _Options, _Tuple) when Max < 4 -> {",...", 3};
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
220 list_bodyc([H|T], Max, #print_options{depth=Depth} = Options, Tuple) ->
221 {List, Len} = print(H, Max, dec_depth(Options)),
222 {Final, FLen} = list_bodyc(T, Max - Len - 1, Options, Tuple),
223 Sep = case Depth == 1 andalso not Tuple of
224 true -> $|;
225 _ -> $,
226 end,
227 {[Sep, List|Final], FLen + Len + 1};
228 list_bodyc(X, Max, Options, _Tuple) -> %% improper list
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
229 {List, Len} = print(X, Max - 1, Options),
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
230 {[$|,List], Len + 1}.
231
232 %% The head of a list we hope is ascii. Examples:
233 %%
234 %% [65,66,67] -> "ABC"
235 %% [65,0,67] -> "A"[0,67]
236 %% [0,65,66] -> [0,65,66]
237 %% [65,b,66] -> "A"[b,66]
238 %%
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
239 alist_start([], _Max, #print_options{force_strings=true}) -> {"", 0};
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
240 alist_start([], _Max, _Options) -> {"[]", 2};
241 alist_start(_, Max, _Options) when Max < 4 -> {"...", 3};
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
242 alist_start(_, _Max, #print_options{depth=0}) -> {"[...]", 3};
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
243 alist_start(L, Max, #print_options{force_strings=true} = Options) ->
244 alist(L, Max, Options);
245 alist_start([H|T], Max, Options) when is_integer(H), H >= 16#20, H =< 16#7e -> % definitely printable
246 try alist([H|T], Max -1, Options) of
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
247 {L, Len} ->
248 {[$"|L], Len + 1}
249 catch
250 throw:unprintable ->
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
251 {R, Len} = list_body([H|T], Max-2, Options, false),
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
252 {[$[, R, $]], Len + 2}
253 end;
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
254 alist_start([H|T], Max, Options) when H =:= 9; H =:= 10; H =:= 13 ->
255 try alist([H|T], Max -1, Options) of
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
256 {L, Len} ->
257 {[$"|L], Len + 1}
258 catch
259 throw:unprintable ->
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
260 {R, Len} = list_body([H|T], Max-2, Options, false),
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
261 {[$[, R, $]], Len + 2}
262 end;
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
263 alist_start(L, Max, Options) ->
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
264 {R, Len} = list_body(L, Max-2, Options, false),
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
265 {[$[, R, $]], Len + 2}.
266
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
267 alist([], _Max, #print_options{force_strings=true}) -> {"", 0};
268 alist([], _Max, _Options) -> {"\"", 1};
269 alist(_, Max, #print_options{force_strings=true}) when Max < 4 -> {"...", 3};
270 alist(_, Max, #print_options{force_strings=false}) when Max < 5 -> {"...\"", 4};
271 alist([H|T], Max, Options) when is_integer(H), H >= 16#20, H =< 16#7e -> % definitely printable
272 {L, Len} = alist(T, Max-1, Options),
273 {[H|L], Len + 1};
274 alist([H|T], Max, Options) when H =:= 9; H =:= 10; H =:= 13 ->
275 {L, Len} = alist(T, Max-1, Options),
9c6ce62 @Vagabond Fix some more formatting bugs
Vagabond authored
276 case Options#print_options.force_strings of
277 true ->
278 {[H|L], Len + 1};
279 _ ->
280 {[escape(H)|L], Len + 1}
281 end;
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
282 alist([H|T], Max, #print_options{force_strings=true} = Options) when is_integer(H) ->
283 {L, Len} = alist(T, Max-1, Options),
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
284 {[H|L], Len + 1};
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
285 alist(_, _, #print_options{force_strings=true}) ->
286 error(badarg);
287 alist(_L, _Max, _Options) ->
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
288 throw(unprintable).
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
289
3babca1 @Vagabond Make sure atoms needing quoting are quoted.
Vagabond authored
290 %% is the first character in the atom alphabetic & lowercase?
291 atom_needs_quoting_start([H|T]) when H >= $a, H =< $z ->
292 atom_needs_quoting(T);
293 atom_needs_quoting_start(_) ->
294 true.
295
296 atom_needs_quoting([]) ->
297 false;
298 atom_needs_quoting([H|T]) when (H >= $a andalso H =< $z);
299 (H >= $A andalso H =< $Z);
300 H == $@; H == $_ ->
301 atom_needs_quoting(T);
302 atom_needs_quoting(_) ->
303 true.
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
304
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
305 prepare_options([], Options) ->
306 Options;
307 prepare_options([{depth, Depth}|T], Options) when is_integer(Depth) ->
308 prepare_options(T, Options#print_options{depth=Depth});
309 prepare_options([{lists_as_strings, Bool}|T], Options) when is_boolean(Bool) ->
310 prepare_options(T, Options#print_options{lists_as_strings = Bool});
311 prepare_options([{force_strings, Bool}|T], Options) when is_boolean(Bool) ->
312 prepare_options(T, Options#print_options{force_strings = Bool}).
313
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
314 dec_depth(#print_options{depth=Depth} = Options) when Depth > 0 ->
315 Options#print_options{depth=Depth-1};
316 dec_depth(Options) ->
317 Options.
7e9da64 @Vagabond Several fixes for printing binaries, improve quote stripping
Vagabond authored
318
9c6ce62 @Vagabond Fix some more formatting bugs
Vagabond authored
319 escape(9) -> "\\t";
320 escape(10) -> "\\n";
321 escape(13) -> "\\r".
322
03d3fa1 @Vagabond Fixes and tests for deep-list handling in trunc_io:format
Vagabond authored
323 -ifdef(TEST).
5bc97a9 @Vagabond Forgot to add trunc_io
Vagabond authored
324 %%--------------------
325 %% The start of a test suite. So far, it only checks for not crashing.
326 -spec test() -> ok.
327 test() ->
328 test(trunc_io, print).
329
330 -spec test(atom(), atom()) -> ok.
331 test(Mod, Func) ->
332 Simple_items = [atom, 1234, 1234.0, {tuple}, [], [list], "string", self(),
333 <<1,2,3>>, make_ref(), fun() -> ok end],
334 F = fun(A) ->
335 Mod:Func(A, 100),
336 Mod:Func(A, 2),
337 Mod:Func(A, 20)
338 end,
339
340 G = fun(A) ->
341 case catch F(A) of
342 {'EXIT', _} -> exit({failed, A});
343 _ -> ok
344 end
345 end,
346
347 lists:foreach(G, Simple_items),
348
349 Tuples = [ {1,2,3,a,b,c}, {"abc", def, 1234},
350 {{{{a},b,c,{d},e}},f}],
351
352 Lists = [ [1,2,3,4,5,6,7], lists:seq(1,1000),
353 [{a}, {a,b}, {a, [b,c]}, "def"], [a|b], [$a|$b] ],
354
355
356 lists:foreach(G, Tuples),
357 lists:foreach(G, Lists).
358
359 -spec perf() -> ok.
360 perf() ->
361 {New, _} = timer:tc(trunc_io, perf, [trunc_io, print, 1000]),
362 {Old, _} = timer:tc(trunc_io, perf, [io_lib, write, 1000]),
363 io:fwrite("New code took ~p us, old code ~p\n", [New, Old]).
364
365 -spec perf(atom(), atom(), integer()) -> done.
366 perf(M, F, Reps) when Reps > 0 ->
367 test(M,F),
368 perf(M,F,Reps-1);
369 perf(_,_,_) ->
370 done.
371
372 %% Performance test. Needs a particularly large term I saved as a binary...
373 -spec perf1() -> {non_neg_integer(), non_neg_integer()}.
374 perf1() ->
375 {ok, Bin} = file:read_file("bin"),
376 A = binary_to_term(Bin),
377 {N, _} = timer:tc(trunc_io, print, [A, 1500]),
378 {M, _} = timer:tc(io_lib, write, [A]),
379 {N, M}.
03d3fa1 @Vagabond Fixes and tests for deep-list handling in trunc_io:format
Vagabond authored
380
381 format_test() ->
382 %% simple format strings
383 ?assertEqual("foobar", lists:flatten(format("~s", [["foo", $b, $a, $r]], 50))),
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
384 ?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~p", [["foo", $b, $a, $r]], 50))),
385 ?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~P", [["foo", $b, $a, $r], 10], 50))),
9c6ce62 @Vagabond Fix some more formatting bugs
Vagabond authored
386 ?assertEqual("[[102,111,111],98,97,114]", lists:flatten(format("~w", [["foo", $b, $a, $r]], 50))),
03d3fa1 @Vagabond Fixes and tests for deep-list handling in trunc_io:format
Vagabond authored
387
388 %% complex ones
e45d5bc @Vagabond Implement an alternative and much faster lager_trunc_io:format/3
Vagabond authored
389 ?assertEqual(" foobar", lists:flatten(format("~10s", [["foo", $b, $a, $r]], 50))),
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
390 ?assertEqual(" [\"foo\",98,97,114]", lists:flatten(format("~22p", [["foo", $b, $a, $r]], 50))),
391 ?assertEqual(" [\"foo\",98,97,114]", lists:flatten(format("~22P", [["foo", $b, $a, $r], 10], 50))),
e45d5bc @Vagabond Implement an alternative and much faster lager_trunc_io:format/3
Vagabond authored
392 ?assertEqual("**********", lists:flatten(format("~10W", [["foo", $b, $a, $r], 10], 50))),
9c6ce62 @Vagabond Fix some more formatting bugs
Vagabond authored
393 ?assertEqual("[[102,111,111],98,97,114]", lists:flatten(format("~25W", [["foo", $b, $a, $r], 10], 50))),
03d3fa1 @Vagabond Fixes and tests for deep-list handling in trunc_io:format
Vagabond authored
394 ok.
395
9a577df @Vagabond Use the io_lib_format:fwrite_g function to print floats
Vagabond authored
396 atom_quoting_test() ->
397 ?assertEqual("hello", lists:flatten(format("~p", [hello], 50))),
398 ?assertEqual("'hello world'", lists:flatten(format("~p", ['hello world'], 50))),
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
399 ?assertEqual("'Hello world'", lists:flatten(format("~p", ['Hello world'], 50))),
9a577df @Vagabond Use the io_lib_format:fwrite_g function to print floats
Vagabond authored
400 ?assertEqual("hello_world", lists:flatten(format("~p", ['hello_world'], 50))),
401 ?assertEqual("'node@127.0.0.1'", lists:flatten(format("~p", ['node@127.0.0.1'], 50))),
402 ?assertEqual("node@nohost", lists:flatten(format("~p", [node@nohost], 50))),
403 ok.
404
405 sane_float_printing_test() ->
406 ?assertEqual("1.0", lists:flatten(format("~p", [1.0], 50))),
407 ?assertEqual("1.23456789", lists:flatten(format("~p", [1.23456789], 50))),
408 ?assertEqual("1.23456789", lists:flatten(format("~p", [1.234567890], 50))),
409 ?assertEqual("0.3333333333333333", lists:flatten(format("~p", [1/3], 50))),
410 ?assertEqual("0.1234567", lists:flatten(format("~p", [0.1234567], 50))),
411 ok.
412
af4ea7f @Vagabond Don't treat floats in a list as printable characters Reported by @bry…
Vagabond authored
413 float_inside_list_test() ->
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
414 ?assertEqual("[97,38.233913133184835,99]", lists:flatten(format("~p", [[$a, 38.233913133184835, $c]], 50))),
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
415 ?assertError(badarg, lists:flatten(format("~s", [[$a, 38.233913133184835, $c]], 50))),
af4ea7f @Vagabond Don't treat floats in a list as printable characters Reported by @bry…
Vagabond authored
416 ok.
417
a0440a9 @Vagabond Smarter doublequote stripping when printing strings with ~s
Vagabond authored
418 quote_strip_test() ->
419 ?assertEqual("\"hello\"", lists:flatten(format("~p", ["hello"], 50))),
420 ?assertEqual("hello", lists:flatten(format("~s", ["hello"], 50))),
421 ?assertEqual("hello", lists:flatten(format("~s", [hello], 50))),
422 ?assertEqual("hello", lists:flatten(format("~p", [hello], 50))),
7e9da64 @Vagabond Several fixes for printing binaries, improve quote stripping
Vagabond authored
423 ?assertEqual("'hello world'", lists:flatten(format("~p", ['hello world'], 50))),
424 ?assertEqual("hello world", lists:flatten(format("~s", ['hello world'], 50))),
425 ok.
426
427 binary_printing_test() ->
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
428 ?assertEqual("<<>>", lists:flatten(format("~p", [<<>>], 50))),
429 ?assertEqual("<<..>>", lists:flatten(format("~p", [<<"hi">>], 0))),
7e9da64 @Vagabond Several fixes for printing binaries, improve quote stripping
Vagabond authored
430 ?assertEqual("<<\"hello\">>", lists:flatten(format("~p", [<<$h, $e, $l, $l, $o>>], 50))),
431 ?assertEqual("<<\"hello\">>", lists:flatten(format("~p", [<<"hello">>], 50))),
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
432 ?assertEqual("<<104,101,108,108,111>>", lists:flatten(format("~w", [<<"hello">>], 50))),
7e9da64 @Vagabond Several fixes for printing binaries, improve quote stripping
Vagabond authored
433 ?assertEqual("<<1,2,3,4>>", lists:flatten(format("~p", [<<1, 2, 3, 4>>], 50))),
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
434 ?assertEqual([1,2,3,4], lists:flatten(format("~s", [<<1, 2, 3, 4>>], 50))),
7e9da64 @Vagabond Several fixes for printing binaries, improve quote stripping
Vagabond authored
435 ?assertEqual("hello", lists:flatten(format("~s", [<<"hello">>], 50))),
9c6ce62 @Vagabond Fix some more formatting bugs
Vagabond authored
436 ?assertEqual("hello\nworld", lists:flatten(format("~s", [<<"hello\nworld">>], 50))),
437 ?assertEqual("<<\"hello\\nworld\">>", lists:flatten(format("~p", [<<"hello\nworld">>], 50))),
e45d5bc @Vagabond Implement an alternative and much faster lager_trunc_io:format/3
Vagabond authored
438 ?assertEqual(" hello", lists:flatten(format("~10s", [<<"hello">>], 50))),
a0440a9 @Vagabond Smarter doublequote stripping when printing strings with ~s
Vagabond authored
439 ok.
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
440
441 list_printing_test() ->
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
442 ?assertEqual("[]", lists:flatten(format("~p", [[]], 50))),
443 ?assertEqual("[]", lists:flatten(format("~w", [[]], 50))),
444 ?assertEqual("", lists:flatten(format("~s", [[]], 50))),
445 ?assertEqual("...", lists:flatten(format("~s", [[]], -1))),
446 ?assertEqual("[[]]", lists:flatten(format("~p", [[[]]], 50))),
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
447 ?assertEqual("[13,11,10,8,5,4]", lists:flatten(format("~p", [[13,11,10,8,5,4]], 50))),
9c6ce62 @Vagabond Fix some more formatting bugs
Vagabond authored
448 ?assertEqual("\"\\rabc\"", lists:flatten(format("~p", [[13,$a, $b, $c]], 50))),
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
449 ?assertEqual("[1,2,3|4]", lists:flatten(format("~p", [[1, 2, 3|4]], 50))),
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
450 ?assertEqual("[...]", lists:flatten(format("~p", [[1, 2, 3,4]], 4))),
451 ?assertEqual("[1,...]", lists:flatten(format("~p", [[1, 2, 3,4]], 6))),
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
452 ?assertEqual("[1|4]", lists:flatten(format("~p", [[1|4]], 50))),
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
453 ?assertEqual("[1]", lists:flatten(format("~p", [[1]], 50))),
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
454 ?assertError(badarg, lists:flatten(format("~s", [[1|4]], 50))),
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
455 ?assertEqual("\"hello...\"", lists:flatten(format("~p", ["hello world"], 10))),
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
456 ?assertEqual("hello w...", lists:flatten(format("~s", ["hello world"], 10))),
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
457 ?assertEqual("hello world\r\n", lists:flatten(format("~s", ["hello world\r\n"], 50))),
458 ?assertEqual("\rhello world\r\n", lists:flatten(format("~s", ["\rhello world\r\n"], 50))),
9c6ce62 @Vagabond Fix some more formatting bugs
Vagabond authored
459 ?assertEqual("\"\\rhello world\\r\\n\"", lists:flatten(format("~p", ["\rhello world\r\n"], 50))),
460 ?assertEqual("[13,104,101,108,108,111,32,119,111,114,108,100,13,10]", lists:flatten(format("~w", ["\rhello world\r\n"], 60))),
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
461 ?assertEqual("...", lists:flatten(format("~s", ["\rhello world\r\n"], 3))),
9e735a7 @Vagabond Improve tests, fix some minor bugs
Vagabond authored
462 ok.
463
464 tuple_printing_test() ->
465 ?assertEqual("{}", lists:flatten(format("~p", [{}], 50))),
466 ?assertEqual("{}", lists:flatten(format("~w", [{}], 50))),
467 ?assertError(badarg, lists:flatten(format("~s", [{}], 50))),
468 ?assertEqual("{...}", lists:flatten(format("~p", [{foo}], 3))),
469 ?assertEqual("{foo,...}", lists:flatten(format("~p", [{foo,bar}], 6))),
470 ?assertEqual("{foo,bar}", lists:flatten(format("~p", [{foo,bar}], 9))),
5140cb3 @Vagabond Don't convert \r, etc to spaces, don't assume printablility by first …
Vagabond authored
471 ok.
e5b58fc @Vagabond Implement print options for trunc_io so ~s/~p/~w emulation is more ac…
Vagabond authored
472
473 unicode_test() ->
474 ?assertEqual([231,167,129], lists:flatten(format("~s", [<<231,167,129>>], 50))),
475 ?assertEqual([31169], lists:flatten(format("~ts", [<<231,167,129>>], 50))),
476 ok.
477
d16dfaa @Vagabond Implement ~P/~W style depth-limiting
Vagabond authored
478 depth_limit_test() ->
479 ?assertEqual("{...}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 1], 50))),
480 ?assertEqual("{a,...}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 2], 50))),
481 ?assertEqual("{a,[...]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 3], 50))),
482 ?assertEqual("{a,[b|...]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 4], 50))),
483 ?assertEqual("{a,[b,[...]]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 5], 50))),
484 ?assertEqual("{a,[b,[c|...]]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 6], 50))),
485 ?assertEqual("{a,[b,[c,[...]]]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 7], 50))),
486 ?assertEqual("{a,[b,[c,[d]]]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 8], 50))),
487 ?assertEqual("{a,[b,[c,[d]]]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 9], 50))),
488
489 ?assertEqual("{a,{...}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 3], 50))),
490 ?assertEqual("{a,{b,...}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 4], 50))),
491 ?assertEqual("{a,{b,{...}}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 5], 50))),
492 ?assertEqual("{a,{b,{c,...}}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 6], 50))),
493 ?assertEqual("{a,{b,{c,{...}}}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 7], 50))),
494 ?assertEqual("{a,{b,{c,{d}}}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 8], 50))),
495
496 ?assertEqual("{\"a\",[...]}", lists:flatten(format("~P", [{"a", ["b", ["c", ["d"]]]}, 3], 50))),
497 ?assertEqual("{\"a\",[\"b\",[[...]|...]]}", lists:flatten(format("~P", [{"a", ["b", ["c", ["d"]]]}, 6], 50))),
498 ?assertEqual("{\"a\",[\"b\",[\"c\",[\"d\"]]]}", lists:flatten(format("~P", [{"a", ["b", ["c", ["d"]]]}, 9], 50))),
499 ok.
500
03d3fa1 @Vagabond Fixes and tests for deep-list handling in trunc_io:format
Vagabond authored
501 -endif.
Something went wrong with that request. Please try again.