utcexprparsscanner.pp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. unit utcExprParsScanner;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, punit, math, fpexprpars;
  6. procedure RegisterTests(aTop : PSuite);
  7. implementation
  8. uses typinfo;
  9. var
  10. FP: TFPExpressionScanner;
  11. FInvalidString: String;
  12. function TestExpressionScanner_SetUp : string;
  13. begin
  14. Result:='';
  15. FP := TFPExpressionScanner.Create;
  16. end;
  17. function TestExpressionScanner_TearDown : string;
  18. begin
  19. Result:='';
  20. FreeAndNil(FP);
  21. end;
  22. procedure AssertEqualsToken(Msg: String; AExpected, AActual: TTokenType);
  23. var
  24. S1, S2: String;
  25. begin
  26. S1 := TokenName(AExpected);
  27. S2 := GetEnumName(TypeInfo(TTokenType), Ord(AActual));
  28. AssertEquals(Msg, S1, S2);
  29. end;
  30. procedure TestString(const AString: String; AToken: TTokenType);
  31. begin
  32. FP.Source := AString;
  33. AssertEqualsToken('String "' + AString + '" results in token ' + TokenName(AToken), AToken, FP.GetToken);
  34. if not (FP.TokenType in [ttString, ttEOF]) then
  35. AssertEquals('String "' + AString + '" results in token string ' + TokenName(AToken), AString, FP.Token)
  36. else if FP.TokenType = ttString then
  37. AssertEquals('String "' + AString + '" results in token string ' + TokenName(AToken),
  38. StringReplace(AString, '''''', '''', [rfReplaceAll]),
  39. '''' + FP.Token + '''');
  40. end;
  41. function TestExpressionScanner_TestCreate: TTestString;
  42. begin
  43. Result := '';
  44. AssertEquals('Empty source', '', FP.Source);
  45. AssertEquals('Pos is zero', 0, FP.Pos);
  46. AssertEquals('CurrentChar is zero', #0, FP.CurrentChar);
  47. AssertEqualsToken('Current token type is EOF', ttEOF, FP.TokenType);
  48. AssertEquals('Current token is empty', '', FP.Token);
  49. end;
  50. function TestExpressionScanner_TestSetSource: TTestString;
  51. begin
  52. Result := '';
  53. FP.Source := 'Abc';
  54. FP.Source := '';
  55. AssertEquals('Empty source', '', FP.Source);
  56. AssertEquals('Pos is zero', 0, FP.Pos);
  57. AssertEquals('CurrentChar is zero', #0, FP.CurrentChar);
  58. AssertEqualsToken('Current token type is EOF', ttEOF, FP.TokenType);
  59. AssertEquals('Current token is empty', '', FP.Token);
  60. end;
  61. function TestExpressionScanner_TestWhiteSpace: TTestString;
  62. begin
  63. Result := '';
  64. TestString(' ', ttEOF);
  65. end;
  66. function TestExpressionScanner_TestTokens: TTestString;
  67. const
  68. TestStrings: array[TTokenType] of String =
  69. ('+', '-', '<', '>', '=', '/',
  70. 'mod', '*', '(', ')', '<=',
  71. '>=', '<>', '1', '''abc''', 'abc',
  72. ',', 'and', 'or', 'xor', 'true', 'false', 'not',
  73. 'if', 'case', '^', '');
  74. var
  75. t: TTokenType;
  76. begin
  77. Result := '';
  78. for t := Low(TTokenType) to High(TTokenType) do
  79. TestString(TestStrings[t], t);
  80. end;
  81. procedure DoInvalidNumber(AString: String);
  82. begin
  83. FInvalidString := AString;
  84. raise EExprScanner.Create('Invalid number');
  85. end;
  86. var
  87. TestProcToRun: TTestRunProc;
  88. function RunTestProc: TTestString;
  89. begin
  90. Result := '';
  91. if Assigned(TestProcToRun) then
  92. TestProcToRun;
  93. end;
  94. procedure DoTestInvalidNumberGG;
  95. begin
  96. DoInvalidNumber('$GG');
  97. end;
  98. procedure DoTestInvalidNumber88;
  99. begin
  100. DoInvalidNumber('&88');
  101. end;
  102. procedure DoTestInvalidNumber22;
  103. begin
  104. DoInvalidNumber('%22');
  105. end;
  106. procedure DoTestInvalidNumber11;
  107. begin
  108. DoInvalidNumber('1..1');
  109. end;
  110. procedure DoTestInvalidNumber1E;
  111. begin
  112. DoInvalidNumber('1.E--1');
  113. end;
  114. function TestExpressionScanner_TestNumber: TTestString;
  115. begin
  116. Result := '';
  117. TestString('123', ttNumber);
  118. TestString('$FF', ttNumber);
  119. TestString('&77', ttNumber);
  120. TestString('%11111111', ttNumber);
  121. TestString('123.4', ttNumber);
  122. TestString('123.E4', ttNumber);
  123. TestString('1.E4', ttNumber);
  124. TestString('1e-2', ttNumber);
  125. TestProcToRun := @DoTestInvalidNumberGG;
  126. AssertException('Invalid number "$GG"', EExprScanner, @RunTestProc);
  127. TestProcToRun := @DoTestInvalidNumber88;
  128. AssertException('Invalid number "&88"', EExprScanner, @RunTestProc);
  129. TestProcToRun := @DoTestInvalidNumber22;
  130. AssertException('Invalid number "%22"', EExprScanner, @RunTestProc);
  131. TestProcToRun := @DoTestInvalidNumber11;
  132. AssertException('Invalid number "1..1"', EExprScanner, @RunTestProc);
  133. TestProcToRun := @DoTestInvalidNumber1E;
  134. AssertException('Invalid number "1.E--1"', EExprScanner, @RunTestProc);
  135. end;
  136. procedure DoTestInvalidCharTilde;
  137. begin
  138. DoInvalidNumber('~');
  139. end;
  140. procedure DoTestInvalidCharHash;
  141. begin
  142. DoInvalidNumber('#');
  143. end;
  144. procedure DoTestInvalidCharDollar;
  145. begin
  146. DoInvalidNumber('$');
  147. end;
  148. function TestExpressionScanner_TestInvalidCharacter: TTestString;
  149. begin
  150. Result := '';
  151. TestProcToRun := @DoTestInvalidCharTilde;
  152. AssertException('Invalid character "~"', EExprScanner, @RunTestProc);
  153. TestProcToRun := @DoTestInvalidCharHash;
  154. AssertException('Invalid character "#"', EExprScanner, @RunTestProc);
  155. TestProcToRun := @DoTestInvalidCharDollar;
  156. AssertException('Invalid character "$"', EExprScanner, @RunTestProc);
  157. end;
  158. procedure DoTestUnterminatedString;
  159. begin
  160. DoInvalidNumber('''abc');
  161. end;
  162. function TestExpressionScanner_TestUnterminatedString: TTestString;
  163. begin
  164. Result := '';
  165. TestProcToRun := @DoTestUnterminatedString;
  166. AssertException('Unterminated string', EExprScanner, @RunTestProc);
  167. end;
  168. function TestExpressionScanner_TestQuotesInString: TTestString;
  169. begin
  170. Result := '';
  171. TestString('''That''''s it''', ttString);
  172. TestString('''''''s it''', ttString);
  173. TestString('''s it''''''', ttString);
  174. end;
  175. procedure TestIdentifier(const ASource, ATokenName: String);
  176. begin
  177. FP.Source := ASource;
  178. AssertEqualsToken('Token type', ttIdentifier, FP.GetToken);
  179. AssertEquals('Token name', ATokenName, FP.Token);
  180. end;
  181. function TestExpressionScanner_TestIdentifiers: TTestString;
  182. begin
  183. Result := '';
  184. TestIdentifier('a', 'a');
  185. TestIdentifier(' a', 'a');
  186. TestIdentifier('a ', 'a');
  187. TestIdentifier('a^b', 'a');
  188. TestIdentifier('a-b', 'a');
  189. TestIdentifier('a.b', 'a.b');
  190. TestIdentifier('"a b"', 'a b');
  191. TestIdentifier('c."a b"', 'c.a b');
  192. TestIdentifier('c."ab"', 'c.ab');
  193. end;
  194. procedure RegisterTests(aTop : PSuite);
  195. begin
  196. AddSuite('TExpressionScannerTests', @TestExpressionScanner_SetUp, @TestExpressionScanner_TearDown, aTop, True);
  197. AddTest('TestCreate', @TestExpressionScanner_TestCreate, 'TExpressionScannerTests');
  198. AddTest('TestSetSource', @TestExpressionScanner_TestSetSource, 'TExpressionScannerTests');
  199. AddTest('TestWhiteSpace', @TestExpressionScanner_TestWhiteSpace, 'TExpressionScannerTests');
  200. AddTest('TestTokens', @TestExpressionScanner_TestTokens, 'TExpressionScannerTests');
  201. AddTest('TestNumber', @TestExpressionScanner_TestNumber, 'TExpressionScannerTests');
  202. AddTest('TestInvalidCharacter', @TestExpressionScanner_TestInvalidCharacter, 'TExpressionScannerTests');
  203. AddTest('TestUnterminatedString', @TestExpressionScanner_TestUnterminatedString, 'TExpressionScannerTests');
  204. AddTest('TestQuotesInString', @TestExpressionScanner_TestQuotesInString, 'TExpressionScannerTests');
  205. AddTest('TestIdentifiers', @TestExpressionScanner_TestIdentifiers, 'TExpressionScannerTests');
  206. end;
  207. end.