testu.pp 13 KB

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