Files
radiantwave/tests/test_color_palettes.cpp
T
2026-08-17 20:36:59 -05:00

184 lines
6.2 KiB
C++

#include "db/database_manager.h"
#include "network/api_client.h"
#include "network/proclamation_sync.h"
#include <gtest/gtest.h>
#include <cstdlib>
#include <filesystem>
#include <string>
#include <vector>
using namespace radiantwave::api;
namespace {
// Reads an env var, returning "" when unset.
std::string env(const char* name) {
const char* value = std::getenv(name);
return value ? std::string(value) : std::string();
}
} // namespace
// ─── Offline: GET /color-palettes parse ────────────────────────────────
TEST(ColorPalettesTest, ParseColorPalettesJson) {
const std::string body =
R"([
{"solfeggioFrequencyId":1,
"colors":["#8B6914","#B8860B","#DAA520","#E8B64C","#FFD700","#FFE9A8","#FFF4CC"]},
{"solfeggioFrequencyId":5,
"colors":["#32CD32","#3CB371","#90EE90","#98FB98","#ADFFA9","#C8FFD2","#F0FFF0"]}
])";
std::vector<ColorPalette> out;
EXPECT_TRUE(parseColorPalettesJson(body, out));
ASSERT_EQ(out.size(), 2u);
EXPECT_EQ(out[0].solfeggio_frequency_id, 1);
ASSERT_EQ(out[0].colors.size(), 7u);
EXPECT_EQ(out[0].colors[0].r, 0x8B);
EXPECT_EQ(out[0].colors[0].g, 0x69);
EXPECT_EQ(out[0].colors[0].b, 0x14);
EXPECT_EQ(out[0].colors[6].b, 0xCC);
EXPECT_EQ(out[1].solfeggio_frequency_id, 5);
ASSERT_EQ(out[1].colors.size(), 7u);
EXPECT_EQ(out[1].colors[0].r, 0x32);
EXPECT_EQ(out[1].colors[0].g, 0xCD);
EXPECT_EQ(out[1].colors[0].b, 0x32);
}
TEST(ColorPalettesTest, ParseColorPalettesJsonAcceptsHexWithoutHash) {
const std::string body = R"([{"solfeggioFrequencyId":1,"colors":["32CD32"]}])";
std::vector<ColorPalette> out;
EXPECT_TRUE(parseColorPalettesJson(body, out));
ASSERT_EQ(out.size(), 1u);
ASSERT_EQ(out[0].colors.size(), 1u);
EXPECT_EQ(out[0].colors[0].r, 0x32);
EXPECT_EQ(out[0].colors[0].g, 0xCD);
EXPECT_EQ(out[0].colors[0].b, 0x32);
}
TEST(ColorPalettesTest, ParseColorPalettesJsonSkipsMissingFrequencyId) {
const std::string body =
R"([{"colors":["#32CD32"]},{"solfeggioFrequencyId":5,"colors":["#00FF7F"]}])";
std::vector<ColorPalette> out;
EXPECT_TRUE(parseColorPalettesJson(body, out));
ASSERT_EQ(out.size(), 1u);
EXPECT_EQ(out[0].solfeggio_frequency_id, 5);
}
TEST(ColorPalettesTest, ParseColorPalettesJsonEmptyAndMalformed) {
std::vector<ColorPalette> out;
EXPECT_TRUE(parseColorPalettesJson("[]", out));
EXPECT_TRUE(out.empty());
out.clear();
EXPECT_FALSE(parseColorPalettesJson("not json", out));
EXPECT_FALSE(parseColorPalettesJson(R"({"solfeggioFrequencyId":1})", out));
}
// ─── Offline: palettes embedded in /proclamations payload ──────────────
TEST(ColorPalettesTest, ParseProclamationPalettesJson) {
const std::string body =
R"PALETTE([
{"id":"p1","name":"One","solfeggioFrequencyId":1,
"colorPalette":["#8B6914","#B8860B"]},
{"id":"p2","name":"Two","solfeggioFrequencyId":5,
"colorPalette":["#32CD32","#3CB371","#90EE90"]},
{"id":"p3","name":"Also freq 5 (ignored, first wins)",
"solfeggioFrequencyId":5,
"colorPalette":["#FF0000"]}
])PALETTE";
std::vector<radiantwave::db::PaletteRecord> out;
EXPECT_TRUE(radiantwave::sync::parseProclamationPalettesJson(body, out));
ASSERT_EQ(out.size(), 2u);
EXPECT_EQ(out[0].solfeggio_frequency_id, 1);
ASSERT_EQ(out[0].colors.size(), 2u);
EXPECT_EQ(out[0].colors[0].r, 0x8B);
EXPECT_EQ(out[1].solfeggio_frequency_id, 5);
ASSERT_EQ(out[1].colors.size(), 3u);
EXPECT_EQ(out[1].colors[0].r, 0x32); // not #FF0000: first proclamation wins
}
TEST(ColorPalettesTest, ParseProclamationPalettesJsonSkipsMissingPalette) {
const std::string body =
R"([{"id":"p1","name":"No palette","solfeggioFrequencyId":1}])";
std::vector<radiantwave::db::PaletteRecord> out;
EXPECT_TRUE(radiantwave::sync::parseProclamationPalettesJson(body, out));
EXPECT_TRUE(out.empty());
}
// ─── Offline: DB round-trip via replaceColorPalettes ───────────────────
TEST(ColorPalettesTest, ReplaceColorPalettesRoundTrip) {
const std::string temp_path =
(std::filesystem::temp_directory_path() / "test_rw_db_palettesync.db").string();
if (std::filesystem::exists(temp_path)) {
std::filesystem::remove(temp_path);
}
radiantwave::db::DatabaseManager db;
ASSERT_TRUE(db.initialize(temp_path));
radiantwave::db::PaletteRecord rec;
rec.solfeggio_frequency_id = 1;
rec.colors = {{0x8B, 0x69, 0x14, 255}, {0xFF, 0xD7, 0x00, 255}};
ASSERT_TRUE(db.replaceColorPalettes({rec}));
auto palette = db.getPaletteForFrequencyId(1);
ASSERT_EQ(palette.size(), 2u);
EXPECT_EQ(palette[0].r, 0x8B);
EXPECT_EQ(palette[0].g, 0x69);
EXPECT_EQ(palette[0].b, 0x14);
EXPECT_EQ(palette[1].r, 0xFF);
EXPECT_EQ(palette[1].g, 0xD7);
EXPECT_EQ(palette[1].b, 0x00);
db.close();
std::filesystem::remove(temp_path);
}
TEST(ColorPalettesTest, ReplaceColorPalettesEmptyClearsAndFallsBackTo528) {
const std::string temp_path =
(std::filesystem::temp_directory_path() / "test_rw_db_paletteclear.db").string();
if (std::filesystem::exists(temp_path)) {
std::filesystem::remove(temp_path);
}
radiantwave::db::DatabaseManager db;
ASSERT_TRUE(db.initialize(temp_path));
ASSERT_TRUE(db.replaceColorPalettes({}));
// id 5 was cleared, so both the direct lookup and the 528 Hz fallback are empty.
EXPECT_TRUE(db.getPaletteForFrequencyId(5).empty());
db.close();
std::filesystem::remove(temp_path);
}
// ─── Live: GET /color-palettes (route not live yet; opt-in) ────────────
TEST(ColorPalettesLiveTest, FetchColorPalettesLive) {
if (env("RW_LIVE_COLOR_PALETTES").empty()) {
GTEST_SKIP() << "RW_LIVE_COLOR_PALETTES not set (route not live yet)";
}
std::vector<ColorPalette> palettes;
ASSERT_TRUE(fetchColorPalettes(palettes));
EXPECT_FALSE(palettes.empty());
for (const auto& p : palettes) {
EXPECT_GE(p.colors.size(), 1u);
}
}