1   /* Copyright 2013-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.rugged.errors;
18  
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertTrue;
22  
23  import java.io.BufferedReader;
24  import java.io.BufferedWriter;
25  import java.io.File;
26  import java.io.FileInputStream;
27  import java.io.FileOutputStream;
28  import java.io.FileReader;
29  import java.io.IOException;
30  import java.io.InputStreamReader;
31  import java.io.OutputStreamWriter;
32  import java.io.PrintWriter;
33  import java.lang.reflect.Constructor;
34  import java.lang.reflect.InvocationTargetException;
35  import java.lang.reflect.Method;
36  import java.net.URISyntaxException;
37  import java.nio.charset.StandardCharsets;
38  import java.util.ArrayList;
39  import java.util.List;
40  import java.util.Locale;
41  
42  import org.hipparchus.analysis.differentiation.DSFactory;
43  import org.hipparchus.analysis.differentiation.DerivativeStructure;
44  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
45  import org.hipparchus.geometry.euclidean.threed.Vector3D;
46  import org.junit.jupiter.api.Assertions;
47  import org.junit.jupiter.api.Test;
48  import org.junit.jupiter.api.io.TempDir;
49  import org.orekit.bodies.GeodeticPoint;
50  import org.orekit.data.DataContext;
51  import org.orekit.data.DirectoryCrawler;
52  import org.orekit.rugged.api.Rugged;
53  import org.orekit.rugged.linesensor.SensorPixel;
54  import org.orekit.rugged.refraction.MultiLayerModel;
55  import org.orekit.rugged.utils.DerivativeGenerator;
56  import org.orekit.time.AbsoluteDate;
57  import org.orekit.time.TimeScalesFactory;
58  import org.orekit.utils.ParameterDriver;
59  
60  public class DumpReplayerTest {
61  
62      @TempDir
63      public File tempFolder;
64  
65      @Test
66      public void testDirectLoc01() throws URISyntaxException, IOException {
67  
68          String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
69          DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
70  
71          String dumpPath = getClass().getClassLoader().getResource("replay/replay-direct-loc-01.txt").toURI().getPath();
72          DumpReplayer replayer = new DumpReplayer();
73          replayer.parse(new File(dumpPath));
74          Rugged rugged = replayer.createRugged();
75          DumpReplayer.Result[] results = replayer.execute(rugged);
76  
77          Assertions.assertEquals(5, results.length);
78          for (final DumpReplayer.Result result : results) {
79              GeodeticPoint expectedGP = (GeodeticPoint) result.getExpected();
80              GeodeticPoint replayedGP = (GeodeticPoint) result.getReplayed();
81              double distance = Vector3D.distance(rugged.getEllipsoid().transform(expectedGP),
82                                                  rugged.getEllipsoid().transform(replayedGP));
83              Assertions.assertEquals(0.0, distance, 6.0e-8);
84          }
85  
86      }
87  
88      @Test
89      public void testDirectLoc02() throws URISyntaxException, IOException {
90  
91          String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
92          DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
93  
94          String dumpPath = getClass().getClassLoader().getResource("replay/replay-direct-loc-02.txt").toURI().getPath();
95          DumpReplayer replayer = new DumpReplayer();
96          replayer.parse(new File(dumpPath));
97          Rugged rugged = replayer.createRugged();
98          DumpReplayer.Result[] results = replayer.execute(rugged);
99  
100         Assertions.assertEquals(1, results.length);
101         for (final DumpReplayer.Result result : results) {
102             GeodeticPoint expectedGP = (GeodeticPoint) result.getExpected();
103             GeodeticPoint replayedGP = (GeodeticPoint) result.getReplayed();
104             double distance = Vector3D.distance(rugged.getEllipsoid().transform(expectedGP),
105                                                 rugged.getEllipsoid().transform(replayedGP));
106             Assertions.assertEquals(0.0, distance, 1.0e-8);
107         }
108 
109     }
110 
111     @Test
112     public void testDirectLoc03() throws URISyntaxException, IOException {
113 
114         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
115         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
116 
117         String dumpPath = getClass().getClassLoader().getResource("replay/replay-direct-loc-03.txt").toURI().getPath();
118         DumpReplayer replayer = new DumpReplayer();
119         replayer.parse(new File(dumpPath));
120         Rugged rugged = replayer.createRugged();
121         DumpReplayer.Result[] results = replayer.execute(rugged);
122 
123         Assertions.assertEquals(1, results.length);
124         for (final DumpReplayer.Result result : results) {
125             GeodeticPoint expectedGP = (GeodeticPoint) result.getExpected();
126             GeodeticPoint replayedGP = (GeodeticPoint) result.getReplayed();
127             double distance = Vector3D.distance(rugged.getEllipsoid().transform(expectedGP),
128                                                 rugged.getEllipsoid().transform(replayedGP));
129             Assertions.assertEquals(0.0, distance, 1.0e-8);
130         }
131 
132     }
133 
134     @Test
135     public void testDirectLoc04() throws URISyntaxException, IOException {
136 
137         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
138         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
139 
140         String dumpPath = getClass().getClassLoader().getResource("replay/replay-direct-loc-04.txt").toURI().getPath();
141         File dump = File.createTempFile("junit", null, tempFolder);
142         DumpManager.activate(dump);
143         DumpReplayer replayer = new DumpReplayer();
144         replayer.parse(new File(dumpPath));
145         Rugged rugged = replayer.createRugged();
146         DumpReplayer.Result[] results = replayer.execute(rugged);
147         DumpManager.deactivate();
148 
149         Assertions.assertEquals(3, results.length);
150         for (final DumpReplayer.Result result : results) {
151             GeodeticPoint expectedGP = (GeodeticPoint) result.getExpected();
152             GeodeticPoint replayedGP = (GeodeticPoint) result.getReplayed();
153             double distance = Vector3D.distance(rugged.getEllipsoid().transform(expectedGP),
154                                                 rugged.getEllipsoid().transform(replayedGP));
155             Assertions.assertEquals(0.0, distance, 1.0e-8);
156         }
157 
158         try (FileReader fr = new FileReader(dump);
159              BufferedReader br = new BufferedReader(fr)) {
160             Assertions.assertEquals(12, br.lines().count());
161         }
162 
163     }
164 
165     @Test
166     public void testDirectLocNull() throws URISyntaxException, IOException {
167 
168         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
169         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
170 
171         File tempFile = File.createTempFile("junit", null, tempFolder);
172         try (FileOutputStream   fos = new FileOutputStream(tempFile);
173              OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
174              BufferedWriter     bw  = new BufferedWriter(osw)) {
175 
176             // Create a dump file with NULL result for direct location
177             createDataForCreateRugged(bw);
178             bw.write("direct location: date 2012-01-01T12:29:30.85Z position 0.0e+00  0.0e+00  0.0e+00 " + 
179                      "los -2.2e-02 -9.1e-02 9.9e-01 lightTime false aberration false refraction false");
180             bw.newLine();
181             bw.write("direct location result: NULL");           
182          }
183         DumpReplayer replayer = new DumpReplayer();
184         replayer.parse(tempFile);
185         Rugged rugged = replayer.createRugged();
186         DumpReplayer.Result[] results = replayer.execute(rugged);
187 
188         assertTrue(results[0].getExpected() == null);
189         tempFile.delete();
190     }
191 
192     @Test
193     public void testInverseLoc01() throws URISyntaxException, IOException {
194 
195         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
196         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
197 
198         String dumpPath = getClass().getClassLoader().getResource("replay/replay-inverse-loc-01.txt").toURI().getPath();
199         DumpReplayer replayer = new DumpReplayer();
200         replayer.parse(new File(dumpPath));
201         Rugged rugged = replayer.createRugged();
202         DumpReplayer.Result[] results = replayer.execute(rugged);
203 
204         Assertions.assertEquals(1, results.length);
205         for (final DumpReplayer.Result result : results) {
206             SensorPixel expectedSP = (SensorPixel) result.getExpected();
207             SensorPixel replayedSP = (SensorPixel) result.getReplayed();
208             Assertions.assertEquals(expectedSP.getLineNumber(),  replayedSP.getLineNumber(),  1.0e-6);
209             Assertions.assertEquals(expectedSP.getPixelNumber(), replayedSP.getPixelNumber(), 1.0e-6);
210         }
211 
212     }
213 
214     @Test
215     public void testInverseLoc02() throws URISyntaxException, IOException {
216 
217         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
218         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
219 
220         String dumpPath = getClass().getClassLoader().getResource("replay/replay-inverse-loc-02.txt").toURI().getPath();
221         DumpReplayer replayer = new DumpReplayer();
222         replayer.parse(new File(dumpPath));
223         Rugged rugged = replayer.createRugged();
224         DumpReplayer.Result[] results = replayer.execute(rugged);
225 
226         Assertions.assertEquals(3, results.length);
227         for (final DumpReplayer.Result result : results) {
228             SensorPixel expectedSP = (SensorPixel) result.getExpected();
229             SensorPixel replayedSP = (SensorPixel) result.getReplayed();
230             Assertions.assertEquals(expectedSP.getLineNumber(),  replayedSP.getLineNumber(),  1.0e-6);
231             Assertions.assertEquals(expectedSP.getPixelNumber(), replayedSP.getPixelNumber(), 1.0e-6);
232         }
233 
234     }
235 
236     @Test
237     public void testInverseLoc03() throws URISyntaxException, IOException {
238 
239         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
240         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
241 
242         String dumpPath = getClass().getClassLoader().getResource("replay/replay-inverse-loc-03.txt").toURI().getPath();
243         DumpReplayer replayer = new DumpReplayer();
244         replayer.parse(new File(dumpPath));
245         Rugged rugged = replayer.createRugged();
246         DumpReplayer.Result[] results = replayer.execute(rugged);
247 
248         Assertions.assertEquals(1, results.length);
249         for (final DumpReplayer.Result result : results) {
250             SensorPixel expectedSP = (SensorPixel) result.getExpected();
251             SensorPixel replayedSP = (SensorPixel) result.getReplayed();
252             Assertions.assertEquals(expectedSP.getLineNumber(),  replayedSP.getLineNumber(),  1.0e-6);
253             Assertions.assertEquals(expectedSP.getPixelNumber(), replayedSP.getPixelNumber(), 1.0e-6);
254         }
255 
256     }
257     
258     @Test
259     public void testInverseLocNull() throws URISyntaxException, IOException {
260 
261         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
262         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
263 
264         File tempFile = File.createTempFile("junit", null, tempFolder);
265         try (FileOutputStream   fos = new FileOutputStream(tempFile);
266              OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
267              BufferedWriter     bw  = new BufferedWriter(osw)) {
268 
269             // Create a dump file with NULL result for inverse location
270             createDataForInvLocResult(bw);
271             bw.write("inverse location result: NULL");           
272          }
273         DumpReplayer replayer = new DumpReplayer();
274         replayer.parse(tempFile);
275         Rugged rugged = replayer.createRugged();
276         DumpReplayer.Result[] results = replayer.execute(rugged);
277 
278         assertTrue(results[0].getExpected() == null);
279         tempFile.delete();
280     }
281 
282    @Test
283     public void testCorruptedFiles() throws URISyntaxException, IOException {
284 
285         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
286         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
287 
288         File folder = new File(getClass().getClassLoader().getResource("replay/replay-direct-loc-01.txt").toURI().getPath()).getParentFile();
289         for (final File file : folder.listFiles()) {
290 
291             // split all data lines into fields
292             final List<String[]> lines = new ArrayList<>();
293             try (FileInputStream fis = new FileInputStream(file);
294                  InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
295                  BufferedReader br = new BufferedReader(isr)) {
296                 br.lines().
297                    filter(line -> {
298                        String trimmed = line.trim();
299                        return trimmed.length() > 0 && !trimmed.startsWith("#");
300                    }).
301                    forEach(line -> lines.add(line.split("\\s+")));
302             }
303 
304             // for each field of each line, delete the field and check parsing fails
305             for (int i = 0; i < lines.size(); ++i) {
306                 for (int j = 0; j < lines.get(i).length; ++j) {
307                     final File corrupted = File.createTempFile("junit", null, tempFolder);
308                     try (PrintWriter pw = new PrintWriter(corrupted, "UTF-8")) {
309                         for (int k = 0; k < lines.size(); ++k) {
310                             for (int l = 0; l < lines.get(k).length; ++l) {
311                                 if (k != i || l != j) {
312                                     pw.print(' ');
313                                     pw.print(lines.get(k)[l]);
314                                 }
315                             }
316                             pw.println();
317                         }
318                     }
319                     try {
320                         new DumpReplayer().parse(corrupted);
321                         Assertions.fail("an exception should have been thrown");
322                     } catch (RuggedException re) {
323                         Assertions.assertEquals(RuggedMessages.CANNOT_PARSE_LINE, re.getSpecifier());
324                         Assertions.assertEquals(i + 1, ((Integer) re.getParts()[0]).intValue());
325                         Assertions.assertEquals(corrupted, re.getParts()[1]);
326                     }
327                     corrupted.delete();
328                 }
329             }
330         }
331 
332     }
333 
334     @Test
335     public void testDirectLocIssue376_01() throws URISyntaxException, IOException {
336 
337         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
338         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
339 
340         String dumpPath = getClass().getClassLoader().getResource("replay/replay-direct-loc-Issue376-01.txt").toURI().getPath();
341 
342         DumpReplayer replayer = new DumpReplayer();
343         replayer.parse(new File(dumpPath));
344         Rugged rugged = replayer.createRugged();
345         DumpReplayer.Result[] results = replayer.execute(rugged);
346 
347         GeodeticPoint expectedGP = (GeodeticPoint) results[0].getExpected();
348         GeodeticPoint replayedGP = (GeodeticPoint) results[0].getReplayed();
349         double distance = Vector3D.distance(rugged.getEllipsoid().transform(expectedGP),
350                                             rugged.getEllipsoid().transform(replayedGP));
351         Assertions.assertEquals(0.0, distance, 1.0e-8);
352     }
353 
354     @Test
355     public void testDirectLocIssue376_02() throws URISyntaxException, IOException {
356 
357         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
358         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
359 
360         String dumpPath = getClass().getClassLoader().getResource("replay/replay-direct-loc-Issue376-02.txt").toURI().getPath();
361 
362         DumpReplayer replayer = new DumpReplayer();
363         replayer.parse(new File(dumpPath));
364         Rugged rugged = replayer.createRugged();
365         DumpReplayer.Result[] results = replayer.execute(rugged);
366 
367         GeodeticPoint expectedGP = (GeodeticPoint) results[0].getExpected();
368         GeodeticPoint replayedGP = (GeodeticPoint) results[0].getReplayed();
369         double distance = Vector3D.distance(rugged.getEllipsoid().transform(expectedGP),
370                                             rugged.getEllipsoid().transform(replayedGP));
371         Assertions.assertEquals(0.0, distance, 1.0e-8);
372     }
373 
374     @Test
375     public void testDirectLocIssue376_03() throws URISyntaxException, IOException {
376 
377         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
378         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
379 
380         String dumpPath = getClass().getClassLoader().getResource("replay/replay-direct-loc-Issue376-03.txt").toURI().getPath();
381 
382         DumpReplayer replayer = new DumpReplayer();
383         replayer.parse(new File(dumpPath));
384         Rugged rugged = replayer.createRugged();
385         DumpReplayer.Result[] results = replayer.execute(rugged);
386 
387         for (int i= 0; i < results.length; i++) {
388             GeodeticPoint expectedGP = (GeodeticPoint) results[i].getExpected();
389             GeodeticPoint replayedGP = (GeodeticPoint) results[i].getReplayed();
390             double distance = Vector3D.distance(rugged.getEllipsoid().transform(expectedGP),
391                     rugged.getEllipsoid().transform(replayedGP));
392             Assertions.assertEquals(0.0, distance, 5.0e-8);
393         }
394     }
395 
396     @Test
397     public void testCreateRuggedWithAtmosphere() throws URISyntaxException, IOException {
398 
399         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
400         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
401 
402         File tempFile = File.createTempFile("junit", null, tempFolder);
403         try (FileOutputStream   fos = new FileOutputStream(tempFile);
404              OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
405              BufferedWriter     bw  = new BufferedWriter(osw)) {
406 
407             // CreateRugged with atmospheric refraction
408             bw.write("direct location: date 2012-01-01T12:30:00.0Z position 1.5e+00  0.e+00 -2.e-01 "+ 
409                      "los  0.e+00 -7.5e-01  6.5e-01 lightTime true aberration true refraction true");
410             bw.newLine();
411             createDataForCreateRugged(bw);
412          }
413         DumpReplayer replayer = new DumpReplayer();
414         replayer.parse(tempFile);
415         Rugged rugged = replayer.createRugged();
416         
417         assertTrue(rugged.getRefractionCorrection().getClass().isInstance(new MultiLayerModel(rugged.getEllipsoid())));
418         tempFile.delete();
419     }
420 
421     @Test
422     public void testCreateRuggedNoDEMdata() throws URISyntaxException, IOException {
423 
424         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
425         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
426 
427         File tempFile = File.createTempFile("junit", null, tempFolder);
428         try (FileOutputStream   fos = new FileOutputStream(tempFile);
429              OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
430              BufferedWriter     bw  = new BufferedWriter(osw)) {
431 
432             // CreateRugged with atmospheric refraction
433             bw.write("direct location: date 2012-01-01T12:30:00.0Z position 1.5e+00  0.e+00 -2.e-01 "+ 
434                      "los  0.e+00 -7.5e-01  6.5e-01 lightTime true aberration true refraction false");
435             bw.newLine();
436             createDataForCreateRugged(bw);
437             bw.write("algorithm: DUVENHAGE");
438          }
439         DumpReplayer replayer = new DumpReplayer();
440         replayer.parse(tempFile);
441         Rugged rugged = replayer.createRugged();
442 
443         try {
444             replayer.execute(rugged);
445             Assertions.fail("an exception should have been thrown");
446         } catch (RuggedException re) {
447             // as the execution stops in the TilesCache: one must reset the DumpManager state
448             DumpManager.endNicely();
449             Assertions.assertEquals(RuggedMessages.NO_DEM_DATA, re.getSpecifier());
450         } 
451         tempFile.delete();
452     }
453     
454     @Test
455     public void testLineParserBadKey() throws URISyntaxException, IOException {
456 
457         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
458         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
459 
460         File tempFile = File.createTempFile("junit", null, tempFolder);
461         try (FileOutputStream   fos = new FileOutputStream(tempFile);
462              OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
463              BufferedWriter     bw  = new BufferedWriter(osw)) {
464             // this empty line to ensure coverage
465             bw.write("");
466             bw.newLine();
467             // LineParser.parse: case bad key
468             bw.write("dummy : dummy");
469         }
470         DumpReplayer replayer = new DumpReplayer();
471         try {
472             replayer.parse(tempFile);
473             Assertions.fail("an exception should have been thrown");
474         } catch (RuggedException re) {
475             Assertions.assertEquals(RuggedMessages.CANNOT_PARSE_LINE, re.getSpecifier());
476             Assertions.assertEquals(2, ((Integer) re.getParts()[0]).intValue());
477             Assertions.assertEquals(tempFile, re.getParts()[1]);
478             Assertions.assertTrue(re.getParts()[2].toString().contains("dummy : dummy"));
479         }
480         tempFile.delete();
481     }
482     
483     @Test
484     public void testLineParserEndColon() throws URISyntaxException, IOException {
485 
486         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
487         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
488 
489         File tempFile = File.createTempFile("junit", null, tempFolder);
490         try (FileOutputStream   fos = new FileOutputStream(tempFile);
491              OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
492              BufferedWriter     bw  = new BufferedWriter(osw)) {
493             // LineParser.parse: case colon at end of line
494             bw.write("direct location result:");
495         }
496         DumpReplayer replayer = new DumpReplayer();
497         try {
498             replayer.parse(tempFile);
499             Assertions.fail("an exception should have been thrown");
500         } catch (RuggedException re) {
501             Assertions.assertEquals(RuggedMessages.CANNOT_PARSE_LINE, re.getSpecifier());
502             Assertions.assertEquals(1, ((Integer) re.getParts()[0]).intValue());
503             Assertions.assertEquals(tempFile, re.getParts()[1]);
504         }
505         tempFile.delete();
506     }
507 
508     @Test
509     public void testLineParserNoColon() throws URISyntaxException, IOException {
510 
511         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
512         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
513 
514         File tempFile = File.createTempFile("junit", null, tempFolder);
515         try (FileOutputStream   fos = new FileOutputStream(tempFile);
516                 OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
517                 BufferedWriter     bw  = new BufferedWriter(osw)) {
518             // LineParser.parse case no colon
519             bw.write("sensorName s0 nbPixels 200 position  1.5e+00  0.0e+00 -2.0e-01");
520         }
521         DumpReplayer replayer = new DumpReplayer();
522         try {
523             replayer.parse(tempFile);
524             Assertions.fail("an exception should have been thrown");
525         } catch (RuggedException re) {
526             Assertions.assertEquals(RuggedMessages.CANNOT_PARSE_LINE, re.getSpecifier());
527             Assertions.assertEquals(1, ((Integer) re.getParts()[0]).intValue());
528             Assertions.assertEquals(tempFile, re.getParts()[1]);
529         }
530         tempFile.delete();
531     }
532 
533     @Test
534     public void testParsedSensorGetDateGetLineCoverage() throws URISyntaxException, ClassNotFoundException, InstantiationException, 
535                                                                 IllegalAccessException, IllegalArgumentException, 
536                                                                 InvocationTargetException, NoSuchMethodException, SecurityException {
537 
538         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
539         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
540 
541         // ParsedSensor inner class
542         Class<?> innerClass = Class.forName("org.orekit.rugged.errors.DumpReplayer$ParsedSensor");
543         Constructor<?>[] constructors = innerClass.getDeclaredConstructors();
544         constructors[0].setAccessible(true);
545         Object parsedSensor = constructors[0].newInstance("dummy");
546 
547 
548         Method getLine = innerClass.getDeclaredMethod("getLine", AbsoluteDate.class);
549         getLine.setAccessible(true);
550         Method getDate = innerClass.getDeclaredMethod("getDate", double.class);
551         getDate.setAccessible(true);
552         Method setDatation = innerClass.getDeclaredMethod("setDatation", double.class, AbsoluteDate.class);
553         setDatation.setAccessible(true);
554 
555         // datation with only one data
556         AbsoluteDate date0 = new AbsoluteDate("2012-01-06T02:27:16.139", TimeScalesFactory.getUTC());
557         setDatation.invoke(parsedSensor, 100., date0);
558 
559         AbsoluteDate date = date0.shiftedBy(5.);
560         double foundLine = (double) getLine.invoke(parsedSensor, date);
561         assertEquals(100., foundLine, 1.e-15);
562 
563         double line = 105.;
564         AbsoluteDate foundDate = (AbsoluteDate) getDate.invoke(parsedSensor, line);
565         assertEquals("2012-01-06T02:27:16.139",foundDate.toString(TimeScalesFactory.getUTC()));
566 
567         // add datations data
568         AbsoluteDate date1 = date0.shiftedBy(10.);
569         AbsoluteDate date2 = date1.shiftedBy(10.);
570 
571         setDatation.invoke(parsedSensor, 120., date1);
572         setDatation.invoke(parsedSensor, 150., date2);
573         foundLine = (double) getLine.invoke(parsedSensor, date);
574         assertEquals(110., foundLine, 1.e-15);
575 
576         date = date2.shiftedBy(5.);
577         foundLine = (double) getLine.invoke(parsedSensor, date);
578         assertEquals(165., foundLine, 1.e-15);
579 
580         date = date0.shiftedBy(-5.);
581         foundLine = (double) getLine.invoke(parsedSensor, date);
582         assertEquals(90., foundLine, 1.e-15);
583 
584     }
585     
586     @Test
587     public void testParsedSensorGetLOSCoverage() throws URISyntaxException, ClassNotFoundException, InstantiationException, 
588                                                         IllegalAccessException, IllegalArgumentException, 
589                                                         InvocationTargetException, NoSuchMethodException, SecurityException {
590 
591         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
592         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
593 
594         // ParsedSensor inner class
595         Class<?> innerClass = Class.forName("org.orekit.rugged.errors.DumpReplayer$ParsedSensor");
596         Constructor<?>[] constructors = innerClass.getDeclaredConstructors();
597         constructors[0].setAccessible(true);
598         Object parsedSensor = constructors[0].newInstance("dummy");
599 
600         AbsoluteDate date = new AbsoluteDate("2012-01-06T02:27:16.139", TimeScalesFactory.getUTC());
601 
602         // ParsedSensor.getLOS RunTimeException
603         Method getLos = innerClass.getDeclaredMethod("getLOS", int.class, AbsoluteDate.class);
604         getLos.setAccessible(true);
605         try {
606             getLos.invoke(parsedSensor, 1, date);
607             Assertions.fail("an exception should have been thrown");
608         } catch (InvocationTargetException ite) {
609             RuggedInternalError rie = (RuggedInternalError) ite.getTargetException();
610             assertEquals(RuggedMessages.INTERNAL_ERROR, rie.getSpecifier());
611             assertEquals("https://gitlab.orekit.org/orekit/rugged/issues", rie.getParts()[0]);
612             assertTrue(rie.getMessage(Locale.FRENCH).startsWith("erreur interne"));
613         }
614     }
615     
616     @Test
617     public void testParsedSensorLOSCoverage() throws URISyntaxException, ClassNotFoundException, InstantiationException, 
618                                                      IllegalAccessException, IllegalArgumentException, 
619                                                      InvocationTargetException, NoSuchMethodException, SecurityException {
620 
621         String orekitPath = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
622         DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitPath)));
623 
624         // ParsedSensor inner class
625         Class<?> innerClass = Class.forName("org.orekit.rugged.errors.DumpReplayer$ParsedSensor");
626         Constructor<?>[] constructors = innerClass.getDeclaredConstructors();
627         constructors[0].setAccessible(true);
628         Object parsedSensor = constructors[0].newInstance("dummy");
629 
630         AbsoluteDate date0 = new AbsoluteDate("2012-01-06T02:27:16.139", TimeScalesFactory.getUTC());
631         AbsoluteDate date = date0.shiftedBy(5.);
632         AbsoluteDate date1 = date0.shiftedBy(10.);
633         AbsoluteDate date2 = date1.shiftedBy(10.);
634 
635         // ParsedSensor.setLos
636         Method setLos = innerClass.getDeclaredMethod("setLOS", AbsoluteDate.class, int.class, Vector3D.class);
637         setLos.setAccessible(true);
638         setLos.invoke(parsedSensor, date, 1, new Vector3D(0, 0, 0));
639         setLos.invoke(parsedSensor, date1, 100, new Vector3D(1, 1, 1));
640         setLos.invoke(parsedSensor, date2, 200, new Vector3D(2, 2, 2));
641         setLos.invoke(parsedSensor, date2.shiftedBy(10.), 200, new Vector3D(3, 3, 3));
642  
643         // ParsedSensor.getLOSDerivatives
644         // Needs some LOS to be set
645         Method getLOSDerivatives = innerClass.getDeclaredMethod("getLOSDerivatives", int.class, AbsoluteDate.class, DerivativeGenerator.class);
646         getLOSDerivatives.setAccessible(true);
647 
648         final DSFactory factory = new DSFactory(1, 1);
649         DerivativeGenerator<DerivativeStructure> generator = new DerivativeGenerator<DerivativeStructure>() {
650             @Override
651             public List<ParameterDriver> getSelected() {
652                 return null;
653             }
654             @Override
655             public DerivativeStructure constant(final double value) {
656                 return factory.constant(value);
657             }
658             @Override
659             public DerivativeStructure variable(final ParameterDriver driver) {
660                 return null;
661             }
662         };
663         @SuppressWarnings("unchecked")
664         FieldVector3D<DerivativeStructure> fv= (FieldVector3D<DerivativeStructure>) getLOSDerivatives.invoke(parsedSensor, 1, date, generator);
665         assertEquals(0., fv.getX().getValue(), 1.e-15);
666         assertEquals(0., fv.getY().getValue(), 1.e-15);
667         assertEquals(0., fv.getZ().getValue(), 1.e-15);
668         
669         
670        // ParsedSensor.getParametersDrivers
671        Method getParametersDrivers = innerClass.getDeclaredMethod("getParametersDrivers");
672        getParametersDrivers.setAccessible(true);
673        
674        getParametersDrivers.invoke(parsedSensor);
675     }
676     
677     private void createDataForCreateRugged(BufferedWriter bw) throws IOException {
678         
679         bw.write("ellipsoid: ae  6.378137e+06 f  3.35e-03 frame ITRF_CIO_CONV_2010_SIMPLE_EOP");
680         bw.newLine();
681         bw.write("span: minDate 2012-01-01T12:29:00.85Z maxDate 2012-01-01T12:30:00.15Z " + 
682                  "tStep  1.e-03 tolerance  5.e+00 inertialFrame EME2000");
683         bw.newLine();
684         bw.write("transform: index 150 body r -8.0e-01 -3.4e-04  4.8e-04 -5.8e-01 Ω -8.7e-08  1.2e-09 -7.3e-05 " + 
685                  "ΩDot -1.6e-16  8.9e-17  1.9e-19 spacecraft p  1.3e+04  3.1e+03 -7.1e+06 v -3.1e+01 -8.0e+00  8.2e+00 " + 
686                  "a -9.3e-01 -8.3e+00  1.3e-03 r -6.8e-01  4.1e-01 -3.8e-01  4.6e-01 Ω -1.e-03  1.9e-04  1.6e-04 " + 
687                  "ΩDot -3.6e-07  2.0e-07 -1.2e-06");
688         bw.newLine();
689     }
690     
691     private void createDataForInvLocResult(BufferedWriter bw) throws IOException {
692         
693         bw.write("inverse location: sensorName s0 latitude  1.4e+00 longitude -8.8e-01 elevation 3.1e+01 minLine -23040 maxLine 39851 " +
694                  "lightTime false aberration false refraction false");
695         bw.newLine();
696         bw.write("ellipsoid: ae  6.378e+06 f 3.35e-03 frame ITRF_CIO_CONV_2010_SIMPLE_EOP");
697         bw.newLine();
698         bw.write("span: minDate 2015-07-07T18:38:55.0Z maxDate 2015-07-07T18:40:35.8Z tStep 1.e-01 tolerance 1.e+01 inertialFrame EME2000");
699         bw.newLine();
700         bw.write("transform: index 516 body r -2.2e-01 -7.3e-04 1.8e-04 -9.7e-01 Ω -1.1e-07 3.6e-09 -7.2e-05 " + 
701                  "ΩDot 0. 0. 0. spacecraft p -3.6e+02 -4.2e+02 -7.1e+06 v -7.4e+01 -3.4e+02 -1.8e-01 " + 
702                  "a 0. 0. 0. r -6.2e-02 7.4e-01 6.5e-01 4.1e-02 Ω 0. 0. 0. " + 
703                  "ΩDot 0. 0. 0.");
704         bw.newLine();
705         bw.write("sensor: sensorName s0 nbPixels 2552 position  0. 0. 0.");
706         bw.newLine();
707         bw.write("sensor mean plane: sensorName s0 minLine -23040 maxLine 39851 maxEval 50 accuracy 1.e-02 " + 
708                  "normal 9.e-01 -2.6e-02  1.8e-02 cachedResults 1 lineNumber 2.4e+04 date 2015-07-07T18:40:12.4Z " + 
709                  "target 5.8e+05 -7.1e+05 6.2e+06 targetDirection -1.5e-02 8.9e-02 9.9e-01 -2.0e-07 2.1e-08 -2.0e-07");
710         bw.newLine();
711         bw.write("sensor datation: sensorName s0 lineNumber 8.4e+03 date 2015-07-07T18:39:46.5Z");
712         bw.newLine();
713         bw.write("sensor rate: sensorName s0 lineNumber 2.4e+04 rate 6.3e+02");
714         bw.newLine();
715     }
716 }