• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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