File indexing completed on 2024-05-12 04:40:20
0001 /* 0002 SPDX-FileCopyrightText: 2013 Milian Wolff <mail@milianw.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "test_projectfilter.h" 0008 0009 #include <QTest> 0010 #include <KConfigGroup> 0011 0012 #include <tests/testcore.h> 0013 #include <tests/autotestshell.h> 0014 #include <tests/testproject.h> 0015 0016 #include "../projectfilter.h" 0017 0018 QTEST_GUILESS_MAIN(TestProjectFilter) 0019 0020 using namespace KDevelop; 0021 0022 using TestFilter = QSharedPointer<ProjectFilter>; 0023 0024 Q_DECLARE_METATYPE(TestFilter) 0025 0026 namespace { 0027 0028 const bool Invalid = false; 0029 const bool Valid = true; 0030 const bool Folder = true; 0031 const bool File = false; 0032 0033 struct MatchTest 0034 { 0035 QString path; 0036 bool isFolder; 0037 bool shouldMatch; 0038 }; 0039 0040 void addTests(const char* tag, const TestProject& project, const TestFilter& filter, const MatchTest* tests, 0041 uint numTests) 0042 { 0043 for (uint i = 0; i < numTests; ++i) { 0044 const MatchTest& test = tests[i]; 0045 QTest::addRow("%s:%s", tag, qUtf8Printable(test.path)) 0046 << filter << Path(project.path(), test.path) << test.isFolder << test.shouldMatch; 0047 0048 if (test.isFolder) { 0049 // also test folder with trailing slash - should not make a difference 0050 QTest::addRow("%s:%s/", tag, qUtf8Printable(test.path)) 0051 << filter << Path(project.path(), test.path) << test.isFolder << test.shouldMatch; 0052 } 0053 } 0054 } 0055 0056 template<typename T> 0057 void addTests(const char* tag, const TestProject& project, const TestFilter& filter, const T& tests) 0058 { 0059 addTests(tag, project, filter, tests, std::size(tests)); 0060 } 0061 0062 struct BenchData 0063 { 0064 BenchData(const Path &path = Path(), bool isFolder = false) 0065 : path(path) 0066 , isFolder(isFolder) 0067 {} 0068 0069 Path path; 0070 bool isFolder; 0071 }; 0072 0073 } 0074 0075 Q_DECLARE_METATYPE(QVector<BenchData>) 0076 0077 void TestProjectFilter::initTestCase() 0078 { 0079 AutoTestShell::init(); 0080 TestCore::initialize(Core::NoUi); 0081 qRegisterMetaType<TestFilter>(); 0082 qRegisterMetaType<Path>(); 0083 qRegisterMetaType<QVector<BenchData> >(); 0084 } 0085 0086 void TestProjectFilter::cleanupTestCase() 0087 { 0088 TestCore::shutdown(); 0089 } 0090 0091 void TestProjectFilter::match() 0092 { 0093 QFETCH(TestFilter, filter); 0094 QFETCH(KDevelop::Path, path); 0095 QFETCH(bool, isFolder); 0096 QFETCH(bool, expectedIsValid); 0097 0098 QCOMPARE(filter->isValid(path, isFolder), expectedIsValid); 0099 } 0100 0101 void TestProjectFilter::match_data() 0102 { 0103 QTest::addColumn<TestFilter>("filter"); 0104 QTest::addColumn<Path>("path"); 0105 QTest::addColumn<bool>("isFolder"); 0106 QTest::addColumn<bool>("expectedIsValid"); 0107 0108 { 0109 // test default filters 0110 const TestProject project; 0111 TestFilter filter(new ProjectFilter(&project, deserialize(defaultFilters()))); 0112 0113 QTest::newRow("projectRoot") << filter << project.path() << Folder << Valid; 0114 QTest::newRow("project.kdev4") << filter << project.projectFile() << File << Invalid; 0115 0116 MatchTest tests[] = { 0117 //{path, isFolder, isValid} 0118 {QStringLiteral(".kdev4"), Folder, Invalid}, 0119 0120 {QStringLiteral("folder"), Folder, Valid}, 0121 {QStringLiteral("folder/folder"), Folder, Valid}, 0122 {QStringLiteral("file"), File, Valid}, 0123 {QStringLiteral("folder/file"), File, Valid}, 0124 {QStringLiteral(".file"), File, Invalid}, 0125 {QStringLiteral(".folder"), Folder, Invalid}, 0126 {QStringLiteral("folder/.folder"), Folder, Invalid}, 0127 {QStringLiteral("folder/.file"), File, Invalid}, 0128 0129 {QStringLiteral(".git"), Folder, Invalid}, 0130 {QStringLiteral(".gitignore"), File, Valid}, 0131 {QStringLiteral(".gitmodules"), File, Valid}, 0132 {QStringLiteral("_darcs"), Folder, Invalid}, 0133 {QStringLiteral("_svn"), Folder, Invalid}, 0134 {QStringLiteral(".svn"), Folder, Invalid}, 0135 {QStringLiteral("CVS"), Folder, Invalid}, 0136 {QStringLiteral("SCCS"), Folder, Invalid}, 0137 {QStringLiteral(".hg"), Folder, Invalid}, 0138 {QStringLiteral(".bzr"), Folder, Invalid}, 0139 0140 {QStringLiteral("foo.o"), File, Invalid}, 0141 {QStringLiteral("foo.so"), File, Invalid}, 0142 {QStringLiteral("foo.so.1"), File, Invalid}, 0143 {QStringLiteral("foo.a"), File, Invalid}, 0144 {QStringLiteral("moc_foo.cpp"), File, Invalid}, 0145 {QStringLiteral("ui_foo.h"), File, Invalid}, 0146 {QStringLiteral("qrc_foo.cpp"), File, Invalid}, 0147 {QStringLiteral("foo.cpp~"), File, Invalid}, 0148 {QStringLiteral(".foo.cpp.kate-swp"), File, Invalid}, 0149 {QStringLiteral(".foo.cpp.swp"), File, Invalid}, 0150 0151 // Default code quality tools explicitly checked 0152 {QStringLiteral(".bumpversion.cfg"), File, Valid}, 0153 {QStringLiteral(".clang-format"), File, Valid}, 0154 {QStringLiteral(".clippy.toml"), File, Valid}, 0155 {QStringLiteral(".codespellrc"), File, Valid}, 0156 {QStringLiteral(".isort.cfg"), File, Valid}, 0157 {QStringLiteral(".mypy.ini"), File, Valid}, 0158 {QStringLiteral(".pydocstyle"), File, Valid}, 0159 {QStringLiteral(".pydocstyle.ini"), File, Valid}, 0160 {QStringLiteral(".pydocstylerc"), File, Valid}, 0161 {QStringLiteral(".pydocstylerc.ini"), File, Valid}, 0162 {QStringLiteral(".pylintrc"), File, Valid}, 0163 {QStringLiteral(".readthedocs.yaml"), File, Valid}, 0164 {QStringLiteral(".readthedocs.yml"), File, Valid}, 0165 {QStringLiteral(".yamllint"), File, Valid}, 0166 {QStringLiteral(".yamllint.yaml"), File, Valid}, 0167 {QStringLiteral(".yamllint.yml"), File, Valid}, 0168 0169 // Code quality tool similar files that should remain hidden 0170 {QStringLiteral(".mypy_cache"), Folder, Invalid}, 0171 {QStringLiteral(".pylint.d"), Folder, Invalid}, 0172 {QStringLiteral(".pytest_cache"), File, Invalid}, 0173 {QStringLiteral(".tox"), File, Invalid}, 0174 }; 0175 addTests("default", project, filter, tests); 0176 } 0177 { 0178 // test exclude files, basename 0179 const TestProject project; 0180 const Filters filters = Filters() 0181 << Filter(SerializedFilter(QStringLiteral("*.cpp"), Filter::Files)); 0182 TestFilter filter(new ProjectFilter(&project, filters)); 0183 0184 QTest::newRow("projectRoot") << filter << project.path() << Folder << Valid; 0185 QTest::newRow("project.kdev4") << filter << project.projectFile() << File << Invalid; 0186 0187 MatchTest tests[] = { 0188 //{path, isFolder, isValid} 0189 {QStringLiteral(".kdev4"), Folder, Invalid}, 0190 0191 {QStringLiteral("folder"), Folder, Valid}, 0192 {QStringLiteral("file"), File, Valid}, 0193 {QStringLiteral("file.cpp"), File, Invalid}, 0194 {QStringLiteral("folder.cpp"), Folder, Valid}, 0195 {QStringLiteral("folder/file.cpp"), File, Invalid}, 0196 {QStringLiteral("folder/folder.cpp"), Folder, Valid} 0197 }; 0198 addTests("exclude:*.cpp", project, filter, tests); 0199 } 0200 { 0201 // test excludes on folders 0202 const TestProject project; 0203 const Filters filters = Filters() 0204 << Filter(SerializedFilter(QStringLiteral("foo"), Filter::Folders)); 0205 TestFilter filter(new ProjectFilter(&project, filters)); 0206 0207 QTest::newRow("projectRoot") << filter << project.path() << Folder << Valid; 0208 QTest::newRow("project.kdev4") << filter << project.projectFile() << File << Invalid; 0209 0210 MatchTest tests[] = { 0211 //{path, isFolder, isValid} 0212 {QStringLiteral(".kdev4"), Folder, Invalid}, 0213 0214 {QStringLiteral("folder"), Folder, Valid}, 0215 {QStringLiteral("file"), File, Valid}, 0216 {QStringLiteral("foo"), Folder, Invalid}, 0217 {QStringLiteral("folder/file"), File, Valid}, 0218 {QStringLiteral("folder/foo"), Folder, Invalid}, 0219 {QStringLiteral("folder/foo"), File, Valid} 0220 }; 0221 addTests("exclude:foo", project, filter, tests); 0222 } 0223 { 0224 // test includes 0225 const TestProject project; 0226 const Filters filters = Filters() 0227 << Filter(SerializedFilter(QStringLiteral("*"), Filter::Files)) 0228 << Filter(SerializedFilter(QStringLiteral("*.cpp"), Filter::Files, Filter::Inclusive)); 0229 TestFilter filter(new ProjectFilter(&project, filters)); 0230 0231 QTest::newRow("projectRoot") << filter << project.path() << Folder << Valid; 0232 QTest::newRow("project.kdev4") << filter << project.projectFile() << File << Invalid; 0233 0234 MatchTest tests[] = { 0235 //{path, isFolder, isValid} 0236 {QStringLiteral(".kdev4"), Folder, Invalid}, 0237 0238 {QStringLiteral("folder"), Folder, Valid}, 0239 {QStringLiteral("file"), File, Invalid}, 0240 {QStringLiteral("file.cpp"), File, Valid}, 0241 {QStringLiteral(".file.cpp"), File, Valid}, 0242 {QStringLiteral("folder/file.cpp"), File, Valid}, 0243 {QStringLiteral("folder/.file.cpp"), File, Valid} 0244 }; 0245 addTests("include:*.cpp", project, filter, tests); 0246 project.projectConfiguration(); 0247 } 0248 { 0249 // test mixed stuff 0250 const TestProject project; 0251 const Filters filters = Filters() 0252 << Filter(SerializedFilter(QStringLiteral("*"), Filter::Files, Filter::Exclusive)) 0253 << Filter(SerializedFilter(QStringLiteral("*.inc"), Filter::Files, Filter::Inclusive)) 0254 << Filter(SerializedFilter(QStringLiteral("*ex.inc"), Filter::Files, Filter::Exclusive)) 0255 << Filter(SerializedFilter(QStringLiteral("bar"), Filter::Folders, Filter::Exclusive)); 0256 TestFilter filter(new ProjectFilter(&project, filters)); 0257 0258 QTest::newRow("projectRoot") << filter << project.path() << Folder << Valid; 0259 QTest::newRow("project.kdev4") << filter << project.projectFile() << File << Invalid; 0260 0261 MatchTest tests[] = { 0262 //{path, isFolder, isValid} 0263 {QStringLiteral(".kdev4"), Folder, Invalid}, 0264 0265 {QStringLiteral("folder"), Folder, Valid}, 0266 {QStringLiteral("file"), File, Invalid}, 0267 {QStringLiteral("file.inc"), File, Valid}, 0268 {QStringLiteral("file.ex.inc"), File, Invalid}, 0269 {QStringLiteral("folder/file"), File, Invalid}, 0270 {QStringLiteral("folder/file.inc"), File, Valid}, 0271 {QStringLiteral("folder/file.ex.inc"), File, Invalid}, 0272 {QStringLiteral("bar"), Folder, Invalid}, 0273 }; 0274 addTests("mixed", project, filter, tests); 0275 } 0276 { 0277 // relative path 0278 const TestProject project; 0279 const Filters filters = Filters() 0280 << Filter(SerializedFilter(QStringLiteral("/foo/*bar"), Filter::Targets(Filter::Files | Filter::Folders))); 0281 TestFilter filter(new ProjectFilter(&project, filters)); 0282 0283 QTest::newRow("projectRoot") << filter << project.path() << Folder << Valid; 0284 QTest::newRow("project.kdev4") << filter << project.projectFile() << File << Invalid; 0285 0286 MatchTest tests[] = { 0287 //{path, isFolder, isValid} 0288 {QStringLiteral(".kdev4"), Folder, Invalid}, 0289 0290 {QStringLiteral("foo"), Folder, Valid}, 0291 {QStringLiteral("bar"), File, Valid}, 0292 {QStringLiteral("foo/bar"), Folder, Invalid}, 0293 {QStringLiteral("foo/bar"), File, Invalid}, 0294 {QStringLiteral("foo/asdf/bar"), Folder, Invalid}, 0295 {QStringLiteral("foo/asdf/bar"), File, Invalid}, 0296 {QStringLiteral("foo/asdf_bar"), Folder, Invalid}, 0297 {QStringLiteral("foo/asdf_bar"), File, Invalid}, 0298 {QStringLiteral("asdf/bar"), File, Valid}, 0299 {QStringLiteral("asdf/foo/bar"), File, Valid}, 0300 }; 0301 addTests("relative", project, filter, tests); 0302 } 0303 { 0304 // trailing slash 0305 const TestProject project; 0306 const Filters filters = Filters() 0307 << Filter(SerializedFilter(QStringLiteral("bar/"), Filter::Targets(Filter::Files | Filter::Folders))); 0308 TestFilter filter(new ProjectFilter(&project, filters)); 0309 0310 QTest::newRow("projectRoot") << filter << project.path() << Folder << Valid; 0311 QTest::newRow("project.kdev4") << filter << project.projectFile() << File << Invalid; 0312 0313 MatchTest tests[] = { 0314 //{path, isFolder, isValid} 0315 {QStringLiteral(".kdev4"), Folder, Invalid}, 0316 0317 {QStringLiteral("foo"), Folder, Valid}, 0318 {QStringLiteral("bar"), File, Valid}, 0319 {QStringLiteral("bar"), Folder, Invalid}, 0320 {QStringLiteral("foo/bar"), File, Valid}, 0321 {QStringLiteral("foo/bar"), Folder, Invalid} 0322 }; 0323 addTests("trailingslash", project, filter, tests); 0324 } 0325 { 0326 // escaping 0327 const TestProject project; 0328 const Filters filters = Filters() 0329 << Filter(SerializedFilter(QStringLiteral("foo\\*bar"), Filter::Files)); 0330 TestFilter filter(new ProjectFilter(&project, filters)); 0331 0332 QTest::newRow("projectRoot") << filter << project.path() << Folder << Valid; 0333 QTest::newRow("project.kdev4") << filter << project.projectFile() << File << Invalid; 0334 0335 MatchTest tests[] = { 0336 //{path, isFolder, isValid} 0337 {QStringLiteral(".kdev4"), Folder, Invalid}, 0338 0339 {QStringLiteral("foobar"), Folder, Valid}, 0340 {QStringLiteral("fooasdfbar"), File, Valid}, 0341 {QStringLiteral("foo*bar"), File, Invalid}, 0342 {QStringLiteral("foo/bar"), Folder, Valid} 0343 }; 0344 addTests("escaping", project, filter, tests); 0345 } 0346 } 0347 0348 static QVector<BenchData> createBenchData(const Path& base, int folderDepth, int foldersPerFolder, int filesPerFolder) 0349 { 0350 QVector<BenchData> data; 0351 data << BenchData(base, true); 0352 0353 for(int i = 0; i < filesPerFolder; ++i) { 0354 if (i % 2) { 0355 data << BenchData(Path(base, QStringLiteral("file%1.cpp").arg(i)), false); 0356 } else { 0357 data << BenchData(Path(base, QStringLiteral("file%1.h").arg(i)), true); 0358 } 0359 } 0360 for(int i = 0; i < foldersPerFolder && folderDepth > 0; ++i) { 0361 data += createBenchData(Path(base, QStringLiteral("folder%1").arg(i)), folderDepth - 1, foldersPerFolder, filesPerFolder); 0362 } 0363 return data; 0364 } 0365 0366 void TestProjectFilter::bench() 0367 { 0368 QFETCH(TestFilter, filter); 0369 QFETCH(const QVector<BenchData>, data); 0370 0371 QBENCHMARK { 0372 for (const BenchData& bench : data) { 0373 filter->isValid(bench.path, bench.isFolder); 0374 } 0375 } 0376 } 0377 0378 void TestProjectFilter::bench_data() 0379 { 0380 QTest::addColumn<TestFilter>("filter"); 0381 QTest::addColumn<QVector<BenchData> >("data"); 0382 0383 const TestProject project; 0384 0385 const QVector<QVector<BenchData> > dataSets = QVector<QVector<BenchData> >() 0386 << createBenchData(project.path(), 3, 5, 10) 0387 << createBenchData(project.path(), 3, 5, 20) 0388 << createBenchData(project.path(), 4, 5, 10) 0389 << createBenchData(project.path(), 3, 10, 10); 0390 0391 { 0392 TestFilter filter(new ProjectFilter(&project, Filters())); 0393 for (const QVector<BenchData>& data : dataSets) { 0394 QTest::newRow(QByteArray("baseline-" + QByteArray::number(data.size()))) << filter << data; 0395 } 0396 } 0397 0398 { 0399 TestFilter filter(new ProjectFilter(&project, deserialize(defaultFilters()))); 0400 for (const QVector<BenchData>& data : dataSets) { 0401 QTest::newRow(QByteArray("defaults-" + QByteArray::number(data.size()))) << filter << data; 0402 } 0403 } 0404 } 0405 0406 #include "moc_test_projectfilter.cpp"