utyamlscanner.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. {
  2. This file is part of the Free Component Library
  3. Copyright (c) 2024 by Michael Van Canneyt [email protected]
  4. YAML scanner unit tests
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit utyamlscanner;
  12. {$mode ObjFPC}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, fpcunit, testregistry, fpyaml.scanner;
  16. Type
  17. { TTestYAMLScanner }
  18. TTestYAMLScanner= class(TTestCase)
  19. private
  20. FDocument : String;
  21. FInput : TStream;
  22. FLineBreak : String;
  23. FScanner: TYAMLScanner;
  24. FLastToken : TYAMLTokenData;
  25. procedure AssertEscape(aEscape, aResult: TYAMLString);
  26. protected
  27. procedure StartDocument(const aDoc: array of AnsiString);
  28. procedure SetUp; override;
  29. procedure TearDown; override;
  30. Procedure StartDocument(aDoc : AnsiString);
  31. procedure ReadToken;
  32. Public
  33. class procedure AssertEquals(const msg: string; aExpected, aActual: TYAMLToken); overload;
  34. procedure AssertToken(const msg: string; aTokenData: TYAMLTokenData; aToken: TYAMLToken; aRow: Integer; aCol: Integer);
  35. function AssertToken(const msg: string; aToken: TYAMLToken; aRow: Integer; aCol: Integer): TYAMLTokenData;
  36. function AssertToken(const msg: string; aToken: TYAMLToken; const aValue: string; aRow: Integer; aCol: Integer): TYAMLTokenData;
  37. procedure AssertEOF;
  38. Property Document : String read FDocument;
  39. Property Scanner : TYAMLScanner Read FScanner;
  40. Property ScannerInput : TStream Read FInput;
  41. Property LineBreak : String Read FLineBreak;
  42. published
  43. procedure TestHookUp;
  44. procedure TestEmpty;
  45. procedure TestDocumentStart;
  46. procedure TestDocumentEnd;
  47. procedure TestComment;
  48. procedure TestAnchor;
  49. procedure TestAnchorFailNoSpace;
  50. procedure TestAlias;
  51. procedure TestAliasFailNoSpace;
  52. procedure TestScalar;
  53. procedure TestNumScalar;
  54. procedure TestSingleQuotedScalar;
  55. procedure TestSingleQuotedScalarSpaces;
  56. procedure TestDoubleQuotedScalar;
  57. procedure TestDoubleQuotedScalarSpacesNewline;
  58. procedure TestDoubleQuotedScalarError;
  59. procedure TestLiteralScalar;
  60. procedure TestLiteralScalar2;
  61. procedure TestFoldedScalar;
  62. procedure TestFoldedScalar2;
  63. procedure TestPlainMultilineScalar;
  64. procedure TestYAMLDirective;
  65. procedure TestTAGDirectiveLocal;
  66. procedure TestTAGDirectiveGlobal;
  67. procedure TestSequence;
  68. procedure TestFlowSequence;
  69. procedure TestFlowSequenceEnd;
  70. procedure TestSimplekey;
  71. procedure TestSimpleLongkey;
  72. procedure TestExplicitkey;
  73. procedure TestEscape0;
  74. procedure TestEscapeA;
  75. procedure TestEscapeB;
  76. procedure TestEscapeT;
  77. procedure TestEscapeNMin;
  78. procedure TestEscapeV;
  79. procedure TestEscapeF;
  80. procedure TestEscapeR;
  81. procedure TestEscapeE;
  82. procedure TestEscapeSpace;
  83. procedure TestEscapeQuote;
  84. procedure TestEscapeSlash;
  85. procedure TestEscapeBackSlash;
  86. procedure TestEscapeNMaj;
  87. procedure TestEscapeUnderscore;
  88. procedure TestEscapeL;
  89. procedure TestEscapeP;
  90. procedure TestEscapeX;
  91. procedure TestEscapeUMin;
  92. procedure TestEscapeUMAj;
  93. end;
  94. implementation
  95. uses typinfo;
  96. { TTestYAMLScanner }
  97. procedure TTestYAMLScanner.SetUp;
  98. begin
  99. inherited SetUp;
  100. FLineBreak:=#10;
  101. FDocument:='';
  102. FInput:=Nil;
  103. FScanner:=Nil;
  104. end;
  105. procedure TTestYAMLScanner.TearDown;
  106. begin
  107. FDocument:='';
  108. FreeAndNil(FScanner);
  109. FreeAndNil(FInput);
  110. inherited TearDown;
  111. end;
  112. procedure TTestYAMLScanner.StartDocument(const aDoc: array of AnsiString);
  113. var
  114. lDoc,S : String;
  115. begin
  116. lDoc:='';
  117. for S in aDoc do
  118. begin
  119. if lDoc<>'' then
  120. lDoc:=lDoc+FLineBreak;
  121. lDoc:=lDoc+S;
  122. end;
  123. StartDocument(lDoc);
  124. end;
  125. procedure TTestYAMLScanner.StartDocument(aDoc: AnsiString);
  126. begin
  127. FDocument:=aDoc;
  128. FInput:=TStringStream.Create(aDoc);
  129. FScanner:=TYAMLScanner.Create(FInput);
  130. end;
  131. procedure TTestYAMLScanner.ReadToken;
  132. begin
  133. AssertNotNull('have scanner',Scanner);
  134. FLastToken:=FScanner.GetNextToken;
  135. end;
  136. procedure TTestYAMLScanner.TestHookUp;
  137. begin
  138. AssertNull('No scanner',Scanner);
  139. AssertNull('No input',ScannerInput);
  140. AssertEquals('LineBreak',#10,LineBreak);
  141. AssertEquals('No document','',Document);
  142. end;
  143. class procedure TTestYAMLScanner.AssertEquals(const msg: string; aExpected,aActual: TYAMLToken);
  144. begin
  145. AssertEquals(Msg,GetEnumName(TypeInfo(TYAMLToken),ord(aExpected)),
  146. GetEnumName(TypeInfo(TYAMLToken),ord(aActual)));
  147. end;
  148. function TTestYAMLScanner.AssertToken(const msg: string; aToken: TYAMLToken; aRow: Integer; aCol: Integer) : TYAMLTokenData;
  149. var
  150. lToken : TYAMLTokenData;
  151. begin
  152. AssertNotNull(Scanner);
  153. lToken:=Scanner.GetNextToken;
  154. AssertToken(Msg,lToken,aToken,aRow,aCol);
  155. FLastToken:=lToken;
  156. Result:=lToken;
  157. end;
  158. procedure TTestYAMLScanner.AssertToken(const msg: string; aTokenData : TYAMLTokenData; aToken: TYAMLToken; aRow: Integer; aCol: Integer);
  159. begin
  160. AssertEquals(msg+': Correct token',aToken,aTokenData.token);
  161. if aRow<>-1 then
  162. AssertEquals(msg+': Correct row',aRow,aTokenData.beginpos.Line);
  163. if aCol<>-1 then
  164. AssertEquals(msg+': Correct col',aCol,aTokenData.beginpos.Column);
  165. end;
  166. function TTestYAMLScanner.AssertToken(const msg: string; aToken: TYAMLToken; const aValue: string; aRow: Integer; aCol: Integer) : TYAMLTokenData;
  167. var
  168. lToken : TYAMLTokenData;
  169. begin
  170. AssertNotNull(Scanner);
  171. lToken:=Scanner.GetNextToken;
  172. AssertToken(Msg,lToken,aToken,aRow,aCol);
  173. AssertEquals(Msg+' token value',aValue,lToken.value);
  174. FLastToken:=lToken;
  175. Result:=lToken;
  176. end;
  177. procedure TTestYAMLScanner.AssertEOF;
  178. begin
  179. AssertToken('Empty',ytEOF,-1,-1);
  180. end;
  181. procedure TTestYAMLScanner.TestEmpty;
  182. begin
  183. StartDocument('');
  184. AssertToken('Empty',ytEOF,0,0);
  185. end;
  186. procedure TTestYAMLScanner.TestDocumentStart;
  187. begin
  188. StartDocument('---');
  189. AssertToken('Document start',ytDocumentStart,1,1);
  190. AssertEOF;
  191. end;
  192. procedure TTestYAMLScanner.TestDocumentEnd;
  193. begin
  194. StartDocument('...');
  195. AssertToken('Document start',ytDocumentEnd,1,1);
  196. AssertEOF;
  197. end;
  198. procedure TTestYAMLScanner.TestComment;
  199. begin
  200. StartDocument('#');
  201. AssertToken('Empty',ytEOF,1,0);
  202. end;
  203. procedure TTestYAMLScanner.TestAnchor;
  204. begin
  205. StartDocument('&one ');
  206. AssertToken('anchor',ytAnchor,'one',1,2);
  207. end;
  208. procedure TTestYAMLScanner.TestAnchorFailNoSpace;
  209. begin
  210. StartDocument('&one');
  211. AssertException('Need space',EYAMLScanner,@ReadToken);
  212. end;
  213. procedure TTestYAMLScanner.TestAlias;
  214. begin
  215. StartDocument('*one ');
  216. AssertToken('Alias',ytAlias,'one',1,2);
  217. end;
  218. procedure TTestYAMLScanner.TestAliasFailNoSpace;
  219. begin
  220. StartDocument('*alias');
  221. AssertException('Need space',EYAMLScanner,@ReadToken);
  222. end;
  223. procedure TTestYAMLScanner.TestScalar;
  224. begin
  225. StartDocument('one');
  226. AssertToken('scalar',ytScalarPlain,'one',1,1);
  227. end;
  228. procedure TTestYAMLScanner.TestNumScalar;
  229. begin
  230. StartDocument('123');
  231. AssertToken('scalar',ytScalarPlain,'123',1,1);
  232. end;
  233. procedure TTestYAMLScanner.TestSingleQuotedScalar;
  234. begin
  235. StartDocument('''123''');
  236. AssertToken('scalar',ytScalarSingle,'123',1,1);
  237. end;
  238. procedure TTestYAMLScanner.TestSingleQuotedScalarSpaces;
  239. begin
  240. StartDocument('''123 456''');
  241. AssertToken('scalar',ytScalarSingle,'123 456',1,1);
  242. end;
  243. procedure TTestYAMLScanner.TestDoubleQuotedScalarSpacesNewline;
  244. begin
  245. StartDocument('"123 456\'#10' \ abc def"');
  246. AssertToken('scalar',ytScalarDouble,'123 456 abc def',1,1);
  247. end;
  248. procedure TTestYAMLScanner.TestDoubleQuotedScalar;
  249. begin
  250. StartDocument('"123"');
  251. AssertToken('scalar',ytScalarDouble,'123',1,1);
  252. end;
  253. procedure TTestYAMLScanner.TestDoubleQuotedScalarError;
  254. begin
  255. StartDocument('"\"');
  256. AssertException('End of stream',EYAMLScanner,@ReadToken);
  257. end;
  258. procedure TTestYAMLScanner.TestLiteralScalar;
  259. begin
  260. // Example 8.7
  261. StartDocument(['|',
  262. ' literal',
  263. ' '#9'text',
  264. '']);
  265. AssertToken('Literal scalar',ytScalarLiteral,'literal'#10#9'text'#10,1,1);
  266. AssertEOF;
  267. end;
  268. procedure TTestYAMLScanner.TestLiteralScalar2;
  269. begin
  270. // Example 8.8
  271. StartDocument(['|',
  272. ' ',
  273. ' ',
  274. ' literal',
  275. ' ',
  276. ' ',
  277. ' text',
  278. '',
  279. ' # Comment']);
  280. AssertToken('Literal scalar',ytScalarLiteral,#10#10'literal'#10' '#10#10'text'#10,1,1);
  281. AssertEOF;
  282. end;
  283. procedure TTestYAMLScanner.TestFoldedScalar;
  284. begin
  285. // Example 8.9
  286. StartDocument(['>',
  287. ' folded',
  288. ' text',
  289. '']);
  290. AssertToken('Literal scalar',ytScalarFolded,'folded text'#10,1,1);
  291. AssertEOF;
  292. end;
  293. procedure TTestYAMLScanner.TestFoldedScalar2;
  294. begin
  295. // Example 8.10
  296. // The example seems wrong in the sense that none of the scanners I tried
  297. // returns a space for the empty line between bullet and list.
  298. // Adapted the test accordingly
  299. StartDocument(['>',
  300. '',
  301. ' folded',
  302. ' line',
  303. '',
  304. ' next',
  305. ' line',
  306. ' * bullet',
  307. '',
  308. ' * list',
  309. ' * lines',
  310. '',
  311. ' last',
  312. ' line',
  313. '',
  314. '# comment']);
  315. AssertToken('Literal scalar',ytScalarFolded,#10'folded line'#10+
  316. 'next line'#10+
  317. ' * bullet'#10+
  318. ''#10+
  319. ' * list'#10+
  320. ' * lines'#10+
  321. #10+
  322. 'last line'#10,1,1);
  323. AssertEOF;
  324. end;
  325. procedure TTestYAMLScanner.TestPlainMultilineScalar;
  326. begin
  327. StartDocument(['5',
  328. ' 00']);
  329. AssertToken('Plain scalar',ytScalarPlain,'5 00',1,1);
  330. end;
  331. procedure TTestYAMLScanner.TestYAMLDirective;
  332. var
  333. lToken : TYAMLTokenData;
  334. begin
  335. StartDocument('%YAML 1.2');
  336. lToken:=AssertToken('Directive',ytVersionDirective,'1',1,1);
  337. AssertEquals('minor','2',lToken.Value2);
  338. end;
  339. procedure TTestYAMLScanner.TestTAGDirectiveLocal;
  340. var
  341. lToken : TYAMLTokenData;
  342. begin
  343. StartDocument('%TAG !me! !you');
  344. lToken:=AssertToken('Tag directive',ytTagDirective,'!me!',1,1);
  345. AssertEquals('local prefix','!you',lToken.Value2);
  346. end;
  347. procedure TTestYAMLScanner.TestTAGDirectiveGlobal;
  348. var
  349. lToken : TYAMLTokenData;
  350. begin
  351. StartDocument('%TAG !me! tag:example.com,2000:app/');
  352. lToken:=AssertToken('Tag directive',ytTagDirective,'!me!',1,1);
  353. AssertEquals('local prefix','tag:example.com,2000:app/',lToken.Value2);
  354. end;
  355. procedure TTestYAMLScanner.TestSequence;
  356. begin
  357. StartDocument('- ');
  358. AssertToken('Sequence start',ytBlockSequenceStart,'',1,1);
  359. AssertFalse('Block context',scanner.InFlowContext);
  360. end;
  361. procedure TTestYAMLScanner.TestFlowSequence;
  362. begin
  363. StartDocument('[');
  364. AssertToken('Flow sequence start',ytFlowSequenceStart,'',1,1);
  365. AssertTrue('Flow context',scanner.InFlowContext);
  366. end;
  367. procedure TTestYAMLScanner.TestFlowSequenceEnd;
  368. begin
  369. StartDocument(']');
  370. AssertToken('Flow sequence end',ytFlowSequenceEnd,'',1,1);
  371. AssertFalse('Block context',scanner.InFlowContext);
  372. end;
  373. procedure TTestYAMLScanner.TestSimplekey;
  374. begin
  375. StartDocument('key: ');
  376. AssertToken('Start mapping',ytBlockMappingStart,'',1,1);
  377. AssertFalse('Block context',scanner.InFlowContext);
  378. AssertToken('Key directive',ytKey,'',1,1);
  379. AssertToken('scalar key value',ytScalarPlain,'key',1,1);
  380. AssertToken('value directive',ytValue,'',1,4);
  381. AssertToken('end mapping',ytBlockEnd,'',1,0);
  382. AssertFalse('Block context',scanner.InFlowContext);
  383. AssertEOF;
  384. end;
  385. procedure TTestYAMLScanner.TestSimpleLongkey;
  386. begin
  387. StartDocument('long key: ');
  388. AssertToken('Start mapping',ytBlockMappingStart,'',1,1);
  389. AssertFalse('Block context',scanner.InFlowContext);
  390. AssertToken('Key directive',ytKey,'',1,1);
  391. AssertToken('scalar key value',ytScalarPlain,'long key',1,1);
  392. AssertToken('value directive',ytValue,'',1,9);
  393. AssertToken('end mapping',ytBlockEnd,'',1,0);
  394. AssertFalse('Block context',scanner.InFlowContext);
  395. AssertEOF;
  396. end;
  397. procedure TTestYAMLScanner.TestExplicitkey;
  398. begin
  399. StartDocument('? key');
  400. AssertToken('Start mapping',ytBlockMappingStart,'',1,1);
  401. AssertFalse('Block context',scanner.InFlowContext);
  402. AssertToken('Key directive',ytKey,'',1,1);
  403. AssertToken('scalar key value',ytScalarPlain,'key',1,3);
  404. AssertToken('end mapping',ytBlockEnd,'',1,0);
  405. AssertFalse('Block context',scanner.InFlowContext);
  406. AssertToken('end',ytEOF,'',1,0);
  407. end;
  408. procedure TTestYAMLScanner.AssertEscape(aEscape,aResult : TYAMLString);
  409. begin
  410. StartDocument('"a\'+aEscape+'"');
  411. AssertToken('Token',ytScalarDouble,'a'+aResult,1,1);
  412. end;
  413. procedure TTestYAMLScanner.TestEscape0;
  414. begin
  415. AssertEscape('0',#0);
  416. end;
  417. procedure TTestYAMLScanner.TestEscapeA;
  418. begin
  419. AssertEscape('a',#7);
  420. end;
  421. procedure TTestYAMLScanner.TestEscapeB;
  422. begin
  423. AssertEscape('b',#8);
  424. end;
  425. procedure TTestYAMLScanner.TestEscapeT;
  426. begin
  427. AssertEscape('t',#9);
  428. end;
  429. procedure TTestYAMLScanner.TestEscapeNMin;
  430. begin
  431. AssertEscape('n',#10);
  432. end;
  433. procedure TTestYAMLScanner.TestEscapeV;
  434. begin
  435. AssertEscape('v',#11);
  436. end;
  437. procedure TTestYAMLScanner.TestEscapeF;
  438. begin
  439. AssertEscape('f',#12);
  440. end;
  441. procedure TTestYAMLScanner.TestEscapeR;
  442. begin
  443. AssertEscape('r',#13);
  444. end;
  445. procedure TTestYAMLScanner.TestEscapeE;
  446. begin
  447. AssertEscape('e',#$1B);
  448. end;
  449. procedure TTestYAMLScanner.TestEscapeSpace;
  450. begin
  451. AssertEscape(' ',' ');
  452. end;
  453. procedure TTestYAMLScanner.TestEscapeQuote;
  454. begin
  455. AssertEscape('"','"');
  456. end;
  457. procedure TTestYAMLScanner.TestEscapeSlash;
  458. begin
  459. AssertEscape('/','/');
  460. end;
  461. procedure TTestYAMLScanner.TestEscapeBackSlash;
  462. begin
  463. AssertEscape('\','\');
  464. end;
  465. procedure TTestYAMLScanner.TestEscapeNMaj;
  466. begin
  467. AssertEscape('N',#$C2#$85);
  468. end;
  469. procedure TTestYAMLScanner.TestEscapeUnderscore;
  470. begin
  471. AssertEscape('_',#$C2#$A0);
  472. end;
  473. procedure TTestYAMLScanner.TestEscapeL;
  474. begin
  475. AssertEscape('L',#$E2#$80#$A8);
  476. end;
  477. procedure TTestYAMLScanner.TestEscapeP;
  478. begin
  479. AssertEscape('P',#$E2#$80#$A9);
  480. end;
  481. procedure TTestYAMLScanner.TestEscapeX;
  482. begin
  483. AssertEscape('xA0',#$C2#$A0);
  484. end;
  485. procedure TTestYAMLScanner.TestEscapeUMin;
  486. begin
  487. AssertEscape('u2029',#$E2#$80#$A9);
  488. end;
  489. procedure TTestYAMLScanner.TestEscapeUMAj;
  490. begin
  491. AssertEscape('U000E0030',#$F3#$A0#$80#$B0);
  492. end;
  493. initialization
  494. RegisterTest(TTestYAMLScanner);
  495. end.