function_ref_ut.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #include "function_ref.h"
  2. #include <library/cpp/testing/unittest/registar.h>
  3. Y_UNIT_TEST_SUITE(TestFunctionRef) {
  4. template <typename Signature>
  5. struct TTestFunction;
  6. template <typename Ret, typename... Args, bool IsNoexcept>
  7. struct TTestFunction<Ret(Args...) noexcept(IsNoexcept)> {
  8. Ret operator()(Args...) const noexcept(IsNoexcept) {
  9. return {};
  10. }
  11. };
  12. Y_UNIT_TEST(NonDefaultConstructible) {
  13. static_assert(!std::is_default_constructible_v<TFunctionRef<void()>>);
  14. static_assert(!std::is_default_constructible_v<TFunctionRef<void() noexcept>>);
  15. static_assert(!std::is_default_constructible_v<TFunctionRef<int(double, void********* megaptr, TTestFunction<void(int)>)>>);
  16. }
  17. int F1(bool x) {
  18. if (x) {
  19. throw 19;
  20. }
  21. return 42;
  22. }
  23. int F2(bool x) noexcept {
  24. return 42 + x;
  25. }
  26. static const TTestFunction<int(bool)> C1;
  27. static const TTestFunction<int(bool) noexcept> C2;
  28. Y_UNIT_TEST(Noexcept) {
  29. static_assert(std::is_constructible_v<TFunctionRef<int(bool)>, decltype(F1)>);
  30. static_assert(std::is_constructible_v<TFunctionRef<int(bool)>, decltype(F2)>);
  31. static_assert(!std::is_constructible_v<TFunctionRef<int(bool) noexcept>, decltype(F1)>);
  32. static_assert(std::is_constructible_v<TFunctionRef<int(bool) noexcept>, decltype(F2)>);
  33. static_assert(std::is_constructible_v<TFunctionRef<int(bool)>, decltype(C1)>);
  34. static_assert(std::is_constructible_v<TFunctionRef<int(bool)>, decltype(C2)>);
  35. static_assert(!std::is_constructible_v<TFunctionRef<int(bool) noexcept>, decltype(C1)>);
  36. static_assert(std::is_constructible_v<TFunctionRef<int(bool) noexcept>, decltype(C2)>);
  37. }
  38. Y_UNIT_TEST(Deduction) {
  39. TFunctionRef ref1(F1);
  40. TFunctionRef ref2(F2);
  41. TFunctionRef ref3(C1);
  42. TFunctionRef ref4(C2);
  43. static_assert(!std::is_nothrow_invocable_r_v<int, decltype(ref1), bool>);
  44. static_assert(std::is_nothrow_invocable_r_v<int, decltype(ref2), bool>);
  45. static_assert(std::is_same_v<decltype(ref1)::TSignature, int(bool)>);
  46. static_assert(std::is_same_v<decltype(ref2)::TSignature, int(bool) noexcept>);
  47. }
  48. void WithCallback(TFunctionRef<double(double, int) noexcept>);
  49. void Iterate(int from, int to, TFunctionRef<void(int)> callback) {
  50. while (from < to) {
  51. callback(from++);
  52. }
  53. }
  54. void IterateNoexcept(int from, int to, TFunctionRef<void(int) noexcept> callback) {
  55. while (from < to) {
  56. callback(from++);
  57. }
  58. }
  59. Y_UNIT_TEST(AsArgument) {
  60. int sum = 0;
  61. Iterate(0, 10, [&](int x) { sum += x; });
  62. UNIT_ASSERT_EQUAL(sum, 45);
  63. Iterate(0, 10, [&](int x) noexcept { sum += x; });
  64. UNIT_ASSERT_EQUAL(sum, 90);
  65. IterateNoexcept(0, 10, [&](int x) noexcept { sum += x; });
  66. UNIT_ASSERT_EQUAL(sum, 135);
  67. auto summer = [&](int x) { sum += x; };
  68. Iterate(0, 10, summer);
  69. Iterate(0, 10, summer);
  70. Iterate(0, 10, summer);
  71. UNIT_ASSERT_EQUAL(sum, 270);
  72. TFunctionRef ref = summer;
  73. Iterate(0, 10, ref);
  74. UNIT_ASSERT_EQUAL(sum, 315);
  75. }
  76. int GlobalSum = 0;
  77. void AddToGlobalSum(int x) {
  78. GlobalSum += x;
  79. }
  80. Y_UNIT_TEST(FunctionPointer) {
  81. GlobalSum = 0;
  82. Iterate(0, 10, AddToGlobalSum);
  83. UNIT_ASSERT_EQUAL(GlobalSum, 45);
  84. TFunctionRef ref1 = AddToGlobalSum;
  85. Iterate(0, 10, ref1);
  86. UNIT_ASSERT_EQUAL(GlobalSum, 90);
  87. TFunctionRef ref2{AddToGlobalSum};
  88. Iterate(0, 10, ref2);
  89. UNIT_ASSERT_EQUAL(GlobalSum, 135);
  90. }
  91. Y_UNIT_TEST(Reassign) {
  92. TFunctionRef kek = [](double) { return 42; };
  93. kek = [](double) { return 19; };
  94. kek = [](int) { return 22.8; };
  95. }
  96. const char* Greet() {
  97. return "Hello, world!";
  98. }
  99. Y_UNIT_TEST(ImplicitCasts) {
  100. TFunctionRef<void(int)> ref = [](int x) { return x; };
  101. ref = [](double x) { return x; };
  102. ref = [](char x) { return x; };
  103. TFunctionRef<int()> ref1 = [] { return 0.5; };
  104. ref1 = [] { return 'a'; };
  105. ref1 = [] { return 124u; };
  106. TFunctionRef<TStringBuf()> ref2{Greet};
  107. }
  108. Y_UNIT_TEST(StatelessLambdaLifetime) {
  109. TFunctionRef<int(int, int)> ref{[](int a, int b) { return a + b; }};
  110. UNIT_ASSERT_EQUAL(ref(5, 5), 10);
  111. }
  112. Y_UNIT_TEST(ForwardArguments) {
  113. char x = 'x';
  114. TFunctionRef<void(std::unique_ptr<int>, char&)> ref = [](std::unique_ptr<int> ptr, char& ch) {
  115. UNIT_ASSERT_EQUAL(*ptr, 5);
  116. ch = 'a';
  117. };
  118. ref(std::make_unique<int>(5), x);
  119. UNIT_ASSERT_EQUAL(x, 'a');
  120. }
  121. } // Y_UNIT_TEST_SUITE(TestFunctionRef)