|  | // Copyright 2017 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/threading/scoped_blocking_call.h" | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/macros.h" | 
|  | #include "base/test/gtest_util.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class MockBlockingObserver : public internal::BlockingObserver { | 
|  | public: | 
|  | MockBlockingObserver() = default; | 
|  |  | 
|  | MOCK_METHOD1(BlockingStarted, void(BlockingType)); | 
|  | MOCK_METHOD0(BlockingTypeUpgraded, void()); | 
|  | MOCK_METHOD0(BlockingEnded, void()); | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(MockBlockingObserver); | 
|  | }; | 
|  |  | 
|  | class ScopedBlockingCallTest : public testing::Test { | 
|  | protected: | 
|  | ScopedBlockingCallTest() { | 
|  | internal::SetBlockingObserverForCurrentThread(&observer_); | 
|  | } | 
|  |  | 
|  | ~ScopedBlockingCallTest() override { | 
|  | internal::ClearBlockingObserverForTesting(); | 
|  | } | 
|  |  | 
|  | testing::StrictMock<MockBlockingObserver> observer_; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(ScopedBlockingCallTest); | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | TEST_F(ScopedBlockingCallTest, MayBlock) { | 
|  | EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK)); | 
|  | ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK); | 
|  | testing::Mock::VerifyAndClear(&observer_); | 
|  | EXPECT_CALL(observer_, BlockingEnded()); | 
|  | } | 
|  |  | 
|  | TEST_F(ScopedBlockingCallTest, WillBlock) { | 
|  | EXPECT_CALL(observer_, BlockingStarted(BlockingType::WILL_BLOCK)); | 
|  | ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK); | 
|  | testing::Mock::VerifyAndClear(&observer_); | 
|  | EXPECT_CALL(observer_, BlockingEnded()); | 
|  | } | 
|  |  | 
|  | TEST_F(ScopedBlockingCallTest, MayBlockWillBlock) { | 
|  | EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK)); | 
|  | ScopedBlockingCall scoped_blocking_call_a(BlockingType::MAY_BLOCK); | 
|  | testing::Mock::VerifyAndClear(&observer_); | 
|  |  | 
|  | { | 
|  | EXPECT_CALL(observer_, BlockingTypeUpgraded()); | 
|  | ScopedBlockingCall scoped_blocking_call_b(BlockingType::WILL_BLOCK); | 
|  | testing::Mock::VerifyAndClear(&observer_); | 
|  | } | 
|  |  | 
|  | EXPECT_CALL(observer_, BlockingEnded()); | 
|  | } | 
|  |  | 
|  | TEST_F(ScopedBlockingCallTest, WillBlockMayBlock) { | 
|  | EXPECT_CALL(observer_, BlockingStarted(BlockingType::WILL_BLOCK)); | 
|  | ScopedBlockingCall scoped_blocking_call_a(BlockingType::WILL_BLOCK); | 
|  | testing::Mock::VerifyAndClear(&observer_); | 
|  |  | 
|  | { ScopedBlockingCall scoped_blocking_call_b(BlockingType::MAY_BLOCK); } | 
|  |  | 
|  | EXPECT_CALL(observer_, BlockingEnded()); | 
|  | } | 
|  |  | 
|  | TEST_F(ScopedBlockingCallTest, MayBlockMayBlock) { | 
|  | EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK)); | 
|  | ScopedBlockingCall scoped_blocking_call_a(BlockingType::MAY_BLOCK); | 
|  | testing::Mock::VerifyAndClear(&observer_); | 
|  |  | 
|  | { ScopedBlockingCall scoped_blocking_call_b(BlockingType::MAY_BLOCK); } | 
|  |  | 
|  | EXPECT_CALL(observer_, BlockingEnded()); | 
|  | } | 
|  |  | 
|  | TEST_F(ScopedBlockingCallTest, WillBlockWillBlock) { | 
|  | EXPECT_CALL(observer_, BlockingStarted(BlockingType::WILL_BLOCK)); | 
|  | ScopedBlockingCall scoped_blocking_call_a(BlockingType::WILL_BLOCK); | 
|  | testing::Mock::VerifyAndClear(&observer_); | 
|  |  | 
|  | { ScopedBlockingCall scoped_blocking_call_b(BlockingType::WILL_BLOCK); } | 
|  |  | 
|  | EXPECT_CALL(observer_, BlockingEnded()); | 
|  | } | 
|  |  | 
|  | TEST_F(ScopedBlockingCallTest, MayBlockWillBlockTwice) { | 
|  | EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK)); | 
|  | ScopedBlockingCall scoped_blocking_call_a(BlockingType::MAY_BLOCK); | 
|  | testing::Mock::VerifyAndClear(&observer_); | 
|  |  | 
|  | { | 
|  | EXPECT_CALL(observer_, BlockingTypeUpgraded()); | 
|  | ScopedBlockingCall scoped_blocking_call_b(BlockingType::WILL_BLOCK); | 
|  | testing::Mock::VerifyAndClear(&observer_); | 
|  |  | 
|  | { | 
|  | ScopedBlockingCall scoped_blocking_call_c(BlockingType::MAY_BLOCK); | 
|  | ScopedBlockingCall scoped_blocking_call_d(BlockingType::WILL_BLOCK); | 
|  | } | 
|  | } | 
|  |  | 
|  | EXPECT_CALL(observer_, BlockingEnded()); | 
|  | } | 
|  |  | 
|  | TEST(ScopedBlockingCallDestructionOrderTest, InvalidDestructionOrder) { | 
|  | auto scoped_blocking_call_a = | 
|  | std::make_unique<ScopedBlockingCall>(BlockingType::WILL_BLOCK); | 
|  | auto scoped_blocking_call_b = | 
|  | std::make_unique<ScopedBlockingCall>(BlockingType::WILL_BLOCK); | 
|  |  | 
|  | EXPECT_DCHECK_DEATH({ scoped_blocking_call_a.reset(); }); | 
|  | } | 
|  |  | 
|  | }  // namespace base |