| Index: base/android/activity_status_unittest.cc
|
| diff --git a/base/android/activity_status_unittest.cc b/base/android/activity_status_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8b685b4295a69c7e17d1d7d6e9e6c6a409b55bc0
|
| --- /dev/null
|
| +++ b/base/android/activity_status_unittest.cc
|
| @@ -0,0 +1,175 @@
|
| +// Copyright 2013 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/android/activity_status.h"
|
| +#include "base/android/jni_android.h"
|
| +#include "base/bind.h"
|
| +#include "base/callback_forward.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/message_loop/message_loop_proxy.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/synchronization/waitable_event.h"
|
| +#include "base/threading/thread.h"
|
| +
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace base {
|
| +namespace android {
|
| +
|
| +namespace {
|
| +
|
| +using base::android::ScopedJavaLocalRef;
|
| +
|
| +// Call org.chromium.base.ActivityStatus.onStateChange() from C++.
|
| +// |env| is the current JNI environment pointer.
|
| +// |activity| is a JNI reference to an activity object. Can be NULL
|
| +// during unit-testing.
|
| +// |newState| is the new state, as an integer.
|
| +//
|
| +// The code below is equivalent to what the JNI generator would output if
|
| +// ActivityStatus.onStateChange() was tagged with @CalledByNative.
|
| +// because this is only useful for unit-testing, there is no point in
|
| +// making this permanent for production code.
|
| +void Java_ActivityStatus_onStateChange(JNIEnv* env,
|
| + jobject activity,
|
| + jint newState) {
|
| + static const char kActivityStatusClassPath[] =
|
| + "org/chromium/base/ActivityStatus";
|
| + static jclass g_ActivityStatus_clazz = NULL;
|
| + static base::subtle::AtomicWord g_ActivityStatus_onStateChange = 0;
|
| +
|
| + // Ensure g_ActivityStatus_clazz is initialized
|
| + if (g_ActivityStatus_clazz == NULL) {
|
| + g_ActivityStatus_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
|
| + base::android::GetClass(env, kActivityStatusClassPath).obj()));
|
| + DCHECK(g_ActivityStatus_clazz);
|
| + }
|
| + jmethodID method_id =
|
| + base::android::MethodID::LazyGet<base::android::MethodID::TYPE_STATIC>(
|
| + env,
|
| + g_ActivityStatus_clazz,
|
| + "onStateChange",
|
| + "("
|
| + "Landroid/app/Activity;"
|
| + "I"
|
| + ")"
|
| + "V",
|
| + &g_ActivityStatus_onStateChange);
|
| +
|
| + env->CallStaticVoidMethod(
|
| + g_ActivityStatus_clazz, method_id, activity, newState);
|
| + base::android::CheckException(env);
|
| +}
|
| +
|
| +// Change the activity state, return true on success, false otherwise.
|
| +bool ForceActivityStateTo(ActivityState state) {
|
| + JNIEnv* env = base::android::AttachCurrentThread();
|
| + if (!env)
|
| + return false;
|
| +
|
| + RunLoop run_loop;
|
| + Java_ActivityStatus_onStateChange(env, NULL, static_cast<int>(state));
|
| + run_loop.RunUntilIdle();
|
| + return true;
|
| +}
|
| +
|
| +// Used to generate a callback that stores the new state at a given
|
| +// location.
|
| +void StoreStateTo(ActivityState* target, ActivityState state) {
|
| + *target = state;
|
| +}
|
| +
|
| +// An invalid ActivityState value.
|
| +const ActivityState kInvalidActivityState = static_cast<ActivityState>(100);
|
| +
|
| +// Shared state for the multi-threaded test.
|
| +// This uses a thread to register for events and listen to them,
|
| +// while state changes are forced on the main thread.
|
| +class MultiThreadedTest {
|
| + public:
|
| + MultiThreadedTest()
|
| + : state_(kInvalidActivityState),
|
| + event_(false, false),
|
| + thread_("ActivityStatusTest thread"),
|
| + main_(),
|
| + listener_(NULL) {}
|
| +
|
| + void Run() {
|
| + // Start the thread and tell it to register for events.
|
| + thread_.Start();
|
| + thread_.message_loop()
|
| + ->PostTask(FROM_HERE,
|
| + base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
|
| + base::Unretained(this)));
|
| +
|
| + // Wait for its completion.
|
| + event_.Wait();
|
| +
|
| + // Change state, then wait for the thread to modify state.
|
| + EXPECT_TRUE(ForceActivityStateTo(ACTIVITY_STATE_CREATED));
|
| + event_.Wait();
|
| + EXPECT_EQ(ACTIVITY_STATE_CREATED, state_);
|
| +
|
| + // Again
|
| + EXPECT_TRUE(ForceActivityStateTo(ACTIVITY_STATE_DESTROYED));
|
| + event_.Wait();
|
| + EXPECT_EQ(ACTIVITY_STATE_DESTROYED, state_);
|
| + }
|
| +
|
| + private:
|
| + void ExpectOnThread() {
|
| + EXPECT_EQ(thread_.message_loop(), base::MessageLoop::current());
|
| + }
|
| +
|
| + void RegisterThreadForEvents() {
|
| + ExpectOnThread();
|
| + listener_.reset(new ActivityStatus::Listener(base::Bind(
|
| + &MultiThreadedTest::StoreStateAndSignal, base::Unretained(this))));
|
| + EXPECT_TRUE(listener_.get());
|
| + event_.Signal();
|
| + }
|
| +
|
| + void StoreStateAndSignal(ActivityState state) {
|
| + ExpectOnThread();
|
| + state_ = state;
|
| + event_.Signal();
|
| + }
|
| +
|
| + ActivityState state_;
|
| + base::WaitableEvent event_;
|
| + base::Thread thread_;
|
| + base::MessageLoop main_;
|
| + scoped_ptr<ActivityStatus::Listener> listener_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +TEST(ActivityStatusTest, SingleThread) {
|
| + MessageLoop message_loop;
|
| +
|
| + ActivityState result = kInvalidActivityState;
|
| +
|
| + // Create a new listener that stores the new state into |result|
|
| + // on every state change.
|
| + scoped_ptr<ActivityStatus::Listener> listener(new ActivityStatus::Listener(
|
| + base::Bind(&StoreStateTo, base::Unretained(&result))));
|
| + ASSERT_TRUE(listener.get());
|
| +
|
| + EXPECT_EQ(kInvalidActivityState, result);
|
| +
|
| + ASSERT_TRUE(ForceActivityStateTo(ACTIVITY_STATE_CREATED));
|
| + EXPECT_EQ(ACTIVITY_STATE_CREATED, result);
|
| +
|
| + ASSERT_TRUE(ForceActivityStateTo(ACTIVITY_STATE_DESTROYED));
|
| + EXPECT_EQ(ACTIVITY_STATE_DESTROYED, result);
|
| +}
|
| +
|
| +TEST(ActivityStatusTest, TwoThreads) {
|
| + MultiThreadedTest test;
|
| + test.Run();
|
| +}
|
| +
|
| +} // namespace android
|
| +} // namespace base
|
|
|