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