Commit 66da3caa authored by David Zeuthen's avatar David Zeuthen

add unit tests for PolKitPolicyFile and add some features to PolKitHash

parent 41d8bcd0
......@@ -177,10 +177,12 @@ polkit_error_set_error (PolKitError **error, PolKitErrorCode error_code, const c
va_list args;
PolKitError *e;
g_return_val_if_fail (error != NULL, FALSE);
g_return_val_if_fail (format != NULL, FALSE);
g_return_val_if_fail (error_code >= 0 && error_code < POLKIT_ERROR_NUM_ERROR_CODES, FALSE);
if (error == NULL)
goto out;
e = p_new0 (PolKitError, 1);
if (e == NULL) {
*error = &_oom_error;
......@@ -198,6 +200,7 @@ polkit_error_set_error (PolKitError **error, PolKitErrorCode error_code, const c
}
}
out:
return TRUE;
}
......
......@@ -70,6 +70,8 @@ struct _PolKitHash
PolKitHashFunc hash_func;
PolKitEqualFunc key_equal_func;
PolKitCopyFunc key_copy_func;
PolKitCopyFunc value_copy_func;
PolKitFreeFunc key_destroy_func;
PolKitFreeFunc value_destroy_func;
};
......@@ -78,6 +80,8 @@ struct _PolKitHash
* polkit_hash_new:
* @hash_func: The hash function to use
* @key_equal_func: The function used to determine key equality
* @key_copy_func: Function for copying keys or #NULL
* @value_copy_func: Function for copying values or #NULL
* @key_destroy_func: Function for freeing keys or #NULL
* @value_destroy_func: Function for freeing values or #NULL
*
......@@ -90,6 +94,8 @@ struct _PolKitHash
PolKitHash *
polkit_hash_new (PolKitHashFunc hash_func,
PolKitEqualFunc key_equal_func,
PolKitCopyFunc key_copy_func,
PolKitCopyFunc value_copy_func,
PolKitFreeFunc key_destroy_func,
PolKitFreeFunc value_destroy_func)
{
......@@ -104,6 +110,8 @@ polkit_hash_new (PolKitHashFunc hash_func,
h->refcount = 1;
h->hash_func = hash_func;
h->key_copy_func = key_copy_func;
h->value_copy_func = value_copy_func;
h->key_equal_func = key_equal_func;
h->key_destroy_func = key_destroy_func;
h->value_destroy_func = value_destroy_func;
......@@ -198,14 +206,32 @@ polkit_hash_insert (PolKitHash *hash,
void *value)
{
int bucket;
polkit_bool_t ret;
PolKitHashNode **nodep;
PolKitHashNode *node;
void *key_copy;
void *value_copy;
g_return_val_if_fail (hash != NULL, FALSE);
g_return_val_if_fail (key != NULL, FALSE);
ret = FALSE;
key_copy = NULL;
value_copy = NULL;
if (hash->key_copy_func != NULL) {
key_copy = hash->key_copy_func (key);
if (key_copy == NULL) {
goto oom;
}
} else {
key_copy = key;
}
if (hash->value_copy_func != NULL) {
value_copy = hash->value_copy_func (value);
if (value_copy == NULL) {
goto oom;
}
} else {
value_copy = value;
}
bucket = hash->hash_func (key) % hash->num_top_nodes;
......@@ -221,10 +247,10 @@ polkit_hash_insert (PolKitHash *hash,
hash->key_destroy_func (node->key);
if (hash->value_destroy_func != NULL)
hash->value_destroy_func (node->value);
node->key = key;
node->value = value;
ret = TRUE;
node->key = key_copy;
node->value = value_copy;
goto out;
} else {
node = node->next;
......@@ -233,16 +259,23 @@ polkit_hash_insert (PolKitHash *hash,
node = p_new0 (PolKitHashNode, 1);
if (node == NULL)
goto out;
goto oom;
node->key = key;
node->value = value;
node->key = key_copy;
node->value = value_copy;
*nodep = node;
ret = TRUE;
out:
return ret;
return TRUE;
oom:
if (key_copy != NULL && hash->key_copy_func != NULL && hash->key_destroy_func != NULL)
hash->key_destroy_func (key_copy);
if (value_copy != NULL && hash->value_copy_func != NULL && hash->value_destroy_func != NULL)
hash->value_destroy_func (value_copy);
return FALSE;
}
/**
......@@ -395,6 +428,20 @@ polkit_hash_str_equal_func (const void *v1, const void *v2)
return g_str_equal (v1, v2);
}
/**
* polkit_hash_str_copy:
* @p: void pointer to string
*
* Similar to p_strdup() except for types.
*
* Returns: a void pointer to a copy or #NULL on OOM
*/
void *
polkit_hash_str_copy (const void *p)
{
return (void *) p_strdup ((const char *) p);
}
#ifdef POLKIT_BUILD_TESTS
static polkit_bool_t
......@@ -421,7 +468,9 @@ _run_test (void)
polkit_bool_t found;
/* string hash tables */
if ((h = polkit_hash_new (polkit_hash_str_hash_func, polkit_hash_str_equal_func, p_free, p_free)) != NULL) {
if ((h = polkit_hash_new (polkit_hash_str_hash_func, polkit_hash_str_equal_func,
polkit_hash_str_copy, polkit_hash_str_copy,
p_free, p_free)) != NULL) {
int n;
char *key;
char *value;
......@@ -441,22 +490,7 @@ _run_test (void)
/* first insert the values */
for (n = 0; test_data [n*2] != NULL; n++) {
key = p_strdup (test_data [n*2]);
if (key == NULL) {
goto oom;
}
value = p_strdup (test_data [n*2 + 1]);
if (value == NULL) {
p_free (key);
goto oom;
}
if (!polkit_hash_insert (h, key, value)) {
p_free (key);
p_free (value);
if (!polkit_hash_insert (h, test_data [n*2], test_data [n*2 + 1])) {
goto oom;
}
}
......@@ -473,15 +507,8 @@ _run_test (void)
g_assert (polkit_hash_lookup (h, "unknown", &found) == NULL && !found);
/* replace key */
key = p_strdup ("key1");
if (key != NULL) {
value = p_strdup ("val1-replaced");
if (value == NULL) {
p_free (key);
} else {
/* this can never fail because on replace no new node is ever created */
g_assert (polkit_hash_insert (h, key, value));
if (polkit_hash_insert (h, "key1", "val1-replaced")) {
/* check for replaced value */
value = polkit_hash_lookup (h, "key1", &found);
g_assert (found && value != NULL && strcmp (value, "val1-replaced") == 0);
......@@ -503,7 +530,9 @@ _run_test (void)
}
/* direct hash tables */
if ((h = polkit_hash_new (polkit_hash_direct_hash_func, polkit_hash_direct_equal_func, NULL, NULL)) != NULL) {
if ((h = polkit_hash_new (polkit_hash_direct_hash_func, polkit_hash_direct_equal_func,
NULL, NULL,
NULL, NULL)) != NULL) {
if (polkit_hash_insert (h, h, h)) {
g_assert ((polkit_hash_lookup (h, h, &found) == h) && found);
if (polkit_hash_insert (h, h, NULL)) {
......
......@@ -74,12 +74,27 @@ typedef polkit_bool_t (*PolKitEqualFunc) (const void *key1, const void *key2);
*
* Specifies the type of function which is called when a data element
* is destroyed. It is passed the pointer to the data element and
* should free any memory and resources allocated for it.
* should free any memory and resources allocated for it. The function
* p_free() or any of the object unref functions can be passed here.
*
* Since: 0.7
*/
typedef void (*PolKitFreeFunc) (void *p);
/**
* PolKitCopyFunc:
* @p: pointer
*
* Specifies the type of function which is called when a data element
* is to be cloned or reffed. It is passed the pointer to the data
* element and should return a new pointer to a reffed or cloned
* object. The function polkit_hash_str_copy() or any of the object
* ref functions can be passed here.
*
* Since: 0.7
*/
typedef void *(*PolKitCopyFunc) (const void *p);
/**
* PolKitHashForeachFunc:
* @hash: the hash table
......@@ -101,6 +116,8 @@ typedef polkit_bool_t (*PolKitHashForeachFunc) (PolKitHash *hash,
PolKitHash *polkit_hash_new (PolKitHashFunc hash_func,
PolKitEqualFunc key_equal_func,
PolKitCopyFunc key_copy_func,
PolKitCopyFunc value_copy_func,
PolKitFreeFunc key_destroy_func,
PolKitFreeFunc value_destroy_func);
......@@ -119,6 +136,7 @@ polkit_bool_t polkit_hash_direct_equal_func (const void *v1, const void *v2);
polkit_uint32_t polkit_hash_str_hash_func (const void *key);
polkit_bool_t polkit_hash_str_equal_func (const void *v1, const void *v2);
void *polkit_hash_str_copy (const void *p);
POLKIT_END_DECLS
......
......@@ -181,6 +181,38 @@ out:
return p;
}
/**
* p_strndup:
* @s: string
* @n: size
*
* Duplicate a string but copy at most @n characters. If @s is longer
* than @n, only @n characters are copied, and a terminating null byte
* is added. Similar to strndup(3).
*
* Returns: Allocated memory or #NULL on OOM. Free with p_free().
*
* Since: 0.7
*/
char *
p_strndup (const char *s, size_t n)
{
void *p;
size_t len;
len = strlen (s) + 1;
if (len > n)
len = n;
p = p_malloc (len + 1);
if (p == NULL)
goto out;
memcpy (p, s, len + 1);
out:
return p;
}
/*--------------------------------------------------------------------------------------------------------------*/
#else
/*--------------------------------------------------------------------------------------------------------------*/
......@@ -231,6 +263,12 @@ p_strdup (const char *s)
return strdup (s);
}
char *
p_strndup (const char *s, size_t n)
{
return strndup (s, n);
}
#endif /* POLKIT_BUILD_TESTS */
/**
......
......@@ -61,7 +61,8 @@ void p_free (void *memory);
*/
#define p_new0(type, count) ((type*)p_malloc0 (sizeof (type) * (count)));
char *p_strdup (const char *s);
char *p_strdup (const char *s);
char *p_strndup (const char *s, size_t n);
char* p_strdup_printf (const char *format, ...);
char* p_strdup_vprintf (const char *format, va_list args);
......
......@@ -386,8 +386,8 @@ _run_test (void)
if ((a = polkit_hash_new (polkit_hash_str_hash_func,
polkit_hash_str_equal_func,
NULL,
NULL)) == NULL)
NULL, NULL,
NULL, NULL)) == NULL)
goto oom;
if (!polkit_hash_insert (a, "a1", "v1"))
......
......@@ -46,6 +46,7 @@
#include "polkit-policy-file-entry.h"
#include "polkit-debug.h"
#include "polkit-private.h"
#include "polkit-test.h"
/**
* SECTION:polkit-policy-file
......@@ -96,13 +97,13 @@ typedef struct {
PolKitResult defaults_allow_any;
PolKitResult defaults_allow_inactive;
PolKitResult defaults_allow_active;
PolKitPolicyFile *pf;
polkit_bool_t load_descriptions;
GHashTable *policy_descriptions;
GHashTable *policy_messages;
PolKitHash *policy_descriptions;
PolKitHash *policy_messages;
char *policy_description_nolang;
char *policy_message_nolang;
......@@ -115,26 +116,28 @@ typedef struct {
char *annotate_key;
PolKitHash *annotations;
polkit_bool_t is_oom;
} ParserData;
static void
pd_unref_action_data (ParserData *pd)
{
g_free (pd->action_id);
p_free (pd->action_id);
pd->action_id = NULL;
g_free (pd->policy_description_nolang);
p_free (pd->policy_description_nolang);
pd->policy_description_nolang = NULL;
g_free (pd->policy_message_nolang);
p_free (pd->policy_message_nolang);
pd->policy_message_nolang = NULL;
if (pd->policy_descriptions != NULL) {
g_hash_table_destroy (pd->policy_descriptions);
polkit_hash_unref (pd->policy_descriptions);
pd->policy_descriptions = NULL;
}
if (pd->policy_messages != NULL) {
g_hash_table_destroy (pd->policy_messages);
polkit_hash_unref (pd->policy_messages);
pd->policy_messages = NULL;
}
g_free (pd->annotate_key);
p_free (pd->annotate_key);
pd->annotate_key = NULL;
if (pd->annotations != NULL) {
polkit_hash_unref (pd->annotations);
......@@ -170,9 +173,17 @@ _start (void *data, const char *el, const char **attr)
goto error;
pd_unref_action_data (pd);
pd->action_id = g_strdup (attr[1]);
pd->policy_descriptions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
pd->policy_messages = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
pd->action_id = p_strdup (attr[1]);
if (pd->action_id == NULL)
goto oom;
pd->policy_descriptions = polkit_hash_new (polkit_hash_str_hash_func,
polkit_hash_str_equal_func,
polkit_hash_str_copy, polkit_hash_str_copy,
p_free, p_free);
pd->policy_messages = polkit_hash_new (polkit_hash_str_hash_func,
polkit_hash_str_equal_func,
polkit_hash_str_copy, polkit_hash_str_copy,
p_free, p_free);
/* initialize defaults */
pd->defaults_allow_any = POLKIT_RESULT_NO;
......@@ -185,12 +196,16 @@ _start (void *data, const char *el, const char **attr)
state = STATE_IN_DEFAULTS;
} else if (strcmp (el, "description") == 0) {
if (num_attr == 2 && strcmp (attr[0], "xml:lang") == 0) {
pd->elem_lang = g_strdup (attr[1]);
pd->elem_lang = p_strdup (attr[1]);
if (pd->elem_lang == NULL)
goto oom;
}
state = STATE_IN_ACTION_DESCRIPTION;
} else if (strcmp (el, "message") == 0) {
if (num_attr == 2 && strcmp (attr[0], "xml:lang") == 0) {
pd->elem_lang = g_strdup (attr[1]);
pd->elem_lang = p_strdup (attr[1]);
if (pd->elem_lang == NULL)
goto oom;
}
state = STATE_IN_ACTION_MESSAGE;
} else if (strcmp (el, "annotate") == 0) {
......@@ -198,8 +213,10 @@ _start (void *data, const char *el, const char **attr)
goto error;
state = STATE_IN_ANNOTATE;
g_free (pd->annotate_key);
pd->annotate_key = g_strdup (attr[1]);
p_free (pd->annotate_key);
pd->annotate_key = p_strdup (attr[1]);
if (pd->annotate_key == NULL)
goto oom;
}
break;
case STATE_IN_ACTION_DESCRIPTION:
......@@ -238,6 +255,8 @@ _start (void *data, const char *el, const char **attr)
pd->state_stack[pd->stack_depth] = pd->state;
pd->stack_depth++;
return;
oom:
pd->is_oom = TRUE;
error:
XML_StopParser (pd->parser, FALSE);
}
......@@ -248,16 +267,21 @@ _cdata (void *data, const char *s, int len)
char *str;
ParserData *pd = data;
str = g_strndup (s, len);
str = p_strndup (s, len);
if (str == NULL)
goto oom;
switch (pd->state) {
case STATE_IN_ACTION_DESCRIPTION:
if (pd->load_descriptions) {
if (pd->elem_lang == NULL) {
g_free (pd->policy_description_nolang);
pd->policy_description_nolang = g_strdup (str);
p_free (pd->policy_description_nolang);
pd->policy_description_nolang = str;
str = NULL;
} else {
g_hash_table_insert (pd->policy_descriptions, g_strdup (pd->elem_lang), g_strdup (str));
if (!polkit_hash_insert (pd->policy_descriptions, pd->elem_lang, str))
goto oom;
}
}
break;
......@@ -265,10 +289,12 @@ _cdata (void *data, const char *s, int len)
case STATE_IN_ACTION_MESSAGE:
if (pd->load_descriptions) {
if (pd->elem_lang == NULL) {
g_free (pd->policy_message_nolang);
pd->policy_message_nolang = g_strdup (str);
p_free (pd->policy_message_nolang);
pd->policy_message_nolang = str;
str = NULL;
} else {
g_hash_table_insert (pd->policy_messages, g_strdup (pd->elem_lang), g_strdup (str));
if (!polkit_hash_insert (pd->policy_messages, pd->elem_lang, str))
goto oom;
}
}
break;
......@@ -290,19 +316,24 @@ _cdata (void *data, const char *s, int len)
if (pd->annotations == NULL) {
pd->annotations = polkit_hash_new (polkit_hash_str_hash_func,
polkit_hash_str_equal_func,
p_free,
p_free);
polkit_hash_str_copy, polkit_hash_str_copy,
p_free, p_free);
if (pd->annotations == NULL)
goto oom;
}
polkit_hash_insert (pd->annotations, p_strdup (pd->annotate_key), p_strdup (str));
if (!polkit_hash_insert (pd->annotations, pd->annotate_key, str))
goto oom;
break;
default:
break;
}
g_free (str);
p_free (str);
return;
oom:
pd->is_oom = TRUE;
error:
g_free (str);
p_free (str);
XML_StopParser (pd->parser, FALSE);
}
......@@ -318,10 +349,10 @@ error:
* Returns: the localized string to use
*/
static const char *
_localize (GHashTable *translations, const char *untranslated, const char *lang)
_localize (PolKitHash *translations, const char *untranslated, const char *lang)
{
const char *result;
char *lang2;
char lang2[256];
int n;
if (lang == NULL) {
......@@ -330,20 +361,19 @@ _localize (GHashTable *translations, const char *untranslated, const char *lang)
}
/* first see if we have the translation */
result = g_hash_table_lookup (translations, lang);
result = (const char *) polkit_hash_lookup (translations, (void *) lang, NULL);
if (result != NULL)
goto out;
/* we could have a translation for 'da' but lang=='da_DK'; cut off the last part and try again */
lang2 = g_strdup (lang);
strncpy (lang2, lang, sizeof (lang2));
for (n = 0; lang2[n] != '\0'; n++) {
if (lang2[n] == '_') {
lang2[n] = '\0';
break;
}
}
result = g_hash_table_lookup (translations, lang2);
g_free (lang2);
result = (const char *) polkit_hash_lookup (translations, (void *) lang2, NULL);
if (result != NULL)
goto out;
......@@ -358,7 +388,7 @@ _end (void *data, const char *el)
{
ParserData *pd = data;
g_free (pd->elem_lang);
p_free (pd->elem_lang);
pd->elem_lang = NULL;
switch (pd->state) {
......@@ -374,6 +404,8 @@ _end (void *data, const char *el)
pd->defaults_allow_inactive,
pd->defaults_allow_active,
pd->annotations);
if (pfe == NULL)
goto oom;
pd->annotations = NULL;
if (pfe == NULL)
......@@ -387,10 +419,12 @@ _end (void *data, const char *el)
policy_message = NULL;
}
if (pd->load_descriptions)
_polkit_policy_file_entry_set_descriptions (pfe,
policy_description,
policy_message);
if (pd->load_descriptions) {
if (!_polkit_policy_file_entry_set_descriptions (pfe,
policy_description,
policy_message))
goto oom;
}
pd->pf->entries = g_slist_prepend (pd->pf->entries, pfe);
break;
......@@ -410,6 +444,8 @@ _end (void *data, const char *el)
pd->state = STATE_NONE;
return;
oom:
pd->is_oom = 1;
error:
XML_StopParser (pd->parser, FALSE);
}
......@@ -438,6 +474,9 @@ polkit_policy_file_new (const char *path, polkit_bool_t load_descriptions, PolKi
pf = NULL;
/* clear parser data */
memset (&pd, 0, sizeof (ParserData));
if (!g_str_has_suffix (path, ".policy")) {
polkit_error_set_error (error,
POLKIT_ERROR_POLICY_FILE_INVALID,
......@@ -455,9 +494,6 @@ polkit_policy_file_new (const char *path, polkit_bool_t load_descriptions, PolKi
goto error;
}
/* clear parser data */
memset (&pd, 0, sizeof (ParserData));
pd.path = path;
pd.parser = XML_ParserCreate (NULL);
pd.stack_depth = 0;
......@@ -472,7 +508,10 @@ polkit_policy_file_new (const char *path, polkit_bool_t load_descriptions, PolKi
XML_SetElementHandler (pd.parser, _start, _end);
XML_SetCharacterDataHandler (pd.parser, _cdata);
pf = g_new0 (PolKitPolicyFile, 1);