From b48e8e93791d3601caab2c3d913eaedade576150 Mon Sep 17 00:00:00 2001 From: Luis Diaz Date: Sat, 12 Mar 2022 18:49:37 +0100 Subject: [PATCH] Add unit tests for Jp2Image revealing bugs (see #2147) --- src/jp2image.cpp | 6 -- unitTests/CMakeLists.txt | 1 + unitTests/test_basicio.cpp | 44 ++++++++++++++ unitTests/test_jp2image.cpp | 117 ++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 unitTests/test_jp2image.cpp diff --git a/src/jp2image.cpp b/src/jp2image.cpp index 556e67ff..a52b0860 100644 --- a/src/jp2image.cpp +++ b/src/jp2image.cpp @@ -174,10 +174,7 @@ void Jp2Image::readMetadata() { throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError()); } IoCloser closer(*io_); - // Ensure that this is the correct image type if (!isJp2Type(*io_, true)) { - if (io_->error() || io_->eof()) - throw Error(ErrorCode::kerFailedToReadImageData); throw Error(ErrorCode::kerNotAnImage, "JPEG-2000"); } @@ -411,10 +408,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, in if (io_->open() != 0) throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError()); - // Ensure that this is the correct image type if (!isJp2Type(*io_, false)) { - if (io_->error() || io_->eof()) - throw Error(ErrorCode::kerFailedToReadImageData); throw Error(ErrorCode::kerNotAJpeg); } diff --git a/unitTests/CMakeLists.txt b/unitTests/CMakeLists.txt index b6e0178b..df7cb100 100644 --- a/unitTests/CMakeLists.txt +++ b/unitTests/CMakeLists.txt @@ -14,6 +14,7 @@ add_executable(unit_tests test_helper_functions.cpp test_image_int.cpp test_ImageFactory.cpp + test_jp2image.cpp test_IptcKey.cpp test_LangAltValueRead.cpp test_pngimage.cpp diff --git a/unitTests/test_basicio.cpp b/unitTests/test_basicio.cpp index 76071a87..92672596 100644 --- a/unitTests/test_basicio.cpp +++ b/unitTests/test_basicio.cpp @@ -7,6 +7,50 @@ using namespace Exiv2; +TEST(MemIo_Default, readEReturns0) { + std::array buf; + MemIo io; + ASSERT_EQ(0, io.read(buf.data(), buf.size())); +} + +TEST(MemIo_Default, isNotAtEof) { + MemIo io; + ASSERT_FALSE(io.eof()); +} + +TEST(MemIo_Default, seekBeyondBufferSizeReturns1AndSetsEofToTrue) { + MemIo io; + ASSERT_EQ(1, io.seek(1, BasicIo::beg)); + ASSERT_TRUE(io.eof()); +} + +TEST(MemIo_Default, seekBefore0Returns1ButItDoesNotSetEofToTrue) { + MemIo io; + ASSERT_EQ(1, io.seek(-1, BasicIo::beg)); + ASSERT_FALSE(io.eof()); +} + +TEST(MemIo_Default, seekToEndPosition_doesNotTriggerEof) { + MemIo io; + ASSERT_EQ(0, io.tell()); + ASSERT_EQ(0, io.seek(0, BasicIo::end)); + ASSERT_EQ(0, io.tell()); + ASSERT_FALSE(io.eof()); +} + +TEST(MemIo_Default, seekToEndPositionAndReadTriggersEof) { + MemIo io; + ASSERT_EQ(0, io.seek(0, BasicIo::end)); + ASSERT_EQ(0, io.tell()); + + std::array buf2; + buf2.fill(0); + ASSERT_EQ(0, io.read(buf2.data(), 1)); // Note that we cannot even read 1 byte being at the end + ASSERT_TRUE(io.eof()); +} + +// ------------------------- + TEST(MemIo, isNotAtEofInitially) { std::array buf; buf.fill(0); diff --git a/unitTests/test_jp2image.cpp b/unitTests/test_jp2image.cpp new file mode 100644 index 00000000..faacb64b --- /dev/null +++ b/unitTests/test_jp2image.cpp @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include + +using namespace Exiv2; + +TEST(Jp2Image, canBeCreatedFromScratch) { + auto memIo = std::make_unique(); + const bool create{true}; + ASSERT_NO_THROW(Jp2Image image(std::move(memIo), create)); +} + +TEST(Jp2Image, canBeOpenedEvenWithAnEmptyMemIo) { + auto memIo = std::make_unique(); + const bool create{false}; + ASSERT_NO_THROW(Jp2Image image(std::move(memIo), create)); +} + +TEST(Jp2Image, mimeTypeIsPng) { + auto memIo = std::make_unique(); + const bool create{true}; + Jp2Image image(std::move(memIo), create); + + ASSERT_EQ("image/jp2", image.mimeType()); +} + +TEST(Jp2Image, printStructurePrintsNothingWithKpsNone) { + auto memIo = std::make_unique(); + const bool create{true}; + Jp2Image image(std::move(memIo), create); + + std::ostringstream stream; + image.printStructure(stream, Exiv2::kpsNone, 1); + + ASSERT_TRUE(stream.str().empty()); +} + +TEST(Jp2Image, printStructurePrintsDataWithKpsBasic) { + auto memIo = std::make_unique(); + const bool create{true}; + Jp2Image image(std::move(memIo), create); + + std::ostringstream stream; + image.printStructure(stream, Exiv2::kpsBasic, 1); + + ASSERT_FALSE(stream.str().empty()); +} + +TEST(Jp2Image, cannotReadMetadataFromEmptyIo) { + auto memIo = std::make_unique(); + const bool create{false}; + Jp2Image image(std::move(memIo), create); + + try { + image.readMetadata(); + FAIL(); + } catch (const Exiv2::Error& e) { + ASSERT_EQ(ErrorCode::kerNotAnImage, e.code()); + ASSERT_STREQ("This does not look like a JPEG-2000 image", e.what()); + } +} + +TEST(Jp2Image, cannotReadMetadataFromIoWhichCannotBeOpened) { + auto memIo = std::make_unique("NonExistingPath.jp2"); + const bool create{false}; + Jp2Image image(std::move(memIo), create); + + try { + image.readMetadata(); + FAIL(); + } catch (const Exiv2::Error& e) { + ASSERT_EQ(ErrorCode::kerDataSourceOpenFailed, e.code()); + } +} + +TEST(Jp2Image, cannotWriteMetadataToEmptyIo) { + auto memIo = std::make_unique(); + const bool create{false}; + Jp2Image image(std::move(memIo), create); + + try { + image.writeMetadata(); + FAIL(); + } catch (const Exiv2::Error& e) { + ASSERT_EQ(ErrorCode::kerNoImageInInputData, e.code()); + } +} + +TEST(Jp2Image, canWriteMetadataFromCreatedJp2Image) { + auto memIo = std::make_unique(); + const bool create{true}; + Jp2Image image(std::move(memIo), create); + ASSERT_NO_THROW(image.writeMetadata()); +} + +TEST(Jp2Image, cannotWriteMetadataToIoWhichCannotBeOpened) { + auto memIo = std::make_unique("NonExistingPath.jp2"); + const bool create{false}; + Jp2Image image(std::move(memIo), create); + + try { + image.readMetadata(); + FAIL(); + } catch (const Exiv2::Error& e) { + ASSERT_EQ(ErrorCode::kerDataSourceOpenFailed, e.code()); + } +} + +TEST(Jp2Image, canWriteMetadataAndReadAfterwards) { + auto memIo = std::make_unique(); + const bool create{true}; + Jp2Image image(std::move(memIo), create); + ASSERT_NO_THROW(image.writeMetadata()); + ASSERT_NO_THROW(image.readMetadata()); +}