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("Bd5LEb5LBb5LBb5L", fits.getHDU(0).getHeader().getStringValue("CHECKSUM"));
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 
170         // Now load the data in RAM and repeat.
171         im.getData().getData();
172         assertFalse("loaded before checksum", im.getData().isDeferred());
173         fits.setChecksum();
174 
175         String sum2 = im.getHeader().getStringValue(CHECKSUM);
176         assertEquals(sum1, sum2);
177     }
178 
179     @Test
180     public void testCheckSumVerifyOfficial() throws Exception {
181         Fits fits = new Fits("src/test/resources/nom/tam/fits/test/checksum.fits");
182         fits.verifyIntegrity();
183         // No exception...
184 
185         int n = fits.getNumberOfHDUs();
186 
187         for (int i = 0; i < n; i++) {
188             assertTrue(fits.getHDU(i).verifyDataIntegrity());
189             assertTrue(fits.getHDU(i).verifyIntegrity());
190         }
191     }
192 
193     @Test(expected = FitsIntegrityException.class)
194     public void testCheckSumVerifyModifiedHeaderFail() throws Exception {
195         File copy = new File("target/checksum-modhead.fits");
196 
197         Files.copy(new File("src/test/resources/nom/tam/fits/test/checksum.fits").toPath(), copy.toPath(),
198                 StandardCopyOption.REPLACE_EXISTING);
199 
200         RandomAccessFile rf = new RandomAccessFile(copy, "rw");
201         rf.seek(FitsFactory.FITS_BLOCK_SIZE - 1); // Guaranteed to be inside header.
202         rf.write('~');
203         rf.close();
204 
205         try (Fits fits = new Fits(copy)) {
206             fits.verifyIntegrity();
207         }
208     }
209 
210     @Test(expected = FitsIntegrityException.class)
211     public void testCheckSumVerifyModifiedDatasumFail() throws Exception {
212         File copy = new File("target/checksum-moddata.fits");
213 
214         Files.copy(new File("src/test/resources/nom/tam/fits/test/checksum.fits").toPath(), copy.toPath(),
215                 StandardCopyOption.REPLACE_EXISTING);
216 
217         RandomAccessFile rf = new RandomAccessFile(copy, "rw");
218         rf.seek(rf.length() - 1);
219         rf.write('~');
220         rf.close();
221 
222         try (Fits fits = new Fits(copy)) {
223             fits.verifyIntegrity();
224         }
225     }
226 
227     @Test
228     public void testCheckSumVerifyNoSum() throws Exception {
229         Fits fits = new Fits("src/test/resources/nom/tam/fits/test/test.fits");
230         fits.verifyIntegrity();
231         assertFalse(fits.getHDU(0).verifyIntegrity());
232         assertFalse(fits.getHDU(0).verifyDataIntegrity());
233         // No exception...
234     }
235 
236     @Test
237     public void testCheckSumVerifyStream() throws Exception {
238         try (Fits fits = new Fits(new FileInputStream(new File("src/test/resources/nom/tam/fits/test/checksum.fits")))) {
239             fits.verifyIntegrity();
240         }
241         /* No exception */
242     }
243 
244     @Test
245     public void testDatasumVerifyStream() throws Exception {
246         try (Fits fits = new Fits(new FileInputStream(new File("src/test/resources/nom/tam/fits/test/checksum.fits")))) {
247             assertTrue(fits.getHDU(0).verifyDataIntegrity());
248         }
249     }
250 
251     @Test
252     public void testCheckSumReadHDUStream() throws Exception {
253         try (FitsInputStream in = new FitsInputStream(
254                 new FileInputStream(new File("src/test/resources/nom/tam/fits/test/checksum.fits")))) {
255             ImageHDU hdu = new ImageHDU(null, null);
256             hdu.read(in);
257             hdu.verifyDataIntegrity();
258             hdu.verifyIntegrity();
259         }
260         /* No exception */
261     }
262 
263     @Test
264     public void testCheckSumReadHDUFile() throws Exception {
265         try (FitsFile in = new FitsFile("src/test/resources/nom/tam/fits/test/checksum.fits", "r")) {
266             ImageHDU hdu = new ImageHDU(null, null);
267             hdu.read(in);
268             hdu.verifyDataIntegrity();
269             hdu.verifyIntegrity();
270         }
271         /* No exception */
272     }
273 
274     @Test
275     public void testCStreamheckSumReads() throws Exception {
276         try (FitsInputStream in = new FitsInputStream(
277                 new FileInputStream(new File("src/test/resources/nom/tam/fits/test/checksum.fits")))) {
278             assertEquals(0, in.nextChecksum());
279             for (int i = 0; i < FitsFactory.FITS_BLOCK_SIZE; i++) {
280                 in.read();
281             }
282             assertNotEquals(0, in.nextChecksum());
283         }
284         /* No exception */
285     }
286 
287     @Test
288     public void testCheckSumVerifyFail() throws Exception {
289         Fits fits = new Fits("src/test/resources/nom/tam/fits/test/test.fits");
290         fits.read();
291         fits.setChecksum();
292 
293         ImageHDU im = (ImageHDU) fits.getHDU(0);
294 
295         short[][] data = (short[][]) im.getData().getData();
296         data[0][0]++;
297 
298         // Deferree read
299         assertNotEquals(FitsCheckSum.checksum(im.getData()), im.getStoredDatasum());
300         assertNotEquals(FitsCheckSum.checksum(im), im.getStoredChecksum());
301         assertNotEquals(fits.calcChecksum(0), im.getStoredChecksum());
302 
303         // in-memory
304         assertNotEquals(im.getData().calcChecksum(), im.getStoredDatasum());
305         assertNotEquals(im.calcChecksum(), im.getStoredChecksum());
306     }
307 
308     @Test
309     public void testCheckSumIncrement() throws Exception {
310         Fits fits = new Fits("src/test/resources/nom/tam/fits/test/test.fits");
311         fits.read();
312         fits.setChecksum();
313 
314         ImageHDU im = (ImageHDU) fits.getHDU(0);
315         Header h = im.getHeader();
316 
317         short[][] data = (short[][]) im.getData().getData();
318 
319         data[0][0]++;
320 
321         FitsCheckSum.setDatasum(h, FitsCheckSum.checksum(im.getData()));
322 
323         // Deferred read
324         assertEquals(FitsCheckSum.checksum(im.getData()), im.getStoredDatasum());
325         assertEquals(FitsCheckSum.checksum(im), im.getStoredChecksum());
326         assertEquals(fits.calcChecksum(0), im.getStoredChecksum());
327 
328         // in-memory
329         im.setChecksum();
330         assertEquals(im.getData().calcChecksum(), im.getStoredDatasum());
331         assertEquals(im.calcChecksum(), im.getStoredChecksum());
332     }
333 
334     @Test
335     public void testCheckSumDecode() throws Exception {
336         long sum = 20220829;
337         assertEquals(sum, FitsCheckSum.decode(FitsCheckSum.encode(sum)));
338         assertEquals(sum, FitsCheckSum.decode(FitsCheckSum.encode(sum, false), false));
339         assertEquals(sum, FitsCheckSum.decode(FitsCheckSum.encode(sum, true), true));
340         assertEquals(sum, FitsCheckSum.decode(FitsCheckSum.checksumEnc(sum, false), false));
341         assertEquals(sum, FitsCheckSum.decode(FitsCheckSum.checksumEnc(sum, true), true));
342     }
343 
344     @Test(expected = IllegalArgumentException.class)
345     public void testCheckSumDecodeInvalidLength() throws Exception {
346         FitsCheckSum.decode("");
347     }
348 
349     @Test(expected = IllegalArgumentException.class)
350     public void testCheckSumDecodeInvalidChars() throws Exception {
351         byte[] b = new byte[16];
352         Arrays.fill(b, (byte) 0x2f);
353         FitsCheckSum.decode(new String(b));
354     }
355 
356     @Test(expected = FitsException.class)
357     public void testCheckSumNoDatasum() throws Exception {
358         FitsCheckSum.getStoredDatasum(new Header());
359     }
360 
361     @Test(expected = FitsException.class)
362     public void testCheckSumNoChecksum() throws Exception {
363         FitsCheckSum.getStoredChecksum(new Header());
364     }
365 
366     @Test
367     public void testCheckSumwWrap() throws Exception {
368         assertEquals(0, FitsCheckSum.sumOf(Integer.MAX_VALUE, Integer.MAX_VALUE) & ~FitsIO.INTEGER_MASK);
369     }
370 
371     @Test
372     public void testCheckSumAutoAdd() throws Exception {
373         Header h = new Header();
374         h.setSimple(true);
375         h.setBitpix(Bitpix.INTEGER);
376         h.setNaxes(0);
377         FitsCheckSum.checksum(h);
378         assertTrue(h.containsKey(CHECKSUM));
379     }
380 
381     @Test
382     public void testCheckSumKeep() throws Exception {
383         Header h = new Header();
384         h.setSimple(true);
385         h.setBitpix(Bitpix.INTEGER);
386         h.setNaxes(0);
387         h.addValue(CHECKSUM, "blah");
388         FitsCheckSum.checksum(h);
389         assertEquals("blah", h.getStringValue(CHECKSUM));
390     }
391 
392     @Test
393     public void testCheckSumSubtract() throws Exception {
394         long a = 20220829;
395         long b = 19740131;
396 
397         long sum = FitsCheckSum.sumOf(a, b);
398 
399         assertEquals(b, FitsCheckSum.differenceOf(sum, a));
400         assertEquals(a, FitsCheckSum.differenceOf(sum, b));
401     }
402 
403     @Test(expected = FitsException.class)
404     public void testSetChecksumFitsException() throws Exception {
405         ImageData data = new ImageData() {
406             @Override
407             public void write(ArrayDataOutput bdos) throws FitsException {
408                 throw new FitsException("not implemented");
409             }
410         };
411 
412         Header h = new Header();
413         h.setSimple(true);
414         h.setBitpix(Bitpix.INTEGER);
415         h.setNaxes(0);
416 
417         ImageHDU im = new ImageHDU(h, data);
418         FitsCheckSum.setChecksum(im);
419     }
420 
421     @Test
422     public void testChecksumFitsLoaded() throws Exception {
423         Fits fits = new Fits(new File("src/test/resources/nom/tam/fits/test/test.fits"));
424         fits.read();
425         fits.setChecksum();
426         BasicHDU<?> hdu = fits.getHDU(0);
427         Header h = hdu.getHeader();
428         assertTrue(h.containsKey(CHECKSUM));
429         assertTrue(h.containsKey(DATASUM));
430         assertNotEquals(0, hdu.getStoredChecksum());
431         assertNotEquals(0, hdu.getStoredDatasum());
432     }
433 
434     @Test
435     public void testChecksumFitsUnloaded() throws Exception {
436         Fits fits = new Fits(new File("src/test/resources/nom/tam/fits/test/test.fits"));
437         fits.setChecksum();
438         BasicHDU<?> hdu = fits.getHDU(0);
439         Header h = hdu.getHeader();
440         assertTrue(h.containsKey(CHECKSUM));
441         assertTrue(h.containsKey(DATASUM));
442         assertNotEquals(0, hdu.getStoredChecksum());
443         assertNotEquals(0, hdu.getStoredDatasum());
444     }
445 
446     @Test
447     public void testChecksumFitsCreated() throws Exception {
448         int[][] data = new int[5][5];
449         data[0][0] = 1;
450         Fits fits = new Fits();
451         fits.addHDU(FitsFactory.hduFactory(data));
452         fits.setChecksum();
453         BasicHDU<?> hdu = fits.getHDU(0);
454         Header h = hdu.getHeader();
455         assertTrue(h.containsKey(CHECKSUM));
456         assertTrue(h.containsKey(DATASUM));
457         assertNotEquals(0, hdu.getStoredChecksum());
458         assertNotEquals(0, hdu.getStoredDatasum());
459     }
460 
461     @Test
462     public void testChecksumNullFile() throws Exception {
463         assertEquals(0, FitsCheckSum.checksum((RandomAccess) null, 0, 1000));
464     }
465 
466     @Test
467     public void testDeferredChecksumRange() throws Exception {
468         int[][] im = new int[10][10];
469 
470         for (int i = 0; i < 10; i++) {
471             for (int j = 0; j < 10; j++) {
472                 im[i][j] = i + j;
473             }
474         }
475 
476         ImageHDU hdu = (ImageHDU) FitsFactory.hduFactory(im);
477         long sum = hdu.getData().calcChecksum();
478 
479         Fits fits = new Fits();
480         fits.addHDU(hdu);
481         fits.addHDU(hdu);
482 
483         fits.write("target/checksumRangeTest.fits");
484         fits.close();
485 
486         fits = new Fits("target/checksumRangeTest.fits");
487         assertEquals(sum, fits.calcDatasum(0));
488         fits.close();
489     }
490 }