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/strings/string16.h" 6#include "base/strings/utf_string_conversions.h" 7#include "content/browser/accessibility/browser_accessibility.h" 8#include "content/browser/accessibility/browser_accessibility_manager.h" 9#include "content/common/accessibility_messages.h" 10#include "content/common/accessibility_node_data.h" 11#include "testing/gtest/include/gtest/gtest.h" 12 13namespace content { 14namespace { 15 16// Subclass of BrowserAccessibility that counts the number of instances. 17class CountedBrowserAccessibility : public BrowserAccessibility { 18 public: 19 CountedBrowserAccessibility() { 20 global_obj_count_++; 21 native_ref_count_ = 1; 22 } 23 virtual ~CountedBrowserAccessibility() { 24 global_obj_count_--; 25 } 26 27 virtual void NativeAddReference() OVERRIDE { 28 native_ref_count_++; 29 } 30 31 virtual void NativeReleaseReference() OVERRIDE { 32 native_ref_count_--; 33 if (native_ref_count_ == 0) 34 delete this; 35 } 36 37 int native_ref_count_; 38 static int global_obj_count_; 39}; 40 41int CountedBrowserAccessibility::global_obj_count_ = 0; 42 43// Factory that creates a CountedBrowserAccessibility. 44class CountedBrowserAccessibilityFactory 45 : public BrowserAccessibilityFactory { 46 public: 47 virtual ~CountedBrowserAccessibilityFactory() {} 48 virtual BrowserAccessibility* Create() OVERRIDE { 49 return new CountedBrowserAccessibility(); 50 } 51}; 52 53class TestBrowserAccessibilityDelegate 54 : public BrowserAccessibilityDelegate { 55 public: 56 TestBrowserAccessibilityDelegate() 57 : got_fatal_error_(false) {} 58 59 virtual void SetAccessibilityFocus(int acc_obj_id) OVERRIDE {} 60 virtual void AccessibilityDoDefaultAction(int acc_obj_id) OVERRIDE {} 61 virtual void AccessibilityScrollToMakeVisible( 62 int acc_obj_id, gfx::Rect subfocus) OVERRIDE {} 63 virtual void AccessibilityScrollToPoint( 64 int acc_obj_id, gfx::Point point) OVERRIDE {} 65 virtual void AccessibilitySetTextSelection( 66 int acc_obj_id, int start_offset, int end_offset) OVERRIDE {} 67 virtual bool HasFocus() const OVERRIDE { 68 return false; 69 } 70 virtual gfx::Rect GetViewBounds() const OVERRIDE { 71 return gfx::Rect(); 72 } 73 virtual gfx::Point GetLastTouchEventLocation() const OVERRIDE { 74 return gfx::Point(); 75 } 76 virtual void FatalAccessibilityTreeError() OVERRIDE { 77 got_fatal_error_ = true; 78 } 79 80 bool got_fatal_error() const { return got_fatal_error_; } 81 void reset_got_fatal_error() { got_fatal_error_ = false; } 82 83private: 84 bool got_fatal_error_; 85}; 86 87} // anonymous namespace 88 89TEST(BrowserAccessibilityManagerTest, TestNoLeaks) { 90 // Create AccessibilityNodeData objects for a simple document tree, 91 // representing the accessibility information used to initialize 92 // BrowserAccessibilityManager. 93 AccessibilityNodeData button; 94 button.id = 2; 95 button.name = UTF8ToUTF16("Button"); 96 button.role = AccessibilityNodeData::ROLE_BUTTON; 97 button.state = 0; 98 99 AccessibilityNodeData checkbox; 100 checkbox.id = 3; 101 checkbox.name = UTF8ToUTF16("Checkbox"); 102 checkbox.role = AccessibilityNodeData::ROLE_CHECKBOX; 103 checkbox.state = 0; 104 105 AccessibilityNodeData root; 106 root.id = 1; 107 root.name = UTF8ToUTF16("Document"); 108 root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA; 109 root.state = 0; 110 root.child_ids.push_back(2); 111 root.child_ids.push_back(3); 112 113 // Construct a BrowserAccessibilityManager with this 114 // AccessibilityNodeData tree and a factory for an instance-counting 115 // BrowserAccessibility, and ensure that exactly 3 instances were 116 // created. Note that the manager takes ownership of the factory. 117 CountedBrowserAccessibility::global_obj_count_ = 0; 118 BrowserAccessibilityManager* manager = 119 BrowserAccessibilityManager::Create( 120 root, 121 NULL, 122 new CountedBrowserAccessibilityFactory()); 123 manager->UpdateNodesForTesting(button, checkbox); 124 125 ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_); 126 127 // Delete the manager and test that all 3 instances are deleted. 128 delete manager; 129 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); 130 131 // Construct a manager again, and this time save references to two of 132 // the three nodes in the tree. 133 manager = 134 BrowserAccessibilityManager::Create( 135 root, 136 NULL, 137 new CountedBrowserAccessibilityFactory()); 138 manager->UpdateNodesForTesting(button, checkbox); 139 ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_); 140 141 CountedBrowserAccessibility* root_accessible = 142 static_cast<CountedBrowserAccessibility*>(manager->GetRoot()); 143 root_accessible->NativeAddReference(); 144 CountedBrowserAccessibility* child1_accessible = 145 static_cast<CountedBrowserAccessibility*>(root_accessible->GetChild(1)); 146 child1_accessible->NativeAddReference(); 147 148 // Now delete the manager, and only one of the three nodes in the tree 149 // should be released. 150 delete manager; 151 ASSERT_EQ(2, CountedBrowserAccessibility::global_obj_count_); 152 153 // Release each of our references and make sure that each one results in 154 // the instance being deleted as its reference count hits zero. 155 root_accessible->NativeReleaseReference(); 156 ASSERT_EQ(1, CountedBrowserAccessibility::global_obj_count_); 157 child1_accessible->NativeReleaseReference(); 158 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); 159} 160 161TEST(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects) { 162 // Make sure that changes to a subtree reuse as many objects as possible. 163 164 // Tree 1: 165 // 166 // root 167 // child1 168 // child2 169 // child3 170 171 AccessibilityNodeData tree1_child1; 172 tree1_child1.id = 2; 173 tree1_child1.name = UTF8ToUTF16("Child1"); 174 tree1_child1.role = AccessibilityNodeData::ROLE_BUTTON; 175 tree1_child1.state = 0; 176 177 AccessibilityNodeData tree1_child2; 178 tree1_child2.id = 3; 179 tree1_child2.name = UTF8ToUTF16("Child2"); 180 tree1_child2.role = AccessibilityNodeData::ROLE_BUTTON; 181 tree1_child2.state = 0; 182 183 AccessibilityNodeData tree1_child3; 184 tree1_child3.id = 4; 185 tree1_child3.name = UTF8ToUTF16("Child3"); 186 tree1_child3.role = AccessibilityNodeData::ROLE_BUTTON; 187 tree1_child3.state = 0; 188 189 AccessibilityNodeData tree1_root; 190 tree1_root.id = 1; 191 tree1_root.name = UTF8ToUTF16("Document"); 192 tree1_root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA; 193 tree1_root.state = 0; 194 tree1_root.child_ids.push_back(2); 195 tree1_root.child_ids.push_back(3); 196 tree1_root.child_ids.push_back(4); 197 198 // Tree 2: 199 // 200 // root 201 // child0 <-- inserted 202 // child1 203 // child2 204 // <-- child3 deleted 205 206 AccessibilityNodeData tree2_child0; 207 tree2_child0.id = 5; 208 tree2_child0.name = UTF8ToUTF16("Child0"); 209 tree2_child0.role = AccessibilityNodeData::ROLE_BUTTON; 210 tree2_child0.state = 0; 211 212 AccessibilityNodeData tree2_root; 213 tree2_root.id = 1; 214 tree2_root.name = UTF8ToUTF16("DocumentChanged"); 215 tree2_root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA; 216 tree2_root.state = 0; 217 tree2_root.child_ids.push_back(5); 218 tree2_root.child_ids.push_back(2); 219 tree2_root.child_ids.push_back(3); 220 221 // Construct a BrowserAccessibilityManager with tree1. 222 CountedBrowserAccessibility::global_obj_count_ = 0; 223 BrowserAccessibilityManager* manager = 224 BrowserAccessibilityManager::Create( 225 tree1_root, 226 NULL, 227 new CountedBrowserAccessibilityFactory()); 228 manager->UpdateNodesForTesting(tree1_child1, tree1_child2, tree1_child3); 229 ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_); 230 231 // Save references to all of the objects. 232 CountedBrowserAccessibility* root_accessible = 233 static_cast<CountedBrowserAccessibility*>(manager->GetRoot()); 234 root_accessible->NativeAddReference(); 235 CountedBrowserAccessibility* child1_accessible = 236 static_cast<CountedBrowserAccessibility*>(root_accessible->GetChild(0)); 237 child1_accessible->NativeAddReference(); 238 CountedBrowserAccessibility* child2_accessible = 239 static_cast<CountedBrowserAccessibility*>(root_accessible->GetChild(1)); 240 child2_accessible->NativeAddReference(); 241 CountedBrowserAccessibility* child3_accessible = 242 static_cast<CountedBrowserAccessibility*>(root_accessible->GetChild(2)); 243 child3_accessible->NativeAddReference(); 244 245 // Check the index in parent. 246 EXPECT_EQ(0, child1_accessible->index_in_parent()); 247 EXPECT_EQ(1, child2_accessible->index_in_parent()); 248 EXPECT_EQ(2, child3_accessible->index_in_parent()); 249 250 // Process a notification containing the changed subtree. 251 std::vector<AccessibilityHostMsg_NotificationParams> params; 252 params.push_back(AccessibilityHostMsg_NotificationParams()); 253 AccessibilityHostMsg_NotificationParams* msg = ¶ms[0]; 254 msg->notification_type = AccessibilityNotificationChildrenChanged; 255 msg->nodes.push_back(tree2_root); 256 msg->nodes.push_back(tree2_child0); 257 msg->id = tree2_root.id; 258 manager->OnAccessibilityNotifications(params); 259 260 // There should be 5 objects now: the 4 from the new tree, plus the 261 // reference to child3 we kept. 262 EXPECT_EQ(5, CountedBrowserAccessibility::global_obj_count_); 263 264 // Check that our references to the root, child1, and child2 are still valid, 265 // but that the reference to child3 is now invalid. 266 EXPECT_TRUE(root_accessible->instance_active()); 267 EXPECT_TRUE(child1_accessible->instance_active()); 268 EXPECT_TRUE(child2_accessible->instance_active()); 269 EXPECT_FALSE(child3_accessible->instance_active()); 270 271 // Check that the index in parent has been updated. 272 EXPECT_EQ(1, child1_accessible->index_in_parent()); 273 EXPECT_EQ(2, child2_accessible->index_in_parent()); 274 275 // Release our references. The object count should only decrease by 1 276 // for child3. 277 root_accessible->NativeReleaseReference(); 278 child1_accessible->NativeReleaseReference(); 279 child2_accessible->NativeReleaseReference(); 280 child3_accessible->NativeReleaseReference(); 281 282 EXPECT_EQ(4, CountedBrowserAccessibility::global_obj_count_); 283 284 // Delete the manager and make sure all memory is cleaned up. 285 delete manager; 286 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); 287} 288 289TEST(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects2) { 290 // Similar to the test above, but with a more complicated tree. 291 292 // Tree 1: 293 // 294 // root 295 // container 296 // child1 297 // grandchild1 298 // child2 299 // grandchild2 300 // child3 301 // grandchild3 302 303 AccessibilityNodeData tree1_grandchild1; 304 tree1_grandchild1.id = 4; 305 tree1_grandchild1.name = UTF8ToUTF16("GrandChild1"); 306 tree1_grandchild1.role = AccessibilityNodeData::ROLE_BUTTON; 307 tree1_grandchild1.state = 0; 308 309 AccessibilityNodeData tree1_child1; 310 tree1_child1.id = 3; 311 tree1_child1.name = UTF8ToUTF16("Child1"); 312 tree1_child1.role = AccessibilityNodeData::ROLE_BUTTON; 313 tree1_child1.state = 0; 314 tree1_child1.child_ids.push_back(4); 315 316 AccessibilityNodeData tree1_grandchild2; 317 tree1_grandchild2.id = 6; 318 tree1_grandchild2.name = UTF8ToUTF16("GrandChild1"); 319 tree1_grandchild2.role = AccessibilityNodeData::ROLE_BUTTON; 320 tree1_grandchild2.state = 0; 321 322 AccessibilityNodeData tree1_child2; 323 tree1_child2.id = 5; 324 tree1_child2.name = UTF8ToUTF16("Child2"); 325 tree1_child2.role = AccessibilityNodeData::ROLE_BUTTON; 326 tree1_child2.state = 0; 327 tree1_child2.child_ids.push_back(6); 328 329 AccessibilityNodeData tree1_grandchild3; 330 tree1_grandchild3.id = 8; 331 tree1_grandchild3.name = UTF8ToUTF16("GrandChild3"); 332 tree1_grandchild3.role = AccessibilityNodeData::ROLE_BUTTON; 333 tree1_grandchild3.state = 0; 334 335 AccessibilityNodeData tree1_child3; 336 tree1_child3.id = 7; 337 tree1_child3.name = UTF8ToUTF16("Child3"); 338 tree1_child3.role = AccessibilityNodeData::ROLE_BUTTON; 339 tree1_child3.state = 0; 340 tree1_child3.child_ids.push_back(8); 341 342 AccessibilityNodeData tree1_container; 343 tree1_container.id = 2; 344 tree1_container.name = UTF8ToUTF16("Container"); 345 tree1_container.role = AccessibilityNodeData::ROLE_GROUP; 346 tree1_container.state = 0; 347 tree1_container.child_ids.push_back(3); 348 tree1_container.child_ids.push_back(5); 349 tree1_container.child_ids.push_back(7); 350 351 AccessibilityNodeData tree1_root; 352 tree1_root.id = 1; 353 tree1_root.name = UTF8ToUTF16("Document"); 354 tree1_root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA; 355 tree1_root.state = 0; 356 tree1_root.child_ids.push_back(2); 357 358 // Tree 2: 359 // 360 // root 361 // container 362 // child0 <-- inserted 363 // grandchild0 <-- 364 // child1 365 // grandchild1 366 // child2 367 // grandchild2 368 // <-- child3 (and grandchild3) deleted 369 370 AccessibilityNodeData tree2_grandchild0; 371 tree2_grandchild0.id = 9; 372 tree2_grandchild0.name = UTF8ToUTF16("GrandChild0"); 373 tree2_grandchild0.role = AccessibilityNodeData::ROLE_BUTTON; 374 tree2_grandchild0.state = 0; 375 376 AccessibilityNodeData tree2_child0; 377 tree2_child0.id = 10; 378 tree2_child0.name = UTF8ToUTF16("Child0"); 379 tree2_child0.role = AccessibilityNodeData::ROLE_BUTTON; 380 tree2_child0.state = 0; 381 tree2_child0.child_ids.push_back(9); 382 383 AccessibilityNodeData tree2_container; 384 tree2_container.id = 2; 385 tree2_container.name = UTF8ToUTF16("Container"); 386 tree2_container.role = AccessibilityNodeData::ROLE_GROUP; 387 tree2_container.state = 0; 388 tree2_container.child_ids.push_back(10); 389 tree2_container.child_ids.push_back(3); 390 tree2_container.child_ids.push_back(5); 391 392 // Construct a BrowserAccessibilityManager with tree1. 393 CountedBrowserAccessibility::global_obj_count_ = 0; 394 BrowserAccessibilityManager* manager = 395 BrowserAccessibilityManager::Create( 396 tree1_root, 397 NULL, 398 new CountedBrowserAccessibilityFactory()); 399 manager->UpdateNodesForTesting(tree1_container, 400 tree1_child1, tree1_grandchild1, 401 tree1_child2, tree1_grandchild2, 402 tree1_child3, tree1_grandchild3); 403 ASSERT_EQ(8, CountedBrowserAccessibility::global_obj_count_); 404 405 // Save references to some objects. 406 CountedBrowserAccessibility* root_accessible = 407 static_cast<CountedBrowserAccessibility*>(manager->GetRoot()); 408 root_accessible->NativeAddReference(); 409 CountedBrowserAccessibility* container_accessible = 410 static_cast<CountedBrowserAccessibility*>(root_accessible->GetChild(0)); 411 container_accessible->NativeAddReference(); 412 CountedBrowserAccessibility* child2_accessible = 413 static_cast<CountedBrowserAccessibility*>( 414 container_accessible->GetChild(1)); 415 child2_accessible->NativeAddReference(); 416 CountedBrowserAccessibility* child3_accessible = 417 static_cast<CountedBrowserAccessibility*>( 418 container_accessible->GetChild(2)); 419 child3_accessible->NativeAddReference(); 420 421 // Check the index in parent. 422 EXPECT_EQ(1, child2_accessible->index_in_parent()); 423 EXPECT_EQ(2, child3_accessible->index_in_parent()); 424 425 // Process a notification containing the changed subtree rooted at 426 // the container. 427 std::vector<AccessibilityHostMsg_NotificationParams> params; 428 params.push_back(AccessibilityHostMsg_NotificationParams()); 429 AccessibilityHostMsg_NotificationParams* msg = ¶ms[0]; 430 msg->notification_type = AccessibilityNotificationChildrenChanged; 431 msg->nodes.push_back(tree2_container); 432 msg->nodes.push_back(tree2_child0); 433 msg->nodes.push_back(tree2_grandchild0); 434 msg->id = tree2_container.id; 435 manager->OnAccessibilityNotifications(params); 436 437 // There should be 9 objects now: the 8 from the new tree, plus the 438 // reference to child3 we kept. 439 EXPECT_EQ(9, CountedBrowserAccessibility::global_obj_count_); 440 441 // Check that our references to the root and container and child2 are 442 // still valid, but that the reference to child3 is now invalid. 443 EXPECT_TRUE(root_accessible->instance_active()); 444 EXPECT_TRUE(container_accessible->instance_active()); 445 EXPECT_TRUE(child2_accessible->instance_active()); 446 EXPECT_FALSE(child3_accessible->instance_active()); 447 448 // Ensure that we retain the parent of the detached subtree. 449 EXPECT_EQ(root_accessible, container_accessible->parent()); 450 EXPECT_EQ(0, container_accessible->index_in_parent()); 451 452 // Check that the index in parent has been updated. 453 EXPECT_EQ(2, child2_accessible->index_in_parent()); 454 455 // Release our references. The object count should only decrease by 1 456 // for child3. 457 root_accessible->NativeReleaseReference(); 458 container_accessible->NativeReleaseReference(); 459 child2_accessible->NativeReleaseReference(); 460 child3_accessible->NativeReleaseReference(); 461 462 EXPECT_EQ(8, CountedBrowserAccessibility::global_obj_count_); 463 464 // Delete the manager and make sure all memory is cleaned up. 465 delete manager; 466 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); 467} 468 469TEST(BrowserAccessibilityManagerTest, TestMoveChildUp) { 470 // Tree 1: 471 // 472 // 1 473 // 2 474 // 3 475 // 4 476 477 AccessibilityNodeData tree1_4; 478 tree1_4.id = 4; 479 tree1_4.state = 0; 480 481 AccessibilityNodeData tree1_3; 482 tree1_3.id = 3; 483 tree1_3.state = 0; 484 tree1_3.child_ids.push_back(4); 485 486 AccessibilityNodeData tree1_2; 487 tree1_2.id = 2; 488 tree1_2.state = 0; 489 490 AccessibilityNodeData tree1_1; 491 tree1_1.id = 1; 492 tree1_1.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA; 493 tree1_1.state = 0; 494 tree1_1.child_ids.push_back(2); 495 tree1_1.child_ids.push_back(3); 496 497 // Tree 2: 498 // 499 // 1 500 // 4 <-- moves up a level and gains child 501 // 6 <-- new 502 // 5 <-- new 503 504 AccessibilityNodeData tree2_6; 505 tree2_6.id = 6; 506 tree2_6.state = 0; 507 508 AccessibilityNodeData tree2_5; 509 tree2_5.id = 5; 510 tree2_5.state = 0; 511 512 AccessibilityNodeData tree2_4; 513 tree2_4.id = 4; 514 tree2_4.state = 0; 515 tree2_4.child_ids.push_back(6); 516 517 AccessibilityNodeData tree2_1; 518 tree2_1.id = 1; 519 tree2_1.state = 0; 520 tree2_1.child_ids.push_back(4); 521 tree2_1.child_ids.push_back(5); 522 523 // Construct a BrowserAccessibilityManager with tree1. 524 CountedBrowserAccessibility::global_obj_count_ = 0; 525 BrowserAccessibilityManager* manager = 526 BrowserAccessibilityManager::Create( 527 tree1_1, 528 NULL, 529 new CountedBrowserAccessibilityFactory()); 530 manager->UpdateNodesForTesting(tree1_2, tree1_3, tree1_4); 531 ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_); 532 533 // Process a notification containing the changed subtree. 534 std::vector<AccessibilityHostMsg_NotificationParams> params; 535 params.push_back(AccessibilityHostMsg_NotificationParams()); 536 AccessibilityHostMsg_NotificationParams* msg = ¶ms[0]; 537 msg->notification_type = AccessibilityNotificationChildrenChanged; 538 msg->nodes.push_back(tree2_1); 539 msg->nodes.push_back(tree2_4); 540 msg->nodes.push_back(tree2_5); 541 msg->nodes.push_back(tree2_6); 542 msg->id = tree2_1.id; 543 manager->OnAccessibilityNotifications(params); 544 545 // There should be 4 objects now. 546 EXPECT_EQ(4, CountedBrowserAccessibility::global_obj_count_); 547 548 // Delete the manager and make sure all memory is cleaned up. 549 delete manager; 550 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); 551} 552 553TEST(BrowserAccessibilityManagerTest, TestFatalError) { 554 // Test that BrowserAccessibilityManager raises a fatal error 555 // (which will crash the renderer) if the same id is used in 556 // two places in the tree. 557 558 AccessibilityNodeData root; 559 root.id = 1; 560 root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA; 561 root.child_ids.push_back(2); 562 root.child_ids.push_back(2); 563 564 CountedBrowserAccessibilityFactory* factory = 565 new CountedBrowserAccessibilityFactory(); 566 scoped_ptr<TestBrowserAccessibilityDelegate> delegate( 567 new TestBrowserAccessibilityDelegate()); 568 scoped_ptr<BrowserAccessibilityManager> manager; 569 ASSERT_FALSE(delegate->got_fatal_error()); 570 manager.reset(BrowserAccessibilityManager::Create( 571 root, 572 delegate.get(), 573 factory)); 574 ASSERT_TRUE(delegate->got_fatal_error()); 575 576 AccessibilityNodeData root2; 577 root2.id = 1; 578 root2.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA; 579 root2.child_ids.push_back(2); 580 root2.child_ids.push_back(3); 581 582 AccessibilityNodeData child1; 583 child1.id = 2; 584 child1.child_ids.push_back(4); 585 child1.child_ids.push_back(5); 586 587 AccessibilityNodeData child2; 588 child2.id = 3; 589 child2.child_ids.push_back(6); 590 child2.child_ids.push_back(5); // Duplicate 591 592 delegate->reset_got_fatal_error(); 593 factory = new CountedBrowserAccessibilityFactory(); 594 manager.reset(BrowserAccessibilityManager::Create( 595 root2, 596 delegate.get(), 597 factory)); 598 ASSERT_FALSE(delegate->got_fatal_error()); 599 manager->UpdateNodesForTesting(child1, child2); 600 ASSERT_TRUE(delegate->got_fatal_error()); 601} 602 603} // namespace content 604