// The candidate window colours taken from a libmonet scheme must stay readable // for any seed, in both modes. // g++ -std=c++20 -Isrc -I/include tests/monettheme_test.cpp // (add the flags from: pkg-config --cflags --libs Fcitx5Utils) #include #include #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::lround(c.redF() * 255)), static_cast(std::lround(c.greenF() * 255)), static_cast(std::lround(c.blueF() * 255))}; } int main() { unsigned state = 4242; auto next = [&] { state = state * 1664525u + 1013904223u; return static_cast(state >> 24); }; std::vector 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; }