utcjsontypes.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. unit utcjsontypes;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpcunit, testutils, testregistry,
  6. System.JSON.Types, Generics.Collections, Math;
  7. type
  8. { TTestJsonLineInfo }
  9. TTestJsonLineInfo = class(TTestCase)
  10. private
  11. FLineInfo: TJsonLineInfo;
  12. protected
  13. procedure SetUp; override;
  14. procedure TearDown; override;
  15. published
  16. procedure TestGetLineNumber;
  17. procedure TestGetLinePosition;
  18. procedure TestHasLineInfo;
  19. procedure TestLineNumberProperty;
  20. procedure TestLinePositionProperty;
  21. end;
  22. { TTestJsonPosition }
  23. TTestJsonPosition = class(TTestCase)
  24. private
  25. FPosition: TJsonPosition;
  26. published
  27. procedure TestCreateDefault;
  28. procedure TestCreateWithType;
  29. procedure TestClear;
  30. procedure TestWriteToObject;
  31. procedure TestWriteToArray;
  32. procedure TestWriteToConstructor;
  33. procedure TestBuildPathEmpty;
  34. procedure TestBuildPathSingle;
  35. procedure TestBuildPathMultiple;
  36. procedure TestFormatMessage;
  37. end;
  38. { TTestJsonFiler }
  39. TTestJsonFiler = class(TTestCase)
  40. private
  41. type
  42. TTestJsonFilerImpl = class(TJsonFiler)
  43. protected
  44. function GetInsideContainer: Boolean; override;
  45. end;
  46. var
  47. FFiler: TTestJsonFilerImpl;
  48. protected
  49. procedure SetUp; override;
  50. procedure TearDown; override;
  51. published
  52. procedure TestCreateDestroy;
  53. procedure TestPushPop;
  54. procedure TestPeek;
  55. procedure TestGetPath;
  56. procedure TestRewind;
  57. procedure TestIsEndToken;
  58. procedure TestIsStartToken;
  59. procedure TestIsPrimitiveToken;
  60. end;
  61. { TTestJsonOid }
  62. TTestJsonOid = class(TTestCase)
  63. private
  64. FOid: TJsonOid;
  65. published
  66. procedure TestCreateFromBytes;
  67. procedure TestCreateFromString;
  68. procedure TestAsString;
  69. procedure TestAsBytes;
  70. procedure TestStringRoundTrip;
  71. procedure TestBytesRoundTrip;
  72. procedure TestInvalidStringLength;
  73. end;
  74. { TTestJsonRegEx }
  75. TTestJsonRegEx = class(TTestCase)
  76. private
  77. FRegEx: TJsonRegEx;
  78. published
  79. procedure TestCreate;
  80. procedure TestAsString;
  81. procedure TestSetAsString;
  82. procedure TestSetAsStringVariations;
  83. end;
  84. { TTestJsonDBRef }
  85. TTestJsonDBRef = class(TTestCase)
  86. private
  87. FDBRef: TJsonDBRef;
  88. published
  89. procedure TestCreateWithDB;
  90. procedure TestCreateWithoutDB;
  91. procedure TestCreateWithOid;
  92. procedure TestAsString;
  93. procedure TestSetAsString;
  94. end;
  95. { TTestJsonCodeWScope }
  96. TTestJsonCodeWScope = class(TTestCase)
  97. private
  98. FCodeWScope: TJsonCodeWScope;
  99. published
  100. procedure TestCreateEmpty;
  101. procedure TestCreateWithScope;
  102. end;
  103. { TTestJsonDecimal128 }
  104. TTestJsonDecimal128 = class(TTestCase)
  105. private
  106. FDecimal: TJsonDecimal128;
  107. published
  108. procedure TestCreateFromString;
  109. procedure TestCreateFromExtended;
  110. procedure TestIsZero;
  111. procedure TestIsNan;
  112. procedure TestIsPosInfinity;
  113. procedure TestIsNegInfinity;
  114. procedure TestAsExtended;
  115. procedure TestAsString;
  116. end;
  117. { TTestJsonNameAttribute }
  118. TTestJsonNameAttribute = class(TTestCase)
  119. private
  120. FAttribute: JsonNameAttribute;
  121. protected
  122. procedure TearDown; override;
  123. published
  124. procedure TestCreate;
  125. procedure TestValue;
  126. end;
  127. { TTestEJsonException }
  128. TTestEJsonException = class(TTestCase)
  129. published
  130. procedure TestCreateSimple;
  131. procedure TestCreateWithInner;
  132. procedure TestInnerException;
  133. end;
  134. implementation
  135. { TTestJsonLineInfo }
  136. procedure TTestJsonLineInfo.SetUp;
  137. begin
  138. inherited SetUp;
  139. FLineInfo := TJsonLineInfo.Create;
  140. end;
  141. procedure TTestJsonLineInfo.TearDown;
  142. begin
  143. FLineInfo.Free;
  144. inherited TearDown;
  145. end;
  146. procedure TTestJsonLineInfo.TestGetLineNumber;
  147. begin
  148. AssertEquals('Default line number', 0, FLineInfo.GetLineNumber);
  149. end;
  150. procedure TTestJsonLineInfo.TestGetLinePosition;
  151. begin
  152. AssertEquals('Default line position', 0, FLineInfo.GetLinePosition);
  153. end;
  154. procedure TTestJsonLineInfo.TestHasLineInfo;
  155. begin
  156. AssertFalse('Default has no line info', FLineInfo.HasLineInfo);
  157. end;
  158. procedure TTestJsonLineInfo.TestLineNumberProperty;
  159. begin
  160. AssertEquals('Line number property', 0, FLineInfo.LineNumber);
  161. end;
  162. procedure TTestJsonLineInfo.TestLinePositionProperty;
  163. begin
  164. AssertEquals('Line position property', 0, FLineInfo.LinePosition);
  165. end;
  166. { TTestJsonPosition }
  167. procedure TTestJsonPosition.TestCreateDefault;
  168. begin
  169. FPosition := TJsonPosition.Create;
  170. AssertEquals('Default container type', Ord(TJsonContainerType.None), Ord(FPosition.ContainerType));
  171. AssertEquals('Default position', -1, FPosition.Position);
  172. AssertEquals('Default property name', '', FPosition.PropertyName);
  173. AssertFalse('Default has no index', FPosition.HasIndex);
  174. end;
  175. procedure TTestJsonPosition.TestCreateWithType;
  176. begin
  177. FPosition := TJsonPosition.Create(TJsonContainerType.&Array);
  178. AssertEquals('Array container type', Ord(TJsonContainerType.&Array), Ord(FPosition.ContainerType));
  179. AssertTrue('Array has index', FPosition.HasIndex);
  180. AssertEquals('Array position', -1, FPosition.Position);
  181. end;
  182. procedure TTestJsonPosition.TestClear;
  183. begin
  184. FPosition.ContainerType := TJsonContainerType.&Object;
  185. FPosition.Position := 5;
  186. FPosition.PropertyName := 'test';
  187. FPosition.Clear;
  188. AssertEquals('Cleared container type', Ord(TJsonContainerType.None), Ord(FPosition.ContainerType));
  189. AssertEquals('Cleared position', -1, FPosition.Position);
  190. AssertEquals('Cleared property name', '', FPosition.PropertyName);
  191. end;
  192. procedure TTestJsonPosition.TestWriteToObject;
  193. var
  194. Sb: TStringBuilder;
  195. begin
  196. Sb := TStringBuilder.Create;
  197. try
  198. FPosition := TJsonPosition.Create(TJsonContainerType.&Object);
  199. FPosition.PropertyName := 'test';
  200. FPosition.WriteTo(Sb);
  201. AssertEquals('Object path', 'test', Sb.ToString);
  202. Sb.Clear;
  203. Sb.Append('root');
  204. FPosition.WriteTo(Sb);
  205. AssertEquals('Object path with prefix', 'root.test', Sb.ToString);
  206. finally
  207. Sb.Free;
  208. end;
  209. end;
  210. procedure TTestJsonPosition.TestWriteToArray;
  211. var
  212. Sb: TStringBuilder;
  213. begin
  214. Sb := TStringBuilder.Create;
  215. try
  216. FPosition := TJsonPosition.Create(TJsonContainerType.&Array);
  217. FPosition.Position := 5;
  218. FPosition.WriteTo(Sb);
  219. AssertEquals('Array path', '[5]', Sb.ToString);
  220. finally
  221. Sb.Free;
  222. end;
  223. end;
  224. procedure TTestJsonPosition.TestWriteToConstructor;
  225. var
  226. Sb: TStringBuilder;
  227. begin
  228. Sb := TStringBuilder.Create;
  229. try
  230. FPosition := TJsonPosition.Create(TJsonContainerType.&Constructor);
  231. FPosition.Position := 3;
  232. FPosition.WriteTo(Sb);
  233. AssertEquals('Constructor path', '[3]', Sb.ToString);
  234. finally
  235. Sb.Free;
  236. end;
  237. end;
  238. procedure TTestJsonPosition.TestBuildPathEmpty;
  239. var
  240. Positions: TJsonPositionList;
  241. Path: string;
  242. begin
  243. Positions := TJsonPositionList.Create;
  244. try
  245. Path := TJsonPosition.BuildPath(Positions);
  246. AssertEquals('Empty path', '', Path);
  247. finally
  248. Positions.Free;
  249. end;
  250. end;
  251. procedure TTestJsonPosition.TestBuildPathSingle;
  252. var
  253. Positions: TJsonPositionList;
  254. Pos: TJsonPosition;
  255. Path: string;
  256. begin
  257. Positions := TJsonPositionList.Create;
  258. try
  259. Pos := TJsonPosition.Create(TJsonContainerType.&Object);
  260. Pos.PropertyName := 'test';
  261. Positions.Add(Pos);
  262. Path := TJsonPosition.BuildPath(Positions);
  263. AssertEquals('Single object path', 'test', Path);
  264. finally
  265. Positions.Free;
  266. end;
  267. end;
  268. procedure TTestJsonPosition.TestBuildPathMultiple;
  269. var
  270. Positions: TJsonPositionList;
  271. Pos1, Pos2: TJsonPosition;
  272. Path: string;
  273. begin
  274. Positions := TJsonPositionList.Create;
  275. try
  276. Pos1 := TJsonPosition.Create(TJsonContainerType.&Object);
  277. Pos1.PropertyName := 'root';
  278. Positions.Add(Pos1);
  279. Pos2 := TJsonPosition.Create(TJsonContainerType.&Array);
  280. Pos2.Position := 0;
  281. Positions.Add(Pos2);
  282. Path := TJsonPosition.BuildPath(Positions);
  283. AssertEquals('Multiple path', 'root[0]', Path);
  284. finally
  285. Positions.Free;
  286. end;
  287. end;
  288. procedure TTestJsonPosition.TestFormatMessage;
  289. var
  290. LineInfo: TJsonLineInfo;
  291. Msg: string;
  292. begin
  293. LineInfo := TJsonLineInfo.Create;
  294. try
  295. Msg := TJsonPosition.FormatMessage(LineInfo, 'test.path', 'Error occurred');
  296. AssertTrue('Message contains error', Pos('Error occurred', Msg) > 0);
  297. AssertTrue('Message contains path', Pos('test.path', Msg) > 0);
  298. finally
  299. LineInfo.Free;
  300. end;
  301. end;
  302. { TTestJsonFiler.TTestJsonFilerImpl }
  303. function TTestJsonFiler.TTestJsonFilerImpl.GetInsideContainer: Boolean;
  304. begin
  305. Result := FCurrentPosition.ContainerType <> TJsonContainerType.None;
  306. end;
  307. { TTestJsonFiler }
  308. procedure TTestJsonFiler.SetUp;
  309. begin
  310. inherited SetUp;
  311. FFiler := TTestJsonFilerImpl.Create;
  312. end;
  313. procedure TTestJsonFiler.TearDown;
  314. begin
  315. FFiler.Free;
  316. inherited TearDown;
  317. end;
  318. procedure TTestJsonFiler.TestCreateDestroy;
  319. begin
  320. AssertNotNull('Filer created', FFiler);
  321. AssertEquals('Empty path', '', FFiler.Path);
  322. end;
  323. procedure TTestJsonFiler.TestPushPop;
  324. begin
  325. AssertEquals('Initial peek', Ord(TJsonContainerType.None), Ord(FFiler.Peek));
  326. FFiler.Push(TJsonContainerType.&Object);
  327. AssertEquals('After push object', Ord(TJsonContainerType.&Object), Ord(FFiler.Peek));
  328. FFiler.Push(TJsonContainerType.&Array);
  329. AssertEquals('After push array', Ord(TJsonContainerType.&Array), Ord(FFiler.Peek));
  330. AssertEquals('Pop array', Ord(TJsonContainerType.&Array), Ord(FFiler.Pop));
  331. AssertEquals('After pop array', Ord(TJsonContainerType.&Object), Ord(FFiler.Peek));
  332. AssertEquals('Pop object', Ord(TJsonContainerType.&Object), Ord(FFiler.Pop));
  333. AssertEquals('After pop object', Ord(TJsonContainerType.None), Ord(FFiler.Peek));
  334. end;
  335. procedure TTestJsonFiler.TestPeek;
  336. begin
  337. AssertEquals('Initial peek', Ord(TJsonContainerType.None), Ord(FFiler.Peek));
  338. FFiler.Push(TJsonContainerType.&Object);
  339. AssertEquals('Peek object', Ord(TJsonContainerType.&Object), Ord(FFiler.Peek));
  340. AssertEquals('Peek again', Ord(TJsonContainerType.&Object), Ord(FFiler.Peek));
  341. end;
  342. procedure TTestJsonFiler.TestGetPath;
  343. begin
  344. AssertEquals('Empty path', '', FFiler.Path);
  345. FFiler.Push(TJsonContainerType.&Object);
  346. // Path building requires the position to be set up properly
  347. // Since we haven't set any property names, the path should still be empty
  348. AssertEquals('Path after push without properties', '', FFiler.Path);
  349. end;
  350. procedure TTestJsonFiler.TestRewind;
  351. begin
  352. FFiler.Push(TJsonContainerType.&Object);
  353. FFiler.Push(TJsonContainerType.&Array);
  354. FFiler.Rewind;
  355. AssertEquals('After rewind', Ord(TJsonContainerType.None), Ord(FFiler.Peek));
  356. end;
  357. procedure TTestJsonFiler.TestIsEndToken;
  358. begin
  359. AssertTrue('EndObject is end', TJsonFiler.IsEndToken(TJsonToken.EndObject));
  360. AssertTrue('EndArray is end', TJsonFiler.IsEndToken(TJsonToken.EndArray));
  361. AssertTrue('EndConstructor is end', TJsonFiler.IsEndToken(TJsonToken.EndConstructor));
  362. AssertFalse('StartObject is not end', TJsonFiler.IsEndToken(TJsonToken.StartObject));
  363. AssertFalse('String is not end', TJsonFiler.IsEndToken(TJsonToken.&String));
  364. end;
  365. procedure TTestJsonFiler.TestIsStartToken;
  366. begin
  367. AssertTrue('StartObject is start', TJsonFiler.IsStartToken(TJsonToken.StartObject));
  368. AssertTrue('StartArray is start', TJsonFiler.IsStartToken(TJsonToken.StartArray));
  369. AssertTrue('StartConstructor is start', TJsonFiler.IsStartToken(TJsonToken.StartConstructor));
  370. AssertFalse('EndObject is not start', TJsonFiler.IsStartToken(TJsonToken.EndObject));
  371. AssertFalse('String is not start', TJsonFiler.IsStartToken(TJsonToken.&String));
  372. end;
  373. procedure TTestJsonFiler.TestIsPrimitiveToken;
  374. begin
  375. AssertTrue('Integer is primitive', TJsonFiler.IsPrimitiveToken(TJsonToken.Integer));
  376. AssertTrue('Float is primitive', TJsonFiler.IsPrimitiveToken(TJsonToken.Float));
  377. AssertTrue('String is primitive', TJsonFiler.IsPrimitiveToken(TJsonToken.&String));
  378. AssertTrue('Boolean is primitive', TJsonFiler.IsPrimitiveToken(TJsonToken.Boolean));
  379. AssertTrue('Null is primitive', TJsonFiler.IsPrimitiveToken(TJsonToken.Null));
  380. AssertFalse('StartObject is not primitive', TJsonFiler.IsPrimitiveToken(TJsonToken.StartObject));
  381. AssertFalse('EndObject is not primitive', TJsonFiler.IsPrimitiveToken(TJsonToken.EndObject));
  382. end;
  383. { TTestJsonOid }
  384. procedure TTestJsonOid.TestCreateFromBytes;
  385. var
  386. TestBytes: TBytes;
  387. begin
  388. SetLength(TestBytes, 12);
  389. TestBytes[0] := $01;
  390. TestBytes[1] := $02;
  391. TestBytes[11] := $0C;
  392. FOid := TJsonOid.Create(TestBytes);
  393. AssertEquals('First byte', $01, FOid.Bytes[0]);
  394. AssertEquals('Second byte', $02, FOid.Bytes[1]);
  395. AssertEquals('Last byte', $0C, FOid.Bytes[11]);
  396. end;
  397. procedure TTestJsonOid.TestCreateFromString;
  398. begin
  399. FOid := TJsonOid.Create('0102030405060708090a0b0c');
  400. AssertEquals('First byte from string', $01, FOid.Bytes[0]);
  401. AssertEquals('Second byte from string', $02, FOid.Bytes[1]);
  402. AssertEquals('Last byte from string', $0C, FOid.Bytes[11]);
  403. end;
  404. procedure TTestJsonOid.TestAsString;
  405. var
  406. TestBytes: TBytes;
  407. begin
  408. SetLength(TestBytes, 12);
  409. TestBytes[0] := $01;
  410. TestBytes[1] := $02;
  411. TestBytes[11] := $0C;
  412. FOid := TJsonOid.Create(TestBytes);
  413. AssertEquals('String representation', '01020000000000000000000C', FOid.AsString.ToUpper);
  414. end;
  415. procedure TTestJsonOid.TestAsBytes;
  416. var
  417. TestBytes, ResultBytes: TBytes;
  418. begin
  419. SetLength(TestBytes, 12);
  420. TestBytes[0] := $AB;
  421. TestBytes[11] := $CD;
  422. FOid := TJsonOid.Create(TestBytes);
  423. ResultBytes := FOid.AsBytes;
  424. AssertEquals('Byte array length', 12, Length(ResultBytes));
  425. AssertEquals('First byte', $AB, ResultBytes[0]);
  426. AssertEquals('Last byte', $CD, ResultBytes[11]);
  427. end;
  428. procedure TTestJsonOid.TestStringRoundTrip;
  429. const
  430. TestString = '0123456789abcdef01234567';
  431. begin
  432. FOid := TJsonOid.Create(TestString);
  433. AssertEquals('String round trip', TestString.ToUpper, FOid.AsString.ToUpper);
  434. end;
  435. procedure TTestJsonOid.TestBytesRoundTrip;
  436. var
  437. TestBytes, ResultBytes: TBytes;
  438. begin
  439. SetLength(TestBytes, 12);
  440. TestBytes[0] := $12;
  441. TestBytes[5] := $34;
  442. TestBytes[11] := $56;
  443. FOid := TJsonOid.Create(TestBytes);
  444. ResultBytes := FOid.AsBytes;
  445. AssertEquals('Bytes round trip length', Length(TestBytes), Length(ResultBytes));
  446. AssertEquals('Bytes round trip first', TestBytes[0], ResultBytes[0]);
  447. AssertEquals('Bytes round trip middle', TestBytes[5], ResultBytes[5]);
  448. AssertEquals('Bytes round trip last', TestBytes[11], ResultBytes[11]);
  449. end;
  450. procedure TTestJsonOid.TestInvalidStringLength;
  451. begin
  452. try
  453. FOid := TJsonOid.Create('invalid');
  454. Fail('Should have raised exception for invalid string length');
  455. except
  456. on E: Exception do
  457. AssertTrue('Correct exception type', E is EJsonException);
  458. end;
  459. end;
  460. { TTestJsonRegEx }
  461. procedure TTestJsonRegEx.TestCreate;
  462. begin
  463. FRegEx := TJsonRegEx.Create('test.*', 'gi');
  464. AssertEquals('RegEx pattern', 'test.*', FRegEx.RegEx);
  465. AssertEquals('RegEx options', 'gi', FRegEx.Options);
  466. end;
  467. procedure TTestJsonRegEx.TestAsString;
  468. begin
  469. FRegEx := TJsonRegEx.Create('test.*', 'gi');
  470. AssertEquals('AsString format', '/test.*/gi', FRegEx.AsString);
  471. end;
  472. procedure TTestJsonRegEx.TestSetAsString;
  473. begin
  474. FRegEx.AsString := '/test.*/gi';
  475. AssertEquals('Set regex pattern', 'test.*', FRegEx.RegEx);
  476. AssertEquals('Set regex options', 'gi', FRegEx.Options);
  477. end;
  478. procedure TTestJsonRegEx.TestSetAsStringVariations;
  479. begin
  480. // Test single part
  481. FRegEx.AsString := 'simple';
  482. AssertEquals('Simple regex', 'simple', FRegEx.RegEx);
  483. AssertEquals('Simple options', '', FRegEx.Options);
  484. // Test two parts
  485. FRegEx.AsString := '/pattern';
  486. AssertEquals('Two part regex', 'pattern', FRegEx.RegEx);
  487. AssertEquals('Two part options', '', FRegEx.Options);
  488. // Test three parts (normal case)
  489. FRegEx.AsString := '/pattern/flags';
  490. AssertEquals('Three part regex', 'pattern', FRegEx.RegEx);
  491. AssertEquals('Three part options', 'flags', FRegEx.Options);
  492. end;
  493. { TTestJsonDBRef }
  494. procedure TTestJsonDBRef.TestCreateWithDB;
  495. begin
  496. FDBRef := TJsonDBRef.Create('testdb', 'testcoll', '507f1f77bcf86cd799439011');
  497. AssertEquals('DB name', 'testdb', FDBRef.DB);
  498. AssertEquals('Collection name', 'testcoll', FDBRef.Ref);
  499. AssertEquals('ID string', '507F1F77BCF86CD799439011', FDBRef.Id.AsString.ToUpper);
  500. end;
  501. procedure TTestJsonDBRef.TestCreateWithoutDB;
  502. begin
  503. FDBRef := TJsonDBRef.Create('testcoll', '507f1f77bcf86cd799439011');
  504. AssertEquals('Empty DB name', '', FDBRef.DB);
  505. AssertEquals('Collection name', 'testcoll', FDBRef.Ref);
  506. AssertEquals('ID string', '507F1F77BCF86CD799439011', FDBRef.Id.AsString.ToUpper);
  507. end;
  508. procedure TTestJsonDBRef.TestCreateWithOid;
  509. var
  510. TestOid: TJsonOid;
  511. begin
  512. TestOid := TJsonOid.Create('507f1f77bcf86cd799439011');
  513. FDBRef := TJsonDBRef.Create('testdb', 'testcoll', TestOid);
  514. AssertEquals('DB name with OID', 'testdb', FDBRef.DB);
  515. AssertEquals('Collection name with OID', 'testcoll', FDBRef.Ref);
  516. AssertEquals('ID from OID', TestOid.AsString.ToUpper, FDBRef.Id.AsString.ToUpper);
  517. end;
  518. procedure TTestJsonDBRef.TestAsString;
  519. begin
  520. FDBRef := TJsonDBRef.Create('testdb', 'testcoll', '507f1f77bcf86cd799439011');
  521. AssertEquals('Full string format', 'TESTDB.TESTCOLL.507F1F77BCF86CD799439011', FDBRef.AsString.ToUpper);
  522. FDBRef := TJsonDBRef.Create('testcoll', '507f1f77bcf86cd799439011');
  523. AssertEquals('No DB string format', 'TESTCOLL.507F1F77BCF86CD799439011', FDBRef.AsString.ToUpper);
  524. end;
  525. procedure TTestJsonDBRef.TestSetAsString;
  526. begin
  527. FDBRef.AsString := 'testdb.testcoll.507f1f77bcf86cd799439011';
  528. AssertEquals('Set DB from string', 'testdb', FDBRef.DB);
  529. AssertEquals('Set collection from string', 'testcoll', FDBRef.Ref);
  530. FDBRef.AsString := 'testcoll.507f1f77bcf86cd799439011';
  531. AssertEquals('Set empty DB from string', '', FDBRef.DB);
  532. AssertEquals('Set collection from short string', 'testcoll', FDBRef.Ref);
  533. end;
  534. { TTestJsonCodeWScope }
  535. procedure TTestJsonCodeWScope.TestCreateEmpty;
  536. begin
  537. FCodeWScope := TJsonCodeWScope.Create('function() { return 1; }', nil);
  538. AssertEquals('Code value', 'function() { return 1; }', FCodeWScope.Code);
  539. AssertEquals('Empty scope length', 0, Length(FCodeWScope.Scope));
  540. end;
  541. procedure TTestJsonCodeWScope.TestCreateWithScope;
  542. var
  543. Scope: TStringList;
  544. begin
  545. Scope := TStringList.Create;
  546. try
  547. Scope.Add('var1=value1');
  548. Scope.Add('var2=value2');
  549. FCodeWScope := TJsonCodeWScope.Create('function() { return var1 + var2; }', Scope);
  550. AssertEquals('Code with scope', 'function() { return var1 + var2; }', FCodeWScope.Code);
  551. AssertEquals('Scope length', 2, Length(FCodeWScope.Scope));
  552. AssertEquals('First scope ident', 'var1', FCodeWScope.Scope[0].Ident);
  553. AssertEquals('First scope value', 'value1', FCodeWScope.Scope[0].Value);
  554. AssertEquals('Second scope ident', 'var2', FCodeWScope.Scope[1].Ident);
  555. AssertEquals('Second scope value', 'value2', FCodeWScope.Scope[1].Value);
  556. finally
  557. Scope.Free;
  558. end;
  559. end;
  560. { TTestJsonDecimal128 }
  561. procedure TTestJsonDecimal128.TestCreateFromString;
  562. begin
  563. // Basic test - actual implementation depends on assigned conversion functions
  564. try
  565. FDecimal := TJsonDecimal128.Create('123.45');
  566. // If we get here, creation succeeded
  567. AssertTrue('Created from string', True);
  568. except
  569. on EJsonException do
  570. // Expected if conversion functions not implemented
  571. AssertTrue('Expected exception for unimplemented decimal', True);
  572. end;
  573. end;
  574. procedure TTestJsonDecimal128.TestCreateFromExtended;
  575. begin
  576. try
  577. FDecimal := TJsonDecimal128.Create(123.45);
  578. AssertTrue('Created from extended', True);
  579. except
  580. on EJsonException do
  581. AssertTrue('Expected exception for unimplemented decimal', True);
  582. end;
  583. end;
  584. procedure TTestJsonDecimal128.TestIsZero;
  585. begin
  586. FDecimal.lo := 0;
  587. FDecimal.hi := $3040000000000000;
  588. AssertTrue('Is zero', FDecimal.IsZero);
  589. FDecimal.lo := 1;
  590. AssertFalse('Not zero with lo=1', FDecimal.IsZero);
  591. end;
  592. procedure TTestJsonDecimal128.TestIsNan;
  593. begin
  594. FDecimal.lo := 0;
  595. FDecimal.hi := $7C00000000000000;
  596. AssertTrue('Is NaN', FDecimal.IsNan);
  597. FDecimal.hi := $7C00000000000001;
  598. AssertFalse('Not NaN with different hi', FDecimal.IsNan);
  599. end;
  600. procedure TTestJsonDecimal128.TestIsPosInfinity;
  601. begin
  602. FDecimal.lo := 0;
  603. FDecimal.hi := $7800000000000000;
  604. AssertTrue('Is positive infinity', FDecimal.IsPosInfinity);
  605. FDecimal.hi := $7800000000000001;
  606. AssertFalse('Not positive infinity with different hi', FDecimal.IsPosInfinity);
  607. end;
  608. procedure TTestJsonDecimal128.TestIsNegInfinity;
  609. begin
  610. FDecimal.lo := 0;
  611. FDecimal.hi := QWord($F800000000000000);
  612. AssertTrue('Is negative infinity', FDecimal.IsNegInfinity);
  613. FDecimal.hi := $7800000000000001;
  614. AssertFalse('Not negative infinity with different hi', FDecimal.IsNegInfinity);
  615. end;
  616. procedure TTestJsonDecimal128.TestAsExtended;
  617. var
  618. Result: Extended;
  619. begin
  620. // Test zero
  621. FDecimal.lo := 0;
  622. FDecimal.hi := $3040000000000000;
  623. Result := FDecimal.AsExtended;
  624. AssertEquals('Zero as extended', 0.0, Result, 0.0001);
  625. // Test NaN
  626. FDecimal.lo := 0;
  627. FDecimal.hi := $7C00000000000000;
  628. Result := FDecimal.AsExtended;
  629. AssertTrue('NaN as extended', IsNaN(Result));
  630. end;
  631. procedure TTestJsonDecimal128.TestAsString;
  632. begin
  633. try
  634. FDecimal.lo := 0;
  635. FDecimal.hi := $3040000000000000;
  636. // This will likely fail unless conversion functions are set up
  637. FDecimal.AsString;
  638. AssertTrue('String conversion succeeded', True);
  639. except
  640. on EJsonException do
  641. AssertTrue('Expected exception for unimplemented string conversion', True);
  642. end;
  643. end;
  644. { TTestJsonNameAttribute }
  645. procedure TTestJsonNameAttribute.TearDown;
  646. begin
  647. FAttribute.Free;
  648. inherited TearDown;
  649. end;
  650. procedure TTestJsonNameAttribute.TestCreate;
  651. begin
  652. FAttribute := JsonNameAttribute.Create('testName');
  653. AssertNotNull('Attribute created', FAttribute);
  654. end;
  655. procedure TTestJsonNameAttribute.TestValue;
  656. begin
  657. FAttribute := JsonNameAttribute.Create('testName');
  658. AssertEquals('Attribute value', 'testName', FAttribute.Value);
  659. end;
  660. { TTestEJsonException }
  661. procedure TTestEJsonException.TestCreateSimple;
  662. var
  663. Ex: EJsonException;
  664. begin
  665. Ex := EJsonException.Create('Test message');
  666. try
  667. AssertEquals('Simple message', 'Test message', Ex.Message);
  668. AssertNull('No inner exception', Ex.InnerException);
  669. finally
  670. Ex.Free;
  671. end;
  672. end;
  673. procedure TTestEJsonException.TestCreateWithInner;
  674. var
  675. Inner: Exception;
  676. Ex: EJsonException;
  677. begin
  678. Inner := Exception.Create('Inner message');
  679. try
  680. Ex := EJsonException.Create('Outer message', Inner);
  681. try
  682. AssertEquals('Outer message', 'Outer message', Ex.Message);
  683. AssertNotNull('Has inner exception', Ex.InnerException);
  684. AssertSame('Same inner exception', Inner, Ex.InnerException);
  685. finally
  686. Ex.Free;
  687. end;
  688. finally
  689. Inner.Free;
  690. end;
  691. end;
  692. procedure TTestEJsonException.TestInnerException;
  693. var
  694. Inner: Exception;
  695. Ex: EJsonException;
  696. begin
  697. Inner := Exception.Create('Inner message');
  698. try
  699. Ex := EJsonException.Create('Outer message', Inner);
  700. try
  701. AssertEquals('Inner exception message', 'Inner message', Ex.InnerException.Message);
  702. finally
  703. Ex.Free;
  704. end;
  705. finally
  706. Inner.Free;
  707. end;
  708. end;
  709. initialization
  710. RegisterTests([
  711. TTestJsonLineInfo,
  712. TTestJsonPosition,
  713. TTestJsonFiler,
  714. TTestJsonOid,
  715. TTestJsonRegEx,
  716. TTestJsonDBRef,
  717. TTestJsonCodeWScope,
  718. TTestJsonDecimal128,
  719. TTestJsonNameAttribute,
  720. TTestEJsonException
  721. ]);
  722. end.