View Javadoc
1   package nom.tam.fits.test;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertFalse;
5   import static org.junit.Assert.assertNotEquals;
6   import static org.junit.Assert.assertTrue;
7   
8   import java.io.ByteArrayOutputStream;
9   import java.io.File;
10  import java.io.FileInputStream;
11  import java.io.RandomAccessFile;
12  import java.nio.file.Files;
13  import java.nio.file.StandardCopyOption;
14  import java.util.Arrays;
15  
16  import org.junit.Ignore;
17  import org.junit.Test;
18  
19  import nom.tam.fits.BasicHDU;
20  import nom.tam.fits.Fits;
21  import nom.tam.fits.FitsException;
22  import nom.tam.fits.FitsFactory;
23  import nom.tam.fits.FitsIntegrityException;
24  import nom.tam.fits.Header;
25  import nom.tam.fits.ImageData;
26  import nom.tam.fits.ImageHDU;
27  import nom.tam.fits.header.Bitpix;
28  import nom.tam.fits.header.Standard;
29  import nom.tam.fits.utilities.FitsCheckSum;
30  import nom.tam.util.ArrayDataOutput;
31  import nom.tam.util.FitsFile;
32  import nom.tam.util.FitsIO;
33  import nom.tam.util.FitsInputStream;
34  import nom.tam.util.FitsOutputStream;
35  import nom.tam.util.RandomAccess;
36  import nom.tam.util.test.ThrowAnyException;
37  
38  /*
39   * #%L
40   * nom.tam FITS library
41   * %%
42   * Copyright (C) 2004 - 2024 nom-tam-fits
43   * %%
44   * This is free and unencumbered software released into the public domain.
45   *
46   * Anyone is free to copy, modify, publish, use, compile, sell, or
47   * distribute this software, either in source code form or as a compiled
48   * binary, for any purpose, commercial or non-commercial, and by any
49   * means.
50   *
51   * In jurisdictions that recognize copyright laws, the author or authors
52   * of this software dedicate any and all copyright interest in the
53   * software to the public domain. We make this dedication for the benefit
54   * of the public at large and to the detriment of our heirs and
55   * successors. We intend this dedication to be an overt act of
56   * relinquishment in perpetuity of all present and future rights to this
57   * software under copyright law.
58   *
59   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
60   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
61   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
62   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
63   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
64   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
65   * OTHER DEALINGS IN THE SOFTWARE.
66   * #L%
67   */
68  
69  import static nom.tam.fits.header.Checksum.CHECKSUM;
70  import static nom.tam.fits.header.Checksum.DATASUM;
71  
72  /**
73   * @author tmcglynn
74   */
75  public class ChecksumTest {
76  
77      @Test(expected = IllegalArgumentException.class)
78      public void testChecksumDataFail() throws Exception {
79          FitsCheckSum.checksum(new byte[999]);
80      }
81  
82      @Test(expected = FitsException.class)
83      public void testChecksumDataFailException() throws Exception {
84          int[][] data = new int[][] {{1, 2}, {3, 4}, {5, 6}};
85          ImageData d = ImageHDU.encapsulate(data);
86          Header h = ImageHDU.manufactureHeader(d);
87          BasicHDU<?> bhdu = new ImageHDU(h, d) {
88  
89              @Override
90              public ImageData getData() {
91                  ThrowAnyException.throwIOException("fake");
92                  return null;
93              }
94          };
95          Fits.setChecksum(bhdu);
96  
97      }
98  
99      @Test
100     public void testChecksum() throws Exception {
101         // AK: This test requires long strings to be disabled.
102         FitsFactory.setLongStringsEnabled(false);
103         Fits f = new Fits();
104         int[][] data = new int[][] {{1, 2}, {3, 4}, {5, 6}};
105         BasicHDU<?> bhdu1 = FitsFactory.hduFactory(data);
106 
107         BasicHDU<?> bhdu = bhdu1;
108         f.addHDU(bhdu);
109 
110         Fits.setChecksum(bhdu);
111         ByteArrayOutputStream bs = new ByteArrayOutputStream();
112         FitsOutputStream bdos = new FitsOutputStream(bs);
113         f.write(bdos);
114         bdos.close();
115         byte[] stream = bs.toByteArray();
116         long chk = Fits.checksum(stream);
117         int val = (int) chk;
118 
119         assertEquals("CheckSum test", -1, val);
120     }
121 
122     @Test
123     public void testCheckSumBasic() throws Exception {
124         FileInputStream in = new FileInputStream("src/test/resources/nom/tam/fits/test/test.fits");
125         Fits fits = new Fits();
126         fits.setStream(new FitsInputStream(in));
127         fits.read();
128         in.close();
129         fits.setChecksum();
130     }
131 
132     @Test
133     public void testCheckSum2() throws Exception {
134         // AK: This test requires long strings to be disabled.
135         FitsFactory.setLongStringsEnabled(false);
136         FileInputStream in = new FileInputStream("src/test/resources/nom/tam/fits/test/test.fits");
137         Fits fits = new Fits();
138         fits.setStream(new FitsInputStream(in));
139         fits.read();
140         in.close();
141         fits.setChecksum();
142         assertEquals(FitsIO.INTEGER_MASK, fits.getHDU(0).calcChecksum());
143     }
144 
145     // TODO This test fails in the CI for some reason, but not locally.
146     @Ignore
147     @Test
148     public void testIntegerOverflowChecksum() throws Exception {
149         byte[][] data = new byte[2][1440];
150         Arrays.fill(data[0], (byte) 17); // this generates a high checksum.
151         Arrays.fill(data[1], (byte) 17); // this generates a high checksum.
152         ImageData imageData = ImageHDU.encapsulate(data);
153         ImageHDU imageHdu = new ImageHDU(ImageHDU.manufactureHeader(imageData), imageData);
154         // now force no now date in the header (will change the checksum)
155         imageHdu.card(Standard.SIMPLE).comment("XXX").value(true);
156         imageHdu.setChecksum();
157         assertEquals("CVfXFTeVCTeVCTeV", imageHdu.getHeader().card(CHECKSUM).card().getValue());
158     }
159 
160     @Test
161     public void testCheckSumDeferred() throws Exception {
162         Fits fits = new Fits("src/test/resources/nom/tam/fits/test/test.fits");
163         ImageHDU im = (ImageHDU) fits.readHDU();
164 
165         assertTrue("deferred before checksum", im.getData().isDeferred());
166         fits.setChecksum();
167         assertTrue("deferrred after checksum", im.getData().isDeferred());
168         String sum1 = im.getHeader().getStringValue(CHECKSUM);
169         assertEquals(FitsIO.INTEGER_MASK, im.calcChecksum());
170 
171         // Now load the data in RAM and repeat.
172         im.getData().getData();
173         assertFalse("loaded before checksum", im.getData().isDeferred());
174         fits.setChecksum();
175         assertEquals(FitsIO.INTEGER_MASK, im.calcChecksum());
176     }
177 
178     @Test
179     public void testCheckSumVerifyOfficial() throws Exception {
180         Fits fits = new Fits("src/test/resources/nom/tam/fits/test/checksum.fits");
181         fits.verifyIntegrity();
182         // No exception...
183 
184         int n = fits.getNumberOfHDUs();
185 
186         for (int i = 0; i < n; i++) {
187             assertTrue(fits.getHDU(i).verifyDataIntegrity());
188             assertTrue(fits.getHDU(i).verifyIntegrity());
189         }
190     }
191 
192     @Test(expected = FitsIntegrityException.class)
193     public void testCheckSumVerifyModifiedHeaderFail() throws Exception {
194         File copy = new File("target/checksum-modhead.fits");
195 
196         Files.copy(new File("src/test/resources/nom/tam/fits/test/checksum.fits").toPath(), copy.toPath(),
197                 StandardCopyOption.REPLACE_EXISTING);
198 
199         RandomAccessFile rf = new RandomAccessFile(copy, "rw");
200         rf.seek(FitsFactory.FITS_BLOCK_SIZE - 1); // Guaranteed to be inside header.
201         rf.write('~');
202         rf.close();
203 
204         try (Fits fits = new Fits(copy)) {
205             fits.verifyIntegrity();
206         }
207     }
208 
209     @Test(expected = FitsIntegrityException.class)
210     public void testCheckSumVerifyModifiedDatasumFail() throws Exception {
211         File copy = new File("target/checksum-moddata.fits");
212 
213         Files.copy(new File("src/test/resources/nom/tam/fits/test/checksum.fits").toPath(), copy.toPath(),
214                 StandardCopyOption.REPLACE_EXISTING);
215 
216         RandomAccessFile rf = new RandomAccessFile(copy, "rw");
217         rf.seek(rf.length() - 1);
218         rf.write('~');
219         rf.close();
220 
221         try (Fits fits = new Fits(copy)) {
222             fits.verifyIntegrity();
223         }
224     }
225 
226     @Test
227     public void testCheckSumVerifyNoSum() throws Exception {
228         Fits fits = new Fits("src/test/resources/nom/tam/fits/test/test.fits");
229         fits.verifyIntegrity();
230         assertFalse(fits.getHDU(0).verifyIntegrity());
231         assertFalse(fits.getHDU(0).verifyDataIntegrity());
232         // No exception...
233     }
234 
235     @Test
236     public void testCheckSumVerifyStream() throws Exception {
237         try (Fits fits = new Fits(new FileInputStream(new File("src/test/resources/nom/tam/fits/test/checksum.fits")))) {
238             fits.verifyIntegrity();
239         }
240         /* No exception */
241     }
242 
243     @Test
244     public void testDatasumVerifyStream() throws Exception {
245         try (Fits fits = new Fits(new FileInputStream(new File("src/test/resources/nom/tam/fits/test/checksum.fits")))) {
246             assertTrue(fits.getHDU(0).verifyDataIntegrity());
247         }
248     }
249 
250     @Test
251     public void testCheckSumReadHDUStream() throws Exception {
252         try (FitsInputStream in = new FitsInputStream(
253                 new FileInputStream(new File("src/test/resources/nom/tam/fits/test/checksum.fits")))) {
254             ImageHDU hdu = new ImageHDU(null, null);
255             hdu.read(in);
256             hdu.verifyDataIntegrity();
257             hdu.verifyIntegrity();
258         }
259         /* No exception */
260     }
261 
262     @Test
263     public void testCheckSumReadHDUFile() throws Exception {
264         try (FitsFile in = new FitsFile("src/test/resources/nom/tam/fits/test/checksum.fits", "r")) {
265             ImageHDU hdu = new ImageHDU(null, null);
266             hdu.read(in);
267             hdu.verifyDataIntegrity();
268             hdu.verifyIntegrity();
269         }
270         /* No exception */
271     }
272 
273     @Test
274     public void testCStreamheckSumReads() throws Exception {
275         try (FitsInputStream in = new FitsInputStream(
276                 new FileInputStream(new File("src/test/resources/nom/tam/fits/test/checksum.fits")))) {
277             assertEquals(0, in.nextChecksum());
278             for (int i = 0; i < FitsFactory.FITS_BLOCK_SIZE; i++) {
279                 in.read();
280             }
281             assertNotEquals(0, in.nextChecksum());
282         }
283         /* No exception */
284     }
285 
286     @Test
287     public void testCheckSumVerifyFail() throws Exception {
288         Fits fits = new Fits("src/test/resources/nom/tam/fits/test/test.fits");
289         fits.read();
290         fits.setChecksum();
291 
292         ImageHDU im = (ImageHDU) fits.getHDU(0);
293 
294         short[][] data = (short[][]) im.getData().getData();
295         data[0][0]++;
296 
297         // Deferree read
298         assertNotEquals(FitsCheckSum.checksum(im.getData()), im.getStoredDatasum());
299         assertNotEquals(FitsCheckSum.checksum(im), im.getStoredChecksum());
300         assertNotEquals(fits.calcChecksum(0), im.getStoredChecksum());
301 
302         // in-memory
303         assertNotEquals(im.getData().calcChecksum(), im.getStoredDatasum());
304         assertNotEquals(im.calcChecksum(), im.getStoredChecksum());
305     }
306 
307     @Test
308     public void testCheckSumIncrement() throws Exception {
309         Fits fits = new Fits("src/test/resources/nom/tam/fits/test/test.fits");
310         fits.read();
311         fits.setChecksum();
312 
313         ImageHDU im = (ImageHDU) fits.getHDU(0);
314         Header h = im.getHeader();
315 
316         short[][] data = (short[][]) im.getData().getData();
317 
318         data[0][0]++;
319 
320         FitsCheckSum.setDatasum(h, FitsCheckSum.checksum(im.getData()));
321 
322         // Deferred read
323         assertEquals(FitsCheckSum.checksum(im.getData()), im.getStoredDatasum());
324         assertEquals(FitsIO.INTEGER_MASK, im.calcChecksum());
325 
326         // in-memory
327         im.setChecksum();
328         assertEquals(im.getData().calcChecksum(), im.getStoredDatasum());
329         assertEquals(FitsIO.INTEGER_MASK, im.calcChecksum());
330     }
331 
332     @Test
333     public void testCheckSumDecode() throws Exception {
334         long sum = 20220829;
335         assertEquals(sum, FitsCheckSum.decode(FitsCheckSum.encode(sum)));
336         assertEquals(sum, FitsCheckSum.decode(FitsCheckSum.encode(sum, false), false));
337         assertEquals(sum, FitsCheckSum.decode(FitsCheckSum.encode(sum, true), true));
338         assertEquals(sum, FitsCheckSum.decode(FitsCheckSum.checksumEnc(sum, false), false));
339         assertEquals(sum, FitsCheckSum.decode(FitsCheckSum.checksumEnc(sum, true), true));
340     }
341 
342     @Test(expected = IllegalArgumentException.class)
343     public void testCheckSumDecodeInvalidLength() throws Exception {
344         FitsCheckSum.decode("");
345     }
346 
347     @Test(expected = IllegalArgumentException.class)
348     public void testCheckSumDecodeInvalidChars() throws Exception {
349         byte[] b = new byte[16];
350         Arrays.fill(b, (byte) 0x2f);
351         FitsCheckSum.decode(new String(b));
352     }
353 
354     @Test(expected = FitsException.class)
355     public void testCheckSumNoDatasum() throws Exception {
356         FitsCheckSum.getStoredDatasum(new Header());
357     }
358 
359     @Test(expected = FitsException.class)
360     public void testCheckSumNoChecksum() throws Exception {
361         FitsCheckSum.getStoredChecksum(new Header());
362     }
363 
364     @Test
365     public void testCheckSumwWrap() throws Exception {
366         assertEquals(0, FitsCheckSum.sumOf(Integer.MAX_VALUE, Integer.MAX_VALUE) & ~FitsIO.INTEGER_MASK);
367     }
368 
369     @Test
370     public void testCheckSumAutoAdd() throws Exception {
371         Header h = new Header();
372         h.setSimple(true);
373         h.setBitpix(Bitpix.INTEGER);
374         h.setNaxes(0);
375         FitsCheckSum.checksum(h);
376         assertFalse(h.containsKey(CHECKSUM));
377     }
378 
379     @Test
380     public void testCheckSumKeep() throws Exception {
381         Header h = new Header();
382         h.setSimple(true);
383         h.setBitpix(Bitpix.INTEGER);
384         h.setNaxes(0);
385         h.addValue(DATASUM, "0");
386         h.addValue(CHECKSUM, "blah");
387         FitsCheckSum.checksum(h);
388         assertEquals("blah", h.getStringValue(CHECKSUM));
389     }
390 
391     @Test
392     public void testCheckSumMissingDatasum() throws Exception {
393         Header h = new Header();
394         h.setSimple(true);
395         h.setBitpix(Bitpix.INTEGER);
396         h.setNaxes(0);
397         h.addValue(CHECKSUM, "blah");
398         h.validate(true);
399         assertFalse(h.containsKey(CHECKSUM));
400     }
401 
402     @Test
403     public void testCheckSumSubtract() throws Exception {
404         long a = 20220829;
405         long b = 19740131;
406 
407         long sum = FitsCheckSum.sumOf(a, b);
408 
409         assertEquals(b, FitsCheckSum.differenceOf(sum, a));
410         assertEquals(a, FitsCheckSum.differenceOf(sum, b));
411     }
412 
413     @Test(expected = FitsException.class)
414     public void testSetChecksumFitsException() throws Exception {
415         ImageData data = new ImageData() {
416             @Override
417             public void write(ArrayDataOutput bdos) throws FitsException {
418                 throw new FitsException("not implemented");
419             }
420         };
421 
422         Header h = new Header();
423         h.setSimple(true);
424         h.setBitpix(Bitpix.INTEGER);
425         h.setNaxes(0);
426 
427         ImageHDU im = new ImageHDU(h, data);
428         FitsCheckSum.setChecksum(im);
429     }
430 
431     @Test
432     public void testChecksumFitsLoaded() throws Exception {
433         Fits fits = new Fits(new File("src/test/resources/nom/tam/fits/test/test.fits"));
434         fits.read();
435         fits.setChecksum();
436         BasicHDU<?> hdu = fits.getHDU(0);
437         Header h = hdu.getHeader();
438         assertTrue(h.containsKey(CHECKSUM));
439         assertTrue(h.containsKey(DATASUM));
440         assertNotEquals(0, hdu.getStoredChecksum());
441         assertNotEquals(0, hdu.getStoredDatasum());
442     }
443 
444     @Test
445     public void testChecksumFitsUnloaded() throws Exception {
446         Fits fits = new Fits(new File("src/test/resources/nom/tam/fits/test/test.fits"));
447         fits.setChecksum();
448         BasicHDU<?> hdu = fits.getHDU(0);
449         Header h = hdu.getHeader();
450         assertTrue(h.containsKey(CHECKSUM));
451         assertTrue(h.containsKey(DATASUM));
452         assertNotEquals(0, hdu.getStoredChecksum());
453         assertNotEquals(0, hdu.getStoredDatasum());
454     }
455 
456     @Test
457     public void testChecksumFitsCreated() throws Exception {
458         int[][] data = new int[5][5];
459         data[0][0] = 1;
460         Fits fits = new Fits();
461         fits.addHDU(FitsFactory.hduFactory(data));
462         fits.setChecksum();
463         BasicHDU<?> hdu = fits.getHDU(0);
464         Header h = hdu.getHeader();
465         assertTrue(h.containsKey(CHECKSUM));
466         assertTrue(h.containsKey(DATASUM));
467         assertNotEquals(0, hdu.getStoredChecksum());
468         assertNotEquals(0, hdu.getStoredDatasum());
469     }
470 
471     @Test
472     public void testChecksumNullFile() throws Exception {
473         assertEquals(0, FitsCheckSum.checksum((RandomAccess) null, 0, 1000));
474     }
475 
476     @Test
477     public void testDeferredChecksumRange() throws Exception {
478         int[][] im = new int[10][10];
479 
480         for (int i = 0; i < 10; i++) {
481             for (int j = 0; j < 10; j++) {
482                 im[i][j] = i + j;
483             }
484         }
485 
486         ImageHDU hdu = (ImageHDU) FitsFactory.hduFactory(im);
487         long sum = hdu.getData().calcChecksum();
488 
489         Fits fits = new Fits();
490         fits.addHDU(hdu);
491         fits.addHDU(hdu);
492 
493         fits.write("target/checksumRangeTest.fits");
494         fits.close();
495 
496         fits = new Fits("target/checksumRangeTest.fits");
497         assertEquals(sum, fits.calcDatasum(0));
498         fits.close();
499     }
500 
501     @Test
502     public void testChecksumEncode() throws Exception {
503         assertEquals("hcHjjc9ghcEghc9g", FitsCheckSum.encode(868229149L));
504     }
505 
506     @Test
507     public void testChecksumDecode() throws Exception {
508         assertEquals(868229149L, FitsCheckSum.decode("hcHjjc9ghcEghc9g"));
509     }
510 }