Browse Source

DebugTools: add CompareImageFile, CompareImageToFile + CompareFileToImage.

These provide more convenience for the usual cases of comparing a
generated image to a file and vice versa.
pull/289/head
Vladimír Vondruš 8 years ago
parent
commit
7ad64bda2a
  1. 6
      doc/changelog.dox
  2. 62
      doc/snippets/MagnumDebugTools.cpp
  3. 8
      src/Magnum/DebugTools/CMakeLists.txt
  4. 162
      src/Magnum/DebugTools/CompareImage.cpp
  5. 297
      src/Magnum/DebugTools/CompareImage.h
  6. 50
      src/Magnum/DebugTools/Test/CMakeLists.txt
  7. BIN
      src/Magnum/DebugTools/Test/CompareImageActual.tga
  8. BIN
      src/Magnum/DebugTools/Test/CompareImageCompressed.dds
  9. BIN
      src/Magnum/DebugTools/Test/CompareImageExpected.tga
  10. 543
      src/Magnum/DebugTools/Test/CompareImageTest.cpp
  11. 28
      src/Magnum/DebugTools/Test/configure.h.cmake
  12. 2
      src/Magnum/DebugTools/visibility.h

6
doc/changelog.dox

@ -45,6 +45,12 @@ See also:
- New experimental @ref Animation library for keyframe-based animation
playback
@subsubsection changelog-latest-new-debugtools DebugTools library
- New @ref DebugTools::CompareImageFile, @ref DebugTools::CompareImageToFile
and @ref DebugTools::CompareFileToImage comparators extending
@ref DebugTools::CompareImage with convenient image file loading
@subsubsection changelog-latest-new-math Math library
- New @ref Math::CubicHermite class for cubic Hermite spline interpolation,

62
doc/snippets/MagnumDebugTools.cpp

@ -23,14 +23,76 @@
DEALINGS IN THE SOFTWARE.
*/
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/PluginManager/Manager.h>
#include <Magnum/Image.h>
#include <Magnum/PixelFormat.h>
#include <Magnum/DebugTools/CompareImage.h>
#include <Magnum/DebugTools/ResourceManager.h>
#include <Magnum/DebugTools/ObjectRenderer.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/Object.h>
#include <Magnum/SceneGraph/MatrixTransformation3D.h>
#include <Magnum/Trade/AbstractImporter.h>
using namespace Magnum;
namespace {
Image2D doProcessing() {
return Image2D{PixelFormat::RGBA8Unorm, {}, {}};
}
Image2D loadExpectedImage() {
return Image2D{PixelFormat::RGBA8Unorm, {}, {}};
}
}
struct Foo: TestSuite::Tester {
void foo() {
{
/* [CompareImageFile] */
CORRADE_COMPARE_WITH("actual.png", "expected.png",
(DebugTools::CompareImageFile{15.5f, 5.0f}));
/* [CompareImageFile] */
}
{
/* [CompareImageFile-manager] */
PluginManager::Manager<Trade::AbstractImporter> manager;
CORRADE_COMPARE_WITH("actual.png", "expected.png",
(DebugTools::CompareImageFile{manager, 15.5f, 5.0f}));
/* [CompareImageFile-manager] */
}
{
/* [CompareImageFile-skip] */
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("PngImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter/PngImporter not found, can't compare.");
CORRADE_COMPARE_WITH("actual.png", "expected.png",
(DebugTools::CompareImageFile{manager, 15.5f, 5.0f}));
/* [CompareImageFile-skip] */
}
{
/* [CompareImageToFile] */
Image2D actual = doProcessing();
CORRADE_COMPARE_WITH(actual, "expected.png",
(DebugTools::CompareImageToFile{15.5f, 5.0f}));
/* [CompareImageToFile] */
/* [CompareFileToImage] */
Image2D expected = loadExpectedImage();
CORRADE_COMPARE_WITH("actual.png", expected,
(DebugTools::CompareFileToImage{15.5f, 5.0f}));
/* [CompareFileToImage] */
}
}
};
int main() {
{
SceneGraph::Object<SceneGraph::MatrixTransformation3D>* object{};

8
src/Magnum/DebugTools/CMakeLists.txt

@ -149,7 +149,9 @@ elseif(BUILD_STATIC_PIC)
endif()
target_link_libraries(MagnumDebugTools PUBLIC Magnum)
if(Corrade_TestSuite_FOUND)
target_link_libraries(MagnumDebugTools PUBLIC Corrade::TestSuite)
target_link_libraries(MagnumDebugTools PUBLIC
Corrade::TestSuite
MagnumTrade)
endif()
if(TARGET_GL)
target_link_libraries(MagnumDebugTools PUBLIC MagnumGL)
@ -188,7 +190,9 @@ if(BUILD_TESTS)
endif()
target_link_libraries(MagnumDebugToolsTestLib PUBLIC Magnum)
if(Corrade_TestSuite_FOUND)
target_link_libraries(MagnumDebugToolsTestLib PUBLIC Corrade::TestSuite)
target_link_libraries(MagnumDebugToolsTestLib PUBLIC
Corrade::TestSuite
MagnumTrade)
endif()
if(TARGET_GL)
target_link_libraries(MagnumDebugToolsTestLib PUBLIC MagnumGL)

162
src/Magnum/DebugTools/CompareImage.cpp

@ -28,12 +28,16 @@
#include <map>
#include <sstream>
#include <vector>
#include <Corrade/Containers/Optional.h>
#include <Corrade/PluginManager/Manager.h>
#include "Magnum/ImageView.h"
#include "Magnum/PixelFormat.h"
#include "Magnum/Math/Functions.h"
#include "Magnum/Math/Color.h"
#include "Magnum/Math/Algorithms/KahanSum.h"
#include "Magnum/Trade/AbstractImporter.h"
#include "Magnum/Trade/ImageData.h"
namespace Magnum { namespace DebugTools { namespace Implementation {
@ -407,21 +411,46 @@ void printPixelDeltas(Debug& out, const std::vector<Float>& delta, const ImageVi
}
}
}}}
#ifndef DOXYGEN_GENERATING_OUTPUT
/* If Doxygen sees this, all @ref Corrade::TestSuite links break (prolly
because the namespace is undocumented in this project) */
namespace Corrade { namespace TestSuite {
enum class ImageComparatorBase::State: UnsignedByte {
PluginLoadFailed = 1,
ActualImageLoadFailed,
ExpectedImageLoadFailed,
ActualImageIsCompressed,
ExpectedImageIsCompressed,
DifferentSize,
DifferentFormat,
AboveThresholds,
AboveMeanThreshold,
AboveMaxThreshold
};
class ImageComparatorBase::FileState {
public:
explicit FileState(PluginManager::Manager<Trade::AbstractImporter>& manager): manager{&manager} {}
explicit FileState(): _privateManager{Containers::InPlaceInit}, manager{&*_privateManager} {}
private:
Containers::Optional<PluginManager::Manager<Trade::AbstractImporter>> _privateManager;
public:
PluginManager::Manager<Trade::AbstractImporter>* manager;
std::string actualFilename, expectedFilename;
Containers::Optional<Trade::ImageData2D> actualImageData, expectedImageData;
/** @todo could at least the views have a NoCreate constructor? */
Containers::Optional<ImageView2D> actualImage, expectedImage;
};
ImageComparatorBase::ImageComparatorBase(PluginManager::Manager<Trade::AbstractImporter>* manager, Float maxThreshold, Float meanThreshold): _maxThreshold{maxThreshold}, _meanThreshold{meanThreshold}, _max{}, _mean{} {
if(manager) _fileState.reset(new FileState{*manager});
using namespace Magnum;
Comparator<DebugTools::CompareImage>::Comparator(Float maxThreshold, Float meanThreshold): _maxThreshold{maxThreshold}, _meanThreshold{meanThreshold}, _max{}, _mean{} {
CORRADE_ASSERT(meanThreshold <= maxThreshold,
"DebugTools::CompareImage: maxThreshold can't be smaller than meanThreshold", );
}
bool Comparator<DebugTools::CompareImage>::operator()(const ImageView2D& actual, const ImageView2D& expected) {
ImageComparatorBase::~ImageComparatorBase() = default;
bool ImageComparatorBase::operator()(const ImageView2D& actual, const ImageView2D& expected) {
_actualImage = &actual;
_expectedImage = &expected;
@ -452,7 +481,115 @@ bool Comparator<DebugTools::CompareImage>::operator()(const ImageView2D& actual,
return false;
}
void Comparator<DebugTools::CompareImage>::printErrorMessage(Debug& out, const std::string& actual, const std::string& expected) const {
bool ImageComparatorBase::operator()(const std::string& actual, const std::string& expected) {
if(!_fileState) _fileState.reset(new FileState);
_fileState->actualFilename = actual;
_fileState->expectedFilename = expected;
std::unique_ptr<Trade::AbstractImporter> importer;
if(!(importer = _fileState->manager->loadAndInstantiate("AnyImageImporter"))) {
_state = State::PluginLoadFailed;
return false;
}
if(!importer->openFile(actual) || !(_fileState->actualImageData = importer->image2D(0))) {
_state = State::ActualImageLoadFailed;
return false;
}
if(!importer->openFile(expected) || !(_fileState->expectedImageData = importer->image2D(0))) {
_state = State::ExpectedImageLoadFailed;
return false;
}
if(_fileState->actualImageData->isCompressed()) {
_state = State::ActualImageIsCompressed;
return false;
}
if(_fileState->expectedImageData->isCompressed()) {
_state = State::ExpectedImageIsCompressed;
return false;
}
_fileState->actualImage.emplace(*_fileState->actualImageData);
_fileState->expectedImage.emplace(*_fileState->expectedImageData);
return operator()(*_fileState->actualImage, *_fileState->expectedImage);
}
bool ImageComparatorBase::operator()(const ImageView2D& actual, const std::string& expected) {
if(!_fileState) _fileState.reset(new FileState);
_fileState->expectedFilename = expected;
std::unique_ptr<Trade::AbstractImporter> importer;
if(!(importer = _fileState->manager->loadAndInstantiate("AnyImageImporter"))) {
_state = State::PluginLoadFailed;
return false;
}
if(!importer->openFile(expected) || !(_fileState->expectedImageData = importer->image2D(0))) {
_state = State::ExpectedImageLoadFailed;
return false;
}
if(_fileState->expectedImageData->isCompressed()) {
_state = State::ExpectedImageIsCompressed;
return false;
}
_fileState->expectedImage.emplace(*_fileState->expectedImageData);
return operator()(actual, *_fileState->expectedImage);
}
bool ImageComparatorBase::operator()(const std::string& actual, const ImageView2D& expected) {
if(!_fileState) _fileState.reset(new FileState);
_fileState->actualFilename = actual;
std::unique_ptr<Trade::AbstractImporter> importer;
if(!(importer = _fileState->manager->loadAndInstantiate("AnyImageImporter"))) {
_state = State::PluginLoadFailed;
return false;
}
if(!importer->openFile(actual) || !(_fileState->actualImageData = importer->image2D(0))) {
_state = State::ActualImageLoadFailed;
return false;
}
if(_fileState->actualImageData->isCompressed()) {
_state = State::ActualImageIsCompressed;
return false;
}
_fileState->actualImage.emplace(*_fileState->actualImageData);
return operator()(*_fileState->actualImage, expected);
}
void ImageComparatorBase::printErrorMessage(Debug& out, const std::string& actual, const std::string& expected) const {
if(_state == State::PluginLoadFailed) {
out << "AnyImageImporter plugin could not be loaded.";
return;
}
if(_state == State::ActualImageLoadFailed) {
out << "Actual image" << actual << "(" << Debug::nospace << _fileState->actualFilename << Debug::nospace << ")" << "could not be loaded.";
return;
}
if(_state == State::ExpectedImageLoadFailed) {
out << "Expected image" << expected << "(" << Debug::nospace << _fileState->expectedFilename << Debug::nospace << ")" << "could not be loaded.";
return;
}
if(_state == State::ActualImageIsCompressed) {
out << "Actual image" << actual << "(" << Debug::nospace << _fileState->actualFilename << Debug::nospace << ")" << "is compressed, comparison not possible.";
return;
}
if(_state == State::ExpectedImageIsCompressed) {
out << "Expected image" << expected << "(" << Debug::nospace << _fileState->expectedFilename << Debug::nospace << ")" << "is compressed, comparison not possible.";
return;
}
out << "Images" << actual << "and" << expected << "have";
if(_state == State::DifferentSize)
out << "different size, actual" << _actualImage->size() << "but"
@ -484,5 +621,4 @@ void Comparator<DebugTools::CompareImage>::printErrorMessage(Debug& out, const s
}
}
}}
#endif
}}}

297
src/Magnum/DebugTools/CompareImage.h

@ -29,13 +29,16 @@
* @brief Class @ref Magnum::DebugTools::CompareImage
*/
#include <memory>
#include <vector>
#include <Corrade/PluginManager/PluginManager.h>
#include <Corrade/TestSuite/Comparator.h>
#include "Magnum/Magnum.h"
#include "Magnum/GL/GL.h"
#include "Magnum/Math/Vector2.h"
#include "Magnum/DebugTools/visibility.h"
#include "Magnum/Trade/Trade.h"
namespace Magnum { namespace DebugTools {
@ -48,39 +51,87 @@ namespace Implementation {
}
class CompareImage;
class CompareImageFile;
class CompareImageToFile;
class CompareFileToImage;
}}
namespace Implementation {
class MAGNUM_DEBUGTOOLS_EXPORT ImageComparatorBase {
public:
explicit ImageComparatorBase(PluginManager::Manager<Trade::AbstractImporter>* manager, Float maxThreshold, Float meanThreshold);
/*implicit*/ ImageComparatorBase(): ImageComparatorBase{nullptr, 0.0f, 0.0f} {}
~ImageComparatorBase();
bool operator()(const ImageView2D& actual, const ImageView2D& expected);
bool operator()(const std::string& actual, const std::string& expected);
bool operator()(const std::string& actual, const ImageView2D& expected);
bool operator()(const ImageView2D& actual, const std::string& expected);
void printErrorMessage(Debug& out, const std::string& actual, const std::string& expected) const;
private:
class MAGNUM_DEBUGTOOLS_LOCAL FileState;
enum class State: UnsignedByte;
std::unique_ptr<FileState> _fileState;
Float _maxThreshold, _meanThreshold;
State _state{};
const ImageView2D *_actualImage, *_expectedImage;
Float _max, _mean;
std::vector<Float> _delta;
};
}}}
#ifndef DOXYGEN_GENERATING_OUTPUT
/* If Doxygen sees this, all @ref Corrade::TestSuite links break (prolly
because the namespace is undocumented in this project) */
namespace Corrade { namespace TestSuite {
template<> class MAGNUM_DEBUGTOOLS_EXPORT Comparator<Magnum::DebugTools::CompareImage> {
template<> class MAGNUM_DEBUGTOOLS_EXPORT Comparator<Magnum::DebugTools::CompareImage>: public Magnum::DebugTools::Implementation::ImageComparatorBase {
public:
explicit Comparator(Magnum::Float maxThreshold, Magnum::Float meanThreshold);
explicit Comparator(Magnum::Float maxThreshold, Magnum::Float meanThreshold): Magnum::DebugTools::Implementation::ImageComparatorBase{nullptr, maxThreshold, meanThreshold} {}
/*implicit*/ Comparator(): Comparator{0.0f, 0.0f} {}
bool operator()(const Magnum::ImageView2D& actual, const Magnum::ImageView2D& expected) {
return Magnum::DebugTools::Implementation::ImageComparatorBase::operator()(actual, expected);
}
};
bool operator()(const Magnum::ImageView2D& actual, const Magnum::ImageView2D& expected);
template<> class MAGNUM_DEBUGTOOLS_EXPORT Comparator<Magnum::DebugTools::CompareImageFile>: public Magnum::DebugTools::Implementation::ImageComparatorBase {
public:
explicit Comparator(PluginManager::Manager<Magnum::Trade::AbstractImporter>* manager, Magnum::Float maxThreshold, Magnum::Float meanThreshold): Magnum::DebugTools::Implementation::ImageComparatorBase{manager, maxThreshold, meanThreshold} {}
void printErrorMessage(Utility::Debug& out, const std::string& actual, const std::string& expected) const;
/*implicit*/ Comparator(): Comparator{nullptr, 0.0f, 0.0f} {}
private:
enum class State {
DifferentSize = 1,
DifferentFormat,
AboveThresholds,
AboveMeanThreshold,
AboveMaxThreshold
};
bool operator()(const std::string& actual, const std::string& expected) {
return Magnum::DebugTools::Implementation::ImageComparatorBase::operator()(actual, expected);
}
};
Magnum::Float _maxThreshold, _meanThreshold;
template<> class MAGNUM_DEBUGTOOLS_EXPORT Comparator<Magnum::DebugTools::CompareImageToFile>: public Magnum::DebugTools::Implementation::ImageComparatorBase {
public:
explicit Comparator(PluginManager::Manager<Magnum::Trade::AbstractImporter>* manager, Magnum::Float maxThreshold, Magnum::Float meanThreshold): Magnum::DebugTools::Implementation::ImageComparatorBase{manager, maxThreshold, meanThreshold} {}
State _state{};
const Magnum::ImageView2D *_actualImage, *_expectedImage;
Magnum::Float _max, _mean;
std::vector<Magnum::Float> _delta;
bool operator()(const Magnum::ImageView2D& actual, const std::string& expected) {
return Magnum::DebugTools::Implementation::ImageComparatorBase::operator()(actual, expected);
}
};
template<> class MAGNUM_DEBUGTOOLS_EXPORT Comparator<Magnum::DebugTools::CompareFileToImage>: public Magnum::DebugTools::Implementation::ImageComparatorBase {
public:
explicit Comparator(PluginManager::Manager<Magnum::Trade::AbstractImporter>* manager, Magnum::Float maxThreshold, Magnum::Float meanThreshold): Magnum::DebugTools::Implementation::ImageComparatorBase{manager, maxThreshold, meanThreshold} {}
bool operator()(const std::string& actual, const Magnum::ImageView2D& expected) {
return Magnum::DebugTools::Implementation::ImageComparatorBase::operator()(actual, expected);
}
};
}}
@ -95,6 +146,9 @@ To be used with @ref Corrade::TestSuite. Basic use is really simple:
@snippet debugtools-compareimage.cpp 0
@note For comparing image files, there are also @ref CompareImageFile,
@ref CompareImageToFile and @ref CompareFileToImage variants.
Based on actual images used, in case of commparison failure the comparator can
give for example the following result:
@ -130,12 +184,12 @@ is channel count), with max and mean delta being taken over the whole picture. @
@f]
The two parameters passed to the @ref CompareImage(Float, Float) "CompareImage(Float, Float)"
constructor are max and mean delta threshold. If the calculated values are
above these threshold, the comparison fails. In case of comparison failure the
diagnostic output contains calculated max/meanvalues, delta image visualization
and a list of top deltas. The delta image is an ASCII-art representation of the
image difference with each block being a maximum of pixel deltas in some area,
The two parameters passed to the @ref CompareImage(Float, Float) constructor
are max and mean delta threshold. If the calculated values are above these
threshold, the comparison fails. In case of comparison failure the diagnostic
output contains calculated max/meanvalues, delta image visualization and a list
of top deltas. The delta image is an ASCII-art representation of the image
difference with each block being a maximum of pixel deltas in some area,
printed as characters of different perceived brightness. Blocks with delta over
the max threshold are colored red, blocks with delta over the mean threshold
are colored yellow. The delta list contains X,Y pixel position (with origin at
@ -153,11 +207,12 @@ class CompareImage {
explicit CompareImage(Float maxThreshold, Float meanThreshold): _c{maxThreshold, meanThreshold} {}
/**
* @brief Implicit constructor
* @brief Construct with implicit thresholds
*
* Equivalent to calling the above with zero values.
* Equivalent to calling @ref CompareImage(Float, Float) with zero
* values.
*/
explicit CompareImage(): CompareImage{0.0f, 0.0f} {}
explicit CompareImage(): _c{0.0f, 0.0f} {}
#ifndef DOXYGEN_GENERATING_OUTPUT
TestSuite::Comparator<CompareImage>& comparator() {
@ -169,6 +224,192 @@ class CompareImage {
TestSuite::Comparator<CompareImage> _c;
};
/**
@brief Image file comparator
Similar to @ref CompareImage, but comparing images loaded from files. Example
usage:
@snippet MagnumDebugTools.cpp CompareImageFile
By default, the comparator uses a local instance of
@ref Corrade::PluginManager::Manager to load image files. This might be
problematic if the code being tested also uses a plugin manager instance or if
you need to use a different plugin directory, for example. For such cases it's
possible to supply an external instance:
@snippet MagnumDebugTools.cpp CompareImageFile-manager
The comparator uses the @ref Trade::AnyImageImporter "AnyImageImporter" plugin,
which in turn delegates the import to some importer plugin matching the image
format(s). Both the @ref Trade::AnyImageImporter "AnyImageImporter" and the
concrete importer plugin(s) need to be available, otherwise the comparison
fails. An alternative way is manually skipping the test if the plugins are not
available:
@snippet MagnumDebugTools.cpp CompareImageFile-skip
See also @ref CompareImageToFile and @ref CompareFileToImage for comparing
in-memory images to image files and vice versa.
*/
class CompareImageFile {
public:
/**
* @brief Constructor
* @param maxThreshold Max threshold. If any pixel has delta above
* this value, this comparison fails
* @param meanThreshold Mean threshold. If mean delta over all pixels
* is above this value, the comparison fails
*/
explicit CompareImageFile(Float maxThreshold, Float meanThreshold): _c{nullptr, maxThreshold, meanThreshold} {}
/**
* @brief Construct with an explicit plugin manager instance
* @param manager Image importer plugin manager instance used
* when comparing against images loaded from files
* @param maxThreshold Max threshold. If any pixel has delta above
* this value, this comparison fails
* @param meanThreshold Mean threshold. If mean delta over all pixels
* is above this value, the comparison fails
*/
explicit CompareImageFile(PluginManager::Manager<Trade::AbstractImporter>& manager, Float maxThreshold, Float meanThreshold): _c{&manager, maxThreshold, meanThreshold} {}
/**
* @brief Construct with an explicit plugin manager instance and implicit thresholds
*
* Equivalent to calling @ref CompareImageFile(PluginManager::Manager<Trade::AbstractImporter>&, Float, Float)
* with zero values.
*/
explicit CompareImageFile(PluginManager::Manager<Trade::AbstractImporter>& manager): _c{&manager, 0.0f, 0.0f} {}
/**
* @brief Construct with implicit thresholds
*
* Equivalent to calling @ref CompareImageFile(Float, Float) with zero
* values.
*/
explicit CompareImageFile(): _c{nullptr, 0.0f, 0.0f} {}
#ifndef DOXYGEN_GENERATING_OUTPUT
TestSuite::Comparator<CompareImageFile>& comparator() {
return _c;
}
#endif
private:
TestSuite::Comparator<CompareImageFile> _c;
};
/**
@brief Image-to-file comparator
A combination of @ref CompareImage and @ref CompareImageToFile, which allows to
compare an in-memory image to a image file. See their documentation for more
information. Example usage:
@snippet MagnumDebugTools.cpp CompareImageToFile
@see @ref CompareFileToImage
*/
class CompareImageToFile {
public:
/**
* @brief Constructor
*
* See @ref CompareImageFile::CompareImageFile(Float, Float) for more
* information.
*/
explicit CompareImageToFile(Float maxThreshold, Float meanThreshold): _c{nullptr, maxThreshold, meanThreshold} {}
/**
* @brief Construct with an explicit plugin manager instance
*
* See @ref CompareImageFile::CompareImageFile(PluginManager::Manager<Trade::AbstractImporter>&, Float, Float)
* for more information.
*/
explicit CompareImageToFile(PluginManager::Manager<Trade::AbstractImporter>& manager, Float maxThreshold, Float meanThreshold): _c{&manager, maxThreshold, meanThreshold} {}
/**
* @brief Construct with an explicit plugin manager instance and implicit thresholds
*
* Equivalent to calling @ref CompareImageToFile(PluginManager::Manager<Trade::AbstractImporter>&, Float, Float)
* with zero values.
*/
explicit CompareImageToFile(PluginManager::Manager<Trade::AbstractImporter>& manager): _c{&manager, 0.0f, 0.0f} {}
/**
* @brief Implicit constructor
*
* Equivalent to calling @ref CompareImageToFile(Float, Float) with zero
* values.
*/
explicit CompareImageToFile(): _c{nullptr, 0.0f, 0.0f} {}
#ifndef DOXYGEN_GENERATING_OUTPUT
TestSuite::Comparator<CompareImageToFile>& comparator() {
return _c;
}
#endif
private:
TestSuite::Comparator<CompareImageToFile> _c;
};
/**
@brief File-to-image comparator
A combination of @ref CompareImage and @ref CompareImageToFile, which allows to
compare an image file to an in-memory image. See their documentation for more
information. Example usage:
@snippet MagnumDebugTools.cpp CompareFileToImage
@see @ref CompareImageToFile
*/
class CompareFileToImage {
public:
/**
* @brief Constructor
*
* See @ref CompareImageFile::CompareImageFile(Float, Float) for more
* information.
*/
explicit CompareFileToImage(Float maxThreshold, Float meanThreshold): _c{nullptr, maxThreshold, meanThreshold} {}
/**
* @brief Construct with an explicit plugin manager instance
*
* See @ref CompareImageFile::CompareImageFile(PluginManager::Manager<Trade::AbstractImporter>&, Float, Float)
* for more information.
*/
explicit CompareFileToImage(PluginManager::Manager<Trade::AbstractImporter>& manager, Float maxThreshold, Float meanThreshold): _c{&manager, maxThreshold, meanThreshold} {}
/**
* @brief Construct with an explicit plugin manager instance and implicit thresholds
*
* Equivalent to calling @ref CompareFileToImage(PluginManager::Manager<Trade::AbstractImporter>&, Float, Float)
* with zero values.
*/
explicit CompareFileToImage(PluginManager::Manager<Trade::AbstractImporter>& manager): _c{&manager, 0.0f, 0.0f} {}
/**
* @brief Implicit constructor
*
* Equivalent to calling @ref CompareFileToImage(Float, Float) with zero
* values.
*/
explicit CompareFileToImage(): _c{nullptr, 0.0f, 0.0f} {}
#ifndef DOXYGEN_GENERATING_OUTPUT
TestSuite::Comparator<CompareFileToImage>& comparator() {
return _c;
}
#endif
private:
TestSuite::Comparator<CompareFileToImage> _c;
};
}}
#endif

50
src/Magnum/DebugTools/Test/CMakeLists.txt

@ -24,8 +24,56 @@
#
if(Corrade_TestSuite_FOUND)
corrade_add_test(DebugToolsCompareImageTest CompareImageTest.cpp LIBRARIES MagnumDebugToolsTestLib)
# Otherwise CMake complains that Corrade::PluginManager is not found, wtf
find_package(Corrade REQUIRED PluginManager)
if(CORRADE_TARGET_EMSCRIPTEN OR CORRADE_TARGET_ANDROID)
set(DEBUGTOOLS_TEST_DIR ".")
else()
set(DEBUGTOOLS_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR})
endif()
# CMake before 3.8 has broken $<TARGET_FILE*> expressions for iOS (see
# https://gitlab.kitware.com/cmake/cmake/merge_requests/404) and since
# Corrade doesn't support dynamic plugins on iOS, this sorta works around
# that. Should be revisited when updating Travis to newer Xcode (current
# has CMake 3.6).
if(NOT BUILD_PLUGINS_STATIC)
if(WITH_ANYIMAGEIMPORTER)
set(ANYIMAGEIMPORTER_PLUGIN_FILENAME $<TARGET_FILE:AnyImageImporter>)
endif()
if(WITH_TGAIMPORTER)
set(TGAIMPORTER_PLUGIN_FILENAME $<TARGET_FILE:TgaImporter>)
endif()
# First replace ${} variables, then $<> generator expressions
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/configure.h.in)
file(GENERATE OUTPUT $<TARGET_FILE_DIR:DebugToolsCompareImageTest>/configure.h
INPUT ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in)
else()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/configure.h)
endif()
corrade_add_test(DebugToolsCompareImageTest CompareImageTest.cpp
LIBRARIES MagnumDebugToolsTestLib
FILES
CompareImageActual.tga
CompareImageExpected.tga
CompareImageCompressed.dds)
set_target_properties(DebugToolsCompareImageTest PROPERTIES FOLDER "Magnum/DebugTools/Test")
if(NOT BUILD_PLUGINS_STATIC)
target_include_directories(DebugToolsCompareImageTest PRIVATE $<TARGET_FILE_DIR:DebugToolsCompareImageTest>)
else()
target_include_directories(DebugToolsCompareImageTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
if(WITH_ANYIMAGEIMPORTER)
target_link_libraries(DebugToolsCompareImageTest PRIVATE AnyImageImporter)
endif()
if(WITH_TGAIMPORTER)
target_link_libraries(DebugToolsCompareImageTest PRIVATE TgaImporter)
endif()
endif()
endif()
if(TARGET_GL)

BIN
src/Magnum/DebugTools/Test/CompareImageActual.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 B

BIN
src/Magnum/DebugTools/Test/CompareImageCompressed.dds

Binary file not shown.

BIN
src/Magnum/DebugTools/Test/CompareImageExpected.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 B

543
src/Magnum/DebugTools/Test/CompareImageTest.cpp

@ -25,14 +25,20 @@
#include <sstream>
#include <numeric>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/String.h>
#include "Magnum/ImageView.h"
#include "Magnum/PixelFormat.h"
#include "Magnum/DebugTools/CompareImage.h"
#include "Magnum/Math/Functions.h"
#include "Magnum/Math/Color.h"
#include "Magnum/Trade/AbstractImporter.h"
#include "configure.h"
namespace Magnum { namespace DebugTools { namespace Test {
@ -62,6 +68,38 @@ struct CompareImageTest: TestSuite::Tester {
void compareAboveThresholds();
void compareAboveMaxThreshold();
void compareAboveMeanThreshold();
void setupExternalPluginManager();
void teardownExternalPluginManager();
void image();
void imageError();
void imageFile();
void imageFileError();
void imageFileExternalPluginManager();
void imageFileExternalPluginManagerError();
void imageFilePluginLoadFailed();
void imageFileActualLoadFailed();
void imageFileExpectedLoadFailed();
void imageFileActualIsCompressed();
void imageFileExpectedIsCompressed();
void imageToFile();
void imageToFileError();
void imageToFileExternalPluginManager();
void imageToFileExternalPluginManagerError();
void imageToFilePluginLoadFailed();
void imageToFileExpectedLoadFailed();
void imageToFileExpectedIsCompressed();
void fileToImage();
void fileToImageError();
void fileToImageExternalPluginManager();
void fileToImageExternalPluginManagerError();
void fileToImagePluginLoadFailed();
void fileToImageActualLoadFailed();
void fileToImageActualIsCompressed();
private:
Containers::Optional<PluginManager::Manager<Trade::AbstractImporter>> _manager;
};
CompareImageTest::CompareImageTest() {
@ -87,7 +125,45 @@ CompareImageTest::CompareImageTest() {
&CompareImageTest::compareSameZeroThreshold,
&CompareImageTest::compareAboveThresholds,
&CompareImageTest::compareAboveMaxThreshold,
&CompareImageTest::compareAboveMeanThreshold});
&CompareImageTest::compareAboveMeanThreshold,
&CompareImageTest::image,
&CompareImageTest::imageError,
&CompareImageTest::imageFile,
&CompareImageTest::imageFileError});
addTests({&CompareImageTest::imageFileExternalPluginManager,
&CompareImageTest::imageFileExternalPluginManagerError},
&CompareImageTest::setupExternalPluginManager,
&CompareImageTest::teardownExternalPluginManager);
addTests({&CompareImageTest::imageFilePluginLoadFailed,
&CompareImageTest::imageFileActualLoadFailed,
&CompareImageTest::imageFileExpectedLoadFailed,
&CompareImageTest::imageFileActualIsCompressed,
&CompareImageTest::imageFileExpectedIsCompressed,
&CompareImageTest::imageToFile,
&CompareImageTest::imageToFileError});
addTests({&CompareImageTest::imageToFileExternalPluginManager,
&CompareImageTest::imageToFileExternalPluginManagerError},
&CompareImageTest::setupExternalPluginManager,
&CompareImageTest::teardownExternalPluginManager);
addTests({&CompareImageTest::imageToFilePluginLoadFailed,
&CompareImageTest::imageToFileExpectedLoadFailed,
&CompareImageTest::imageToFileExpectedIsCompressed,
&CompareImageTest::fileToImage,
&CompareImageTest::fileToImageError});
addTests({&CompareImageTest::fileToImageExternalPluginManager,
&CompareImageTest::fileToImageExternalPluginManagerError},
&CompareImageTest::setupExternalPluginManager,
&CompareImageTest::teardownExternalPluginManager);
addTests({&CompareImageTest::fileToImagePluginLoadFailed,
&CompareImageTest::fileToImageActualLoadFailed,
&CompareImageTest::fileToImageActualIsCompressed});
}
namespace {
@ -309,7 +385,7 @@ void CompareImageTest::compareDifferentSize() {
{
Error e(&out);
TestSuite::Comparator<CompareImage> compare;
TestSuite::Comparator<CompareImage> compare{{}, {}};
CORRADE_VERIFY(!compare(a, b));
compare.printErrorMessage(e, "a", "b");
}
@ -325,7 +401,7 @@ void CompareImageTest::compareDifferentFormat() {
{
Error e(&out);
TestSuite::Comparator<CompareImage> compare;
TestSuite::Comparator<CompareImage> compare{{}, {}};
CORRADE_VERIFY(!compare(a, b));
compare.printErrorMessage(e, "a", "b");
}
@ -399,6 +475,467 @@ void CompareImageTest::compareAboveMeanThreshold() {
" [1,0] #5647ec, expected #5610ed (Δ = 18.6667)\n");
}
void CompareImageTest::setupExternalPluginManager() {
_manager.emplace();
/* Load the plugin directly from the build tree. Otherwise it's either
static and already loaded or not present in the build tree */
#if defined(ANYIMAGEIMPORTER_PLUGIN_FILENAME) && defined(TGAIMPORTER_PLUGIN_FILENAME)
CORRADE_INTERNAL_ASSERT(_manager->load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded);
CORRADE_INTERNAL_ASSERT(_manager->load(TGAIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded);
#endif
}
void CompareImageTest::teardownExternalPluginManager() {
_manager = Containers::NullOpt;
}
namespace {
constexpr const char* ImageCompareError =
"Images a and b have both max and mean delta above threshold, actual 39/18.5 but at most 20/10 expected. Delta image:\n"
" |?M|\n"
" Pixels above max/mean threshold:\n"
" [1,1] #abcd85, expected #abcdfa (Δ = 39)\n"
" [1,0] #5647ec, expected #5610ed (Δ = 18.6667)\n"
" [0,1] #235710, expected #232710 (Δ = 16)\n";
}
void CompareImageTest::image() {
CORRADE_COMPARE_WITH(ActualRgb, ExpectedRgb, (CompareImage{40.0f, 20.0f}));
}
void CompareImageTest::imageError() {
std::stringstream out;
{
TestSuite::Comparator<CompareImage> compare{20.0f, 10.0f};
CORRADE_VERIFY(!compare(ActualRgb, ExpectedRgb));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), ImageCompareError);
}
void CompareImageTest::imageFile() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
}
CORRADE_COMPARE_WITH(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga"),
(CompareImageFile{40.0f, 20.0f}));
}
void CompareImageTest::imageFileError() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareImageFile> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga")));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), ImageCompareError);
}
void CompareImageTest::imageFileExternalPluginManager() {
if(_manager->loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
_manager->loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
CORRADE_COMPARE_WITH(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga"),
(CompareImageFile{*_manager, 40.0f, 20.0f}));
}
void CompareImageTest::imageFileExternalPluginManagerError() {
if(_manager->loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
_manager->loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
std::stringstream out;
{
TestSuite::Comparator<CompareImageFile> compare{&*_manager, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga")));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), ImageCompareError);
}
void CompareImageTest::imageFilePluginLoadFailed() {
PluginManager::Manager<Trade::AbstractImporter> manager{"nonexistent"};
if(manager.loadState("AnyImageImporter") != PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter plugin found, can't test.");
std::stringstream out;
{
TestSuite::Comparator<CompareImageFile> compare{&manager, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga")));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), "AnyImageImporter plugin could not be loaded.\n");
}
void CompareImageTest::imageFileActualLoadFailed() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareImageFile> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare("nonexistent.tga",
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga")));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), "Actual image a (nonexistent.tga) could not be loaded.\n");
}
void CompareImageTest::imageFileExpectedLoadFailed() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareImageFile> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
"nonexistent.tga"));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), "Expected image b (nonexistent.tga) could not be loaded.\n");
}
void CompareImageTest::imageFileActualIsCompressed() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("DdsImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or DdsImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareImageFile> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageCompressed.dds"),
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga")));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(Utility::String::replaceFirst(out.str(), DEBUGTOOLS_TEST_DIR, "..."), "Actual image a (.../CompareImageCompressed.dds) is compressed, comparison not possible.\n");
}
void CompareImageTest::imageFileExpectedIsCompressed() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("DdsImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or DdsImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareImageFile> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageCompressed.dds")));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(Utility::String::replaceFirst(out.str(), DEBUGTOOLS_TEST_DIR, "..."),
"Expected image b (.../CompareImageCompressed.dds) is compressed, comparison not possible.\n");
}
void CompareImageTest::imageToFile() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
}
CORRADE_COMPARE_WITH(ActualRgb,
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga"),
(CompareImageToFile{40.0f, 20.0f}));
}
void CompareImageTest::imageToFileError() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareImageToFile> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(ActualRgb,
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga")));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), ImageCompareError);
}
void CompareImageTest::imageToFileExternalPluginManager() {
if(_manager->loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
_manager->loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
CORRADE_COMPARE_WITH(ActualRgb,
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga"),
(CompareImageToFile{*_manager, 40.0f, 20.0f}));
}
void CompareImageTest::imageToFileExternalPluginManagerError() {
if(_manager->loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
_manager->loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
std::stringstream out;
{
TestSuite::Comparator<CompareImageToFile> compare{&*_manager, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(ActualRgb,
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga")));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), ImageCompareError);
}
void CompareImageTest::imageToFilePluginLoadFailed() {
PluginManager::Manager<Trade::AbstractImporter> manager{"nonexistent"};
if(manager.loadState("AnyImageImporter") != PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter plugin found, can't test.");
std::stringstream out;
{
TestSuite::Comparator<CompareImageToFile> compare{&manager, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(ActualRgb,
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageExpected.tga")));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), "AnyImageImporter plugin could not be loaded.\n");
}
void CompareImageTest::imageToFileExpectedLoadFailed() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareImageToFile> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(ActualRgb, "nonexistent.tga"));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), "Expected image b (nonexistent.tga) could not be loaded.\n");
}
void CompareImageTest::imageToFileExpectedIsCompressed() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("DdsImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or DdsImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareImageToFile> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(ActualRgb, Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageCompressed.dds")));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(Utility::String::replaceFirst(out.str(), DEBUGTOOLS_TEST_DIR, "..."),
"Expected image b (.../CompareImageCompressed.dds) is compressed, comparison not possible.\n");
}
void CompareImageTest::fileToImage() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
}
CORRADE_COMPARE_WITH(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
ExpectedRgb,
(CompareFileToImage{40.0f, 20.0f}));
}
void CompareImageTest::fileToImageError() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareFileToImage> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
ExpectedRgb));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), ImageCompareError);
}
void CompareImageTest::fileToImageExternalPluginManager() {
if(_manager->loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
_manager->loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
CORRADE_COMPARE_WITH(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
ExpectedRgb,
(CompareFileToImage{*_manager, 40.0f, 20.0f}));
}
void CompareImageTest::fileToImageExternalPluginManagerError() {
if(_manager->loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
_manager->loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
std::stringstream out;
{
TestSuite::Comparator<CompareFileToImage> compare{&*_manager, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
ExpectedRgb));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), ImageCompareError);
}
void CompareImageTest::fileToImagePluginLoadFailed() {
PluginManager::Manager<Trade::AbstractImporter> manager{"nonexistent"};
if(manager.loadState("AnyImageImporter") != PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter plugin found, can't test.");
std::stringstream out;
{
TestSuite::Comparator<CompareFileToImage> compare{&manager, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(
Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageActual.tga"),
ExpectedRgb));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), "AnyImageImporter plugin could not be loaded.\n");
}
void CompareImageTest::fileToImageActualLoadFailed() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("TgaImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or TgaImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareFileToImage> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare("nonexistent.tga", ExpectedRgb));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(out.str(), "Actual image a (nonexistent.tga) could not be loaded.\n");
}
void CompareImageTest::fileToImageActualIsCompressed() {
{
PluginManager::Manager<Trade::AbstractImporter> manager;
if(manager.loadState("AnyImageImporter") == PluginManager::LoadState::NotFound ||
manager.loadState("DdsImporter") == PluginManager::LoadState::NotFound)
CORRADE_SKIP("AnyImageImporter or DdsImporter plugins not found.");
}
std::stringstream out;
{
TestSuite::Comparator<CompareFileToImage> compare{nullptr, 20.0f, 10.0f};
CORRADE_VERIFY(!compare(Utility::Directory::join(DEBUGTOOLS_TEST_DIR, "CompareImageCompressed.dds"), ExpectedRgb));
Debug d{&out, Debug::Flag::DisableColors};
compare.printErrorMessage(d, "a", "b");
}
CORRADE_COMPARE(Utility::String::replaceFirst(out.str(), DEBUGTOOLS_TEST_DIR, "..."),
"Actual image a (.../CompareImageCompressed.dds) is compressed, comparison not possible.\n");
}
}}}
CORRADE_TEST_MAIN(Magnum::DebugTools::Test::CompareImageTest)

28
src/Magnum/DebugTools/Test/configure.h.cmake

@ -0,0 +1,28 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#cmakedefine ANYIMAGEIMPORTER_PLUGIN_FILENAME "${ANYIMAGEIMPORTER_PLUGIN_FILENAME}"
#cmakedefine TGAIMPORTER_PLUGIN_FILENAME "${TGAIMPORTER_PLUGIN_FILENAME}"
#define DEBUGTOOLS_TEST_DIR "${DEBUGTOOLS_TEST_DIR}"

2
src/Magnum/DebugTools/visibility.h

@ -39,8 +39,10 @@
#else
#define MAGNUM_DEBUGTOOLS_EXPORT CORRADE_VISIBILITY_STATIC
#endif
#define MAGNUM_DEBUGTOOLS_LOCAL CORRADE_VISIBILITY_LOCAL
#else
#define MAGNUM_DEBUGTOOLS_EXPORT
#define MAGNUM_DEBUGTOOLS_LOCAL
#endif
#endif

Loading…
Cancel
Save