[bcl] Remove NET_4_0 defines from class libs
[mono.git] / mcs / class / System / Test / System.Collections.ObjectModel / ObservableCollectionTest.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2007 Novell, Inc. (http://www.novell.com)
21 // Copyright 2011 Xamarin Inc.
22 //
23 // Authors:
24 //      Chris Toshok (toshok@ximian.com)
25 //      Brian O'Keefe (zer0keefie@gmail.com)
26 //      Marek Safar (marek.safar@gmail.com)
27 //
28
29
30 using System.Collections.ObjectModel;
31 using System.Collections.Specialized;
32 using NUnit.Framework;
33 using System.ComponentModel;
34 using System.Collections.Generic;
35 using System;
36 using System.Collections;
37 using MonoTests.System.Collections.Specialized;
38
39 namespace MonoTests.System.Collections.ObjectModel {
40
41         [TestFixture]
42         public class ObservableCollectionTest
43         {
44                 [Test]
45                 public void Constructor ()
46                 {
47                         var list = new List<int> { 3 };
48                         var col = new ObservableCollection<int> (list);
49                         col.Add (5);
50                         Assert.AreEqual (1, list.Count, "#1");
51
52                         col = new ObservableCollection<int> ((IEnumerable<int>) list);
53                         col.Add (5);
54                         Assert.AreEqual (1, list.Count, "#2");
55                 }
56
57                 [Test]
58                 public void Constructor_Invalid ()
59                 {
60                         try {
61                                 new ObservableCollection<int> ((List<int>) null);
62                                 Assert.Fail ("#1");
63                         } catch (ArgumentNullException) {
64                         }
65
66                         try {
67                                 new ObservableCollection<int> ((IEnumerable<int>) null);
68                                 Assert.Fail ("#2");
69                         } catch (ArgumentNullException) {
70                         }
71                 }
72
73                 [Test]
74                 public void Insert()
75                 {
76                         bool reached = false;
77                         ObservableCollection<int> col = new ObservableCollection<int> ();
78                         col.CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
79                                 reached = true;
80                                 Assert.AreEqual (NotifyCollectionChangedAction.Add, e.Action, "INS_1");
81                                 Assert.AreEqual (0, e.NewStartingIndex, "INS_2");
82                                 Assert.AreEqual (-1, e.OldStartingIndex, "INS_3");
83                                 Assert.AreEqual (1, e.NewItems.Count, "INS_4");
84                                 Assert.AreEqual (5, (int)e.NewItems [0], "INS_5");
85                                 Assert.AreEqual (null, e.OldItems, "INS_6");
86                         };
87                         col.Insert (0, 5);
88                         Assert.IsTrue (reached, "INS_5");
89                 }
90
91                 [Test]
92                 public void RemoveAt()
93                 {
94                         bool reached = false;
95                         ObservableCollection<int> col = new ObservableCollection<int> ();
96                         col.Insert (0, 5);
97                         col.CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
98                                 reached = true;
99                                 Assert.AreEqual (NotifyCollectionChangedAction.Remove, e.Action, "REMAT_1");
100                                 Assert.AreEqual (-1, e.NewStartingIndex, "REMAT_2");
101                                 Assert.AreEqual (0, e.OldStartingIndex, "REMAT_3");
102                                 Assert.AreEqual (null, e.NewItems, "REMAT_4");
103                                 Assert.AreEqual (1, e.OldItems.Count, "REMAT_5");
104                                 Assert.AreEqual (5, (int)e.OldItems [0], "REMAT_6");
105                         };
106                         col.RemoveAt (0);
107                         Assert.IsTrue (reached, "REMAT_7");
108                 }
109
110                 [Test]
111                 public void Move()
112                 {
113                         bool reached = false;
114                         ObservableCollection<int> col = new ObservableCollection<int> ();
115                         col.Insert (0, 0);
116                         col.Insert (1, 1);
117                         col.Insert (2, 2);
118                         col.Insert (3, 3);
119                         col.CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
120                                 reached = true;
121                                 Assert.AreEqual (NotifyCollectionChangedAction.Move, e.Action, "MOVE_1");
122                                 Assert.AreEqual (3, e.NewStartingIndex, "MOVE_2");
123                                 Assert.AreEqual (1, e.OldStartingIndex, "MOVE_3");
124                                 Assert.AreEqual (1, e.NewItems.Count, "MOVE_4");
125                                 Assert.AreEqual (1, e.NewItems [0], "MOVE_5");
126                                 Assert.AreEqual (1, e.OldItems.Count, "MOVE_6");
127                                 Assert.AreEqual (1, e.OldItems [0], "MOVE_7");
128                         };
129                         col.Move (1, 3);
130                         Assert.IsTrue (reached, "MOVE_8");
131                 }
132
133                 [Test]
134                 public void Add()
135                 {
136                         ObservableCollection<char> collection = new ObservableCollection<char> ();
137                         bool propertyChanged = false;
138                         List<string> changedProps = new List<string> ();
139                         NotifyCollectionChangedEventArgs args = null;
140
141                         ((INotifyPropertyChanged)collection).PropertyChanged += delegate (object sender, PropertyChangedEventArgs e) {
142                                 propertyChanged = true;
143                                 changedProps.Add (e.PropertyName);
144                         };
145
146                         collection.CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
147                                 args = e;
148                         };
149
150                         collection.Add ('A');
151
152                         Assert.IsTrue (propertyChanged, "ADD_1");
153                         Assert.IsTrue (changedProps.Contains ("Count"), "ADD_2");
154                         Assert.IsTrue (changedProps.Contains ("Item[]"), "ADD_3");
155
156                         CollectionChangedEventValidators.ValidateAddOperation (args, new char [] { 'A' }, 0, "ADD_4");
157                 }
158
159                 [Test]
160                 public void Remove()
161                 {
162                         ObservableCollection<char> collection = new ObservableCollection<char> ();
163                         bool propertyChanged = false;
164                         List<string> changedProps = new List<string> ();
165                         NotifyCollectionChangedEventArgs args = null;
166
167                         collection.Add ('A');
168                         collection.Add ('B');
169                         collection.Add ('C');
170
171                         ((INotifyPropertyChanged)collection).PropertyChanged += delegate (object sender, PropertyChangedEventArgs e) {
172                                 propertyChanged = true;
173                                 changedProps.Add (e.PropertyName);
174                         };
175
176                         collection.CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
177                                 args = e;
178                         };
179
180                         collection.Remove ('B');
181
182                         Assert.IsTrue (propertyChanged, "REM_1");
183                         Assert.IsTrue (changedProps.Contains ("Count"), "REM_2");
184                         Assert.IsTrue (changedProps.Contains ("Item[]"), "REM_3");
185
186                         CollectionChangedEventValidators.ValidateRemoveOperation (args, new char [] { 'B' }, 1, "REM_4");
187                 }
188
189                 [Test]
190                 public void Set()
191                 {
192                         ObservableCollection<char> collection = new ObservableCollection<char> ();
193                         bool propertyChanged = false;
194                         List<string> changedProps = new List<string> ();
195                         NotifyCollectionChangedEventArgs args = null;
196
197                         collection.Add ('A');
198                         collection.Add ('B');
199                         collection.Add ('C');
200
201                         ((INotifyPropertyChanged)collection).PropertyChanged += delegate (object sender, PropertyChangedEventArgs e) {
202                                 propertyChanged = true;
203                                 changedProps.Add (e.PropertyName);
204                         };
205
206                         collection.CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
207                                 args = e;
208                         };
209
210                         collection [2] = 'I';
211
212                         Assert.IsTrue (propertyChanged, "SET_1");
213                         Assert.IsTrue (changedProps.Contains ("Item[]"), "SET_2");
214
215                         CollectionChangedEventValidators.ValidateReplaceOperation (args, new char [] { 'C' }, new char [] { 'I' }, 2, "SET_3");
216                 }
217
218                 [Test]
219                 public void Reentrant()
220                 {
221                         ObservableCollection<char> collection = new ObservableCollection<char> ();
222                         bool propertyChanged = false;
223                         List<string> changedProps = new List<string> ();
224                         NotifyCollectionChangedEventArgs args = null;
225
226                         collection.Add ('A');
227                         collection.Add ('B');
228                         collection.Add ('C');
229
230                         PropertyChangedEventHandler pceh = delegate (object sender, PropertyChangedEventArgs e) {
231                                 propertyChanged = true;
232                                 changedProps.Add (e.PropertyName);
233                         };
234
235                         // Adding a PropertyChanged event handler
236                         ((INotifyPropertyChanged)collection).PropertyChanged += pceh;
237
238                         collection.CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
239                                 args = e;
240                         };
241
242                         collection.CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
243                                 // This one will attempt to break reentrancy
244                                 try {
245                                         collection.Add ('X');
246                                         Assert.Fail ("Reentrancy should not be allowed.");
247                                 } catch (InvalidOperationException) {
248                                 }
249                         };
250
251                         collection [2] = 'I';
252
253                         Assert.IsTrue (propertyChanged, "REENT_1");
254                         Assert.IsTrue (changedProps.Contains ("Item[]"), "REENT_2");
255
256                         CollectionChangedEventValidators.ValidateReplaceOperation (args, new char [] { 'C' }, new char [] { 'I' }, 2, "REENT_3");
257
258                         // Removing the PropertyChanged event handler should work as well:
259                         ((INotifyPropertyChanged)collection).PropertyChanged -= pceh;
260                 }
261
262                 //Private test class for protected members of ObservableCollection
263                 private class ObservableCollectionTestHelper : ObservableCollection<char> {
264                         internal void DoubleEnterReentrant()
265                         {
266                                 IDisposable object1 = BlockReentrancy ();
267                                 IDisposable object2 = BlockReentrancy ();
268
269                                 Assert.AreSame (object1, object2);
270
271                                 //With double block, try the reentrant:
272                                 NotifyCollectionChangedEventArgs args = null;
273
274                                 CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
275                                         args = e;
276                                 };
277
278                                 // We need a second callback for reentrancy to matter
279                                 CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
280                                         // Doesn't need to do anything; just needs more than one callback registered.
281                                 };
282
283                                 // Try adding - this should cause reentrancy, and fail
284                                 try {
285                                         Add ('I');
286                                         Assert.Fail ("Reentrancy should not be allowed. -- #2");
287                                 } catch (InvalidOperationException) {
288                                 }
289                                 
290                                 // Release the first reentrant
291                                 object1.Dispose ();
292
293                                 // Try adding again - this should cause reentrancy, and fail again
294                                 try {
295                                         Add ('J');
296                                         Assert.Fail ("Reentrancy should not be allowed. -- #3");
297                                 } catch (InvalidOperationException) {
298                                 }
299
300                                 // Release the reentrant a second time
301                                 object1.Dispose ();
302
303                                 // This last add should work fine.
304                                 Add ('K');
305                                 CollectionChangedEventValidators.ValidateAddOperation (args, new char [] { 'K' }, 0, "REENTHELP_1");
306                         }
307                 }
308
309                 [Test]
310                 public void ReentrantReuseObject()
311                 {
312                         ObservableCollectionTestHelper helper = new ObservableCollectionTestHelper ();
313
314                         helper.DoubleEnterReentrant ();
315                 }
316
317                 [Test]
318                 public void Clear()
319                 {
320                         List<char> initial = new List<char> ();
321
322                         initial.Add ('A');
323                         initial.Add ('B');
324                         initial.Add ('C');
325
326                         ObservableCollection<char> collection = new ObservableCollection<char> (initial);
327                         bool propertyChanged = false;
328                         List<string> changedProps = new List<string> ();
329                         NotifyCollectionChangedEventArgs args = null;
330
331                         ((INotifyPropertyChanged)collection).PropertyChanged += delegate (object sender, PropertyChangedEventArgs e) {
332                                 propertyChanged = true;
333                                 changedProps.Add (e.PropertyName);
334                         };
335
336                         collection.CollectionChanged += delegate (object sender, NotifyCollectionChangedEventArgs e) {
337                                 args = e;
338                         };
339
340                         collection.Clear ();
341
342                         Assert.IsTrue (propertyChanged, "CLEAR_1");
343                         Assert.IsTrue (changedProps.Contains ("Count"), "CLEAR_2");
344                         Assert.IsTrue (changedProps.Contains ("Item[]"), "CLEAR_3");
345
346                         CollectionChangedEventValidators.ValidateResetOperation (args, "CLEAR_4");
347                 }
348         }
349 }
350