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 testMoveTransitionFutureCollision() {
919         final TimeSpanMap<Integer> map = new TimeSpanMap<>(null);
920         for (int i = 0; i < 100; i +=10) {
921             map.addValidBetween(i,
922                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i),
923                                 AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(i + 10));
924         }
925         TimeSpanMap.Transition<Integer> transition = map.getSpan(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(45)).getStartTransition();
926         Assertions.assertEquals(40, transition.getDate().durationFrom(AbsoluteDate.ARBITRARY_EPOCH));
927         try {
928             transition.resetDate(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(3600), false);
929             Assertions.fail("an exception should have been thrown");
930         } catch (OrekitException oe) {
931             Assertions.assertEquals(OrekitMessages.TRANSITION_DATES_COLLISION, oe.getSpecifier());
932             Assertions.assertEquals(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(  40), oe.getParts()[0]);
933             Assertions.assertEquals(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(3600), oe.getParts()[1]);
934             Assertions.assertEquals(AbsoluteDate.ARBITRARY_EPOCH.shiftedBy(  50), oe.getParts()[2]);
935         }
936     }
937 
938     private <T> void checkException(final TimeSpanMap<T> map,
939                                     final Consumer<TimeSpanMap<T>> f,
940                                     OrekitMessages expected) {
941         try {
942             f.accept(map);
943             Assertions.fail("an exception should have been thrown");
944         } catch (OrekitException oe) {
945             Assertions.assertEquals(expected, oe.getSpecifier());
946         }
947     }
948 
949     private <T> void checkCountConsistency(final TimeSpanMap<T> map) {
950         final int count1 = map.getSpansNumber();
951         int count2 = 0;
952         for (Span<T> span = map.getFirstSpan(); span != null; span = span.next()) {
953             ++count2;
954         }
955         Assertions.assertEquals(count1, count2);
956     }
957 
958     @BeforeEach
959     public void setUp() {
960         Utils.setDataRoot("regular-data");
961     }
962 
963 }