| Index: ui/views/view_unittest.cc
 | 
| diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
 | 
| index e1b6710554409fd3a4dce25fd321645b93530eff..05f015507ffbb55a2764684ebbae79304704363b 100644
 | 
| --- a/ui/views/view_unittest.cc
 | 
| +++ b/ui/views/view_unittest.cc
 | 
| @@ -3335,6 +3335,146 @@ TEST_F(ViewTest, ViewHierarchyChanged) {
 | 
|    EXPECT_EQ(v2.get(), v4->add_details().move_view);
 | 
|  }
 | 
|  
 | 
| +class WidgetObserverView : public View {
 | 
| + public:
 | 
| +  WidgetObserverView();
 | 
| +  ~WidgetObserverView() override;
 | 
| +
 | 
| +  void ResetTestState();
 | 
| +
 | 
| +  int added_to_widget_count() { return added_to_widget_count_; }
 | 
| +  int removed_from_widget_count() { return removed_from_widget_count_; }
 | 
| +
 | 
| + private:
 | 
| +  void AddedToWidget() override;
 | 
| +  void RemovedFromWidget() override;
 | 
| +
 | 
| +  int added_to_widget_count_ = 0;
 | 
| +  int removed_from_widget_count_ = 0;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(WidgetObserverView);
 | 
| +};
 | 
| +
 | 
| +WidgetObserverView::WidgetObserverView() {
 | 
| +  ResetTestState();
 | 
| +}
 | 
| +
 | 
| +WidgetObserverView::~WidgetObserverView() {}
 | 
| +
 | 
| +void WidgetObserverView::ResetTestState() {
 | 
| +  added_to_widget_count_ = 0;
 | 
| +  removed_from_widget_count_ = 0;
 | 
| +}
 | 
| +
 | 
| +void WidgetObserverView::AddedToWidget() {
 | 
| +  ++added_to_widget_count_;
 | 
| +}
 | 
| +
 | 
| +void WidgetObserverView::RemovedFromWidget() {
 | 
| +  ++removed_from_widget_count_;
 | 
| +}
 | 
| +
 | 
| +// Verifies that AddedToWidget and RemovedFromWidget are called for a view when
 | 
| +// it is added to hierarchy.
 | 
| +// The tree looks like this:
 | 
| +// widget
 | 
| +// +-- root
 | 
| +//
 | 
| +// then v1 is added to root:
 | 
| +//
 | 
| +//     v1
 | 
| +//     +-- v2
 | 
| +//
 | 
| +// finally v1 is removed from root.
 | 
| +TEST_F(ViewTest, AddedToRemovedFromWidget) {
 | 
| +  Widget widget;
 | 
| +  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
 | 
| +  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
 | 
| +  params.bounds = gfx::Rect(50, 50, 650, 650);
 | 
| +  widget.Init(params);
 | 
| +
 | 
| +  View* root = widget.GetRootView();
 | 
| +
 | 
| +  WidgetObserverView v1;
 | 
| +  WidgetObserverView v2;
 | 
| +  WidgetObserverView v3;
 | 
| +  v1.set_owned_by_client();
 | 
| +  v2.set_owned_by_client();
 | 
| +  v3.set_owned_by_client();
 | 
| +
 | 
| +  v1.AddChildView(&v2);
 | 
| +  EXPECT_EQ(0, v2.added_to_widget_count());
 | 
| +  EXPECT_EQ(0, v2.removed_from_widget_count());
 | 
| +
 | 
| +  root->AddChildView(&v1);
 | 
| +  EXPECT_EQ(1, v1.added_to_widget_count());
 | 
| +  EXPECT_EQ(0, v1.removed_from_widget_count());
 | 
| +  EXPECT_EQ(1, v2.added_to_widget_count());
 | 
| +  EXPECT_EQ(0, v2.removed_from_widget_count());
 | 
| +
 | 
| +  v1.ResetTestState();
 | 
| +  v2.ResetTestState();
 | 
| +
 | 
| +  v2.AddChildView(&v3);
 | 
| +  EXPECT_EQ(0, v1.added_to_widget_count());
 | 
| +  EXPECT_EQ(0, v1.removed_from_widget_count());
 | 
| +  EXPECT_EQ(0, v2.added_to_widget_count());
 | 
| +  EXPECT_EQ(0, v2.removed_from_widget_count());
 | 
| +
 | 
| +  v1.ResetTestState();
 | 
| +  v2.ResetTestState();
 | 
| +
 | 
| +  root->RemoveChildView(&v1);
 | 
| +  EXPECT_EQ(0, v1.added_to_widget_count());
 | 
| +  EXPECT_EQ(1, v1.removed_from_widget_count());
 | 
| +  EXPECT_EQ(0, v2.added_to_widget_count());
 | 
| +  EXPECT_EQ(1, v2.removed_from_widget_count());
 | 
| +
 | 
| +  v2.ResetTestState();
 | 
| +  v1.RemoveChildView(&v2);
 | 
| +  EXPECT_EQ(0, v2.removed_from_widget_count());
 | 
| +
 | 
| +  // Test move between parents in a single Widget.
 | 
| +  v2.RemoveChildView(&v3);
 | 
| +  v1.ResetTestState();
 | 
| +  v2.ResetTestState();
 | 
| +  v3.ResetTestState();
 | 
| +
 | 
| +  v1.AddChildView(&v2);
 | 
| +  root->AddChildView(&v1);
 | 
| +  root->AddChildView(&v3);
 | 
| +  EXPECT_EQ(1, v1.added_to_widget_count());
 | 
| +  EXPECT_EQ(1, v2.added_to_widget_count());
 | 
| +  EXPECT_EQ(1, v3.added_to_widget_count());
 | 
| +
 | 
| +  v3.AddChildView(&v1);
 | 
| +  EXPECT_EQ(1, v1.added_to_widget_count());
 | 
| +  EXPECT_EQ(0, v1.removed_from_widget_count());
 | 
| +  EXPECT_EQ(1, v2.added_to_widget_count());
 | 
| +  EXPECT_EQ(0, v2.removed_from_widget_count());
 | 
| +  EXPECT_EQ(1, v3.added_to_widget_count());
 | 
| +  EXPECT_EQ(0, v3.removed_from_widget_count());
 | 
| +
 | 
| +  // Test move between widgets.
 | 
| +  Widget second_widget;
 | 
| +  params.bounds = gfx::Rect(150, 150, 650, 650);
 | 
| +  second_widget.Init(params);
 | 
| +
 | 
| +  View* second_root = second_widget.GetRootView();
 | 
| +
 | 
| +  v1.ResetTestState();
 | 
| +  v2.ResetTestState();
 | 
| +  v3.ResetTestState();
 | 
| +
 | 
| +  second_root->AddChildView(&v1);
 | 
| +  EXPECT_EQ(1, v1.removed_from_widget_count());
 | 
| +  EXPECT_EQ(1, v1.added_to_widget_count());
 | 
| +  EXPECT_EQ(1, v2.added_to_widget_count());
 | 
| +  EXPECT_EQ(1, v2.removed_from_widget_count());
 | 
| +  EXPECT_EQ(0, v3.added_to_widget_count());
 | 
| +  EXPECT_EQ(0, v3.removed_from_widget_count());
 | 
| +}
 | 
| +
 | 
|  // Verifies if the child views added under the root are all deleted when calling
 | 
|  // RemoveAllChildViews.
 | 
|  // The tree looks like this:
 | 
| 
 |