tests: Add tests for ZmFont
This commit is contained in:
parent
0c939f45dd
commit
4d14347c42
|
@ -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/)
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,54 @@
|
|||
#!/bin/python
|
||||
|
||||
import struct
|
||||
|
||||
GOOD_MAGIC = b"ZMFNT\0"
|
||||
BAD_MAGIC = b"ABCDE\0"
|
||||
NUM_FONT_SIZES = 4
|
||||
|
||||
|
||||
class FontFile:
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
|
||||
def write_file_header(self, magic):
|
||||
with open(self.path, "wb") as f:
|
||||
f.write(magic)
|
||||
f.write(struct.pack("BB", 0, 0)) # pad
|
||||
|
||||
def write_bm_header(self, height, width, cp_count, idx):
|
||||
with open(self.path, "ab") as f:
|
||||
f.write(struct.pack("HHIII", height, width, cp_count, idx, 0))
|
||||
|
||||
def write_codepoints(self, value, height, count):
|
||||
with open(self.path, "ab") as f:
|
||||
for _ in range(height * count):
|
||||
f.write(struct.pack("Q", value))
|
||||
|
||||
|
||||
font = FontFile("01_bad_magic.zmfnt")
|
||||
font.write_file_header(BAD_MAGIC)
|
||||
|
||||
# height, width and number of codepoints out of bounds
|
||||
font = FontFile("02_variant_invalid.zmfnt")
|
||||
font.write_file_header(GOOD_MAGIC)
|
||||
font.write_bm_header(201, 65, 256, 0)
|
||||
|
||||
# mismatch between number of codepoints specified in header and actually stored ones
|
||||
font = FontFile("03_missing_cps.zmfnt")
|
||||
font.write_file_header(GOOD_MAGIC)
|
||||
offs = 0
|
||||
for _ in range(NUM_FONT_SIZES):
|
||||
font.write_bm_header(10, 10, 10, offs)
|
||||
offs += 10 * 10
|
||||
for _ in range(NUM_FONT_SIZES):
|
||||
font.write_codepoints(1, 10, 9)
|
||||
|
||||
font = FontFile("04_valid.zmfnt")
|
||||
font.write_file_header(GOOD_MAGIC)
|
||||
offs = 0
|
||||
for i in range(NUM_FONT_SIZES):
|
||||
font.write_bm_header(10 + i, 10 + i, 10, offs)
|
||||
offs += 10 * (10 + i)
|
||||
for i in range(NUM_FONT_SIZES):
|
||||
font.write_codepoints(i, 10 + i, 10)
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* This file is part of the ZoneMinder Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<uint64> 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<uint64> 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<uint64> 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<uint64> 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<uint64> bitmap(FontVariant::kMaxNumCodePoints * height);
|
||||
|
||||
// fill bitmap for each codepoint alternating with 1 and std::numeric_limits<uint64>::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<uint64>(1);
|
||||
} else {
|
||||
return std::numeric_limits<uint64>::max();
|
||||
}
|
||||
});
|
||||
|
||||
FontVariant variant(height, width, bitmap);
|
||||
nonstd::span<const uint64> 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<uint64>::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<decltype(kNumFontSizes)>(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<decltype(variant.GetCodepointsCount())>(0), variant.GetCodepointsCount()));
|
||||
nonstd::span<const uint64> cp = variant.GetCodepoint(cp_idx);
|
||||
REQUIRE(std::all_of(cp.begin(), cp.end(),
|
||||
[=](uint64 l) { return l == var_idx; }) == true);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue