tests.rtti.pas 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127
  1. unit tests.rtti;
  2. {$ifdef fpc}
  3. {$mode objfpc}{$H+}
  4. {$modeswitch advancedrecords}
  5. {$endif}
  6. interface
  7. uses
  8. {$IFDEF FPC}
  9. fpcunit,testregistry, testutils,
  10. {$ELSE FPC}
  11. TestFramework,
  12. {$ENDIF FPC}
  13. Classes, SysUtils, typinfo,
  14. Rtti;
  15. type
  16. { TTestCase1 }
  17. TTestCase1= class(TTestCase)
  18. published
  19. //procedure GetTypes;
  20. procedure GetTypeInteger;
  21. procedure GetClassProperties;
  22. procedure GetClassPropertiesValue;
  23. procedure TestTRttiTypeProperties;
  24. procedure TestPropGetValueString;
  25. procedure TestPropGetValueInteger;
  26. procedure TestPropGetValueBoolean;
  27. procedure TestPropGetValueShortString;
  28. procedure TestPropGetValueProcString;
  29. procedure TestPropGetValueProcInteger;
  30. procedure TestPropGetValueProcBoolean;
  31. procedure TestPropGetValueProcShortString;
  32. procedure TestPropSetValueString;
  33. procedure TestPropSetValueInteger;
  34. procedure TestPropSetValueBoolean;
  35. procedure TestPropSetValueShortString;
  36. procedure TestGetValueStringCastError;
  37. procedure TestGetIsReadable;
  38. procedure TestIsWritable;
  39. procedure TestMakeNil;
  40. procedure TestMakeObject;
  41. procedure TestMakeArrayDynamic;
  42. procedure TestMakeArrayStatic;
  43. procedure TestDataSize;
  44. procedure TestReferenceRawData;
  45. procedure TestIsManaged;
  46. end;
  47. implementation
  48. type
  49. {$M+}
  50. TGetClassProperties = class
  51. private
  52. FPubPropRO: integer;
  53. FPubPropRW: integer;
  54. published
  55. property PubPropRO: integer read FPubPropRO;
  56. property PubPropRW: integer read FPubPropRW write FPubPropRW;
  57. property PubPropSetRO: integer read FPubPropRO;
  58. property PubPropSetRW: integer read FPubPropRW write FPubPropRW;
  59. end;
  60. {$M-}
  61. { TTestValueClass }
  62. {$M+}
  63. TTestValueClass = class
  64. private
  65. FAInteger: integer;
  66. FAString: string;
  67. FABoolean: boolean;
  68. FAShortString: ShortString;
  69. function GetAInteger: integer;
  70. function GetAString: string;
  71. function GetABoolean: boolean;
  72. function GetAShortString: ShortString;
  73. procedure SetWriteOnly(AValue: integer);
  74. published
  75. property AInteger: Integer read FAInteger write FAInteger;
  76. property AString: string read FAString write FAString;
  77. property ABoolean: boolean read FABoolean write FABoolean;
  78. property AShortString: ShortString read FAShortString write FAShortString;
  79. property AGetInteger: Integer read GetAInteger;
  80. property AGetString: string read GetAString;
  81. property AGetBoolean: boolean read GetABoolean;
  82. property AGetShortString: ShortString read GetAShortString;
  83. property AWriteOnly: integer write SetWriteOnly;
  84. end;
  85. {$M-}
  86. TManagedRec = record
  87. s: string;
  88. end;
  89. {$ifdef fpc}
  90. TManagedRecOp = record
  91. class operator AddRef(var a: TManagedRecOp);
  92. end;
  93. {$endif}
  94. TNonManagedRec = record
  95. i: Integer;
  96. end;
  97. TManagedObj = object
  98. i: IInterface;
  99. end;
  100. TNonManagedObj = object
  101. d: double;
  102. end;
  103. TTestEnum = (te1, te2, te3, te4, te5);
  104. TTestSet = set of TTestEnum;
  105. TTestProc = procedure;
  106. TTestMethod = procedure of object;
  107. TTestHelper = class helper for TObject
  108. end;
  109. TArrayOfString = array[0..0] of string;
  110. TArrayOfManagedRec = array[0..0] of TManagedRec;
  111. TArrayOfNonManagedRec = array[0..0] of TNonManagedRec;
  112. TArrayOfByte = array[0..0] of byte;
  113. {$ifdef fpc}
  114. {$PUSH}
  115. {$INTERFACES CORBA}
  116. ICORBATest = interface
  117. end;
  118. {$POP}
  119. {$endif}
  120. {$ifdef fpc}
  121. class operator TManagedRecOp.AddRef(var a: TManagedRecOp);
  122. begin
  123. end;
  124. {$endif}
  125. { TTestValueClass }
  126. function TTestValueClass.GetAInteger: integer;
  127. begin
  128. result := FAInteger;
  129. end;
  130. function TTestValueClass.GetAString: string;
  131. begin
  132. result := FAString;
  133. end;
  134. function TTestValueClass.GetABoolean: boolean;
  135. begin
  136. result := FABoolean;
  137. end;
  138. function TTestValueClass.GetAShortString: ShortString;
  139. begin
  140. Result := FAShortString;
  141. end;
  142. procedure TTestValueClass.SetWriteOnly(AValue: integer);
  143. begin
  144. // Do nothing
  145. end;
  146. { Note: GetTypes currently only returns those types that had been acquired using
  147. GetType, so GetTypes itself can't be really tested currently }
  148. (*procedure TTestCase1.GetTypes;
  149. var
  150. LContext: TRttiContext;
  151. LType: TRttiType;
  152. IsTestCaseClassFound: boolean;
  153. begin
  154. LContext := TRttiContext.Create;
  155. { Enumerate all types declared in the application }
  156. for LType in LContext.GetTypes() do
  157. begin
  158. if LType.Name='TTestCase1' then
  159. IsTestCaseClassFound:=true;
  160. end;
  161. LContext.Free;
  162. CheckTrue(IsTestCaseClassFound, 'RTTI information does not contain class of testcase.');
  163. end;*)
  164. procedure TTestCase1.TestGetValueStringCastError;
  165. var
  166. ATestClass : TTestValueClass;
  167. c: TRttiContext;
  168. ARttiType: TRttiType;
  169. AValue: TValue;
  170. i: integer;
  171. HadException: boolean;
  172. begin
  173. c := TRttiContext.Create;
  174. try
  175. ATestClass := TTestValueClass.Create;
  176. ATestClass.AString := '12';
  177. try
  178. ARttiType := c.GetType(ATestClass.ClassInfo);
  179. AValue := ARttiType.GetProperty('astring').GetValue(ATestClass);
  180. HadException := false;
  181. try
  182. i := AValue.AsInteger;
  183. except
  184. on E: Exception do
  185. if E.ClassType=EInvalidCast then
  186. HadException := true;
  187. end;
  188. Check(HadException, 'No or invalid exception on invalid cast');
  189. finally
  190. AtestClass.Free;
  191. end;
  192. finally
  193. c.Free;
  194. end;
  195. end;
  196. procedure TTestCase1.TestMakeNil;
  197. var
  198. value: TValue;
  199. begin
  200. TValue.Make(Nil, TypeInfo(TObject), value);
  201. CheckTrue(value.IsEmpty);
  202. CheckTrue(value.IsObject);
  203. CheckTrue(value.IsClass);
  204. CheckTrue(value.IsOrdinal);
  205. CheckFalse(value.IsArray);
  206. CheckTrue(value.AsObject=Nil);
  207. CheckTrue(value.AsClass=Nil);
  208. CheckTrue(value.AsInterface=Nil);
  209. CheckEquals(0, value.AsOrdinal);
  210. TValue.Make(Nil, TypeInfo(TClass), value);
  211. CheckTrue(value.IsEmpty);
  212. CheckTrue(value.IsClass);
  213. CheckTrue(value.IsOrdinal);
  214. CheckFalse(value.IsArray);
  215. CheckTrue(value.AsObject=Nil);
  216. CheckTrue(value.AsClass=Nil);
  217. CheckTrue(value.AsInterface=Nil);
  218. CheckEquals(0, value.AsOrdinal);
  219. TValue.Make(Nil, TypeInfo(LongInt), value);
  220. CheckTrue(value.IsOrdinal);
  221. CheckFalse(value.IsEmpty);
  222. CheckFalse(value.IsClass);
  223. CheckFalse(value.IsObject);
  224. CheckFalse(value.IsArray);
  225. CheckEquals(0, value.AsOrdinal);
  226. CheckEquals(0, value.AsInteger);
  227. CheckEquals(0, value.AsInt64);
  228. CheckEquals(0, value.AsUInt64);
  229. TValue.Make(Nil, TypeInfo(String), value);
  230. CheckFalse(value.IsEmpty);
  231. CheckFalse(value.IsObject);
  232. CheckFalse(value.IsClass);
  233. CheckFalse(value.IsArray);
  234. CheckEquals('', value.AsString);
  235. end;
  236. procedure TTestCase1.TestMakeObject;
  237. var
  238. AValue: TValue;
  239. ATestClass: TTestValueClass;
  240. begin
  241. ATestClass := TTestValueClass.Create;
  242. ATestClass.AInteger := 54329;
  243. TValue.Make(@ATestClass, TypeInfo(TTestValueClass),AValue);
  244. CheckEquals(AValue.IsClass, False);
  245. CheckEquals(AValue.IsObject, True);
  246. Check(AValue.AsObject=ATestClass);
  247. CheckEquals(TTestValueClass(AValue.AsObject).AInteger, 54329);
  248. ATestClass.Free;
  249. end;
  250. procedure TTestCase1.TestMakeArrayDynamic;
  251. type
  252. TArrDyn = array of LongInt;
  253. var
  254. arr: TArrDyn;
  255. value: TValue;
  256. begin
  257. SetLength(arr, 2);
  258. arr[0] := 42;
  259. arr[1] := 21;
  260. TValue.Make(@arr, TypeInfo(TArrDyn), value);
  261. CheckEquals(value.IsArray, True);
  262. CheckEquals(value.IsObject, False);
  263. CheckEquals(value.IsOrdinal, False);
  264. CheckEquals(value.IsClass, False);
  265. CheckEquals(value.GetArrayLength, 2);
  266. CheckEquals(value.GetArrayElement(0).AsInteger, 42);
  267. CheckEquals(value.GetArrayElement(1).AsInteger, 21);
  268. value.SetArrayElement(0, 84);
  269. CheckEquals(arr[0], 84);
  270. end;
  271. procedure TTestCase1.TestMakeArrayStatic;
  272. type
  273. TArrStat = array[0..1] of LongInt;
  274. TArrStat2D = array[0..1, 0..1] of LongInt;
  275. var
  276. arr: TArrStat;
  277. arr2D: TArrStat2D;
  278. value: TValue;
  279. begin
  280. arr[0] := 42;
  281. arr[1] := 21;
  282. TValue.Make(@arr, TypeInfo(TArrStat), value);
  283. CheckEquals(value.IsArray, True);
  284. CheckEquals(value.IsObject, False);
  285. CheckEquals(value.IsOrdinal, False);
  286. CheckEquals(value.IsClass, False);
  287. CheckEquals(value.GetArrayLength, 2);
  288. CheckEquals(value.GetArrayElement(0).AsInteger, 42);
  289. CheckEquals(value.GetArrayElement(1).AsInteger, 21);
  290. value.SetArrayElement(0, 84);
  291. { since this is a static array the original array isn't touched! }
  292. CheckEquals(arr[0], 42);
  293. arr2D[0, 0] := 42;
  294. arr2D[0, 1] := 21;
  295. arr2D[1, 0] := 84;
  296. arr2D[1, 1] := 63;
  297. TValue.Make(@arr2D, TypeInfo(TArrStat2D), value);
  298. CheckEquals(value.IsArray, True);
  299. CheckEquals(value.GetArrayLength, 4);
  300. CheckEquals(value.GetArrayElement(0).AsInteger, 42);
  301. CheckEquals(value.GetArrayElement(1).AsInteger, 21);
  302. CheckEquals(value.GetArrayElement(2).AsInteger, 84);
  303. CheckEquals(value.GetArrayElement(3).AsInteger, 63);
  304. end;
  305. procedure TTestCase1.TestGetIsReadable;
  306. var
  307. c: TRttiContext;
  308. ARttiType: TRttiType;
  309. AProperty: TRttiProperty;
  310. begin
  311. c := TRttiContext.Create;
  312. try
  313. ARttiType := c.GetType(TTestValueClass);
  314. AProperty := ARttiType.GetProperty('aBoolean');
  315. CheckEquals(AProperty.IsReadable, true);
  316. AProperty := ARttiType.GetProperty('aGetBoolean');
  317. CheckEquals(AProperty.IsReadable, true);
  318. AProperty := ARttiType.GetProperty('aWriteOnly');
  319. CheckEquals(AProperty.IsReadable, False);
  320. finally
  321. c.Free;
  322. end;
  323. end;
  324. procedure TTestCase1.TestIsWritable;
  325. var
  326. c: TRttiContext;
  327. ARttiType: TRttiType;
  328. AProperty: TRttiProperty;
  329. begin
  330. c := TRttiContext.Create;
  331. try
  332. ARttiType := c.GetType(TTestValueClass);
  333. AProperty := ARttiType.GetProperty('aBoolean');
  334. CheckEquals(AProperty.IsWritable, true);
  335. AProperty := ARttiType.GetProperty('aGetBoolean');
  336. CheckEquals(AProperty.IsWritable, false);
  337. AProperty := ARttiType.GetProperty('aWriteOnly');
  338. CheckEquals(AProperty.IsWritable, True);
  339. finally
  340. c.Free;
  341. end;
  342. end;
  343. procedure TTestCase1.TestPropGetValueBoolean;
  344. var
  345. ATestClass : TTestValueClass;
  346. c: TRttiContext;
  347. ARttiType: TRttiType;
  348. AProperty: TRttiProperty;
  349. AValue: TValue;
  350. begin
  351. c := TRttiContext.Create;
  352. try
  353. ATestClass := TTestValueClass.Create;
  354. ATestClass.ABoolean := true;
  355. try
  356. ARttiType := c.GetType(ATestClass.ClassInfo);
  357. Check(assigned(ARttiType));
  358. AProperty := ARttiType.GetProperty('aBoolean');
  359. AValue := AProperty.GetValue(ATestClass);
  360. CheckEquals(true,AValue.AsBoolean);
  361. ATestClass.ABoolean := false;
  362. CheckEquals(true, AValue.AsBoolean);
  363. CheckEquals('True', AValue.ToString);
  364. CheckEquals(True, AValue.IsOrdinal);
  365. CheckEquals(1, AValue.AsOrdinal);
  366. finally
  367. AtestClass.Free;
  368. end;
  369. CheckEquals(True,AValue.AsBoolean);
  370. finally
  371. c.Free;
  372. end;
  373. end;
  374. procedure TTestCase1.TestPropGetValueShortString;
  375. var
  376. ATestClass : TTestValueClass;
  377. c: TRttiContext;
  378. ARttiType: TRttiType;
  379. AProperty: TRttiProperty;
  380. AValue: TValue;
  381. begin
  382. c := TRttiContext.Create;
  383. try
  384. ATestClass := TTestValueClass.Create;
  385. ATestClass.AShortString := 'Hello World';
  386. try
  387. ARttiType := c.GetType(ATestClass.ClassInfo);
  388. Check(assigned(ARttiType));
  389. AProperty := ARttiType.GetProperty('aShortString');
  390. AValue := AProperty.GetValue(ATestClass);
  391. CheckEquals('Hello World',AValue.AsString);
  392. ATestClass.AShortString := 'Foobar';
  393. CheckEquals('Hello World', AValue.AsString);
  394. CheckEquals(False, AValue.IsOrdinal);
  395. CheckEquals(False, AValue.IsObject);
  396. CheckEquals(False, AValue.IsArray);
  397. CheckEquals(False, AValue.IsClass);
  398. finally
  399. AtestClass.Free;
  400. end;
  401. CheckEquals('Hello World',AValue.AsString);
  402. finally
  403. c.Free;
  404. end;
  405. end;
  406. procedure TTestCase1.TestPropGetValueInteger;
  407. var
  408. ATestClass : TTestValueClass;
  409. c: TRttiContext;
  410. ARttiType: TRttiType;
  411. AProperty: TRttiProperty;
  412. AValue: TValue;
  413. begin
  414. c := TRttiContext.Create;
  415. try
  416. ATestClass := TTestValueClass.Create;
  417. ATestClass.AInteger := 472349;
  418. try
  419. ARttiType := c.GetType(ATestClass.ClassInfo);
  420. Check(assigned(ARttiType));
  421. AProperty := ARttiType.GetProperty('ainteger');
  422. AValue := AProperty.GetValue(ATestClass);
  423. CheckEquals(472349,AValue.AsInteger);
  424. ATestClass.AInteger := 12;
  425. CheckEquals(472349, AValue.AsInteger);
  426. CheckEquals('472349', AValue.ToString);
  427. CheckEquals(True, AValue.IsOrdinal);
  428. finally
  429. AtestClass.Free;
  430. end;
  431. CheckEquals(472349,AValue.AsInteger);
  432. finally
  433. c.Free;
  434. end;
  435. end;
  436. procedure TTestCase1.TestPropGetValueString;
  437. var
  438. ATestClass : TTestValueClass;
  439. c: TRttiContext;
  440. ARttiType: TRttiType;
  441. AProperty: TRttiProperty;
  442. AValue: TValue;
  443. i: int64;
  444. begin
  445. c := TRttiContext.Create;
  446. try
  447. ATestClass := TTestValueClass.Create;
  448. ATestClass.AString := 'Hello World';
  449. try
  450. ARttiType := c.GetType(ATestClass.ClassInfo);
  451. Check(assigned(ARttiType));
  452. AProperty := ARttiType.GetProperty('astring');
  453. AValue := AProperty.GetValue(ATestClass);
  454. CheckEquals('Hello World',AValue.AsString);
  455. ATestClass.AString := 'Goodbye World';
  456. CheckEquals('Hello World',AValue.AsString);
  457. CheckEquals('Hello World',AValue.ToString);
  458. Check(TypeInfo(string)=AValue.TypeInfo);
  459. Check(AValue.TypeData=GetTypeData(AValue.TypeInfo));
  460. Check(AValue.IsEmpty=false);
  461. Check(AValue.IsObject=false);
  462. Check(AValue.IsClass=false);
  463. CheckEquals(AValue.IsOrdinal, false);
  464. CheckEquals(AValue.TryAsOrdinal(i), false);
  465. CheckEquals(AValue.IsType(TypeInfo(string)), true);
  466. CheckEquals(AValue.IsType(TypeInfo(integer)), false);
  467. CheckEquals(AValue.IsArray, false);
  468. finally
  469. AtestClass.Free;
  470. end;
  471. CheckEquals('Hello World',AValue.AsString);
  472. finally
  473. c.Free;
  474. end;
  475. end;
  476. procedure TTestCase1.TestPropGetValueProcBoolean;
  477. var
  478. ATestClass : TTestValueClass;
  479. c: TRttiContext;
  480. ARttiType: TRttiType;
  481. AProperty: TRttiProperty;
  482. AValue: TValue;
  483. begin
  484. c := TRttiContext.Create;
  485. try
  486. ATestClass := TTestValueClass.Create;
  487. ATestClass.ABoolean := true;
  488. try
  489. ARttiType := c.GetType(ATestClass.ClassInfo);
  490. Check(assigned(ARttiType));
  491. AProperty := ARttiType.GetProperty('aGetBoolean');
  492. AValue := AProperty.GetValue(ATestClass);
  493. CheckEquals(true,AValue.AsBoolean);
  494. finally
  495. AtestClass.Free;
  496. end;
  497. CheckEquals(True,AValue.AsBoolean);
  498. finally
  499. c.Free;
  500. end;
  501. end;
  502. procedure TTestCase1.TestPropGetValueProcShortString;
  503. var
  504. ATestClass : TTestValueClass;
  505. c: TRttiContext;
  506. ARttiType: TRttiType;
  507. AProperty: TRttiProperty;
  508. AValue: TValue;
  509. begin
  510. c := TRttiContext.Create;
  511. try
  512. ATestClass := TTestValueClass.Create;
  513. ATestClass.AShortString := 'Hello World';
  514. try
  515. ARttiType := c.GetType(ATestClass.ClassInfo);
  516. Check(assigned(ARttiType));
  517. AProperty := ARttiType.GetProperty('aGetShortString');
  518. AValue := AProperty.GetValue(ATestClass);
  519. CheckEquals('Hello World',AValue.AsString);
  520. finally
  521. AtestClass.Free;
  522. end;
  523. CheckEquals('Hello World',AValue.AsString);
  524. finally
  525. c.Free;
  526. end;
  527. end;
  528. procedure TTestCase1.TestPropSetValueString;
  529. var
  530. ATestClass : TTestValueClass;
  531. c: TRttiContext;
  532. ARttiType: TRttiType;
  533. AProperty: TRttiProperty;
  534. AValue: TValue;
  535. s: string;
  536. begin
  537. c := TRttiContext.Create;
  538. try
  539. ATestClass := TTestValueClass.Create;
  540. try
  541. ARttiType := c.GetType(ATestClass.ClassInfo);
  542. AProperty := ARttiType.GetProperty('astring');
  543. s := 'ipse lorem or something like that';
  544. TValue.Make(@s, TypeInfo(string), AValue);
  545. AProperty.SetValue(ATestClass, AValue);
  546. CheckEquals(ATestClass.AString, s);
  547. s := 'Another string';
  548. CheckEquals(ATestClass.AString, 'ipse lorem or something like that');
  549. finally
  550. AtestClass.Free;
  551. end;
  552. finally
  553. c.Free;
  554. end;
  555. end;
  556. procedure TTestCase1.TestPropSetValueInteger;
  557. var
  558. ATestClass : TTestValueClass;
  559. c: TRttiContext;
  560. ARttiType: TRttiType;
  561. AProperty: TRttiProperty;
  562. AValue: TValue;
  563. i: integer;
  564. begin
  565. c := TRttiContext.Create;
  566. try
  567. ATestClass := TTestValueClass.Create;
  568. try
  569. ARttiType := c.GetType(ATestClass.ClassInfo);
  570. AProperty := ARttiType.GetProperty('aInteger');
  571. i := -43573;
  572. TValue.Make(@i, TypeInfo(Integer), AValue);
  573. AProperty.SetValue(ATestClass, AValue);
  574. CheckEquals(ATestClass.AInteger, i);
  575. i := 1;
  576. CheckEquals(ATestClass.AInteger, -43573);
  577. finally
  578. AtestClass.Free;
  579. end;
  580. finally
  581. c.Free;
  582. end;
  583. end;
  584. procedure TTestCase1.TestPropSetValueBoolean;
  585. var
  586. ATestClass : TTestValueClass;
  587. c: TRttiContext;
  588. ARttiType: TRttiType;
  589. AProperty: TRttiProperty;
  590. AValue: TValue;
  591. b: boolean;
  592. begin
  593. c := TRttiContext.Create;
  594. try
  595. ATestClass := TTestValueClass.Create;
  596. try
  597. ARttiType := c.GetType(ATestClass.ClassInfo);
  598. AProperty := ARttiType.GetProperty('aboolean');
  599. b := true;
  600. TValue.Make(@b, TypeInfo(Boolean), AValue);
  601. AProperty.SetValue(ATestClass, AValue);
  602. CheckEquals(ATestClass.ABoolean, b);
  603. b := false;
  604. CheckEquals(ATestClass.ABoolean, true);
  605. TValue.Make(@b, TypeInfo(Boolean), AValue);
  606. AProperty.SetValue(ATestClass, AValue);
  607. CheckEquals(ATestClass.ABoolean, false);
  608. finally
  609. AtestClass.Free;
  610. end;
  611. finally
  612. c.Free;
  613. end;
  614. end;
  615. procedure TTestCase1.TestPropSetValueShortString;
  616. var
  617. ATestClass : TTestValueClass;
  618. c: TRttiContext;
  619. ARttiType: TRttiType;
  620. AProperty: TRttiProperty;
  621. AValue: TValue;
  622. s: string;
  623. ss: ShortString;
  624. begin
  625. c := TRttiContext.Create;
  626. try
  627. ATestClass := TTestValueClass.Create;
  628. try
  629. ARttiType := c.GetType(ATestClass.ClassInfo);
  630. AProperty := ARttiType.GetProperty('aShortString');
  631. s := 'ipse lorem or something like that';
  632. TValue.Make(@s, TypeInfo(String), AValue);
  633. AProperty.SetValue(ATestClass, AValue);
  634. CheckEquals(ATestClass.AShortString, s);
  635. s := 'Another string';
  636. CheckEquals(ATestClass.AShortString, 'ipse lorem or something like that');
  637. ss := 'Hello World';
  638. TValue.Make(@ss, TypeInfo(ShortString), AValue);
  639. AProperty.SetValue(ATestClass, AValue);
  640. CheckEquals(ATestClass.AShortString, ss);
  641. ss := 'Foobar';
  642. CheckEquals(ATestClass.AShortString, 'Hello World');
  643. finally
  644. AtestClass.Free;
  645. end;
  646. finally
  647. c.Free;
  648. end;
  649. end;
  650. procedure TTestCase1.TestPropGetValueProcInteger;
  651. var
  652. ATestClass : TTestValueClass;
  653. c: TRttiContext;
  654. ARttiType: TRttiType;
  655. AProperty: TRttiProperty;
  656. AValue: TValue;
  657. begin
  658. c := TRttiContext.Create;
  659. try
  660. ATestClass := TTestValueClass.Create;
  661. ATestClass.AInteger := 472349;
  662. try
  663. ARttiType := c.GetType(ATestClass.ClassInfo);
  664. Check(assigned(ARttiType));
  665. AProperty := ARttiType.GetProperty('agetinteger');
  666. AValue := AProperty.GetValue(ATestClass);
  667. CheckEquals(472349,AValue.AsInteger);
  668. finally
  669. AtestClass.Free;
  670. end;
  671. CheckEquals(472349,AValue.AsInteger);
  672. finally
  673. c.Free;
  674. end;
  675. end;
  676. procedure TTestCase1.TestPropGetValueProcString;
  677. var
  678. ATestClass : TTestValueClass;
  679. c: TRttiContext;
  680. ARttiType: TRttiType;
  681. AProperty: TRttiProperty;
  682. AValue: TValue;
  683. begin
  684. c := TRttiContext.Create;
  685. try
  686. ATestClass := TTestValueClass.Create;
  687. ATestClass.AString := 'Hello World';
  688. try
  689. ARttiType := c.GetType(ATestClass.ClassInfo);
  690. Check(assigned(ARttiType));
  691. AProperty := ARttiType.GetProperty('agetstring');
  692. AValue := AProperty.GetValue(ATestClass);
  693. CheckEquals('Hello World',AValue.AsString);
  694. finally
  695. AtestClass.Free;
  696. end;
  697. CheckEquals('Hello World',AValue.AsString);
  698. finally
  699. c.Free;
  700. end;
  701. end;
  702. procedure TTestCase1.TestTRttiTypeProperties;
  703. var
  704. c: TRttiContext;
  705. ARttiType: TRttiType;
  706. begin
  707. c := TRttiContext.Create;
  708. try
  709. ARttiType := c.GetType(TTestValueClass);
  710. Check(assigned(ARttiType));
  711. CheckEquals(ARttiType.Name,'TTestValueClass');
  712. Check(ARttiType.TypeKind=tkClass);
  713. // CheckEquals(ARttiType.IsPublicType,false);
  714. CheckEquals(ARttiType.TypeSize,SizeOf(TObject));
  715. CheckEquals(ARttiType.IsManaged,false);
  716. CheckEquals(ARttiType.BaseType.classname,'TRttiInstanceType');
  717. CheckEquals(ARttiType.IsInstance,True);
  718. CheckEquals(ARttiType.AsInstance.DeclaringUnitName,'tests.rtti');
  719. Check(ARttiType.BaseType.Name='TObject');
  720. Check(ARttiType.AsInstance.BaseType.Name='TObject');
  721. CheckEquals(ARttiType.IsOrdinal,False);
  722. CheckEquals(ARttiType.IsRecord,False);
  723. CheckEquals(ARttiType.IsSet,False);
  724. finally
  725. c.Free;
  726. end;
  727. end;
  728. procedure TTestCase1.GetTypeInteger;
  729. var
  730. LContext: TRttiContext;
  731. LType: TRttiType;
  732. begin
  733. LContext := TRttiContext.Create;
  734. LType := LContext.GetType(TypeInfo(integer));
  735. {$ifdef fpc}
  736. CheckEquals(LType.Name, 'LongInt');
  737. {$else}
  738. CheckEquals(LType.Name, 'Integer');
  739. {$endif}
  740. LContext.Free;
  741. end;
  742. procedure TTestCase1.GetClassProperties;
  743. var
  744. LContext: TRttiContext;
  745. LType: TRttiType;
  746. PropList: {$ifdef fpc}specialize{$endif} TArray<TRttiProperty>;
  747. begin
  748. LContext := TRttiContext.Create;
  749. LType := LContext.GetType(TypeInfo(TGetClassProperties));
  750. PropList := LType.GetProperties;
  751. CheckEquals(4, length(PropList));
  752. CheckEquals('PubPropRO', PropList[0].Name);
  753. CheckEquals('PubPropRW', PropList[1].Name);
  754. CheckEquals('PubPropSetRO', PropList[2].Name);
  755. CheckEquals('PubPropSetRW', PropList[3].Name);
  756. LContext.Free;
  757. end;
  758. procedure TTestCase1.GetClassPropertiesValue;
  759. var
  760. AGetClassProperties: TGetClassProperties;
  761. LContext: TRttiContext;
  762. LType: TRttiType;
  763. AValue: TValue;
  764. begin
  765. LContext := TRttiContext.Create;
  766. LType := LContext.GetType(TGetClassProperties);
  767. AGetClassProperties := TGetClassProperties.Create;
  768. try
  769. AGetClassProperties.PubPropRW:=12345;
  770. AValue := LType.GetProperty('PubPropRW').GetValue(AGetClassProperties);
  771. CheckEquals(12345, AValue.AsInteger);
  772. finally
  773. AGetClassProperties.Free;
  774. end;
  775. LContext.Free;
  776. end;
  777. procedure TTestCase1.TestReferenceRawData;
  778. type
  779. TTest = record
  780. a: LongInt;
  781. b: String;
  782. end;
  783. PTest = ^TTest;
  784. TArrDyn = array of LongInt;
  785. TArrStat = array[0..2] of LongInt;
  786. var
  787. value: TValue;
  788. str: String;
  789. intf: IInterface;
  790. i: LongInt;
  791. test: TTest;
  792. arrdyn: TArrDyn;
  793. arrstat: TArrStat;
  794. begin
  795. str := 'Hello World';
  796. UniqueString(str);
  797. TValue.Make(@str, TypeInfo(String), value);
  798. Check(PPointer(value.GetReferenceToRawData)^ = Pointer(str), 'Reference to string data differs');
  799. intf := TInterfacedObject.Create;
  800. TValue.Make(@intf, TypeInfo(IInterface), value);
  801. Check(PPointer(value.GetReferenceToRawData)^ = Pointer(intf), 'Reference to interface data differs');
  802. i := 42;
  803. TValue.Make(@i, TypeInfo(LongInt), value);
  804. Check(value.GetReferenceToRawData <> @i, 'Reference to longint is equal');
  805. Check(PLongInt(value.GetReferenceToRawData)^ = PLongInt(@i)^, 'Reference to longint data differs');
  806. test.a := 42;
  807. test.b := 'Hello World';
  808. TValue.Make(@test, TypeInfo(TTest), value);
  809. Check(value.GetReferenceToRawData <> @test, 'Reference to record is equal');
  810. Check(PTest(value.GetReferenceToRawData)^.a = PTest(@test)^.a, 'Reference to record data a differs');
  811. Check(PTest(value.GetReferenceToRawData)^.b = PTest(@test)^.b, 'Reference to record data b differs');
  812. SetLength(arrdyn, 3);
  813. arrdyn[0] := 42;
  814. arrdyn[1] := 23;
  815. arrdyn[2] := 49;
  816. TValue.Make(@arrdyn, TypeInfo(TArrDyn), value);
  817. Check(PPointer(value.GetReferenceToRawData)^ = Pointer(arrdyn), 'Reference to dynamic array data differs');
  818. arrstat[0] := 42;
  819. arrstat[1] := 23;
  820. arrstat[2] := 49;
  821. TValue.Make(@arrstat, TypeInfo(TArrStat), value);
  822. Check(value.GetReferenceToRawData <> @arrstat, 'Reference to static array is equal');
  823. Check(PLongInt(value.GetReferenceToRawData)^ = PLongInt(@arrstat)^, 'Reference to static array data differs');
  824. end;
  825. procedure TTestCase1.TestDataSize;
  826. type
  827. TEnum = (eOne, eTwo, eThree);
  828. TSet = set of TEnum;
  829. TTestRecord = record
  830. Value1: LongInt;
  831. Value2: Pointer;
  832. end;
  833. TObjProc = procedure of object;
  834. TArrDyn = array of LongInt;
  835. TArrStatic = array[0..3] of LongInt;
  836. var
  837. u8: UInt8;
  838. u16: UInt16;
  839. u32: UInt32;
  840. u64: UInt64;
  841. s8: Int8;
  842. s16: Int16;
  843. s32: Int32;
  844. s64: Int64;
  845. f32: Single;
  846. f64: Double;
  847. {$ifdef FPC_HAS_TYPE_EXTENDED}
  848. f80: Extended;
  849. {$endif}
  850. fco: Comp;
  851. fcu: Currency;
  852. ss: ShortString;
  853. sa: AnsiString;
  854. su: UnicodeString;
  855. sw: WideString;
  856. o: TObject;
  857. c: TClass;
  858. i: IInterface;
  859. ad: TArrDyn;
  860. _as: TArrStatic;
  861. b8: Boolean;
  862. {$ifdef fpc}
  863. b16: Boolean16;
  864. b32: Boolean32;
  865. b64: Boolean64;
  866. {$endif}
  867. bl8: ByteBool;
  868. bl16: WordBool;
  869. bl32: LongBool;
  870. {$ifdef fpc}
  871. bl64: QWordBool;
  872. {$endif}
  873. e: TEnum;
  874. s: TSet;
  875. t: TTestRecord;
  876. p: Pointer;
  877. proc: TProcedure;
  878. method: TObjProc;
  879. value: TValue;
  880. begin
  881. TValue.Make(@u8, TypeInfo(UInt8), value);
  882. CheckEquals(1, value.DataSize);
  883. TValue.Make(@u16, TypeInfo(UInt16), value);
  884. CheckEquals(2, value.DataSize);
  885. TValue.Make(@u32, TypeInfo(UInt32), value);
  886. CheckEquals(4, value.DataSize);
  887. TValue.Make(@u64, TypeInfo(UInt64), value);
  888. CheckEquals(8, value.DataSize);
  889. TValue.Make(@s8, TypeInfo(Int8), value);
  890. CheckEquals(1, value.DataSize);
  891. TValue.Make(@s16, TypeInfo(Int16), value);
  892. CheckEquals(2, value.DataSize);
  893. TValue.Make(@s32, TypeInfo(Int32), value);
  894. CheckEquals(4, value.DataSize);
  895. TValue.Make(@s64, TypeInfo(Int64), value);
  896. CheckEquals(8, value.DataSize);
  897. TValue.Make(@b8, TypeInfo(Boolean), value);
  898. CheckEquals(1, value.DataSize);
  899. {$ifdef fpc}
  900. TValue.Make(@b16, TypeInfo(Boolean16), value);
  901. CheckEquals(2, value.DataSize);
  902. TValue.Make(@b32, TypeInfo(Boolean32), value);
  903. CheckEquals(4, value.DataSize);
  904. TValue.Make(@b64, TypeInfo(Boolean64), value);
  905. CheckEquals(8, value.DataSize);
  906. {$endif}
  907. TValue.Make(@bl8, TypeInfo(ByteBool), value);
  908. CheckEquals(1, value.DataSize);
  909. TValue.Make(@bl16, TypeInfo(WordBool), value);
  910. CheckEquals(2, value.DataSize);
  911. TValue.Make(@bl32, TypeInfo(LongBool), value);
  912. CheckEquals(4, value.DataSize);
  913. {$ifdef fpc}
  914. TValue.Make(@bl64, TypeInfo(QWordBool), value);
  915. CheckEquals(8, value.DataSize);
  916. {$endif}
  917. TValue.Make(@f32, TypeInfo(Single), value);
  918. CheckEquals(4, value.DataSize);
  919. TValue.Make(@f64, TypeInfo(Double), value);
  920. CheckEquals(8, value.DataSize);
  921. {$ifdef FPC_HAS_TYPE_EXTENDED}
  922. TValue.Make(@f80, TypeInfo(Extended), value);
  923. CheckEquals(10, value.DataSize);
  924. {$endif}
  925. TValue.Make(@fcu, TypeInfo(Currency), value);
  926. CheckEquals(SizeOf(Currency), value.DataSize);
  927. TValue.Make(@fco, TypeInfo(Comp), value);
  928. CheckEquals(SizeOf(Comp), value.DataSize);
  929. ss := '';
  930. TValue.Make(@ss, TypeInfo(ShortString), value);
  931. CheckEquals(254, value.DataSize);
  932. TValue.Make(@sa, TypeInfo(AnsiString), value);
  933. CheckEquals(SizeOf(Pointer), value.DataSize);
  934. TValue.Make(@sw, TypeInfo(WideString), value);
  935. CheckEquals(SizeOf(Pointer), value.DataSize);
  936. TValue.Make(@su, TypeInfo(UnicodeString), value);
  937. CheckEquals(SizeOf(Pointer), value.DataSize);
  938. o := TTestValueClass.Create;
  939. TValue.Make(@o, TypeInfo(TObject), value);
  940. CheckEquals(SizeOf(Pointer), value.DataSize);
  941. o.Free;
  942. c := TObject;
  943. TValue.Make(@c, TypeInfo(TClass), value);
  944. CheckEquals(SizeOf(Pointer), value.DataSize);
  945. TValue.Make(@i, TypeInfo(IInterface), value);
  946. CheckEquals(SizeOf(Pointer), value.DataSize);
  947. TValue.Make(@t, TypeInfo(TTestRecord), value);
  948. CheckEquals(SizeOf(TTestRecord), value.DataSize);
  949. proc := Nil;
  950. TValue.Make(@proc, TypeInfo(TProcedure), value);
  951. CheckEquals(SizeOf(TProcedure), value.DataSize);
  952. {method := Nil;
  953. TValue.Make(@method, TypeInfo(TObjProc), value);
  954. CheckEquals(SizeOf(TObjProc), value.DataSize);}
  955. TValue.Make(@_as, TypeInfo(TArrStatic), value);
  956. CheckEquals(SizeOf(TArrStatic), value.DataSize);
  957. TValue.Make(@ad, TypeInfo(TArrDyn), value);
  958. CheckEquals(SizeOf(TArrDyn), value.DataSize);
  959. {TValue.Make(@e, TypeInfo(TEnum), value);
  960. CheckEquals(SizeOf(TEnum), value.DataSize);
  961. TValue.Make(@s, TypeInfo(TSet), value);
  962. CheckEquals(SizeOf(TSet), value.DataSize);}
  963. p := Nil;
  964. TValue.Make(@p, TypeInfo(Pointer), value);
  965. CheckEquals(SizeOf(Pointer), value.DataSize);
  966. end;
  967. procedure TTestCase1.TestIsManaged;
  968. begin
  969. CheckEquals(true, IsManaged(TypeInfo(ansistring)), 'IsManaged for tkAString');
  970. CheckEquals(true, IsManaged(TypeInfo(widestring)), 'IsManaged for tkWString');
  971. CheckEquals(true, IsManaged(TypeInfo(Variant)), 'IsManaged for tkVariant');
  972. CheckEquals(true, IsManaged(TypeInfo(TArrayOfManagedRec)),
  973. 'IsManaged for tkArray (with managed ElType)');
  974. CheckEquals(true, IsManaged(TypeInfo(TArrayOfString)),
  975. 'IsManaged for tkArray (with managed ElType)');
  976. CheckEquals(true, IsManaged(TypeInfo(TManagedRec)), 'IsManaged for tkRecord');
  977. {$ifdef fpc}
  978. CheckEquals(true, IsManaged(TypeInfo(TManagedRecOp)), 'IsManaged for tkRecord');
  979. {$endif}
  980. CheckEquals(true, IsManaged(TypeInfo(IInterface)), 'IsManaged for tkInterface');
  981. CheckEquals(true, IsManaged(TypeInfo(TManagedObj)), 'IsManaged for tkObject');
  982. {$ifdef fpc}
  983. CheckEquals(true, IsManaged(TypeInfo(specialize TArray<byte>)), 'IsManaged for tkDynArray');
  984. {$else}
  985. CheckEquals(true, IsManaged(TypeInfo(TArray<byte>)), 'IsManaged for tkDynArray');
  986. {$endif}
  987. CheckEquals(true, IsManaged(TypeInfo(unicodestring)), 'IsManaged for tkUString');
  988. CheckEquals(false, IsManaged(TypeInfo(shortstring)), 'IsManaged for tkSString');
  989. CheckEquals(false, IsManaged(TypeInfo(Byte)), 'IsManaged for tkInteger');
  990. CheckEquals(false, IsManaged(TypeInfo(Char)), 'IsManaged for tkChar');
  991. CheckEquals(false, IsManaged(TypeInfo(TTestEnum)), 'IsManaged for tkEnumeration');
  992. CheckEquals(false, IsManaged(TypeInfo(Single)), 'IsManaged for tkFloat');
  993. CheckEquals(false, IsManaged(TypeInfo(TTestSet)), 'IsManaged for tkSet');
  994. {$ifdef fpc}
  995. CheckEquals(false, IsManaged(TypeInfo(TTestMethod)), 'IsManaged for tkMethod');
  996. {$else}
  997. { Delphi bug (or sabotage). For some reason Delphi considers method pointers to be managed (only in newer versions, probably since XE7) :/ }
  998. CheckEquals({$if RTLVersion>=28}true{$else}false{$endif}, IsManaged(TypeInfo(TTestMethod)), 'IsManaged for tkMethod');
  999. {$endif}
  1000. CheckEquals(false, IsManaged(TypeInfo(TArrayOfByte)),
  1001. 'IsManaged for tkArray (with non managed ElType)');
  1002. CheckEquals(false, IsManaged(TypeInfo(TArrayOfNonManagedRec)),
  1003. 'IsManaged for tkArray (with non managed ElType)');
  1004. CheckEquals(false, IsManaged(TypeInfo(TNonManagedRec)), 'IsManaged for tkRecord');
  1005. CheckEquals(false, IsManaged(TypeInfo(TObject)), 'IsManaged for tkClass');
  1006. CheckEquals(false, IsManaged(TypeInfo(TNonManagedObj)), 'IsManaged for tkObject');
  1007. CheckEquals(false, IsManaged(TypeInfo(WideChar)), 'IsManaged for tkWChar');
  1008. CheckEquals(false, IsManaged(TypeInfo(Boolean)), 'IsManaged for tkBool');
  1009. CheckEquals(false, IsManaged(TypeInfo(Int64)), 'IsManaged for tkInt64');
  1010. CheckEquals(false, IsManaged(TypeInfo(UInt64)), 'IsManaged for tkQWord');
  1011. {$ifdef fpc}
  1012. CheckEquals(false, IsManaged(TypeInfo(ICORBATest)), 'IsManaged for tkInterfaceRaw');
  1013. {$endif}
  1014. CheckEquals(false, IsManaged(TypeInfo(TTestProc)), 'IsManaged for tkProcVar');
  1015. CheckEquals(false, IsManaged(TypeInfo(TTestHelper)), 'IsManaged for tkHelper');
  1016. {$ifdef fpc}
  1017. CheckEquals(false, IsManaged(TypeInfo(file)), 'IsManaged for tkFile');
  1018. {$endif}
  1019. CheckEquals(false, IsManaged(TypeInfo(TClass)), 'IsManaged for tkClassRef');
  1020. CheckEquals(false, IsManaged(TypeInfo(Pointer)), 'IsManaged for tkPointer');
  1021. CheckEquals(false, IsManaged(nil), 'IsManaged for nil');
  1022. end;
  1023. initialization
  1024. {$ifdef fpc}
  1025. RegisterTest(TTestCase1);
  1026. {$else fpc}
  1027. RegisterTest(TTestCase1.Suite);
  1028. {$endif fpc}
  1029. end.