From 22720fdd3e7d4ed326b95e8a6243379cbf7150c8 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 4 Feb 2025 12:47:55 +0100 Subject: [PATCH] Utils: Add FilePath::pathComponents() Change-Id: I8741ea395435d90b30c2d07a1c33355213300ad7 Reviewed-by: hjk --- src/libs/utils/filepath.cpp | 31 +++++++++++++ src/libs/utils/filepath.h | 2 + tests/auto/utils/filepath/tst_filepath.cpp | 53 ++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index b3704617314..a3263e4a0e9 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -531,6 +531,37 @@ QString FilePath::completeSuffix() const return {}; } +QList FilePath::pathComponents() const +{ + QList result; + QStringView path = pathView(); + int start = 0; + + if (osType() == OsTypeWindows && startsWithDriveLetter()) { + start = 2; + result.append(path.mid(0, 2)); + if (path.size() == 2) + return result; + else if (path.at(2) == '/') { + result.append(path.mid(2, 1)); + start = 3; + } + } + + while (start < path.size()) { + int end = path.indexOf('/', start); + if (end == -1) + end = path.size(); + // Consider "/" as a path component + if (end == 0) + result.append(path.mid(start, 1)); + else + result.append(path.mid(start, end - start)); + start = end + 1; + } + return result; +} + QStringView FilePath::scheme() const { return QStringView{m_data}.mid(m_pathLen, m_schemeLen); diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index bf6a13c740b..7106954dfa7 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -138,6 +138,8 @@ public: QStringView suffixView() const; QString completeSuffix() const; + [[nodiscard]] QList pathComponents() const; + [[nodiscard]] FilePath pathAppended(const QString &str) const; [[nodiscard]] FilePath stringAppended(const QString &str) const; [[nodiscard]] std::optional tailRemoved(const QString &str) const; diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index e04dbc53b2d..6b8cd057336 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -129,6 +129,9 @@ private slots: void isRelativePath(); void isRelativePath_data(); + void pathComponents(); + void pathComponents_data(); + private: QTemporaryDir tempDir; QString rootPath; @@ -1883,6 +1886,56 @@ void tst_filepath::dontBreakPathOnWierdWindowsPaths() QCOMPARE(path4.toUrlishString(), "device://host/./foo/bar"); } +void tst_filepath::pathComponents_data() +{ + QTest::addColumn("path"); + QTest::addColumn("expected"); + + QTest::newRow("empty") << "" << QStringList{}; + QTest::newRow("root") << "/" << QStringList{"/"}; + QTest::newRow("relative") << "foo" << QStringList{"foo"}; + QTest::newRow("relative-path") << "foo/bar" << QStringList{"foo", "bar"}; + QTest::newRow("absolute") << "/foo" << QStringList{"/", "foo"}; + QTest::newRow("absolute-path") << "/foo/bar" << QStringList{"/", "foo", "bar"}; + QTest::newRow("remote") << "device://host/foo" << QStringList{"/", "foo"}; + QTest::newRow("remote-path") << "device://host/foo/bar" << QStringList{"/", "foo", "bar"}; + QTest::newRow("remote-relative") << "device://host/./foo" << QStringList{"foo"}; + QTest::newRow("windows-current-dir") << "c:" << QStringList{"c:"}; + + QTest::newRow("single-letter") << "c" << QStringList{"c"}; + QTest::newRow("single-letter-path") << "c/b" << QStringList{"c", "b"}; + QTest::newRow("single-letter-path-with-root") << "/c/b" << QStringList{"/", "c", "b"}; + + if (HostOsInfo::isWindowsHost()) { + QTest::newRow("cwd-windows-path") << "c:foo" << QStringList{"c:", "foo"}; + QTest::newRow("windows-path") << "c:/" << QStringList{"c:", "/"}; + QTest::newRow("windows-path-2") << "c:/test" << QStringList{"c:", "/", "test"}; + QTest::newRow("single-letter-path-with-windows-root") + << "c:/a/b/c" << QStringList{"c:", "/", "a", "b", "c"}; + QTest::newRow("windows-path-with-dir") << "c:/foo" << QStringList{"c:", "/", "foo"}; + } else { + QTest::newRow("cwd-windows-path") << "c:foo" << QStringList{"c:foo"}; + QTest::newRow("windows-path") << "c:/" << QStringList{"c:"}; + QTest::newRow("windows-path-2") << "c:/test" << QStringList{"c:", "test"}; + QTest::newRow("single-letter-path-with-windows-root") + << "c:/a/b/c" << QStringList{"c:", "a", "b", "c"}; + QTest::newRow("windows-path-with-dir") << "c:/foo" << QStringList{"c:", "foo"}; + } +} + +void tst_filepath::pathComponents() +{ + QFETCH(QString, path); + QFETCH(QStringList, expected); + + const auto components + = Utils::transform(FilePath::fromString(path).pathComponents(), [](auto view) { + return QString(view); + }); + + QCOMPARE(components, expected); +} + } // Utils QTEST_GUILESS_MAIN(Utils::tst_filepath)