1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS 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.orekit.utils;
18  
19  import org.junit.jupiter.api.Assertions;
20  import org.junit.jupiter.api.BeforeEach;
21  import org.junit.jupiter.api.Test;
22  import org.orekit.Utils;
23  import org.orekit.errors.OrekitException;
24  import org.orekit.errors.OrekitMessages;
25  import org.orekit.time.AbsoluteDate;
26  import org.orekit.utils.TimeSpanMap.Span;
27  import org.orekit.utils.TimeSpanMap.Transition;
28  
29  import java.util.function.Consumer;
30  
31  public class TimeSpanMapTest {
32  
33      @Test
34      public void testSingleEntry() {
35          String single = "single";
36          TimeSpanMap<String> map = new TimeSpanMap<>(single);
37          checkCountConsistency(map);
38          Assertions.assertSame(single, map.get(AbsoluteDate.CCSDS_EPOCH));
39          Assertions.assertSame(single, map.get(AbsoluteDate.FIFTIES_EPOCH));
40          Assertions.assertSame(single, map.get(AbsoluteDate.FUTURE_INFINITY));
41          Assertions.assertSame(single, map.get(AbsoluteDate.GALILEO_EPOCH));
42          Assertions.assertSame(single, map.get(AbsoluteDate.GPS_EPOCH));
43          Assertions.assertSame(single, map.get(AbsoluteDate.J2000_EPOCH));
44          Assertions.assertSame(single, map.get(AbsoluteDate.JAVA_EPOCH));
45          Assertions.assertSame(single, map.get(AbsoluteDate.JULIAN_EPOCH));
46          Assertions.assertSame(single, map.get(AbsoluteDate.MODIFIED_JULIAN_EPOCH));
47          Assertions.assertSame(single, map.get(AbsoluteDate.PAST_INFINITY));
48          Assertions.assertEquals(1, map.getSpansNumber());
49          Assertions.assertSame(single, map.getFirstNonNullSpan().getData());
50          Assertions.assertSame(single, map.getLastNonNullSpan().getData());
51      }
52  
53      @Test
54      public void testForwardAdd() {
55          final AbsoluteDate ref = AbsoluteDate.J2000_EPOCH;
56          TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
57          checkCountConsistency(map);
58          for (int i = 1; i < 100; ++i) {
59              Integer entry = i;
60              TimeSpanMap.Span<Integer> span = map.addValidAfter(entry, ref.shiftedBy(i), false);
61              Assertions.assertSame(entry, span.getData());
62              checkCountConsistency(map);
63          }
64          Assertions.assertEquals(0, map.get(ref.shiftedBy(-1000.0)).intValue());
65          Assertions.assertEquals(0, map.get(ref.shiftedBy( -100.0)).intValue());
66          TimeSpanMap.Span<Integer> span = map.getSpan(ref.shiftedBy(-1000.0));
67          Assertions.assertEquals(0, span.getData().intValue());
68          Assertions.assertTrue(span.getStart().durationFrom(AbsoluteDate.J2000_EPOCH) < -Double.MAX_VALUE);
69          Assertions.assertEquals(1.0, span.getEnd().durationFrom(AbsoluteDate.J2000_EPOCH), 1.0e-15);
70          for (int i = 0; i < 100; ++i) {
71              Assertions.assertEquals(i, map.get(ref.shiftedBy(i + 0.1)).intValue());
72              Assertions.assertEquals(i, map.get(ref.shiftedBy(i + 0.9)).intValue());
73              span = map.getSpan(ref.shiftedBy(i + 0.1));
74              Assertions.assertEquals(i, span.getData().intValue());
75              if (i == 0) {
76                  Assertions.assertTrue(span.getStart().durationFrom(AbsoluteDate.J2000_EPOCH) < -Double.MAX_VALUE);
77              } else {
78                  Assertions.assertEquals(i, span.getStart().durationFrom(AbsoluteDate.J2000_EPOCH), 1.0e-15);
79              } if (i == 99) {
80                  Assertions.assertTrue(span.getEnd().durationFrom(AbsoluteDate.J2000_EPOCH) > Double.MAX_VALUE);
81              } else {
82                  Assertions.assertEquals(i + 1, span.getEnd().durationFrom(AbsoluteDate.J2000_EPOCH), 1.0e-15);
83              }
84          }
85          Assertions.assertEquals(99, map.get(ref.shiftedBy(  100.0)).intValue());
86          Assertions.assertEquals(99, map.get(ref.shiftedBy( 1000.0)).intValue());
87          checkCountConsistency(map);
88      }
89  
90      @Test
91      public void testBackwardAdd() {
92          final AbsoluteDate ref = AbsoluteDate.J2000_EPOCH;
93          TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
94          checkCountConsistency(map);
95          for (int i = -1; i > -100; --i) {
96              Integer entry = i;
97              TimeSpanMap.Span<Integer> span = map.addValidBefore(entry, ref.shiftedBy(i), false);
98              Assertions.assertSame(entry, span.getData());
99              checkCountConsistency(map);
100         }
101         Assertions.assertEquals(0, map.get(ref.shiftedBy( 1000.0)).intValue());
102         Assertions.assertEquals(0, map.get(ref.shiftedBy(  100.0)).intValue());
103         for (int i = 0; i > -100; --i) {
104             Assertions.assertEquals(i, map.get(ref.shiftedBy(i - 0.1)).intValue());
105             Assertions.assertEquals(i, map.get(ref.shiftedBy(i - 0.9)).intValue());
106         }
107         Assertions.assertEquals(-99, map.get(ref.shiftedBy( -100.0)).intValue());
108         Assertions.assertEquals(-99, map.get(ref.shiftedBy(-1000.0)).intValue());
109         checkCountConsistency(map);
110     }
111 
112     @Test
113     public void testRandomAddNoErase() {
114         final AbsoluteDate ref = AbsoluteDate.J2000_EPOCH;
115         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
116         map.addValidAfter(10, ref.shiftedBy(10.0), false);
117         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
118         map.addValidAfter( 9, ref.shiftedBy( 5.0), false);
119         map.addValidBefore( 2, ref.shiftedBy( 3.0), false);
120         map.addValidBefore( 5, ref.shiftedBy( 9.0), false);
121         Assertions.assertEquals( 0, map.get(ref.shiftedBy( -1.0)).intValue());
122         Assertions.assertEquals( 0, map.get(ref.shiftedBy(  1.9)).intValue());
123         Assertions.assertEquals( 2, map.get(ref.shiftedBy(  2.1)).intValue());
124         Assertions.assertEquals( 2, map.get(ref.shiftedBy(  2.9)).intValue());
125         Assertions.assertEquals( 3, map.get(ref.shiftedBy(  3.1)).intValue());
126         Assertions.assertEquals( 3, map.get(ref.shiftedBy(  4.9)).intValue());
127         Assertions.assertEquals( 5, map.get(ref.shiftedBy(  5.1)).intValue());
128         Assertions.assertEquals( 5, map.get(ref.shiftedBy(  8.9)).intValue());
129         Assertions.assertEquals( 9, map.get(ref.shiftedBy(  9.1)).intValue());
130         Assertions.assertEquals( 9, map.get(ref.shiftedBy(  9.9)).intValue());
131         Assertions.assertEquals(10, map.get(ref.shiftedBy( 10.1)).intValue());
132         Assertions.assertEquals(10, map.get(ref.shiftedBy(100.0)).intValue());
133         final StringBuilder builder = new StringBuilder();
134         map.forEach(i -> builder.append(' ').append(i));
135         Assertions.assertEquals(" 0 2 3 5 9 10", builder.toString());
136         Assertions.assertEquals(6, map.getSpansNumber());
137         checkCountConsistency(map);
138     }
139 
140     @Test
141     public void testRandomAddErase() {
142         final AbsoluteDate ref = AbsoluteDate.J2000_EPOCH;
143         TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
144         map.addValidAfter(10, ref.shiftedBy(10.0), false);
145         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
146         map.addValidBefore( 5, ref.shiftedBy( 7.0), false);
147         map.addValidAfter(null, ref.shiftedBy( 5.0), true);
148         map.addValidAfter( 1, ref.shiftedBy( 1.0), false);
149         map.addValidBefore(null, ref.shiftedBy( 3.0), true);
150         map.addValidBefore( 7, ref.shiftedBy( 9.0), false);
151         Assertions.assertNull(map.get(ref.shiftedBy( -1.0)));
152         Assertions.assertNull(map.get(ref.shiftedBy(  1.9)));
153         Assertions.assertNull(map.get(ref.shiftedBy(  2.1)));
154         Assertions.assertNull(map.get(ref.shiftedBy(  2.9)));
155         Assertions.assertEquals( 5, map.get(ref.shiftedBy(  3.1)).intValue());
156         Assertions.assertEquals( 5, map.get(ref.shiftedBy(  4.9)).intValue());
157         Assertions.assertEquals( 7, map.get(ref.shiftedBy(  5.1)).intValue());
158         Assertions.assertEquals( 7, map.get(ref.shiftedBy(  6.9)).intValue());
159         Assertions.assertEquals( 7, map.get(ref.shiftedBy(  7.1)).intValue());
160         Assertions.assertEquals( 7, map.get(ref.shiftedBy(  8.9)).intValue());
161         Assertions.assertNull(map.get(ref.shiftedBy(  9.1)));
162         Assertions.assertNull(map.get(ref.shiftedBy(  9.9)));
163         Assertions.assertNull(map.get(ref.shiftedBy( 10.1)));
164         Assertions.assertNull(map.get(ref.shiftedBy(100.0)));
165         final StringBuilder builder = new StringBuilder();
166         map.forEach(i -> builder.append(' ').append(i));
167         Assertions.assertEquals(" 5 7", builder.toString());
168         Assertions.assertEquals(4, map.getSpansNumber());
169         checkCountConsistency(map);
170     }
171 
172     @Test
173     public void testAddBetweenEmpty() {
174         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
175         map.addValidBetween(1, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-2), AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+2));
176         Assertions.assertEquals(3, map.getSpansNumber());
177         Assertions.assertEquals(0, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-3)).intValue());
178         Assertions.assertEquals(1, map.get(AbsoluteDate.ARBITRARY_EPOCH).intValue());
179         Assertions.assertEquals(0, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+3)).intValue());
180         checkCountConsistency(map);
181     }
182 
183     @Test
184     public void testAddBetweenBefore() {
185         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
186         map.addValidBefore(1, AbsoluteDate.ARBITRARY_EPOCH, false);
187         map.addValidBetween(7, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-4), AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-2));
188         Assertions.assertEquals(4, map.getSpansNumber());
189         Assertions.assertEquals(1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-5)).intValue());
190         Assertions.assertEquals(7, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-3)).intValue());
191         Assertions.assertEquals(1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1)).intValue());
192         Assertions.assertEquals(0, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+3)).intValue());
193         checkCountConsistency(map);
194     }
195 
196     @Test
197     public void testAddBetweenAfter() {
198         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
199         map.addValidBefore(1, AbsoluteDate.ARBITRARY_EPOCH, false);
200         map.addValidBetween(7, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2), AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4));
201         Assertions.assertEquals(4, map.getSpansNumber());
202         Assertions.assertEquals(1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-3)).intValue());
203         Assertions.assertEquals(0, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy( 1)).intValue());
204         Assertions.assertEquals(7, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy( 3)).intValue());
205         Assertions.assertEquals(0, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy( 5)).intValue());
206         checkCountConsistency(map);
207     }
208 
209     @Test
210     public void testAddBetweenCoveringAll() {
211         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
212         map.addValidAfter(1, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1), false);
213         map.addValidAfter(2, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2), false);
214         map.addValidAfter(3, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(3), false);
215         map.addValidAfter(4, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4), false);
216         map.addValidAfter(5, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(5), false);
217         Assertions.assertEquals(6, map.getSpansNumber());
218         map.addValidBetween(-1, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1), AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(6));
219         Assertions.assertEquals( 3, map.getSpansNumber());
220         Assertions.assertEquals( 0, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-5)).intValue());
221         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy( 2)).intValue());
222         Assertions.assertEquals( 5, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+7)).intValue());
223         checkCountConsistency(map);
224     }
225 
226     @Test
227     public void testAddBetweenCoveringSome() {
228         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
229         map.addValidAfter(1, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1), false);
230         map.addValidAfter(2, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2), false);
231         map.addValidAfter(3, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(3), false);
232         map.addValidAfter(4, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4), false);
233         map.addValidAfter(5, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(5), false);
234         Assertions.assertEquals(6, map.getSpansNumber());
235         Integer entry = -1;
236         TimeSpanMap.Span<Integer> span = map.addValidBetween(entry, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1.5), AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4.5));
237         Assertions.assertSame(entry, span.getData());
238         Assertions.assertEquals(5, map.getSpansNumber());
239         Assertions.assertEquals( 0, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(0.75)).intValue());
240         Assertions.assertEquals( 1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1.25)).intValue());
241         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1.75)).intValue());
242         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4.25)).intValue());
243         Assertions.assertEquals( 4, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4.75)).intValue());
244         Assertions.assertEquals( 5, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(5.25)).intValue());
245         checkCountConsistency(map);
246     }
247 
248     @Test
249     public void testAddBetweenSplittingOneSpanOnly() {
250         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
251         map.addValidAfter(1, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1), false);
252         map.addValidAfter(2, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2), false);
253         map.addValidAfter(3, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(3), false);
254         map.addValidAfter(4, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4), false);
255         map.addValidAfter(5, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(5), false);
256         Assertions.assertEquals(6, map.getSpansNumber());
257         map.addValidBetween(-1, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2.25), AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2.75));
258         Assertions.assertEquals(8, map.getSpansNumber());
259         Assertions.assertEquals( 0, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(0.75)).intValue());
260         Assertions.assertEquals( 1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1.99)).intValue());
261         Assertions.assertEquals( 2, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2.01)).intValue());
262         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2.50)).intValue());
263         Assertions.assertEquals( 2, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2.99)).intValue());
264         Assertions.assertEquals( 3, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(3.01)).intValue());
265         Assertions.assertEquals( 4, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4.25)).intValue());
266         Assertions.assertEquals( 5, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(5.25)).intValue());
267         checkCountConsistency(map);
268     }
269 
270     @Test
271     public void testAddBetweenExistingDates() {
272         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
273         map.addValidAfter(1, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1), false);
274         map.addValidAfter(2, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2), false);
275         map.addValidAfter(3, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(3), false);
276         map.addValidAfter(4, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4), false);
277         map.addValidAfter(5, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(5), false);
278         Assertions.assertEquals(6, map.getSpansNumber());
279         map.addValidBetween(-1, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2), AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4));
280         Assertions.assertEquals(5, map.getSpansNumber());
281         Assertions.assertEquals( 0, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(0.99)).intValue());
282         Assertions.assertEquals( 1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1.01)).intValue());
283         Assertions.assertEquals( 1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1.99)).intValue());
284         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(2.01)).intValue());
285         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(3.99)).intValue());
286         Assertions.assertEquals( 4, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4.01)).intValue());
287         Assertions.assertEquals( 4, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(4.99)).intValue());
288         Assertions.assertEquals( 5, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(5.01)).intValue());
289         checkCountConsistency(map);
290     }
291 
292     @Test
293     public void testExtractRangeInfinity() {
294         final AbsoluteDate ref = AbsoluteDate.J2000_EPOCH;
295         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
296         map.addValidAfter(10, ref.shiftedBy(10.0), false);
297         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
298         map.addValidAfter( 9, ref.shiftedBy( 5.0), false);
299         map.addValidBefore( 2, ref.shiftedBy( 3.0), false);
300         map.addValidBefore( 5, ref.shiftedBy( 9.0), false);
301         TimeSpanMap<Integer> range = map.extractRange(AbsoluteDate.PAST_INFINITY, AbsoluteDate.FUTURE_INFINITY);
302         Assertions.assertEquals(map.getSpansNumber(), range.getSpansNumber());
303         checkCountConsistency(map);
304     }
305 
306     @Test
307     public void testExtractRangeSingleEntry() {
308         final AbsoluteDate ref = AbsoluteDate.J2000_EPOCH;
309         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
310         map.addValidAfter(10, ref.shiftedBy(10.0), false);
311         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
312         map.addValidAfter( 9, ref.shiftedBy( 5.0), false);
313         map.addValidBefore( 2, ref.shiftedBy( 3.0), false);
314         map.addValidBefore( 5, ref.shiftedBy( 9.0), false);
315         TimeSpanMap<Integer> range = map.extractRange(ref.shiftedBy(6), ref.shiftedBy(8));
316         Assertions.assertEquals(1, range.getSpansNumber());
317         Assertions.assertEquals(5, range.get(ref.shiftedBy(-10000)).intValue());
318         Assertions.assertEquals(5, range.get(ref.shiftedBy(+10000)).intValue());
319         checkCountConsistency(map);
320     }
321 
322     @Test
323     public void testExtractFromPastInfinity() {
324         final AbsoluteDate ref = AbsoluteDate.J2000_EPOCH;
325         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
326         map.addValidAfter(10, ref.shiftedBy(10.0), false);
327         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
328         map.addValidAfter( 9, ref.shiftedBy( 5.0), false);
329         map.addValidBefore( 2, ref.shiftedBy( 3.0), false);
330         map.addValidBefore( 5, ref.shiftedBy( 9.0), false);
331         TimeSpanMap<Integer> range = map.extractRange(AbsoluteDate.PAST_INFINITY, ref.shiftedBy(8));
332         Assertions.assertEquals(4, range.getSpansNumber());
333         Assertions.assertEquals( 0, range.get(ref.shiftedBy( -1.0)).intValue());
334         Assertions.assertEquals( 0, range.get(ref.shiftedBy(  1.9)).intValue());
335         Assertions.assertEquals( 2, range.get(ref.shiftedBy(  2.1)).intValue());
336         Assertions.assertEquals( 2, range.get(ref.shiftedBy(  2.9)).intValue());
337         Assertions.assertEquals( 3, range.get(ref.shiftedBy(  3.1)).intValue());
338         Assertions.assertEquals( 3, range.get(ref.shiftedBy(  4.9)).intValue());
339         Assertions.assertEquals( 5, range.get(ref.shiftedBy(  5.1)).intValue());
340         Assertions.assertEquals( 5, range.get(ref.shiftedBy(  8.9)).intValue());
341         Assertions.assertEquals( 5, range.get(ref.shiftedBy(  9.1)).intValue());
342         Assertions.assertEquals( 5, range.get(ref.shiftedBy( 99.0)).intValue());
343         checkCountConsistency(map);
344     }
345 
346     @Test
347     public void testExtractToFutureInfinity() {
348         final AbsoluteDate ref = AbsoluteDate.J2000_EPOCH;
349         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
350         map.addValidAfter(10, ref.shiftedBy(10.0), false);
351         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
352         map.addValidAfter( 9, ref.shiftedBy( 5.0), false);
353         map.addValidBefore( 2, ref.shiftedBy( 3.0), false);
354         map.addValidBefore( 5, ref.shiftedBy( 9.0), false);
355         TimeSpanMap<Integer> range = map.extractRange(ref.shiftedBy(4), AbsoluteDate.FUTURE_INFINITY);
356         Assertions.assertEquals(4, range.getSpansNumber());
357         Assertions.assertEquals( 3, range.get(ref.shiftedBy(-99.0)).intValue());
358         Assertions.assertEquals( 3, range.get(ref.shiftedBy(  4.9)).intValue());
359         Assertions.assertEquals( 5, range.get(ref.shiftedBy(  5.1)).intValue());
360         Assertions.assertEquals( 5, range.get(ref.shiftedBy(  8.9)).intValue());
361         Assertions.assertEquals( 9, range.get(ref.shiftedBy(  9.1)).intValue());
362         Assertions.assertEquals( 9, range.get(ref.shiftedBy(  9.9)).intValue());
363         Assertions.assertEquals(10, range.get(ref.shiftedBy( 10.1)).intValue());
364         Assertions.assertEquals(10, range.get(ref.shiftedBy(100.0)).intValue());
365         checkCountConsistency(map);
366     }
367 
368     @Test
369     public void testExtractIntermediate() {
370         final AbsoluteDate ref = AbsoluteDate.J2000_EPOCH;
371         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
372         map.addValidAfter(10, ref.shiftedBy(10.0), false);
373         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
374         map.addValidAfter( 9, ref.shiftedBy( 5.0), false);
375         map.addValidBefore( 2, ref.shiftedBy( 3.0), false);
376         map.addValidBefore( 5, ref.shiftedBy( 9.0), false);
377         TimeSpanMap<Integer> range = map.extractRange(ref.shiftedBy(4), ref.shiftedBy(8));
378         Assertions.assertEquals(2, range.getSpansNumber());
379         Assertions.assertEquals( 3, range.get(ref.shiftedBy(-99.0)).intValue());
380         Assertions.assertEquals( 3, range.get(ref.shiftedBy(  4.9)).intValue());
381         Assertions.assertEquals( 5, range.get(ref.shiftedBy(  5.1)).intValue());
382         Assertions.assertEquals( 5, range.get(ref.shiftedBy(  8.9)).intValue());
383         Assertions.assertEquals( 5, range.get(ref.shiftedBy(  9.1)).intValue());
384         Assertions.assertEquals( 5, range.get(ref.shiftedBy(999.9)).intValue());
385         checkCountConsistency(map);
386     }
387 
388     @Test
389     public void testSpanToTransitionLinkEmpty() {
390         TimeSpanMap.Span<Integer> span = new TimeSpanMap<>(1).getSpan(AbsoluteDate.ARBITRARY_EPOCH);
391         Assertions.assertEquals(1, span.getData().intValue());
392         Assertions.assertSame(AbsoluteDate.PAST_INFINITY, span.getStart());
393         Assertions.assertNull(span.getStartTransition());
394         Assertions.assertSame(AbsoluteDate.FUTURE_INFINITY, span.getEnd());
395         Assertions.assertNull(span.getEndTransition());
396     }
397 
398     @Test
399     public void testSpanToTransitionLink() {
400         final AbsoluteDate ref = AbsoluteDate.ARBITRARY_EPOCH;
401         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
402         map.addValidAfter(10, ref.shiftedBy(10.0), false);
403         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
404         map.addValidAfter( 9, ref.shiftedBy( 5.0), false);
405         map.addValidBefore( 2, ref.shiftedBy( 3.0), false);
406         map.addValidBefore( 5, ref.shiftedBy( 9.0), false);
407 
408         TimeSpanMap.Span<Integer> first = map.getSpan(ref.shiftedBy(-99.0));
409         Assertions.assertEquals(0, first.getData().intValue());
410         Assertions.assertSame(AbsoluteDate.PAST_INFINITY, first.getStart());
411         Assertions.assertNull(first.getStartTransition());
412         Assertions.assertEquals(2.0, first.getEnd().durationFrom(ref), 1.0e-15);
413         Assertions.assertNotNull(first.getEndTransition());
414 
415         TimeSpanMap.Span<Integer> middle = map.getSpan(ref.shiftedBy(6.0));
416         Assertions.assertEquals(5, middle.getData().intValue());
417         Assertions.assertEquals(5.0, middle.getStart().durationFrom(ref), 1.0e-15);
418         Assertions.assertNotNull(middle.getStartTransition());
419         Assertions.assertEquals(9.0, middle.getEnd().durationFrom(ref), 1.0e-15);
420         Assertions.assertNotNull(middle.getEndTransition());
421         Assertions.assertSame(middle.getStartTransition().getAfter(), middle.getEndTransition().getBefore());
422         Assertions.assertEquals(3, middle.getStartTransition().getBefore().intValue());
423         Assertions.assertEquals(5, middle.getStartTransition().getAfter().intValue());
424         Assertions.assertEquals(5, middle.getEndTransition().getBefore().intValue());
425         Assertions.assertEquals(9, middle.getEndTransition().getAfter().intValue());
426 
427         TimeSpanMap.Span<Integer> last = map.getSpan(ref.shiftedBy(+99.0));
428         Assertions.assertEquals(10, last.getData().intValue());
429         Assertions.assertEquals(10.0, last.getStart().durationFrom(ref), 1.0e-15);
430         Assertions.assertNotNull(last.getStartTransition());
431         Assertions.assertSame(AbsoluteDate.FUTURE_INFINITY, last.getEnd());
432         Assertions.assertNull(last.getEndTransition());
433 
434         checkCountConsistency(map);
435 
436     }
437 
438     @Test
439     public void testTransitionToSpanLink() {
440         final AbsoluteDate ref = AbsoluteDate.ARBITRARY_EPOCH;
441         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
442         map.addValidAfter(10, ref.shiftedBy(10.0), false);
443         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
444         map.addValidAfter( 9, ref.shiftedBy( 5.0), false);
445         map.addValidBefore( 2, ref.shiftedBy( 3.0), false);
446         map.addValidBefore( 5, ref.shiftedBy( 9.0), false);
447 
448         TimeSpanMap.Transition<Integer> first = map.getSpan(ref.shiftedBy(-99.0)).getEndTransition();
449         Assertions.assertEquals(2.0, first.getDate().durationFrom(ref), 1.0e-15);
450         Assertions.assertEquals(0, first.getBefore().intValue());
451         Assertions.assertEquals(2, first.getAfter().intValue());
452 
453         TimeSpanMap.Transition<Integer> middle = map.getSpan(ref.shiftedBy(6.0)).getStartTransition();
454         Assertions.assertEquals( 5.0, middle.getDate().durationFrom(ref), 1.0e-15);
455         Assertions.assertEquals( 3, middle.getBefore().intValue());
456         Assertions.assertEquals( 5, middle.getAfter().intValue());
457 
458         TimeSpanMap.Transition<Integer> last = map.getSpan(ref.shiftedBy(+99.0)).getStartTransition();
459         Assertions.assertEquals(10.0, last.getDate().durationFrom(ref), 1.0e-15);
460         Assertions.assertEquals( 9, last.getBefore().intValue());
461         Assertions.assertEquals(10, last.getAfter().intValue());
462 
463         checkCountConsistency(map);
464 
465     }
466 
467     @Test
468     public void tesFirstLastEmpty() {
469         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
470         Assertions.assertNull(map.getFirstTransition());
471         Assertions.assertNull(map.getLastTransition());
472         Assertions.assertSame(map.getFirstSpan(), map.getLastSpan());
473         Assertions.assertNull(map.getFirstSpan().getStartTransition());
474         Assertions.assertNull(map.getFirstSpan().getEndTransition());
475         Assertions.assertNull(map.getFirstSpan().previous());
476         Assertions.assertNull(map.getLastSpan().next());
477         checkCountConsistency(map);
478     }
479 
480     @Test
481     public void testSpansNavigation() {
482         final AbsoluteDate ref = AbsoluteDate.ARBITRARY_EPOCH;
483         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
484         map.addValidAfter(10, ref.shiftedBy(10.0), false);
485         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
486         map.addValidAfter( 9, ref.shiftedBy( 5.0), false);
487         map.addValidBefore( 2, ref.shiftedBy( 3.0), false);
488         map.addValidBefore( 5, ref.shiftedBy( 9.0), false);
489         Assertions.assertNull(map.getFirstSpan().previous());
490         Assertions.assertNull(map.getLastSpan().next());
491 
492         TimeSpanMap.Span<Integer> span = map.getFirstSpan();
493         Assertions.assertEquals(0, span.getData().intValue());
494         span = span.next();
495         Assertions.assertEquals(2, span.getData().intValue());
496         span = span.next();
497         Assertions.assertEquals(3, span.getData().intValue());
498         span = span.next();
499         Assertions.assertEquals(5, span.getData().intValue());
500         span = span.next();
501         Assertions.assertEquals(9, span.getData().intValue());
502         span = span.next();
503         Assertions.assertEquals(10, span.getData().intValue());
504         Assertions.assertNull(span.next());
505         span = span.previous();
506         Assertions.assertEquals(9, span.getData().intValue());
507         span = span.previous();
508         Assertions.assertEquals(5, span.getData().intValue());
509         span = span.previous();
510         Assertions.assertEquals(3, span.getData().intValue());
511         span = span.previous();
512         Assertions.assertEquals(2, span.getData().intValue());
513         span = span.previous();
514         Assertions.assertEquals(0, span.getData().intValue());
515         Assertions.assertNull(span.previous());
516 
517         checkCountConsistency(map);
518 
519     }
520 
521     @Test
522     public void testTransitionsNavigation() {
523         final AbsoluteDate ref = AbsoluteDate.ARBITRARY_EPOCH;
524         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
525         map.addValidAfter(10, ref.shiftedBy(10.0), false);
526         map.addValidAfter( 3, ref.shiftedBy( 2.0), false);
527         map.addValidAfter( 9, ref.shiftedBy( 5.0), false);
528         map.addValidBefore( 2, ref.shiftedBy( 3.0), false);
529         map.addValidBefore( 5, ref.shiftedBy( 9.0), false);
530 
531         Assertions.assertEquals( 2.0, map.getFirstTransition().getDate().durationFrom(ref), 1.0e-15);
532         Assertions.assertEquals(10.0, map.getLastTransition().getDate().durationFrom(ref), 1.0e-15);
533 
534         Transition<Integer> transition = map.getLastTransition();
535         Assertions.assertEquals(10.0, transition.getDate().durationFrom(ref), 1.0e-15);
536         transition = transition.previous();
537         Assertions.assertEquals( 9.0, transition.getDate().durationFrom(ref), 1.0e-15);
538         transition = transition.previous();
539         Assertions.assertEquals( 5.0, transition.getDate().durationFrom(ref), 1.0e-15);
540         transition = transition.previous();
541         Assertions.assertEquals( 3.0, transition.getDate().durationFrom(ref), 1.0e-15);
542         transition = transition.previous();
543         Assertions.assertEquals( 2.0, transition.getDate().durationFrom(ref), 1.0e-15);
544         Assertions.assertNull(transition.previous());
545         transition = transition.next();
546         Assertions.assertEquals( 3.0, transition.getDate().durationFrom(ref), 1.0e-15);
547         transition = transition.next();
548         Assertions.assertEquals( 5.0, transition.getDate().durationFrom(ref), 1.0e-15);
549         transition = transition.next();
550         Assertions.assertEquals( 9.0, transition.getDate().durationFrom(ref), 1.0e-15);
551         transition = transition.next();
552         Assertions.assertEquals(10.0, transition.getDate().durationFrom(ref), 1.0e-15);
553         Assertions.assertNull(transition.next());
554 
555         checkCountConsistency(map);
556 
557     }
558 
559     @Test
560     public void testDuplicatedBeforeAfterAtEnd() {
561         TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
562         map.addValidBefore(-1, AbsoluteDate.ARBITRARY_EPOCH, false);
563         map.addValidAfter(+1, AbsoluteDate.ARBITRARY_EPOCH, false);
564         Assertions.assertEquals(2, map.getSpansNumber());
565         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1)).intValue());
566         Assertions.assertEquals(+1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+1)).intValue());
567         checkCountConsistency(map);
568     }
569 
570     @Test
571     public void testDuplicatedBeforeAfterMiddle() {
572         TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
573         map.addValidBefore(-2, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-2), false);
574         map.addValidAfter(+2, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+2), false);
575         map.addValidBefore(-1, AbsoluteDate.ARBITRARY_EPOCH, false);
576         map.addValidAfter(+1, AbsoluteDate.ARBITRARY_EPOCH, false);
577         Assertions.assertEquals(4, map.getSpansNumber());
578         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1)).intValue());
579         Assertions.assertEquals(+1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+1)).intValue());
580         checkCountConsistency(map);
581     }
582 
583     @Test
584     public void testDuplicatedBeforeBefore() {
585         TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
586         map.addValidBefore(-2, AbsoluteDate.ARBITRARY_EPOCH, false); // first call at ARBITRARY_EPOCH
587         map.addValidAfter(0, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-2), false);
588         map.addValidBefore(-1, AbsoluteDate.ARBITRARY_EPOCH, false); // second call at ARBITRARY_EPOCH
589         Assertions.assertEquals(3, map.getSpansNumber());
590         Assertions.assertEquals(-2, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-10)).intValue());
591         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1)).intValue());
592         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+1)));
593         checkCountConsistency(map);
594     }
595 
596     @Test
597     public void testDuplicatedAfterBeforeAtEnd() {
598         TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
599         map.addValidAfter(+1, AbsoluteDate.ARBITRARY_EPOCH, false);
600         map.addValidBefore(-1, AbsoluteDate.ARBITRARY_EPOCH, false);
601         Assertions.assertEquals(2, map.getSpansNumber());
602         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1)).intValue());
603         Assertions.assertEquals(+1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+1)).intValue());
604         checkCountConsistency(map);
605     }
606 
607     @Test
608     public void testDuplicatedAfterBeforeMiddle() {
609         TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
610         map.addValidBefore(-2, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-2), false);
611         map.addValidAfter(+2, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+2), false);
612         map.addValidAfter(+1, AbsoluteDate.ARBITRARY_EPOCH, false);
613         map.addValidBefore(-1, AbsoluteDate.ARBITRARY_EPOCH, false);
614         Assertions.assertEquals(4, map.getSpansNumber());
615         Assertions.assertEquals(-1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1)).intValue());
616         Assertions.assertEquals(+1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+1)).intValue());
617         checkCountConsistency(map);
618     }
619 
620     @Test
621     public void testDuplicatedAfterAfter() {
622         TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
623         map.addValidAfter(+2, AbsoluteDate.ARBITRARY_EPOCH, false); // first call at ARBITRARY_EPOCH
624         map.addValidBefore(0, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+2), false);
625         map.addValidAfter(+1, AbsoluteDate.ARBITRARY_EPOCH, false); // second call at ARBITRARY_EPOCH
626         Assertions.assertEquals(3, map.getSpansNumber());
627         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1)));
628         Assertions.assertEquals(+1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+1)).intValue());
629         Assertions.assertEquals(+2, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+10)).intValue());
630         checkCountConsistency(map);
631     }
632 
633     @Test
634     public void testValidAllTime() {
635         AbsoluteDate ref = AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1);
636         TimeSpanMap<Integer> map = new TimeSpanMap<>(0);
637 
638         // action
639         map.addValidAfter(1, ref, false);
640         map.addValidBefore(2, ref, false);
641 
642         // verify
643         Assertions.assertEquals(1, (int) map.get(ref.shiftedBy(1)));
644         Assertions.assertEquals(2, (int) map.get(ref.shiftedBy(-1)));
645         Assertions.assertEquals(1, (int) map.get(ref));
646     }
647 
648     @Test
649     public void testBetweenPastInfinity() {
650         TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
651         Assertions.assertEquals(1, map.getSpansNumber());
652         map.addValidBetween(1, AbsoluteDate.PAST_INFINITY, AbsoluteDate.ARBITRARY_EPOCH);
653         Assertions.assertEquals(2, map.getSpansNumber());
654         Assertions.assertEquals(1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1)).intValue());
655         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+1)));
656     }
657 
658     @Test
659     public void testBetweenFutureInfinity() {
660         TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
661         Assertions.assertEquals(1, map.getSpansNumber());
662         map.addValidBetween(1, AbsoluteDate.ARBITRARY_EPOCH, AbsoluteDate.FUTURE_INFINITY);
663         Assertions.assertEquals(2, map.getSpansNumber());
664         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1)));
665         Assertions.assertEquals(1, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(+1)).intValue());
666     }
667 
668     @Test
669     public void testBetweenBothInfinity() {
670         TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
671         Assertions.assertEquals(1, map.getSpansNumber());
672         map.addValidBetween(1, AbsoluteDate.PAST_INFINITY, AbsoluteDate.FUTURE_INFINITY);
673         Assertions.assertEquals(1, map.getSpansNumber());
674         Assertions.assertEquals(1, map.get(AbsoluteDate.ARBITRARY_EPOCH).intValue());
675     }
676 
677     @Test
678     public void testFirstNonNull() {
679         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
680         checkException(map, TimeSpanMap::getFirstNonNullSpan, OrekitMessages.NO_CACHED_ENTRIES);
681         for (double dt = 0; dt < 10; dt += 0.25) {
682             map.addValidAfter(null, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(dt), false);
683         }
684         checkException(map, TimeSpanMap::getFirstNonNullSpan, OrekitMessages.NO_CACHED_ENTRIES);
685         map.addValidAfter(22, map.getLastTransition().getDate().shiftedBy( 60.0), false);
686         map.addValidAfter(17, map.getLastTransition().getDate().shiftedBy(-20.0), false);
687         Assertions.assertEquals(17, map.getFirstNonNullSpan().getData());
688     }
689 
690     @Test
691     public void testLastNonNull() {
692         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
693         checkException(map, TimeSpanMap::getLastNonNullSpan, OrekitMessages.NO_CACHED_ENTRIES);
694         for (double dt = 0; dt < 10; dt += 0.25) {
695             map.addValidBefore(null, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-dt), false);
696         }
697         checkException(map, TimeSpanMap::getLastNonNullSpan, OrekitMessages.NO_CACHED_ENTRIES);
698         map.addValidBefore(22, map.getLastTransition().getDate().shiftedBy(-60.0), false);
699         map.addValidBefore(17, map.getLastTransition().getDate().shiftedBy( 20.0), false);
700         Assertions.assertEquals(17, map.getLastNonNullSpan().getData());
701     }
702 
703     @Test
704     public void testMoveTowardsPastNoOverride() {
705         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
706         for (int i = 0; i < 100; i +=10) {
707             map.addValidAfter(i, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i), false);
708         }
709         Assertions.assertEquals(11, map.getSpansNumber());
710         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45)).getStartTransition();
711         Assertions.assertEquals(40, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
712         Assertions.assertEquals(30, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(35.5)));
713         Assertions.assertEquals(30, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(34.5)));
714         transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(35), true);
715         Assertions.assertEquals(11, map.getSpansNumber());
716         Assertions.assertEquals(35, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
717         Assertions.assertEquals(30, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(34.5)));
718         Assertions.assertEquals(40, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(35.5)));
719     }
720 
721     @Test
722     public void testMoveTowardsPastOverride() {
723         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
724         for (int i = 0; i < 100; i +=10) {
725             map.addValidAfter(i, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i), false);
726         }
727         Assertions.assertEquals(11, map.getSpansNumber());
728         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45)).getStartTransition();
729         Assertions.assertEquals(40, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
730         Assertions.assertEquals(10, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(15.5)));
731         Assertions.assertEquals(10, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(14.5)));
732         transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(15), true);
733         Assertions.assertEquals( 9, map.getSpansNumber());
734         Assertions.assertEquals(15, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
735         Assertions.assertEquals(10, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(14.5)));
736         Assertions.assertEquals(40, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(15.5)));
737     }
738 
739     @Test
740     public void testMoveTowardsPastOverrideAll() {
741         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
742         for (int i = 0; i < 100; i +=10) {
743             map.addValidBetween(i,
744                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
745                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
746         }
747         Assertions.assertEquals(12, map.getSpansNumber());
748         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45)).getStartTransition();
749         Assertions.assertEquals(40, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
750         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-10.5)));
751         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-9.5)));
752         transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-10), true);
753         Assertions.assertEquals( 8, map.getSpansNumber());
754         Assertions.assertEquals(-10, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
755         Assertions.assertEquals(40, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-9.5)));
756         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-10.5)));
757     }
758 
759     @Test
760     public void testMoveTowardsPastFirst() {
761         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
762         for (int i = 0; i < 100; i +=10) {
763             map.addValidBetween(i,
764                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
765                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
766         }
767         Assertions.assertEquals(12, map.getSpansNumber());
768         TimeSpanMap.Transition<Integer> transition = map.getFirstTransition();
769         Assertions.assertEquals(0, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
770         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-10.5)));
771         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-9.5)));
772         transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-10), true);
773         Assertions.assertEquals(12, map.getSpansNumber());
774         Assertions.assertEquals(-10, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
775         Assertions.assertEquals(0, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-9.5)));
776         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-10.5)));
777     }
778 
779     @Test
780     public void testMoveToPastInfinity() {
781         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
782         for (int i = 0; i < 100; i +=10) {
783             map.addValidBetween(i,
784                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
785                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
786         }
787         Assertions.assertEquals(12, map.getSpansNumber());
788         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(55)).getStartTransition();
789         Assertions.assertEquals(50, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
790         transition.resetDate(AbsoluteDate.PAST_INFINITY, true);
791         Assertions.assertEquals( 6, map.getSpansNumber());
792         Assertions.assertEquals(60, map.getFirstTransition().getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
793         Assertions.assertEquals(60, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(60.5)));
794         Assertions.assertEquals(50, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-1000)));
795     }
796 
797     @Test
798     public void testMoveTransitionPastCollision() {
799         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
800         for (int i = 0; i < 100; i +=10) {
801             map.addValidBetween(i,
802                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
803                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
804         }
805         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45)).getStartTransition();
806         Assertions.assertEquals(40, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
807         try {
808             transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-3600), false);
809             Assertions.fail("an exception should have been thrown");
810         } catch (OrekitException oe) {
811             Assertions.assertEquals(OrekitMessages.TRANSITION_DATES_COLLISION, oe.getSpecifier());
812             Assertions.assertEquals(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(   40), oe.getParts()[0]);
813             Assertions.assertEquals(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(-3600), oe.getParts()[1]);
814             Assertions.assertEquals(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(   30), oe.getParts()[2]);
815         }
816     }
817 
818     @Test
819     public void testMoveTowardsFutureNoOverride() {
820         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
821         for (int i = 0; i < 100; i +=10) {
822             map.addValidBetween(i,
823                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
824                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
825         }
826         Assertions.assertEquals(12, map.getSpansNumber());
827         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45)).getStartTransition();
828         Assertions.assertEquals(40, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
829         Assertions.assertEquals(40, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45.5)));
830         Assertions.assertEquals(40, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(44.5)));
831         transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45), true);
832         Assertions.assertEquals(12, map.getSpansNumber());
833         Assertions.assertEquals(45, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
834         Assertions.assertEquals(30, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(44.5)));
835         Assertions.assertEquals(40, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45.5)));
836     }
837 
838     @Test
839     public void testMoveTowardsFutureOverride() {
840         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
841         for (int i = 0; i < 100; i +=10) {
842             map.addValidBetween(i,
843                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
844                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
845         }
846         Assertions.assertEquals(12, map.getSpansNumber());
847         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45)).getStartTransition();
848         Assertions.assertEquals(40, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
849         Assertions.assertEquals(70, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(75.5)));
850         Assertions.assertEquals(70, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(74.5)));
851         transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(75), true);
852         Assertions.assertEquals( 9, map.getSpansNumber());
853         Assertions.assertEquals(75, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
854         Assertions.assertEquals(30, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(74.5)));
855         Assertions.assertEquals(70, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(75.5)));
856     }
857 
858     @Test
859     public void testMoveTowardsFutureOverrideAll() {
860         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
861         for (int i = 0; i < 100; i +=10) {
862             map.addValidBetween(i,
863                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
864                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
865         }
866         Assertions.assertEquals(12, map.getSpansNumber());
867         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45)).getStartTransition();
868         Assertions.assertEquals(40, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
869         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(110.5)));
870         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(109.5)));
871         transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(110), true);
872         Assertions.assertEquals( 6, map.getSpansNumber());
873         Assertions.assertEquals(110, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
874         Assertions.assertEquals(30, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(109.5)));
875         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(110.5)));
876     }
877 
878     @Test
879     public void testMoveTowardsFutureLast() {
880         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
881         for (int i = 0; i < 100; i +=10) {
882             map.addValidBetween(i,
883                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
884                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
885         }
886         Assertions.assertEquals(12, map.getSpansNumber());
887         TimeSpanMap.Transition<Integer> transition = map.getLastTransition();
888         Assertions.assertEquals(100, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
889         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(110.5)));
890         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(109.5)));
891         transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(110), true);
892         Assertions.assertEquals(12, map.getSpansNumber());
893         Assertions.assertEquals(110, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
894         Assertions.assertEquals(90,  map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(109.5)));
895         Assertions.assertNull(map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(110.5)));
896     }
897 
898     @Test
899     public void testMoveToFutureInfinity() {
900         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
901         for (int i = 0; i < 100; i +=10) {
902             map.addValidBetween(i,
903                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
904                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
905         }
906         Assertions.assertEquals(12, map.getSpansNumber());
907         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45)).getStartTransition();
908         Assertions.assertEquals(40, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
909         Assertions.assertEquals(70, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(75.5)));
910         Assertions.assertEquals(70, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(74.5)));
911         transition.resetDate(AbsoluteDate.FUTURE_INFINITY, true);
912         Assertions.assertEquals( 5, map.getSpansNumber());
913         Assertions.assertEquals(30, map.getLastTransition().getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
914         Assertions.assertEquals(30, map.get(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(1000)));
915     }
916 
917     @Test
918     public void testExpungeNumberEarliestForward() {
919         doTestExpunge(5, Double.POSITIVE_INFINITY, ExpungePolicy.EXPUNGE_EARLIEST, true,
920                       5, 50, 90, 25.0);
921     }
922 
923     @Test
924     public void testExpungeRangeEarliestForward() {
925         doTestExpunge(Integer.MAX_VALUE, 55.0, ExpungePolicy.EXPUNGE_EARLIEST, true,
926                       7, 30, 90, 25.0);
927     }
928 
929     @Test
930     public void testExpungeNumberEarliestBackward() {
931         doTestExpunge(5, Double.POSITIVE_INFINITY, ExpungePolicy.EXPUNGE_EARLIEST, false,
932                       5, 60, null, 25.0);
933     }
934 
935     @Test
936     public void testExpungeRangeEarliestBackward() {
937         doTestExpunge(Integer.MAX_VALUE, 55.0, ExpungePolicy.EXPUNGE_EARLIEST, false,
938                       7, 40, null, 25.0);
939     }
940 
941     @Test
942     public void testExpungeNumberLatestForward() {
943         doTestExpunge(5, Double.POSITIVE_INFINITY, ExpungePolicy.EXPUNGE_LATEST, true,
944                       5, null, 30, 75.0);
945     }
946 
947     @Test
948     public void testExpungeRangeLatestForward() {
949         doTestExpunge(Integer.MAX_VALUE, 55.0, ExpungePolicy.EXPUNGE_LATEST, true,
950                       7, null, 50, 75.0);
951     }
952 
953     @Test
954     public void testExpungeNumberLatestBackward() {
955         doTestExpunge(5, Double.POSITIVE_INFINITY, ExpungePolicy.EXPUNGE_LATEST, false,
956                       5, 0, 40, 75.0);
957     }
958 
959     @Test
960     public void testExpungeRangeLatestBackward() {
961         doTestExpunge(Integer.MAX_VALUE, 55.0, ExpungePolicy.EXPUNGE_LATEST, false,
962                       7, 0, 60, 75.0);
963     }
964 
965     @Test
966     public void testExpungeNumberFarthestForward() {
967         doTestExpunge(5, Double.POSITIVE_INFINITY, ExpungePolicy.EXPUNGE_FARTHEST, true,
968                       5, 50, 90, 25.0);
969     }
970 
971     @Test
972     public void testExpungeRangeFarthestForward() {
973         doTestExpunge(Integer.MAX_VALUE, 55.0, ExpungePolicy.EXPUNGE_FARTHEST, true,
974                       7, 30, 90, 25.0);
975     }
976 
977     @Test
978     public void testExpungeNumberFarthestBackward() {
979         doTestExpunge(5, Double.POSITIVE_INFINITY, ExpungePolicy.EXPUNGE_FARTHEST, false,
980                       5, 0, 40, 75.0);
981     }
982 
983     @Test
984     public void testExpungeRangeFarthestBackward() {
985         doTestExpunge(Integer.MAX_VALUE, 55.0, ExpungePolicy.EXPUNGE_FARTHEST, false,
986                       7, 0, 60, 75.0);
987     }
988 
989     private void doTestExpunge(final int maxNbSpans, final double maxRange, final ExpungePolicy expungePolicy,
990                                final boolean fillUpForward, final int expectedNbSpans,
991                                final Integer expectedFirst, final Integer expectedLast,
992                                final double invalidOffset) {
993         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
994         map.configureExpunge(maxNbSpans, maxRange, expungePolicy);
995         if (fillUpForward) {
996             for (int i = 0; i < 100; i += 10) {
997                 map.addValidAfter(i, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i), false);
998             }
999         } else {
1000             for (int i = 90; i >= 0; i -= 10) {
1001                 map.addValidBefore(i,  AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10), false);
1002             }
1003         }
1004         Assertions.assertEquals(expectedNbSpans, map.getSpansNumber());
1005         Assertions.assertEquals(expectedFirst,   map.getFirstSpan().getData());
1006         Assertions.assertEquals(expectedLast,    map.getLastSpan().getData());
1007         try {
1008             map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(invalidOffset));
1009             Assertions.fail("an exception should have been thrown");
1010         } catch (OrekitException oe) {
1011             Assertions.assertEquals(OrekitMessages.EXPUNGED_SPAN, oe.getSpecifier());
1012         }
1013     }
1014 
1015     @Test
1016     public void testLateExpungeConfiguration() {
1017 
1018         // initial setup
1019         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
1020         for (int i = 0; i < 100; i += 10) {
1021             map.addValidAfter(i, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i), false);
1022         }
1023         Assertions.assertEquals(  11, map.getSpansNumber());
1024         Assertions.assertNull(map.getFirstSpan().getData());
1025         Assertions.assertEquals(  90, map.getLastSpan().getData());
1026 
1027         // no changes just after configuration
1028         map.configureExpunge(5, Double.POSITIVE_INFINITY, ExpungePolicy.EXPUNGE_EARLIEST);
1029         Assertions.assertEquals(  11, map.getSpansNumber());
1030         Assertions.assertNull(map.getFirstSpan().getData());
1031         Assertions.assertEquals(  90, map.getLastSpan().getData());
1032 
1033         // changes applied after addition
1034         map.addValidAfter(100, AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(100), false);
1035         Assertions.assertEquals(  5, map.getSpansNumber());
1036         Assertions.assertEquals( 60, map.getFirstSpan().getData());
1037         Assertions.assertEquals(100, map.getLastSpan().getData());
1038 
1039     }
1040 
1041     @Test
1042     public void testMoveTransitionFutureCollision() {
1043         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
1044         for (int i = 0; i < 100; i +=10) {
1045             map.addValidBetween(i,
1046                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
1047                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
1048         }
1049         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45)).getStartTransition();
1050         Assertions.assertEquals(40, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
1051         try {
1052             transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(3600), false);
1053             Assertions.fail("an exception should have been thrown");
1054         } catch (OrekitException oe) {
1055             Assertions.assertEquals(OrekitMessages.TRANSITION_DATES_COLLISION, oe.getSpecifier());
1056             Assertions.assertEquals(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(  40), oe.getParts()[0]);
1057             Assertions.assertEquals(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(3600), oe.getParts()[1]);
1058             Assertions.assertEquals(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(  50), oe.getParts()[2]);
1059         }
1060     }
1061 
1062     private <T> void checkException(final TimeSpanMap<T> map,
1063                                     final Consumer<TimeSpanMap<T>> f,
1064                                     OrekitMessages expected) {
1065         try {
1066             f.accept(map);
1067             Assertions.fail("an exception should have been thrown");
1068         } catch (OrekitException oe) {
1069             Assertions.assertEquals(expected, oe.getSpecifier());
1070         }
1071     }
1072 
1073     private <T> void checkCountConsistency(final TimeSpanMap<T> map) {
1074         final int count1 = map.getSpansNumber();
1075         int count2 = 0;
1076         for (Span<T> span = map.getFirstSpan(); span != null; span = span.next()) {
1077             ++count2;
1078         }
1079         Assertions.assertEquals(count1, count2);
1080     }
1081 
1082     @BeforeEach
1083     public void setUp() {
1084         Utils.setDataRoot("regular-data");
1085     }
1086 
1087 }