1 // Copyright 2012 The Chromium Authors. All rights reserved.
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 "base/message_loop/message_pump_io_ios.h"
6 
7 #include <unistd.h>
8 
9 #include "base/logging.h"
10 #include "base/macros.h"
11 #include "base/message_loop/message_pump_for_io.h"
12 #include "base/posix/eintr_wrapper.h"
13 #include "base/test/gtest_util.h"
14 #include "base/threading/thread.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace base {
18 
19 class MessagePumpIOSForIOTest : public testing::Test {
20  protected:
21   MessagePumpIOSForIOTest() = default;
22   ~MessagePumpIOSForIOTest() override = default;
23 
SetUp()24   void SetUp() override {
25     int ret = pipe(pipefds_);
26     ASSERT_EQ(0, ret);
27     ret = pipe(alternate_pipefds_);
28     ASSERT_EQ(0, ret);
29   }
30 
TearDown()31   void TearDown() override {
32     if (IGNORE_EINTR(close(pipefds_[0])) < 0)
33       PLOG(ERROR) << "close";
34     if (IGNORE_EINTR(close(pipefds_[1])) < 0)
35       PLOG(ERROR) << "close";
36   }
37 
HandleFdIOEvent(MessagePumpForIO::FdWatchController * watcher)38   void HandleFdIOEvent(MessagePumpForIO::FdWatchController* watcher) {
39     MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_.get(),
40         kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack,
41         watcher);
42   }
43 
44   int pipefds_[2];
45   int alternate_pipefds_[2];
46 
47  private:
48   DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIOTest);
49 };
50 
51 namespace {
52 
53 // Concrete implementation of MessagePumpIOSForIO::FdWatcher that does
54 // nothing useful.
55 class StupidWatcher : public MessagePumpIOSForIO::FdWatcher {
56  public:
~StupidWatcher()57   ~StupidWatcher() override {}
58 
59   // base:MessagePumpIOSForIO::FdWatcher interface
OnFileCanReadWithoutBlocking(int fd)60   void OnFileCanReadWithoutBlocking(int fd) override {}
OnFileCanWriteWithoutBlocking(int fd)61   void OnFileCanWriteWithoutBlocking(int fd) override {}
62 };
63 
64 class BaseWatcher : public MessagePumpIOSForIO::FdWatcher {
65  public:
BaseWatcher(MessagePumpIOSForIO::FdWatchController * controller)66   BaseWatcher(MessagePumpIOSForIO::FdWatchController* controller)
67       : controller_(controller) {
68     DCHECK(controller_);
69   }
~BaseWatcher()70   ~BaseWatcher() override {}
71 
72   // MessagePumpIOSForIO::FdWatcher interface
OnFileCanReadWithoutBlocking(int)73   void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); }
74 
OnFileCanWriteWithoutBlocking(int)75   void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); }
76 
77  protected:
78   MessagePumpIOSForIO::FdWatchController* controller_;
79 };
80 
81 class DeleteWatcher : public BaseWatcher {
82  public:
DeleteWatcher(MessagePumpIOSForIO::FdWatchController * controller)83   explicit DeleteWatcher(MessagePumpIOSForIO::FdWatchController* controller)
84       : BaseWatcher(controller) {}
85 
~DeleteWatcher()86   ~DeleteWatcher() override { DCHECK(!controller_); }
87 
OnFileCanWriteWithoutBlocking(int)88   void OnFileCanWriteWithoutBlocking(int /* fd */) override {
89     DCHECK(controller_);
90     delete controller_;
91     controller_ = NULL;
92   }
93 };
94 
TEST_F(MessagePumpIOSForIOTest,DeleteWatcher)95 TEST_F(MessagePumpIOSForIOTest, DeleteWatcher) {
96   std::unique_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
97   MessagePumpIOSForIO::FdWatchController* watcher =
98       new MessagePumpIOSForIO::FdWatchController(FROM_HERE);
99   DeleteWatcher delegate(watcher);
100   pump->WatchFileDescriptor(pipefds_[1],
101       false, MessagePumpIOSForIO::WATCH_READ_WRITE, watcher, &delegate);
102 
103   // Spoof a callback.
104   HandleFdIOEvent(watcher);
105 }
106 
107 class StopWatcher : public BaseWatcher {
108  public:
StopWatcher(MessagePumpIOSForIO::FdWatchController * controller,MessagePumpIOSForIO * pump,int fd_to_start_watching=-1)109   StopWatcher(MessagePumpIOSForIO::FdWatchController* controller,
110               MessagePumpIOSForIO* pump,
111               int fd_to_start_watching = -1)
112       : BaseWatcher(controller),
113         pump_(pump),
114         fd_to_start_watching_(fd_to_start_watching) {}
115 
~StopWatcher()116   ~StopWatcher() override {}
117 
OnFileCanWriteWithoutBlocking(int)118   void OnFileCanWriteWithoutBlocking(int /* fd */) override {
119     controller_->StopWatchingFileDescriptor();
120     if (fd_to_start_watching_ >= 0) {
121       pump_->WatchFileDescriptor(fd_to_start_watching_,
122           false, MessagePumpIOSForIO::WATCH_READ_WRITE, controller_, this);
123     }
124   }
125 
126  private:
127   MessagePumpIOSForIO* pump_;
128   int fd_to_start_watching_;
129 };
130 
TEST_F(MessagePumpIOSForIOTest,StopWatcher)131 TEST_F(MessagePumpIOSForIOTest, StopWatcher) {
132   std::unique_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
133   MessagePumpIOSForIO::FdWatchController watcher(FROM_HERE);
134   StopWatcher delegate(&watcher, pump.get());
135   pump->WatchFileDescriptor(pipefds_[1],
136       false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate);
137 
138   // Spoof a callback.
139   HandleFdIOEvent(&watcher);
140 }
141 
TEST_F(MessagePumpIOSForIOTest,StopWatcherAndWatchSomethingElse)142 TEST_F(MessagePumpIOSForIOTest, StopWatcherAndWatchSomethingElse) {
143   std::unique_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
144   MessagePumpIOSForIO::FdWatchController watcher(FROM_HERE);
145   StopWatcher delegate(&watcher, pump.get(), alternate_pipefds_[1]);
146   pump->WatchFileDescriptor(pipefds_[1],
147       false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate);
148 
149   // Spoof a callback.
150   HandleFdIOEvent(&watcher);
151 }
152 
153 }  // namespace
154 
155 }  // namespace base
156