testexcludedfiles.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /*
  2. * This software is in the public domain, furnished "as is", without technical
  3. * support, and with no warranty, express or implied, as to its usefulness for
  4. * any purpose.
  5. *
  6. */
  7. #include <QtTest>
  8. #include <QTemporaryDir>
  9. #include "csync_exclude.h"
  10. using namespace OCC;
  11. #define EXCLUDE_LIST_FILE SOURCEDIR "/../../sync-exclude.lst"
  12. // The tests were converted from the old CMocka framework, that's why there is a global
  13. static QScopedPointer<ExcludedFiles> excludedFiles;
  14. static void setup() {
  15. excludedFiles.reset(new ExcludedFiles);
  16. excludedFiles->setWildcardsMatchSlash(false);
  17. }
  18. static void setup_init() {
  19. setup();
  20. excludedFiles->addExcludeFilePath(EXCLUDE_LIST_FILE);
  21. QVERIFY(excludedFiles->reloadExcludeFiles());
  22. /* and add some unicode stuff */
  23. excludedFiles->addManualExclude("*.💩"); // is this source file utf8 encoded?
  24. excludedFiles->addManualExclude("пятницы.*");
  25. excludedFiles->addManualExclude("*/*.out");
  26. excludedFiles->addManualExclude("latex*/*.run.xml");
  27. excludedFiles->addManualExclude("latex/*/*.tex.tmp");
  28. QVERIFY(excludedFiles->reloadExcludeFiles());
  29. }
  30. class TestExcludedFiles: public QObject
  31. {
  32. Q_OBJECT
  33. static auto check_file_full(const char *path)
  34. {
  35. return excludedFiles->fullPatternMatch(path, ItemTypeFile);
  36. }
  37. static auto check_dir_full(const char *path)
  38. {
  39. return excludedFiles->fullPatternMatch(path, ItemTypeDirectory);
  40. }
  41. static auto check_file_traversal(const char *path)
  42. {
  43. return excludedFiles->traversalPatternMatch(path, ItemTypeFile);
  44. }
  45. static auto check_dir_traversal(const char *path)
  46. {
  47. return excludedFiles->traversalPatternMatch(path, ItemTypeDirectory);
  48. }
  49. private slots:
  50. void testFun()
  51. {
  52. ExcludedFiles excluded;
  53. bool excludeHidden = true;
  54. bool keepHidden = false;
  55. QVERIFY(!excluded.isExcluded("/a/b", "/a", keepHidden));
  56. QVERIFY(!excluded.isExcluded("/a/b~", "/a", keepHidden));
  57. QVERIFY(!excluded.isExcluded("/a/.b", "/a", keepHidden));
  58. QVERIFY(excluded.isExcluded("/a/.b", "/a", excludeHidden));
  59. excluded.addExcludeFilePath(EXCLUDE_LIST_FILE);
  60. excluded.reloadExcludeFiles();
  61. QVERIFY(!excluded.isExcluded("/a/b", "/a", keepHidden));
  62. QVERIFY(excluded.isExcluded("/a/b~", "/a", keepHidden));
  63. QVERIFY(!excluded.isExcluded("/a/.b", "/a", keepHidden));
  64. QVERIFY(excluded.isExcluded("/a/.Trashes", "/a", keepHidden));
  65. QVERIFY(excluded.isExcluded("/a/foo_conflict-bar", "/a", keepHidden));
  66. QVERIFY(excluded.isExcluded("/a/foo (conflicted copy bar)", "/a", keepHidden));
  67. QVERIFY(excluded.isExcluded("/a/.b", "/a", excludeHidden));
  68. QVERIFY(excluded.isExcluded("/a/#b#", "/a", keepHidden));
  69. }
  70. void check_csync_exclude_add()
  71. {
  72. setup();
  73. excludedFiles->addManualExclude("/tmp/check_csync1/*");
  74. QCOMPARE(check_file_full("/tmp/check_csync1/foo"), CSYNC_FILE_EXCLUDE_LIST);
  75. QCOMPARE(check_file_full("/tmp/check_csync2/foo"), CSYNC_NOT_EXCLUDED);
  76. QVERIFY(excludedFiles->_allExcludes[QStringLiteral("/")].contains("/tmp/check_csync1/*"));
  77. QVERIFY(excludedFiles->_fullRegexFile[QStringLiteral("/")].pattern().contains("csync1"));
  78. QVERIFY(excludedFiles->_fullTraversalRegexFile[QStringLiteral("/")].pattern().contains("csync1"));
  79. QVERIFY(!excludedFiles->_bnameTraversalRegexFile[QStringLiteral("/")].pattern().contains("csync1"));
  80. excludedFiles->addManualExclude("foo");
  81. QVERIFY(excludedFiles->_bnameTraversalRegexFile[QStringLiteral("/")].pattern().contains("foo"));
  82. QVERIFY(excludedFiles->_fullRegexFile[QStringLiteral("/")].pattern().contains("foo"));
  83. QVERIFY(!excludedFiles->_fullTraversalRegexFile[QStringLiteral("/")].pattern().contains("foo"));
  84. }
  85. void check_csync_exclude_add_per_dir()
  86. {
  87. setup();
  88. excludedFiles->addManualExclude("*", "/tmp/check_csync1/");
  89. QCOMPARE(check_file_full("/tmp/check_csync1/foo"), CSYNC_FILE_EXCLUDE_LIST);
  90. QCOMPARE(check_file_full("/tmp/check_csync2/foo"), CSYNC_NOT_EXCLUDED);
  91. QVERIFY(excludedFiles->_allExcludes[QStringLiteral("/tmp/check_csync1/")].contains("*"));
  92. excludedFiles->addManualExclude("foo");
  93. QVERIFY(excludedFiles->_fullRegexFile[QStringLiteral("/")].pattern().contains("foo"));
  94. excludedFiles->addManualExclude("foo/bar", "/tmp/check_csync1/");
  95. QVERIFY(excludedFiles->_fullRegexFile[QStringLiteral("/tmp/check_csync1/")].pattern().contains("bar"));
  96. QVERIFY(excludedFiles->_fullTraversalRegexFile[QStringLiteral("/tmp/check_csync1/")].pattern().contains("bar"));
  97. QVERIFY(!excludedFiles->_bnameTraversalRegexFile[QStringLiteral("/tmp/check_csync1/")].pattern().contains("foo"));
  98. }
  99. void check_csync_excluded()
  100. {
  101. setup_init();
  102. QCOMPARE(check_file_full(""), CSYNC_NOT_EXCLUDED);
  103. QCOMPARE(check_file_full("/"), CSYNC_NOT_EXCLUDED);
  104. QCOMPARE(check_file_full("A"), CSYNC_NOT_EXCLUDED);
  105. QCOMPARE(check_file_full("krawel_krawel"), CSYNC_NOT_EXCLUDED);
  106. QCOMPARE(check_file_full(".kde/share/config/kwin.eventsrc"), CSYNC_NOT_EXCLUDED);
  107. QCOMPARE(check_file_full(".directory/cache-maximegalon/cache1.txt"), CSYNC_FILE_EXCLUDE_LIST);
  108. QCOMPARE(check_dir_full("mozilla/.directory"), CSYNC_FILE_EXCLUDE_LIST);
  109. /*
  110. * Test for patterns in subdirs. '.beagle' is defined as a pattern and has
  111. * to be found in top dir as well as in directories underneath.
  112. */
  113. QCOMPARE(check_dir_full(".apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  114. QCOMPARE(check_dir_full("foo/.apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  115. QCOMPARE(check_dir_full("foo/bar/.apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  116. QCOMPARE(check_file_full(".java"), CSYNC_NOT_EXCLUDED);
  117. /* Files in the ignored dir .java will also be ignored. */
  118. QCOMPARE(check_file_full(".apdisk/totally_amazing.jar"), CSYNC_FILE_EXCLUDE_LIST);
  119. /* and also in subdirs */
  120. QCOMPARE(check_file_full("projects/.apdisk/totally_amazing.jar"), CSYNC_FILE_EXCLUDE_LIST);
  121. /* csync-journal is ignored in general silently. */
  122. QCOMPARE(check_file_full(".csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  123. QCOMPARE(check_file_full(".csync_journal.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  124. QCOMPARE(check_file_full("subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  125. /* also the new form of the database name */
  126. QCOMPARE(check_file_full("._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  127. QCOMPARE(check_file_full("._sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  128. QCOMPARE(check_file_full("._sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED);
  129. QCOMPARE(check_file_full("subdir/._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  130. QCOMPARE(check_file_full(".sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  131. QCOMPARE(check_file_full(".sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  132. QCOMPARE(check_file_full(".sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED);
  133. QCOMPARE(check_file_full("subdir/.sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  134. /* pattern ]*.directory - ignore and remove */
  135. QCOMPARE(check_file_full("my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE);
  136. QCOMPARE(check_file_full("/a_folder/my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE);
  137. /* Not excluded because the pattern .netscape/cache requires directory. */
  138. QCOMPARE(check_file_full(".netscape/cache"), CSYNC_NOT_EXCLUDED);
  139. /* Not excluded */
  140. QCOMPARE(check_file_full("unicode/中文.hé"), CSYNC_NOT_EXCLUDED);
  141. /* excluded */
  142. QCOMPARE(check_file_full("unicode/пятницы.txt"), CSYNC_FILE_EXCLUDE_LIST);
  143. QCOMPARE(check_file_full("unicode/中文.💩"), CSYNC_FILE_EXCLUDE_LIST);
  144. /* path wildcards */
  145. QCOMPARE(check_file_full("foobar/my_manuscript.out"), CSYNC_FILE_EXCLUDE_LIST);
  146. QCOMPARE(check_file_full("latex_tmp/my_manuscript.run.xml"), CSYNC_FILE_EXCLUDE_LIST);
  147. QCOMPARE(check_file_full("word_tmp/my_manuscript.run.xml"), CSYNC_NOT_EXCLUDED);
  148. QCOMPARE(check_file_full("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED);
  149. QCOMPARE(check_file_full("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST);
  150. #ifdef _WIN32
  151. QCOMPARE(check_file_full("file_trailing_space "), CSYNC_FILE_EXCLUDE_TRAILING_SPACE);
  152. QCOMPARE(check_file_full("file_trailing_dot."), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  153. QCOMPARE(check_file_full("AUX"), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  154. QCOMPARE(check_file_full("file_invalid_char<"), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  155. QCOMPARE(check_file_full("file_invalid_char\n"), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  156. #endif
  157. /* ? character */
  158. excludedFiles->addManualExclude("bond00?");
  159. excludedFiles->reloadExcludeFiles();
  160. QCOMPARE(check_file_full("bond00"), CSYNC_NOT_EXCLUDED);
  161. QCOMPARE(check_file_full("bond007"), CSYNC_FILE_EXCLUDE_LIST);
  162. QCOMPARE(check_file_full("bond0071"), CSYNC_NOT_EXCLUDED);
  163. /* brackets */
  164. excludedFiles->addManualExclude("a [bc] d");
  165. excludedFiles->reloadExcludeFiles();
  166. QCOMPARE(check_file_full("a d d"), CSYNC_NOT_EXCLUDED);
  167. QCOMPARE(check_file_full("a d"), CSYNC_NOT_EXCLUDED);
  168. QCOMPARE(check_file_full("a b d"), CSYNC_FILE_EXCLUDE_LIST);
  169. QCOMPARE(check_file_full("a c d"), CSYNC_FILE_EXCLUDE_LIST);
  170. #ifndef Q_OS_WIN // Because of CSYNC_FILE_EXCLUDE_INVALID_CHAR on windows
  171. /* escapes */
  172. excludedFiles->addManualExclude("a \\*");
  173. excludedFiles->addManualExclude("b \\?");
  174. excludedFiles->addManualExclude("c \\[d]");
  175. excludedFiles->reloadExcludeFiles();
  176. QCOMPARE(check_file_full("a \\*"), CSYNC_NOT_EXCLUDED);
  177. QCOMPARE(check_file_full("a bc"), CSYNC_NOT_EXCLUDED);
  178. QCOMPARE(check_file_full("a *"), CSYNC_FILE_EXCLUDE_LIST);
  179. QCOMPARE(check_file_full("b \\?"), CSYNC_NOT_EXCLUDED);
  180. QCOMPARE(check_file_full("b f"), CSYNC_NOT_EXCLUDED);
  181. QCOMPARE(check_file_full("b ?"), CSYNC_FILE_EXCLUDE_LIST);
  182. QCOMPARE(check_file_full("c \\[d]"), CSYNC_NOT_EXCLUDED);
  183. QCOMPARE(check_file_full("c d"), CSYNC_NOT_EXCLUDED);
  184. QCOMPARE(check_file_full("c [d]"), CSYNC_FILE_EXCLUDE_LIST);
  185. #endif
  186. }
  187. void check_csync_excluded_per_dir()
  188. {
  189. setup();
  190. excludedFiles->addManualExclude("A");
  191. excludedFiles->reloadExcludeFiles();
  192. QCOMPARE(check_file_full("A"), CSYNC_FILE_EXCLUDE_LIST);
  193. excludedFiles->clearManualExcludes();
  194. excludedFiles->addManualExclude("A", "/B/");
  195. excludedFiles->reloadExcludeFiles();
  196. QCOMPARE(check_file_full("A"), CSYNC_NOT_EXCLUDED);
  197. QCOMPARE(check_file_full("B/A"), CSYNC_FILE_EXCLUDE_LIST);
  198. excludedFiles->clearManualExcludes();
  199. excludedFiles->addManualExclude("A/a1", "/B/");
  200. excludedFiles->reloadExcludeFiles();
  201. QCOMPARE(check_file_full("A"), CSYNC_NOT_EXCLUDED);
  202. QCOMPARE(check_file_full("B/A/a1"), CSYNC_FILE_EXCLUDE_LIST);
  203. #define FOO_DIR "/tmp/check_csync1/foo"
  204. #define FOO_EXCLUDE_LIST FOO_DIR "/.sync-exclude.lst"
  205. int rc = 0;
  206. rc = system("mkdir -p " FOO_DIR);
  207. QCOMPARE(rc, 0);
  208. FILE *fh = fopen(FOO_EXCLUDE_LIST, "w");
  209. QVERIFY(fh != nullptr);
  210. rc = fprintf(fh, "bar");
  211. QVERIFY(rc != 0);
  212. rc = fclose(fh);
  213. QCOMPARE(rc, 0);
  214. excludedFiles->addInTreeExcludeFilePath(FOO_EXCLUDE_LIST);
  215. excludedFiles->reloadExcludeFiles();
  216. QCOMPARE(check_file_full(FOO_DIR), CSYNC_NOT_EXCLUDED);
  217. QCOMPARE(check_file_full(FOO_DIR "/bar"), CSYNC_FILE_EXCLUDE_LIST);
  218. QCOMPARE(check_file_full(FOO_DIR "/baz"), CSYNC_NOT_EXCLUDED);
  219. #undef FOO_DIR
  220. #undef FOO_EXCLUDE_LIST
  221. }
  222. void check_csync_excluded_traversal_per_dir()
  223. {
  224. setup_init();
  225. QCOMPARE(check_file_traversal("/"), CSYNC_NOT_EXCLUDED);
  226. /* path wildcards */
  227. excludedFiles->addManualExclude("*/*.tex.tmp", "/latex/");
  228. QCOMPARE(check_file_traversal("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED);
  229. QCOMPARE(check_file_traversal("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST);
  230. }
  231. void check_csync_excluded_traversal()
  232. {
  233. setup_init();
  234. QCOMPARE(check_file_traversal(""), CSYNC_NOT_EXCLUDED);
  235. QCOMPARE(check_file_traversal("/"), CSYNC_NOT_EXCLUDED);
  236. QCOMPARE(check_file_traversal("A"), CSYNC_NOT_EXCLUDED);
  237. QCOMPARE(check_file_traversal("krawel_krawel"), CSYNC_NOT_EXCLUDED);
  238. QCOMPARE(check_file_traversal(".kde/share/config/kwin.eventsrc"), CSYNC_NOT_EXCLUDED);
  239. QCOMPARE(check_dir_traversal("mozilla/.directory"), CSYNC_FILE_EXCLUDE_LIST);
  240. /*
  241. * Test for patterns in subdirs. '.beagle' is defined as a pattern and has
  242. * to be found in top dir as well as in directories underneath.
  243. */
  244. QCOMPARE(check_dir_traversal(".apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  245. QCOMPARE(check_dir_traversal("foo/.apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  246. QCOMPARE(check_dir_traversal("foo/bar/.apdisk"), CSYNC_FILE_EXCLUDE_LIST);
  247. QCOMPARE(check_file_traversal(".java"), CSYNC_NOT_EXCLUDED);
  248. /* csync-journal is ignored in general silently. */
  249. QCOMPARE(check_file_traversal(".csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  250. QCOMPARE(check_file_traversal(".csync_journal.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  251. QCOMPARE(check_file_traversal("subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  252. QCOMPARE(check_file_traversal("/two/subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  253. /* also the new form of the database name */
  254. QCOMPARE(check_file_traversal("._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  255. QCOMPARE(check_file_traversal("._sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  256. QCOMPARE(check_file_traversal("._sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED);
  257. QCOMPARE(check_file_traversal("subdir/._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  258. QCOMPARE(check_file_traversal(".sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  259. QCOMPARE(check_file_traversal(".sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED);
  260. QCOMPARE(check_file_traversal(".sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED);
  261. QCOMPARE(check_file_traversal("subdir/.sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED);
  262. /* Other builtin excludes */
  263. QCOMPARE(check_file_traversal("foo/Desktop.ini"), CSYNC_NOT_EXCLUDED);
  264. QCOMPARE(check_file_traversal("Desktop.ini"), CSYNC_FILE_SILENTLY_EXCLUDED);
  265. /* pattern ]*.directory - ignore and remove */
  266. QCOMPARE(check_file_traversal("my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE);
  267. QCOMPARE(check_file_traversal("/a_folder/my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE);
  268. /* Not excluded because the pattern .netscape/cache requires directory. */
  269. QCOMPARE(check_file_traversal(".netscape/cache"), CSYNC_NOT_EXCLUDED);
  270. /* Not excluded */
  271. QCOMPARE(check_file_traversal("unicode/中文.hé"), CSYNC_NOT_EXCLUDED);
  272. /* excluded */
  273. QCOMPARE(check_file_traversal("unicode/пятницы.txt"), CSYNC_FILE_EXCLUDE_LIST);
  274. QCOMPARE(check_file_traversal("unicode/中文.💩"), CSYNC_FILE_EXCLUDE_LIST);
  275. /* path wildcards */
  276. QCOMPARE(check_file_traversal("foobar/my_manuscript.out"), CSYNC_FILE_EXCLUDE_LIST);
  277. QCOMPARE(check_file_traversal("latex_tmp/my_manuscript.run.xml"), CSYNC_FILE_EXCLUDE_LIST);
  278. QCOMPARE(check_file_traversal("word_tmp/my_manuscript.run.xml"), CSYNC_NOT_EXCLUDED);
  279. QCOMPARE(check_file_traversal("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED);
  280. QCOMPARE(check_file_traversal("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST);
  281. #ifdef _WIN32
  282. QCOMPARE(check_file_traversal("file_trailing_space "), CSYNC_FILE_EXCLUDE_TRAILING_SPACE);
  283. QCOMPARE(check_file_traversal("file_trailing_dot."), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  284. QCOMPARE(check_file_traversal("AUX"), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  285. QCOMPARE(check_file_traversal("file_invalid_char<"), CSYNC_FILE_EXCLUDE_INVALID_CHAR);
  286. #endif
  287. /* From here the actual traversal tests */
  288. excludedFiles->addManualExclude("/exclude");
  289. excludedFiles->reloadExcludeFiles();
  290. /* Check toplevel dir, the pattern only works for toplevel dir. */
  291. QCOMPARE(check_dir_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST);
  292. QCOMPARE(check_dir_traversal("/foo/exclude"), CSYNC_NOT_EXCLUDED);
  293. /* check for a file called exclude. Must still work */
  294. QCOMPARE(check_file_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST);
  295. QCOMPARE(check_file_traversal("/foo/exclude"), CSYNC_NOT_EXCLUDED);
  296. /* Add an exclude for directories only: excl/ */
  297. excludedFiles->addManualExclude("excl/");
  298. excludedFiles->reloadExcludeFiles();
  299. QCOMPARE(check_dir_traversal("/excl"), CSYNC_FILE_EXCLUDE_LIST);
  300. QCOMPARE(check_dir_traversal("meep/excl"), CSYNC_FILE_EXCLUDE_LIST);
  301. // because leading dirs aren't checked!
  302. QCOMPARE(check_file_traversal("meep/excl/file"), CSYNC_NOT_EXCLUDED);
  303. QCOMPARE(check_file_traversal("/excl"), CSYNC_NOT_EXCLUDED);
  304. excludedFiles->addManualExclude("/excludepath/withsubdir");
  305. excludedFiles->reloadExcludeFiles();
  306. QCOMPARE(check_dir_traversal("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST);
  307. QCOMPARE(check_file_traversal("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST);
  308. QCOMPARE(check_dir_traversal("/excludepath/withsubdir2"), CSYNC_NOT_EXCLUDED);
  309. // because leading dirs aren't checked!
  310. QCOMPARE(check_dir_traversal("/excludepath/withsubdir/foo"), CSYNC_NOT_EXCLUDED);
  311. /* Check ending of pattern */
  312. QCOMPARE(check_file_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST);
  313. QCOMPARE(check_file_traversal("/excludeX"), CSYNC_NOT_EXCLUDED);
  314. QCOMPARE(check_file_traversal("exclude"), CSYNC_NOT_EXCLUDED);
  315. excludedFiles->addManualExclude("exclude");
  316. excludedFiles->reloadExcludeFiles();
  317. QCOMPARE(check_file_traversal("exclude"), CSYNC_FILE_EXCLUDE_LIST);
  318. /* ? character */
  319. excludedFiles->addManualExclude("bond00?");
  320. excludedFiles->reloadExcludeFiles();
  321. QCOMPARE(check_file_traversal("bond00"), CSYNC_NOT_EXCLUDED);
  322. QCOMPARE(check_file_traversal("bond007"), CSYNC_FILE_EXCLUDE_LIST);
  323. QCOMPARE(check_file_traversal("bond0071"), CSYNC_NOT_EXCLUDED);
  324. /* brackets */
  325. excludedFiles->addManualExclude("a [bc] d");
  326. excludedFiles->reloadExcludeFiles();
  327. QCOMPARE(check_file_traversal("a d d"), CSYNC_NOT_EXCLUDED);
  328. QCOMPARE(check_file_traversal("a d"), CSYNC_NOT_EXCLUDED);
  329. QCOMPARE(check_file_traversal("a b d"), CSYNC_FILE_EXCLUDE_LIST);
  330. QCOMPARE(check_file_traversal("a c d"), CSYNC_FILE_EXCLUDE_LIST);
  331. #ifndef Q_OS_WIN // Because of CSYNC_FILE_EXCLUDE_INVALID_CHAR on windows
  332. /* escapes */
  333. excludedFiles->addManualExclude("a \\*");
  334. excludedFiles->addManualExclude("b \\?");
  335. excludedFiles->addManualExclude("c \\[d]");
  336. excludedFiles->reloadExcludeFiles();
  337. QCOMPARE(check_file_traversal("a \\*"), CSYNC_NOT_EXCLUDED);
  338. QCOMPARE(check_file_traversal("a bc"), CSYNC_NOT_EXCLUDED);
  339. QCOMPARE(check_file_traversal("a *"), CSYNC_FILE_EXCLUDE_LIST);
  340. QCOMPARE(check_file_traversal("b \\?"), CSYNC_NOT_EXCLUDED);
  341. QCOMPARE(check_file_traversal("b f"), CSYNC_NOT_EXCLUDED);
  342. QCOMPARE(check_file_traversal("b ?"), CSYNC_FILE_EXCLUDE_LIST);
  343. QCOMPARE(check_file_traversal("c \\[d]"), CSYNC_NOT_EXCLUDED);
  344. QCOMPARE(check_file_traversal("c d"), CSYNC_NOT_EXCLUDED);
  345. QCOMPARE(check_file_traversal("c [d]"), CSYNC_FILE_EXCLUDE_LIST);
  346. #endif
  347. }
  348. void check_csync_dir_only()
  349. {
  350. setup();
  351. excludedFiles->addManualExclude("filedir");
  352. excludedFiles->addManualExclude("dir/");
  353. QCOMPARE(check_file_traversal("other"), CSYNC_NOT_EXCLUDED);
  354. QCOMPARE(check_file_traversal("filedir"), CSYNC_FILE_EXCLUDE_LIST);
  355. QCOMPARE(check_file_traversal("dir"), CSYNC_NOT_EXCLUDED);
  356. QCOMPARE(check_file_traversal("s/other"), CSYNC_NOT_EXCLUDED);
  357. QCOMPARE(check_file_traversal("s/filedir"), CSYNC_FILE_EXCLUDE_LIST);
  358. QCOMPARE(check_file_traversal("s/dir"), CSYNC_NOT_EXCLUDED);
  359. QCOMPARE(check_dir_traversal("other"), CSYNC_NOT_EXCLUDED);
  360. QCOMPARE(check_dir_traversal("filedir"), CSYNC_FILE_EXCLUDE_LIST);
  361. QCOMPARE(check_dir_traversal("dir"), CSYNC_FILE_EXCLUDE_LIST);
  362. QCOMPARE(check_dir_traversal("s/other"), CSYNC_NOT_EXCLUDED);
  363. QCOMPARE(check_dir_traversal("s/filedir"), CSYNC_FILE_EXCLUDE_LIST);
  364. QCOMPARE(check_dir_traversal("s/dir"), CSYNC_FILE_EXCLUDE_LIST);
  365. QCOMPARE(check_dir_full("filedir/foo"), CSYNC_FILE_EXCLUDE_LIST);
  366. QCOMPARE(check_file_full("filedir/foo"), CSYNC_FILE_EXCLUDE_LIST);
  367. QCOMPARE(check_dir_full("dir/foo"), CSYNC_FILE_EXCLUDE_LIST);
  368. QCOMPARE(check_file_full("dir/foo"), CSYNC_FILE_EXCLUDE_LIST);
  369. }
  370. void check_csync_pathes()
  371. {
  372. setup_init();
  373. excludedFiles->addManualExclude("/exclude");
  374. excludedFiles->reloadExcludeFiles();
  375. /* Check toplevel dir, the pattern only works for toplevel dir. */
  376. QCOMPARE(check_dir_full("/exclude"), CSYNC_FILE_EXCLUDE_LIST);
  377. QCOMPARE(check_dir_full("/foo/exclude"), CSYNC_NOT_EXCLUDED);
  378. /* check for a file called exclude. Must still work */
  379. QCOMPARE(check_file_full("/exclude"), CSYNC_FILE_EXCLUDE_LIST);
  380. QCOMPARE(check_file_full("/foo/exclude"), CSYNC_NOT_EXCLUDED);
  381. /* Add an exclude for directories only: excl/ */
  382. excludedFiles->addManualExclude("excl/");
  383. excludedFiles->reloadExcludeFiles();
  384. QCOMPARE(check_dir_full("/excl"), CSYNC_FILE_EXCLUDE_LIST);
  385. QCOMPARE(check_dir_full("meep/excl"), CSYNC_FILE_EXCLUDE_LIST);
  386. QCOMPARE(check_file_full("meep/excl/file"), CSYNC_FILE_EXCLUDE_LIST);
  387. QCOMPARE(check_file_full("/excl"), CSYNC_NOT_EXCLUDED);
  388. excludedFiles->addManualExclude("/excludepath/withsubdir");
  389. excludedFiles->reloadExcludeFiles();
  390. QCOMPARE(check_dir_full("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST);
  391. QCOMPARE(check_file_full("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST);
  392. QCOMPARE(check_dir_full("/excludepath/withsubdir2"), CSYNC_NOT_EXCLUDED);
  393. QCOMPARE(check_dir_full("/excludepath/withsubdir/foo"), CSYNC_FILE_EXCLUDE_LIST);
  394. }
  395. void check_csync_wildcards()
  396. {
  397. setup();
  398. excludedFiles->addManualExclude("a/foo*bar");
  399. excludedFiles->addManualExclude("b/foo*bar*");
  400. excludedFiles->addManualExclude("c/foo?bar");
  401. excludedFiles->addManualExclude("d/foo?bar*");
  402. excludedFiles->addManualExclude("e/foo?bar?");
  403. excludedFiles->addManualExclude("g/bar*");
  404. excludedFiles->addManualExclude("h/bar?");
  405. excludedFiles->setWildcardsMatchSlash(false);
  406. QCOMPARE(check_file_traversal("a/fooXYZbar"), CSYNC_FILE_EXCLUDE_LIST);
  407. QCOMPARE(check_file_traversal("a/fooX/Zbar"), CSYNC_NOT_EXCLUDED);
  408. QCOMPARE(check_file_traversal("b/fooXYZbarABC"), CSYNC_FILE_EXCLUDE_LIST);
  409. QCOMPARE(check_file_traversal("b/fooX/ZbarABC"), CSYNC_NOT_EXCLUDED);
  410. QCOMPARE(check_file_traversal("c/fooXbar"), CSYNC_FILE_EXCLUDE_LIST);
  411. QCOMPARE(check_file_traversal("c/foo/bar"), CSYNC_NOT_EXCLUDED);
  412. QCOMPARE(check_file_traversal("d/fooXbarABC"), CSYNC_FILE_EXCLUDE_LIST);
  413. QCOMPARE(check_file_traversal("d/foo/barABC"), CSYNC_NOT_EXCLUDED);
  414. QCOMPARE(check_file_traversal("e/fooXbarA"), CSYNC_FILE_EXCLUDE_LIST);
  415. QCOMPARE(check_file_traversal("e/foo/barA"), CSYNC_NOT_EXCLUDED);
  416. QCOMPARE(check_file_traversal("g/barABC"), CSYNC_FILE_EXCLUDE_LIST);
  417. QCOMPARE(check_file_traversal("g/XbarABC"), CSYNC_NOT_EXCLUDED);
  418. QCOMPARE(check_file_traversal("h/barZ"), CSYNC_FILE_EXCLUDE_LIST);
  419. QCOMPARE(check_file_traversal("h/XbarZ"), CSYNC_NOT_EXCLUDED);
  420. excludedFiles->setWildcardsMatchSlash(true);
  421. QCOMPARE(check_file_traversal("a/fooX/Zbar"), CSYNC_FILE_EXCLUDE_LIST);
  422. QCOMPARE(check_file_traversal("b/fooX/ZbarABC"), CSYNC_FILE_EXCLUDE_LIST);
  423. QCOMPARE(check_file_traversal("c/foo/bar"), CSYNC_FILE_EXCLUDE_LIST);
  424. QCOMPARE(check_file_traversal("d/foo/barABC"), CSYNC_FILE_EXCLUDE_LIST);
  425. QCOMPARE(check_file_traversal("e/foo/barA"), CSYNC_FILE_EXCLUDE_LIST);
  426. }
  427. void check_csync_regex_translation()
  428. {
  429. setup();
  430. QByteArray storage;
  431. auto translate = [&storage](const char *pattern) {
  432. storage = ExcludedFiles::convertToRegexpSyntax(pattern, false).toUtf8();
  433. return storage.constData();
  434. };
  435. QCOMPARE(translate(""), "");
  436. QCOMPARE(translate("abc"), "abc");
  437. QCOMPARE(translate("a*c"), "a[^/]*c");
  438. QCOMPARE(translate("a?c"), "a[^/]c");
  439. QCOMPARE(translate("a[xyz]c"), "a[xyz]c");
  440. QCOMPARE(translate("a[xyzc"), "a\\[xyzc");
  441. QCOMPARE(translate("a[!xyz]c"), "a[^xyz]c");
  442. QCOMPARE(translate("a\\*b\\?c\\[d\\\\e"), "a\\*b\\?c\\[d\\\\e");
  443. QCOMPARE(translate("a.c"), "a\\.c");
  444. QCOMPARE(translate("?𠜎?"), "[^/]\\𠜎[^/]"); // 𠜎 is 4-byte utf8
  445. }
  446. void check_csync_bname_trigger()
  447. {
  448. setup();
  449. bool wildcardsMatchSlash = false;
  450. QByteArray storage;
  451. auto translate = [&storage, &wildcardsMatchSlash](const char *pattern) {
  452. storage = ExcludedFiles::extractBnameTrigger(pattern, wildcardsMatchSlash).toUtf8();
  453. return storage.constData();
  454. };
  455. QCOMPARE(translate(""), "");
  456. QCOMPARE(translate("a/b/"), "");
  457. QCOMPARE(translate("a/b/c"), "c");
  458. QCOMPARE(translate("c"), "c");
  459. QCOMPARE(translate("a/foo*"), "foo*");
  460. QCOMPARE(translate("a/abc*foo*"), "abc*foo*");
  461. wildcardsMatchSlash = true;
  462. QCOMPARE(translate(""), "");
  463. QCOMPARE(translate("a/b/"), "");
  464. QCOMPARE(translate("a/b/c"), "c");
  465. QCOMPARE(translate("c"), "c");
  466. QCOMPARE(translate("*"), "*");
  467. QCOMPARE(translate("a/foo*"), "foo*");
  468. QCOMPARE(translate("a/abc?foo*"), "*foo*");
  469. QCOMPARE(translate("a/abc*foo*"), "*foo*");
  470. QCOMPARE(translate("a/abc?foo?"), "*foo?");
  471. QCOMPARE(translate("a/abc*foo?*"), "*foo?*");
  472. QCOMPARE(translate("a/abc*/foo*"), "foo*");
  473. }
  474. void check_csync_is_windows_reserved_word()
  475. {
  476. auto csync_is_windows_reserved_word = [](const char *fn) {
  477. QString s = QString::fromLatin1(fn);
  478. extern bool csync_is_windows_reserved_word(const QStringRef &filename);
  479. return csync_is_windows_reserved_word(&s);
  480. };
  481. QVERIFY(csync_is_windows_reserved_word("CON"));
  482. QVERIFY(csync_is_windows_reserved_word("con"));
  483. QVERIFY(csync_is_windows_reserved_word("CON."));
  484. QVERIFY(csync_is_windows_reserved_word("con."));
  485. QVERIFY(csync_is_windows_reserved_word("CON.ference"));
  486. QVERIFY(!csync_is_windows_reserved_word("CONference"));
  487. QVERIFY(!csync_is_windows_reserved_word("conference"));
  488. QVERIFY(!csync_is_windows_reserved_word("conf.erence"));
  489. QVERIFY(!csync_is_windows_reserved_word("co"));
  490. QVERIFY(csync_is_windows_reserved_word("COM2"));
  491. QVERIFY(csync_is_windows_reserved_word("com2"));
  492. QVERIFY(csync_is_windows_reserved_word("COM2."));
  493. QVERIFY(csync_is_windows_reserved_word("com2."));
  494. QVERIFY(csync_is_windows_reserved_word("COM2.ference"));
  495. QVERIFY(!csync_is_windows_reserved_word("COM2ference"));
  496. QVERIFY(!csync_is_windows_reserved_word("com2ference"));
  497. QVERIFY(!csync_is_windows_reserved_word("com2f.erence"));
  498. QVERIFY(!csync_is_windows_reserved_word("com"));
  499. QVERIFY(csync_is_windows_reserved_word("CLOCK$"));
  500. QVERIFY(csync_is_windows_reserved_word("$Recycle.Bin"));
  501. QVERIFY(csync_is_windows_reserved_word("ClocK$"));
  502. QVERIFY(csync_is_windows_reserved_word("$recycle.bin"));
  503. QVERIFY(csync_is_windows_reserved_word("A:"));
  504. QVERIFY(csync_is_windows_reserved_word("a:"));
  505. QVERIFY(csync_is_windows_reserved_word("z:"));
  506. QVERIFY(csync_is_windows_reserved_word("Z:"));
  507. QVERIFY(csync_is_windows_reserved_word("M:"));
  508. QVERIFY(csync_is_windows_reserved_word("m:"));
  509. }
  510. /* QT_ENABLE_REGEXP_JIT=0 to get slower results :-) */
  511. void check_csync_excluded_performance1()
  512. {
  513. setup_init();
  514. const int N = 1000;
  515. int totalRc = 0;
  516. QBENCHMARK {
  517. for (int i = 0; i < N; ++i) {
  518. totalRc += check_dir_full("/this/is/quite/a/long/path/with/many/components");
  519. totalRc += check_file_full("/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29");
  520. }
  521. QCOMPARE(totalRc, 0); // mainly to avoid optimization
  522. }
  523. }
  524. void check_csync_excluded_performance2()
  525. {
  526. const int N = 1000;
  527. int totalRc = 0;
  528. QBENCHMARK {
  529. for (int i = 0; i < N; ++i) {
  530. totalRc += check_dir_traversal("/this/is/quite/a/long/path/with/many/components");
  531. totalRc += check_file_traversal("/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29");
  532. }
  533. QCOMPARE(totalRc, 0); // mainly to avoid optimization
  534. }
  535. }
  536. void check_csync_exclude_expand_escapes()
  537. {
  538. extern void csync_exclude_expand_escapes(QByteArray &input);
  539. QByteArray line = "keep \\' \\\" \\? \\\\ \\a \\b \\f \\n \\r \\t \\v \\z \\#";
  540. csync_exclude_expand_escapes(line);
  541. QVERIFY(0 == strcmp(line.constData(), "keep ' \" ? \\\\ \a \b \f \n \r \t \v \\z #"));
  542. line = "";
  543. csync_exclude_expand_escapes(line);
  544. QVERIFY(0 == strcmp(line.constData(), ""));
  545. line = "\\";
  546. csync_exclude_expand_escapes(line);
  547. QVERIFY(0 == strcmp(line.constData(), "\\"));
  548. }
  549. void check_version_directive()
  550. {
  551. ExcludedFiles excludes;
  552. excludes.setClientVersion(ExcludedFiles::Version(2, 5, 0));
  553. std::vector<std::pair<const char *, bool>> tests = {
  554. { "#!version == 2.5.0", true },
  555. { "#!version == 2.6.0", false },
  556. { "#!version < 2.6.0", true },
  557. { "#!version <= 2.6.0", true },
  558. { "#!version > 2.6.0", false },
  559. { "#!version >= 2.6.0", false },
  560. { "#!version < 2.4.0", false },
  561. { "#!version <= 2.4.0", false },
  562. { "#!version > 2.4.0", true },
  563. { "#!version >= 2.4.0", true },
  564. { "#!version < 2.5.0", false },
  565. { "#!version <= 2.5.0", true },
  566. { "#!version > 2.5.0", false },
  567. { "#!version >= 2.5.0", true },
  568. };
  569. for (auto test : tests) {
  570. QVERIFY(excludes.versionDirectiveKeepNextLine(test.first) == test.second);
  571. }
  572. }
  573. };
  574. QTEST_APPLESS_MAIN(TestExcludedFiles)
  575. #include "testexcludedfiles.moc"