Parcourir la source

[Project] Css: Add some c++ unit tests

tags/3.0
Vsevolod Stakhov il y a 3 ans
Parent
révision
1a799bffa7

+ 1
- 0
contrib/DEPENDENCY_INFO.md Voir le fichier

@@ -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 | |

+ 3
- 0
src/libserver/css/css.cxx Voir le fichier

@@ -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,

+ 78
- 55
src/libserver/css/css_value.cxx Voir le fichier

@@ -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<rspamd::css::css_color> {
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<css_value>
{
-> std::optional<css_value> {
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<css_value>
{
-> std::optional<css_value> {
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<css_value>
{
-> std::optional<css_value> {

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<css_value>
{
-> std::optional<css_value> {
if (std::holds_alternative<double>(tok.value)) {
auto dbl = std::get<double>(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<frozen::string, css_display_value>({
{"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<css_value>
{
-> std::optional<css_value> {
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<decltype(arg)>;

if constexpr (std::is_same_v<T, css_color>) {
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<T, double>) {
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<const char*, css_color> 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);
}
}
};

}

+ 5
- 0
src/libserver/css/css_value.hxx Voir le fichier

@@ -23,6 +23,7 @@
#include <variant>
#include <optional>
#include <vector>
#include <iosfwd>
#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

+ 10
- 0
test/CMakeLists.txt Voir le fichier

@@ -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/*.*")

+ 32
- 0
test/rspamd_cxx_unit.cxx Voir le fichier

@@ -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;
}

Chargement…
Annuler
Enregistrer