From: Vsevolod Stakhov Date: Fri, 12 Mar 2021 17:58:52 +0000 (+0000) Subject: [Project] Css: Add some c++ unit tests X-Git-Tag: 3.0~591 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=1a799bffa70e88369713cee9391a10e68cd072a9;p=rspamd.git [Project] Css: Add some c++ unit tests --- diff --git a/contrib/DEPENDENCY_INFO.md b/contrib/DEPENDENCY_INFO.md index 12e00df26..9f6a156f9 100644 --- a/contrib/DEPENDENCY_INFO.md +++ b/contrib/DEPENDENCY_INFO.md @@ -32,3 +32,4 @@ | robin-hood | 3.9.1 | MIT | NO | | | frozen | 1.0.1 | Apache 2 | NO | | | fmt | 7.1.3 | MIT | NO | | +| doctest | 2.4.5 | MIT | NO | | diff --git a/src/libserver/css/css.cxx b/src/libserver/css/css.cxx index 6633b68fd..49bab734d 100644 --- a/src/libserver/css/css.cxx +++ b/src/libserver/css/css.cxx @@ -18,6 +18,9 @@ #include "css.hxx" #include "css_style.hxx" #include "css_parser.hxx" +#define DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#define DOCTEST_CONFIG_IMPLEMENT +#include "doctest/doctest.h" rspamd_css rspamd_css_parse_style (rspamd_mempool_t *pool, const guchar *begin, gsize len, diff --git a/src/libserver/css/css_value.cxx b/src/libserver/css/css_value.cxx index 5470e8f30..a2b4ba5d7 100644 --- a/src/libserver/css/css_value.cxx +++ b/src/libserver/css/css_value.cxx @@ -19,12 +19,26 @@ #include "frozen/unordered_map.h" #include "frozen/string.h" #include "contrib/robin-hood/robin_hood.h" +#include "fmt/core.h" + +#define DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#include "doctest/doctest.h" + +/* Helper for unit test stringification */ +namespace doctest { +template<> struct StringMaker { + static String convert(const rspamd::css::css_color& value) { + return fmt::format("r={};g={};b={};alpha={}", + value.r, value.g, value.b, value.alpha).c_str(); + } +}; + +} namespace rspamd::css { auto css_value::maybe_color_from_string(const std::string_view &input) - -> std::optional -{ +-> std::optional { auto found_it = css_colors_map.find(input); if (found_it != css_colors_map.end()) { @@ -34,17 +48,16 @@ auto css_value::maybe_color_from_string(const std::string_view &input) return std::nullopt; } -constexpr static inline auto hexpair_decode(char c1, char c2) -> std::uint8_t -{ +constexpr static inline auto hexpair_decode(char c1, char c2) -> std::uint8_t { std::uint8_t ret = 0; - if (c1 >= '0' && c1 <= '9') ret = c1 - '0'; + if (c1 >= '0' && c1 <= '9') ret = c1 - '0'; else if (c1 >= 'A' && c1 <= 'F') ret = c1 - 'A' + 10; else if (c1 >= 'a' && c1 <= 'f') ret = c1 - 'a' + 10; ret *= 16; - if (c2 >= '0' && c2 <= '9') ret += c2 - '0'; + if (c2 >= '0' && c2 <= '9') ret += c2 - '0'; else if (c2 >= 'A' && c2 <= 'F') ret += c2 - 'A' + 10; else if (c2 >= 'a' && c2 <= 'f') ret += c2 - 'a' + 10; @@ -52,8 +65,7 @@ constexpr static inline auto hexpair_decode(char c1, char c2) -> std::uint8_t } auto css_value::maybe_color_from_hex(const std::string_view &input) - -> std::optional -{ +-> std::optional { if (input.length() == 6) { /* Plain RGB */ css_color col(hexpair_decode(input[0], input[1]), @@ -81,8 +93,7 @@ auto css_value::maybe_color_from_hex(const std::string_view &input) } constexpr static inline auto rgb_color_component_convert(const css_parser_token &tok) - -> std::uint8_t -{ +-> std::uint8_t { std::uint8_t ret = 0; if (tok.type == css_parser_token::token_type::number_token) { @@ -95,7 +106,7 @@ constexpr static inline auto rgb_color_component_convert(const css_parser_token else if (dbl < 0) { dbl = 0; } - ret = (std::uint8_t)(dbl / 100.0 * 255.0); + ret = (std::uint8_t) (dbl / 100.0 * 255.0); } else { if (dbl > 1) { @@ -105,7 +116,7 @@ constexpr static inline auto rgb_color_component_convert(const css_parser_token dbl = 0; } - ret = (std::uint8_t)(dbl * 255.0); + ret = (std::uint8_t) (dbl * 255.0); } } @@ -113,8 +124,7 @@ constexpr static inline auto rgb_color_component_convert(const css_parser_token } constexpr static inline auto alpha_component_convert(const css_parser_token &tok) - -> std::uint8_t -{ +-> std::uint8_t { double ret = 1.0; if (tok.type == css_parser_token::token_type::number_token) { @@ -141,12 +151,11 @@ constexpr static inline auto alpha_component_convert(const css_parser_token &tok } } - return (std::uint8_t)(ret * 255.0); + return (std::uint8_t) (ret * 255.0); } constexpr static inline auto h_component_convert(const css_parser_token &tok) - -> double -{ +-> double { double ret = 0.0; if (tok.type == css_parser_token::token_type::number_token) { @@ -162,7 +171,7 @@ constexpr static inline auto h_component_convert(const css_parser_token &tok) ret = (dbl / 100.0); } else { - dbl = ((((int)dbl % 360) + 360) % 360); /* Deal with rotations */ + dbl = ((((int) dbl % 360) + 360) % 360); /* Deal with rotations */ ret = dbl / 360.0; /* Normalize to 0..1 */ } } @@ -171,8 +180,7 @@ constexpr static inline auto h_component_convert(const css_parser_token &tok) } constexpr static inline auto sl_component_convert(const css_parser_token &tok) - -> double -{ +-> double { double ret = 0.0; if (tok.type == css_parser_token::token_type::number_token) { @@ -183,8 +191,7 @@ constexpr static inline auto sl_component_convert(const css_parser_token &tok) } static inline auto hsl_to_rgb(double h, double s, double l) - -> css_color -{ +-> css_color { css_color ret; constexpr auto hue2rgb = [](auto p, auto q, auto t) -> auto { @@ -201,7 +208,7 @@ static inline auto hsl_to_rgb(double h, double s, double l) return q; } if (t * 3. < 2.) { - return p + (q - p) * (2.0/3.0 - t) * 6.0; + return p + (q - p) * (2.0 / 3.0 - t) * 6.0; } return p; }; @@ -226,8 +233,7 @@ static inline auto hsl_to_rgb(double h, double s, double l) } auto css_value::maybe_color_from_function(const css_consumed_block::css_function_block &func) - -> std::optional -{ +-> std::optional { if (func.as_string() == "rgb" && func.args.size() == 3) { css_color col{rgb_color_component_convert(func.args[0]->get_token_or_empty()), @@ -268,8 +274,7 @@ auto css_value::maybe_color_from_function(const css_consumed_block::css_function } auto css_value::maybe_dimension_from_number(const css_parser_token &tok) --> std::optional -{ +-> std::optional { if (std::holds_alternative(tok.value)) { auto dbl = std::get(tok.value); css_dimension dim; @@ -290,34 +295,33 @@ auto css_value::maybe_dimension_from_number(const css_parser_token &tok) } constexpr const auto display_names_map = frozen::make_unordered_map({ - {"hidden", css_display_value::DISPLAY_HIDDEN}, - {"none", css_display_value::DISPLAY_HIDDEN}, - {"inline", css_display_value::DISPLAY_NORMAL}, - {"block", css_display_value::DISPLAY_NORMAL}, - {"content", css_display_value::DISPLAY_NORMAL}, - {"flex", css_display_value::DISPLAY_NORMAL}, - {"grid" , css_display_value::DISPLAY_NORMAL}, - {"inline-block", css_display_value::DISPLAY_NORMAL}, - {"inline-flex", css_display_value::DISPLAY_NORMAL}, - {"inline-grid", css_display_value::DISPLAY_NORMAL}, - {"inline-table", css_display_value::DISPLAY_NORMAL}, - {"list-item", css_display_value::DISPLAY_NORMAL}, - {"run-in", css_display_value::DISPLAY_NORMAL}, - {"table", css_display_value::DISPLAY_NORMAL}, - {"table-caption", css_display_value::DISPLAY_NORMAL}, + {"hidden", css_display_value::DISPLAY_HIDDEN}, + {"none", css_display_value::DISPLAY_HIDDEN}, + {"inline", css_display_value::DISPLAY_NORMAL}, + {"block", css_display_value::DISPLAY_NORMAL}, + {"content", css_display_value::DISPLAY_NORMAL}, + {"flex", css_display_value::DISPLAY_NORMAL}, + {"grid", css_display_value::DISPLAY_NORMAL}, + {"inline-block", css_display_value::DISPLAY_NORMAL}, + {"inline-flex", css_display_value::DISPLAY_NORMAL}, + {"inline-grid", css_display_value::DISPLAY_NORMAL}, + {"inline-table", css_display_value::DISPLAY_NORMAL}, + {"list-item", css_display_value::DISPLAY_NORMAL}, + {"run-in", css_display_value::DISPLAY_NORMAL}, + {"table", css_display_value::DISPLAY_NORMAL}, + {"table-caption", css_display_value::DISPLAY_NORMAL}, {"table-column-group", css_display_value::DISPLAY_NORMAL}, {"table-header-group", css_display_value::DISPLAY_NORMAL}, {"table-footer-group", css_display_value::DISPLAY_NORMAL}, - {"table-row-group", css_display_value::DISPLAY_NORMAL}, - {"table-cell", css_display_value::DISPLAY_NORMAL}, - {"table-column", css_display_value::DISPLAY_NORMAL}, - {"table-row", css_display_value::DISPLAY_NORMAL}, - {"initial", css_display_value::DISPLAY_NORMAL}, + {"table-row-group", css_display_value::DISPLAY_NORMAL}, + {"table-cell", css_display_value::DISPLAY_NORMAL}, + {"table-column", css_display_value::DISPLAY_NORMAL}, + {"table-row", css_display_value::DISPLAY_NORMAL}, + {"initial", css_display_value::DISPLAY_NORMAL}, }); auto css_value::maybe_display_from_string(const std::string_view &input) - -> std::optional -{ +-> std::optional { auto f = display_names_map.find(input); if (f != display_names_map.end()) { @@ -328,18 +332,17 @@ auto css_value::maybe_display_from_string(const std::string_view &input) } -auto css_value::debug_str() const -> std::string -{ +auto css_value::debug_str() const -> std::string { std::string ret; - std::visit([&](const auto& arg) { + std::visit([&](const auto &arg) { using T = std::decay_t; if constexpr (std::is_same_v) { ret += "color: r=" + std::to_string(arg.r) + - "; g=" + std::to_string(arg.g) + - "; b=" + std::to_string(arg.b) + - "; a=" + std::to_string(arg.alpha); + "; g=" + std::to_string(arg.g) + + "; b=" + std::to_string(arg.b) + + "; a=" + std::to_string(arg.alpha); } else if constexpr (std::is_same_v) { ret += "size: " + std::to_string(arg); @@ -365,4 +368,24 @@ auto css_value::debug_str() const -> std::string return ret; } +TEST_SUITE("css values") { + TEST_CASE("css hex colors") { + const std::pair hex_tests[] = { + {"000", css_color(0, 0, 0)}, + {"000000", css_color(0, 0, 0)}, + {"f00", css_color(255, 0, 0)}, + {"FEDCBA", css_color(254, 220, 186)}, + {"234", css_color(34, 51, 68)}, + }; + + for (const auto &p : hex_tests) { + auto col_parsed = css_value::maybe_color_from_hex(p.first); + //CHECK_UNARY(col_parsed); + //CHECK_UNARY(col_parsed.value().to_color()); + auto final_col = col_parsed.value().to_color().value(); + CHECK(final_col == p.second); + } + } +}; + } diff --git a/src/libserver/css/css_value.hxx b/src/libserver/css/css_value.hxx index 93324a57c..4c013124c 100644 --- a/src/libserver/css/css_value.hxx +++ b/src/libserver/css/css_value.hxx @@ -23,6 +23,7 @@ #include #include #include +#include #include "parse_error.hxx" #include "css_parser.hxx" #include "contrib/expected/expected.hpp" @@ -39,6 +40,9 @@ struct alignas(int) css_color { css_color(std::uint8_t _r, std::uint8_t _g, std::uint8_t _b, std::uint8_t _alpha = 255) : r(_r), g(_g), b(_b), alpha(_alpha) {} css_color() = default; + friend bool operator==(const css_color& l, const css_color& r) { + return (memcmp(&l, &r, sizeof(css_color)) == 0); + } }; struct css_dimension { @@ -137,4 +141,5 @@ struct css_value { } + #endif //RSPAMD_CSS_VALUE_HXX diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0d85b08de..934b141c7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,6 +21,16 @@ IF(USE_CXX_LINKER) ENDIF() TARGET_LINK_LIBRARIES(rspamd-test rspamd-server) +SET(CXXTESTSSRC rspamd_cxx_unit.cxx) + +ADD_EXECUTABLE(rspamd-test-cxx EXCLUDE_FROM_ALL ${CXXTESTSSRC}) +SET_TARGET_PROPERTIES(rspamd-test-cxx PROPERTIES LINKER_LANGUAGE CXX) +ADD_DEPENDENCIES(rspamd-test-cxx rspamd-server) +ADD_DEPENDENCIES(rspamd-test-cxx doctest) +TARGET_LINK_LIBRARIES(rspamd-test-cxx PRIVATE rspamd-server) +TARGET_LINK_LIBRARIES(rspamd-test-cxx PRIVATE doctest) +SET_TARGET_PROPERTIES(rspamd-test-cxx PROPERTIES LINKER_LANGUAGE CXX) + IF(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") # Also add dependencies for convenience FILE(GLOB_RECURSE LUA_TESTS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/lua/*.*") diff --git a/test/rspamd_cxx_unit.cxx b/test/rspamd_cxx_unit.cxx new file mode 100644 index 000000000..eb456d2fd --- /dev/null +++ b/test/rspamd_cxx_unit.cxx @@ -0,0 +1,32 @@ +/*- + * Copyright 2021 Vsevolod Stakhov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#define DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#include "doctest/doctest.h" + +int +main(int argc, char** argv) +{ + doctest::Context context(argc, argv); + int res = context.run(); + + if(context.shouldExit()) { + return res; + } + + return res; +} \ No newline at end of file