catcrafts.net/tests/ShouldParseSendcloudRates/main.cpp
Jorijn van der Graaf 749f525f83
All checks were successful
Deploy / build-deploy (push) Successful in 4m19s
tests and eurc
2026-08-15 00:54:05 +02:00

102 lines
4.8 KiB
C++

/*
catcrafts.net
Copyright (C) 2026 Catcrafts
The source code of this website is made available for viewing purposes only.
No permission is granted to copy, modify, distribute, or create derivative works.
*/
// The Sendcloud response parser. Weights are the kilogram strings the API
// sends; every Find() below asks for a parcel weight, because a price without
// a weight is not a thing this table has any more.
import std;
import Catcrafts.Shared;
import Catcrafts.Server;
using namespace Catcrafts;
namespace {
int failures = 0;
void Check(bool ok, std::string_view what, std::string_view got = {}) {
if (ok) return;
++failures;
std::println(std::cerr, "FAIL: {}{}{}", what,
got.empty() ? "" : " got: ", got);
}
} // namespace
int main() {
const auto table = Server::ParseSendcloudMethods(R"({"shipping_methods":[
{"name":"Other Method","min_weight":"0.001","max_weight":"10.000",
"countries":[{"iso_2":"NL","price":1.00}]},
{"name":"DHL For You Home","min_weight":"0.001","max_weight":"2.000",
"countries":[
{"iso_2":"NL","price":6.25},
{"iso_2":"DE","price":8.20},
{"iso_2":"CA","price":42.50},
{"iso_2":"XX","price":0},
{"iso_2":"TOOLONG","price":5.00}]},
{"name":"DHL For You Home","min_weight":"2.000","max_weight":"10.000",
"countries":[{"iso_2":"NL","price":9.95},{"iso_2":"DE","price":13.40}]},
{"name":"DHL For You Home","countries":[{"iso_2":"BE","price":1.00}]}]})",
"DHL For You");
Check(table.method == "DHL For You Home", "sendcloud: method matched by substring");
Check(table.Find("NL", 700) == 625, "sendcloud: NL price to cents");
Check(table.Find("DE", 700) == 820, "sendcloud: 8.20 rounds exactly");
Check(table.Find("CA", 700) == 4250, "sendcloud: CA price");
Check(table.Find("XX", 700) == 0, "sendcloud: zero price dropped");
Check(table.Find("TOOLONG", 700) == 0, "sendcloud: malformed iso dropped");
// The bug the old parser had: it stopped at the FIRST matching method,
// so every parcel was priced at whichever band came first and the
// heavier bands were invisible.
Check(table.Find("NL", 2100) == 995 && table.Find("DE", 2100) == 1340,
"sendcloud: every weight band of a matched method is kept");
Check(table.Find("NL", 11000) == 0,
"sendcloud: past the heaviest band there is no price");
Check(table.Find("BE", 700) == 0,
"sendcloud: a method with no weight range is unusable, not unlimited");
Check(Server::ParseSendcloudMethods("garbage", "x").perCountry.empty(),
"sendcloud: malformed payload yields nothing");
// Comma-separated merge: courier for Europe, post for the world; the
// earlier FILTER keeps any country both cover — including that
// country's heavier bands, which must not leak in from the later one.
const auto merged = Server::ParseSendcloudMethods(R"({"shipping_methods":[
{"name":"DPD Home","min_weight":"0.001","max_weight":"10.000","countries":[
{"iso_2":"NL","price":7.13},{"iso_2":"DE","price":10.49}]},
{"name":"PostNL Parcels non-EU","min_weight":"0.001","max_weight":"2.000",
"countries":[
{"iso_2":"CA","price":23.95},{"iso_2":"US","price":17.94},
{"iso_2":"DE","price":99.99}]},
{"name":"PostNL Parcels non-EU","min_weight":"2.000","max_weight":"20.000",
"countries":[{"iso_2":"CA","price":48.10},{"iso_2":"DE","price":99.99}]}]})",
"DPD Home, PostNL Parcels non-EU");
Check(merged.Find("NL", 700) == 713 && merged.Find("CA", 700) == 2395,
"sendcloud: merged table covers both filters");
Check(merged.Find("CA", 5000) == 4810, "sendcloud: heavier band from the later filter");
Check(merged.Find("DE", 700) == 1049,
"sendcloud: earlier filter wins a shared country");
Check(merged.Find("DE", 12000) == 0,
"sendcloud: and owns it outright — no band from the loser");
Check(merged.method == "DPD Home + PostNL Parcels non-EU",
"sendcloud: merged method names recorded, deduplicated per band");
// Two services under one filter publishing the same ceiling: the
// cheaper is the only sensible quote, since both carry the parcel.
const auto dup = Server::ParseSendcloudMethods(R"({"shipping_methods":[
{"name":"DPD Home","min_weight":"0.001","max_weight":"10.000",
"countries":[{"iso_2":"NL","price":9.00}]},
{"name":"DPD Home Signed","min_weight":"0.001","max_weight":"10.000",
"countries":[{"iso_2":"NL","price":7.50}]}]})", "DPD Home");
Check(dup.Find("NL", 700) == 750, "sendcloud: duplicate band keeps the cheaper");
if (failures != 0) {
std::println(std::cerr, "{} check(s) failed", failures);
return 1;
}
return 0;
}