From 20f1a03c9135f33a5b040902aee10ae347ef7045 Mon Sep 17 00:00:00 2001 From: Bart Louwers Date: Mon, 13 Jan 2025 18:27:36 +0100 Subject: [PATCH] Add benchmark and test for color parser (#3139) --- benchmark/CMakeLists.txt | 1 + benchmark/util/color.benchmark.cpp | 31 +++++++++++++ benchmark/util/tilecover.benchmark.cpp | 10 ++-- test/CMakeLists.txt | 1 + test/util/color.test.cpp | 63 ++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 benchmark/util/color.benchmark.cpp create mode 100644 test/util/color.test.cpp diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index ed085650a..818ab90e0 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -11,6 +11,7 @@ add_library( ${PROJECT_SOURCE_DIR}/benchmark/src/mbgl/benchmark/benchmark.cpp ${PROJECT_SOURCE_DIR}/benchmark/storage/offline_database.benchmark.cpp ${PROJECT_SOURCE_DIR}/benchmark/util/tilecover.benchmark.cpp + ${PROJECT_SOURCE_DIR}/benchmark/util/color.benchmark.cpp ) target_include_directories( diff --git a/benchmark/util/color.benchmark.cpp b/benchmark/util/color.benchmark.cpp new file mode 100644 index 000000000..a6b90d0eb --- /dev/null +++ b/benchmark/util/color.benchmark.cpp @@ -0,0 +1,31 @@ +#include + +#include +#include +#include + +static const std::vector testStrings = {"#000000", + "#FFFFFF", + "#FF00FFAA", + "rgba(255, 0, 0, 1.0)", + "rgb(0, 255, 0)", + "blue", + "red", + "invalid-color", + "rgba(255, 255, 255, 0.5)", + "#123"}; + +namespace { + +void ColorParse(benchmark::State& state) { + for (auto _ : state) { + for (const auto& str : testStrings) { + auto result = mbgl::Color::parse(str); + benchmark::DoNotOptimize(result); + } + } +} + +}; // namespace + +BENCHMARK(ColorParse); diff --git a/benchmark/util/tilecover.benchmark.cpp b/benchmark/util/tilecover.benchmark.cpp index b3c63c61e..dde9f3e9e 100644 --- a/benchmark/util/tilecover.benchmark.cpp +++ b/benchmark/util/tilecover.benchmark.cpp @@ -15,7 +15,7 @@ static void TileCountBounds(benchmark::State& state) { auto count = util::tileCount(sanFrancisco, 10); length += count; } - (void)length; + benchmark::DoNotOptimize(length); } static void TileCoverPitchedViewport(benchmark::State& state) { @@ -29,7 +29,7 @@ static void TileCoverPitchedViewport(benchmark::State& state) { auto tiles = util::tileCover(transform.getState(), 8); length += tiles.size(); } - (void)length; + benchmark::DoNotOptimize(length); } static void TileCoverBounds(benchmark::State& state) { @@ -38,7 +38,7 @@ static void TileCoverBounds(benchmark::State& state) { auto tiles = util::tileCover(sanFrancisco, 8); length += tiles.size(); } - (void)length; + benchmark::DoNotOptimize(length); } static const auto geomPolygon = Polygon{ @@ -62,7 +62,7 @@ static void TileCoverPolygon(benchmark::State& state) { auto tiles = util::tileCover(geomPolygon, 8); length += tiles.size(); } - (void)length; + benchmark::DoNotOptimize(length); } static void TileCountPolygon(benchmark::State& state) { @@ -72,7 +72,7 @@ static void TileCountPolygon(benchmark::State& state) { auto tiles = util::tileCount(geomPolygon, 16); length += tiles; } - (void)length; + benchmark::DoNotOptimize(length); } BENCHMARK(TileCountBounds); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2955aa3a5..3469349c0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -89,6 +89,7 @@ add_library( ${PROJECT_SOURCE_DIR}/test/util/async_task.test.cpp ${PROJECT_SOURCE_DIR}/test/util/bounding_volumes.test.cpp ${PROJECT_SOURCE_DIR}/test/util/camera.test.cpp + ${PROJECT_SOURCE_DIR}/test/util/color.test.cpp ${PROJECT_SOURCE_DIR}/test/util/geo.test.cpp ${PROJECT_SOURCE_DIR}/test/util/grid_index.test.cpp ${PROJECT_SOURCE_DIR}/test/util/hash.test.cpp diff --git a/test/util/color.test.cpp b/test/util/color.test.cpp new file mode 100644 index 000000000..dd3f67df8 --- /dev/null +++ b/test/util/color.test.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +#include + +using namespace mbgl; + +void logUnexpectedValidResult(const std::string& input, const Color& color) { + std::cerr << "Unexpected valid result for input: " << input << "\n"; + std::cerr << "Parsed Color: r = " << color.r << ", g = " << color.g << ", b = " << color.b << ", a = " << color.a + << "\n"; +} + +const std::map> testCases = { + // Valid inputs + {"#000000", Color(0.0f, 0.0f, 0.0f, 1.0f)}, + {"#FFFFFF", Color(1.0f, 1.0f, 1.0f, 1.0f)}, + {"#FF0000", Color(1.0f, 0.0f, 0.0f, 1.0f)}, + {"rgba(255, 0, 0, 1.0)", Color(1.0f, 0.0f, 0.0f, 1.0f)}, + {"rgb(0, 255, 0)", Color(0.0f, 1.0f, 0.0f, 1.0f)}, + {"blue", Color::blue()}, + {"red", Color::red()}, + {"rgba(0, 0, 0, 0)", Color(0.0f, 0.0f, 0.0f, 0.0f)}, + {"#123", Color(0.067f, 0.133f, 0.2f, 1.0f)}, // Short hex format + {"rgb(-10, 0, 0)", Color(0.0f, 0.0f, 0.0f, 1.0f)}, // Clamped to 0 + {"rgba(300, 0, 0, 1.0)", Color(1.0f, 0.0f, 0.0f, 1.0f)}, // Clamped to 1 + // {"#GGGGGG", Color(0.0f, 0.0f, 0.0f, 1.0f)}, // Treated as fallback black + // not supported right now + // {"#0F0F", Color(0.0f, 1.0f, 0.0f, 1.0f)}, + // {"#123F", Color( + // static_cast(0x1) / (0xF + 1), + // static_cast(0x2) / (0xF + 1), + // static_cast(0x3) / (0xF + 1), + // static_cast(0x4) / (0xF + 1) + // )}, + + // Invalid inputs + {"not-a-color", std::nullopt}, + {"", std::nullopt}, +}; + +TEST(ColorParse, AllCases) { + constexpr float absError = 0.02f; + for (const auto& [input, expectedResult] : testCases) { + auto result = Color::parse(input); + + if (expectedResult.has_value()) { + // Valid case: Check the values + ASSERT_TRUE(result.has_value()); + EXPECT_NEAR(result->r, expectedResult->r, absError); + EXPECT_NEAR(result->g, expectedResult->g, absError); + EXPECT_NEAR(result->b, expectedResult->b, absError); + EXPECT_NEAR(result->a, expectedResult->a, absError); + } else { + // Invalid case: Ensure no value is returned + if (result.has_value()) { + logUnexpectedValidResult(input, *result); + } + EXPECT_FALSE(result.has_value()); + } + } +}