1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2006-2019. 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%%% Purpose : Sub routines for test suite for the xmerl application, 22%%% xmerl_xsd module. 23%%%------------------------------------------------------------------- 24%%% @private 25%%% File : xmerl_xsd_lib.erl 26%%% Author : Bertil Karlsson <bertil@finrod> 27%%% Description : 28%%% 29%%% Created : 28 Apr 2006 by Bertil Karlsson <bertil@finrod> 30%%%------------------------------------------------------------------- 31-module(xmerl_xsd_lib). 32 33-compile(export_all). 34 35-include_lib("common_test/include/ct.hrl"). 36-include("xmerl.hrl"). 37-include("xmerl_xsd.hrl"). 38-include_lib("kernel/include/file.hrl"). 39 40 41compare_test_results(Config, ST, IT) -> 42 ResST=compare_schema_test_results(ST), 43 ResIT=compare_instance_test_results(IT), 44 io:format("compare_test_results:~n ST = ~p~n IT = ~p~n ResST = ~p~n ResIT = ~p~n",[ST, IT, ResST, ResIT]), 45 case process_reference_results(Config, ResST, ResIT) of 46 error -> error; 47 Diff -> return_results(Diff, ResST, ResIT, length(ST)+length(IT)) 48 end. 49 50compare_schema_test_results(ST) -> 51 {[N||{N, false}<-ST], [N||{N, enoent}<-ST]}. 52compare_instance_test_results(IT) -> 53 {[N||{N, false}<-IT], [N||{N, enoent}<-IT]}. 54 55return_results({SkippedN, Diff},{STErrs, _},{ITErrs, _}, TotN) -> 56 NumErrs = length(STErrs ++ ITErrs), 57 case NumErrs == TotN of 58 true when TotN > 0 -> 59 exit(all_tests_cases_failed); 60 _ -> 61 return_results2(Diff, TotN - NumErrs, SkippedN, TotN) 62 end. 63 64%% return_results2(Diff,{[],[]},{[],[]},TotN) -> 65%% {comment,io_lib:format("~p successful test cases.~n"++Diff,[TotN])}; 66%% return_results2(Diff,{STErrs,[]},{ITErrs,[]},TotN) -> 67%% {comment,io_lib:format("Total number of test cases: ~p~nThe following ~p test cases failed: ~p~n"++Diff,[TotN,length(STErrs++ITErrs),STErrs++ITErrs])}; 68%% return_results2(Diff,{STErrs,STOther},{ITErrs,ITOther},TotN) -> 69%% {comment,io_lib:format("Total number of test cases: ~p~nThe following ~p test cases failed: ~p~nThe following ~p test cases was malicious ~p~~n"++Diff,[TotN,length(STErrs++ITErrs),STErrs++ITErrs,length(STOther++ITOther),STOther++ITOther])}. 70 71return_results2(_, 0, 0, 0) -> 72 {comment,io_lib:format("This test case was empty.~n", [])}; 73return_results2({[], [], [], []}, NumSucc, SkippedN, TotN) -> 74 {comment,io_lib:format("~p successful tests, ~p skipped tests of totally ~p test cases.~n", 75 [NumSucc, SkippedN, TotN])}; 76return_results2({NewFail, NewSuccess, NewMal, NewNotMal}, NumSucc, SkippedN, TotN) -> 77 NFComm = case NewFail of 78 [] -> ""; 79 _ -> io_lib:format("These ~p tests are new failures: ~p~n", 80 [length(NewFail), NewFail]) 81 end, 82 NSComm = case NewSuccess of 83 [] -> ""; 84 _ -> io_lib:format("These ~p skipped tests are new succeeding cases: ~p~n", 85 [length(NewSuccess), NewSuccess]) 86 end, 87 NMComm = case NewMal of 88 [] -> ""; 89 _ -> io_lib:format("These ~p tests are now malicious: ~p~n", 90 [length(NewMal), NewMal]) 91 end, 92 NNMComm = case NewNotMal of 93 [] -> ""; 94 _ -> io_lib:format("These ~p skipped tests were malicious, but succeeds now: ~p~n", 95 [length(NewNotMal), NewNotMal]) 96 end, 97 ct:comment(io_lib:format("~p successful tests, ~p skipped tests of totally ~p test cases. ~n~ts", 98 [NumSucc, SkippedN, TotN, 99 NFComm ++ NSComm ++ NMComm ++ NNMComm])), 100 [] = NewFail. 101 102%% return_results2(Diff,{STErrs,STOther},{ITErrs,ITOther},TotN) -> 103%% {comment,io_lib:format("Total number of test cases: ~p~n The following ~p test cases failed: ~p~nThe following ~p test cases was malicious ~p~~n",[TotN,length(STErrs++ITErrs),STErrs++ITErrs,length(STOther++ITOther),STOther++ITOther])}. 104 105 106process_reference_results(Config, {ErrsST, MalST}, {ErrsIT, MalIT}) -> 107 {RefFailed, RefMalicious} = xsd_reference_log(Config), 108 io:format("A: ~p : ~p\n\n",[RefFailed, RefMalicious]), 109 AllErrs = ErrsST ++ ErrsIT, 110 AllMals = MalST ++ MalIT, 111 %% test cases failed now but succeeded in reference results. 112 NewFailures = [X||X<-AllErrs, lists:member(X, RefFailed) == false], 113 %% test cases succeeded now but failed in reference results. 114 NewSucceeds = [X||X<-RefFailed, lists:member(X, AllErrs) == false], 115 %% test cases malicious now but succeeded in reference results. 116 NewMalicious = [X||X<-AllMals, lists:member(X, RefMalicious) == false], 117 %% test cases succeeded now but malicious in reference results. 118 NewNotMal = [X||X<-RefMalicious, lists:member(X, AllMals) == false], 119 write_in_log(Config, AllErrs, AllMals), 120 % io:format("process_reference_results:~n AllErrs = ~p~n NewFailures = ~p~n",[AllErrs,NewFailures]), 121 {length(RefFailed) + length(RefMalicious), {NewFailures, NewSucceeds, NewMalicious, NewNotMal}}. 122 123xsd_reference_log(Config) -> 124 DataDir = datadir(Config), 125 Suite = proplists:get_value(suite, Config), 126 SuiteReferenceLog = 127 filename:join([DataDir,lists:concat([Suite,"_failed_cases.log"])]), 128 io:format("B: ~p\n\n",[SuiteReferenceLog]), 129 case file:consult(SuiteReferenceLog) of 130 {ok,List} when is_list(List) -> 131 io:format("C: ~p\n\n",[List]), 132 case lists:keysearch(proplists:get_value(testcase, Config), 1, List) of 133 {value,{_, TCRefFails}} -> 134 io:format("D: ~p\n\n",[TCRefFails]), 135 TCRefFails; 136 _ -> 137 io:format("D: ~no result\n\n",[]), 138 {[], []} 139 end; 140 _ -> 141 {[], []} 142 end. 143 144write_in_log(_Config, [], []) -> 145 ok; 146write_in_log(Config, AllErrs, AllMals) -> 147 LogFileName = proplists:get_value(xmerl_error_log, Config), 148 {ok,IO}=file:open(LogFileName, [append]), 149 TestCase = proplists:get_value(testcase, Config), 150 io:format(IO,"{~p,{~p,~p}}.~n", [TestCase, AllErrs, AllMals]), 151 file:close(IO), 152 ok. 153 154schema_test(Config,FileName,XsdBase,Validity) -> 155 ModuleName = filename:basename(FileName), 156 DataDir = datadir(Config), 157 case xmerl_xsd:process_schema(filename:join([DataDir, FileName]), 158 [{xsdbase,filename:join([DataDir, XsdBase])}]) of 159 {error, enoent} -> 160 {{ModuleName, enoent},#xsd_state{}}; 161 {Ok, S} -> 162 case Validity of 163 valid when Ok == ok -> 164%% io:format("schema_test1: Validity=valid,Ok=ok,S=~p~n",[S]), 165 {{ModuleName, S#xsd_state.errors == []}, S}; 166 invalid when Ok == error -> %% S is in this case an error reason 167 {{ModuleName, no_internal_error(S)}, #xsd_state{}}; 168 notKnown -> 169 {{ModuleName, true}, #xsd_state{}}; 170 valid -> 171 io:format("schema_test2: Validity=valid,Ok=~p,S=~p~n", [Ok, S]), 172%% io:format("FileName: ~p~n",[FileName]), 173 {{ModuleName, false}, #xsd_state{}}; 174 _ -> %% invalid Ok == ok 175 io:format("schema_test3: Validity=~p,Ok=~p,S=~p~n", [Validity, Ok, S]), 176 {{ModuleName, false}, S} 177 end 178 end. 179schema_test(Config, FileName, XsdBase, Validity, AccState) -> 180 ModuleName = filename:basename(FileName), 181 DataDir = datadir(Config), 182 case xmerl_xsd:process_schema(filename:join([DataDir, FileName]), 183 [{xsdbase,filename:join([DataDir, XsdBase])}, AccState]) of 184 {error, enoent} -> 185 {{ModuleName, enoent}, AccState}; 186 {Ok, S} -> 187 case Validity of 188 valid when Ok == ok -> 189 {{ModuleName, S#xsd_state.errors == []}, S}; 190 invalid when Ok == error -> 191 {{ModuleName, no_internal_error(S)}, AccState}; 192 notKnown -> 193 {{ModuleName, true}, AccState}; 194 valid -> 195 {{ModuleName, false}, AccState}; 196 _ -> 197 {{ModuleName, false}, S} 198 end 199 end. 200instance_test(Config, FileName, XMLBase, Validity, State) -> 201 ModuleName = filename:basename(FileName), 202 DataDir = datadir(Config), 203 case xmerl_scan:file(filename:join([DataDir, FileName]), 204 [{xmlbase,filename:join([DataDir, XMLBase])}]) of 205 {error, enoent} -> 206 {ModuleName, enoent}; 207 {E, _} -> 208 {VE, S2} = xmerl_xsd:validate(E, State), 209 case Validity of 210 valid when is_record(VE, xmlElement) -> 211 case S2#xsd_state.errors of 212 [] -> ok; 213 _ -> io:format("test case ~p failed.~nValidity: ~p~nValidation result:~p~n", [FileName, Validity, VE]) 214 end, 215 {ModuleName, S2#xsd_state.errors == []}; 216 invalid when VE == error -> 217 {ModuleName, no_internal_error(S2)}; 218 notKnown -> 219 {ModuleName, true}; 220 _ -> 221 io:format("test case ~p failed.~nValidity: ~p~nValidation result:~p~n", [FileName, Validity, VE]), 222 {ModuleName,false} 223 end 224 end. 225 226no_internal_error(R) -> 227 case lists:keymember(internal_error,1,R) of 228 true -> 229 false; 230 _ -> 231 true 232 end. 233 234unpack(Config, Suite) -> 235 TarFile = suite_tar(Suite), 236 file:set_cwd(datadir(Config)), 237 ok=erl_tar:extract(TarFile, [compressed]), 238 change_mode(filename:rootname(TarFile, ".tar.gz")). 239 240suite_tar(sun) -> 241 "suntest.tar.gz"; 242suite_tar(msx) -> 243 "msxsdtest.tar.gz"; 244suite_tar(nist) -> 245 "nisttest.tar.gz". 246 247change_mode(Files) -> 248 change_mode3(Files). 249change_mode2(Dir)-> 250 {ok, CWD} = file:get_cwd(), 251 {ok, FileList} = file:list_dir(Dir), 252 file:set_cwd(filename:join([CWD, Dir])), 253 change_mode3(FileList), 254 file:set_cwd(CWD). 255change_mode3([]) -> 256 ok; 257change_mode3([F |Fs]) -> 258 case filelib:is_dir(F) of 259 true -> 260 chmod(F), 261 change_mode2(F); 262 _ -> 263 chmod(F) 264 end, 265 change_mode3(Fs). 266 267chmod(F) -> 268 case file:read_file_info(F) of 269 {ok, FileInfo} -> 270 Mode= FileInfo#file_info.mode, 271 file:write_file_info(F, FileInfo#file_info{mode=8#00777 bor Mode}); 272 _ -> 273 ok 274 end. 275 276rmdir(Config, Suite) -> 277 file:set_cwd(datadir(Config)), 278 SuiteDir = filename:rootname(suite_tar(Suite), ".tar.gz"), 279 ok=rm_f_(SuiteDir). 280 281%% Dir is a directory 282rm_f_(Dir) -> 283 {ok, CWD} = file:get_cwd(), 284 {ok, FileList} = file:list_dir(Dir), 285 file:set_cwd(filename:join([CWD, Dir])), 286 rm_files(FileList), 287 file:set_cwd(CWD), 288 ok = file:del_dir(Dir). 289 290rm_files([])-> 291 ok; 292rm_files([F |Fs]) -> 293 case filelib:is_dir(F) of 294 true -> 295 rm_f_(F); 296 _ -> 297 io:format("rm_files: ~p~n", [F]), 298 ok = file:delete(F) 299 end, 300 rm_files(Fs). 301 302create_error_log_file(Config, Suite) -> 303 {{Y, M, D}, {H, Min, S}} = calendar:local_time(), 304 DTString=lists:concat([Y, "-", M,"-", D, "_", H, ".", Min, ".", S]), 305 FileName = lists:concat([Suite, "_", DTString, ".errorlog"]), 306%% {ok,_IO} = file:open(filename:join([privdir(Config), 307%% FileName]),[append]). 308 309%% {ok,_IO} = file:open(FileName,[append]). 310 io:format("error log file: ~p~n", [filename:join([privdir(Config), FileName])]), 311 {ok, filename:join([privdir(Config), FileName])}. 312 313close_error_log_file(Config) -> 314 case lists:keysearch(xmerl_error_log, 1, Config) of 315 {value,{_, IO}} -> 316 file:close(IO); 317 _ -> 318 ok 319 end. 320 321privdir(Config) -> 322 proplists:get_value(priv_dir, Config). 323datadir(Config) -> 324 proplists:get_value(data_dir, Config). 325