aboutsummaryrefslogblamecommitdiffstats
path: root/lib/test_server/src/things/verify.erl
blob: eac20c013ecfc60c8d675dfbcf6f8e8e1ffbae1a (plain) (tree)






































































































































































































                                                                              
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
%% 
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%% 
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%% 
%% %CopyrightEnd%
%%
-module(verify).

-export([dir/0, dir/1]).

%% usage verify:dir()
%% or    verify:dir(Dir)
%% 
%% runs tests on all files with the extension ".t1"
%% creates an error log file verify.log in the directory where the
%% tests were run

-import(lists, [reverse/1, foldl/3, map/2]).

dir() ->
    dir(".").

dir(Dir) ->
    case file:list_dir(Dir) of
	{ok, Files} ->
	    VFiles = collect_vers(Files, []),
	    VFiles1 = map(fun(F) -> Dir ++ "/" ++ F end, VFiles),
	    Nerrs = foldl(fun(F, Sum) -> 
				  case file(F) of
				      {file,_,had,N,errors} ->
					  Sum + N;
				      no_errors ->
					  Sum;
				      Other ->
					  Sum + 1
				  end
			  end, 0, VFiles1),
	    case Nerrs of
		0 -> no_errors;
		_ -> {dir,Dir,had,Nerrs,errors}
	    end;
	_ ->
	    {error, cannot,list_dir, Dir}
    end.

collect_vers([H|T], L) ->
    case reverse(H) of
	[$1,$t,$.|T1] -> collect_vers(T, [reverse(T1)|L]);
	_             -> collect_vers(T, L)
    end;
collect_vers([], L) ->
    L.

file(File) ->
    case file:open(File ++ ".t1", read) of
	{ok, S} ->
	    io:format("Verifying: ~s\n", [File]),
	    ErrFile = File ++ ".errs",
	    {ok, E} = file:open(ErrFile, write),
	    Bind0 = erl_eval:new_bindings(),
	    NErrs = do(S, {E, File, Bind0, 0}, 1),
	    file:close(S),
	    file:close(E),
	    case NErrs of
		0 ->
		    file:delete(ErrFile),
		    no_errors;
		_ ->
		    {file,File,had,NErrs,errors}
	    end;
	_ ->
	    error_in_opening_file
    end.

do(S, Env, Line) ->
    R = io:scan_erl_exprs(S, '', Line),
    do1(R, S, Env).

do1({eof,_}, _, {_,_,_,NErrs}) ->
    NErrs;
do1({ok,Toks,Next}, S, Env0) ->
    E1 = handle_toks(Toks, Next, Env0),
    do(S, E1, Next);
do1({error, {Line,Mod,Args}, Next}, S, E) ->
    io:format("*** ~w ~p~n", [Line,Mod:format_error(Args)]),
    E1 = add_error(E),
    do(S, E1, Next).

add_error({Stream, File, Bindings, N}) -> {Stream, File, Bindings, N+1}.

handle_toks(Toks, Line, Env0) ->
    %% io:format("Toks:~p\n", [Toks]).
    case erl_parse:parse_exprs(Toks) of
	{ok, Exprs} ->
	    %% io:format("Got:~p\n", [Exprs]),
	    eval(Exprs, Line, Env0);
	{error, {LineNo, Mod, What}} ->
	    Str = apply(Mod, format_error, [What]),
	    io:format("*** Line:~w  ***~s\n", [LineNo, Str]),
	    add_error(Env0);
	Parse_error ->
	    io:format("Parse Error:~p\n",[Parse_error]),
 	    add_error(Env0)
    end.

forget([{var,_,Name}], B0) -> erl_eval:del_binding(Name, B0);
forget([], _)              -> erl_eval:new_bindings().

eval([{call,_,{atom,_,f}, Args}], _, {Stream, Bind0, Errs}) ->
    Bind1 = forget(Args, Bind0),
    {Stream, Bind1, Errs};
eval(Exprs, Line, {Stream, File, Bind0, NErrs}) ->
    %% io:format("Bindings >> ~p\n", [Bind0]),
    %% io:format("Exprs >> ~p\n", [Exprs]),
    case catch erl_eval:exprs(Exprs, Bind0) of
	{'EXIT', Reason} ->
	    out_both(Stream, "----------------------------------~n", []),
	    out_both(Stream, "File:~s Error in:~s~n", [File, pp(Exprs)]),
	    print_bindings(Stream, Exprs, Bind0),
	    print_lhs(Stream, Exprs),
	    out_both(Stream, '*** Rhs evaluated to:~p~n',[rhs(Exprs, Bind0)]),
	    {Stream, File, Bind0, NErrs+1};
	{value, _, Bind1} ->
	    {Stream, File, Bind1, NErrs}
    end.

pp([H])   -> erl_pp:expr(H);
pp([H|T]) -> [erl_pp:expr(H),$,|pp(T)];
pp([])    -> [].

print_bindings(E, Form, Bindings) ->
    case varsin(Form) of
	[] ->
	    true;
	Vars ->
	    print_vars(E, Vars, Bindings)
    end.

print_vars(E, [Var|T], Bindings) ->
    case erl_eval:binding(Var, Bindings) of
	{value, Val} ->
	    out_both(E, '~s = ~p\n',[Var, Val]);
	unbound ->
	    out_both(E, '~s *is unbound*\n', [Var])
    end,
    print_vars(E, T, Bindings);
print_vars(_, [], _) ->
    true.


out_both(E, Format, Data) ->
    io:format(Format, Data),
    io:format(E, Format, Data).

print_lhs(E, [{match, _, Lhs, Rhs}]) ->
    %% io:format(">>>> here:~w\n",[Lhs]),
    out_both(E, '*** Lhs was:~s\n',[erl_pp:expr(Lhs)]);
print_lhs(E, _) ->
    out_both(E, '** UNDEFINED **', []).


rhs([{match, _, Lhs, Rhs}], Bindings) ->
    case catch erl_eval:exprs([Rhs], Bindings) of
	{value, Val, _} -> Val;
	Other           ->  undefined()
    end;
rhs(_, _) ->
    undefined().

varsin(X) -> varsin(X, []).

varsin({var,_,'_'}, L) ->
    L;
varsin({var,_,V}, L) ->
    case lists:member(V, L) of
	true  -> L;
	false -> [V|L]
    end;
varsin([H|T], L) ->
    varsin(T, varsin(H, L));
varsin(T, L) when tuple(T) ->
    varsin(tuple_to_list(T), L);
varsin(_, L) ->
    L.
    
undefined() ->
    '** UNDEFINED **'.