dotest.pp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254
  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=3;
  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. if RemotePath<>'' then
  675. s:='-R '+RemotePath+' '+s;
  676. execres:=ExecuteEmulated(EmulatorName,s);
  677. {$I-}
  678. ChDir(OldDir);
  679. {$I+}
  680. end
  681. else if RemoteAddr<>'' then
  682. begin
  683. { We don't want to create subdirs, remove paths from the test }
  684. TestRemoteExe:=RemotePath+'/'+SplitFileName(TestExe);
  685. if deBefore in DelExecutable then
  686. ExecuteRemote(rshprog,RemotePara+' '+RemoteAddr+' rm -f '+TestRemoteExe);
  687. ExecuteRemote(rcpprog,RemotePara+' '+TestExe+' '+RemoteAddr+':'+TestRemoteExe);
  688. { rsh doesn't pass the exitcode, use a second command to print the exitcode
  689. on the remoteshell to stdout }
  690. execcmd:=RemotePara+' '+RemoteAddr+' '+rquote+'chmod 755 '+TestRemoteExe+
  691. ' ; cd '+RemotePath+' ;';
  692. if UseTimeout then
  693. begin
  694. execcmd:=execcmd+'timeout -9 ';
  695. if Config.Timeout=0 then
  696. Config.Timeout:=DefaultTimeout;
  697. str(Config.Timeout,s);
  698. execcmd:=execcmd+s;
  699. end;
  700. execcmd:=execcmd+' '+TestRemoteExe+' ; echo "TestExitCode: $?"';
  701. if deAfter in DelExecutable then
  702. execcmd:=execcmd+' ; rm -f '+TestRemoteExe;
  703. execcmd:=execcmd+rquote;
  704. execres:=ExecuteRemote(rshprog,execcmd);
  705. { Check for TestExitCode error in output, sets ExecuteResult }
  706. CheckTestExitCode(EXELogFile);
  707. end
  708. else
  709. begin
  710. { Get full name out log file, because we change the directory during
  711. execution }
  712. FullExeLogFile:=FExpand(EXELogFile);
  713. Verbose(V_Debug,'Executing '+TestExe);
  714. {$I-}
  715. GetDir(0,OldDir);
  716. ChDir(TestOutputDir);
  717. {$I+}
  718. ioresult;
  719. { don't redirect interactive and graph programs }
  720. StartTicks:=GetMicroSTicks;
  721. if Config.IsInteractive or Config.UsesGraph then
  722. execres:=ExecuteRedir(CurrDir+SplitFileName(TestExe),'','','','')
  723. else
  724. execres:=ExecuteRedir(CurrDir+SplitFileName(TestExe),'','',FullExeLogFile,'stdout');
  725. EndTicks:=GetMicroSTicks;
  726. {$I-}
  727. ChDir(OldDir);
  728. {$I+}
  729. ioresult;
  730. end;
  731. { Error during execution? }
  732. Verbose(V_Debug,'Exitcode '+ToStr(ExecuteResult));
  733. if BenchmarkInfo then
  734. begin
  735. Verbose(V_Normal,'Execution took '+ToStr(EndTicks-StartTicks)+' us');
  736. end;
  737. if (not execres) and (ExecuteResult=0) then
  738. begin
  739. AddLog(FailLogFile,TestName);
  740. AddLog(ResLogFile,failed_to_run+PPFileInfo);
  741. AddLog(LongLogFile,line_separation);
  742. AddLog(LongLogFile,failed_to_run+PPFileInfo);
  743. CopyFile(EXELogFile,LongLogFile,true);
  744. { avoid to try again }
  745. AddLog(ExeLogFile,failed_to_run+PPFileInfo);
  746. Verbose(V_Abort,'IOStatus: '+ToStr(IOStatus));
  747. exit;
  748. end;
  749. if ExecuteResult<>Config.ResultCode then
  750. begin
  751. if (ExecuteResult<>0) and
  752. (ExecuteResult=Config.KnownRunError) then
  753. begin
  754. AddLog(FailLogFile,TestName+known_problem+Config.KnownRunNote);
  755. AddLog(ResLogFile,failed_to_run+PPFileInfo+known_problem+Config.KnownRunNote);
  756. AddLog(LongLogFile,line_separation);
  757. AddLog(LongLogFile,known_problem+Config.KnownRunNote);
  758. AddLog(LongLogFile,failed_to_run+PPFileInfo+' ('+ToStr(ExecuteResult)+')');
  759. Copyfile(EXELogFile,LongLogFile,true);
  760. Verbose(V_Abort,known_problem+'exitcode: '+ToStr(ExecuteResult)+' (expected '+ToStr(Config.ResultCode)+')');
  761. end
  762. else
  763. begin
  764. AddLog(FailLogFile,TestName);
  765. AddLog(ResLogFile,failed_to_run+PPFileInfo);
  766. AddLog(LongLogFile,line_separation);
  767. AddLog(LongLogFile,failed_to_run+PPFileInfo+' ('+ToStr(ExecuteResult)+')');
  768. Copyfile(EXELogFile,LongLogFile,true);
  769. Verbose(V_Abort,'Exitcode: '+ToStr(ExecuteResult)+' (expected '+ToStr(Config.ResultCode)+')');
  770. end
  771. end
  772. else
  773. begin
  774. AddLog(ResLogFile,successfully_run+PPFileInfo);
  775. RunExecutable:=true;
  776. end;
  777. if deAfter in DelExecutable then
  778. begin
  779. Verbose(V_Debug,'Deleting executable '+TestExe);
  780. RemoveFile(TestExe);
  781. RemoveFile(ForceExtension(TestExe,ObjExt));
  782. RemoveFile(ForceExtension(TestExe,PPUExt));
  783. end;
  784. end;
  785. procedure getargs;
  786. var
  787. ch : char;
  788. para : string;
  789. i,j : longint;
  790. procedure helpscreen;
  791. begin
  792. writeln('dotest [Options] <File>');
  793. writeln;
  794. writeln('Options can be:');
  795. writeln(' -B delete executable before remote upload');
  796. writeln(' -C<compiler> set compiler to use');
  797. writeln(' -V verbose');
  798. writeln(' -E execute test also');
  799. writeln(' -X don''t use COMSPEC');
  800. writeln(' -A include ALL tests');
  801. writeln(' -G include graph tests');
  802. writeln(' -K include known bug tests');
  803. writeln(' -I include interactive tests');
  804. writeln(' -O use timeout wrapper for (remote) execution');
  805. writeln(' -M<emulator> run the tests using the given emulator');
  806. writeln(' -R<remote> run the tests remotely with the given rsh/ssh address');
  807. writeln(' -S use ssh instead of rsh');
  808. writeln(' -T[cpu-]<os> run tests for target cpu and os');
  809. writeln(' -P<path> path to the tests tree on the remote machine');
  810. writeln(' -U<remotepara>');
  811. writeln(' pass additional parameter to remote program. Multiple -U can be used');
  812. writeln(' -V be verbose');
  813. writeln(' -W use putty compatible file names when testing (plink and pscp)');
  814. writeln(' -Y<opts> extra options passed to the compiler. Several -Y<opt> can be given.');
  815. writeln(' -Z remove temporary files (executable,ppu,o)');
  816. halt(1);
  817. end;
  818. begin
  819. PPFile:='';
  820. if exeext<>'' then
  821. CompilerBin:='ppc386.'+exeext
  822. else
  823. CompilerBin:='ppc386';
  824. for i:=1 to paramcount do
  825. begin
  826. para:=Paramstr(i);
  827. if (para[1]='-') then
  828. begin
  829. ch:=Upcase(para[2]);
  830. delete(para,1,2);
  831. case ch of
  832. 'A' :
  833. begin
  834. DoGraph:=true;
  835. DoInteractive:=true;
  836. DoKnown:=true;
  837. DoAll:=true;
  838. end;
  839. 'B' : Include(DelExecutable,deBefore);
  840. 'C' : CompilerBin:=Para;
  841. 'E' : DoExecute:=true;
  842. 'G' : begin
  843. DoGraph:=true;
  844. if para='-' then
  845. DoUsual:=false;
  846. end;
  847. 'I' : begin
  848. DoInteractive:=true;
  849. if para='-' then
  850. DoUsual:=false;
  851. end;
  852. 'K' : begin
  853. DoKnown:=true;
  854. if para='-' then
  855. DoUsual:=false;
  856. end;
  857. 'M' : EmulatorName:=Para;
  858. 'O' : UseTimeout:=true;
  859. 'P' : RemotePath:=Para;
  860. 'R' : RemoteAddr:=Para;
  861. 'S' :
  862. begin
  863. rshprog:='ssh';
  864. rcpprog:='scp';
  865. end;
  866. 'T' :
  867. begin
  868. j:=Pos('-',Para);
  869. if j>0 then
  870. begin
  871. CompilerCPU:=Copy(Para,1,j-1);
  872. CompilerTarget:=Copy(Para,j+1,255);
  873. end
  874. else
  875. CompilerTarget:=Para
  876. end;
  877. 'U' :
  878. RemotePara:=RemotePara+' '+Para;
  879. 'V' : DoVerbose:=true;
  880. 'W' :
  881. begin
  882. rshprog:='plink';
  883. rcpprog:='pscp';
  884. rquote:=' ';
  885. end;
  886. 'X' : UseComSpec:=false;
  887. 'Y' : ExtraCompilerOpts:= ExtraCompilerOpts +' '+ Para;
  888. 'Z' : Include(DelExecutable,deAfter);
  889. end;
  890. end
  891. else
  892. begin
  893. If PPFile<>'' then
  894. HelpScreen;
  895. PPFile:=ForceExtension(Para,'pp');
  896. end;
  897. end;
  898. if (PPFile='') then
  899. HelpScreen;
  900. { disable graph,interactive when running remote }
  901. if RemoteAddr<>'' then
  902. begin
  903. DoGraph:=false;
  904. DoInteractive:=false;
  905. end;
  906. SetPPFileInfo;
  907. TestName:=Copy(PPFile,1,Pos('.pp',PPFile)-1);
  908. Verbose(V_Debug,'Running test '+TestName+', file '+PPFile);
  909. end;
  910. procedure RunTest;
  911. var
  912. PPDir : string;
  913. Res : boolean;
  914. begin
  915. Res:=GetConfig(ppfile,Config);
  916. if Res then
  917. begin
  918. Res:=GetCompilerCPU;
  919. Res:=GetCompilerTarget;
  920. {$ifndef MACOS}
  921. RTLUnitsDir:='units/'+{$ifdef LIMIT83FS}CompilerTarget{$else}CompilerFullTarget{$endif};
  922. {$else MACOS}
  923. RTLUnitsDir:=':units:'+CompilerFullTarget;
  924. {$endif MACOS}
  925. if not PathExists(RTLUnitsDir) then
  926. Verbose(V_Abort,'Unit path "'+RTLUnitsDir+'" does not exists');
  927. {$ifndef MACOS}
  928. OutputDir:='output/'+{$ifdef LIMIT83FS}CompilerTarget{$else}CompilerFullTarget{$endif};
  929. {$else MACOS}
  930. OutputDir:=':output:'+CompilerFullTarget;
  931. {$endif MACOS}
  932. if not PathExists(OutputDir) then
  933. Verbose(V_Abort,'Output path "'+OutputDir+'" does not exists');
  934. { Global log files }
  935. ResLogFile:=OutputFileName('log','');
  936. LongLogFile:=OutputFileName('longlog','');
  937. FailLogFile:=OutputFileName('faillist','');
  938. { Make subdir in output if needed }
  939. PPDir:=SplitPath(PPFile);
  940. if PPDir[length(PPDir)] in ['/','\'{$ifdef MACOS},':'{$endif MACOS}] then
  941. Delete(PPDir,length(PPDir),1);
  942. if PPDir<>'' then
  943. begin
  944. {$ifndef MACOS}
  945. TestOutputDir:=OutputDir+'/'+PPDir;
  946. {$else MACOS}
  947. TestOutputDir:=OutputDir+PPDir;
  948. {$endif MACOS}
  949. mkdirtree(TestOutputDir);
  950. end
  951. else
  952. TestOutputDir:=OutputDir;
  953. { Per test logfiles }
  954. CompilerLogFile:=TestOutputFileName(SplitFileName(PPFile),'log');
  955. ExeLogFile:=TestOutputFileName(SplitFileName(PPFile),'elg');
  956. Verbose(V_Debug,'Using Compiler logfile: '+CompilerLogFile);
  957. Verbose(V_Debug,'Using Execution logfile: '+ExeLogFile);
  958. end;
  959. if Res then
  960. begin
  961. if Config.UsesGraph and (not DoGraph) then
  962. begin
  963. AddLog(ResLogFile,skipping_graph_test+PPFileInfo);
  964. { avoid a second attempt by writing to elg file }
  965. AddLog(EXELogFile,skipping_graph_test+PPFileInfo);
  966. Verbose(V_Abort,skipping_graph_test);
  967. Res:=false;
  968. end;
  969. end;
  970. if Res then
  971. begin
  972. if Config.IsInteractive and (not DoInteractive) then
  973. begin
  974. { avoid a second attempt by writing to elg file }
  975. AddLog(EXELogFile,skipping_interactive_test+PPFileInfo);
  976. AddLog(ResLogFile,skipping_interactive_test+PPFileInfo);
  977. Verbose(V_Abort,skipping_interactive_test);
  978. Res:=false;
  979. end;
  980. end;
  981. if Res then
  982. begin
  983. if Config.IsKnownCompileError and (not DoKnown) then
  984. begin
  985. { avoid a second attempt by writing to elg file }
  986. AddLog(EXELogFile,skipping_known_bug+PPFileInfo);
  987. AddLog(ResLogFile,skipping_known_bug+PPFileInfo);
  988. Verbose(V_Abort,skipping_known_bug);
  989. Res:=false;
  990. end;
  991. end;
  992. if Res and not DoUsual then
  993. res:=(Config.IsInteractive and DoInteractive) or
  994. (Config.IsKnownRunError and DoKnown) or
  995. (Config.UsesGraph and DoGraph);
  996. if Res then
  997. begin
  998. if (Config.MinVersion<>'') and not DoAll then
  999. begin
  1000. Verbose(V_Debug,'Required compiler version: '+Config.MinVersion);
  1001. Res:=GetCompilerVersion;
  1002. if CompilerVersion<Config.MinVersion then
  1003. begin
  1004. { avoid a second attempt by writing to elg file }
  1005. AddLog(EXELogFile,skipping_compiler_version_too_low+PPFileInfo);
  1006. AddLog(ResLogFile,skipping_compiler_version_too_low+PPFileInfo);
  1007. Verbose(V_Abort,'Compiler version too low '+CompilerVersion+' < '+Config.MinVersion);
  1008. Res:=false;
  1009. end;
  1010. end;
  1011. end;
  1012. if Res then
  1013. begin
  1014. if (Config.MaxVersion<>'') and not DoAll then
  1015. begin
  1016. Verbose(V_Debug,'Highest compiler version: '+Config.MaxVersion);
  1017. Res:=GetCompilerVersion;
  1018. if CompilerVersion>Config.MaxVersion then
  1019. begin
  1020. { avoid a second attempt by writing to elg file }
  1021. AddLog(EXELogFile,skipping_compiler_version_too_high+PPFileInfo);
  1022. AddLog(ResLogFile,skipping_compiler_version_too_high+PPFileInfo);
  1023. Verbose(V_Abort,'Compiler version too high '+CompilerVersion+' > '+Config.MaxVersion);
  1024. Res:=false;
  1025. end;
  1026. end;
  1027. end;
  1028. if Res then
  1029. begin
  1030. if Config.NeedCPU<>'' then
  1031. begin
  1032. Verbose(V_Debug,'Required compiler cpu: '+Config.NeedCPU);
  1033. if not IsInList(CompilerCPU,Config.NeedCPU) then
  1034. begin
  1035. { avoid a second attempt by writing to elg file }
  1036. AddLog(EXELogFile,skipping_other_cpu+PPFileInfo);
  1037. AddLog(ResLogFile,skipping_other_cpu+PPFileInfo);
  1038. Verbose(V_Abort,'Compiler cpu "'+CompilerCPU+'" is not in list "'+Config.NeedCPU+'"');
  1039. Res:=false;
  1040. end;
  1041. end;
  1042. end;
  1043. if Res then
  1044. begin
  1045. if Config.SkipCPU<>'' then
  1046. begin
  1047. Verbose(V_Debug,'Skip compiler cpu: '+Config.SkipCPU);
  1048. if IsInList(CompilerCPU,Config.SkipCPU) then
  1049. begin
  1050. { avoid a second attempt by writing to elg file }
  1051. AddLog(EXELogFile,skipping_other_cpu+PPFileInfo);
  1052. AddLog(ResLogFile,skipping_other_cpu+PPFileInfo);
  1053. Verbose(V_Abort,'Compiler cpu "'+CompilerCPU+'" is in list "'+Config.SkipCPU+'"');
  1054. Res:=false;
  1055. end;
  1056. end;
  1057. end;
  1058. if Res then
  1059. begin
  1060. if Config.SkipEmu<>'' then
  1061. begin
  1062. Verbose(V_Debug,'Skip emulator: '+emulatorname);
  1063. if IsInList(emulatorname,Config.SkipEmu) then
  1064. begin
  1065. { avoid a second attempt by writing to elg file }
  1066. AddLog(EXELogFile,skipping_other_cpu+PPFileInfo);
  1067. AddLog(ResLogFile,skipping_other_cpu+PPFileInfo);
  1068. Verbose(V_Abort,'Emulator "'+emulatorname+'" is in list "'+Config.SkipEmu+'"');
  1069. Res:=false;
  1070. end;
  1071. end;
  1072. end;
  1073. if Res then
  1074. begin
  1075. if Config.NeedTarget<>'' then
  1076. begin
  1077. Verbose(V_Debug,'Required compiler target: '+Config.NeedTarget);
  1078. if not IsInList(CompilerTarget,Config.NeedTarget) then
  1079. begin
  1080. { avoid a second attempt by writing to elg file }
  1081. AddLog(EXELogFile,skipping_other_target+PPFileInfo);
  1082. AddLog(ResLogFile,skipping_other_target+PPFileInfo);
  1083. Verbose(V_Abort,'Compiler target "'+CompilerTarget+'" is not in list "'+Config.NeedTarget+'"');
  1084. Res:=false;
  1085. end;
  1086. end;
  1087. end;
  1088. if Res then
  1089. begin
  1090. if Config.SkipTarget<>'' then
  1091. begin
  1092. Verbose(V_Debug,'Skip compiler target: '+Config.NeedTarget);
  1093. if IsInList(CompilerTarget,Config.SkipTarget) then
  1094. begin
  1095. { avoid a second attempt by writing to elg file }
  1096. AddLog(EXELogFile,skipping_other_target+PPFileInfo);
  1097. AddLog(ResLogFile,skipping_other_target+PPFileInfo);
  1098. Verbose(V_Abort,'Compiler target "'+CompilerTarget+'" is in list "'+Config.SkipTarget+'"');
  1099. Res:=false;
  1100. end;
  1101. end;
  1102. end;
  1103. if Res then
  1104. begin
  1105. Res:=RunCompiler;
  1106. if Res and Config.NeedRecompile then
  1107. Res:=RunCompiler;
  1108. end;
  1109. if Res and (not Config.ShouldFail) then
  1110. begin
  1111. if (Config.NoRun) then
  1112. begin
  1113. { avoid a second attempt by writing to elg file }
  1114. AddLog(EXELogFile,skipping_run_test+PPFileInfo);
  1115. AddLog(ResLogFile,skipping_run_test+PPFileInfo);
  1116. Verbose(V_Debug,skipping_run_test);
  1117. end
  1118. else if Config.IsKnownRunError and (not DoKnown) then
  1119. begin
  1120. { avoid a second attempt by writing to elg file }
  1121. AddLog(EXELogFile,skipping_known_bug+PPFileInfo);
  1122. AddLog(ResLogFile,skipping_known_bug+PPFileInfo);
  1123. Verbose(V_Abort,skipping_known_bug);
  1124. end
  1125. else
  1126. begin
  1127. if DoExecute then
  1128. begin
  1129. if FileExists(TestOutputFilename(PPFile,'ppu')) or
  1130. FileExists(TestOutputFilename(PPFile,'ppo')) or
  1131. FileExists(TestOutputFilename(PPFile,'ppw')) then
  1132. begin
  1133. AddLog(ExeLogFile,skipping_run_unit+PPFileInfo);
  1134. AddLog(ResLogFile,skipping_run_unit+PPFileInfo);
  1135. Verbose(V_Debug,'Unit found, skipping run test')
  1136. end
  1137. else
  1138. Res:=RunExecutable;
  1139. end;
  1140. end;
  1141. end;
  1142. end;
  1143. begin
  1144. GetArgs;
  1145. RunTest;
  1146. end.