|  | // Copyright 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/message_loop/message_pump_io_ios.h" | 
|  |  | 
|  | #include <unistd.h> | 
|  |  | 
|  | #include "base/macros.h" | 
|  | #include "base/posix/eintr_wrapper.h" | 
|  | #include "base/test/gtest_util.h" | 
|  | #include "base/threading/thread.h" | 
|  | #include "starboard/types.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | class MessagePumpIOSForIOTest : public testing::Test { | 
|  | protected: | 
|  | MessagePumpIOSForIOTest() = default; | 
|  | ~MessagePumpIOSForIOTest() override = default; | 
|  |  | 
|  | void SetUp() override { | 
|  | int ret = pipe(pipefds_); | 
|  | ASSERT_EQ(0, ret); | 
|  | ret = pipe(alternate_pipefds_); | 
|  | ASSERT_EQ(0, ret); | 
|  | } | 
|  |  | 
|  | void TearDown() override { | 
|  | if (IGNORE_EINTR(close(pipefds_[0])) < 0) | 
|  | PLOG(ERROR) << "close"; | 
|  | if (IGNORE_EINTR(close(pipefds_[1])) < 0) | 
|  | PLOG(ERROR) << "close"; | 
|  | } | 
|  |  | 
|  | void HandleFdIOEvent(MessagePumpForIO::FdWatchController* watcher) { | 
|  | MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_.get(), | 
|  | kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack, | 
|  | watcher); | 
|  | } | 
|  |  | 
|  | int pipefds_[2]; | 
|  | int alternate_pipefds_[2]; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIOTest); | 
|  | }; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Concrete implementation of MessagePumpIOSForIO::FdWatcher that does | 
|  | // nothing useful. | 
|  | class StupidWatcher : public MessagePumpIOSForIO::FdWatcher { | 
|  | public: | 
|  | ~StupidWatcher() override {} | 
|  |  | 
|  | // base:MessagePumpIOSForIO::FdWatcher interface | 
|  | void OnFileCanReadWithoutBlocking(int fd) override {} | 
|  | void OnFileCanWriteWithoutBlocking(int fd) override {} | 
|  | }; | 
|  |  | 
|  | class BaseWatcher : public MessagePumpIOSForIO::FdWatcher { | 
|  | public: | 
|  | BaseWatcher(MessagePumpIOSForIO::FdWatchController* controller) | 
|  | : controller_(controller) { | 
|  | DCHECK(controller_); | 
|  | } | 
|  | ~BaseWatcher() override {} | 
|  |  | 
|  | // MessagePumpIOSForIO::FdWatcher interface | 
|  | void OnFileCanReadWithoutBlocking(int fd) override { NOTREACHED(); } | 
|  |  | 
|  | void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } | 
|  |  | 
|  | protected: | 
|  | MessagePumpIOSForIO::FdWatchController* controller_; | 
|  | }; | 
|  |  | 
|  | class DeleteWatcher : public BaseWatcher { | 
|  | public: | 
|  | explicit DeleteWatcher(MessagePumpIOSForIO::FdWatchController* controller) | 
|  | : BaseWatcher(controller) {} | 
|  |  | 
|  | ~DeleteWatcher() override { DCHECK(!controller_); } | 
|  |  | 
|  | void OnFileCanWriteWithoutBlocking(int fd) override { | 
|  | DCHECK(controller_); | 
|  | delete controller_; | 
|  | controller_ = NULL; | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST_F(MessagePumpIOSForIOTest, DeleteWatcher) { | 
|  | std::unique_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); | 
|  | MessagePumpIOSForIO::FdWatchController* watcher = | 
|  | new MessagePumpIOSForIO::FdWatchController(FROM_HERE); | 
|  | DeleteWatcher delegate(watcher); | 
|  | pump->WatchFileDescriptor(pipefds_[1], | 
|  | false, MessagePumpIOSForIO::WATCH_READ_WRITE, watcher, &delegate); | 
|  |  | 
|  | // Spoof a callback. | 
|  | HandleFdIOEvent(watcher); | 
|  | } | 
|  |  | 
|  | class StopWatcher : public BaseWatcher { | 
|  | public: | 
|  | StopWatcher(MessagePumpIOSForIO::FdWatchController* controller, | 
|  | MessagePumpIOSForIO* pump, | 
|  | int fd_to_start_watching = -1) | 
|  | : BaseWatcher(controller), | 
|  | pump_(pump), | 
|  | fd_to_start_watching_(fd_to_start_watching) {} | 
|  |  | 
|  | ~StopWatcher() override {} | 
|  |  | 
|  | void OnFileCanWriteWithoutBlocking(int fd) override { | 
|  | controller_->StopWatchingFileDescriptor(); | 
|  | if (fd_to_start_watching_ >= 0) { | 
|  | pump_->WatchFileDescriptor(fd_to_start_watching_, | 
|  | false, MessagePumpIOSForIO::WATCH_READ_WRITE, controller_, this); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | MessagePumpIOSForIO* pump_; | 
|  | int fd_to_start_watching_; | 
|  | }; | 
|  |  | 
|  | TEST_F(MessagePumpIOSForIOTest, StopWatcher) { | 
|  | std::unique_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); | 
|  | MessagePumpIOSForIO::FdWatchController watcher(FROM_HERE); | 
|  | StopWatcher delegate(&watcher, pump.get()); | 
|  | pump->WatchFileDescriptor(pipefds_[1], | 
|  | false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate); | 
|  |  | 
|  | // Spoof a callback. | 
|  | HandleFdIOEvent(&watcher); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagePumpIOSForIOTest, StopWatcherAndWatchSomethingElse) { | 
|  | std::unique_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); | 
|  | MessagePumpIOSForIO::FdWatchController watcher(FROM_HERE); | 
|  | StopWatcher delegate(&watcher, pump.get(), alternate_pipefds_[1]); | 
|  | pump->WatchFileDescriptor(pipefds_[1], | 
|  | false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate); | 
|  |  | 
|  | // Spoof a callback. | 
|  | HandleFdIOEvent(&watcher); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | }  // namespace base |