1// Copyright 2014 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/android/application_status_listener.h"
6#include "base/bind.h"
7#include "base/callback_forward.h"
8#include "base/logging.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/message_loop/message_loop_proxy.h"
11#include "base/run_loop.h"
12#include "base/synchronization/waitable_event.h"
13#include "base/threading/thread.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace base {
17namespace android {
18
19namespace {
20
21using base::android::ScopedJavaLocalRef;
22
23// An invalid ApplicationState value.
24const ApplicationState kInvalidApplicationState =
25    static_cast<ApplicationState>(100);
26
27// Used to generate a callback that stores the new state at a given location.
28void StoreStateTo(ApplicationState* target, ApplicationState state) {
29  *target = state;
30}
31
32void RunTasksUntilIdle() {
33  RunLoop run_loop;
34  run_loop.RunUntilIdle();
35}
36
37// Shared state for the multi-threaded test.
38// This uses a thread to register for events and listen to them, while state
39// changes are forced on the main thread.
40class MultiThreadedTest {
41 public:
42  MultiThreadedTest()
43      : state_(kInvalidApplicationState),
44        event_(false, false),
45        thread_("ApplicationStatusTest thread"),
46        main_() {
47  }
48
49  void Run() {
50    // Start the thread and tell it to register for events.
51    thread_.Start();
52    thread_.message_loop()
53        ->PostTask(FROM_HERE,
54                   base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
55                              base::Unretained(this)));
56
57    // Wait for its completion.
58    event_.Wait();
59
60    // Change state, then wait for the thread to modify state.
61    ApplicationStatusListener::NotifyApplicationStateChange(
62        APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
63    event_.Wait();
64    EXPECT_EQ(APPLICATION_STATE_HAS_RUNNING_ACTIVITIES, state_);
65
66    // Again
67    ApplicationStatusListener::NotifyApplicationStateChange(
68        APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES);
69    event_.Wait();
70    EXPECT_EQ(APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES, state_);
71  }
72
73 private:
74  void ExpectOnThread() {
75    EXPECT_EQ(thread_.message_loop(), base::MessageLoop::current());
76  }
77
78  void RegisterThreadForEvents() {
79    ExpectOnThread();
80    listener_.reset(new ApplicationStatusListener(base::Bind(
81        &MultiThreadedTest::StoreStateAndSignal, base::Unretained(this))));
82    EXPECT_TRUE(listener_.get());
83    event_.Signal();
84  }
85
86  void StoreStateAndSignal(ApplicationState state) {
87    ExpectOnThread();
88    state_ = state;
89    event_.Signal();
90  }
91
92  ApplicationState state_;
93  base::WaitableEvent event_;
94  base::Thread thread_;
95  base::MessageLoop main_;
96  scoped_ptr<ApplicationStatusListener> listener_;
97};
98
99}  // namespace
100
101TEST(ApplicationStatusListenerTest, SingleThread) {
102  MessageLoop message_loop;
103
104  ApplicationState result = kInvalidApplicationState;
105
106  // Create a new listener that stores the new state into |result| on every
107  // state change.
108  ApplicationStatusListener listener(
109      base::Bind(&StoreStateTo, base::Unretained(&result)));
110
111  EXPECT_EQ(kInvalidApplicationState, result);
112
113  ApplicationStatusListener::NotifyApplicationStateChange(
114      APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
115  RunTasksUntilIdle();
116  EXPECT_EQ(APPLICATION_STATE_HAS_RUNNING_ACTIVITIES, result);
117
118  ApplicationStatusListener::NotifyApplicationStateChange(
119      APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES);
120  RunTasksUntilIdle();
121  EXPECT_EQ(APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES, result);
122}
123
124TEST(ApplicationStatusListenerTest, TwoThreads) {
125  MultiThreadedTest test;
126  test.Run();
127}
128
129}  // namespace android
130}  // namespace base
131