View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4.set;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  
21  import java.util.Iterator;
22  import java.util.NavigableSet;
23  import java.util.TreeSet;
24  
25  import org.apache.commons.collections4.BulkTest;
26  
27  /**
28   * Abstract test class for {@link NavigableSet} methods and contracts.
29   * <p>
30   * To use, subclass and override the {@link #makeObject()}
31   * method.  You may have to override other protected methods if your
32   * set is not modifiable, or if your set restricts what kinds of
33   * elements may be added; see {@link AbstractSetTest} for more details.
34   */
35  public abstract class AbstractNavigableSetTest<E> extends AbstractSortedSetTest<E> {
36  
37      public class TestNavigableSetSubSet extends AbstractNavigableSetTest<E> {
38  
39          static final int TYPE_SUBSET = 0;
40          static final int TYPE_TAILSET = 1;
41          static final int TYPE_HEADSET = 2;
42          private final int type;
43          private int lowBound;
44          private int highBound;
45  
46          private final E[] fullElements;
47  
48          private final E[] otherElements;
49  
50          private final boolean inclusive;
51          @SuppressWarnings("unchecked")
52          public TestNavigableSetSubSet(final int bound, final boolean head, final boolean inclusive) {
53              super("TestNavigableSetSubSet");
54              if (head) {
55                  this.type = TYPE_HEADSET;
56                  this.inclusive = inclusive;
57                  this.highBound = bound;
58  
59                  final int realBound = inclusive ? bound + 1 : bound;
60                  fullElements = (E[]) new Object[realBound];
61                  System.arraycopy(AbstractNavigableSetTest.this.getFullElements(), 0, fullElements, 0, realBound);
62                  otherElements = (E[]) new Object[bound - 1];
63                  System.arraycopy(//src src_pos dst dst_pos length
64                      AbstractNavigableSetTest.this.getOtherElements(), 0, otherElements, 0, bound - 1);
65              } else {
66                  type = TYPE_TAILSET;
67                  this.inclusive = inclusive;
68                  lowBound = bound;
69                  final Object[] allElements = AbstractNavigableSetTest.this.getFullElements();
70                  final int realBound = inclusive ? bound : bound + 1;
71                  fullElements = (E[]) new Object[allElements.length - realBound];
72                  System.arraycopy(allElements, realBound, fullElements, 0, allElements.length - realBound);
73                  otherElements = (E[]) new Object[allElements.length - bound - 1];
74                  System.arraycopy(//src src_pos dst dst_pos length
75                      AbstractNavigableSetTest.this.getOtherElements(), bound, otherElements, 0, allElements.length - bound - 1);
76              }
77  
78          } //type
79          @SuppressWarnings("unchecked")
80          public TestNavigableSetSubSet(final int loBound, final int hiBound, final boolean inclusive) {
81              super("TestNavigableSetSubSet");
82              this.type = TYPE_SUBSET;
83              this.lowBound = loBound;
84              this.highBound = hiBound;
85              this.inclusive = inclusive;
86  
87              final int fullLoBound = inclusive ? loBound : loBound + 1;
88              final int length = hiBound - loBound + 1 - (inclusive ? 0 : 2);
89              fullElements = (E[]) new Object[length];
90              System.arraycopy(AbstractNavigableSetTest.this.getFullElements(), fullLoBound, fullElements, 0, length);
91              final int otherLength = hiBound - loBound;
92              otherElements = (E[]) new Object[otherLength - 1];
93              System.arraycopy(//src src_pos dst dst_pos length
94                  AbstractNavigableSetTest.this.getOtherElements(), loBound, otherElements, 0, otherLength - 1);
95          }
96          @Override
97          public BulkTest bulkTestNavigableSetHeadSet() {
98              return null;  // prevent infinite recursion
99          }
100 
101         @Override
102         public BulkTest bulkTestNavigableSetSubSet() {
103             return null;  // prevent infinite recursion
104         }
105         @Override
106         public BulkTest bulkTestNavigableSetTailSet() {
107             return null;  // prevent infinite recursion
108         }
109 
110         @Override
111         public BulkTest bulkTestSortedSetHeadSet() {
112             return null;  // prevent infinite recursion
113         }
114 
115         @Override
116         public BulkTest bulkTestSortedSetSubSet() {
117             return null;  // prevent infinite recursion
118         }
119 
120         @Override
121         public BulkTest bulkTestSortedSetTailSet() {
122             return null;  // prevent infinite recursion
123         }
124 
125         @Override
126         public E[] getFullElements() {
127             return fullElements;
128         }
129 
130         @Override
131         public E[] getOtherElements() {
132             return otherElements;
133         }
134         private NavigableSet<E> getSubSet(final NavigableSet<E> set) {
135             final E[] elements = AbstractNavigableSetTest.this.getFullElements();
136             switch (type) {
137             case TYPE_SUBSET :
138                 return set.subSet(elements[lowBound], inclusive, elements[highBound], inclusive);
139             case TYPE_HEADSET :
140                 return set.headSet(elements[highBound], inclusive);
141             case TYPE_TAILSET :
142                 return set.tailSet(elements[lowBound], inclusive);
143             default :
144                 return null;
145             }
146         }
147         @Override
148         public boolean isAddSupported() {
149             return AbstractNavigableSetTest.this.isAddSupported();
150         }
151         @Override
152         public boolean isFailFastSupported() {
153             return AbstractNavigableSetTest.this.isFailFastSupported();
154         }
155         @Override
156         public boolean isNullSupported() {
157             return AbstractNavigableSetTest.this.isNullSupported();
158         }
159         @Override
160         public boolean isRemoveSupported() {
161             return AbstractNavigableSetTest.this.isRemoveSupported();
162         }
163 
164         @Override
165         public boolean isTestSerialization() {
166             return false;
167         }
168         @Override
169         public NavigableSet<E> makeFullCollection() {
170             return getSubSet(AbstractNavigableSetTest.this.makeFullCollection());
171         }
172         @Override
173         public NavigableSet<E> makeObject() {
174             return getSubSet(AbstractNavigableSetTest.this.makeObject());
175         }
176 
177     }
178 
179     /**
180      * JUnit constructor.
181      *
182      * @param name  name for test
183      */
184     public AbstractNavigableSetTest(final String name) {
185         super(name);
186     }
187 
188     /**
189      * Bulk test {@link NavigableSet#headSet(Object, boolean)}.
190      * This method runs through all of the tests in {@link AbstractNavigableSetTest}.
191      * After modification operations, {@link #verify()} is invoked to ensure
192      * that the set and the other collection views are still valid.
193      *
194      * @return a {@link AbstractNavigableSetTest} instance for testing a headset.
195      */
196     public BulkTest bulkTestNavigableSetHeadSet() {
197         final int length = getFullElements().length;
198 
199         final int loBound = length / 3;
200         final int hiBound = loBound * 2;
201         return new TestNavigableSetSubSet(hiBound, true, true);
202     }
203 
204     /**
205      * Bulk test {@link NavigableSet#subSet(Object, boolean, Object, boolean)}.
206      * This method runs through all of the tests in {@link AbstractNavigableSetTest}.
207      * After modification operations, {@link #verify()} is invoked to ensure
208      * that the set and the other collection views are still valid.
209      *
210      * @return a {@link AbstractNavigableSetTest} instance for testing a subset.
211      */
212     public BulkTest bulkTestNavigableSetSubSet() {
213         final int length = getFullElements().length;
214 
215         final int loBound = length / 3;
216         final int hiBound = loBound * 2;
217         return new TestNavigableSetSubSet(loBound, hiBound, false);
218     }
219 
220     /**
221      * Bulk test {@link NavigableSet#tailSet(Object, boolean)}.
222      * This method runs through all of the tests in {@link AbstractNavigableSetTest}.
223      * After modification operations, {@link #verify()} is invoked to ensure
224      * that the set and the other collection views are still valid.
225      *
226      * @return a {@link AbstractNavigableSetTest} instance for testing a tailset.
227      */
228     public BulkTest bulkTestNavigableSetTailSet() {
229         final int length = getFullElements().length;
230         final int loBound = length / 3;
231         return new TestNavigableSetSubSet(loBound, false, false);
232     }
233 
234     /**
235      * {@inheritDoc}
236      */
237     @Override
238     public NavigableSet<E> getCollection() {
239         return (NavigableSet<E>) super.getCollection();
240     }
241 
242     /**
243      * {@inheritDoc}
244      */
245     @Override
246     public NavigableSet<E> getConfirmed() {
247         return (NavigableSet<E>) super.getConfirmed();
248     }
249 
250     /**
251      * Override to return comparable objects.
252      */
253     @Override
254     @SuppressWarnings("unchecked")
255     public E[] getFullNonNullElements() {
256         final Object[] elements = new Object[30];
257 
258         for (int i = 0; i < 30; i++) {
259             elements[i] = Integer.valueOf(i + i + 1);
260         }
261         return (E[]) elements;
262     }
263 
264     /**
265      * Override to return comparable objects.
266      */
267     @Override
268     @SuppressWarnings("unchecked")
269     public E[] getOtherNonNullElements() {
270         final Object[] elements = new Object[30];
271         for (int i = 0; i < 30; i++) {
272             elements[i] = Integer.valueOf(i + i + 2);
273         }
274         return (E[]) elements;
275     }
276 
277     /**
278      * Returns an empty {@link TreeSet} for use in modification testing.
279      *
280      * @return a confirmed empty collection
281      */
282     @Override
283     public NavigableSet<E> makeConfirmedCollection() {
284         return new TreeSet<>();
285     }
286 
287     /**
288      * {@inheritDoc}
289      */
290     @Override
291     public NavigableSet<E> makeFullCollection() {
292         return (NavigableSet<E>) super.makeFullCollection();
293     }
294 
295     /**
296      * {@inheritDoc}
297      */
298     @Override
299     public abstract NavigableSet<E> makeObject();
300 
301     /**
302      * Verification extension, will check the order of elements,
303      * the sets should already be verified equal.
304      */
305     @Override
306     public void verify() {
307         super.verify();
308 
309         // Check that descending iterator returns elements in order and higher(), lower(),
310         // floor() and ceiling() are consistent
311         final Iterator<E> collIter = getCollection().descendingIterator();
312         final Iterator<E> confIter = getConfirmed().descendingIterator();
313         while (collIter.hasNext()) {
314             final E element = collIter.next();
315             final E confElement = confIter.next();
316             assertEquals(confElement, element, "Element appears to be out of order.");
317 
318             assertEquals(getConfirmed().higher(element),
319                     getCollection().higher(element), "Incorrect element returned by higher().");
320 
321             assertEquals(getConfirmed().lower(element),
322                     getCollection().lower(element), "Incorrect element returned by lower().");
323 
324             assertEquals(getConfirmed().floor(element),
325                     getCollection().floor(element), "Incorrect element returned by floor().");
326 
327             assertEquals(getConfirmed().ceiling(element),
328                     getCollection().ceiling(element), "Incorrect element returned by ceiling().");
329         }
330     }
331 
332 }