blob: f00421d279d6f0423fb8d25f1bec2f416b947403 [file] [log] [blame]
// Copyright 2015 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.
#import "ios/web/public/crw_browsing_data_store.h"
#include "base/ios/ios_util.h"
#include "base/logging.h"
#import "base/mac/scoped_nsobject.h"
#include "base/memory/scoped_ptr.h"
#import "base/test/ios/wait_util.h"
#include "ios/web/public/active_state_manager.h"
#include "ios/web/public/browser_state.h"
#include "ios/web/public/test/test_browser_state.h"
#include "ios/web/public/test/test_web_thread_bundle.h"
#import "ios/web/test/web_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
// An observer to observe the |mode| key changes to a CRWBrowsingDataStore.
// Used for testing purposes.
@interface CRWTestBrowsingDataStoreObserver : NSObject
// The number of times that the mode of the underlying CRWBrowsingDataStore
// changed.
@property(nonatomic, assign) NSUInteger modeChangeCount;
// |browsingDataStore| cannot be null.
- (instancetype)initWithBrowsingDataStore:
(CRWBrowsingDataStore*)browsingDataStore NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
@implementation CRWTestBrowsingDataStoreObserver {
// The underlying CRWBrowsingDataStore.
CRWBrowsingDataStore* _browsingDataStore; // weak
}
@synthesize modeChangeCount = _modeChangeCount;
- (instancetype)initWithBrowsingDataStore:
(CRWBrowsingDataStore*)browsingDataStore {
self = [super init];
if (self) {
DCHECK(browsingDataStore);
[browsingDataStore addObserver:self
forKeyPath:@"mode"
options:0
context:nil];
_browsingDataStore = browsingDataStore;
}
return self;
}
- (instancetype)init {
NOTREACHED();
return nil;
}
- (void)dealloc {
[_browsingDataStore removeObserver:self forKeyPath:@"mode"];
[super dealloc];
}
- (void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object
change:(NSDictionary*)change
context:(void*)context {
DCHECK([keyPath isEqual:@"mode"]);
DCHECK_EQ(_browsingDataStore, object);
++self.modeChangeCount;
}
@end
namespace web {
namespace {
// A test fixture for testing CRWBrowsingDataStore.
class BrowsingDataStoreTest : public WebTest {
protected:
void SetUp() override {
WebTest::SetUp();
ASSERT_TRUE(
BrowserState::GetActiveStateManager(GetBrowserState())->IsActive());
browsing_data_store_.reset(
[[CRWBrowsingDataStore alloc] initWithBrowserState:GetBrowserState()]);
}
// Sets the mode of the |browsing_data_store_| to |ACTIVE| and blocks until
// the mode has actually been changed.
void MakeActive() {
[browsing_data_store_ makeActiveWithCompletionHandler:^(BOOL success) {
DCHECK(success);
}];
base::test::ios::WaitUntilCondition(^bool() {
return [browsing_data_store_ mode] == ACTIVE;
});
}
// Sets the mode of the |browsing_data_store_| to |INACTIVE| and blocks until
// the mode has actually been changed.
void MakeInactive() {
[browsing_data_store_ makeInactiveWithCompletionHandler:^(BOOL success) {
DCHECK(success);
}];
base::test::ios::WaitUntilCondition(^bool() {
return [browsing_data_store_ mode] == INACTIVE;
});
}
// Removes browsing data of |browsingDataTypes| from the underlying
// CRWBrowsingDataStore and waits until the operation finished.
void RemoveDataOfTypes(web::BrowsingDataTypes browsing_data_types) {
__block BOOL block_was_called = NO;
[browsing_data_store_ removeDataOfTypes:browsing_data_types
completionHandler:^{
block_was_called = YES;
}];
base::test::ios::WaitUntilCondition(^bool() {
return block_was_called;
});
}
// The CRWBrowsingDataStore used for testing purposes.
base::scoped_nsobject<CRWBrowsingDataStore> browsing_data_store_;
};
} // namespace
// Tests that a CRWBrowsingDataStore's initial mode is set correctly and that it
// has no pending operations.
TEST_F(BrowsingDataStoreTest, InitialModeAndNoPendingOperations) {
if (!base::ios::IsRunningOnIOS8OrLater()) {
return;
}
EXPECT_EQ(ACTIVE, [browsing_data_store_ mode]);
EXPECT_FALSE([browsing_data_store_ hasPendingOperations]);
}
// Tests that CRWBrowsingDataStore handles several consecutive calls to
// |makeActive| and |makeInactive| correctly.
TEST_F(BrowsingDataStoreTest, MakeActiveAndInactiveOperations) {
if (!base::ios::IsRunningOnIOS8OrLater()) {
return;
}
MakeInactive();
base::scoped_nsobject<CRWTestBrowsingDataStoreObserver> observer(
[[CRWTestBrowsingDataStoreObserver alloc]
initWithBrowsingDataStore:browsing_data_store_]);
EXPECT_EQ(0U, [observer modeChangeCount]);
__block int callbacks_received_count = 0;
void (^unsuccessfullCallback)(BOOL) = ^(BOOL success) {
ASSERT_TRUE([NSThread isMainThread]);
++callbacks_received_count;
BrowsingDataStoreMode mode = [browsing_data_store_ mode];
EXPECT_FALSE(success);
EXPECT_EQ(CHANGING, mode);
};
[browsing_data_store_ makeActiveWithCompletionHandler:^(BOOL success) {
EXPECT_EQ(0, callbacks_received_count);
unsuccessfullCallback(success);
}];
EXPECT_EQ(CHANGING, [browsing_data_store_ mode]);
EXPECT_EQ(1U, [observer modeChangeCount]);
[browsing_data_store_ makeInactiveWithCompletionHandler:^(BOOL success) {
EXPECT_EQ(1, callbacks_received_count);
unsuccessfullCallback(success);
}];
EXPECT_EQ(CHANGING, [browsing_data_store_ mode]);
[browsing_data_store_ makeActiveWithCompletionHandler:^(BOOL success) {
EXPECT_EQ(2, callbacks_received_count);
unsuccessfullCallback(success);
}];
EXPECT_EQ(CHANGING, [browsing_data_store_ mode]);
__block BOOL block_was_called = NO;
[browsing_data_store_ makeInactiveWithCompletionHandler:^(BOOL success) {
ASSERT_TRUE([NSThread isMainThread]);
EXPECT_EQ(3, callbacks_received_count);
BrowsingDataStoreMode mode = [browsing_data_store_ mode];
EXPECT_TRUE(success);
EXPECT_EQ(INACTIVE, mode);
block_was_called = YES;
}];
EXPECT_EQ(CHANGING, [browsing_data_store_ mode]);
base::test::ios::WaitUntilCondition(^bool{
return block_was_called;
});
EXPECT_EQ(INACTIVE, [browsing_data_store_ mode]);
EXPECT_EQ(2U, [observer modeChangeCount]);
}
// Tests that CRWBrowsingDataStore correctly handles |removeDataOfTypes:|.
TEST_F(BrowsingDataStoreTest, RemoveDataOperations) {
if (!base::ios::IsRunningOnIOS8OrLater()) {
return;
}
ASSERT_EQ(ACTIVE, [browsing_data_store_ mode]);
// |removeDataOfTypes| is called when the mode was ACTIVE.
RemoveDataOfTypes(BROWSING_DATA_TYPE_COOKIES);
MakeInactive();
ASSERT_EQ(INACTIVE, [browsing_data_store_ mode]);
// |removeDataOfTypes| is called when the mode was INACTIVE.
RemoveDataOfTypes(BROWSING_DATA_TYPE_COOKIES);
}
// Tests that CRWBrowsingDataStore correctly handles |removeDataOfTypes:| after
// a |makeActive| call.
TEST_F(BrowsingDataStoreTest, RemoveDataOperationAfterMakeActiveCall) {
if (!base::ios::IsRunningOnIOS8OrLater()) {
return;
}
MakeInactive();
ASSERT_EQ(INACTIVE, [browsing_data_store_ mode]);
[browsing_data_store_ makeActiveWithCompletionHandler:nil];
// |removeDataOfTypes| is called immediately after a |makeActive| call.
RemoveDataOfTypes(BROWSING_DATA_TYPE_COOKIES);
EXPECT_EQ(ACTIVE, [browsing_data_store_ mode]);
}
// Tests that CRWBrowsingDataStore correctly handles |removeDataOfTypes:| after
// a |makeActive| call.
TEST_F(BrowsingDataStoreTest, RemoveDataOperationAfterMakeInactiveCall) {
if (!base::ios::IsRunningOnIOS8OrLater()) {
return;
}
ASSERT_EQ(ACTIVE, [browsing_data_store_ mode]);
[browsing_data_store_ makeInactiveWithCompletionHandler:nil];
// |removeDataOfTypes| is called immediately after a |makeInactive| call.
RemoveDataOfTypes(BROWSING_DATA_TYPE_COOKIES);
EXPECT_EQ(INACTIVE, [browsing_data_store_ mode]);
}
} // namespace web