[go: nahoru, domu]

blob: eec501de810bf7e07c24ae7bb3f29d49a0d74d06 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/web/public/session/crw_session_storage.h"
#import "base/apple/foundation_util.h"
#import "base/ios/ios_util.h"
#import "base/strings/sys_string_conversions.h"
#import "base/strings/utf_string_conversions.h"
#import "base/test/scoped_feature_list.h"
#import "components/sessions/core/session_id.h"
#import "ios/web/common/features.h"
#import "ios/web/navigation/navigation_item_impl.h"
#import "ios/web/navigation/navigation_item_storage_test_util.h"
#import "ios/web/navigation/serializable_user_data_manager_impl.h"
#import "ios/web/public/navigation/referrer.h"
#import "ios/web/public/session/crw_navigation_item_storage.h"
#import "ios/web/public/session/crw_session_user_data.h"
#import "ios/web/public/session/proto/metadata.pb.h"
#import "ios/web/public/session/proto/proto_util.h"
#import "ios/web/public/session/proto/storage.pb.h"
#import "net/base/mac/url_conversions.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/gtest_support.h"
#import "ui/base/page_transition_types.h"
namespace {
// Checks for equality between the item storages in `items1` and `items2`.
BOOL ItemStorageListsAreEqual(NSArray* items1, NSArray* items2) {
__block BOOL items_are_equal = items1.count == items2.count;
if (!items_are_equal)
return NO;
[items1 enumerateObjectsUsingBlock:^(CRWNavigationItemStorage* item,
NSUInteger idx, BOOL* stop) {
items_are_equal &= web::ItemStoragesAreEqual(item, items2[idx]);
*stop = !items_are_equal;
}];
return items_are_equal;
}
// Checks for equality between `session1` and `session2`.
BOOL SessionStoragesAreEqual(CRWSessionStorage* session1,
CRWSessionStorage* session2) {
// Check the rest of the properties.
NSArray<CRWNavigationItemStorage*>* items1 = session1.itemStorages;
NSArray<CRWNavigationItemStorage*>* items2 = session2.itemStorages;
return ItemStorageListsAreEqual(items1, items2) &&
session1.hasOpener == session2.hasOpener &&
session1.lastCommittedItemIndex == session2.lastCommittedItemIndex &&
session1.userAgentType == session2.userAgentType &&
[session1.userData isEqual:session2.userData] &&
session1.lastActiveTime == session2.lastActiveTime &&
session1.creationTime == session2.creationTime &&
session1.uniqueIdentifier == session2.uniqueIdentifier &&
[session1.stableIdentifier isEqual:session2.stableIdentifier];
}
// Creates a CRWSessionUserData from an NSDictionary.
CRWSessionUserData* SessionUserDataFromDictionary(
NSDictionary<NSString*, id<NSCoding>>* dictionary) {
CRWSessionUserData* data = [[CRWSessionUserData alloc] init];
for (NSString* key in dictionary) {
[data setObject:dictionary[key] forKey:key];
}
return data;
}
} // namespace
class CRWSessionStorageTest : public PlatformTest {
protected:
CRWSessionStorageTest() {
// Set up `session_storage_`.
session_storage_ = [[CRWSessionStorage alloc] init];
session_storage_.hasOpener = YES;
session_storage_.lastCommittedItemIndex = 0;
session_storage_.userAgentType = web::UserAgentType::DESKTOP;
session_storage_.stableIdentifier = [[NSUUID UUID] UUIDString];
session_storage_.uniqueIdentifier = SessionID::NewUnique();
session_storage_.userData =
SessionUserDataFromDictionary(@{@"key" : @"value"});
// Create an item storage.
CRWNavigationItemStorage* item_storage =
[[CRWNavigationItemStorage alloc] init];
item_storage.virtualURL = GURL("http://init.test");
item_storage.referrer =
web::Referrer(GURL("http://referrer.url"), web::ReferrerPolicyDefault);
item_storage.timestamp = base::Time::Now();
item_storage.title = base::SysNSStringToUTF16(@"Title");
item_storage.HTTPRequestHeaders = @{@"HeaderKey" : @"HeaderValue"};
session_storage_.itemStorages = @[ item_storage ];
}
protected:
CRWSessionStorage* session_storage_;
};
namespace {
// Helper function to encode a CRWSessionStorage to NSData.
NSData* EncodeSessionStorage(CRWSessionStorage* session_storage) {
NSKeyedArchiver* archiver =
[[NSKeyedArchiver alloc] initRequiringSecureCoding:NO];
[archiver encodeObject:session_storage forKey:NSKeyedArchiveRootObjectKey];
[archiver finishEncoding];
return [archiver encodedData];
}
// Helper function to decode a CRWSessionStorage from NSData.
CRWSessionStorage* DecodeSessionStorage(NSData* data) {
NSKeyedUnarchiver* unarchiver =
[[NSKeyedUnarchiver alloc] initForReadingFromData:data error:nil];
unarchiver.requiresSecureCoding = NO;
return base::apple::ObjCCast<CRWSessionStorage>(
[unarchiver decodeObjectForKey:NSKeyedArchiveRootObjectKey]);
}
}
// Tests that unarchiving CRWSessionStorage data results in an equivalent
// storage.
TEST_F(CRWSessionStorageTest, EncodeDecode) {
CRWSessionStorage* decoded =
DecodeSessionStorage(EncodeSessionStorage(session_storage_));
EXPECT_TRUE(SessionStoragesAreEqual(session_storage_, decoded));
}
// Tests that conversion to/from proto results in an equivalent storage.
TEST_F(CRWSessionStorageTest, EncodeDecodeToProto) {
web::proto::WebStateStorage storage;
[session_storage_ serializeToProto:storage];
CRWSessionStorage* decoded =
[[CRWSessionStorage alloc] initWithProto:storage];
// The serialization to proto does not maintain the following properties
// - stableIdentifier
// - uniqueIdentifier
// - userData
//
// For stableIdentifier and uniqueIdentifier, the decoding generates new
// random values (since they are not present in the protobuf message but
// CRWSessionStorage getter assert that the values are set). Expect them
// to be different from the original values.
EXPECT_NE(decoded.uniqueIdentifier, session_storage_.uniqueIdentifier);
EXPECT_NSNE(decoded.stableIdentifier, session_storage_.stableIdentifier);
// For userData, the decoded object should have the property set to nil.
EXPECT_FALSE(decoded.userData);
// Copy the properties that are not serialized by the protobuf message
// format from the original object to the decoded value, then use
// SessionStoragesAreEqual() to ensure the other fields are properly
// deserialized.
ASSERT_FALSE(SessionStoragesAreEqual(session_storage_, decoded));
decoded.uniqueIdentifier = session_storage_.uniqueIdentifier;
decoded.stableIdentifier = session_storage_.stableIdentifier;
decoded.userData = session_storage_.userData;
EXPECT_TRUE(SessionStoragesAreEqual(session_storage_, decoded));
}
// Tests that when converting to proto, the metadata information are correct.
TEST_F(CRWSessionStorageTest, MetadataWhenEncodingToProto) {
web::proto::WebStateStorage storage;
[session_storage_ serializeToProto:storage];
// Check that the protobuf message has the expected fields.
EXPECT_TRUE(storage.has_metadata());
const web::proto::WebStateMetadataStorage& metadata = storage.metadata();
EXPECT_EQ(web::TimeFromProto(metadata.creation_time()),
session_storage_.creationTime);
EXPECT_EQ(web::TimeFromProto(metadata.last_active_time()),
session_storage_.lastActiveTime);
EXPECT_GT(metadata.navigation_item_count(), 0);
EXPECT_EQ(static_cast<NSUInteger>(metadata.navigation_item_count()),
session_storage_.itemStorages.count);
// Fetch the last committed item and check the value in the last active page
// are initialized from this item.
ASSERT_GE(session_storage_.lastCommittedItemIndex, 0);
ASSERT_LT(static_cast<NSUInteger>(session_storage_.lastCommittedItemIndex),
session_storage_.itemStorages.count);
CRWNavigationItemStorage* item =
session_storage_.itemStorages[session_storage_.lastCommittedItemIndex];
EXPECT_TRUE(metadata.has_active_page());
const web::proto::PageMetadataStorage& active_page = metadata.active_page();
EXPECT_EQ(item.title, base::UTF8ToUTF16(active_page.page_title()));
EXPECT_EQ(item.virtualURL, GURL(active_page.page_url()));
}
// Tests that unarchiving CRWSessionStorage data results in an equivalent
// storage when the user agent is automatic.
TEST_F(CRWSessionStorageTest, EncodeDecodeAutomatic) {
session_storage_.userAgentType = web::UserAgentType::AUTOMATIC;
CRWSessionStorage* decoded =
DecodeSessionStorage(EncodeSessionStorage(session_storage_));
EXPECT_TRUE(SessionStoragesAreEqual(session_storage_, decoded));
}
// Tests that unarchiving CRWSessionStorage correctly creates a fresh
// stable identifier if missing from the serialized data.
TEST_F(CRWSessionStorageTest, DecodeStableIdentifierMissing) {
session_storage_.userData = SessionUserDataFromDictionary(@{});
session_storage_.stableIdentifier = nil;
CRWSessionStorage* decoded =
DecodeSessionStorage(EncodeSessionStorage(session_storage_));
EXPECT_GT(decoded.stableIdentifier.length, 0u);
}
// Tests that unarchiving CRWSessionStorage correctly initialises the
// stable identifier from the serializable user data key "TabId" if
// present, and that the value is cleared from the decoded object user
// data.
TEST_F(CRWSessionStorageTest, DecodeStableIdentifierFromTabId) {
session_storage_.userData =
SessionUserDataFromDictionary(@{@"TabId" : @"tabid-identifier"});
session_storage_.stableIdentifier = nil;
CRWSessionStorage* decoded =
DecodeSessionStorage(EncodeSessionStorage(session_storage_));
EXPECT_NSEQ(decoded.stableIdentifier, @"tabid-identifier");
EXPECT_FALSE([decoded.userData objectForKey:@"TabId"]);
}