View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.model;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.io.ObjectInputStream;
25  import java.io.ObjectOutputStream;
26  
27  import java.util.AbstractList;
28  import java.util.ArrayList;
29  import java.util.Iterator;
30  import java.util.List;
31  
32  import java.util.Set;
33  
34  import junit.framework.AssertionFailedError;
35  import junit.framework.Test;
36  import junit.framework.TestSuite;
37  
38  import org.apache.myfaces.trinidad.model.CollectionModel;
39  import org.apache.myfaces.trinidad.model.ModelUtils;
40  import org.apache.myfaces.trinidad.model.RowKeySetImpl;
41  import org.apache.shale.test.base.AbstractJsfTestCase;
42  
43  /**
44   * Test for the RowKeySetImpl class.
45   * 
46   * There is a hardcoded dependency between this test and the SortableModel implementation that 
47   * happens to be used by ModelUtils.toCollectionModel().
48   * 
49   */
50  public final class RowKeySetImplTest extends AbstractJsfTestCase
51  {
52    public RowKeySetImplTest(String testName)
53    {
54      super(testName);
55    }
56  
57    @Override
58    protected void setUp() throws Exception
59    {
60      super.setUp();
61    }
62  
63    @Override
64    protected void tearDown() throws Exception
65    {
66      super.tearDown();
67    }
68    public static Test suite()
69    {
70      return new TestSuite(RowKeySetImplTest.class);
71    }
72    
73    public void testInitialyEmpty()
74    {
75      RowKeySetImpl set = _createKeySet(false);
76      // make sure that set is empty:
77      _testAll(set, false);
78    }
79  
80    public void testInitialAddAll()
81    {
82      RowKeySetImpl set = _createKeySet(true);
83      // make sure that everything is added:
84      _testAll(set, true);
85    }
86  
87    public void testAddAll()
88    {
89      RowKeySetImpl set = _createKeySet(false);
90      _initModel(set);
91      set.addAll();
92      _testAll(set, true);
93    }
94  
95    public void testAddRemoveAllWithSimpleSet()
96    {
97      RowKeySetImpl set1 = _createKeySet(false);
98      RowKeySetImpl set2 = _createKeySet(false);
99  
100     Object k1 = _getKey(0);
101     Object k2 = _getKey(1);
102     Object k3 = _getKey(2);
103 
104     set1.add(k1);
105     set1.add(k2);
106     set2.add(k2);
107     set2.add(k3);
108 
109     set1.addAll(set2);
110     assertEquals("size", 3, set1.size());
111     assertEquals("size", 2, set2.size());
112 
113     assertTrue(set1.contains(k1));
114     assertTrue(set1.contains(k2));
115     assertTrue(set1.contains(k3));
116 
117     assertFalse(set2.contains(k1));
118     assertTrue(set2.contains(k2));
119     assertTrue(set2.contains(k3));
120 
121     set1.removeAll(set2);
122     assertEquals("size", 1, set1.size());
123     assertTrue(set1.contains(k1));
124     assertFalse(set1.contains(k2));
125     assertFalse(set1.contains(k3));
126   }
127 
128   public void testAddRemoveAllWithInfiniteSet()
129     throws CloneNotSupportedException
130   {
131     Object k1 = _getKey(0);
132     Object k2 = _getKey(1);
133     Object k3 = _getKey(2);
134 
135     List<Object> infinite = new AbstractList<Object>()
136     {
137       @Override
138       public int size()
139       {
140         return Integer.MAX_VALUE;
141       }
142 
143       @Override
144       public Object get(int index)
145       {
146         // code in javax.faces.model.ListDataModel always fetches index 0:
147         if (index == 0)
148           return Boolean.TRUE;
149 
150         throw new AssertionFailedError("must not fetch all data");
151       }
152     };
153 
154     RowKeySetImpl set1 = _createKeySet(true);
155     set1.setCollectionModel(ModelUtils.toCollectionModel(infinite));
156     set1.remove(k3);
157 
158     RowKeySetImpl set2 = _createKeySet(false);
159     set2.addAll(set1);
160     assertTrue(set2.contains(k1));
161     assertTrue(set2.contains(k2));
162     assertFalse(set2.contains(k3));
163 
164     // now test removeAll:
165     set2.add(k3);
166     set2.removeAll(set1);
167     assertFalse(set2.contains(k1));
168     assertFalse(set2.contains(k2));
169     assertTrue(set2.contains(k3));
170     assertEquals("size", 1, set2.size());
171 
172     // now test with both sets being infinite:
173     set1 = _createKeySet(true);
174     set1.setCollectionModel(ModelUtils.toCollectionModel(infinite));
175     set1.remove(k1);
176     set1.remove(k2);
177 
178     set2 = _createKeySet(true);
179     set2.setCollectionModel(ModelUtils.toCollectionModel(infinite));
180     set2.remove(k2);
181     set2.remove(k3);
182 
183     RowKeySetImpl set3 = set2.clone(); // save for later
184 
185     // test addAll:
186     set2.addAll(set1);
187     assertTrue(set2.contains(k1));
188     assertFalse(set2.contains(k2));
189     assertTrue(set2.contains(k3));
190 
191     // test removeAll:
192     set3.removeAll(set1);
193     assertTrue(set3.contains(k1));
194     assertFalse(set3.contains(k2));
195     assertFalse(set3.contains(k3));
196     assertEquals("size", 1, set3.size());
197   }
198 
199   public void testClear()
200   {
201     RowKeySetImpl set = _createKeySet(false);
202     _initModel(set);
203     set.clear();
204     _testAll(set, false);
205   }
206 
207   public void testAddRemove()
208   {
209     RowKeySetImpl set = _createKeySet(false);
210     int endOfTrueRange = _initModel(set);
211     boolean state = true;
212     for(int i=0; i<endOfTrueRange; i++)
213     {
214       // all of the items in this range should have been previously
215       // added:
216       set.getCollectionModel().setRowKey(_getKey(i));
217       assertTrue("item is selected", set.isContained());
218       if (state)
219         set.add();
220       else
221         set.remove();
222       // make sure that the selection changed correctly:
223       assertEquals("selection changed", state, set.isContained());
224       // we are going to alternate between selecting and unselecting:
225       state = !state;
226     }
227     for(int i=endOfTrueRange; i<_TEST_SIZE; i++)
228     {
229       // all of the items in this range should have been previously
230       // removed:
231       set.getCollectionModel().setRowKey(_getKey(i));
232       assertFalse("item not selected", set.isContained());
233       if (state)
234         set.add();
235       else
236         set.remove();
237       assertEquals("selection changed", state, set.isContained());
238       state = !state;
239     }
240   }
241 
242   private void _testRange(Set<Object> keySet, int start, int end,
243                           boolean expected, boolean newValue)
244   {
245     for(int i=start; i<end; i++)
246     {
247       Object rowKey = _getKey(i);
248       assertEquals("current state", expected, keySet.contains(rowKey));
249       if (newValue)
250       {
251         assertEquals("was set changed?", !expected, keySet.add(rowKey));
252       }
253       else
254       {
255         assertEquals("was set changed?", expected, keySet.remove(rowKey));
256       }
257       assertEquals("new state", newValue, keySet.contains(rowKey));
258     }
259   }
260 
261   public void testAddRemoveNoModel()
262   {
263     RowKeySetImpl keySet = _createKeySet(false);
264     keySet.setCollectionModel(null);
265 
266     int size = 10;
267     _testRange(keySet, 0, size, false, true);
268     _testRange(keySet, size/2, size, true, true);
269     _testRange(keySet, size/2, size, true, false);
270     _testRange(keySet, size, size*2, false, false);
271   }
272 
273   public void testInvert()
274   {
275     RowKeySetImpl set = _createKeySet(false);
276     int endOfTrueRange = _initModel(set);
277 
278     // the item at this index was previously selected:
279     int index = endOfTrueRange - 1;
280     // make sure that the item is unselected after inverting:
281     set.getCollectionModel().setRowKey(_getKey(index));
282     assertFalse("item is unselected", set.invert());
283     assertFalse("item is unselected", set.isContained());
284 
285     // the item at this index was previously unselected:
286     index = endOfTrueRange + 1;
287     // make sure that the item is selected after inverting:
288     set.getCollectionModel().setRowKey(_getKey(index));
289     assertTrue("item is selected", set.invert());
290     assertTrue("item is selected", set.isContained());
291   }
292 
293   public void testInvertAll()
294   {
295     RowKeySetImpl set = _createKeySet(false);
296     int endOfTrueRange = _initModel(set);
297     set.invertAll();
298     // after inverting, all the items in this range should be unselected:
299     _testAll(set, false, 0, endOfTrueRange);
300     // after inverting, all the items in this range should be selected:
301     _testAll(set, true, endOfTrueRange, _TEST_SIZE);
302   }
303 
304   public void testSerialization() throws IOException, ClassNotFoundException
305   {
306     final byte[] bytes;
307     final int endOfTrueRange;
308     {
309       RowKeySetImpl set = _createKeySet(false);
310       endOfTrueRange = _initModel(set);
311 
312       ByteArrayOutputStream bos = new ByteArrayOutputStream();
313       ObjectOutputStream out = new ObjectOutputStream(bos);
314       // no need to worry about testing to make sure the model isn't
315       // serialized, because the Entry class isn't Serializable.
316       out.writeObject(set);
317       out.close();
318 
319       bytes = bos.toByteArray();
320       // test to make sure that the serialized size is reasonable:
321      assertTrue(bytes.length <= 200);
322      assertTrue(bytes.length >= 80);
323     }
324 
325     ObjectInputStream in =
326       new ObjectInputStream(new ByteArrayInputStream(bytes));
327     RowKeySetImpl set = (RowKeySetImpl)in.readObject();
328     assertNull("transient model", set.getCollectionModel());
329     set.setCollectionModel(_MODEL);
330     in.close();
331 
332     _testAll(set, true, 0, endOfTrueRange);
333     _testAll(set, false, endOfTrueRange, _TEST_SIZE);
334   }
335 
336   public void testGetRowKeyIterator()
337   {
338     RowKeySetImpl set = _createKeySet(false);
339     int endOfTrueRange = _initModel(set);
340     Iterator<Object> selections = set.iterator();
341     _testSelectionIterator(set.getCollectionModel(), selections,
342                            endOfTrueRange, 0, endOfTrueRange);
343   }
344 
345   public void testInvertAllRowKeyIterator()
346   {
347     RowKeySetImpl set = _createKeySet(false);
348     int endOfTrueRange = _initModel(set);
349     set.invertAll();
350     Iterator<Object> selections = set.iterator();
351     _testSelectionIterator(set.getCollectionModel(), selections,
352                            _TEST_SIZE - endOfTrueRange,
353                            endOfTrueRange, _TEST_SIZE);
354   }
355 
356   public void testClone() throws CloneNotSupportedException
357   {
358     RowKeySetImpl set = _createKeySet(false);
359     int endOfTrueRange = _initModel(set);
360 
361     RowKeySetImpl clone = set.clone();
362     _testAll(clone, true, 0, endOfTrueRange);
363     _testAll(clone, false, endOfTrueRange, _TEST_SIZE);
364 
365     // modify the original. no change should be observed on the clone:
366     CollectionModel model = set.getCollectionModel();
367     model.setRowIndex(0);
368     set.remove();
369     assertFalse(set.isContained());
370     assertTrue(clone.isContained());
371 
372     // modify the clone. no change should be observed on the original:
373     model.setRowIndex(endOfTrueRange);
374     clone.add();
375     assertFalse(set.isContained());
376     assertTrue(clone.isContained());
377   }
378 
379   private void _testSelectionIterator(CollectionModel table,
380                                       Iterator<Object> selections, int size,
381                                       int rangeStart, int rangeEnd)
382   {
383     List<Object> selectedList = new ArrayList<Object>(size);
384     for(;selections.hasNext();)
385     {
386       selectedList.add(selections.next());
387     }
388 
389     int sz = selectedList.size();
390     // make sure that we have the correct number of selected items:
391     assertEquals("number of selected items", size, sz);
392 
393     for(int i=0; i<sz; i++)
394     {
395       Object rowKey = selectedList.get(i);
396       table.setRowKey(rowKey);
397       Entry val = (Entry) table.getRowData();
398 
399       // make sure this item was in the selected range:
400       assertTrue("item is in selected range", val.index < rangeEnd);
401       assertTrue("item is in selected range", val.index >= rangeStart);
402 
403       // make sure we haven't seen this value before:
404       assertFalse("no repeats", val.used);
405       // mark that this value was seen:
406       val.used = true;
407     }
408   }
409 
410 
411   private static CollectionModel _createCollectionModel(int testSize)
412   {
413     List<Object> lst = new ArrayList<Object>(testSize);
414     for(int i=0; i < testSize; i++)
415     {
416       lst.add(new Entry(i));
417     }
418     return ModelUtils.toCollectionModel(lst);
419   }
420 
421   private RowKeySetImpl _createKeySet(boolean defState)
422   {
423     RowKeySetImpl set = new RowKeySetImpl(defState);
424     set.setCollectionModel(_MODEL);
425     return set;
426   }
427 
428   // this class is not Serializable, so that if the model is
429   // accidentally serialized, then we will catch that error here:
430   private static final class Entry
431   {
432     public final int index;
433     public boolean used = false;
434     public Entry(int index)
435     {
436       this.index = index;
437     }
438   }
439 
440   // modify the selection so that the first half are selected, and the
441   // remaining half are not:
442   private int _initModel(RowKeySetImpl set)
443   {
444     int endOfTrueRange = _TEST_SIZE / 2;
445     for(int i=0; i<endOfTrueRange; i++)
446     {
447       set.getCollectionModel().setRowKey(_getKey(i));
448       set.add();
449     }
450     for(int i=endOfTrueRange; i<_TEST_SIZE; i++)
451     {
452       set.getCollectionModel().setRowKey(_getKey(i));
453       set.remove();
454     }
455     return endOfTrueRange;
456   }
457 
458   private void _testAll(RowKeySetImpl set, boolean expected)
459   {
460     _testAll(set, expected, 0, _TEST_SIZE);
461   }
462 
463   private void _testAll(RowKeySetImpl set, boolean expected,
464                         int start, int end)
465   {
466     for(int i=start; i<end; i++)
467     {
468       set.getCollectionModel().setRowKey(_getKey(i));
469       boolean isSet = set.isContained();
470       assertEquals("is item selected?", expected, isSet);
471     }
472   }
473 
474   private static Object _getKey(int index)
475   {
476     return index;
477   }
478 
479 //  private static int _getIndex(String key)
480 //  {
481 //    return Integer.parseInt(key);
482 //  }
483 
484   private static final int _TEST_SIZE = 11;
485   private static final CollectionModel _MODEL = _createCollectionModel(_TEST_SIZE);
486 }