Files
fcitx5-m3ui/tests/monettheme_test.cpp
2026-10-20 00:23:12 +08:00

63 lines
3.9 KiB
C++

// The candidate window colours taken from a libmonet scheme must stay readable
// for any seed, in both modes.
// g++ -std=c++20 -Isrc -I<libmonet>/include tests/monettheme_test.cpp
// (add the flags from: pkg-config --cflags --libs Fcitx5Utils)
#include <cmath>
#include <cstdio>
#include "monettheme.h"
using namespace fcitx::m3ui;
static int failures = 0;
#define CHECK_MSG(cond, ...) \
do { \
if (!(cond)) { \
std::printf("FAIL line %d: %s ", __LINE__, #cond); \
std::printf(__VA_ARGS__); \
std::printf("\n"); \
failures++; \
} \
} while (0)
static monet::Rgb rgb(const fcitx::Color &c) {
return {static_cast<std::uint8_t>(std::lround(c.redF() * 255)), static_cast<std::uint8_t>(std::lround(c.greenF() * 255)),
static_cast<std::uint8_t>(std::lround(c.blueF() * 255))};
}
int main() {
unsigned state = 4242;
auto next = [&] { state = state * 1664525u + 1013904223u; return static_cast<std::uint8_t>(state >> 24); };
std::vector<monet::Rgb> seeds = {{61, 174, 233}, {255, 176, 201}, {0, 0, 0}, {255, 255, 255}, {128, 128, 128},
{255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0}, {0x67, 0x50, 0xA4}};
for (int i = 0; i < 300; i++) seeds.push_back({next(), next(), next()});
for (auto seed : seeds) {
for (auto mode : {monet::Mode::Light, monet::Mode::Dark}) {
const MonetColors c = mapScheme(monet::generate(seed, mode));
const char *m = mode == monet::Mode::Dark ? "dark" : "light";
const auto surface = rgb(c.surface), fill = rgb(c.highlightFill);
auto pair = [&](const char *name, monet::Rgb bg, const fcitx::Color &fg, double min) {
CHECK_MSG(monet::contrast(bg, rgb(fg)) >= min, "%s %s, seed %s: %.2f < %.1f", m, name, monet::hex(seed).c_str(),
monet::contrast(bg, rgb(fg)), min);
};
pair("candidate text", surface, c.normal, 7.0);
pair("candidate number", surface, c.candidateLabel, 4.5);
pair("candidate comment", surface, c.candidateComment, 4.5);
pair("typed pinyin being converted", surface, c.highlight, 4.5);
pair("text on the current candidate", fill, c.highlightCandidate, 7.0);
pair("number on the current candidate", fill, c.highlightCandidateLabel, 7.0);
pair("comment on the current candidate", fill, c.highlightCandidateComment, 7.0);
// the panel border can be seen against the panel
CHECK_MSG(monet::contrast(surface, rgb(c.outline)) >= 1.1, "%s border of seed %s", m, monet::hex(seed).c_str());
// the pill can be told apart from the panel, by tone since a container is only a few tones off the surface
CHECK_MSG(std::fabs(monet::toneOf(fill) - monet::toneOf(surface)) >= 3.0, "%s pill of seed %s: tones %.1f and %.1f", m,
monet::hex(seed).c_str(), monet::toneOf(fill), monet::toneOf(surface));
CHECK_MSG(c.surface.alpha() == 245 && c.normal.alpha() == 255 && c.highlightFill.alpha() == 255, "%s alpha of seed %s", m, monet::hex(seed).c_str());
// dark panel in dark mode, light panel in light mode
CHECK_MSG((monet::toneOf(surface) < 50) == (mode == monet::Mode::Dark), "%s panel tone of seed %s", m, monet::hex(seed).c_str());
}
}
std::printf(failures ? "%d check(s) failed\n" : "monettheme: all checks passed\n", failures);
return failures ? 1 : 0;
}