4 Copyright (c) 2018, Mungo Carstairs
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
10 * Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above copyright notice,
14 this list of conditions and the following disclaimer in the documentation
15 and/or other materials provided with the distribution.
17 * Neither the name of the copyright holder nor the names of its
18 contributors may be used to endorse or promote products derived from
19 this software without specific prior written permission.
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 package intervalstore.nonc;
34 import static org.testng.Assert.assertEquals;
35 import static org.testng.Assert.assertFalse;
36 import static org.testng.Assert.assertSame;
37 import static org.testng.Assert.assertTrue;
39 import java.util.ArrayList;
40 import java.util.List;
42 import org.testng.annotations.Test;
44 public class IntervalStoreTest
46 @Test(groups = "Functional")
47 public void testFindOverlaps_nonNested()
49 IntervalStore<SimpleFeature> store = new IntervalStore<>();
50 SimpleFeature sf1 = add(store, 10, 20);
51 // same range different description
52 SimpleFeature sf2 = new SimpleFeature(10, 20, "desc");
54 SimpleFeature sf3 = add(store, 15, 25);
55 SimpleFeature sf4 = add(store, 20, 35);
57 assertEquals(store.size(), 4);
58 List<SimpleFeature> overlaps = store.findOverlaps(1, 9);
59 assertTrue(overlaps.isEmpty());
61 overlaps = store.findOverlaps(8, 10);
62 assertEquals(overlaps.size(), 2);
63 assertTrue(overlaps.contains(sf1));
64 assertTrue(overlaps.contains(sf2));
66 overlaps = store.findOverlaps(12, 16);
67 assertEquals(overlaps.size(), 3);
68 assertTrue(overlaps.contains(sf1));
69 assertTrue(overlaps.contains(sf2));
70 assertTrue(overlaps.contains(sf3));
72 overlaps = store.findOverlaps(33, 33);
73 assertEquals(overlaps.size(), 1);
74 assertTrue(overlaps.contains(sf4));
77 * ensure edge cases are covered
79 overlaps = store.findOverlaps(35, 40);
80 assertEquals(overlaps.size(), 1);
81 assertTrue(overlaps.contains(sf4));
82 assertTrue(store.findOverlaps(36, 100).isEmpty());
83 assertTrue(store.findOverlaps(1, 9).isEmpty());
86 @Test(groups = "Functional")
87 public void testFindOverlaps_nested()
89 IntervalStore<SimpleFeature> store = new IntervalStore<>();
90 SimpleFeature sf1 = add(store, 10, 50);
91 SimpleFeature sf2 = add(store, 10, 40);
92 SimpleFeature sf3 = add(store, 20, 30);
93 // feature at same location but different description
94 SimpleFeature sf4 = new SimpleFeature(20, 30, "different desc");
96 SimpleFeature sf5 = add(store, 35, 36);
98 List<SimpleFeature> overlaps = store.findOverlaps(1, 9);
99 assertTrue(overlaps.isEmpty());
101 overlaps = store.findOverlaps(10, 15);
102 assertEquals(overlaps.size(), 2);
103 assertTrue(overlaps.contains(sf1));
104 assertTrue(overlaps.contains(sf2));
106 overlaps = store.findOverlaps(45, 60);
107 assertEquals(overlaps.size(), 1);
108 assertTrue(overlaps.contains(sf1));
110 overlaps = store.findOverlaps(32, 38);
111 assertEquals(overlaps.size(), 3);
112 assertTrue(overlaps.contains(sf1));
113 assertTrue(overlaps.contains(sf2));
114 assertTrue(overlaps.contains(sf5));
116 overlaps = store.findOverlaps(15, 25);
117 assertEquals(overlaps.size(), 4);
118 assertTrue(overlaps.contains(sf1));
119 assertTrue(overlaps.contains(sf2));
120 assertTrue(overlaps.contains(sf3));
121 assertTrue(overlaps.contains(sf4));
124 @Test(groups = "Functional")
125 public void testFindOverlaps_mixed()
127 IntervalStore<SimpleFeature> store = new IntervalStore<>();
128 SimpleFeature sf1 = add(store, 10, 50);
129 SimpleFeature sf2 = add(store, 1, 15);
130 SimpleFeature sf3 = add(store, 20, 30);
131 SimpleFeature sf4 = add(store, 40, 100);
132 SimpleFeature sf5 = add(store, 60, 100);
133 SimpleFeature sf6 = add(store, 70, 70);
135 List<SimpleFeature> overlaps = store.findOverlaps(200, 200);
136 assertTrue(overlaps.isEmpty());
138 overlaps = store.findOverlaps(1, 9);
139 assertEquals(overlaps.size(), 1);
140 assertTrue(overlaps.contains(sf2));
142 overlaps = store.findOverlaps(5, 18);
143 assertEquals(overlaps.size(), 2);
144 assertTrue(overlaps.contains(sf1));
145 assertTrue(overlaps.contains(sf2));
147 overlaps = store.findOverlaps(30, 40);
148 assertEquals(overlaps.size(), 3);
149 assertTrue(overlaps.contains(sf1));
150 assertTrue(overlaps.contains(sf3));
151 assertTrue(overlaps.contains(sf4));
153 overlaps = store.findOverlaps(80, 90);
154 assertEquals(overlaps.size(), 2);
155 assertTrue(overlaps.contains(sf4));
156 assertTrue(overlaps.contains(sf5));
158 overlaps = store.findOverlaps(68, 70);
159 assertEquals(overlaps.size(), 3);
160 assertTrue(overlaps.contains(sf4));
161 assertTrue(overlaps.contains(sf5));
162 assertTrue(overlaps.contains(sf6));
166 * Helper method to add a feature with type "desc"
173 SimpleFeature add(IntervalStore<SimpleFeature> store, int from,
176 SimpleFeature sf1 = new SimpleFeature(from, to, "desc");
181 @Test(groups = "Functional")
182 public void testRemove()
184 IntervalStore<SimpleFeature> store = new IntervalStore<>();
185 SimpleFeature sf1 = add(store, 10, 20);
186 assertTrue(store.contains(sf1));
190 store.remove("what is this?");
191 } catch (ClassCastException e)
195 assertFalse(store.remove(null));
200 assertTrue(store.remove(sf1));
201 assertTrue(store.isEmpty());
203 SimpleFeature sf2 = add(store, 0, 0);
204 SimpleFeature sf2a = add(store, 30, 40);
205 assertTrue(store.contains(sf2));
206 assertFalse(store.remove(sf1));
207 assertTrue(store.remove(sf2));
208 assertTrue(store.remove(sf2a));
209 assertTrue(store.isEmpty());
212 * nested feature deletion
214 SimpleFeature sf4 = add(store, 20, 30);
215 SimpleFeature sf5 = add(store, 22, 26); // to NCList
216 SimpleFeature sf6 = add(store, 23, 24); // child of sf5
217 SimpleFeature sf7 = add(store, 25, 25); // sibling of sf6
218 SimpleFeature sf8 = add(store, 24, 24); // child of sf6
219 SimpleFeature sf9 = add(store, 23, 23); // child of sf6
220 assertEquals(store.size(), 6);
222 // delete a node with children - they take its place
223 assertTrue(store.remove(sf6)); // sf8, sf9 should become children of sf5
224 assertEquals(store.size(), 5);
225 assertFalse(store.contains(sf6));
227 // delete a node with no children
228 assertTrue(store.remove(sf7));
229 assertEquals(store.size(), 4);
230 assertFalse(store.contains(sf7));
232 // delete root of NCList
233 assertTrue(store.remove(sf5));
234 assertEquals(store.size(), 3);
235 assertFalse(store.contains(sf5));
237 // continue the killing fields
238 assertTrue(store.remove(sf4));
239 assertEquals(store.size(), 2);
240 assertFalse(store.contains(sf4));
242 assertTrue(store.remove(sf9));
243 assertEquals(store.size(), 1);
244 assertFalse(store.contains(sf9));
246 assertTrue(store.remove(sf8));
247 assertTrue(store.isEmpty());
251 * A helper method to test whether a list contains a specific object (by
252 * object identity, not equality test as used by List.contains())
258 private static boolean containsObject(List<? extends Object> list,
261 for (Object i : list)
271 @Test(groups = "Functional")
272 public void testAdd()
274 IntervalStore<SimpleFeature> store = new IntervalStore<>();
276 assertFalse(store.add(null));
278 SimpleFeature sf1 = new SimpleFeature(10, 20, "Cath");
279 SimpleFeature sf2 = new SimpleFeature(10, 20, "Cath");
281 assertTrue(store.add(sf1));
282 assertEquals(store.size(), 1);
285 * contains should return true for the same or an identical feature
287 assertTrue(store.contains(sf1));
288 assertTrue(store.contains(sf2));
291 * duplicates are accepted
293 assertTrue(store.add(sf2));
294 assertEquals(store.size(), 2);
296 SimpleFeature sf3 = new SimpleFeature(0, 0, "Cath");
297 assertTrue(store.add(sf3));
298 assertEquals(store.size(), 3);
301 @Test(groups = "Functional")
302 public void testAdd_noDuplicates()
304 IntervalStore<SimpleFeature> store = new IntervalStore<>();
306 SimpleFeature sf1 = new SimpleFeature(10, 20, "Cath");
307 SimpleFeature sf2 = new SimpleFeature(10, 20, "Cath");
308 assertTrue(sf1.equals(sf2));
309 assertTrue(store.add(sf1));
310 assertEquals(store.size(), 1);
311 assertFalse(store.add(sf2, false));
312 assertEquals(store.size(), 1);
313 assertTrue(store.contains(sf1));
314 assertTrue(store.contains(sf2)); // because sf1.equals(sf2) !
317 @Test(groups = "Functional")
318 public void testIsEmpty()
320 IntervalStore<SimpleFeature> store = new IntervalStore<>();
321 assertTrue(store.isEmpty());
322 assertEquals(store.size(), 0);
327 SimpleFeature sf1 = new SimpleFeature(10, 20, "Cath");
329 assertFalse(store.isEmpty());
330 assertEquals(store.size(), 1);
332 assertTrue(store.isEmpty());
333 assertEquals(store.size(), 0);
335 sf1 = new SimpleFeature(0, 0, "Cath");
337 assertFalse(store.isEmpty());
338 assertEquals(store.size(), 1);
340 assertTrue(store.isEmpty());
341 assertEquals(store.size(), 0);
344 * sf2, sf3 added as nested features
346 sf1 = new SimpleFeature(19, 49, "Cath");
347 SimpleFeature sf2 = new SimpleFeature(20, 40, "Cath");
348 SimpleFeature sf3 = new SimpleFeature(25, 35, "Cath");
350 assertEquals(store.size(), 1);
352 assertEquals(store.size(), 2);
354 assertEquals(store.size(), 3);
355 assertTrue(store.remove(sf1));
356 assertEquals(store.size(), 2);
358 assertFalse(store.isEmpty());
359 assertTrue(store.remove(sf2));
360 assertEquals(store.size(), 1);
361 assertFalse(store.isEmpty());
362 assertTrue(store.remove(sf3));
363 assertEquals(store.size(), 0);
364 assertTrue(store.isEmpty()); // all gone
367 @Test(groups = "Functional")
368 public void testRemove_readd()
371 * add a feature and a nested feature
373 IntervalStore<SimpleFeature> store = new IntervalStore<>();
374 SimpleFeature sf1 = add(store, 10, 20);
375 // sf2 is nested in sf1 so will be stored in nestedFeatures
376 SimpleFeature sf2 = add(store, 12, 14);
377 assertEquals(store.size(), 2);
378 assertTrue(store.contains(sf1));
379 assertTrue(store.contains(sf2));
382 * delete the first feature
384 assertTrue(store.remove(sf1));
385 assertFalse(store.contains(sf1));
386 assertTrue(store.contains(sf2));
389 * re-add the 'nested' feature; it is now duplicated
392 assertEquals(store.size(), 2);
393 assertTrue(store.contains(sf2));
396 @Test(groups = "Functional")
397 public void testContains()
399 IntervalStore<SimpleFeature> store = new IntervalStore<>();
400 SimpleFeature sf1 = new SimpleFeature(10, 20, "Cath");
401 SimpleFeature sf2 = new SimpleFeature(10, 20, "Pfam");
404 assertTrue(store.contains(sf1));
405 assertTrue(store.contains(new SimpleFeature(sf1))); // identical feature
406 assertFalse(store.contains(sf2)); // different description
409 * add a nested feature
411 SimpleFeature sf3 = new SimpleFeature(12, 16, "Cath");
413 assertTrue(store.contains(sf3));
414 assertTrue(store.contains(new SimpleFeature(sf3)));
417 * delete the outer (enclosing, non-nested) feature
420 assertFalse(store.contains(sf1));
421 assertTrue(store.contains(sf3));
423 assertFalse(store.contains(null));
426 assertFalse(store.contains("junk"));
427 } catch (ClassCastException e)
433 @Test(groups = "Functional")
434 public void testFindOverlaps_resultsArg_mixed()
436 IntervalStore<SimpleFeature> store = new IntervalStore<>();
437 SimpleFeature sf1 = add(store, 10, 50);
438 SimpleFeature sf2 = add(store, 1, 15);
439 SimpleFeature sf3 = add(store, 20, 30);
440 SimpleFeature sf4 = add(store, 40, 100);
441 SimpleFeature sf5 = add(store, 60, 100);
442 SimpleFeature sf6 = add(store, 70, 70);
444 List<SimpleFeature> overlaps = new ArrayList<>();
445 List<SimpleFeature> overlaps2 = store.findOverlaps(200, 200, overlaps);
446 assertSame(overlaps, overlaps2);
447 assertTrue(overlaps.isEmpty());
450 store.findOverlaps(1, 9, overlaps);
451 assertEquals(overlaps.size(), 1);
452 assertTrue(overlaps.contains(sf2));
455 store.findOverlaps(5, 18, overlaps);
456 assertEquals(overlaps.size(), 2);
457 assertTrue(overlaps.contains(sf1));
458 assertTrue(overlaps.contains(sf2));
461 store.findOverlaps(30, 40, overlaps);
462 assertEquals(overlaps.size(), 3);
463 assertTrue(overlaps.contains(sf1));
464 assertTrue(overlaps.contains(sf3));
465 assertTrue(overlaps.contains(sf4));
468 store.findOverlaps(80, 90, overlaps);
469 assertEquals(overlaps.size(), 2);
470 assertTrue(overlaps.contains(sf4));
471 assertTrue(overlaps.contains(sf5));
474 store.findOverlaps(68, 70, overlaps);
475 assertEquals(overlaps.size(), 3);
476 assertTrue(overlaps.contains(sf4));
477 assertTrue(overlaps.contains(sf5));
478 assertTrue(overlaps.contains(sf6));
481 * and without clearing the list first
482 * note that sf4 is included twice, as an
483 * overlap of 68-70 and also of 30-40
485 store.findOverlaps(30, 40, overlaps);
486 assertEquals(overlaps.size(), 6);
487 assertTrue(overlaps.contains(sf1));
488 assertTrue(overlaps.contains(sf3));
489 assertTrue(overlaps.contains(sf4));
490 assertTrue(overlaps.contains(sf5));
491 assertTrue(overlaps.contains(sf6));
492 assertSame(sf4, overlaps.get(0));
493 assertSame(sf4, overlaps.get(4));
496 @Test(groups = "Functional")
497 public void testFindOverlaps_resultsArg_nested()
499 IntervalStore<SimpleFeature> store = new IntervalStore<>();
500 SimpleFeature sf1 = add(store, 10, 50);
501 SimpleFeature sf2 = add(store, 10, 40);
502 SimpleFeature sf3 = add(store, 20, 30);
503 // feature at same location but different description
504 SimpleFeature sf4 = new SimpleFeature(20, 30, "different desc");
506 SimpleFeature sf5 = add(store, 35, 36);
508 List<SimpleFeature> overlaps = new ArrayList<>();
509 store.findOverlaps(1, 9, overlaps);
510 assertTrue(overlaps.isEmpty());
512 store.findOverlaps(10, 15, overlaps);
513 assertEquals(overlaps.size(), 2);
514 assertTrue(overlaps.contains(sf1));
515 assertTrue(overlaps.contains(sf2));
518 store.findOverlaps(45, 60, overlaps);
519 assertEquals(overlaps.size(), 1);
520 assertTrue(overlaps.contains(sf1));
523 store.findOverlaps(32, 38, overlaps);
524 assertEquals(overlaps.size(), 3);
525 assertTrue(overlaps.contains(sf1));
526 assertTrue(overlaps.contains(sf2));
527 assertTrue(overlaps.contains(sf5));
530 store.findOverlaps(15, 25, overlaps);
531 assertEquals(overlaps.size(), 4);
532 assertTrue(overlaps.contains(sf1));
533 assertTrue(overlaps.contains(sf2));
534 assertTrue(overlaps.contains(sf3));
535 assertTrue(overlaps.contains(sf4));
538 @Test(groups = "Functional")
539 public void testFindOverlaps_resultsArg_nonNested()
541 IntervalStore<SimpleFeature> store = new IntervalStore<>();
542 SimpleFeature sf1 = add(store, 10, 20);
543 // same range different description
544 SimpleFeature sf2 = new SimpleFeature(10, 20, "desc");
546 SimpleFeature sf3 = add(store, 15, 25);
547 SimpleFeature sf4 = add(store, 20, 35);
549 assertEquals(store.size(), 4);
550 List<SimpleFeature> overlaps = new ArrayList<>();
551 store.findOverlaps(1, 9, overlaps);
552 assertTrue(overlaps.isEmpty());
554 store.findOverlaps(8, 10, overlaps);
555 assertEquals(overlaps.size(), 2);
556 assertTrue(overlaps.contains(sf1));
557 assertTrue(overlaps.contains(sf2));
560 store.findOverlaps(12, 16, overlaps);
561 assertEquals(overlaps.size(), 3);
562 assertTrue(overlaps.contains(sf1));
563 assertTrue(overlaps.contains(sf2));
564 assertTrue(overlaps.contains(sf3));
567 store.findOverlaps(33, 33, overlaps);
568 assertEquals(overlaps.size(), 1);
569 assertTrue(overlaps.contains(sf4));
572 * ensure edge cases are covered
575 store.findOverlaps(35, 40, overlaps);
576 assertEquals(overlaps.size(), 1);
577 assertTrue(overlaps.contains(sf4));
580 assertTrue(store.findOverlaps(36, 100, overlaps).isEmpty());
581 assertTrue(store.findOverlaps(1, 9, overlaps).isEmpty());