tcbaseparser.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. unit tcbaseparser;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpcunit, pastree, pscanner, pparser, testregistry;
  6. Type
  7. { TTestEngine }
  8. TTestEngine = Class(TPasTreeContainer)
  9. Private
  10. FList : TFPList;
  11. public
  12. Destructor Destroy; override;
  13. function CreateElement(AClass: TPTreeElement; const AName: String;
  14. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  15. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  16. override;
  17. function FindElement(const AName: String): TPasElement; override;
  18. end;
  19. TTestPasParser = Class(TPasParser);
  20. { TTestParser }
  21. TTestParser= class(TTestCase)
  22. Private
  23. FDeclarations: TPasDeclarations;
  24. FDefinition: TPasElement;
  25. FEngine : TTestEngine;
  26. FModule: TPasModule;
  27. FParseResult: TPasElement;
  28. FScanner : TPascalScanner;
  29. FResolver : TStreamResolver;
  30. FParser : TTestPasParser;
  31. FSource: TStrings;
  32. FFileName : string;
  33. FIsUnit : Boolean;
  34. FImplementation : Boolean;
  35. FEndSource: Boolean;
  36. FUseImplementation: Boolean;
  37. function GetPL: TPasLibrary;
  38. function GetPP: TPasProgram;
  39. procedure CleanupParser;
  40. procedure SetupParser;
  41. protected
  42. procedure SetUp; override;
  43. procedure TearDown; override;
  44. Procedure StartUnit(AUnitName : String);
  45. Procedure StartProgram(AFileName : String; AIn : String = ''; AOut : String = '');
  46. Procedure StartLibrary(AFileName : String);
  47. Procedure UsesClause(Units : Array of string);
  48. Procedure StartImplementation;
  49. Procedure EndSource;
  50. Procedure Add(Const ALine : String);
  51. Procedure StartParsing;
  52. Procedure ParseDeclarations;
  53. Procedure ParseModule;
  54. procedure ResetParser;
  55. Procedure CheckHint(AHint : TPasMemberHint);
  56. Function AssertExpression(Const Msg: String; AExpr : TPasExpr; aKind : TPasExprKind; AClass : TClass) : TPasExpr;
  57. Function AssertExpression(Const Msg: String; AExpr : TPasExpr; aKind : TPasExprKind; AValue : String) : TPrimitiveExpr;
  58. Procedure AssertExportSymbol(Const Msg: String; AIndex : Integer; AName,AExportName : String; AExportIndex : Integer = -1);
  59. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasExprKind); overload;
  60. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TLoopType); overload;
  61. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasObjKind); overload;
  62. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TexprOpcode); overload;
  63. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasMemberHint); overload;
  64. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TCallingConvention); overload;
  65. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TArgumentAccess); overload;
  66. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TVariableModifier); overload;
  67. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TVariableModifiers); overload;
  68. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TPasMemberVisibility); overload;
  69. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcedureModifier); overload;
  70. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcedureModifiers); overload;
  71. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TAssignKind); overload;
  72. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TProcedureMessageType); overload;
  73. Procedure AssertEquals(Const Msg : String; AExpected, AActual: TOperatorType); overload;
  74. Procedure HaveHint(AHint : TPasMemberHint; AHints : TPasMemberHints);
  75. Property Resolver : TStreamResolver Read FResolver;
  76. Property Scanner : TPascalScanner Read FScanner;
  77. Property Engine : TTestEngine read FEngine;
  78. Property Parser : TTestPasParser read FParser ;
  79. Property Source : TStrings Read FSource;
  80. Property Module : TPasModule Read FModule;
  81. Property PasProgram : TPasProgram Read GetPP;
  82. Property PasLibrary : TPasLibrary Read GetPL;
  83. Property Declarations : TPasDeclarations read FDeclarations Write FDeclarations;
  84. Property Definition : TPasElement Read FDefinition Write FDefinition;
  85. // If set, Will be freed in teardown
  86. Property ParseResult : TPasElement Read FParseResult Write FParseResult;
  87. Property UseImplementation : Boolean Read FUseImplementation Write FUseImplementation;
  88. end;
  89. implementation
  90. uses typinfo;
  91. { TTestEngine }
  92. destructor TTestEngine.Destroy;
  93. begin
  94. FreeAndNil(FList);
  95. inherited Destroy;
  96. end;
  97. function TTestEngine.CreateElement(AClass: TPTreeElement; const AName: String;
  98. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  99. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  100. begin
  101. Result := AClass.Create(AName, AParent);
  102. Result.Visibility := AVisibility;
  103. Result.SourceFilename := ASourceFilename;
  104. Result.SourceLinenumber := ASourceLinenumber;
  105. if NeedComments and Assigned(CurrentParser) then
  106. begin
  107. // Writeln('Saving comment : ',CurrentParser.SavedComments);
  108. Result.DocComment:=CurrentParser.SavedComments;
  109. end;
  110. If not Assigned(FList) then
  111. FList:=TFPList.Create;
  112. FList.Add(Result);
  113. end;
  114. function TTestEngine.FindElement(const AName: String): TPasElement;
  115. Var
  116. I : Integer;
  117. begin
  118. Result:=Nil;
  119. if Assigned(FList) then
  120. begin
  121. I:=FList.Count-1;
  122. While (Result=Nil) and (I>=0) do
  123. begin
  124. if CompareText(TPasElement(FList[I]).Name,AName)=0 then
  125. Result:=TPasElement(Flist[i]);
  126. Dec(i);
  127. end;
  128. end;
  129. end;
  130. function TTestParser.GetPP: TPasProgram;
  131. begin
  132. Result:=Module as TPasProgram;
  133. end;
  134. function TTestParser.GetPL: TPasLibrary;
  135. begin
  136. Result:=Module as TPasLibrary;
  137. end;
  138. procedure TTestParser.SetupParser;
  139. begin
  140. FResolver:=TStreamResolver.Create;
  141. FResolver.OwnsStreams:=True;
  142. FScanner:=TPascalScanner.Create(FResolver);
  143. FEngine:=TTestEngine.Create;
  144. FParser:=TTestPasParser.Create(FScanner,FResolver,FEngine);
  145. FSource:=TStringList.Create;
  146. FModule:=Nil;
  147. FDeclarations:=Nil;
  148. FEndSource:=False;
  149. FImplementation:=False;
  150. FIsUnit:=False;
  151. end;
  152. procedure TTestParser.CleanupParser;
  153. begin
  154. if Not Assigned(FModule) then
  155. FreeAndNil(FDeclarations)
  156. else
  157. FDeclarations:=Nil;
  158. FImplementation:=False;
  159. FEndSource:=False;
  160. FIsUnit:=False;
  161. FreeAndNil(FModule);
  162. FreeAndNil(FSource);
  163. FreeAndNil(FParseResult);
  164. FreeAndNil(FParser);
  165. FreeAndNil(FEngine);
  166. FreeAndNil(FScanner);
  167. FreeAndNil(FResolver);
  168. end;
  169. procedure TTestParser.ResetParser;
  170. begin
  171. CleanupParser;
  172. SetupParser;
  173. end;
  174. procedure TTestParser.SetUp;
  175. begin
  176. Inherited;
  177. SetupParser;
  178. end;
  179. procedure TTestParser.TearDown;
  180. begin
  181. CleanupParser;
  182. Inherited;
  183. end;
  184. procedure TTestParser.StartUnit(AUnitName: String);
  185. begin
  186. FIsUnit:=True;
  187. If (AUnitName='') then
  188. AUnitName:='afile';
  189. Add('unit '+aUnitName+';');
  190. Add('');
  191. Add('interface');
  192. Add('');
  193. FFileName:=AUnitName+'.pp';
  194. end;
  195. procedure TTestParser.StartProgram(AFileName : String; AIn : String = ''; AOut : String = '');
  196. begin
  197. FIsUnit:=False;
  198. If (AFileName='') then
  199. AFileName:='proga';
  200. FFileName:=AFileName+'.pp';
  201. If (AIn<>'') then
  202. begin
  203. AFileName:=AFileName+'('+AIn;
  204. if (AOut<>'') then
  205. AFileName:=AFIleName+','+AOut;
  206. AFileName:=AFileName+')';
  207. end;
  208. Add('program '+AFileName+';');
  209. FImplementation:=True;
  210. end;
  211. procedure TTestParser.StartLibrary(AFileName: String);
  212. begin
  213. FIsUnit:=False;
  214. If (AFileName='') then
  215. AFileName:='liba';
  216. FFileName:=AFileName+'.pp';
  217. Add('library '+AFileName+';');
  218. FImplementation:=True;
  219. end;
  220. procedure TTestParser.UsesClause(Units: array of string);
  221. Var
  222. S : String;
  223. I : integer;
  224. begin
  225. S:='';
  226. For I:=Low(units) to High(units) do
  227. begin
  228. If (S<>'') then
  229. S:=S+', ';
  230. S:=S+Units[i];
  231. end;
  232. Add('uses '+S+';');
  233. Add('');
  234. end;
  235. procedure TTestParser.StartImplementation;
  236. begin
  237. if Not FImplementation then
  238. begin
  239. if UseImplementation then
  240. begin
  241. FSource.Insert(0,'');
  242. FSource.Insert(0,'Implementation');
  243. FSource.Insert(0,'');
  244. end
  245. else
  246. begin
  247. Add('');
  248. Add('Implementation');
  249. Add('');
  250. end;
  251. FImplementation:=True;
  252. end;
  253. end;
  254. procedure TTestParser.EndSource;
  255. begin
  256. if Not FEndSource then
  257. begin
  258. Add('end.');
  259. FEndSource:=True;
  260. end;
  261. end;
  262. procedure TTestParser.Add(const ALine: String);
  263. begin
  264. FSource.Add(ALine);
  265. end;
  266. procedure TTestParser.StartParsing;
  267. begin
  268. If FIsUnit then
  269. StartImplementation;
  270. EndSource;
  271. If (FFileName='') then
  272. FFileName:='afile.pp';
  273. FResolver.AddStream(FFileName,TStringStream.Create(FSource.text));
  274. FScanner.OpenFile(FFileName);
  275. Writeln('// Test : ',Self.TestName);
  276. Writeln(FSource.Text);
  277. end;
  278. procedure TTestParser.ParseDeclarations;
  279. begin
  280. if UseImplementation then
  281. StartImplementation;
  282. FSource.Insert(0,'');
  283. FSource.Insert(0,'interface');
  284. FSource.Insert(0,'');
  285. FSource.Insert(0,'unit afile;');
  286. if Not UseImplementation then
  287. StartImplementation;
  288. EndSource;
  289. ParseModule;
  290. if UseImplementation then
  291. FDeclarations:=Module.ImplementationSection
  292. else
  293. FDeclarations:=Module.InterfaceSection;
  294. end;
  295. procedure TTestParser.ParseModule;
  296. begin
  297. StartParsing;
  298. FParser.ParseMain(FModule);
  299. AssertNotNull('Module resulted in Module',FModule);
  300. AssertEquals('modulename',ChangeFileExt(FFileName,''),Module.Name);
  301. end;
  302. procedure TTestParser.CheckHint(AHint: TPasMemberHint);
  303. begin
  304. HaveHint(AHint,Definition.Hints);
  305. end;
  306. function TTestParser.AssertExpression(const Msg: String; AExpr: TPasExpr;
  307. aKind: TPasExprKind; AClass: TClass): TPasExpr;
  308. begin
  309. AssertEquals(Msg+': Correct expression kind',aKind,AExpr.Kind);
  310. AssertEquals(Msg+': Correct expression class',AClass,AExpr.ClassType);
  311. Result:=AExpr;
  312. end;
  313. function TTestParser.AssertExpression(const Msg: String; AExpr: TPasExpr;
  314. aKind: TPasExprKind; AValue: String): TPrimitiveExpr;
  315. begin
  316. Result:=AssertExpression(Msg,AExpr,aKind,TPrimitiveExpr) as TPrimitiveExpr;
  317. AssertEquals(Msg+': Primitive expression value',AValue,TPrimitiveExpr(AExpr).Value);
  318. end;
  319. procedure TTestParser.AssertExportSymbol(const Msg: String; AIndex: Integer;
  320. AName, AExportName: String; AExportIndex: Integer);
  321. Var
  322. E: TPasExportSymbol;
  323. begin
  324. AssertNotNull(Msg+'Have export symbols list',PasLibrary.LibrarySection.ExportSymbols);
  325. if AIndex>=PasLibrary.LibrarySection.ExportSymbols.Count then
  326. Fail(Format(Msg+'%d not a valid export list symbol',[AIndex]));
  327. AssertNotNull(Msg+'Have export symbol',PasLibrary.LibrarySection.ExportSymbols[Aindex]);
  328. AssertEquals(Msg+'Correct export symbol class',TPasExportSymbol,TObject(PasLibrary.LibrarySection.ExportSymbols[Aindex]).ClassType);
  329. E:=TPasExportSymbol(PasLibrary.LibrarySection.ExportSymbols[Aindex]);
  330. AssertEquals(Msg+'Correct export symbol name',AName,E.Name);
  331. if (AExportName='') then
  332. AssertNull(Msg+'No export name',E.ExportName)
  333. else
  334. begin
  335. AssertNotNull(Msg+'Export name symbol',E.ExportName);
  336. AssertEquals(Msg+'TPrimitiveExpr',TPrimitiveExpr,E.ExportName.CLassType);
  337. AssertEquals(Msg+'Correct export symbol export name ',''''+AExportName+'''',TPrimitiveExpr(E.ExportName).Value);
  338. end;
  339. If AExportIndex=-1 then
  340. AssertNull(Msg+'No export name',E.ExportIndex)
  341. else
  342. begin
  343. AssertNotNull(Msg+'Export name symbol',E.ExportIndex);
  344. AssertEquals(Msg+'TPrimitiveExpr',TPrimitiveExpr,E.ExportIndex.CLassType);
  345. AssertEquals(Msg+'Correct export symbol export index',IntToStr(AExportindex),TPrimitiveExpr(E.ExportIndex).Value);
  346. end;
  347. end;
  348. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  349. AActual: TPasExprKind);
  350. begin
  351. AssertEquals(Msg,GetEnumName(TypeInfo(TPasExprKind),Ord(AExpected)),
  352. GetEnumName(TypeInfo(TPasExprKind),Ord(AActual)));
  353. end;
  354. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  355. AActual: TLoopType);
  356. begin
  357. AssertEquals(Msg,GetEnumName(TypeInfo(TLoopType),Ord(AExpected)),
  358. GetEnumName(TypeInfo(TLoopType),Ord(AActual)));
  359. end;
  360. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  361. AActual: TPasObjKind);
  362. begin
  363. AssertEquals(Msg,GetEnumName(TypeInfo(TexprOpcode),Ord(AExpected)),
  364. GetEnumName(TypeInfo(TexprOpcode),Ord(AActual)));
  365. end;
  366. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  367. AActual: TexprOpcode);
  368. begin
  369. AssertEquals(Msg,GetEnumName(TypeInfo(TexprOpcode),Ord(AExpected)),
  370. GetEnumName(TypeInfo(TexprOpcode),Ord(AActual)));
  371. end;
  372. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  373. AActual: TPasMemberHint);
  374. begin
  375. AssertEquals(Msg,GetEnumName(TypeInfo(TPasMemberHint),Ord(AExpected)),
  376. GetEnumName(TypeInfo(TPasMemberHint),Ord(AActual)));
  377. end;
  378. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  379. AActual: TCallingConvention);
  380. begin
  381. AssertEquals(Msg,GetEnumName(TypeInfo(TCallingConvention),Ord(AExpected)),
  382. GetEnumName(TypeInfo(TCallingConvention),Ord(AActual)));
  383. end;
  384. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  385. AActual: TArgumentAccess);
  386. begin
  387. AssertEquals(Msg,GetEnumName(TypeInfo(TArgumentAccess),Ord(AExpected)),
  388. GetEnumName(TypeInfo(TArgumentAccess),Ord(AActual)));
  389. end;
  390. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  391. AActual: TVariableModifier);
  392. begin
  393. AssertEquals(Msg,GetEnumName(TypeInfo(TVariableModifier),Ord(AExpected)),
  394. GetEnumName(TypeInfo(TVariableModifier),Ord(AActual)));
  395. end;
  396. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  397. AActual: TVariableModifiers);
  398. Function sn (S : TVariableModifiers) : string;
  399. Var
  400. M : TVariableModifier;
  401. begin
  402. Result:='';
  403. For M:=Low(TVariableModifier) to High(TVariableModifier) do
  404. if M in S then
  405. begin
  406. if (Result<>'') then
  407. Result:=Result+',';
  408. end;
  409. Result:='['+Result+']';
  410. end;
  411. begin
  412. AssertEquals(Msg,Sn(AExpected),Sn(AActual));
  413. end;
  414. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  415. AActual: TPasMemberVisibility);
  416. begin
  417. AssertEquals(Msg,GetEnumName(TypeInfo(TPasMemberVisibility),Ord(AExpected)),
  418. GetEnumName(TypeInfo(TPasMemberVisibility),Ord(AActual)));
  419. end;
  420. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  421. AActual: TProcedureModifier);
  422. begin
  423. AssertEquals(Msg,GetEnumName(TypeInfo(TProcedureModifier),Ord(AExpected)),
  424. GetEnumName(TypeInfo(TProcedureModifier),Ord(AActual)));
  425. end;
  426. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  427. AActual: TProcedureModifiers);
  428. Function Sn (S : TProcedureModifiers) : String;
  429. Var
  430. m : TProcedureModifier;
  431. begin
  432. Result:='';
  433. For M:=Low(TProcedureModifier) to High(TProcedureModifier) do
  434. If (m in S) then
  435. begin
  436. If (Result<>'') then
  437. Result:=Result+',';
  438. Result:=Result+GetEnumName(TypeInfo(TProcedureModifier),Ord(m))
  439. end;
  440. end;
  441. begin
  442. AssertEquals(Msg,Sn(AExpected),SN(AActual));
  443. end;
  444. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  445. AActual: TAssignKind);
  446. begin
  447. AssertEquals(Msg,GetEnumName(TypeInfo(TAssignKind),Ord(AExpected)),
  448. GetEnumName(TypeInfo(TAssignKind),Ord(AActual)));
  449. end;
  450. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  451. AActual: TProcedureMessageType);
  452. begin
  453. AssertEquals(Msg,GetEnumName(TypeInfo(TProcedureMessageType),Ord(AExpected)),
  454. GetEnumName(TypeInfo(TProcedureMessageType),Ord(AActual)));
  455. end;
  456. procedure TTestParser.AssertEquals(const Msg: String; AExpected,
  457. AActual: TOperatorType);
  458. begin
  459. AssertEquals(Msg,GetEnumName(TypeInfo(TOperatorType),Ord(AExpected)),
  460. GetEnumName(TypeInfo(TOperatorType),Ord(AExpected)));
  461. end;
  462. procedure TTestParser.HaveHint(AHint: TPasMemberHint; AHints: TPasMemberHints);
  463. begin
  464. If not (AHint in AHints) then
  465. Fail(GetEnumName(TypeInfo(TPasMemberHint),Ord(AHint))+'hint expected.');
  466. end;
  467. end.