xref: /llvm-project/libcxx/test/std/input.output/filesystems/class.path/path.member/path.compare.pass.cpp (revision aa427b1aae445ed46d9f60c5e2eaac61bdf76be3)
1f7b43230SLouis Dionne //===----------------------------------------------------------------------===//
2f7b43230SLouis Dionne //
3f7b43230SLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f7b43230SLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
5f7b43230SLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f7b43230SLouis Dionne //
7f7b43230SLouis Dionne //===----------------------------------------------------------------------===//
8f7b43230SLouis Dionne 
9ac8c9f1eSLouis Dionne // UNSUPPORTED: c++03, c++11, c++14
10c352fa74SLouis Dionne // UNSUPPORTED: availability-filesystem-missing
11f7b43230SLouis Dionne 
12f7b43230SLouis Dionne // <filesystem>
13f7b43230SLouis Dionne 
14f7b43230SLouis Dionne // class path
15f7b43230SLouis Dionne 
16f7b43230SLouis Dionne // int compare(path const&) const noexcept;
17f7b43230SLouis Dionne // int compare(string_type const&) const;
18f7b43230SLouis Dionne // int compare(value_type const*) const;
19f7b43230SLouis Dionne //
20f7b43230SLouis Dionne // bool operator==(path const&, path const&) noexcept;
21f7b43230SLouis Dionne // bool operator!=(path const&, path const&) noexcept;
22f7b43230SLouis Dionne // bool operator< (path const&, path const&) noexcept;
23f7b43230SLouis Dionne // bool operator<=(path const&, path const&) noexcept;
24f7b43230SLouis Dionne // bool operator> (path const&, path const&) noexcept;
25f7b43230SLouis Dionne // bool operator>=(path const&, path const&) noexcept;
26b3ab3becSAdrian Vogelsgesang // strong_ordering operator<=>(path const&, path const&) noexcept;
27f7b43230SLouis Dionne //
28f7b43230SLouis Dionne // size_t hash_value(path const&) noexcept;
29efc494aaSLouis Dionne // template<> struct hash<filesystem::path>;
30f7b43230SLouis Dionne 
31ac8c9f1eSLouis Dionne #include <filesystem>
32c352fa74SLouis Dionne #include <cassert>
33c352fa74SLouis Dionne #include <string>
34f7b43230SLouis Dionne #include <type_traits>
35f7b43230SLouis Dionne #include <vector>
36f7b43230SLouis Dionne 
37c352fa74SLouis Dionne #include "assert_macros.h"
38c352fa74SLouis Dionne #include "count_new.h"
39b3ab3becSAdrian Vogelsgesang #include "test_comparisons.h"
40f7b43230SLouis Dionne #include "test_iterators.h"
41c352fa74SLouis Dionne #include "test_macros.h"
42ac8c9f1eSLouis Dionne namespace fs = std::filesystem;
43f7b43230SLouis Dionne 
44f7b43230SLouis Dionne struct PathCompareTest {
45f7b43230SLouis Dionne   const char* LHS;
46f7b43230SLouis Dionne   const char* RHS;
47f7b43230SLouis Dionne   int expect;
48f7b43230SLouis Dionne };
49f7b43230SLouis Dionne 
50*aa427b1aSRichardLuo #define LONGA                                                                                                          \
51*aa427b1aSRichardLuo   "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \
52*aa427b1aSRichardLuo   "AAAAAAAA"
53*aa427b1aSRichardLuo #define LONGB                                                                                                          \
54*aa427b1aSRichardLuo   "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" \
55*aa427b1aSRichardLuo   "BBBBBBBB"
56*aa427b1aSRichardLuo #define LONGC                                                                                                          \
57*aa427b1aSRichardLuo   "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" \
58*aa427b1aSRichardLuo   "CCCCCCCC"
59*aa427b1aSRichardLuo #define LONGD                                                                                                          \
60*aa427b1aSRichardLuo   "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" \
61*aa427b1aSRichardLuo   "DDDDDDDD"
62*aa427b1aSRichardLuo const PathCompareTest CompareTestCases[] = {
63f7b43230SLouis Dionne     {"", "", 0},
64f7b43230SLouis Dionne     {"a", "", 1},
65f7b43230SLouis Dionne     {"", "a", -1},
66f7b43230SLouis Dionne     {"a/b/c", "a/b/c", 0},
67f7b43230SLouis Dionne     {"b/a/c", "a/b/c", 1},
68f7b43230SLouis Dionne     {"a/b/c", "b/a/c", -1},
69f7b43230SLouis Dionne     {"a/b", "a/b/c", -1},
70f7b43230SLouis Dionne     {"a/b/c", "a/b", 1},
71f7b43230SLouis Dionne     {"a/b/", "a/b/.", -1},
72f7b43230SLouis Dionne     {"a/b/", "a/b", 1},
73f7b43230SLouis Dionne     {"a/b//////", "a/b/////.", -1},
74f7b43230SLouis Dionne     {"a/.././b", "a///..//.////b", 0},
75f7b43230SLouis Dionne     {"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators
76f7b43230SLouis Dionne     {"///foo/bar", "/foo/bar", 0},                 // "///" is not a root directory
77f7b43230SLouis Dionne     {"/foo/bar/", "/foo/bar", 1},                  // trailing separator
78f7b43230SLouis Dionne     {"foo", "/foo", -1}, // if !this->has_root_directory() and p.has_root_directory(), a value less than 0.
79f7b43230SLouis Dionne     {"/foo", "foo", 1},  //  if this->has_root_directory() and !p.has_root_directory(), a value greater than 0.
80*aa427b1aSRichardLuo #ifdef _WIN32
81*aa427b1aSRichardLuo     {"C:/a", "C:\\a", 0},
82*aa427b1aSRichardLuo #else
83*aa427b1aSRichardLuo     {"C:/a", "C:\\a", -1},
84*aa427b1aSRichardLuo #endif
85c58f1fe2SLouis Dionne     {("//" LONGA "////" LONGB "/" LONGC "///" LONGD), ("//" LONGA "/" LONGB "/" LONGC "/" LONGD), 0},
86c58f1fe2SLouis Dionne     {(LONGA "/" LONGB "/" LONGC), (LONGA "/" LONGB "/" LONGB), 1}
87f7b43230SLouis Dionne 
88f7b43230SLouis Dionne };
89f7b43230SLouis Dionne #undef LONGA
90f7b43230SLouis Dionne #undef LONGB
91f7b43230SLouis Dionne #undef LONGC
92f7b43230SLouis Dionne #undef LONGD
93f7b43230SLouis Dionne 
94*aa427b1aSRichardLuo static inline int normalize_ret(int ret) { return ret < 0 ? -1 : (ret > 0 ? 1 : 0); }
95f7b43230SLouis Dionne 
96*aa427b1aSRichardLuo void test_compare_basic() {
97f7b43230SLouis Dionne   using namespace fs;
98f7b43230SLouis Dionne   for (auto const& TC : CompareTestCases) {
99f7b43230SLouis Dionne     const path p1(TC.LHS);
100f7b43230SLouis Dionne     const path p2(TC.RHS);
10174c883f7SMartin Storsjö     std::string RHS(TC.RHS);
10274c883f7SMartin Storsjö     const path::string_type R(RHS.begin(), RHS.end());
10374c883f7SMartin Storsjö     const std::basic_string_view<path::value_type> RV(R);
10474c883f7SMartin Storsjö     const path::value_type* Ptr = R.c_str();
105f7b43230SLouis Dionne     const int E                 = TC.expect;
106f7b43230SLouis Dionne     {                           // compare(...) functions
107f7b43230SLouis Dionne       DisableAllocationGuard g; // none of these operations should allocate
108f7b43230SLouis Dionne 
109f7b43230SLouis Dionne       // check runtime results
110f7b43230SLouis Dionne       int ret1 = normalize_ret(p1.compare(p2));
111f7b43230SLouis Dionne       int ret2 = normalize_ret(p1.compare(R));
11274c883f7SMartin Storsjö       int ret3 = normalize_ret(p1.compare(Ptr));
113f7b43230SLouis Dionne       int ret4 = normalize_ret(p1.compare(RV));
114f7b43230SLouis Dionne 
115f7b43230SLouis Dionne       g.release();
116e557b6a6SLouis Dionne       assert(ret1 == ret2);
117e557b6a6SLouis Dionne       assert(ret1 == ret3);
118e557b6a6SLouis Dionne       assert(ret1 == ret4);
119e557b6a6SLouis Dionne       assert(ret1 == E);
120f7b43230SLouis Dionne 
121f7b43230SLouis Dionne       // check signatures
122f7b43230SLouis Dionne       ASSERT_NOEXCEPT(p1.compare(p2));
123f7b43230SLouis Dionne     }
124f7b43230SLouis Dionne     {                           // comparison operators
125f7b43230SLouis Dionne       DisableAllocationGuard g; // none of these operations should allocate
126f7b43230SLouis Dionne 
127b3ab3becSAdrian Vogelsgesang       // check signatures
128b3ab3becSAdrian Vogelsgesang       AssertComparisonsAreNoexcept<path>();
129b3ab3becSAdrian Vogelsgesang       AssertComparisonsReturnBool<path>();
130b3ab3becSAdrian Vogelsgesang #if TEST_STD_VER > 17
131b3ab3becSAdrian Vogelsgesang       AssertOrderAreNoexcept<path>();
132b3ab3becSAdrian Vogelsgesang       AssertOrderReturn<std::strong_ordering, path>();
133b3ab3becSAdrian Vogelsgesang #endif
134f7b43230SLouis Dionne 
135b3ab3becSAdrian Vogelsgesang       // check comarison results
136b3ab3becSAdrian Vogelsgesang       assert(testComparisons(p1, p2, /*isEqual*/ E == 0, /*isLess*/ E < 0));
137b3ab3becSAdrian Vogelsgesang #if TEST_STD_VER > 17
138b3ab3becSAdrian Vogelsgesang       assert(testOrder(p1, p2, E <=> 0));
139b3ab3becSAdrian Vogelsgesang #endif
140f7b43230SLouis Dionne     }
141f7b43230SLouis Dionne     { // check hash values
142f7b43230SLouis Dionne       auto h1 = hash_value(p1);
143f7b43230SLouis Dionne       auto h2 = hash_value(p2);
144f7b43230SLouis Dionne       assert((h1 == h2) == (p1 == p2));
145f7b43230SLouis Dionne       // check signature
146fb855eb9SMark de Wever       ASSERT_SAME_TYPE(std::size_t, decltype(hash_value(p1)));
147f7b43230SLouis Dionne       ASSERT_NOEXCEPT(hash_value(p1));
148f7b43230SLouis Dionne     }
1491cf344d9SLouis Dionne     { // check std::hash
1501cf344d9SLouis Dionne       auto h1 = std::hash<fs::path>()(p1);
1511cf344d9SLouis Dionne       auto h2 = std::hash<fs::path>()(p2);
1521cf344d9SLouis Dionne       assert((h1 == h2) == (p1 == p2));
1531cf344d9SLouis Dionne       // check signature
154fb855eb9SMark de Wever       ASSERT_SAME_TYPE(std::size_t, decltype(std::hash<fs::path>()(p1)));
1551cf344d9SLouis Dionne       ASSERT_NOEXCEPT(std::hash<fs::path>()(p1));
1561cf344d9SLouis Dionne     }
157f7b43230SLouis Dionne   }
158f7b43230SLouis Dionne }
159f7b43230SLouis Dionne 
160f7b43230SLouis Dionne int CompareElements(std::vector<std::string> const& LHS, std::vector<std::string> const& RHS) {
161f7b43230SLouis Dionne   bool IsLess = std::lexicographical_compare(LHS.begin(), LHS.end(), RHS.begin(), RHS.end());
162f7b43230SLouis Dionne   if (IsLess)
163f7b43230SLouis Dionne     return -1;
164f7b43230SLouis Dionne 
165f7b43230SLouis Dionne   bool IsGreater = std::lexicographical_compare(RHS.begin(), RHS.end(), LHS.begin(), LHS.end());
166f7b43230SLouis Dionne   if (IsGreater)
167f7b43230SLouis Dionne     return 1;
168f7b43230SLouis Dionne 
169f7b43230SLouis Dionne   return 0;
170f7b43230SLouis Dionne }
171f7b43230SLouis Dionne 
172f7b43230SLouis Dionne void test_compare_elements() {
173f7b43230SLouis Dionne   struct {
174f7b43230SLouis Dionne     std::vector<std::string> LHSElements;
175f7b43230SLouis Dionne     std::vector<std::string> RHSElements;
176f7b43230SLouis Dionne     int Expect;
177f7b43230SLouis Dionne   } TestCases[] = {
178f7b43230SLouis Dionne       {{"a"}, {"a"}, 0},
179f7b43230SLouis Dionne       {{"a"}, {"b"}, -1},
180f7b43230SLouis Dionne       {{"b"}, {"a"}, 1},
181f7b43230SLouis Dionne       {{"a", "b", "c"}, {"a", "b", "c"}, 0},
182f7b43230SLouis Dionne       {{"a", "b", "c"}, {"a", "b", "d"}, -1},
183f7b43230SLouis Dionne       {{"a", "b", "d"}, {"a", "b", "c"}, 1},
184f7b43230SLouis Dionne       {{"a", "b"}, {"a", "b", "c"}, -1},
185f7b43230SLouis Dionne       {{"a", "b", "c"}, {"a", "b"}, 1},
186f7b43230SLouis Dionne 
187f7b43230SLouis Dionne   };
188f7b43230SLouis Dionne 
189f7b43230SLouis Dionne   auto BuildPath = [](std::vector<std::string> const& Elems) {
190f7b43230SLouis Dionne     fs::path p;
191f7b43230SLouis Dionne     for (auto& E : Elems)
192f7b43230SLouis Dionne       p /= E;
193f7b43230SLouis Dionne     return p;
194f7b43230SLouis Dionne   };
195f7b43230SLouis Dionne 
196f7b43230SLouis Dionne   for (auto& TC : TestCases) {
197f7b43230SLouis Dionne     fs::path LHS        = BuildPath(TC.LHSElements);
198f7b43230SLouis Dionne     fs::path RHS        = BuildPath(TC.RHSElements);
199f7b43230SLouis Dionne     const int ExpectCmp = CompareElements(TC.LHSElements, TC.RHSElements);
200f7b43230SLouis Dionne     assert(ExpectCmp == TC.Expect);
201f7b43230SLouis Dionne     const int GotCmp = normalize_ret(LHS.compare(RHS));
202f7b43230SLouis Dionne     assert(GotCmp == TC.Expect);
203f7b43230SLouis Dionne   }
204f7b43230SLouis Dionne }
205f7b43230SLouis Dionne 
206f7b43230SLouis Dionne int main(int, char**) {
207f7b43230SLouis Dionne   test_compare_basic();
208f7b43230SLouis Dionne   test_compare_elements();
209f7b43230SLouis Dionne 
210f7b43230SLouis Dionne   return 0;
211f7b43230SLouis Dionne }
212