Use the GTest portability headers
[folly.git] / folly / test / FunctionTest.cpp
index 718c00fc12988bcb3651bfd2feabcc8f8c8fbcf2..b23eb3e941e47084070aadaf4c3c72fa82aec6f0 100644 (file)
  * limitations under the License.
  */
 
+#include <array>
 #include <cstdarg>
 
 #include <folly/Function.h>
 
 #include <folly/Memory.h>
-#include <gtest/gtest.h>
+#include <folly/portability/GTest.h>
 
-using folly::FunctionMoveCtor;
 using folly::Function;
 
 namespace {
@@ -31,9 +31,6 @@ int func_int_int_add_25(int x) {
 int func_int_int_add_111(int x) {
   return x + 111;
 }
-int func_int_return_987() {
-  return 987;
-}
 float floatMult(float a, float b) {
   return a * b;
 }
@@ -54,160 +51,66 @@ struct Functor {
   }
 };
 
-// TEST =====================================================================
-// NoExceptMovable
-
-struct MoveMayThrow {
-  bool doThrow{false};
-
-  MoveMayThrow() = default;
-  MoveMayThrow(MoveMayThrow const&) = default;
-  MoveMayThrow& operator=(MoveMayThrow const&) = default;
-  MoveMayThrow(MoveMayThrow&&) noexcept(false) {
-    if (doThrow) {
-      throw std::runtime_error("MoveMayThrow(MoveMayThrow&&)");
-    }
-  }
-  MoveMayThrow& operator=(MoveMayThrow&&) noexcept(false) {
-    if (doThrow) {
-      throw std::runtime_error("MoveMayThrow::operator=(MoveMayThrow&&)");
-    }
-    return *this;
-  }
-};
-}
+template <typename Ret, typename... Args>
+void deduceArgs(Function<Ret(Args...)>) {}
 
-TEST(Function, NoExceptMovable) {
-  // callable_noexcept is noexcept-movable
-  auto callable_noexcept = [](int x) { return x + 1; };
-  EXPECT_TRUE(
-      std::is_nothrow_move_constructible<decltype(callable_noexcept)>::value);
-
-  // callable_throw may throw when moved
-  MoveMayThrow mmt;
-  auto callable_throw = [mmt](int x) { return x + 10; };
-  EXPECT_FALSE(
-      std::is_nothrow_move_constructible<decltype(callable_throw)>::value);
-
-  // callable_noexcept can be stored in the Function object
-  Function<int(int), FunctionMoveCtor::NO_THROW> func(callable_noexcept);
-  EXPECT_EQ(func(42), 43);
-  EXPECT_FALSE(func.hasAllocatedMemory());
-  EXPECT_TRUE(std::is_nothrow_move_constructible<decltype(func)>::value);
-
-  // callable_throw cannot be stored in the Function object,
-  // because Function guarantees noexcept-movability, but
-  // callable_throw may throw when moved
-  Function<int(int), FunctionMoveCtor::NO_THROW> func_safe_move(callable_throw);
-  EXPECT_EQ(func_safe_move(42), 52);
-  EXPECT_TRUE(func_safe_move.hasAllocatedMemory());
-  EXPECT_TRUE(
-      std::is_nothrow_move_constructible<decltype(func_safe_move)>::value);
-
-  // callable_throw can be stored in the Function object when
-  // the NoExceptMovable template parameter is set to NO
-  Function<int(int), FunctionMoveCtor::MAY_THROW> func_movethrows(
-      callable_throw);
-  EXPECT_EQ(func_movethrows(42), 52);
-  EXPECT_FALSE(func_movethrows.hasAllocatedMemory());
-  EXPECT_FALSE(
-      std::is_nothrow_move_constructible<decltype(func_movethrows)>::value);
-}
+} // namespace
 
 // TEST =====================================================================
 // InvokeFunctor & InvokeReference
 
-template <FunctionMoveCtor NEM, size_t S>
-void invoke_functor_test() {
+TEST(Function, InvokeFunctor) {
   Functor<int, 100> func;
+  static_assert(
+      sizeof(func) > sizeof(Function<int(size_t)>),
+      "sizeof(Function) is much larger than expected");
   func(5, 123);
 
-  // Try Functions with differently sized storage areas
-  // S=0: request storage for functors of size 0. The storage size
-  // will be actually larger, because there is a lower limit which
-  // still allows to store at least pointers to functors on the heap.
-  // S=1: request minimum storage size of 0.5x the sizeof(func)
-  // S=2: request sizeof(func)
-  // S=3: request 1.5*sizeof(func)
-  Function<int(size_t) const, NEM, sizeof(func)* S / 2> getter =
-      std::move(func);
-
-  // Function will allocate memory on the heap to store
-  // the functor object if the internal storage area is smaller than
-  // sizeof(func).
-  EXPECT_EQ(getter.hasAllocatedMemory(), S < 2);
-
-  EXPECT_EQ(getter(5), 123);
-}
-TEST(Function, InvokeFunctor_T0) {
-  invoke_functor_test<FunctionMoveCtor::MAY_THROW, 0>();
-}
-TEST(Function, InvokeFunctor_N0) {
-  invoke_functor_test<FunctionMoveCtor::NO_THROW, 0>();
-}
-TEST(Function, InvokeFunctor_T1) {
-  invoke_functor_test<FunctionMoveCtor::MAY_THROW, 1>();
-}
-TEST(Function, InvokeFunctor_N1) {
-  invoke_functor_test<FunctionMoveCtor::NO_THROW, 1>();
-}
-TEST(Function, InvokeFunctor_T2) {
-  invoke_functor_test<FunctionMoveCtor::MAY_THROW, 2>();
-}
-TEST(Function, InvokeFunctor_N2) {
-  invoke_functor_test<FunctionMoveCtor::NO_THROW, 2>();
-}
-TEST(Function, InvokeFunctor_T3) {
-  invoke_functor_test<FunctionMoveCtor::MAY_THROW, 3>();
-}
-TEST(Function, InvokeFunctor_N3) {
-  invoke_functor_test<FunctionMoveCtor::NO_THROW, 3>();
+  Function<int(size_t) const> getter = std::move(func);
+
+  // Function will allocate memory on the heap to store the functor object
+  EXPECT_TRUE(getter.hasAllocatedMemory());
+
+  EXPECT_EQ(123, getter(5));
 }
 
-template <FunctionMoveCtor NEM>
-void invoke_reference_test() {
+TEST(Function, InvokeReference) {
   Functor<int, 10> func;
   func(5, 123);
 
-  // Have Functions for getter and setter, both referencing the
-  // same funtor
-  Function<int(size_t) const, NEM, 0> getter = std::ref(func);
-  Function<int(size_t, int), NEM, 0> setter = std::ref(func);
+  // Have Functions for getter and setter, both referencing the same funtor
+  Function<int(size_t) const> getter = std::ref(func);
+  Function<int(size_t, int)> setter = std::ref(func);
 
-  EXPECT_EQ(getter(5), 123);
-  EXPECT_EQ(setter(5, 456), 123);
-  EXPECT_EQ(setter(5, 567), 456);
-  EXPECT_EQ(getter(5), 567);
-}
-TEST(Function, InvokeReference_T) {
-  invoke_reference_test<FunctionMoveCtor::MAY_THROW>();
-}
-TEST(Function, InvokeReference_N) {
-  invoke_reference_test<FunctionMoveCtor::NO_THROW>();
+  EXPECT_EQ(123, getter(5));
+  EXPECT_EQ(123, setter(5, 456));
+  EXPECT_EQ(456, setter(5, 567));
+  EXPECT_EQ(567, getter(5));
 }
 
 // TEST =====================================================================
 // Emptiness
 
-template <FunctionMoveCtor NEM>
-void emptiness_test() {
-  Function<int(int), NEM> f;
+TEST(Function, Emptiness_T) {
+  Function<int(int)> f;
   EXPECT_EQ(f, nullptr);
   EXPECT_EQ(nullptr, f);
   EXPECT_FALSE(f);
   EXPECT_THROW(f(98), std::bad_function_call);
 
-  Function<int(int), NEM> g([](int x) { return x + 1; });
+  Function<int(int)> g([](int x) { return x + 1; });
   EXPECT_NE(g, nullptr);
   EXPECT_NE(nullptr, g);
-  EXPECT_TRUE(g);
-  EXPECT_EQ(g(99), 100);
+  // Explicitly convert to bool to work around
+  // https://github.com/google/googletest/issues/429
+  EXPECT_TRUE(bool(g));
+  EXPECT_EQ(100, g(99));
 
-  Function<int(int), NEM> h(&func_int_int_add_25);
+  Function<int(int)> h(&func_int_int_add_25);
   EXPECT_NE(h, nullptr);
   EXPECT_NE(nullptr, h);
-  EXPECT_TRUE(h);
-  EXPECT_EQ(h(100), 125);
+  EXPECT_TRUE(bool(h));
+  EXPECT_EQ(125, h(100));
 
   h = {};
   EXPECT_EQ(h, nullptr);
@@ -216,315 +119,97 @@ void emptiness_test() {
   EXPECT_THROW(h(101), std::bad_function_call);
 }
 
-TEST(Function, Emptiness_T) {
-  emptiness_test<FunctionMoveCtor::MAY_THROW>();
-}
-TEST(Function, Emptiness_N) {
-  emptiness_test<FunctionMoveCtor::NO_THROW>();
-}
-
-// TEST =====================================================================
-// Types
-
-TEST(Function, Types) {
-  EXPECT_TRUE((
-      !std::is_base_of<std::unary_function<int, int>, Function<int()>>::value));
-  EXPECT_TRUE(
-      (!std::is_base_of<std::binary_function<int, int, int>, Function<int()>>::
-           value));
-  EXPECT_TRUE((std::is_same<Function<int()>::ResultType, int>::value));
-
-  EXPECT_TRUE((
-      std::is_base_of<std::unary_function<int, double>, Function<double(int)>>::
-          value));
-  EXPECT_TRUE((!std::is_base_of<
-               std::binary_function<int, int, double>,
-               Function<double(int)>>::value));
-  EXPECT_TRUE((std::is_same<Function<double(int)>::ResultType, double>::value));
-  EXPECT_TRUE(
-      (std::is_same<Function<double(int)>::result_type, double>::value));
-  EXPECT_TRUE((std::is_same<Function<double(int)>::argument_type, int>::value));
-
-  EXPECT_TRUE((!std::is_base_of<
-               std::unary_function<int, double>,
-               Function<double(int, char)>>::value));
-  EXPECT_TRUE((std::is_base_of<
-               std::binary_function<int, char, double>,
-               Function<double(int, char)>>::value));
-  EXPECT_TRUE(
-      (std::is_same<Function<double(int, char)>::ResultType, double>::value));
-  EXPECT_TRUE(
-      (std::is_same<Function<double(int, char)>::result_type, double>::value));
-  EXPECT_TRUE(
-      (std::is_same<Function<double(int, char)>::first_argument_type, int>::
-           value));
-  EXPECT_TRUE(
-      (std::is_same<Function<double(int, char)>::second_argument_type, char>::
-           value));
-}
-
 // TEST =====================================================================
 // Swap
 
-template <FunctionMoveCtor NEM1, FunctionMoveCtor NEM2>
+template <bool UseSwapMethod>
 void swap_test() {
-  Function<int(int), NEM1> mf1(func_int_int_add_25);
-  Function<int(int), NEM2> mf2(func_int_int_add_111);
+  Function<int(int)> mf1(func_int_int_add_25);
+  Function<int(int)> mf2(func_int_int_add_111);
 
-  EXPECT_EQ(mf1(100), 125);
-  EXPECT_EQ(mf2(100), 211);
+  EXPECT_EQ(125, mf1(100));
+  EXPECT_EQ(211, mf2(100));
 
-  mf1.swap(mf2);
+  if (UseSwapMethod) {
+    mf1.swap(mf2);
+  } else {
+    swap(mf1, mf2);
+  }
 
-  EXPECT_EQ(mf2(100), 125);
-  EXPECT_EQ(mf1(100), 211);
+  EXPECT_EQ(125, mf2(100));
+  EXPECT_EQ(211, mf1(100));
 
   Function<int(int)> mf3(nullptr);
   EXPECT_EQ(mf3, nullptr);
 
-  mf1.swap(mf3);
+  if (UseSwapMethod) {
+    mf1.swap(mf3);
+  } else {
+    swap(mf1, mf3);
+  }
 
-  EXPECT_EQ(mf3(100), 211);
-  EXPECT_EQ(mf1, nullptr);
+  EXPECT_EQ(211, mf3(100));
+  EXPECT_EQ(nullptr, mf1);
 
   Function<int(int)> mf4([](int x) { return x + 222; });
-  EXPECT_EQ(mf4(100), 322);
+  EXPECT_EQ(322, mf4(100));
 
-  mf4.swap(mf3);
-  EXPECT_EQ(mf4(100), 211);
-  EXPECT_EQ(mf3(100), 322);
+  if (UseSwapMethod) {
+    mf4.swap(mf3);
+  } else {
+    swap(mf4, mf3);
+  }
+  EXPECT_EQ(211, mf4(100));
+  EXPECT_EQ(322, mf3(100));
 
-  mf3.swap(mf1);
-  EXPECT_EQ(mf3, nullptr);
-  EXPECT_EQ(mf1(100), 322);
-}
-TEST(Function, Swap_TT) {
-  swap_test<FunctionMoveCtor::MAY_THROW, FunctionMoveCtor::MAY_THROW>();
-}
-TEST(Function, Swap_TN) {
-  swap_test<FunctionMoveCtor::MAY_THROW, FunctionMoveCtor::NO_THROW>();
+  if (UseSwapMethod) {
+    mf3.swap(mf1);
+  } else {
+    swap(mf3, mf1);
+  }
+  EXPECT_EQ(nullptr, mf3);
+  EXPECT_EQ(322, mf1(100));
 }
-TEST(Function, Swap_NT) {
-  swap_test<FunctionMoveCtor::NO_THROW, FunctionMoveCtor::MAY_THROW>();
+TEST(Function, SwapMethod) {
+  swap_test<true>();
 }
-TEST(Function, Swap_NN) {
-  swap_test<FunctionMoveCtor::NO_THROW, FunctionMoveCtor::NO_THROW>();
+TEST(Function, SwapFunction) {
+  swap_test<false>();
 }
 
 // TEST =====================================================================
 // Bind
 
-template <FunctionMoveCtor NEM>
-void bind_test() {
-  Function<float(float, float), NEM> fnc = floatMult;
+TEST(Function, Bind) {
+  Function<float(float, float)> fnc = floatMult;
   auto task = std::bind(std::move(fnc), 2.f, 4.f);
   EXPECT_THROW(fnc(0, 0), std::bad_function_call);
-  EXPECT_EQ(task(), 8);
+  EXPECT_EQ(8, task());
   auto task2(std::move(task));
   EXPECT_THROW(task(), std::bad_function_call);
-  EXPECT_EQ(task2(), 8);
-}
-TEST(Function, Bind_T) {
-  bind_test<FunctionMoveCtor::MAY_THROW>();
-}
-TEST(Function, Bind_N) {
-  bind_test<FunctionMoveCtor::NO_THROW>();
+  EXPECT_EQ(8, task2());
 }
 
 // TEST =====================================================================
 // NonCopyableLambda
 
-template <FunctionMoveCtor NEM, size_t S>
-void non_copyable_lambda_test() {
+TEST(Function, NonCopyableLambda) {
   auto unique_ptr_int = folly::make_unique<int>(900);
-  EXPECT_EQ(*unique_ptr_int, 900);
+  EXPECT_EQ(900, *unique_ptr_int);
 
   char fooData[64] = {0};
-  EXPECT_EQ(fooData[0], 0); // suppress gcc warning about fooData not being used
+  EXPECT_EQ(0, fooData[0]); // suppress gcc warning about fooData not being used
 
   auto functor = std::bind(
       [fooData](std::unique_ptr<int>& up) mutable { return ++*up; },
       std::move(unique_ptr_int));
 
-  EXPECT_EQ(functor(), 901);
-
-  Function<int(void), NEM, sizeof(functor)* S / 2> func = std::move(functor);
-  EXPECT_EQ(
-      func.hasAllocatedMemory(),
-      S < 2 || (NEM == FunctionMoveCtor::NO_THROW &&
-                !std::is_nothrow_move_constructible<decltype(functor)>::value));
+  EXPECT_EQ(901, functor());
 
-  EXPECT_EQ(func(), 902);
-}
-TEST(Function, NonCopyableLambda_T0) {
-  non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 0>();
-}
-TEST(Function, NonCopyableLambda_N0) {
-  non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 0>();
-}
-TEST(Function, NonCopyableLambda_T1) {
-  non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 1>();
-}
-TEST(Function, NonCopyableLambda_N1) {
-  non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 1>();
-}
-TEST(Function, NonCopyableLambda_T2) {
-  non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 2>();
-}
-TEST(Function, NonCopyableLambda_N2) {
-  non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 2>();
-}
-TEST(Function, NonCopyableLambda_T3) {
-  non_copyable_lambda_test<FunctionMoveCtor::MAY_THROW, 3>();
-}
-TEST(Function, NonCopyableLambda_N3) {
-  non_copyable_lambda_test<FunctionMoveCtor::NO_THROW, 3>();
-}
+  Function<int(void)> func = std::move(functor);
+  EXPECT_TRUE(func.hasAllocatedMemory());
 
-// TEST =====================================================================
-// Downsize
-
-template <FunctionMoveCtor NEM>
-void downsize_test() {
-  Functor<int, 10> functor;
-
-  // set element 3
-  functor(3, 123);
-  EXPECT_EQ(functor(3), 123);
-
-  // Function with large callable storage area (twice the size of
-  // the functor)
-  Function<int(size_t, int), NEM, sizeof(functor)* 2> func2x =
-      std::move(functor);
-  EXPECT_FALSE(func2x.hasAllocatedMemory());
-  EXPECT_EQ(func2x(3, 200), 123);
-  EXPECT_EQ(func2x(3, 201), 200);
-
-  // Function with sufficient callable storage area (equal to
-  // size of the functor)
-  Function<int(size_t, int), NEM, sizeof(functor)> func1x = std::move(func2x);
-  EXPECT_THROW(func2x(0, 0), std::bad_function_call);
-  EXPECT_FALSE(func2x);
-  EXPECT_FALSE(func1x.hasAllocatedMemory());
-  EXPECT_EQ(func1x(3, 202), 201);
-  EXPECT_EQ(func1x(3, 203), 202);
-
-  // Function with minimal callable storage area (functor does
-  // not fit and will be moved to memory on the heap)
-  Function<int(size_t, int), NEM, 0> func0x = std::move(func1x);
-  EXPECT_THROW(func1x(0, 0), std::bad_function_call);
-  EXPECT_FALSE(func1x);
-  EXPECT_TRUE(func0x.hasAllocatedMemory());
-  EXPECT_EQ(func0x(3, 204), 203);
-  EXPECT_EQ(func0x(3, 205), 204);
-
-  // bonus test: move to Function with opposite NoExceptMovable
-  // setting
-  Function<
-      int(size_t, int),
-      NEM == FunctionMoveCtor::NO_THROW ? FunctionMoveCtor::MAY_THROW
-                                        : FunctionMoveCtor::NO_THROW,
-      0>
-      funcnot = std::move(func0x);
-  EXPECT_THROW(func0x(0, 0), std::bad_function_call);
-  EXPECT_FALSE(func0x);
-  EXPECT_TRUE(funcnot.hasAllocatedMemory());
-  EXPECT_EQ(funcnot(3, 206), 205);
-  EXPECT_EQ(funcnot(3, 207), 206);
-}
-TEST(Function, Downsize_T) {
-  downsize_test<FunctionMoveCtor::MAY_THROW>();
-}
-TEST(Function, Downsize_N) {
-  downsize_test<FunctionMoveCtor::NO_THROW>();
-}
-
-// TEST =====================================================================
-// Refcount
-
-template <FunctionMoveCtor NEM>
-void refcount_test() {
-  Functor<int, 100> functor;
-  functor(3, 999);
-  auto shared_int = std::make_shared<int>(100);
-
-  EXPECT_EQ(*shared_int, 100);
-  EXPECT_EQ(shared_int.use_count(), 1);
-
-  Function<int(void), NEM> func1 = [shared_int]() { return ++*shared_int; };
-  EXPECT_EQ(shared_int.use_count(), 2);
-  EXPECT_EQ(func1(), 101);
-  EXPECT_EQ(*shared_int, 101);
-
-  // func2: made to not fit functor.
-  Function<int(void), NEM, sizeof(functor) / 2> func2 = std::move(func1);
-  EXPECT_THROW(func1(), std::bad_function_call);
-  EXPECT_EQ(shared_int.use_count(), 2);
-  EXPECT_FALSE(func1);
-  EXPECT_EQ(func2(), 102);
-  EXPECT_EQ(*shared_int, 102);
-
-  func2 = [shared_int]() { return ++*shared_int; };
-  EXPECT_EQ(shared_int.use_count(), 2);
-  EXPECT_EQ(func2(), 103);
-  EXPECT_EQ(*shared_int, 103);
-
-  // We set func2 to a lambda that captures 'functor', which forces it on
-  // the heap
-  func2 = [functor]() { return functor(3); };
-  EXPECT_TRUE(func2.hasAllocatedMemory());
-  EXPECT_EQ(func2(), 999);
-  EXPECT_EQ(shared_int.use_count(), 1);
-  EXPECT_EQ(*shared_int, 103);
-
-  func2 = [shared_int]() { return ++*shared_int; };
-  EXPECT_EQ(shared_int.use_count(), 2);
-  EXPECT_EQ(func2(), 104);
-  EXPECT_EQ(*shared_int, 104);
-
-  // We set func2 to function pointer, which always fits into the
-  // Function object and is no-except-movable
-  func2 = &func_int_return_987;
-  EXPECT_FALSE(func2.hasAllocatedMemory());
-  EXPECT_EQ(func2(), 987);
-  EXPECT_EQ(shared_int.use_count(), 1);
-  EXPECT_EQ(*shared_int, 104);
-}
-TEST(Function, Refcount_T) {
-  refcount_test<FunctionMoveCtor::MAY_THROW>();
-}
-TEST(Function, Refcount_N) {
-  refcount_test<FunctionMoveCtor::NO_THROW>();
-}
-
-// TEST =====================================================================
-// Target
-
-template <FunctionMoveCtor NEM>
-void target_test() {
-  std::function<int(int)> func = [](int x) { return x + 25; };
-  EXPECT_EQ(func(100), 125);
-
-  Function<int(int), NEM> ufunc = std::move(func);
-  EXPECT_THROW(func(0), std::bad_function_call);
-  EXPECT_EQ(ufunc(200), 225);
-
-  EXPECT_EQ(ufunc.target_type(), typeid(std::function<int(int)>));
-
-  EXPECT_FALSE(ufunc.template target<int>());
-  EXPECT_FALSE(ufunc.template target<std::function<void(void)>>());
-
-  std::function<int(int)>& ufunc_target =
-      *ufunc.template target<std::function<int(int)>>();
-
-  EXPECT_EQ(ufunc_target(300), 325);
-}
-
-TEST(Function, Target_T) {
-  target_test<FunctionMoveCtor::MAY_THROW>();
-}
-TEST(Function, Target_N) {
-  target_test<FunctionMoveCtor::NO_THROW>();
+  EXPECT_EQ(902, func());
 }
 
 // TEST =====================================================================
@@ -565,26 +250,26 @@ TEST(Function, OverloadedFunctor) {
   OverloadedFunctor of;
 
   Function<int(int)> variant1 = of;
-  EXPECT_EQ(variant1(15), 100 + 1 * 15);
+  EXPECT_EQ(100 + 1 * 15, variant1(15));
 
   Function<int(int) const> variant2 = of;
-  EXPECT_EQ(variant2(16), 100 + 2 * 16);
+  EXPECT_EQ(100 + 2 * 16, variant2(16));
 
   Function<int(int, int)> variant3 = of;
-  EXPECT_EQ(variant3(17, 0), 100 + 3 * 17);
+  EXPECT_EQ(100 + 3 * 17, variant3(17, 0));
 
   Function<int(int, int) const> variant4 = of;
-  EXPECT_EQ(variant4(18, 0), 100 + 4 * 18);
+  EXPECT_EQ(100 + 4 * 18, variant4(18, 0));
 
   Function<int(int, char const*)> variant5 = of;
-  EXPECT_EQ(variant5(19, "foo"), 100 + 5 * 19);
+  EXPECT_EQ(100 + 5 * 19, variant5(19, "foo"));
 
   Function<int(int, std::vector<int> const&)> variant6 = of;
-  EXPECT_EQ(variant6(20, {}), 100 + 6 * 20);
-  EXPECT_EQ(variant6(20, {1, 2, 3}), 100 + 6 * 20);
+  EXPECT_EQ(100 + 6 * 20, variant6(20, {}));
+  EXPECT_EQ(100 + 6 * 20, variant6(20, {1, 2, 3}));
 
   Function<int(int, std::vector<int> const&) const> variant6const = of;
-  EXPECT_EQ(variant6const(21, {}), 100 + 6 * 21);
+  EXPECT_EQ(100 + 6 * 21, variant6const(21, {}));
 
   // Cast const-functions to non-const and the other way around: if the functor
   // has both const and non-const operator()s for a given parameter signature,
@@ -598,32 +283,32 @@ TEST(Function, OverloadedFunctor) {
 
   auto variant1_const = folly::constCastFunction(std::move(variant1));
   EXPECT_THROW(variant1(0), std::bad_function_call);
-  EXPECT_EQ(variant1_const(22), 100 + 1 * 22);
+  EXPECT_EQ(100 + 1 * 22, variant1_const(22));
 
   Function<int(int)> variant2_nonconst = std::move(variant2);
   EXPECT_THROW(variant2(0), std::bad_function_call);
-  EXPECT_EQ(variant2_nonconst(23), 100 + 2 * 23);
+  EXPECT_EQ(100 + 2 * 23, variant2_nonconst(23));
 
   auto variant3_const = folly::constCastFunction(std::move(variant3));
   EXPECT_THROW(variant3(0, 0), std::bad_function_call);
-  EXPECT_EQ(variant3_const(24, 0), 100 + 3 * 24);
+  EXPECT_EQ(100 + 3 * 24, variant3_const(24, 0));
 
   Function<int(int, int)> variant4_nonconst = std::move(variant4);
   EXPECT_THROW(variant4(0, 0), std::bad_function_call);
-  EXPECT_EQ(variant4_nonconst(25, 0), 100 + 4 * 25);
+  EXPECT_EQ(100 + 4 * 25, variant4_nonconst(25, 0));
 
   auto variant5_const = folly::constCastFunction(std::move(variant5));
   EXPECT_THROW(variant5(0, ""), std::bad_function_call);
-  EXPECT_EQ(variant5_const(26, "foo"), 100 + 5 * 26);
+  EXPECT_EQ(100 + 5 * 26, variant5_const(26, "foo"));
 
   auto variant6_const = folly::constCastFunction(std::move(variant6));
   EXPECT_THROW(variant6(0, {}), std::bad_function_call);
-  EXPECT_EQ(variant6_const(27, {}), 100 + 6 * 27);
+  EXPECT_EQ(100 + 6 * 27, variant6_const(27, {}));
 
   Function<int(int, std::vector<int> const&)> variant6const_nonconst =
       std::move(variant6const);
   EXPECT_THROW(variant6const(0, {}), std::bad_function_call);
-  EXPECT_EQ(variant6const_nonconst(28, {}), 100 + 6 * 28);
+  EXPECT_EQ(100 + 6 * 28, variant6const_nonconst(28, {}));
 }
 
 // TEST =====================================================================
@@ -632,33 +317,33 @@ TEST(Function, OverloadedFunctor) {
 TEST(Function, Lambda) {
   // Non-mutable lambdas: can be stored in a non-const...
   Function<int(int)> func = [](int x) { return 1000 + x; };
-  EXPECT_EQ(func(1), 1001);
+  EXPECT_EQ(1001, func(1));
 
   // ...as well as in a const Function
   Function<int(int) const> func_const = [](int x) { return 2000 + x; };
-  EXPECT_EQ(func_const(1), 2001);
+  EXPECT_EQ(2001, func_const(1));
 
   // Mutable lambda: can only be stored in a const Function:
   int number = 3000;
   Function<int()> func_mutable = [number]() mutable { return ++number; };
-  EXPECT_EQ(func_mutable(), 3001);
-  EXPECT_EQ(func_mutable(), 3002);
+  EXPECT_EQ(3001, func_mutable());
+  EXPECT_EQ(3002, func_mutable());
 
   // test after const-casting
 
   Function<int(int) const> func_made_const =
       folly::constCastFunction(std::move(func));
-  EXPECT_EQ(func_made_const(2), 1002);
+  EXPECT_EQ(1002, func_made_const(2));
   EXPECT_THROW(func(0), std::bad_function_call);
 
   Function<int(int)> func_const_made_nonconst = std::move(func_const);
-  EXPECT_EQ(func_const_made_nonconst(2), 2002);
+  EXPECT_EQ(2002, func_const_made_nonconst(2));
   EXPECT_THROW(func_const(0), std::bad_function_call);
 
   Function<int() const> func_mutable_made_const =
       folly::constCastFunction(std::move(func_mutable));
-  EXPECT_EQ(func_mutable_made_const(), 3003);
-  EXPECT_EQ(func_mutable_made_const(), 3004);
+  EXPECT_EQ(3003, func_mutable_made_const());
+  EXPECT_EQ(3004, func_mutable_made_const());
   EXPECT_THROW(func_mutable(), std::bad_function_call);
 }
 
@@ -681,13 +366,13 @@ TEST(Function, DataMember) {
   mf.x = 123;
 
   Function<int(MemberFunc const*)> data_getter1 = &MemberFunc::x;
-  EXPECT_EQ(data_getter1(&cmf), 123);
+  EXPECT_EQ(123, data_getter1(&cmf));
   Function<int(MemberFunc*)> data_getter2 = &MemberFunc::x;
-  EXPECT_EQ(data_getter2(&mf), 123);
+  EXPECT_EQ(123, data_getter2(&mf));
   Function<int(MemberFunc const&)> data_getter3 = &MemberFunc::x;
-  EXPECT_EQ(data_getter3(cmf), 123);
+  EXPECT_EQ(123, data_getter3(cmf));
   Function<int(MemberFunc&)> data_getter4 = &MemberFunc::x;
-  EXPECT_EQ(data_getter4(mf), 123);
+  EXPECT_EQ(123, data_getter4(mf));
 }
 
 TEST(Function, MemberFunction) {
@@ -696,21 +381,21 @@ TEST(Function, MemberFunction) {
   mf.x = 123;
 
   Function<int(MemberFunc const*)> getter1 = &MemberFunc::getX;
-  EXPECT_EQ(getter1(&cmf), 123);
+  EXPECT_EQ(123, getter1(&cmf));
   Function<int(MemberFunc*)> getter2 = &MemberFunc::getX;
-  EXPECT_EQ(getter2(&mf), 123);
+  EXPECT_EQ(123, getter2(&mf));
   Function<int(MemberFunc const&)> getter3 = &MemberFunc::getX;
-  EXPECT_EQ(getter3(cmf), 123);
+  EXPECT_EQ(123, getter3(cmf));
   Function<int(MemberFunc&)> getter4 = &MemberFunc::getX;
-  EXPECT_EQ(getter4(mf), 123);
+  EXPECT_EQ(123, getter4(mf));
 
   Function<void(MemberFunc*, int)> setter1 = &MemberFunc::setX;
   setter1(&mf, 234);
-  EXPECT_EQ(mf.x, 234);
+  EXPECT_EQ(234, mf.x);
 
   Function<void(MemberFunc&, int)> setter2 = &MemberFunc::setX;
   setter2(mf, 345);
-  EXPECT_EQ(mf.x, 345);
+  EXPECT_EQ(345, mf.x);
 }
 
 // TEST =====================================================================
@@ -764,9 +449,9 @@ TEST(Function, CaptureCopyMoveCount) {
   // This test checks that no unnecessary copies/moves are made.
 
   CopyMoveTracker cmt(CopyMoveTracker::ConstructorTag{});
-  EXPECT_EQ(cmt.copyCount(), 0);
-  EXPECT_EQ(cmt.moveCount(), 0);
-  EXPECT_EQ(cmt.refCount(), 1);
+  EXPECT_EQ(0, cmt.copyCount());
+  EXPECT_EQ(0, cmt.moveCount());
+  EXPECT_EQ(1, cmt.refCount());
 
   // Move into lambda, move lambda into Function
   auto lambda1 = [cmt = std::move(cmt)]() {
@@ -794,17 +479,17 @@ TEST(Function, CaptureCopyMoveCount) {
   cmt.resetCounters();
   uf1();
   uf2();
-  EXPECT_EQ(cmt.copyCount(), 0);
-  EXPECT_EQ(cmt.moveCount(), 0);
+  EXPECT_EQ(0, cmt.copyCount());
+  EXPECT_EQ(0, cmt.moveCount());
 }
 
 TEST(Function, ParameterCopyMoveCount) {
   // This test checks that no unnecessary copies/moves are made.
 
   CopyMoveTracker cmt(CopyMoveTracker::ConstructorTag{});
-  EXPECT_EQ(cmt.copyCount(), 0);
-  EXPECT_EQ(cmt.moveCount(), 0);
-  EXPECT_EQ(cmt.refCount(), 1);
+  EXPECT_EQ(0, cmt.copyCount());
+  EXPECT_EQ(0, cmt.moveCount());
+  EXPECT_EQ(1, cmt.refCount());
 
   // pass by value
   Function<size_t(CopyMoveTracker)> uf1 = [](CopyMoveTracker c) {
@@ -857,149 +542,6 @@ TEST(Function, ParameterCopyMoveCount) {
   EXPECT_LE(cmt.copyCount(), 0);
 }
 
-// TEST =====================================================================
-// CopyMoveThrows
-
-enum ExceptionType { COPY, MOVE };
-
-template <ExceptionType ET>
-class CopyMoveException : public std::runtime_error {
- public:
-  using std::runtime_error::runtime_error;
-};
-
-template <bool CopyThrows, bool MoveThrows>
-struct CopyMoveThrowsCallable {
-  int allowCopyOperations{0};
-  int allowMoveOperations{0};
-
-  CopyMoveThrowsCallable() = default;
-  CopyMoveThrowsCallable(CopyMoveThrowsCallable const& o) noexcept(
-      !CopyThrows) {
-    *this = o;
-  }
-  CopyMoveThrowsCallable& operator=(CopyMoveThrowsCallable const& o) noexcept(
-      !CopyThrows) {
-    allowCopyOperations = o.allowCopyOperations;
-    allowMoveOperations = o.allowMoveOperations;
-
-    if (allowCopyOperations > 0) {
-      --allowCopyOperations;
-    } else if (CopyThrows) {
-      throw CopyMoveException<COPY>("CopyMoveThrowsCallable copy");
-    }
-    return *this;
-  }
-  CopyMoveThrowsCallable(CopyMoveThrowsCallable&& o) noexcept(!MoveThrows) {
-    *this = std::move(o);
-  }
-  CopyMoveThrowsCallable& operator=(CopyMoveThrowsCallable&& o) noexcept(
-      !MoveThrows) {
-    allowCopyOperations = o.allowCopyOperations;
-    allowMoveOperations = o.allowMoveOperations;
-
-    if (o.allowMoveOperations > 0) {
-      --allowMoveOperations;
-    } else if (MoveThrows) {
-      throw CopyMoveException<MOVE>("CopyMoveThrowsCallable move");
-    }
-    return *this;
-  }
-
-  void operator()() const {}
-};
-
-TEST(Function, CopyMoveThrowsCallable) {
-  EXPECT_TRUE((std::is_nothrow_move_constructible<
-               CopyMoveThrowsCallable<false, false>>::value));
-  EXPECT_TRUE((std::is_nothrow_move_constructible<
-               CopyMoveThrowsCallable<true, false>>::value));
-  EXPECT_FALSE((std::is_nothrow_move_constructible<
-                CopyMoveThrowsCallable<false, true>>::value));
-  EXPECT_FALSE((std::is_nothrow_move_constructible<
-                CopyMoveThrowsCallable<true, true>>::value));
-
-  EXPECT_TRUE((std::is_nothrow_copy_constructible<
-               CopyMoveThrowsCallable<false, false>>::value));
-  EXPECT_FALSE((std::is_nothrow_copy_constructible<
-                CopyMoveThrowsCallable<true, false>>::value));
-  EXPECT_TRUE((std::is_nothrow_copy_constructible<
-               CopyMoveThrowsCallable<false, true>>::value));
-  EXPECT_FALSE((std::is_nothrow_copy_constructible<
-                CopyMoveThrowsCallable<true, true>>::value));
-}
-
-template <FunctionMoveCtor NEM, bool CopyThrows, bool MoveThrows>
-void copy_and_move_throws_test() {
-  CopyMoveThrowsCallable<CopyThrows, MoveThrows> c;
-  Function<void(void), NEM> uf;
-
-  if (CopyThrows) {
-    EXPECT_THROW((uf = c), CopyMoveException<COPY>);
-  } else {
-    EXPECT_NO_THROW((uf = c));
-  }
-
-  if (MoveThrows) {
-    EXPECT_THROW((uf = std::move(c)), CopyMoveException<MOVE>);
-  } else {
-    EXPECT_NO_THROW((uf = std::move(c)));
-  }
-
-  c.allowMoveOperations = 1;
-  uf = std::move(c);
-  if (NEM == FunctionMoveCtor::MAY_THROW && MoveThrows) {
-    Function<void(void), NEM> uf2;
-    EXPECT_THROW((uf2 = std::move(uf)), CopyMoveException<MOVE>);
-  } else {
-    Function<void(void), NEM> uf2;
-    EXPECT_NO_THROW((uf2 = std::move(uf)));
-  }
-
-  c.allowMoveOperations = 0;
-  c.allowCopyOperations = 1;
-  uf = c;
-  if (NEM == FunctionMoveCtor::MAY_THROW && MoveThrows) {
-    Function<void(void), NEM> uf2;
-    EXPECT_THROW((uf2 = std::move(uf)), CopyMoveException<MOVE>);
-  } else {
-    Function<void(void), NEM> uf2;
-    EXPECT_NO_THROW((uf2 = std::move(uf)));
-  }
-}
-
-TEST(Function, CopyAndMoveThrows_TNN) {
-  copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, false, false>();
-}
-
-TEST(Function, CopyAndMoveThrows_NNN) {
-  copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, false, false>();
-}
-
-TEST(Function, CopyAndMoveThrows_TTN) {
-  copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, true, false>();
-}
-
-TEST(Function, CopyAndMoveThrows_NTN) {
-  copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, true, false>();
-}
-
-TEST(Function, CopyAndMoveThrows_TNT) {
-  copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, false, true>();
-}
-
-TEST(Function, CopyAndMoveThrows_NNT) {
-  copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, false, true>();
-}
-
-TEST(Function, CopyAndMoveThrows_TTT) {
-  copy_and_move_throws_test<FunctionMoveCtor::MAY_THROW, true, true>();
-}
-
-TEST(Function, CopyAndMoveThrows_NTT) {
-  copy_and_move_throws_test<FunctionMoveCtor::NO_THROW, true, true>();
-}
-
 // TEST =====================================================================
 // VariadicTemplate & VariadicArguments
 
@@ -1018,9 +560,9 @@ TEST(Function, VariadicTemplate) {
   Function<int(int, int)> uf2 = VariadicTemplateSum();
   Function<int(int, int, int)> uf3 = VariadicTemplateSum();
 
-  EXPECT_EQ(uf1(66), 66);
-  EXPECT_EQ(uf2(55, 44), 99);
-  EXPECT_EQ(uf3(33, 22, 11), 66);
+  EXPECT_EQ(66, uf1(66));
+  EXPECT_EQ(99, uf2(55, 44));
+  EXPECT_EQ(66, uf3(33, 22, 11));
 }
 
 struct VariadicArgumentsSum {
@@ -1041,9 +583,9 @@ TEST(Function, VariadicArguments) {
   Function<int(int, int)> uf2 = VariadicArgumentsSum();
   Function<int(int, int, int)> uf3 = VariadicArgumentsSum();
 
-  EXPECT_EQ(uf1(0), 0);
-  EXPECT_EQ(uf2(1, 66), 66);
-  EXPECT_EQ(uf3(2, 55, 44), 99);
+  EXPECT_EQ(0, uf1(0));
+  EXPECT_EQ(66, uf2(1, 66));
+  EXPECT_EQ(99, uf3(2, 55, 44));
 }
 
 // TEST =====================================================================
@@ -1079,7 +621,7 @@ TEST(Function, SafeCaptureByReference) {
   // to for_each. Modern compiler versions can compile the following line:
   //   for_each(vec, [&sum](int x) { sum += x; });
 
-  EXPECT_EQ(sum, 999);
+  EXPECT_EQ(999, sum);
 }
 
 // TEST =====================================================================
@@ -1091,16 +633,16 @@ TEST(Function, IgnoreReturnValue) {
   // Assign a lambda that return int to a folly::Function that returns void.
   Function<void()> f = [&]() -> int { return ++x; };
 
-  EXPECT_EQ(x, 95);
+  EXPECT_EQ(95, x);
   f();
-  EXPECT_EQ(x, 96);
+  EXPECT_EQ(96, x);
 
   Function<int()> g = [&]() -> int { return ++x; };
   Function<void()> cg = std::move(g);
 
-  EXPECT_EQ(x, 96);
+  EXPECT_EQ(96, x);
   cg();
-  EXPECT_EQ(x, 97);
+  EXPECT_EQ(97, x);
 }
 
 // TEST =====================================================================
@@ -1113,38 +655,38 @@ TEST(Function, ReturnConvertible) {
   struct CDerived : CBase {};
 
   Function<double()> f1 = []() -> int { return 5; };
-  EXPECT_EQ(f1(), 5.0);
+  EXPECT_EQ(5.0, f1());
 
   Function<int()> f2 = []() -> double { return 5.2; };
-  EXPECT_EQ(f2(), 5);
+  EXPECT_EQ(5, f2());
 
   CDerived derived;
   derived.x = 55;
 
   Function<CBase const&()> f3 = [&]() -> CDerived const& { return derived; };
-  EXPECT_EQ(f3().x, 55);
+  EXPECT_EQ(55, f3().x);
 
   Function<CBase const&()> f4 = [&]() -> CDerived& { return derived; };
-  EXPECT_EQ(f4().x, 55);
+  EXPECT_EQ(55, f4().x);
 
   Function<CBase&()> f5 = [&]() -> CDerived& { return derived; };
-  EXPECT_EQ(f5().x, 55);
+  EXPECT_EQ(55, f5().x);
 
   Function<CBase const*()> f6 = [&]() -> CDerived const* { return &derived; };
   EXPECT_EQ(f6()->x, 55);
 
   Function<CBase const*()> f7 = [&]() -> CDerived* { return &derived; };
-  EXPECT_EQ(f7()->x, 55);
+  EXPECT_EQ(55, f7()->x);
 
   Function<CBase*()> f8 = [&]() -> CDerived* { return &derived; };
-  EXPECT_EQ(f8()->x, 55);
+  EXPECT_EQ(55, f8()->x);
 
   Function<CBase()> f9 = [&]() -> CDerived {
     auto d = derived;
     d.x = 66;
     return d;
   };
-  EXPECT_EQ(f9().x, 66);
+  EXPECT_EQ(66, f9().x);
 }
 
 TEST(Function, ConvertReturnType) {
@@ -1155,44 +697,44 @@ TEST(Function, ConvertReturnType) {
 
   Function<int()> f1 = []() -> int { return 5; };
   Function<double()> cf1 = std::move(f1);
-  EXPECT_EQ(cf1(), 5.0);
+  EXPECT_EQ(5.0, cf1());
   Function<int()> ccf1 = std::move(cf1);
-  EXPECT_EQ(ccf1(), 5);
+  EXPECT_EQ(5, ccf1());
 
   Function<double()> f2 = []() -> double { return 5.2; };
   Function<int()> cf2 = std::move(f2);
-  EXPECT_EQ(cf2(), 5);
+  EXPECT_EQ(5, cf2());
   Function<double()> ccf2 = std::move(cf2);
-  EXPECT_EQ(ccf2(), 5.0);
+  EXPECT_EQ(5.0, ccf2());
 
   CDerived derived;
   derived.x = 55;
 
   Function<CDerived const&()> f3 = [&]() -> CDerived const& { return derived; };
   Function<CBase const&()> cf3 = std::move(f3);
-  EXPECT_EQ(cf3().x, 55);
+  EXPECT_EQ(55, cf3().x);
 
   Function<CDerived&()> f4 = [&]() -> CDerived& { return derived; };
   Function<CBase const&()> cf4 = std::move(f4);
-  EXPECT_EQ(cf4().x, 55);
+  EXPECT_EQ(55, cf4().x);
 
   Function<CDerived&()> f5 = [&]() -> CDerived& { return derived; };
   Function<CBase&()> cf5 = std::move(f5);
-  EXPECT_EQ(cf5().x, 55);
+  EXPECT_EQ(55, cf5().x);
 
   Function<CDerived const*()> f6 = [&]() -> CDerived const* {
     return &derived;
   };
   Function<CBase const*()> cf6 = std::move(f6);
-  EXPECT_EQ(cf6()->x, 55);
+  EXPECT_EQ(55, cf6()->x);
 
   Function<CDerived const*()> f7 = [&]() -> CDerived* { return &derived; };
   Function<CBase const*()> cf7 = std::move(f7);
-  EXPECT_EQ(cf7()->x, 55);
+  EXPECT_EQ(55, cf7()->x);
 
   Function<CDerived*()> f8 = [&]() -> CDerived* { return &derived; };
   Function<CBase*()> cf8 = std::move(f8);
-  EXPECT_EQ(cf8()->x, 55);
+  EXPECT_EQ(55, cf8()->x);
 
   Function<CDerived()> f9 = [&]() -> CDerived {
     auto d = derived;
@@ -1200,5 +742,123 @@ TEST(Function, ConvertReturnType) {
     return d;
   };
   Function<CBase()> cf9 = std::move(f9);
-  EXPECT_EQ(cf9().x, 66);
+  EXPECT_EQ(66, cf9().x);
+}
+
+// TEST =====================================================================
+// asStdFunction_*
+
+TEST(Function, asStdFunction_void) {
+  int i = 0;
+  folly::Function<void()> f = [&] { ++i; };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<void()>>::value,
+      "std::function has wrong type");
+  sf();
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, asStdFunction_void_const) {
+  int i = 0;
+  folly::Function<void() const> f = [&] { ++i; };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<void()>>::value,
+      "std::function has wrong type");
+  sf();
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, asStdFunction_return) {
+  int i = 0;
+  folly::Function<int()> f = [&] {
+    ++i;
+    return 42;
+  };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<int()>>::value,
+      "std::function has wrong type");
+  EXPECT_EQ(42, sf());
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, asStdFunction_return_const) {
+  int i = 0;
+  folly::Function<int() const> f = [&] {
+    ++i;
+    return 42;
+  };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<int()>>::value,
+      "std::function has wrong type");
+  EXPECT_EQ(42, sf());
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, asStdFunction_args) {
+  int i = 0;
+  folly::Function<void(int, int)> f = [&](int x, int y) {
+    ++i;
+    return x + y;
+  };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<void(int, int)>>::value,
+      "std::function has wrong type");
+  sf(42, 42);
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, asStdFunction_args_const) {
+  int i = 0;
+  folly::Function<void(int, int) const> f = [&](int x, int y) {
+    ++i;
+    return x + y;
+  };
+  auto sf = std::move(f).asStdFunction();
+  static_assert(std::is_same<decltype(sf), std::function<void(int, int)>>::value,
+      "std::function has wrong type");
+  sf(42, 42);
+  EXPECT_EQ(1, i);
+}
+
+TEST(Function, NoAllocatedMemoryAfterMove) {
+  Functor<int, 100> foo;
+
+  Function<int(size_t)> func = foo;
+  EXPECT_TRUE(func.hasAllocatedMemory());
+
+  Function<int(size_t)> func2 = std::move(func);
+  EXPECT_TRUE(func2.hasAllocatedMemory());
+  EXPECT_FALSE(func.hasAllocatedMemory());
+}
+
+TEST(Function, ConstCastEmbedded) {
+  int x = 0;
+  auto functor = [&x]() { ++x; };
+
+  Function<void() const> func(functor);
+  EXPECT_FALSE(func.hasAllocatedMemory());
+
+  Function<void()> func2(std::move(func));
+  EXPECT_FALSE(func2.hasAllocatedMemory());
+}
+
+TEST(Function, EmptyAfterConstCast) {
+  Function<int(size_t)> func;
+  EXPECT_FALSE(func);
+
+  Function<int(size_t) const> func2 = constCastFunction(std::move(func));
+  EXPECT_FALSE(func2);
+}
+
+TEST(Function, SelfMoveAssign) {
+  Function<int()> f = [] { return 0; };
+  Function<int()>& g = f;
+  f = std::move(g);
+  EXPECT_TRUE(bool(f));
+}
+
+TEST(Function, DeducableArguments) {
+  deduceArgs(Function<void()>{[] {}});
+  deduceArgs(Function<void(int, float)>{[](int, float) {}});
+  deduceArgs(Function<int(int, float)>{[](int i, float) { return i; }});
 }