1// Copyright (c) 2012 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 "chrome/browser/profiles/off_the_record_profile_impl.h"
6
7#include "base/prefs/pref_registry_simple.h"
8#include "base/prefs/pref_service.h"
9#include "base/prefs/scoped_user_pref_update.h"
10#include "base/run_loop.h"
11#include "chrome/browser/prefs/browser_prefs.h"
12#include "chrome/common/pref_names.h"
13#include "chrome/test/base/browser_with_test_window_test.h"
14#include "chrome/test/base/testing_browser_process.h"
15#include "chrome/test/base/testing_io_thread_state.h"
16#include "chrome/test/base/testing_pref_service_syncable.h"
17#include "chrome/test/base/testing_profile.h"
18#include "chrome/test/base/testing_profile_manager.h"
19#include "content/public/browser/host_zoom_map.h"
20#include "content/public/common/page_zoom.h"
21#include "net/dns/mock_host_resolver.h"
22
23using content::HostZoomMap;
24
25namespace {
26
27class TestingProfileWithHostZoomMap : public TestingProfile {
28 public:
29  TestingProfileWithHostZoomMap() {
30    zoom_subscription_ =
31        HostZoomMap::GetDefaultForBrowserContext(this)
32            ->AddZoomLevelChangedCallback(
33                base::Bind(&TestingProfileWithHostZoomMap::OnZoomLevelChanged,
34                           base::Unretained(this)));
35  }
36
37  virtual ~TestingProfileWithHostZoomMap() {}
38
39  // Profile overrides:
40  virtual PrefService* GetOffTheRecordPrefs() OVERRIDE {
41    return GetPrefs();
42  }
43
44 private:
45  void OnZoomLevelChanged(const HostZoomMap::ZoomLevelChange& change) {
46
47    if (change.mode != HostZoomMap::ZOOM_CHANGED_FOR_HOST)
48      return;
49
50    HostZoomMap* host_zoom_map = HostZoomMap::GetDefaultForBrowserContext(this);
51
52    double level = change.zoom_level;
53    DictionaryPrefUpdate update(prefs_.get(), prefs::kPerHostZoomLevels);
54    base::DictionaryValue* host_zoom_dictionary = update.Get();
55    if (content::ZoomValuesEqual(level, host_zoom_map->GetDefaultZoomLevel())) {
56      host_zoom_dictionary->RemoveWithoutPathExpansion(change.host, NULL);
57    } else {
58      host_zoom_dictionary->SetWithoutPathExpansion(
59          change.host, new base::FundamentalValue(level));
60    }
61  }
62
63  scoped_ptr<HostZoomMap::Subscription> zoom_subscription_;
64
65  DISALLOW_COPY_AND_ASSIGN(TestingProfileWithHostZoomMap);
66};
67
68}  // namespace
69
70// We need to have a BrowserProcess in g_browser_process variable, since
71// OffTheRecordProfileImpl ctor uses it in
72// ProfileIOData::InitializeProfileParams.
73class OffTheRecordProfileImplTest : public BrowserWithTestWindowTest {
74 protected:
75  OffTheRecordProfileImplTest() {}
76
77  virtual ~OffTheRecordProfileImplTest() {}
78
79  // testing::Test overrides:
80  virtual void SetUp() OVERRIDE {
81    profile_manager_.reset(new TestingProfileManager(browser_process()));
82    ASSERT_TRUE(profile_manager_->SetUp());
83
84    testing_io_thread_state_.reset(new chrome::TestingIOThreadState());
85    testing_io_thread_state_->io_thread_state()->globals()->host_resolver.reset(
86        new net::MockHostResolver());
87
88    BrowserWithTestWindowTest::SetUp();
89  }
90
91  virtual void TearDown() OVERRIDE {
92    BrowserWithTestWindowTest::TearDown();
93
94    testing_io_thread_state_.reset();
95
96    profile_manager_.reset();
97  }
98
99  // BrowserWithTestWindowTest overrides:
100  virtual TestingProfile* CreateProfile() OVERRIDE {
101    return new TestingProfileWithHostZoomMap;
102  }
103
104 private:
105  TestingBrowserProcess* browser_process() {
106    return TestingBrowserProcess::GetGlobal();
107  }
108
109  scoped_ptr<TestingProfileManager> profile_manager_;
110  scoped_ptr<chrome::TestingIOThreadState> testing_io_thread_state_;
111
112  DISALLOW_COPY_AND_ASSIGN(OffTheRecordProfileImplTest);
113};
114
115// Test four things:
116//  1. Host zoom maps of parent profile and child profile are different.
117//  2. Child host zoom map inherites zoom level at construction.
118//  3. Change of zoom level doesn't propagate from child to parent.
119//  4. Change of zoom level propagate from parent to child.
120TEST_F(OffTheRecordProfileImplTest, GetHostZoomMap) {
121  // Constants for test case.
122  const std::string host("example.com");
123  const double zoom_level_25 = 2.5;
124  const double zoom_level_30 = 3.0;
125  const double zoom_level_40 = 4.0;
126
127  // The TestingProfile from CreateProfile above is the parent.
128  TestingProfile* parent_profile = GetProfile();
129  ASSERT_TRUE(parent_profile);
130  ASSERT_TRUE(parent_profile->GetPrefs());
131  ASSERT_TRUE(parent_profile->GetOffTheRecordPrefs());
132
133  // Prepare parent host zoom map.
134  HostZoomMap* parent_zoom_map =
135      HostZoomMap::GetDefaultForBrowserContext(parent_profile);
136  ASSERT_TRUE(parent_zoom_map);
137
138  parent_zoom_map->SetZoomLevelForHost(host, zoom_level_25);
139  ASSERT_EQ(parent_zoom_map->GetZoomLevelForHostAndScheme("http", host),
140      zoom_level_25);
141
142  // TODO(yosin) We need to wait ProfileImpl::Observe done for
143  // OnZoomLevelChanged.
144
145  // Prepare an off the record profile owned by the parent profile.
146  parent_profile->SetOffTheRecordProfile(
147      scoped_ptr<Profile>(new OffTheRecordProfileImpl(parent_profile)));
148  OffTheRecordProfileImpl* child_profile =
149      static_cast<OffTheRecordProfileImpl*>(
150          parent_profile->GetOffTheRecordProfile());
151  child_profile->InitIoData();
152  child_profile->InitHostZoomMap();
153
154  // Prepare child host zoom map.
155  HostZoomMap* child_zoom_map =
156      HostZoomMap::GetDefaultForBrowserContext(child_profile);
157  ASSERT_TRUE(child_zoom_map);
158
159  // Verify.
160  EXPECT_NE(parent_zoom_map, child_zoom_map);
161
162  EXPECT_EQ(parent_zoom_map->GetZoomLevelForHostAndScheme("http", host),
163            child_zoom_map->GetZoomLevelForHostAndScheme("http", host)) <<
164                "Child must inherit from parent.";
165
166  child_zoom_map->SetZoomLevelForHost(host, zoom_level_30);
167  ASSERT_EQ(
168      child_zoom_map->GetZoomLevelForHostAndScheme("http", host),
169      zoom_level_30);
170
171  EXPECT_NE(parent_zoom_map->GetZoomLevelForHostAndScheme("http", host),
172            child_zoom_map->GetZoomLevelForHostAndScheme("http", host)) <<
173                "Child change must not propagate to parent.";
174
175  parent_zoom_map->SetZoomLevelForHost(host, zoom_level_40);
176  ASSERT_EQ(
177      parent_zoom_map->GetZoomLevelForHostAndScheme("http", host),
178      zoom_level_40);
179
180  EXPECT_EQ(parent_zoom_map->GetZoomLevelForHostAndScheme("http", host),
181            child_zoom_map->GetZoomLevelForHostAndScheme("http", host)) <<
182                "Parent change should propagate to child.";
183  base::RunLoop().RunUntilIdle();
184}
185