//===----------------------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03 // // class path // int compare(path const&) const noexcept; // int compare(string_type const&) const; // int compare(value_type const*) const; // // bool operator==(path const&, path const&) noexcept; // bool operator!=(path const&, path const&) noexcept; // bool operator< (path const&, path const&) noexcept; // bool operator<=(path const&, path const&) noexcept; // bool operator> (path const&, path const&) noexcept; // bool operator>=(path const&, path const&) noexcept; // // size_t hash_value(path const&) noexcept; #include "filesystem_include.hpp" #include #include #include #include "test_macros.h" #include "test_iterators.h" #include "count_new.hpp" #include "filesystem_test_helper.hpp" #include "verbose_assert.h" struct PathCompareTest { const char* LHS; const char* RHS; int expect; }; #define LONGA "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" #define LONGB "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" #define LONGC "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" #define LONGD "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" const PathCompareTest CompareTestCases[] = { {"", "", 0}, {"a", "", 1}, {"", "a", -1}, {"a/b/c", "a/b/c", 0}, {"b/a/c", "a/b/c", 1}, {"a/b/c", "b/a/c", -1}, {"a/b", "a/b/c", -1}, {"a/b/c", "a/b", 1}, {"a/b/", "a/b/.", -1}, {"a/b/", "a/b", 1}, {"a/b//////", "a/b/////.", -1}, {"a/.././b", "a///..//.////b", 0}, {"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory {"/foo/bar/", "/foo/bar", 1}, // trailing separator {"foo", "/foo", -1}, // if !this->has_root_directory() and p.has_root_directory(), a value less than 0. {"/foo", "foo", 1}, // if this->has_root_directory() and !p.has_root_directory(), a value greater than 0. {"//" LONGA "////" LONGB "/" LONGC "///" LONGD, "//" LONGA "/" LONGB "/" LONGC "/" LONGD, 0}, { LONGA "/" LONGB "/" LONGC, LONGA "/" LONGB "/" LONGB, 1} }; #undef LONGA #undef LONGB #undef LONGC #undef LONGD static inline int normalize_ret(int ret) { return ret < 0 ? -1 : (ret > 0 ? 1 : 0); } void test_compare_basic() { using namespace fs; for (auto const & TC : CompareTestCases) { const path p1(TC.LHS); const path p2(TC.RHS); const std::string R(TC.RHS); const std::string_view RV(TC.RHS); const int E = TC.expect; { // compare(...) functions DisableAllocationGuard g; // none of these operations should allocate // check runtime results int ret1 = normalize_ret(p1.compare(p2)); int ret2 = normalize_ret(p1.compare(R)); int ret3 = normalize_ret(p1.compare(TC.RHS)); int ret4 = normalize_ret(p1.compare(RV)); g.release(); ASSERT_EQ(ret1, ret2); ASSERT_EQ(ret1, ret3); ASSERT_EQ(ret1, ret4); ASSERT_EQ(ret1, E) << DISPLAY(TC.LHS) << DISPLAY(TC.RHS); // check signatures ASSERT_NOEXCEPT(p1.compare(p2)); } { // comparison operators DisableAllocationGuard g; // none of these operations should allocate // Check runtime result assert((p1 == p2) == (E == 0)); assert((p1 != p2) == (E != 0)); assert((p1 < p2) == (E < 0)); assert((p1 <= p2) == (E <= 0)); assert((p1 > p2) == (E > 0)); assert((p1 >= p2) == (E >= 0)); // Check signatures ASSERT_NOEXCEPT(p1 == p2); ASSERT_NOEXCEPT(p1 != p2); ASSERT_NOEXCEPT(p1 < p2); ASSERT_NOEXCEPT(p1 <= p2); ASSERT_NOEXCEPT(p1 > p2); ASSERT_NOEXCEPT(p1 >= p2); } { // check hash values auto h1 = hash_value(p1); auto h2 = hash_value(p2); assert((h1 == h2) == (p1 == p2)); // check signature ASSERT_SAME_TYPE(size_t, decltype(hash_value(p1))); ASSERT_NOEXCEPT(hash_value(p1)); } } } int CompareElements(std::vector const& LHS, std::vector const& RHS) { bool IsLess = std::lexicographical_compare(LHS.begin(), LHS.end(), RHS.begin(), RHS.end()); if (IsLess) return -1; bool IsGreater = std::lexicographical_compare(RHS.begin(), RHS.end(), LHS.begin(), LHS.end()); if (IsGreater) return 1; return 0; } void test_compare_elements() { struct { std::vector LHSElements; std::vector RHSElements; int Expect; } TestCases[] = { {{"a"}, {"a"}, 0}, {{"a"}, {"b"}, -1}, {{"b"}, {"a"}, 1}, {{"a", "b", "c"}, {"a", "b", "c"}, 0}, {{"a", "b", "c"}, {"a", "b", "d"}, -1}, {{"a", "b", "d"}, {"a", "b", "c"}, 1}, {{"a", "b"}, {"a", "b", "c"}, -1}, {{"a", "b", "c"}, {"a", "b"}, 1}, }; auto BuildPath = [](std::vector const& Elems) { fs::path p; for (auto &E : Elems) p /= E; return p; }; for (auto &TC : TestCases) { fs::path LHS = BuildPath(TC.LHSElements); fs::path RHS = BuildPath(TC.RHSElements); const int ExpectCmp = CompareElements(TC.LHSElements, TC.RHSElements); assert(ExpectCmp == TC.Expect); const int GotCmp = normalize_ret(LHS.compare(RHS)); assert(GotCmp == TC.Expect); } } int main() { test_compare_basic(); test_compare_elements(); }