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 14#if !defined(__has_feature) || !__has_feature(objc_arc) 15#error "This file requires ARC support." 16#endif 17 18namespace { 19 20TEST(BindObjcBlockTestARC, TestScopedClosureRunnerExitScope) { 21 int run_count = 0; 22 int* ptr = &run_count; 23 { 24 base::ScopedClosureRunner runner(base::BindOnce(^{ 25 (*ptr)++; 26 })); 27 EXPECT_EQ(0, run_count); 28 } 29 EXPECT_EQ(1, run_count); 30} 31 32TEST(BindObjcBlockTestARC, TestScopedClosureRunnerRelease) { 33 int run_count = 0; 34 int* ptr = &run_count; 35 base::OnceClosure c; 36 { 37 base::ScopedClosureRunner runner(base::BindOnce(^{ 38 (*ptr)++; 39 })); 40 c = runner.Release(); 41 EXPECT_EQ(0, run_count); 42 } 43 EXPECT_EQ(0, run_count); 44 std::move(c).Run(); 45 EXPECT_EQ(1, run_count); 46} 47 48TEST(BindObjcBlockTestARC, TestReturnValue) { 49 const int kReturnValue = 42; 50 base::OnceCallback<int(void)> c = base::BindOnce(^{ 51 return kReturnValue; 52 }); 53 EXPECT_EQ(kReturnValue, std::move(c).Run()); 54} 55 56TEST(BindObjcBlockTestARC, TestArgument) { 57 const int kArgument = 42; 58 base::OnceCallback<int(int)> c = base::BindOnce(^(int a) { 59 return a + 1; 60 }); 61 EXPECT_EQ(kArgument + 1, std::move(c).Run(kArgument)); 62} 63 64TEST(BindObjcBlockTestARC, TestTwoArguments) { 65 std::string result; 66 std::string* ptr = &result; 67 base::OnceCallback<void(const std::string&, const std::string&)> c = 68 base::BindOnce(^(const std::string& a, const std::string& b) { 69 *ptr = a + b; 70 }); 71 std::move(c).Run("forty", "two"); 72 EXPECT_EQ(result, "fortytwo"); 73} 74 75TEST(BindObjcBlockTestARC, TestThreeArguments) { 76 std::string result; 77 std::string* ptr = &result; 78 base::OnceCallback<void(const std::string&, const std::string&, 79 const std::string&)> 80 cb = base::BindOnce( 81 ^(const std::string& a, const std::string& b, const std::string& c) { 82 *ptr = a + b + c; 83 }); 84 std::move(cb).Run("six", "times", "nine"); 85 EXPECT_EQ(result, "sixtimesnine"); 86} 87 88TEST(BindObjcBlockTestARC, TestSixArguments) { 89 std::string result1; 90 std::string* ptr = &result1; 91 int result2; 92 int* ptr2 = &result2; 93 base::OnceCallback<void(int, int, const std::string&, const std::string&, int, 94 const std::string&)> 95 cb = base::BindOnce(^(int a, int b, const std::string& c, 96 const std::string& d, int e, const std::string& f) { 97 *ptr = c + d + f; 98 *ptr2 = a + b + e; 99 }); 100 std::move(cb).Run(1, 2, "infinite", "improbability", 3, "drive"); 101 EXPECT_EQ(result1, "infiniteimprobabilitydrive"); 102 EXPECT_EQ(result2, 6); 103} 104 105TEST(BindObjcBlockTestARC, TestBlockMoveable) { 106 base::OnceClosure c; 107 __block BOOL invoked_block = NO; 108 @autoreleasepool { 109 c = base::BindOnce( 110 ^(std::unique_ptr<BOOL> v) { 111 invoked_block = *v; 112 }, 113 std::make_unique<BOOL>(YES)); 114 } 115 std::move(c).Run(); 116 EXPECT_TRUE(invoked_block); 117} 118 119// Tests that the bound block is retained until the end of its execution, 120// even if the callback itself is destroyed during the invocation. It was 121// found that some code depends on this behaviour (see crbug.com/845687). 122TEST(BindObjcBlockTestARC, TestBlockDeallocation) { 123 base::RepeatingClosure closure; 124 __block BOOL invoked_block = NO; 125 closure = base::BindRepeating( 126 ^(base::RepeatingClosure* this_closure) { 127 *this_closure = base::RepeatingClosure(); 128 invoked_block = YES; 129 }, 130 &closure); 131 closure.Run(); 132 EXPECT_TRUE(invoked_block); 133} 134 135#if BUILDFLAG(IS_IOS) 136 137TEST(BindObjcBlockTestARC, TestBlockReleased) { 138 __weak NSObject* weak_nsobject; 139 @autoreleasepool { 140 NSObject* nsobject = [[NSObject alloc] init]; 141 weak_nsobject = nsobject; 142 143 auto callback = base::BindOnce(^{ 144 [nsobject description]; 145 }); 146 } 147 EXPECT_NSEQ(nil, weak_nsobject); 148} 149 150#endif 151 152} // namespace 153