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 
normalize_ret(int ret)77 static inline int normalize_ret(int ret)
78 {
79   return ret < 0 ? -1 : (ret > 0 ? 1 : 0);
80 }
81 
test_compare_basic()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     std::string RHS(TC.RHS);
89     const path::string_type R(RHS.begin(), RHS.end());
90     const std::basic_string_view<path::value_type> RV(R);
91     const path::value_type *Ptr = R.c_str();
92     const int E = TC.expect;
93     { // compare(...) functions
94       DisableAllocationGuard g; // none of these operations should allocate
95 
96       // check runtime results
97       int ret1 = normalize_ret(p1.compare(p2));
98       int ret2 = normalize_ret(p1.compare(R));
99       int ret3 = normalize_ret(p1.compare(Ptr));
100       int ret4 = normalize_ret(p1.compare(RV));
101 
102       g.release();
103       assert(ret1 == ret2);
104       assert(ret1 == ret3);
105       assert(ret1 == ret4);
106       assert(ret1 == E);
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 
CompareElements(std::vector<std::string> const & LHS,std::vector<std::string> const & RHS)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 
test_compare_elements()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 
main(int,char **)187 int main(int, char**) {
188   test_compare_basic();
189   test_compare_elements();
190 
191   return 0;
192 }
193