testu.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. {$mode objfpc}
  2. {$h+}
  3. unit testu;
  4. Interface
  5. uses
  6. dos;
  7. { ---------------------------------------------------------------------
  8. utility functions, shared by several programs of the test suite
  9. ---------------------------------------------------------------------}
  10. type
  11. TCharSet = set of char;
  12. TVerboseLevel=(V_Abort,V_Error,V_Warning,V_Normal,V_Debug,V_SQL);
  13. TConfig = record
  14. NeedOptions,
  15. DelOptions,
  16. NeedCPU,
  17. SkipCPU,
  18. SkipEmu,
  19. NeedTarget,
  20. SkipTarget,
  21. MinVersion,
  22. MaxVersion,
  23. KnownRunNote,
  24. KnownCompileNote,
  25. RecompileOpt: string;
  26. ResultCode : longint;
  27. KnownRunError : longint;
  28. KnownCompileError : longint;
  29. NeedRecompile : boolean;
  30. NeedLibrary : boolean;
  31. NeededAfter : boolean;
  32. IsInteractive : boolean;
  33. IsKnownRunError,
  34. IsKnownCompileError : boolean;
  35. NoRun : boolean;
  36. UsesGraph : boolean;
  37. ShouldFail : boolean;
  38. Timeout : longint;
  39. Category : string;
  40. Note : string;
  41. Files : string;
  42. ConfigFileSrc : string;
  43. ConfigFileDst : string;
  44. WpoParas : string;
  45. WpoPasses : longint;
  46. DelFiles : string;
  47. end;
  48. Const
  49. DoVerbose : boolean = false;
  50. DoSQL : boolean = false;
  51. MaxLogSize : LongInt = 50000;
  52. procedure TrimB(var s:string);
  53. procedure TrimE(var s:string);
  54. function upper(const s : string) : string;
  55. procedure Verbose(lvl:TVerboseLevel;const s:string);
  56. function GetConfig(const fn:string;var r:TConfig):boolean;
  57. Function GetFileContents (FN : String) : String;
  58. const
  59. { Constants used in IsAbsolute function }
  60. TargetHasDosStyleDirectories : boolean = false;
  61. TargetAmigaLike : boolean = false;
  62. TargetIsMacOS : boolean = false;
  63. TargetIsUnix : boolean = false;
  64. { File path helper functions }
  65. function SplitPath(const s:string):string;
  66. function SplitBasePath(const s:string): string;
  67. Function SplitFileName(const s:string):string;
  68. Function SplitFileBase(const s:string):string;
  69. Function SplitFileExt(const s:string):string;
  70. Function FileExists (Const F : String) : Boolean;
  71. Function PathExists (Const F : String) : Boolean;
  72. Function IsAbsolute (Const F : String) : boolean;
  73. function GetToken(var s: string; Delims: TCharSet = [' ']):string;
  74. Implementation
  75. function GetToken(var s: string; Delims: TCharSet = [' ']):string;
  76. var
  77. i : longint;
  78. p: PChar;
  79. begin
  80. p:=PChar(s);
  81. i:=0;
  82. while (p^ <> #0) and not (p^ in Delims) do begin
  83. Inc(p);
  84. Inc(i);
  85. end;
  86. GetToken:=Copy(s,1,i);
  87. Delete(s,1,i+1);
  88. end;
  89. function SplitPath(const s:string):string;
  90. var
  91. i : longint;
  92. begin
  93. i:=Length(s);
  94. while (i>0) and not(s[i] in ['/','\'{$IFDEF MACOS},':'{$ENDIF}]) do
  95. dec(i);
  96. SplitPath:=Copy(s,1,i);
  97. end;
  98. function SplitBasePath(const s:string): string;
  99. var
  100. i : longint;
  101. begin
  102. i:=1;
  103. while (i<length(s)) and not(s[i] in ['/','\'{$IFDEF MACOS},':'{$ENDIF}]) do
  104. inc(i);
  105. if s[i] in ['/','\'{$IFDEF MACOS},':'{$ENDIF}] then
  106. dec(i);
  107. SplitBasePath:=Copy(s,1,i);
  108. end;
  109. Function SplitFileName(const s:string):string;
  110. var
  111. p : dirstr;
  112. n : namestr;
  113. e : extstr;
  114. begin
  115. FSplit(s,p,n,e);
  116. SplitFileName:=n+e;
  117. end;
  118. Function SplitFileBase(const s:string):string;
  119. var
  120. p : dirstr;
  121. n : namestr;
  122. e : extstr;
  123. begin
  124. FSplit(s,p,n,e);
  125. SplitFileBase:=n;
  126. end;
  127. Function SplitFileExt(const s:string):string;
  128. var
  129. p : dirstr;
  130. n : namestr;
  131. e : extstr;
  132. begin
  133. FSplit(s,p,n,e);
  134. SplitFileExt:=e;
  135. end;
  136. Function FileExists (Const F : String) : Boolean;
  137. {
  138. Returns True if the file exists, False if not.
  139. }
  140. Var
  141. info : searchrec;
  142. begin
  143. FindFirst (F,anyfile,Info);
  144. FileExists:=DosError=0;
  145. FindClose (Info);
  146. end;
  147. Function PathExists (Const F : String) : Boolean;
  148. {
  149. Returns True if the file exists, False if not.
  150. }
  151. Var
  152. info : searchrec;
  153. begin
  154. FindFirst (F,anyfile,Info);
  155. PathExists:=(DosError=0) and (Info.Attr and Directory=Directory);
  156. FindClose (Info);
  157. end;
  158. { extracted from rtl/macos/macutils.inc }
  159. function IsMacFullPath (const path: string): Boolean;
  160. begin
  161. if Pos(':', path) = 0 then {its partial}
  162. IsMacFullPath := false
  163. else if path[1] = ':' then
  164. IsMacFullPath := false
  165. else
  166. IsMacFullPath := true
  167. end;
  168. Function IsAbsolute (Const F : String) : boolean;
  169. {
  170. Returns True if the name F is a absolute file name
  171. }
  172. begin
  173. IsAbsolute:=false;
  174. if TargetHasDosStyleDirectories then
  175. begin
  176. if (F[1]='/') or (F[1]='\') then
  177. IsAbsolute:=true;
  178. if (Length(F)>2) and (F[2]=':') and ((F[3]='\') or (F[3]='/')) then
  179. IsAbsolute:=true;
  180. end
  181. else if TargetAmigaLike then
  182. begin
  183. if (length(F)>0) and (Pos(':',F) <> 0) then
  184. IsAbsolute:=true;
  185. end
  186. else if TargetIsMacOS then
  187. begin
  188. IsAbsolute:=IsMacFullPath(F);
  189. end
  190. { generic case }
  191. else if (F[1]='/') then
  192. IsAbsolute:=true;
  193. end;
  194. procedure Verbose(lvl:TVerboseLevel;const s:string);
  195. begin
  196. case lvl of
  197. V_Normal :
  198. writeln(s);
  199. V_Debug :
  200. if DoVerbose then
  201. writeln('Debug: ',s);
  202. V_SQL :
  203. if DoSQL then
  204. writeln('SQL: ',s);
  205. V_Warning :
  206. writeln('Warning: ',s);
  207. V_Error :
  208. begin
  209. writeln('Error: ',s);
  210. halt(1);
  211. end;
  212. V_Abort :
  213. begin
  214. writeln('Abort: ',s);
  215. halt(0);
  216. end;
  217. end;
  218. end;
  219. procedure TrimB(var s:string);
  220. begin
  221. while (s<>'') and (s[1] in [' ',#9]) do
  222. delete(s,1,1);
  223. end;
  224. procedure TrimE(var s:string);
  225. begin
  226. while (s<>'') and (s[length(s)] in [' ',#9]) do
  227. delete(s,length(s),1);
  228. end;
  229. function upper(const s : string) : string;
  230. var
  231. i,l : longint;
  232. begin
  233. L:=Length(S);
  234. SetLength(upper,l);
  235. for i:=1 to l do
  236. if s[i] in ['a'..'z'] then
  237. upper[i]:=char(byte(s[i])-32)
  238. else
  239. upper[i]:=s[i];
  240. end;
  241. function GetConfig(const fn:string;var r:TConfig):boolean;
  242. var
  243. t : text;
  244. part,code : integer;
  245. l : longint;
  246. s,res : string;
  247. function GetEntry(const entry:string):boolean;
  248. var
  249. i : longint;
  250. begin
  251. Getentry:=false;
  252. Res:='';
  253. if Upper(Copy(s,1,length(entry)))=Upper(entry) then
  254. begin
  255. Delete(s,1,length(entry));
  256. TrimB(s);
  257. if (s<>'') then
  258. begin
  259. if (s[1]='=') then
  260. begin
  261. delete(s,1,1);
  262. i:=pos('}',s);
  263. if i=0 then
  264. i:=255
  265. else
  266. dec(i);
  267. res:=Copy(s,1,i);
  268. TrimB(res);
  269. TrimE(res);
  270. end;
  271. Verbose(V_Debug,'Config: '+Entry+' = "'+Res+'"');
  272. GetEntry:=true;
  273. end;
  274. end;
  275. end;
  276. begin
  277. FillChar(r,sizeof(r),0);
  278. GetConfig:=false;
  279. Verbose(V_Debug,'Reading '+fn);
  280. assign(t,fn);
  281. {$I-}
  282. reset(t);
  283. {$I+}
  284. if ioresult<>0 then
  285. begin
  286. Verbose(V_Error,'Can''t open '+fn);
  287. exit;
  288. end;
  289. r.Note:='';
  290. while not eof(t) do
  291. begin
  292. readln(t,s);
  293. if Copy(s,1,3)=#$EF#$BB#$BF then
  294. delete(s,1,3);
  295. TrimB(s);
  296. if s<>'' then
  297. begin
  298. if s[1]='{' then
  299. begin
  300. delete(s,1,1);
  301. TrimB(s);
  302. if (s<>'') and (s[1]='%') then
  303. begin
  304. delete(s,1,1);
  305. if GetEntry('OPT') then
  306. r.NeedOptions:=res
  307. else
  308. if GetEntry('DELOPT') then
  309. r.DelOptions:=res
  310. else
  311. if GetEntry('TARGET') then
  312. r.NeedTarget:=res
  313. else
  314. if GetEntry('SKIPTARGET') then
  315. r.SkipTarget:=res
  316. else
  317. if GetEntry('CPU') then
  318. r.NeedCPU:=res
  319. else
  320. if GetEntry('SKIPCPU') then
  321. r.SkipCPU:=res
  322. else
  323. if GetEntry('SKIPEMU') then
  324. r.SkipEmu:=res
  325. else
  326. if GetEntry('VERSION') then
  327. r.MinVersion:=res
  328. else
  329. if GetEntry('MAXVERSION') then
  330. r.MaxVersion:=res
  331. else
  332. if GetEntry('RESULT') then
  333. Val(res,r.ResultCode,code)
  334. else
  335. if GetEntry('GRAPH') then
  336. r.UsesGraph:=true
  337. else
  338. if GetEntry('FAIL') then
  339. r.ShouldFail:=true
  340. else
  341. if GetEntry('RECOMPILE') then
  342. begin
  343. r.NeedRecompile:=true;
  344. r.RecompileOpt:=res;
  345. end
  346. else
  347. if GetEntry('NORUN') then
  348. r.NoRun:=true
  349. else
  350. if GetEntry('NEEDLIBRARY') then
  351. r.NeedLibrary:=true
  352. else
  353. if GetEntry('NEEDEDAFTER') then
  354. r.NeededAfter:=true
  355. else
  356. if GetEntry('KNOWNRUNERROR') then
  357. begin
  358. r.IsKnownRunError:=true;
  359. if res<>'' then
  360. begin
  361. val(res,l,code);
  362. if code>1 then
  363. begin
  364. part:=code;
  365. val(copy(res,1,code-1),l,code);
  366. delete(res,1,part);
  367. end;
  368. if code=0 then
  369. r.KnownRunError:=l;
  370. if res<>'' then
  371. r.KnownRunNote:=res;
  372. end;
  373. end
  374. else
  375. if GetEntry('KNOWNCOMPILEERROR') then
  376. begin
  377. r.IsKnownCompileError:=true;
  378. if res<>'' then
  379. begin
  380. val(res,l,code);
  381. if code>1 then
  382. begin
  383. part:=code;
  384. val(copy(res,1,code-1),l,code);
  385. delete(res,1,part);
  386. end;
  387. if code=0 then
  388. r.KnownCompileError:=l;
  389. if res<>'' then
  390. r.KnownCompileNote:=res;
  391. end;
  392. end
  393. else
  394. if GetEntry('INTERACTIVE') then
  395. r.IsInteractive:=true
  396. else
  397. if GetEntry('NOTE') then
  398. begin
  399. R.Note:='Note: '+res;
  400. Verbose(V_Normal,r.Note);
  401. end
  402. else
  403. if GetEntry('TIMEOUT') then
  404. Val(res,r.Timeout,code)
  405. else
  406. if GetEntry('FILES') then
  407. r.Files:=res
  408. else
  409. if GetEntry('CONFIGFILE') then
  410. begin
  411. l:=Pos(' ',res);
  412. if l>0 then
  413. begin
  414. r.ConfigFileSrc:=Copy(res,1,l-1);
  415. r.ConfigFileDst:=Copy(res,l+1,Length(res)-l+1);
  416. if r.ConfigFileSrc='' then
  417. Verbose(V_Error,'Config file source is empty');
  418. if r.ConfigFileDst='' then
  419. Verbose(V_Error,'Config file destination is empty');
  420. end
  421. else
  422. begin
  423. r.ConfigFileSrc:=res;
  424. r.ConfigFileDst:=res;
  425. end;
  426. end
  427. else
  428. if GetEntry('WPOPARAS') then
  429. r.wpoparas:=res
  430. else
  431. if GetEntry('WPOPASSES') then
  432. val(res,r.wpopasses,code)
  433. else
  434. if GetEntry('DELFILES') then
  435. r.DelFiles:=res
  436. else
  437. Verbose(V_Error,'Unknown entry: '+s);
  438. end;
  439. end
  440. else
  441. break;
  442. end;
  443. end;
  444. close(t);
  445. GetConfig:=true;
  446. end;
  447. Function GetFileContents (FN : String) : String;
  448. Var
  449. F : Text;
  450. S : String;
  451. begin
  452. Result:='';
  453. Assign(F,FN);
  454. {$I-}
  455. Reset(F);
  456. If IOResult<>0 then
  457. Exit;
  458. {$I+}
  459. While Not(EOF(F)) do
  460. begin
  461. ReadLn(F,S);
  462. if length(Result)<MaxLogSize then
  463. Result:=Result+S+LineEnding;
  464. end;
  465. Close(F);
  466. end;
  467. end.