tests_rtti.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. unit tests_rtti;
  2. {$ifdef fpc}
  3. {$mode objfpc}{$H+}
  4. {$endif}
  5. interface
  6. uses
  7. {$IFDEF FPC}
  8. fpcunit,testregistry, testutils,
  9. {$ELSE FPC}
  10. TestFramework,
  11. {$ENDIF FPC}
  12. Classes, SysUtils, typinfo,
  13. Rtti;
  14. type
  15. { TTestCase1 }
  16. TTestCase1= class(TTestCase)
  17. published
  18. procedure GetTypes;
  19. procedure GetTypeInteger;
  20. procedure GetClassProperties;
  21. procedure GetClassAttributes;
  22. procedure GetClassPropertiesAttributes;
  23. procedure GetClassPropertiesValue;
  24. procedure TestTRttiTypeProperties;
  25. procedure TestPropGetValueString;
  26. procedure TestPropGetValueInteger;
  27. procedure TestPropGetValueBoolean;
  28. procedure TestPropGetValueProcString;
  29. procedure TestPropGetValueProcInteger;
  30. procedure TestPropGetValueProcBoolean;
  31. procedure TestPropSetValueString;
  32. procedure TestPropSetValueInteger;
  33. procedure TestPropSetValueBoolean;
  34. procedure TestGetValueStringCastError;
  35. procedure TestMakeObject;
  36. procedure TestGetIsReadable;
  37. procedure TestIsWritable;
  38. end;
  39. implementation
  40. type
  41. { TIntAttribute }
  42. TIntAttribute = class(TCustomAttribute)
  43. private
  44. FInt: Integer;
  45. public
  46. constructor create(AInt: integer); virtual;
  47. property Int: integer read FInt;
  48. end;
  49. [TIntAttribute(1)]
  50. [TIntAttribute(2)]
  51. TGetClassProperties = class
  52. private
  53. FPubPropRO: integer;
  54. FPubPropRW: integer;
  55. published
  56. property PubPropRO: integer read FPubPropRO;
  57. [TIntAttribute(3)]
  58. property PubPropRW: integer read FPubPropRW write FPubPropRW;
  59. property PubPropSetRO: integer read FPubPropRO;
  60. [TIntAttribute(4)]
  61. property PubPropSetRW: integer read FPubPropRW write FPubPropRW;
  62. end;
  63. { TTestValueClass }
  64. TTestValueClass = class
  65. private
  66. FAInteger: integer;
  67. FAString: string;
  68. FABoolean: boolean;
  69. function GetAInteger: integer;
  70. function GetAString: string;
  71. function GetABoolean: boolean;
  72. procedure SetWriteOnly(AValue: integer);
  73. published
  74. property AInteger: Integer read FAInteger write FAInteger;
  75. property AString: string read FAString write FAString;
  76. property ABoolean: boolean read FABoolean write FABoolean;
  77. property AGetInteger: Integer read GetAInteger;
  78. property AGetString: string read GetAString;
  79. property AGetBoolean: boolean read GetABoolean;
  80. property AWriteOnly: integer write SetWriteOnly;
  81. end;
  82. { TTestValueClass }
  83. function TTestValueClass.GetAInteger: integer;
  84. begin
  85. result := FAInteger;
  86. end;
  87. function TTestValueClass.GetAString: string;
  88. begin
  89. result := FAString;
  90. end;
  91. function TTestValueClass.GetABoolean: boolean;
  92. begin
  93. result := FABoolean;
  94. end;
  95. procedure TTestValueClass.SetWriteOnly(AValue: integer);
  96. begin
  97. // Do nothing
  98. end;
  99. { TIntAttribute }
  100. constructor TIntAttribute.create(AInt: integer);
  101. begin
  102. FInt:=AInt;
  103. end;
  104. procedure TTestCase1.GetTypes;
  105. var
  106. LContext: TRttiContext;
  107. LType: TRttiType;
  108. IsTestCaseClassFound: boolean;
  109. begin
  110. LContext := TRttiContext.Create;
  111. { Enumerate all types declared in the application }
  112. for LType in LContext.GetTypes() do
  113. begin
  114. if LType.Name='TTestCase1' then
  115. IsTestCaseClassFound:=true;
  116. end;
  117. LContext.Free;
  118. CheckTrue(IsTestCaseClassFound, 'RTTI information does not contain class of testcase.');
  119. end;
  120. procedure TTestCase1.TestGetValueStringCastError;
  121. var
  122. ATestClass : TTestValueClass;
  123. c: TRttiContext;
  124. ARttiType: TRttiType;
  125. AValue: TValue;
  126. i: integer;
  127. HadException: boolean;
  128. begin
  129. c := TRttiContext.Create;
  130. try
  131. ATestClass := TTestValueClass.Create;
  132. ATestClass.AString := '12';
  133. try
  134. ARttiType := c.GetType(ATestClass.ClassInfo);
  135. AValue := ARttiType.GetProperty('astring').GetValue(ATestClass);
  136. HadException := false;
  137. try
  138. i := AValue.AsInteger;
  139. except
  140. on E: Exception do
  141. if E.ClassType=EInvalidCast then
  142. HadException := true;
  143. end;
  144. Check(HadException, 'No or invalid exception on invalid cast');
  145. finally
  146. AtestClass.Free;
  147. end;
  148. finally
  149. c.Free;
  150. end;
  151. end;
  152. procedure TTestCase1.TestMakeObject;
  153. var
  154. AValue: TValue;
  155. ATestClass: TTestValueClass;
  156. begin
  157. ATestClass := TTestValueClass.Create;
  158. ATestClass.AInteger := 54329;
  159. TValue.Make(@ATestClass, TypeInfo(TTestValueClass),AValue);
  160. CheckEquals(AValue.IsClass, False);
  161. CheckEquals(AValue.IsObject, True);
  162. Check(AValue.AsObject=ATestClass);
  163. CheckEquals(TTestValueClass(AValue.AsObject).AInteger, 54329);
  164. ATestClass.Free;
  165. end;
  166. procedure TTestCase1.TestGetIsReadable;
  167. var
  168. c: TRttiContext;
  169. ARttiType: TRttiType;
  170. AProperty: TRttiProperty;
  171. begin
  172. c := TRttiContext.Create;
  173. try
  174. ARttiType := c.GetType(TTestValueClass);
  175. AProperty := ARttiType.GetProperty('aBoolean');
  176. CheckEquals(AProperty.IsReadable, true);
  177. AProperty := ARttiType.GetProperty('aGetBoolean');
  178. CheckEquals(AProperty.IsReadable, true);
  179. AProperty := ARttiType.GetProperty('aWriteOnly');
  180. CheckEquals(AProperty.IsReadable, False);
  181. finally
  182. c.Free;
  183. end;
  184. end;
  185. procedure TTestCase1.TestIsWritable;
  186. var
  187. c: TRttiContext;
  188. ARttiType: TRttiType;
  189. AProperty: TRttiProperty;
  190. begin
  191. c := TRttiContext.Create;
  192. try
  193. ARttiType := c.GetType(TTestValueClass);
  194. AProperty := ARttiType.GetProperty('aBoolean');
  195. CheckEquals(AProperty.IsWritable, true);
  196. AProperty := ARttiType.GetProperty('aGetBoolean');
  197. CheckEquals(AProperty.IsWritable, false);
  198. AProperty := ARttiType.GetProperty('aWriteOnly');
  199. CheckEquals(AProperty.IsWritable, True);
  200. finally
  201. c.Free;
  202. end;
  203. end;
  204. procedure TTestCase1.TestPropGetValueBoolean;
  205. var
  206. ATestClass : TTestValueClass;
  207. c: TRttiContext;
  208. ARttiType: TRttiType;
  209. AProperty: TRttiProperty;
  210. AValue: TValue;
  211. begin
  212. c := TRttiContext.Create;
  213. try
  214. ATestClass := TTestValueClass.Create;
  215. ATestClass.ABoolean := true;
  216. try
  217. ARttiType := c.GetType(ATestClass.ClassInfo);
  218. Check(assigned(ARttiType));
  219. AProperty := ARttiType.GetProperty('aBoolean');
  220. AValue := AProperty.GetValue(ATestClass);
  221. CheckEquals(true,AValue.AsBoolean);
  222. ATestClass.ABoolean := false;
  223. CheckEquals(true, AValue.AsBoolean);
  224. CheckEquals('True', AValue.ToString);
  225. CheckEquals(True, AValue.IsOrdinal);
  226. CheckEquals(1, AValue.AsOrdinal);
  227. finally
  228. AtestClass.Free;
  229. end;
  230. CheckEquals(True,AValue.AsBoolean);
  231. finally
  232. c.Free;
  233. end;
  234. end;
  235. procedure TTestCase1.TestPropGetValueInteger;
  236. var
  237. ATestClass : TTestValueClass;
  238. c: TRttiContext;
  239. ARttiType: TRttiType;
  240. AProperty: TRttiProperty;
  241. AValue: TValue;
  242. begin
  243. c := TRttiContext.Create;
  244. try
  245. ATestClass := TTestValueClass.Create;
  246. ATestClass.AInteger := 472349;
  247. try
  248. ARttiType := c.GetType(ATestClass.ClassInfo);
  249. Check(assigned(ARttiType));
  250. AProperty := ARttiType.GetProperty('ainteger');
  251. AValue := AProperty.GetValue(ATestClass);
  252. CheckEquals(472349,AValue.AsInteger);
  253. ATestClass.AInteger := 12;
  254. CheckEquals(472349, AValue.AsInteger);
  255. CheckEquals('472349', AValue.ToString);
  256. CheckEquals(True, AValue.IsOrdinal);
  257. finally
  258. AtestClass.Free;
  259. end;
  260. CheckEquals(472349,AValue.AsInteger);
  261. finally
  262. c.Free;
  263. end;
  264. end;
  265. procedure TTestCase1.TestPropGetValueString;
  266. var
  267. ATestClass : TTestValueClass;
  268. c: TRttiContext;
  269. ARttiType: TRttiType;
  270. AProperty: TRttiProperty;
  271. AValue: TValue;
  272. i: int64;
  273. begin
  274. c := TRttiContext.Create;
  275. try
  276. ATestClass := TTestValueClass.Create;
  277. ATestClass.AString := 'Hello World';
  278. try
  279. ARttiType := c.GetType(ATestClass.ClassInfo);
  280. Check(assigned(ARttiType));
  281. AProperty := ARttiType.GetProperty('astring');
  282. AValue := AProperty.GetValue(ATestClass);
  283. CheckEquals('Hello World',AValue.AsString);
  284. ATestClass.AString := 'Goodbye World';
  285. CheckEquals('Hello World',AValue.AsString);
  286. CheckEquals('Hello World',AValue.ToString);
  287. Check(TypeInfo(string)=AValue.TypeInfo);
  288. Check(AValue.TypeData=GetTypeData(AValue.TypeInfo));
  289. Check(AValue.IsEmpty=false);
  290. Check(AValue.IsObject=false);
  291. Check(AValue.IsClass=false);
  292. CheckEquals(AValue.IsOrdinal, false);
  293. CheckEquals(AValue.TryAsOrdinal(i), false);
  294. CheckEquals(AValue.IsType(TypeInfo(string)), true);
  295. CheckEquals(AValue.IsType(TypeInfo(integer)), false);
  296. CheckEquals(AValue.IsArray, false);
  297. finally
  298. AtestClass.Free;
  299. end;
  300. CheckEquals('Hello World',AValue.AsString);
  301. finally
  302. c.Free;
  303. end;
  304. end;
  305. procedure TTestCase1.TestPropGetValueProcBoolean;
  306. var
  307. ATestClass : TTestValueClass;
  308. c: TRttiContext;
  309. ARttiType: TRttiType;
  310. AProperty: TRttiProperty;
  311. AValue: TValue;
  312. begin
  313. c := TRttiContext.Create;
  314. try
  315. ATestClass := TTestValueClass.Create;
  316. ATestClass.ABoolean := true;
  317. try
  318. ARttiType := c.GetType(ATestClass.ClassInfo);
  319. Check(assigned(ARttiType));
  320. AProperty := ARttiType.GetProperty('aGetBoolean');
  321. AValue := AProperty.GetValue(ATestClass);
  322. CheckEquals(true,AValue.AsBoolean);
  323. finally
  324. AtestClass.Free;
  325. end;
  326. CheckEquals(True,AValue.AsBoolean);
  327. finally
  328. c.Free;
  329. end;
  330. end;
  331. procedure TTestCase1.TestPropSetValueString;
  332. var
  333. ATestClass : TTestValueClass;
  334. c: TRttiContext;
  335. ARttiType: TRttiType;
  336. AProperty: TRttiProperty;
  337. AValue: TValue;
  338. s: string;
  339. begin
  340. c := TRttiContext.Create;
  341. try
  342. ATestClass := TTestValueClass.Create;
  343. try
  344. ARttiType := c.GetType(ATestClass.ClassInfo);
  345. AProperty := ARttiType.GetProperty('astring');
  346. s := 'ipse lorem or something like that';
  347. TValue.Make(@s, TypeInfo(s), AValue);
  348. AProperty.SetValue(ATestClass, AValue);
  349. CheckEquals(ATestClass.AString, s);
  350. s := 'Another string';
  351. CheckEquals(ATestClass.AString, 'ipse lorem or something like that');
  352. finally
  353. AtestClass.Free;
  354. end;
  355. finally
  356. c.Free;
  357. end;
  358. end;
  359. procedure TTestCase1.TestPropSetValueInteger;
  360. var
  361. ATestClass : TTestValueClass;
  362. c: TRttiContext;
  363. ARttiType: TRttiType;
  364. AProperty: TRttiProperty;
  365. AValue: TValue;
  366. i: integer;
  367. begin
  368. c := TRttiContext.Create;
  369. try
  370. ATestClass := TTestValueClass.Create;
  371. try
  372. ARttiType := c.GetType(ATestClass.ClassInfo);
  373. AProperty := ARttiType.GetProperty('aInteger');
  374. i := -43573;
  375. TValue.Make(@i, TypeInfo(i), AValue);
  376. AProperty.SetValue(ATestClass, AValue);
  377. CheckEquals(ATestClass.AInteger, i);
  378. i := 1;
  379. CheckEquals(ATestClass.AInteger, -43573);
  380. finally
  381. AtestClass.Free;
  382. end;
  383. finally
  384. c.Free;
  385. end;
  386. end;
  387. procedure TTestCase1.TestPropSetValueBoolean;
  388. var
  389. ATestClass : TTestValueClass;
  390. c: TRttiContext;
  391. ARttiType: TRttiType;
  392. AProperty: TRttiProperty;
  393. AValue: TValue;
  394. b: boolean;
  395. begin
  396. c := TRttiContext.Create;
  397. try
  398. ATestClass := TTestValueClass.Create;
  399. try
  400. ARttiType := c.GetType(ATestClass.ClassInfo);
  401. AProperty := ARttiType.GetProperty('aboolean');
  402. b := true;
  403. TValue.Make(@b, TypeInfo(b), AValue);
  404. AProperty.SetValue(ATestClass, AValue);
  405. CheckEquals(ATestClass.ABoolean, b);
  406. b := false;
  407. CheckEquals(ATestClass.ABoolean, true);
  408. TValue.Make(@b, TypeInfo(b), AValue);
  409. AProperty.SetValue(ATestClass, AValue);
  410. CheckEquals(ATestClass.ABoolean, false);
  411. finally
  412. AtestClass.Free;
  413. end;
  414. finally
  415. c.Free;
  416. end;
  417. end;
  418. procedure TTestCase1.TestPropGetValueProcInteger;
  419. var
  420. ATestClass : TTestValueClass;
  421. c: TRttiContext;
  422. ARttiType: TRttiType;
  423. AProperty: TRttiProperty;
  424. AValue: TValue;
  425. begin
  426. c := TRttiContext.Create;
  427. try
  428. ATestClass := TTestValueClass.Create;
  429. ATestClass.AInteger := 472349;
  430. try
  431. ARttiType := c.GetType(ATestClass.ClassInfo);
  432. Check(assigned(ARttiType));
  433. AProperty := ARttiType.GetProperty('agetinteger');
  434. AValue := AProperty.GetValue(ATestClass);
  435. CheckEquals(472349,AValue.AsInteger);
  436. finally
  437. AtestClass.Free;
  438. end;
  439. CheckEquals(472349,AValue.AsInteger);
  440. finally
  441. c.Free;
  442. end;
  443. end;
  444. procedure TTestCase1.TestPropGetValueProcString;
  445. var
  446. ATestClass : TTestValueClass;
  447. c: TRttiContext;
  448. ARttiType: TRttiType;
  449. AProperty: TRttiProperty;
  450. AValue: TValue;
  451. i: int64;
  452. begin
  453. c := TRttiContext.Create;
  454. try
  455. ATestClass := TTestValueClass.Create;
  456. ATestClass.AString := 'Hello World';
  457. try
  458. ARttiType := c.GetType(ATestClass.ClassInfo);
  459. Check(assigned(ARttiType));
  460. AProperty := ARttiType.GetProperty('agetstring');
  461. AValue := AProperty.GetValue(ATestClass);
  462. CheckEquals('Hello World',AValue.AsString);
  463. finally
  464. AtestClass.Free;
  465. end;
  466. CheckEquals('Hello World',AValue.AsString);
  467. finally
  468. c.Free;
  469. end;
  470. end;
  471. procedure TTestCase1.TestTRttiTypeProperties;
  472. var
  473. c: TRttiContext;
  474. ARttiType: TRttiType;
  475. begin
  476. c := TRttiContext.Create;
  477. try
  478. ARttiType := c.GetType(TTestValueClass);
  479. Check(assigned(ARttiType));
  480. CheckEquals(ARttiType.Name,'TTestValueClass');
  481. Check(ARttiType.TypeKind=tkClass);
  482. // CheckEquals(ARttiType.IsPublicType,false);
  483. CheckEquals(ARttiType.TypeSize,4);
  484. CheckEquals(ARttiType.IsManaged,false);
  485. CheckEquals(ARttiType.BaseType.classname,'TRttiInstanceType');
  486. CheckEquals(ARttiType.IsInstance,True);
  487. CheckEquals(ARttiType.AsInstance.DeclaringUnitName,'tests_rtti');
  488. Check(ARttiType.BaseType.Name='TObject');
  489. Check(ARttiType.AsInstance.BaseType.Name='TObject');
  490. CheckEquals(ARttiType.IsOrdinal,False);
  491. CheckEquals(ARttiType.IsRecord,False);
  492. CheckEquals(ARttiType.IsSet,False);
  493. finally
  494. c.Free;
  495. end;
  496. end;
  497. procedure TTestCase1.GetTypeInteger;
  498. var
  499. LContext: TRttiContext;
  500. LType: TRttiType;
  501. begin
  502. LContext := TRttiContext.Create;
  503. LType := LContext.GetType(TypeInfo(integer));
  504. CheckEquals(LType.Name, 'LongInt');
  505. LContext.Free;
  506. end;
  507. procedure TTestCase1.GetClassProperties;
  508. var
  509. LContext: TRttiContext;
  510. LType: TRttiType;
  511. PropList: {$ifdef fpc}specialize{$endif} TArray<TRttiProperty>;
  512. begin
  513. LContext := TRttiContext.Create;
  514. LType := LContext.GetType(TypeInfo(TGetClassProperties));
  515. PropList := LType.GetProperties;
  516. CheckEquals(4, length(PropList));
  517. CheckEquals('PubPropRO', PropList[0].Name);
  518. CheckEquals('PubPropRW', PropList[1].Name);
  519. CheckEquals('PubPropSetRO', PropList[2].Name);
  520. CheckEquals('PubPropSetRW', PropList[3].Name);
  521. LContext.Free;
  522. end;
  523. procedure TTestCase1.GetClassAttributes;
  524. var
  525. LContext: TRttiContext;
  526. LType: TRttiType;
  527. AttrList: {$ifdef fpc}specialize{$endif} TArray<TCustomAttribute>;
  528. begin
  529. LContext := TRttiContext.Create;
  530. LType := LContext.GetType(TypeInfo(TGetClassProperties));
  531. AttrList := LType.GetAttributes;
  532. CheckEquals(2, length(AttrList));
  533. CheckEquals('TIntAttribute', AttrList[0].ClassName);
  534. CheckEquals('TIntAttribute', AttrList[1].ClassName);
  535. CheckEquals(1, TIntAttribute(AttrList[0]).Int);
  536. CheckEquals(2, TIntAttribute(AttrList[1]).Int);
  537. LContext.Free;
  538. end;
  539. procedure TTestCase1.GetClassPropertiesAttributes;
  540. var
  541. LContext: TRttiContext;
  542. LType: TRttiType;
  543. PropList: {$ifdef fpc}specialize{$endif} TArray<TRttiProperty>;
  544. AttrList: {$ifdef fpc}specialize{$endif} TArray<TCustomAttribute>;
  545. begin
  546. LContext := TRttiContext.Create;
  547. LType := LContext.GetType(TypeInfo(TGetClassProperties));
  548. PropList := LType.GetProperties;
  549. AttrList := PropList[1].GetAttributes;
  550. CheckEquals(1, length(AttrList));
  551. CheckEquals(3, TIntAttribute(AttrList[0]).Int);
  552. AttrList := PropList[3].GetAttributes;
  553. CheckEquals(1, length(AttrList));
  554. CheckEquals(4, TIntAttribute(AttrList[0]).Int);
  555. LContext.Free;
  556. end;
  557. procedure TTestCase1.GetClassPropertiesValue;
  558. var
  559. AGetClassProperties: TGetClassProperties;
  560. LContext: TRttiContext;
  561. LType: TRttiType;
  562. AValue: TValue;
  563. begin
  564. LContext := TRttiContext.Create;
  565. LType := LContext.GetType(TGetClassProperties);
  566. AGetClassProperties := TGetClassProperties.Create;
  567. try
  568. AGetClassProperties.PubPropRW:=12345;
  569. AValue := LType.GetProperty('PubPropRW').GetValue(AGetClassProperties);
  570. CheckEquals(12345, AValue.AsInteger);
  571. finally
  572. AGetClassProperties.Free;
  573. end;
  574. LContext.Free;
  575. end;
  576. initialization
  577. {$ifdef fpc}
  578. RegisterTest(TTestCase1);
  579. {$else fpc}
  580. RegisterTest(TTestCase1.Suite);
  581. {$endif fpc}
  582. end.