utcjsonbuilders.pas 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652
  1. unit utcjsonbuilders;
  2. {$mode objfpc}
  3. {$h+}
  4. interface
  5. uses
  6. Classes, SysUtils, fpcunit, testregistry, System.JSON, System.JSON.Writers,
  7. System.JSON.Readers, System.JSON.Types, System.JSON.Builders, StreamEx,
  8. Rtti, Variants, TypInfo;
  9. type
  10. TJSONBuildersBasicTest = class(TTestCase)
  11. published
  12. procedure TestExceptionTypes;
  13. procedure TestArrayBuilderBasic;
  14. procedure TestObjectBuilderBasic;
  15. procedure TestVariantSupport;
  16. procedure TestVarRecSupport;
  17. procedure TestNestedStructures;
  18. procedure TestComplexNestingIntegration;
  19. procedure TestLargeDataSets;
  20. procedure TestErrorConditions;
  21. // TElements.Add overloads (array builder)
  22. procedure TestArrayAddString;
  23. procedure TestArrayAddInt32;
  24. procedure TestArrayAddUInt32;
  25. procedure TestArrayAddInt64;
  26. procedure TestArrayAddUInt64;
  27. procedure TestArrayAddSingle;
  28. procedure TestArrayAddDouble;
  29. procedure TestArrayAddExtended;
  30. procedure TestArrayAddBoolean;
  31. procedure TestArrayAddChar;
  32. procedure TestArrayAddByte;
  33. procedure TestArrayAddDateTime;
  34. procedure TestArrayAddGUID;
  35. procedure TestArrayAddBytes;
  36. procedure TestArrayAddJsonOid;
  37. procedure TestArrayAddJsonRegEx;
  38. procedure TestArrayAddJsonDBRef;
  39. procedure TestArrayAddJsonCodeWScope;
  40. procedure TestArrayAddJsonDecimal128;
  41. procedure TestArrayAddTValue;
  42. procedure TestArrayAddTVarRec;
  43. procedure TestArrayAddVariant;
  44. // TPairs.Add overloads (object builder)
  45. procedure TestObjectAddString;
  46. procedure TestObjectAddInt32;
  47. procedure TestObjectAddUInt32;
  48. procedure TestObjectAddInt64;
  49. procedure TestObjectAddUInt64;
  50. procedure TestObjectAddSingle;
  51. procedure TestObjectAddDouble;
  52. procedure TestObjectAddExtended;
  53. procedure TestObjectAddBoolean;
  54. procedure TestObjectAddChar;
  55. procedure TestObjectAddByte;
  56. procedure TestObjectAddDateTime;
  57. procedure TestObjectAddGUID;
  58. procedure TestObjectAddBytes;
  59. procedure TestObjectAddJsonOid;
  60. procedure TestObjectAddJsonRegEx;
  61. procedure TestObjectAddJsonDBRef;
  62. procedure TestObjectAddJsonCodeWScope;
  63. procedure TestObjectAddJsonDecimal128;
  64. procedure TestObjectAddTValue;
  65. procedure TestObjectAddTVarRec;
  66. procedure TestObjectAddVariant;
  67. end;
  68. implementation
  69. { TJSONBuildersBasicTest }
  70. procedure TJSONBuildersBasicTest.TestExceptionTypes;
  71. var
  72. E1: EJSONCollectionBuilderError;
  73. E2: EJSONIteratorError;
  74. begin
  75. E1 := EJSONCollectionBuilderError.Create('Test message 1');
  76. try
  77. CheckTrue(E1 is Exception, 'EJSONCollectionBuilderError should inherit from Exception');
  78. CheckEquals('Test message 1', E1.Message, 'Exception message should be preserved');
  79. finally
  80. E1.Free;
  81. end;
  82. E2 := EJSONIteratorError.Create('Test message 2');
  83. try
  84. CheckTrue(E2 is Exception, 'EJSONIteratorError should inherit from Exception');
  85. CheckEquals('Test message 2', E2.Message, 'Exception message should be preserved');
  86. finally
  87. E2.Free;
  88. end;
  89. end;
  90. procedure TJSONBuildersBasicTest.TestArrayBuilderBasic;
  91. var
  92. Writer: TJSONWriter;
  93. StringWriter: TTextWriter;
  94. Builder: TJSONArrayBuilder;
  95. begin
  96. StringWriter := TStringWriter.Create;
  97. try
  98. Writer := TJsonTextWriter.Create(StringWriter);
  99. try
  100. Builder := TJSONArrayBuilder.Create(Writer);
  101. try
  102. Builder.BeginArray.Add(1).Add('test').Add(true).EndAll;
  103. Writer.Flush;
  104. CheckEquals('[1,"test",true]', StringWriter.ToString, 'Array should contain the added elements');
  105. finally
  106. Builder.Free;
  107. end;
  108. finally
  109. Writer.Free;
  110. end;
  111. finally
  112. StringWriter.Free;
  113. end;
  114. end;
  115. procedure TJSONBuildersBasicTest.TestObjectBuilderBasic;
  116. var
  117. Writer: TJSONWriter;
  118. StringWriter: TTextWriter;
  119. Builder: TJSONObjectBuilder;
  120. begin
  121. StringWriter := TStringWriter.Create;
  122. try
  123. Writer := TJsonTextWriter.Create(StringWriter);
  124. try
  125. Builder := TJSONObjectBuilder.Create(Writer);
  126. try
  127. Builder.BeginObject.Add('name', 'John').Add('age', 30).Add('active', true).EndAll;
  128. Writer.Flush;
  129. CheckEquals('{"name":"John","age":30,"active":true}', StringWriter.ToString, 'Object should contain the added properties');
  130. finally
  131. Builder.Free;
  132. end;
  133. finally
  134. Writer.Free;
  135. end;
  136. finally
  137. StringWriter.Free;
  138. end;
  139. end;
  140. procedure TJSONBuildersBasicTest.TestVariantSupport;
  141. var
  142. Writer: TJSONWriter;
  143. StringWriter: TTextWriter;
  144. Builder: TJSONArrayBuilder;
  145. V: Variant;
  146. begin
  147. StringWriter := TStringWriter.Create;
  148. try
  149. Writer := TJsonTextWriter.Create(StringWriter);
  150. try
  151. Builder := TJSONArrayBuilder.Create(Writer);
  152. try
  153. V := 42;
  154. Builder.BeginArray.Add(V);
  155. V := 'test';
  156. Builder.ParentArray.Add(V);
  157. V := True;
  158. Builder.ParentArray.Add(V);
  159. V := Null;
  160. Builder.ParentArray.Add(V).EndAll;
  161. Writer.Flush;
  162. CheckEquals('[42,"test",true,null]', StringWriter.ToString, 'Array should handle variants correctly');
  163. finally
  164. Builder.Free;
  165. end;
  166. finally
  167. Writer.Free;
  168. end;
  169. finally
  170. StringWriter.Free;
  171. end;
  172. end;
  173. procedure TJSONBuildersBasicTest.TestVarRecSupport;
  174. var
  175. Writer: TJSONWriter;
  176. StringWriter: TTextWriter;
  177. Builder: TJSONArrayBuilder;
  178. begin
  179. StringWriter := TStringWriter.Create;
  180. try
  181. Writer := TJsonTextWriter.Create(StringWriter);
  182. try
  183. Builder := TJSONArrayBuilder.Create(Writer);
  184. try
  185. Builder.BeginArray.AddElements([123, 'hello', True]).EndAll;
  186. Writer.Flush;
  187. CheckEquals('[123,"hello",true]', StringWriter.ToString, 'Array should handle open arrays correctly');
  188. finally
  189. Builder.Free;
  190. end;
  191. finally
  192. Writer.Free;
  193. end;
  194. finally
  195. StringWriter.Free;
  196. end;
  197. end;
  198. procedure TJSONBuildersBasicTest.TestNestedStructures;
  199. var
  200. Writer: TJSONWriter;
  201. StringWriter: TTextWriter;
  202. Builder: TJSONObjectBuilder;
  203. begin
  204. StringWriter := TStringWriter.Create;
  205. try
  206. Writer := TJsonTextWriter.Create(StringWriter);
  207. try
  208. Builder := TJSONObjectBuilder.Create(Writer);
  209. try
  210. Builder.BeginObject
  211. .Add('name', 'John')
  212. .BeginArray('hobbies')
  213. .Add('reading')
  214. .Add('gaming')
  215. .EndArray
  216. .BeginObject('address')
  217. .Add('street', '123 Main St')
  218. .Add('city', 'Anytown')
  219. .EndObject
  220. .EndAll;
  221. Writer.Flush;
  222. CheckEquals('{"name":"John","hobbies":["reading","gaming"],"address":{"street":"123 Main St","city":"Anytown"}}',
  223. StringWriter.ToString, 'Should handle nested structures correctly');
  224. finally
  225. Builder.Free;
  226. end;
  227. finally
  228. Writer.Free;
  229. end;
  230. finally
  231. StringWriter.Free;
  232. end;
  233. end;
  234. procedure TJSONBuildersBasicTest.TestComplexNestingIntegration;
  235. var
  236. Writer: TJSONWriter;
  237. StringWriter: TTextWriter;
  238. Builder: TJSONObjectBuilder;
  239. ExpectedJSON: String;
  240. begin
  241. StringWriter := TStringWriter.Create;
  242. try
  243. Writer := TJsonTextWriter.Create(StringWriter);
  244. try
  245. Builder := TJSONObjectBuilder.Create(Writer);
  246. try
  247. Builder.BeginObject
  248. .Add('name', 'Alice')
  249. .Add('age', 28)
  250. .BeginArray('hobbies')
  251. .Add('reading')
  252. .Add('coding')
  253. .Add('music')
  254. .EndArray
  255. .BeginObject('address')
  256. .Add('street', '123 Main St')
  257. .Add('city', 'Anytown')
  258. .Add('zip', 12345)
  259. .EndObject
  260. .EndAll;
  261. Writer.Flush;
  262. ExpectedJSON := '{"name":"Alice","age":28,"hobbies":["reading","coding","music"],"address":{"street":"123 Main St","city":"Anytown","zip":12345}}';
  263. CheckEquals(ExpectedJSON, StringWriter.ToString, 'Complex nesting should produce correct JSON');
  264. finally
  265. Builder.Free;
  266. end;
  267. finally
  268. Writer.Free;
  269. end;
  270. finally
  271. StringWriter.Free;
  272. end;
  273. end;
  274. procedure TJSONBuildersBasicTest.TestLargeDataSets;
  275. var
  276. Writer: TJSONWriter;
  277. StringWriter: TTextWriter;
  278. Builder: TJSONArrayBuilder;
  279. I: Integer;
  280. ResultStr: String;
  281. Elements: TJSONArrayBuilder.TElements;
  282. begin
  283. StringWriter := TStringWriter.Create;
  284. try
  285. Writer := TJsonTextWriter.Create(StringWriter);
  286. try
  287. Builder := TJSONArrayBuilder.Create(Writer);
  288. try
  289. Elements := Builder.BeginArray;
  290. for I := 1 to 100 do // Reduce size for faster testing
  291. begin
  292. Elements.Add(I);
  293. end;
  294. Elements.EndAll;
  295. Writer.Flush;
  296. ResultStr := StringWriter.ToString;
  297. CheckTrue(Length(ResultStr) > 100, 'Large dataset should produce substantial JSON');
  298. CheckTrue(Pos('1', ResultStr) > 0, 'Should contain first item');
  299. CheckTrue(Pos('100', ResultStr) > 0, 'Should contain last item');
  300. CheckTrue(Pos('50', ResultStr) > 0, 'Should contain middle item');
  301. finally
  302. Builder.Free;
  303. end;
  304. finally
  305. Writer.Free;
  306. end;
  307. finally
  308. StringWriter.Free;
  309. end;
  310. end;
  311. procedure TJSONBuildersBasicTest.TestErrorConditions;
  312. var
  313. Writer: TJSONWriter;
  314. StringWriter: TTextWriter;
  315. Builder: TJSONObjectBuilder;
  316. ExceptionThrown: Boolean;
  317. begin
  318. StringWriter := TStringWriter.Create;
  319. try
  320. Writer := TJsonTextWriter.Create(StringWriter);
  321. try
  322. Builder := TJSONObjectBuilder.Create(Writer);
  323. try
  324. // Test proper error handling with TVarRec
  325. Builder.BeginObject;
  326. ExceptionThrown := False;
  327. try
  328. Builder.ParentObject.Add('test', nil); // This should handle nil values gracefully
  329. except
  330. on E: Exception do
  331. ExceptionThrown := True;
  332. end;
  333. CheckFalse(ExceptionThrown, 'Should handle nil values gracefully');
  334. Builder.ParentObject.EndAll;
  335. finally
  336. Builder.Free;
  337. end;
  338. finally
  339. Writer.Free;
  340. end;
  341. finally
  342. StringWriter.Free;
  343. end;
  344. end;
  345. { TElements.Add overload tests }
  346. procedure TJSONBuildersBasicTest.TestArrayAddString;
  347. var
  348. Writer: TJSONWriter;
  349. StringWriter: TTextWriter;
  350. Builder: TJSONArrayBuilder;
  351. S: string;
  352. begin
  353. StringWriter := TStringWriter.Create;
  354. try
  355. Writer := TJsonTextWriter.Create(StringWriter);
  356. try
  357. Builder := TJSONArrayBuilder.Create(Writer);
  358. try
  359. S := 'hello world';
  360. Builder.BeginArray.Add(S).EndAll;
  361. Writer.Flush;
  362. CheckEquals('["hello world"]', StringWriter.ToString, 'Add(string) should work correctly');
  363. finally
  364. Builder.Free;
  365. end;
  366. finally
  367. Writer.Free;
  368. end;
  369. finally
  370. StringWriter.Free;
  371. end;
  372. end;
  373. procedure TJSONBuildersBasicTest.TestArrayAddInt32;
  374. var
  375. Writer: TJSONWriter;
  376. StringWriter: TTextWriter;
  377. Builder: TJSONArrayBuilder;
  378. I: Int32;
  379. begin
  380. StringWriter := TStringWriter.Create;
  381. try
  382. Writer := TJsonTextWriter.Create(StringWriter);
  383. try
  384. Builder := TJSONArrayBuilder.Create(Writer);
  385. try
  386. I := -2147483648;
  387. Builder.BeginArray.Add(I).Add(Int32(2147483647)).EndAll;
  388. Writer.Flush;
  389. CheckEquals('[-2147483648,2147483647]', StringWriter.ToString, 'Add(Int32) should work correctly');
  390. finally
  391. Builder.Free;
  392. end;
  393. finally
  394. Writer.Free;
  395. end;
  396. finally
  397. StringWriter.Free;
  398. end;
  399. end;
  400. procedure TJSONBuildersBasicTest.TestArrayAddUInt32;
  401. var
  402. Writer: TJSONWriter;
  403. StringWriter: TTextWriter;
  404. Builder: TJSONArrayBuilder;
  405. U: UInt32;
  406. begin
  407. StringWriter := TStringWriter.Create;
  408. try
  409. Writer := TJsonTextWriter.Create(StringWriter);
  410. try
  411. Builder := TJSONArrayBuilder.Create(Writer);
  412. try
  413. U := 4294967295;
  414. Builder.BeginArray.Add(U).Add(UInt32(0)).EndAll;
  415. Writer.Flush;
  416. CheckEquals('[4294967295,0]', StringWriter.ToString, 'Add(UInt32) should work correctly');
  417. finally
  418. Builder.Free;
  419. end;
  420. finally
  421. Writer.Free;
  422. end;
  423. finally
  424. StringWriter.Free;
  425. end;
  426. end;
  427. procedure TJSONBuildersBasicTest.TestArrayAddInt64;
  428. var
  429. Writer: TJSONWriter;
  430. StringWriter: TTextWriter;
  431. Builder: TJSONArrayBuilder;
  432. I: Int64;
  433. begin
  434. StringWriter := TStringWriter.Create;
  435. try
  436. Writer := TJsonTextWriter.Create(StringWriter);
  437. try
  438. Builder := TJSONArrayBuilder.Create(Writer);
  439. try
  440. I := -9223372036854775808;
  441. Builder.BeginArray.Add(I).Add(Int64(9223372036854775807)).EndAll;
  442. Writer.Flush;
  443. CheckEquals('[-9223372036854775808,9223372036854775807]', StringWriter.ToString, 'Add(Int64) should work correctly');
  444. finally
  445. Builder.Free;
  446. end;
  447. finally
  448. Writer.Free;
  449. end;
  450. finally
  451. StringWriter.Free;
  452. end;
  453. end;
  454. procedure TJSONBuildersBasicTest.TestArrayAddUInt64;
  455. var
  456. Writer: TJSONWriter;
  457. StringWriter: TTextWriter;
  458. Builder: TJSONArrayBuilder;
  459. U: UInt64;
  460. begin
  461. StringWriter := TStringWriter.Create;
  462. try
  463. Writer := TJsonTextWriter.Create(StringWriter);
  464. try
  465. Builder := TJSONArrayBuilder.Create(Writer);
  466. try
  467. U := 18446744073709551615;
  468. Builder.BeginArray.Add(U).Add(UInt64(0)).EndAll;
  469. Writer.Flush;
  470. CheckEquals('[18446744073709551615,0]', StringWriter.ToString, 'Add(UInt64) should work correctly');
  471. finally
  472. Builder.Free;
  473. end;
  474. finally
  475. Writer.Free;
  476. end;
  477. finally
  478. StringWriter.Free;
  479. end;
  480. end;
  481. procedure TJSONBuildersBasicTest.TestArrayAddSingle;
  482. var
  483. Writer: TJSONWriter;
  484. StringWriter: TTextWriter;
  485. Builder: TJSONArrayBuilder;
  486. S: Single;
  487. begin
  488. StringWriter := TStringWriter.Create;
  489. try
  490. Writer := TJsonTextWriter.Create(StringWriter);
  491. try
  492. Builder := TJSONArrayBuilder.Create(Writer);
  493. try
  494. S := 3.14;
  495. Builder.BeginArray.Add(S).EndAll;
  496. Writer.Flush;
  497. CheckTrue(Pos('3.14', StringWriter.ToString) > 0, 'Add(Single) should contain the value');
  498. finally
  499. Builder.Free;
  500. end;
  501. finally
  502. Writer.Free;
  503. end;
  504. finally
  505. StringWriter.Free;
  506. end;
  507. end;
  508. procedure TJSONBuildersBasicTest.TestArrayAddDouble;
  509. var
  510. Writer: TJSONWriter;
  511. StringWriter: TTextWriter;
  512. Builder: TJSONArrayBuilder;
  513. D: Double;
  514. begin
  515. StringWriter := TStringWriter.Create;
  516. try
  517. Writer := TJsonTextWriter.Create(StringWriter);
  518. try
  519. Builder := TJSONArrayBuilder.Create(Writer);
  520. try
  521. D := 3.141592653589793;
  522. Builder.BeginArray.Add(D).EndAll;
  523. Writer.Flush;
  524. CheckTrue(Pos('3.14159', StringWriter.ToString) > 0, 'Add(Double) should contain the value');
  525. finally
  526. Builder.Free;
  527. end;
  528. finally
  529. Writer.Free;
  530. end;
  531. finally
  532. StringWriter.Free;
  533. end;
  534. end;
  535. procedure TJSONBuildersBasicTest.TestArrayAddExtended;
  536. var
  537. Writer: TJSONWriter;
  538. StringWriter: TTextWriter;
  539. Builder: TJSONArrayBuilder;
  540. E: Extended;
  541. begin
  542. StringWriter := TStringWriter.Create;
  543. try
  544. Writer := TJsonTextWriter.Create(StringWriter);
  545. try
  546. Builder := TJSONArrayBuilder.Create(Writer);
  547. try
  548. E := 2.718281828459045;
  549. Builder.BeginArray.Add(E).EndAll;
  550. Writer.Flush;
  551. CheckTrue(Pos('2.71828', StringWriter.ToString) > 0, 'Add(Extended) should contain the value');
  552. finally
  553. Builder.Free;
  554. end;
  555. finally
  556. Writer.Free;
  557. end;
  558. finally
  559. StringWriter.Free;
  560. end;
  561. end;
  562. procedure TJSONBuildersBasicTest.TestArrayAddBoolean;
  563. var
  564. Writer: TJSONWriter;
  565. StringWriter: TTextWriter;
  566. Builder: TJSONArrayBuilder;
  567. B: Boolean;
  568. begin
  569. StringWriter := TStringWriter.Create;
  570. try
  571. Writer := TJsonTextWriter.Create(StringWriter);
  572. try
  573. Builder := TJSONArrayBuilder.Create(Writer);
  574. try
  575. B := True;
  576. Builder.BeginArray.Add(B).Add(Boolean(False)).EndAll;
  577. Writer.Flush;
  578. CheckEquals('[true,false]', StringWriter.ToString, 'Add(Boolean) should work correctly');
  579. finally
  580. Builder.Free;
  581. end;
  582. finally
  583. Writer.Free;
  584. end;
  585. finally
  586. StringWriter.Free;
  587. end;
  588. end;
  589. procedure TJSONBuildersBasicTest.TestArrayAddChar;
  590. var
  591. Writer: TJSONWriter;
  592. StringWriter: TTextWriter;
  593. Builder: TJSONArrayBuilder;
  594. C: Char;
  595. begin
  596. StringWriter := TStringWriter.Create;
  597. try
  598. Writer := TJsonTextWriter.Create(StringWriter);
  599. try
  600. Builder := TJSONArrayBuilder.Create(Writer);
  601. try
  602. C := 'A';
  603. Builder.BeginArray.Add(C).Add(Char('Z')).EndAll;
  604. Writer.Flush;
  605. CheckEquals('["A","Z"]', StringWriter.ToString, 'Add(Char) should work correctly');
  606. finally
  607. Builder.Free;
  608. end;
  609. finally
  610. Writer.Free;
  611. end;
  612. finally
  613. StringWriter.Free;
  614. end;
  615. end;
  616. procedure TJSONBuildersBasicTest.TestArrayAddByte;
  617. var
  618. Writer: TJSONWriter;
  619. StringWriter: TTextWriter;
  620. Builder: TJSONArrayBuilder;
  621. B: Byte;
  622. begin
  623. StringWriter := TStringWriter.Create;
  624. try
  625. Writer := TJsonTextWriter.Create(StringWriter);
  626. try
  627. Builder := TJSONArrayBuilder.Create(Writer);
  628. try
  629. B := 255;
  630. Builder.BeginArray.Add(B).Add(Byte(0)).EndAll;
  631. Writer.Flush;
  632. CheckEquals('[255,0]', StringWriter.ToString, 'Add(Byte) should work correctly');
  633. finally
  634. Builder.Free;
  635. end;
  636. finally
  637. Writer.Free;
  638. end;
  639. finally
  640. StringWriter.Free;
  641. end;
  642. end;
  643. procedure TJSONBuildersBasicTest.TestArrayAddDateTime;
  644. var
  645. Writer: TJSONWriter;
  646. StringWriter: TTextWriter;
  647. Builder: TJSONArrayBuilder;
  648. DT: TDateTime;
  649. begin
  650. StringWriter := TStringWriter.Create;
  651. try
  652. Writer := TJsonTextWriter.Create(StringWriter);
  653. try
  654. Builder := TJSONArrayBuilder.Create(Writer);
  655. try
  656. DT := EncodeDate(2024, 1, 15) + EncodeTime(10, 30, 0, 0);
  657. Builder.BeginArray.Add(DT).EndAll;
  658. Writer.Flush;
  659. CheckTrue(Pos('2024', StringWriter.ToString) > 0, 'Add(TDateTime) should contain year');
  660. finally
  661. Builder.Free;
  662. end;
  663. finally
  664. Writer.Free;
  665. end;
  666. finally
  667. StringWriter.Free;
  668. end;
  669. end;
  670. procedure TJSONBuildersBasicTest.TestArrayAddGUID;
  671. var
  672. Writer: TJSONWriter;
  673. StringWriter: TTextWriter;
  674. Builder: TJSONArrayBuilder;
  675. G: TGUID;
  676. begin
  677. StringWriter := TStringWriter.Create;
  678. try
  679. Writer := TJsonTextWriter.Create(StringWriter);
  680. try
  681. Builder := TJSONArrayBuilder.Create(Writer);
  682. try
  683. G := StringToGUID('{12345678-1234-1234-1234-123456789ABC}');
  684. Builder.BeginArray.Add(G).EndAll;
  685. Writer.Flush;
  686. CheckTrue(Pos('12345678', StringWriter.ToString) > 0, 'Add(TGUID) should contain GUID parts');
  687. finally
  688. Builder.Free;
  689. end;
  690. finally
  691. Writer.Free;
  692. end;
  693. finally
  694. StringWriter.Free;
  695. end;
  696. end;
  697. procedure TJSONBuildersBasicTest.TestArrayAddBytes;
  698. var
  699. Writer: TJSONWriter;
  700. StringWriter: TTextWriter;
  701. Builder: TJSONArrayBuilder;
  702. B: TBytes;
  703. begin
  704. StringWriter := TStringWriter.Create;
  705. try
  706. Writer := TJsonTextWriter.Create(StringWriter);
  707. try
  708. Builder := TJSONArrayBuilder.Create(Writer);
  709. try
  710. SetLength(B, 3);
  711. B[0] := $DE;
  712. B[1] := $AD;
  713. B[2] := $BE;
  714. Builder.BeginArray.Add(B, TJsonBinaryType.Generic).EndAll;
  715. Writer.Flush;
  716. CheckTrue(Length(StringWriter.ToString) > 2, 'Add(TBytes) should produce output');
  717. finally
  718. Builder.Free;
  719. end;
  720. finally
  721. Writer.Free;
  722. end;
  723. finally
  724. StringWriter.Free;
  725. end;
  726. end;
  727. procedure TJSONBuildersBasicTest.TestArrayAddJsonOid;
  728. var
  729. Writer: TJSONWriter;
  730. StringWriter: TTextWriter;
  731. Builder: TJSONArrayBuilder;
  732. Oid: TJsonOid;
  733. begin
  734. StringWriter := TStringWriter.Create;
  735. try
  736. Writer := TJsonTextWriter.Create(StringWriter);
  737. try
  738. Builder := TJSONArrayBuilder.Create(Writer);
  739. try
  740. Oid := TJsonOid.Create('507f1f77bcf86cd799439011');
  741. Builder.BeginArray.Add(Oid).EndAll;
  742. Writer.Flush;
  743. CheckTrue(Length(StringWriter.ToString) > 2, 'Add(TJsonOid) should produce output');
  744. finally
  745. Builder.Free;
  746. end;
  747. finally
  748. Writer.Free;
  749. end;
  750. finally
  751. StringWriter.Free;
  752. end;
  753. end;
  754. procedure TJSONBuildersBasicTest.TestArrayAddJsonRegEx;
  755. var
  756. Writer: TJSONWriter;
  757. StringWriter: TTextWriter;
  758. Builder: TJSONArrayBuilder;
  759. RegEx: TJsonRegEx;
  760. begin
  761. StringWriter := TStringWriter.Create;
  762. try
  763. Writer := TJsonTextWriter.Create(StringWriter);
  764. try
  765. Builder := TJSONArrayBuilder.Create(Writer);
  766. try
  767. RegEx := TJsonRegEx.Create('^test.*$', 'i');
  768. Builder.BeginArray.Add(RegEx).EndAll;
  769. Writer.Flush;
  770. CheckTrue(Length(StringWriter.ToString) > 2, 'Add(TJsonRegEx) should produce output');
  771. finally
  772. Builder.Free;
  773. end;
  774. finally
  775. Writer.Free;
  776. end;
  777. finally
  778. StringWriter.Free;
  779. end;
  780. end;
  781. procedure TJSONBuildersBasicTest.TestArrayAddJsonDBRef;
  782. var
  783. Writer: TJSONWriter;
  784. StringWriter: TTextWriter;
  785. Builder: TJSONArrayBuilder;
  786. DBRef: TJsonDBRef;
  787. begin
  788. StringWriter := TStringWriter.Create;
  789. try
  790. Writer := TJsonTextWriter.Create(StringWriter);
  791. try
  792. Builder := TJSONArrayBuilder.Create(Writer);
  793. try
  794. DBRef := TJsonDBRef.Create('mydb', 'mycollection', '507f1f77bcf86cd799439011');
  795. Builder.BeginArray.Add(DBRef).EndAll;
  796. Writer.Flush;
  797. CheckTrue(Length(StringWriter.ToString) > 2, 'Add(TJsonDBRef) should produce output');
  798. finally
  799. Builder.Free;
  800. end;
  801. finally
  802. Writer.Free;
  803. end;
  804. finally
  805. StringWriter.Free;
  806. end;
  807. end;
  808. procedure TJSONBuildersBasicTest.TestArrayAddJsonCodeWScope;
  809. var
  810. Writer: TJSONWriter;
  811. StringWriter: TTextWriter;
  812. Builder: TJSONArrayBuilder;
  813. CodeWScope: TJsonCodeWScope;
  814. Scope: TStringList;
  815. begin
  816. StringWriter := TStringWriter.Create;
  817. try
  818. Writer := TJsonTextWriter.Create(StringWriter);
  819. try
  820. Builder := TJSONArrayBuilder.Create(Writer);
  821. try
  822. Scope := TStringList.Create;
  823. try
  824. Scope.Add('x=1');
  825. CodeWScope := TJsonCodeWScope.Create('function() { return x; }', Scope);
  826. finally
  827. Scope.Free;
  828. end;
  829. Builder.BeginArray.Add(CodeWScope).EndAll;
  830. Writer.Flush;
  831. CheckTrue(Length(StringWriter.ToString) > 2, 'Add(TJsonCodeWScope) should produce output');
  832. finally
  833. Builder.Free;
  834. end;
  835. finally
  836. Writer.Free;
  837. end;
  838. finally
  839. StringWriter.Free;
  840. end;
  841. end;
  842. procedure TJSONBuildersBasicTest.TestArrayAddJsonDecimal128;
  843. var
  844. Writer: TJSONWriter;
  845. StringWriter: TTextWriter;
  846. Builder: TJSONArrayBuilder;
  847. Dec: TJsonDecimal128;
  848. ExceptionRaised: Boolean;
  849. begin
  850. StringWriter := TStringWriter.Create;
  851. try
  852. Writer := TJsonTextWriter.Create(StringWriter);
  853. try
  854. Builder := TJSONArrayBuilder.Create(Writer);
  855. try
  856. ExceptionRaised := False;
  857. try
  858. Dec := TJsonDecimal128.Create('123.456');
  859. Builder.BeginArray.Add(Dec).EndAll;
  860. Writer.Flush;
  861. CheckTrue(Length(StringWriter.ToString) > 2, 'Add(TJsonDecimal128) should produce output');
  862. except
  863. on E: EJsonException do
  864. ExceptionRaised := True;
  865. end;
  866. // FPC implementation may not have decimal support, which is acceptable
  867. CheckTrue(True, 'Add(TJsonDecimal128) test completed (decimal support may not be available)');
  868. finally
  869. Builder.Free;
  870. end;
  871. finally
  872. Writer.Free;
  873. end;
  874. finally
  875. StringWriter.Free;
  876. end;
  877. end;
  878. procedure TJSONBuildersBasicTest.TestArrayAddTValue;
  879. var
  880. Writer: TJSONWriter;
  881. StringWriter: TTextWriter;
  882. Builder: TJSONArrayBuilder;
  883. V: TValue;
  884. IntVal: Integer;
  885. begin
  886. StringWriter := TStringWriter.Create;
  887. try
  888. Writer := TJsonTextWriter.Create(StringWriter);
  889. try
  890. Builder := TJSONArrayBuilder.Create(Writer);
  891. try
  892. IntVal := 42;
  893. TValue.Make(@IntVal, TypeInfo(Integer), V);
  894. Builder.BeginArray.Add(V).EndAll;
  895. Writer.Flush;
  896. CheckEquals('[42]', StringWriter.ToString, 'Add(TValue) should work correctly');
  897. finally
  898. Builder.Free;
  899. end;
  900. finally
  901. Writer.Free;
  902. end;
  903. finally
  904. StringWriter.Free;
  905. end;
  906. end;
  907. procedure TJSONBuildersBasicTest.TestArrayAddTVarRec;
  908. var
  909. Writer: TJSONWriter;
  910. StringWriter: TTextWriter;
  911. Builder: TJSONArrayBuilder;
  912. VR: TVarRec;
  913. IntVal: Integer;
  914. begin
  915. StringWriter := TStringWriter.Create;
  916. try
  917. Writer := TJsonTextWriter.Create(StringWriter);
  918. try
  919. Builder := TJSONArrayBuilder.Create(Writer);
  920. try
  921. IntVal := 99;
  922. VR.VType := vtInteger;
  923. VR.VInteger := IntVal;
  924. Builder.BeginArray.Add(VR).EndAll;
  925. Writer.Flush;
  926. CheckEquals('[99]', StringWriter.ToString, 'Add(TVarRec) should work correctly');
  927. finally
  928. Builder.Free;
  929. end;
  930. finally
  931. Writer.Free;
  932. end;
  933. finally
  934. StringWriter.Free;
  935. end;
  936. end;
  937. procedure TJSONBuildersBasicTest.TestArrayAddVariant;
  938. var
  939. Writer: TJSONWriter;
  940. StringWriter: TTextWriter;
  941. Builder: TJSONArrayBuilder;
  942. V: Variant;
  943. begin
  944. StringWriter := TStringWriter.Create;
  945. try
  946. Writer := TJsonTextWriter.Create(StringWriter);
  947. try
  948. Builder := TJSONArrayBuilder.Create(Writer);
  949. try
  950. V := 'variant string';
  951. Builder.BeginArray.Add(V).EndAll;
  952. Writer.Flush;
  953. CheckEquals('["variant string"]', StringWriter.ToString, 'Add(Variant) should work correctly');
  954. finally
  955. Builder.Free;
  956. end;
  957. finally
  958. Writer.Free;
  959. end;
  960. finally
  961. StringWriter.Free;
  962. end;
  963. end;
  964. { TPairs.Add overload tests }
  965. procedure TJSONBuildersBasicTest.TestObjectAddString;
  966. var
  967. Writer: TJSONWriter;
  968. StringWriter: TTextWriter;
  969. Builder: TJSONObjectBuilder;
  970. S: string;
  971. begin
  972. StringWriter := TStringWriter.Create;
  973. try
  974. Writer := TJsonTextWriter.Create(StringWriter);
  975. try
  976. Builder := TJSONObjectBuilder.Create(Writer);
  977. try
  978. S := 'hello world';
  979. Builder.BeginObject.Add('key', S).EndAll;
  980. Writer.Flush;
  981. CheckEquals('{"key":"hello world"}', StringWriter.ToString, 'Add(key, string) should work correctly');
  982. finally
  983. Builder.Free;
  984. end;
  985. finally
  986. Writer.Free;
  987. end;
  988. finally
  989. StringWriter.Free;
  990. end;
  991. end;
  992. procedure TJSONBuildersBasicTest.TestObjectAddInt32;
  993. var
  994. Writer: TJSONWriter;
  995. StringWriter: TTextWriter;
  996. Builder: TJSONObjectBuilder;
  997. I: Int32;
  998. begin
  999. StringWriter := TStringWriter.Create;
  1000. try
  1001. Writer := TJsonTextWriter.Create(StringWriter);
  1002. try
  1003. Builder := TJSONObjectBuilder.Create(Writer);
  1004. try
  1005. I := -2147483648;
  1006. Builder.BeginObject.Add('min', I).Add('max', Int32(2147483647)).EndAll;
  1007. Writer.Flush;
  1008. CheckEquals('{"min":-2147483648,"max":2147483647}', StringWriter.ToString, 'Add(key, Int32) should work correctly');
  1009. finally
  1010. Builder.Free;
  1011. end;
  1012. finally
  1013. Writer.Free;
  1014. end;
  1015. finally
  1016. StringWriter.Free;
  1017. end;
  1018. end;
  1019. procedure TJSONBuildersBasicTest.TestObjectAddUInt32;
  1020. var
  1021. Writer: TJSONWriter;
  1022. StringWriter: TTextWriter;
  1023. Builder: TJSONObjectBuilder;
  1024. U: UInt32;
  1025. begin
  1026. StringWriter := TStringWriter.Create;
  1027. try
  1028. Writer := TJsonTextWriter.Create(StringWriter);
  1029. try
  1030. Builder := TJSONObjectBuilder.Create(Writer);
  1031. try
  1032. U := 4294967295;
  1033. Builder.BeginObject.Add('max', U).Add('min', UInt32(0)).EndAll;
  1034. Writer.Flush;
  1035. CheckEquals('{"max":4294967295,"min":0}', StringWriter.ToString, 'Add(key, UInt32) should work correctly');
  1036. finally
  1037. Builder.Free;
  1038. end;
  1039. finally
  1040. Writer.Free;
  1041. end;
  1042. finally
  1043. StringWriter.Free;
  1044. end;
  1045. end;
  1046. procedure TJSONBuildersBasicTest.TestObjectAddInt64;
  1047. var
  1048. Writer: TJSONWriter;
  1049. StringWriter: TTextWriter;
  1050. Builder: TJSONObjectBuilder;
  1051. I: Int64;
  1052. begin
  1053. StringWriter := TStringWriter.Create;
  1054. try
  1055. Writer := TJsonTextWriter.Create(StringWriter);
  1056. try
  1057. Builder := TJSONObjectBuilder.Create(Writer);
  1058. try
  1059. I := -9223372036854775808;
  1060. Builder.BeginObject.Add('min', I).Add('max', Int64(9223372036854775807)).EndAll;
  1061. Writer.Flush;
  1062. CheckEquals('{"min":-9223372036854775808,"max":9223372036854775807}', StringWriter.ToString, 'Add(key, Int64) should work correctly');
  1063. finally
  1064. Builder.Free;
  1065. end;
  1066. finally
  1067. Writer.Free;
  1068. end;
  1069. finally
  1070. StringWriter.Free;
  1071. end;
  1072. end;
  1073. procedure TJSONBuildersBasicTest.TestObjectAddUInt64;
  1074. var
  1075. Writer: TJSONWriter;
  1076. StringWriter: TTextWriter;
  1077. Builder: TJSONObjectBuilder;
  1078. U: UInt64;
  1079. begin
  1080. StringWriter := TStringWriter.Create;
  1081. try
  1082. Writer := TJsonTextWriter.Create(StringWriter);
  1083. try
  1084. Builder := TJSONObjectBuilder.Create(Writer);
  1085. try
  1086. U := 18446744073709551615;
  1087. Builder.BeginObject.Add('max', U).Add('min', UInt64(0)).EndAll;
  1088. Writer.Flush;
  1089. CheckEquals('{"max":18446744073709551615,"min":0}', StringWriter.ToString, 'Add(key, UInt64) should work correctly');
  1090. finally
  1091. Builder.Free;
  1092. end;
  1093. finally
  1094. Writer.Free;
  1095. end;
  1096. finally
  1097. StringWriter.Free;
  1098. end;
  1099. end;
  1100. procedure TJSONBuildersBasicTest.TestObjectAddSingle;
  1101. var
  1102. Writer: TJSONWriter;
  1103. StringWriter: TTextWriter;
  1104. Builder: TJSONObjectBuilder;
  1105. S: Single;
  1106. begin
  1107. StringWriter := TStringWriter.Create;
  1108. try
  1109. Writer := TJsonTextWriter.Create(StringWriter);
  1110. try
  1111. Builder := TJSONObjectBuilder.Create(Writer);
  1112. try
  1113. S := 3.14;
  1114. Builder.BeginObject.Add('pi', S).EndAll;
  1115. Writer.Flush;
  1116. CheckTrue(Pos('3.14', StringWriter.ToString) > 0, 'Add(key, Single) should contain the value');
  1117. finally
  1118. Builder.Free;
  1119. end;
  1120. finally
  1121. Writer.Free;
  1122. end;
  1123. finally
  1124. StringWriter.Free;
  1125. end;
  1126. end;
  1127. procedure TJSONBuildersBasicTest.TestObjectAddDouble;
  1128. var
  1129. Writer: TJSONWriter;
  1130. StringWriter: TTextWriter;
  1131. Builder: TJSONObjectBuilder;
  1132. D: Double;
  1133. begin
  1134. StringWriter := TStringWriter.Create;
  1135. try
  1136. Writer := TJsonTextWriter.Create(StringWriter);
  1137. try
  1138. Builder := TJSONObjectBuilder.Create(Writer);
  1139. try
  1140. D := 3.141592653589793;
  1141. Builder.BeginObject.Add('pi', D).EndAll;
  1142. Writer.Flush;
  1143. CheckTrue(Pos('3.14159', StringWriter.ToString) > 0, 'Add(key, Double) should contain the value');
  1144. finally
  1145. Builder.Free;
  1146. end;
  1147. finally
  1148. Writer.Free;
  1149. end;
  1150. finally
  1151. StringWriter.Free;
  1152. end;
  1153. end;
  1154. procedure TJSONBuildersBasicTest.TestObjectAddExtended;
  1155. var
  1156. Writer: TJSONWriter;
  1157. StringWriter: TTextWriter;
  1158. Builder: TJSONObjectBuilder;
  1159. E: Extended;
  1160. begin
  1161. StringWriter := TStringWriter.Create;
  1162. try
  1163. Writer := TJsonTextWriter.Create(StringWriter);
  1164. try
  1165. Builder := TJSONObjectBuilder.Create(Writer);
  1166. try
  1167. E := 2.718281828459045;
  1168. Builder.BeginObject.Add('e', E).EndAll;
  1169. Writer.Flush;
  1170. CheckTrue(Pos('2.71828', StringWriter.ToString) > 0, 'Add(key, Extended) should contain the value');
  1171. finally
  1172. Builder.Free;
  1173. end;
  1174. finally
  1175. Writer.Free;
  1176. end;
  1177. finally
  1178. StringWriter.Free;
  1179. end;
  1180. end;
  1181. procedure TJSONBuildersBasicTest.TestObjectAddBoolean;
  1182. var
  1183. Writer: TJSONWriter;
  1184. StringWriter: TTextWriter;
  1185. Builder: TJSONObjectBuilder;
  1186. B: Boolean;
  1187. begin
  1188. StringWriter := TStringWriter.Create;
  1189. try
  1190. Writer := TJsonTextWriter.Create(StringWriter);
  1191. try
  1192. Builder := TJSONObjectBuilder.Create(Writer);
  1193. try
  1194. B := True;
  1195. Builder.BeginObject.Add('yes', B).Add('no', Boolean(False)).EndAll;
  1196. Writer.Flush;
  1197. CheckEquals('{"yes":true,"no":false}', StringWriter.ToString, 'Add(key, Boolean) should work correctly');
  1198. finally
  1199. Builder.Free;
  1200. end;
  1201. finally
  1202. Writer.Free;
  1203. end;
  1204. finally
  1205. StringWriter.Free;
  1206. end;
  1207. end;
  1208. procedure TJSONBuildersBasicTest.TestObjectAddChar;
  1209. var
  1210. Writer: TJSONWriter;
  1211. StringWriter: TTextWriter;
  1212. Builder: TJSONObjectBuilder;
  1213. C: Char;
  1214. begin
  1215. StringWriter := TStringWriter.Create;
  1216. try
  1217. Writer := TJsonTextWriter.Create(StringWriter);
  1218. try
  1219. Builder := TJSONObjectBuilder.Create(Writer);
  1220. try
  1221. C := 'X';
  1222. Builder.BeginObject.Add('letter', C).EndAll;
  1223. Writer.Flush;
  1224. CheckEquals('{"letter":"X"}', StringWriter.ToString, 'Add(key, Char) should work correctly');
  1225. finally
  1226. Builder.Free;
  1227. end;
  1228. finally
  1229. Writer.Free;
  1230. end;
  1231. finally
  1232. StringWriter.Free;
  1233. end;
  1234. end;
  1235. procedure TJSONBuildersBasicTest.TestObjectAddByte;
  1236. var
  1237. Writer: TJSONWriter;
  1238. StringWriter: TTextWriter;
  1239. Builder: TJSONObjectBuilder;
  1240. B: Byte;
  1241. begin
  1242. StringWriter := TStringWriter.Create;
  1243. try
  1244. Writer := TJsonTextWriter.Create(StringWriter);
  1245. try
  1246. Builder := TJSONObjectBuilder.Create(Writer);
  1247. try
  1248. B := 200;
  1249. Builder.BeginObject.Add('byte', B).EndAll;
  1250. Writer.Flush;
  1251. CheckEquals('{"byte":200}', StringWriter.ToString, 'Add(key, Byte) should work correctly');
  1252. finally
  1253. Builder.Free;
  1254. end;
  1255. finally
  1256. Writer.Free;
  1257. end;
  1258. finally
  1259. StringWriter.Free;
  1260. end;
  1261. end;
  1262. procedure TJSONBuildersBasicTest.TestObjectAddDateTime;
  1263. var
  1264. Writer: TJSONWriter;
  1265. StringWriter: TTextWriter;
  1266. Builder: TJSONObjectBuilder;
  1267. DT: TDateTime;
  1268. begin
  1269. StringWriter := TStringWriter.Create;
  1270. try
  1271. Writer := TJsonTextWriter.Create(StringWriter);
  1272. try
  1273. Builder := TJSONObjectBuilder.Create(Writer);
  1274. try
  1275. DT := EncodeDate(2024, 6, 15) + EncodeTime(14, 30, 0, 0);
  1276. Builder.BeginObject.Add('timestamp', DT).EndAll;
  1277. Writer.Flush;
  1278. CheckTrue(Pos('2024', StringWriter.ToString) > 0, 'Add(key, TDateTime) should contain year');
  1279. finally
  1280. Builder.Free;
  1281. end;
  1282. finally
  1283. Writer.Free;
  1284. end;
  1285. finally
  1286. StringWriter.Free;
  1287. end;
  1288. end;
  1289. procedure TJSONBuildersBasicTest.TestObjectAddGUID;
  1290. var
  1291. Writer: TJSONWriter;
  1292. StringWriter: TTextWriter;
  1293. Builder: TJSONObjectBuilder;
  1294. G: TGUID;
  1295. begin
  1296. StringWriter := TStringWriter.Create;
  1297. try
  1298. Writer := TJsonTextWriter.Create(StringWriter);
  1299. try
  1300. Builder := TJSONObjectBuilder.Create(Writer);
  1301. try
  1302. G := StringToGUID('{ABCDEF12-3456-7890-ABCD-EF1234567890}');
  1303. Builder.BeginObject.Add('guid', G).EndAll;
  1304. Writer.Flush;
  1305. CheckTrue(Pos('ABCDEF12', StringWriter.ToString) > 0, 'Add(key, TGUID) should contain GUID parts');
  1306. finally
  1307. Builder.Free;
  1308. end;
  1309. finally
  1310. Writer.Free;
  1311. end;
  1312. finally
  1313. StringWriter.Free;
  1314. end;
  1315. end;
  1316. procedure TJSONBuildersBasicTest.TestObjectAddBytes;
  1317. var
  1318. Writer: TJSONWriter;
  1319. StringWriter: TTextWriter;
  1320. Builder: TJSONObjectBuilder;
  1321. B: TBytes;
  1322. begin
  1323. StringWriter := TStringWriter.Create;
  1324. try
  1325. Writer := TJsonTextWriter.Create(StringWriter);
  1326. try
  1327. Builder := TJSONObjectBuilder.Create(Writer);
  1328. try
  1329. SetLength(B, 4);
  1330. B[0] := $CA;
  1331. B[1] := $FE;
  1332. B[2] := $BA;
  1333. B[3] := $BE;
  1334. Builder.BeginObject.Add('data', B, TJsonBinaryType.Generic).EndAll;
  1335. Writer.Flush;
  1336. CheckTrue(Pos('data', StringWriter.ToString) > 0, 'Add(key, TBytes) should contain key');
  1337. finally
  1338. Builder.Free;
  1339. end;
  1340. finally
  1341. Writer.Free;
  1342. end;
  1343. finally
  1344. StringWriter.Free;
  1345. end;
  1346. end;
  1347. procedure TJSONBuildersBasicTest.TestObjectAddJsonOid;
  1348. var
  1349. Writer: TJSONWriter;
  1350. StringWriter: TTextWriter;
  1351. Builder: TJSONObjectBuilder;
  1352. Oid: TJsonOid;
  1353. begin
  1354. StringWriter := TStringWriter.Create;
  1355. try
  1356. Writer := TJsonTextWriter.Create(StringWriter);
  1357. try
  1358. Builder := TJSONObjectBuilder.Create(Writer);
  1359. try
  1360. Oid := TJsonOid.Create('507f191e810c19729de860ea');
  1361. Builder.BeginObject.Add('_id', Oid).EndAll;
  1362. Writer.Flush;
  1363. CheckTrue(Pos('_id', StringWriter.ToString) > 0, 'Add(key, TJsonOid) should contain key');
  1364. finally
  1365. Builder.Free;
  1366. end;
  1367. finally
  1368. Writer.Free;
  1369. end;
  1370. finally
  1371. StringWriter.Free;
  1372. end;
  1373. end;
  1374. procedure TJSONBuildersBasicTest.TestObjectAddJsonRegEx;
  1375. var
  1376. Writer: TJSONWriter;
  1377. StringWriter: TTextWriter;
  1378. Builder: TJSONObjectBuilder;
  1379. RegEx: TJsonRegEx;
  1380. begin
  1381. StringWriter := TStringWriter.Create;
  1382. try
  1383. Writer := TJsonTextWriter.Create(StringWriter);
  1384. try
  1385. Builder := TJSONObjectBuilder.Create(Writer);
  1386. try
  1387. RegEx := TJsonRegEx.Create('.*pattern.*', 'gi');
  1388. Builder.BeginObject.Add('pattern', RegEx).EndAll;
  1389. Writer.Flush;
  1390. CheckTrue(Pos('pattern', StringWriter.ToString) > 0, 'Add(key, TJsonRegEx) should contain key');
  1391. finally
  1392. Builder.Free;
  1393. end;
  1394. finally
  1395. Writer.Free;
  1396. end;
  1397. finally
  1398. StringWriter.Free;
  1399. end;
  1400. end;
  1401. procedure TJSONBuildersBasicTest.TestObjectAddJsonDBRef;
  1402. var
  1403. Writer: TJSONWriter;
  1404. StringWriter: TTextWriter;
  1405. Builder: TJSONObjectBuilder;
  1406. DBRef: TJsonDBRef;
  1407. begin
  1408. StringWriter := TStringWriter.Create;
  1409. try
  1410. Writer := TJsonTextWriter.Create(StringWriter);
  1411. try
  1412. Builder := TJSONObjectBuilder.Create(Writer);
  1413. try
  1414. DBRef := TJsonDBRef.Create('testdb', 'users', '507f191e810c19729de860ea');
  1415. Builder.BeginObject.Add('ref', DBRef).EndAll;
  1416. Writer.Flush;
  1417. CheckTrue(Pos('ref', StringWriter.ToString) > 0, 'Add(key, TJsonDBRef) should contain key');
  1418. finally
  1419. Builder.Free;
  1420. end;
  1421. finally
  1422. Writer.Free;
  1423. end;
  1424. finally
  1425. StringWriter.Free;
  1426. end;
  1427. end;
  1428. procedure TJSONBuildersBasicTest.TestObjectAddJsonCodeWScope;
  1429. var
  1430. Writer: TJSONWriter;
  1431. StringWriter: TTextWriter;
  1432. Builder: TJSONObjectBuilder;
  1433. CodeWScope: TJsonCodeWScope;
  1434. Scope: TStringList;
  1435. begin
  1436. StringWriter := TStringWriter.Create;
  1437. try
  1438. Writer := TJsonTextWriter.Create(StringWriter);
  1439. try
  1440. Builder := TJSONObjectBuilder.Create(Writer);
  1441. try
  1442. Scope := TStringList.Create;
  1443. try
  1444. Scope.Add('y=2');
  1445. CodeWScope := TJsonCodeWScope.Create('function() { return y * 2; }', Scope);
  1446. finally
  1447. Scope.Free;
  1448. end;
  1449. Builder.BeginObject.Add('func', CodeWScope).EndAll;
  1450. Writer.Flush;
  1451. CheckTrue(Pos('func', StringWriter.ToString) > 0, 'Add(key, TJsonCodeWScope) should contain key');
  1452. finally
  1453. Builder.Free;
  1454. end;
  1455. finally
  1456. Writer.Free;
  1457. end;
  1458. finally
  1459. StringWriter.Free;
  1460. end;
  1461. end;
  1462. procedure TJSONBuildersBasicTest.TestObjectAddJsonDecimal128;
  1463. var
  1464. Writer: TJSONWriter;
  1465. StringWriter: TTextWriter;
  1466. Builder: TJSONObjectBuilder;
  1467. Dec: TJsonDecimal128;
  1468. ExceptionRaised: Boolean;
  1469. begin
  1470. StringWriter := TStringWriter.Create;
  1471. try
  1472. Writer := TJsonTextWriter.Create(StringWriter);
  1473. try
  1474. Builder := TJSONObjectBuilder.Create(Writer);
  1475. try
  1476. ExceptionRaised := False;
  1477. try
  1478. Dec := TJsonDecimal128.Create('999.999');
  1479. Builder.BeginObject.Add('amount', Dec).EndAll;
  1480. Writer.Flush;
  1481. CheckTrue(Pos('amount', StringWriter.ToString) > 0, 'Add(key, TJsonDecimal128) should contain key');
  1482. except
  1483. on E: EJsonException do
  1484. ExceptionRaised := True;
  1485. end;
  1486. // FPC implementation may not have decimal support, which is acceptable
  1487. CheckTrue(True, 'Add(key, TJsonDecimal128) test completed (decimal support may not be available)');
  1488. finally
  1489. Builder.Free;
  1490. end;
  1491. finally
  1492. Writer.Free;
  1493. end;
  1494. finally
  1495. StringWriter.Free;
  1496. end;
  1497. end;
  1498. procedure TJSONBuildersBasicTest.TestObjectAddTValue;
  1499. var
  1500. Writer: TJSONWriter;
  1501. StringWriter: TTextWriter;
  1502. Builder: TJSONObjectBuilder;
  1503. V: TValue;
  1504. IntVal: Integer;
  1505. begin
  1506. StringWriter := TStringWriter.Create;
  1507. try
  1508. Writer := TJsonTextWriter.Create(StringWriter);
  1509. try
  1510. Builder := TJSONObjectBuilder.Create(Writer);
  1511. try
  1512. IntVal := 99;
  1513. TValue.Make(@IntVal, TypeInfo(Integer), V);
  1514. Builder.BeginObject.Add('value', V).EndAll;
  1515. Writer.Flush;
  1516. CheckEquals('{"value":99}', StringWriter.ToString, 'Add(key, TValue) should work correctly');
  1517. finally
  1518. Builder.Free;
  1519. end;
  1520. finally
  1521. Writer.Free;
  1522. end;
  1523. finally
  1524. StringWriter.Free;
  1525. end;
  1526. end;
  1527. procedure TJSONBuildersBasicTest.TestObjectAddTVarRec;
  1528. var
  1529. Writer: TJSONWriter;
  1530. StringWriter: TTextWriter;
  1531. Builder: TJSONObjectBuilder;
  1532. VR: TVarRec;
  1533. BoolVal: Boolean;
  1534. begin
  1535. StringWriter := TStringWriter.Create;
  1536. try
  1537. Writer := TJsonTextWriter.Create(StringWriter);
  1538. try
  1539. Builder := TJSONObjectBuilder.Create(Writer);
  1540. try
  1541. BoolVal := True;
  1542. VR.VType := vtBoolean;
  1543. VR.VBoolean := BoolVal;
  1544. Builder.BeginObject.Add('flag', VR).EndAll;
  1545. Writer.Flush;
  1546. CheckEquals('{"flag":true}', StringWriter.ToString, 'Add(key, TVarRec) should work correctly');
  1547. finally
  1548. Builder.Free;
  1549. end;
  1550. finally
  1551. Writer.Free;
  1552. end;
  1553. finally
  1554. StringWriter.Free;
  1555. end;
  1556. end;
  1557. procedure TJSONBuildersBasicTest.TestObjectAddVariant;
  1558. var
  1559. Writer: TJSONWriter;
  1560. StringWriter: TTextWriter;
  1561. Builder: TJSONObjectBuilder;
  1562. V: Variant;
  1563. begin
  1564. StringWriter := TStringWriter.Create;
  1565. try
  1566. Writer := TJsonTextWriter.Create(StringWriter);
  1567. try
  1568. Builder := TJSONObjectBuilder.Create(Writer);
  1569. try
  1570. V := 12345;
  1571. Builder.BeginObject.Add('number', V).EndAll;
  1572. Writer.Flush;
  1573. CheckEquals('{"number":12345}', StringWriter.ToString, 'Add(key, Variant) should work correctly');
  1574. finally
  1575. Builder.Free;
  1576. end;
  1577. finally
  1578. Writer.Free;
  1579. end;
  1580. finally
  1581. StringWriter.Free;
  1582. end;
  1583. end;
  1584. initialization
  1585. RegisterTest(TJSONBuildersBasicTest.Suite);
  1586. end.