tfpmasks.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. {$mode objfpc}
  2. program test;
  3. {$codepage utf8}
  4. uses classes, fpcunit, fpmasks;
  5. type
  6. { TTestMask }
  7. TTestMask = class
  8. private
  9. FS, FMask: Utf8String;
  10. procedure Test;
  11. procedure TestMask(const S, Mask: Utf8String; Result: Boolean);
  12. procedure TestMaskCaseInSensitive(const S, Mask: Utf8String; Result: Boolean);
  13. procedure TestMaskDisableRange(const S, Mask: Utf8String; Result: Boolean);
  14. procedure TestMaskAdvanced(const S, Mask: Utf8String; Result: Boolean);
  15. procedure TestMaskWindows(const S, Mask: Utf8String; Result: Boolean);
  16. procedure TestMaskWindowsNonDefaultQuirks(const S, Mask: Utf8String; Result: Boolean);
  17. procedure TestMaskException(const S, Mask: Utf8String; AFail: Boolean);
  18. public
  19. procedure TestMaskSyntax;
  20. procedure TestNil;
  21. procedure TestAnyText;
  22. procedure TestAnyChar;
  23. procedure TestCharSet;
  24. procedure TestDisableRange;
  25. procedure TestCase;
  26. procedure TestDefault;
  27. procedure TestAdvanced;
  28. procedure TestWindows;
  29. end;
  30. procedure TTestMask.Test;
  31. begin
  32. MatchesMask(FS, FMask);
  33. end;
  34. procedure TTestMask.TestMask(const S, Mask: Utf8String; Result: Boolean);
  35. begin
  36. TAssert.AssertEquals(S + ' match ' + Mask + ': ', Result, MatchesMask(S, Mask));
  37. end;
  38. procedure TTestMask.TestMaskCaseInSensitive(const S, Mask: Utf8String;
  39. Result: Boolean);
  40. begin
  41. TAssert.AssertEquals(S + ' match ' + Mask + ': ', Result, MatchesMask(S, Mask, False));
  42. end;
  43. procedure TTestMask.TestMaskDisableRange(const S, Mask: Utf8String; Result: Boolean);
  44. begin
  45. TAssert.AssertEquals(S + ' match ' + Mask + ': ', Result,
  46. MatchesMask(S, Mask, False, MaskOpCodesDisableRange));
  47. end;
  48. procedure TTestMask.TestMaskAdvanced(const S, Mask: Utf8String; Result: Boolean);
  49. begin
  50. TAssert.AssertEquals(S + ' match ' + Mask + ': ', Result,
  51. MatchesMask(S, Mask, False, AllMaskOpCodes));
  52. end;
  53. procedure TTestMask.TestMaskWindows(const S, Mask: Utf8String; Result: Boolean);
  54. begin
  55. TAssert.AssertEquals(S + ' match ' + Mask + ': ', Result, MatchesWindowsMask(S, Mask));
  56. end;
  57. procedure TTestMask.TestMaskWindowsNonDefaultQuirks(const S, Mask: Utf8String;
  58. Result: Boolean);
  59. begin
  60. TAssert.AssertEquals(S + ' match ' + Mask + ': ', Result, MatchesWindowsMask(S, Mask, False, DefaultMaskOpCodes, [wqFilenameEnd,wqExtension3More,wqAllByExtension]));
  61. end;
  62. procedure TTestMask.TestMaskException(const S, Mask: Utf8String; AFail: Boolean);
  63. begin
  64. FS := S;
  65. FMask := Mask;
  66. if AFail then
  67. TAssert.AssertException('Invalid syntax: ' + S + ' match ' + Mask + ': ', EMaskError, @Test)
  68. else
  69. try
  70. Test;
  71. except
  72. TAssert.Fail('Invalid syntax: ' + S + ' match ' + Mask);
  73. end;
  74. end;
  75. procedure TTestMask.TestMaskSyntax;
  76. begin
  77. TestMaskException('', '', False);
  78. TestMaskException('', 'a', False);
  79. TestMaskException('', '?', False);
  80. TestMaskException('', '*', False);
  81. TestMaskException('', '[a]', False);
  82. TestMaskException('', '[a-b]', False);
  83. TestMaskException('', '[!a-b]', False);
  84. TestMaskException('', '[abc]', False);
  85. TestMaskException('', '[abc-fgh]', False);
  86. TestMaskException('', '[a------h]', False);
  87. TestMaskException('', '**', False);
  88. TestMaskException('', 'aa', False);
  89. TestMaskException('', 'a*', False);
  90. TestMaskException('', '*a', False);
  91. TestMaskException('', '*?', False);
  92. TestMaskException('', '[', True);
  93. TestMaskException('', '[a', True);
  94. TestMaskException('', '[]', True);
  95. //TestMaskException('', '[!]', True);
  96. //TestMaskException('', '[-]', True);
  97. TestMaskException('', '[a-]', True);
  98. //TestMaskException('', '[-a]', True);
  99. //TestMaskException('', '[--a]', True);
  100. end;
  101. procedure TTestMask.TestNil;
  102. begin
  103. TestMask('', '', True);
  104. TestMask('', '*', True);
  105. TestMask('', '?', False);
  106. TestMask('', 'a', False);
  107. TestMask('', '[a]', False);
  108. TestMask('', 'ä', False);
  109. TestMask('', '[ä]', False);
  110. end;
  111. procedure TTestMask.TestAnyText;
  112. begin
  113. TestMask('abc', '*', True); // ASCII
  114. TestMask('abc', 'a*', True);
  115. TestMask('abc', '*c', True);
  116. TestMask('abc', '*a*', True);
  117. TestMask('abc', '*b*', True);
  118. TestMask('abc', '*c*', True);
  119. TestMask('abc', 'a*c', True);
  120. TestMask('abc', '*bc', True);
  121. TestMask('abc', 'ab*', True);
  122. TestMask('äöæ', '*', True); // Unicode
  123. TestMask('äöæ', 'ä*', True);
  124. TestMask('äöæ', '*æ', True);
  125. TestMask('äöæ', '*ä*', True);
  126. TestMask('äöæ', '*ö*', True);
  127. TestMask('äöæ', '*æ*', True);
  128. TestMask('äöæ', 'ä*æ', True);
  129. TestMask('äöæ', '*öæ', True);
  130. TestMask('äöæ', 'äö*', True);
  131. TestMask('abcde', '*', True); // ASCII
  132. TestMask('abcde', 'a*e', True);
  133. TestMask('abcde', 'a*b*e', True);
  134. TestMask('abcde', 'a*d*e', True);
  135. TestMask('abcde', 'a*c*e', True);
  136. TestMask('abcde', 'a*b*e', True);
  137. TestMask('abc.pas.bak', '*.bak', True);
  138. TestMask('äöæ獵豹☺', '*', True); // Unicode
  139. TestMask('äöæ獵豹☺', 'ä*☺', True);
  140. TestMask('äöæ獵豹☺', 'ä*ö*☺', True);
  141. TestMask('äöæ獵豹☺', 'ä*獵豹*☺', True);
  142. TestMask('äöæ獵豹☺', 'ä*æ*☺', True);
  143. TestMask('äöæ獵豹☺', 'ä*ö*☺', True);
  144. TestMask('abc', '*b', False); // ASCII
  145. TestMask('abc', 'b*', False);
  146. TestMask('abc', '*a', False);
  147. TestMask('abc', 'c*', False);
  148. TestMask('abc', 'ab*d', False);
  149. TestMask('äöæ', '*ö', False); // Unicode
  150. TestMask('äöæ', 'ö*', False);
  151. TestMask('äöæ', '*ä', False);
  152. TestMask('äöæ', 'æ*', False);
  153. TestMask('äöæ', 'äö*ũ', False);
  154. TestMask('abcde', 'a*d', False); // ASCII
  155. TestMask('abcde', 'a*c*d', False);
  156. TestMask('abcde', 'b*d*e', False);
  157. TestMask('abc.txt', '.*', False);
  158. TestMask('abc.txt', '*.', False);
  159. TestMask('abc', '*.', False);
  160. TestMask('abc.pas.bak', '*.pas', False);
  161. TestMask('äöæ獵豹☺', 'ä*獵豹', False); // Unicode
  162. TestMask('äöæ獵豹☺', 'ä*æ*獵豹', False);
  163. TestMask('äöæ獵豹☺', 'ö*獵豹*☺', False);
  164. end;
  165. procedure TTestMask.TestAnyChar;
  166. begin
  167. TestMask('abc', '?bc', True); // ASCII
  168. TestMask('abc', '?b?', True);
  169. TestMask('abc', '???', True);
  170. TestMask('äöæ', '?öæ', True); // Unicode
  171. TestMask('äöæ', '?ö?', True);
  172. TestMask('äöæ', '???', True);
  173. TestMask('abc', '?*?', True); // ASCII
  174. TestMask('abc', '?*??', True);
  175. TestMask('abc', '?*?*?', True);
  176. TestMask('äöæ', '?*?', True); // Unicode
  177. TestMask('äöæ', '?*??', True);
  178. TestMask('äöæ', '?*?*?', True);
  179. TestMask('abc', 'a?', False); // ASCII
  180. TestMask('abc', 'abc?', False);
  181. TestMask('abc', '?abc', False);
  182. TestMask('abc', '??*??', False);
  183. TestMask('abc', '?*?*??', False);
  184. TestMask('äöæ', 'ä?', False); // Unicode
  185. TestMask('äöæ', 'äöæ?', False);
  186. TestMask('äöæ', '?äöæ', False);
  187. TestMask('äöæ', '??*??', False);
  188. TestMask('äöæ', '?*?*??', False);
  189. end;
  190. procedure TTestMask.TestCharSet;
  191. begin
  192. TestMask('c', '[c]', True); // ASCII
  193. TestMask('c', '[!b]', True);
  194. TestMask('c', '[a-c]', True);
  195. TestMask('c', '[a-d]', True);
  196. TestMask('c', '[d-a]', True); // Reverse range
  197. TestMask('c', '[!a-b]', True);
  198. TestMask('c', '[abc]', True);
  199. TestMask('ö', '[ö]', True); // Unicode
  200. TestMask('ö', '[!ä]', True);
  201. TestMask('ö', '[ä-ũ]', True);
  202. TestMask('է', '[ՠ-կ]', True);
  203. TestMask('ö', '[!☺-☂]', True);
  204. TestMask('ö', '[äũö]', True);
  205. TestMask('c', '[a]', False); // ASCII
  206. TestMask('c', '[!c]', False);
  207. TestMask('c', '[a-b]', False);
  208. TestMask('c', '[z-d]', False); // Reverse range
  209. TestMask('c', '[abd]', False);
  210. TestMask('ö', '[ä]', False); // Unicode
  211. TestMask('ö', '[!ö]', False);
  212. TestMask('ö', '[ՠ-կ]', False);
  213. TestMask('ö', '[äũæ]', False);
  214. end;
  215. procedure TTestMask.TestDisableRange;
  216. begin
  217. TestMaskDisableRange('a[b]c', 'a[b]c', True); // [] is now literal.
  218. // Wildcard syntax should still work.
  219. TestMaskDisableRange('a[b]c', '?[b]?', True);
  220. TestMaskDisableRange('abc', 'a*', True);
  221. TestMaskDisableRange('abc', '?b?', True);
  222. TestMaskDisableRange('abc', '?[b]?', False);
  223. TestMaskDisableRange('c', '[c]', False);
  224. end;
  225. procedure TTestMask.TestCase;
  226. begin
  227. TestMaskCaseInsensitive('aBc', '?b?', True);
  228. TestMaskCaseInsensitive('äÖæ', 'Äö?', True);
  229. TestMaskCaseInsensitive('abcÖ', '*[äũö]', True);
  230. end;
  231. procedure TTestMask.TestDefault;
  232. begin
  233. TestMask('a?c', '?[?]?', True);
  234. TestMask('C:\x', 'C:\x', True);
  235. TestMask('a?c', '?\??', False);
  236. TestMask('ab*.x', '??\*.x', False);
  237. TestMask('x \ y', '? \\ ?', False);
  238. TestMask('abc', '?[?]?', False);
  239. TestMask('a??d', '?[?]?', False);
  240. end;
  241. procedure TTestMask.TestAdvanced;
  242. begin
  243. TestMaskAdvanced('a?c', '?[?]?', True);
  244. TestMaskAdvanced('abc', '?[?]?', True);
  245. TestMaskAdvanced('ac', '?[?]?', True);
  246. TestMaskAdvanced('a?c', '?\??', True);
  247. TestMaskAdvanced('ab*.x', '??\*.x', True);
  248. TestMaskAdvanced('a[c]d', '?\[*', True);
  249. TestMaskAdvanced('x \ y', '? \\ ?', True);
  250. TestMaskAdvanced('abcd', 'a[??]d', True);
  251. TestMaskAdvanced('abd', 'a[??]d', True);
  252. TestMaskAdvanced('ad', 'a[??]d', True);
  253. TestMaskAdvanced('C:\x', 'C:\x', False);
  254. TestMaskAdvanced('abcd', '?[?]?', False);
  255. end;
  256. procedure TTestMask.TestWindows;
  257. begin
  258. TestMaskWindows('abc.txt', '*.*', True);
  259. TestMaskWindows('abc', '*.*', True);
  260. TestMaskWindows('abc.txt', '*', True);
  261. TestMaskWindows('abc', '*', True);
  262. TestMaskWindows('abc', '*.', True);
  263. TestMaskWindows('abcd.txt', 'abc???.*', False);
  264. TestMaskWindows('abcd.txt', 'abc???.txt?', False);
  265. TestMaskWindowsNonDefaultQuirks('abcd.txt', 'abc???.*', True);
  266. TestMaskWindowsNonDefaultQuirks('abcd.txt', 'abc???.txt?', True);
  267. TestMaskWindows('abcd.txt', 'abc*', True);
  268. TestMaskWindows('abc.pas.bak', '*.bak', True);
  269. TestMaskWindows('C:\x', 'C:\x', True);
  270. TestMaskWindows('C:\ab[c]d', 'C:*[*]*', False); //sets and ranges are enabled by default on TWindowsMask as well
  271. TestMaskWindows('', '*', True);
  272. TestMaskWindows('', '?', False);
  273. TestMaskWindowsNonDefaultQuirks('', '?', True); //requires wqFileNameEnd
  274. TestMaskWindows('abcd.txt', '*.txtx', False);
  275. TestMaskWindows('abc.txt', '*.', False);
  276. TestMaskWindows('abc.txt', '.*', False);
  277. TestMaskWindows('abc.pas.bak', '*.pas', False);
  278. TestMaskWindows('abc', '.*', False);
  279. TestMaskWindows('x \ y', '? \\ ?', False);
  280. TestMaskWindows('', 'a', False);
  281. TestMaskWindows('', '[a]', False);
  282. TestMaskWindows('foo','foo.*',True);
  283. end;
  284. var
  285. TestMask: TTestMask;
  286. begin
  287. system.FileNameCaseSensitive:=true;
  288. TestMask := TTestMask.Create;
  289. try
  290. TestMask.TestMaskSyntax;
  291. TestMask.TestNil;
  292. TestMask.TestAnyText;
  293. TestMask.TestAnyChar;
  294. TestMask.TestCharSet;
  295. TestMask.TestDisableRange;
  296. TestMask.TestCase;
  297. TestMask.TestDefault;
  298. TestMask.TestAdvanced;
  299. TestMask.TestWindows;
  300. finally
  301. TestMask.Free;
  302. end;
  303. end.