1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03 10 11 // <filesystem> 12 13 // class path 14 15 // int compare(path const&) const noexcept; 16 // int compare(string_type const&) const; 17 // int compare(value_type const*) const; 18 // 19 // bool operator==(path const&, path const&) noexcept; 20 // bool operator!=(path const&, path const&) noexcept; 21 // bool operator< (path const&, path const&) noexcept; 22 // bool operator<=(path const&, path const&) noexcept; 23 // bool operator> (path const&, path const&) noexcept; 24 // bool operator>=(path const&, path const&) noexcept; 25 // 26 // size_t hash_value(path const&) noexcept; 27 28 29 #include "filesystem_include.h" 30 #include <type_traits> 31 #include <vector> 32 #include <cassert> 33 34 #include "test_macros.h" 35 #include "test_iterators.h" 36 #include "count_new.h" 37 #include "filesystem_test_helper.h" 38 #include "verbose_assert.h" 39 40 struct PathCompareTest { 41 const char* LHS; 42 const char* RHS; 43 int expect; 44 }; 45 46 #define LONGA "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 47 #define LONGB "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" 48 #define LONGC "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" 49 #define LONGD "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" 50 const PathCompareTest CompareTestCases[] = 51 { 52 {"", "", 0}, 53 {"a", "", 1}, 54 {"", "a", -1}, 55 {"a/b/c", "a/b/c", 0}, 56 {"b/a/c", "a/b/c", 1}, 57 {"a/b/c", "b/a/c", -1}, 58 {"a/b", "a/b/c", -1}, 59 {"a/b/c", "a/b", 1}, 60 {"a/b/", "a/b/.", -1}, 61 {"a/b/", "a/b", 1}, 62 {"a/b//////", "a/b/////.", -1}, 63 {"a/.././b", "a///..//.////b", 0}, 64 {"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators 65 {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory 66 {"/foo/bar/", "/foo/bar", 1}, // trailing separator 67 {"foo", "/foo", -1}, // if !this->has_root_directory() and p.has_root_directory(), a value less than 0. 68 {"/foo", "foo", 1}, // if this->has_root_directory() and !p.has_root_directory(), a value greater than 0. 69 {"//" LONGA "////" LONGB "/" LONGC "///" LONGD, "//" LONGA "/" LONGB "/" LONGC "/" LONGD, 0}, 70 { LONGA "/" LONGB "/" LONGC, LONGA "/" LONGB "/" LONGB, 1} 71 72 }; 73 #undef LONGA 74 #undef LONGB 75 #undef LONGC 76 #undef LONGD 77 78 static inline int normalize_ret(int ret) 79 { 80 return ret < 0 ? -1 : (ret > 0 ? 1 : 0); 81 } 82 83 void test_compare_basic() 84 { 85 using namespace fs; 86 for (auto const & TC : CompareTestCases) { 87 const path p1(TC.LHS); 88 const path p2(TC.RHS); 89 const std::string R(TC.RHS); 90 const std::string_view RV(TC.RHS); 91 const int E = TC.expect; 92 { // compare(...) functions 93 DisableAllocationGuard g; // none of these operations should allocate 94 95 // check runtime results 96 int ret1 = normalize_ret(p1.compare(p2)); 97 int ret2 = normalize_ret(p1.compare(R)); 98 int ret3 = normalize_ret(p1.compare(TC.RHS)); 99 int ret4 = normalize_ret(p1.compare(RV)); 100 101 g.release(); 102 ASSERT_EQ(ret1, ret2); 103 ASSERT_EQ(ret1, ret3); 104 ASSERT_EQ(ret1, ret4); 105 ASSERT_EQ(ret1, E) 106 << DISPLAY(TC.LHS) << DISPLAY(TC.RHS); 107 108 // check signatures 109 ASSERT_NOEXCEPT(p1.compare(p2)); 110 } 111 { // comparison operators 112 DisableAllocationGuard g; // none of these operations should allocate 113 114 // Check runtime result 115 assert((p1 == p2) == (E == 0)); 116 assert((p1 != p2) == (E != 0)); 117 assert((p1 < p2) == (E < 0)); 118 assert((p1 <= p2) == (E <= 0)); 119 assert((p1 > p2) == (E > 0)); 120 assert((p1 >= p2) == (E >= 0)); 121 122 // Check signatures 123 ASSERT_NOEXCEPT(p1 == p2); 124 ASSERT_NOEXCEPT(p1 != p2); 125 ASSERT_NOEXCEPT(p1 < p2); 126 ASSERT_NOEXCEPT(p1 <= p2); 127 ASSERT_NOEXCEPT(p1 > p2); 128 ASSERT_NOEXCEPT(p1 >= p2); 129 } 130 { // check hash values 131 auto h1 = hash_value(p1); 132 auto h2 = hash_value(p2); 133 assert((h1 == h2) == (p1 == p2)); 134 // check signature 135 ASSERT_SAME_TYPE(size_t, decltype(hash_value(p1))); 136 ASSERT_NOEXCEPT(hash_value(p1)); 137 } 138 } 139 } 140 141 int CompareElements(std::vector<std::string> const& LHS, std::vector<std::string> const& RHS) { 142 bool IsLess = std::lexicographical_compare(LHS.begin(), LHS.end(), RHS.begin(), RHS.end()); 143 if (IsLess) 144 return -1; 145 146 bool IsGreater = std::lexicographical_compare(RHS.begin(), RHS.end(), LHS.begin(), LHS.end()); 147 if (IsGreater) 148 return 1; 149 150 return 0; 151 } 152 153 void test_compare_elements() { 154 struct { 155 std::vector<std::string> LHSElements; 156 std::vector<std::string> RHSElements; 157 int Expect; 158 } TestCases[] = { 159 {{"a"}, {"a"}, 0}, 160 {{"a"}, {"b"}, -1}, 161 {{"b"}, {"a"}, 1}, 162 {{"a", "b", "c"}, {"a", "b", "c"}, 0}, 163 {{"a", "b", "c"}, {"a", "b", "d"}, -1}, 164 {{"a", "b", "d"}, {"a", "b", "c"}, 1}, 165 {{"a", "b"}, {"a", "b", "c"}, -1}, 166 {{"a", "b", "c"}, {"a", "b"}, 1}, 167 168 }; 169 170 auto BuildPath = [](std::vector<std::string> const& Elems) { 171 fs::path p; 172 for (auto &E : Elems) 173 p /= E; 174 return p; 175 }; 176 177 for (auto &TC : TestCases) { 178 fs::path LHS = BuildPath(TC.LHSElements); 179 fs::path RHS = BuildPath(TC.RHSElements); 180 const int ExpectCmp = CompareElements(TC.LHSElements, TC.RHSElements); 181 assert(ExpectCmp == TC.Expect); 182 const int GotCmp = normalize_ret(LHS.compare(RHS)); 183 assert(GotCmp == TC.Expect); 184 } 185 } 186 187 int main(int, char**) { 188 test_compare_basic(); 189 test_compare_elements(); 190 191 return 0; 192 } 193