From: Olivier Goffart Date: Fri, 30 Nov 2018 14:31:10 +0000 (+0100) Subject: Port the exclude test to the QTest Framework X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~21^2~468^2~362 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=6da96cd0269d9ff3cf40d7bc2f2d9279cf7032d3;p=nextcloud-desktop.git Port the exclude test to the QTest Framework This is just a port to QtTest, I did not change the layout of the test. I did search and replace to replace the assert with QCOMPARE/QVERIFY I still call setup and setup_init like before (only explicitly, now) Also ported the preformence tests to QBENCHMAK because windows don't have gettimeofday. Relates #6358 --- diff --git a/src/csync/csync_exclude.cpp b/src/csync/csync_exclude.cpp index b443c3bc4..8233a6b1f 100644 --- a/src/csync/csync_exclude.cpp +++ b/src/csync/csync_exclude.cpp @@ -41,7 +41,7 @@ /** Expands C-like escape sequences (in place) */ -static void csync_exclude_expand_escapes(QByteArray &input) +OCSYNC_EXPORT void csync_exclude_expand_escapes(QByteArray &input) { size_t o = 0; char *line = input.data(); @@ -92,7 +92,7 @@ static const char *win_reserved_words_n[] = { "CLOCK$", "$Recycle.Bin" }; * @param file_name filename * @return true if file is reserved, false otherwise */ -bool csync_is_windows_reserved_word(const QStringRef &filename) +OCSYNC_EXPORT bool csync_is_windows_reserved_word(const QStringRef &filename) { size_t len_filename = filename.size(); @@ -548,7 +548,7 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::fullPatternMatch(const QString &p, ItemType fi * didn't have that behavior. wildcardsMatchSlash can be used to control which behavior * the resulting regex shall use. */ -static QString convertToRegexpSyntax(QString exclude, bool wildcardsMatchSlash) +QString ExcludedFiles::convertToRegexpSyntax(QString exclude, bool wildcardsMatchSlash) { // Translate *, ?, [...] to their regex variants. // The escape sequences \*, \?, \[. \\ have a special meaning, @@ -638,7 +638,7 @@ static QString convertToRegexpSyntax(QString exclude, bool wildcardsMatchSlash) return regex; } -static QString extractBnameTrigger(const QString &exclude, bool wildcardsMatchSlash) +QString ExcludedFiles::extractBnameTrigger(const QString &exclude, bool wildcardsMatchSlash) { // We can definitely drop everything to the left of a / - that will never match // any bname. diff --git a/src/csync/csync_exclude.h b/src/csync/csync_exclude.h index 5de60eb26..0656371e7 100644 --- a/src/csync/csync_exclude.h +++ b/src/csync/csync_exclude.h @@ -227,8 +227,11 @@ private: void prepare(); + static QString extractBnameTrigger(const QString &exclude, bool wildcardsMatchSlash); + static QString convertToRegexpSyntax(QString exclude, bool wildcardsMatchSlash); QString _localPath; + /// Files to load excludes from QMap _excludeFiles; @@ -262,7 +265,7 @@ private: */ Version _clientVersion; - friend class ExcludedFilesTest; + friend class TestExcludedFiles; }; #endif /* _CSYNC_EXCLUDE_H */ diff --git a/test/csync/CMakeLists.txt b/test/csync/CMakeLists.txt index 621c8a154..5a8336c15 100644 --- a/test/csync/CMakeLists.txt +++ b/test/csync/CMakeLists.txt @@ -22,10 +22,6 @@ add_cmocka_test(check_std_c_alloc std_tests/check_std_c_alloc.c ${TEST_TARGET_LI add_cmocka_test(check_std_c_jhash std_tests/check_std_c_jhash.c ${TEST_TARGET_LIBRARIES}) add_cmocka_test(check_std_c_str std_tests/check_std_c_str.c ${TEST_TARGET_LIBRARIES}) - -# csync tests -add_cmocka_test(check_csync_exclude csync_tests/check_csync_exclude.cpp ${TEST_TARGET_LIBRARIES}) - # vio add_cmocka_test(check_vio_ext vio_tests/check_vio_ext.cpp ${TEST_TARGET_LIBRARIES}) diff --git a/test/csync/csync_tests/check_csync_exclude.cpp b/test/csync/csync_tests/check_csync_exclude.cpp deleted file mode 100644 index a8268449c..000000000 --- a/test/csync/csync_tests/check_csync_exclude.cpp +++ /dev/null @@ -1,739 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "config_csync.h" -#include -#include -#include -#include - -#include - -#define CSYNC_TEST 1 -#include "csync_exclude.cpp" - -#include "torture.h" - -#define EXCLUDE_LIST_FILE SOURCEDIR"/../../sync-exclude.lst" - -ExcludedFiles *excludedFiles = nullptr; - -class ExcludedFilesTest -{ -public: - -static int setup(void **) { - excludedFiles = new ExcludedFiles; - excludedFiles->setWildcardsMatchSlash(false); - return 0; -} - -static int setup_init(void **) { - excludedFiles = new ExcludedFiles; - excludedFiles->setWildcardsMatchSlash(false); - - excludedFiles->addExcludeFilePath(EXCLUDE_LIST_FILE); - assert_true(excludedFiles->reloadExcludeFiles()); - - /* and add some unicode stuff */ - excludedFiles->addManualExclude("*.💩"); // is this source file utf8 encoded? - excludedFiles->addManualExclude("пятницы.*"); - excludedFiles->addManualExclude("*/*.out"); - excludedFiles->addManualExclude("latex*/*.run.xml"); - excludedFiles->addManualExclude("latex/*/*.tex.tmp"); - - assert_true(excludedFiles->reloadExcludeFiles()); - return 0; -} - -static int teardown(void **) { - int rc = 0; - - delete excludedFiles; - - rc = system("rm -rf /tmp/check_csync1"); - assert_int_equal(rc, 0); - rc = system("rm -rf /tmp/check_csync2"); - assert_int_equal(rc, 0); - - return 0; -} - -static int check_file_full(const char *path) -{ - return excludedFiles->fullPatternMatch(path, ItemTypeFile); -} - -static int check_dir_full(const char *path) -{ - return excludedFiles->fullPatternMatch(path, ItemTypeDirectory); -} - -static int check_file_traversal(const char *path) -{ - return excludedFiles->traversalPatternMatch(path, ItemTypeFile); -} - -static int check_dir_traversal(const char *path) -{ - return excludedFiles->traversalPatternMatch(path, ItemTypeDirectory); -} - -static void check_csync_exclude_add(void **) -{ - excludedFiles->addManualExclude("/tmp/check_csync1/*"); - assert_int_equal(check_file_full("/tmp/check_csync1/foo"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("/tmp/check_csync2/foo"), CSYNC_NOT_EXCLUDED); - assert_true(excludedFiles->_allExcludes[QStringLiteral("/")].contains("/tmp/check_csync1/*")); - - assert_true(excludedFiles->_fullRegexFile[QStringLiteral("/")].pattern().contains("csync1")); - assert_true(excludedFiles->_fullTraversalRegexFile[QStringLiteral("/")].pattern().contains("csync1")); - assert_false(excludedFiles->_bnameTraversalRegexFile[QStringLiteral("/")].pattern().contains("csync1")); - - excludedFiles->addManualExclude("foo"); - assert_true(excludedFiles->_bnameTraversalRegexFile[QStringLiteral("/")].pattern().contains("foo")); - assert_true(excludedFiles->_fullRegexFile[QStringLiteral("/")].pattern().contains("foo")); - assert_false(excludedFiles->_fullTraversalRegexFile[QStringLiteral("/")].pattern().contains("foo")); -} - -static void check_csync_exclude_add_per_dir(void **) -{ - excludedFiles->addManualExclude("*", "/tmp/check_csync1/"); - assert_int_equal(check_file_full("/tmp/check_csync1/foo"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("/tmp/check_csync2/foo"), CSYNC_NOT_EXCLUDED); - assert_true(excludedFiles->_allExcludes[QStringLiteral("/tmp/check_csync1/")].contains("*")); - - excludedFiles->addManualExclude("foo"); - assert_true(excludedFiles->_fullRegexFile[QStringLiteral("/")].pattern().contains("foo")); - - excludedFiles->addManualExclude("foo/bar", "/tmp/check_csync1/"); - assert_true(excludedFiles->_fullRegexFile[QStringLiteral("/tmp/check_csync1/")].pattern().contains("bar")); - assert_true(excludedFiles->_fullTraversalRegexFile[QStringLiteral("/tmp/check_csync1/")].pattern().contains("bar")); - assert_false(excludedFiles->_bnameTraversalRegexFile[QStringLiteral("/tmp/check_csync1/")].pattern().contains("foo")); -} - -static void check_csync_excluded(void **) -{ - assert_int_equal(check_file_full(""), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("/"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("A"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("krawel_krawel"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full(".kde/share/config/kwin.eventsrc"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full(".directory/cache-maximegalon/cache1.txt"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_full("mozilla/.directory"), CSYNC_FILE_EXCLUDE_LIST); - - /* - * Test for patterns in subdirs. '.beagle' is defined as a pattern and has - * to be found in top dir as well as in directories underneath. - */ - assert_int_equal(check_dir_full(".apdisk"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_full("foo/.apdisk"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_full("foo/bar/.apdisk"), CSYNC_FILE_EXCLUDE_LIST); - - assert_int_equal(check_file_full(".java"), CSYNC_NOT_EXCLUDED); - - /* Files in the ignored dir .java will also be ignored. */ - assert_int_equal(check_file_full(".apdisk/totally_amazing.jar"), CSYNC_FILE_EXCLUDE_LIST); - - /* and also in subdirs */ - assert_int_equal(check_file_full("projects/.apdisk/totally_amazing.jar"), CSYNC_FILE_EXCLUDE_LIST); - - /* csync-journal is ignored in general silently. */ - assert_int_equal(check_file_full(".csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_full(".csync_journal.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_full("subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - - /* also the new form of the database name */ - assert_int_equal(check_file_full("._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_full("._sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_full("._sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_full("subdir/._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - - assert_int_equal(check_file_full(".sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_full(".sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_full(".sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_full("subdir/.sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - - - /* pattern ]*.directory - ignore and remove */ - assert_int_equal(check_file_full("my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE); - assert_int_equal(check_file_full("/a_folder/my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE); - - /* Not excluded because the pattern .netscape/cache requires directory. */ - assert_int_equal(check_file_full(".netscape/cache"), CSYNC_NOT_EXCLUDED); - - /* Not excluded */ - assert_int_equal(check_file_full("unicode/中文.hé"), CSYNC_NOT_EXCLUDED); - /* excluded */ - assert_int_equal(check_file_full("unicode/пятницы.txt"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("unicode/中文.💩"), CSYNC_FILE_EXCLUDE_LIST); - - /* path wildcards */ - assert_int_equal(check_file_full("foobar/my_manuscript.out"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("latex_tmp/my_manuscript.run.xml"), CSYNC_FILE_EXCLUDE_LIST); - - assert_int_equal(check_file_full("word_tmp/my_manuscript.run.xml"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_file_full("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_file_full("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST); - -#ifdef _WIN32 - assert_int_equal(exclude_check_file("file_trailing_space "), CSYNC_FILE_EXCLUDE_TRAILING_SPACE); - - assert_int_equal(exclude_check_file("file_trailing_dot."), CSYNC_FILE_EXCLUDE_INVALID_CHAR); - assert_int_equal(exclude_check_file("AUX"), CSYNC_FILE_EXCLUDE_INVALID_CHAR); - assert_int_equal(exclude_check_file("file_invalid_char<"), CSYNC_FILE_EXCLUDE_INVALID_CHAR); -#endif - - /* ? character */ - excludedFiles->addManualExclude("bond00?"); - excludedFiles->reloadExcludeFiles(); - assert_int_equal(check_file_full("bond00"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("bond007"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("bond0071"), CSYNC_NOT_EXCLUDED); - - /* brackets */ - excludedFiles->addManualExclude("a [bc] d"); - excludedFiles->reloadExcludeFiles(); - assert_int_equal(check_file_full("a d d"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("a d"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("a b d"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("a c d"), CSYNC_FILE_EXCLUDE_LIST); - - /* escapes */ - excludedFiles->addManualExclude("a \\*"); - excludedFiles->addManualExclude("b \\?"); - excludedFiles->addManualExclude("c \\[d]"); - excludedFiles->reloadExcludeFiles(); - assert_int_equal(check_file_full("a \\*"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("a bc"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("a *"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("b \\?"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("b f"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("b ?"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("c \\[d]"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("c d"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("c [d]"), CSYNC_FILE_EXCLUDE_LIST); -} - -static void check_csync_excluded_per_dir(void **) -{ - excludedFiles->addManualExclude("A"); - excludedFiles->reloadExcludeFiles(); - - assert_int_equal(check_file_full("A"), CSYNC_FILE_EXCLUDE_LIST); - - excludedFiles->clearManualExcludes(); - excludedFiles->addManualExclude("A", "/B/"); - excludedFiles->reloadExcludeFiles(); - - assert_int_equal(check_file_full("A"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("B/A"), CSYNC_FILE_EXCLUDE_LIST); - - excludedFiles->clearManualExcludes(); - excludedFiles->addManualExclude("A/a1", "/B/"); - excludedFiles->reloadExcludeFiles(); - - assert_int_equal(check_file_full("A"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full("B/A/a1"), CSYNC_FILE_EXCLUDE_LIST); - -#define FOO_DIR "/tmp/check_csync1/foo" -#define FOO_EXCLUDE_LIST FOO_DIR "/.sync-exclude.lst" - int rc = 0; - rc = system("mkdir -p " FOO_DIR); - assert_int_equal(rc, 0); - FILE *fh = fopen(FOO_EXCLUDE_LIST, "w"); - assert_non_null(fh); - rc = fprintf(fh, "bar"); - assert_int_not_equal(rc, 0); - rc = fclose(fh); - assert_int_equal(rc, 0); - - excludedFiles->addInTreeExcludeFilePath(FOO_EXCLUDE_LIST); - excludedFiles->reloadExcludeFiles(); - assert_int_equal(check_file_full(FOO_DIR), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_full(FOO_DIR "/bar"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full(FOO_DIR "/baz"), CSYNC_NOT_EXCLUDED); -#undef FOO_DIR -#undef FOO_EXCLUDE_LIST -} - -static void check_csync_excluded_traversal_per_dir(void **) -{ - assert_int_equal(check_file_traversal("/"), CSYNC_NOT_EXCLUDED); - - /* path wildcards */ - excludedFiles->addManualExclude("*/*.tex.tmp", "/latex/"); - assert_int_equal(check_file_traversal("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST); -} - -static void check_csync_excluded_traversal(void **) -{ - assert_int_equal(check_file_traversal(""), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("/"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_file_traversal("A"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_file_traversal("krawel_krawel"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal(".kde/share/config/kwin.eventsrc"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_dir_traversal("mozilla/.directory"), CSYNC_FILE_EXCLUDE_LIST); - - /* - * Test for patterns in subdirs. '.beagle' is defined as a pattern and has - * to be found in top dir as well as in directories underneath. - */ - assert_int_equal(check_dir_traversal(".apdisk"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_traversal("foo/.apdisk"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_traversal("foo/bar/.apdisk"), CSYNC_FILE_EXCLUDE_LIST); - - assert_int_equal(check_file_traversal(".java"), CSYNC_NOT_EXCLUDED); - - /* csync-journal is ignored in general silently. */ - assert_int_equal(check_file_traversal(".csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_traversal(".csync_journal.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_traversal("subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_traversal("/two/subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - - /* also the new form of the database name */ - assert_int_equal(check_file_traversal("._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_traversal("._sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_traversal("._sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_traversal("subdir/._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - - assert_int_equal(check_file_traversal(".sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_traversal(".sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_traversal(".sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED); - assert_int_equal(check_file_traversal("subdir/.sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); - - /* Other builtin excludes */ - assert_int_equal(check_file_traversal("foo/Desktop.ini"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("Desktop.ini"), CSYNC_FILE_SILENTLY_EXCLUDED); - - /* pattern ]*.directory - ignore and remove */ - assert_int_equal(check_file_traversal("my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE); - assert_int_equal(check_file_traversal("/a_folder/my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE); - - /* Not excluded because the pattern .netscape/cache requires directory. */ - assert_int_equal(check_file_traversal(".netscape/cache"), CSYNC_NOT_EXCLUDED); - - /* Not excluded */ - assert_int_equal(check_file_traversal("unicode/中文.hé"), CSYNC_NOT_EXCLUDED); - /* excluded */ - assert_int_equal(check_file_traversal("unicode/пятницы.txt"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("unicode/中文.💩"), CSYNC_FILE_EXCLUDE_LIST); - - /* path wildcards */ - assert_int_equal(check_file_traversal("foobar/my_manuscript.out"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("latex_tmp/my_manuscript.run.xml"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("word_tmp/my_manuscript.run.xml"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST); - -#ifdef _WIN32 - assert_int_equal(check_file_traversal("file_trailing_space "), CSYNC_FILE_EXCLUDE_TRAILING_SPACE); - assert_int_equal(check_file_traversal("file_trailing_dot."), CSYNC_FILE_EXCLUDE_INVALID_CHAR); - assert_int_equal(check_file_traversal("AUX"), CSYNC_FILE_EXCLUDE_INVALID_CHAR); - assert_int_equal(check_file_traversal("file_invalid_char<"), CSYNC_FILE_EXCLUDE_INVALID_CHAR); -#endif - - - /* From here the actual traversal tests */ - - excludedFiles->addManualExclude("/exclude"); - excludedFiles->reloadExcludeFiles(); - - /* Check toplevel dir, the pattern only works for toplevel dir. */ - assert_int_equal(check_dir_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_traversal("/foo/exclude"), CSYNC_NOT_EXCLUDED); - - /* check for a file called exclude. Must still work */ - assert_int_equal(check_file_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("/foo/exclude"), CSYNC_NOT_EXCLUDED); - - /* Add an exclude for directories only: excl/ */ - excludedFiles->addManualExclude("excl/"); - excludedFiles->reloadExcludeFiles(); - assert_int_equal(check_dir_traversal("/excl"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_traversal("meep/excl"), CSYNC_FILE_EXCLUDE_LIST); - - // because leading dirs aren't checked! - assert_int_equal(check_file_traversal("meep/excl/file"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("/excl"), CSYNC_NOT_EXCLUDED); - - excludedFiles->addManualExclude("/excludepath/withsubdir"); - excludedFiles->reloadExcludeFiles(); - - assert_int_equal(check_dir_traversal("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_traversal("/excludepath/withsubdir2"), CSYNC_NOT_EXCLUDED); - - // because leading dirs aren't checked! - assert_int_equal(check_dir_traversal("/excludepath/withsubdir/foo"), CSYNC_NOT_EXCLUDED); - - /* Check ending of pattern */ - assert_int_equal(check_file_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("/excludeX"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("exclude"), CSYNC_NOT_EXCLUDED); - - excludedFiles->addManualExclude("exclude"); - excludedFiles->reloadExcludeFiles(); - assert_int_equal(check_file_traversal("exclude"), CSYNC_FILE_EXCLUDE_LIST); - - /* ? character */ - excludedFiles->addManualExclude("bond00?"); - excludedFiles->reloadExcludeFiles(); - assert_int_equal(check_file_traversal("bond00"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("bond007"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("bond0071"), CSYNC_NOT_EXCLUDED); - - /* brackets */ - excludedFiles->addManualExclude("a [bc] d"); - excludedFiles->reloadExcludeFiles(); - assert_int_equal(check_file_traversal("a d d"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("a d"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("a b d"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("a c d"), CSYNC_FILE_EXCLUDE_LIST); - - /* escapes */ - excludedFiles->addManualExclude("a \\*"); - excludedFiles->addManualExclude("b \\?"); - excludedFiles->addManualExclude("c \\[d]"); - excludedFiles->reloadExcludeFiles(); - assert_int_equal(check_file_traversal("a \\*"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("a bc"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("a *"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("b \\?"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("b f"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("b ?"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("c \\[d]"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("c d"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("c [d]"), CSYNC_FILE_EXCLUDE_LIST); -} - -static void check_csync_dir_only(void **) -{ - excludedFiles->addManualExclude("filedir"); - excludedFiles->addManualExclude("dir/"); - - assert_int_equal(check_file_traversal("other"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("filedir"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("dir"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("s/other"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_file_traversal("s/filedir"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("s/dir"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_dir_traversal("other"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_dir_traversal("filedir"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_traversal("dir"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_traversal("s/other"), CSYNC_NOT_EXCLUDED); - assert_int_equal(check_dir_traversal("s/filedir"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_traversal("s/dir"), CSYNC_FILE_EXCLUDE_LIST); - - assert_int_equal(check_dir_full("filedir/foo"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("filedir/foo"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_full("dir/foo"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("dir/foo"), CSYNC_FILE_EXCLUDE_LIST); -} - -static void check_csync_pathes(void **) -{ - excludedFiles->addManualExclude("/exclude"); - excludedFiles->reloadExcludeFiles(); - - /* Check toplevel dir, the pattern only works for toplevel dir. */ - assert_int_equal(check_dir_full("/exclude"), CSYNC_FILE_EXCLUDE_LIST); - - assert_int_equal(check_dir_full("/foo/exclude"), CSYNC_NOT_EXCLUDED); - - /* check for a file called exclude. Must still work */ - assert_int_equal(check_file_full("/exclude"), CSYNC_FILE_EXCLUDE_LIST); - - assert_int_equal(check_file_full("/foo/exclude"), CSYNC_NOT_EXCLUDED); - - /* Add an exclude for directories only: excl/ */ - excludedFiles->addManualExclude("excl/"); - excludedFiles->reloadExcludeFiles(); - assert_int_equal(check_dir_full("/excl"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_dir_full("meep/excl"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("meep/excl/file"), CSYNC_FILE_EXCLUDE_LIST); - - assert_int_equal(check_file_full("/excl"), CSYNC_NOT_EXCLUDED); - - excludedFiles->addManualExclude("/excludepath/withsubdir"); - excludedFiles->reloadExcludeFiles(); - - assert_int_equal(check_dir_full("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_full("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST); - - assert_int_equal(check_dir_full("/excludepath/withsubdir2"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_dir_full("/excludepath/withsubdir/foo"), CSYNC_FILE_EXCLUDE_LIST); -} - -static void check_csync_wildcards(void **) -{ - excludedFiles->addManualExclude("a/foo*bar"); - excludedFiles->addManualExclude("b/foo*bar*"); - excludedFiles->addManualExclude("c/foo?bar"); - excludedFiles->addManualExclude("d/foo?bar*"); - excludedFiles->addManualExclude("e/foo?bar?"); - excludedFiles->addManualExclude("g/bar*"); - excludedFiles->addManualExclude("h/bar?"); - - excludedFiles->setWildcardsMatchSlash(false); - - assert_int_equal(check_file_traversal("a/fooXYZbar"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("a/fooX/Zbar"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_file_traversal("b/fooXYZbarABC"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("b/fooX/ZbarABC"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_file_traversal("c/fooXbar"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("c/foo/bar"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_file_traversal("d/fooXbarABC"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("d/foo/barABC"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_file_traversal("e/fooXbarA"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("e/foo/barA"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_file_traversal("g/barABC"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("g/XbarABC"), CSYNC_NOT_EXCLUDED); - - assert_int_equal(check_file_traversal("h/barZ"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("h/XbarZ"), CSYNC_NOT_EXCLUDED); - - excludedFiles->setWildcardsMatchSlash(true); - - assert_int_equal(check_file_traversal("a/fooX/Zbar"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("b/fooX/ZbarABC"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("c/foo/bar"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("d/foo/barABC"), CSYNC_FILE_EXCLUDE_LIST); - assert_int_equal(check_file_traversal("e/foo/barA"), CSYNC_FILE_EXCLUDE_LIST); -} - -static void check_csync_regex_translation(void **) -{ - QByteArray storage; - auto translate = [&storage](const char *pattern) { - storage = convertToRegexpSyntax(pattern, false).toUtf8(); - return storage.constData(); - }; - - assert_string_equal(translate(""), ""); - assert_string_equal(translate("abc"), "abc"); - assert_string_equal(translate("a*c"), "a[^/]*c"); - assert_string_equal(translate("a?c"), "a[^/]c"); - assert_string_equal(translate("a[xyz]c"), "a[xyz]c"); - assert_string_equal(translate("a[xyzc"), "a\\[xyzc"); - assert_string_equal(translate("a[!xyz]c"), "a[^xyz]c"); - assert_string_equal(translate("a\\*b\\?c\\[d\\\\e"), "a\\*b\\?c\\[d\\\\e"); - assert_string_equal(translate("a.c"), "a\\.c"); - assert_string_equal(translate("?𠜎?"), "[^/]\\𠜎[^/]"); // 𠜎 is 4-byte utf8 -} - -static void check_csync_bname_trigger(void **) -{ - bool wildcardsMatchSlash = false; - QByteArray storage; - auto translate = [&storage, &wildcardsMatchSlash](const char *pattern) { - storage = extractBnameTrigger(pattern, wildcardsMatchSlash).toUtf8(); - return storage.constData(); - }; - - assert_string_equal(translate(""), ""); - assert_string_equal(translate("a/b/"), ""); - assert_string_equal(translate("a/b/c"), "c"); - assert_string_equal(translate("c"), "c"); - assert_string_equal(translate("a/foo*"), "foo*"); - assert_string_equal(translate("a/abc*foo*"), "abc*foo*"); - - wildcardsMatchSlash = true; - - assert_string_equal(translate(""), ""); - assert_string_equal(translate("a/b/"), ""); - assert_string_equal(translate("a/b/c"), "c"); - assert_string_equal(translate("c"), "c"); - assert_string_equal(translate("*"), "*"); - assert_string_equal(translate("a/foo*"), "foo*"); - assert_string_equal(translate("a/abc?foo*"), "*foo*"); - assert_string_equal(translate("a/abc*foo*"), "*foo*"); - assert_string_equal(translate("a/abc?foo?"), "*foo?"); - assert_string_equal(translate("a/abc*foo?*"), "*foo?*"); - assert_string_equal(translate("a/abc*/foo*"), "foo*"); -} - -static void check_csync_is_windows_reserved_word(void **) -{ - auto csync_is_windows_reserved_word = [](const char *fn) { - QString s = QString::fromLatin1(fn); - return ::csync_is_windows_reserved_word(&s); - }; - - assert_true(csync_is_windows_reserved_word("CON")); - assert_true(csync_is_windows_reserved_word("con")); - assert_true(csync_is_windows_reserved_word("CON.")); - assert_true(csync_is_windows_reserved_word("con.")); - assert_true(csync_is_windows_reserved_word("CON.ference")); - assert_false(csync_is_windows_reserved_word("CONference")); - assert_false(csync_is_windows_reserved_word("conference")); - assert_false(csync_is_windows_reserved_word("conf.erence")); - assert_false(csync_is_windows_reserved_word("co")); - - assert_true(csync_is_windows_reserved_word("COM2")); - assert_true(csync_is_windows_reserved_word("com2")); - assert_true(csync_is_windows_reserved_word("COM2.")); - assert_true(csync_is_windows_reserved_word("com2.")); - assert_true(csync_is_windows_reserved_word("COM2.ference")); - assert_false(csync_is_windows_reserved_word("COM2ference")); - assert_false(csync_is_windows_reserved_word("com2ference")); - assert_false(csync_is_windows_reserved_word("com2f.erence")); - assert_false(csync_is_windows_reserved_word("com")); - - assert_true(csync_is_windows_reserved_word("CLOCK$")); - assert_true(csync_is_windows_reserved_word("$Recycle.Bin")); - assert_true(csync_is_windows_reserved_word("ClocK$")); - assert_true(csync_is_windows_reserved_word("$recycle.bin")); - - assert_true(csync_is_windows_reserved_word("A:")); - assert_true(csync_is_windows_reserved_word("a:")); - assert_true(csync_is_windows_reserved_word("z:")); - assert_true(csync_is_windows_reserved_word("Z:")); - assert_true(csync_is_windows_reserved_word("M:")); - assert_true(csync_is_windows_reserved_word("m:")); -} - -/* QT_ENABLE_REGEXP_JIT=0 to get slower results :-) */ -static void check_csync_excluded_performance(void **) -{ - const int N = 10000; - int totalRc = 0; - int i = 0; - - // Being able to use QElapsedTimer for measurement would be nice... - { - struct timeval before, after; - gettimeofday(&before, nullptr); - - for (i = 0; i < N; ++i) { - totalRc += check_dir_full("/this/is/quite/a/long/path/with/many/components"); - 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"); - } - assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization - - gettimeofday(&after, nullptr); - - const auto total = static_cast(after.tv_sec - before.tv_sec) - + static_cast(after.tv_usec - before.tv_usec) / 1.0e6; - const double perCallMs = total / 2 / N * 1000; - printf("csync_excluded: %f ms per call\n", perCallMs); - } - - { - struct timeval before, after; - gettimeofday(&before, nullptr); - - for (i = 0; i < N; ++i) { - totalRc += check_dir_traversal("/this/is/quite/a/long/path/with/many/components"); - 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"); - } - assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization - - gettimeofday(&after, nullptr); - - const auto total = static_cast(after.tv_sec - before.tv_sec) - + static_cast(after.tv_usec - before.tv_usec) / 1.0e6; - const double perCallMs = total / 2 / N * 1000; - printf("csync_excluded_traversal: %f ms per call\n", perCallMs); - } -} - -static void check_csync_exclude_expand_escapes(void **state) -{ - (void)state; - - QByteArray line = R"(keep \' \" \? \\ \a \b \f \n \r \t \v \z \#)"; - csync_exclude_expand_escapes(line); - assert_true(0 == strcmp(line.constData(), "keep ' \" ? \\\\ \a \b \f \n \r \t \v \\z #")); - - line = ""; - csync_exclude_expand_escapes(line); - assert_true(0 == strcmp(line.constData(), "")); - - line = "\\"; - csync_exclude_expand_escapes(line); - assert_true(0 == strcmp(line.constData(), "\\")); -} - -static void check_version_directive(void **state) -{ - (void)state; - - ExcludedFiles excludes; - excludes.setClientVersion(ExcludedFiles::Version(2, 5, 0)); - - std::vector> tests = { - { "#!version == 2.5.0", true }, - { "#!version == 2.6.0", false }, - { "#!version < 2.6.0", true }, - { "#!version <= 2.6.0", true }, - { "#!version > 2.6.0", false }, - { "#!version >= 2.6.0", false }, - { "#!version < 2.4.0", false }, - { "#!version <= 2.4.0", false }, - { "#!version > 2.4.0", true }, - { "#!version >= 2.4.0", true }, - { "#!version < 2.5.0", false }, - { "#!version <= 2.5.0", true }, - { "#!version > 2.5.0", false }, - { "#!version >= 2.5.0", true }, - }; - for (auto test : tests) { - assert_true(excludes.versionDirectiveKeepNextLine(test.first) == test.second); - } -} - -}; // class ExcludedFilesTest - -int torture_run_tests(void) -{ - using T = ExcludedFilesTest; - - const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(T::check_csync_exclude_add, T::setup, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_exclude_add_per_dir, T::setup, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_excluded, T::setup_init, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_excluded_per_dir, T::setup, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_excluded_traversal, T::setup_init, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_excluded_traversal_per_dir, T::setup, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_dir_only, T::setup, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_pathes, T::setup_init, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_wildcards, T::setup, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_regex_translation, T::setup, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_bname_trigger, T::setup, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_is_windows_reserved_word, T::setup_init, T::teardown), - cmocka_unit_test_setup_teardown(T::check_csync_excluded_performance, T::setup_init, T::teardown), - cmocka_unit_test(T::check_csync_exclude_expand_escapes), - cmocka_unit_test(T::check_version_directive), - }; - - return cmocka_run_group_tests(tests, nullptr, nullptr); -} diff --git a/test/testexcludedfiles.cpp b/test/testexcludedfiles.cpp index ea68440ad..cb6b3c1a2 100644 --- a/test/testexcludedfiles.cpp +++ b/test/testexcludedfiles.cpp @@ -6,6 +6,7 @@ */ #include +#include #include "csync_exclude.h" @@ -13,10 +14,55 @@ using namespace OCC; #define EXCLUDE_LIST_FILE SOURCEDIR "/../../sync-exclude.lst" +// The tests were converted from the old CMocka framework, that's why there is a global +static QScopedPointer excludedFiles; + +static void setup() { + excludedFiles.reset(new ExcludedFiles); + excludedFiles->setWildcardsMatchSlash(false); +} + +static void setup_init() { + setup(); + + excludedFiles->addExcludeFilePath(EXCLUDE_LIST_FILE); + QVERIFY(excludedFiles->reloadExcludeFiles()); + + /* and add some unicode stuff */ + excludedFiles->addManualExclude("*.💩"); // is this source file utf8 encoded? + excludedFiles->addManualExclude("пятницы.*"); + excludedFiles->addManualExclude("*/*.out"); + excludedFiles->addManualExclude("latex*/*.run.xml"); + excludedFiles->addManualExclude("latex/*/*.tex.tmp"); + + QVERIFY(excludedFiles->reloadExcludeFiles()); +} + class TestExcludedFiles: public QObject { Q_OBJECT +static auto check_file_full(const char *path) +{ + return excludedFiles->fullPatternMatch(path, ItemTypeFile); +} + +static auto check_dir_full(const char *path) +{ + return excludedFiles->fullPatternMatch(path, ItemTypeDirectory); +} + +static auto check_file_traversal(const char *path) +{ + return excludedFiles->traversalPatternMatch(path, ItemTypeFile); +} + +static auto check_dir_traversal(const char *path) +{ + return excludedFiles->traversalPatternMatch(path, ItemTypeDirectory); +} + + private slots: void testFun() { @@ -42,6 +88,623 @@ private slots: QVERIFY(excluded.isExcluded("/a/#b#", "/a", keepHidden)); } + + void check_csync_exclude_add() + { + setup(); + excludedFiles->addManualExclude("/tmp/check_csync1/*"); + QCOMPARE(check_file_full("/tmp/check_csync1/foo"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("/tmp/check_csync2/foo"), CSYNC_NOT_EXCLUDED); + QVERIFY(excludedFiles->_allExcludes[QStringLiteral("/")].contains("/tmp/check_csync1/*")); + + QVERIFY(excludedFiles->_fullRegexFile[QStringLiteral("/")].pattern().contains("csync1")); + QVERIFY(excludedFiles->_fullTraversalRegexFile[QStringLiteral("/")].pattern().contains("csync1")); + QVERIFY(!excludedFiles->_bnameTraversalRegexFile[QStringLiteral("/")].pattern().contains("csync1")); + + excludedFiles->addManualExclude("foo"); + QVERIFY(excludedFiles->_bnameTraversalRegexFile[QStringLiteral("/")].pattern().contains("foo")); + QVERIFY(excludedFiles->_fullRegexFile[QStringLiteral("/")].pattern().contains("foo")); + QVERIFY(!excludedFiles->_fullTraversalRegexFile[QStringLiteral("/")].pattern().contains("foo")); + } + + void check_csync_exclude_add_per_dir() + { + setup(); + excludedFiles->addManualExclude("*", "/tmp/check_csync1/"); + QCOMPARE(check_file_full("/tmp/check_csync1/foo"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("/tmp/check_csync2/foo"), CSYNC_NOT_EXCLUDED); + QVERIFY(excludedFiles->_allExcludes[QStringLiteral("/tmp/check_csync1/")].contains("*")); + + excludedFiles->addManualExclude("foo"); + QVERIFY(excludedFiles->_fullRegexFile[QStringLiteral("/")].pattern().contains("foo")); + + excludedFiles->addManualExclude("foo/bar", "/tmp/check_csync1/"); + QVERIFY(excludedFiles->_fullRegexFile[QStringLiteral("/tmp/check_csync1/")].pattern().contains("bar")); + QVERIFY(excludedFiles->_fullTraversalRegexFile[QStringLiteral("/tmp/check_csync1/")].pattern().contains("bar")); + QVERIFY(!excludedFiles->_bnameTraversalRegexFile[QStringLiteral("/tmp/check_csync1/")].pattern().contains("foo")); + } + + void check_csync_excluded() + { + setup_init(); + QCOMPARE(check_file_full(""), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("/"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("A"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("krawel_krawel"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full(".kde/share/config/kwin.eventsrc"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full(".directory/cache-maximegalon/cache1.txt"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_full("mozilla/.directory"), CSYNC_FILE_EXCLUDE_LIST); + + /* + * Test for patterns in subdirs. '.beagle' is defined as a pattern and has + * to be found in top dir as well as in directories underneath. + */ + QCOMPARE(check_dir_full(".apdisk"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_full("foo/.apdisk"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_full("foo/bar/.apdisk"), CSYNC_FILE_EXCLUDE_LIST); + + QCOMPARE(check_file_full(".java"), CSYNC_NOT_EXCLUDED); + + /* Files in the ignored dir .java will also be ignored. */ + QCOMPARE(check_file_full(".apdisk/totally_amazing.jar"), CSYNC_FILE_EXCLUDE_LIST); + + /* and also in subdirs */ + QCOMPARE(check_file_full("projects/.apdisk/totally_amazing.jar"), CSYNC_FILE_EXCLUDE_LIST); + + /* csync-journal is ignored in general silently. */ + QCOMPARE(check_file_full(".csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_full(".csync_journal.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_full("subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + + /* also the new form of the database name */ + QCOMPARE(check_file_full("._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_full("._sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_full("._sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_full("subdir/._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + + QCOMPARE(check_file_full(".sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_full(".sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_full(".sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_full("subdir/.sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + + + /* pattern ]*.directory - ignore and remove */ + QCOMPARE(check_file_full("my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE); + QCOMPARE(check_file_full("/a_folder/my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE); + + /* Not excluded because the pattern .netscape/cache requires directory. */ + QCOMPARE(check_file_full(".netscape/cache"), CSYNC_NOT_EXCLUDED); + + /* Not excluded */ + QCOMPARE(check_file_full("unicode/中文.hé"), CSYNC_NOT_EXCLUDED); + /* excluded */ + QCOMPARE(check_file_full("unicode/пятницы.txt"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("unicode/中文.💩"), CSYNC_FILE_EXCLUDE_LIST); + + /* path wildcards */ + QCOMPARE(check_file_full("foobar/my_manuscript.out"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("latex_tmp/my_manuscript.run.xml"), CSYNC_FILE_EXCLUDE_LIST); + + QCOMPARE(check_file_full("word_tmp/my_manuscript.run.xml"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_file_full("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_file_full("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST); + + #ifdef _WIN32 + QCOMPARE(check_file_full("file_trailing_space "), CSYNC_FILE_EXCLUDE_TRAILING_SPACE); + + QCOMPARE(check_file_full("file_trailing_dot."), CSYNC_FILE_EXCLUDE_INVALID_CHAR); + QCOMPARE(check_file_full("AUX"), CSYNC_FILE_EXCLUDE_INVALID_CHAR); + QCOMPARE(check_file_full("file_invalid_char<"), CSYNC_FILE_EXCLUDE_INVALID_CHAR); + #endif + + /* ? character */ + excludedFiles->addManualExclude("bond00?"); + excludedFiles->reloadExcludeFiles(); + QCOMPARE(check_file_full("bond00"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("bond007"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("bond0071"), CSYNC_NOT_EXCLUDED); + + /* brackets */ + excludedFiles->addManualExclude("a [bc] d"); + excludedFiles->reloadExcludeFiles(); + QCOMPARE(check_file_full("a d d"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("a d"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("a b d"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("a c d"), CSYNC_FILE_EXCLUDE_LIST); + +#ifndef Q_OS_WIN // Because of CSYNC_FILE_EXCLUDE_INVALID_CHAR on windows + /* escapes */ + excludedFiles->addManualExclude("a \\*"); + excludedFiles->addManualExclude("b \\?"); + excludedFiles->addManualExclude("c \\[d]"); + excludedFiles->reloadExcludeFiles(); + QCOMPARE(check_file_full("a \\*"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("a bc"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("a *"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("b \\?"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("b f"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("b ?"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("c \\[d]"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("c d"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("c [d]"), CSYNC_FILE_EXCLUDE_LIST); +#endif + } + + void check_csync_excluded_per_dir() + { + setup(); + excludedFiles->addManualExclude("A"); + excludedFiles->reloadExcludeFiles(); + + QCOMPARE(check_file_full("A"), CSYNC_FILE_EXCLUDE_LIST); + + excludedFiles->clearManualExcludes(); + excludedFiles->addManualExclude("A", "/B/"); + excludedFiles->reloadExcludeFiles(); + + QCOMPARE(check_file_full("A"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("B/A"), CSYNC_FILE_EXCLUDE_LIST); + + excludedFiles->clearManualExcludes(); + excludedFiles->addManualExclude("A/a1", "/B/"); + excludedFiles->reloadExcludeFiles(); + + QCOMPARE(check_file_full("A"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full("B/A/a1"), CSYNC_FILE_EXCLUDE_LIST); + + #define FOO_DIR "/tmp/check_csync1/foo" + #define FOO_EXCLUDE_LIST FOO_DIR "/.sync-exclude.lst" + int rc = 0; + rc = system("mkdir -p " FOO_DIR); + QCOMPARE(rc, 0); + FILE *fh = fopen(FOO_EXCLUDE_LIST, "w"); + QVERIFY(fh != nullptr); + rc = fprintf(fh, "bar"); + QVERIFY(rc != 0); + rc = fclose(fh); + QCOMPARE(rc, 0); + + excludedFiles->addInTreeExcludeFilePath(FOO_EXCLUDE_LIST); + excludedFiles->reloadExcludeFiles(); + QCOMPARE(check_file_full(FOO_DIR), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_full(FOO_DIR "/bar"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full(FOO_DIR "/baz"), CSYNC_NOT_EXCLUDED); + #undef FOO_DIR + #undef FOO_EXCLUDE_LIST + } + + void check_csync_excluded_traversal_per_dir() + { + setup_init(); + QCOMPARE(check_file_traversal("/"), CSYNC_NOT_EXCLUDED); + + /* path wildcards */ + excludedFiles->addManualExclude("*/*.tex.tmp", "/latex/"); + QCOMPARE(check_file_traversal("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST); + } + + void check_csync_excluded_traversal() + { + setup_init(); + QCOMPARE(check_file_traversal(""), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("/"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_file_traversal("A"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_file_traversal("krawel_krawel"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal(".kde/share/config/kwin.eventsrc"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_dir_traversal("mozilla/.directory"), CSYNC_FILE_EXCLUDE_LIST); + + /* + * Test for patterns in subdirs. '.beagle' is defined as a pattern and has + * to be found in top dir as well as in directories underneath. + */ + QCOMPARE(check_dir_traversal(".apdisk"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_traversal("foo/.apdisk"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_traversal("foo/bar/.apdisk"), CSYNC_FILE_EXCLUDE_LIST); + + QCOMPARE(check_file_traversal(".java"), CSYNC_NOT_EXCLUDED); + + /* csync-journal is ignored in general silently. */ + QCOMPARE(check_file_traversal(".csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_traversal(".csync_journal.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_traversal("subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_traversal("/two/subdir/.csync_journal.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + + /* also the new form of the database name */ + QCOMPARE(check_file_traversal("._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_traversal("._sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_traversal("._sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_traversal("subdir/._sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + + QCOMPARE(check_file_traversal(".sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_traversal(".sync_5bdd60bdfcfa.db.ctmp"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_traversal(".sync_5bdd60bdfcfa.db-shm"), CSYNC_FILE_SILENTLY_EXCLUDED); + QCOMPARE(check_file_traversal("subdir/.sync_5bdd60bdfcfa.db"), CSYNC_FILE_SILENTLY_EXCLUDED); + + /* Other builtin excludes */ + QCOMPARE(check_file_traversal("foo/Desktop.ini"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("Desktop.ini"), CSYNC_FILE_SILENTLY_EXCLUDED); + + /* pattern ]*.directory - ignore and remove */ + QCOMPARE(check_file_traversal("my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE); + QCOMPARE(check_file_traversal("/a_folder/my.~directory"), CSYNC_FILE_EXCLUDE_AND_REMOVE); + + /* Not excluded because the pattern .netscape/cache requires directory. */ + QCOMPARE(check_file_traversal(".netscape/cache"), CSYNC_NOT_EXCLUDED); + + /* Not excluded */ + QCOMPARE(check_file_traversal("unicode/中文.hé"), CSYNC_NOT_EXCLUDED); + /* excluded */ + QCOMPARE(check_file_traversal("unicode/пятницы.txt"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("unicode/中文.💩"), CSYNC_FILE_EXCLUDE_LIST); + + /* path wildcards */ + QCOMPARE(check_file_traversal("foobar/my_manuscript.out"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("latex_tmp/my_manuscript.run.xml"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("word_tmp/my_manuscript.run.xml"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("latex/my_manuscript.tex.tmp"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("latex/songbook/my_manuscript.tex.tmp"), CSYNC_FILE_EXCLUDE_LIST); + + #ifdef _WIN32 + QCOMPARE(check_file_traversal("file_trailing_space "), CSYNC_FILE_EXCLUDE_TRAILING_SPACE); + QCOMPARE(check_file_traversal("file_trailing_dot."), CSYNC_FILE_EXCLUDE_INVALID_CHAR); + QCOMPARE(check_file_traversal("AUX"), CSYNC_FILE_EXCLUDE_INVALID_CHAR); + QCOMPARE(check_file_traversal("file_invalid_char<"), CSYNC_FILE_EXCLUDE_INVALID_CHAR); + #endif + + + /* From here the actual traversal tests */ + + excludedFiles->addManualExclude("/exclude"); + excludedFiles->reloadExcludeFiles(); + + /* Check toplevel dir, the pattern only works for toplevel dir. */ + QCOMPARE(check_dir_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_traversal("/foo/exclude"), CSYNC_NOT_EXCLUDED); + + /* check for a file called exclude. Must still work */ + QCOMPARE(check_file_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("/foo/exclude"), CSYNC_NOT_EXCLUDED); + + /* Add an exclude for directories only: excl/ */ + excludedFiles->addManualExclude("excl/"); + excludedFiles->reloadExcludeFiles(); + QCOMPARE(check_dir_traversal("/excl"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_traversal("meep/excl"), CSYNC_FILE_EXCLUDE_LIST); + + // because leading dirs aren't checked! + QCOMPARE(check_file_traversal("meep/excl/file"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("/excl"), CSYNC_NOT_EXCLUDED); + + excludedFiles->addManualExclude("/excludepath/withsubdir"); + excludedFiles->reloadExcludeFiles(); + + QCOMPARE(check_dir_traversal("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_traversal("/excludepath/withsubdir2"), CSYNC_NOT_EXCLUDED); + + // because leading dirs aren't checked! + QCOMPARE(check_dir_traversal("/excludepath/withsubdir/foo"), CSYNC_NOT_EXCLUDED); + + /* Check ending of pattern */ + QCOMPARE(check_file_traversal("/exclude"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("/excludeX"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("exclude"), CSYNC_NOT_EXCLUDED); + + excludedFiles->addManualExclude("exclude"); + excludedFiles->reloadExcludeFiles(); + QCOMPARE(check_file_traversal("exclude"), CSYNC_FILE_EXCLUDE_LIST); + + /* ? character */ + excludedFiles->addManualExclude("bond00?"); + excludedFiles->reloadExcludeFiles(); + QCOMPARE(check_file_traversal("bond00"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("bond007"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("bond0071"), CSYNC_NOT_EXCLUDED); + + /* brackets */ + excludedFiles->addManualExclude("a [bc] d"); + excludedFiles->reloadExcludeFiles(); + QCOMPARE(check_file_traversal("a d d"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("a d"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("a b d"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("a c d"), CSYNC_FILE_EXCLUDE_LIST); + +#ifndef Q_OS_WIN // Because of CSYNC_FILE_EXCLUDE_INVALID_CHAR on windows + /* escapes */ + excludedFiles->addManualExclude("a \\*"); + excludedFiles->addManualExclude("b \\?"); + excludedFiles->addManualExclude("c \\[d]"); + excludedFiles->reloadExcludeFiles(); + QCOMPARE(check_file_traversal("a \\*"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("a bc"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("a *"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("b \\?"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("b f"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("b ?"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("c \\[d]"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("c d"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("c [d]"), CSYNC_FILE_EXCLUDE_LIST); +#endif + } + + void check_csync_dir_only() + { + setup(); + excludedFiles->addManualExclude("filedir"); + excludedFiles->addManualExclude("dir/"); + + QCOMPARE(check_file_traversal("other"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("filedir"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("dir"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("s/other"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_file_traversal("s/filedir"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("s/dir"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_dir_traversal("other"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_dir_traversal("filedir"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_traversal("dir"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_traversal("s/other"), CSYNC_NOT_EXCLUDED); + QCOMPARE(check_dir_traversal("s/filedir"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_traversal("s/dir"), CSYNC_FILE_EXCLUDE_LIST); + + QCOMPARE(check_dir_full("filedir/foo"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("filedir/foo"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_full("dir/foo"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("dir/foo"), CSYNC_FILE_EXCLUDE_LIST); + } + + void check_csync_pathes() + { + setup_init(); + excludedFiles->addManualExclude("/exclude"); + excludedFiles->reloadExcludeFiles(); + + /* Check toplevel dir, the pattern only works for toplevel dir. */ + QCOMPARE(check_dir_full("/exclude"), CSYNC_FILE_EXCLUDE_LIST); + + QCOMPARE(check_dir_full("/foo/exclude"), CSYNC_NOT_EXCLUDED); + + /* check for a file called exclude. Must still work */ + QCOMPARE(check_file_full("/exclude"), CSYNC_FILE_EXCLUDE_LIST); + + QCOMPARE(check_file_full("/foo/exclude"), CSYNC_NOT_EXCLUDED); + + /* Add an exclude for directories only: excl/ */ + excludedFiles->addManualExclude("excl/"); + excludedFiles->reloadExcludeFiles(); + QCOMPARE(check_dir_full("/excl"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_dir_full("meep/excl"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("meep/excl/file"), CSYNC_FILE_EXCLUDE_LIST); + + QCOMPARE(check_file_full("/excl"), CSYNC_NOT_EXCLUDED); + + excludedFiles->addManualExclude("/excludepath/withsubdir"); + excludedFiles->reloadExcludeFiles(); + + QCOMPARE(check_dir_full("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_full("/excludepath/withsubdir"), CSYNC_FILE_EXCLUDE_LIST); + + QCOMPARE(check_dir_full("/excludepath/withsubdir2"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_dir_full("/excludepath/withsubdir/foo"), CSYNC_FILE_EXCLUDE_LIST); + } + + void check_csync_wildcards() + { + setup(); + excludedFiles->addManualExclude("a/foo*bar"); + excludedFiles->addManualExclude("b/foo*bar*"); + excludedFiles->addManualExclude("c/foo?bar"); + excludedFiles->addManualExclude("d/foo?bar*"); + excludedFiles->addManualExclude("e/foo?bar?"); + excludedFiles->addManualExclude("g/bar*"); + excludedFiles->addManualExclude("h/bar?"); + + excludedFiles->setWildcardsMatchSlash(false); + + QCOMPARE(check_file_traversal("a/fooXYZbar"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("a/fooX/Zbar"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_file_traversal("b/fooXYZbarABC"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("b/fooX/ZbarABC"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_file_traversal("c/fooXbar"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("c/foo/bar"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_file_traversal("d/fooXbarABC"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("d/foo/barABC"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_file_traversal("e/fooXbarA"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("e/foo/barA"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_file_traversal("g/barABC"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("g/XbarABC"), CSYNC_NOT_EXCLUDED); + + QCOMPARE(check_file_traversal("h/barZ"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("h/XbarZ"), CSYNC_NOT_EXCLUDED); + + excludedFiles->setWildcardsMatchSlash(true); + + QCOMPARE(check_file_traversal("a/fooX/Zbar"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("b/fooX/ZbarABC"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("c/foo/bar"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("d/foo/barABC"), CSYNC_FILE_EXCLUDE_LIST); + QCOMPARE(check_file_traversal("e/foo/barA"), CSYNC_FILE_EXCLUDE_LIST); + } + + void check_csync_regex_translation() + { + setup(); + QByteArray storage; + auto translate = [&storage](const char *pattern) { + storage = ExcludedFiles::convertToRegexpSyntax(pattern, false).toUtf8(); + return storage.constData(); + }; + + QCOMPARE(translate(""), ""); + QCOMPARE(translate("abc"), "abc"); + QCOMPARE(translate("a*c"), "a[^/]*c"); + QCOMPARE(translate("a?c"), "a[^/]c"); + QCOMPARE(translate("a[xyz]c"), "a[xyz]c"); + QCOMPARE(translate("a[xyzc"), "a\\[xyzc"); + QCOMPARE(translate("a[!xyz]c"), "a[^xyz]c"); + QCOMPARE(translate("a\\*b\\?c\\[d\\\\e"), "a\\*b\\?c\\[d\\\\e"); + QCOMPARE(translate("a.c"), "a\\.c"); + QCOMPARE(translate("?𠜎?"), "[^/]\\𠜎[^/]"); // 𠜎 is 4-byte utf8 + } + + void check_csync_bname_trigger() + { + setup(); + bool wildcardsMatchSlash = false; + QByteArray storage; + auto translate = [&storage, &wildcardsMatchSlash](const char *pattern) { + storage = ExcludedFiles::extractBnameTrigger(pattern, wildcardsMatchSlash).toUtf8(); + return storage.constData(); + }; + + QCOMPARE(translate(""), ""); + QCOMPARE(translate("a/b/"), ""); + QCOMPARE(translate("a/b/c"), "c"); + QCOMPARE(translate("c"), "c"); + QCOMPARE(translate("a/foo*"), "foo*"); + QCOMPARE(translate("a/abc*foo*"), "abc*foo*"); + + wildcardsMatchSlash = true; + + QCOMPARE(translate(""), ""); + QCOMPARE(translate("a/b/"), ""); + QCOMPARE(translate("a/b/c"), "c"); + QCOMPARE(translate("c"), "c"); + QCOMPARE(translate("*"), "*"); + QCOMPARE(translate("a/foo*"), "foo*"); + QCOMPARE(translate("a/abc?foo*"), "*foo*"); + QCOMPARE(translate("a/abc*foo*"), "*foo*"); + QCOMPARE(translate("a/abc?foo?"), "*foo?"); + QCOMPARE(translate("a/abc*foo?*"), "*foo?*"); + QCOMPARE(translate("a/abc*/foo*"), "foo*"); + } + + void check_csync_is_windows_reserved_word() + { + auto csync_is_windows_reserved_word = [](const char *fn) { + QString s = QString::fromLatin1(fn); + extern bool csync_is_windows_reserved_word(const QStringRef &filename); + return csync_is_windows_reserved_word(&s); + }; + + QVERIFY(csync_is_windows_reserved_word("CON")); + QVERIFY(csync_is_windows_reserved_word("con")); + QVERIFY(csync_is_windows_reserved_word("CON.")); + QVERIFY(csync_is_windows_reserved_word("con.")); + QVERIFY(csync_is_windows_reserved_word("CON.ference")); + QVERIFY(!csync_is_windows_reserved_word("CONference")); + QVERIFY(!csync_is_windows_reserved_word("conference")); + QVERIFY(!csync_is_windows_reserved_word("conf.erence")); + QVERIFY(!csync_is_windows_reserved_word("co")); + + QVERIFY(csync_is_windows_reserved_word("COM2")); + QVERIFY(csync_is_windows_reserved_word("com2")); + QVERIFY(csync_is_windows_reserved_word("COM2.")); + QVERIFY(csync_is_windows_reserved_word("com2.")); + QVERIFY(csync_is_windows_reserved_word("COM2.ference")); + QVERIFY(!csync_is_windows_reserved_word("COM2ference")); + QVERIFY(!csync_is_windows_reserved_word("com2ference")); + QVERIFY(!csync_is_windows_reserved_word("com2f.erence")); + QVERIFY(!csync_is_windows_reserved_word("com")); + + QVERIFY(csync_is_windows_reserved_word("CLOCK$")); + QVERIFY(csync_is_windows_reserved_word("$Recycle.Bin")); + QVERIFY(csync_is_windows_reserved_word("ClocK$")); + QVERIFY(csync_is_windows_reserved_word("$recycle.bin")); + + QVERIFY(csync_is_windows_reserved_word("A:")); + QVERIFY(csync_is_windows_reserved_word("a:")); + QVERIFY(csync_is_windows_reserved_word("z:")); + QVERIFY(csync_is_windows_reserved_word("Z:")); + QVERIFY(csync_is_windows_reserved_word("M:")); + QVERIFY(csync_is_windows_reserved_word("m:")); + } + + /* QT_ENABLE_REGEXP_JIT=0 to get slower results :-) */ + void check_csync_excluded_performance1() + { + setup_init(); + const int N = 1000; + int totalRc = 0; + + QBENCHMARK { + + for (int i = 0; i < N; ++i) { + totalRc += check_dir_full("/this/is/quite/a/long/path/with/many/components"); + 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"); + } + QCOMPARE(totalRc, 0); // mainly to avoid optimization + } + } + + void check_csync_excluded_performance2() + { + const int N = 1000; + int totalRc = 0; + + QBENCHMARK { + for (int i = 0; i < N; ++i) { + totalRc += check_dir_traversal("/this/is/quite/a/long/path/with/many/components"); + 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"); + } + QCOMPARE(totalRc, 0); // mainly to avoid optimization + } + } + + void check_csync_exclude_expand_escapes() + { + extern void csync_exclude_expand_escapes(QByteArray &input); + + QByteArray line = "keep \\' \\\" \\? \\\\ \\a \\b \\f \\n \\r \\t \\v \\z \\#"; + csync_exclude_expand_escapes(line); + QVERIFY(0 == strcmp(line.constData(), "keep ' \" ? \\\\ \a \b \f \n \r \t \v \\z #")); + + line = ""; + csync_exclude_expand_escapes(line); + QVERIFY(0 == strcmp(line.constData(), "")); + + line = "\\"; + csync_exclude_expand_escapes(line); + QVERIFY(0 == strcmp(line.constData(), "\\")); + } + + void check_version_directive() + { + ExcludedFiles excludes; + excludes.setClientVersion(ExcludedFiles::Version(2, 5, 0)); + + std::vector> tests = { + { "#!version == 2.5.0", true }, + { "#!version == 2.6.0", false }, + { "#!version < 2.6.0", true }, + { "#!version <= 2.6.0", true }, + { "#!version > 2.6.0", false }, + { "#!version >= 2.6.0", false }, + { "#!version < 2.4.0", false }, + { "#!version <= 2.4.0", false }, + { "#!version > 2.4.0", true }, + { "#!version >= 2.4.0", true }, + { "#!version < 2.5.0", false }, + { "#!version <= 2.5.0", true }, + { "#!version > 2.5.0", false }, + { "#!version >= 2.5.0", true }, + }; + for (auto test : tests) { + QVERIFY(excludes.versionDirectiveKeepNextLine(test.first) == test.second); + } + } + }; QTEST_APPLESS_MAIN(TestExcludedFiles)