private void assertTiffEquals(final TiffOutputSet sourceTiffOutputSet, final TiffOutputSet duplicateTiffOutputSet) {
        final List<TiffOutputDirectory> sourceDirectories = sourceTiffOutputSet.getDirectories();
        final List<TiffOutputDirectory> duplicatedDirectories = duplicateTiffOutputSet.getDirectories();

        assertEquals(sourceDirectories.size(), duplicatedDirectories.size(), "The TiffOutputSets have different numbers of directories.");

        for (int i = 0; i < sourceDirectories.size(); i++) {
            final TiffOutputDirectory sourceDirectory = sourceDirectories.get(i);
            final TiffOutputDirectory duplicateDirectory = duplicatedDirectories.get(i);

            assertEquals(sourceDirectory.getType(), duplicateDirectory.getType(), "Directory type mismatch.");

            final List<TiffOutputField> sourceFields = sourceDirectory.getFields();
            final List<TiffOutputField> duplicateFields = duplicateDirectory.getFields();

            final boolean fieldCountMatches = sourceFields.size() == duplicateFields.size();

            if (!fieldCountMatches) {
                /*
                 * Note that offset fields are not written again if a re-order makes
                 * them unnecessary. The TiffWriter does not write in the same order,
                 * but tries to optimize it.
                 */
                final List<Integer> sourceTags = new ArrayList<>();
                final List<Integer> duplicatedTags = new ArrayList<>();

                for (final TiffOutputField field : sourceFields) {
                    sourceTags.add(field.tag);
                }

                for (final TiffOutputField field : duplicateFields) {
                    duplicatedTags.add(field.tag);
                }

                final List<Integer> missingTags = new ArrayList<>(sourceTags);
                missingTags.removeAll(duplicatedTags);
                missingTags.remove((Integer) ExifTagConstants.EXIF_TAG_EXIF_OFFSET.tag);
                missingTags.remove((Integer) ExifTagConstants.EXIF_TAG_GPSINFO.tag);
                missingTags.remove((Integer) ExifTagConstants.EXIF_TAG_INTEROP_OFFSET.tag);
                missingTags.remove((Integer) TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT.tag);

                assertTrue(missingTags.isEmpty(), "Missing tags: " + missingTags);
            }

            for (final TiffOutputField sourceField : sourceFields) {
                final boolean isOffsetField =
                        sourceField.tag == ExifTagConstants.EXIF_TAG_EXIF_OFFSET.tag ||
                                sourceField.tag == ExifTagConstants.EXIF_TAG_GPSINFO.tag ||
                                sourceField.tag == ExifTagConstants.EXIF_TAG_INTEROP_OFFSET.tag ||
                                sourceField.tag == TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT.tag;

                /*
                 * Ignore offset fields. They may not be needed after rewrite
                 * and their value changes anyway.
                 */
                if (isOffsetField) {
                    continue;
                }

                final TiffOutputField duplicateField = duplicateDirectory.findField(sourceField.tag);

                assertNotNull(duplicateField, "Field is missing: " + sourceField.tagInfo);

                assertEquals(sourceField.tag, duplicateField.tag, "TiffOutputField tag mismatch.");
                assertEquals(sourceField.abstractFieldType, duplicateField.abstractFieldType, "TiffOutputField fieldType mismatch.");
                assertEquals(sourceField.count, duplicateField.count, "TiffOutputField count mismatch.");

                assertArrayEquals(sourceField.getData(), duplicateField.getData(), "Bytes are different for field: " + sourceField);
            }
        }
    }
Test data.
@return test data.
@throws Exception if it fails to read the images with EXIF.
src/test/java/org/apache/commons/imaging/formats/jpeg/exif/ExifRewriterRoundtripTest.java