dotest.pp 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252
  1. {
  2. This file is part of the Free Pascal test suite.
  3. Copyright (c) 1999-2002 by the Free Pascal development team.
  4. This program makes the compilation and
  5. execution of individual test sources.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$H+}
  13. program dotest;
  14. uses
  15. dos,
  16. {$ifdef macos}
  17. macutils,
  18. {$endif}
  19. teststr,
  20. testu,
  21. redir,
  22. bench;
  23. {$ifdef go32v2}
  24. {$define LIMIT83FS}
  25. {$endif}
  26. {$ifdef os2}
  27. {$define LIMIT83FS}
  28. {$endif}
  29. type
  30. tcompinfo = (compver,comptarget,compcpu);
  31. tdelexecutable = (deBefore, deAfter);
  32. tdelexecutables = set of tdelexecutable;
  33. const
  34. ObjExt='o';
  35. PPUExt='ppu';
  36. {$ifdef UNIX}
  37. ExeExt='';
  38. {$else UNIX}
  39. {$ifdef MACOS}
  40. ExeExt='';
  41. {$else MACOS}
  42. ExeExt='exe';
  43. {$endif MACOS}
  44. {$endif UNIX}
  45. DefaultTimeout=60;
  46. var
  47. Config : TConfig;
  48. CompilerLogFile,
  49. ExeLogFile,
  50. LongLogfile,
  51. FailLogfile,
  52. RTLUnitsDir,
  53. TestOutputDir,
  54. OutputDir : string;
  55. CompilerBin,
  56. CompilerCPU,
  57. CompilerTarget,
  58. CompilerVersion,
  59. DefaultCompilerCPU,
  60. DefaultCompilerTarget,
  61. DefaultCompilerVersion : string;
  62. PPFile : string;
  63. PPFileInfo : string;
  64. TestName : string;
  65. const
  66. DoGraph : boolean = false;
  67. DoInteractive : boolean = false;
  68. DoExecute : boolean = false;
  69. DoKnown : boolean = false;
  70. DoAll : boolean = false;
  71. DoUsual : boolean = true;
  72. TargetDir : string = '';
  73. BenchmarkInfo : boolean = false;
  74. ExtraCompilerOpts : string = '';
  75. DelExecutable : TDelExecutables = [];
  76. RemoteAddr : string = '';
  77. RemotePath : string = '/tmp';
  78. RemotePara : string = '';
  79. rshprog : string = 'rsh';
  80. rcpprog : string = 'rcp';
  81. rquote : char = '''';
  82. UseTimeout : boolean = false;
  83. emulatorname : string = '';
  84. Function FileExists (Const F : String) : Boolean;
  85. {
  86. Returns True if the file exists, False if not.
  87. }
  88. Var
  89. info : searchrec;
  90. begin
  91. FindFirst (F,anyfile,Info);
  92. FileExists:=DosError=0;
  93. FindClose (Info);
  94. end;
  95. Function PathExists (Const F : String) : Boolean;
  96. {
  97. Returns True if the file exists, False if not.
  98. }
  99. Var
  100. info : searchrec;
  101. begin
  102. FindFirst (F,anyfile,Info);
  103. PathExists:=(DosError=0) and (Info.Attr and Directory=Directory);
  104. FindClose (Info);
  105. end;
  106. function ToStr(l:longint):string;
  107. var
  108. s : string;
  109. begin
  110. Str(l,s);
  111. ToStr:=s;
  112. end;
  113. function ToStrZero(l:longint;nbzero : byte):string;
  114. var
  115. s : string;
  116. begin
  117. Str(l,s);
  118. while length(s)<nbzero do
  119. s:='0'+s;
  120. ToStrZero:=s;
  121. end;
  122. function trimspace(const s:string):string;
  123. var
  124. i,j : longint;
  125. begin
  126. i:=length(s);
  127. while (i>0) and (s[i] in [#9,' ']) do
  128. dec(i);
  129. j:=1;
  130. while (j<i) and (s[j] in [#9,' ']) do
  131. inc(j);
  132. trimspace:=Copy(s,j,i-j+1);
  133. end;
  134. function IsInList(const entry,list:string):boolean;
  135. var
  136. i,istart : longint;
  137. begin
  138. IsInList:=false;
  139. i:=0;
  140. while (i<length(list)) do
  141. begin
  142. { Find list item }
  143. istart:=i+1;
  144. while (i<length(list)) and
  145. (list[i+1]<>',') do
  146. inc(i);
  147. if Upcase(entry)=Upcase(TrimSpace(Copy(list,istart,i-istart+1))) then
  148. begin
  149. IsInList:=true;
  150. exit;
  151. end;
  152. { skip , }
  153. inc(i);
  154. end;
  155. end;
  156. procedure SetPPFileInfo;
  157. Var
  158. info : searchrec;
  159. dt : DateTime;
  160. begin
  161. FindFirst (PPFile,anyfile,Info);
  162. If DosError=0 then
  163. begin
  164. UnpackTime(info.time,dt);
  165. PPFileInfo:=PPFile+' '+ToStr(dt.year)+'/'+ToStrZero(dt.month,2)+'/'+
  166. ToStrZero(dt.day,2)+' '+ToStrZero(dt.Hour,2)+':'+ToStrZero(dt.min,2)+':'+ToStrZero(dt.sec,2);
  167. end
  168. else
  169. PPFileInfo:=PPfile;
  170. FindClose (Info);
  171. end;
  172. function SplitPath(const s:string):string;
  173. var
  174. i : longint;
  175. begin
  176. i:=Length(s);
  177. while (i>0) and not(s[i] in ['/','\'{$IFDEF MACOS},':'{$ENDIF}]) do
  178. dec(i);
  179. SplitPath:=Copy(s,1,i);
  180. end;
  181. Function SplitFileName(const s:string):string;
  182. var
  183. p : dirstr;
  184. n : namestr;
  185. e : extstr;
  186. begin
  187. FSplit(s,p,n,e);
  188. SplitFileName:=n+e;
  189. end;
  190. function ForceExtension(Const HStr,ext:String):String;
  191. {
  192. Return a filename which certainly has the extension ext
  193. }
  194. var
  195. j : longint;
  196. begin
  197. j:=length(Hstr);
  198. while (j>0) and (Hstr[j]<>'.') do
  199. dec(j);
  200. if j=0 then
  201. j:=255;
  202. if Ext<>'' then
  203. ForceExtension:=Copy(Hstr,1,j-1)+'.'+Ext
  204. else
  205. ForceExtension:=Copy(Hstr,1,j-1);
  206. end;
  207. procedure mkdirtree(const s:string);
  208. var
  209. hs : string;
  210. begin
  211. if s='' then
  212. exit;
  213. if s[length(s)] in ['\','/'{$IFDEF MACOS},':'{$ENDIF}] then
  214. hs:=Copy(s,1,length(s)-1)
  215. else
  216. hs:=s;
  217. if not PathExists(hs) then
  218. begin
  219. { Try parent first }
  220. mkdirtree(SplitPath(hs));
  221. { make this dir }
  222. Verbose(V_Debug,'Making Directory '+s);
  223. {$I-}
  224. mkdir(s);
  225. {$I+}
  226. ioresult;
  227. end;
  228. end;
  229. Function RemoveFile(const f:string):boolean;
  230. var
  231. g : file;
  232. begin
  233. assign(g,f);
  234. {$I-}
  235. erase(g);
  236. {$I+}
  237. RemoveFile:=(ioresult=0);
  238. end;
  239. procedure Copyfile(const fn1,fn2:string;append:boolean);
  240. const
  241. bufsize = 16384;
  242. var
  243. f,g : file;
  244. i : longint;
  245. buf : pointer;
  246. begin
  247. if Append then
  248. Verbose(V_Debug,'Appending '+fn1+' to '+fn2)
  249. else
  250. Verbose(V_Debug,'Copying '+fn1+' to '+fn2);
  251. assign(f,fn1);
  252. assign(g,fn2);
  253. {$I-}
  254. reset(f,1);
  255. {$I+}
  256. if ioresult<>0 then
  257. Verbose(V_Error,'Can''t open '+fn1);
  258. if append then
  259. begin
  260. {$I-}
  261. reset(g,1);
  262. {$I+}
  263. if ioresult<>0 then
  264. append:=false
  265. else
  266. seek(g,filesize(g));
  267. end;
  268. if not append then
  269. begin
  270. {$I-}
  271. rewrite(g,1);
  272. {$I+}
  273. if ioresult<>0 then
  274. Verbose(V_Error,'Can''t open '+fn2+' for output');
  275. end;
  276. getmem(buf,bufsize);
  277. repeat
  278. blockread(f,buf^,bufsize,i);
  279. blockwrite(g,buf^,i);
  280. until i<bufsize;
  281. freemem(buf,bufsize);
  282. close(f);
  283. close(g);
  284. end;
  285. procedure AddLog(const logfile,s:string);
  286. var
  287. t : text;
  288. begin
  289. assign(t,logfile);
  290. {$I-}
  291. append(t);
  292. {$I+}
  293. if ioresult<>0 then
  294. begin
  295. {$I-}
  296. rewrite(t);
  297. {$I+}
  298. if ioresult<>0 then
  299. Verbose(V_Abort,'Can''t append to '+logfile);
  300. end;
  301. writeln(t,s);
  302. close(t);
  303. end;
  304. function GetCompilerInfo(c:tcompinfo):boolean;
  305. function GetToken(var s:string):string;
  306. var
  307. i : longint;
  308. begin
  309. i:=pos(' ',s);
  310. if i=0 then
  311. i:=length(s)+1;
  312. GetToken:=Copy(s,1,i-1);
  313. Delete(s,1,i);
  314. end;
  315. var
  316. t : text;
  317. hs : string;
  318. begin
  319. GetCompilerInfo:=false;
  320. { Try to get all information in one call, this is
  321. supported in 1.1. Older compilers 1.0.x will only
  322. return the first info }
  323. case c of
  324. compver :
  325. begin
  326. if DefaultCompilerVersion<>'' then
  327. begin
  328. GetCompilerInfo:=true;
  329. exit;
  330. end;
  331. hs:='-iVTPTO';
  332. end;
  333. compcpu :
  334. begin
  335. if DefaultCompilerCPU<>'' then
  336. begin
  337. GetCompilerInfo:=true;
  338. exit;
  339. end;
  340. hs:='-iTPTOV';
  341. end;
  342. comptarget :
  343. begin
  344. if DefaultCompilerTarget<>'' then
  345. begin
  346. GetCompilerInfo:=true;
  347. exit;
  348. end;
  349. hs:='-iTOTPV';
  350. end;
  351. end;
  352. ExecuteRedir(CompilerBin,hs,'','out','');
  353. assign(t,'out');
  354. {$I-}
  355. reset(t);
  356. readln(t,hs);
  357. close(t);
  358. erase(t);
  359. {$I+}
  360. if ioresult<>0 then
  361. Verbose(V_Error,'Can''t get Compiler Info')
  362. else
  363. begin
  364. Verbose(V_Debug,'Retrieved Compiler Info: "'+hs+'"');
  365. case c of
  366. compver :
  367. begin
  368. DefaultCompilerVersion:=GetToken(hs);
  369. DefaultCompilerCPU:=GetToken(hs);
  370. DefaultCompilerTarget:=GetToken(hs);
  371. end;
  372. compcpu :
  373. begin
  374. DefaultCompilerCPU:=GetToken(hs);
  375. DefaultCompilerTarget:=GetToken(hs);
  376. DefaultCompilerVersion:=GetToken(hs);
  377. end;
  378. comptarget :
  379. begin
  380. DefaultCompilerTarget:=GetToken(hs);
  381. DefaultCompilerCPU:=GetToken(hs);
  382. DefaultCompilerVersion:=GetToken(hs);
  383. end;
  384. end;
  385. GetCompilerInfo:=true;
  386. end;
  387. end;
  388. function GetCompilerVersion:boolean;
  389. begin
  390. if CompilerVersion='' then
  391. begin
  392. GetCompilerVersion:=GetCompilerInfo(compver);
  393. CompilerVersion:=DefaultCompilerVersion;
  394. end
  395. else
  396. GetCompilerVersion:=true;
  397. if GetCompilerVersion then
  398. Verbose(V_Debug,'Compiler Version: "'+CompilerVersion+'"');
  399. end;
  400. function GetCompilerCPU:boolean;
  401. begin
  402. if CompilerCPU='' then
  403. begin
  404. GetCompilerCPU:=GetCompilerInfo(compcpu);
  405. CompilerCPU:=DefaultCompilerCPU;
  406. end
  407. else
  408. GetCompilerCPU:=true;
  409. if GetCompilerCPU then
  410. Verbose(V_Debug,'Compiler CPU: "'+CompilerCPU+'"');
  411. end;
  412. function GetCompilerTarget:boolean;
  413. begin
  414. if CompilerTarget='' then
  415. begin
  416. GetCompilerTarget:=GetCompilerInfo(comptarget);
  417. CompilerTarget:=DefaultCompilerTarget;
  418. end
  419. else
  420. GetCompilerTarget:=true;
  421. if GetCompilerTarget then
  422. Verbose(V_Debug,'Compiler Target: "'+CompilerTarget+'"');
  423. end;
  424. function CompilerFullTarget:string;
  425. begin
  426. CompilerFullTarget:=CompilerCPU+'-'+CompilerTarget;
  427. end;
  428. function OutputFileName(Const s,ext:String):String;
  429. begin
  430. {$ifndef macos}
  431. OutputFileName:=OutputDir+'/'+ForceExtension(s,ext);
  432. {$else macos}
  433. OutputFileName:=ConcatMacPath(OutputDir,ForceExtension(s,ext));
  434. {$endif macos}
  435. end;
  436. function TestOutputFileName(Const s,ext:String):String;
  437. begin
  438. {$ifndef macos}
  439. TestOutputFileName:=TestOutputDir+'/'+ForceExtension(SplitFileName(s),ext);
  440. {$else macos}
  441. TestOutputFileName:=ConcatMacPath(TestOutputDir,ForceExtension(SplitFileName(s),ext));
  442. {$endif macos}
  443. end;
  444. function ExitWithInternalError(const OutName:string):boolean;
  445. var
  446. t : text;
  447. s : string;
  448. begin
  449. ExitWithInternalError:=false;
  450. { open logfile }
  451. assign(t,Outname);
  452. {$I-}
  453. reset(t);
  454. {$I+}
  455. if ioresult<>0 then
  456. exit;
  457. while not eof(t) do
  458. begin
  459. readln(t,s);
  460. if pos('Fatal: Internal error ',s)>0 then
  461. begin
  462. ExitWithInternalError:=true;
  463. break;
  464. end;
  465. end;
  466. close(t);
  467. end;
  468. function RunCompiler:boolean;
  469. var
  470. args : string;
  471. execres : boolean;
  472. begin
  473. RunCompiler:=false;
  474. args:='-n -T'+CompilerTarget+' -Fu'+RTLUnitsDir;
  475. args:=args+' -FE'+TestOutputDir;
  476. {$ifdef macos}
  477. args:=args+' -WT '; {tests should be compiled as MPWTool}
  478. {$endif macos}
  479. if ExtraCompilerOpts<>'' then
  480. args:=args+ExtraCompilerOpts;
  481. {$ifdef unix}
  482. { Add runtime library path to current dir to find .so files }
  483. if Config.NeedLibrary then
  484. {$ifndef darwin}
  485. args:=args+' -Fl'+TestOutputDir+' ''-k-rpath .''';
  486. {$else darwin}
  487. args:=args+' -Fl'+TestOutputDir;
  488. {$endif darwin}
  489. {$endif unix}
  490. if Config.NeedOptions<>'' then
  491. args:=args+' '+Config.NeedOptions;
  492. args:=args+' '+ppfile;
  493. Verbose(V_Debug,'Executing '+compilerbin+' '+args);
  494. { also get the output from as and ld that writes to stderr sometimes }
  495. {$ifndef macos}
  496. execres:=ExecuteRedir(CompilerBin,args,'',CompilerLogFile,'stdout');
  497. {$else macos}
  498. {Due to that Toolserver is not reentrant, we have to asm and link via script.}
  499. execres:=ExecuteRedir(CompilerBin,'-s '+args,'',CompilerLogFile,'stdout');
  500. if execres then
  501. execres:=ExecuteRedir(TestOutputDir + ':ppas','','',CompilerLogFile,'stdout');
  502. {$endif macos}
  503. Verbose(V_Debug,'Exitcode '+ToStr(ExecuteResult));
  504. { Error during execution? }
  505. if (not execres) and (ExecuteResult=0) then
  506. begin
  507. AddLog(FailLogFile,TestName);
  508. AddLog(ResLogFile,failed_to_compile+PPFileInfo);
  509. AddLog(LongLogFile,line_separation);
  510. AddLog(LongLogFile,failed_to_compile+PPFileInfo);
  511. CopyFile(CompilerLogFile,LongLogFile,true);
  512. { avoid to try again }
  513. AddLog(ExeLogFile,failed_to_compile+PPFileInfo);
  514. Verbose(V_Abort,'IOStatus: '+ToStr(IOStatus));
  515. exit;
  516. end;
  517. { Check for internal error }
  518. if ExitWithInternalError(CompilerLogFile) then
  519. begin
  520. AddLog(FailLogFile,TestName);
  521. if Config.Note<>'' then
  522. AddLog(FailLogFile,Config.Note);
  523. AddLog(ResLogFile,failed_to_compile+PPFileInfo+' internalerror generated');
  524. AddLog(LongLogFile,line_separation);
  525. AddLog(LongLogFile,failed_to_compile+PPFileInfo);
  526. if Config.Note<>'' then
  527. AddLog(LongLogFile,Config.Note);
  528. CopyFile(CompilerLogFile,LongLogFile,true);
  529. { avoid to try again }
  530. AddLog(ExeLogFile,'Failed to compile '+PPFileInfo);
  531. Verbose(V_Abort,'Internal error in compiler');
  532. exit;
  533. end;
  534. { Should the compile fail ? }
  535. if Config.ShouldFail then
  536. begin
  537. if ExecuteResult<>0 then
  538. begin
  539. AddLog(ResLogFile,success_compilation_failed+PPFileInfo);
  540. { avoid to try again }
  541. AddLog(ExeLogFile,success_compilation_failed+PPFileInfo);
  542. RunCompiler:=true;
  543. end
  544. else
  545. begin
  546. AddLog(FailLogFile,TestName);
  547. if Config.Note<>'' then
  548. AddLog(FailLogFile,Config.Note);
  549. AddLog(ResLogFile,failed_compilation_successful+PPFileInfo);
  550. AddLog(LongLogFile,line_separation);
  551. AddLog(LongLogFile,failed_compilation_successful+PPFileInfo);
  552. { avoid to try again }
  553. AddLog(ExeLogFile,failed_compilation_successful+PPFileInfo);
  554. if Config.Note<>'' then
  555. AddLog(LongLogFile,Config.Note);
  556. CopyFile(CompilerLogFile,LongLogFile,true);
  557. end;
  558. end
  559. else
  560. begin
  561. if (ExecuteResult<>0) and
  562. (((Config.KnownCompileNote<>'') and (Config.KnownCompileError=0)) or
  563. ((Config.KnownCompileError<>0) and (ExecuteResult=Config.KnownCompileError))) then
  564. begin
  565. AddLog(FailLogFile,TestName+known_problem+Config.KnownCompileNote);
  566. AddLog(ResLogFile,failed_to_run+PPFileInfo+known_problem+Config.KnownCompileNote);
  567. AddLog(LongLogFile,line_separation);
  568. AddLog(LongLogFile,known_problem+Config.KnownCompileNote);
  569. AddLog(LongLogFile,failed_to_compile+PPFileInfo+' ('+ToStr(ExecuteResult)+')');
  570. Copyfile(CompilerLogFile,LongLogFile,true);
  571. Verbose(V_Abort,known_problem+'exitcode: '+ToStr(ExecuteResult));
  572. end
  573. else if ExecuteResult<>0 then
  574. begin
  575. AddLog(FailLogFile,TestName);
  576. if Config.Note<>'' then
  577. AddLog(FailLogFile,Config.Note);
  578. AddLog(ResLogFile,failed_to_compile+PPFileInfo);
  579. AddLog(LongLogFile,line_separation);
  580. AddLog(LongLogFile,failed_to_compile+PPFileInfo);
  581. if Config.Note<>'' then
  582. AddLog(LongLogFile,Config.Note);
  583. CopyFile(CompilerLogFile,LongLogFile,true);
  584. { avoid to try again }
  585. AddLog(ExeLogFile,failed_to_compile+PPFileInfo);
  586. Verbose(V_Abort,'Exitcode: '+ToStr(ExecuteResult)+' (expected 0)');
  587. end
  588. else
  589. begin
  590. AddLog(ResLogFile,successfully_compiled+PPFileInfo);
  591. RunCompiler:=true;
  592. end;
  593. end;
  594. end;
  595. function CheckTestExitCode(const OutName:string):boolean;
  596. var
  597. t : text;
  598. s : string;
  599. i,code : integer;
  600. begin
  601. CheckTestExitCode:=false;
  602. { open logfile }
  603. assign(t,Outname);
  604. {$I-}
  605. reset(t);
  606. {$I+}
  607. if ioresult<>0 then
  608. exit;
  609. while not eof(t) do
  610. begin
  611. readln(t,s);
  612. i:=pos('TestExitCode: ',s);
  613. if i>0 then
  614. begin
  615. delete(s,1,i+14-1);
  616. val(s,ExecuteResult,code);
  617. if code=0 then;
  618. CheckTestExitCode:=true;
  619. break;
  620. end;
  621. end;
  622. close(t);
  623. end;
  624. function RunExecutable:boolean;
  625. const
  626. {$ifdef unix}
  627. CurrDir = './';
  628. {$else}
  629. CurrDir = '';
  630. {$endif}
  631. var
  632. s,
  633. OldDir,
  634. FullExeLogFile,
  635. TestRemoteExe,
  636. TestExe : string;
  637. execcmd : string;
  638. execres : boolean;
  639. EndTicks,
  640. StartTicks : int64;
  641. function ExecuteRemote(const prog,args:string):boolean;
  642. begin
  643. Verbose(V_Debug,'RemoteExecuting '+Prog+' '+args);
  644. StartTicks:=GetMicroSTicks;
  645. ExecuteRemote:=ExecuteRedir(prog,args,'',EXELogFile,'stdout');
  646. EndTicks:=GetMicroSTicks;
  647. end;
  648. function ExecuteEmulated(const prog,args:string):boolean;
  649. begin
  650. Verbose(V_Debug,'EmulatorExecuting '+Prog+' '+args);
  651. StartTicks:=GetMicroSTicks;
  652. ExecuteEmulated:=ExecuteRedir(prog,args,'',FullExeLogFile,'stdout');
  653. EndTicks:=GetMicroSTicks;
  654. end;
  655. begin
  656. RunExecutable:=false;
  657. execres:=true;
  658. { when remote testing, leave extension away }
  659. if RemoteAddr='' then
  660. TestExe:=OutputFileName(PPFile,ExeExt)
  661. else
  662. TestExe:=OutputFileName(PPFile,'');
  663. if EmulatorName<>'' then
  664. begin
  665. { Get full name out log file, because we change the directory during
  666. execution }
  667. FullExeLogFile:=FExpand(EXELogFile);
  668. {$I-}
  669. GetDir(0,OldDir);
  670. ChDir(TestOutputDir);
  671. {$I+}
  672. ioresult;
  673. s:=CurrDir+SplitFileName(TestExe);
  674. execres:=ExecuteEmulated(EmulatorName,s);
  675. {$I-}
  676. ChDir(OldDir);
  677. {$I+}
  678. end
  679. else if RemoteAddr<>'' then
  680. begin
  681. { We don't want to create subdirs, remove paths from the test }
  682. TestRemoteExe:=RemotePath+'/'+SplitFileName(TestExe);
  683. if deBefore in DelExecutable then
  684. ExecuteRemote(rshprog,RemotePara+' '+RemoteAddr+' rm -f '+TestRemoteExe);
  685. ExecuteRemote(rcpprog,RemotePara+' '+TestExe+' '+RemoteAddr+':'+TestRemoteExe);
  686. { rsh doesn't pass the exitcode, use a second command to print the exitcode
  687. on the remoteshell to stdout }
  688. execcmd:=RemotePara+' '+RemoteAddr+' '+rquote+'chmod 755 '+TestRemoteExe+
  689. ' ; cd '+RemotePath+' ;';
  690. if UseTimeout then
  691. begin
  692. execcmd:=execcmd+'timeout -9 ';
  693. if Config.Timeout=0 then
  694. Config.Timeout:=DefaultTimeout;
  695. str(Config.Timeout,s);
  696. execcmd:=execcmd+s;
  697. end;
  698. execcmd:=execcmd+' '+TestRemoteExe+' ; echo "TestExitCode: $?"';
  699. if deAfter in DelExecutable then
  700. execcmd:=execcmd+' ; rm -f '+TestRemoteExe;
  701. execcmd:=execcmd+rquote;
  702. execres:=ExecuteRemote(rshprog,execcmd);
  703. { Check for TestExitCode error in output, sets ExecuteResult }
  704. CheckTestExitCode(EXELogFile);
  705. end
  706. else
  707. begin
  708. { Get full name out log file, because we change the directory during
  709. execution }
  710. FullExeLogFile:=FExpand(EXELogFile);
  711. Verbose(V_Debug,'Executing '+TestExe);
  712. {$I-}
  713. GetDir(0,OldDir);
  714. ChDir(TestOutputDir);
  715. {$I+}
  716. ioresult;
  717. { don't redirect interactive and graph programs }
  718. StartTicks:=GetMicroSTicks;
  719. if Config.IsInteractive or Config.UsesGraph then
  720. execres:=ExecuteRedir(CurrDir+SplitFileName(TestExe),'','','','')
  721. else
  722. execres:=ExecuteRedir(CurrDir+SplitFileName(TestExe),'','',FullExeLogFile,'stdout');
  723. EndTicks:=GetMicroSTicks;
  724. {$I-}
  725. ChDir(OldDir);
  726. {$I+}
  727. ioresult;
  728. end;
  729. { Error during execution? }
  730. Verbose(V_Debug,'Exitcode '+ToStr(ExecuteResult));
  731. if BenchmarkInfo then
  732. begin
  733. Verbose(V_Normal,'Execution took '+ToStr(EndTicks-StartTicks)+' us');
  734. end;
  735. if (not execres) and (ExecuteResult=0) then
  736. begin
  737. AddLog(FailLogFile,TestName);
  738. AddLog(ResLogFile,failed_to_run+PPFileInfo);
  739. AddLog(LongLogFile,line_separation);
  740. AddLog(LongLogFile,failed_to_run+PPFileInfo);
  741. CopyFile(EXELogFile,LongLogFile,true);
  742. { avoid to try again }
  743. AddLog(ExeLogFile,failed_to_run+PPFileInfo);
  744. Verbose(V_Abort,'IOStatus: '+ToStr(IOStatus));
  745. exit;
  746. end;
  747. if ExecuteResult<>Config.ResultCode then
  748. begin
  749. if (ExecuteResult<>0) and
  750. (ExecuteResult=Config.KnownRunError) then
  751. begin
  752. AddLog(FailLogFile,TestName+known_problem+Config.KnownRunNote);
  753. AddLog(ResLogFile,failed_to_run+PPFileInfo+known_problem+Config.KnownRunNote);
  754. AddLog(LongLogFile,line_separation);
  755. AddLog(LongLogFile,known_problem+Config.KnownRunNote);
  756. AddLog(LongLogFile,failed_to_run+PPFileInfo+' ('+ToStr(ExecuteResult)+')');
  757. Copyfile(EXELogFile,LongLogFile,true);
  758. Verbose(V_Abort,known_problem+'exitcode: '+ToStr(ExecuteResult)+' (expected '+ToStr(Config.ResultCode)+')');
  759. end
  760. else
  761. begin
  762. AddLog(FailLogFile,TestName);
  763. AddLog(ResLogFile,failed_to_run+PPFileInfo);
  764. AddLog(LongLogFile,line_separation);
  765. AddLog(LongLogFile,failed_to_run+PPFileInfo+' ('+ToStr(ExecuteResult)+')');
  766. Copyfile(EXELogFile,LongLogFile,true);
  767. Verbose(V_Abort,'Exitcode: '+ToStr(ExecuteResult)+' (expected '+ToStr(Config.ResultCode)+')');
  768. end
  769. end
  770. else
  771. begin
  772. AddLog(ResLogFile,successfully_run+PPFileInfo);
  773. RunExecutable:=true;
  774. end;
  775. if deAfter in DelExecutable then
  776. begin
  777. Verbose(V_Debug,'Deleting executable '+TestExe);
  778. RemoveFile(TestExe);
  779. RemoveFile(ForceExtension(TestExe,ObjExt));
  780. RemoveFile(ForceExtension(TestExe,PPUExt));
  781. end;
  782. end;
  783. procedure getargs;
  784. var
  785. ch : char;
  786. para : string;
  787. i,j : longint;
  788. procedure helpscreen;
  789. begin
  790. writeln('dotest [Options] <File>');
  791. writeln;
  792. writeln('Options can be:');
  793. writeln(' -B delete executable before remote upload');
  794. writeln(' -C<compiler> set compiler to use');
  795. writeln(' -V verbose');
  796. writeln(' -E execute test also');
  797. writeln(' -X don''t use COMSPEC');
  798. writeln(' -A include ALL tests');
  799. writeln(' -G include graph tests');
  800. writeln(' -K include known bug tests');
  801. writeln(' -I include interactive tests');
  802. writeln(' -O use timeout wrapper for (remote) execution');
  803. writeln(' -M<emulator> run the tests using the given emulator');
  804. writeln(' -R<remote> run the tests remotely with the given rsh/ssh address');
  805. writeln(' -S use ssh instead of rsh');
  806. writeln(' -T[cpu-]<os> run tests for target cpu and os');
  807. writeln(' -P<path> path to the tests tree on the remote machine');
  808. writeln(' -U<remotepara>');
  809. writeln(' pass additional parameter to remote program. Multiple -U can be used');
  810. writeln(' -V be verbose');
  811. writeln(' -W use putty compatible file names when testing (plink and pscp)');
  812. writeln(' -Y<opts> extra options passed to the compiler. Several -Y<opt> can be given.');
  813. writeln(' -Z remove temporary files (executable,ppu,o)');
  814. halt(1);
  815. end;
  816. begin
  817. PPFile:='';
  818. if exeext<>'' then
  819. CompilerBin:='ppc386.'+exeext
  820. else
  821. CompilerBin:='ppc386';
  822. for i:=1 to paramcount do
  823. begin
  824. para:=Paramstr(i);
  825. if (para[1]='-') then
  826. begin
  827. ch:=Upcase(para[2]);
  828. delete(para,1,2);
  829. case ch of
  830. 'A' :
  831. begin
  832. DoGraph:=true;
  833. DoInteractive:=true;
  834. DoKnown:=true;
  835. DoAll:=true;
  836. end;
  837. 'B' : Include(DelExecutable,deBefore);
  838. 'C' : CompilerBin:=Para;
  839. 'E' : DoExecute:=true;
  840. 'G' : begin
  841. DoGraph:=true;
  842. if para='-' then
  843. DoUsual:=false;
  844. end;
  845. 'I' : begin
  846. DoInteractive:=true;
  847. if para='-' then
  848. DoUsual:=false;
  849. end;
  850. 'K' : begin
  851. DoKnown:=true;
  852. if para='-' then
  853. DoUsual:=false;
  854. end;
  855. 'M' : EmulatorName:=Para;
  856. 'O' : UseTimeout:=true;
  857. 'P' : RemotePath:=Para;
  858. 'R' : RemoteAddr:=Para;
  859. 'S' :
  860. begin
  861. rshprog:='ssh';
  862. rcpprog:='scp';
  863. end;
  864. 'T' :
  865. begin
  866. j:=Pos('-',Para);
  867. if j>0 then
  868. begin
  869. CompilerCPU:=Copy(Para,1,j-1);
  870. CompilerTarget:=Copy(Para,j+1,255);
  871. end
  872. else
  873. CompilerTarget:=Para
  874. end;
  875. 'U' :
  876. RemotePara:=RemotePara+' '+Para;
  877. 'V' : DoVerbose:=true;
  878. 'W' :
  879. begin
  880. rshprog:='plink';
  881. rcpprog:='pscp';
  882. rquote:=' ';
  883. end;
  884. 'X' : UseComSpec:=false;
  885. 'Y' : ExtraCompilerOpts:= ExtraCompilerOpts +' '+ Para;
  886. 'Z' : Include(DelExecutable,deAfter);
  887. end;
  888. end
  889. else
  890. begin
  891. If PPFile<>'' then
  892. HelpScreen;
  893. PPFile:=ForceExtension(Para,'pp');
  894. end;
  895. end;
  896. if (PPFile='') then
  897. HelpScreen;
  898. { disable graph,interactive when running remote }
  899. if RemoteAddr<>'' then
  900. begin
  901. DoGraph:=false;
  902. DoInteractive:=false;
  903. end;
  904. SetPPFileInfo;
  905. TestName:=Copy(PPFile,1,Pos('.pp',PPFile)-1);
  906. Verbose(V_Debug,'Running test '+TestName+', file '+PPFile);
  907. end;
  908. procedure RunTest;
  909. var
  910. PPDir : string;
  911. Res : boolean;
  912. begin
  913. Res:=GetConfig(ppfile,Config);
  914. if Res then
  915. begin
  916. Res:=GetCompilerCPU;
  917. Res:=GetCompilerTarget;
  918. {$ifndef MACOS}
  919. RTLUnitsDir:='units/'+{$ifdef LIMIT83FS}CompilerTarget{$else}CompilerFullTarget{$endif};
  920. {$else MACOS}
  921. RTLUnitsDir:=':units:'+CompilerFullTarget;
  922. {$endif MACOS}
  923. if not PathExists(RTLUnitsDir) then
  924. Verbose(V_Abort,'Unit path "'+RTLUnitsDir+'" does not exists');
  925. {$ifndef MACOS}
  926. OutputDir:='output/'+{$ifdef LIMIT83FS}CompilerTarget{$else}CompilerFullTarget{$endif};
  927. {$else MACOS}
  928. OutputDir:=':output:'+CompilerFullTarget;
  929. {$endif MACOS}
  930. if not PathExists(OutputDir) then
  931. Verbose(V_Abort,'Output path "'+OutputDir+'" does not exists');
  932. { Global log files }
  933. ResLogFile:=OutputFileName('log','');
  934. LongLogFile:=OutputFileName('longlog','');
  935. FailLogFile:=OutputFileName('faillist','');
  936. { Make subdir in output if needed }
  937. PPDir:=SplitPath(PPFile);
  938. if PPDir[length(PPDir)] in ['/','\'{$ifdef MACOS},':'{$endif MACOS}] then
  939. Delete(PPDir,length(PPDir),1);
  940. if PPDir<>'' then
  941. begin
  942. {$ifndef MACOS}
  943. TestOutputDir:=OutputDir+'/'+PPDir;
  944. {$else MACOS}
  945. TestOutputDir:=OutputDir+PPDir;
  946. {$endif MACOS}
  947. mkdirtree(TestOutputDir);
  948. end
  949. else
  950. TestOutputDir:=OutputDir;
  951. { Per test logfiles }
  952. CompilerLogFile:=TestOutputFileName(SplitFileName(PPFile),'log');
  953. ExeLogFile:=TestOutputFileName(SplitFileName(PPFile),'elg');
  954. Verbose(V_Debug,'Using Compiler logfile: '+CompilerLogFile);
  955. Verbose(V_Debug,'Using Execution logfile: '+ExeLogFile);
  956. end;
  957. if Res then
  958. begin
  959. if Config.UsesGraph and (not DoGraph) then
  960. begin
  961. AddLog(ResLogFile,skipping_graph_test+PPFileInfo);
  962. { avoid a second attempt by writing to elg file }
  963. AddLog(EXELogFile,skipping_graph_test+PPFileInfo);
  964. Verbose(V_Abort,skipping_graph_test);
  965. Res:=false;
  966. end;
  967. end;
  968. if Res then
  969. begin
  970. if Config.IsInteractive and (not DoInteractive) then
  971. begin
  972. { avoid a second attempt by writing to elg file }
  973. AddLog(EXELogFile,skipping_interactive_test+PPFileInfo);
  974. AddLog(ResLogFile,skipping_interactive_test+PPFileInfo);
  975. Verbose(V_Abort,skipping_interactive_test);
  976. Res:=false;
  977. end;
  978. end;
  979. if Res then
  980. begin
  981. if Config.IsKnownCompileError and (not DoKnown) then
  982. begin
  983. { avoid a second attempt by writing to elg file }
  984. AddLog(EXELogFile,skipping_known_bug+PPFileInfo);
  985. AddLog(ResLogFile,skipping_known_bug+PPFileInfo);
  986. Verbose(V_Abort,skipping_known_bug);
  987. Res:=false;
  988. end;
  989. end;
  990. if Res and not DoUsual then
  991. res:=(Config.IsInteractive and DoInteractive) or
  992. (Config.IsKnownRunError and DoKnown) or
  993. (Config.UsesGraph and DoGraph);
  994. if Res then
  995. begin
  996. if (Config.MinVersion<>'') and not DoAll then
  997. begin
  998. Verbose(V_Debug,'Required compiler version: '+Config.MinVersion);
  999. Res:=GetCompilerVersion;
  1000. if CompilerVersion<Config.MinVersion then
  1001. begin
  1002. { avoid a second attempt by writing to elg file }
  1003. AddLog(EXELogFile,skipping_compiler_version_too_low+PPFileInfo);
  1004. AddLog(ResLogFile,skipping_compiler_version_too_low+PPFileInfo);
  1005. Verbose(V_Abort,'Compiler version too low '+CompilerVersion+' < '+Config.MinVersion);
  1006. Res:=false;
  1007. end;
  1008. end;
  1009. end;
  1010. if Res then
  1011. begin
  1012. if (Config.MaxVersion<>'') and not DoAll then
  1013. begin
  1014. Verbose(V_Debug,'Highest compiler version: '+Config.MaxVersion);
  1015. Res:=GetCompilerVersion;
  1016. if CompilerVersion>Config.MaxVersion then
  1017. begin
  1018. { avoid a second attempt by writing to elg file }
  1019. AddLog(EXELogFile,skipping_compiler_version_too_high+PPFileInfo);
  1020. AddLog(ResLogFile,skipping_compiler_version_too_high+PPFileInfo);
  1021. Verbose(V_Abort,'Compiler version too high '+CompilerVersion+' > '+Config.MaxVersion);
  1022. Res:=false;
  1023. end;
  1024. end;
  1025. end;
  1026. if Res then
  1027. begin
  1028. if Config.NeedCPU<>'' then
  1029. begin
  1030. Verbose(V_Debug,'Required compiler cpu: '+Config.NeedCPU);
  1031. if not IsInList(CompilerCPU,Config.NeedCPU) then
  1032. begin
  1033. { avoid a second attempt by writing to elg file }
  1034. AddLog(EXELogFile,skipping_other_cpu+PPFileInfo);
  1035. AddLog(ResLogFile,skipping_other_cpu+PPFileInfo);
  1036. Verbose(V_Abort,'Compiler cpu "'+CompilerCPU+'" is not in list "'+Config.NeedCPU+'"');
  1037. Res:=false;
  1038. end;
  1039. end;
  1040. end;
  1041. if Res then
  1042. begin
  1043. if Config.SkipCPU<>'' then
  1044. begin
  1045. Verbose(V_Debug,'Skip compiler cpu: '+Config.SkipCPU);
  1046. if IsInList(CompilerCPU,Config.SkipCPU) then
  1047. begin
  1048. { avoid a second attempt by writing to elg file }
  1049. AddLog(EXELogFile,skipping_other_cpu+PPFileInfo);
  1050. AddLog(ResLogFile,skipping_other_cpu+PPFileInfo);
  1051. Verbose(V_Abort,'Compiler cpu "'+CompilerCPU+'" is in list "'+Config.SkipCPU+'"');
  1052. Res:=false;
  1053. end;
  1054. end;
  1055. end;
  1056. if Res then
  1057. begin
  1058. if Config.SkipEmu<>'' then
  1059. begin
  1060. Verbose(V_Debug,'Skip emulator: '+emulatorname);
  1061. if IsInList(emulatorname,Config.SkipEmu) then
  1062. begin
  1063. { avoid a second attempt by writing to elg file }
  1064. AddLog(EXELogFile,skipping_other_cpu+PPFileInfo);
  1065. AddLog(ResLogFile,skipping_other_cpu+PPFileInfo);
  1066. Verbose(V_Abort,'Emulator "'+emulatorname+'" is in list "'+Config.SkipEmu+'"');
  1067. Res:=false;
  1068. end;
  1069. end;
  1070. end;
  1071. if Res then
  1072. begin
  1073. if Config.NeedTarget<>'' then
  1074. begin
  1075. Verbose(V_Debug,'Required compiler target: '+Config.NeedTarget);
  1076. if not IsInList(CompilerTarget,Config.NeedTarget) then
  1077. begin
  1078. { avoid a second attempt by writing to elg file }
  1079. AddLog(EXELogFile,skipping_other_target+PPFileInfo);
  1080. AddLog(ResLogFile,skipping_other_target+PPFileInfo);
  1081. Verbose(V_Abort,'Compiler target "'+CompilerTarget+'" is not in list "'+Config.NeedTarget+'"');
  1082. Res:=false;
  1083. end;
  1084. end;
  1085. end;
  1086. if Res then
  1087. begin
  1088. if Config.SkipTarget<>'' then
  1089. begin
  1090. Verbose(V_Debug,'Skip compiler target: '+Config.NeedTarget);
  1091. if IsInList(CompilerTarget,Config.SkipTarget) then
  1092. begin
  1093. { avoid a second attempt by writing to elg file }
  1094. AddLog(EXELogFile,skipping_other_target+PPFileInfo);
  1095. AddLog(ResLogFile,skipping_other_target+PPFileInfo);
  1096. Verbose(V_Abort,'Compiler target "'+CompilerTarget+'" is in list "'+Config.SkipTarget+'"');
  1097. Res:=false;
  1098. end;
  1099. end;
  1100. end;
  1101. if Res then
  1102. begin
  1103. Res:=RunCompiler;
  1104. if Res and Config.NeedRecompile then
  1105. Res:=RunCompiler;
  1106. end;
  1107. if Res and (not Config.ShouldFail) then
  1108. begin
  1109. if (Config.NoRun) then
  1110. begin
  1111. { avoid a second attempt by writing to elg file }
  1112. AddLog(EXELogFile,skipping_run_test+PPFileInfo);
  1113. AddLog(ResLogFile,skipping_run_test+PPFileInfo);
  1114. Verbose(V_Debug,skipping_run_test);
  1115. end
  1116. else if Config.IsKnownRunError and (not DoKnown) then
  1117. begin
  1118. { avoid a second attempt by writing to elg file }
  1119. AddLog(EXELogFile,skipping_known_bug+PPFileInfo);
  1120. AddLog(ResLogFile,skipping_known_bug+PPFileInfo);
  1121. Verbose(V_Abort,skipping_known_bug);
  1122. end
  1123. else
  1124. begin
  1125. if DoExecute then
  1126. begin
  1127. if FileExists(TestOutputFilename(PPFile,'ppu')) or
  1128. FileExists(TestOutputFilename(PPFile,'ppo')) or
  1129. FileExists(TestOutputFilename(PPFile,'ppw')) then
  1130. begin
  1131. AddLog(ExeLogFile,skipping_run_unit+PPFileInfo);
  1132. AddLog(ResLogFile,skipping_run_unit+PPFileInfo);
  1133. Verbose(V_Debug,'Unit found, skipping run test')
  1134. end
  1135. else
  1136. Res:=RunExecutable;
  1137. end;
  1138. end;
  1139. end;
  1140. end;
  1141. begin
  1142. GetArgs;
  1143. RunTest;
  1144. end.