View Javadoc
1   package nom.tam.image.compression.hdu;
2   
3   import java.io.ByteArrayInputStream;
4   import java.io.ByteArrayOutputStream;
5   import java.io.File;
6   import java.io.IOException;
7   import java.nio.Buffer;
8   import java.nio.ByteBuffer;
9   import java.util.Random;
10  import java.util.zip.GZIPInputStream;
11  
12  import org.junit.jupiter.api.Assertions;
13  import org.junit.jupiter.api.Test;
14  
15  import nom.tam.fits.BinaryTable;
16  import nom.tam.fits.BinaryTableHDU;
17  import nom.tam.fits.Fits;
18  import nom.tam.fits.FitsException;
19  import nom.tam.fits.Header;
20  import nom.tam.fits.HeaderCard;
21  import nom.tam.fits.compression.algorithm.api.ICompressOption;
22  import nom.tam.fits.compression.algorithm.api.ICompressorControl;
23  import nom.tam.fits.header.Compression;
24  import nom.tam.fits.header.IFitsHeader;
25  import nom.tam.fits.header.Standard;
26  import nom.tam.fits.util.BlackBoxImages;
27  import nom.tam.image.compression.bintable.BinaryTableTileCompressor;
28  import nom.tam.image.compression.bintable.BinaryTableTileDecompressor;
29  import nom.tam.image.compression.bintable.BinaryTableTileDescription;
30  import nom.tam.util.ColumnTable;
31  import nom.tam.util.Cursor;
32  
33  /*
34   * #%L
35   * nom.tam FITS library
36   * %%
37   * Copyright (C) 1996 - 2024 nom-tam-fits
38   * %%
39   * This is free and unencumbered software released into the public domain.
40   *
41   * Anyone is free to copy, modify, publish, use, compile, sell, or
42   * distribute this software, either in source code form or as a compiled
43   * binary, for any purpose, commercial or non-commercial, and by any
44   * means.
45   *
46   * In jurisdictions that recognize copyright laws, the author or authors
47   * of this software dedicate any and all copyright interest in the
48   * software to the public domain. We make this dedication for the benefit
49   * of the public at large and to the detriment of our heirs and
50   * successors. We intend this dedication to be an overt act of
51   * relinquishment in perpetuity of all present and future rights to this
52   * software under copyright law.
53   *
54   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
55   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
56   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
57   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
58   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
59   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
60   * OTHER DEALINGS IN THE SOFTWARE.
61   * #L%
62   */
63  
64  import static nom.tam.fits.header.Standard.XTENSION_BINTABLE;
65  import static nom.tam.image.compression.bintable.BinaryTableTileDescription.tile;
66  
67  @SuppressWarnings({"javadoc", "deprecation"})
68  public class CompressedTableTest {
69  
70      private final double[][][] doubles = new double[50][5][5];
71  
72      public CompressedTableTest() {
73          super();
74          Random random = new Random();
75          for (int i1 = 0; i1 < doubles.length; i1++) {
76              for (int i2 = 0; i2 < doubles[i1].length; i2++) {
77                  for (int i3 = 0; i3 < doubles[i1][i2].length; i3++) {
78                      doubles[i1][i2][i3] = random.nextDouble();
79                  }
80              }
81          }
82      }
83  
84      @Test
85      public void testBasicBinaryTable() throws Exception {
86  
87          BinaryTableHDU binaryTable2HDU = null;
88  
89          try (Fits fitsComp = new Fits("src/test/resources/nom/tam/table/comp/testBinaryTable.fits.fz")) {
90              CompressedTableHDU cfitsioTable = (CompressedTableHDU) fitsComp.getHDU(1);
91              cfitsioTable.info(System.out);
92              binaryTable2HDU = cfitsioTable.asBinaryTableHDU();
93          }
94  
95          Assertions.assertNotNull(binaryTable2HDU);
96  
97          try (Fits fits = new Fits()) {
98              fits.addHDU(binaryTable2HDU);
99              fits.write(new File("target/testBinaryTable_uncompressed.fits"));
100         }
101 
102         CompressedTableHDU compressed = CompressedTableHDU.fromBinaryTableHDU(binaryTable2HDU, 10).compress();
103         compressed.compress();
104 
105         try (Fits fits = new Fits()) {
106             fits.addHDU(compressed);
107             fits.write(new File("target/testBinaryTable_recompressed.fits"));
108         }
109 
110         try (Fits fits = new Fits("target/testBinaryTable_uncompressed.fits")) {
111             Header header = fits.getHDU(1).getHeader();
112             Cursor<String, HeaderCard> iter = header.iterator();
113             assertStringCard(Standard.XTENSION, XTENSION_BINTABLE, iter.next());
114             assertIntCard(Standard.BITPIX, 8, iter.next());
115             assertIntCard(Standard.NAXIS, 2, iter.next());
116             assertIntCard(Standard.NAXISn.n(1), 200, iter.next());
117             assertIntCard(Standard.NAXISn.n(2), 50, iter.next());
118             assertIntCard(Standard.PCOUNT, 0, iter.next());
119             assertIntCard(Standard.GCOUNT, 1, iter.next());
120             assertIntCard(Standard.TFIELDS, 1, iter.next());
121             // the order of the next two fields is not fix
122             assertStringCard(Standard.TFORMn.n(1), "25D", header.card(Standard.TFORMn.n(1)).card());
123             assertStringCard(Standard.TDIMn.n(1), "(5,5)", header.card(Standard.TDIMn.n(1)).card());
124         }
125 
126         try (Fits fits = new Fits("target/testBinaryTable_recompressed.fits")) {
127             Header header = fits.getHDU(1).getHeader();
128             Cursor<String, HeaderCard> iter = header.iterator();
129             assertStringCard(Standard.XTENSION, XTENSION_BINTABLE, iter.next());
130             assertIntCard(Standard.BITPIX, 8, iter.next());
131             assertIntCard(Standard.NAXIS, 2, iter.next());
132             assertIntCard(Standard.NAXISn.n(1), 8, iter.next());
133             assertIntCard(Standard.NAXISn.n(2), 5, iter.next());
134 
135             HeaderCard hc = iter.next();
136             Assertions.assertEquals(Standard.PCOUNT.key(), hc.getKey());
137             Assertions.assertNotEquals((long) hc.getValue(Long.class, 0L), 0L);
138 
139             assertIntCard(Standard.GCOUNT, 1, iter.next());
140             assertIntCard(Standard.TFIELDS, 1, iter.next());
141             // the order of the next two fields is not fix
142             assertStringCard(Standard.TFORMn.n(1), "1PB", header.card(Standard.TFORMn.n(1)).card());
143             assertStringCard(Standard.TDIMn.n(1), "(5,5)", header.card(Standard.TDIMn.n(1)).card());
144         }
145     }
146 
147     @Test
148     public void testCompressedVarTable() throws Exception {
149         String compressedVarTable = BlackBoxImages.getBlackBoxImage("map_one_source_a_level_1_cal.fits.fz");
150 
151         BinaryTableHDU binaryTable2HDU = null;
152 
153         try (Fits fitsComp = new Fits(compressedVarTable)) {
154             CompressedTableHDU cfitsioTable = (CompressedTableHDU) fitsComp.getHDU(1);
155             cfitsioTable.info(System.out);
156             binaryTable2HDU = cfitsioTable.asBinaryTableHDU();
157         }
158 
159         Assertions.assertNotNull(binaryTable2HDU);
160 
161         try (Fits fits = new Fits()) {
162             fits.addHDU(binaryTable2HDU);
163             fits.write(new File("target/map_one_source_a_level_1_cal_uncompressed.fits"));
164         }
165 
166         BinaryTableHDU table = null;
167 
168         try (Fits fits = new Fits("target/map_one_source_a_level_1_cal_uncompressed.fits")) {
169             table = (BinaryTableHDU) fits.getHDU(1);
170 
171             Assertions.assertNotNull(table); // table could be read.
172 
173             Assertions.assertEquals(21, table.getNCols());
174             Assertions.assertEquals(1, table.getNRows());
175 
176             // Make sure we load all the data...
177             table.getKernel();
178         }
179 
180         Assertions.assertNotNull(table);
181 
182         String originalVarTable = BlackBoxImages.getBlackBoxImage("map_one_source_a_level_1_cal.fits");
183 
184         try (Fits fitsOrg = new Fits(originalVarTable)) {
185             Header orgHeader = fitsOrg.getHDU(1).getHeader();
186 
187             Assertions.assertEquals(orgHeader.getSize(), table.getHeader().getSize());
188             Cursor<String, HeaderCard> iterator = orgHeader.iterator();
189             while (iterator.hasNext()) {
190                 HeaderCard headerCard = iterator.next();
191                 String uncompressed = table.getHeader().getStringValue(headerCard.getKey());
192                 String original = orgHeader.getStringValue(headerCard.getKey());
193                 if (uncompressed != null || original != null) {
194                     Assertions.assertEquals(original, uncompressed);
195                 }
196             }
197         }
198     }
199 
200     private void assertIntCard(IFitsHeader expectedKey, int expectedValue, HeaderCard card) {
201         Assertions.assertEquals(expectedKey.key(), card.getKey());
202         Assertions.assertEquals(Integer.valueOf(expectedValue), card.getValue(Integer.class, -1));
203     }
204 
205     private void assertStringCard(IFitsHeader expectedKey, String expectedValue, HeaderCard card) {
206         Assertions.assertEquals(expectedKey.key(), card.getKey());
207         Assertions.assertEquals(expectedValue, card.getValue());
208     }
209 
210     @Test
211     public void testB12TableDecompress() throws Exception {
212         try (Fits fitsOrg = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits");
213                 Fits fitsComp = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits.fz")) {
214 
215             CompressedTableHDU cfitsioTable = (CompressedTableHDU) fitsComp.getHDU(1);
216             BinaryTableHDU orgTable = (BinaryTableHDU) fitsOrg.getHDU(1);
217             BinaryTableHDU decompressedTable = cfitsioTable.asBinaryTableHDU();
218 
219             for (int row = 0; row < 50; row++) {
220                 Object decompressedElement = decompressedTable.getElement(row, 0);
221                 Object orgElement = orgTable.getElement(row, 0);
222                 Assertions.assertEquals(orgElement, decompressedElement);
223                 decompressedElement = decompressedTable.getElement(row, 1);
224                 orgElement = orgTable.getElement(row, 1);
225                 Assertions.assertArrayEquals((short[]) orgElement, (short[]) decompressedElement);
226                 decompressedElement = decompressedTable.getElement(row, 2);
227                 orgElement = orgTable.getElement(row, 2);
228                 Assertions.assertArrayEquals((float[][]) orgElement, (float[][]) decompressedElement);
229                 decompressedElement = decompressedTable.getElement(row, 3);
230                 orgElement = orgTable.getElement(row, 3);
231                 Assertions.assertArrayEquals((double[]) orgElement, (double[]) decompressedElement, 0.000000001d);
232                 decompressedElement = decompressedTable.getElement(row, 4);
233                 orgElement = orgTable.getElement(row, 4);
234                 Assertions.assertArrayEquals((String[]) orgElement, (String[]) decompressedElement);
235             }
236 
237         }
238     }
239 
240     @Test
241     public void testB12TableCompress() throws Exception {
242         CompressedTableHDU compressedTable = null;
243 
244         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
245             compressedTable = CompressedTableHDU.fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), 0)
246                     .compress();
247             compressedTable.compress();
248         }
249 
250         Assertions.assertNotNull(compressedTable);
251 
252         try (Fits fitsOrg = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits.fz")) {
253             BinaryTableHDU orgTable = (BinaryTableHDU) fitsOrg.getHDU(1);
254 
255             for (int column = 0; column < 5; column++) {
256                 Object decompressedElement = compressedTable.getElement(0, column);
257                 Object orgElement = orgTable.getElement(0, column);
258                 byte[] decompressed = decompress(decompressedElement);
259                 byte[] org = decompress(orgElement);
260                 if (column == 3) {
261                     org = unshuffle(org, 8);
262                     decompressed = unshuffle(decompressed, 8);
263                 }
264                 Assertions.assertArrayEquals(org, decompressed, "column " + column);
265             }
266 
267         }
268     }
269 
270     private int[] calculateOffsets(byte[] byteArray, int primitiveSize) {
271         int[] offset = new int[primitiveSize];
272         offset[0] = 0;
273         for (int primitivIndex = 1; primitivIndex < primitiveSize; primitivIndex++) {
274             offset[primitivIndex] = offset[primitivIndex - 1] + byteArray.length / primitiveSize;
275         }
276         return offset;
277     }
278 
279     public byte[] unshuffle(byte[] byteArray, int primitiveSize) {
280         byte[] result = new byte[byteArray.length];
281         int resultIndex = 0;
282         int[] offset = calculateOffsets(byteArray, primitiveSize);
283         for (int index = 0; index < byteArray.length; index += primitiveSize) {
284             for (int primitiveIndex = 0; primitiveIndex < primitiveSize; primitiveIndex++) {
285                 result[index + primitiveIndex] = byteArray[resultIndex + offset[primitiveIndex]];
286             }
287             resultIndex++;
288         }
289         return result;
290     }
291 
292     private byte[] decompress(Object decompressedElement) throws IOException {
293         if (decompressedElement instanceof byte[]) {
294             if (((byte[]) decompressedElement)[0] != 31 && ((byte[]) decompressedElement)[1] != -117) {
295                 return (byte[]) decompressedElement;
296             }
297         }
298         ByteArrayOutputStream decompressed = new ByteArrayOutputStream();
299         byte[] buffer = new byte[1024];
300         GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream((byte[]) decompressedElement));
301         int count;
302         while ((count = gzipInputStream.read(buffer)) >= 0) {
303             decompressed.write(buffer, 0, count);
304         }
305         return decompressed.toByteArray();
306     }
307 
308     @Test
309     public void testB12TableTileDecompress() throws Exception {
310         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
311             int tileSize = 5;
312 
313             CompressedTableHDU compressedTable = CompressedTableHDU
314                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
315             compressedTable.compress();
316 
317             BinaryTableHDU hdu = compressedTable.asBinaryTableHDU(1);
318 
319             Assertions.assertEquals(tileSize, hdu.getNRows());
320 
321             BinaryTableHDU hdu0 = (BinaryTableHDU) fitsUncompressed.getHDU(1);
322 
323             BinaryTable tab0 = hdu0.getData();
324             BinaryTable tab = hdu.getData();
325 
326             for (int row = 0; row < hdu.getNRows(); row++) {
327                 int row0 = tileSize + row;
328                 Assertions.assertEquals(tab0.getElement(row0, 0), tab.getElement(row, 0), "row " + row);
329                 Assertions.assertArrayEquals((short[]) tab0.getElement(row0, 1), (short[]) tab.getElement(row, 1),
330                         "row " + row);
331 
332                 float[][] f0 = (float[][]) tab0.getElement(row0, 2);
333                 float[][] f = (float[][]) tab.getElement(row, 2);
334                 Assertions.assertEquals(f0.length, f.length);
335                 for (int j = 0; j < f0.length; j++) {
336                     Assertions.assertArrayEquals(f0[j], f[j], 1e-4f);
337                 }
338 
339                 Assertions.assertArrayEquals((double[]) tab0.getElement(row0, 3), (double[]) tab.getElement(row, 3), 1e-8,
340                         "row " + row);
341 
342                 String[] s0 = (String[]) tab0.getElement(row0, 4);
343                 String[] s = (String[]) tab.getElement(row, 4);
344                 Assertions.assertEquals(s0.length, s.length);
345                 for (int j = 0; j < s0.length; j++) {
346                     Assertions.assertEquals(s0[j], s[j]);
347                 }
348             }
349         }
350     }
351 
352     @Test
353     public void testB12TableDecompressColumn() throws Exception {
354         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
355             int tileSize = 5;
356 
357             CompressedTableHDU compressedTable = CompressedTableHDU
358                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
359             compressedTable.compress();
360 
361             String[] s = (String[]) compressedTable.getColumnData(0, 1, 3);
362 
363             Assertions.assertEquals(2 * tileSize, s.length);
364 
365             BinaryTableHDU hdu0 = (BinaryTableHDU) fitsUncompressed.getHDU(1);
366 
367             BinaryTable tab0 = hdu0.getData();
368 
369             for (int row = 0; row < s.length; row++) {
370                 int row0 = tileSize + row;
371                 Assertions.assertEquals(tab0.getElement(row0, 0), s[row], "row " + row);
372             }
373         }
374     }
375 
376     @Test
377     public void testB12TableDecompressFullColumn() throws Exception {
378         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
379             int tileSize = 6; // Non-divisor tile size...
380 
381             BinaryTableHDU hdu0 = (BinaryTableHDU) fitsUncompressed.getHDU(1);
382             CompressedTableHDU compressedTable = CompressedTableHDU.fromBinaryTableHDU(hdu0, tileSize).compress();
383             compressedTable.compress();
384 
385             String[] s = (String[]) compressedTable.getColumnData(0);
386 
387             Assertions.assertEquals(hdu0.getNRows(), s.length);
388 
389             BinaryTable tab0 = hdu0.getData();
390 
391             for (int row = 0; row < s.length; row++) {
392                 Assertions.assertEquals(tab0.getElement(row, 0), s[row], "row " + row);
393             }
394         }
395     }
396 
397     @Test
398     public void testB12TableDecompressNegativeTileStart() throws Exception {
399         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
400             int tileSize = 5;
401 
402             CompressedTableHDU compressedTable = CompressedTableHDU
403                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
404             compressedTable.compress();
405 
406             Assertions.assertThrows(IllegalArgumentException.class, () -> compressedTable.getColumnData(0, -1, 3));
407         }
408     }
409 
410     @Test
411     public void testB12TableDecompressOutOfBoundsTileStart() throws Exception {
412         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
413             int tileSize = 5;
414 
415             CompressedTableHDU compressedTable = CompressedTableHDU
416                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
417             compressedTable.compress();
418 
419             Assertions.assertThrows(IllegalArgumentException.class,
420                     () -> compressedTable.getColumnData(0, compressedTable.getNRows(), 3));
421         }
422     }
423 
424     @Test
425     public void testB12TableDecompressOutOfBoundsTileEnd() throws Exception {
426         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
427             int tileSize = 5;
428 
429             CompressedTableHDU compressedTable = CompressedTableHDU
430                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
431             compressedTable.compress();
432 
433             Assertions.assertThrows(IllegalArgumentException.class,
434                     () -> compressedTable.getColumnData(0, 1, compressedTable.getNRows() + 1));
435         }
436     }
437 
438     @Test
439     public void testB12TableDecompressNoZTILELEN() throws Exception {
440         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
441             int tileSize = 5;
442 
443             CompressedTableHDU compressedTable = CompressedTableHDU
444                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
445             compressedTable.compress();
446             compressedTable.getHeader().deleteKey(Compression.ZTILELEN);
447 
448             Assertions.assertThrows(FitsException.class, () -> compressedTable.getTileRows());
449         }
450     }
451 
452     @Test
453     public void testB12TableDecompressInvalidZTILELEN() throws Exception {
454         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
455             int tileSize = 5;
456 
457             CompressedTableHDU compressedTable = CompressedTableHDU
458                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
459             compressedTable.compress();
460             compressedTable.addValue(Compression.ZTILELEN, 0);
461 
462             Assertions.assertThrows(FitsException.class, () -> compressedTable.getTileRows());
463         }
464     }
465 
466     @Test
467     public void testB12TableDecompressEmptyRange() throws Exception {
468         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
469             int tileSize = 5;
470 
471             CompressedTableHDU compressedTable = CompressedTableHDU
472                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
473             compressedTable.compress();
474             Assertions.assertNull(compressedTable.getColumnData(0, 1, 1));
475         }
476     }
477 
478     @Test
479     public void testB12TableDecompressInvalidTileFrom() throws Exception {
480         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
481             int tileSize = 5;
482 
483             CompressedTableHDU compressedTable = CompressedTableHDU
484                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
485             compressedTable.compress();
486 
487             Assertions.assertThrows(IllegalArgumentException.class, () -> compressedTable.asBinaryTableHDU(-1));
488         }
489     }
490 
491     @Test
492     public void testB12TableDecompressInvalidTileTo() throws Exception {
493         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
494             int tileSize = 5;
495 
496             CompressedTableHDU compressedTable = CompressedTableHDU
497                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
498             compressedTable.compress();
499 
500             Assertions.assertThrows(IllegalArgumentException.class,
501                     () -> compressedTable.asBinaryTableHDU(0, compressedTable.getTileCount() + 1));
502         }
503     }
504 
505     @Test
506     public void testB12TableDecompressEmptyTileRange() throws Exception {
507         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
508             int tileSize = 5;
509 
510             CompressedTableHDU compressedTable = CompressedTableHDU
511                     .fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), tileSize).compress();
512             compressedTable.compress();
513 
514             Assertions.assertThrows(IllegalArgumentException.class, () -> compressedTable.asBinaryTableHDU(0, 0));
515         }
516     }
517 
518     @Test
519     public void testB12TableCompressIllegalAlgo() throws Exception {
520         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
521             Assertions.assertThrows(IllegalArgumentException.class,
522                     () -> CompressedTableHDU.fromBinaryTableHDU((BinaryTableHDU) fitsUncompressed.getHDU(1), 0, "BLAH"));
523         }
524     }
525 
526     @Test
527     public void testB12TableCompressPrepTwice() throws Exception {
528         try (Fits fitsUncompressed = new Fits("src/test/resources/nom/tam/table/comp/bt12.fits")) {
529             BinaryTableHDU hdu = (BinaryTableHDU) fitsUncompressed.getHDU(1);
530             CompressedTableHDU cHDU = CompressedTableHDU.fromBinaryTableHDU(hdu, 0);
531             cHDU.getData().prepareUncompressedData(hdu.getData().getData());
532             cHDU.getData().prepareUncompressedData(hdu.getData().getData());
533             // No exception.
534         }
535     }
536 
537     @Test
538     public void testFixedTableCompressDefragment() throws Exception {
539         BinaryTable btab = new BinaryTable();
540         btab.addColumn(BinaryTable.ColumnDesc.createForFixedArrays(int.class, 6));
541         for (int i = 0; i < 100; i++) {
542             btab.addRowEntries(new int[] {i, i + 1, i + 2, i + 3, i + 4, i + 5});
543         }
544 
545         CompressedTableHDU chdu = CompressedTableHDU.fromBinaryTableHDU(btab.toHDU(), 0);
546         chdu.getData().defragment(); // No exception.
547     }
548 
549     @Test
550     public void testVLACompressDefragment() throws Exception {
551         BinaryTable btab = new BinaryTable();
552         btab.addColumn(BinaryTable.ColumnDesc.createForVariableSize(int.class));
553         for (int i = 0; i < 100; i++) {
554             btab.addRowEntries(new int[] {i, i + 1, i + 2, i + 3, i + 4, i + 5});
555         }
556 
557         CompressedTableHDU chdu = CompressedTableHDU.fromBinaryTableHDU(btab.toHDU(), 0);
558         Assertions.assertEquals(0, chdu.getData().defragment());
559     }
560 
561     @Test
562     public void testSetReversedVLAIndices() throws Exception {
563         try {
564             Assertions.assertFalse(CompressedTableHDU.hasOldStandardVLAIndexing());
565             CompressedTableHDU.useOldStandardVLAIndexing(true);
566             Assertions.assertTrue(CompressedTableHDU.hasOldStandardVLAIndexing());
567             CompressedTableHDU.useOldStandardVLAIndexing(false);
568             Assertions.assertFalse(CompressedTableHDU.hasOldStandardVLAIndexing());
569         } finally {
570             CompressedTableHDU.useOldStandardVLAIndexing(false);
571         }
572     }
573 
574     @Test
575     public void testBinaryTableTileFillHeader() throws Exception {
576         ColumnTable<?> tab = new ColumnTable<>();
577         tab.addColumn(int.class, 10);
578         BinaryTableTileDecompressor tile = new BinaryTableTileDecompressor(new CompressedTableData(), tab, tile()//
579                 .rowStart(0)//
580                 .rowEnd(10)//
581                 .column(0)//
582                 .tileIndex(1)//
583                 .compressionAlgorithm("BLAH"));
584 
585         Header h = new Header();
586         tile.fillHeader(h);
587         Assertions.assertEquals("BLAH", h.getStringValue(Compression.ZCTYPn.n(1)));
588     }
589 
590     @Test
591     public void testCompressedTableColumnNames() throws Exception {
592         String name = "Test Name";
593         BinaryTable btab = new BinaryTable();
594 
595         btab.addColumn(BinaryTable.ColumnDesc.createForFixedArrays(int.class, 6));
596         btab.getDescriptor(0).name(name);
597         Assertions.assertEquals(name, btab.getDescriptor(0).name());
598 
599         for (int i = 0; i < 100; i++) {
600             btab.addRowEntries(new int[] {i, i + 1, i + 2, i + 3, i + 4, i + 5});
601         }
602 
603         CompressedTableHDU chdu = CompressedTableHDU.fromBinaryTableHDU(btab.toHDU(), 0);
604         Assertions.assertEquals(name, chdu.getHeader().getStringValue(Standard.TTYPEn.n(1)));
605     }
606 
607     @Test
608     public void testBinaryTableTileCompressorError() throws Exception {
609         class MyCompressor extends BinaryTableTileCompressor {
610             public MyCompressor(CompressedTableData compressedTable, ColumnTable<?> table,
611                     BinaryTableTileDescription description) {
612                 super(compressedTable, table, description);
613             }
614 
615             @Override
616             public ICompressorControl getCompressorControl() {
617                 return new ICompressorControl() {
618 
619                     @Override
620                     public boolean compress(Buffer in, ByteBuffer out, ICompressOption option) {
621                         return false;
622                     }
623 
624                     @Override
625                     public void decompress(ByteBuffer in, Buffer out, ICompressOption option) {
626                     }
627 
628                     @Override
629                     public ICompressOption option() {
630                         return null;
631                     }
632                 };
633             }
634         }
635 
636         ColumnTable<?> tab = new ColumnTable<>();
637         tab.addColumn(new int[100], 10);
638 
639         MyCompressor tile = new MyCompressor(new CompressedTableData(), tab, tile()//
640                 .rowStart(0)//
641                 .rowEnd(10)//
642                 .column(0)//
643                 .tileIndex(1));
644 
645         Assertions.assertThrows(IllegalStateException.class, () -> tile.run());
646     }
647 
648 }