145 lines
4.8 KiB
C++
145 lines
4.8 KiB
C++
#include <catch2/catch_test_macros.hpp>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <rapidjson/document.h>
|
|
#include <rapidjson/stringbuffer.h>
|
|
#include <rapidjson/writer.h>
|
|
|
|
#include "../../src/cmd_gridsearch.h"
|
|
#include "logger/logger.h"
|
|
|
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
|
|
static std::string read_file_contents(const std::string &path) {
|
|
std::ifstream f(path);
|
|
if (!f.is_open())
|
|
return "";
|
|
std::stringstream ss;
|
|
ss << f.rdbuf();
|
|
return ss.str();
|
|
}
|
|
|
|
/// Read a JSON config file and inject test-safe overrides:
|
|
/// - configPath = "config/postgres.toml"
|
|
/// - enrich = false (no live HTTP / thread-pool in tests)
|
|
/// - persistencePostgres = false
|
|
static std::string load_test_payload(const std::string &config_path) {
|
|
std::string raw = read_file_contents(config_path);
|
|
if (raw.empty())
|
|
return "";
|
|
|
|
rapidjson::Document doc;
|
|
doc.Parse(raw.c_str());
|
|
if (doc.HasParseError())
|
|
return "";
|
|
|
|
auto &alloc = doc.GetAllocator();
|
|
|
|
// Remove-then-add ensures no double-add assertion from rapidjson
|
|
auto inject_bool = [&](const char *key, bool val) {
|
|
if (doc.HasMember(key))
|
|
doc.RemoveMember(key);
|
|
doc.AddMember(rapidjson::Value(key, alloc), rapidjson::Value(val), alloc);
|
|
};
|
|
auto inject_str = [&](const char *key, const char *val) {
|
|
if (doc.HasMember(key))
|
|
doc.RemoveMember(key);
|
|
doc.AddMember(rapidjson::Value(key, alloc), rapidjson::Value(val, alloc),
|
|
alloc);
|
|
};
|
|
|
|
inject_str("configPath", "config/postgres.toml");
|
|
inject_str("cacheDir", "../../packages/gadm/cache/gadm"); // server/cache/gadm
|
|
inject_bool("enrich", false); // no live enrichment in tests
|
|
inject_bool("persistencePostgres", false);
|
|
|
|
rapidjson::StringBuffer buf;
|
|
rapidjson::Writer<rapidjson::StringBuffer> writer(buf);
|
|
doc.Accept(writer);
|
|
return buf.GetString();
|
|
}
|
|
|
|
// ── Tests
|
|
// ─────────────────────────────────────────────────────────────────────
|
|
|
|
TEST_CASE("E2E: Gridsearch Country Boundary Filter (Lamu/KEN)",
|
|
"[e2e][gridsearch][boundary]") {
|
|
REQUIRE_NOTHROW(logger::init("test-gridsearch"));
|
|
|
|
// Lamu, Kenya — SerpAPI often returns US results for obscure African regions.
|
|
// boundary_KEN_0.json should filter them out.
|
|
std::string payload = load_test_payload("config/gridsearch-lamu.json");
|
|
REQUIRE(!payload.empty());
|
|
|
|
std::vector<std::string> location_events;
|
|
int error_count = 0;
|
|
|
|
polymech::GridsearchCallbacks cb;
|
|
cb.onEvent = [&](const std::string &type, const std::string &json) {
|
|
if (type == "location") {
|
|
location_events.push_back(json);
|
|
} else if (type == "error") {
|
|
error_count++;
|
|
std::cout << "[ERROR EVENT]: " << json << "\n";
|
|
}
|
|
};
|
|
|
|
int result =
|
|
polymech::run_cmd_gridsearch_ipc(payload, "test-lamu-job", cb, false, "");
|
|
|
|
REQUIRE(result == 0);
|
|
REQUIRE(error_count == 0);
|
|
|
|
// All returned locations must be within Kenya (no USA coords).
|
|
// Verify: no location has lng < -30 (Americas) or lng > 60 (not Africa/Asia)
|
|
// and lat outside [-5, 5] for Lamu county bounds.
|
|
int outside_kenya = 0;
|
|
for (const auto &loc_json : location_events) {
|
|
rapidjson::Document loc;
|
|
loc.Parse(loc_json.c_str());
|
|
if (loc.HasParseError())
|
|
continue;
|
|
if (loc.HasMember("gps") && loc["gps"].IsObject()) {
|
|
double lng =
|
|
loc["gps"].HasMember("lng") ? loc["gps"]["lng"].GetDouble() : 0;
|
|
// Kenya longitude range: ~34..42; USA is roughly -130..-60
|
|
if (lng < 20.0 || lng > 55.0)
|
|
outside_kenya++;
|
|
}
|
|
}
|
|
|
|
CHECK(outside_kenya == 0);
|
|
std::cout << "Lamu boundary test: " << location_events.size()
|
|
<< " locations kept, " << outside_kenya << " outside Kenya.\n";
|
|
}
|
|
|
|
TEST_CASE("E2E: Gridsearch Type Filter (Sample/ABW)",
|
|
"[e2e][gridsearch][filter]") {
|
|
std::string payload = load_test_payload("config/gridsearch-sample.json");
|
|
REQUIRE(!payload.empty());
|
|
|
|
std::vector<std::string> location_events;
|
|
int error_count = 0;
|
|
|
|
polymech::GridsearchCallbacks cb;
|
|
cb.onEvent = [&](const std::string &type, const std::string &json) {
|
|
if (type == "location")
|
|
location_events.push_back(json);
|
|
else if (type == "error")
|
|
error_count++;
|
|
};
|
|
|
|
int result = polymech::run_cmd_gridsearch_ipc(payload, "test-sample-job", cb,
|
|
false, "");
|
|
|
|
REQUIRE(result == 0);
|
|
REQUIRE(error_count == 0);
|
|
|
|
std::cout << "Sample (ABW) type filter test: " << location_events.size()
|
|
<< " locations.\n";
|
|
}
|