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.queue;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  import static org.junit.jupiter.api.Assertions.assertNull;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import java.io.IOException;
26  import java.io.Serializable;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.Collection;
30  import java.util.Iterator;
31  import java.util.NoSuchElementException;
32  import java.util.Queue;
33  
34  import org.apache.commons.collections4.collection.AbstractCollectionTest;
35  import org.junit.jupiter.api.Test;
36  
37  /**
38   * Abstract test class for {@link java.util.Queue} methods and contracts.
39   * <p>
40   * To use, simply extend this class, and implement
41   * the {@link #makeObject} method.
42   * <p>
43   * If your {@link Queue} fails one of these tests by design,
44   * you may still use this base set of cases.  Simply override the
45   * test case (method) your {@link Queue} fails or override one of the
46   * protected methods from AbstractCollectionTest.
47   */
48  public abstract class AbstractQueueTest<E> extends AbstractCollectionTest<E> {
49  
50      /**
51       * JUnit constructor.
52       *
53       * @param testName  the test class name
54       */
55      public AbstractQueueTest(final String testName) {
56          super(testName);
57      }
58  
59      /**
60       * Returns the {@link #collection} field cast to a {@link Queue}.
61       *
62       * @return the collection field as a Queue
63       */
64      @Override
65      public Queue<E> getCollection() {
66          return (Queue<E>) super.getCollection();
67      }
68  
69      /**
70       *  Returns true if the collections produced by
71       *  {@link #makeObject()} and {@link #makeFullCollection()}
72       *  support the <code>set operation.<p>
73       *  Default implementation returns true.  Override if your collection
74       *  class does not support set.
75       */
76      public boolean isSetSupported() {
77          return true;
78      }
79  
80      /**
81       * Returns an empty {@link ArrayList}.
82       */
83      @Override
84      public Collection<E> makeConfirmedCollection() {
85          return new ArrayList<>();
86      }
87  
88      /**
89       * Returns a full {@link ArrayList}.
90       */
91      @Override
92      public Collection<E> makeConfirmedFullCollection() {
93          return new ArrayList<>(Arrays.asList(getFullElements()));
94      }
95  
96      /**
97       * {@inheritDoc}
98       */
99      @Override
100     public Queue<E> makeFullCollection() {
101         // only works if queue supports optional "addAll(Collection)"
102         final Queue<E> queue = makeObject();
103         queue.addAll(Arrays.asList(getFullElements()));
104         return queue;
105     }
106 
107     /**
108      * Returns {@link #makeObject()}.
109      *
110      * @return an empty queue to be used for testing
111      */
112     @Override
113     public abstract Queue<E> makeObject();
114 
115     /**
116      * Compare the current serialized form of the Queue
117      * against the canonical version in SCM.
118      */
119     @Test
120     @SuppressWarnings("unchecked")
121     public void testEmptyQueueCompatibility() throws IOException, ClassNotFoundException {
122         /*
123          * Create canonical objects with this code
124         Queue queue = makeEmptyQueue();
125         if (!(queue instanceof Serializable)) return;
126 
127         writeExternalFormToDisk((Serializable) queue, getCanonicalEmptyCollectionName(queue));
128         */
129 
130         // test to make sure the canonical form has been preserved
131         final Queue<E> queue = makeObject();
132         if (queue instanceof Serializable && !skipSerializedCanonicalTests()
133                 && isTestSerialization()) {
134             final Queue<E> queue2 = (Queue<E>) readExternalFormFromDisk(getCanonicalEmptyCollectionName(queue));
135             assertEquals(0, queue2.size(), "Queue is empty");
136         }
137     }
138 
139     @Test
140     @SuppressWarnings("unchecked")
141     public void testEmptyQueueSerialization() throws IOException, ClassNotFoundException {
142         final Queue<E> queue = makeObject();
143         if (!(queue instanceof Serializable && isTestSerialization())) {
144             return;
145         }
146 
147         final byte[] object = writeExternalFormToBytes((Serializable) queue);
148         final Queue<E> queue2 = (Queue<E>) readExternalFormFromBytes(object);
149 
150         assertEquals(0, queue.size(), "Both queues are empty");
151         assertEquals(0, queue2.size(), "Both queues are empty");
152     }
153 
154     /**
155      * Compare the current serialized form of the Queue
156      * against the canonical version in SCM.
157      */
158     @Test
159     @SuppressWarnings("unchecked")
160     public void testFullQueueCompatibility() throws IOException, ClassNotFoundException {
161         /*
162          * Create canonical objects with this code
163         Queue queue = makeFullQueue();
164         if (!(queue instanceof Serializable)) return;
165 
166         writeExternalFormToDisk((Serializable) queue, getCanonicalFullCollectionName(queue));
167         */
168 
169         // test to make sure the canonical form has been preserved
170         final Queue<E> queue = makeFullCollection();
171         if (queue instanceof Serializable && !skipSerializedCanonicalTests() && isTestSerialization()) {
172             final Queue<E> queue2 = (Queue<E>) readExternalFormFromDisk(getCanonicalFullCollectionName(queue));
173             assertEquals(queue.size(), queue2.size(), "Queues are not the right size");
174         }
175     }
176 
177     @Test
178     @SuppressWarnings("unchecked")
179     public void testFullQueueSerialization() throws IOException, ClassNotFoundException {
180         final Queue<E> queue = makeFullCollection();
181         final int size = getFullElements().length;
182         if (!(queue instanceof Serializable && isTestSerialization())) {
183             return;
184         }
185 
186         final byte[] object = writeExternalFormToBytes((Serializable) queue);
187         final Queue<E> queue2 = (Queue<E>) readExternalFormFromBytes(object);
188 
189         assertEquals(size, queue.size(), "Both queues are same size");
190         assertEquals(size, queue2.size(), "Both queues are same size");
191     }
192 
193     /**
194      *  Tests {@link Queue#element()}.
195      */
196     @Test
197     public void testQueueElement() {
198         resetEmpty();
199 
200         assertThrows(NoSuchElementException.class, () -> getCollection().element(),
201                 "Queue.element should throw NoSuchElementException");
202 
203         resetFull();
204 
205         assertTrue(getConfirmed().contains(getCollection().element()));
206 
207         if (!isRemoveSupported()) {
208             return;
209         }
210 
211         final int max = getFullElements().length;
212         for (int i = 0; i < max; i++) {
213             final E element = getCollection().element();
214 
215             if (!isNullSupported()) {
216                 assertNotNull(element);
217             }
218 
219             assertTrue(getConfirmed().contains(element));
220 
221             getCollection().remove(element);
222             getConfirmed().remove(element);
223 
224             verify();
225         }
226 
227         assertThrows(NoSuchElementException.class, () -> getCollection().element(),
228                 "Queue.element should throw NoSuchElementException");
229     }
230 
231     /**
232      *  Tests {@link Queue#offer(Object)}.
233      */
234     @Test
235     public void testQueueOffer() {
236         if (!isAddSupported()) {
237             return;
238         }
239 
240         final E[] elements = getFullElements();
241         for (final E element : elements) {
242             resetEmpty();
243             final boolean r = getCollection().offer(element);
244             getConfirmed().add(element);
245             verify();
246             assertTrue(r, "Empty queue changed after add");
247             assertEquals(1, getCollection().size(), "Queue size is 1 after first add");
248         }
249 
250         resetEmpty();
251         int size = 0;
252         for (final E element : elements) {
253             final boolean r = getCollection().offer(element);
254             getConfirmed().add(element);
255             verify();
256             if (r) {
257                 size++;
258             }
259             assertEquals(size, getCollection().size(), "Queue size should grow after add");
260             assertTrue(getCollection().contains(element), "Queue should contain added element");
261         }
262     }
263 
264     /**
265      *  Tests {@link Queue#peek()}.
266      */
267     @Test
268     public void testQueuePeek() {
269         if (!isRemoveSupported()) {
270             return;
271         }
272 
273         resetEmpty();
274 
275         E element = getCollection().peek();
276         assertNull(element);
277 
278         resetFull();
279 
280         final int max = getFullElements().length;
281         for (int i = 0; i < max; i++) {
282             element = getCollection().peek();
283 
284             if (!isNullSupported()) {
285                 assertNotNull(element);
286             }
287 
288             assertTrue(getConfirmed().contains(element));
289 
290             getCollection().remove(element);
291             getConfirmed().remove(element);
292 
293             verify();
294         }
295 
296         element = getCollection().peek();
297         assertNull(element);
298     }
299 
300     /**
301      *  Tests {@link Queue#poll()}.
302      */
303     @Test
304     public void testQueuePoll() {
305         if (!isRemoveSupported()) {
306             return;
307         }
308 
309         resetEmpty();
310 
311         E element = getCollection().poll();
312         assertNull(element);
313 
314         resetFull();
315 
316         final int max = getFullElements().length;
317         for (int i = 0; i < max; i++) {
318             element = getCollection().poll();
319             final boolean success = getConfirmed().remove(element);
320             assertTrue(success, "poll should return correct element");
321             verify();
322         }
323 
324         element = getCollection().poll();
325         assertNull(element);
326     }
327 
328     /**
329      *  Tests {@link Queue#remove()}.
330      */
331     @Test
332     public void testQueueRemove() {
333         if (!isRemoveSupported()) {
334             return;
335         }
336 
337         resetEmpty();
338 
339         assertThrows(NoSuchElementException.class, () -> getCollection().remove(),
340                 "Queue.remove should throw NoSuchElementException");
341 
342         resetFull();
343 
344         final int max = getFullElements().length;
345         for (int i = 0; i < max; i++) {
346             final E element = getCollection().remove();
347             final boolean success = getConfirmed().remove(element);
348             assertTrue(success, "remove should return correct element");
349             verify();
350         }
351 
352         assertThrows(NoSuchElementException.class, () -> getCollection().element(),
353                 "Queue.remove should throw NoSuchElementException");
354     }
355 
356     /**
357      *  Verifies that the test queue implementation matches the confirmed queue
358      *  implementation.
359      */
360     @Override
361     public void verify() {
362         super.verify();
363         final Iterator<E> iterator1 = getCollection().iterator();
364         for (final E e : getConfirmed()) {
365             assertTrue(iterator1.hasNext());
366             final Object o1 = iterator1.next();
367             final Object o2 = e;
368             assertEquals(o1, o2);
369         }
370     }
371 
372 }