#define CATCH_CONFIG_MAIN #include "catch/catch.hpp" #include "text.hpp" #include "sort.hpp" #include "tile-cache.hpp" #include "projection.hpp" #include #include TEST_CASE("UTF-8 enforcement", "[utf8]") { REQUIRE(check_utf8("") == std::string("")); REQUIRE(check_utf8("hello world") == std::string("")); REQUIRE(check_utf8("Καλημέρα κόσμε") == std::string("")); REQUIRE(check_utf8("こんにちは 世界") == std::string("")); REQUIRE(check_utf8("👋🌏") == std::string("")); REQUIRE(check_utf8("Hola m\xF3n") == std::string("\"Hola m\xF3n\" is not valid UTF-8 (0xF3 0x6E)")); } TEST_CASE("UTF-8 truncation", "[trunc]") { REQUIRE(truncate16("0123456789abcdefghi", 16) == std::string("0123456789abcdef")); REQUIRE(truncate16("0123456789éîôüéîôüç", 16) == std::string("0123456789éîôüéî")); REQUIRE(truncate16("0123456789😀😬😁😂😃😄😅😆", 16) == std::string("0123456789😀😬😁")); REQUIRE(truncate16("0123456789😀😬😁😂😃😄😅😆", 17) == std::string("0123456789😀😬😁")); REQUIRE(truncate16("0123456789あいうえおかきくけこさ", 16) == std::string("0123456789あいうえおか")); } int intcmp(const void *v1, const void *v2) { return *((int *) v1) - *((int *) v2); } TEST_CASE("External quicksort", "fqsort") { std::vector inputs; size_t written = 0; for (size_t i = 0; i < 5; i++) { std::string tmpname = "/tmp/in.XXXXXXX"; int fd = mkstemp((char *) tmpname.c_str()); unlink(tmpname.c_str()); FILE *f = fdopen(fd, "w+b"); inputs.emplace_back(f); size_t iterations = 2000 + rand() % 200; for (size_t j = 0; j < iterations; j++) { int n = rand(); fwrite((void *) &n, sizeof(int), 1, f); written++; } rewind(f); } std::string tmpname = "/tmp/out.XXXXXX"; int fd = mkstemp((char *) tmpname.c_str()); unlink(tmpname.c_str()); FILE *f = fdopen(fd, "w+b"); fqsort(inputs, sizeof(int), intcmp, f, 256); rewind(f); int prev = INT_MIN; int here; size_t nread = 0; while (fread((void *) &here, sizeof(int), 1, f)) { REQUIRE(here >= prev); prev = here; nread++; } fclose(f); REQUIRE(nread == written); } mvt_tile mock_get_tile(zxy tile) { mvt_layer l; l.name = std::to_string(tile.z) + "/" + std::to_string(tile.x) + "/" + std::to_string(tile.y); mvt_tile t; t.layers.push_back(l); return t; } TEST_CASE("Tile-join cache", "tile cache") { tile_cache tc; tc.capacity = 5; REQUIRE(tc.get(zxy(11, 327, 791), mock_get_tile).layers[0].name == "11/327/791"); REQUIRE(tc.get(zxy(11, 5, 7), mock_get_tile).layers[0].name == "11/5/7"); REQUIRE(tc.get(zxy(11, 5, 8), mock_get_tile).layers[0].name == "11/5/8"); REQUIRE(tc.get(zxy(11, 5, 9), mock_get_tile).layers[0].name == "11/5/9"); REQUIRE(tc.get(zxy(11, 5, 10), mock_get_tile).layers[0].name == "11/5/10"); REQUIRE(tc.get(zxy(11, 327, 791), mock_get_tile).layers[0].name == "11/327/791"); REQUIRE(tc.overzoom_cache.size() == 5); REQUIRE(tc.overzoom_cache.find(zxy(11, 327, 791)) != tc.overzoom_cache.end()); REQUIRE(tc.overzoom_cache.find(zxy(11, 5, 7)) != tc.overzoom_cache.end()); // verify that additional gets evict the least-recently-used elements REQUIRE(tc.get(zxy(11, 5, 11), mock_get_tile).layers[0].name == "11/5/11"); REQUIRE(tc.overzoom_cache.size() == 5); REQUIRE(tc.overzoom_cache.find(zxy(11, 5, 7)) == tc.overzoom_cache.end()); REQUIRE(tc.get(zxy(11, 5, 12), mock_get_tile).layers[0].name == "11/5/12"); REQUIRE(tc.overzoom_cache.size() == 5); REQUIRE(tc.overzoom_cache.find(zxy(11, 5, 8)) == tc.overzoom_cache.end()); } TEST_CASE("Bit reversal", "bit reversal") { REQUIRE(bit_reverse(1) == 0x8000000000000000); REQUIRE(bit_reverse(0x1234567812489BCF) == 0xF3D912481E6A2C48); REQUIRE(bit_reverse(0xF3D912481E6A2C48) == 0x1234567812489BCF); } TEST_CASE("Projection", "projection") { // troublesome point from tests/accumulate/in.json long long wx36, wy36; lonlat2tile(-123.948513, -81.873970, 36, &wx36, &wy36); REQUIRE(wx36 == 0x27dbdc9fb); REQUIRE(wy36 == 0xebc06c629); long long wx32, wy32; lonlat2tile(-123.948513, -81.873970, 32, &wx32, &wy32); REQUIRE(wx32 == 0x27dbdca0); REQUIRE(wy32 == 0xebc06c63); REQUIRE(std::llround(wx36 / 16.0) == wx32); REQUIRE(std::llround(wy36 / 16.0) == wy32); }