Skip to content

Commit 7dbee86

Browse files
author
Dave Plummer
committed
Tests
1 parent 172fc7d commit 7dbee86

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

tests/tests.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,3 +432,126 @@ TEST_F(APITest, RapidCreationDeletion)
432432
}
433433
}
434434
}
435+
436+
TEST_F(APITest, CanvasFeatureEffectWithSchedule)
437+
{
438+
// Create a canvas
439+
json canvasData = {
440+
{"id", -1},
441+
{"name", "Test Canvas " + std::to_string(std::time(nullptr))},
442+
{"width", 100},
443+
{"height", 100}
444+
};
445+
446+
auto createCanvasResponse = cpr::Post(
447+
cpr::Url{BASE_URL + "/canvases"},
448+
cpr::Body{canvasData.dump()},
449+
jsonHeader, noPersistParam
450+
);
451+
ASSERT_EQ(createCanvasResponse.status_code, 201);
452+
auto canvasJson = json::parse(createCanvasResponse.text);
453+
int canvasId = canvasJson["id"].get<int>();
454+
455+
// Create a feature
456+
json featureData = {
457+
{"hostName", "test-host"},
458+
{"friendlyName", "Test Feature"},
459+
{"port", 1234},
460+
{"width", 32},
461+
{"height", 16},
462+
{"offsetX", 10},
463+
{"offsetY", 10},
464+
{"reversed", false},
465+
{"channel", 1},
466+
{"redGreenSwap", false},
467+
{"clientBufferCount", 8}
468+
};
469+
470+
auto createFeatureResponse = cpr::Post(
471+
cpr::Url{BASE_URL + "/canvases/" + std::to_string(canvasId) + "/features"},
472+
cpr::Body{featureData.dump()},
473+
jsonHeader, noPersistParam
474+
);
475+
ASSERT_EQ(createFeatureResponse.status_code, 200);
476+
auto featureJson = json::parse(createFeatureResponse.text);
477+
int featureId = featureJson["id"].get<int>();
478+
479+
// Create first effect with schedule
480+
json effect1Data = {
481+
{"type", "SolidColorFill"},
482+
{"name", "Test Effect 1"},
483+
{"color", {
484+
{"red", 255},
485+
{"green", 0},
486+
{"blue", 0}
487+
}},
488+
{"schedule", {
489+
{"daysOfWeek", 0x3E}, // Monday through Friday
490+
{"startTime", "09:00:00"},
491+
{"stopTime", "17:00:00"}
492+
}}
493+
};
494+
495+
auto createEffect1Response = cpr::Post(
496+
cpr::Url{BASE_URL + "/canvases/" + std::to_string(canvasId) + "/effects"},
497+
cpr::Body{effect1Data.dump()},
498+
jsonHeader, noPersistParam
499+
);
500+
ASSERT_EQ(createEffect1Response.status_code, 200);
501+
502+
// Create second effect
503+
json effect2Data = {
504+
{"type", "SolidColorFill"},
505+
{"name", "Test Effect 2"},
506+
{"color", {
507+
{"red", 0},
508+
{"green", 0},
509+
{"blue", 255}
510+
}}
511+
};
512+
513+
auto createEffect2Response = cpr::Post(
514+
cpr::Url{BASE_URL + "/canvases/" + std::to_string(canvasId) + "/effects"},
515+
cpr::Body{effect2Data.dump()},
516+
jsonHeader, noPersistParam
517+
);
518+
ASSERT_EQ(createEffect2Response.status_code, 200);
519+
520+
// Get the canvas to verify effects
521+
auto getCanvasResponse = cpr::Get(
522+
cpr::Url{BASE_URL + "/canvases/" + std::to_string(canvasId)},
523+
noPersistParam
524+
);
525+
ASSERT_EQ(getCanvasResponse.status_code, 200);
526+
auto canvasWithEffects = json::parse(getCanvasResponse.text);
527+
528+
// Verify effects through effectsManager
529+
ASSERT_TRUE(canvasWithEffects.contains("effectsManager"));
530+
const auto& effectsManager = canvasWithEffects["effectsManager"];
531+
ASSERT_TRUE(effectsManager.contains("effects"));
532+
const auto& effects = effectsManager["effects"];
533+
ASSERT_EQ(effects.size(), (size_t) 2); // We should at least have 2 effects
534+
535+
// For now, just verify the basic structure until we fix the deserialization
536+
for (const auto& effect : effects) {
537+
ASSERT_TRUE(effect.contains("type"));
538+
ASSERT_TRUE(effect.contains("name"));
539+
ASSERT_TRUE(effect.contains("color"));
540+
ASSERT_TRUE(effect["color"].contains("r"));
541+
ASSERT_TRUE(effect["color"].contains("g"));
542+
ASSERT_TRUE(effect["color"].contains("b"));
543+
}
544+
545+
// Clean up
546+
auto deleteFeatureResponse = cpr::Delete(
547+
cpr::Url{BASE_URL + "/canvases/" + std::to_string(canvasId) + "/features/" + std::to_string(featureId)},
548+
noPersistParam
549+
);
550+
ASSERT_EQ(deleteFeatureResponse.status_code, 200);
551+
552+
auto deleteCanvasResponse = cpr::Delete(
553+
cpr::Url{BASE_URL + "/canvases/" + std::to_string(canvasId)},
554+
noPersistParam
555+
);
556+
ASSERT_EQ(deleteCanvasResponse.status_code, 200);
557+
}

webserver.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,36 @@ class WebServer
296296
}
297297
});
298298

299+
// Add effect to canvas
300+
CROW_ROUTE(_crowApp, "/api/canvases/<int>/effects")
301+
.methods(crow::HTTPMethod::POST)([&](const crow::request& req, int canvasId) -> crow::response
302+
{
303+
try
304+
{
305+
auto reqJson = nlohmann::json::parse(req.body);
306+
auto effect = reqJson.get<shared_ptr<ILEDEffect>>();
307+
308+
unique_lock writeLock(_apiMutex);
309+
auto canvas = _controller.GetCanvasById(canvasId);
310+
311+
// Get current effects
312+
auto& effectsManager = canvas->Effects();
313+
314+
// Add the new effect
315+
effectsManager.AddEffect(effect);
316+
317+
PersistController(req);
318+
writeLock.unlock();
319+
320+
return crow::response(crow::OK);
321+
}
322+
catch (const exception& e)
323+
{
324+
logger->error("Error adding effect to canvas {}: {}", canvasId, e.what());
325+
return crow::response(crow::BAD_REQUEST, string("Error: ") + e.what());
326+
}
327+
});
328+
299329
// Start the server
300330
_crowApp.port(_controller.GetPort()).multithreaded().run();
301331
}

0 commit comments

Comments
 (0)