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 39 struct PathCompareTest { 40 const char* LHS; 41 const char* RHS; 42 int expect; 43 }; 44 45 #define LONGA "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 46 #define LONGB "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" 47 #define LONGC "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" 48 #define LONGD "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" 49 const PathCompareTest CompareTestCases[] = 50 { 51 {"", "", 0}, 52 {"a", "", 1}, 53 {"", "a", -1}, 54 {"a/b/c", "a/b/c", 0}, 55 {"b/a/c", "a/b/c", 1}, 56 {"a/b/c", "b/a/c", -1}, 57 {"a/b", "a/b/c", -1}, 58 {"a/b/c", "a/b", 1}, 59 {"a/b/", "a/b/.", -1}, 60 {"a/b/", "a/b", 1}, 61 {"a/b//////", "a/b/////.", -1}, 62 {"a/.././b", "a///..//.////b", 0}, 63 {"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators 64 {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory 65 {"/foo/bar/", "/foo/bar", 1}, // trailing separator 66 {"foo", "/foo", -1}, // if !this->has_root_directory() and p.has_root_directory(), a value less than 0. 67 {"/foo", "foo", 1}, // if this->has_root_directory() and !p.has_root_directory(), a value greater than 0. 68 {("//" LONGA "////" LONGB "/" LONGC "///" LONGD), ("//" LONGA "/" LONGB "/" LONGC "/" LONGD), 0}, 69 {(LONGA "/" LONGB "/" LONGC), (LONGA "/" LONGB "/" LONGB), 1} 70 71 }; 72 #undef LONGA 73 #undef LONGB 74 #undef LONGC 75 #undef LONGD 76 77 static inline int normalize_ret(int ret) 78 { 79 return ret < 0 ? -1 : (ret > 0 ? 1 : 0); 80 } 81 82 void test_compare_basic() 83 { 84 using namespace fs; 85 for (auto const & TC : CompareTestCases) { 86 const path p1(TC.LHS); 87 const path p2(TC.RHS); 88 const std::string R(TC.RHS); 89 const std::string_view RV(TC.RHS); 90 const int E = TC.expect; 91 { // compare(...) functions 92 DisableAllocationGuard g; // none of these operations should allocate 93 94 // check runtime results 95 int ret1 = normalize_ret(p1.compare(p2)); 96 int ret2 = normalize_ret(p1.compare(R)); 97 int ret3 = normalize_ret(p1.compare(TC.RHS)); 98 int ret4 = normalize_ret(p1.compare(RV)); 99 100 g.release(); 101 assert(ret1 == ret2); 102 assert(ret1 == ret3); 103 assert(ret1 == ret4); 104 assert(ret1 == E); 105 106 // check signatures 107 ASSERT_NOEXCEPT(p1.compare(p2)); 108 } 109 { // comparison operators 110 DisableAllocationGuard g; // none of these operations should allocate 111 112 // Check runtime result 113 assert((p1 == p2) == (E == 0)); 114 assert((p1 != p2) == (E != 0)); 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 120 // Check signatures 121 ASSERT_NOEXCEPT(p1 == p2); 122 ASSERT_NOEXCEPT(p1 != p2); 123 ASSERT_NOEXCEPT(p1 < p2); 124 ASSERT_NOEXCEPT(p1 <= p2); 125 ASSERT_NOEXCEPT(p1 > p2); 126 ASSERT_NOEXCEPT(p1 >= p2); 127 } 128 { // check hash values 129 auto h1 = hash_value(p1); 130 auto h2 = hash_value(p2); 131 assert((h1 == h2) == (p1 == p2)); 132 // check signature 133 ASSERT_SAME_TYPE(size_t, decltype(hash_value(p1))); 134 ASSERT_NOEXCEPT(hash_value(p1)); 135 } 136 } 137 } 138 139 int CompareElements(std::vector<std::string> const& LHS, std::vector<std::string> const& RHS) { 140 bool IsLess = std::lexicographical_compare(LHS.begin(), LHS.end(), RHS.begin(), RHS.end()); 141 if (IsLess) 142 return -1; 143 144 bool IsGreater = std::lexicographical_compare(RHS.begin(), RHS.end(), LHS.begin(), LHS.end()); 145 if (IsGreater) 146 return 1; 147 148 return 0; 149 } 150 151 void test_compare_elements() { 152 struct { 153 std::vector<std::string> LHSElements; 154 std::vector<std::string> RHSElements; 155 int Expect; 156 } TestCases[] = { 157 {{"a"}, {"a"}, 0}, 158 {{"a"}, {"b"}, -1}, 159 {{"b"}, {"a"}, 1}, 160 {{"a", "b", "c"}, {"a", "b", "c"}, 0}, 161 {{"a", "b", "c"}, {"a", "b", "d"}, -1}, 162 {{"a", "b", "d"}, {"a", "b", "c"}, 1}, 163 {{"a", "b"}, {"a", "b", "c"}, -1}, 164 {{"a", "b", "c"}, {"a", "b"}, 1}, 165 166 }; 167 168 auto BuildPath = [](std::vector<std::string> const& Elems) { 169 fs::path p; 170 for (auto &E : Elems) 171 p /= E; 172 return p; 173 }; 174 175 for (auto &TC : TestCases) { 176 fs::path LHS = BuildPath(TC.LHSElements); 177 fs::path RHS = BuildPath(TC.RHSElements); 178 const int ExpectCmp = CompareElements(TC.LHSElements, TC.RHSElements); 179 assert(ExpectCmp == TC.Expect); 180 const int GotCmp = normalize_ret(LHS.compare(RHS)); 181 assert(GotCmp == TC.Expect); 182 } 183 } 184 185 int main(int, char**) { 186 test_compare_basic(); 187 test_compare_elements(); 188 189 return 0; 190 } 191