Skip to content
Snippets Groups Projects
Commit 181ba384 authored by Simon McVittie's avatar Simon McVittie Committed by Frédéric Dalleau
Browse files

Add and test TrpPlace and TrpPlaceBuilder


This is a basic version which only fully supports geo: URIs
(spatial locations), plus an optional label string.

Reviewed-by: default avatarPhilip Withnall <philip.withnall@collabora.co.uk>
Reviewed-by: default avatarGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Signed-off-by: default avatarSimon McVittie <simon.mcvittie@collabora.co.uk>
Signed-off-by: default avatarFrédéric Dalleau <frederic.dalleau@collabora.com>
Differential Revision: https://phabricator.apertis.org/D4609
parent 4186dca6
No related branches found
No related tags found
No related merge requests found
......@@ -132,14 +132,26 @@ noinst_LTLIBRARIES += traprain-common/libtraprain-common-internal.la
traprain_commonincludedir = $(includedir)/traprain-common-@TRP_API_VERSION@
traprain_common_headers = \
traprain-common/route.h \
traprain-common/languages-map.h \
traprain-common/place.h \
traprain-common/route.h \
$(NULL)
nodist_traprain_common_headers = \
traprain-common/enumtypes.h \
$(NULL)
BUILT_SOURCES += $(nodist_traprain_common_headers)
traprain_common_private_headers = \
traprain-common/glib-derived.h \
traprain-common/languages-map-internal.h \
traprain-common/messages-internal.h \
traprain-common/route-internal.h \
traprain-common/uri-internal.h \
$(NULL)
nobase_nodist_traprain_commoninclude_HEADERS = \
$(nodist_traprain_common_headers) \
$(NULL)
nobase_traprain_commoninclude_HEADERS = \
......@@ -147,8 +159,20 @@ nobase_traprain_commoninclude_HEADERS = \
$(NULL)
traprain_common_sources = \
traprain-common/glib-derived.c \
traprain-common/languages-map.c \
traprain-common/place.c \
traprain-common/route.c \
traprain-common/uri.c \
$(NULL)
nodist_traprain_common_sources = \
traprain-common/enumtypes.c \
$(NULL)
BUILT_SOURCES += $(nodist_traprain_common_sources)
nodist_traprain_common_libtraprain_common_internal_la_SOURCES = \
$(nodist_traprain_common_sources) \
$(NULL)
traprain_common_libtraprain_common_internal_la_SOURCES = \
......@@ -170,6 +194,7 @@ traprain_common_libtraprain_common_internal_la_CFLAGS = \
$(NULL)
traprain_common_libtraprain_common_internal_la_LIBADD = \
$(LIBM) \
$(TRAPRAIN_LIBS) \
$(CODE_COVERAGE_LDFLAGS) \
$(NULL)
......@@ -180,6 +205,18 @@ traprain_common_libtraprain_common_internal_la_LDFLAGS = \
$(AM_LDFLAGS) \
$(NULL)
traprain-common/enumtypes.h: traprain-common/enumtypes.h.template \
$(traprain_common_headers)
$(AM_V_GEN)$(GLIB_MKENUMS) --template $< \
$(patsubst %,$(srcdir)/%,$(traprain_common_headers)) \
> $@.tmp && mv $@.tmp $@
traprain-common/enumtypes.c: traprain-common/enumtypes.c.template \
$(traprain_common_headers)
$(AM_V_GEN)$(GLIB_MKENUMS) --template $< \
$(patsubst %,$(srcdir)/%,$(traprain_common_headers)) \
> $@.tmp && mv $@.tmp $@
traprain_common_libtraprain_common_@TRP_API_VERSION@_la_SOURCES = $(NULL)
traprain_common_libtraprain_common_@TRP_API_VERSION@_la_LIBADD = traprain-common/libtraprain-common-internal.la
......@@ -425,7 +462,12 @@ traprain_common_TraprainCommon_@TRP_API_VERSION@_gir_CFLAGS = \
$(traprain_common_libtraprain_common_internal_la_CFLAGS) \
$(NULL)
traprain_common_TraprainCommon_@TRP_API_VERSION@_gir_LIBS = traprain-common/libtraprain-common-@TRP_API_VERSION@.la
traprain_common_TraprainCommon_@TRP_API_VERSION@_gir_FILES = $(traprain_common_sources) $(traprain_common_headers)
traprain_common_TraprainCommon_@TRP_API_VERSION@_gir_FILES = \
$(traprain_common_headers) \
$(traprain_common_sources) \
$(nodist_traprain_common_headers) \
$(nodist_traprain_common_sources) \
$(NULL)
traprain_common_TraprainCommon_@TRP_API_VERSION@_gir_NAMESPACE = TraprainCommon
traprain_common_TraprainCommon_@TRP_API_VERSION@_gir_EXPORT_PACKAGES = traprain-common-@TRP_API_VERSION@
traprain_common_TraprainCommon_@TRP_API_VERSION@_gir_SCANNERFLAGS = \
......@@ -599,6 +641,8 @@ EXTRA_DIST += \
$(systemdsysusers_DATA:%=%.in) \
$(apparmor_policy_DATA:%=%.in) \
$(dbusconf_DATA:%=%.in) \
traprain-common/enumtypes.c.template \
traprain-common/enumtypes.h.template \
$(NULL)
CLEANFILES += \
......@@ -654,6 +698,7 @@ test_programs = \
tests/test-mock-service \
tests/test-guidance-progress \
tests/test-guidance-turn-by-turn \
tests/test-place \
$(NULL)
tests_test_service_navigation_SOURCES = \
......@@ -784,6 +829,30 @@ tests_test_guidance_turn_by_turn_LDADD = \
$(top_builddir)/traprain-service/libtraprain-service-internal.la \
$(NULL)
tests_test_place_SOURCES = \
tests/test-place.c \
$(NULL)
tests_test_place_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_builddir) \
$(NULL)
tests_test_place_CFLAGS = \
$(WARN_CFLAGS) \
$(TRAPRAIN_CFLAGS) \
$(NULL)
tests_test_place_LDFLAGS = \
-no-undefined \
$(WARN_LDFLAGS) \
$(NULL)
tests_test_place_LDADD = \
$(TRAPRAIN_LIBS) \
$(top_builddir)/traprain-common/libtraprain-common-@TRP_API_VERSION@.la \
$(NULL)
EXTRA_DIST += tests/services/org.apertis.Navigation1.service.in
DISTCLEANFILES += tests/services/org.apertis.Navigation1.service
......
......@@ -28,6 +28,9 @@ LT_INIT
PKG_PROG_PKG_CONFIG
AC_PROG_LN_S
LT_LIB_M
AC_SUBST([LIBM])
# Before making a release, the TRP_LT_VERSION string should be modified. The
# string is of the form c:r:a. Follow these instructions sequentially:
#
......
......@@ -6,6 +6,15 @@ Copyright:
© 2016 Collabora Ltd.
License: MPL-2.0
Files:
traprain-common/glib-derived.c
traprain-common/glib-derived.h
Copyright:
© 2004 Red Hat, Inc.
© 2006 Alberto Ruiz
© 2016 Collabora Ltd.
License: LGPL-2+
License: MPL-2.0
Mozilla Public License Version 2.0
==================================
......@@ -380,3 +389,20 @@ License: MPL-2.0
.
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.
License: LGPL-2+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
.
On Apertis systems, a copy of the GNU Lesser General Public License
version 2 can be found in <file:///usr/share/common-licenses/LGPL-2>.
/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */
/*
* Copyright © 2016 Collabora Ltd.
*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <stdlib.h>
#include <gio/gio.h>
#include <glib.h>
#include "traprain-common/place.h"
/* Put this one first, before we turn off -Wfloat-equal, to
* check that we can use these macros without triggering warnings. */
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic error "-Wfloat-equal"
#endif
static void
test_macros (void)
{
g_assert_false (trp_place_is_latitude (+90.5));
g_assert_true (trp_place_is_latitude (+90.0));
g_assert_true (trp_place_is_latitude (0.0));
g_assert_true (trp_place_is_latitude (-90.0));
g_assert_false (trp_place_is_latitude (-90.5));
g_assert_false (trp_place_is_latitude (TRP_PLACE_LATITUDE_UNKNOWN));
g_assert_false (trp_place_is_longitude (+180.5));
g_assert_true (trp_place_is_longitude (+180.0));
g_assert_true (trp_place_is_longitude (0.0));
g_assert_true (trp_place_is_longitude (-180.0));
g_assert_false (trp_place_is_longitude (-180.5));
g_assert_false (trp_place_is_longitude (TRP_PLACE_LONGITUDE_UNKNOWN));
g_assert_true (trp_place_is_altitude (10000.0));
g_assert_true (trp_place_is_altitude (0.0));
g_assert_true (trp_place_is_altitude (-100.0));
g_assert_false (trp_place_is_altitude (TRP_PLACE_ALTITUDE_UNKNOWN));
g_assert_true (trp_place_is_uncertainty (10000.0));
g_assert_true (trp_place_is_uncertainty (1.0));
g_assert_true (trp_place_is_uncertainty (0.0));
g_assert_false (trp_place_is_uncertainty (-1.0));
g_assert_false (trp_place_is_uncertainty (TRP_PLACE_UNCERTAINTY_UNKNOWN));
}
/* We are using float equality in the rest of this test; don't warn about it,
* since we are only using it for quantities that should be stored without
* any parsing or computation, or that can be represented exactly in
* text. */
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
static void
test_builder (void)
{
g_autoptr (TrpPlace) place = NULL;
g_autoptr (TrpPlaceBuilder) builder = NULL;
g_autofree gchar *location_string = NULL;
builder = trp_place_builder_new (NULL);
/* This pair of statements is refcount-neutral. g_assert_true() is
* always compiled in */
g_assert_true (trp_place_builder_ref (builder) == builder);
trp_place_builder_unref (builder);
trp_place_builder_set_latitude (builder, 50.827138);
trp_place_builder_set_longitude (builder, -0.230885);
place = trp_place_builder_copy (builder);
g_assert_cmpfloat (trp_place_get_latitude (place), ==, 50.827138);
g_assert_cmpfloat (trp_place_get_longitude (place), ==, -0.230885);
g_assert_cmpfloat (trp_place_get_altitude (place), ==,
TRP_PLACE_ALTITUDE_UNKNOWN);
g_assert_cmpfloat (trp_place_get_uncertainty (place), ==,
TRP_PLACE_UNCERTAINTY_UNKNOWN);
g_assert_cmpint (trp_place_get_crs (place), ==,
TRP_COORDINATE_REFERENCE_SYSTEM_WGS84);
g_assert_cmpstr (trp_place_get_location_string (place), ==, NULL);
location_string = trp_place_force_location_string (place);
g_assert_cmpstr (location_string, ==, "50.83°N 0.23°W");
g_clear_pointer (&location_string, g_free);
trp_place_builder_set_altitude (builder, 14.0);
trp_place_builder_set_uncertainty (builder, 100.0);
trp_place_builder_set_location_string (builder, "Shoreham Port");
/* it didn't affect the existing object */
g_assert_cmpstr (trp_place_get_location_string (place), ==, NULL);
g_assert_cmpfloat (trp_place_get_uncertainty (place), ==,
TRP_PLACE_UNCERTAINTY_UNKNOWN);
g_clear_object (&place);
place = trp_place_builder_end (builder);
g_assert_cmpfloat (trp_place_get_latitude (place), ==, 50.827138);
g_assert_cmpfloat (trp_place_get_longitude (place), ==, -0.230885);
g_assert_cmpfloat (trp_place_get_uncertainty (place), ==, 100.0);
g_assert_cmpfloat (trp_place_get_altitude (place), ==, 14.0);
g_assert_cmpint (trp_place_get_crs (place), ==,
TRP_COORDINATE_REFERENCE_SYSTEM_WGS84);
g_assert_cmpstr (trp_place_get_location_string (place), ==, "Shoreham Port");
location_string = trp_place_force_location_string (place);
g_assert_cmpstr (location_string, ==, "Shoreham Port");
g_clear_pointer (&location_string, g_free);
g_clear_object (&place);
/* After being ended, the builder is blanked, but it is not allowed to end a
* blank builder, it needs at least location string or lat/long pair */
trp_place_builder_set_location_string (builder, "Nowhere");
place = trp_place_builder_end (builder);
g_assert_false (trp_place_is_latitude (trp_place_get_latitude (place)));
g_assert_false (trp_place_is_longitude (trp_place_get_longitude (place)));
g_assert_false (trp_place_is_altitude (trp_place_get_altitude (place)));
g_assert_false (trp_place_is_uncertainty (trp_place_get_uncertainty (place)));
g_assert_cmpint (trp_place_get_crs (place), ==,
TRP_COORDINATE_REFERENCE_SYSTEM_WGS84);
g_assert_cmpstr (trp_place_get_location_string (place), ==, "Nowhere");
}
static void
test_to_uri (void)
{
g_autoptr (TrpPlace) place = NULL;
g_autoptr (TrpPlaceBuilder) builder = NULL;
g_autofree gchar *uri = NULL;
builder = trp_place_builder_new (NULL);
/* This is chosen to be exactly representable in both decimal and FP */
trp_place_builder_set_latitude (builder, 50.5);
trp_place_builder_set_longitude (builder, -0.25);
place = trp_place_builder_copy (builder);
uri = trp_place_to_uri (place, TRP_URI_SCHEME_GEO);
g_assert_cmpstr (uri, ==, "geo:50.5,-0.25");
g_clear_pointer (&uri, g_free);
/* If there is just a geographical location, ANY is equivalent to GEO */
uri = trp_place_to_uri (place, TRP_URI_SCHEME_ANY);
g_assert_cmpstr (uri, ==, "geo:50.5,-0.25");
g_clear_pointer (&uri, g_free);
g_clear_object (&place);
/* This is chosen to be exactly representable in both decimal and FP */
trp_place_builder_set_altitude (builder, 2.375);
trp_place_builder_set_uncertainty (builder, 1.0);
trp_place_builder_set_location_string (builder, "Somewhere");
place = trp_place_builder_copy (builder);
uri = trp_place_to_uri (place, TRP_URI_SCHEME_GEO);
g_assert_cmpstr (uri, ==, "geo:50.5,-0.25,2.375;u=1");
g_clear_pointer (&uri, g_free);
/* TODO: with SCHEME_ANY, we should get a place: URI, because that can
* represent the location string too */
g_clear_object (&place);
}
/* Use the implementation detail that all the unknown values are
* mathematically equal, which lets us abbreviate good_uris[] significantly */
#define UNKNOWN (-G_MAXDOUBLE)
typedef struct
{
const char *uri;
gint code;
gdouble latitude;
gdouble longitude;
gdouble altitude;
gdouble uncertainty;
const char *location_string;
} SampleUri;
static const SampleUri good_uris[] =
{
{ "geo:0,1", 0, 0.0, 1.0, UNKNOWN, UNKNOWN, NULL },
{ "geo:0,1,2", 0, 0.0, 1.0, 2.0, UNKNOWN, NULL },
{ "geo:-0.5,-1.25,-2.125", 0, -0.5, -1.25, -2.125, UNKNOWN, NULL },
{ "geo:-0.5,-1.25,-2.125;crs=wgs84", 0, -0.5, -1.25, -2.125, UNKNOWN, NULL },
{ "geo:-0.5,-1.25,-2.125;u=3.75", 0, -0.5, -1.25, -2.125, 3.75, NULL },
{ "GEO:-0.5,-1.25,-2.125;CRS=WGS84;U=3.75", 0, -0.5, -1.25, -2.125, 3.75, NULL },
/* We accept and ignore unknown parameters even in strict mode */
{ "geo:-0.5,-1.25,-2.125;crs=wgs84;u=3.75;param=whatever",
0, -0.5, -1.25, -2.125, 3.75, NULL },
/* At the poles, we normalize longitude to 0 */
{ "geo:90,123", 0, 90.0, 0.0, UNKNOWN, UNKNOWN, NULL },
{ "geo:-90,123", 0, -90.0, 0.0, UNKNOWN, UNKNOWN, NULL },
};
static const struct
{
const char *uri;
gint code;
} bad_uris[] =
{
{ "about:blank", TRP_PLACE_ERROR_UNKNOWN_SCHEME },
{ "http://example.com/", TRP_PLACE_ERROR_UNKNOWN_SCHEME },
{ "geo://0,1", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:/0,1", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:0,1,2,3", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:,1", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:,,", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:0,", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:0,,2", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:0,1,", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:0,1,;param=foo", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:0,1;crs", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:0,1;crs;param=foo", TRP_PLACE_ERROR_INVALID_URI },
{ "geo:0,1;crs=edenprime2183", TRP_PLACE_ERROR_UNKNOWN_CRS },
};
static const struct
{
const char *uri;
gint code_when_tolerant;
gint code_when_strict;
} differently_bad_uris[] =
{
{ "geo:0,1;crs=",
TRP_PLACE_ERROR_UNKNOWN_CRS,
TRP_PLACE_ERROR_INVALID_URI },
{ "geo:0,1;crs=;param=foo",
TRP_PLACE_ERROR_UNKNOWN_CRS,
TRP_PLACE_ERROR_INVALID_URI },
};
static const SampleUri ugly_uris[] =
{
/* Out of range values are clamped in non-strict mode */
{ "geo:92,100", TRP_PLACE_ERROR_OUT_OF_RANGE,
90.0, 0.0, UNKNOWN, UNKNOWN, NULL },
{ "geo:-91,-100", TRP_PLACE_ERROR_OUT_OF_RANGE,
-90.0, 0.0, UNKNOWN, UNKNOWN, NULL },
{ "geo:82,181", TRP_PLACE_ERROR_OUT_OF_RANGE,
82.0, 180.0, UNKNOWN, UNKNOWN, NULL },
{ "geo:-81,-183", TRP_PLACE_ERROR_OUT_OF_RANGE,
-81.0, 180.0, UNKNOWN, UNKNOWN, NULL },
{ "geo:-0.5,-1.25,-2.125;u=-3.75", TRP_PLACE_ERROR_INVALID_URI,
-0.5, -1.25, -2.125, UNKNOWN, NULL },
/* A poorly designed Google Maps extension used on Android */
{ "geo:0,0?q=52.25,0.125(near+Cambridge)", TRP_PLACE_ERROR_INVALID_URI,
0.0, 0.0, UNKNOWN, UNKNOWN, NULL },
/* A Google Maps extension: search for a place near here */
{ "geo:52.25,0.125?q=Golden%20Curry", TRP_PLACE_ERROR_INVALID_URI,
52.25, 0.125, UNKNOWN, UNKNOWN, NULL },
/* We expect URIs, not URI-references */
{ "geo:52.25,0.125#Whatever", TRP_PLACE_ERROR_INVALID_URI,
52.25, 0.125, UNKNOWN, UNKNOWN, NULL },
/* HTTP-style query string and fragment */
{ "geo:52.25,0.125?a=b&c=d&e#f", TRP_PLACE_ERROR_INVALID_URI,
52.25, 0.125, UNKNOWN, UNKNOWN, NULL },
/* Parameters aren't parsed after the ? or #, so this doesn't have
* an uncertainty of ± 1 metre */
{ "geo:52.25,0.125?a;u=1.0", TRP_PLACE_ERROR_INVALID_URI,
52.25, 0.125, UNKNOWN, UNKNOWN, NULL },
/* In strict mode we expect URIs, not IRIs */
{ "geo:0,1;param=føö", TRP_PLACE_ERROR_INVALID_URI,
0.0, 1.0, UNKNOWN, UNKNOWN, NULL },
/* Check for trailing ';' */
{ "geo:0,1;", TRP_PLACE_ERROR_INVALID_URI,
0.0, 1.0, UNKNOWN, UNKNOWN, NULL },
/* Check for multiple trailing ';' */
{ "geo:0,2;;;", TRP_PLACE_ERROR_INVALID_URI,
0.0, 2.0, UNKNOWN, UNKNOWN, NULL },
/* The ';' can still be used as a separator */
{ "geo:0,4;param=foo;", TRP_PLACE_ERROR_INVALID_URI,
0.0, 4.0, UNKNOWN, UNKNOWN, NULL },
/* Check for multiple trailing ';' */
{ "geo:0,3;param=foo;;;;", TRP_PLACE_ERROR_INVALID_URI,
0.0, 3.0, UNKNOWN, UNKNOWN, NULL },
/* Check for multiple ';' used as separators */
{ "geo:5,1;;;;;param=foo;", TRP_PLACE_ERROR_INVALID_URI,
5.0, 1.0, UNKNOWN, UNKNOWN, NULL },
/* Check for multiple ';' everywhere */
{ "geo:6,1;;;param=foo;;;;", TRP_PLACE_ERROR_INVALID_URI,
6.0, 1.0, UNKNOWN, UNKNOWN, NULL },
};
static void
test_sample_uris (const SampleUri *samples, gsize len, TrpUriFlags flags)
{
gsize i;
for (i = 0; i < len; i++)
{
const SampleUri *sample = samples + i;
g_autoptr (GError) error = NULL;
g_autoptr (TrpPlace) place = trp_place_new_for_uri (sample->uri,
flags,
&error);
g_autofree gchar *location_string = NULL;
gdouble latitude, longitude, altitude, uncertainty;
g_test_message ("%s (%s)", sample->uri,
(flags == TRP_URI_FLAGS_STRICT) ? "strict" : "none");
g_assert_no_error (error);
g_object_get (place,
"location-string", &location_string,
"latitude", &latitude,
"longitude", &longitude,
"altitude", &altitude,
"uncertainty", &uncertainty,
NULL);
g_assert_cmpfloat (latitude, ==, sample->latitude);
g_assert_cmpfloat (longitude, ==, sample->longitude);
g_assert_cmpfloat (altitude, ==, sample->altitude);
g_assert_cmpfloat (uncertainty, ==, sample->uncertainty);
g_assert_cmpstr (location_string, ==, sample->location_string);
}
}
static void
test_from_uri (void)
{
test_sample_uris (good_uris, G_N_ELEMENTS (good_uris), TRP_URI_FLAGS_STRICT);
test_sample_uris (good_uris, G_N_ELEMENTS (good_uris), TRP_URI_FLAGS_NONE);
test_sample_uris (ugly_uris, G_N_ELEMENTS (ugly_uris), TRP_URI_FLAGS_NONE);
}
static void
test_from_invalid_uri (void)
{
gsize i;
for (i = 0; i < G_N_ELEMENTS (bad_uris); i++)
{
g_autoptr (GError) error = NULL;
g_autoptr (TrpPlace) place = trp_place_new_for_uri (bad_uris[i].uri,
TRP_URI_FLAGS_NONE,
&error);
g_test_message ("%s (none)", bad_uris[i].uri);
g_assert_error (error, TRP_PLACE_ERROR, bad_uris[i].code);
g_assert_null (place);
g_test_message ("-> %s", error->message);
}
for (i = 0; i < G_N_ELEMENTS (bad_uris); i++)
{
g_autoptr (GError) error = NULL;
g_autoptr (TrpPlace) place = trp_place_new_for_uri (bad_uris[i].uri,
TRP_URI_FLAGS_STRICT,
&error);
g_test_message ("%s (strict)", bad_uris[i].uri);
g_assert_error (error, TRP_PLACE_ERROR, bad_uris[i].code);
g_assert_null (place);
g_test_message ("-> %s", error->message);
}
for (i = 0; i < G_N_ELEMENTS (differently_bad_uris); i++)
{
g_autoptr (GError) error = NULL;
g_autoptr (TrpPlace) place =
trp_place_new_for_uri (differently_bad_uris[i].uri,
TRP_URI_FLAGS_NONE, &error);
g_test_message ("%s (none)", differently_bad_uris[i].uri);
g_assert_error (error, TRP_PLACE_ERROR,
differently_bad_uris[i].code_when_tolerant);
g_assert_null (place);
g_test_message ("-> %s", error->message);
}
for (i = 0; i < G_N_ELEMENTS (differently_bad_uris); i++)
{
g_autoptr (GError) error = NULL;
g_autoptr (TrpPlace) place =
trp_place_new_for_uri (differently_bad_uris[i].uri,
TRP_URI_FLAGS_STRICT, &error);
g_test_message ("%s (strict)", differently_bad_uris[i].uri);
g_assert_error (error, TRP_PLACE_ERROR,
differently_bad_uris[i].code_when_strict);
g_assert_null (place);
g_test_message ("-> %s", error->message);
}
/* These do not parse successfully with the STRICT flag */
for (i = 0; i < G_N_ELEMENTS (ugly_uris); i++)
{
g_autoptr (GError) error = NULL;
g_autoptr (TrpPlace) place = trp_place_new_for_uri (ugly_uris[i].uri,
TRP_URI_FLAGS_STRICT,
&error);
g_test_message ("%s (strict)", ugly_uris[i].uri);
g_assert_error (error, TRP_PLACE_ERROR, ugly_uris[i].code);
g_assert_null (place);
g_test_message ("-> %s", error->message);
}
}
int
main (int argc,
char **argv)
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/place/macros", test_macros);
g_test_add_func ("/place/builder", test_builder);
g_test_add_func ("/place/to-uri", test_to_uri);
g_test_add_func ("/place/from-uri", test_from_uri);
g_test_add_func ("/place/from-invalid-uri", test_from_invalid_uri);
return g_test_run ();
}
/*** BEGIN file-header ***/
/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s ft=c: */
/*
* Copyright © 2016 Collabora Ltd.
*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "traprain-common/enumtypes.h"
#include "traprain-common/place.h"
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
GType g_define_type_id =
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
/*** END value-tail ***/
/*** BEGIN file-header ***/
/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s ft=c: */
/*
* Copyright © 2016 Collabora Ltd.
*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef __TRAPRAIN_COMMON_ENUMTYPES_H__
#define __TRAPRAIN_COMMON_ENUMTYPES_H__
#include <glib-object.h>
G_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
/*** END value-header ***/
/*** BEGIN file-tail ***/
G_END_DECLS
#endif
/*** END file-tail ***/
/*
* Copyright (C) 2004 Red Hat, Inc.
* Copyright (C) 2006 Alberto Ruiz
* Copyright (C) 2016 Collabora Ltd.
*
* SPDX-License-Identifier: LGPL-2+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "traprain-common/glib-derived.h"
#include <string.h>
/**
* _trp_utf8_make_valid:
* @str: string to coerce into UTF-8
*
* If the provided string is valid UTF-8, return a copy of it. If not,
* return a copy in which bytes that could not be interpreted as valid Unicode
* are replaced with the Unicode replacement character (U+FFFD).
*
* For example, this is an appropriate function to use if you have received
* a string that was incorrectly declared to be UTF-8, and you need a valid
* UTF-8 version of it that can be logged or displayed to the user, with the
* assumption that it is close enough to ASCII or UTF-8 to be mostly
* readable as-is.
*
* Returns: (transfer full): a valid UTF-8 string whose content resembles @str
*
* Since: 2.52
*/
/* FIXME: replace with g_utf8_make_valid() when we get GLib 2.51 */
gchar *
_trp_utf8_make_valid (const gchar *str)
{
GString *string;
const gchar *remainder, *invalid;
gint remaining_bytes, valid_bytes;
g_return_val_if_fail (str != NULL, NULL);
string = NULL;
remainder = str;
remaining_bytes = strlen (str);
while (remaining_bytes != 0)
{
if (g_utf8_validate (remainder, remaining_bytes, &invalid))
break;
valid_bytes = invalid - remainder;
if (string == NULL)
string = g_string_sized_new (remaining_bytes);
g_string_append_len (string, remainder, valid_bytes);
/* append U+FFFD REPLACEMENT CHARACTER */
g_string_append (string, "\357\277\275");
remaining_bytes -= valid_bytes + 1;
remainder = invalid + 1;
}
if (string == NULL)
return g_strdup (str);
g_string_append (string, remainder);
g_assert (g_utf8_validate (string->str, -1, NULL));
return g_string_free (string, FALSE);
}
/*<private_header>*/
/*
* Copyright (C) 2004 Red Hat, Inc.
* Copyright (C) 2006 Alberto Ruiz
* Copyright (C) 2016 Collabora Ltd.
*
* SPDX-License-Identifier: LGPL-2+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* On Apertis systems, a copy of the GNU Lesser General Public License
* version 2 can be found in <file:///usr/share/common-licenses/LGPL-2>.
*/
#ifndef __TRAPRAIN_COMMON_GLIB_DERIVED_H__
#define __TRAPRAIN_COMMON_GLIB_DERIVED_H__
#include <glib.h>
G_BEGIN_DECLS
gchar *_trp_utf8_make_valid (const gchar *str);
G_END_DECLS
#endif
This diff is collapsed.
/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */
/*
* Copyright © 2016 Collabora Ltd.
*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef __TRAPRAIN_COMMON_PLACE_H__
#define __TRAPRAIN_COMMON_PLACE_H__
#include <glib-object.h>
G_BEGIN_DECLS
/**
* TrpUriFlags:
* @TRP_URI_FLAGS_NONE: No special behaviour
* @TRP_URI_FLAGS_STRICT: Strictly follow RFC 5870 during parsing
*
* Flags influencing how we parse URIs. %TRP_URI_FLAGS_STRICT is more
* appropriate when reading a URI that has been written out.
*
* Since: UNRELEASED
*/
typedef enum
{
TRP_URI_FLAGS_NONE = 0,
TRP_URI_FLAGS_STRICT = (1 << 0),
} TrpUriFlags;
/**
* TrpUriScheme:
* %TRP_URI_SCHEME_ANY: return whatever URI best represents this place
* %TRP_URI_SCHEME_GEO: a [`geo:` URI][RFC 5870] for physical locations
* %TRP_URI_SCHEME_PLACE: a [`place:` URI][place URI] for physical locations,
* postal addresses, search terms or a combination of these
*
* The URI scheme used to represent a place.
*
* [RFC 5870]: https://tools.ietf.org/html/rfc5870
* [place URI]: https://docs.apertis.org/latest/geolocation-and-navigation.html#appendix-place-uri-scheme
*
* Since: UNRELEASED
*/
typedef enum
{
TRP_URI_SCHEME_ANY,
TRP_URI_SCHEME_GEO,
} TrpUriScheme;
/**
* TrpCoordinateReferenceSystem:
* %TRP_COORDINATE_REFERENCE_SYSTEM_WGS84: The [World Geodetic System
* 1984](http://earth-info.nga.mil/GandG/publications/tr8350.2/tr8350_2.html)
* (WGS-84), as used in GPS
*
* The coordinate reference system used as a mathematical model of the
* Earth when interpreting the #TrpPlace:latitude, #TrpPlace:longitude and
* #TrpPlace:altitude. WGS-84, the CRS used by the Global Positioning
* System, is currently the only one supported.
*
* [The Wikipedia page on the World Geodetic
* System](https://en.wikipedia.org/wiki/World_Geodetic_System) provides
* a useful overview.
*
* Members of this enum correspond to the IANA registry of
* ['geo' URI 'crs' Parameter
* Values](https://www.iana.org/assignments/geo-uri-parameters/geo-uri-parameters.xhtml#geo-uri-parameters-2).
*
* Since: UNRELEASED
*/
typedef enum
{
TRP_COORDINATE_REFERENCE_SYSTEM_WGS84,
} TrpCoordinateReferenceSystem;
/**
* TRP_PLACE_ERROR:
*
* Error domain corresponding to the #TrpPlaceError enumeration.
*
* Since: UNRELEASED
*/
#define TRP_PLACE_ERROR (trp_place_error_quark ())
GQuark trp_place_error_quark (void);
/**
* TrpPlaceError:
* @TRP_PLACE_ERROR_FAILED: Generic error
* @TRP_PLACE_ERROR_INVALID_URI: A URI was syntactically invalid
* @TRP_PLACE_ERROR_UNKNOWN_SCHEME: An unknown URI scheme was used
* @TRP_PLACE_ERROR_UNKNOWN_CRS: An unknown coordinate reference system
* was used
* @TRP_PLACE_ERROR_OUT_OF_RANGE: A coordinate was out of range, for
* example a latitude of 91°N
*
* An error in defining a place or parsing a navigation-related URI.
*
* Since: UNRELEASED
*/
typedef enum
{
TRP_PLACE_ERROR_FAILED,
TRP_PLACE_ERROR_INVALID_URI,
TRP_PLACE_ERROR_UNKNOWN_SCHEME,
TRP_PLACE_ERROR_UNKNOWN_CRS,
TRP_PLACE_ERROR_OUT_OF_RANGE,
} TrpPlaceError;
#define TRP_TYPE_PLACE (trp_place_get_type ())
G_DECLARE_FINAL_TYPE (TrpPlace, trp_place, TRP, PLACE, GObject)
TrpPlace *trp_place_new_for_uri (const gchar *uri,
TrpUriFlags flags,
GError **error);
gchar *trp_place_to_uri (TrpPlace *self,
TrpUriScheme scheme);
const gchar *trp_place_get_location_string (TrpPlace *self);
gchar *trp_place_force_location_string (TrpPlace *self);
gdouble trp_place_get_latitude (TrpPlace *self);
gdouble trp_place_get_longitude (TrpPlace *self);
gdouble trp_place_get_altitude (TrpPlace *self);
gdouble trp_place_get_uncertainty (TrpPlace *self);
TrpCoordinateReferenceSystem trp_place_get_crs (TrpPlace *self);
/**
* TRP_PLACE_LATITUDE_UNKNOWN:
*
* Value representing an unknown latitude.
*
* Since: UNRELEASED
*/
#define TRP_PLACE_LATITUDE_UNKNOWN (-G_MAXDOUBLE)
/**
* TRP_PLACE_LONGITUDE_UNKNOWN:
*
* Value representing an unknown longitude.
*
* Since: UNRELEASED
*/
#define TRP_PLACE_LONGITUDE_UNKNOWN (-G_MAXDOUBLE)
/**
* TRP_PLACE_ALTITUDE_UNKNOWN:
*
* Value representing an unknown altitude.
*
* Since: UNRELEASED
*/
#define TRP_PLACE_ALTITUDE_UNKNOWN (-G_MAXDOUBLE)
/**
* TRP_PLACE_UNCERTAINTY_UNKNOWN:
*
* Value representing an unknown uncertainty. An exact point has an
* uncertainty value of 0.
*
* Since: UNRELEASED
*/
#define TRP_PLACE_UNCERTAINTY_UNKNOWN (-G_MAXDOUBLE)
/**
* trp_place_is_latitude:
* @d: a potential latitude
*
* Check whether @d is a valid latitude. Valid latitudes range from
* -90 degrees (the South Pole) to +90 degrees (the North Pole), inclusive.
* %TRP_PLACE_LATITUDE_UNKNOWN is not considered to be a valid latitude.
*
* Returns: %TRUE if @d is between -90 and 90 degrees, inclusive
* Since: UNRELEASED
*/
static inline gboolean
_trp_place_is_latitude (gdouble d)
{
return (d >= -90 && d <= 90);
}
#define trp_place_is_latitude(d) (_trp_place_is_latitude (d))
gboolean (trp_place_is_latitude) (gdouble d);
/**
* trp_place_is_longitude:
* @d: a potential longitude
*
* Check whether @d is a valid longitude. Valid longitudes range from
* -180 degrees (180 degrees west of Greenwich) to +180 degrees
* (180 degrees east of Greenwich), inclusive.
* %TRP_PLACE_LONGITUDE_UNKNOWN is not considered to be a valid longitude.
*
* Returns: %TRUE if @d is between -180 and 180 degrees, inclusive
* Since: UNRELEASED
*/
static inline gboolean
_trp_place_is_longitude (gdouble d)
{
return (d >= -180 && d <= 180);
}
#define trp_place_is_longitude(d) (_trp_place_is_longitude (d))
gboolean (trp_place_is_longitude) (gdouble d);
/**
* trp_place_is_altitude:
* @d: a potential altitude
*
* Check whether @d is a valid altitude.
* %TRP_PLACE_ALTITUDE_UNKNOWN is not considered to be a valid altitude.
*
* Returns: %TRUE if @d represents a known altitude
* Since: UNRELEASED
*/
/* https://en.wikipedia.org/wiki/Earth_radius, rounding up */
#define trp_place_is_altitude(d) ((d) > -6.4e6)
gboolean (trp_place_is_altitude) (gdouble d);
/**
* trp_place_is_uncertainty:
* @d: a potential altitude
*
* Check whether @d is a valid uncertainty. Valid uncertainties are
* non-negative numbers in metres; %TRP_PLACE_UNCERTAINTY_UNKNOWN is not
* considered to be a valid uncertainty.
*
* Returns: %TRUE if @d represents a known uncertainty
* Since: UNRELEASED
*/
#define trp_place_is_uncertainty(d) ((d) >= 0)
gboolean (trp_place_is_uncertainty) (gdouble d);
typedef struct _TrpPlaceBuilder TrpPlaceBuilder;
#define TRP_TYPE_PLACE_BUILDER (trp_place_builder_get_type ())
GType trp_place_builder_get_type (void);
TrpPlaceBuilder *trp_place_builder_new (TrpPlace *place);
TrpPlaceBuilder *trp_place_builder_ref (TrpPlaceBuilder *self);
void trp_place_builder_unref (TrpPlaceBuilder *self);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (TrpPlaceBuilder, trp_place_builder_unref)
void trp_place_builder_set_latitude (TrpPlaceBuilder *self,
gdouble latitude);
void trp_place_builder_set_longitude (TrpPlaceBuilder *self,
gdouble longitude);
void trp_place_builder_set_altitude (TrpPlaceBuilder *self,
gdouble altitude);
void trp_place_builder_set_uncertainty (TrpPlaceBuilder *self,
gdouble uncertainty);
void trp_place_builder_set_location_string (TrpPlaceBuilder *self,
const gchar *location_string);
TrpPlace *trp_place_builder_copy (TrpPlaceBuilder *self);
TrpPlace *trp_place_builder_end (TrpPlaceBuilder *self);
G_END_DECLS
#endif
/*<private_header>*/
/* vim: set sts=2 sw=2 et : */
/*
* Copyright © 2016 Collabora Ltd.
*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef __TRAPRAIN_COMMON_URI_INTERNAL_H__
#define __TRAPRAIN_COMMON_URI_INTERNAL_H__
#include <glib.h>
#include "traprain-common/place.h"
G_BEGIN_DECLS
/* Character classes from https://tools.ietf.org/html/rfc5870#section-3.3 */
#define TRP_URI_RFC5870_MARK "-_.!~*'()"
#define TRP_URI_RFC5870_P_UNRESERVED "[]:&+$"
gboolean _trp_uri_consume_double (const gchar **p,
gdouble *value,
GError **error);
gboolean _trp_uri_consume_label_text (const gchar **p,
gchar **value,
GError **error);
gboolean _trp_uri_consume_parameter_value (const gchar **p,
TrpUriFlags flags,
gchar **value,
GError **error);
G_END_DECLS
#endif
/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */
/*
* Copyright © 2016 Collabora Ltd.
*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "config.h"
#include "traprain-common/uri-internal.h"
#include <string.h>
#include "traprain-common/glib-derived.h"
/*
* @p: (inout) (not nullable) (not optional):
* @value: (out) (not optional):
*/
gboolean
_trp_uri_consume_double (const gchar **p,
gdouble *value,
GError **error)
{
gdouble d;
gchar *endptr;
d = g_ascii_strtod (*p, &endptr);
if (*p == endptr)
{
g_set_error (error, TRP_PLACE_ERROR, TRP_PLACE_ERROR_INVALID_URI,
"Expected a number at the beginning of: %s", *p);
return FALSE;
}
*p = endptr;
*value = d;
return TRUE;
}
/*
* @p: (inout) (not nullable) (not optional):
* @value: (out) (not optional):
*
* Consume a RFC5870 labeltext token (a parameter name). On success,
* advance @p to the first character after the labeltext token, probably
* '=', ';' or end-of-string.
*/
gboolean
_trp_uri_consume_label_text (const gchar **p,
gchar **value,
GError **error)
{
const gchar *tmp;
gsize n = 0;
for (tmp = *p; g_ascii_isalnum (*tmp) || *tmp == '-'; tmp++)
n++;
if (n == 0)
{
g_set_error (error, TRP_PLACE_ERROR, TRP_PLACE_ERROR_INVALID_URI,
"Expected RFC 5870 labeltext at the beginning of: %s", *p);
return FALSE;
}
*value = g_strndup (*p, n);
*p += n;
return TRUE;
}
/* U+FFFD REPLACEMENT CHARACTER */
#define UNICODE_REPLACEMENT_CHARACTER ((gunicode) 0xFFFD)
/*
* @p: (inout):
* @value: (out) (not optional):
*
* Consume a RFC5870 pvalue token (a parameter value). On success, advance
* @p to the first character after the pvalue token, probably ';' or
* end-of-string.
*
* If %TRP_URI_FLAGS_STRICT is not in @flags, unescaped commas and equals
* signs are treated as part of the pvalue. In strict mode, parsing
* follows RFC5870.
*
* If %TRP_URI_FLAGS_STRICT is not in @flags, @p may point into an IRI
* (internationalized resource identifier), and the returned string
* is coerced into UTF-8 by replacing invalid encodings with U+FFFD.
* In strict mode, only a URI (which is defined to be ASCII) is accepted,
* and any percent-encoded text must be valid UTF-8.
*/
gboolean
_trp_uri_consume_parameter_value (const gchar **p,
TrpUriFlags flags,
gchar **value,
GError **error)
{
const gchar *tmp;
g_autoptr (GString) buffer = g_string_new ("");
gboolean strict = ((flags & TRP_URI_FLAGS_STRICT) ? TRUE : FALSE);
for (tmp = *p; *tmp != '\0'; tmp++)
{
if (*tmp == '%')
{
/* %XX escape */
if (g_ascii_isxdigit (tmp[1]) &&
g_ascii_isxdigit (tmp[2]))
{
g_string_append_c (buffer,
((g_ascii_xdigit_value (tmp[1]) << 4) |
g_ascii_xdigit_value (tmp[2])));
/* consume the two hex digits */
tmp += 2;
}
else
{
g_set_error (error, TRP_PLACE_ERROR,
TRP_PLACE_ERROR_INVALID_URI,
"Invalid URI %% escape at the beginning of: %s",
tmp);
return FALSE;
}
}
else if (g_ascii_isalnum (*tmp) ||
strchr (TRP_URI_RFC5870_MARK
TRP_URI_RFC5870_P_UNRESERVED, *tmp) != NULL)
{
/* Unreserved (in the context of a parameter value) */
g_string_append_c (buffer, *tmp);
}
else if (!strict && (*tmp == ',' || *tmp == '=' || (guchar) *tmp >= 128))
{
g_string_append_c (buffer, *tmp);
}
else
{
break;
}
}
if (tmp == *p && strict)
{
g_set_error (error, TRP_PLACE_ERROR, TRP_PLACE_ERROR_INVALID_URI,
"Expected RFC 5870 pvalue at the beginning of: %s", *p);
return FALSE;
}
if (g_utf8_validate (buffer->str, -1, NULL))
{
*value = g_string_free (g_steal_pointer (&buffer), FALSE);
}
else if (strict)
{
g_set_error (error, TRP_PLACE_ERROR, TRP_PLACE_ERROR_INVALID_URI,
"Expected parameter value to be UTF-8");
return FALSE;
}
else
{
*value = _trp_utf8_make_valid (buffer->str);
}
*p = tmp;
return TRUE;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment