|  | // Copyright 2014 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/net/cookies/cookie_creation_time_manager.h" | 
|  |  | 
|  | #import <Foundation/Foundation.h> | 
|  | #import <stdint.h> | 
|  |  | 
|  | #import "base/time/time.h" | 
|  | #import "testing/gtest/include/gtest/gtest.h" | 
|  | #import "testing/platform_test.h" | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | class CookieCreationTimeManagerTest : public PlatformTest { | 
|  | public: | 
|  | NSHTTPCookie* GetCookie(NSString* cookie_line) { | 
|  | NSArray* cookies = [NSHTTPCookie | 
|  | cookiesWithResponseHeaderFields:@{@"Set-Cookie" : cookie_line} | 
|  | forURL:[NSURL URLWithString:@"http://foo"]]; | 
|  | if ([cookies count] != 1) { | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | return [cookies objectAtIndex:0]; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | CookieCreationTimeManager creation_time_manager_; | 
|  | }; | 
|  |  | 
|  | TEST_F(CookieCreationTimeManagerTest, SetAndGet) { | 
|  | NSHTTPCookie* cookie = GetCookie(@"A=B"); | 
|  | ASSERT_TRUE(cookie); | 
|  | base::Time creation_time = base::Time::Now(); | 
|  | creation_time_manager_.SetCreationTime(cookie, creation_time); | 
|  | EXPECT_EQ(creation_time, creation_time_manager_.GetCreationTime(cookie)); | 
|  | } | 
|  |  | 
|  | TEST_F(CookieCreationTimeManagerTest, GetFromSystemCookie) { | 
|  | NSHTTPCookie* cookie = GetCookie(@"A=B"); | 
|  |  | 
|  | // The creation time of a cookie that was never set through the | 
|  | // CookieCreationTimeManager should be retrieved from the system with 1 | 
|  | // second precision. | 
|  | base::Time time = creation_time_manager_.GetCreationTime(cookie); | 
|  | base::Time now = base::Time::Now(); | 
|  | ASSERT_FALSE(time.is_null()); | 
|  | int64_t delta = (now - time).InMilliseconds(); | 
|  | // On iOS 8, the range is (0, 1000) ms. The intervals tested are actually | 
|  | // 1200 ms to allow some imprecision. | 
|  | EXPECT_GT(delta, -100); | 
|  | EXPECT_LT(delta, 1100); | 
|  | } | 
|  |  | 
|  | TEST_F(CookieCreationTimeManagerTest, MakeUniqueCreationTime) { | 
|  | base::Time now = base::Time::Now(); | 
|  |  | 
|  | // |now| is not used yet, so MakeUniqueCreationTime() should return that. | 
|  | base::Time creation_time = creation_time_manager_.MakeUniqueCreationTime(now); | 
|  | EXPECT_EQ(now, creation_time); | 
|  |  | 
|  | NSHTTPCookie* cookie1 = GetCookie(@"A=B"); | 
|  | ASSERT_TRUE(cookie1); | 
|  | creation_time_manager_.SetCreationTime(cookie1, creation_time); | 
|  | // |now| is used by cookie1, MakeUniqueCreationTime() should return the | 
|  | // incremented value. | 
|  | creation_time = creation_time_manager_.MakeUniqueCreationTime(now); | 
|  | EXPECT_EQ(base::Time::FromInternalValue(now.ToInternalValue() + 1), | 
|  | creation_time); | 
|  |  | 
|  | // Delete |cookie1|. | 
|  | creation_time_manager_.DeleteCreationTime(cookie1); | 
|  | // |now| is available again because |cookie1| was deleted. | 
|  | creation_time = creation_time_manager_.MakeUniqueCreationTime(now); | 
|  | EXPECT_EQ(now, creation_time); | 
|  |  | 
|  | creation_time_manager_.SetCreationTime(GetCookie(@"C=D"), creation_time); | 
|  | // Override |C| with a cookie that has a different time, to make |now| | 
|  | // available again. | 
|  | creation_time_manager_.SetCreationTime(GetCookie(@"C=E"), | 
|  | now - base::Milliseconds(1)); | 
|  | // |now| is available again because |C| was overriden. | 
|  | creation_time = creation_time_manager_.MakeUniqueCreationTime(now); | 
|  | EXPECT_EQ(now, creation_time); | 
|  |  | 
|  | creation_time_manager_.SetCreationTime(GetCookie(@"F=G"), creation_time); | 
|  | // Delete all creation times. | 
|  | creation_time_manager_.Clear(); | 
|  | // |now| is available again because all creation times were cleared. | 
|  | creation_time = creation_time_manager_.MakeUniqueCreationTime(now); | 
|  | EXPECT_EQ(now, creation_time); | 
|  | } | 
|  |  | 
|  | TEST_F(CookieCreationTimeManagerTest, MakeUniqueCreationTimeConflicts) { | 
|  | base::Time creation_time = base::Time::Now(); | 
|  | int64_t time_internal_value = creation_time.ToInternalValue(); | 
|  | // Insert two cookies with consecutive times. | 
|  | creation_time_manager_.SetCreationTime(GetCookie(@"A=B"), creation_time); | 
|  | creation_time_manager_.SetCreationTime( | 
|  | GetCookie(@"C=D"), | 
|  | base::Time::FromInternalValue(time_internal_value + 1)); | 
|  |  | 
|  | // MakeUniqueCreationTime() should insert at |time_internal_value + 2|. | 
|  | base::Time time = | 
|  | creation_time_manager_.MakeUniqueCreationTime(creation_time); | 
|  | EXPECT_EQ(time_internal_value + 2, time.ToInternalValue()); | 
|  | creation_time_manager_.SetCreationTime(GetCookie(@"E=F"), time); | 
|  |  | 
|  | // Leave an available slot at |time_internal_value + 3| and insert another | 
|  | // cookie at |time_internal_value + 4|. | 
|  | creation_time_manager_.SetCreationTime( | 
|  | GetCookie(@"G=H"), | 
|  | base::Time::FromInternalValue(time_internal_value + 4)); | 
|  |  | 
|  | // MakeUniqueCreationTime() should use the available slot. | 
|  | time = creation_time_manager_.MakeUniqueCreationTime(creation_time); | 
|  | EXPECT_EQ(time_internal_value + 3, time.ToInternalValue()); | 
|  | } | 
|  |  | 
|  | }  // namespace net |