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   * Tests {@link NavigableSet}.
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              if (head) {
54                  this.type = TYPE_HEADSET;
55                  this.inclusive = inclusive;
56                  this.highBound = bound;
57  
58                  final int realBound = inclusive ? bound + 1 : bound;
59                  fullElements = (E[]) new Object[realBound];
60                  System.arraycopy(AbstractNavigableSetTest.this.getFullElements(), 0, fullElements, 0, realBound);
61                  otherElements = (E[]) new Object[bound - 1];
62                  System.arraycopy(//src src_pos dst dst_pos length
63                      AbstractNavigableSetTest.this.getOtherElements(), 0, otherElements, 0, bound - 1);
64              } else {
65                  type = TYPE_TAILSET;
66                  this.inclusive = inclusive;
67                  lowBound = bound;
68                  final Object[] allElements = AbstractNavigableSetTest.this.getFullElements();
69                  final int realBound = inclusive ? bound : bound + 1;
70                  fullElements = (E[]) new Object[allElements.length - realBound];
71                  System.arraycopy(allElements, realBound, fullElements, 0, allElements.length - realBound);
72                  otherElements = (E[]) new Object[allElements.length - bound - 1];
73                  System.arraycopy(//src src_pos dst dst_pos length
74                      AbstractNavigableSetTest.this.getOtherElements(), bound, otherElements, 0, allElements.length - bound - 1);
75              }
76  
77          } //type
78          @SuppressWarnings("unchecked")
79          public TestNavigableSetSubSet(final int loBound, final int hiBound, final boolean inclusive) {
80              this.type = TYPE_SUBSET;
81              this.lowBound = loBound;
82              this.highBound = hiBound;
83              this.inclusive = inclusive;
84  
85              final int fullLoBound = inclusive ? loBound : loBound + 1;
86              final int length = hiBound - loBound + 1 - (inclusive ? 0 : 2);
87              fullElements = (E[]) new Object[length];
88              System.arraycopy(AbstractNavigableSetTest.this.getFullElements(), fullLoBound, fullElements, 0, length);
89              final int otherLength = hiBound - loBound;
90              otherElements = (E[]) new Object[otherLength - 1];
91              System.arraycopy(//src src_pos dst dst_pos length
92                  AbstractNavigableSetTest.this.getOtherElements(), loBound, otherElements, 0, otherLength - 1);
93          }
94          @Override
95          public BulkTest bulkTestNavigableSetHeadSet() {
96              return null;  // prevent infinite recursion
97          }
98  
99          @Override
100         public BulkTest bulkTestNavigableSetSubSet() {
101             return null;  // prevent infinite recursion
102         }
103         @Override
104         public BulkTest bulkTestNavigableSetTailSet() {
105             return null;  // prevent infinite recursion
106         }
107 
108         @Override
109         public BulkTest bulkTestSortedSetHeadSet() {
110             return null;  // prevent infinite recursion
111         }
112 
113         @Override
114         public BulkTest bulkTestSortedSetSubSet() {
115             return null;  // prevent infinite recursion
116         }
117 
118         @Override
119         public BulkTest bulkTestSortedSetTailSet() {
120             return null;  // prevent infinite recursion
121         }
122 
123         @Override
124         public E[] getFullElements() {
125             return fullElements;
126         }
127 
128         @Override
129         public E[] getOtherElements() {
130             return otherElements;
131         }
132 
133         private NavigableSet<E> getSubSet(final NavigableSet<E> set) {
134             final E[] elements = AbstractNavigableSetTest.this.getFullElements();
135             switch (type) {
136             case TYPE_SUBSET:
137                 return set.subSet(elements[lowBound], inclusive, elements[highBound], inclusive);
138             case TYPE_HEADSET:
139                 return set.headSet(elements[highBound], inclusive);
140             case TYPE_TAILSET:
141                 return set.tailSet(elements[lowBound], inclusive);
142             default:
143                 return null;
144             }
145         }
146         @Override
147         public boolean isAddSupported() {
148             return AbstractNavigableSetTest.this.isAddSupported();
149         }
150         @Override
151         public boolean isFailFastSupported() {
152             return AbstractNavigableSetTest.this.isFailFastSupported();
153         }
154         @Override
155         public boolean isNullSupported() {
156             return AbstractNavigableSetTest.this.isNullSupported();
157         }
158         @Override
159         public boolean isRemoveSupported() {
160             return AbstractNavigableSetTest.this.isRemoveSupported();
161         }
162 
163         @Override
164         public boolean isTestSerialization() {
165             return false;
166         }
167         @Override
168         public NavigableSet<E> makeFullCollection() {
169             return getSubSet(AbstractNavigableSetTest.this.makeFullCollection());
170         }
171         @Override
172         public NavigableSet<E> makeObject() {
173             return getSubSet(AbstractNavigableSetTest.this.makeObject());
174         }
175 
176     }
177 
178     /**
179      * Bulk test {@link NavigableSet#headSet(Object, boolean)}.
180      * This method runs through all of the tests in {@link AbstractNavigableSetTest}.
181      * After modification operations, {@link #verify()} is invoked to ensure
182      * that the set and the other collection views are still valid.
183      *
184      * @return a {@link AbstractNavigableSetTest} instance for testing a headset.
185      */
186     public BulkTest bulkTestNavigableSetHeadSet() {
187         final int length = getFullElements().length;
188 
189         final int loBound = length / 3;
190         final int hiBound = loBound * 2;
191         return new TestNavigableSetSubSet(hiBound, true, true);
192     }
193 
194     /**
195      * Bulk test {@link NavigableSet#subSet(Object, boolean, Object, boolean)}.
196      * This method runs through all of the tests in {@link AbstractNavigableSetTest}.
197      * After modification operations, {@link #verify()} is invoked to ensure
198      * that the set and the other collection views are still valid.
199      *
200      * @return a {@link AbstractNavigableSetTest} instance for testing a subset.
201      */
202     public BulkTest bulkTestNavigableSetSubSet() {
203         final int length = getFullElements().length;
204 
205         final int loBound = length / 3;
206         final int hiBound = loBound * 2;
207         return new TestNavigableSetSubSet(loBound, hiBound, false);
208     }
209 
210     /**
211      * Bulk test {@link NavigableSet#tailSet(Object, boolean)}.
212      * This method runs through all of the tests in {@link AbstractNavigableSetTest}.
213      * After modification operations, {@link #verify()} is invoked to ensure
214      * that the set and the other collection views are still valid.
215      *
216      * @return a {@link AbstractNavigableSetTest} instance for testing a tailset.
217      */
218     public BulkTest bulkTestNavigableSetTailSet() {
219         final int length = getFullElements().length;
220         final int loBound = length / 3;
221         return new TestNavigableSetSubSet(loBound, false, false);
222     }
223 
224     /**
225      * {@inheritDoc}
226      */
227     @Override
228     public NavigableSet<E> getCollection() {
229         return (NavigableSet<E>) super.getCollection();
230     }
231 
232     /**
233      * {@inheritDoc}
234      */
235     @Override
236     public NavigableSet<E> getConfirmed() {
237         return (NavigableSet<E>) super.getConfirmed();
238     }
239 
240     /**
241      * Override to return comparable objects.
242      */
243     @Override
244     @SuppressWarnings("unchecked")
245     public E[] getFullNonNullElements() {
246         final Object[] elements = new Object[30];
247 
248         for (int i = 0; i < 30; i++) {
249             elements[i] = Integer.valueOf(i + i + 1);
250         }
251         return (E[]) elements;
252     }
253 
254     /**
255      * Override to return comparable objects.
256      */
257     @Override
258     @SuppressWarnings("unchecked")
259     public E[] getOtherNonNullElements() {
260         final Object[] elements = new Object[30];
261         for (int i = 0; i < 30; i++) {
262             elements[i] = Integer.valueOf(i + i + 2);
263         }
264         return (E[]) elements;
265     }
266 
267     /**
268      * Returns an empty {@link TreeSet} for use in modification testing.
269      *
270      * @return a confirmed empty collection
271      */
272     @Override
273     public NavigableSet<E> makeConfirmedCollection() {
274         return new TreeSet<>();
275     }
276 
277     /**
278      * {@inheritDoc}
279      */
280     @Override
281     public NavigableSet<E> makeFullCollection() {
282         return (NavigableSet<E>) super.makeFullCollection();
283     }
284 
285     /**
286      * {@inheritDoc}
287      */
288     @Override
289     public abstract NavigableSet<E> makeObject();
290 
291     /**
292      * Verification extension, will check the order of elements,
293      * the sets should already be verified equal.
294      */
295     @Override
296     public void verify() {
297         super.verify();
298 
299         // Check that descending iterator returns elements in order and higher(), lower(),
300         // floor() and ceiling() are consistent
301         final Iterator<E> collIter = getCollection().descendingIterator();
302         final Iterator<E> confIter = getConfirmed().descendingIterator();
303         while (collIter.hasNext()) {
304             final E element = collIter.next();
305             final E confElement = confIter.next();
306             assertEquals(confElement, element, "Element appears to be out of order.");
307 
308             assertEquals(getConfirmed().higher(element),
309                     getCollection().higher(element), "Incorrect element returned by higher().");
310 
311             assertEquals(getConfirmed().lower(element),
312                     getCollection().lower(element), "Incorrect element returned by lower().");
313 
314             assertEquals(getConfirmed().floor(element),
315                     getCollection().floor(element), "Incorrect element returned by floor().");
316 
317             assertEquals(getConfirmed().ceiling(element),
318                     getCollection().ceiling(element), "Incorrect element returned by ceiling().");
319         }
320     }
321 
322 }