1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2003-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-module(test_lib). 21 22-include_lib("common_test/include/ct.hrl"). 23-compile({no_auto_import,[binary_part/2]}). 24-export([id/1,recompile/1,recompile_core/1,parallel/0, 25 uniq/0,opt_opts/1,get_data_dir/1, 26 is_cloned_mod/1,smoke_disasm/1,p_run/2, 27 highest_opcode/1]). 28 29%% Used by test case that override BIFs. 30-export([binary_part/2,binary/1]). 31 32id(I) -> I. 33 34recompile(Mod) when is_atom(Mod) -> 35 case whereis(cover_server) of 36 undefined -> ok; 37 _ -> 38 %% Re-compile the test suite if the cover server is running. 39 Beam = code:which(Mod), 40 Src = filename:rootname(Beam, ".beam") ++ ".erl", 41 Opts = [bin_opt_info,recv_opt_info|opt_opts(Mod)], 42 io:format("Recompiling ~p (~p)\n", [Mod,Opts]), 43 c:c(Src, [{outdir,filename:dirname(Src)}|Opts]) 44 end, 45 46 %% Smoke-test of beam disassembler. 47 smoke_disasm(Mod). 48 49recompile_core(Mod) when is_atom(Mod) -> 50 case whereis(cover_server) of 51 undefined -> ok; 52 _ -> 53 %% Re-compile the test suite if the cover server is running. 54 Beam = code:which(Mod), 55 Src = filename:rootname(Beam, ".beam"), 56 Opts = [bin_opt_info,recv_opt_info|opt_opts(Mod)], 57 io:format("Recompiling ~p (~p)\n", [Mod,Opts]), 58 c:c(Src, [from_core,{outdir,filename:dirname(Src)}|Opts]) 59 end, 60 61 %% Smoke-test of beam disassembler. 62 smoke_disasm(Mod). 63 64smoke_disasm(Mod) when is_atom(Mod) -> 65 smoke_disasm(code:which(Mod)); 66smoke_disasm(File) when is_list(File) -> 67 Res = beam_disasm:file(File), 68 {beam_file,_Mod} = {element(1, Res),element(2, Res)}. 69 70parallel() -> 71 case erlang:system_info(schedulers) =:= 1 of 72 true -> []; 73 false -> [parallel] 74 end. 75 76uniq() -> 77 U = erlang:unique_integer([positive]), 78 "_" ++ integer_to_list(U). 79 80%% Retrieve the "interesting" compiler options (options for optimization 81%% and compatibility) for the given module. 82 83opt_opts(Mod) -> 84 Comp = Mod:module_info(compile), 85 {options,Opts} = lists:keyfind(options, 1, Comp), 86 lists:filter(fun 87 (debug_info) -> true; 88 (dialyzer) -> true; 89 (inline) -> true; 90 (no_bsm3) -> true; 91 (no_bsm_opt) -> true; 92 (no_copt) -> true; 93 (no_fun_opt) -> true; 94 (no_init_yregs) -> true; 95 (no_make_fun3) -> true; 96 (no_module_opt) -> true; 97 (no_postopt) -> true; 98 (no_put_tuple2) -> true; 99 (no_recv_opt) -> true; 100 (no_share_opt) -> true; 101 (no_shared_fun_wrappers) -> true; 102 (no_ssa_float) -> true; 103 (no_ssa_opt) -> true; 104 (no_stack_trimming) -> true; 105 (no_swap) -> true; 106 (no_type_opt) -> true; 107 (_) -> false 108 end, Opts). 109 110%% Some test suites gets cloned (e.g. to "record_SUITE" to 111%% "record_no_opt_SUITE"), but the data directory is not cloned. 112%% This function retrieves the path to the original data directory. 113 114get_data_dir(Config) -> 115 Data = proplists:get_value(data_dir, Config), 116 Opts = [{return,list}], 117 Suffixes = ["_no_opt_SUITE", 118 "_no_copt_SUITE", 119 "_post_opt_SUITE", 120 "_inline_SUITE", 121 "_r21_SUITE", 122 "_no_module_opt_SUITE", 123 "_no_type_opt_SUITE", 124 "_no_ssa_opt_SUITE"], 125 lists:foldl(fun(Suffix, Acc) -> 126 Opts = [{return,list}], 127 re:replace(Acc, Suffix, "_SUITE", Opts) 128 end, Data, Suffixes). 129 130is_cloned_mod(Mod) -> 131 is_cloned_mod_1(atom_to_list(Mod)). 132 133%% Test whether Mod is a cloned module. 134 135is_cloned_mod_1("_no_opt_SUITE") -> true; 136is_cloned_mod_1("_no_copt_SUITE") -> true; 137is_cloned_mod_1("_no_ssa_opt_SUITE") -> true; 138is_cloned_mod_1("_post_opt_SUITE") -> true; 139is_cloned_mod_1("_inline_SUITE") -> true; 140is_cloned_mod_1("_21_SUITE") -> true; 141is_cloned_mod_1("_no_module_opt_SUITE") -> true; 142is_cloned_mod_1([_|T]) -> is_cloned_mod_1(T); 143is_cloned_mod_1([]) -> false. 144 145%% Return the highest opcode use in the BEAM module. 146 147highest_opcode(Beam) -> 148 {ok,{_Mod,[{"Code",Code}]}} = beam_lib:chunks(Beam, ["Code"]), 149 FormatNumber = 0, 150 <<16:32,FormatNumber:32,HighestOpcode:32,_/binary>> = Code, 151 HighestOpcode. 152 153%% p_run(fun(Data) -> ok|error, List) -> ok 154%% Will fail the test case if there were any errors. 155 156p_run(Test, List) -> 157 S = erlang:system_info(schedulers), 158 N = S + 1, 159 io:format("p_run: ~p parallel processes\n", [N]), 160 p_run_loop(Test, List, N, [], 0, 0). 161 162p_run_loop(_, [], _, [], Errors, Ws) -> 163 case Errors of 164 0 -> 165 case Ws of 166 0 -> ok; 167 1 -> {comment,"1 warning"}; 168 N -> {comment,integer_to_list(N)++" warnings"} 169 end; 170 N -> 171 ct:fail({N,errors}) 172 end; 173p_run_loop(Test, [H|T], N, Refs, Errors, Ws) when length(Refs) < N -> 174 {_,Ref} = erlang:spawn_monitor(fun() -> exit(Test(H)) end), 175 p_run_loop(Test, T, N, [Ref|Refs], Errors, Ws); 176p_run_loop(Test, List, N, Refs0, Errors0, Ws0) -> 177 receive 178 {'DOWN',Ref,process,_,Res} -> 179 {Errors,Ws} = case Res of 180 ok -> {Errors0,Ws0}; 181 error -> {Errors0+1,Ws0}; 182 warning -> {Errors0,Ws0+1} 183 end, 184 Refs = Refs0 -- [Ref], 185 p_run_loop(Test, List, N, Refs, Errors, Ws) 186 end. 187 188%% This is for the misc_SUITE:override_bif testcase 189binary_part(_A,_B) -> 190 dummy. 191 192%% This is for overridden_bif_SUITE. 193binary(N) -> 194 N rem 10 =:= 0. 195