Fix class member shadowing in folly::ProducerConsumerQueue
[folly.git] / folly / test / FunctionTest.cpp
index 99c5b6c519767a3bf3eb4a1118d127682049b141..a739100993b5163ad56ed19b7f18a60d1757ab59 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -54,8 +54,127 @@ struct Functor {
 template <typename Ret, typename... Args>
 void deduceArgs(Function<Ret(Args...)>) {}
 
+struct CallableButNotCopyable {
+  CallableButNotCopyable() {}
+  CallableButNotCopyable(CallableButNotCopyable const&) = delete;
+  CallableButNotCopyable(CallableButNotCopyable&&) = delete;
+  CallableButNotCopyable& operator=(CallableButNotCopyable const&) = delete;
+  CallableButNotCopyable& operator=(CallableButNotCopyable&&) = delete;
+  template <class... Args>
+  void operator()(Args&&...) const {}
+};
+
 } // namespace
 
+// TEST =====================================================================
+// Test constructibility and non-constructibility for some tricky conversions
+static_assert(
+    !std::is_assignable<Function<void()>, CallableButNotCopyable>::value,
+    "");
+static_assert(
+    !std::is_constructible<Function<void()>, CallableButNotCopyable&>::value,
+    "");
+static_assert(
+    !std::is_constructible<Function<void() const>, CallableButNotCopyable>::
+        value,
+    "");
+static_assert(
+    !std::is_constructible<Function<void() const>, CallableButNotCopyable&>::
+        value,
+    "");
+
+static_assert(
+    !std::is_assignable<Function<void()>, CallableButNotCopyable>::value,
+    "");
+static_assert(
+    !std::is_assignable<Function<void()>, CallableButNotCopyable&>::value,
+    "");
+static_assert(
+    !std::is_assignable<Function<void() const>, CallableButNotCopyable>::value,
+    "");
+static_assert(
+    !std::is_assignable<Function<void() const>, CallableButNotCopyable&>::value,
+    "");
+
+static_assert(
+    std::is_constructible<Function<int(int)>, Function<int(int) const>>::value,
+    "");
+static_assert(
+    !std::is_constructible<Function<int(int) const>, Function<int(int)>>::value,
+    "");
+static_assert(
+    std::is_constructible<Function<int(short)>, Function<short(int) const>>::
+        value,
+    "");
+static_assert(
+    !std::is_constructible<Function<int(short) const>, Function<short(int)>>::
+        value,
+    "");
+static_assert(
+    !std::is_constructible<Function<int(int)>, Function<int(int) const>&>::
+        value,
+    "");
+static_assert(
+    !std::is_constructible<Function<int(int) const>, Function<int(int)>&>::
+        value,
+    "");
+static_assert(
+    !std::is_constructible<Function<int(short)>, Function<short(int) const>&>::
+        value,
+    "");
+static_assert(
+    !std::is_constructible<Function<int(short) const>, Function<short(int)>&>::
+        value,
+    "");
+
+static_assert(
+    std::is_assignable<Function<int(int)>, Function<int(int) const>>::value,
+    "");
+static_assert(
+    !std::is_assignable<Function<int(int) const>, Function<int(int)>>::value,
+    "");
+static_assert(
+    std::is_assignable<Function<int(short)>, Function<short(int) const>>::value,
+    "");
+static_assert(
+    !std::is_assignable<Function<int(short) const>, Function<short(int)>>::
+        value,
+    "");
+static_assert(
+    !std::is_assignable<Function<int(int)>, Function<int(int) const>&>::value,
+    "");
+static_assert(
+    !std::is_assignable<Function<int(int) const>, Function<int(int)>&>::value,
+    "");
+static_assert(
+    !std::is_assignable<Function<int(short)>, Function<short(int) const>&>::
+        value,
+    "");
+static_assert(
+    !std::is_assignable<Function<int(short) const>, Function<short(int)>&>::
+        value,
+    "");
+
+static_assert(
+    std::is_nothrow_constructible<
+        Function<int(int)>,
+        Function<int(int) const>>::value,
+    "");
+static_assert(
+    !std::is_nothrow_constructible<
+        Function<int(short)>,
+        Function<short(int) const>>::value,
+    "");
+static_assert(
+    std::is_nothrow_assignable<Function<int(int)>, Function<int(int) const>>::
+        value,
+    "");
+static_assert(
+    !std::is_nothrow_assignable<
+        Function<int(short)>,
+        Function<short(int) const>>::value,
+    "");
+
 // TEST =====================================================================
 // InvokeFunctor & InvokeReference
 
@@ -194,14 +313,19 @@ TEST(Function, Bind) {
 // NonCopyableLambda
 
 TEST(Function, NonCopyableLambda) {
-  auto unique_ptr_int = folly::make_unique<int>(900);
+  auto unique_ptr_int = std::make_unique<int>(900);
   EXPECT_EQ(900, *unique_ptr_int);
 
-  char fooData[64] = {0};
-  EXPECT_EQ(0, fooData[0]); // suppress gcc warning about fooData not being used
+  struct {
+    char data[64];
+  } fooData = {{0}};
+  (void)fooData; // suppress gcc warning about fooData not being used
 
   auto functor = std::bind(
-      [fooData](std::unique_ptr<int>& up) mutable { return ++*up; },
+      [fooData](std::unique_ptr<int>& up) mutable {
+        (void)fooData;
+        return ++*up;
+      },
       std::move(unique_ptr_int));
 
   EXPECT_EQ(901, functor());
@@ -924,11 +1048,27 @@ TEST(Function, EmptyAfterConstCast) {
   EXPECT_FALSE(func2);
 }
 
-TEST(Function, SelfMoveAssign) {
-  Function<int()> f = [] { return 0; };
+TEST(Function, SelfStdSwap) {
+  Function<int()> f = [] { return 42; };
+  f.swap(f);
+  EXPECT_TRUE(bool(f));
+  EXPECT_EQ(42, f());
+  std::swap(f, f);
+  EXPECT_TRUE(bool(f));
+  EXPECT_EQ(42, f());
+  folly::swap(f, f);
+  EXPECT_TRUE(bool(f));
+  EXPECT_EQ(42, f());
+}
+
+TEST(Function, SelfMove) {
+  Function<int()> f = [] { return 42; };
   Function<int()>& g = f;
-  f = std::move(g);
+  f = std::move(g); // shouldn't crash!
+  (void)bool(f); // valid but unspecified state
+  f = [] { return 43; };
   EXPECT_TRUE(bool(f));
+  EXPECT_EQ(43, f());
 }
 
 TEST(Function, DeducableArguments) {
@@ -936,3 +1076,22 @@ TEST(Function, DeducableArguments) {
   deduceArgs(Function<void(int, float)>{[](int, float) {}});
   deduceArgs(Function<int(int, float)>{[](int i, float) { return i; }});
 }
+
+TEST(Function, CtorWithCopy) {
+  struct X {
+    X() {}
+    X(X const&) noexcept(true) {}
+    X& operator=(X const&) = default;
+  };
+  struct Y {
+    Y() {}
+    Y(Y const&) noexcept(false) {}
+    Y(Y&&) noexcept(true) {}
+    Y& operator=(Y&&) = default;
+    Y& operator=(Y const&) = default;
+  };
+  auto lx = [x = X()]{};
+  auto ly = [y = Y()]{};
+  EXPECT_TRUE(noexcept(Function<void()>(lx)));
+  EXPECT_FALSE(noexcept(Function<void()>(ly)));
+}