From 4d14347c42af5578edd4e334a80a9d48c43bec79 Mon Sep 17 00:00:00 2001 From: Peter Keresztes Schmidt Date: Mon, 12 Apr 2021 09:07:35 +0200 Subject: [PATCH] tests: Add tests for ZmFont --- tests/CMakeLists.txt | 7 + tests/data/fonts/01_bad_magic.zmfnt | Bin 0 -> 8 bytes tests/data/fonts/02_variant_invalid.zmfnt | Bin 0 -> 24 bytes tests/data/fonts/03_missing_cps.zmfnt | Bin 0 -> 2952 bytes tests/data/fonts/04_valid.zmfnt | Bin 0 -> 3752 bytes tests/data/fonts/generate_fonts.py | 54 ++++++++ tests/zm_font.cpp | 156 ++++++++++++++++++++++ 7 files changed, 217 insertions(+) create mode 100644 tests/data/fonts/01_bad_magic.zmfnt create mode 100644 tests/data/fonts/02_variant_invalid.zmfnt create mode 100644 tests/data/fonts/03_missing_cps.zmfnt create mode 100644 tests/data/fonts/04_valid.zmfnt create mode 100644 tests/data/fonts/generate_fonts.py create mode 100644 tests/zm_font.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c863c7cbb..e0c68aeff 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,6 +14,7 @@ include(Catch) set(TEST_SOURCES zm_comms.cpp zm_crypt.cpp + zm_font.cpp zm_utils.cpp) add_executable(tests main.cpp ${TEST_SOURCES}) @@ -31,3 +32,9 @@ target_include_directories(tests ${CMAKE_CURRENT_BINARY_DIR}) catch_discover_tests(tests) + +add_custom_command(TARGET tests + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/data/ ${CMAKE_CURRENT_BINARY_DIR}/data/ + BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/data/) diff --git a/tests/data/fonts/01_bad_magic.zmfnt b/tests/data/fonts/01_bad_magic.zmfnt new file mode 100644 index 0000000000000000000000000000000000000000..a73d2b51f77b75a39290ad9df7cab0fcf8a3412f GIT binary patch literal 8 PcmZ>Ca&~cLU|;|M2iO5n literal 0 HcmV?d00001 diff --git a/tests/data/fonts/02_variant_invalid.zmfnt b/tests/data/fonts/02_variant_invalid.zmfnt new file mode 100644 index 0000000000000000000000000000000000000000..9cbd0b0243ac06f63fc9ec2b40cec80721e1fe76 GIT binary patch literal 24 Ycma#@b@K~hU|=}O;K;zh2xLG305X;Wn*aa+ literal 0 HcmV?d00001 diff --git a/tests/data/fonts/03_missing_cps.zmfnt b/tests/data/fonts/03_missing_cps.zmfnt new file mode 100644 index 0000000000000000000000000000000000000000..b66e696ed1229e76f925d096b81f03bc740d5be3 GIT binary patch literal 2952 zcma#@b@K~hU|`?^Lm&eRVEhy`{s}a`4kJVWN->Pmqu~Jxfzfm@nhr+O!Dv1hEeA%+ Qfzfhcv>X^M2k@5z0GE~o$p8QV literal 0 HcmV?d00001 diff --git a/tests/data/fonts/04_valid.zmfnt b/tests/data/fonts/04_valid.zmfnt new file mode 100644 index 0000000000000000000000000000000000000000..3cb839931a69e8ef9b82db2b9865357aaae1d0d2 GIT binary patch literal 3752 zcmeIxAr^oj5QO1To4~aUzNg7#_Qak@mR+OK;PZzt4Dn;xmucN3jcwOMtfW+Lq$7G( zZvBj2R9c_AxF8Tf;8EcICZrSLfP)FVH3z-(igXAZa4>. + */ + +#include "catch2/catch.hpp" + +#include "zm_font.h" + +CATCH_REGISTER_ENUM(FontLoadError, + FontLoadError::kOk, + FontLoadError::kFileNotFound, + FontLoadError::kInvalidFile) + +TEST_CASE("FontVariant: construction") { + FontVariant variant; + + SECTION("default construction") { + REQUIRE(variant.GetCharHeight() == 0); + REQUIRE(variant.GetCharWidth() == 0); + } + + SECTION("values in range") { + constexpr uint8 height = 10; + constexpr uint8 width = 10; + std::vector bitmap(FontVariant::kMaxNumCodePoints * height); + + REQUIRE_NOTHROW(variant = FontVariant(height, width, bitmap)); + + REQUIRE(variant.GetCharHeight() == height); + REQUIRE(variant.GetCharWidth() == width); + REQUIRE(variant.GetCodepointsCount() == FontVariant::kMaxNumCodePoints); + } + + SECTION("height out of range") { + constexpr uint8 height = FontVariant::kMaxCharHeight + 1; + constexpr uint8 width = 10; + std::vector bitmap(FontVariant::kMaxNumCodePoints * height); + + REQUIRE_THROWS(variant = FontVariant(height, width, bitmap)); + } + + SECTION("width out of range") { + constexpr uint8 height = 10; + constexpr uint8 width = FontVariant::kMaxCharWidth + 1; + std::vector bitmap(FontVariant::kMaxNumCodePoints * height); + + REQUIRE_THROWS(variant = FontVariant(height, width, bitmap)); + } + + SECTION("bitmap of wrong size") { + constexpr uint8 height = 10; + constexpr uint8 width = 10; + std::vector bitmap(FontVariant::kMaxNumCodePoints * height + 1); + + REQUIRE_THROWS(variant = FontVariant(height, width, bitmap)); + } +} + +TEST_CASE("FontVariant: GetCodepoint") { + constexpr uint8 height = 10; + constexpr uint8 width = 10; + std::vector bitmap(FontVariant::kMaxNumCodePoints * height); + + // fill bitmap for each codepoint alternating with 1 and std::numeric_limits::max() + std::generate(bitmap.begin(), bitmap.end(), + [n = 0, zero = true]() mutable { + if (n == height) { + zero = !zero; + n = 0; + } + n++; + if (zero) { + return static_cast(1); + } else { + return std::numeric_limits::max(); + } + }); + + FontVariant variant(height, width, bitmap); + nonstd::span cp; + + SECTION("in bounds") { + cp = variant.GetCodepoint(0); + REQUIRE(std::all_of(cp.begin(), cp.end(), + [](uint64 l) { return l == 1; }) == true); + + cp = variant.GetCodepoint(1); + REQUIRE(std::all_of(cp.begin(), cp.end(), + [](uint64 l) { return l == std::numeric_limits::max(); }) == true); + } + + SECTION("out-of-bounds: all-zero bitmap") { + cp = variant.GetCodepoint(FontVariant::kMaxNumCodePoints); + REQUIRE(std::all_of(cp.begin(), cp.end(), + [](uint64 l) { return l == 0; }) == true); + } +} + +TEST_CASE("ZmFont: variants not loaded") { + ZmFont font; + + SECTION("returns empty variant") { + FontVariant variant; + REQUIRE_NOTHROW(variant = font.GetFontVariant(0)); + + REQUIRE(variant.GetCharHeight() == 0); + REQUIRE(variant.GetCharWidth() == 0); + REQUIRE(variant.GetCodepoint(0).empty() == true); + } + + SECTION("variant idx out-of-bounds") { + REQUIRE_THROWS(font.GetFontVariant(kNumFontSizes)); + } +} + +TEST_CASE("ZmFont: load font file") { + ZmFont font; + + SECTION("file not found") { + REQUIRE(font.LoadFontFile("does_not_exist.zmfnt") == FontLoadError::kFileNotFound); + } + + SECTION("invalid files") { + REQUIRE(font.LoadFontFile("data/fonts/01_bad_magic.zmfnt") == FontLoadError::kInvalidFile); + REQUIRE(font.LoadFontFile("data/fonts/02_variant_invalid.zmfnt") == FontLoadError::kInvalidFile); + REQUIRE(font.LoadFontFile("data/fonts/03_missing_cps.zmfnt") == FontLoadError::kInvalidFile); + } + + SECTION("valid file") { + REQUIRE(font.LoadFontFile("data/fonts/04_valid.zmfnt") == FontLoadError::kOk); + + uint8 var_idx = GENERATE(range(static_cast(0), kNumFontSizes)); + FontVariant variant = font.GetFontVariant(var_idx); + REQUIRE(variant.GetCharHeight() == 10 + var_idx); + REQUIRE(variant.GetCharWidth() == 10 + var_idx); + + uint8 cp_idx = + GENERATE_COPY(range(static_cast(0), variant.GetCodepointsCount())); + nonstd::span cp = variant.GetCodepoint(cp_idx); + REQUIRE(std::all_of(cp.begin(), cp.end(), + [=](uint64 l) { return l == var_idx; }) == true); + } +}