1// Copyright 2012 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <string> 6 7#include "base/functional/bind.h" 8#include "base/functional/callback.h" 9#include "base/functional/callback_helpers.h" 10#include "build/build_config.h" 11#include "testing/gtest/include/gtest/gtest.h" 12#include "testing/gtest_mac.h" 13 14namespace { 15 16TEST(BindObjcBlockTest, TestScopedClosureRunnerExitScope) { 17 int run_count = 0; 18 int* ptr = &run_count; 19 { 20 base::ScopedClosureRunner runner(base::BindOnce(base::RetainBlock(^{ 21 (*ptr)++; 22 }))); 23 EXPECT_EQ(0, run_count); 24 } 25 EXPECT_EQ(1, run_count); 26} 27 28TEST(BindObjcBlockTest, TestScopedClosureRunnerRelease) { 29 int run_count = 0; 30 int* ptr = &run_count; 31 base::OnceClosure c; 32 { 33 base::ScopedClosureRunner runner(base::BindOnce(base::RetainBlock(^{ 34 (*ptr)++; 35 }))); 36 c = runner.Release(); 37 EXPECT_EQ(0, run_count); 38 } 39 EXPECT_EQ(0, run_count); 40 std::move(c).Run(); 41 EXPECT_EQ(1, run_count); 42} 43 44TEST(BindObjcBlockTest, TestReturnValue) { 45 const int kReturnValue = 42; 46 base::OnceCallback<int(void)> c = base::BindOnce(base::RetainBlock(^{ 47 return kReturnValue; 48 })); 49 EXPECT_EQ(kReturnValue, std::move(c).Run()); 50} 51 52TEST(BindObjcBlockTest, TestArgument) { 53 const int kArgument = 42; 54 base::OnceCallback<int(int)> c = base::BindOnce(base::RetainBlock(^(int a) { 55 return a + 1; 56 })); 57 EXPECT_EQ(kArgument + 1, std::move(c).Run(kArgument)); 58} 59 60TEST(BindObjcBlockTest, TestTwoArguments) { 61 std::string result; 62 std::string* ptr = &result; 63 base::OnceCallback<void(const std::string&, const std::string&)> c = 64 base::BindOnce( 65 base::RetainBlock(^(const std::string& a, const std::string& b) { 66 *ptr = a + b; 67 })); 68 std::move(c).Run("forty", "two"); 69 EXPECT_EQ(result, "fortytwo"); 70} 71 72TEST(BindObjcBlockTest, TestThreeArguments) { 73 std::string result; 74 std::string* ptr = &result; 75 base::OnceCallback<void(const std::string&, const std::string&, 76 const std::string&)> 77 callback = base::BindOnce(base::RetainBlock( 78 ^(const std::string& a, const std::string& b, const std::string& c) { 79 *ptr = a + b + c; 80 })); 81 std::move(callback).Run("six", "times", "nine"); 82 EXPECT_EQ(result, "sixtimesnine"); 83} 84 85TEST(BindObjcBlockTest, TestSixArguments) { 86 std::string result1; 87 std::string* ptr = &result1; 88 int result2; 89 int* ptr2 = &result2; 90 base::OnceCallback<void(int, int, const std::string&, const std::string&, int, 91 const std::string&)> 92 callback = base::BindOnce(base::RetainBlock( 93 ^(int a, int b, const std::string& c, const std::string& d, int e, 94 const std::string& f) { 95 *ptr = c + d + f; 96 *ptr2 = a + b + e; 97 })); 98 std::move(callback).Run(1, 2, "infinite", "improbability", 3, "drive"); 99 EXPECT_EQ(result1, "infiniteimprobabilitydrive"); 100 EXPECT_EQ(result2, 6); 101} 102 103TEST(BindObjcBlockTest, TestBlockMoveable) { 104 base::OnceClosure c; 105 __block BOOL invoked_block = NO; 106 @autoreleasepool { 107 c = base::BindOnce(base::RetainBlock(^(std::unique_ptr<BOOL> v) { 108 invoked_block = *v; 109 }), 110 std::make_unique<BOOL>(YES)); 111 }; 112 std::move(c).Run(); 113 EXPECT_TRUE(invoked_block); 114} 115 116// Tests that the bound block is retained until the end of its execution, 117// even if the callback itself is destroyed during the invocation. It was 118// found that some code depends on this behaviour (see crbug.com/845687). 119TEST(BindObjcBlockTest, TestBlockDeallocation) { 120 base::RepeatingClosure closure; 121 __block BOOL invoked_block = NO; 122 closure = base::BindRepeating( 123 base::RetainBlock(^(base::RepeatingClosure* this_closure) { 124 *this_closure = base::RepeatingClosure(); 125 invoked_block = YES; 126 }), 127 &closure); 128 closure.Run(); 129 EXPECT_TRUE(invoked_block); 130} 131 132} // namespace 133