#define DROGON_TEST_MAIN #include #include #include #include "common/GeoJson.h" #include "common/Crypto.h" #include "common/Http.h" #include "common/Validation.h" #include "repositories/Sql.h" #include using namespace drogon; namespace { std::pair sendRequest(const HttpRequestPtr &request) { auto client = HttpClient::newHttpClient("http://127.0.0.1:15555", app().getLoop()); auto promise = std::make_shared>>(); auto future = promise->get_future(); client->sendRequest( request, [promise](ReqResult result, const HttpResponsePtr &response) { promise->set_value({result, response}); }); return future.get(); } } // namespace DROGON_TEST(HealthEndpoint) { auto request = HttpRequest::newHttpRequest(); request->setMethod(Get); request->setPath("/api/v1/health"); auto [result, response] = sendRequest(request); REQUIRE(result == ReqResult::Ok); REQUIRE(response != nullptr); CHECK(response->getStatusCode() == k200OK); REQUIRE(response->getJsonObject() != nullptr); CHECK((*response->getJsonObject())["status"].asString() == "ok"); CHECK((*response->getJsonObject())["service"].asString() == "visione-backend"); } DROGON_TEST(ValidationRejectsMalformedIdentity) { CHECK(visione::validation::isValidEmail("mario.rossi@example.com")); CHECK(!visione::validation::isValidEmail("not-an-email")); CHECK(visione::validation::isValidFiscalCode("RSSMRA80A01H501U")); CHECK(visione::validation::isValidFiscalCode("VSSGNR94M08A662P")); CHECK(!visione::validation::isValidFiscalCode("short")); CHECK(!visione::validation::isValidFiscalCode("VSSGNR94M08A662A")); } DROGON_TEST(SqlScalarSerializationKeepsTypes) { const auto json = []() { Json::Value value(Json::objectValue); value["id"] = Json::UInt64(7); value["banned"] = false; value["points"] = Json::Int64(42); value["phone"] = "380 6180216"; return value; }(); CHECK(json["id"].isUInt64()); CHECK(json["banned"].isBool()); CHECK(json["points"].isInt64()); CHECK(json["phone"].isString()); } DROGON_TEST(CryptoHmacIsDeterministic) { const auto digest = visione::crypto::hmacSha256Hex("secret", "{\"a\":1}"); CHECK(digest == "AA9E2E3575F5D7098B6CACCD790888C36D5FDB63342A73BADA2D6A51747A8494"); CHECK(visione::crypto::constantTimeEquals(digest, digest)); CHECK(!visione::crypto::constantTimeEquals(digest, "different")); } DROGON_TEST(ParseJsonBodyRejectsInvalidPayload) { const auto parsed = visione::http::parseJsonBody("{\"ok\":true}"); CHECK(parsed.isObject()); CHECK(parsed["ok"].asBool()); const auto invalid = visione::http::parseJsonBody("{oops"); CHECK(invalid.isNull()); } DROGON_TEST(GeoJsonMatchesPointInsidePolygon) { Json::Value polygon; polygon["type"] = "Polygon"; Json::Value ring(Json::arrayValue); Json::Value a(Json::arrayValue); a.append(12.0); a.append(41.0); Json::Value b(Json::arrayValue); b.append(13.0); b.append(41.0); Json::Value c(Json::arrayValue); c.append(13.0); c.append(42.0); Json::Value d(Json::arrayValue); d.append(12.0); d.append(42.0); ring.append(a); ring.append(b); ring.append(c); ring.append(d); ring.append(a); polygon["coordinates"].append(ring); CHECK(visione::geojson::pointInPolygon(41.5, 12.5, polygon)); CHECK(!visione::geojson::pointInPolygon(43.0, 12.5, polygon)); CHECK(visione::geojson::pointInGeometry(41.5, 12.5, polygon)); CHECK(!visione::geojson::pointInGeometry(43.0, 12.5, polygon)); } DROGON_TEST(GeoJsonAcceptsContainedPolygon) { Json::Value container; container["type"] = "Polygon"; Json::Value outer(Json::arrayValue); Json::Value a(Json::arrayValue); a.append(12.0); a.append(41.0); Json::Value b(Json::arrayValue); b.append(13.0); b.append(41.0); Json::Value c(Json::arrayValue); c.append(13.0); c.append(42.0); Json::Value d(Json::arrayValue); d.append(12.0); d.append(42.0); outer.append(a); outer.append(b); outer.append(c); outer.append(d); outer.append(a); container["coordinates"].append(outer); Json::Value candidate; candidate["type"] = "Polygon"; Json::Value inner(Json::arrayValue); Json::Value p1(Json::arrayValue); p1.append(12.2); p1.append(41.2); Json::Value p2(Json::arrayValue); p2.append(12.8); p2.append(41.2); Json::Value p3(Json::arrayValue); p3.append(12.8); p3.append(41.8); Json::Value p4(Json::arrayValue); p4.append(12.2); p4.append(41.8); inner.append(p1); inner.append(p2); inner.append(p3); inner.append(p4); inner.append(p1); candidate["coordinates"].append(inner); CHECK(visione::geojson::polygonInsideGeometry(candidate, container)); candidate["coordinates"][0][3][0] = 14.0; CHECK(!visione::geojson::polygonInsideGeometry(candidate, container)); } int main(int argc, char **argv) { std::promise startedPromise; auto startedFuture = startedPromise.get_future(); app().addListener("127.0.0.1", 15555); std::thread serverThread([&startedPromise]() { app().getLoop()->queueInLoop([&startedPromise]() { startedPromise.set_value(); }); app().run(); }); startedFuture.get(); const int status = test::run(argc, argv); app().getLoop()->queueInLoop([]() { app().quit(); }); serverThread.join(); return status; }