Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / mojo / services / public / cpp / view_manager / tests / view_unittest.cc
1 // Copyright 2014 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 "mojo/services/public/cpp/view_manager/view.h"
6
7 #include "base/logging.h"
8 #include "base/strings/stringprintf.h"
9 #include "mojo/services/public/cpp/view_manager/lib/view_private.h"
10 #include "mojo/services/public/cpp/view_manager/util.h"
11 #include "mojo/services/public/cpp/view_manager/view_observer.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace mojo {
15
16 // View ------------------------------------------------------------------------
17
18 typedef testing::Test ViewTest;
19
20 // Subclass with public ctor/dtor.
21 class TestView : public View {
22  public:
23   TestView() {
24     ViewPrivate(this).set_id(1);
25   }
26   ~TestView() {}
27
28  private:
29   DISALLOW_COPY_AND_ASSIGN(TestView);
30 };
31
32 TEST_F(ViewTest, AddChild) {
33   TestView v1;
34   TestView v11;
35   v1.AddChild(&v11);
36   EXPECT_EQ(1U, v1.children().size());
37 }
38
39 TEST_F(ViewTest, RemoveChild) {
40   TestView v1;
41   TestView v11;
42   v1.AddChild(&v11);
43   EXPECT_EQ(1U, v1.children().size());
44   v1.RemoveChild(&v11);
45   EXPECT_EQ(0U, v1.children().size());
46 }
47
48 TEST_F(ViewTest, Reparent) {
49   TestView v1;
50   TestView v2;
51   TestView v11;
52   v1.AddChild(&v11);
53   EXPECT_EQ(1U, v1.children().size());
54   v2.AddChild(&v11);
55   EXPECT_EQ(1U, v2.children().size());
56   EXPECT_EQ(0U, v1.children().size());
57 }
58
59 TEST_F(ViewTest, Contains) {
60   TestView v1;
61
62   // Direct descendant.
63   TestView v11;
64   v1.AddChild(&v11);
65   EXPECT_TRUE(v1.Contains(&v11));
66
67   // Indirect descendant.
68   TestView v111;
69   v11.AddChild(&v111);
70   EXPECT_TRUE(v1.Contains(&v111));
71 }
72
73 TEST_F(ViewTest, GetChildById) {
74   TestView v1;
75   ViewPrivate(&v1).set_id(1);
76   TestView v11;
77   ViewPrivate(&v11).set_id(11);
78   v1.AddChild(&v11);
79   TestView v111;
80   ViewPrivate(&v111).set_id(111);
81   v11.AddChild(&v111);
82
83   // Find direct & indirect descendents.
84   EXPECT_EQ(&v11, v1.GetChildById(v11.id()));
85   EXPECT_EQ(&v111, v1.GetChildById(v111.id()));
86 }
87
88 TEST_F(ViewTest, DrawnAndVisible) {
89   TestView v1;
90   EXPECT_TRUE(v1.visible());
91   EXPECT_FALSE(v1.IsDrawn());
92
93   ViewPrivate(&v1).set_drawn(true);
94
95   TestView v11;
96   v1.AddChild(&v11);
97   EXPECT_TRUE(v11.visible());
98   EXPECT_TRUE(v11.IsDrawn());
99
100   v1.RemoveChild(&v11);
101   EXPECT_TRUE(v11.visible());
102   EXPECT_FALSE(v11.IsDrawn());
103 }
104
105 // ViewObserver --------------------------------------------------------
106
107 typedef testing::Test ViewObserverTest;
108
109 bool TreeChangeParamsMatch(const ViewObserver::TreeChangeParams& lhs,
110                            const ViewObserver::TreeChangeParams& rhs) {
111   return lhs.target == rhs.target &&  lhs.old_parent == rhs.old_parent &&
112       lhs.new_parent == rhs.new_parent && lhs.receiver == rhs.receiver;
113 }
114
115 class TreeChangeObserver : public ViewObserver {
116  public:
117   explicit TreeChangeObserver(View* observee) : observee_(observee) {
118     observee_->AddObserver(this);
119   }
120   ~TreeChangeObserver() override { observee_->RemoveObserver(this); }
121
122   void Reset() {
123     received_params_.clear();
124   }
125
126   const std::vector<TreeChangeParams>& received_params() {
127     return received_params_;
128   }
129
130  private:
131   // Overridden from ViewObserver:
132   void OnTreeChanging(const TreeChangeParams& params) override {
133      received_params_.push_back(params);
134    }
135    void OnTreeChanged(const TreeChangeParams& params) override {
136     received_params_.push_back(params);
137   }
138
139   View* observee_;
140   std::vector<TreeChangeParams> received_params_;
141
142   DISALLOW_COPY_AND_ASSIGN(TreeChangeObserver);
143 };
144
145 // Adds/Removes v11 to v1.
146 TEST_F(ViewObserverTest, TreeChange_SimpleAddRemove) {
147   TestView v1;
148   TreeChangeObserver o1(&v1);
149   EXPECT_TRUE(o1.received_params().empty());
150
151   TestView v11;
152   TreeChangeObserver o11(&v11);
153   EXPECT_TRUE(o11.received_params().empty());
154
155   // Add.
156
157   v1.AddChild(&v11);
158
159   EXPECT_EQ(2U, o1.received_params().size());
160   ViewObserver::TreeChangeParams p1;
161   p1.target = &v11;
162   p1.receiver = &v1;
163   p1.old_parent = NULL;
164   p1.new_parent = &v1;
165   EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back()));
166
167   EXPECT_EQ(2U, o11.received_params().size());
168   ViewObserver::TreeChangeParams p11 = p1;
169   p11.receiver = &v11;
170   EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
171   EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back()));
172
173   o1.Reset();
174   o11.Reset();
175   EXPECT_TRUE(o1.received_params().empty());
176   EXPECT_TRUE(o11.received_params().empty());
177
178   // Remove.
179
180   v1.RemoveChild(&v11);
181
182   EXPECT_EQ(2U, o1.received_params().size());
183   p1.target = &v11;
184   p1.receiver = &v1;
185   p1.old_parent = &v1;
186   p1.new_parent = NULL;
187   EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front()));
188
189   EXPECT_EQ(2U, o11.received_params().size());
190   p11 = p1;
191   p11.receiver = &v11;
192   EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
193   EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back()));
194 }
195
196 // Creates these two trees:
197 // v1
198 //  +- v11
199 // v111
200 //  +- v1111
201 //  +- v1112
202 // Then adds/removes v111 from v11.
203 TEST_F(ViewObserverTest, TreeChange_NestedAddRemove) {
204   TestView v1, v11, v111, v1111, v1112;
205
206   // Root tree.
207   v1.AddChild(&v11);
208
209   // Tree to be attached.
210   v111.AddChild(&v1111);
211   v111.AddChild(&v1112);
212
213   TreeChangeObserver o1(&v1), o11(&v11), o111(&v111), o1111(&v1111),
214       o1112(&v1112);
215   ViewObserver::TreeChangeParams p1, p11, p111, p1111, p1112;
216
217   // Add.
218
219   v11.AddChild(&v111);
220
221   EXPECT_EQ(2U, o1.received_params().size());
222   p1.target = &v111;
223   p1.receiver = &v1;
224   p1.old_parent = NULL;
225   p1.new_parent = &v11;
226   EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back()));
227
228   EXPECT_EQ(2U, o11.received_params().size());
229   p11 = p1;
230   p11.receiver = &v11;
231   EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().back()));
232
233   EXPECT_EQ(2U, o111.received_params().size());
234   p111 = p11;
235   p111.receiver = &v111;
236   EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front()));
237   EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back()));
238
239   EXPECT_EQ(2U, o1111.received_params().size());
240   p1111 = p111;
241   p1111.receiver = &v1111;
242   EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front()));
243   EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back()));
244
245   EXPECT_EQ(2U, o1112.received_params().size());
246   p1112 = p111;
247   p1112.receiver = &v1112;
248   EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front()));
249   EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back()));
250
251   // Remove.
252   o1.Reset();
253   o11.Reset();
254   o111.Reset();
255   o1111.Reset();
256   o1112.Reset();
257   EXPECT_TRUE(o1.received_params().empty());
258   EXPECT_TRUE(o11.received_params().empty());
259   EXPECT_TRUE(o111.received_params().empty());
260   EXPECT_TRUE(o1111.received_params().empty());
261   EXPECT_TRUE(o1112.received_params().empty());
262
263   v11.RemoveChild(&v111);
264
265   EXPECT_EQ(2U, o1.received_params().size());
266   p1.target = &v111;
267   p1.receiver = &v1;
268   p1.old_parent = &v11;
269   p1.new_parent = NULL;
270   EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front()));
271
272   EXPECT_EQ(2U, o11.received_params().size());
273   p11 = p1;
274   p11.receiver = &v11;
275   EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
276
277   EXPECT_EQ(2U, o111.received_params().size());
278   p111 = p11;
279   p111.receiver = &v111;
280   EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front()));
281   EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back()));
282
283   EXPECT_EQ(2U, o1111.received_params().size());
284   p1111 = p111;
285   p1111.receiver = &v1111;
286   EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().front()));
287   EXPECT_TRUE(TreeChangeParamsMatch(p1111, o1111.received_params().back()));
288
289   EXPECT_EQ(2U, o1112.received_params().size());
290   p1112 = p111;
291   p1112.receiver = &v1112;
292   EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().front()));
293   EXPECT_TRUE(TreeChangeParamsMatch(p1112, o1112.received_params().back()));
294 }
295
296 TEST_F(ViewObserverTest, TreeChange_Reparent) {
297   TestView v1, v11, v12, v111;
298   v1.AddChild(&v11);
299   v1.AddChild(&v12);
300   v11.AddChild(&v111);
301
302   TreeChangeObserver o1(&v1), o11(&v11), o12(&v12), o111(&v111);
303
304   // Reparent.
305   v12.AddChild(&v111);
306
307   // v1 (root) should see both changing and changed notifications.
308   EXPECT_EQ(4U, o1.received_params().size());
309   ViewObserver::TreeChangeParams p1;
310   p1.target = &v111;
311   p1.receiver = &v1;
312   p1.old_parent = &v11;
313   p1.new_parent = &v12;
314   EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().front()));
315   EXPECT_TRUE(TreeChangeParamsMatch(p1, o1.received_params().back()));
316
317   // v11 should see changing notifications.
318   EXPECT_EQ(2U, o11.received_params().size());
319   ViewObserver::TreeChangeParams p11;
320   p11 = p1;
321   p11.receiver = &v11;
322   EXPECT_TRUE(TreeChangeParamsMatch(p11, o11.received_params().front()));
323
324   // v12 should see changed notifications.
325   EXPECT_EQ(2U, o12.received_params().size());
326   ViewObserver::TreeChangeParams p12;
327   p12 = p1;
328   p12.receiver = &v12;
329   EXPECT_TRUE(TreeChangeParamsMatch(p12, o12.received_params().back()));
330
331   // v111 should see both changing and changed notifications.
332   EXPECT_EQ(2U, o111.received_params().size());
333   ViewObserver::TreeChangeParams p111;
334   p111 = p1;
335   p111.receiver = &v111;
336   EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().front()));
337   EXPECT_TRUE(TreeChangeParamsMatch(p111, o111.received_params().back()));
338 }
339
340 namespace {
341
342 class OrderChangeObserver : public ViewObserver {
343  public:
344   struct Change {
345     View* view;
346     View* relative_view;
347     OrderDirection direction;
348   };
349   typedef std::vector<Change> Changes;
350
351   explicit OrderChangeObserver(View* observee) : observee_(observee) {
352     observee_->AddObserver(this);
353   }
354   ~OrderChangeObserver() override { observee_->RemoveObserver(this); }
355
356   Changes GetAndClearChanges() {
357     Changes changes;
358     changes_.swap(changes);
359     return changes;
360   }
361
362  private:
363   // Overridden from ViewObserver:
364   void OnViewReordering(View* view,
365                         View* relative_view,
366                         OrderDirection direction) override {
367     OnViewReordered(view, relative_view, direction);
368   }
369
370   void OnViewReordered(View* view,
371                        View* relative_view,
372                        OrderDirection direction) override {
373     Change change;
374     change.view = view;
375     change.relative_view = relative_view;
376     change.direction = direction;
377     changes_.push_back(change);
378   }
379
380   View* observee_;
381   Changes changes_;
382
383   DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver);
384 };
385
386 }  // namespace
387
388 TEST_F(ViewObserverTest, Order) {
389   TestView v1, v11, v12, v13;
390   v1.AddChild(&v11);
391   v1.AddChild(&v12);
392   v1.AddChild(&v13);
393
394   // Order: v11, v12, v13
395   EXPECT_EQ(3U, v1.children().size());
396   EXPECT_EQ(&v11, v1.children().front());
397   EXPECT_EQ(&v13, v1.children().back());
398
399   {
400     OrderChangeObserver observer(&v11);
401
402     // Move v11 to front.
403     // Resulting order: v12, v13, v11
404     v11.MoveToFront();
405     EXPECT_EQ(&v12, v1.children().front());
406     EXPECT_EQ(&v11, v1.children().back());
407
408     OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
409     ASSERT_EQ(2U, changes.size());
410     EXPECT_EQ(&v11, changes[0].view);
411     EXPECT_EQ(&v13, changes[0].relative_view);
412     EXPECT_EQ(ORDER_DIRECTION_ABOVE, changes[0].direction);
413
414     EXPECT_EQ(&v11, changes[1].view);
415     EXPECT_EQ(&v13, changes[1].relative_view);
416     EXPECT_EQ(ORDER_DIRECTION_ABOVE, changes[1].direction);
417   }
418
419   {
420     OrderChangeObserver observer(&v11);
421
422     // Move v11 to back.
423     // Resulting order: v11, v12, v13
424     v11.MoveToBack();
425     EXPECT_EQ(&v11, v1.children().front());
426     EXPECT_EQ(&v13, v1.children().back());
427
428     OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
429     ASSERT_EQ(2U, changes.size());
430     EXPECT_EQ(&v11, changes[0].view);
431     EXPECT_EQ(&v12, changes[0].relative_view);
432     EXPECT_EQ(ORDER_DIRECTION_BELOW, changes[0].direction);
433
434     EXPECT_EQ(&v11, changes[1].view);
435     EXPECT_EQ(&v12, changes[1].relative_view);
436     EXPECT_EQ(ORDER_DIRECTION_BELOW, changes[1].direction);
437   }
438
439   {
440     OrderChangeObserver observer(&v11);
441
442     // Move v11 above v12.
443     // Resulting order: v12. v11, v13
444     v11.Reorder(&v12, ORDER_DIRECTION_ABOVE);
445     EXPECT_EQ(&v12, v1.children().front());
446     EXPECT_EQ(&v13, v1.children().back());
447
448     OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
449     ASSERT_EQ(2U, changes.size());
450     EXPECT_EQ(&v11, changes[0].view);
451     EXPECT_EQ(&v12, changes[0].relative_view);
452     EXPECT_EQ(ORDER_DIRECTION_ABOVE, changes[0].direction);
453
454     EXPECT_EQ(&v11, changes[1].view);
455     EXPECT_EQ(&v12, changes[1].relative_view);
456     EXPECT_EQ(ORDER_DIRECTION_ABOVE, changes[1].direction);
457   }
458
459   {
460     OrderChangeObserver observer(&v11);
461
462     // Move v11 below v12.
463     // Resulting order: v11, v12, v13
464     v11.Reorder(&v12, ORDER_DIRECTION_BELOW);
465     EXPECT_EQ(&v11, v1.children().front());
466     EXPECT_EQ(&v13, v1.children().back());
467
468     OrderChangeObserver::Changes changes = observer.GetAndClearChanges();
469     ASSERT_EQ(2U, changes.size());
470     EXPECT_EQ(&v11, changes[0].view);
471     EXPECT_EQ(&v12, changes[0].relative_view);
472     EXPECT_EQ(ORDER_DIRECTION_BELOW, changes[0].direction);
473
474     EXPECT_EQ(&v11, changes[1].view);
475     EXPECT_EQ(&v12, changes[1].relative_view);
476     EXPECT_EQ(ORDER_DIRECTION_BELOW, changes[1].direction);
477   }
478 }
479
480 namespace {
481
482 typedef std::vector<std::string> Changes;
483
484 std::string ViewIdToString(Id id) {
485   return (id == 0) ? "null" :
486       base::StringPrintf("%d,%d", HiWord(id), LoWord(id));
487 }
488
489 std::string RectToString(const Rect& rect) {
490   return base::StringPrintf("%d,%d %dx%d",
491                             rect.x, rect.y, rect.width, rect.height);
492 }
493
494 class BoundsChangeObserver : public ViewObserver {
495  public:
496   explicit BoundsChangeObserver(View* view) : view_(view) {
497     view_->AddObserver(this);
498   }
499   ~BoundsChangeObserver() override { view_->RemoveObserver(this); }
500
501   Changes GetAndClearChanges() {
502     Changes changes;
503     changes.swap(changes_);
504     return changes;
505   }
506
507  private:
508   // Overridden from ViewObserver:
509   void OnViewBoundsChanging(View* view,
510                             const Rect& old_bounds,
511                             const Rect& new_bounds) override {
512     changes_.push_back(
513         base::StringPrintf(
514             "view=%s old_bounds=%s new_bounds=%s phase=changing",
515             ViewIdToString(view->id()).c_str(),
516             RectToString(old_bounds).c_str(),
517             RectToString(new_bounds).c_str()));
518   }
519   void OnViewBoundsChanged(View* view,
520                            const Rect& old_bounds,
521                            const Rect& new_bounds) override {
522     changes_.push_back(
523         base::StringPrintf(
524             "view=%s old_bounds=%s new_bounds=%s phase=changed",
525             ViewIdToString(view->id()).c_str(),
526             RectToString(old_bounds).c_str(),
527             RectToString(new_bounds).c_str()));
528   }
529
530   View* view_;
531   Changes changes_;
532
533   DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver);
534 };
535
536 }  // namespace
537
538 TEST_F(ViewObserverTest, SetBounds) {
539   TestView v1;
540   {
541     BoundsChangeObserver observer(&v1);
542     Rect rect;
543     rect.width = rect.height = 100;
544     v1.SetBounds(rect);
545
546     Changes changes = observer.GetAndClearChanges();
547     ASSERT_EQ(2U, changes.size());
548     EXPECT_EQ(
549         "view=0,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changing",
550         changes[0]);
551     EXPECT_EQ(
552         "view=0,1 old_bounds=0,0 0x0 new_bounds=0,0 100x100 phase=changed",
553         changes[1]);
554   }
555 }
556
557 namespace {
558
559 class VisibilityChangeObserver : public ViewObserver {
560  public:
561   explicit VisibilityChangeObserver(View* view) : view_(view) {
562     view_->AddObserver(this);
563   }
564   ~VisibilityChangeObserver() override { view_->RemoveObserver(this); }
565
566   Changes GetAndClearChanges() {
567     Changes changes;
568     changes.swap(changes_);
569     return changes;
570   }
571
572  private:
573   // Overridden from ViewObserver:
574   void OnViewVisibilityChanging(View* view) override {
575     changes_.push_back(
576         base::StringPrintf("view=%s phase=changing visibility=%s",
577                            ViewIdToString(view->id()).c_str(),
578                            view->visible() ? "true" : "false"));
579   }
580   void OnViewVisibilityChanged(View* view) override {
581     changes_.push_back(base::StringPrintf("view=%s phase=changed visibility=%s",
582                                           ViewIdToString(view->id()).c_str(),
583                                           view->visible() ? "true" : "false"));
584   }
585
586   View* view_;
587   Changes changes_;
588
589   DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver);
590 };
591
592 }  // namespace
593
594 TEST_F(ViewObserverTest, SetVisible) {
595   TestView v1;
596   EXPECT_TRUE(v1.visible());
597   {
598     // Change visibility from true to false and make sure we get notifications.
599     VisibilityChangeObserver observer(&v1);
600     v1.SetVisible(false);
601
602     Changes changes = observer.GetAndClearChanges();
603     ASSERT_EQ(2U, changes.size());
604     EXPECT_EQ("view=0,1 phase=changing visibility=true", changes[0]);
605     EXPECT_EQ("view=0,1 phase=changed visibility=false", changes[1]);
606   }
607   {
608     // Set visible to existing value and verify no notifications.
609     VisibilityChangeObserver observer(&v1);
610     v1.SetVisible(false);
611     EXPECT_TRUE(observer.GetAndClearChanges().empty());
612   }
613 }
614
615 namespace {
616
617 class PropertyChangeObserver : public ViewObserver {
618  public:
619   explicit PropertyChangeObserver(View* view) : view_(view) {
620     view_->AddObserver(this);
621   }
622   virtual ~PropertyChangeObserver() { view_->RemoveObserver(this); }
623
624   Changes GetAndClearChanges() {
625     Changes changes;
626     changes.swap(changes_);
627     return changes;
628   }
629
630  private:
631   // Overridden from ViewObserver:
632   void OnViewPropertyChanged(View* view,
633                              const std::string& name,
634                              const std::vector<uint8_t>* old_data,
635                              const std::vector<uint8_t>* new_data) override {
636     changes_.push_back(base::StringPrintf(
637         "view=%s property changed key=%s old_value=%s new_value=%s",
638         ViewIdToString(view->id()).c_str(),
639         name.c_str(),
640         VectorToString(old_data).c_str(),
641         VectorToString(new_data).c_str()));
642   }
643
644   std::string VectorToString(const std::vector<uint8_t>* data) {
645     if (!data)
646       return "NULL";
647     std::string s;
648     for (char c : *data)
649       s += c;
650     return s;
651   }
652
653   View* view_;
654   Changes changes_;
655
656   DISALLOW_COPY_AND_ASSIGN(PropertyChangeObserver);
657 };
658
659 }  // namespace
660
661 TEST_F(ViewObserverTest, SetProperty) {
662   TestView v1;
663   std::vector<uint8_t> one(1, '1');
664
665   {
666     // Change visibility from true to false and make sure we get notifications.
667     PropertyChangeObserver observer(&v1);
668     v1.SetProperty("one", &one);
669     Changes changes = observer.GetAndClearChanges();
670     ASSERT_EQ(1U, changes.size());
671     EXPECT_EQ("view=0,1 property changed key=one old_value=NULL new_value=1",
672               changes[0]);
673     EXPECT_EQ(1U, v1.properties().size());
674   }
675   {
676     // Set visible to existing value and verify no notifications.
677     PropertyChangeObserver observer(&v1);
678     v1.SetProperty("one", &one);
679     EXPECT_TRUE(observer.GetAndClearChanges().empty());
680     EXPECT_EQ(1U, v1.properties().size());
681   }
682   {
683     // Set the value to NULL to delete it.
684     // Change visibility from true to false and make sure we get notifications.
685     PropertyChangeObserver observer(&v1);
686     v1.SetProperty("one", NULL);
687     Changes changes = observer.GetAndClearChanges();
688     ASSERT_EQ(1U, changes.size());
689     EXPECT_EQ("view=0,1 property changed key=one old_value=1 new_value=NULL",
690               changes[0]);
691     EXPECT_EQ(0U, v1.properties().size());
692   }
693   {
694     // Setting a null property to null shouldn't update us.
695     PropertyChangeObserver observer(&v1);
696     v1.SetProperty("one", NULL);
697     EXPECT_TRUE(observer.GetAndClearChanges().empty());
698     EXPECT_EQ(0U, v1.properties().size());
699   }
700 }
701
702 }  // namespace mojo