OLD | NEW |
| (Empty) |
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 "base/memory/scoped_ptr.h" | |
6 #include "base/prefs/mock_pref_change_callback.h" | |
7 #include "base/strings/string_number_conversions.h" | |
8 #include "chrome/browser/extensions/extension_prefs.h" | |
9 #include "chrome/browser/extensions/shell_window_geometry_cache.h" | |
10 #include "chrome/browser/extensions/test_extension_prefs.h" | |
11 #include "chrome/browser/prefs/pref_service_syncable.h" | |
12 #include "chrome/test/base/testing_profile.h" | |
13 #include "content/public/test/test_browser_thread.h" | |
14 #include "content/public/test/test_utils.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 | |
17 namespace { | |
18 static const char kWindowId[] = "windowid"; | |
19 static const char kWindowId2[] = "windowid2"; | |
20 | |
21 const char kWindowGeometryKey[] = "window_geometry"; | |
22 } // namespace | |
23 | |
24 using content::BrowserThread; | |
25 | |
26 namespace extensions { | |
27 | |
28 // Base class for tests. | |
29 class ShellWindowGeometryCacheTest : public testing::Test { | |
30 public: | |
31 ShellWindowGeometryCacheTest() : | |
32 ui_thread_(BrowserThread::UI, &ui_message_loop_) { | |
33 prefs_.reset(new TestExtensionPrefs(ui_message_loop_.message_loop_proxy())); | |
34 cache_.reset( | |
35 new ShellWindowGeometryCache(&profile_, prefs_->prefs())); | |
36 cache_->SetSyncDelayForTests(0); | |
37 } | |
38 | |
39 void AddGeometryAndLoadExtension( | |
40 const std::string& extension_id, | |
41 const std::string& window_id, | |
42 const gfx::Rect& bounds, | |
43 ui::WindowShowState state); | |
44 | |
45 // Spins the UI threads' message loops to make sure any task | |
46 // posted to sync the geometry to the value store gets a chance to run. | |
47 void WaitForSync(); | |
48 | |
49 void LoadExtension(const std::string& extension_id); | |
50 void UnloadExtension(const std::string& extension_id); | |
51 | |
52 protected: | |
53 TestingProfile profile_; | |
54 MessageLoopForUI ui_message_loop_; | |
55 content::TestBrowserThread ui_thread_; | |
56 scoped_ptr<TestExtensionPrefs> prefs_; | |
57 scoped_ptr<ShellWindowGeometryCache> cache_; | |
58 }; | |
59 | |
60 void ShellWindowGeometryCacheTest::AddGeometryAndLoadExtension( | |
61 const std::string& extension_id, | |
62 const std::string& window_id, | |
63 const gfx::Rect& bounds, | |
64 ui::WindowShowState state) { | |
65 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue); | |
66 base::DictionaryValue* value = new base::DictionaryValue; | |
67 value->SetInteger("x", bounds.x()); | |
68 value->SetInteger("y", bounds.y()); | |
69 value->SetInteger("w", bounds.width()); | |
70 value->SetInteger("h", bounds.height()); | |
71 value->SetInteger("state", state); | |
72 dict->SetWithoutPathExpansion(window_id, value); | |
73 prefs_->prefs()->SetGeometryCache(extension_id, dict.Pass()); | |
74 LoadExtension(extension_id); | |
75 } | |
76 | |
77 void ShellWindowGeometryCacheTest::WaitForSync() { | |
78 content::RunAllPendingInMessageLoop(); | |
79 } | |
80 | |
81 void ShellWindowGeometryCacheTest::LoadExtension( | |
82 const std::string& extension_id) { | |
83 cache_->OnExtensionLoaded(extension_id); | |
84 WaitForSync(); | |
85 } | |
86 | |
87 void ShellWindowGeometryCacheTest::UnloadExtension( | |
88 const std::string& extension_id) { | |
89 cache_->OnExtensionUnloaded(extension_id); | |
90 WaitForSync(); | |
91 } | |
92 | |
93 // Test getting geometry from an empty store. | |
94 TEST_F(ShellWindowGeometryCacheTest, GetGeometryEmptyStore) { | |
95 const std::string extension_id = prefs_->AddExtensionAndReturnId("ext1"); | |
96 ASSERT_FALSE(cache_->GetGeometry(extension_id, kWindowId, NULL, NULL)); | |
97 } | |
98 | |
99 // Test getting geometry for an unknown extension. | |
100 TEST_F(ShellWindowGeometryCacheTest, GetGeometryUnkownExtension) { | |
101 const std::string extension_id1 = prefs_->AddExtensionAndReturnId("ext1"); | |
102 const std::string extension_id2 = prefs_->AddExtensionAndReturnId("ext2"); | |
103 AddGeometryAndLoadExtension(extension_id1, kWindowId, | |
104 gfx::Rect(4, 5, 31, 43), | |
105 ui::SHOW_STATE_DEFAULT); | |
106 ASSERT_FALSE(cache_->GetGeometry(extension_id2, kWindowId, NULL, NULL)); | |
107 } | |
108 | |
109 // Test getting geometry for an unknown window in a known extension. | |
110 TEST_F(ShellWindowGeometryCacheTest, GetGeometryUnkownWindow) { | |
111 const std::string extension_id = prefs_->AddExtensionAndReturnId("ext1"); | |
112 AddGeometryAndLoadExtension(extension_id, kWindowId, | |
113 gfx::Rect(4, 5, 31, 43), | |
114 ui::SHOW_STATE_DEFAULT); | |
115 ASSERT_FALSE(cache_->GetGeometry(extension_id, kWindowId2, NULL, NULL)); | |
116 } | |
117 | |
118 // Test that loading geometry and state from the store works correctly. | |
119 TEST_F(ShellWindowGeometryCacheTest, GetGeometryAndStateFromStore) { | |
120 const std::string extension_id = prefs_->AddExtensionAndReturnId("ext1"); | |
121 gfx::Rect bounds(4, 5, 31, 43); | |
122 ui::WindowShowState state = ui::SHOW_STATE_NORMAL; | |
123 AddGeometryAndLoadExtension(extension_id, kWindowId, bounds, state); | |
124 gfx::Rect new_bounds; | |
125 ui::WindowShowState new_state = ui::SHOW_STATE_DEFAULT; | |
126 ASSERT_TRUE(cache_->GetGeometry( | |
127 extension_id, kWindowId, &new_bounds, &new_state)); | |
128 ASSERT_EQ(bounds, new_bounds); | |
129 ASSERT_EQ(state, new_state); | |
130 } | |
131 | |
132 // Test saving geometry and state to the cache and state store, and reading | |
133 // it back. | |
134 TEST_F(ShellWindowGeometryCacheTest, SaveGeometryAndStateToStore) { | |
135 const std::string extension_id = prefs_->AddExtensionAndReturnId("ext1"); | |
136 const std::string window_id(kWindowId); | |
137 | |
138 // inform cache of extension | |
139 LoadExtension(extension_id); | |
140 | |
141 // update geometry stored in cache | |
142 gfx::Rect bounds(4, 5, 31, 43); | |
143 ui::WindowShowState state = ui::SHOW_STATE_NORMAL; | |
144 cache_->SaveGeometry(extension_id, window_id, bounds, state); | |
145 | |
146 // make sure that immediately reading back geometry works | |
147 gfx::Rect new_bounds; | |
148 ui::WindowShowState new_state = ui::SHOW_STATE_DEFAULT; | |
149 ASSERT_TRUE(cache_->GetGeometry( | |
150 extension_id, window_id, &new_bounds, &new_state)); | |
151 ASSERT_EQ(bounds, new_bounds); | |
152 ASSERT_EQ(state, new_state); | |
153 | |
154 // unload extension to force cache to save data to the state store | |
155 UnloadExtension(extension_id); | |
156 | |
157 // check if geometry got stored correctly in the state store | |
158 const base::DictionaryValue* dict = | |
159 prefs_->prefs()->GetGeometryCache(extension_id); | |
160 ASSERT_TRUE(dict); | |
161 | |
162 ASSERT_TRUE(dict->HasKey(window_id)); | |
163 int v; | |
164 ASSERT_TRUE(dict->GetInteger(window_id + ".x", &v)); | |
165 ASSERT_EQ(bounds.x(), v); | |
166 ASSERT_TRUE(dict->GetInteger(window_id + ".y", &v)); | |
167 ASSERT_EQ(bounds.y(), v); | |
168 ASSERT_TRUE(dict->GetInteger(window_id + ".w", &v)); | |
169 ASSERT_EQ(bounds.width(), v); | |
170 ASSERT_TRUE(dict->GetInteger(window_id + ".h", &v)); | |
171 ASSERT_EQ(bounds.height(), v); | |
172 ASSERT_TRUE(dict->GetInteger(window_id + ".state", &v)); | |
173 ASSERT_EQ(state, v); | |
174 | |
175 // check to make sure cache indeed doesn't know about this extension anymore | |
176 ASSERT_FALSE(cache_->GetGeometry( | |
177 extension_id, window_id, &new_bounds, &new_state)); | |
178 | |
179 // reload extension | |
180 LoadExtension(extension_id); | |
181 // and make sure the geometry got reloaded properly too | |
182 ASSERT_TRUE(cache_->GetGeometry( | |
183 extension_id, window_id, &new_bounds, &new_state)); | |
184 ASSERT_EQ(bounds, new_bounds); | |
185 ASSERT_EQ(state, new_state); | |
186 } | |
187 | |
188 // Tests that we won't do writes to the state store for SaveGeometry calls | |
189 // which don't change the state we already have. | |
190 TEST_F(ShellWindowGeometryCacheTest, NoDuplicateWrites) { | |
191 using testing::_; | |
192 using testing::Mock; | |
193 | |
194 const std::string extension_id = prefs_->AddExtensionAndReturnId("ext1"); | |
195 gfx::Rect bounds1(100, 200, 300, 400); | |
196 gfx::Rect bounds2(200, 400, 600, 800); | |
197 gfx::Rect bounds2_duplicate(200, 400, 600, 800); | |
198 | |
199 MockPrefChangeCallback observer(prefs_->pref_service()); | |
200 PrefChangeRegistrar registrar; | |
201 registrar.Init(prefs_->pref_service()); | |
202 registrar.Add("extensions.settings", observer.GetCallback()); | |
203 | |
204 // Write the first bounds - it should do > 0 writes. | |
205 EXPECT_CALL(observer, OnPreferenceChanged(_)); | |
206 cache_->SaveGeometry(extension_id, kWindowId, bounds1, | |
207 ui::SHOW_STATE_DEFAULT); | |
208 WaitForSync(); | |
209 Mock::VerifyAndClearExpectations(&observer); | |
210 | |
211 // Write a different bounds - it should also do > 0 writes. | |
212 EXPECT_CALL(observer, OnPreferenceChanged(_)); | |
213 cache_->SaveGeometry(extension_id, kWindowId, bounds2, | |
214 ui::SHOW_STATE_DEFAULT); | |
215 WaitForSync(); | |
216 Mock::VerifyAndClearExpectations(&observer); | |
217 | |
218 // Write a different state - it should also do > 0 writes. | |
219 EXPECT_CALL(observer, OnPreferenceChanged(_)); | |
220 cache_->SaveGeometry(extension_id, kWindowId, bounds2, | |
221 ui::SHOW_STATE_NORMAL); | |
222 WaitForSync(); | |
223 Mock::VerifyAndClearExpectations(&observer); | |
224 | |
225 // Write a bounds and state that's a duplicate of what we already have. | |
226 // This should not do any writes. | |
227 EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0); | |
228 cache_->SaveGeometry(extension_id, kWindowId, bounds2_duplicate, | |
229 ui::SHOW_STATE_NORMAL); | |
230 WaitForSync(); | |
231 Mock::VerifyAndClearExpectations(&observer); | |
232 } | |
233 | |
234 // Tests that no more than kMaxCachedWindows windows will be cached. | |
235 TEST_F(ShellWindowGeometryCacheTest, MaxWindows) { | |
236 const std::string extension_id = prefs_->AddExtensionAndReturnId("ext1"); | |
237 // inform cache of extension | |
238 LoadExtension(extension_id); | |
239 | |
240 gfx::Rect bounds(4, 5, 31, 43); | |
241 for (size_t i = 0; i < ShellWindowGeometryCache::kMaxCachedWindows + 1; ++i) { | |
242 std::string window_id = "window_" + base::IntToString(i); | |
243 cache_->SaveGeometry(extension_id, window_id, bounds, | |
244 ui::SHOW_STATE_DEFAULT); | |
245 } | |
246 | |
247 // The first added window should no longer have cached geometry. | |
248 EXPECT_FALSE(cache_->GetGeometry(extension_id, "window_0", NULL, NULL)); | |
249 // All other windows should still exist. | |
250 for (size_t i = 1; i < ShellWindowGeometryCache::kMaxCachedWindows + 1; ++i) { | |
251 std::string window_id = "window_" + base::IntToString(i); | |
252 EXPECT_TRUE(cache_->GetGeometry(extension_id, window_id, NULL, NULL)); | |
253 } | |
254 } | |
255 | |
256 } // namespace extensions | |
OLD | NEW |