tests_rtti.pas 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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 TestGetValueStringCastError;
  29. end;
  30. implementation
  31. type
  32. { TIntAttribute }
  33. TIntAttribute = class(TCustomAttribute)
  34. private
  35. FInt: Integer;
  36. public
  37. constructor create(AInt: integer); virtual;
  38. property Int: integer read FInt;
  39. end;
  40. [TIntAttribute(1)]
  41. [TIntAttribute(2)]
  42. TGetClassProperties = class
  43. private
  44. FPubPropRO: integer;
  45. FPubPropRW: integer;
  46. published
  47. property PubPropRO: integer read FPubPropRO;
  48. [TIntAttribute(3)]
  49. property PubPropRW: integer read FPubPropRW write FPubPropRW;
  50. property PubPropSetRO: integer read FPubPropRO;
  51. [TIntAttribute(4)]
  52. property PubPropSetRW: integer read FPubPropRW write FPubPropRW;
  53. end;
  54. TTestValueClass = class
  55. private
  56. FAInteger: integer;
  57. FAString: string;
  58. FABoolean: boolean;
  59. published
  60. property AInteger: Integer read FAInteger write FAInteger;
  61. property AString: string read FAString write FAString;
  62. property ABoolean: boolean read FABoolean write FABoolean;
  63. end;
  64. { TIntAttribute }
  65. constructor TIntAttribute.create(AInt: integer);
  66. begin
  67. FInt:=AInt;
  68. end;
  69. procedure TTestCase1.GetTypes;
  70. var
  71. LContext: TRttiContext;
  72. LType: TRttiType;
  73. IsTestCaseClassFound: boolean;
  74. begin
  75. LContext := TRttiContext.Create;
  76. { Enumerate all types declared in the application }
  77. for LType in LContext.GetTypes() do
  78. begin
  79. if LType.Name='TTestCase1' then
  80. IsTestCaseClassFound:=true;
  81. end;
  82. LContext.Free;
  83. CheckTrue(IsTestCaseClassFound, 'RTTI information does not contain class of testcase.');
  84. end;
  85. procedure TTestCase1.TestGetValueStringCastError;
  86. var
  87. ATestClass : TTestValueClass;
  88. c: TRttiContext;
  89. ARttiType: TRttiType;
  90. AValue: TValue;
  91. i: integer;
  92. HadException: boolean;
  93. begin
  94. c := TRttiContext.Create;
  95. try
  96. ATestClass := TTestValueClass.Create;
  97. ATestClass.AString := '12';
  98. try
  99. ARttiType := c.GetType(ATestClass.ClassInfo);
  100. AValue := ARttiType.GetProperty('astring').GetValue(ATestClass);
  101. HadException := false;
  102. try
  103. i := AValue.AsInteger;
  104. except
  105. on E: Exception do
  106. if E.ClassType=EInvalidCast then
  107. HadException := true;
  108. end;
  109. Check(HadException, 'No or invalid exception on invalid cast');
  110. finally
  111. AtestClass.Free;
  112. end;
  113. finally
  114. c.Free;
  115. end;
  116. end;
  117. procedure TTestCase1.TestPropGetValueBoolean;
  118. var
  119. ATestClass : TTestValueClass;
  120. c: TRttiContext;
  121. ARttiType: TRttiType;
  122. AProperty: TRttiProperty;
  123. AValue: TValue;
  124. begin
  125. c := TRttiContext.Create;
  126. try
  127. ATestClass := TTestValueClass.Create;
  128. ATestClass.ABoolean := true;
  129. try
  130. ARttiType := c.GetType(ATestClass.ClassInfo);
  131. Check(assigned(ARttiType));
  132. AProperty := ARttiType.GetProperty('aBoolean');
  133. AValue := AProperty.GetValue(ATestClass);
  134. CheckEquals(true,AValue.AsBoolean);
  135. ATestClass.ABoolean := false;
  136. CheckEquals(true, AValue.AsBoolean);
  137. CheckEquals('True', AValue.ToString);
  138. CheckEquals(True, AValue.IsOrdinal);
  139. CheckEquals(1, AValue.AsOrdinal);
  140. finally
  141. AtestClass.Free;
  142. end;
  143. CheckEquals(True,AValue.AsBoolean);
  144. finally
  145. c.Free;
  146. end;
  147. end;
  148. procedure TTestCase1.TestPropGetValueInteger;
  149. var
  150. ATestClass : TTestValueClass;
  151. c: TRttiContext;
  152. ARttiType: TRttiType;
  153. AProperty: TRttiProperty;
  154. AValue: TValue;
  155. begin
  156. c := TRttiContext.Create;
  157. try
  158. ATestClass := TTestValueClass.Create;
  159. ATestClass.AInteger := 472349;
  160. try
  161. ARttiType := c.GetType(ATestClass.ClassInfo);
  162. Check(assigned(ARttiType));
  163. AProperty := ARttiType.GetProperty('ainteger');
  164. AValue := AProperty.GetValue(ATestClass);
  165. CheckEquals(472349,AValue.AsInteger);
  166. ATestClass.AInteger := 12;
  167. CheckEquals(472349, AValue.AsInteger);
  168. CheckEquals('472349', AValue.ToString);
  169. CheckEquals(True, AValue.IsOrdinal);
  170. finally
  171. AtestClass.Free;
  172. end;
  173. CheckEquals(472349,AValue.AsInteger);
  174. finally
  175. c.Free;
  176. end;
  177. end;
  178. procedure TTestCase1.TestPropGetValueString;
  179. var
  180. ATestClass : TTestValueClass;
  181. c: TRttiContext;
  182. ARttiType: TRttiType;
  183. AProperty: TRttiProperty;
  184. AValue: TValue;
  185. i: int64;
  186. begin
  187. c := TRttiContext.Create;
  188. try
  189. ATestClass := TTestValueClass.Create;
  190. ATestClass.AString := 'Hello World';
  191. try
  192. ARttiType := c.GetType(ATestClass.ClassInfo);
  193. Check(assigned(ARttiType));
  194. AProperty := ARttiType.GetProperty('astring');
  195. AValue := AProperty.GetValue(ATestClass);
  196. CheckEquals('Hello World',AValue.AsString);
  197. ATestClass.AString := 'Goodbye World';
  198. CheckEquals('Hello World',AValue.AsString);
  199. CheckEquals('Hello World',AValue.ToString);
  200. Check(TypeInfo(string)=AValue.TypeInfo);
  201. Check(AValue.TypeData=GetTypeData(AValue.TypeInfo));
  202. // Check(AValue.IsEmpty=false);
  203. Check(AValue.IsObject=false);
  204. Check(AValue.IsClass=false);
  205. CheckEquals(AValue.IsOrdinal, false);
  206. CheckEquals(AValue.TryAsOrdinal(i), false);
  207. CheckEquals(AValue.IsType(TypeInfo(string)), true);
  208. CheckEquals(AValue.IsType(TypeInfo(integer)), false);
  209. CheckEquals(AValue.IsArray, false);
  210. finally
  211. AtestClass.Free;
  212. end;
  213. CheckEquals('Hello World',AValue.AsString);
  214. finally
  215. c.Free;
  216. end;
  217. end;
  218. procedure TTestCase1.TestTRttiTypeProperties;
  219. var
  220. c: TRttiContext;
  221. ARttiType: TRttiType;
  222. begin
  223. c := TRttiContext.Create;
  224. try
  225. ARttiType := c.GetType(TTestValueClass);
  226. Check(assigned(ARttiType));
  227. CheckEquals(ARttiType.Name,'TTestValueClass');
  228. Check(ARttiType.TypeKind=tkClass);
  229. // CheckEquals(ARttiType.IsPublicType,false);
  230. CheckEquals(ARttiType.TypeSize,4);
  231. CheckEquals(ARttiType.IsManaged,false);
  232. CheckEquals(ARttiType.BaseType.classname,'TRttiInstanceType');
  233. CheckEquals(ARttiType.IsInstance,True);
  234. CheckEquals(ARttiType.AsInstance.DeclaringUnitName,'tests_rtti');
  235. Check(ARttiType.BaseType.Name='TObject');
  236. Check(ARttiType.AsInstance.BaseType.Name='TObject');
  237. CheckEquals(ARttiType.IsOrdinal,False);
  238. CheckEquals(ARttiType.IsRecord,False);
  239. CheckEquals(ARttiType.IsSet,False);
  240. finally
  241. c.Free;
  242. end;
  243. end;
  244. procedure TTestCase1.GetTypeInteger;
  245. var
  246. LContext: TRttiContext;
  247. LType: TRttiType;
  248. begin
  249. LContext := TRttiContext.Create;
  250. LType := LContext.GetType(TypeInfo(integer));
  251. CheckEquals(LType.Name, 'LongInt');
  252. LContext.Free;
  253. end;
  254. procedure TTestCase1.GetClassProperties;
  255. var
  256. LContext: TRttiContext;
  257. LType: TRttiType;
  258. PropList: {$ifdef fpc}specialize{$endif} TArray<TRttiProperty>;
  259. begin
  260. LContext := TRttiContext.Create;
  261. LType := LContext.GetType(TypeInfo(TGetClassProperties));
  262. PropList := LType.GetProperties;
  263. CheckEquals(4, length(PropList));
  264. CheckEquals('PubPropRO', PropList[0].Name);
  265. CheckEquals('PubPropRW', PropList[1].Name);
  266. CheckEquals('PubPropSetRO', PropList[2].Name);
  267. CheckEquals('PubPropSetRW', PropList[3].Name);
  268. LContext.Free;
  269. end;
  270. procedure TTestCase1.GetClassAttributes;
  271. var
  272. LContext: TRttiContext;
  273. LType: TRttiType;
  274. AttrList: {$ifdef fpc}specialize{$endif} TArray<TCustomAttribute>;
  275. begin
  276. LContext := TRttiContext.Create;
  277. LType := LContext.GetType(TypeInfo(TGetClassProperties));
  278. AttrList := LType.GetAttributes;
  279. CheckEquals(2, length(AttrList));
  280. CheckEquals('TIntAttribute', AttrList[0].ClassName);
  281. CheckEquals('TIntAttribute', AttrList[1].ClassName);
  282. CheckEquals(1, TIntAttribute(AttrList[0]).Int);
  283. CheckEquals(2, TIntAttribute(AttrList[1]).Int);
  284. LContext.Free;
  285. end;
  286. procedure TTestCase1.GetClassPropertiesAttributes;
  287. var
  288. LContext: TRttiContext;
  289. LType: TRttiType;
  290. PropList: {$ifdef fpc}specialize{$endif} TArray<TRttiProperty>;
  291. AttrList: {$ifdef fpc}specialize{$endif} TArray<TCustomAttribute>;
  292. begin
  293. LContext := TRttiContext.Create;
  294. LType := LContext.GetType(TypeInfo(TGetClassProperties));
  295. PropList := LType.GetProperties;
  296. AttrList := PropList[1].GetAttributes;
  297. CheckEquals(1, length(AttrList));
  298. CheckEquals(3, TIntAttribute(AttrList[0]).Int);
  299. AttrList := PropList[3].GetAttributes;
  300. CheckEquals(1, length(AttrList));
  301. CheckEquals(4, TIntAttribute(AttrList[0]).Int);
  302. LContext.Free;
  303. end;
  304. procedure TTestCase1.GetClassPropertiesValue;
  305. var
  306. AGetClassProperties: TGetClassProperties;
  307. LContext: TRttiContext;
  308. LType: TRttiType;
  309. AValue: TValue;
  310. begin
  311. LContext := TRttiContext.Create;
  312. LType := LContext.GetType(TGetClassProperties);
  313. AGetClassProperties := TGetClassProperties.Create;
  314. try
  315. AGetClassProperties.PubPropRW:=12345;
  316. AValue := LType.GetProperty('PubPropRW').GetValue(AGetClassProperties);
  317. CheckEquals(12345, AValue.AsInteger);
  318. finally
  319. AGetClassProperties.Free;
  320. end;
  321. LContext.Free;
  322. end;
  323. initialization
  324. {$ifdef fpc}
  325. RegisterTest(TTestCase1);
  326. {$else fpc}
  327. RegisterTest(TTestCase1.Suite);
  328. {$endif fpc}
  329. end.