Skip to content

Commit

Permalink
Structure to allow asserting on tiff files (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
tom-seqera authored Oct 30, 2024
1 parent e3528f6 commit 79e0301
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 17 deletions.
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
# nft-tiff

An nf-test plugin to test nft-tiff files
An nf-test plugin to write assertions on TIFF files

Currently just a stub with the intention that more specific/accurate checks can be added over time.

Please read the [documentation](https://nf-core.github.io/nft-tiff) for more information.
It adds a `.tiff` function to the `path` calls in nf-test. For example:
```groovy
def tiff = path('filename.tiff').tiff
```

This tiff validator object exposes two functions, allowing comparison to be based on either the tiff
metadata or the raw bitmap data. For example:
```groovy
def tiff = path(process.out.tiff[0]).tiff
def reference = path('reference.tiff').tiff
// compare the metadata of the two tiffs, ignoring the bitmap data
assert tiff.meta == reference.meta
// or, compare the bitmaps of the two tiffs, ignoring the metadata
assert tiff.bitmaps == reference.bitmaps
```

Since this is just a stub, both approaches (metadata and bitmaps) it compares only the image height and width.

### Possible extensions

- More detailing comparisons of metadata/bitmap data
- Comparing only specific dirs, rather than all of them
- Specifying lists of metadata fields to compare
- Supporting out-of-order dirs?
56 changes: 56 additions & 0 deletions src/main/java/nf_core/nf/test/tiff/BitmapValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package nf_core.nf.test.tiff;

import mil.nga.tiff.FileDirectory;
import mil.nga.tiff.Rasters;
import mil.nga.tiff.TIFFImage;

import java.util.List;
import java.util.Objects;

/**
* Ignores metadata and compares raw bitmap data within each dir.
*/
public class BitmapValidator {
private final TIFFImage image;

BitmapValidator(TIFFImage image) {
this.image = image;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BitmapValidator that = (BitmapValidator) o;

// a tiff file contains multiple 'directories', each containing multiple bitmaps.
// since the metadata isn't always standard, we can compare information about the
// raw bitmaps instead
List<FileDirectory> dirs = image.getFileDirectories();
List<FileDirectory> thatDirs = that.image.getFileDirectories();

if (dirs.size() != thatDirs.size()) {
throw new RuntimeException(String.format("Number of dirs does not match: '%s' vs '%s'", dirs.size(), thatDirs.size()));
}
// NOTE: this assumes dirs are always in same order
for (int i = 0; i < dirs.size(); i++) {
if (!matches(dirs.get(i), thatDirs.get(i))) return false;
}
return true;
}

private boolean matches(FileDirectory dir1, FileDirectory dir2) {
Rasters r1 = dir1.readRasters();
Rasters r2 = dir2.readRasters();

compare(r1.getHeight(), r2.getHeight(), "height");
compare(r1.getWidth(), r2.getWidth(), "width");
return true;
}

private void compare(Object a, Object b, String description) {
if (!Objects.equals(a, b)) {
throw new RuntimeException(String.format("Bitmap '%s' does not match: '%s' != '%s'", description, a, b));
}
}
}
57 changes: 57 additions & 0 deletions src/main/java/nf_core/nf/test/tiff/MetadataValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package nf_core.nf.test.tiff;

import mil.nga.tiff.FileDirectory;
import mil.nga.tiff.TIFFImage;

import java.util.List;
import java.util.Objects;

/**
* Compare the metadata declared in each dir.
*/
public class MetadataValidator {
private final TIFFImage image;

MetadataValidator(TIFFImage image) {
this.image = image;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MetadataValidator that = (MetadataValidator) o;

// a tiff file contains multiple 'directories', each containing multiple bitmaps
// consider two 'metadatas' equal if all their directories' stable metadata matches
List<FileDirectory> dirs = image.getFileDirectories();
List<FileDirectory> thatDirs = that.image.getFileDirectories();

if (dirs.size() != thatDirs.size()) {
throw new RuntimeException(String.format("Number of dirs does not match: '%s' vs '%s'", dirs.size(), thatDirs.size()));
}
// NOTE: this assumes dirs are always in same order
for (int i = 0; i < dirs.size(); i++) {
if (!matches(dirs.get(i), thatDirs.get(i))) return false;
}
return true;
}

/**
* Compare metadata between two dirs
* <p>
* Not all tiffs will use the same metadata, so this might not always work. In which
* case, consider comparing the bitmaps instead.
*/
private boolean matches(FileDirectory dir1, FileDirectory dir2) {
compare(dir1.getImageHeight(), dir2.getImageHeight(), "ImageHeight");
compare(dir1.getImageWidth(), dir2.getImageWidth(), "ImageWidth");
return true;
}

private void compare(Object a, Object b, String description) {
if (!Objects.equals(a, b)) {
throw new RuntimeException(String.format("Metadata '%s' does not match: '%s' != '%s'", description, a, b));
}
}
}
10 changes: 1 addition & 9 deletions src/main/java/nf_core/nf/test/tiff/Methods.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
package nf_core.nf.test.tiff;

import mil.nga.tiff.TIFFImage;

/*
* Add your custom methods to nf-test
*
*
* @author: nf-core
*/
public class Methods {

public static void hello() {
System.out.println("Hello from nft-tiff");
TIFFImage img = new TIFFImage();
}

}
21 changes: 15 additions & 6 deletions src/main/java/nf_core/nf/test/tiff/PathExtension.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
package nf_core.nf.test.tiff;

import mil.nga.tiff.TIFFImage;
import mil.nga.tiff.TiffReader;

import java.io.IOException;
import java.nio.file.Path;

/*
* Add your custom extensions to the path() method
*
* Adds custom extensions to the path() method
*
* @author: nf-core
*/

public class PathExtension {

public static void hello() {
System.out.println("Hello from nft-tiff");
}
/**
* Allows calling {@code path('filename').tiff} in nf-test
*/
public static TiffValidator getTiff(Path self) throws IOException {
TIFFImage image = TiffReader.readTiff(self.toFile());
return new TiffValidator(image);
}

}
19 changes: 19 additions & 0 deletions src/main/java/nf_core/nf/test/tiff/TiffValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package nf_core.nf.test.tiff;

import mil.nga.tiff.TIFFImage;

public class TiffValidator {
private final TIFFImage image;

public TiffValidator(TIFFImage image) {
this.image = image;
}

public MetadataValidator getMeta() {
return new MetadataValidator(image);
}

public BitmapValidator getBitmaps() {
return new BitmapValidator(image);
}
}
Binary file added tests/mindagap.mouse_heart.wga.tiff
Binary file not shown.
12 changes: 12 additions & 0 deletions tests/test_metadata/main.nf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
process COPY_TIFF {
input:
path(tiff)

output:
path("*.tiff"), emit: tiff

script:
"""
cp $tiff ${tiff.baseName}.copy.${tiff.extension}
"""
}
44 changes: 44 additions & 0 deletions tests/test_metadata/main.nf.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
nextflow_process {

name "Validate tiff metadata"
script "./main.nf"
process "COPY_TIFF"

tag "methods"

test("check can read tiff") {
when {
process {
"""
input[0] = Channel.of(
file("${baseDir}/tests/mindagap.mouse_heart.wga.tiff", checkIfExists:true),
)
"""
}
}
then {
def tiff = path(process.out.tiff[0]).tiff
assert tiff.meta != null
assert tiff.bitmaps != null
}
}

test("check compare same tiff") {
when {
process {
"""
input[0] = Channel.of(
file("${baseDir}/tests/mindagap.mouse_heart.wga.tiff", checkIfExists:true),
)
"""
}
}
then {
def tiff = path(process.out.tiff[0]).tiff
def reference = path("${baseDir}/tests/mindagap.mouse_heart.wga.tiff").tiff
assert tiff.meta == reference.meta
assert tiff.bitmaps == reference.bitmaps
}
}

}

0 comments on commit 79e0301

Please sign in to comment.