[libc++][spaceship] Additional tests for `operator<=>` `map` and `multimap`
authorHristo Hristov <zingam@outlook.com>
Tue, 23 May 2023 12:06:41 +0000 (15:06 +0300)
committerHristo Hristov <zingam@outlook.com>
Wed, 31 May 2023 07:36:57 +0000 (10:36 +0300)
- Added additional tests
- Improved existing tests
- Moved misplaced test files to the correct location

Reviewed By: #libc, philnik

Differential Revision: https://reviews.llvm.org/D151205

libcxx/test/std/containers/associative/map/map.nonmember/compare.three_way.pass.cpp [moved from libcxx/test/std/containers/associative/map/compare.three_way.pass.cpp with 100% similarity]
libcxx/test/std/containers/associative/map/map.nonmember/compare.three_way.verify.cpp [new file with mode: 0644]
libcxx/test/std/containers/associative/multimap/multimap.nonmember/compare.three_way.pass.cpp [moved from libcxx/test/std/containers/associative/multimap/compare.three_way.pass.cpp with 100% similarity]
libcxx/test/std/containers/associative/multimap/multimap.nonmember/compare.three_way.verify.cpp [new file with mode: 0644]
libcxx/test/support/test_container_comparisons.h

diff --git a/libcxx/test/std/containers/associative/map/map.nonmember/compare.three_way.verify.cpp b/libcxx/test/std/containers/associative/map/map.nonmember/compare.three_way.verify.cpp
new file mode 100644 (file)
index 0000000..a1cd2ab
--- /dev/null
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// <map>
+
+// class map
+
+// template<class Key, class T, class Compare, class Allocator>
+//   synth-three-way-result<pair<const Key, T>>
+//     operator<=>(const map<Key, T, Compare, Allocator>& x,
+//                 const map<Key, T, Compare, Allocator>& y);
+
+#include <map>
+
+#include "test_allocator.h"
+
+int main(int, char**) {
+  // Mismatching allocators
+  {
+    std::map<int, int, std::less<int>, std::allocator<int>> s1;
+    std::map<int, int, std::less<int>, test_allocator<int>> s2;
+    // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement 'is_same<int, std::pair<const int, int>>::value'{{.*}}Allocator::value_type must be same type as value_type}}
+    s1 <=> s2;
+    // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement 'is_same<int, std::pair<const int, int>>::value'{{.*}}Allocator::value_type must be same type as value_type}}
+    s2 <=> s1;
+  }
+  // Mismatching comparision functions
+  {
+    std::map<int, int, std::less<int>> s1;
+    std::map<int, int, std::greater<int>> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s1 <=> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s2 <=> s1;
+  }
+  {
+    std::map<int, int, std::less<int>> s1;
+    std::map<int, int, std::less<float>> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s1 <=> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s2 <=> s1;
+  }
+  // Mismatching types
+  {
+    std::map<int, int> s1;
+    std::map<int, float> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s1 <=> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s2 <=> s1;
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.nonmember/compare.three_way.verify.cpp b/libcxx/test/std/containers/associative/multimap/multimap.nonmember/compare.three_way.verify.cpp
new file mode 100644 (file)
index 0000000..a6b3a0c
--- /dev/null
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// <map>
+
+// class multimap
+
+// template<class Key, class T, class Compare, class Allocator>
+//   synth-three-way-result<pair<const Key, T>>
+//     operator<=>(const multimap<Key, T, Compare, Allocator>& x,
+//                 const multimap<Key, T, Compare, Allocator>& y);
+
+#include <map>
+
+#include "test_allocator.h"
+
+int main(int, char**) {
+  // Mismatching allocators
+  {
+    std::multimap<int, int, std::less<int>, std::allocator<int>> s1;
+    std::multimap<int, int, std::less<int>, test_allocator<int>> s2;
+    // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement 'is_same<int, std::pair<const int, int>>::value'{{.*}}Allocator::value_type must be same type as value_type}}
+    s1 <=> s2;
+    // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement 'is_same<int, std::pair<const int, int>>::value'{{.*}}Allocator::value_type must be same type as value_type}}
+    s2 <=> s1;
+  }
+  // Mismatching comparision functions
+  {
+    std::multimap<int, int, std::less<int>> s1;
+    std::multimap<int, int, std::greater<int>> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s1 <=> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s2 <=> s1;
+  }
+  {
+    std::multimap<int, int, std::less<int>> s1;
+    std::multimap<int, int, std::less<float>> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s1 <=> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s2 <=> s1;
+  }
+  // Mismatching types
+  {
+    std::multimap<int, int> s1;
+    std::multimap<int, float> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s1 <=> s2;
+    // expected-error@+1 {{invalid operands to binary expression}}
+    s2 <=> s1;
+  }
+
+  return 0;
+}
index d3b4033..8748f2d 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef TEST_CONTAINER_COMPARISONS
 #define TEST_CONTAINER_COMPARISONS
 
+#include <functional>
 #include <set>
 
 #include "test_comparisons.h"
@@ -84,103 +85,109 @@ constexpr bool test_sequence_container_spaceship() {
 }
 
 // Implementation detail of `test_ordered_map_container_spaceship`
-template <template <typename...> typename Container, typename Key, typename Val, typename Order>
-constexpr void test_ordered_map_container_spaceship_with_type() {
+template <template <typename...> typename Container, typename Key, typename Val, typename Order, typename Compare>
+constexpr void test_ordered_map_container_spaceship_with_type(Compare comp) {
   // Empty containers
   {
-    Container<Key, Val> l1;
-    Container<Key, Val> l2;
+    Container<Key, Val, Compare> l1{{}, comp};
+    Container<Key, Val, Compare> l2{{}, comp};
     assert(testOrder(l1, l2, Order::equivalent));
   }
   // Identical contents
   {
-    Container<Key, Val> l1{{1, 1}, {2, 1}};
-    Container<Key, Val> l2{{1, 1}, {2, 1}};
+    Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 1}}, comp};
     assert(testOrder(l1, l2, Order::equivalent));
   }
   // Less, due to contained values
   {
-    Container<Key, Val> l1{{1, 1}, {2, 1}};
-    Container<Key, Val> l2{{1, 1}, {2, 2}};
+    Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
     assert(testOrder(l1, l2, Order::less));
   }
   // Greater, due to contained values
   {
-    Container<Key, Val> l1{{1, 1}, {2, 3}};
-    Container<Key, Val> l2{{1, 1}, {2, 2}};
+    Container<Key, Val, Compare> l1{{{1, 1}, {2, 3}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
     assert(testOrder(l1, l2, Order::greater));
   }
   // Shorter list
   {
-    Container<Key, Val> l1{{1, 1}};
-    Container<Key, Val> l2{{1, 1}, {2, 2}};
+    Container<Key, Val, Compare> l1{{{1, 1}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
     assert(testOrder(l1, l2, Order::less));
   }
   // Longer list
   {
-    Container<Key, Val> l1{{1, 2}, {2, 2}};
-    Container<Key, Val> l2{{1, 1}};
+    Container<Key, Val, Compare> l1{{{1, 2}, {2, 2}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}}, comp};
     assert(testOrder(l1, l2, Order::greater));
   }
   // Unordered
   if constexpr (std::is_same_v<Val, PartialOrder>) {
-    Container<Key, Val> l1{{1, 1}, {2, std::numeric_limits<int>::min()}};
-    Container<Key, Val> l2{{1, 1}, {2, 2}};
+    Container<Key, Val, Compare> l1{{{1, 1}, {2, std::numeric_limits<int>::min()}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
     assert(testOrder(l1, l2, Order::unordered));
   }
 
   // Identical contents
   {
-    Container<Key, Val> l1{{1, 1}, {2, 1}, {2, 2}};
-    Container<Key, Val> l2{{1, 1}, {2, 1}, {2, 2}};
+    Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}, {2, 2}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 1}, {2, 2}}, comp};
     assert(testOrder(l1, l2, Order::equivalent));
-    Container<Key, Val> l3{{1, 1}, {2, 1}, {2, 2}};
-    Container<Key, Val> l4{{2, 1}, {2, 2}, {1, 1}};
+
+    Container<Key, Val, Compare> l3{{{1, 1}, {2, 1}, {2, 2}}, comp};
+    Container<Key, Val, Compare> l4{{{2, 1}, {2, 2}, {1, 1}}, comp};
     assert(testOrder(l3, l4, Order::equivalent));
   }
   // Less, due to contained values
   {
-    Container<Key, Val> l1{{1, 1}, {2, 1}, {2, 1}};
-    Container<Key, Val> l2{{1, 1}, {2, 2}, {2, 2}};
+    Container<Key, Val, Compare> l1{{{1, 1}, {2, 1}, {2, 1}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 2}}, comp};
     assert(testOrder(l1, l2, Order::less));
-    Container<Key, Val> l3{{1, 1}, {2, 1}, {2, 1}};
-    Container<Key, Val> l4{{2, 2}, {2, 2}, {1, 1}};
+
+    Container<Key, Val, Compare> l3{{{1, 1}, {2, 1}, {2, 1}}, comp};
+    Container<Key, Val, Compare> l4{{{2, 2}, {2, 2}, {1, 1}}, comp};
     assert(testOrder(l3, l4, Order::less));
   }
   // Greater, due to contained values
   {
-    Container<Key, Val> l1{{1, 1}, {2, 3}, {2, 3}};
-    Container<Key, Val> l2{{1, 1}, {2, 2}, {2, 2}};
+    Container<Key, Val, Compare> l1{{{1, 1}, {2, 3}, {2, 3}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 2}}, comp};
     assert(testOrder(l1, l2, Order::greater));
-    Container<Key, Val> l3{{1, 1}, {2, 3}, {2, 3}};
-    Container<Key, Val> l4{{2, 2}, {2, 2}, {1, 1}};
+
+    Container<Key, Val, Compare> l3{{{1, 1}, {2, 3}, {2, 3}}, comp};
+    Container<Key, Val, Compare> l4{{{2, 2}, {2, 2}, {1, 1}}, comp};
     assert(testOrder(l3, l4, Order::greater));
   }
   // Shorter list
   {
-    Container<Key, Val> l1{{1, 1}, {2, 2}};
-    Container<Key, Val> l2{{1, 1}, {2, 2}, {2, 2}, {3, 1}};
+    Container<Key, Val, Compare> l1{{{1, 1}, {2, 2}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 2}, {3, 1}}, comp};
     assert(testOrder(l1, l2, Order::less));
-    Container<Key, Val> l3{{1, 1}, {2, 2}};
-    Container<Key, Val> l4{{3, 1}, {2, 2}, {2, 2}, {1, 1}};
+
+    Container<Key, Val, Compare> l3{{{1, 1}, {2, 2}}, comp};
+    Container<Key, Val, Compare> l4{{{3, 1}, {2, 2}, {2, 2}, {1, 1}}, comp};
     assert(testOrder(l3, l4, Order::less));
   }
   // Longer list
   {
-    Container<Key, Val> l1{{1, 2}, {2, 2}, {2, 2}, {3, 1}};
-    Container<Key, Val> l2{{1, 1}, {2, 2}};
+    Container<Key, Val, Compare> l1{{{1, 2}, {2, 2}, {2, 2}, {3, 1}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}}, comp};
     assert(testOrder(l1, l2, Order::greater));
-    Container<Key, Val> l3{{1, 2}, {2, 2}, {2, 2}, {3, 1}};
-    Container<Key, Val> l4{{2, 2}, {1, 1}};
+
+    Container<Key, Val, Compare> l3{{{1, 2}, {2, 2}, {2, 2}, {3, 1}}, comp};
+    Container<Key, Val, Compare> l4{{{2, 2}, {1, 1}}, comp};
     assert(testOrder(l3, l4, Order::greater));
   }
   // Unordered
   if constexpr (std::is_same_v<Val, PartialOrder>) {
-    Container<Key, Val> l1{{1, 1}, {2, std::numeric_limits<int>::min()}, {2, 3}};
-    Container<Key, Val> l2{{1, 1}, {2, 2}, {2, 3}};
+    Container<Key, Val, Compare> l1{{{1, 1}, {2, std::numeric_limits<int>::min()}, {2, 3}}, comp};
+    Container<Key, Val, Compare> l2{{{1, 1}, {2, 2}, {2, 3}}, comp};
     assert(testOrder(l1, l2, Order::unordered));
-    Container<Key, Val> l3{{1, 1}, {2, std::numeric_limits<int>::min()}, {2, 3}};
-    Container<Key, Val> l4{{2, 3}, {2, 2}, {1, 1}};
+
+    Container<Key, Val, Compare> l3{{{1, 1}, {2, std::numeric_limits<int>::min()}, {2, 3}}, comp};
+    Container<Key, Val, Compare> l4{{{2, 3}, {2, 2}, {1, 1}}, comp};
     assert(testOrder(l3, l4, Order::unordered));
   }
 }
@@ -188,21 +195,25 @@ constexpr void test_ordered_map_container_spaceship_with_type() {
 // Tests the `operator<=>` on ordered map containers
 template <template <typename...> typename Container>
 constexpr bool test_ordered_map_container_spaceship() {
+  // Thanks to SFINAE, the following is not a compiler error but returns `false`
+  struct NonComparable {};
+  static_assert(!std::three_way_comparable<Container<int, NonComparable>>);
+
   // The container should fulfill `std::three_way_comparable`
   static_assert(std::three_way_comparable<Container<int, int>>);
 
   // Test different comparison categories
-  test_ordered_map_container_spaceship_with_type<Container, int, int, std::strong_ordering>();
-  test_ordered_map_container_spaceship_with_type<Container, int, StrongOrder, std::strong_ordering>();
-  test_ordered_map_container_spaceship_with_type<Container, int, WeakOrder, std::weak_ordering>();
-  test_ordered_map_container_spaceship_with_type<Container, int, PartialOrder, std::partial_ordering>();
+  test_ordered_map_container_spaceship_with_type<Container, int, int, std::strong_ordering>(std::less{});
+  test_ordered_map_container_spaceship_with_type<Container, int, int, std::strong_ordering>(std::greater{});
+  test_ordered_map_container_spaceship_with_type<Container, int, StrongOrder, std::strong_ordering>(std::less{});
+  test_ordered_map_container_spaceship_with_type<Container, int, StrongOrder, std::strong_ordering>(std::greater{});
+  test_ordered_map_container_spaceship_with_type<Container, int, WeakOrder, std::weak_ordering>(std::less{});
+  test_ordered_map_container_spaceship_with_type<Container, int, WeakOrder, std::weak_ordering>(std::greater{});
+  test_ordered_map_container_spaceship_with_type<Container, int, PartialOrder, std::partial_ordering>(std ::less{});
+  test_ordered_map_container_spaceship_with_type<Container, int, PartialOrder, std::partial_ordering>(std ::greater{});
 
   // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
-  test_ordered_map_container_spaceship_with_type<Container, int, LessAndEqComp, std::weak_ordering>();
-
-  // Thanks to SFINAE, the following is not a compiler error but returns `false`
-  struct NonComparable {};
-  static_assert(!std::three_way_comparable<Container<int, NonComparable>>);
+  test_ordered_map_container_spaceship_with_type<Container, int, LessAndEqComp, std::weak_ordering>(std::less{});
 
   return true;
 }