1 // Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "include/base/cef_bind.h"
6 #include "include/cef_request_context_handler.h"
7 #include "include/cef_waitable_event.h"
8 #include "include/wrapper/cef_closure_task.h"
9 #include "tests/ceftests/test_handler.h"
10 #include "tests/ceftests/test_util.h"
11 #include "tests/gtest/include/gtest/gtest.h"
12 #include "tests/shared/browser/client_app_browser.h"
13
14 namespace {
15
16 // Fully qualified preference names.
17 const char kPrefTest[] = "test";
18 const char kPrefTestBool[] = "test.bool";
19 const char kPrefTestInt[] = "test.int";
20 const char kPrefTestDouble[] = "test.double";
21 const char kPrefTestString[] = "test.string";
22 const char kPrefTestList[] = "test.list";
23 const char kPrefTestDict[] = "test.dict";
24 const char kPrefTestNoExist[] = "test.noexist";
25
26 // Unqualified preference names.
27 const char kPrefBool[] = "bool";
28 const char kPrefInt[] = "int";
29 const char kPrefDouble[] = "double";
30 const char kPrefString[] = "string";
31 const char kPrefList[] = "list";
32 const char kPrefDict[] = "dict";
33
PendingAction()34 std::string* PendingAction() {
35 static std::string str;
36 return &str;
37 }
38
39 // Browser-side app delegate.
40 class PreferenceBrowserTest : public client::ClientAppBrowser::Delegate {
41 public:
PreferenceBrowserTest()42 PreferenceBrowserTest() {}
43
OnBeforeCommandLineProcessing(CefRefPtr<client::ClientAppBrowser> app,CefRefPtr<CefCommandLine> command_line)44 void OnBeforeCommandLineProcessing(
45 CefRefPtr<client::ClientAppBrowser> app,
46 CefRefPtr<CefCommandLine> command_line) override {
47 // Enables testing of preferences.
48 // See CefBrowserPrefStore::CreateService.
49 command_line->AppendSwitch("enable-preference-testing");
50 }
51
52 private:
53 IMPLEMENT_REFCOUNTING(PreferenceBrowserTest);
54 };
55
ValidateReset(CefRefPtr<CefRequestContext> context,const char * name)56 void ValidateReset(CefRefPtr<CefRequestContext> context, const char* name) {
57 EXPECT_TRUE(context->HasPreference(name));
58 EXPECT_TRUE(context->CanSetPreference(name));
59
60 CefString error;
61 EXPECT_TRUE(context->SetPreference(name, nullptr, error));
62 EXPECT_TRUE(error.empty());
63 }
64
ValidateBool(CefRefPtr<CefRequestContext> context,bool set,bool expected,const char * name=kPrefTestBool)65 void ValidateBool(CefRefPtr<CefRequestContext> context,
66 bool set,
67 bool expected,
68 const char* name = kPrefTestBool) {
69 EXPECT_TRUE(context->HasPreference(name));
70 EXPECT_TRUE(context->CanSetPreference(name));
71
72 CefRefPtr<CefValue> value;
73
74 if (set) {
75 value = CefValue::Create();
76 value->SetBool(expected);
77 CefString error;
78 EXPECT_TRUE(context->SetPreference(name, value, error));
79 EXPECT_TRUE(error.empty());
80 }
81
82 value = context->GetPreference(name);
83 EXPECT_TRUE(value.get());
84 EXPECT_EQ(VTYPE_BOOL, value->GetType());
85 EXPECT_EQ(expected, value->GetBool()) << *PendingAction();
86 }
87
ValidateInt(CefRefPtr<CefRequestContext> context,bool set,int expected,const char * name=kPrefTestInt)88 void ValidateInt(CefRefPtr<CefRequestContext> context,
89 bool set,
90 int expected,
91 const char* name = kPrefTestInt) {
92 EXPECT_TRUE(context->HasPreference(name));
93 EXPECT_TRUE(context->CanSetPreference(name));
94
95 CefRefPtr<CefValue> value;
96
97 if (set) {
98 value = CefValue::Create();
99 value->SetInt(expected);
100 CefString error;
101 EXPECT_TRUE(context->SetPreference(name, value, error));
102 EXPECT_TRUE(error.empty());
103 }
104
105 value = context->GetPreference(name);
106 EXPECT_TRUE(value.get());
107 EXPECT_EQ(VTYPE_INT, value->GetType());
108 EXPECT_EQ(expected, value->GetInt()) << *PendingAction();
109 }
110
ValidateDouble(CefRefPtr<CefRequestContext> context,bool set,double expected,const char * name=kPrefTestDouble)111 void ValidateDouble(CefRefPtr<CefRequestContext> context,
112 bool set,
113 double expected,
114 const char* name = kPrefTestDouble) {
115 EXPECT_TRUE(context->HasPreference(name));
116 EXPECT_TRUE(context->CanSetPreference(name));
117
118 CefRefPtr<CefValue> value;
119
120 if (set) {
121 value = CefValue::Create();
122 value->SetDouble(expected);
123 CefString error;
124 EXPECT_TRUE(context->SetPreference(name, value, error));
125 EXPECT_TRUE(error.empty());
126 }
127
128 value = context->GetPreference(name);
129 EXPECT_TRUE(value.get());
130 EXPECT_EQ(VTYPE_DOUBLE, value->GetType());
131 EXPECT_EQ(expected, value->GetDouble()) << *PendingAction();
132 }
133
ValidateString(CefRefPtr<CefRequestContext> context,bool set,const std::string & expected,const char * name=kPrefTestString)134 void ValidateString(CefRefPtr<CefRequestContext> context,
135 bool set,
136 const std::string& expected,
137 const char* name = kPrefTestString) {
138 EXPECT_TRUE(context->HasPreference(name));
139 EXPECT_TRUE(context->CanSetPreference(name));
140
141 CefRefPtr<CefValue> value;
142
143 if (set) {
144 value = CefValue::Create();
145 value->SetString(expected);
146 CefString error;
147 EXPECT_TRUE(context->SetPreference(name, value, error));
148 EXPECT_TRUE(error.empty());
149 }
150
151 value = context->GetPreference(name);
152 EXPECT_TRUE(value.get());
153 EXPECT_EQ(VTYPE_STRING, value->GetType());
154 EXPECT_STREQ(expected.c_str(), value->GetString().ToString().c_str())
155 << *PendingAction();
156 }
157
ValidateList(CefRefPtr<CefRequestContext> context,bool set,CefRefPtr<CefListValue> expected,const char * name=kPrefTestList)158 void ValidateList(CefRefPtr<CefRequestContext> context,
159 bool set,
160 CefRefPtr<CefListValue> expected,
161 const char* name = kPrefTestList) {
162 EXPECT_TRUE(context->HasPreference(name));
163 EXPECT_TRUE(context->CanSetPreference(name));
164
165 CefRefPtr<CefValue> value;
166
167 if (set) {
168 value = CefValue::Create();
169 value->SetList(expected);
170 CefString error;
171 EXPECT_TRUE(context->SetPreference(name, value, error));
172 EXPECT_TRUE(error.empty());
173 }
174
175 value = context->GetPreference(name);
176 EXPECT_TRUE(value.get());
177 EXPECT_EQ(VTYPE_LIST, value->GetType());
178 CefRefPtr<CefListValue> list_val = value->GetList();
179 EXPECT_TRUE(list_val);
180 TestListEqual(expected, list_val);
181 }
182
ValidateDict(CefRefPtr<CefRequestContext> context,bool set,CefRefPtr<CefDictionaryValue> expected,const char * name=kPrefTestDict)183 void ValidateDict(CefRefPtr<CefRequestContext> context,
184 bool set,
185 CefRefPtr<CefDictionaryValue> expected,
186 const char* name = kPrefTestDict) {
187 EXPECT_TRUE(context->HasPreference(name));
188 EXPECT_TRUE(context->CanSetPreference(name));
189
190 CefRefPtr<CefValue> value;
191
192 if (set) {
193 value = CefValue::Create();
194 value->SetDictionary(expected);
195 CefString error;
196 EXPECT_TRUE(context->SetPreference(name, value, error));
197 EXPECT_TRUE(error.empty());
198 }
199
200 value = context->GetPreference(name);
201 EXPECT_TRUE(value.get());
202 EXPECT_EQ(VTYPE_DICTIONARY, value->GetType());
203 CefRefPtr<CefDictionaryValue> dict_val = value->GetDictionary();
204 EXPECT_TRUE(dict_val);
205 TestDictionaryEqual(expected, dict_val);
206 }
207
ValidateNoExist(CefRefPtr<CefRequestContext> context,bool set,const char * name=kPrefTestNoExist)208 void ValidateNoExist(CefRefPtr<CefRequestContext> context,
209 bool set,
210 const char* name = kPrefTestNoExist) {
211 EXPECT_FALSE(context->HasPreference(name));
212 EXPECT_FALSE(context->CanSetPreference(name));
213
214 CefRefPtr<CefValue> value;
215
216 if (set) {
217 value = CefValue::Create();
218 value->SetBool(false);
219 CefString error;
220 EXPECT_FALSE(context->SetPreference(name, value, error));
221 EXPECT_FALSE(error.empty());
222 }
223
224 value = context->GetPreference(name);
225 EXPECT_FALSE(value.get()) << *PendingAction();
226 }
227
PopulateRootDefaults(CefRefPtr<CefDictionaryValue> val)228 void PopulateRootDefaults(CefRefPtr<CefDictionaryValue> val) {
229 // Should match the values in CefBrowserPrefStore::CreateService.
230 val->SetBool(kPrefBool, true);
231 val->SetInt(kPrefInt, 2);
232 val->SetDouble(kPrefDouble, 5.0);
233 val->SetString(kPrefString, "default");
234 val->SetList(kPrefList, CefListValue::Create());
235 val->SetDictionary(kPrefDict, CefDictionaryValue::Create());
236 }
237
ValidateRoot(CefRefPtr<CefDictionaryValue> root,CefRefPtr<CefDictionaryValue> expected,const char * name=kPrefTest)238 void ValidateRoot(CefRefPtr<CefDictionaryValue> root,
239 CefRefPtr<CefDictionaryValue> expected,
240 const char* name = kPrefTest) {
241 EXPECT_TRUE(root->HasKey(kPrefTest));
242 EXPECT_EQ(VTYPE_DICTIONARY, root->GetType(kPrefTest));
243
244 CefRefPtr<CefDictionaryValue> actual = root->GetDictionary(kPrefTest);
245 TestDictionaryEqual(expected, actual);
246 }
247
248 // Validate getting default values.
ValidateDefaults(CefRefPtr<CefRequestContext> context,bool reset,CefRefPtr<CefWaitableEvent> event)249 void ValidateDefaults(CefRefPtr<CefRequestContext> context,
250 bool reset,
251 CefRefPtr<CefWaitableEvent> event) {
252 if (!CefCurrentlyOn(TID_UI)) {
253 CefPostTask(TID_UI, base::Bind(ValidateDefaults, context, reset, event));
254 return;
255 }
256
257 if (reset) {
258 // Reset default values.
259 ValidateReset(context, kPrefTestBool);
260 ValidateReset(context, kPrefTestInt);
261 ValidateReset(context, kPrefTestDouble);
262 ValidateReset(context, kPrefTestString);
263 ValidateReset(context, kPrefTestList);
264 ValidateReset(context, kPrefTestDict);
265 }
266
267 // Test default values.
268 // Should match the values in CefBrowserPrefStore::CreateService.
269 ValidateBool(context, false, true);
270 ValidateInt(context, false, 2);
271 ValidateDouble(context, false, 5.0);
272 ValidateString(context, false, "default");
273 ValidateList(context, false, CefListValue::Create());
274 ValidateDict(context, false, CefDictionaryValue::Create());
275 ValidateNoExist(context, false);
276
277 // Expected value of the tests root.
278 CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
279 PopulateRootDefaults(expected);
280
281 // Test all preferences including defaults.
282 ValidateRoot(context->GetAllPreferences(true), expected);
283
284 // Test all preferences excluding defaults.
285 EXPECT_FALSE(context->GetAllPreferences(false)->HasKey(kPrefTest));
286
287 event->Signal();
288 }
289
PopulateListValue(CefRefPtr<CefListValue> val)290 void PopulateListValue(CefRefPtr<CefListValue> val) {
291 // Test list values.
292 val->SetInt(0, 54);
293 val->SetString(1, "foobar");
294 val->SetDouble(2, 99.7643);
295 }
296
PopulateDictValue(CefRefPtr<CefDictionaryValue> val)297 void PopulateDictValue(CefRefPtr<CefDictionaryValue> val) {
298 // Test dictionary values.
299 val->SetString("key1", "some string");
300 val->SetBool("key2", false);
301
302 CefRefPtr<CefListValue> list_val = CefListValue::Create();
303 PopulateListValue(list_val);
304 val->SetList("key3", list_val);
305 }
306
PopulateRootSet(CefRefPtr<CefDictionaryValue> val)307 void PopulateRootSet(CefRefPtr<CefDictionaryValue> val) {
308 CefRefPtr<CefListValue> list_val = CefListValue::Create();
309 CefRefPtr<CefDictionaryValue> dict_val = CefDictionaryValue::Create();
310
311 PopulateListValue(list_val);
312 PopulateDictValue(dict_val);
313
314 // Should match the values in ValidateSetGet and ValidateGet.
315 val->SetBool(kPrefBool, true);
316 val->SetInt(kPrefInt, 65);
317 val->SetDouble(kPrefDouble, 54.5443);
318 val->SetString(kPrefString, "My test string");
319 val->SetList(kPrefList, list_val);
320 val->SetDictionary(kPrefDict, dict_val);
321 }
322
323 // Validate getting and setting values.
ValidateSetGet(CefRefPtr<CefRequestContext> context,CefRefPtr<CefWaitableEvent> event)324 void ValidateSetGet(CefRefPtr<CefRequestContext> context,
325 CefRefPtr<CefWaitableEvent> event) {
326 if (!CefCurrentlyOn(TID_UI)) {
327 CefPostTask(TID_UI, base::Bind(ValidateSetGet, context, event));
328 return;
329 }
330
331 CefRefPtr<CefListValue> list_val = CefListValue::Create();
332 CefRefPtr<CefDictionaryValue> dict_val = CefDictionaryValue::Create();
333
334 PopulateListValue(list_val);
335 PopulateDictValue(dict_val);
336
337 // Test setting/getting values.
338 // Should match the values in PopulateRootSet and ValidateGet.
339 ValidateBool(context, true, true);
340 ValidateInt(context, true, 65);
341 ValidateDouble(context, true, 54.5443);
342 ValidateString(context, true, "My test string");
343 ValidateList(context, true, list_val);
344 ValidateDict(context, true, dict_val);
345 ValidateNoExist(context, true);
346
347 // Expected value of the tests root.
348 CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
349 PopulateRootSet(expected);
350
351 // Validate all preferences including defaults.
352 ValidateRoot(context->GetAllPreferences(true), expected);
353
354 // Validate all preferences excluding defaults.
355 ValidateRoot(context->GetAllPreferences(false), expected);
356
357 event->Signal();
358 }
359
360 // Validate getting values.
ValidateGet(CefRefPtr<CefRequestContext> context,CefRefPtr<CefWaitableEvent> event)361 void ValidateGet(CefRefPtr<CefRequestContext> context,
362 CefRefPtr<CefWaitableEvent> event) {
363 if (!CefCurrentlyOn(TID_UI)) {
364 CefPostTask(TID_UI, base::Bind(ValidateGet, context, event));
365 return;
366 }
367
368 CefRefPtr<CefListValue> list_val = CefListValue::Create();
369 CefRefPtr<CefDictionaryValue> dict_val = CefDictionaryValue::Create();
370
371 PopulateListValue(list_val);
372 PopulateDictValue(dict_val);
373
374 // Test getting values.
375 // Should match the values in PopulateRootSet and ValidateSetGet.
376 ValidateBool(context, false, true);
377 ValidateInt(context, false, 65);
378 ValidateDouble(context, false, 54.5443);
379 ValidateString(context, false, "My test string");
380 ValidateList(context, false, list_val);
381 ValidateDict(context, false, dict_val);
382 ValidateNoExist(context, false);
383
384 // Expected value of the tests root.
385 CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
386 PopulateRootSet(expected);
387
388 // Validate all preferences including defaults.
389 ValidateRoot(context->GetAllPreferences(true), expected);
390
391 // Validate all preferences excluding defaults.
392 ValidateRoot(context->GetAllPreferences(false), expected);
393
394 event->Signal();
395 }
396
397 // No-op implementation.
398 class TestRequestContextHandler : public CefRequestContextHandler {
399 public:
TestRequestContextHandler()400 TestRequestContextHandler() {}
TestRequestContextHandler(CefRefPtr<CefWaitableEvent> event)401 explicit TestRequestContextHandler(CefRefPtr<CefWaitableEvent> event)
402 : event_(event) {}
403
OnRequestContextInitialized(CefRefPtr<CefRequestContext> context)404 void OnRequestContextInitialized(
405 CefRefPtr<CefRequestContext> context) override {
406 if (event_) {
407 event_->Signal();
408 event_ = nullptr;
409 }
410 }
411
412 private:
413 CefRefPtr<CefWaitableEvent> event_;
414
415 IMPLEMENT_REFCOUNTING(TestRequestContextHandler);
416 };
417
418 } // namespace
419
420 // Verify default preference values on the global context.
TEST(PreferenceTest,GlobalDefaults)421 TEST(PreferenceTest, GlobalDefaults) {
422 CefRefPtr<CefWaitableEvent> event =
423 CefWaitableEvent::CreateWaitableEvent(true, false);
424
425 CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
426 EXPECT_TRUE(context.get());
427
428 ValidateDefaults(context, false, event);
429 event->Wait();
430 }
431
432 // Verify setting/getting preference values on the global context.
TEST(PreferenceTest,GlobalSetGet)433 TEST(PreferenceTest, GlobalSetGet) {
434 CefRefPtr<CefWaitableEvent> event =
435 CefWaitableEvent::CreateWaitableEvent(true, false);
436
437 CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
438 EXPECT_TRUE(context.get());
439
440 ValidateSetGet(context, event);
441 event->Wait();
442
443 // Reset to the default values.
444 ValidateDefaults(context, true, event);
445 event->Wait();
446 }
447
448 // Verify setting/getting preference values on shared global contexts.
TEST(PreferenceTest,GlobalSetGetShared)449 TEST(PreferenceTest, GlobalSetGetShared) {
450 CefRefPtr<CefWaitableEvent> event =
451 CefWaitableEvent::CreateWaitableEvent(true, false);
452
453 CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
454 EXPECT_TRUE(context.get());
455
456 // Sharing storage.
457 CefRefPtr<CefRequestContext> context2 =
458 CefRequestContext::CreateContext(context, nullptr);
459 EXPECT_TRUE(context2.get());
460
461 // Sharing storage.
462 CefRefPtr<CefRequestContext> context3 =
463 CefRequestContext::CreateContext(context, new TestRequestContextHandler);
464 EXPECT_TRUE(context3.get());
465
466 // Unassociated context.
467 CefRequestContextSettings settings;
468 CefRefPtr<CefRequestContext> context4 = CefRequestContext::CreateContext(
469 settings, new TestRequestContextHandler(event));
470 EXPECT_TRUE(context4.get());
471 // Wait for the context to be fully initialized.
472 event->Wait();
473
474 // Set/get the values on the first context.
475 *PendingAction() = "Set/get the values on the first context";
476 ValidateSetGet(context, event);
477 event->Wait();
478
479 // Get the values from the 2nd and 3rd contexts. They should be the same.
480 *PendingAction() = "Get the values from the 2nd context.";
481 ValidateGet(context2, event);
482 event->Wait();
483 *PendingAction() = "Get the values from the 3rd context.";
484 ValidateGet(context3, event);
485 event->Wait();
486
487 // Get the values from the 4th context.
488 *PendingAction() = "Get the values from the 4th context.";
489 if (IsChromeRuntimeEnabled()) {
490 // With the Chrome runtime, prefs set via an incognito profile will become
491 // an overlay on top of the global (parent) profile. The incognito profile
492 // shares the prefs in this case because they were set via the global
493 // profile.
494 ValidateGet(context4, event);
495 } else {
496 // They should be at the default.
497 ValidateDefaults(context4, false, event);
498 }
499 event->Wait();
500
501 // Reset to the default values.
502 *PendingAction() = "Reset to the default values.";
503 ValidateDefaults(context, true, event);
504 event->Wait();
505 }
506
507 // Verify default preference values on a custom context.
TEST(PreferenceTest,CustomDefaults)508 TEST(PreferenceTest, CustomDefaults) {
509 CefRefPtr<CefWaitableEvent> event =
510 CefWaitableEvent::CreateWaitableEvent(true, false);
511
512 CefRequestContextSettings settings;
513 CefRefPtr<CefRequestContext> context = CefRequestContext::CreateContext(
514 settings, new TestRequestContextHandler(event));
515 EXPECT_TRUE(context.get());
516 // Wait for the context to be fully initialized.
517 event->Wait();
518
519 ValidateDefaults(context, false, event);
520 event->Wait();
521 }
522
523 // Verify setting/getting preference values on a custom context.
TEST(PreferenceTest,CustomSetGet)524 TEST(PreferenceTest, CustomSetGet) {
525 CefRefPtr<CefWaitableEvent> event =
526 CefWaitableEvent::CreateWaitableEvent(true, false);
527
528 CefRequestContextSettings settings;
529 CefRefPtr<CefRequestContext> context = CefRequestContext::CreateContext(
530 settings, new TestRequestContextHandler(event));
531 EXPECT_TRUE(context.get());
532 // Wait for the context to be fully initialized.
533 event->Wait();
534
535 ValidateSetGet(context, event);
536 event->Wait();
537
538 // Reset to the default values.
539 ValidateDefaults(context, true, event);
540 event->Wait();
541 }
542
543 // Verify setting/getting preference values on shared custom contexts.
TEST(PreferenceTest,CustomSetGetShared)544 TEST(PreferenceTest, CustomSetGetShared) {
545 CefRefPtr<CefWaitableEvent> event =
546 CefWaitableEvent::CreateWaitableEvent(true, false);
547
548 CefRequestContextSettings settings;
549 CefRefPtr<CefRequestContext> context = CefRequestContext::CreateContext(
550 settings, new TestRequestContextHandler(event));
551 EXPECT_TRUE(context.get());
552 // Wait for the context to be fully initialized.
553 event->Wait();
554
555 // Sharing storage.
556 CefRefPtr<CefRequestContext> context2 =
557 CefRequestContext::CreateContext(context, nullptr);
558 EXPECT_TRUE(context2.get());
559
560 // Sharing storage.
561 CefRefPtr<CefRequestContext> context3 =
562 CefRequestContext::CreateContext(context, new TestRequestContextHandler);
563 EXPECT_TRUE(context3.get());
564
565 // Unassociated context.
566 CefRefPtr<CefRequestContext> context4 = CefRequestContext::CreateContext(
567 settings, new TestRequestContextHandler(event));
568 EXPECT_TRUE(context4.get());
569 // Wait for the context to be fully initialized.
570 event->Wait();
571
572 // Set/get the values on the first context.
573 *PendingAction() = "Set/get the values on the first context";
574 ValidateSetGet(context, event);
575 event->Wait();
576
577 // Get the values from the 2nd and 3d contexts. They should be the same.
578 *PendingAction() = "Get the values from the 2nd context.";
579 ValidateGet(context2, event);
580 event->Wait();
581 *PendingAction() = "Get the values from the 3rd context.";
582 ValidateGet(context3, event);
583 event->Wait();
584
585 // Get the values from the 4th context. They should be at the default.
586 // This works with the Chrome runtime because the preference changes only
587 // exist in the other incognito profile's overlay.
588 *PendingAction() = "Get the values from the 4th context.";
589 ValidateDefaults(context4, false, event);
590 event->Wait();
591
592 // Reset to the default values.
593 *PendingAction() = "Reset to the default values.";
594 ValidateDefaults(context, true, event);
595 event->Wait();
596 }
597
598 // Entry point for creating preference browser test objects.
599 // Called from client_app_delegates.cc.
CreatePreferenceBrowserTests(client::ClientAppBrowser::DelegateSet & delegates)600 void CreatePreferenceBrowserTests(
601 client::ClientAppBrowser::DelegateSet& delegates) {
602 delegates.insert(new PreferenceBrowserTest);
603 }
604