utcscanner.pas 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2025 by Michael Van Canneyt ([email protected])
  4. Test EBNF Scanner
  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 utcscanner;
  12. interface
  13. uses
  14. sysutils, fpcunit, testregistry, ebnf.scanner;
  15. type
  16. { TTestEBNFScanner }
  17. TTestEBNFScanner = class(TTestCase)
  18. private
  19. FScanner: TEBNFScanner;
  20. procedure CheckToken(aType: TEBNFTokenType; aValue: string; AMessage: string);
  21. protected
  22. procedure SetUp; override;
  23. procedure TearDown; override;
  24. procedure AssertEquals(const Msg : String; aExpected, aActual : TEBNFTokenType); overload;
  25. procedure CheckEquals(aExpected, aActual : TEBNFTokenType; const Msg : String = ''); overload;
  26. property Scanner : TEBNFScanner Read FScanner Write FScanner;
  27. published
  28. // Test methods for each token type
  29. procedure TestIdentifier;
  30. procedure TestStringLiteralSingleQuote;
  31. procedure TestStringLiteralDoubleQuote;
  32. procedure TestEquals;
  33. procedure TestComment;
  34. procedure TestPipe;
  35. procedure TestOpenParen;
  36. procedure TestCloseParen;
  37. procedure TestOpenBracket;
  38. procedure TestCloseBracket;
  39. procedure TestOpenBrace;
  40. procedure TestCloseBrace;
  41. procedure TestSemicolon;
  42. procedure TestQuestion;
  43. procedure TestEOF;
  44. procedure TestWhitespaceHandling;
  45. procedure TestMultipleTokens;
  46. procedure TestUnknownTokenError;
  47. procedure TestUnterminatedStringError;
  48. end;
  49. implementation
  50. uses typinfo;
  51. { TTestEBNFScanner }
  52. procedure TTestEBNFScanner.SetUp;
  53. begin
  54. inherited SetUp;
  55. FreeAndNil(FScanner);
  56. end;
  57. procedure TTestEBNFScanner.TearDown;
  58. begin
  59. FreeAndNil(FScanner);
  60. inherited TearDown;
  61. end;
  62. procedure TTestEBNFScanner.AssertEquals(const Msg: String; aExpected, aActual: TEBNFTokenType);
  63. begin
  64. AssertEquals(Msg,GetEnumName(typeInfo(TEBNFTokenType),ord(aExpected)),
  65. GetEnumName(typeInfo(TEBNFTokenType),ord(aActual)));
  66. end;
  67. procedure TTestEBNFScanner.CheckEquals(aExpected, aActual: TEBNFTokenType; const Msg: String);
  68. begin
  69. AssertEquals(Msg,aExpected,aActual);
  70. end;
  71. procedure TTestEBNFScanner.CheckToken(aType : TEBNFTokenType; aValue : string; AMessage : string);
  72. var
  73. Token: TToken;
  74. begin
  75. Token := Scanner.GetNextToken;
  76. CheckEquals(aType, Token.TokenType, 'Expected token type');
  77. if aType<>ttEOF then
  78. CheckEquals(aValue, Token.Value, 'Expected token value');
  79. end;
  80. procedure TTestEBNFScanner.TestIdentifier;
  81. begin
  82. Scanner := TEBNFScanner.Create('myRuleName another_id Rule123');
  83. CheckToken(ttIdentifier,'myRuleName', 'first identifier');
  84. CheckToken(ttIdentifier,'another_id', 'second identifier');
  85. CheckToken(ttIdentifier,'Rule123', 'third identifier');
  86. CheckToken(ttEOF,'', 'EOF');
  87. end;
  88. procedure TTestEBNFScanner.TestStringLiteralSingleQuote;
  89. begin
  90. Scanner := TEBNFScanner.Create('''hello world'' ''a''');
  91. CheckToken(ttStringLiteral,'hello world','first literal');
  92. CheckToken(ttStringLiteral,'a','second literal');
  93. CheckToken(ttEOF,'', 'EOF');
  94. end;
  95. procedure TTestEBNFScanner.TestStringLiteralDoubleQuote;
  96. begin
  97. Scanner := TEBNFScanner.Create('"another string" "123"');
  98. CheckToken(ttStringLiteral,'another string','first literal');
  99. CheckToken(ttStringLiteral,'123','second literal');
  100. CheckToken(ttEOF,'', 'EOF');
  101. end;
  102. procedure TTestEBNFScanner.TestEquals;
  103. begin
  104. Scanner := TEBNFScanner.Create('=');
  105. CheckToken(ttEquals,'','Equals');
  106. CheckToken(ttEOF,'', 'EOF');
  107. end;
  108. procedure TTestEBNFScanner.TestComment;
  109. begin
  110. Scanner := TEBNFScanner.Create('(* some comment *) =');
  111. CheckToken(ttEquals,'','Equals');
  112. CheckToken(ttEOF,'', 'EOF');
  113. end;
  114. procedure TTestEBNFScanner.TestPipe;
  115. begin
  116. Scanner := TEBNFScanner.Create('|');
  117. CheckToken(ttPipe,'','Pipe');
  118. CheckToken(ttEOF,'', 'EOF');
  119. end;
  120. procedure TTestEBNFScanner.TestOpenParen;
  121. begin
  122. Scanner := TEBNFScanner.Create('(');
  123. CheckToken(ttOpenParen,'','open parenthesis');
  124. CheckToken(ttEOF,'', 'EOF');
  125. end;
  126. procedure TTestEBNFScanner.TestCloseParen;
  127. begin
  128. Scanner := TEBNFScanner.Create(')');
  129. CheckToken(ttCloseParen,'','close parenthesis');
  130. CheckToken(ttEOF,'', 'EOF');
  131. end;
  132. procedure TTestEBNFScanner.TestOpenBracket;
  133. begin
  134. Scanner := TEBNFScanner.Create('[');
  135. CheckToken(ttOpenBracket,'','open bracket');
  136. CheckToken(ttEOF,'', 'EOF');
  137. end;
  138. procedure TTestEBNFScanner.TestCloseBracket;
  139. begin
  140. Scanner := TEBNFScanner.Create(']');
  141. CheckToken(ttCloseBracket,'','close bracket');
  142. CheckToken(ttEOF,'', 'EOF');
  143. end;
  144. procedure TTestEBNFScanner.TestOpenBrace;
  145. begin
  146. Scanner := TEBNFScanner.Create('{');
  147. CheckToken(ttOpenBrace,'','open brace');
  148. CheckToken(ttEOF,'', 'EOF');
  149. end;
  150. procedure TTestEBNFScanner.TestCloseBrace;
  151. begin
  152. Scanner := TEBNFScanner.Create('}');
  153. CheckToken(ttCloseBrace,'','close brace');
  154. CheckToken(ttEOF,'', 'EOF');
  155. end;
  156. procedure TTestEBNFScanner.TestSemicolon;
  157. begin
  158. Scanner := TEBNFScanner.Create(';');
  159. CheckToken(ttSemicolon,'','semicolon');
  160. CheckToken(ttEOF,'', 'EOF');
  161. end;
  162. procedure TTestEBNFScanner.TestQuestion;
  163. begin
  164. Scanner := TEBNFScanner.Create('?');
  165. CheckToken(ttQuestion,'','Question');
  166. CheckToken(ttEOF,'', 'EOF');
  167. end;
  168. procedure TTestEBNFScanner.TestEOF;
  169. begin
  170. Scanner := TEBNFScanner.Create('');
  171. CheckToken(ttEOF,'', 'EOF');
  172. end;
  173. procedure TTestEBNFScanner.TestWhitespaceHandling;
  174. begin
  175. Scanner := TEBNFScanner.Create(#13#10' rule = "test" ; ');
  176. CheckToken(ttIdentifier,'rule','first');
  177. CheckToken(ttEquals,'','second');
  178. CheckToken(ttStringLiteral,'test','third');
  179. CheckToken(ttsemicolon,'','fourth');
  180. CheckToken(ttEOF,'', 'EOF');
  181. end;
  182. procedure TTestEBNFScanner.TestMultipleTokens;
  183. begin
  184. Scanner := TEBNFScanner.Create('grammar = rule { "|" rule } ;');
  185. CheckToken(ttIdentifier, 'grammar', 'first');
  186. CheckToken(ttEquals,'','second');
  187. CheckToken(ttIdentifier, 'rule', 'third');
  188. CheckToken(ttOpenBrace, '','fourth');
  189. CheckToken(ttStringLiteral, '|', 'fifth');
  190. CheckToken(ttIdentifier, 'rule', 'sixth');
  191. CheckToken(ttCloseBrace, '','seventh');
  192. CheckToken(ttSemicolon, '','eighth');
  193. CheckToken(ttEOF, '', 'EOF');
  194. end;
  195. procedure TTestEBNFScanner.TestUnknownTokenError;
  196. begin
  197. Scanner := TEBNFScanner.Create('@');
  198. try
  199. Scanner.GetNextToken;
  200. Fail('Expected an exception for unknown token');
  201. except
  202. on E: Exception do
  203. Check(Pos('Unknown token: "@"', E.Message) > 0, 'Expected "Unknown token: "@"" error message');
  204. end;
  205. end;
  206. procedure TTestEBNFScanner.TestUnterminatedStringError;
  207. begin
  208. Scanner := TEBNFScanner.Create('''unterminated');
  209. try
  210. Scanner.GetNextToken;
  211. Fail('Expected an exception for unterminated string');
  212. except
  213. on E: Exception do
  214. Check(Pos('Unterminated string literal', E.Message) > 0, 'Expected "Unterminated string literal" error message');
  215. end;
  216. end;
  217. initialization
  218. RegisterTest(TTestEBNFScanner);
  219. end.