Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View file

@ -0,0 +1,11 @@
project(ge0_tests)
set(SRC
geo_url_tests.cpp
parser_tests.cpp
url_generator_tests.cpp
)
omim_add_test(${PROJECT_NAME} ${SRC})
target_link_libraries(${PROJECT_NAME} ge0)

View file

@ -0,0 +1,304 @@
#include "testing/testing.hpp"
#include "ge0/geo_url_parser.hpp"
namespace geo_url_tests
{
double const kEps = 1e-10;
using namespace geo;
UNIT_TEST(GeoUrl_Geo)
{
UnifiedParser parser;
GeoURLInfo info;
// Bare RFC5870 URI with lat,lon.
TEST(parser.Parse("geo:53.666,-27.666", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 53.666, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, -27.666, kEps, ());
// Bare RFC5870 URI with lat,lon,altitude.
TEST(parser.Parse("geo:53.666,-27.666,1000", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 53.666, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, -27.666, kEps, ());
// Altitude is ignored.
// OSMAnd on Android 2023-11-12.
TEST(parser.Parse("geo:35.34156,33.32210?z=16", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 35.34156, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 33.32210, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 16.0, kEps, ());
// Bare RFC5870 URI with a space between lat, lon.
TEST(parser.Parse("geo:53.666, -27.666", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 53.666, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, -27.666, kEps, ());
// Google's q= extension: 0,0 are treated as special values.
TEST(parser.Parse("geo:0,0?q=Kyrenia%20Castle&z=15", info), ());
TEST(!info.IsLatLonValid(), ());
TEST_EQUAL(info.m_query, "Kyrenia Castle", ());
TEST_EQUAL(info.m_zoom, 15, ());
// Coordinates in q= parameter.
TEST(parser.Parse("geo:0,0?z=14&q=-54.683486138,25.289361259", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -54.683486138, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 25.289361259, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 14.0, kEps, ());
// Instagram on Android 2023-11-12.
TEST(parser.Parse("geo:?q=35.20488357543945, 33.345027923583984", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 35.20488357543945, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 33.345027923583984, kEps, ());
// Invalid lat,lon in q= parameter is saved as a query.
TEST(parser.Parse("geo:0,0?z=14&q=-100500.232,1213.232", info), ());
TEST(!info.IsLatLonValid(), ());
TEST_EQUAL(info.m_query, "-100500.232,1213.232", ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 14.0, kEps, ());
// RFC5870 additional parameters are ignored.
TEST(parser.Parse("geo:48.198634,16.371648;crs=wgs84;u=40", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 48.198634, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 16.371648, kEps, ());
// ;crs=wgs84;u=40 tail is ignored
// 0,0 are not treated as special values if q is empty.
TEST(parser.Parse("geo:0,0", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 0.0, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 0.0, kEps, ());
TEST_EQUAL(info.m_query, "", ());
// 0,0 are not treated as special values if q is empty.
TEST(parser.Parse("geo:0,0?q=", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 0.0, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 0.0, kEps, ());
TEST_EQUAL(info.m_query, "", ());
// Lat is 0.
TEST(parser.Parse("geo:0,16.371648", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 0.0, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 16.371648, kEps, ());
// Lon is 0.
TEST(parser.Parse("geo:53.666,0", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 53.666, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 0.0, kEps, ());
// URL Encoded comma (%2C) as delimiter
TEST(parser.Parse("geo:-18.9151863%2C-48.28712359999999?q=-18.9151863%2C-48.28712359999999", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -18.9151863, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, -48.28712359999999, kEps, ());
// URL Encoded comma (%2C) and space (%20)
TEST(parser.Parse("geo:-18.9151863%2C%20-48.28712359999999?q=-18.9151863%2C-48.28712359999999", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -18.9151863, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, -48.28712359999999, kEps, ());
// URL Encoded comma (%2C) and space as +
TEST(parser.Parse("geo:-18.9151863%2C+-48.28712359999999?q=-18.9151863%2C-48.28712359999999", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -18.9151863, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, -48.28712359999999, kEps, ());
// URL encoded with altitude
TEST(parser.Parse("geo:53.666%2C-27.666%2C+1000", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 53.666, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, -27.666, kEps, ());
TEST(parser.Parse("geo:-32.899583,139.043969&z=12", info), ("& instead of ? from a user report"));
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -32.899583, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 139.043969, kEps, ());
TEST_EQUAL(info.m_zoom, 12, ());
// Invalid coordinates.
TEST(!parser.Parse("geo:0,0garbage", info), ());
TEST(!parser.Parse("geo:garbage0,0", info), ());
TEST(!parser.Parse("geo:53.666", info), ());
// Garbage.
TEST(!parser.Parse("geo:", info), ());
TEST(!parser.Parse("geo:", info), ());
TEST(!parser.Parse("geo:random,garbage", info), ());
TEST(!parser.Parse("geo://random,garbage", info), ());
TEST(!parser.Parse("geo://point/?lon=27.666&lat=53.666&zoom=10", info), ());
}
UNIT_TEST(GeoURL_GeoLabel)
{
UnifiedParser parser;
GeoURLInfo info;
TEST(parser.Parse("geo:0,0?z=14&q=-54.683486138,25.289361259 (Forto%20dvaras)", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -54.683486138, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 25.289361259, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 14.0, kEps, ());
TEST_EQUAL(info.m_label, "Forto dvaras", ());
TEST(parser.Parse("geo:0,0?z=14&q=-54.683486138,25.289361259(Forto%20dvaras)", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -54.683486138, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 25.289361259, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 14.0, kEps, ());
TEST_EQUAL(info.m_label, "Forto dvaras", ());
TEST(parser.Parse("geo:0,0?q=-54.683486138,25.289361259&z=14 (Forto%20dvaras)", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -54.683486138, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 25.289361259, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 14.0, kEps, ());
TEST_EQUAL(info.m_label, "Forto dvaras", ());
TEST(parser.Parse("geo:0,0(Forto%20dvaras)", info), ());
TEST(info.IsLatLonValid(), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 0.0, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 0.0, kEps, ());
TEST_EQUAL(info.m_label, "Forto dvaras", ());
TEST(parser.Parse("geo:0,0?q=Forto%20dvaras)", info), ());
TEST(!info.IsLatLonValid(), ());
TEST_EQUAL(info.m_query, "Forto dvaras)", ());
TEST(!parser.Parse("geo:(Forto%20dvaras)", info), ());
}
UNIT_TEST(GeoURL_GoogleMaps)
{
UnifiedParser parser;
GeoURLInfo info;
TEST(parser.Parse("https://maps.google.com/maps?z=16&q=Mezza9%401.3067198,103.83282", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 1.3067198, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 103.83282, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 16.0, kEps, ());
TEST(parser.Parse("https://maps.google.com/maps?z=16&q=House+of+Seafood+%40+180%40-1.356706,103.87591", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -1.356706, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 103.87591, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 16.0, kEps, ());
TEST(parser.Parse("https://www.google.com/maps/place/Falafel+M.+Sahyoun/@33.8904447,35.5044618,16z", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 33.8904447, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 35.5044618, kEps, ());
// Sic: zoom is not parsed
// TEST_ALMOST_EQUAL_ABS(info.m_zoom, 16.0, kEps, ());
TEST(parser.Parse("https://www.google.com/maps?q=55.751809,-37.6130029", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 55.751809, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, -37.6130029, kEps, ());
}
UNIT_TEST(GeoURL_Yandex)
{
UnifiedParser parser;
GeoURLInfo info;
TEST(parser.Parse("https://yandex.ru/maps/213/moscow/?ll=37.000000%2C55.000000&z=10", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 55.0, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 37.0, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 10.0, kEps, ());
}
UNIT_TEST(GeoURL_2GIS)
{
UnifiedParser parser;
GeoURLInfo info;
TEST(parser.Parse("https://2gis.ru/moscow/firm/4504127908589159/center/37.6186,55.7601/zoom/15.9764", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 55.7601, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 37.6186, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 15.9764, kEps, ());
TEST(parser.Parse("https://2gis.ru/moscow/firm/4504127908589159/center/-37,55/zoom/15", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 55.0, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, -37.0, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 15.0, kEps, ());
TEST(parser.Parse("https://2gis.ru/moscow/firm/4504127908589159?m=37.618632%2C55.760069%2F15.232", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 55.760069, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 37.618632, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 15.232, kEps, ());
TEST(parser.Parse("https://2gis.ru/moscow/firm/4504127908589159?m=37.618632%2C-55.760069%2F15", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -55.760069, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 37.618632, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 15.0, kEps, ());
}
UNIT_TEST(GeoURL_LatLon)
{
UnifiedParser parser;
GeoURLInfo info;
TEST(!parser.Parse("mapswithme:123.33,32.22/showmethemagic", info), ());
TEST(!parser.Parse("mapswithme:32.22, 123.33/showmethemagic", info), ());
TEST(!parser.Parse("model: iphone 7,1", info), ());
}
UNIT_TEST(GeoURL_OpenStreetMap)
{
UnifiedParser parser;
GeoURLInfo info;
TEST(parser.Parse("https://www.openstreetmap.org/#map=16/33.89041/35.50664", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 33.89041, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 35.50664, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 16.0, kEps, ());
TEST(parser.Parse("https://www.openstreetmap.org/search?query=Falafel%20Sahyoun#map=16/33.89041/35.50664", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 33.89041, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 35.50664, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 16.0, kEps, ());
TEST(parser.Parse("https://www.openstreetmap.org/#map=21/53.90323/-27.55806", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 53.90323, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, -27.55806, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 20.0, kEps, ());
TEST(parser.Parse("https://www.openstreetmap.org/way/45394171#map=10/34.67379/33.04422", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 34.67379, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 33.04422, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 10.0, kEps, ());
// Links in such format are generated by
// https://geohack.toolforge.org/geohack.php?pagename=White_House&params=38_53_52_N_77_02_11_W_type:landmark_region:US-DC
TEST(parser.Parse("https://www.openstreetmap.org/index.html?mlat=48.277222&mlon=24.152222&zoom=15", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 48.277222, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 24.152222, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 15.0, kEps, ());
}
UNIT_TEST(GeoURL_BadZoom)
{
UnifiedParser parser;
GeoURLInfo info;
TEST(parser.Parse("geo:52.23405,21.01547?z=22", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 52.23405, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 21.01547, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 20.0, kEps, ());
TEST(parser.Parse("geo:-52.23405,21.01547?z=nineteen", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, -52.23405, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 21.01547, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 0.0, kEps, ());
TEST(parser.Parse("geo:52.23405,21.01547?z=-1", info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 52.23405, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 21.01547, kEps, ());
TEST_GREATER_OR_EQUAL(info.m_zoom, 0.0, ());
}
} // namespace geo_url_tests

View file

@ -0,0 +1,314 @@
#include "testing/testing.hpp"
#include "ge0/parser.hpp"
#include "ge0/url_generator.hpp"
#include "base/math.hpp"
#include <algorithm>
#include <string>
using namespace std;
namespace
{
double const kZoomEps = 1e-10;
} // namespace
namespace ge0
{
class Ge0ParserForTest : public Ge0Parser
{
public:
using Ge0Parser::DecodeBase64Char;
using Ge0Parser::DecodeLatLon;
using Ge0Parser::DecodeZoom;
};
double GetLatEpsilon(size_t coordBytes)
{
// Should be / 2.0 but probably because of accumulates loss of precision, 1.77 works but 2.0
// doesn't.
double infelicity = 1 << ((kMaxPointBytes - coordBytes) * 3);
return infelicity / ((1 << kMaxCoordBits) - 1) * 180 / 1.77;
}
double GetLonEpsilon(size_t coordBytes)
{
// Should be / 2.0 but probably because of accumulates loss of precision, 1.77 works but 2.0
// doesn't.
double infelicity = 1 << ((kMaxPointBytes - coordBytes) * 3);
return (infelicity / ((1 << kMaxCoordBits) - 1)) * 360 / 1.77;
}
void TestSuccess(char const * s, double lat, double lon, double zoom, char const * name)
{
Ge0Parser parser;
Ge0Parser::Result parseResult;
bool const success = parser.Parse(s, parseResult);
TEST(success, (s, parseResult));
TEST_EQUAL(parseResult.m_name, string(name), (s));
double const latEps = GetLatEpsilon(9);
double const lonEps = GetLonEpsilon(9);
TEST_ALMOST_EQUAL_ABS(parseResult.m_lat, lat, latEps, (s, parseResult));
TEST_ALMOST_EQUAL_ABS(parseResult.m_lon, lon, lonEps, (s, parseResult));
TEST_ALMOST_EQUAL_ABS(parseResult.m_zoomLevel, zoom, kZoomEps, (s, parseResult));
}
void TestFailure(char const * s)
{
Ge0Parser parser;
Ge0Parser::Result parseResult;
bool const success = parser.Parse(s, parseResult);
TEST(!success, (s, parseResult));
}
bool ConvergenceTest(double lat, double lon, double latEps, double lonEps)
{
double tmpLat = lat;
double tmpLon = lon;
Ge0ParserForTest parser;
for (size_t i = 0; i < 100000; ++i)
{
char urlPrefix[] = "Coord6789";
ge0::LatLonToString(tmpLat, tmpLon, urlPrefix + 0, 9);
parser.DecodeLatLon(urlPrefix, tmpLat, tmpLon);
}
return AlmostEqualAbs(lat, tmpLat, latEps) && AlmostEqualAbs(lon, tmpLon, lonEps);
}
UNIT_TEST(Base64DecodingWorksForAValidChar)
{
Ge0ParserForTest parser;
for (int i = 0; i < 64; ++i)
{
char c = ge0::Base64Char(i);
int i1 = parser.DecodeBase64Char(c);
TEST_EQUAL(i, i1, (c));
}
}
UNIT_TEST(Base64DecodingReturns255ForInvalidChar)
{
Ge0ParserForTest parser;
TEST_EQUAL(parser.DecodeBase64Char(' '), 255, ());
}
UNIT_TEST(Base64DecodingDoesNotCrashForAllChars)
{
Ge0ParserForTest parser;
for (size_t i = 0; i < 256; ++i)
parser.DecodeBase64Char(static_cast<char>(i));
}
UNIT_TEST(Base64DecodingCharFrequency)
{
vector<int> charCounts(256, 0);
Ge0ParserForTest parser;
for (size_t i = 0; i < 256; ++i)
++charCounts[parser.DecodeBase64Char(static_cast<char>(i))];
sort(charCounts.begin(), charCounts.end());
TEST_EQUAL(charCounts[255], 256 - 64, ());
TEST_EQUAL(charCounts[254], 1, ());
TEST_EQUAL(charCounts[254 - 63], 1, ());
TEST_EQUAL(charCounts[254 - 64], 0, ());
TEST_EQUAL(charCounts[0], 0, ());
}
UNIT_TEST(UrlSchemaValidationFailed)
{
TestFailure("trali vali");
TestFailure("trali vali tili tili eto my prohodili");
}
UNIT_TEST(DecodeZoomLevel)
{
TEST_EQUAL(Ge0ParserForTest::DecodeZoom(0), 4, ());
TEST_EQUAL(Ge0ParserForTest::DecodeZoom(4), 5, ());
TEST_EQUAL(Ge0ParserForTest::DecodeZoom(6), 5.5, ());
TEST_EQUAL(Ge0ParserForTest::DecodeZoom(53), 17.25, ());
TEST_EQUAL(Ge0ParserForTest::DecodeZoom(60), 19, ());
TEST_EQUAL(Ge0ParserForTest::DecodeZoom(63), 19.75, ());
TestFailure("ge0://!wAAAAAAAA/Name");
TestFailure("ge0:///wAAAAAAAA/Name");
}
UNIT_TEST(LatLonConvergence)
{
double const latEps = GetLatEpsilon(9);
double const lonEps = GetLonEpsilon(9);
TEST(ConvergenceTest(0, 0, latEps, lonEps), ());
TEST(ConvergenceTest(1.111111, 2.11111, latEps, lonEps), ());
TEST(ConvergenceTest(-1.111111, -2.11111, latEps, lonEps), ());
TEST(ConvergenceTest(-90, -179.999999, latEps, lonEps), ());
TEST(ConvergenceTest(-88.12313, 80.4532999999, latEps, lonEps), ());
}
UNIT_TEST(ZoomDecoding)
{
TestSuccess("ge0://8wAAAAAAAA/Name", 0, 0, 19, "Name");
TestSuccess("ge0://AwAAAAAAAA/Name", 0, 0, 4, "Name");
TestSuccess("ge0://BwAAAAAAAA/Name", 0, 0, 4.25, "Name");
}
UNIT_TEST(LatLonDecoding)
{
TestSuccess("ge0://Byqqqqqqqq/Name", 45, 0, 4.25, "Name");
TestSuccess("ge0://B6qqqqqqqq/Name", 90, 0, 4.25, "Name");
TestSuccess("ge0://BVVVVVVVVV/Name", -90, 179.999999, 4.25, "Name");
TestSuccess("ge0://BP________/Name", -0.000001, -0.000001, 4.25, "Name");
TestSuccess("ge0://Bzqqqqqqqq/Name", 45, 45, 4.25, "Name");
TestSuccess("ge0://BaF6F6F6F6/Name", -20, 20, 4.25, "Name");
TestSuccess("ge0://B4srhdHVVt/Name", 64.5234, 12.1234, 4.25, "Name");
TestSuccess("ge0://B_________/Name", 90, 179.999999, 4.25, "Name");
TestSuccess("ge0://Bqqqqqqqqq/Name", 90, -180, 4.25, "Name");
TestSuccess("ge0://BAAAAAAAAA/Name", -90, -180, 4.25, "Name");
TestFailure("ge0://Byqqqqqqq/Name");
TestFailure("ge0://Byqqqqqqq/");
TestFailure("ge0://Byqqqqqqq");
TestFailure("ge0://B");
TestFailure("ge0://");
}
UNIT_TEST(NameDecoding)
{
TestSuccess("ge0://AwAAAAAAAA/Super_Poi", 0, 0, 4, "Super Poi");
TestSuccess("ge0://AwAAAAAAAA/Super%5FPoi", 0, 0, 4, "Super Poi");
TestSuccess("ge0://AwAAAAAAAA/Super%5fPoi", 0, 0, 4, "Super Poi");
TestSuccess("ge0://AwAAAAAAAA/Super Poi", 0, 0, 4, "Super_Poi");
TestSuccess("ge0://AwAAAAAAAA/Super%20Poi", 0, 0, 4, "Super_Poi");
TestSuccess("ge0://AwAAAAAAAA/Name%", 0, 0, 4, "Name");
TestSuccess("ge0://AwAAAAAAAA/Name%2", 0, 0, 4, "Name");
TestSuccess("ge0://AwAAAAAAAA/Hello%09World%0A", 0, 0, 4, "Hello\tWorld\n");
TestSuccess("ge0://AwAAAAAAAA/Hello%%%%%%%%%", 0, 0, 4, "Hello");
TestSuccess("ge0://AwAAAAAAAA/Hello%%%%%%%%%World", 0, 0, 4, "Hello");
TestSuccess(
"ge0://AwAAAAAAAA/"
"%d0%9c%d0%b8%d0%bd%d1%81%d0%ba_%d1%83%d0%bb._%d0%9b%d0%b5%d0%bd%d0%b8%d0%bd%d0%b0_9",
0, 0, 4, "Минск ул. Ленина 9");
TestSuccess("ge0://AwAAAAAAAA/z%c3%bcrich_bahnhofstrasse", 0, 0, 4, "zürich bahnhofstrasse");
TestSuccess("ge0://AwAAAAAAAA/%e5%8c%97%e4%ba%ac_or_B%c4%9bij%c4%abng%3F", 0, 0, 4, "北京 or Běijīng?");
TestSuccess(
"ge0://AwAAAAAAAA/"
"\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xba\xd0\xb0_\xd0\xb2_\xd1\x8e\xd1\x82\xd1\x84-8",
0, 0, 4, "строка в ютф-8");
TestSuccess("ge0://AwAAAAAAAA/", 0, 0, 4, "");
TestSuccess("ge0://AwAAAAAAAA/s", 0, 0, 4, "s");
TestFailure("ge0://AwAAAAAAAAs");
TestFailure("ge0://AwAAAAAAAAss");
{
auto const name =
"Как вы считаете, надо ли писать const для параметров, которые передаются в функцию по "
"значению?";
double lat = 0;
double lon = 0;
double zoom = 4;
string const url =
"ge0://AwAAAAAAAA/"
"%d0%9a%d0%b0%d0%ba_%d0%b2%d1%8b_%d1%81%d1%87%d0%b8%d1%82%d0%b0%d0%b5%d1%82%d0%b5%2C_%d0%"
"bd%d0%b0%d0%b4%d0%be_%d0%bb%d0%b8_%d0%bf%d0%b8%d1%81%d0%b0%d1%82%d1%8c_const_%d0%b4%d0%bb%"
"d1%8f_%d0%bf%d0%b0%d1%80%d0%b0%d0%bc%d0%b5%d1%82%d1%80%d0%be%d0%b2%2C_%d0%ba%d0%be%d1%82%"
"d0%be%d1%80%d1%8b%d0%b5_%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d1%8e%d1%82%d1%81%d1%8f_%d0%"
"b2_%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d1%8e_%d0%bf%d0%be_%d0%b7%d0%bd%d0%b0%d1%87%d0%b5%"
"d0%bd%d0%b8%d1%8e%3F";
Ge0Parser parser;
Ge0Parser::Result parseResult;
bool const success = parser.Parse(url.c_str(), parseResult);
TEST(success, (url, parseResult));
// Name would be valid but is too long.
TEST_NOT_EQUAL(parseResult.m_name, string(name), (url));
double const latEps = GetLatEpsilon(9);
double const lonEps = GetLonEpsilon(9);
TEST_ALMOST_EQUAL_ABS(parseResult.m_lat, lat, latEps, (url, parseResult));
TEST_ALMOST_EQUAL_ABS(parseResult.m_lon, lon, lonEps, (url, parseResult));
TEST_ALMOST_EQUAL_ABS(parseResult.m_zoomLevel, zoom, kZoomEps, (url, parseResult));
}
}
UNIT_TEST(LatLonFullAndClippedCoordinates)
{
double maxLatDiffForCoordSize[10] = {0};
double maxLonDiffForCoordSize[10] = {0};
for (double lat = -90; lat <= 90; lat += 0.7)
{
for (double lon = -180; lon < 180; lon += 0.7)
{
string const buf = ge0::GenerateShortShowMapUrl(lat, lon, 4, "");
size_t const coordInd = buf.find("://") + 4;
for (int i = 9; i >= 1; --i)
{
string const str = buf.substr(coordInd, i);
size_t const coordSize = str.size();
Ge0ParserForTest parser;
double latTmp, lonTmp;
parser.DecodeLatLon(str, latTmp, lonTmp);
double const epsLat = GetLatEpsilon(coordSize);
double const epsLon = GetLonEpsilon(coordSize);
double const difLat = fabs(lat - latTmp);
double const difLon = fabs(lon - lonTmp);
TEST(difLat <= epsLat, (str, lat, latTmp, lon, lonTmp, difLat, epsLat));
TEST(difLon <= epsLon, (str, lat, latTmp, lon, lonTmp, difLon, epsLon));
maxLatDiffForCoordSize[coordSize] = max(maxLatDiffForCoordSize[coordSize], difLat);
maxLonDiffForCoordSize[coordSize] = max(maxLonDiffForCoordSize[coordSize], difLon);
}
}
}
for (size_t coordSize = 1; coordSize <= 8; ++coordSize)
{
TEST(maxLatDiffForCoordSize[coordSize] > maxLatDiffForCoordSize[coordSize + 1], (coordSize));
TEST(maxLonDiffForCoordSize[coordSize] > maxLonDiffForCoordSize[coordSize + 1], (coordSize));
TEST(maxLatDiffForCoordSize[coordSize] <= GetLatEpsilon(coordSize), (coordSize));
TEST(maxLonDiffForCoordSize[coordSize] <= GetLonEpsilon(coordSize), (coordSize));
TEST(maxLatDiffForCoordSize[coordSize] > GetLatEpsilon(coordSize + 1), (coordSize));
TEST(maxLonDiffForCoordSize[coordSize] > GetLonEpsilon(coordSize + 1), (coordSize));
}
}
UNIT_TEST(ClippedName)
{
TestSuccess("ge0://AwAAAAAAAA/Super%5fPoi", 0, 0, 4, "Super Poi");
TestSuccess("ge0://AwAAAAAAAA/Super%5fPo", 0, 0, 4, "Super Po");
TestSuccess("ge0://AwAAAAAAAA/Super%5fP", 0, 0, 4, "Super P");
TestSuccess("ge0://AwAAAAAAAA/Super%5f", 0, 0, 4, "Super ");
TestSuccess("ge0://AwAAAAAAAA/Super%5", 0, 0, 4, "Super");
TestSuccess("ge0://AwAAAAAAAA/Super%", 0, 0, 4, "Super");
TestSuccess("ge0://AwAAAAAAAA/Super", 0, 0, 4, "Super");
TestSuccess("ge0://AwAAAAAAAA/Supe", 0, 0, 4, "Supe");
TestSuccess("ge0://AwAAAAAAAA/Sup", 0, 0, 4, "Sup");
TestSuccess("ge0://AwAAAAAAAA/Su", 0, 0, 4, "Su");
TestSuccess("ge0://AwAAAAAAAA/S", 0, 0, 4, "S");
TestSuccess("ge0://AwAAAAAAAA/", 0, 0, 4, "");
TestSuccess("ge0://AwAAAAAAAA", 0, 0, 4, "");
}
UNIT_TEST(Bad_Base64)
{
TestSuccess("ge0://Byqqqqqqqq", 45, 0, 4.25, "");
TestFailure("ge0://Byqqqqqqq");
TestFailure("ge0://Byqqqqqqq\xEE");
}
UNIT_TEST(OtherPrefixes)
{
TestSuccess("http://comaps.app/Byqqqqqqqq/Name", 45, 0, 4.25, "Name");
TestSuccess("https://comaps.app/Byqqqqqqqq/Name", 45, 0, 4.25, "Name");
TestFailure("http://comapz.app/Byqqqqqqqq/Name");
TestSuccess("http://comaps.app/AwAAAAAAAA/Super%5fPoi", 0, 0, 4, "Super Poi");
TestSuccess("https://comaps.app/AwAAAAAAAA/Super%5fPoi", 0, 0, 4, "Super Poi");
TestFailure("https://comapz.app/AwAAAAAAAA/Super%5fPoi");
TestSuccess("https://comaps.app/Byqqqqqqqq", 45, 0, 4.25, "");
TestFailure("https://comaps.app/Byqqqqqqq");
}
} // namespace ge0

View file

@ -0,0 +1,362 @@
#include "testing/testing.hpp"
#include "ge0/geo_url_parser.hpp"
#include "ge0/url_generator.hpp"
#include <string>
using namespace std;
namespace
{
int const kTestCoordBytes = 9;
double const kEps = 1e-10;
} // namespace
namespace ge0
{
string TestLatLonToStr(double lat, double lon)
{
static char s[kTestCoordBytes + 1] = {0};
LatLonToString(lat, lon, s, kTestCoordBytes);
return string(s);
}
UNIT_TEST(Base64Char)
{
TEST_EQUAL('A', Base64Char(0), ());
TEST_EQUAL('B', Base64Char(1), ());
TEST_EQUAL('9', Base64Char(61), ());
TEST_EQUAL('-', Base64Char(62), ());
TEST_EQUAL('_', Base64Char(63), ());
}
UNIT_TEST(LatToInt_0)
{
TEST_EQUAL(499, LatToInt(0, 998), ());
TEST_EQUAL(500, LatToInt(0, 999), ());
TEST_EQUAL(500, LatToInt(0, 1000), ());
TEST_EQUAL(501, LatToInt(0, 1001), ());
}
UNIT_TEST(LatToInt_NearOrGreater90)
{
TEST_EQUAL(999, LatToInt(89.9, 1000), ());
TEST_EQUAL(1000, LatToInt(89.999999, 1000), ());
TEST_EQUAL(1000, LatToInt(90.0, 1000), ());
TEST_EQUAL(1000, LatToInt(90.1, 1000), ());
TEST_EQUAL(1000, LatToInt(100.0, 1000), ());
TEST_EQUAL(1000, LatToInt(180.0, 1000), ());
TEST_EQUAL(1000, LatToInt(350.0, 1000), ());
TEST_EQUAL(1000, LatToInt(360.0, 1000), ());
TEST_EQUAL(1000, LatToInt(370.0, 1000), ());
}
UNIT_TEST(LatToInt_NearOrLess_minus90)
{
TEST_EQUAL(1, LatToInt(-89.9, 1000), ());
TEST_EQUAL(0, LatToInt(-89.999999, 1000), ());
TEST_EQUAL(0, LatToInt(-90.0, 1000), ());
TEST_EQUAL(0, LatToInt(-90.1, 1000), ());
TEST_EQUAL(0, LatToInt(-100.0, 1000), ());
TEST_EQUAL(0, LatToInt(-180.0, 1000), ());
TEST_EQUAL(0, LatToInt(-350.0, 1000), ());
TEST_EQUAL(0, LatToInt(-360.0, 1000), ());
TEST_EQUAL(0, LatToInt(-370.0, 1000), ());
}
UNIT_TEST(LatToInt_NearOrLess_Rounding)
{
TEST_EQUAL(0, LatToInt(-90.0, 2), ());
TEST_EQUAL(0, LatToInt(-45.1, 2), ());
TEST_EQUAL(1, LatToInt(-45.0, 2), ());
TEST_EQUAL(1, LatToInt(0.0, 2), ());
TEST_EQUAL(1, LatToInt(44.9, 2), ());
TEST_EQUAL(2, LatToInt(45.0, 2), ());
TEST_EQUAL(2, LatToInt(90.0, 2), ());
}
UNIT_TEST(LonIn180180)
{
double const kEps = 1e-20;
TEST_ALMOST_EQUAL_ABS(0.0, LonIn180180(0), kEps, ());
TEST_ALMOST_EQUAL_ABS(20.0, LonIn180180(20), kEps, ());
TEST_ALMOST_EQUAL_ABS(90.0, LonIn180180(90), kEps, ());
TEST_ALMOST_EQUAL_ABS(179.0, LonIn180180(179), kEps, ());
TEST_ALMOST_EQUAL_ABS(-180.0, LonIn180180(180), kEps, ());
TEST_ALMOST_EQUAL_ABS(-180.0, LonIn180180(-180), kEps, ());
TEST_ALMOST_EQUAL_ABS(-179.0, LonIn180180(-179), kEps, ());
TEST_ALMOST_EQUAL_ABS(-20.0, LonIn180180(-20), kEps, ());
TEST_ALMOST_EQUAL_ABS(0.0, LonIn180180(360), kEps, ());
TEST_ALMOST_EQUAL_ABS(0.0, LonIn180180(720), kEps, ());
TEST_ALMOST_EQUAL_ABS(0.0, LonIn180180(-360), kEps, ());
TEST_ALMOST_EQUAL_ABS(0.0, LonIn180180(-720), kEps, ());
TEST_ALMOST_EQUAL_ABS(179.0, LonIn180180(360 + 179), kEps, ());
TEST_ALMOST_EQUAL_ABS(-180.0, LonIn180180(360 + 180), kEps, ());
TEST_ALMOST_EQUAL_ABS(-180.0, LonIn180180(360 - 180), kEps, ());
TEST_ALMOST_EQUAL_ABS(-179.0, LonIn180180(360 - 179), kEps, ());
}
UNIT_TEST(LonToInt_NearOrLess_Rounding)
{
/*
135 90 45
\ | /
03333
180 0\|/2
-----0-o-2---- 0
-180 0/|\2
11112
/ | \
-135 -90 -45
*/
TEST_EQUAL(0, LonToInt(-180.0, 3), ());
TEST_EQUAL(0, LonToInt(-135.1, 3), ());
TEST_EQUAL(1, LonToInt(-135.0, 3), ());
TEST_EQUAL(1, LonToInt(-90.0, 3), ());
TEST_EQUAL(1, LonToInt(-60.1, 3), ());
TEST_EQUAL(1, LonToInt(-45.1, 3), ());
TEST_EQUAL(2, LonToInt(-45.0, 3), ());
TEST_EQUAL(2, LonToInt(0.0, 3), ());
TEST_EQUAL(2, LonToInt(44.9, 3), ());
TEST_EQUAL(3, LonToInt(45.0, 3), ());
TEST_EQUAL(3, LonToInt(120.0, 3), ());
TEST_EQUAL(3, LonToInt(134.9, 3), ());
TEST_EQUAL(0, LonToInt(135.0, 3), ());
}
UNIT_TEST(LonToInt_0)
{
TEST_EQUAL(499, LonToInt(0, 997), ());
TEST_EQUAL(500, LonToInt(0, 998), ());
TEST_EQUAL(500, LonToInt(0, 999), ());
TEST_EQUAL(501, LonToInt(0, 1000), ());
TEST_EQUAL(501, LonToInt(0, 1001), ());
TEST_EQUAL(499, LonToInt(360, 997), ());
TEST_EQUAL(500, LonToInt(360, 998), ());
TEST_EQUAL(500, LonToInt(360, 999), ());
TEST_EQUAL(501, LonToInt(360, 1000), ());
TEST_EQUAL(501, LonToInt(360, 1001), ());
TEST_EQUAL(499, LonToInt(-360, 997), ());
TEST_EQUAL(500, LonToInt(-360, 998), ());
TEST_EQUAL(500, LonToInt(-360, 999), ());
TEST_EQUAL(501, LonToInt(-360, 1000), ());
TEST_EQUAL(501, LonToInt(-360, 1001), ());
}
UNIT_TEST(LonToInt_180)
{
TEST_EQUAL(0, LonToInt(-180, 1000), ());
TEST_EQUAL(0, LonToInt(180, 1000), ());
TEST_EQUAL(0, LonToInt(-180 - 360, 1000), ());
TEST_EQUAL(0, LonToInt(180 + 360, 1000), ());
}
UNIT_TEST(LonToInt_360)
{
TEST_EQUAL(2, LonToInt(0, 3), ());
TEST_EQUAL(2, LonToInt(0 + 360, 3), ());
TEST_EQUAL(2, LonToInt(0 - 360, 3), ());
TEST_EQUAL(2, LonToInt(1, 3), ());
TEST_EQUAL(2, LonToInt(1 + 360, 3), ());
TEST_EQUAL(2, LonToInt(1 - 360, 3), ());
TEST_EQUAL(2, LonToInt(-1, 3), ());
TEST_EQUAL(2, LonToInt(-1 + 360, 3), ());
TEST_EQUAL(2, LonToInt(-1 - 360, 3), ());
}
UNIT_TEST(LatLonToString)
{
TEST_EQUAL("AAAAAAAAA", TestLatLonToStr(-90, -180), ());
TEST_EQUAL("qqqqqqqqq", TestLatLonToStr(90, -180), ());
TEST_EQUAL("_________", TestLatLonToStr(90, 179.999999), ());
TEST_EQUAL("VVVVVVVVV", TestLatLonToStr(-90, 179.999999), ());
TEST_EQUAL("wAAAAAAAA", TestLatLonToStr(0.0, 0.0), ());
TEST_EQUAL("6qqqqqqqq", TestLatLonToStr(90.0, 0.0), ());
TEST_EQUAL("P________", TestLatLonToStr(-0.000001, -0.000001), ());
}
UNIT_TEST(LatLonToString_PrefixIsTheSame)
{
for (double lat = -95; lat <= 95; lat += 0.7)
{
for (double lon = -190; lon < 190; lon += 0.9)
{
char prevStepS[kMaxPointBytes + 1] = {0};
LatLonToString(lat, lon, prevStepS, kMaxPointBytes);
for (int len = kMaxPointBytes - 1; len > 0; --len)
{
// Test that the current string is a prefix of the previous one.
char s[kMaxPointBytes] = {0};
LatLonToString(lat, lon, s, len);
prevStepS[len] = 0;
TEST_EQUAL(s, string(prevStepS), ());
}
}
}
}
UNIT_TEST(LatLonToString_StringDensity)
{
int b64toI[256];
for (int i = 0; i < 256; ++i)
b64toI[i] = -1;
for (int i = 0; i < 64; ++i)
b64toI[static_cast<size_t>(Base64Char(i))] = i;
int num1[256] = {0};
int num2[256][256] = {{0}};
for (double lat = -90; lat <= 90; lat += 0.1)
{
for (double lon = -180; lon < 180; lon += 0.05)
{
char s[3] = {0};
LatLonToString(lat, lon, s, 2);
auto const s0 = static_cast<size_t>(s[0]);
auto const s1 = static_cast<size_t>(s[1]);
++num1[b64toI[s0]];
++num2[b64toI[s0]][b64toI[s1]];
}
}
int min1 = 1 << 30;
int min2 = 1 << 30;
int max1 = 0;
int max2 = 0;
for (int i = 0; i < 256; ++i)
{
if (num1[i] != 0 && num1[i] < min1)
min1 = num1[i];
if (num1[i] != 0 && num1[i] > max1)
max1 = num1[i];
for (int j = 0; j < 256; ++j)
{
if (num2[i][j] != 0 && num2[i][j] < min2)
min2 = num2[i][j];
if (num2[i][j] != 0 && num2[i][j] > max2)
max2 = num2[i][j];
}
}
// printf("\n1: %i-%i 2: %i-%i\n", min1, max1, min2, max2);
TEST((max1 - min1) * 1.0 / max1 < 0.05, ());
TEST((max2 - min2) * 1.0 / max2 < 0.05, ());
}
UNIT_TEST(GenerateShortShowMapUrl_SmokeTest)
{
string res = GenerateShortShowMapUrl(0, 0, 19, "Name");
TEST_EQUAL("cm://8wAAAAAAAA/Name", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_NameIsEmpty)
{
string res = GenerateShortShowMapUrl(0, 0, 19, "");
TEST_EQUAL("cm://8wAAAAAAAA", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_ZoomVerySmall)
{
string res = GenerateShortShowMapUrl(0, 0, 2, "Name");
TEST_EQUAL("cm://AwAAAAAAAA/Name", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_ZoomNegative)
{
string res = GenerateShortShowMapUrl(0, 0, -5, "Name");
TEST_EQUAL("cm://AwAAAAAAAA/Name", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_ZoomLarge)
{
string res = GenerateShortShowMapUrl(0, 0, 20, "Name");
TEST_EQUAL("cm://_wAAAAAAAA/Name", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_ZoomVeryLarge)
{
string res = GenerateShortShowMapUrl(0, 0, 2000000000, "Name");
TEST_EQUAL("cm://_wAAAAAAAA/Name", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_FractionalZoom)
{
string res = GenerateShortShowMapUrl(0, 0, 8.25, "Name");
TEST_EQUAL("cm://RwAAAAAAAA/Name", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_FractionalZoomRoundsDown)
{
string res = GenerateShortShowMapUrl(0, 0, 8.499, "Name");
TEST_EQUAL("cm://RwAAAAAAAA/Name", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_FractionalZoomNextStep)
{
string res = GenerateShortShowMapUrl(0, 0, 8.5, "Name");
TEST_EQUAL("cm://SwAAAAAAAA/Name", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_SpaceIsReplacedWithUnderscore)
{
string res = GenerateShortShowMapUrl(0, 0, 19, "Hello World");
TEST_EQUAL("cm://8wAAAAAAAA/Hello_World", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_NamesAreEscaped)
{
string res = GenerateShortShowMapUrl(0, 0, 19, "'Hello,World!%$");
TEST_EQUAL("cm://8wAAAAAAAA/%27Hello%2CWorld%21%25%24", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_UnderscoreIsReplacedWith_Percent_20)
{
string res = GenerateShortShowMapUrl(0, 0, 19, "Hello_World");
TEST_EQUAL("cm://8wAAAAAAAA/Hello%20World", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_ControlCharsAreEscaped)
{
string res = GenerateShortShowMapUrl(0, 0, 19, "Hello\tWorld\n");
TEST_EQUAL("cm://8wAAAAAAAA/Hello%09World%0A", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_Unicode)
{
string res = GenerateShortShowMapUrl(0, 0, 19, "\xe2\x98\x84");
TEST_EQUAL("cm://8wAAAAAAAA/\xe2\x98\x84", res, ());
}
UNIT_TEST(GenerateShortShowMapUrl_UnicodeMixedWithOtherChars)
{
string res = GenerateShortShowMapUrl(0, 0, 19, "Back_in \xe2\x98\x84!\xd1\x8e\xd0\xbc");
TEST_EQUAL("cm://8wAAAAAAAA/Back%20in_\xe2\x98\x84%21\xd1\x8e\xd0\xbc", res, ());
}
UNIT_TEST(GenerateGeoUri_SmokeTest)
{
string res = GenerateGeoUri(33.8904075, 35.5066454, 16.5, "Falafel M. Sahyoun");
TEST_EQUAL("geo:33.8904075,35.5066454?z=16.5&q=33.8904075,35.5066454(Falafel%20M.%20Sahyoun)", res, ());
// geo:33.8904075,35.5066454?z=16.5(Falafel%20M.%20Sahyoun)
// geo:33.890408,35.506645?z=16.5(Falafel%20M.%20Sahyoun)
geo::GeoURLInfo info;
geo::GeoParser parser;
TEST(parser.Parse(res, info), ());
TEST_ALMOST_EQUAL_ABS(info.m_lat, 33.8904075, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_lon, 35.5066454, kEps, ());
TEST_ALMOST_EQUAL_ABS(info.m_zoom, 16.5, kEps, ());
TEST_EQUAL(info.m_label, "Falafel M. Sahyoun", ());
}
} // namespace ge0