%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed 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. %% %% %CopyrightEnd% %%%------------------------------------------------------------------- %%% File : wx_test_lib.erl %%% Author : Dan Gudmundsson %%% Description : Library for testing wxerlang. %%% %%% Created : 30 Oct 2008 by Dan Gudmundsson %%%------------------------------------------------------------------- -module(wx_test_lib). -export([init_per_suite/1, end_per_suite/1, init_per_testcase/2, end_per_testcase/2]). -export([tc_info/1, log/2, log/4, verbose/4, error/4, flush/0, pick_msg/0, user_available/1, wx_destroy/2, wx_close/2, wait_for_close/0, run_test/2, run_test/3, test_case_evaluator/3]). -include("wx_test_lib.hrl"). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init_per_suite(Config) -> try case os:type() of {unix,darwin} -> exit("Can not test on MacOSX"); {unix, _} -> io:format("DISPLAY ~s~n", [os:getenv("DISPLAY")]), case ct:get_config(xserver, none) of none -> ignore; Server -> os:putenv("DISPLAY", Server) end; _ -> ignore end, wx:new(), wx:destroy(), Config catch _:undef -> {skipped, "No wx compiled for this platform"}; _:Reason -> {skipped, lists:flatten(io_lib:format("Start wx failed: ~p", [Reason]))} end. end_per_suite(_Config) -> ok. init_per_testcase(_Func, Config) -> global:register_name(wx_global_logger, group_leader()), Config. end_per_testcase(_Func, Config) -> global:unregister_name(wx_global_logger), Config. %% Backwards compatible with test_server tc_info(suite) -> []; tc_info(doc) -> "". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Use ?log(Format, Args) as wrapper log(Format, Args, LongFile, Line) -> File = filename:basename(LongFile), Format2 = lists:concat([File, "(", Line, ")", ": ", Format]), log(Format2, Args). log(Format, Args) -> case global:whereis_name(wx_global_logger) of undefined -> io:format(user, Format, Args); Pid -> io:format(Pid, Format, Args) end. verbose(Format, Args, File, Line) -> Arg = wx_test_verbose, case get(Arg) of false -> ok; true -> log(Format, Args, File, Line); undefined -> case init:get_argument(Arg) of {ok, List} when is_list(List) -> case lists:last(List) of ["true"] -> put(Arg, true), log(Format, Args, File, Line); _ -> put(Arg, false), ok end; _ -> put(Arg, false), ok end end. error(Format, Args, File, Line) -> global:send(wx_global_logger, {failed, File, Line}), Fail = {filename:basename(File),Line,Args}, case global:whereis_name(wx_test_case_sup) of undefined -> ignore; Pid -> Pid ! Fail %% global:send(wx_test_case_sup, Fail), end, log("~n" ++ Format, Args, File, Line). pick_msg() -> receive Message -> Message after 4000 -> timeout end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Utility functions user_available(Config) -> false /= proplists:get_value(user, Config, false). wx_destroy(Frame, Config) -> wx_close(Frame, Config), ?m(ok, wx:destroy()). wx_close(Frame, Config) -> case proplists:get_value(user, Config, false) of false -> timer:sleep(100), ?m(ok, wxWindow:destroy(Frame)); true -> timer:sleep(500), ?m(ok, wxWindow:destroy(Frame)); step -> %% Wait for user to close window ?m(ok, wxEvtHandler:connect(Frame, close_window, [{skip,true}])), wait_for_close(), catch wxEvtHandler:disconnect(Frame, close_window), ok end. wait_for_close() -> receive #wx{event=#wxClose{}} -> ?log("Got close~n",[]); #wx{obj=Obj, event=Event} -> try Name = wxTopLevelWindow:getTitle(Obj), ?log("~p Event: ~p~n", [Name, Event]) catch _:_ -> ?log("Event: ~p~n", [Event]) end, wait_for_close(); Other -> ?log("Unexpected: ~p~n", [Other]), wait_for_close() end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% A small test server, which can be run standalone in a shell run_test(Test = {_,_},Config) -> run_test([Test],Config); run_test([{Module, TC}|Rest], Config) -> [run_test(Module, TC, Config) | run_test(Rest, Config)]; run_test([], _Config) -> []. run_test(Module, all, Config) -> All = [{Module, Test} || Test <- Module:all()], run_test(All, Config); run_test(Module, {group, Group}, Config) -> {_, _, TCs} = lists:keyfind(Group, 1, Module:groups()), All = [{Module, Test} || Test <- TCs], run_test(All, Config); run_test(Module, TestCase, Config) -> log("Eval test case: ~w~n", [{Module, TestCase}]), Sec = timer:seconds(1) * 1000, {T, Res} = timer:tc(fun() -> eval_test_case(Module, TestCase, Config) end), log("Tested ~w in ~w sec~n", [TestCase, T div Sec]), {T div Sec, Res}. eval_test_case(Mod, Fun, Config) -> flush(), global:register_name(wx_test_case_sup, self()), Flag = process_flag(trap_exit, true), Pid = spawn_link(?MODULE, test_case_evaluator, [Mod, Fun, [Config]]), R = wait_for_evaluator(Pid, Mod, Fun, Config), global:unregister_name(wx_test_case_sup), process_flag(trap_exit, Flag), R. test_case_evaluator(Mod, Fun, [Config]) -> NewConfig = Mod:init_per_testcase(Fun, Config), R = apply(Mod, Fun, [NewConfig]), Mod:end_per_testcase(Fun, NewConfig), exit({test_case_ok, R}). wait_for_evaluator(Pid, Mod, Fun, Config) -> receive {'EXIT', Pid, {test_case_ok, _PidRes}} -> Errors = flush(), Res = case Errors of [] -> ok; Errors -> failed end, {Res, {Mod, Fun}, Errors}; {'EXIT', Pid, {skipped, Reason}} -> log(" Test case ~w skipped, because ~p~n", [{Mod, Fun}, Reason]), Mod:end_per_testcase(Fun, Config), {skip, {Mod, Fun}, Reason}; {'EXIT', Pid, Reason} -> log(" Eval process ~w exited, because ~p~n", [{Mod, Fun}, Reason]), Mod:end_per_testcase(Fun, Config), {crash, {Mod, Fun}, Reason} end. flush() -> receive Msg -> [Msg | flush()] after 0 -> [] end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%