tcbaseparser.pas 15 KB

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