211 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++1410 11// <filesystem>12 13// class path14 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// strong_ordering operator<=>(path const&, path const&) noexcept;26//27// size_t hash_value(path const&) noexcept;28// template<> struct hash<filesystem::path>;29 30#include <filesystem>31#include <cassert>32#include <string>33#include <type_traits>34#include <vector>35 36#include "assert_macros.h"37#include "count_new.h"38#include "test_comparisons.h"39#include "test_iterators.h"40#include "test_macros.h"41namespace fs = std::filesystem;42 43struct PathCompareTest {44 const char* LHS;45 const char* RHS;46 int expect;47};48 49#define LONGA \50 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \51 "AAAAAAAA"52#define LONGB \53 "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" \54 "BBBBBBBB"55#define LONGC \56 "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" \57 "CCCCCCCC"58#define LONGD \59 "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" \60 "DDDDDDDD"61const PathCompareTest CompareTestCases[] = {62 {"", "", 0},63 {"a", "", 1},64 {"", "a", -1},65 {"a/b/c", "a/b/c", 0},66 {"b/a/c", "a/b/c", 1},67 {"a/b/c", "b/a/c", -1},68 {"a/b", "a/b/c", -1},69 {"a/b/c", "a/b", 1},70 {"a/b/", "a/b/.", -1},71 {"a/b/", "a/b", 1},72 {"a/b//////", "a/b/////.", -1},73 {"a/.././b", "a///..//.////b", 0},74 {"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators75 {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory76 {"/foo/bar/", "/foo/bar", 1}, // trailing separator77 {"foo", "/foo", -1}, // if !this->has_root_directory() and p.has_root_directory(), a value less than 0.78 {"/foo", "foo", 1}, // if this->has_root_directory() and !p.has_root_directory(), a value greater than 0.79#ifdef _WIN3280 {"C:/a", "C:\\a", 0},81#else82 {"C:/a", "C:\\a", -1},83#endif84 {("//" LONGA "////" LONGB "/" LONGC "///" LONGD), ("//" LONGA "/" LONGB "/" LONGC "/" LONGD), 0},85 {(LONGA "/" LONGB "/" LONGC), (LONGA "/" LONGB "/" LONGB), 1}86 87};88#undef LONGA89#undef LONGB90#undef LONGC91#undef LONGD92 93static inline int normalize_ret(int ret) { return ret < 0 ? -1 : (ret > 0 ? 1 : 0); }94 95void test_compare_basic() {96 using namespace fs;97 for (auto const& TC : CompareTestCases) {98 const path p1(TC.LHS);99 const path p2(TC.RHS);100 std::string RHS(TC.RHS);101 const path::string_type R(RHS.begin(), RHS.end());102 const std::basic_string_view<path::value_type> RV(R);103 const path::value_type* Ptr = R.c_str();104 const int E = TC.expect;105 { // compare(...) functions106 DisableAllocationGuard g; // none of these operations should allocate107 108 // check runtime results109 int ret1 = normalize_ret(p1.compare(p2));110 int ret2 = normalize_ret(p1.compare(R));111 int ret3 = normalize_ret(p1.compare(Ptr));112 int ret4 = normalize_ret(p1.compare(RV));113 114 g.release();115 assert(ret1 == ret2);116 assert(ret1 == ret3);117 assert(ret1 == ret4);118 assert(ret1 == E);119 120 // check signatures121 ASSERT_NOEXCEPT(p1.compare(p2));122 }123 { // comparison operators124 DisableAllocationGuard g; // none of these operations should allocate125 126 // check signatures127 AssertComparisonsAreNoexcept<path>();128 AssertComparisonsReturnBool<path>();129#if TEST_STD_VER > 17130 AssertOrderAreNoexcept<path>();131 AssertOrderReturn<std::strong_ordering, path>();132#endif133 134 // check comparison results135 assert(testComparisons(p1, p2, /*isEqual*/ E == 0, /*isLess*/ E < 0));136#if TEST_STD_VER > 17137 assert(testOrder(p1, p2, E <=> 0));138#endif139 }140 { // check hash values141 auto h1 = hash_value(p1);142 auto h2 = hash_value(p2);143 assert((h1 == h2) == (p1 == p2));144 // check signature145 ASSERT_SAME_TYPE(std::size_t, decltype(hash_value(p1)));146 ASSERT_NOEXCEPT(hash_value(p1));147 }148 { // check std::hash149 auto h1 = std::hash<fs::path>()(p1);150 auto h2 = std::hash<fs::path>()(p2);151 assert((h1 == h2) == (p1 == p2));152 // check signature153 ASSERT_SAME_TYPE(std::size_t, decltype(std::hash<fs::path>()(p1)));154 ASSERT_NOEXCEPT(std::hash<fs::path>()(p1));155 }156 }157}158 159int CompareElements(std::vector<std::string> const& LHS, std::vector<std::string> const& RHS) {160 bool IsLess = std::lexicographical_compare(LHS.begin(), LHS.end(), RHS.begin(), RHS.end());161 if (IsLess)162 return -1;163 164 bool IsGreater = std::lexicographical_compare(RHS.begin(), RHS.end(), LHS.begin(), LHS.end());165 if (IsGreater)166 return 1;167 168 return 0;169}170 171void test_compare_elements() {172 struct {173 std::vector<std::string> LHSElements;174 std::vector<std::string> RHSElements;175 int Expect;176 } TestCases[] = {177 {{"a"}, {"a"}, 0},178 {{"a"}, {"b"}, -1},179 {{"b"}, {"a"}, 1},180 {{"a", "b", "c"}, {"a", "b", "c"}, 0},181 {{"a", "b", "c"}, {"a", "b", "d"}, -1},182 {{"a", "b", "d"}, {"a", "b", "c"}, 1},183 {{"a", "b"}, {"a", "b", "c"}, -1},184 {{"a", "b", "c"}, {"a", "b"}, 1},185 186 };187 188 auto BuildPath = [](std::vector<std::string> const& Elems) {189 fs::path p;190 for (auto& E : Elems)191 p /= E;192 return p;193 };194 195 for (auto& TC : TestCases) {196 fs::path LHS = BuildPath(TC.LHSElements);197 fs::path RHS = BuildPath(TC.RHSElements);198 const int ExpectCmp = CompareElements(TC.LHSElements, TC.RHSElements);199 assert(ExpectCmp == TC.Expect);200 const int GotCmp = normalize_ret(LHS.compare(RHS));201 assert(GotCmp == TC.Expect);202 }203}204 205int main(int, char**) {206 test_compare_basic();207 test_compare_elements();208 209 return 0;210}211