Преглед изворни кода

AK: Add LexicalPath::is_child_of

This API checks whether this path is a child of (or the same as) another
path.
kleines Filmröllchen пре 3 година
родитељ
комит
16ca41ec10
3 измењених фајлова са 58 додато и 0 уклоњено
  1. 16 0
      AK/LexicalPath.cpp
  2. 1 0
      AK/LexicalPath.h
  3. 41 0
      Tests/AK/TestLexicalPath.cpp

+ 16 - 0
AK/LexicalPath.cpp

@@ -72,6 +72,22 @@ bool LexicalPath::has_extension(StringView extension) const
     return m_string.ends_with(extension, CaseSensitivity::CaseInsensitive);
 }
 
+bool LexicalPath::is_child_of(LexicalPath const& possible_parent) const
+{
+    // Any relative path is a child of an absolute path.
+    if (!this->is_absolute() && possible_parent.is_absolute())
+        return true;
+    // An absolute path can't meaningfully be a child of a relative path.
+    if (this->is_absolute() && !possible_parent.is_absolute())
+        return false;
+
+    // Two relative paths and two absolute paths can be meaningfully compared.
+    if (possible_parent.parts_view().size() > this->parts_view().size())
+        return false;
+    auto common_parts_with_parent = this->parts_view().span().trim(possible_parent.parts_view().size());
+    return common_parts_with_parent == possible_parent.parts_view().span();
+}
+
 DeprecatedString LexicalPath::canonicalized_path(DeprecatedString path)
 {
     if (path.is_null())

+ 1 - 0
AK/LexicalPath.h

@@ -33,6 +33,7 @@ public:
     [[nodiscard]] Vector<DeprecatedString> parts() const;
 
     bool has_extension(StringView) const;
+    bool is_child_of(LexicalPath const& possible_parent) const;
 
     [[nodiscard]] LexicalPath append(StringView) const;
     [[nodiscard]] LexicalPath prepend(StringView) const;

+ 41 - 0
Tests/AK/TestLexicalPath.cpp

@@ -208,3 +208,44 @@ TEST_CASE(parent)
         EXPECT_EQ(parent.string(), "/");
     }
 }
+
+TEST_CASE(is_child_of)
+{
+    {
+        LexicalPath parent("/a/parent/directory");
+        LexicalPath child("/a/parent/directory/a/child");
+        LexicalPath mismatching("/not/a/child/directory");
+        EXPECT(child.is_child_of(parent));
+        EXPECT(child.is_child_of(child));
+        EXPECT(parent.is_child_of(parent));
+        EXPECT(!parent.is_child_of(child));
+        EXPECT(!mismatching.is_child_of(parent));
+
+        EXPECT(parent.is_child_of(parent.parent()));
+        EXPECT(child.parent().parent().is_child_of(parent));
+        EXPECT(!child.parent().parent().parent().is_child_of(parent));
+    }
+    {
+        LexicalPath root("/");
+        EXPECT(LexicalPath("/").is_child_of(root));
+        EXPECT(LexicalPath("/any").is_child_of(root));
+        EXPECT(LexicalPath("/child/directory").is_child_of(root));
+    }
+    {
+        LexicalPath relative("folder");
+        LexicalPath relative_child("folder/sub");
+        LexicalPath absolute("/folder");
+        LexicalPath absolute_child("/folder/sub");
+        EXPECT(relative_child.is_child_of(relative));
+        EXPECT(absolute_child.is_child_of(absolute));
+
+        EXPECT(relative.is_child_of(absolute));
+        EXPECT(relative.is_child_of(absolute_child));
+        EXPECT(relative_child.is_child_of(absolute));
+        EXPECT(relative_child.is_child_of(absolute_child));
+
+        EXPECT(!absolute.is_child_of(relative));
+        EXPECT(!absolute_child.is_child_of(relative));
+        EXPECT(!absolute_child.is_child_of(relative_child));
+    }
+}