diff --git a/CMakeLists.txt b/CMakeLists.txt index ea542c37f..0fd490348 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,9 @@ find_package(Boost 1.67.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) # GIL headers from installed Boost instead of this clone of boostog/gil). include_directories(include) +# GIL header gil_test_common.hpp shared between tests +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/test) + #----------------------------------------------------------------------------- # Dependency: libpng, libjpeg, libtiff via Vcpkg or Conan #----------------------------------------------------------------------------- @@ -101,6 +104,7 @@ if(MSVC) string(REGEX REPLACE "/W3" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) string(REGEX REPLACE "-W3" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) add_compile_options(-W4) + add_compile_options(-bigobj) add_compile_options(-FC) # Need absolute path for __FILE__ used in tests add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE=1) @@ -134,6 +138,9 @@ file(GLOB _boost_gil_headers # Tests #----------------------------------------------------------------------------- if(GIL_BUILD_TESTS) + file(GLOB _boost_gil_test_headers + ${PROJECT_SOURCE_DIR}/test/gil_test_common.hpp) + enable_testing() add_subdirectory(test) if (GIL_ENABLE_IO) diff --git a/Jamfile b/Jamfile index 73e5759f3..a85b52cee 100644 --- a/Jamfile +++ b/Jamfile @@ -11,7 +11,8 @@ project boost-gil requirements # MSVC: Since VS2017, default is -std:c++14, so no explicit switch is required. msvc:on - msvc:"/W4" + msvc:/W4 + msvc:/bigobj msvc:_SCL_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE NOMINMAX intel:off gcc:"-std=c++11 -pedantic -fstrict-aliasing -Wconversion -Wextra -Wfloat-equal -Wshadow -Wsign-promo -Wstrict-aliasing -Wunused-parameter " diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6178d2107..136ec3e20 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,5 @@ # # Copyright (c) 2017 Mateusz Loskot -# All rights reserved. # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at @@ -9,32 +8,37 @@ message(STATUS "Configuring Boost.GIL core tests") foreach(name channel pixel pixel_iterator) - add_executable(gil_test_core_${name}) - target_sources(gil_test_core_${name} + add_executable(gil_test_${name}) + target_sources(gil_test_${name} PRIVATE ${_boost_gil_headers} + ${_boost_gil_test_headers} ${name}.cpp error_if.cpp) - target_link_libraries(gil_test_core_${name} + target_link_libraries(gil_test_${name} PRIVATE Boost::disable_autolinking Boost::filesystem Boost::unit_test_framework) - add_test(gil.tests.core.${name} gil_test_core_${name}) + add_test(gil.tests.core.${name} gil_test_${name}) endforeach() -add_executable(gil_test_core_image) -target_sources(gil_test_core_image +add_executable(gil_test_image) +target_sources(gil_test_image PRIVATE ${_boost_gil_headers} + ${_boost_gil_test_headers} error_if.cpp image.cpp sample_image.cpp) -target_link_libraries(gil_test_core_image +target_link_libraries(gil_test_image PRIVATE Boost::disable_autolinking Boost::filesystem Boost::unit_test_framework) add_test(gil.tests.core.image - gil_test_core_image + gil_test_image ${CMAKE_CURRENT_SOURCE_DIR}/gil_reference_checksums.txt) + +# New tests based on Boost.Test +add_subdirectory(channel) diff --git a/test/Jamfile b/test/Jamfile index 5d4da9d90..a36f1f06f 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -3,7 +3,8 @@ # (C) Copyright 2008: Lubomir Bourdev and Hailin Jin # # Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# (See accompanying file LICENSE_1_0.txt or +# copy at http://www.boost.org/LICENSE_1_0.txt) # bring in rules for testing import testing ; @@ -11,10 +12,11 @@ import testing ; project : requirements $(BOOST_ROOT) + . /boost/filesystem//boost_filesystem ; -test-suite gil : +test-suite "boost-gil-test" : [ run image.cpp sample_image.cpp error_if.cpp : : gil_reference_checksums.txt @@ -24,3 +26,5 @@ test-suite gil : [ run pixel.cpp error_if.cpp ] [ run pixel_iterator.cpp error_if.cpp ] ; + +build-project channel ; diff --git a/test/channel/CMakeLists.txt b/test/channel/CMakeLists.txt new file mode 100644 index 000000000..5e238d414 --- /dev/null +++ b/test/channel/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2018 Mateusz Loskot +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# +list(APPEND _boost_gil_test_headers ${CMAKE_CURRENT_SOURCE_DIR}/channel_test_fixture.hpp) + +foreach(name + channel_concepts + channel_test_fixture + channel_traits + scoped_channel_value + algorithm_channel_arithmetic + algorithm_channel_convert + algorithm_channel_invert + algorithm_channel_multiply + algorithm_channel_relation) + + add_executable(gil_test_${name}) + target_sources(gil_test_${name} + PRIVATE + ${_boost_gil_headers} + ${_boost_gil_test_headers} + ${name}.cpp) + target_link_libraries(gil_test_${name} + PRIVATE + Boost::disable_autolinking + Boost::unit_test_framework) + add_test(gil.tests.core.${name} gil_test_${name}) +endforeach() diff --git a/test/channel/Jamfile b/test/channel/Jamfile new file mode 100644 index 000000000..63e64a2db --- /dev/null +++ b/test/channel/Jamfile @@ -0,0 +1,28 @@ +# Boost.GIL +# +# Copyright (c) 2018 Mateusz Loskot +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or +# copy at http://www.boost.org/LICENSE_1_0.txt) + +import testing ; + +project + : requirements + $(BOOST_ROOT) + .. + ; + +test-suite "boost-gil-test-channel" + : + [ compile channel_concepts.cpp ] + [ run channel_test_fixture.cpp ] + [ run channel_traits.cpp ] + [ run scoped_channel_value.cpp ] + [ run algorithm_channel_arithmetic.cpp ] + [ run algorithm_channel_convert.cpp ] + [ run algorithm_channel_invert.cpp ] + [ run algorithm_channel_multiply.cpp ] + [ run algorithm_channel_relation.cpp ] + ; diff --git a/test/channel/TODO.md b/test/channel/TODO.md new file mode 100644 index 000000000..7a2604052 --- /dev/null +++ b/test/channel/TODO.md @@ -0,0 +1,10 @@ +# Channel TODO + +Issues and questions related to implementation, testing, etc. of channel: + +- Provide algorithm performance overloads for scoped channel and packed channels +- Update concepts and documentation +- What to do about pointer types?! +- Performance!! +- Is channel_convert the same as native? +- Is operator++ on float32_t the same as native? How about if operator++ is defined in scoped_channel to do _value++? diff --git a/test/channel/algorithm_channel_arithmetic.cpp b/test/channel/algorithm_channel_arithmetic.cpp new file mode 100644 index 000000000..78ee3a575 --- /dev/null +++ b/test/channel/algorithm_channel_arithmetic.cpp @@ -0,0 +1,112 @@ +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Copyright 2018 Mateusz Loskot +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#include +#include +#include + +#define BOOST_TEST_MODULE test_algorithm_channel_arithmetic +#include +#include "channel_test_fixture.hpp" + +namespace gil = boost::gil; +namespace fixture = boost::gil::test::fixture; + +template +void test_channel_arithmetic_mutable(boost::mpl::false_) {} + +template +void test_channel_arithmetic_mutable(boost::mpl::true_) +{ + using fixture_t = fixture::channel; + using channel_value_t = typename fixture_t::channel_value_t; + fixture_t f; + channel_value_t const v = f.min_v_; + + ++f.min_v_; + f.min_v_++; + --f.min_v_; + f.min_v_--; + BOOST_TEST(v == f.min_v_); + + f.min_v_ += 1; + f.min_v_ -= 1; + BOOST_TEST(v == f.min_v_); + + f.min_v_ *= 1; + f.min_v_ /= 1; + BOOST_TEST(v == f.min_v_); + + f.min_v_ = 1; // assignable to scalar + BOOST_TEST(f.min_v_ == 1); + f.min_v_ = v; // and to value type + BOOST_TEST(f.min_v_ == v); + + // test swap + channel_value_t v1 = f.min_v_; + channel_value_t v2 = f.max_v_; + std::swap(f.min_v_, f.max_v_); + BOOST_TEST(f.min_v_ > f.max_v_); + channel_value_t v3 = f.min_v_; + channel_value_t v4 = f.max_v_; + BOOST_TEST(v1 == v4); + BOOST_TEST(v2 == v3); +} + +template +void test_channel_arithmetic() +{ + using fixture_t = fixture::channel; + fixture_t f; + BOOST_TEST(f.min_v_ * 1 == f.min_v_); + BOOST_TEST(f.min_v_ / 1 == f.min_v_); + BOOST_TEST((f.min_v_ + 1) + 1 == f.min_v_ + 2); + BOOST_TEST((f.max_v_ - 1) - 1 == f.max_v_ - 2); + + using is_mutable_t = boost::mpl::bool_ + < + gil::channel_traits::is_mutable + >; + test_channel_arithmetic_mutable(is_mutable_t()); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_value, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_value; + test_channel_arithmetic(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_reference, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_reference; + test_channel_arithmetic(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + channel_reference_const, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_reference; + test_channel_arithmetic(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + packed_channel_reference, BitField, fixture::channel_bitfield_types) +{ + using channels565_t = fixture::packed_channels565; + test_channel_arithmetic(); + test_channel_arithmetic(); + test_channel_arithmetic(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + packed_dynamic_channel_reference, BitField, fixture::channel_bitfield_types) +{ + using channels565_t = fixture::packed_dynamic_channels565; + test_channel_arithmetic(); + test_channel_arithmetic(); +} diff --git a/test/channel/algorithm_channel_convert.cpp b/test/channel/algorithm_channel_convert.cpp new file mode 100644 index 000000000..d9ad2b571 --- /dev/null +++ b/test/channel/algorithm_channel_convert.cpp @@ -0,0 +1,115 @@ +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Copyright 2018 Mateusz Loskot +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#include +#include + +#define BOOST_TEST_MODULE test_algorithm_channel_convert +#include +#include "channel_test_fixture.hpp" + +namespace gil = boost::gil; +namespace fixture = boost::gil::test::fixture; + +template +struct test_convert_to +{ + using channel_t = typename fixture::channel::channel_t; + using channel_value_t = typename fixture::channel::channel_value_t; + + template + static void from(Channel src_min_v, Channel src_max_v) + { + channel_value_t min_v = gil::channel_convert(src_min_v); + channel_value_t max_v = gil::channel_convert(src_max_v); + fixture::channel_minmax_value expect; + BOOST_TEST(min_v == expect.min_v_); + BOOST_TEST(max_v == expect.max_v_); + } +}; + +//--- Test gil::channel_convert from integral channels to all byte channels ------------- +#define GIL_TEST_CHANNEL_CONVERT_FROM(source_channel_type) \ + BOOST_FIXTURE_TEST_SUITE( \ + channel_convert_from_##source_channel_type, \ + fixture::channel_minmax_value) \ + BOOST_AUTO_TEST_CASE_TEMPLATE(channel_value, Channel, fixture::channel_byte_types) \ + { test_convert_to>::from(min_v_, max_v_); } \ + BOOST_AUTO_TEST_CASE_TEMPLATE(channel_reference, Channel, fixture::channel_byte_types) \ + { test_convert_to>::from(min_v_, max_v_); } \ + BOOST_AUTO_TEST_CASE_TEMPLATE(channel_reference_const, Channel, fixture::channel_byte_types) \ + { test_convert_to>::from(min_v_, max_v_); } \ + BOOST_AUTO_TEST_CASE(packed_channel_reference) \ + { \ + using channels565_t = fixture::packed_channels565; \ + test_convert_to::from(min_v_, max_v_); \ + test_convert_to::from(min_v_, max_v_); \ + test_convert_to::from(min_v_, max_v_); \ + } \ + BOOST_AUTO_TEST_CASE(packed_dynamic_channel_reference) \ + { \ + using channels565_t = fixture::packed_dynamic_channels565; \ + test_convert_to::from(min_v_, max_v_); \ + test_convert_to::from(min_v_, max_v_); \ + } \ + BOOST_AUTO_TEST_SUITE_END() + +GIL_TEST_CHANNEL_CONVERT_FROM(uint8_t) +GIL_TEST_CHANNEL_CONVERT_FROM(int8_t) +GIL_TEST_CHANNEL_CONVERT_FROM(uint16_t) +GIL_TEST_CHANNEL_CONVERT_FROM(int16_t) +GIL_TEST_CHANNEL_CONVERT_FROM(uint32_t) +GIL_TEST_CHANNEL_CONVERT_FROM(int32_t) + +#undef GIL_TEST_CHANNEL_CONVERT_FROM + +// FIXME: gil::float32_t <-> gil::float64_t seems not supported + +//--- Test gil::channel_convert from gil::float32_t to all integer channels ------------- +BOOST_FIXTURE_TEST_SUITE(channel_convert_from_float32_t, + fixture::channel_minmax_value) + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_value, Channel, fixture::channel_integer_types) +{ + test_convert_to>::from(min_v_, max_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_reference, Channel, fixture::channel_integer_types) +{ + test_convert_to>::from(min_v_, max_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + channel_reference_const, Channel, fixture::channel_integer_types) +{ + test_convert_to>::from(min_v_, max_v_); +} + +BOOST_AUTO_TEST_SUITE_END() + +//--- Test gil::channel_convert from gil::float64_t to all integer channels ------------- +BOOST_FIXTURE_TEST_SUITE(channel_convert_from_float64_t, + fixture::channel_minmax_value) + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_value, Channel, fixture::channel_integer_types) +{ + test_convert_to>::from(min_v_, max_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_reference, Channel, fixture::channel_integer_types) +{ + test_convert_to>::from(min_v_, max_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + channel_reference_const, Channel, fixture::channel_integer_types) +{ + test_convert_to>::from(min_v_, max_v_); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/channel/algorithm_channel_invert.cpp b/test/channel/algorithm_channel_invert.cpp new file mode 100644 index 000000000..ab279151d --- /dev/null +++ b/test/channel/algorithm_channel_invert.cpp @@ -0,0 +1,63 @@ +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Copyright 2018 Mateusz Loskot +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#include + +#define BOOST_TEST_MODULE test_algorithm_channel_invert +#include +#include "channel_test_fixture.hpp" + +namespace gil = boost::gil; +namespace fixture = boost::gil::test::fixture; + +template +void test_channel_invert() +{ + fixture::channel f; + BOOST_TEST(gil::channel_invert(f.min_v_) == f.max_v_); + BOOST_TEST(gil::channel_invert(f.max_v_) == f.min_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_value, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_value; + test_channel_invert(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_reference, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_reference; + test_channel_invert(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + channel_reference_const, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_reference; + test_channel_invert(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + packed_channel_reference, BitField, fixture::channel_bitfield_types) +{ + using channels565_t = fixture::packed_channels565; + test_channel_invert(); + test_channel_invert(); + test_channel_invert(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + packed_dynamic_channel_reference, BitField, fixture::channel_bitfield_types) +{ + using channels565_t = fixture::packed_dynamic_channels565; + test_channel_invert(); + test_channel_invert(); +} + +// TODO: packed_channel_reference_const ? +// TODO: packed_dynamic_channel_reference_const ? diff --git a/test/channel/algorithm_channel_multiply.cpp b/test/channel/algorithm_channel_multiply.cpp new file mode 100644 index 000000000..c7521bf20 --- /dev/null +++ b/test/channel/algorithm_channel_multiply.cpp @@ -0,0 +1,61 @@ +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Copyright 2018 Mateusz Loskot +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#include + +#define BOOST_TEST_MODULE test_algorithm_channel_multiply +#include +#include "channel_test_fixture.hpp" + +namespace gil = boost::gil; +namespace fixture = boost::gil::test::fixture; + +template +void test_channel_multiply() +{ + fixture::channel f; + BOOST_TEST(gil::channel_multiply(f.min_v_, f.min_v_) == f.min_v_); + BOOST_TEST(gil::channel_multiply(f.max_v_, f.max_v_) == f.max_v_); + BOOST_TEST(gil::channel_multiply(f.max_v_, f.min_v_) == f.min_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_value, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_value; + test_channel_multiply(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_reference, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_reference; + test_channel_multiply(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + channel_reference_const, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_reference; + test_channel_multiply(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + packed_channel_reference, BitField, fixture::channel_bitfield_types) +{ + using channels565_t = fixture::packed_channels565; + test_channel_multiply(); + test_channel_multiply(); + test_channel_multiply(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + packed_dynamic_channel_reference, BitField, fixture::channel_bitfield_types) +{ + using channels565_t = fixture::packed_dynamic_channels565; + test_channel_multiply(); + test_channel_multiply(); +} diff --git a/test/channel/algorithm_channel_relation.cpp b/test/channel/algorithm_channel_relation.cpp new file mode 100644 index 000000000..4fab441a9 --- /dev/null +++ b/test/channel/algorithm_channel_relation.cpp @@ -0,0 +1,62 @@ +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Copyright 2018 Mateusz Loskot +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#include + +#define BOOST_TEST_MODULE test_algorithm_channel_relation +#include +#include "channel_test_fixture.hpp" + +namespace gil = boost::gil; +namespace fixture = boost::gil::test::fixture; + +template +void test_channel_relation() +{ + fixture::channel f; + BOOST_TEST(f.min_v_ <= f.max_v_); + BOOST_TEST(f.max_v_ >= f.min_v_); + BOOST_TEST(f.min_v_ < f.max_v_); + BOOST_TEST(f.max_v_ > f.min_v_); + BOOST_TEST(f.max_v_ != f.min_v_); + BOOST_TEST(f.min_v_ == f.min_v_); + BOOST_TEST(f.min_v_ != 1); // comparable to integral +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_value, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_value; + test_channel_relation(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_reference, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_reference; + test_channel_relation(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_reference_const, Channel, fixture::channel_byte_types) +{ + using fixture_t = fixture::channel_reference; + test_channel_relation(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(packed_channel_reference, BitField, fixture::channel_bitfield_types) +{ + using channels565_t = fixture::packed_channels565; + test_channel_relation(); + test_channel_relation(); + test_channel_relation(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(packed_dynamic_channel_reference, BitField, fixture::channel_bitfield_types) +{ + using channels565_t = fixture::packed_dynamic_channels565; + test_channel_relation(); + test_channel_relation(); +} diff --git a/test/channel/channel_concepts.cpp b/test/channel/channel_concepts.cpp new file mode 100644 index 000000000..bdf580d4d --- /dev/null +++ b/test/channel/channel_concepts.cpp @@ -0,0 +1,92 @@ +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Copyright 2018 Mateusz Loskot +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#include +#include + +#define BOOST_TEST_MODULE test_channel_concepts +#include +#include "channel_test_fixture.hpp" + +namespace gil = boost::gil; +namespace fixture = boost::gil::test::fixture; + +// A channel archetype - to test the minimum requirements of the concept +struct channel_value_archetype; + +struct channel_archetype +{ + // equality comparable + friend bool operator==(channel_archetype const&, channel_archetype const&) + { return true; } + // inequality comparable + friend bool operator!=(channel_archetype const&, channel_archetype const&) + { return false; } + // less-than comparable + friend bool operator<(channel_archetype const&, channel_archetype const&) + { return false; } + // convertible to a scalar + operator std::uint8_t() const { return 0; } + + channel_archetype& operator++() { return *this; } + channel_archetype& operator--() { return *this; } + channel_archetype operator++(int) { return *this; } + channel_archetype operator--(int) { return *this; } + + template + channel_archetype operator+=(Scalar) { return *this; } + template + channel_archetype operator-=(Scalar) { return *this; } + template + channel_archetype operator*=(Scalar) { return *this; } + template + channel_archetype operator/=(Scalar) { return *this; } + + using value_type = channel_value_archetype; + using reference = channel_archetype; + using const_reference = channel_archetype const; + using pointer = channel_value_archetype*; + using const_pointer = channel_value_archetype const*; + BOOST_STATIC_CONSTANT(bool, is_mutable=true); + + static value_type min_value(); + static value_type max_value(); +}; + +struct channel_value_archetype : public channel_archetype +{ + // default constructible + channel_value_archetype() {} + // copy constructible + channel_value_archetype(channel_value_archetype const&) = default; + // assignable + channel_value_archetype& operator=(channel_value_archetype const&) + {return *this;} + channel_value_archetype(std::uint8_t) {} +}; + +channel_value_archetype channel_archetype::min_value() +{ + return channel_value_archetype(); +} + +channel_value_archetype channel_archetype::max_value() +{ + return channel_value_archetype(); +} + +BOOST_AUTO_TEST_CASE(channel_minimal_requirements) +{ + // Do only compile-time tests for the archetype + // (because asserts like val1>(); + + fixture::channel_value(); + fixture::channel_reference(); + fixture::channel_reference(); +} diff --git a/test/channel/channel_test_fixture.cpp b/test/channel/channel_test_fixture.cpp new file mode 100644 index 000000000..cacb3e97a --- /dev/null +++ b/test/channel/channel_test_fixture.cpp @@ -0,0 +1,69 @@ +// +// Copyright 2018 Mateusz Loskot +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#define BOOST_TEST_MODULE test_channel_test_fixture +#include +#include "channel_test_fixture.hpp" + +namespace fixture = boost::gil::test::fixture; + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_minmax_value, Channel, fixture::channel_byte_types) +{ + fixture::channel_minmax_value fix; + fixture::channel_minmax_value exp; + BOOST_TEST(fix.min_v_ == exp.min_v_); + BOOST_TEST(fix.max_v_ == exp.max_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_value, Channel, fixture::channel_byte_types) +{ + fixture::channel_value fix; + fixture::channel_minmax_value exp; + BOOST_TEST(fix.min_v_ == exp.min_v_); + BOOST_TEST(fix.max_v_ == exp.max_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(channel_reference, Channel, fixture::channel_byte_types) +{ + fixture::channel_reference fix; + fixture::channel_minmax_value exp; + BOOST_TEST(fix.min_v_ == exp.min_v_); + BOOST_TEST(fix.max_v_ == exp.max_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + channel_reference_const, Channel, fixture::channel_byte_types) +{ + fixture::channel_reference fix; + fixture::channel_minmax_value exp; + BOOST_TEST(fix.min_v_ == exp.min_v_); + BOOST_TEST(fix.max_v_ == exp.max_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + packed_channels565, BitField, fixture::channel_bitfield_types) +{ + static_assert(std::is_integral::value, "bitfield is not integral type"); + + // Regardless of BitField buffer bit-size, the fixture is initialized + // with max value that fits into 5+6+5 bit integer + fixture::packed_channels565 fix; + fixture::channel_minmax_value exp; + BOOST_TEST(fix.data_ == exp.max_v_); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( + packed_dynamic_channels565, BitField, fixture::channel_bitfield_types) +{ + static_assert(std::is_integral::value, "bitfield is not integral type"); + + // Regardless of BitField buffer bit-size, the fixture is initialized + // with max value that fits into 5+6+5 bit integer + fixture::packed_dynamic_channels565 fix; + fixture::channel_minmax_value exp; + BOOST_TEST(fix.data_ == exp.max_v_); +} diff --git a/test/channel/channel_test_fixture.hpp b/test/channel/channel_test_fixture.hpp new file mode 100644 index 000000000..e8fe49feb --- /dev/null +++ b/test/channel/channel_test_fixture.hpp @@ -0,0 +1,226 @@ +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Copyright 2018 Mateusz Loskot +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#include +#include +#include +#include +#include +#include + +namespace boost { namespace gil { namespace test { namespace fixture { + +using channel_byte_types = std::tuple + < + std::uint8_t, + std::int8_t, + std::uint16_t, + std::int16_t, + std::uint32_t, + std::int32_t, + gil::float32_t, + gil::float64_t + >; + +using channel_integer_types = std::tuple + < + std::uint8_t, + std::int8_t, + std::uint16_t, + std::int16_t, + std::uint32_t, + std::int32_t + >; + +// FIXME: If float types are convertible between each other, +// currently they are not, then move to channel_byte_types and +// remove channel_integer_types as redundant. +using channel_float_types = std::tuple + < + gil::float32_t, + gil::float64_t + >; + +using channel_bitfield_types = std::tuple + < + std::uint16_t, + std::uint32_t, + std::uint64_t + // TODO: Shall we test signed types for unexpected conversions, etc.? + >; + + +template +struct channel_minmax_value +{ + //static_assert(std::) + ChannelValue min_v_; + ChannelValue max_v_; + channel_minmax_value() + : min_v_(gil::channel_traits::min_value()) + , max_v_(gil::channel_traits::max_value()) + {} +}; + +template +struct channel : public ChannelFixtureBase +{ + using channel_t = typename ChannelFixtureBase::channel_t; + using channel_value_t = typename gil::channel_traits::value_type; + + channel() + { + BOOST_TEST(this->min_v_ == gil::channel_traits::min_value()); + BOOST_TEST(this->max_v_ == gil::channel_traits::max_value()); + } +}; + +// The channel fixtures are defined for different types of channels +// (ie. channel values, references and subbyte references) +// ensure there are two members, min_v_ and max_v_ initialized +// with the minimum and maximum channel value. +// The different channel types have different ways to initialize them, +// thus require different fixtures provided. + +// For basic channel types values can be initialized directly. +template +struct channel_value +{ + using channel_t = ChannelValue; + channel_t min_v_; + channel_t max_v_; + + channel_value() + : min_v_(gil::channel_traits::min_value()) + , max_v_(gil::channel_traits::max_value()) + { + boost::function_requires>(); + } +}; + +// For channel references we need to have separate channel values. +template +struct channel_reference + : public channel_value::value_type> +{ + using parent_t = channel_value::value_type>; + using channel_t = ChannelRef; + channel_t min_v_; + channel_t max_v_; + + channel_reference() + : parent_t() + , min_v_(parent_t::min_v_) + , max_v_(parent_t::max_v_) + { + boost::function_requires>(); + } +}; + +// For sub-byte channel references we need to store the bit buffers somewhere +template +struct packed_channel_reference +{ + using channel_t = ChannelSubbyteRef; + using integer_t = typename channel_t::integer_t; + channel_t min_v_; + channel_t max_v_; + integer_t min_bitbuf_; + integer_t max_bitbuf_; + + packed_channel_reference() : min_v_(&min_bitbuf_), max_v_(&max_bitbuf_) + { + boost::function_requires>(); + + ChannelMutableRef b1(&min_bitbuf_); + b1 = gil::channel_traits::min_value(); + ChannelMutableRef b2(&max_bitbuf_); + b2 = gil::channel_traits::max_value(); + } +}; + +// For sub-byte channel references we need to store the bit buffers somewhere +template +struct packed_dynamic_channel_reference +{ + using channel_t = ChannelSubbyteRef; + using integer_t = typename channel_t::integer_t; + channel_t min_v_; + channel_t max_v_; + integer_t min_bitbuf_; + integer_t max_bitbuf_; + + packed_dynamic_channel_reference(int first_bit1 = 1, int first_bit2 = 2) + : min_v_(&min_bitbuf_, first_bit1) + , max_v_(&max_bitbuf_, first_bit2) + { + boost::function_requires>(); + + ChannelMutableRef b1(&min_bitbuf_, 1); + b1 = gil::channel_traits::min_value(); + ChannelMutableRef b2(&max_bitbuf_, 2); + b2 = gil::channel_traits::max_value(); + } +}; + +// Concrete fixture for 16-bit pack of 5,6,5-bit channels +template +struct packed_channels565 +{ + static_assert(sizeof(BitField) >= sizeof(std::uint16_t), "16-bit or more required"); + using channel_0_5_t = gil::packed_channel_reference; + using channel_5_6_t = gil::packed_channel_reference; + using channel_11_5_t = gil::packed_channel_reference; + + using fixture_0_5_t = fixture::packed_channel_reference; + using fixture_5_6_t = fixture::packed_channel_reference; + using fixture_11_5_t = fixture::packed_channel_reference; + + std::uint16_t data_ = 0; + channel_0_5_t channel1_; + channel_5_6_t channel2_; + channel_11_5_t channel3_; + + packed_channels565() : channel1_(&data_), channel2_(&data_), channel3_(&data_) + { + channel1_ = gil::channel_traits::max_value(); + channel2_ = gil::channel_traits::max_value(); + channel3_ = gil::channel_traits::max_value(); + BOOST_TEST(data_ == 65535); + } +}; + +// Concrete fixture for dynamically-referenced 16-bit pack of 5,6,5-bit channels +template +struct packed_dynamic_channels565 +{ + static_assert(sizeof(BitField) >= sizeof(std::uint16_t), "16-bit or more required"); + using channel_5_t = gil::packed_dynamic_channel_reference; + using channel_6_t = gil::packed_dynamic_channel_reference; + + using fixture_5_t = fixture::packed_dynamic_channel_reference; + using fixture_6_t = fixture::packed_dynamic_channel_reference; + + std::uint16_t data_ = 0; + channel_5_t channel1_; + channel_6_t channel2_; + channel_5_t channel3_; + + packed_dynamic_channels565() + : channel1_(&data_, 0) + , channel2_(&data_, 5) + , channel3_(&data_, 11) + { + channel1_ = gil::channel_traits::max_value(); + channel2_ = gil::channel_traits::max_value(); + channel3_ = gil::channel_traits::max_value(); + BOOST_TEST(data_ == 65535); + } +}; + +}}}} // namespace boost::gil::test::fixture diff --git a/test/channel/channel_traits.cpp b/test/channel/channel_traits.cpp new file mode 100644 index 000000000..7f0dd3f5b --- /dev/null +++ b/test/channel/channel_traits.cpp @@ -0,0 +1,56 @@ +// +// Copyright 2018 Mateusz Loskot +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#include +#include +#include +#include + +#define BOOST_TEST_MODULE test_channel_traits +#include + +namespace gil = boost::gil; + +template +void test_channel_minmax() +{ + BOOST_TEST(gil::channel_traits::min_value() == + std::numeric_limits::min()); + + BOOST_TEST(gil::channel_traits::max_value() == + std::numeric_limits::max()); +} + +BOOST_AUTO_TEST_CASE(channel_minmax_uint8_t) +{ + test_channel_minmax(); +} + +BOOST_AUTO_TEST_CASE(channel_minmax_int8_t) +{ + test_channel_minmax(); +} + +BOOST_AUTO_TEST_CASE(channel_minmax_uint16_t) +{ + test_channel_minmax(); +} + +BOOST_AUTO_TEST_CASE(channel_minmax_int16_t) +{ + test_channel_minmax(); +} + +BOOST_AUTO_TEST_CASE(channel_minmax_uint32_t) +{ + test_channel_minmax(); +} + +BOOST_AUTO_TEST_CASE(channel_minmax_int32_t) +{ + test_channel_minmax(); +} diff --git a/test/channel/scoped_channel_value.cpp b/test/channel/scoped_channel_value.cpp new file mode 100644 index 000000000..ce6832e50 --- /dev/null +++ b/test/channel/scoped_channel_value.cpp @@ -0,0 +1,55 @@ +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Copyright 2018 Mateusz Loskot +// +// Distribtted under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#include +#include +#include +#include +#include + +#define BOOST_TEST_MODULE test_scoped_channel_value +#include + +namespace gil = boost::gil; + +BOOST_AUTO_TEST_CASE(scoped_channel_float32_t) +{ + auto const tolerance = btt::tolerance(std::numeric_limits::epsilon()); + // min + BOOST_TEST(gil::float_point_zero::apply() == 0.0, tolerance); + BOOST_TEST(gil::channel_traits::min_value() == 0.0); + // max + BOOST_TEST(gil::float_point_one::apply() == 1.0, tolerance); + BOOST_TEST(gil::channel_traits::max_value() == 1.0); +} + +BOOST_AUTO_TEST_CASE(scoped_channel_float64_t) +{ + auto const tolerance = btt::tolerance(std::numeric_limits::epsilon()); + // min + BOOST_TEST(gil::float_point_zero::apply() == 0.0, tolerance); + BOOST_TEST(gil::channel_traits::min_value() == 0.0, tolerance); + // max + BOOST_TEST(gil::float_point_one::apply() == 1.0, tolerance); + BOOST_TEST(gil::channel_traits::max_value() == 1.0, tolerance); +} + +BOOST_AUTO_TEST_CASE(scoped_channel_halfs) +{ + // Create a double channel with range [-0.5 .. 0.5] + struct minus_half { static double apply() { return -0.5; } }; + struct plus_half { static double apply() { return 0.5; } }; + using halfs = gil::scoped_channel_value; + + auto const tolerance = btt::tolerance(std::numeric_limits::epsilon()); + BOOST_TEST(gil::channel_traits::min_value() == minus_half::apply(), tolerance); + BOOST_TEST(gil::channel_traits::max_value() == plus_half::apply(), tolerance); + // scoped channel maximum should map to the maximum + BOOST_TEST(gil::channel_convert( + gil::channel_traits::max_value()) == 65535, tolerance); +} diff --git a/test/gil_test_common.hpp b/test/gil_test_common.hpp new file mode 100644 index 000000000..9249c35b2 --- /dev/null +++ b/test/gil_test_common.hpp @@ -0,0 +1,38 @@ +// +// Copyright 2018 Mateusz Loskot +// +// Distribtted under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +#ifndef BOOST_GIL_TEST_TEST_TOOLS_HPP +#define BOOST_GIL_TEST_TEST_TOOLS_HPP + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4702) // unreachable code +#elif defined(__clang__) && defined(__has_warning) +#pragma clang diagnostic push +#elif defined(__GNUC__) && \ + !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wfloat-equal" +#pragma GCC diagnostic ignored "-Wshadow" +#endif + +#include + +#if defined(_MSC_VER) +#pragma warning(pop) +#elif defined(__clang__) && defined(__has_warning) +#pragma clang diagnostic pop +#elif defined(__GNUC__) && \ + !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) +#pragma GCC diagnostic pop +#endif + +namespace btt = boost::test_tools; +namespace but = boost::unit_test; + +#endif