| // 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/task_scheduler/lazy_task_runner.h" | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/bind_helpers.h" | 
 | #include "base/sequence_checker_impl.h" | 
 | #include "base/task_scheduler/scoped_set_task_priority_for_current_thread.h" | 
 | #include "base/test/scoped_task_environment.h" | 
 | #include "base/threading/thread_checker_impl.h" | 
 | #include "build/build_config.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | #if defined(OS_WIN) | 
 | #include "base/win/com_init_util.h" | 
 | #endif | 
 |  | 
 | namespace base { | 
 |  | 
 | namespace { | 
 |  | 
 | LazySequencedTaskRunner g_sequenced_task_runner_user_visible = | 
 |     LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({TaskPriority::USER_VISIBLE}); | 
 | LazySequencedTaskRunner g_sequenced_task_runner_user_blocking = | 
 |     LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({TaskPriority::USER_BLOCKING}); | 
 |  | 
 | LazySingleThreadTaskRunner g_single_thread_task_runner_user_visible = | 
 |     LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER( | 
 |         {TaskPriority::USER_VISIBLE}, | 
 |         SingleThreadTaskRunnerThreadMode::SHARED); | 
 | LazySingleThreadTaskRunner g_single_thread_task_runner_user_blocking = | 
 |     LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER( | 
 |         {TaskPriority::USER_BLOCKING}, | 
 |         SingleThreadTaskRunnerThreadMode::SHARED); | 
 |  | 
 | #if defined(OS_WIN) | 
 | LazyCOMSTATaskRunner g_com_sta_task_runner_user_visible = | 
 |     LAZY_COM_STA_TASK_RUNNER_INITIALIZER( | 
 |         {TaskPriority::USER_VISIBLE}, | 
 |         SingleThreadTaskRunnerThreadMode::SHARED); | 
 | LazyCOMSTATaskRunner g_com_sta_task_runner_user_blocking = | 
 |     LAZY_COM_STA_TASK_RUNNER_INITIALIZER( | 
 |         {TaskPriority::USER_BLOCKING}, | 
 |         SingleThreadTaskRunnerThreadMode::SHARED); | 
 | #endif  // defined(OS_WIN) | 
 |  | 
 | void InitCheckers(SequenceCheckerImpl* sequence_checker, | 
 |                   ThreadCheckerImpl* thread_checker) { | 
 |   sequence_checker->DetachFromSequence(); | 
 |   EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); | 
 |   thread_checker->DetachFromThread(); | 
 |   EXPECT_TRUE(thread_checker->CalledOnValidThread()); | 
 | } | 
 |  | 
 | void ExpectSequencedEnvironment(SequenceCheckerImpl* sequence_checker, | 
 |                                 ThreadCheckerImpl* thread_checker, | 
 |                                 TaskPriority expected_priority) { | 
 |   EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); | 
 |   EXPECT_FALSE(thread_checker->CalledOnValidThread()); | 
 |   EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread()); | 
 | } | 
 |  | 
 | void ExpectSingleThreadEnvironment(SequenceCheckerImpl* sequence_checker, | 
 |                                    ThreadCheckerImpl* thread_checker, | 
 |                                    TaskPriority expected_priority | 
 | #if defined(OS_WIN) | 
 |                                    , | 
 |                                    bool expect_com_sta = false | 
 | #endif | 
 |                                    ) { | 
 |   EXPECT_TRUE(sequence_checker->CalledOnValidSequence()); | 
 |   EXPECT_TRUE(thread_checker->CalledOnValidThread()); | 
 |   EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread()); | 
 |  | 
 | #if defined(OS_WIN) | 
 |   if (expect_com_sta) | 
 |     win::AssertComApartmentType(win::ComApartmentType::STA); | 
 | #endif | 
 | } | 
 |  | 
 | class TaskSchedulerLazyTaskRunnerEnvironmentTest : public testing::Test { | 
 |  protected: | 
 |   TaskSchedulerLazyTaskRunnerEnvironmentTest() = default; | 
 |  | 
 |   void TestTaskRunnerEnvironment(scoped_refptr<SequencedTaskRunner> task_runner, | 
 |                                  bool expect_single_thread, | 
 |                                  TaskPriority expected_priority | 
 | #if defined(OS_WIN) | 
 |                                  , | 
 |                                  bool expect_com_sta = false | 
 | #endif | 
 |                                  ) { | 
 |     SequenceCheckerImpl sequence_checker; | 
 |     ThreadCheckerImpl thread_checker; | 
 |     task_runner->PostTask(FROM_HERE, | 
 |                           BindOnce(&InitCheckers, Unretained(&sequence_checker), | 
 |                                    Unretained(&thread_checker))); | 
 |     scoped_task_environment_.RunUntilIdle(); | 
 |  | 
 |     OnceClosure task = | 
 |         expect_single_thread | 
 |             ? BindOnce(&ExpectSingleThreadEnvironment, | 
 |                        Unretained(&sequence_checker), | 
 |                        Unretained(&thread_checker), expected_priority | 
 | #if defined(OS_WIN) | 
 |                        , | 
 |                        expect_com_sta | 
 | #endif | 
 |                        ) | 
 |             : BindOnce(&ExpectSequencedEnvironment, | 
 |                        Unretained(&sequence_checker), | 
 |                        Unretained(&thread_checker), expected_priority); | 
 |     task_runner->PostTask(FROM_HERE, std::move(task)); | 
 |     scoped_task_environment_.RunUntilIdle(); | 
 |   } | 
 |  | 
 |   test::ScopedTaskEnvironment scoped_task_environment_; | 
 |  | 
 |  private: | 
 |   DISALLOW_COPY_AND_ASSIGN(TaskSchedulerLazyTaskRunnerEnvironmentTest); | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, | 
 |        LazySequencedTaskRunnerUserVisible) { | 
 |   TestTaskRunnerEnvironment(g_sequenced_task_runner_user_visible.Get(), false, | 
 |                             TaskPriority::USER_VISIBLE); | 
 | } | 
 |  | 
 | TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, | 
 |        LazySequencedTaskRunnerUserBlocking) { | 
 |   TestTaskRunnerEnvironment(g_sequenced_task_runner_user_blocking.Get(), false, | 
 |                             TaskPriority::USER_BLOCKING); | 
 | } | 
 |  | 
 | TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, | 
 |        LazySingleThreadTaskRunnerUserVisible) { | 
 |   TestTaskRunnerEnvironment(g_single_thread_task_runner_user_visible.Get(), | 
 |                             true, TaskPriority::USER_VISIBLE); | 
 | } | 
 |  | 
 | TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, | 
 |        LazySingleThreadTaskRunnerUserBlocking) { | 
 |   TestTaskRunnerEnvironment(g_single_thread_task_runner_user_blocking.Get(), | 
 |                             true, TaskPriority::USER_BLOCKING); | 
 | } | 
 |  | 
 | #if defined(OS_WIN) | 
 | TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, | 
 |        LazyCOMSTATaskRunnerUserVisible) { | 
 |   TestTaskRunnerEnvironment(g_com_sta_task_runner_user_visible.Get(), true, | 
 |                             TaskPriority::USER_VISIBLE, true); | 
 | } | 
 |  | 
 | TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest, | 
 |        LazyCOMSTATaskRunnerUserBlocking) { | 
 |   TestTaskRunnerEnvironment(g_com_sta_task_runner_user_blocking.Get(), true, | 
 |                             TaskPriority::USER_BLOCKING, true); | 
 | } | 
 | #endif  // defined(OS_WIN) | 
 |  | 
 | TEST(TaskSchdulerLazyTaskRunnerTest, LazySequencedTaskRunnerReset) { | 
 |   for (int i = 0; i < 2; ++i) { | 
 |     test::ScopedTaskEnvironment scoped_task_environment; | 
 |     // If the TaskRunner isn't released when the test::ScopedTaskEnvironment | 
 |     // goes out of scope, the second invocation of the line below will access a | 
 |     // deleted TaskScheduler and crash. | 
 |     g_sequenced_task_runner_user_visible.Get()->PostTask(FROM_HERE, | 
 |                                                          DoNothing()); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TaskSchdulerLazyTaskRunnerTest, LazySingleThreadTaskRunnerReset) { | 
 |   for (int i = 0; i < 2; ++i) { | 
 |     test::ScopedTaskEnvironment scoped_task_environment; | 
 |     // If the TaskRunner isn't released when the test::ScopedTaskEnvironment | 
 |     // goes out of scope, the second invocation of the line below will access a | 
 |     // deleted TaskScheduler and crash. | 
 |     g_single_thread_task_runner_user_visible.Get()->PostTask(FROM_HERE, | 
 |                                                              DoNothing()); | 
 |   } | 
 | } | 
 |  | 
 | #if defined(OS_WIN) | 
 | TEST(TaskSchdulerLazyTaskRunnerTest, LazyCOMSTATaskRunnerReset) { | 
 |   for (int i = 0; i < 2; ++i) { | 
 |     test::ScopedTaskEnvironment scoped_task_environment; | 
 |     // If the TaskRunner isn't released when the test::ScopedTaskEnvironment | 
 |     // goes out of scope, the second invocation of the line below will access a | 
 |     // deleted TaskScheduler and crash. | 
 |     g_com_sta_task_runner_user_visible.Get()->PostTask(FROM_HERE, DoNothing()); | 
 |   } | 
 | } | 
 | #endif  // defined(OS_WIN) | 
 |  | 
 | }  // namespace base |