Maps URL Scheme API base parser

This commit is contained in:
Yury Melnichek 2012-11-28 18:33:43 +01:00 committed by Alex Zolotarev
parent f93a18c9bd
commit 9dd1d67db4
4 changed files with 215 additions and 0 deletions

View file

@ -50,6 +50,7 @@ HEADERS += \
move_screen_task.hpp \
change_viewport_task.hpp \
dialog_settings.hpp \
mwm_url.hpp \
SOURCES += \
feature_vec_model.cpp \
@ -91,6 +92,7 @@ SOURCES += \
move_screen_task.cpp \
change_viewport_task.cpp \
dialog_settings.cpp \
mwm_url.cpp \
!iphone*:!bada*:!android* {
HEADERS += qgl_render_context.hpp

View file

@ -0,0 +1,80 @@
#include "../../testing/testing.hpp"
#include "../mwm_url.hpp"
#include "../../coding/uri.hpp"
using namespace url_scheme;
UNIT_TEST(MapApiSmoke)
{
Uri uri("mapswithme://map?ll=38.970559,-9.419289&ignoreThisParam=Yes&z=17&n=Point%20Name");
TEST(uri.IsValid(), ());
ParsedMapApi api(uri);
TEST(api.IsValid(), ());
TEST_EQUAL(api.GetPoints().size(), 1, ());
TEST_EQUAL(api.GetPoints()[0].m_lat, 38.970559, ());
TEST_EQUAL(api.GetPoints()[0].m_lon, -9.419289, ());
TEST_EQUAL(api.GetPoints()[0].m_title, "Point Name", ());
}
UNIT_TEST(MapApiInvalidUrl)
{
TEST(!ParsedMapApi(Uri("competitors://map?ll=12.3,34.54")).IsValid(), ());
TEST(!ParsedMapApi(Uri("mapswithme://ggg?ll=12.3,34.54")).IsValid(), ());
TEST(!ParsedMapApi(Uri("mapswithme://")).IsValid(), ("No path"));
TEST(!ParsedMapApi(Uri("mapswithme://map?")).IsValid(), ("No parameters"));
TEST(!ParsedMapApi(Uri("mapswithme://map?ll=23.55")).IsValid(), ("No longtitude"));
TEST(!ParsedMapApi(Uri("mapswithme://map?ll=1,2,3")).IsValid(), ("Too many values for ll"));
}
UNIT_TEST(MapApiLatLonLimits)
{
TEST(!ParsedMapApi(Uri("mapswithme://map?ll=-91,10")).IsValid(), ("Invalid latitude"));
TEST(!ParsedMapApi(Uri("mapswithme://map?ll=523.55,10")).IsValid(), ("Invalid latitude"));
TEST(ParsedMapApi(Uri("mapswithme://map?ll=23.55,450")).IsValid(), ("But valid longtitude"));
TEST(ParsedMapApi(Uri("mapswithme://map?ll=23.55,-450")).IsValid(), ("But valid longtitude"));
}
UNIT_TEST(MapApiPointNameBeforeLatLon)
{
ParsedMapApi api(Uri("mapswithme://map?n=Name&ll=1,2"));
TEST(api.IsValid(), ());
TEST_EQUAL(api.GetPoints().size(), 1, ());
TEST_EQUAL(api.GetPoints()[0].m_title, "", ());
}
UNIT_TEST(MapApiPointNameOverwritten)
{
ParsedMapApi api(Uri("mapswithme://map?ll=1,2&n=A&n=B"));
TEST(api.IsValid(), ());
TEST_EQUAL(api.GetPoints().size(), 1, ());
TEST_EQUAL(api.GetPoints()[0].m_title, "B", ());
}
UNIT_TEST(MapApiMultiplePoints)
{
ParsedMapApi api(Uri("mapswithme://map?ll=1.1,1.2&n=A&ll=2.1,2.2&ll=-3.1,-3.2&n=C"));
TEST(api.IsValid(), ());
TEST_EQUAL(api.GetPoints().size(), 3, ());
TEST_EQUAL(api.GetPoints()[0].m_lat, 1.1, ());
TEST_EQUAL(api.GetPoints()[0].m_lon, 1.2, ());
TEST_EQUAL(api.GetPoints()[0].m_title, "A", ());
TEST_EQUAL(api.GetPoints()[1].m_title, "", ());
TEST_EQUAL(api.GetPoints()[1].m_lat, 2.1, ());
TEST_EQUAL(api.GetPoints()[1].m_lon, 2.2, ());
TEST_EQUAL(api.GetPoints()[2].m_title, "C", ());
TEST_EQUAL(api.GetPoints()[2].m_lat, -3.1, ());
TEST_EQUAL(api.GetPoints()[2].m_lon, -3.2, ());
}
UNIT_TEST(MapApiInvalidPointLatLonButValidOtherParts)
{
ParsedMapApi api(Uri("mapswithme://map?ll=1,1,1&n=A&ll=2,2&n=B&ll=3,3,3&n=C"));
TEST(api.IsValid(), ());
TEST_EQUAL(api.GetPoints().size(), 1, ());
TEST_EQUAL(api.GetPoints()[0].m_lat, 2, ());
TEST_EQUAL(api.GetPoints()[0].m_lon, 2, ());
TEST_EQUAL(api.GetPoints()[0].m_title, "B", ());
}

92
map/mwm_url.cpp Normal file
View file

@ -0,0 +1,92 @@
#include "mwm_url.hpp"
#include "../indexer/mercator.hpp"
#include "../coding/uri.hpp"
#include "../base/logging.hpp"
#include "../base/string_utils.hpp"
#include "../std/algorithm.hpp"
#include "../std/bind.hpp"
using namespace url_scheme;
namespace
{
static int const INVALID_LAT_VALUE = -1000;
bool IsInvalidApiPoint(ApiPoint const & p) { return p.m_lat == INVALID_LAT_VALUE; }
} // unnames namespace
ParsedMapApi::ParsedMapApi(Uri const & uri)
{
if (!Parse(uri))
{
m_points.clear();
}
}
bool ParsedMapApi::IsValid() const
{
return !m_points.empty();
}
bool ParsedMapApi::Parse(Uri const & uri)
{
if (uri.GetScheme() != "mapswithme" || uri.GetPath() != "map")
return false;
uri.ForEachKeyValue(bind(&ParsedMapApi::AddKeyValue, this, _1, _2));
m_points.erase(remove_if(m_points.begin(), m_points.end(), &IsInvalidApiPoint), m_points.end());
return true;
}
void ParsedMapApi::AddKeyValue(string const & key, string const & value)
{
if (key == "ll")
{
m_points.push_back(ApiPoint());
m_points.back().m_lat = INVALID_LAT_VALUE;
size_t const firstComma = value.find(',');
if (firstComma == string::npos)
{
LOG(LWARNING, ("Map API: no comma between lat and lon for 'll' key", key, value));
return;
}
if (value.find(',', firstComma + 1) != string::npos)
{
LOG(LWARNING, ("Map API: more than one comma in a value for 'll' key", key, value));
return;
}
double lat, lon;
if (!strings::to_double(value.substr(0, firstComma), lat) ||
!strings::to_double(value.substr(firstComma + 1), lon))
{
LOG(LWARNING, ("Map API: can't parse lat,lon for 'll' key", key, value));
return;
}
if (!MercatorBounds::ValidLat(lat) || !MercatorBounds::ValidLon(lon))
{
LOG(LWARNING, ("Map API: incorrect value for lat and/or lon", key, value, lat, lon));
return;
}
m_points.back().m_lat = lat;
m_points.back().m_lon = lon;
}
else if (key == "n")
{
if (!m_points.empty())
m_points.back().m_title = value;
else
LOG(LWARNING, ("Map API: Point name with no point. 'll' should come first!"));
}
}

41
map/mwm_url.hpp Normal file
View file

@ -0,0 +1,41 @@
#include "../geometry/rect2d.hpp"
#include "../std/string.hpp"
namespace url_scheme
{
class Uri;
struct ApiPoint
{
double m_lat;
double m_lon;
string m_title;
string m_url;
};
/// Handles mapswithme://map?params - everything related to displaying info on a map
class ParsedMapApi
{
public:
ParsedMapApi(Uri const & uri);
bool IsValid() const;
vector<ApiPoint> const & GetPoints() const { return m_points; }
private:
bool Parse(Uri const & uri);
void AddKeyValue(string const & key, string const & value);
vector<ApiPoint> m_points;
/*
string m_title;
string m_backTitle;
string m_backUrl;
// Calculated from zoom parameter or from m_points
m2::RectD m_showRect;
// vector<char> m_iconData;
*/
};
}