service-providers: Add parsing for service provider info
We currently only need the emergency number information Signed-off-by: Guido Günther <agx@sigxcpu.org> Part-of: <https://gitlab.gnome.org/GNOME/calls/-/merge_requests/790>
This commit is contained in:
@@ -25,7 +25,7 @@ typedef enum {
|
||||
|
||||
/* See 3GPP TS 22.101 version 14.8.0 Release 14, Chapter 10.1 */
|
||||
typedef enum {
|
||||
CALLS_EMERGENCY_CALL_TYPE_UNKNOWN = 0,
|
||||
CALLS_EMERGENCY_CALL_TYPE_NONE = 0,
|
||||
CALLS_EMERGENCY_CALL_TYPE_POLICE = (1 << 0),
|
||||
CALLS_EMERGENCY_CALL_TYPE_AMBULANCE = (1 << 1),
|
||||
CALLS_EMERGENCY_CALL_TYPE_FIRE_BRIGADE = (1 << 2),
|
||||
|
||||
461
src/calls-service-providers.c
Normal file
461
src/calls-service-providers.c
Normal file
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Phosh.mobi e.V.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Author: Guido Günther <agx@sigxcpu.org>
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "calls-service-providers"
|
||||
|
||||
#include "calls-emergency-call-types.h"
|
||||
#include "calls-service-providers.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gmobile.h>
|
||||
|
||||
typedef enum {
|
||||
PARSER_TOPLEVEL = 0,
|
||||
PARSER_COUNTRY,
|
||||
PARSER_EMERGENCY_NUMBERS,
|
||||
PARSER_EMERGENCY_NUMBER,
|
||||
PARSER_CALLEE,
|
||||
PARSER_DONE,
|
||||
PARSER_ERROR
|
||||
} GsdParseContextState;
|
||||
|
||||
|
||||
typedef struct {
|
||||
GMarkupParseContext *ctx;
|
||||
GHashTable *info;
|
||||
char buffer[4096];
|
||||
|
||||
char *text_buffer;
|
||||
GsdParseContextState state;
|
||||
CallsEmergencyCallCountryData *current_data;
|
||||
CallsEmergencyNumber *current_number;
|
||||
CallsEmergencyCallTypeFlags current_flags;
|
||||
} CallsParseContext;
|
||||
|
||||
|
||||
typedef struct {
|
||||
GAsyncResult *res;
|
||||
GMainLoop *loop;
|
||||
} GetChannelsSyncData;
|
||||
|
||||
|
||||
static void
|
||||
calls_parse_context_free (CallsParseContext *parse_context)
|
||||
{
|
||||
g_markup_parse_context_free (parse_context->ctx);
|
||||
g_clear_pointer (&parse_context->current_data, calls_emergency_call_country_data_free);
|
||||
g_clear_pointer (&parse_context->current_number, calls_emergency_number_free);
|
||||
g_clear_pointer (&parse_context->info, g_hash_table_unref);
|
||||
g_clear_pointer (&parse_context->text_buffer, g_free);
|
||||
|
||||
g_free (parse_context);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_toplevel_start (CallsParseContext *parse_context,
|
||||
const char *name,
|
||||
const char **attribute_names,
|
||||
const char **attribute_values)
|
||||
{
|
||||
if (g_str_equal (name, "serviceproviders")) {
|
||||
for (int i = 0; !gm_str_is_null_or_empty (attribute_names[i]); i++) {
|
||||
if (g_str_equal (attribute_names[i], "format")) {
|
||||
if (!g_str_equal (attribute_values[i], "2.0")) {
|
||||
g_warning ("Mobile broadband provider database format '%s' not supported.",
|
||||
attribute_values[i]);
|
||||
parse_context->state = PARSER_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (g_str_equal (name, "country")) {
|
||||
parse_context->state = PARSER_COUNTRY;
|
||||
|
||||
if (parse_context->current_data) {
|
||||
g_warning ("Country '%s' not fully parsed", parse_context->current_data->country_code);
|
||||
g_clear_pointer (&parse_context->current_data, calls_emergency_call_country_data_free);
|
||||
}
|
||||
|
||||
for (int i = 0; !gm_str_is_null_or_empty (attribute_names[i]); i++) {
|
||||
if (g_str_equal (attribute_names[i], "code")) {
|
||||
g_assert (parse_context->current_data == NULL);
|
||||
parse_context->current_data = calls_emergency_call_country_data_new (attribute_values[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_country_start (CallsParseContext *parse_context,
|
||||
const char *name,
|
||||
const char **attribute_names,
|
||||
const char **attribute_values)
|
||||
{
|
||||
if (g_str_equal (name, "emergency-numbers"))
|
||||
parse_context->state = PARSER_EMERGENCY_NUMBERS;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_emergency_numbers_start (CallsParseContext *parse_context,
|
||||
const char *name,
|
||||
const char **attribute_names,
|
||||
const char **attribute_values)
|
||||
{
|
||||
if (g_str_equal (name, "emergency-number")) {
|
||||
for (int i = 0; !gm_str_is_null_or_empty (attribute_names[i]); i++) {
|
||||
if (g_str_equal (attribute_names[i], "number")) {
|
||||
|
||||
g_assert (parse_context->current_number == NULL);
|
||||
parse_context->current_number = calls_emergency_number_new (attribute_values[i],
|
||||
CALLS_EMERGENCY_CALL_TYPE_NONE);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
parse_context->state = PARSER_EMERGENCY_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static CallsEmergencyCallTypeFlags
|
||||
type_to_flag (const char *type)
|
||||
{
|
||||
if (g_str_equal (type, "police")) {
|
||||
return CALLS_EMERGENCY_CALL_TYPE_POLICE;
|
||||
} else if (g_str_equal (type, "ambulance")) {
|
||||
return CALLS_EMERGENCY_CALL_TYPE_AMBULANCE;
|
||||
} else if (g_str_equal (type, "fire-brigade")) {
|
||||
return CALLS_EMERGENCY_CALL_TYPE_FIRE_BRIGADE;
|
||||
}
|
||||
|
||||
return CALLS_EMERGENCY_CALL_TYPE_NONE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_emergency_number_start (CallsParseContext *parse_context,
|
||||
const char *name,
|
||||
const char **attribute_names,
|
||||
const char **attribute_values)
|
||||
{
|
||||
if (g_str_equal (name, "callee")) {
|
||||
|
||||
g_assert (parse_context->current_flags == CALLS_EMERGENCY_CALL_TYPE_NONE);
|
||||
for (int i = 0; !gm_str_is_null_or_empty (attribute_names[i]); i++) {
|
||||
if (g_str_equal (attribute_names[i], "type")) {
|
||||
parse_context->current_flags = type_to_flag (attribute_values[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parse_context->state = PARSER_CALLEE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_start_element (GMarkupParseContext *context,
|
||||
const char *element_name,
|
||||
const char **attribute_names,
|
||||
const char **attribute_values,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
CallsParseContext *parse_context = user_data;
|
||||
|
||||
g_clear_pointer (&parse_context->text_buffer, g_free);
|
||||
|
||||
switch (parse_context->state) {
|
||||
case PARSER_TOPLEVEL:
|
||||
parser_toplevel_start (parse_context, element_name, attribute_names, attribute_values);
|
||||
break;
|
||||
case PARSER_COUNTRY:
|
||||
parser_country_start (parse_context, element_name, attribute_names, attribute_values);
|
||||
break;
|
||||
case PARSER_EMERGENCY_NUMBERS:
|
||||
parser_emergency_numbers_start (parse_context, element_name, attribute_names, attribute_values);
|
||||
break;
|
||||
case PARSER_EMERGENCY_NUMBER:
|
||||
parser_emergency_number_start (parse_context, element_name, attribute_names, attribute_values);
|
||||
break;
|
||||
case PARSER_CALLEE:
|
||||
break;
|
||||
case PARSER_ERROR:
|
||||
break;
|
||||
case PARSER_DONE:
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_callee_end (CallsParseContext *parse_context, const char *name)
|
||||
{
|
||||
if (g_str_equal (name, "callee")) {
|
||||
parse_context->current_number->flags |= parse_context->current_flags;
|
||||
parse_context->current_flags = CALLS_EMERGENCY_CALL_TYPE_NONE;
|
||||
g_clear_pointer (&parse_context->text_buffer, g_free);
|
||||
parse_context->state = PARSER_EMERGENCY_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_emergency_number_end (CallsParseContext *parse_context, const char *name)
|
||||
{
|
||||
if (g_str_equal (name, "emergency-number")) {
|
||||
g_ptr_array_add (parse_context->current_data->numbers,
|
||||
g_steal_pointer (&parse_context->current_number));
|
||||
g_clear_pointer (&parse_context->text_buffer, g_free);
|
||||
parse_context->state = PARSER_EMERGENCY_NUMBERS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_emergency_numbers_end (CallsParseContext *parse_context, const char *name)
|
||||
{
|
||||
if (g_str_equal (name, "emergency-numbers")) {
|
||||
g_clear_pointer (&parse_context->text_buffer, g_free);
|
||||
parse_context->state = PARSER_COUNTRY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_country_end (CallsParseContext *parse_context, const char *name)
|
||||
{
|
||||
if (g_str_equal (name, "country")) {
|
||||
/* Only add country if we have any emergency numbers */
|
||||
if (parse_context->current_data->numbers->len) {
|
||||
g_hash_table_insert (parse_context->info,
|
||||
parse_context->current_data->country_code,
|
||||
parse_context->current_data);
|
||||
parse_context->current_data = NULL;
|
||||
}
|
||||
g_clear_pointer (&parse_context->current_data, calls_emergency_call_country_data_free);
|
||||
g_clear_pointer (&parse_context->text_buffer, g_free);
|
||||
parse_context->state = PARSER_TOPLEVEL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_end_element (GMarkupParseContext *context,
|
||||
const char *element_name,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
CallsParseContext *parse_context = user_data;
|
||||
|
||||
switch (parse_context->state) {
|
||||
case PARSER_TOPLEVEL:
|
||||
break;
|
||||
case PARSER_COUNTRY:
|
||||
parser_country_end (parse_context, element_name);
|
||||
break;
|
||||
case PARSER_EMERGENCY_NUMBERS:
|
||||
parser_emergency_numbers_end (parse_context, element_name);
|
||||
break;
|
||||
case PARSER_EMERGENCY_NUMBER:
|
||||
parser_emergency_number_end (parse_context, element_name);
|
||||
break;
|
||||
case PARSER_CALLEE:
|
||||
parser_callee_end (parse_context, element_name);
|
||||
case PARSER_ERROR:
|
||||
break;
|
||||
case PARSER_DONE:
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
parser_text (GMarkupParseContext *context,
|
||||
const char *text,
|
||||
gsize text_len,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
CallsParseContext *parse_context = user_data;
|
||||
|
||||
g_free (parse_context->text_buffer);
|
||||
parse_context->text_buffer = g_strdup (text);
|
||||
}
|
||||
|
||||
|
||||
static const GMarkupParser parser = {
|
||||
.start_element = parser_start_element,
|
||||
.end_element = parser_end_element,
|
||||
.text = parser_text,
|
||||
.passthrough = NULL,
|
||||
.error = NULL,
|
||||
};
|
||||
|
||||
|
||||
static void read_next_chunk (GInputStream *stream, GTask *task);
|
||||
|
||||
|
||||
static void
|
||||
on_stream_read_ready (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
GInputStream *stream = G_INPUT_STREAM (source_object);
|
||||
g_autoptr (GTask) task = G_TASK (user_data);
|
||||
CallsParseContext *parse_context = g_task_get_task_data (task);
|
||||
gssize len;
|
||||
GError *error = NULL;
|
||||
|
||||
len = g_input_stream_read_finish (stream, res, &error);
|
||||
if (len == -1) {
|
||||
g_prefix_error (&error, "Error reading service provider database: ");
|
||||
g_task_return_error (task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&parse_context->info),
|
||||
(GDestroyNotify)g_hash_table_unref);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_markup_parse_context_parse (parse_context->ctx, parse_context->buffer, len, &error)) {
|
||||
g_prefix_error (&error, "Error parsing service provider database: ");
|
||||
g_task_return_error (task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
read_next_chunk (stream, g_steal_pointer (&task));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
read_next_chunk (GInputStream *stream, GTask *task)
|
||||
{
|
||||
CallsParseContext *parse_context = g_task_get_task_data (task);
|
||||
|
||||
g_input_stream_read_async (stream,
|
||||
parse_context->buffer,
|
||||
sizeof (parse_context->buffer),
|
||||
G_PRIORITY_DEFAULT,
|
||||
g_task_get_cancellable (task),
|
||||
on_stream_read_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_file_read_ready (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
g_autoptr (GTask) task = G_TASK (user_data);
|
||||
g_autoptr (GFileInputStream) stream = NULL;
|
||||
GError *error = NULL;
|
||||
GFile *file = G_FILE (source_object);
|
||||
|
||||
stream = g_file_read_finish (file, res, &error);
|
||||
if (!stream) {
|
||||
g_prefix_error (&error, "Error opening service provider database: ");
|
||||
g_task_return_error (task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
read_next_chunk (G_INPUT_STREAM (stream), g_steal_pointer (&task));
|
||||
}
|
||||
|
||||
|
||||
GHashTable *
|
||||
|
||||
calls_service_providers_get_emergency_info_finish (GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
g_assert (G_IS_TASK (res));
|
||||
g_assert (g_task_get_source_tag(G_TASK (res)) == calls_service_providers_get_emergency_info);
|
||||
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
calls_service_providers_get_emergency_info (const char *serviceproviders,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr (GFile) file = NULL;
|
||||
g_autoptr (GTask) task = g_task_new (NULL, cancellable, callback, user_data);
|
||||
CallsParseContext *parse_context = g_new0 (CallsParseContext, 1);
|
||||
|
||||
g_assert (serviceproviders);
|
||||
|
||||
parse_context->ctx = g_markup_parse_context_new (&parser, 0, parse_context, NULL);
|
||||
parse_context->info = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
NULL,
|
||||
(GDestroyNotify)
|
||||
calls_emergency_call_country_data_free);
|
||||
|
||||
g_task_set_task_data (task, parse_context, (GDestroyNotify)calls_parse_context_free);
|
||||
g_task_set_source_tag (task, calls_service_providers_get_emergency_info);
|
||||
|
||||
file = g_file_new_for_path (serviceproviders);
|
||||
g_file_read_async (file, G_PRIORITY_DEFAULT,
|
||||
cancellable,
|
||||
on_file_read_ready,
|
||||
g_steal_pointer (&task));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_get_emergency_info_ready (GObject *object, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
GetChannelsSyncData *data = user_data;
|
||||
|
||||
g_assert (data->res == NULL);
|
||||
data->res = g_object_ref (res);
|
||||
g_main_loop_quit (data->loop);
|
||||
}
|
||||
|
||||
|
||||
GHashTable *
|
||||
calls_service_providers_get_emergency_info_sync (const char *serviceproviders,
|
||||
GError **error)
|
||||
{
|
||||
GHashTable *info;
|
||||
GetChannelsSyncData data;
|
||||
g_autoptr (GMainContext) context = g_main_context_new ();
|
||||
g_autoptr (GMainLoop) loop = NULL;
|
||||
|
||||
g_main_context_push_thread_default (context);
|
||||
loop = g_main_loop_new (context, FALSE);
|
||||
|
||||
data = (GetChannelsSyncData) {
|
||||
.loop = loop,
|
||||
.res = NULL,
|
||||
};
|
||||
|
||||
calls_service_providers_get_emergency_info (serviceproviders,
|
||||
NULL,
|
||||
on_get_emergency_info_ready,
|
||||
&data);
|
||||
g_main_loop_run (data.loop);
|
||||
|
||||
info = calls_service_providers_get_emergency_info_finish (data.res, error);
|
||||
|
||||
g_clear_object (&data.res);
|
||||
g_main_context_pop_thread_default (context);
|
||||
|
||||
return info;
|
||||
}
|
||||
23
src/calls-service-providers.h
Normal file
23
src/calls-service-providers.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Phosh.mobi e.V.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void calls_service_providers_get_emergency_info (const char *serviceproviders,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GHashTable *calls_service_providers_get_emergency_info_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
GHashTable *calls_service_providers_get_emergency_info_sync (const char *serviceproviders,
|
||||
GError **error) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
@@ -123,6 +123,7 @@ calls_sources = files([
|
||||
'calls-ringer.c', 'calls-ringer.h',
|
||||
'calls-secret-store.c', 'calls-secret-store.h',
|
||||
'calls-settings.c', 'calls-settings.h',
|
||||
'calls-service-providers.c', 'calls-service-providers.h',
|
||||
'calls-ui-call-data.c', 'calls-ui-call-data.h',
|
||||
'calls-ussd.c', 'calls-ussd.h',
|
||||
'calls-util.c', 'calls-util.h',
|
||||
|
||||
35
tests/data/serviceproviders.xml
Normal file
35
tests/data/serviceproviders.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding='utf-8'?>
|
||||
<!-- -*- Mode: XML; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- -->
|
||||
<!DOCTYPE serviceproviders SYSTEM "serviceproviders.2.dtd">
|
||||
<serviceproviders format="2.0">
|
||||
<country code="yy">
|
||||
<name>Germany</name>
|
||||
<emergency-numbers>
|
||||
<emergency-number number="112">
|
||||
<callee type="ambulance"/>
|
||||
<callee type="fire-brigade"/>
|
||||
<callee type="police"/>
|
||||
</emergency-number>
|
||||
</emergency-numbers>
|
||||
<provider>
|
||||
</provider>
|
||||
</country>
|
||||
|
||||
<country code="xx">
|
||||
<name>Switzerland</name>
|
||||
<emergency-numbers>
|
||||
<emergency-number number="114">
|
||||
<callee type="ambulance"/>
|
||||
</emergency-number>
|
||||
<emergency-number number="117">
|
||||
<callee type="police"/>
|
||||
</emergency-number>
|
||||
<emergency-number number="118">
|
||||
<callee type="fire-brigade"/>
|
||||
</emergency-number>
|
||||
</emergency-numbers>
|
||||
</country>
|
||||
|
||||
<country code="zz">
|
||||
</country>
|
||||
</serviceproviders>
|
||||
@@ -19,6 +19,7 @@ test_env = [
|
||||
test_cflags = [
|
||||
'-DFOR_TESTING',
|
||||
'-Wno-error=deprecated-declarations',
|
||||
'-DTEST_DATABASE="@0@"'.format(meson.current_source_dir() / 'data' / 'serviceproviders.xml'),
|
||||
]
|
||||
|
||||
test_link_args = [
|
||||
@@ -52,6 +53,19 @@ t = executable('emergency-call-types', test_sources,
|
||||
)
|
||||
test('emergency-call-types', t, env: test_env)
|
||||
|
||||
test_sources = [ 'test-service-providers.c' ]
|
||||
t = executable('service-providers', test_sources,
|
||||
c_args : test_cflags,
|
||||
link_args: test_link_args,
|
||||
pie: true,
|
||||
link_with : [calls_vala, libcalls],
|
||||
dependencies: calls_deps,
|
||||
include_directories : [
|
||||
calls_includes,
|
||||
]
|
||||
)
|
||||
test('service-providers', t, env: test_env)
|
||||
|
||||
test_sources = [ 'test-manager.c' ]
|
||||
|
||||
t = executable('manager', test_sources,
|
||||
|
||||
112
tests/test-service-providers.c
Normal file
112
tests/test-service-providers.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Phosh.mobi e.V.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*
|
||||
* Author: Guido Günther <agx@sigxcpu.org>
|
||||
*/
|
||||
|
||||
#include "calls-emergency-call-types.h"
|
||||
#include "calls-service-providers.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
|
||||
|
||||
#define calls_assert_cmp_emergency_number(d, i, n, f) G_STMT_START { \
|
||||
CallsEmergencyNumber *_n = g_ptr_array_index (d->numbers, i); \
|
||||
if (!_n) { \
|
||||
g_autofree char *__msg = \
|
||||
g_strdup_printf ("Emergency number '%u' does not exist", i); \
|
||||
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, __msg); \
|
||||
} \
|
||||
if (!_n->number) { \
|
||||
g_autofree char *__msg = \
|
||||
g_strdup_printf ("Emergency number of element '%u' is NULL", i); \
|
||||
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, __msg); \
|
||||
} \
|
||||
if (!g_str_equal (_n->number, n)) { \
|
||||
g_autofree char *__msg = \
|
||||
g_strdup_printf ("Emergency number of element '%u' is '%s' not '%s'", i, _n->number, n); \
|
||||
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, __msg); \
|
||||
} \
|
||||
if (_n->flags != f) { \
|
||||
g_autofree char *__msg = \
|
||||
g_strdup_printf ("Emergency number of element '%u' has flags '0x%x'' not '0x%x'", i, _n->flags, f); \
|
||||
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, __msg); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
|
||||
static gboolean
|
||||
numbers_equal (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const CallsEmergencyNumber *n_a = a;
|
||||
const char *needle = b;
|
||||
|
||||
return g_str_equal (n_a->number, needle);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_service_providers_parse_de (void)
|
||||
{
|
||||
g_autoptr (GHashTable) info = NULL;
|
||||
g_autoptr (GError) err = NULL;
|
||||
CallsEmergencyCallCountryData *data;
|
||||
CallsEmergencyNumber *number;
|
||||
guint index;
|
||||
|
||||
info = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
NULL,
|
||||
(GDestroyNotify) calls_emergency_call_country_data_free);
|
||||
|
||||
info = calls_service_providers_get_emergency_info_sync (TEST_DATABASE, &err);
|
||||
|
||||
g_assert_no_error (err);
|
||||
g_assert_nonnull (info);
|
||||
|
||||
data = g_hash_table_lookup (info, "xx");
|
||||
g_assert_nonnull (data);
|
||||
g_assert_cmpint (data->numbers->len, ==, 3);
|
||||
|
||||
g_assert_true (g_ptr_array_find_with_equal_func (data->numbers, "114", numbers_equal, &index));
|
||||
number = g_ptr_array_index (data->numbers, index);
|
||||
g_assert_nonnull (number);
|
||||
calls_assert_cmp_emergency_number(data, index, "114", CALLS_EMERGENCY_CALL_TYPE_AMBULANCE);
|
||||
|
||||
g_assert_true (g_ptr_array_find_with_equal_func (data->numbers, "117", numbers_equal, &index));
|
||||
number = g_ptr_array_index (data->numbers, index);
|
||||
g_assert_nonnull (number);
|
||||
calls_assert_cmp_emergency_number(data, index, "117", CALLS_EMERGENCY_CALL_TYPE_POLICE);
|
||||
|
||||
g_assert_true (g_ptr_array_find_with_equal_func (data->numbers, "118", numbers_equal, &index));
|
||||
number = g_ptr_array_index (data->numbers, index);
|
||||
g_assert_nonnull (number);
|
||||
calls_assert_cmp_emergency_number(data, index, "118", CALLS_EMERGENCY_CALL_TYPE_FIRE_BRIGADE);
|
||||
|
||||
data = g_hash_table_lookup (info, "yy");
|
||||
g_assert_nonnull (data);
|
||||
g_assert_cmpint (data->numbers->len, ==, 1);
|
||||
g_assert_true (g_ptr_array_find_with_equal_func (data->numbers, "112", numbers_equal, &index));
|
||||
number = g_ptr_array_index (data->numbers, index);
|
||||
g_assert_nonnull (number);
|
||||
calls_assert_cmp_emergency_number(data, index, "112", (CALLS_EMERGENCY_CALL_TYPE_POLICE |
|
||||
CALLS_EMERGENCY_CALL_TYPE_FIRE_BRIGADE |
|
||||
CALLS_EMERGENCY_CALL_TYPE_AMBULANCE));
|
||||
|
||||
data = g_hash_table_lookup (info, "zz");
|
||||
g_assert_null (data);
|
||||
}
|
||||
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/calls/service-providers/parse", test_service_providers_parse_de);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
Reference in New Issue
Block a user