1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2001-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22-module(ei_print_SUITE).
23
24-include_lib("common_test/include/ct.hrl").
25-include("ei_print_SUITE_data/ei_print_test_cases.hrl").
26
27-export([all/0, suite/0,
28         init_per_testcase/2,
29         atoms/1, tuples/1, lists/1, strings/1,
30         maps/1, funs/1, binaries/1, bitstrings/1,
31         integers/1]).
32
33-import(runner, [get_term/1]).
34
35%% This test suite test the ei_print() function.
36%% It uses the port program "ei_format_test".
37
38suite() ->
39    [{ct_hooks,[ts_install_cth]}].
40
41all() ->
42    [atoms, tuples, lists, strings, maps, funs, binaries, bitstrings, integers].
43
44init_per_testcase(Case, Config) ->
45    runner:init_per_testcase(?MODULE, Case, Config).
46
47%% Tests formatting various atoms.
48
49atoms(Config) when is_list(Config) ->
50    P = runner:start(Config, ?atoms),
51
52    {term, "''"} = get_term(P),
53    {term, "a"} = get_term(P),
54    {term, "'A'"} = get_term(P),
55    {term, "abc"} = get_term(P),
56    {term, "'Abc'"} = get_term(P),
57    {term, "ab@c"} = get_term(P),
58    {term, "'The rain in Spain stays mainly in the plains'"} = get_term(P),
59
60    {term, "a"} = get_term(P),
61    {term, "ab"} = get_term(P),
62    {term, "abc"} = get_term(P),
63    {term, "ab@c"} = get_term(P),
64    {term, "abcdefghijklmnopq"} = get_term(P),
65
66    {term, "''"} = get_term(P),
67    {term, "a"} = get_term(P),
68    {term, "'A'"} = get_term(P),
69    {term, "abc"} = get_term(P),
70    {term, "'Abc'"} = get_term(P),
71    {term, "ab@c"} = get_term(P),
72    {term, "'The rain in Spain stays mainly in the plains'"} = get_term(P),
73
74    {term, "a"} = get_term(P),
75    {term, "ab"} = get_term(P),
76    {term, "abc"} = get_term(P),
77    {term, "ab@c"} = get_term(P),
78    {term, "'   abcdefghijklmnopq   '"} = get_term(P),
79
80    runner:recv_eot(P),
81    ok.
82
83
84
85%% Tests formatting various tuples
86
87tuples(Config) when is_list(Config) ->
88    P = runner:start(Config, ?tuples),
89
90    {term, "{}"} = get_term(P),
91    {term, "{a}"} = get_term(P),
92    {term, "{a, b}"} = get_term(P),
93    {term, "{a, b, c}"} = get_term(P),
94    {term, "{1}"} = get_term(P),
95    {term, "{[]}"} = get_term(P),
96    {term, "{[], []}"} = get_term(P),
97    {term, "{[], a, b, c}"} = get_term(P),
98    {term, "{[], a, [], b, c}"} = get_term(P),
99    {term, "{[], a, '', b, c}"} = get_term(P),
100
101    runner:recv_eot(P),
102    ok.
103
104
105
106%% Tests formatting various lists
107
108lists(Config) when is_list(Config) ->
109    P = runner:start(Config, ?lists),
110
111    {term, "[]"} = get_term(P),
112    {term, "[a]"} = get_term(P),
113    {term, "[a, b]"} = get_term(P),
114    {term, "[a, b, c]"} = get_term(P),
115    {term, "[1]"} = get_term(P),
116    {term, "[[]]"} = get_term(P),
117    {term, "[[], []]"} = get_term(P),
118    {term, "[[], a, b, c]"} = get_term(P),
119    {term, "[[], a, [], b, c]"} = get_term(P),
120    {term, "[[], a, '', b, c]"} = get_term(P),
121    {term, "[[x, 2], [y, 3], [z, 4]]"}= get_term(P),
122
123    %% {term, "[{name, 'Madonna'}, {age, 21}, {data, [{addr, "E-street", 42}]}]"} = get_term(P),
124    %% maybe regexp instead?
125    {term, "[{pi, 3.141500}, {'cos(70)', 0.342020}]"} = get_term(P),
126    {term, "[[pi, 3.141500], ['cos(70)', 0.342020]]"} = get_term(P),
127
128    {term, "[-1]"} = get_term(P),
129
130    runner:recv_eot(P),
131    ok.
132
133strings(Config) when is_list(Config) ->
134    P = runner:start(Config, ?strings),
135
136    {term, "\"\\n\""} = get_term(P),
137    {term, "\"\\r\\n\""} = get_term(P),
138    {term, "\"a\""} = get_term(P),
139    {term, "\"A\""} = get_term(P),
140    {term, "\"0\""} = get_term(P),
141    {term, "\"9\""} = get_term(P),
142    {term, "\"The rain in Spain stays mainly in the plains\""} = get_term(P),
143    {term, "\"   abcdefghijklmnopq   \""} = get_term(P),
144
145    runner:recv_eot(P),
146    ok.
147
148maps(Config) ->
149    P = runner:start(Config, ?maps),
150
151    {term, "#{}"} = get_term(P),
152    {term, "#{key => value}"} = get_term(P),
153    {term, "#{key => value, another_key => {ok, 42}}"} = get_term(P),
154
155    runner:recv_eot(P),
156    ok.
157
158funs(Config) ->
159    P = runner:start(Config, ?funs),
160
161    {term, "#Fun{some_module.42.3735928559}"} = get_term(P),
162    {term, "#Fun{some_module.37.195935983}"} = get_term(P),
163    {term, "fun erlang:abs/1"} = get_term(P),
164
165    runner:recv_eot(P),
166    ok.
167
168binaries(Config) ->
169    P = runner:start(Config, ?binaries),
170
171    "#Bin<>" = send_term_get_printed(P, <<>>),
172    "#Bin<1,2,3>" = send_term_get_printed(P, <<1,2,3>>),
173    "#Bin<0,127,128,255>" = send_term_get_printed(P, <<0,127,128,255>>),
174    Bin30 = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30>>,
175    "#Bin<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30>"
176        = send_term_get_printed(P, Bin30),
177    "#Bin<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,...>"
178        = send_term_get_printed(P, <<Bin30/binary,31>>),
179
180    runner:recv_eot(P),
181    ok.
182
183bitstrings(Config) ->
184    P = runner:start(Config, ?bitstrings),
185
186    "#Bits<1:1>" = send_term_get_printed(P, <<1:1>>),
187    "#Bits<123:7>" = send_term_get_printed(P, <<123:7>>),
188    "#Bits<1,2,3:4>" = send_term_get_printed(P, <<1,2,3:4>>),
189    "#Bits<0,127,128,255,126:7>" = send_term_get_printed(P, <<0,127,128,255,-2:7>>),
190    Bits30 = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
191               20,21,22,23,24,25,26,27,28,29,30:5>>,
192    "#Bits<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30:5>"
193        = send_term_get_printed(P, Bits30),
194    "#Bin<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,241>"
195        = send_term_get_printed(P, <<Bits30/bits,1:3>>),
196    "#Bits<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,240,...>"
197        = send_term_get_printed(P, <<Bits30/bits,1:4>>),
198
199    runner:recv_eot(P),
200    ok.
201
202integers(Config) ->
203    Port = runner:start(Config, ?integers),
204
205    test_integers(Port, -1000, 1000),
206    test_integers(Port, (1 bsl 27) - 1000, (1 bsl 27) + 1000),
207    test_integers(Port, -(1 bsl 27) - 1000, -(1 bsl 27) + 1000),
208    test_integers(Port, (1 bsl 28) - 1000, (1 bsl 28) + 1000),
209    test_integers(Port, -(1 bsl 28) - 1000, -(1 bsl 28) + 1000),
210    test_integers(Port, (1 bsl 31) - 1000, (1 bsl 31) + 1000),
211    test_integers(Port, -(1 bsl 31) - 1000, -(1 bsl 31) + 1000),
212    test_integers(Port, (1 bsl 32) - 1000, (1 bsl 32) + 1000),
213    test_integers(Port, -(1 bsl 32) - 1000, -(1 bsl 32) + 1000),
214    test_integers(Port, (1 bsl 60) - 1000, (1 bsl 60) + 1000),
215    test_integers(Port, -(1 bsl 60) - 1000, -(1 bsl 60) + 1000),
216    test_integers(Port, 16#feeddeaddeadbeef - 1000, 16#feeddeaddeadbeef + 1000),
217    test_integers(Port, -16#feeddeaddeadbeef - 1000, -16#feeddeaddeadbeef + 1000),
218    test_integers(Port, (1 bsl 64) - 1000, (1 bsl 64) + 1000),
219    test_integers(Port, 16#addfeeddeaddeadbeef - 1000, 16#addfeeddeaddeadbeef + 1000),
220    test_integers(Port, -16#addfeeddeaddeadbeef - 1000, -16#addfeeddeaddeadbeef + 1000),
221    test_integers(Port, -(1 bsl 64) - 1000, -(1 bsl 64) + 1000),
222    test_integers(Port, (1 bsl 8192) - 1000, (1 bsl 8192) + 1000),
223    test_integers(Port, -(1 bsl 8192) - 1000, -(1 bsl 8192) + 1000),
224
225    "done" = send_term_get_printed(Port, done),
226
227    runner:recv_eot(Port),
228
229    ok.
230
231test_integer(Port, Int, Print) when is_integer(Int) ->
232    Res = send_term_get_printed(Port, Int),
233    case Print of
234        true ->
235            io:format("Res: ~s~n", [Res]);
236        false ->
237            ok
238    end,
239    %% Large bignums are printed in base 16...
240    Exp = case Res of
241              "16#" ++ _ ->
242                  "16#" ++ integer_to_list(Int, 16);
243              "-16#" ++ _ ->
244                  "-16#" ++ integer_to_list(-1*Int, 16);
245              _ ->
246                  integer_to_list(Int)
247           end,
248    case Exp =:= Res of
249        true ->
250            ok;
251        false ->
252            io:format("Exp: ~s~nRes: ~s~n", [Exp, Res]),
253            ct:fail({Exp, Res})
254    end.
255
256test_integers(Port, FromInt, ToInt) ->
257    test_integers(Port, FromInt, ToInt, true).
258
259test_integers(_Port, FromInt, ToInt, _Print) when FromInt > ToInt ->
260    ok;
261test_integers(Port, FromInt, ToInt, Print) ->
262    ok = test_integer(Port, FromInt, Print),
263    NewFromInt = FromInt + 1,
264    test_integers(Port, NewFromInt, ToInt, NewFromInt == ToInt).
265
266
267send_term_get_printed(Port, Term) ->
268    Port ! {self(), {command, term_to_binary(Term)}},
269    {term, String} = get_term(Port),
270    String.
271