#include #include "color.h" Color::Color(int r, int g, int b, int a) : r{r}, g{g}, b{b}, a{a} { if ( out_of_range(r) || out_of_range(g) || out_of_range(b) || out_of_range(a) ) { throw std::range_error{"value out of range"}; } } bool Color::out_of_range(int value) const { return ( value < 0 || value > 255); } int average(int a, int b) { return (a + b) / 2; } Color Color::operator+(Color const& rhs) const { return Color{ average(r, rhs.r), average(g, rhs.g), average(b, rhs.b) }; } Color operator+(int lhs, Color const& rhs) { return Color{lhs} + rhs; } Color operator+(Color const& lhs, int rhs) { return lhs + Color{rhs}; } std::ostream& operator<<(std::ostream& os, Color const& c) { return os << "{" << c.r << ", " << c.g << ", " << c.b << "}"; } #define CATCH_CONFIG_MAIN #include "catch.hpp" #include #include "color.h" std::string str(Color const& c) { std::ostringstream oss; oss << c; return oss.str(); } TEST_CASE("construction") { CHECK_NOTHROW( (Color{1,255,0,255}) ); CHECK_NOTHROW( (Color{100,200,0}) ); CHECK_NOTHROW( (Color{75,140,60}) ); CHECK_NOTHROW( (Color{128}) ); CHECK_THROWS( (Color{256,-1,256,-1}) ); } TEST_CASE("print") { CHECK( str(Color{50,80,20,128}) == "{50, 80, 20}"); } TEST_CASE("add color") { Color a{100,200,0}; Color b{50,80,120}; Color c{75,140,60}; REQUIRE( str(Color{50,80,20}) == "{50, 80, 20}"); CHECK( str(a+b) == str(c) ); CHECK( str(a+c) != str(b) ); CHECK( str(b+c) != str(a) ); } TEST_CASE("add grayscale") { Color a{100,200,0}; Color b{100,150,50}; REQUIRE( str(Color{50,80,20}) == "{50, 80, 20}"); CHECK( str(a+100) == str(b) ); CHECK( str(100+a) == str(b) ); }