This post presents a realistic GNodes unbalanced n-ary tree exemplar in C using Gnome glib-2.XXX.You can find more information on the API here.
I wanted to design a client/server node structuring system based on distance metric from a common point, so it made sense to explore unbalanced trees. I wasn't familiar with them nor GLib at the outset. This work took about 2 days of fidgeting.
Online examples are bare presentations of the basic function calls. Here is a completed application that does something. The code you need is here ntree-distance.c.
This one presents an n-tree made from 3D Euclidean distances to and from an arbitrary point (city) and structures them on bounded distance neighbourhood balls. Essentially, the closest cities are siblings, those beyond a minimum metric are children, and those beyond a second metric are grandchildren. One could extend the paradigm as far as one likes.
The data for these cities is randomly generated, cities are then fed into a for loop that sorts them. At the end of the code it uses the GLib g_tree_traverse and executes a simple printf function to display the data at each node.
In order to make children and grandchildren nodes at the start with no data entered, one can make notional child and grandchild nodes etc. to whatever depth is required. So in the code are a base, a middle, and a far (and a farthest I didn't include) GNode that are used to make a 4-depth tree structure before the data is available.
One important thing to note about GNodes is that there is a deep copy but no remove function. There is no direct way to remove a single child without destroying the rest under since the links are all pointers not a more complicated form of structure. There is an unlink so one can construct a different tree from items but that may not be helpful. Of course this means I have extra tree nodes at every level but I considered it as beneficial for my purpose because if in the future I removed other siblings I can maintain the tree skeleton as it were.
You will note in printouts the notional nodes appear as 0.0000 in the list for tree traversed so they are easy to pick out. As we append nodes at each level the notional tree elements are also 0 child so there is another way to ignore them.
Included in the gist github is a Makefile and the original notional GNode file from IBM that wasn't very helpful... like IBM...
I have included a copy of the old gnode.c code for examination, a glibtest.c from MIT I found if you need to sanity check your GLIB, a Makefile that will compile the ntree-distance.c and the glibtest.c if you need them but the main file is ntree-distance.c
I wanted to design a client/server node structuring system based on distance metric from a common point, so it made sense to explore unbalanced trees. I wasn't familiar with them nor GLib at the outset. This work took about 2 days of fidgeting.
Online examples are bare presentations of the basic function calls. Here is a completed application that does something. The code you need is here ntree-distance.c.
This one presents an n-tree made from 3D Euclidean distances to and from an arbitrary point (city) and structures them on bounded distance neighbourhood balls. Essentially, the closest cities are siblings, those beyond a minimum metric are children, and those beyond a second metric are grandchildren. One could extend the paradigm as far as one likes.
The data for these cities is randomly generated, cities are then fed into a for loop that sorts them. At the end of the code it uses the GLib g_tree_traverse and executes a simple printf function to display the data at each node.
In order to make children and grandchildren nodes at the start with no data entered, one can make notional child and grandchild nodes etc. to whatever depth is required. So in the code are a base, a middle, and a far (and a farthest I didn't include) GNode that are used to make a 4-depth tree structure before the data is available.
One important thing to note about GNodes is that there is a deep copy but no remove function. There is no direct way to remove a single child without destroying the rest under since the links are all pointers not a more complicated form of structure. There is an unlink so one can construct a different tree from items but that may not be helpful. Of course this means I have extra tree nodes at every level but I considered it as beneficial for my purpose because if in the future I removed other siblings I can maintain the tree skeleton as it were.
You will note in printouts the notional nodes appear as 0.0000 in the list for tree traversed so they are easy to pick out. As we append nodes at each level the notional tree elements are also 0 child so there is another way to ignore them.
Included in the gist github is a Makefile and the original notional GNode file from IBM that wasn't very helpful... like IBM...
I have included a copy of the old gnode.c code for examination, a glibtest.c from MIT I found if you need to sanity check your GLIB, a Makefile that will compile the ntree-distance.c and the glibtest.c if you need them but the main file is ntree-distance.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* GLIB - Library of useful routines for C programming | |
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald | |
* | |
* 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, write to the | |
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
* Boston, MA 02111-1307, USA. | |
*/ | |
/* | |
* Modified by the GLib Team and others 1997-2000. See the AUTHORS | |
* file for a list of people on the GLib Team. See the ChangeLog | |
* files for a list of changes. These files are distributed with | |
* GLib at ftp://ftp.gtk.org/pub/gtk/. | |
*/ | |
#include "config.h" | |
#undef GLIB_COMPILATION | |
#include <stdio.h> | |
#include <string.h> | |
#include <errno.h> | |
#include "glib.h" | |
#include "gstdio.h" | |
#include <stdlib.h> | |
#ifdef HAVE_UNISTD_H | |
#include <unistd.h> | |
#endif | |
#ifdef G_OS_WIN32 | |
#include <io.h> /* For read(), write() etc */ | |
#endif | |
#define GLIB_TEST_STRING "el dorado " | |
#define GLIB_TEST_STRING_5 "el do" | |
/* --- variables --- */ | |
static gint test_nums[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; | |
static gint more_nums[10] = { 8, 9, 7, 0, 3, 2, 5, 1, 4, 6}; | |
/* --- functions --- */ | |
static gint | |
my_list_compare_one (gconstpointer a, gconstpointer b) | |
{ | |
gint one = *((const gint*)a); | |
gint two = *((const gint*)b); | |
return one-two; | |
} | |
static gint | |
my_list_compare_two (gconstpointer a, gconstpointer b) | |
{ | |
gint one = *((const gint*)a); | |
gint two = *((const gint*)b); | |
return two-one; | |
} | |
/* static void | |
my_list_print (gpointer a, gpointer b) | |
{ | |
gint three = *((gint*)a); | |
g_print("%d", three); | |
}; */ | |
static void | |
glist_test (void) | |
{ | |
GList *list = NULL; | |
guint i; | |
for (i = 0; i < 10; i++) | |
list = g_list_append (list, &test_nums[i]); | |
list = g_list_reverse (list); | |
for (i = 0; i < 10; i++) | |
{ | |
GList *t = g_list_nth (list, i); | |
if (*((gint*) t->data) != (9 - i)) | |
g_error ("Regular insert failed"); | |
} | |
for (i = 0; i < 10; i++) | |
if (g_list_position (list, g_list_nth (list, i)) != i) | |
g_error ("g_list_position does not seem to be the inverse of g_list_nth\n"); | |
g_list_free (list); | |
list = NULL; | |
for (i = 0; i < 10; i++) | |
list = g_list_insert_sorted (list, &more_nums[i], my_list_compare_one); | |
/* | |
g_print("\n"); | |
g_list_foreach (list, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GList *t = g_list_nth (list, i); | |
if (*((gint*) t->data) != i) | |
g_error ("Sorted insert failed"); | |
} | |
g_list_free (list); | |
list = NULL; | |
for (i = 0; i < 10; i++) | |
list = g_list_insert_sorted (list, &more_nums[i], my_list_compare_two); | |
/* | |
g_print("\n"); | |
g_list_foreach (list, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GList *t = g_list_nth (list, i); | |
if (*((gint*) t->data) != (9 - i)) | |
g_error ("Sorted insert failed"); | |
} | |
g_list_free (list); | |
list = NULL; | |
for (i = 0; i < 10; i++) | |
list = g_list_prepend (list, &more_nums[i]); | |
list = g_list_sort (list, my_list_compare_two); | |
/* | |
g_print("\n"); | |
g_list_foreach (list, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GList *t = g_list_nth (list, i); | |
if (*((gint*) t->data) != (9 - i)) | |
g_error ("Merge sort failed"); | |
} | |
g_list_free (list); | |
} | |
static void | |
gslist_test (void) | |
{ | |
GSList *slist = NULL; | |
guint i; | |
for (i = 0; i < 10; i++) | |
slist = g_slist_append (slist, &test_nums[i]); | |
slist = g_slist_reverse (slist); | |
for (i = 0; i < 10; i++) | |
{ | |
GSList *st = g_slist_nth (slist, i); | |
if (*((gint*) st->data) != (9 - i)) | |
g_error ("failed"); | |
} | |
g_slist_free (slist); | |
slist = NULL; | |
for (i = 0; i < 10; i++) | |
slist = g_slist_insert_sorted (slist, &more_nums[i], my_list_compare_one); | |
/* | |
g_print("\n"); | |
g_slist_foreach (slist, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GSList *st = g_slist_nth (slist, i); | |
if (*((gint*) st->data) != i) | |
g_error ("Sorted insert failed"); | |
} | |
g_slist_free (slist); | |
slist = NULL; | |
for (i = 0; i < 10; i++) | |
slist = g_slist_insert_sorted (slist, &more_nums[i], my_list_compare_two); | |
/* | |
g_print("\n"); | |
g_slist_foreach (slist, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GSList *st = g_slist_nth (slist, i); | |
if (*((gint*) st->data) != (9 - i)) | |
g_error("Sorted insert failed"); | |
} | |
g_slist_free(slist); | |
slist = NULL; | |
for (i = 0; i < 10; i++) | |
slist = g_slist_prepend (slist, &more_nums[i]); | |
slist = g_slist_sort (slist, my_list_compare_two); | |
/* | |
g_print("\n"); | |
g_slist_foreach (slist, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GSList *st = g_slist_nth (slist, i); | |
if (*((gint*) st->data) != (9 - i)) | |
g_error("Sorted insert failed"); | |
} | |
g_slist_free(slist); | |
} | |
static gboolean | |
node_build_string (GNode *node, | |
gpointer data) | |
{ | |
gchar **p = data; | |
gchar *string; | |
gchar c[2] = "_"; | |
c[0] = ((gchar) ((long) (node->data))); | |
string = g_strconcat (*p ? *p : "", c, NULL); | |
g_free (*p); | |
*p = string; | |
return FALSE; | |
} | |
static void | |
gnode_test (void) | |
{ | |
#define C2P(c) ((gpointer) ((long) (c))) | |
#define P2C(p) ((gchar) ((long) (p))) | |
GNode *root; | |
GNode *node; | |
GNode *node_B; | |
GNode *node_F; | |
GNode *node_G; | |
GNode *node_J; | |
guint i; | |
gchar *tstring, *cstring; | |
root = g_node_new (C2P ('A')); | |
g_assert (g_node_depth (root) == 1 && g_node_max_height (root) == 1); | |
node_B = g_node_new (C2P ('B')); | |
g_node_append (root, node_B); | |
g_assert (root->children == node_B); | |
g_node_append_data (node_B, C2P ('E')); | |
g_node_prepend_data (node_B, C2P ('C')); | |
g_node_insert (node_B, 1, g_node_new (C2P ('D'))); | |
node_F = g_node_new (C2P ('F')); | |
g_node_append (root, node_F); | |
g_assert (root->children->next == node_F); | |
node_G = g_node_new (C2P ('G')); | |
g_node_append (node_F, node_G); | |
node_J = g_node_new (C2P ('J')); | |
g_node_prepend (node_G, node_J); | |
g_node_insert (node_G, 42, g_node_new (C2P ('K'))); | |
g_node_insert_data (node_G, 0, C2P ('H')); | |
g_node_insert (node_G, 1, g_node_new (C2P ('I'))); | |
g_assert (g_node_depth (root) == 1); | |
g_assert (g_node_max_height (root) == 4); | |
g_assert (g_node_depth (node_G->children->next) == 4); | |
g_assert (g_node_n_nodes (root, G_TRAVERSE_LEAFS) == 7); | |
g_assert (g_node_n_nodes (root, G_TRAVERSE_NON_LEAFS) == 4); | |
g_assert (g_node_n_nodes (root, G_TRAVERSE_ALL) == 11); | |
g_assert (g_node_max_height (node_F) == 3); | |
g_assert (g_node_n_children (node_G) == 4); | |
g_assert (g_node_find_child (root, G_TRAVERSE_ALL, C2P ('F')) == node_F); | |
g_assert (g_node_find (root, G_LEVEL_ORDER, G_TRAVERSE_NON_LEAFS, C2P ('I')) == NULL); | |
g_assert (g_node_find (root, G_IN_ORDER, G_TRAVERSE_LEAFS, C2P ('J')) == node_J); | |
for (i = 0; i < g_node_n_children (node_B); i++) | |
{ | |
node = g_node_nth_child (node_B, i); | |
g_assert (P2C (node->data) == ('C' + i)); | |
} | |
for (i = 0; i < g_node_n_children (node_G); i++) | |
g_assert (g_node_child_position (node_G, g_node_nth_child (node_G, i)) == i); | |
/* we have built: A | |
* / \ | |
* B F | |
* / | \ \ | |
* C D E G | |
* / /\ \ | |
* H I J K | |
* | |
* for in-order traversal, 'G' is considered to be the "left" | |
* child of 'F', which will cause 'F' to be the last node visited. | |
*/ | |
tstring = NULL; | |
g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "ABCDEFGHIJK"); | |
g_free (tstring); tstring = NULL; | |
g_node_traverse (root, G_POST_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "CDEBHIJKGFA"); | |
g_free (tstring); tstring = NULL; | |
g_node_traverse (root, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "CBDEAHGIJKF"); | |
g_free (tstring); tstring = NULL; | |
g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "ABFCDEGHIJK"); | |
g_free (tstring); tstring = NULL; | |
g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_LEAFS, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "CDEHIJK"); | |
g_free (tstring); tstring = NULL; | |
g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_NON_LEAFS, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "ABFG"); | |
g_free (tstring); tstring = NULL; | |
g_node_reverse_children (node_B); | |
g_node_reverse_children (node_G); | |
g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "ABFEDCGKJIH"); | |
g_free (tstring); tstring = NULL; | |
cstring = NULL; | |
node = g_node_copy (root); | |
g_assert (g_node_n_nodes (root, G_TRAVERSE_ALL) == g_node_n_nodes (node, G_TRAVERSE_ALL)); | |
g_assert (g_node_max_height (root) == g_node_max_height (node)); | |
g_node_traverse (root, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_node_traverse (node, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &cstring); | |
g_assert_cmpstr (tstring, ==, cstring); | |
g_free (tstring); tstring = NULL; | |
g_free (cstring); cstring = NULL; | |
g_node_destroy (node); | |
g_node_destroy (root); | |
/* allocation tests */ | |
root = g_node_new (NULL); | |
node = root; | |
for (i = 0; i < 2048; i++) | |
{ | |
g_node_append (node, g_node_new (NULL)); | |
if ((i%5) == 4) | |
node = node->children->next; | |
} | |
g_assert (g_node_max_height (root) > 100); | |
g_assert (g_node_n_nodes (root, G_TRAVERSE_ALL) == 1 + 2048); | |
g_node_destroy (root); | |
#undef C2P | |
#undef P2C | |
} | |
static gint | |
my_compare (gconstpointer a, | |
gconstpointer b) | |
{ | |
const char *cha = a; | |
const char *chb = b; | |
return *cha - *chb; | |
} | |
static gint | |
my_traverse (gpointer key, | |
gpointer value, | |
gpointer data) | |
{ | |
char *ch = key; | |
g_print ("%c ", *ch); | |
return FALSE; | |
} | |
static void | |
binary_tree_test (void) | |
{ | |
GTree *tree; | |
char chars[62]; | |
guint i, j; | |
tree = g_tree_new (my_compare); | |
i = 0; | |
for (j = 0; j < 10; j++, i++) | |
{ | |
chars[i] = '0' + j; | |
g_tree_insert (tree, &chars[i], &chars[i]); | |
} | |
for (j = 0; j < 26; j++, i++) | |
{ | |
chars[i] = 'A' + j; | |
g_tree_insert (tree, &chars[i], &chars[i]); | |
} | |
for (j = 0; j < 26; j++, i++) | |
{ | |
chars[i] = 'a' + j; | |
g_tree_insert (tree, &chars[i], &chars[i]); | |
} | |
g_assert_cmpint (g_tree_nnodes (tree), ==, 10 + 26 + 26); | |
g_assert_cmpint (g_tree_height (tree), ==, 6); | |
if (g_test_verbose()) | |
{ | |
g_print ("tree: "); | |
g_tree_foreach (tree, my_traverse, NULL); | |
g_print ("\n"); | |
} | |
for (i = 0; i < 10; i++) | |
g_tree_remove (tree, &chars[i]); | |
g_assert_cmpint (g_tree_nnodes (tree), ==, 26 + 26); | |
g_assert_cmpint (g_tree_height (tree), ==, 6); | |
if (g_test_verbose()) | |
{ | |
g_print ("tree: "); | |
g_tree_foreach (tree, my_traverse, NULL); | |
g_print ("\n"); | |
} | |
} | |
static gboolean | |
my_hash_callback_remove (gpointer key, | |
gpointer value, | |
gpointer user_data) | |
{ | |
int *d = value; | |
if ((*d) % 2) | |
return TRUE; | |
return FALSE; | |
} | |
static void | |
my_hash_callback_remove_test (gpointer key, | |
gpointer value, | |
gpointer user_data) | |
{ | |
int *d = value; | |
if ((*d) % 2) | |
g_print ("bad!\n"); | |
} | |
static void | |
my_hash_callback (gpointer key, | |
gpointer value, | |
gpointer user_data) | |
{ | |
int *d = value; | |
*d = 1; | |
} | |
static guint | |
my_hash (gconstpointer key) | |
{ | |
return (guint) *((const gint*) key); | |
} | |
static gboolean | |
my_hash_equal (gconstpointer a, | |
gconstpointer b) | |
{ | |
return *((const gint*) a) == *((const gint*) b); | |
} | |
static gboolean | |
find_first_that(gpointer key, | |
gpointer value, | |
gpointer user_data) | |
{ | |
gint *v = value; | |
gint *test = user_data; | |
return (*v == *test); | |
} | |
static void | |
test_g_mkdir_with_parents_1 (const gchar *base) | |
{ | |
char *p0 = g_build_filename (base, "fum", NULL); | |
char *p1 = g_build_filename (p0, "tem", NULL); | |
char *p2 = g_build_filename (p1, "zap", NULL); | |
FILE *f; | |
g_remove (p2); | |
g_remove (p1); | |
g_remove (p0); | |
if (g_file_test (p0, G_FILE_TEST_EXISTS)) | |
g_error ("failed, %s exists, cannot test g_mkdir_with_parents\n", p0); | |
if (g_file_test (p1, G_FILE_TEST_EXISTS)) | |
g_error ("failed, %s exists, cannot test g_mkdir_with_parents\n", p1); | |
if (g_file_test (p2, G_FILE_TEST_EXISTS)) | |
g_error ("failed, %s exists, cannot test g_mkdir_with_parents\n", p2); | |
if (g_mkdir_with_parents (p2, 0777) == -1) | |
g_error ("failed, g_mkdir_with_parents(%s) failed: %s\n", p2, g_strerror (errno)); | |
if (!g_file_test (p2, G_FILE_TEST_IS_DIR)) | |
g_error ("failed, g_mkdir_with_parents(%s) succeeded, but %s is not a directory\n", p2, p2); | |
if (!g_file_test (p1, G_FILE_TEST_IS_DIR)) | |
g_error ("failed, g_mkdir_with_parents(%s) succeeded, but %s is not a directory\n", p2, p1); | |
if (!g_file_test (p0, G_FILE_TEST_IS_DIR)) | |
g_error ("failed, g_mkdir_with_parents(%s) succeeded, but %s is not a directory\n", p2, p0); | |
g_rmdir (p2); | |
if (g_file_test (p2, G_FILE_TEST_EXISTS)) | |
g_error ("failed, did g_rmdir(%s), but %s is still there\n", p2, p2); | |
g_rmdir (p1); | |
if (g_file_test (p1, G_FILE_TEST_EXISTS)) | |
g_error ("failed, did g_rmdir(%s), but %s is still there\n", p1, p1); | |
f = g_fopen (p1, "w"); | |
if (f == NULL) | |
g_error ("failed, couldn't create file %s\n", p1); | |
fclose (f); | |
if (g_mkdir_with_parents (p1, 0666) == 0) | |
g_error ("failed, g_mkdir_with_parents(%s) succeeded, even if %s is a file\n", p1, p1); | |
if (g_mkdir_with_parents (p2, 0666) == 0) | |
g_error("failed, g_mkdir_with_parents(%s) succeeded, even if %s is a file\n", p2, p1); | |
g_remove (p2); | |
g_remove (p1); | |
g_remove (p0); | |
} | |
static void | |
test_g_mkdir_with_parents (void) | |
{ | |
gchar *cwd; | |
if (g_test_verbose()) | |
g_print ("checking g_mkdir_with_parents() in subdir ./hum/"); | |
test_g_mkdir_with_parents_1 ("hum"); | |
g_remove ("hum"); | |
if (g_test_verbose()) | |
g_print ("checking g_mkdir_with_parents() in subdir ./hii///haa/hee/"); | |
test_g_mkdir_with_parents_1 ("hii///haa/hee"); | |
g_remove ("hii/haa/hee"); | |
g_remove ("hii/haa"); | |
g_remove ("hii"); | |
cwd = g_get_current_dir (); | |
if (g_test_verbose()) | |
g_print ("checking g_mkdir_with_parents() in cwd: %s", cwd); | |
test_g_mkdir_with_parents_1 (cwd); | |
g_free (cwd); | |
} | |
static void | |
test_g_parse_debug_string (void) | |
{ | |
GDebugKey keys[3] = { | |
{ "foo", 1 }, | |
{ "bar", 2 }, | |
{ "baz", 4 } | |
}; | |
guint n_keys = 3; | |
guint result; | |
result = g_parse_debug_string ("bar:foo:blubb", keys, n_keys); | |
g_assert (result == 3); | |
result = g_parse_debug_string (":baz::_E@~!_::", keys, n_keys); | |
g_assert (result == 4); | |
result = g_parse_debug_string ("", keys, n_keys); | |
g_assert (result == 0); | |
result = g_parse_debug_string (" : ", keys, n_keys); | |
g_assert (result == 0); | |
} | |
static void | |
log_warning_error_tests (void) | |
{ | |
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)) | |
{ | |
g_message ("this is a g_message test."); | |
g_message ("non-printable UTF-8: \"\xc3\xa4\xda\x85\""); | |
g_message ("unsafe chars: \"\x10\x11\x12\n\t\x7f\x81\x82\x83\""); | |
exit (0); | |
} | |
g_test_trap_assert_passed(); | |
g_test_trap_assert_stderr ("*is a g_message test*"); | |
g_test_trap_assert_stderr ("*non-printable UTF-8*"); | |
g_test_trap_assert_stderr ("*unsafe chars*"); | |
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)) | |
{ | |
g_warning ("harmless warning with parameters: %d %s %#x", 42, "Boo", 12345); | |
exit (0); | |
} | |
g_test_trap_assert_failed(); /* we have fatal-warnings enabled */ | |
g_test_trap_assert_stderr ("*harmless warning*"); | |
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)) | |
{ | |
g_print (NULL); | |
exit (0); | |
} | |
g_test_trap_assert_failed(); /* we have fatal-warnings enabled */ | |
g_test_trap_assert_stderr ("*g_print*assertion*failed*"); | |
g_test_trap_assert_stderr ("*NULL*"); | |
} | |
static void | |
timer_tests (void) | |
{ | |
GTimer *timer, *timer2; | |
gdouble elapsed; | |
/* basic testing */ | |
timer = g_timer_new (); | |
g_timer_start (timer); | |
elapsed = g_timer_elapsed (timer, NULL); | |
g_timer_stop (timer); | |
g_assert_cmpfloat (elapsed, <=, g_timer_elapsed (timer, NULL)); | |
g_timer_destroy (timer); | |
if (g_test_slow()) | |
{ | |
if (g_test_verbose()) | |
g_print ("checking timers...\n"); | |
timer = g_timer_new (); | |
if (g_test_verbose()) | |
g_print (" spinning for 3 seconds...\n"); | |
g_timer_start (timer); | |
while (g_timer_elapsed (timer, NULL) < 3) | |
; | |
g_timer_stop (timer); | |
g_timer_destroy (timer); | |
if (g_test_verbose()) | |
g_print ("ok\n"); | |
} | |
if (g_test_slow()) | |
{ | |
gulong elapsed_usecs; | |
if (g_test_verbose()) | |
g_print ("checking g_timer_continue...\n"); | |
timer2 = g_timer_new (); | |
if (g_test_verbose()) | |
g_print ("\trun for 1 second...\n"); | |
timer = g_timer_new(); | |
g_usleep (G_USEC_PER_SEC); /* run timer for 1 second */ | |
g_timer_stop (timer); | |
if (g_test_verbose()) | |
g_print ("\tstop for 1 second...\n"); | |
g_usleep (G_USEC_PER_SEC); /* wait for 1 second */ | |
if (g_test_verbose()) | |
g_print ("\trun for 2 seconds...\n"); | |
g_timer_continue (timer); | |
g_usleep (2 * G_USEC_PER_SEC); /* run timer for 2 seconds */ | |
g_timer_stop(timer); | |
if (g_test_verbose()) | |
g_print ("\tstop for 1.5 seconds...\n"); | |
g_usleep ((3 * G_USEC_PER_SEC) / 2); /* wait for 1.5 seconds */ | |
if (g_test_verbose()) | |
g_print ("\trun for 0.2 seconds...\n"); | |
g_timer_continue (timer); | |
g_usleep (G_USEC_PER_SEC / 5); /* run timer for 0.2 seconds */ | |
g_timer_stop (timer); | |
if (g_test_verbose()) | |
g_print ("\tstop for 4 seconds...\n"); | |
g_usleep (4 * G_USEC_PER_SEC); /* wait for 4 seconds */ | |
if (g_test_verbose()) | |
g_print ("\trun for 5.8 seconds...\n"); | |
g_timer_continue (timer); | |
g_usleep ((29 * G_USEC_PER_SEC) / 5); /* run timer for 5.8 seconds */ | |
g_timer_stop(timer); | |
elapsed = g_timer_elapsed (timer, &elapsed_usecs); | |
if (g_test_verbose()) | |
g_print ("\t=> timer = %.6f = %d.%06ld (should be: 9.000000) (%.6f off)\n", elapsed, (int) elapsed, elapsed_usecs, ABS (elapsed - 9.)); | |
g_assert_cmpfloat (elapsed, >, 8.8); | |
g_assert_cmpfloat (elapsed, <, 9.2); | |
if (g_test_verbose()) | |
g_print ("g_timer_continue ... ok\n\n"); | |
g_timer_stop (timer2); | |
elapsed = g_timer_elapsed (timer2, &elapsed_usecs); | |
if (g_test_verbose()) | |
g_print ("\t=> timer2 = %.6f = %d.%06ld (should be: %.6f) (%.6f off)\n\n", elapsed, (int) elapsed, elapsed_usecs, 9.+6.5, ABS (elapsed - (9.+6.5))); | |
g_assert_cmpfloat (elapsed, >, 8.8 + 6.5); | |
g_assert_cmpfloat (elapsed, <, 9.2 + 6.5); | |
if (g_test_verbose()) | |
g_print ("timer2 ... ok\n\n"); | |
g_timer_destroy (timer); | |
g_timer_destroy (timer2); | |
} | |
} | |
static void | |
type_sizes (void) | |
{ | |
guint16 gu16t1 = 0x44afU, gu16t2 = 0xaf44U; | |
guint32 gu32t1 = 0x02a7f109U, gu32t2 = 0x09f1a702U; | |
guint64 gu64t1 = G_GINT64_CONSTANT(0x1d636b02300a7aa7U), | |
gu64t2 = G_GINT64_CONSTANT(0xa77a0a30026b631dU); | |
/* type sizes */ | |
g_assert_cmpint (sizeof (gint8), ==, 1); | |
g_assert_cmpint (sizeof (gint16), ==, 2); | |
g_assert_cmpint (sizeof (gint32), ==, 4); | |
g_assert_cmpint (sizeof (gint64), ==, 8); | |
/* endian macros */ | |
if (g_test_verbose()) | |
g_print ("checking endian macros (host is %s)...\n", | |
G_BYTE_ORDER == G_BIG_ENDIAN ? "big endian" : "little endian"); | |
g_assert (GUINT16_SWAP_LE_BE (gu16t1) == gu16t2); | |
g_assert (GUINT32_SWAP_LE_BE (gu32t1) == gu32t2); | |
g_assert (GUINT64_SWAP_LE_BE (gu64t1) == gu64t2); | |
} | |
static void | |
test_info (void) | |
{ | |
const gchar *un, *rn, *hn; | |
const gchar *tmpdir, *homedir, *userdatadir, *uconfdir, *ucachedir; | |
const gchar *uddesktop, *udddocs, *uddpubshare; | |
gchar **sv, *cwd, *sdatadirs, *sconfdirs, *langnames; | |
if (g_test_verbose()) | |
g_print ("TestGLib v%u.%u.%u (i:%u b:%u)\n", | |
glib_major_version, | |
glib_minor_version, | |
glib_micro_version, | |
glib_interface_age, | |
glib_binary_age); | |
cwd = g_get_current_dir (); | |
un = g_get_user_name(); | |
rn = g_get_real_name(); | |
hn = g_get_host_name(); | |
if (g_test_verbose()) | |
{ | |
g_print ("cwd: %s\n", cwd); | |
g_print ("user: %s\n", un); | |
g_print ("real: %s\n", rn); | |
g_print ("host: %s\n", hn); | |
} | |
g_free (cwd); | |
tmpdir = g_get_tmp_dir(); | |
g_assert (tmpdir != NULL); | |
homedir = g_get_home_dir (); | |
g_assert (homedir != NULL); | |
userdatadir = g_get_user_data_dir (); | |
g_assert (userdatadir != NULL); | |
uconfdir = g_get_user_config_dir (); | |
g_assert (uconfdir != NULL); | |
ucachedir = g_get_user_cache_dir (); | |
g_assert (ucachedir != NULL); | |
uddesktop = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP); | |
g_assert (uddesktop != NULL); | |
udddocs = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS); | |
uddpubshare = g_get_user_special_dir (G_USER_DIRECTORY_PUBLIC_SHARE); | |
sv = (gchar **) g_get_system_data_dirs (); | |
sdatadirs = g_strjoinv (G_SEARCHPATH_SEPARATOR_S, sv); | |
sv = (gchar **) g_get_system_config_dirs (); | |
sconfdirs = g_strjoinv (G_SEARCHPATH_SEPARATOR_S, sv); | |
sv = (gchar **) g_get_language_names (); | |
langnames = g_strjoinv (":", sv); | |
if (g_test_verbose()) | |
{ | |
g_print ("tmp-dir: %s\n", tmpdir); | |
g_print ("home: %s\n", homedir); | |
g_print ("user_data: %s\n", userdatadir); | |
g_print ("user_config: %s\n", uconfdir); | |
g_print ("user_cache: %s\n", ucachedir); | |
g_print ("system_data: %s\n", sdatadirs); | |
g_print ("system_config: %s\n", sconfdirs); | |
g_print ("languages: %s\n", langnames); | |
g_print ("user_special[DESKTOP]: %s\n", uddesktop); | |
g_print ("user_special[DOCUMENTS]: %s\n", udddocs); | |
g_print ("user_special[PUBLIC_SHARE]: %s\n", uddpubshare); | |
} | |
g_free (sdatadirs); | |
g_free (sconfdirs); | |
g_free (langnames); | |
if (g_test_verbose()) | |
{ | |
#ifdef G_PLATFORM_WIN32 | |
gchar *glib_dll; | |
#endif | |
const gchar *charset; | |
if (g_get_charset ((G_CONST_RETURN char**)&charset)) | |
g_print ("current charset is UTF-8: %s\n", charset); | |
else | |
g_print ("current charset is not UTF-8: %s\n", charset); | |
#ifdef G_PLATFORM_WIN32 | |
#ifdef G_OS_WIN32 | |
/* Can't calculate GLib DLL name at runtime. */ | |
glib_dll = "libglib-2.0-0.dll"; | |
#endif | |
#ifdef G_WITH_CYGWIN | |
glib_dll = "cygglib-2.0-0.dll"; | |
#endif | |
g_print ("current locale: %s\n", g_win32_getlocale ()); | |
g_print ("GLib DLL name tested for: %s\n", glib_dll); | |
g_print ("GLib installation directory, from Registry entry for %s if available: %s\n", | |
GETTEXT_PACKAGE, | |
g_win32_get_package_installation_directory (GETTEXT_PACKAGE, NULL)); | |
g_print ("Ditto, or from GLib DLL name: %s\n", | |
g_win32_get_package_installation_directory (GETTEXT_PACKAGE, glib_dll)); | |
g_print ("Ditto, only from GLib DLL name: %s\n", | |
g_win32_get_package_installation_directory (NULL, glib_dll)); | |
g_print ("locale subdirectory of GLib installation directory: %s\n", | |
g_win32_get_package_installation_subdirectory (NULL, glib_dll, "lib\\locale")); | |
g_print ("GTK+ 2.0 installation directory, if available: %s\n", | |
g_win32_get_package_installation_directory ("gtk20", NULL)); | |
g_print ("found more.com as %s\n", g_find_program_in_path ("more.com")); | |
g_print ("found regedit as %s\n", g_find_program_in_path ("regedit")); | |
g_print ("a Win32 error message: %s\n", g_win32_error_message (2)); | |
#endif | |
} | |
} | |
static void | |
test_paths (void) | |
{ | |
struct { | |
gchar *filename; | |
gchar *dirname; | |
} dirname_checks[] = { | |
{ "/", "/" }, | |
{ "////", "/" }, | |
{ ".////", "." }, | |
{ "../", ".." }, | |
{ "..////", ".." }, | |
{ "a/b", "a" }, | |
{ "a/b/", "a/b" }, | |
{ "c///", "c" }, | |
#ifdef G_OS_WIN32 | |
{ "\\", "\\" }, | |
{ ".\\\\\\\\", "." }, | |
{ "..\\", ".." }, | |
{ "..\\\\\\\\", ".." }, | |
{ "a\\b", "a" }, | |
{ "a\\b/", "a\\b" }, | |
{ "a/b\\", "a/b" }, | |
{ "c\\\\/", "c" }, | |
{ "//\\", "/" }, | |
#endif | |
#ifdef G_WITH_CYGWIN | |
{ "//server/share///x", "//server/share" }, | |
#endif | |
{ ".", "." }, | |
{ "..", "." }, | |
{ "", "." }, | |
}; | |
const guint n_dirname_checks = G_N_ELEMENTS (dirname_checks); | |
struct { | |
gchar *filename; | |
gchar *without_root; | |
} skip_root_checks[] = { | |
{ "/", "" }, | |
{ "//", "" }, | |
{ "/foo", "foo" }, | |
{ "//foo", "foo" }, | |
{ "a/b", NULL }, | |
#ifdef G_OS_WIN32 | |
{ "\\", "" }, | |
{ "\\foo", "foo" }, | |
{ "\\\\server\\foo", "" }, | |
{ "\\\\server\\foo\\bar", "bar" }, | |
{ "a\\b", NULL }, | |
#endif | |
#ifdef G_WITH_CYGWIN | |
{ "//server/share///x", "//x" }, | |
#endif | |
{ ".", NULL }, | |
{ "", NULL }, | |
}; | |
const guint n_skip_root_checks = G_N_ELEMENTS (skip_root_checks); | |
gchar *string; | |
guint i; | |
if (g_test_verbose()) | |
g_print ("checking g_path_get_basename()..."); | |
string = g_path_get_basename (G_DIR_SEPARATOR_S "foo" G_DIR_SEPARATOR_S "dir" G_DIR_SEPARATOR_S); | |
g_assert (strcmp (string, "dir") == 0); | |
g_free (string); | |
string = g_path_get_basename (G_DIR_SEPARATOR_S "foo" G_DIR_SEPARATOR_S "file"); | |
g_assert (strcmp (string, "file") == 0); | |
g_free (string); | |
if (g_test_verbose()) | |
g_print ("ok\n"); | |
#ifdef G_OS_WIN32 | |
string = g_path_get_basename ("/foo/dir/"); | |
g_assert (strcmp (string, "dir") == 0); | |
g_free (string); | |
string = g_path_get_basename ("/foo/file"); | |
g_assert (strcmp (string, "file") == 0); | |
g_free (string); | |
#endif | |
if (g_test_verbose()) | |
g_print ("checking g_path_get_dirname()..."); | |
for (i = 0; i < n_dirname_checks; i++) | |
{ | |
gchar *dirname = g_path_get_dirname (dirname_checks[i].filename); | |
if (strcmp (dirname, dirname_checks[i].dirname) != 0) | |
{ | |
g_error ("\nfailed for \"%s\"==\"%s\" (returned: \"%s\")\n", | |
dirname_checks[i].filename, | |
dirname_checks[i].dirname, | |
dirname); | |
} | |
g_free (dirname); | |
} | |
if (g_test_verbose()) | |
g_print ("ok\n"); | |
if (g_test_verbose()) | |
g_print ("checking g_path_skip_root()..."); | |
for (i = 0; i < n_skip_root_checks; i++) | |
{ | |
const gchar *skipped = g_path_skip_root (skip_root_checks[i].filename); | |
if ((skipped && !skip_root_checks[i].without_root) || | |
(!skipped && skip_root_checks[i].without_root) || | |
((skipped && skip_root_checks[i].without_root) && | |
strcmp (skipped, skip_root_checks[i].without_root))) | |
{ | |
g_error ("\nfailed for \"%s\"==\"%s\" (returned: \"%s\")\n", | |
skip_root_checks[i].filename, | |
(skip_root_checks[i].without_root ? | |
skip_root_checks[i].without_root : "<NULL>"), | |
(skipped ? skipped : "<NULL>")); | |
} | |
} | |
if (g_test_verbose()) | |
g_print ("ok\n"); | |
} | |
static void | |
test_file_functions (void) | |
{ | |
const char hello[] = "Hello, World"; | |
const int hellolen = sizeof (hello) - 1; | |
GError *error; | |
char template[32]; | |
char *name_used, chars[62]; | |
gint fd, n; | |
strcpy (template, "foobar"); | |
fd = g_mkstemp (template); | |
if (g_test_verbose() && fd != -1) | |
g_print ("g_mkstemp works even if template doesn't end in XXXXXX\n"); | |
close (fd); | |
strcpy (template, "fooXXXXXX"); | |
fd = g_mkstemp (template); | |
if (fd == -1) | |
g_error ("g_mkstemp didn't work for template %s\n", template); | |
n = write (fd, hello, hellolen); | |
if (n == -1) | |
g_error ("write() failed: %s\n", g_strerror (errno)); | |
else if (n != hellolen) | |
g_error ("write() should have written %d bytes, wrote %d\n", hellolen, n); | |
lseek (fd, 0, 0); | |
n = read (fd, chars, sizeof (chars)); | |
if (n == -1) | |
g_error ("read() failed: %s\n", g_strerror (errno)); | |
else if (n != hellolen) | |
g_error ("read() should have read %d bytes, got %d\n", hellolen, n); | |
chars[n] = 0; | |
if (strcmp (chars, hello) != 0) | |
g_error ("wrote '%s', but got '%s'\n", hello, chars); | |
close (fd); | |
remove (template); | |
error = NULL; | |
strcpy (template, "zap" G_DIR_SEPARATOR_S "barXXXXXX"); | |
fd = g_file_open_tmp (template, &name_used, &error); | |
if (g_test_verbose()) | |
{ | |
if (fd != -1) | |
g_print ("g_file_open_tmp works even if template contains '%s'\n", G_DIR_SEPARATOR_S); | |
else | |
g_print ("g_file_open_tmp correctly returns error: %s\n", error->message); | |
} | |
close (fd); | |
g_clear_error (&error); | |
#ifdef G_OS_WIN32 | |
strcpy (template, "zap/barXXXXXX"); | |
fd = g_file_open_tmp (template, &name_used, &error); | |
if (g_test_verbose()) | |
{ | |
if (fd != -1) | |
g_print ("g_file_open_tmp works even if template contains '/'\n"); | |
else | |
g_print ("g_file_open_tmp correctly returns error: %s\n", error->message); | |
} | |
close (fd); | |
g_clear_error (&error); | |
#endif | |
strcpy (template, "zapXXXXXX"); | |
fd = g_file_open_tmp (template, &name_used, &error); | |
if (fd == -1) | |
g_error ("g_file_open_tmp didn't work for template '%s': %s\n", template, error->message); | |
else if (g_test_verbose()) | |
g_print ("g_file_open_tmp for template '%s' used name '%s'\n", template, name_used); | |
close (fd); | |
g_clear_error (&error); | |
remove (name_used); | |
fd = g_file_open_tmp (NULL, &name_used, &error); | |
if (fd == -1) | |
g_error ("g_file_open_tmp didn't work for a NULL template: %s\n", error->message); | |
close (fd); | |
g_clear_error (&error); | |
remove (name_used); | |
} | |
static void | |
test_arrays (void) | |
{ | |
GByteArray *gbarray; | |
GPtrArray *gparray; | |
GArray *garray; | |
guint i; | |
gparray = g_ptr_array_new (); | |
for (i = 0; i < 10000; i++) | |
g_ptr_array_add (gparray, GINT_TO_POINTER (i)); | |
for (i = 0; i < 10000; i++) | |
if (g_ptr_array_index (gparray, i) != GINT_TO_POINTER (i)) | |
g_error ("array fails: %p ( %p )\n", g_ptr_array_index (gparray, i), GINT_TO_POINTER (i)); | |
g_ptr_array_free (gparray, TRUE); | |
gbarray = g_byte_array_new (); | |
for (i = 0; i < 10000; i++) | |
g_byte_array_append (gbarray, (guint8*) "abcd", 4); | |
for (i = 0; i < 10000; i++) | |
{ | |
g_assert (gbarray->data[4*i] == 'a'); | |
g_assert (gbarray->data[4*i+1] == 'b'); | |
g_assert (gbarray->data[4*i+2] == 'c'); | |
g_assert (gbarray->data[4*i+3] == 'd'); | |
} | |
g_byte_array_free (gbarray, TRUE); | |
garray = g_array_new (FALSE, FALSE, sizeof (gint)); | |
for (i = 0; i < 10000; i++) | |
g_array_append_val (garray, i); | |
for (i = 0; i < 10000; i++) | |
if (g_array_index (garray, gint, i) != i) | |
g_error ("failure: %d ( %d )\n", g_array_index (garray, gint, i), i); | |
g_array_free (garray, TRUE); | |
garray = g_array_new (FALSE, FALSE, sizeof (gint)); | |
for (i = 0; i < 100; i++) | |
g_array_prepend_val (garray, i); | |
for (i = 0; i < 100; i++) | |
if (g_array_index (garray, gint, i) != (100 - i - 1)) | |
g_error ("failure: %d ( %d )\n", g_array_index (garray, gint, i), 100 - i - 1); | |
g_array_free (garray, TRUE); | |
} | |
static void | |
hash_table_tests (void) | |
{ | |
GHashTable *hash_table; | |
int array[10000]; | |
gint *pvalue = NULL; | |
gint value = 120; | |
guint i; | |
hash_table = g_hash_table_new (my_hash, my_hash_equal); | |
for (i = 0; i < 10000; i++) | |
{ | |
array[i] = i; | |
g_hash_table_insert (hash_table, &array[i], &array[i]); | |
} | |
pvalue = g_hash_table_find (hash_table, find_first_that, &value); | |
if (*pvalue != value) | |
g_error ("g_hash_table_find failed"); | |
g_hash_table_foreach (hash_table, my_hash_callback, NULL); | |
for (i = 0; i < 10000; i++) | |
if (array[i] == 0) | |
g_error ("hashtable-test: wrong value: %d\n", i); | |
for (i = 0; i < 10000; i++) | |
g_hash_table_remove (hash_table, &array[i]); | |
for (i = 0; i < 10000; i++) | |
{ | |
array[i] = i; | |
g_hash_table_insert (hash_table, &array[i], &array[i]); | |
} | |
if (g_hash_table_foreach_remove (hash_table, my_hash_callback_remove, NULL) != 5000 || | |
g_hash_table_size (hash_table) != 5000) | |
g_error ("hashtable removal failed\n"); | |
g_hash_table_foreach (hash_table, my_hash_callback_remove_test, NULL); | |
g_hash_table_destroy (hash_table); | |
} | |
static void | |
relation_test (void) | |
{ | |
GRelation *relation = g_relation_new (2); | |
GTuples *tuples; | |
gint data [1024]; | |
guint i; | |
g_relation_index (relation, 0, g_int_hash, g_int_equal); | |
g_relation_index (relation, 1, g_int_hash, g_int_equal); | |
for (i = 0; i < 1024; i += 1) | |
data[i] = i; | |
for (i = 1; i < 1023; i += 1) | |
{ | |
g_relation_insert (relation, data + i, data + i + 1); | |
g_relation_insert (relation, data + i, data + i - 1); | |
} | |
for (i = 2; i < 1022; i += 1) | |
{ | |
g_assert (! g_relation_exists (relation, data + i, data + i)); | |
g_assert (! g_relation_exists (relation, data + i, data + i + 2)); | |
g_assert (! g_relation_exists (relation, data + i, data + i - 2)); | |
} | |
for (i = 1; i < 1023; i += 1) | |
{ | |
g_assert (g_relation_exists (relation, data + i, data + i + 1)); | |
g_assert (g_relation_exists (relation, data + i, data + i - 1)); | |
} | |
for (i = 2; i < 1022; i += 1) | |
{ | |
g_assert (g_relation_count (relation, data + i, 0) == 2); | |
g_assert (g_relation_count (relation, data + i, 1) == 2); | |
} | |
g_assert (g_relation_count (relation, data, 0) == 0); | |
g_assert (g_relation_count (relation, data + 42, 0) == 2); | |
g_assert (g_relation_count (relation, data + 43, 1) == 2); | |
g_assert (g_relation_count (relation, data + 41, 1) == 2); | |
g_relation_delete (relation, data + 42, 0); | |
g_assert (g_relation_count (relation, data + 42, 0) == 0); | |
g_assert (g_relation_count (relation, data + 43, 1) == 1); | |
g_assert (g_relation_count (relation, data + 41, 1) == 1); | |
tuples = g_relation_select (relation, data + 200, 0); | |
g_assert (tuples->len == 2); | |
#if 0 | |
for (i = 0; i < tuples->len; i += 1) | |
{ | |
printf ("%d %d\n", | |
*(gint*) g_tuples_index (tuples, i, 0), | |
*(gint*) g_tuples_index (tuples, i, 1)); | |
} | |
#endif | |
g_assert (g_relation_exists (relation, data + 300, data + 301)); | |
g_relation_delete (relation, data + 300, 0); | |
g_assert (!g_relation_exists (relation, data + 300, data + 301)); | |
g_tuples_destroy (tuples); | |
g_relation_destroy (relation); | |
relation = NULL; | |
} | |
static void | |
gstring_tests (void) | |
{ | |
GString *string1, *string2; | |
guint i; | |
if (g_test_verbose()) | |
g_print ("test GString basics\n"); | |
string1 = g_string_new ("hi pete!"); | |
string2 = g_string_new (""); | |
g_assert (strcmp ("hi pete!", string1->str) == 0); | |
for (i = 0; i < 10000; i++) | |
g_string_append_c (string1, 'a'+(i%26)); | |
#ifndef G_OS_WIN32 | |
/* MSVC, mingw32 and LCC use the same run-time C library, which doesn't like | |
the %10000.10000f format... */ | |
g_string_printf (string2, "%s|%0100d|%s|%s|%0*d|%*.*f|%10000.10000f", | |
"this pete guy sure is a wuss, like he's the number ", | |
1, | |
" wuss. everyone agrees.\n", | |
string1->str, | |
10, 666, 15, 15, 666.666666666, 666.666666666); | |
#else | |
g_string_printf (string2, "%s|%0100d|%s|%s|%0*d|%*.*f|%100.100f", | |
"this pete guy sure is a wuss, like he's the number ", | |
1, | |
" wuss. everyone agrees.\n", | |
string1->str, | |
10, 666, 15, 15, 666.666666666, 666.666666666); | |
#endif | |
if (g_test_verbose()) | |
g_print ("string2 length = %lu...\n", (gulong)string2->len); | |
string2->str[70] = '\0'; | |
if (g_test_verbose()) | |
g_print ("first 70 chars:\n%s\n", string2->str); | |
string2->str[141] = '\0'; | |
if (g_test_verbose()) | |
g_print ("next 70 chars:\n%s\n", string2->str+71); | |
string2->str[212] = '\0'; | |
if (g_test_verbose()) | |
g_print ("and next 70:\n%s\n", string2->str+142); | |
if (g_test_verbose()) | |
g_print ("last 70 chars:\n%s\n", string2->str+string2->len - 70); | |
g_string_free (string1, TRUE); | |
g_string_free (string2, TRUE); | |
/* append */ | |
string1 = g_string_new ("firsthalf"); | |
g_string_append (string1, "lasthalf"); | |
g_assert (strcmp (string1->str, "firsthalflasthalf") == 0); | |
g_string_free (string1, TRUE); | |
/* append_len */ | |
string1 = g_string_new ("firsthalf"); | |
g_string_append_len (string1, "lasthalfjunkjunk", strlen ("lasthalf")); | |
g_assert (strcmp (string1->str, "firsthalflasthalf") == 0); | |
g_string_free (string1, TRUE); | |
/* prepend */ | |
string1 = g_string_new ("lasthalf"); | |
g_string_prepend (string1, "firsthalf"); | |
g_assert (strcmp (string1->str, "firsthalflasthalf") == 0); | |
g_string_free (string1, TRUE); | |
/* prepend_len */ | |
string1 = g_string_new ("lasthalf"); | |
g_string_prepend_len (string1, "firsthalfjunkjunk", strlen ("firsthalf")); | |
g_assert (strcmp (string1->str, "firsthalflasthalf") == 0); | |
g_string_free (string1, TRUE); | |
/* insert */ | |
string1 = g_string_new ("firstlast"); | |
g_string_insert (string1, 5, "middle"); | |
g_assert (strcmp (string1->str, "firstmiddlelast") == 0); | |
g_string_free (string1, TRUE); | |
/* insert with pos == end of the string */ | |
string1 = g_string_new ("firstmiddle"); | |
g_string_insert (string1, strlen ("firstmiddle"), "last"); | |
g_assert (strcmp (string1->str, "firstmiddlelast") == 0); | |
g_string_free (string1, TRUE); | |
/* insert_len */ | |
string1 = g_string_new ("firstlast"); | |
g_string_insert_len (string1, 5, "middlejunkjunk", strlen ("middle")); | |
g_assert (strcmp (string1->str, "firstmiddlelast") == 0); | |
g_string_free (string1, TRUE); | |
/* insert_len with magic -1 pos for append */ | |
string1 = g_string_new ("first"); | |
g_string_insert_len (string1, -1, "lastjunkjunk", strlen ("last")); | |
g_assert (strcmp (string1->str, "firstlast") == 0); | |
g_string_free (string1, TRUE); | |
/* insert_len with magic -1 len for strlen-the-string */ | |
string1 = g_string_new ("first"); | |
g_string_insert_len (string1, 5, "last", -1); | |
g_assert (strcmp (string1->str, "firstlast") == 0); | |
g_string_free (string1, TRUE); | |
/* g_string_equal */ | |
string1 = g_string_new ("test"); | |
string2 = g_string_new ("te"); | |
g_assert (! g_string_equal(string1, string2)); | |
g_string_append (string2, "st"); | |
g_assert (g_string_equal(string1, string2)); | |
g_string_free (string1, TRUE); | |
g_string_free (string2, TRUE); | |
/* Check handling of embedded ASCII 0 (NUL) characters in GString. */ | |
if (g_test_verbose()) | |
g_print ("test embedded ASCII 0 (NUL) characters in GString\n"); | |
string1 = g_string_new ("fiddle"); | |
string2 = g_string_new ("fiddle"); | |
g_assert (g_string_equal(string1, string2)); | |
g_string_append_c(string1, '\0'); | |
g_assert (! g_string_equal(string1, string2)); | |
g_string_append_c(string2, '\0'); | |
g_assert (g_string_equal(string1, string2)); | |
g_string_append_c(string1, 'x'); | |
g_string_append_c(string2, 'y'); | |
g_assert (! g_string_equal(string1, string2)); | |
g_assert (string1->len == 8); | |
g_string_append(string1, "yzzy"); | |
g_assert (string1->len == 12); | |
g_assert ( memcmp(string1->str, "fiddle\0xyzzy", 13) == 0); | |
g_string_insert(string1, 1, "QED"); | |
g_assert ( memcmp(string1->str, "fQEDiddle\0xyzzy", 16) == 0); | |
g_string_free (string1, TRUE); | |
g_string_free (string2, TRUE); | |
} | |
static void | |
various_string_tests (void) | |
{ | |
GStringChunk *string_chunk; | |
GTimeVal ref_date, date; | |
gchar *tmp_string = NULL, *tmp_string_2, *string, *date_str; | |
guint i; | |
if (g_test_verbose()) | |
g_print ("checking string chunks..."); | |
string_chunk = g_string_chunk_new (1024); | |
for (i = 0; i < 100000; i ++) | |
{ | |
tmp_string = g_string_chunk_insert (string_chunk, "hi pete"); | |
if (strcmp ("hi pete", tmp_string) != 0) | |
g_error ("string chunks are broken.\n"); | |
} | |
tmp_string_2 = g_string_chunk_insert_const (string_chunk, tmp_string); | |
g_assert (tmp_string_2 != tmp_string && strcmp (tmp_string_2, tmp_string) == 0); | |
tmp_string = g_string_chunk_insert_const (string_chunk, tmp_string); | |
g_assert (tmp_string_2 == tmp_string); | |
g_string_chunk_free (string_chunk); | |
if (g_test_verbose()) | |
g_print ("test positional printf formats (not supported):"); | |
string = g_strdup_printf ("%.*s%s", 5, "a", "b"); | |
tmp_string = g_strdup_printf ("%2$*1$s", 5, "c"); | |
if (g_test_verbose()) | |
g_print ("%s%s\n", string, tmp_string); | |
g_free (tmp_string); | |
g_free (string); | |
#define REF_INVALID "Wed Dec 19 17:20:20 GMT 2007" | |
#define REF_SEC_UTC 320063760 | |
#define REF_STR_UTC "1980-02-22T10:36:00Z" | |
#define REF_STR_CEST "1980-02-22T12:36:00+02:00" | |
#define REF_STR_EST "1980-02-22T05:36:00-05:00" | |
if (g_test_verbose()) | |
g_print ("checking g_time_val_from_iso8601...\n"); | |
ref_date.tv_sec = REF_SEC_UTC; | |
ref_date.tv_usec = 0; | |
g_assert (g_time_val_from_iso8601 (REF_INVALID, &date) == FALSE); | |
g_assert (g_time_val_from_iso8601 (REF_STR_UTC, &date) != FALSE); | |
if (g_test_verbose()) | |
g_print ("\t=> UTC stamp = %ld (should be: %ld) (%ld off)\n", date.tv_sec, ref_date.tv_sec, date.tv_sec - ref_date.tv_sec); | |
g_assert (date.tv_sec == ref_date.tv_sec); | |
g_assert (g_time_val_from_iso8601 (REF_STR_CEST, &date) != FALSE); | |
if (g_test_verbose()) | |
g_print ("\t=> CEST stamp = %ld (should be: %ld) (%ld off)\n", date.tv_sec, ref_date.tv_sec, date.tv_sec - ref_date.tv_sec); | |
g_assert (date.tv_sec == ref_date.tv_sec); | |
g_assert (g_time_val_from_iso8601 (REF_STR_EST, &date) != FALSE); | |
if (g_test_verbose()) | |
g_print ("\t=> EST stamp = %ld (should be: %ld) (%ld off)\n", date.tv_sec, ref_date.tv_sec, date.tv_sec - ref_date.tv_sec); | |
g_assert (date.tv_sec == ref_date.tv_sec); | |
if (g_test_verbose()) | |
g_print ("checking g_time_val_to_iso8601...\n"); | |
ref_date.tv_sec = REF_SEC_UTC; | |
ref_date.tv_usec = 1; | |
date_str = g_time_val_to_iso8601 (&ref_date); | |
g_assert (date_str != NULL); | |
if (g_test_verbose()) | |
g_print ("\t=> date string = %s (should be: %s)\n", date_str, REF_STR_UTC); | |
g_assert (strcmp (date_str, REF_STR_UTC) == 0); | |
g_free (date_str); | |
if (g_test_verbose()) | |
g_print ("checking g_ascii_strcasecmp..."); | |
g_assert (g_ascii_strcasecmp ("FroboZZ", "frobozz") == 0); | |
g_assert (g_ascii_strcasecmp ("frobozz", "frobozz") == 0); | |
g_assert (g_ascii_strcasecmp ("frobozz", "FROBOZZ") == 0); | |
g_assert (g_ascii_strcasecmp ("FROBOZZ", "froboz") > 0); | |
g_assert (g_ascii_strcasecmp ("", "") == 0); | |
g_assert (g_ascii_strcasecmp ("!#%&/()", "!#%&/()") == 0); | |
g_assert (g_ascii_strcasecmp ("a", "b") < 0); | |
g_assert (g_ascii_strcasecmp ("a", "B") < 0); | |
g_assert (g_ascii_strcasecmp ("A", "b") < 0); | |
g_assert (g_ascii_strcasecmp ("A", "B") < 0); | |
g_assert (g_ascii_strcasecmp ("b", "a") > 0); | |
g_assert (g_ascii_strcasecmp ("b", "A") > 0); | |
g_assert (g_ascii_strcasecmp ("B", "a") > 0); | |
g_assert (g_ascii_strcasecmp ("B", "A") > 0); | |
if (g_test_verbose()) | |
g_print ("checking g_strdup...\n"); | |
g_assert (g_strdup (NULL) == NULL); | |
string = g_strdup (GLIB_TEST_STRING); | |
g_assert (string != NULL); | |
g_assert (strcmp(string, GLIB_TEST_STRING) == 0); | |
g_free (string); | |
if (g_test_verbose()) | |
g_print ("checking g_strconcat...\n"); | |
string = g_strconcat (GLIB_TEST_STRING, NULL); | |
g_assert (string != NULL); | |
g_assert (strcmp (string, GLIB_TEST_STRING) == 0); | |
g_free (string); | |
string = g_strconcat (GLIB_TEST_STRING, GLIB_TEST_STRING, | |
GLIB_TEST_STRING, NULL); | |
g_assert (string != NULL); | |
g_assert (strcmp (string, GLIB_TEST_STRING GLIB_TEST_STRING | |
GLIB_TEST_STRING) == 0); | |
g_free (string); | |
if (g_test_verbose()) | |
g_print ("checking g_strlcpy/g_strlcat..."); | |
/* The following is a torture test for strlcpy/strlcat, with lots of | |
* checking; normal users wouldn't use them this way! | |
*/ | |
string = g_malloc (6); | |
*(string + 5) = 'Z'; /* guard value, shouldn't change during test */ | |
*string = 'q'; | |
g_assert (g_strlcpy(string, "" , 5) == 0); | |
g_assert ( *string == '\0' ); | |
*string = 'q'; | |
g_assert (g_strlcpy(string, "abc" , 5) == 3); | |
g_assert ( *(string + 3) == '\0' ); | |
g_assert (g_str_equal(string, "abc")); | |
g_assert (g_strlcpy(string, "abcd" , 5) == 4); | |
g_assert ( *(string + 4) == '\0' ); | |
g_assert ( *(string + 5) == 'Z' ); | |
g_assert (g_str_equal(string, "abcd")); | |
g_assert (g_strlcpy(string, "abcde" , 5) == 5); | |
g_assert ( *(string + 4) == '\0' ); | |
g_assert ( *(string + 5) == 'Z' ); | |
g_assert (g_str_equal(string, "abcd")); | |
g_assert (g_strlcpy(string, "abcdef" , 5) == 6); | |
g_assert ( *(string + 4) == '\0' ); | |
g_assert ( *(string + 5) == 'Z' ); | |
g_assert (g_str_equal(string, "abcd")); | |
*string = 'Y'; | |
*(string + 1)= '\0'; | |
g_assert (g_strlcpy(string, "Hello" , 0) == 5); | |
g_assert (*string == 'Y'); | |
*string = '\0'; | |
g_assert (g_strlcat(string, "123" , 5) == 3); | |
g_assert ( *(string + 3) == '\0' ); | |
g_assert (g_str_equal(string, "123")); | |
g_assert (g_strlcat(string, "" , 5) == 3); | |
g_assert ( *(string + 3) == '\0' ); | |
g_assert (g_str_equal(string, "123")); | |
g_assert (g_strlcat(string, "4", 5) == 4); | |
g_assert (g_str_equal(string, "1234")); | |
g_assert (g_strlcat(string, "5", 5) == 5); | |
g_assert ( *(string + 4) == '\0' ); | |
g_assert (g_str_equal(string, "1234")); | |
g_assert ( *(string + 5) == 'Z' ); | |
*string = 'Y'; | |
*(string + 1)= '\0'; | |
g_assert (g_strlcat(string, "123" , 0) == 3); | |
g_assert (*string == 'Y'); | |
/* A few more tests, demonstrating more "normal" use */ | |
g_assert (g_strlcpy(string, "hi", 5) == 2); | |
g_assert (g_str_equal(string, "hi")); | |
g_assert (g_strlcat(string, "t", 5) == 3); | |
g_assert (g_str_equal(string, "hit")); | |
g_free(string); | |
if (g_test_verbose()) | |
g_print ("checking g_strdup_printf...\n"); | |
string = g_strdup_printf ("%05d %-5s", 21, "test"); | |
g_assert (string != NULL); | |
g_assert (strcmp(string, "00021 test ") == 0); | |
g_free (string); | |
/* g_debug (argv[0]); */ | |
} | |
static void | |
test_mem_chunks (void) | |
{ | |
GMemChunk *mem_chunk = g_mem_chunk_new ("test mem chunk", 50, 100, G_ALLOC_AND_FREE); | |
gchar *mem[10000]; | |
guint i; | |
for (i = 0; i < 10000; i++) | |
{ | |
guint j; | |
mem[i] = g_chunk_new (gchar, mem_chunk); | |
for (j = 0; j < 50; j++) | |
mem[i][j] = i * j; | |
} | |
for (i = 0; i < 10000; i++) | |
g_mem_chunk_free (mem_chunk, mem[i]); | |
} | |
int | |
main (int argc, | |
char *argv[]) | |
{ | |
g_test_init (&argc, &argv, NULL); | |
g_test_add_func ("/testglib/Infos", test_info); | |
g_test_add_func ("/testglib/Types Sizes", type_sizes); | |
g_test_add_func ("/testglib/GStrings", gstring_tests); | |
g_test_add_func ("/testglib/Various Strings", various_string_tests); | |
g_test_add_func ("/testglib/GList", glist_test); | |
g_test_add_func ("/testglib/GSList", gslist_test); | |
g_test_add_func ("/testglib/GNode", gnode_test); | |
g_test_add_func ("/testglib/GTree", binary_tree_test); | |
g_test_add_func ("/testglib/Arrays", test_arrays); | |
g_test_add_func ("/testglib/GHashTable", hash_table_tests); | |
g_test_add_func ("/testglib/Relation", relation_test); | |
g_test_add_func ("/testglib/File Paths", test_paths); | |
g_test_add_func ("/testglib/File Functions", test_file_functions); | |
g_test_add_func ("/testglib/Mkdir", test_g_mkdir_with_parents); | |
g_test_add_func ("/testglib/Parse Debug Strings", test_g_parse_debug_string); | |
g_test_add_func ("/testglib/GMemChunk (deprecated)", test_mem_chunks); | |
g_test_add_func ("/testglib/Warnings & Errors", log_warning_error_tests); | |
g_test_add_func ("/testglib/Timers (slow)", timer_tests); | |
return g_test_run(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CC = gcc | |
CFLAGS = -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/lib64/glib-2.0/include/ -I/usr/include/glib-2.0 | |
LIBS = -lglib-2.0 -lc -lm | |
OBJ1 = ntree-distance.c | |
DEPS1 = | |
OBJ2 = testglib.c | |
DEPS2 = | |
ntree: $(OBJ1) | |
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) | |
test: $(OBJ2) | |
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) | |
clean: | |
rm -f *.o | |
rm -fr *~ | |
rm -f ntree test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//ex-gtree-6.c | |
#include <glib.h> | |
#include <math.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
/* | |
* This simple version expands the city example to make a tree based on distances from each other | |
* | |
* Basic process; | |
* | |
* 1. Cities are created and stored to an array | |
* 2. Home city is declared | |
* 3. Cities are taken from the list and placed into a n-ary tree | |
* based on distance from home city | |
* | |
* 4. Once established, one can find all near nodes and | |
* define nodes based on distance versus level. | |
* | |
* Level tree position is based on bounded distance rings | |
* like | |
* [0,10] | |
* (10,100] | |
* (100, 1000] | |
* of arbitrary distances that define a ball of interest | |
* | |
* | |
* */ | |
#define SMALLDISTANCE 200 | |
#define MIDDISTANCE 600 | |
#define NUM 30 | |
// basic position | |
typedef struct point32 | |
{ | |
float x, y, z; | |
}point32_t; | |
// encapsulates distance from current node | |
typedef struct nodedist | |
{ | |
point32_t coords; | |
float dist; | |
}nodedist_t; | |
typedef struct city | |
{ | |
nodedist_t own; | |
unsigned int id; | |
char name[100]; | |
}city_t; | |
// Create a databased element city | |
city_t * CreateCity( const char * cit, float ax, float ay, float az, int ID ) | |
{ | |
city_t * ret; | |
ret = ( city_t *) malloc ( sizeof(city_t )); | |
strcpy( ret->name, cit ); | |
ret->own.coords.x = ax; | |
ret->own.coords.y = ay; | |
ret->own.coords.z = az; | |
ret->id = ID; | |
ret->own.dist = 0.0; | |
return ret; | |
} | |
int PrintCity( city_t * in) | |
{ | |
printf("(%s)<%d>[%f,%f,%f] dist=%f \n", in->name, in->id, in->own.coords.x, in->own.coords.y, in->own.coords.z, in->own.dist); | |
return 0; | |
} | |
float EstimateCityDistance( nodedist_t a, nodedist_t b ) | |
{ | |
return ( sqrtf( (a.coords.x - b.coords.x)*(a.coords.x - b.coords.x) + (a.coords.y - b.coords.y)*(a.coords.y - b.coords.y) + (a.coords.z - b.coords.z)*(a.coords.z - b.coords.z))); | |
} | |
// compute distance from a city to b ans store in b | |
int ComputeDistance (city_t *a, city_t * b ) | |
{ | |
b->own.dist = EstimateCityDistance( a->own, b->own ); | |
return 0; | |
} | |
// returns Euclidean distance from | |
float EstimateDistance( float ax, float ay, float az, float bx, float by, float bz ) | |
{ | |
return ( sqrtf( (ax - bx)*(ax - bx) + (ay - by)*(ay - by) + (az - bz)*(az - bz) )); | |
} | |
gboolean GNodeIterateFloatPrint(GNode* n, gpointer data) | |
{ | |
float * convert = (float *) n->data; | |
printf("%f\n", *convert); | |
return FALSE; | |
} | |
gboolean GNodeIterateStringPrint(GNode* n, gpointer data) | |
{ | |
printf("%s", (char*) n->data); | |
return FALSE; | |
} | |
int main(int argc, char** argv) | |
{ | |
int number = NUM; | |
int i; | |
city_t ** list; | |
GNode ** tree_array; | |
int origin = 0; | |
int lower = SMALLDISTANCE; | |
int mid = MIDDISTANCE; | |
int byond = MIDDISTANCE+ SMALLDISTANCE; | |
// the home version | |
city_t *home; | |
GNode *middle = g_node_new((gpointer)(&lower)); | |
GNode *far = g_node_new((gpointer)(&mid)); | |
GNode *farthest = g_node_new((gpointer)(&byond)); | |
tree_array = (GNode **) malloc( NUM* sizeof( GNode * )); | |
list = ( city_t ** ) malloc (number * sizeof(city_t *)); | |
float f; | |
float g; | |
float h; | |
for (i = 0; i < number; i++) | |
{ | |
// randomize x y z - these are empirically tested to produce | |
// distance metrics around 500 | |
f = (rand()%500); | |
g = rand()%1000; | |
h = rand()%1000*rand()%2; | |
list[i] = CreateCity( "City\0", f , g , h , i ); | |
} | |
for (i = 0; i < number; i++) | |
{ | |
PrintCity( list[i] ); | |
} | |
home = list[5]; | |
for (i = 0; i < number; i++) | |
{ | |
ComputeDistance (home , list[i] ); | |
} | |
for (i = 0; i < number; i++) | |
{ | |
PrintCity( list[i] ); | |
} | |
// add node as home | |
float *z = &list[5]->own.dist; | |
GNode* base = g_node_new((gpointer)(&z)); | |
printf("base node data %f %f \n", (float*)base->data, *z); | |
// appending places node below current therefore grows tree | |
// make notional middle child node | |
g_node_append(base, middle ); | |
// make notional second layer child | |
g_node_append(middle, far); | |
// make notional far child. | |
g_node_append(far, farthest); | |
// NOTE Use append to add child to the current parent | |
// now make into a n-ary tree | |
for (i = 0; i < number; i++) | |
{ | |
//printf("%f+", list[i]->own.dist); | |
if(i == 5) | |
{ | |
;// do nothing for notional origin | |
} | |
else | |
{ | |
// add cities by range of data | |
if ( list[i]->own.dist <= SMALLDISTANCE ) | |
{ | |
z = &list[i]->own.dist; | |
// shortest add to same level | |
tree_array[i] = g_node_new((gpointer)(z)); | |
g_node_append(base, tree_array[i]); | |
printf ( "added sibling node %d with %f\n", i, *z ); | |
} | |
else if ( list[i]->own.dist <= MIDDISTANCE ) | |
{ | |
// middle add to next level | |
z = &list[i]->own.dist; | |
tree_array[i] = g_node_new((gpointer)z); | |
g_node_append(middle, tree_array[i]); | |
printf ( "added child node %d with %f \n", i, *z ); | |
} | |
else // beyond middle added to the above limit | |
{ | |
if ( far != NULL) | |
{ | |
z = &list[i]->own.dist; | |
tree_array[i] = g_node_new((gpointer)z); | |
g_node_append(far, tree_array[i]); | |
printf ( "added grandchild node %d with %f \n", i, *z ); | |
} | |
} | |
}// i != 5 | |
} | |
// now we remove the notional | |
// elements from the tree | |
// there is no remove function made, only a unlink which makes | |
// new trees with remaining below data nodes - disconnecting your work. | |
// making a remove and save old tree structure would be an extra | |
// to work on. | |
// A way around this without extra functionality is to | |
// ignore the exemplar child at each depth | |
// that allows for removal and insertion of actual nodes | |
// over time without a lot of rework | |
// traverse and find distances - printf | |
g_node_traverse(base, G_LEVEL_ORDER, G_TRAVERSE_MASK, -1, GNodeIterateFloatPrint, NULL); | |
int b = g_node_depth (base); | |
int a = g_node_n_nodes (base ,G_TRAVERSE_ALL); | |
int c = g_node_n_children (base); | |
int d = g_node_max_height (base); | |
printf ( "number of nodes in tree %d in depth %d with %d children of base to max height %d \n", a,b,c,d ); | |
for (i = 0; i < number; i++) | |
{ | |
; | |
} | |
g_node_destroy(base); | |
return 0; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//ex-gtree-6.c | |
#include <glib.h> | |
gboolean GNodeIteratePrint(GNode* n, gpointer data) | |
{ | |
printf("%s ", n->data); | |
return FALSE; | |
} | |
int main(int argc, char** argv) | |
{ | |
GNode* root = g_node_new("Atlanta"); | |
g_node_append(root, g_node_new("Detroit")); | |
GNode* portland = g_node_prepend(root, g_node_new("Portland")); | |
printf(">Some cities to start with\n"); | |
g_node_traverse(root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, GNodeIteratePrint, NULL); | |
printf("\n>Inserting Coos Bay before Portland\n"); | |
g_node_insert_data_before(root, portland, "Coos Bay"); | |
g_node_traverse(root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, GNodeIteratePrint, NULL); | |
printf("\n>Reversing the child nodes\n"); | |
g_node_reverse_children(root); | |
g_node_traverse(root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, GNodeIteratePrint, NULL); | |
printf("\n>Root node is %s\n", g_node_get_root(portland)->data); | |
printf(">Portland node index is %d\n", g_node_child_index(root, "Portland")); | |
g_node_destroy(root); | |
return 0; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* GLIB - Library of useful routines for C programming | |
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald | |
* | |
* 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, write to the | |
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
* Boston, MA 02111-1307, USA. | |
*/ | |
/* | |
* Modified by the GLib Team and others 1997-2000. See the AUTHORS | |
* file for a list of people on the GLib Team. See the ChangeLog | |
* files for a list of changes. These files are distributed with | |
* GLib at ftp://ftp.gtk.org/pub/gtk/. | |
*/ | |
#include "config.h" | |
#undef GLIB_COMPILATION | |
#include <stdio.h> | |
#include <string.h> | |
#include <errno.h> | |
#include "glib.h" | |
#include "gstdio.h" | |
#include <stdlib.h> | |
#ifdef HAVE_UNISTD_H | |
#include <unistd.h> | |
#endif | |
#ifdef G_OS_WIN32 | |
#include <io.h> /* For read(), write() etc */ | |
#endif | |
#define GLIB_TEST_STRING "el dorado " | |
#define GLIB_TEST_STRING_5 "el do" | |
/* --- variables --- */ | |
static gint test_nums[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; | |
static gint more_nums[10] = { 8, 9, 7, 0, 3, 2, 5, 1, 4, 6}; | |
/* --- functions --- */ | |
static gint | |
my_list_compare_one (gconstpointer a, gconstpointer b) | |
{ | |
gint one = *((const gint*)a); | |
gint two = *((const gint*)b); | |
return one-two; | |
} | |
static gint | |
my_list_compare_two (gconstpointer a, gconstpointer b) | |
{ | |
gint one = *((const gint*)a); | |
gint two = *((const gint*)b); | |
return two-one; | |
} | |
/* static void | |
my_list_print (gpointer a, gpointer b) | |
{ | |
gint three = *((gint*)a); | |
g_print("%d", three); | |
}; */ | |
static void | |
glist_test (void) | |
{ | |
GList *list = NULL; | |
guint i; | |
for (i = 0; i < 10; i++) | |
list = g_list_append (list, &test_nums[i]); | |
list = g_list_reverse (list); | |
for (i = 0; i < 10; i++) | |
{ | |
GList *t = g_list_nth (list, i); | |
if (*((gint*) t->data) != (9 - i)) | |
g_error ("Regular insert failed"); | |
} | |
for (i = 0; i < 10; i++) | |
if (g_list_position (list, g_list_nth (list, i)) != i) | |
g_error ("g_list_position does not seem to be the inverse of g_list_nth\n"); | |
g_list_free (list); | |
list = NULL; | |
for (i = 0; i < 10; i++) | |
list = g_list_insert_sorted (list, &more_nums[i], my_list_compare_one); | |
/* | |
g_print("\n"); | |
g_list_foreach (list, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GList *t = g_list_nth (list, i); | |
if (*((gint*) t->data) != i) | |
g_error ("Sorted insert failed"); | |
} | |
g_list_free (list); | |
list = NULL; | |
for (i = 0; i < 10; i++) | |
list = g_list_insert_sorted (list, &more_nums[i], my_list_compare_two); | |
/* | |
g_print("\n"); | |
g_list_foreach (list, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GList *t = g_list_nth (list, i); | |
if (*((gint*) t->data) != (9 - i)) | |
g_error ("Sorted insert failed"); | |
} | |
g_list_free (list); | |
list = NULL; | |
for (i = 0; i < 10; i++) | |
list = g_list_prepend (list, &more_nums[i]); | |
list = g_list_sort (list, my_list_compare_two); | |
/* | |
g_print("\n"); | |
g_list_foreach (list, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GList *t = g_list_nth (list, i); | |
if (*((gint*) t->data) != (9 - i)) | |
g_error ("Merge sort failed"); | |
} | |
g_list_free (list); | |
} | |
static void | |
gslist_test (void) | |
{ | |
GSList *slist = NULL; | |
guint i; | |
for (i = 0; i < 10; i++) | |
slist = g_slist_append (slist, &test_nums[i]); | |
slist = g_slist_reverse (slist); | |
for (i = 0; i < 10; i++) | |
{ | |
GSList *st = g_slist_nth (slist, i); | |
if (*((gint*) st->data) != (9 - i)) | |
g_error ("failed"); | |
} | |
g_slist_free (slist); | |
slist = NULL; | |
for (i = 0; i < 10; i++) | |
slist = g_slist_insert_sorted (slist, &more_nums[i], my_list_compare_one); | |
/* | |
g_print("\n"); | |
g_slist_foreach (slist, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GSList *st = g_slist_nth (slist, i); | |
if (*((gint*) st->data) != i) | |
g_error ("Sorted insert failed"); | |
} | |
g_slist_free (slist); | |
slist = NULL; | |
for (i = 0; i < 10; i++) | |
slist = g_slist_insert_sorted (slist, &more_nums[i], my_list_compare_two); | |
/* | |
g_print("\n"); | |
g_slist_foreach (slist, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GSList *st = g_slist_nth (slist, i); | |
if (*((gint*) st->data) != (9 - i)) | |
g_error("Sorted insert failed"); | |
} | |
g_slist_free(slist); | |
slist = NULL; | |
for (i = 0; i < 10; i++) | |
slist = g_slist_prepend (slist, &more_nums[i]); | |
slist = g_slist_sort (slist, my_list_compare_two); | |
/* | |
g_print("\n"); | |
g_slist_foreach (slist, my_list_print, NULL); | |
*/ | |
for (i = 0; i < 10; i++) | |
{ | |
GSList *st = g_slist_nth (slist, i); | |
if (*((gint*) st->data) != (9 - i)) | |
g_error("Sorted insert failed"); | |
} | |
g_slist_free(slist); | |
} | |
static gboolean | |
node_build_string (GNode *node, | |
gpointer data) | |
{ | |
gchar **p = data; | |
gchar *string; | |
gchar c[2] = "_"; | |
c[0] = ((gchar) ((long) (node->data))); | |
string = g_strconcat (*p ? *p : "", c, NULL); | |
g_free (*p); | |
*p = string; | |
return FALSE; | |
} | |
static void | |
gnode_test (void) | |
{ | |
#define C2P(c) ((gpointer) ((long) (c))) | |
#define P2C(p) ((gchar) ((long) (p))) | |
GNode *root; | |
GNode *node; | |
GNode *node_B; | |
GNode *node_F; | |
GNode *node_G; | |
GNode *node_J; | |
guint i; | |
gchar *tstring, *cstring; | |
root = g_node_new (C2P ('A')); | |
g_assert (g_node_depth (root) == 1 && g_node_max_height (root) == 1); | |
node_B = g_node_new (C2P ('B')); | |
g_node_append (root, node_B); | |
g_assert (root->children == node_B); | |
g_node_append_data (node_B, C2P ('E')); | |
g_node_prepend_data (node_B, C2P ('C')); | |
g_node_insert (node_B, 1, g_node_new (C2P ('D'))); | |
node_F = g_node_new (C2P ('F')); | |
g_node_append (root, node_F); | |
g_assert (root->children->next == node_F); | |
node_G = g_node_new (C2P ('G')); | |
g_node_append (node_F, node_G); | |
node_J = g_node_new (C2P ('J')); | |
g_node_prepend (node_G, node_J); | |
g_node_insert (node_G, 42, g_node_new (C2P ('K'))); | |
g_node_insert_data (node_G, 0, C2P ('H')); | |
g_node_insert (node_G, 1, g_node_new (C2P ('I'))); | |
g_assert (g_node_depth (root) == 1); | |
g_assert (g_node_max_height (root) == 4); | |
g_assert (g_node_depth (node_G->children->next) == 4); | |
g_assert (g_node_n_nodes (root, G_TRAVERSE_LEAFS) == 7); | |
g_assert (g_node_n_nodes (root, G_TRAVERSE_NON_LEAFS) == 4); | |
g_assert (g_node_n_nodes (root, G_TRAVERSE_ALL) == 11); | |
g_assert (g_node_max_height (node_F) == 3); | |
g_assert (g_node_n_children (node_G) == 4); | |
g_assert (g_node_find_child (root, G_TRAVERSE_ALL, C2P ('F')) == node_F); | |
g_assert (g_node_find (root, G_LEVEL_ORDER, G_TRAVERSE_NON_LEAFS, C2P ('I')) == NULL); | |
g_assert (g_node_find (root, G_IN_ORDER, G_TRAVERSE_LEAFS, C2P ('J')) == node_J); | |
for (i = 0; i < g_node_n_children (node_B); i++) | |
{ | |
node = g_node_nth_child (node_B, i); | |
g_assert (P2C (node->data) == ('C' + i)); | |
} | |
for (i = 0; i < g_node_n_children (node_G); i++) | |
g_assert (g_node_child_position (node_G, g_node_nth_child (node_G, i)) == i); | |
/* we have built: A | |
* / \ | |
* B F | |
* / | \ \ | |
* C D E G | |
* / /\ \ | |
* H I J K | |
* | |
* for in-order traversal, 'G' is considered to be the "left" | |
* child of 'F', which will cause 'F' to be the last node visited. | |
*/ | |
tstring = NULL; | |
g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "ABCDEFGHIJK"); | |
g_free (tstring); tstring = NULL; | |
g_node_traverse (root, G_POST_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "CDEBHIJKGFA"); | |
g_free (tstring); tstring = NULL; | |
g_node_traverse (root, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "CBDEAHGIJKF"); | |
g_free (tstring); tstring = NULL; | |
g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "ABFCDEGHIJK"); | |
g_free (tstring); tstring = NULL; | |
g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_LEAFS, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "CDEHIJK"); | |
g_free (tstring); tstring = NULL; | |
g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_NON_LEAFS, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "ABFG"); | |
g_free (tstring); tstring = NULL; | |
g_node_reverse_children (node_B); | |
g_node_reverse_children (node_G); | |
g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_assert_cmpstr (tstring, ==, "ABFEDCGKJIH"); | |
g_free (tstring); tstring = NULL; | |
cstring = NULL; | |
node = g_node_copy (root); | |
g_assert (g_node_n_nodes (root, G_TRAVERSE_ALL) == g_node_n_nodes (node, G_TRAVERSE_ALL)); | |
g_assert (g_node_max_height (root) == g_node_max_height (node)); | |
g_node_traverse (root, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring); | |
g_node_traverse (node, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &cstring); | |
g_assert_cmpstr (tstring, ==, cstring); | |
g_free (tstring); tstring = NULL; | |
g_free (cstring); cstring = NULL; | |
g_node_destroy (node); | |
g_node_destroy (root); | |
/* allocation tests */ | |
root = g_node_new (NULL); | |
node = root; | |
for (i = 0; i < 2048; i++) | |
{ | |
g_node_append (node, g_node_new (NULL)); | |
if ((i%5) == 4) | |
node = node->children->next; | |
} | |
g_assert (g_node_max_height (root) > 100); | |
g_assert (g_node_n_nodes (root, G_TRAVERSE_ALL) == 1 + 2048); | |
g_node_destroy (root); | |
#undef C2P | |
#undef P2C | |
} | |
static gint | |
my_compare (gconstpointer a, | |
gconstpointer b) | |
{ | |
const char *cha = a; | |
const char *chb = b; | |
return *cha - *chb; | |
} | |
static gint | |
my_traverse (gpointer key, | |
gpointer value, | |
gpointer data) | |
{ | |
char *ch = key; | |
g_print ("%c ", *ch); | |
return FALSE; | |
} | |
static void | |
binary_tree_test (void) | |
{ | |
GTree *tree; | |
char chars[62]; | |
guint i, j; | |
tree = g_tree_new (my_compare); | |
i = 0; | |
for (j = 0; j < 10; j++, i++) | |
{ | |
chars[i] = '0' + j; | |
g_tree_insert (tree, &chars[i], &chars[i]); | |
} | |
for (j = 0; j < 26; j++, i++) | |
{ | |
chars[i] = 'A' + j; | |
g_tree_insert (tree, &chars[i], &chars[i]); | |
} | |
for (j = 0; j < 26; j++, i++) | |
{ | |
chars[i] = 'a' + j; | |
g_tree_insert (tree, &chars[i], &chars[i]); | |
} | |
g_assert_cmpint (g_tree_nnodes (tree), ==, 10 + 26 + 26); | |
g_assert_cmpint (g_tree_height (tree), ==, 6); | |
if (g_test_verbose()) | |
{ | |
g_print ("tree: "); | |
g_tree_foreach (tree, my_traverse, NULL); | |
g_print ("\n"); | |
} | |
for (i = 0; i < 10; i++) | |
g_tree_remove (tree, &chars[i]); | |
g_assert_cmpint (g_tree_nnodes (tree), ==, 26 + 26); | |
g_assert_cmpint (g_tree_height (tree), ==, 6); | |
if (g_test_verbose()) | |
{ | |
g_print ("tree: "); | |
g_tree_foreach (tree, my_traverse, NULL); | |
g_print ("\n"); | |
} | |
} | |
static gboolean | |
my_hash_callback_remove (gpointer key, | |
gpointer value, | |
gpointer user_data) | |
{ | |
int *d = value; | |
if ((*d) % 2) | |
return TRUE; | |
return FALSE; | |
} | |
static void | |
my_hash_callback_remove_test (gpointer key, | |
gpointer value, | |
gpointer user_data) | |
{ | |
int *d = value; | |
if ((*d) % 2) | |
g_print ("bad!\n"); | |
} | |
static void | |
my_hash_callback (gpointer key, | |
gpointer value, | |
gpointer user_data) | |
{ | |
int *d = value; | |
*d = 1; | |
} | |
static guint | |
my_hash (gconstpointer key) | |
{ | |
return (guint) *((const gint*) key); | |
} | |
static gboolean | |
my_hash_equal (gconstpointer a, | |
gconstpointer b) | |
{ | |
return *((const gint*) a) == *((const gint*) b); | |
} | |
static gboolean | |
find_first_that(gpointer key, | |
gpointer value, | |
gpointer user_data) | |
{ | |
gint *v = value; | |
gint *test = user_data; | |
return (*v == *test); | |
} | |
static void | |
test_g_mkdir_with_parents_1 (const gchar *base) | |
{ | |
char *p0 = g_build_filename (base, "fum", NULL); | |
char *p1 = g_build_filename (p0, "tem", NULL); | |
char *p2 = g_build_filename (p1, "zap", NULL); | |
FILE *f; | |
g_remove (p2); | |
g_remove (p1); | |
g_remove (p0); | |
if (g_file_test (p0, G_FILE_TEST_EXISTS)) | |
g_error ("failed, %s exists, cannot test g_mkdir_with_parents\n", p0); | |
if (g_file_test (p1, G_FILE_TEST_EXISTS)) | |
g_error ("failed, %s exists, cannot test g_mkdir_with_parents\n", p1); | |
if (g_file_test (p2, G_FILE_TEST_EXISTS)) | |
g_error ("failed, %s exists, cannot test g_mkdir_with_parents\n", p2); | |
if (g_mkdir_with_parents (p2, 0777) == -1) | |
g_error ("failed, g_mkdir_with_parents(%s) failed: %s\n", p2, g_strerror (errno)); | |
if (!g_file_test (p2, G_FILE_TEST_IS_DIR)) | |
g_error ("failed, g_mkdir_with_parents(%s) succeeded, but %s is not a directory\n", p2, p2); | |
if (!g_file_test (p1, G_FILE_TEST_IS_DIR)) | |
g_error ("failed, g_mkdir_with_parents(%s) succeeded, but %s is not a directory\n", p2, p1); | |
if (!g_file_test (p0, G_FILE_TEST_IS_DIR)) | |
g_error ("failed, g_mkdir_with_parents(%s) succeeded, but %s is not a directory\n", p2, p0); | |
g_rmdir (p2); | |
if (g_file_test (p2, G_FILE_TEST_EXISTS)) | |
g_error ("failed, did g_rmdir(%s), but %s is still there\n", p2, p2); | |
g_rmdir (p1); | |
if (g_file_test (p1, G_FILE_TEST_EXISTS)) | |
g_error ("failed, did g_rmdir(%s), but %s is still there\n", p1, p1); | |
f = g_fopen (p1, "w"); | |
if (f == NULL) | |
g_error ("failed, couldn't create file %s\n", p1); | |
fclose (f); | |
if (g_mkdir_with_parents (p1, 0666) == 0) | |
g_error ("failed, g_mkdir_with_parents(%s) succeeded, even if %s is a file\n", p1, p1); | |
if (g_mkdir_with_parents (p2, 0666) == 0) | |
g_error("failed, g_mkdir_with_parents(%s) succeeded, even if %s is a file\n", p2, p1); | |
g_remove (p2); | |
g_remove (p1); | |
g_remove (p0); | |
} | |
static void | |
test_g_mkdir_with_parents (void) | |
{ | |
gchar *cwd; | |
if (g_test_verbose()) | |
g_print ("checking g_mkdir_with_parents() in subdir ./hum/"); | |
test_g_mkdir_with_parents_1 ("hum"); | |
g_remove ("hum"); | |
if (g_test_verbose()) | |
g_print ("checking g_mkdir_with_parents() in subdir ./hii///haa/hee/"); | |
test_g_mkdir_with_parents_1 ("hii///haa/hee"); | |
g_remove ("hii/haa/hee"); | |
g_remove ("hii/haa"); | |
g_remove ("hii"); | |
cwd = g_get_current_dir (); | |
if (g_test_verbose()) | |
g_print ("checking g_mkdir_with_parents() in cwd: %s", cwd); | |
test_g_mkdir_with_parents_1 (cwd); | |
g_free (cwd); | |
} | |
static void | |
test_g_parse_debug_string (void) | |
{ | |
GDebugKey keys[3] = { | |
{ "foo", 1 }, | |
{ "bar", 2 }, | |
{ "baz", 4 } | |
}; | |
guint n_keys = 3; | |
guint result; | |
result = g_parse_debug_string ("bar:foo:blubb", keys, n_keys); | |
g_assert (result == 3); | |
result = g_parse_debug_string (":baz::_E@~!_::", keys, n_keys); | |
g_assert (result == 4); | |
result = g_parse_debug_string ("", keys, n_keys); | |
g_assert (result == 0); | |
result = g_parse_debug_string (" : ", keys, n_keys); | |
g_assert (result == 0); | |
} | |
static void | |
log_warning_error_tests (void) | |
{ | |
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)) | |
{ | |
g_message ("this is a g_message test."); | |
g_message ("non-printable UTF-8: \"\xc3\xa4\xda\x85\""); | |
g_message ("unsafe chars: \"\x10\x11\x12\n\t\x7f\x81\x82\x83\""); | |
exit (0); | |
} | |
g_test_trap_assert_passed(); | |
g_test_trap_assert_stderr ("*is a g_message test*"); | |
g_test_trap_assert_stderr ("*non-printable UTF-8*"); | |
g_test_trap_assert_stderr ("*unsafe chars*"); | |
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)) | |
{ | |
g_warning ("harmless warning with parameters: %d %s %#x", 42, "Boo", 12345); | |
exit (0); | |
} | |
g_test_trap_assert_failed(); /* we have fatal-warnings enabled */ | |
g_test_trap_assert_stderr ("*harmless warning*"); | |
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)) | |
{ | |
g_print (NULL); | |
exit (0); | |
} | |
g_test_trap_assert_failed(); /* we have fatal-warnings enabled */ | |
g_test_trap_assert_stderr ("*g_print*assertion*failed*"); | |
g_test_trap_assert_stderr ("*NULL*"); | |
} | |
static void | |
timer_tests (void) | |
{ | |
GTimer *timer, *timer2; | |
gdouble elapsed; | |
/* basic testing */ | |
timer = g_timer_new (); | |
g_timer_start (timer); | |
elapsed = g_timer_elapsed (timer, NULL); | |
g_timer_stop (timer); | |
g_assert_cmpfloat (elapsed, <=, g_timer_elapsed (timer, NULL)); | |
g_timer_destroy (timer); | |
if (g_test_slow()) | |
{ | |
if (g_test_verbose()) | |
g_print ("checking timers...\n"); | |
timer = g_timer_new (); | |
if (g_test_verbose()) | |
g_print (" spinning for 3 seconds...\n"); | |
g_timer_start (timer); | |
while (g_timer_elapsed (timer, NULL) < 3) | |
; | |
g_timer_stop (timer); | |
g_timer_destroy (timer); | |
if (g_test_verbose()) | |
g_print ("ok\n"); | |
} | |
if (g_test_slow()) | |
{ | |
gulong elapsed_usecs; | |
if (g_test_verbose()) | |
g_print ("checking g_timer_continue...\n"); | |
timer2 = g_timer_new (); | |
if (g_test_verbose()) | |
g_print ("\trun for 1 second...\n"); | |
timer = g_timer_new(); | |
g_usleep (G_USEC_PER_SEC); /* run timer for 1 second */ | |
g_timer_stop (timer); | |
if (g_test_verbose()) | |
g_print ("\tstop for 1 second...\n"); | |
g_usleep (G_USEC_PER_SEC); /* wait for 1 second */ | |
if (g_test_verbose()) | |
g_print ("\trun for 2 seconds...\n"); | |
g_timer_continue (timer); | |
g_usleep (2 * G_USEC_PER_SEC); /* run timer for 2 seconds */ | |
g_timer_stop(timer); | |
if (g_test_verbose()) | |
g_print ("\tstop for 1.5 seconds...\n"); | |
g_usleep ((3 * G_USEC_PER_SEC) / 2); /* wait for 1.5 seconds */ | |
if (g_test_verbose()) | |
g_print ("\trun for 0.2 seconds...\n"); | |
g_timer_continue (timer); | |
g_usleep (G_USEC_PER_SEC / 5); /* run timer for 0.2 seconds */ | |
g_timer_stop (timer); | |
if (g_test_verbose()) | |
g_print ("\tstop for 4 seconds...\n"); | |
g_usleep (4 * G_USEC_PER_SEC); /* wait for 4 seconds */ | |
if (g_test_verbose()) | |
g_print ("\trun for 5.8 seconds...\n"); | |
g_timer_continue (timer); | |
g_usleep ((29 * G_USEC_PER_SEC) / 5); /* run timer for 5.8 seconds */ | |
g_timer_stop(timer); | |
elapsed = g_timer_elapsed (timer, &elapsed_usecs); | |
if (g_test_verbose()) | |
g_print ("\t=> timer = %.6f = %d.%06ld (should be: 9.000000) (%.6f off)\n", elapsed, (int) elapsed, elapsed_usecs, ABS (elapsed - 9.)); | |
g_assert_cmpfloat (elapsed, >, 8.8); | |
g_assert_cmpfloat (elapsed, <, 9.2); | |
if (g_test_verbose()) | |
g_print ("g_timer_continue ... ok\n\n"); | |
g_timer_stop (timer2); | |
elapsed = g_timer_elapsed (timer2, &elapsed_usecs); | |
if (g_test_verbose()) | |
g_print ("\t=> timer2 = %.6f = %d.%06ld (should be: %.6f) (%.6f off)\n\n", elapsed, (int) elapsed, elapsed_usecs, 9.+6.5, ABS (elapsed - (9.+6.5))); | |
g_assert_cmpfloat (elapsed, >, 8.8 + 6.5); | |
g_assert_cmpfloat (elapsed, <, 9.2 + 6.5); | |
if (g_test_verbose()) | |
g_print ("timer2 ... ok\n\n"); | |
g_timer_destroy (timer); | |
g_timer_destroy (timer2); | |
} | |
} | |
static void | |
type_sizes (void) | |
{ | |
guint16 gu16t1 = 0x44afU, gu16t2 = 0xaf44U; | |
guint32 gu32t1 = 0x02a7f109U, gu32t2 = 0x09f1a702U; | |
guint64 gu64t1 = G_GINT64_CONSTANT(0x1d636b02300a7aa7U), | |
gu64t2 = G_GINT64_CONSTANT(0xa77a0a30026b631dU); | |
/* type sizes */ | |
g_assert_cmpint (sizeof (gint8), ==, 1); | |
g_assert_cmpint (sizeof (gint16), ==, 2); | |
g_assert_cmpint (sizeof (gint32), ==, 4); | |
g_assert_cmpint (sizeof (gint64), ==, 8); | |
/* endian macros */ | |
if (g_test_verbose()) | |
g_print ("checking endian macros (host is %s)...\n", | |
G_BYTE_ORDER == G_BIG_ENDIAN ? "big endian" : "little endian"); | |
g_assert (GUINT16_SWAP_LE_BE (gu16t1) == gu16t2); | |
g_assert (GUINT32_SWAP_LE_BE (gu32t1) == gu32t2); | |
g_assert (GUINT64_SWAP_LE_BE (gu64t1) == gu64t2); | |
} | |
static void | |
test_info (void) | |
{ | |
const gchar *un, *rn, *hn; | |
const gchar *tmpdir, *homedir, *userdatadir, *uconfdir, *ucachedir; | |
const gchar *uddesktop, *udddocs, *uddpubshare; | |
gchar **sv, *cwd, *sdatadirs, *sconfdirs, *langnames; | |
if (g_test_verbose()) | |
g_print ("TestGLib v%u.%u.%u (i:%u b:%u)\n", | |
glib_major_version, | |
glib_minor_version, | |
glib_micro_version, | |
glib_interface_age, | |
glib_binary_age); | |
cwd = g_get_current_dir (); | |
un = g_get_user_name(); | |
rn = g_get_real_name(); | |
hn = g_get_host_name(); | |
if (g_test_verbose()) | |
{ | |
g_print ("cwd: %s\n", cwd); | |
g_print ("user: %s\n", un); | |
g_print ("real: %s\n", rn); | |
g_print ("host: %s\n", hn); | |
} | |
g_free (cwd); | |
tmpdir = g_get_tmp_dir(); | |
g_assert (tmpdir != NULL); | |
homedir = g_get_home_dir (); | |
g_assert (homedir != NULL); | |
userdatadir = g_get_user_data_dir (); | |
g_assert (userdatadir != NULL); | |
uconfdir = g_get_user_config_dir (); | |
g_assert (uconfdir != NULL); | |
ucachedir = g_get_user_cache_dir (); | |
g_assert (ucachedir != NULL); | |
uddesktop = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP); | |
g_assert (uddesktop != NULL); | |
udddocs = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS); | |
uddpubshare = g_get_user_special_dir (G_USER_DIRECTORY_PUBLIC_SHARE); | |
sv = (gchar **) g_get_system_data_dirs (); | |
sdatadirs = g_strjoinv (G_SEARCHPATH_SEPARATOR_S, sv); | |
sv = (gchar **) g_get_system_config_dirs (); | |
sconfdirs = g_strjoinv (G_SEARCHPATH_SEPARATOR_S, sv); | |
sv = (gchar **) g_get_language_names (); | |
langnames = g_strjoinv (":", sv); | |
if (g_test_verbose()) | |
{ | |
g_print ("tmp-dir: %s\n", tmpdir); | |
g_print ("home: %s\n", homedir); | |
g_print ("user_data: %s\n", userdatadir); | |
g_print ("user_config: %s\n", uconfdir); | |
g_print ("user_cache: %s\n", ucachedir); | |
g_print ("system_data: %s\n", sdatadirs); | |
g_print ("system_config: %s\n", sconfdirs); | |
g_print ("languages: %s\n", langnames); | |
g_print ("user_special[DESKTOP]: %s\n", uddesktop); | |
g_print ("user_special[DOCUMENTS]: %s\n", udddocs); | |
g_print ("user_special[PUBLIC_SHARE]: %s\n", uddpubshare); | |
} | |
g_free (sdatadirs); | |
g_free (sconfdirs); | |
g_free (langnames); | |
if (g_test_verbose()) | |
{ | |
#ifdef G_PLATFORM_WIN32 | |
gchar *glib_dll; | |
#endif | |
const gchar *charset; | |
if (g_get_charset ((G_CONST_RETURN char**)&charset)) | |
g_print ("current charset is UTF-8: %s\n", charset); | |
else | |
g_print ("current charset is not UTF-8: %s\n", charset); | |
#ifdef G_PLATFORM_WIN32 | |
#ifdef G_OS_WIN32 | |
/* Can't calculate GLib DLL name at runtime. */ | |
glib_dll = "libglib-2.0-0.dll"; | |
#endif | |
#ifdef G_WITH_CYGWIN | |
glib_dll = "cygglib-2.0-0.dll"; | |
#endif | |
g_print ("current locale: %s\n", g_win32_getlocale ()); | |
g_print ("GLib DLL name tested for: %s\n", glib_dll); | |
g_print ("GLib installation directory, from Registry entry for %s if available: %s\n", | |
GETTEXT_PACKAGE, | |
g_win32_get_package_installation_directory (GETTEXT_PACKAGE, NULL)); | |
g_print ("Ditto, or from GLib DLL name: %s\n", | |
g_win32_get_package_installation_directory (GETTEXT_PACKAGE, glib_dll)); | |
g_print ("Ditto, only from GLib DLL name: %s\n", | |
g_win32_get_package_installation_directory (NULL, glib_dll)); | |
g_print ("locale subdirectory of GLib installation directory: %s\n", | |
g_win32_get_package_installation_subdirectory (NULL, glib_dll, "lib\\locale")); | |
g_print ("GTK+ 2.0 installation directory, if available: %s\n", | |
g_win32_get_package_installation_directory ("gtk20", NULL)); | |
g_print ("found more.com as %s\n", g_find_program_in_path ("more.com")); | |
g_print ("found regedit as %s\n", g_find_program_in_path ("regedit")); | |
g_print ("a Win32 error message: %s\n", g_win32_error_message (2)); | |
#endif | |
} | |
} | |
static void | |
test_paths (void) | |
{ | |
struct { | |
gchar *filename; | |
gchar *dirname; | |
} dirname_checks[] = { | |
{ "/", "/" }, | |
{ "////", "/" }, | |
{ ".////", "." }, | |
{ "../", ".." }, | |
{ "..////", ".." }, | |
{ "a/b", "a" }, | |
{ "a/b/", "a/b" }, | |
{ "c///", "c" }, | |
#ifdef G_OS_WIN32 | |
{ "\\", "\\" }, | |
{ ".\\\\\\\\", "." }, | |
{ "..\\", ".." }, | |
{ "..\\\\\\\\", ".." }, | |
{ "a\\b", "a" }, | |
{ "a\\b/", "a\\b" }, | |
{ "a/b\\", "a/b" }, | |
{ "c\\\\/", "c" }, | |
{ "//\\", "/" }, | |
#endif | |
#ifdef G_WITH_CYGWIN | |
{ "//server/share///x", "//server/share" }, | |
#endif | |
{ ".", "." }, | |
{ "..", "." }, | |
{ "", "." }, | |
}; | |
const guint n_dirname_checks = G_N_ELEMENTS (dirname_checks); | |
struct { | |
gchar *filename; | |
gchar *without_root; | |
} skip_root_checks[] = { | |
{ "/", "" }, | |
{ "//", "" }, | |
{ "/foo", "foo" }, | |
{ "//foo", "foo" }, | |
{ "a/b", NULL }, | |
#ifdef G_OS_WIN32 | |
{ "\\", "" }, | |
{ "\\foo", "foo" }, | |
{ "\\\\server\\foo", "" }, | |
{ "\\\\server\\foo\\bar", "bar" }, | |
{ "a\\b", NULL }, | |
#endif | |
#ifdef G_WITH_CYGWIN | |
{ "//server/share///x", "//x" }, | |
#endif | |
{ ".", NULL }, | |
{ "", NULL }, | |
}; | |
const guint n_skip_root_checks = G_N_ELEMENTS (skip_root_checks); | |
gchar *string; | |
guint i; | |
if (g_test_verbose()) | |
g_print ("checking g_path_get_basename()..."); | |
string = g_path_get_basename (G_DIR_SEPARATOR_S "foo" G_DIR_SEPARATOR_S "dir" G_DIR_SEPARATOR_S); | |
g_assert (strcmp (string, "dir") == 0); | |
g_free (string); | |
string = g_path_get_basename (G_DIR_SEPARATOR_S "foo" G_DIR_SEPARATOR_S "file"); | |
g_assert (strcmp (string, "file") == 0); | |
g_free (string); | |
if (g_test_verbose()) | |
g_print ("ok\n"); | |
#ifdef G_OS_WIN32 | |
string = g_path_get_basename ("/foo/dir/"); | |
g_assert (strcmp (string, "dir") == 0); | |
g_free (string); | |
string = g_path_get_basename ("/foo/file"); | |
g_assert (strcmp (string, "file") == 0); | |
g_free (string); | |
#endif | |
if (g_test_verbose()) | |
g_print ("checking g_path_get_dirname()..."); | |
for (i = 0; i < n_dirname_checks; i++) | |
{ | |
gchar *dirname = g_path_get_dirname (dirname_checks[i].filename); | |
if (strcmp (dirname, dirname_checks[i].dirname) != 0) | |
{ | |
g_error ("\nfailed for \"%s\"==\"%s\" (returned: \"%s\")\n", | |
dirname_checks[i].filename, | |
dirname_checks[i].dirname, | |
dirname); | |
} | |
g_free (dirname); | |
} | |
if (g_test_verbose()) | |
g_print ("ok\n"); | |
if (g_test_verbose()) | |
g_print ("checking g_path_skip_root()..."); | |
for (i = 0; i < n_skip_root_checks; i++) | |
{ | |
const gchar *skipped = g_path_skip_root (skip_root_checks[i].filename); | |
if ((skipped && !skip_root_checks[i].without_root) || | |
(!skipped && skip_root_checks[i].without_root) || | |
((skipped && skip_root_checks[i].without_root) && | |
strcmp (skipped, skip_root_checks[i].without_root))) | |
{ | |
g_error ("\nfailed for \"%s\"==\"%s\" (returned: \"%s\")\n", | |
skip_root_checks[i].filename, | |
(skip_root_checks[i].without_root ? | |
skip_root_checks[i].without_root : "<NULL>"), | |
(skipped ? skipped : "<NULL>")); | |
} | |
} | |
if (g_test_verbose()) | |
g_print ("ok\n"); | |
} | |
static void | |
test_file_functions (void) | |
{ | |
const char hello[] = "Hello, World"; | |
const int hellolen = sizeof (hello) - 1; | |
GError *error; | |
char template[32]; | |
char *name_used, chars[62]; | |
gint fd, n; | |
strcpy (template, "foobar"); | |
fd = g_mkstemp (template); | |
if (g_test_verbose() && fd != -1) | |
g_print ("g_mkstemp works even if template doesn't end in XXXXXX\n"); | |
close (fd); | |
strcpy (template, "fooXXXXXX"); | |
fd = g_mkstemp (template); | |
if (fd == -1) | |
g_error ("g_mkstemp didn't work for template %s\n", template); | |
n = write (fd, hello, hellolen); | |
if (n == -1) | |
g_error ("write() failed: %s\n", g_strerror (errno)); | |
else if (n != hellolen) | |
g_error ("write() should have written %d bytes, wrote %d\n", hellolen, n); | |
lseek (fd, 0, 0); | |
n = read (fd, chars, sizeof (chars)); | |
if (n == -1) | |
g_error ("read() failed: %s\n", g_strerror (errno)); | |
else if (n != hellolen) | |
g_error ("read() should have read %d bytes, got %d\n", hellolen, n); | |
chars[n] = 0; | |
if (strcmp (chars, hello) != 0) | |
g_error ("wrote '%s', but got '%s'\n", hello, chars); | |
close (fd); | |
remove (template); | |
error = NULL; | |
strcpy (template, "zap" G_DIR_SEPARATOR_S "barXXXXXX"); | |
fd = g_file_open_tmp (template, &name_used, &error); | |
if (g_test_verbose()) | |
{ | |
if (fd != -1) | |
g_print ("g_file_open_tmp works even if template contains '%s'\n", G_DIR_SEPARATOR_S); | |
else | |
g_print ("g_file_open_tmp correctly returns error: %s\n", error->message); | |
} | |
close (fd); | |
g_clear_error (&error); | |
#ifdef G_OS_WIN32 | |
strcpy (template, "zap/barXXXXXX"); | |
fd = g_file_open_tmp (template, &name_used, &error); | |
if (g_test_verbose()) | |
{ | |
if (fd != -1) | |
g_print ("g_file_open_tmp works even if template contains '/'\n"); | |
else | |
g_print ("g_file_open_tmp correctly returns error: %s\n", error->message); | |
} | |
close (fd); | |
g_clear_error (&error); | |
#endif | |
strcpy (template, "zapXXXXXX"); | |
fd = g_file_open_tmp (template, &name_used, &error); | |
if (fd == -1) | |
g_error ("g_file_open_tmp didn't work for template '%s': %s\n", template, error->message); | |
else if (g_test_verbose()) | |
g_print ("g_file_open_tmp for template '%s' used name '%s'\n", template, name_used); | |
close (fd); | |
g_clear_error (&error); | |
remove (name_used); | |
fd = g_file_open_tmp (NULL, &name_used, &error); | |
if (fd == -1) | |
g_error ("g_file_open_tmp didn't work for a NULL template: %s\n", error->message); | |
close (fd); | |
g_clear_error (&error); | |
remove (name_used); | |
} | |
static void | |
test_arrays (void) | |
{ | |
GByteArray *gbarray; | |
GPtrArray *gparray; | |
GArray *garray; | |
guint i; | |
gparray = g_ptr_array_new (); | |
for (i = 0; i < 10000; i++) | |
g_ptr_array_add (gparray, GINT_TO_POINTER (i)); | |
for (i = 0; i < 10000; i++) | |
if (g_ptr_array_index (gparray, i) != GINT_TO_POINTER (i)) | |
g_error ("array fails: %p ( %p )\n", g_ptr_array_index (gparray, i), GINT_TO_POINTER (i)); | |
g_ptr_array_free (gparray, TRUE); | |
gbarray = g_byte_array_new (); | |
for (i = 0; i < 10000; i++) | |
g_byte_array_append (gbarray, (guint8*) "abcd", 4); | |
for (i = 0; i < 10000; i++) | |
{ | |
g_assert (gbarray->data[4*i] == 'a'); | |
g_assert (gbarray->data[4*i+1] == 'b'); | |
g_assert (gbarray->data[4*i+2] == 'c'); | |
g_assert (gbarray->data[4*i+3] == 'd'); | |
} | |
g_byte_array_free (gbarray, TRUE); | |
garray = g_array_new (FALSE, FALSE, sizeof (gint)); | |
for (i = 0; i < 10000; i++) | |
g_array_append_val (garray, i); | |
for (i = 0; i < 10000; i++) | |
if (g_array_index (garray, gint, i) != i) | |
g_error ("failure: %d ( %d )\n", g_array_index (garray, gint, i), i); | |
g_array_free (garray, TRUE); | |
garray = g_array_new (FALSE, FALSE, sizeof (gint)); | |
for (i = 0; i < 100; i++) | |
g_array_prepend_val (garray, i); | |
for (i = 0; i < 100; i++) | |
if (g_array_index (garray, gint, i) != (100 - i - 1)) | |
g_error ("failure: %d ( %d )\n", g_array_index (garray, gint, i), 100 - i - 1); | |
g_array_free (garray, TRUE); | |
} | |
static void | |
hash_table_tests (void) | |
{ | |
GHashTable *hash_table; | |
int array[10000]; | |
gint *pvalue = NULL; | |
gint value = 120; | |
guint i; | |
hash_table = g_hash_table_new (my_hash, my_hash_equal); | |
for (i = 0; i < 10000; i++) | |
{ | |
array[i] = i; | |
g_hash_table_insert (hash_table, &array[i], &array[i]); | |
} | |
pvalue = g_hash_table_find (hash_table, find_first_that, &value); | |
if (*pvalue != value) | |
g_error ("g_hash_table_find failed"); | |
g_hash_table_foreach (hash_table, my_hash_callback, NULL); | |
for (i = 0; i < 10000; i++) | |
if (array[i] == 0) | |
g_error ("hashtable-test: wrong value: %d\n", i); | |
for (i = 0; i < 10000; i++) | |
g_hash_table_remove (hash_table, &array[i]); | |
for (i = 0; i < 10000; i++) | |
{ | |
array[i] = i; | |
g_hash_table_insert (hash_table, &array[i], &array[i]); | |
} | |
if (g_hash_table_foreach_remove (hash_table, my_hash_callback_remove, NULL) != 5000 || | |
g_hash_table_size (hash_table) != 5000) | |
g_error ("hashtable removal failed\n"); | |
g_hash_table_foreach (hash_table, my_hash_callback_remove_test, NULL); | |
g_hash_table_destroy (hash_table); | |
} | |
static void | |
relation_test (void) | |
{ | |
GRelation *relation = g_relation_new (2); | |
GTuples *tuples; | |
gint data [1024]; | |
guint i; | |
g_relation_index (relation, 0, g_int_hash, g_int_equal); | |
g_relation_index (relation, 1, g_int_hash, g_int_equal); | |
for (i = 0; i < 1024; i += 1) | |
data[i] = i; | |
for (i = 1; i < 1023; i += 1) | |
{ | |
g_relation_insert (relation, data + i, data + i + 1); | |
g_relation_insert (relation, data + i, data + i - 1); | |
} | |
for (i = 2; i < 1022; i += 1) | |
{ | |
g_assert (! g_relation_exists (relation, data + i, data + i)); | |
g_assert (! g_relation_exists (relation, data + i, data + i + 2)); | |
g_assert (! g_relation_exists (relation, data + i, data + i - 2)); | |
} | |
for (i = 1; i < 1023; i += 1) | |
{ | |
g_assert (g_relation_exists (relation, data + i, data + i + 1)); | |
g_assert (g_relation_exists (relation, data + i, data + i - 1)); | |
} | |
for (i = 2; i < 1022; i += 1) | |
{ | |
g_assert (g_relation_count (relation, data + i, 0) == 2); | |
g_assert (g_relation_count (relation, data + i, 1) == 2); | |
} | |
g_assert (g_relation_count (relation, data, 0) == 0); | |
g_assert (g_relation_count (relation, data + 42, 0) == 2); | |
g_assert (g_relation_count (relation, data + 43, 1) == 2); | |
g_assert (g_relation_count (relation, data + 41, 1) == 2); | |
g_relation_delete (relation, data + 42, 0); | |
g_assert (g_relation_count (relation, data + 42, 0) == 0); | |
g_assert (g_relation_count (relation, data + 43, 1) == 1); | |
g_assert (g_relation_count (relation, data + 41, 1) == 1); | |
tuples = g_relation_select (relation, data + 200, 0); | |
g_assert (tuples->len == 2); | |
#if 0 | |
for (i = 0; i < tuples->len; i += 1) | |
{ | |
printf ("%d %d\n", | |
*(gint*) g_tuples_index (tuples, i, 0), | |
*(gint*) g_tuples_index (tuples, i, 1)); | |
} | |
#endif | |
g_assert (g_relation_exists (relation, data + 300, data + 301)); | |
g_relation_delete (relation, data + 300, 0); | |
g_assert (!g_relation_exists (relation, data + 300, data + 301)); | |
g_tuples_destroy (tuples); | |
g_relation_destroy (relation); | |
relation = NULL; | |
} | |
static void | |
gstring_tests (void) | |
{ | |
GString *string1, *string2; | |
guint i; | |
if (g_test_verbose()) | |
g_print ("test GString basics\n"); | |
string1 = g_string_new ("hi pete!"); | |
string2 = g_string_new (""); | |
g_assert (strcmp ("hi pete!", string1->str) == 0); | |
for (i = 0; i < 10000; i++) | |
g_string_append_c (string1, 'a'+(i%26)); | |
#ifndef G_OS_WIN32 | |
/* MSVC, mingw32 and LCC use the same run-time C library, which doesn't like | |
the %10000.10000f format... */ | |
g_string_printf (string2, "%s|%0100d|%s|%s|%0*d|%*.*f|%10000.10000f", | |
"this pete guy sure is a wuss, like he's the number ", | |
1, | |
" wuss. everyone agrees.\n", | |
string1->str, | |
10, 666, 15, 15, 666.666666666, 666.666666666); | |
#else | |
g_string_printf (string2, "%s|%0100d|%s|%s|%0*d|%*.*f|%100.100f", | |
"this pete guy sure is a wuss, like he's the number ", | |
1, | |
" wuss. everyone agrees.\n", | |
string1->str, | |
10, 666, 15, 15, 666.666666666, 666.666666666); | |
#endif | |
if (g_test_verbose()) | |
g_print ("string2 length = %lu...\n", (gulong)string2->len); | |
string2->str[70] = '\0'; | |
if (g_test_verbose()) | |
g_print ("first 70 chars:\n%s\n", string2->str); | |
string2->str[141] = '\0'; | |
if (g_test_verbose()) | |
g_print ("next 70 chars:\n%s\n", string2->str+71); | |
string2->str[212] = '\0'; | |
if (g_test_verbose()) | |
g_print ("and next 70:\n%s\n", string2->str+142); | |
if (g_test_verbose()) | |
g_print ("last 70 chars:\n%s\n", string2->str+string2->len - 70); | |
g_string_free (string1, TRUE); | |
g_string_free (string2, TRUE); | |
/* append */ | |
string1 = g_string_new ("firsthalf"); | |
g_string_append (string1, "lasthalf"); | |
g_assert (strcmp (string1->str, "firsthalflasthalf") == 0); | |
g_string_free (string1, TRUE); | |
/* append_len */ | |
string1 = g_string_new ("firsthalf"); | |
g_string_append_len (string1, "lasthalfjunkjunk", strlen ("lasthalf")); | |
g_assert (strcmp (string1->str, "firsthalflasthalf") == 0); | |
g_string_free (string1, TRUE); | |
/* prepend */ | |
string1 = g_string_new ("lasthalf"); | |
g_string_prepend (string1, "firsthalf"); | |
g_assert (strcmp (string1->str, "firsthalflasthalf") == 0); | |
g_string_free (string1, TRUE); | |
/* prepend_len */ | |
string1 = g_string_new ("lasthalf"); | |
g_string_prepend_len (string1, "firsthalfjunkjunk", strlen ("firsthalf")); | |
g_assert (strcmp (string1->str, "firsthalflasthalf") == 0); | |
g_string_free (string1, TRUE); | |
/* insert */ | |
string1 = g_string_new ("firstlast"); | |
g_string_insert (string1, 5, "middle"); | |
g_assert (strcmp (string1->str, "firstmiddlelast") == 0); | |
g_string_free (string1, TRUE); | |
/* insert with pos == end of the string */ | |
string1 = g_string_new ("firstmiddle"); | |
g_string_insert (string1, strlen ("firstmiddle"), "last"); | |
g_assert (strcmp (string1->str, "firstmiddlelast") == 0); | |
g_string_free (string1, TRUE); | |
/* insert_len */ | |
string1 = g_string_new ("firstlast"); | |
g_string_insert_len (string1, 5, "middlejunkjunk", strlen ("middle")); | |
g_assert (strcmp (string1->str, "firstmiddlelast") == 0); | |
g_string_free (string1, TRUE); | |
/* insert_len with magic -1 pos for append */ | |
string1 = g_string_new ("first"); | |
g_string_insert_len (string1, -1, "lastjunkjunk", strlen ("last")); | |
g_assert (strcmp (string1->str, "firstlast") == 0); | |
g_string_free (string1, TRUE); | |
/* insert_len with magic -1 len for strlen-the-string */ | |
string1 = g_string_new ("first"); | |
g_string_insert_len (string1, 5, "last", -1); | |
g_assert (strcmp (string1->str, "firstlast") == 0); | |
g_string_free (string1, TRUE); | |
/* g_string_equal */ | |
string1 = g_string_new ("test"); | |
string2 = g_string_new ("te"); | |
g_assert (! g_string_equal(string1, string2)); | |
g_string_append (string2, "st"); | |
g_assert (g_string_equal(string1, string2)); | |
g_string_free (string1, TRUE); | |
g_string_free (string2, TRUE); | |
/* Check handling of embedded ASCII 0 (NUL) characters in GString. */ | |
if (g_test_verbose()) | |
g_print ("test embedded ASCII 0 (NUL) characters in GString\n"); | |
string1 = g_string_new ("fiddle"); | |
string2 = g_string_new ("fiddle"); | |
g_assert (g_string_equal(string1, string2)); | |
g_string_append_c(string1, '\0'); | |
g_assert (! g_string_equal(string1, string2)); | |
g_string_append_c(string2, '\0'); | |
g_assert (g_string_equal(string1, string2)); | |
g_string_append_c(string1, 'x'); | |
g_string_append_c(string2, 'y'); | |
g_assert (! g_string_equal(string1, string2)); | |
g_assert (string1->len == 8); | |
g_string_append(string1, "yzzy"); | |
g_assert (string1->len == 12); | |
g_assert ( memcmp(string1->str, "fiddle\0xyzzy", 13) == 0); | |
g_string_insert(string1, 1, "QED"); | |
g_assert ( memcmp(string1->str, "fQEDiddle\0xyzzy", 16) == 0); | |
g_string_free (string1, TRUE); | |
g_string_free (string2, TRUE); | |
} | |
static void | |
various_string_tests (void) | |
{ | |
GStringChunk *string_chunk; | |
GTimeVal ref_date, date; | |
gchar *tmp_string = NULL, *tmp_string_2, *string, *date_str; | |
guint i; | |
if (g_test_verbose()) | |
g_print ("checking string chunks..."); | |
string_chunk = g_string_chunk_new (1024); | |
for (i = 0; i < 100000; i ++) | |
{ | |
tmp_string = g_string_chunk_insert (string_chunk, "hi pete"); | |
if (strcmp ("hi pete", tmp_string) != 0) | |
g_error ("string chunks are broken.\n"); | |
} | |
tmp_string_2 = g_string_chunk_insert_const (string_chunk, tmp_string); | |
g_assert (tmp_string_2 != tmp_string && strcmp (tmp_string_2, tmp_string) == 0); | |
tmp_string = g_string_chunk_insert_const (string_chunk, tmp_string); | |
g_assert (tmp_string_2 == tmp_string); | |
g_string_chunk_free (string_chunk); | |
if (g_test_verbose()) | |
g_print ("test positional printf formats (not supported):"); | |
string = g_strdup_printf ("%.*s%s", 5, "a", "b"); | |
tmp_string = g_strdup_printf ("%2$*1$s", 5, "c"); | |
if (g_test_verbose()) | |
g_print ("%s%s\n", string, tmp_string); | |
g_free (tmp_string); | |
g_free (string); | |
#define REF_INVALID "Wed Dec 19 17:20:20 GMT 2007" | |
#define REF_SEC_UTC 320063760 | |
#define REF_STR_UTC "1980-02-22T10:36:00Z" | |
#define REF_STR_CEST "1980-02-22T12:36:00+02:00" | |
#define REF_STR_EST "1980-02-22T05:36:00-05:00" | |
if (g_test_verbose()) | |
g_print ("checking g_time_val_from_iso8601...\n"); | |
ref_date.tv_sec = REF_SEC_UTC; | |
ref_date.tv_usec = 0; | |
g_assert (g_time_val_from_iso8601 (REF_INVALID, &date) == FALSE); | |
g_assert (g_time_val_from_iso8601 (REF_STR_UTC, &date) != FALSE); | |
if (g_test_verbose()) | |
g_print ("\t=> UTC stamp = %ld (should be: %ld) (%ld off)\n", date.tv_sec, ref_date.tv_sec, date.tv_sec - ref_date.tv_sec); | |
g_assert (date.tv_sec == ref_date.tv_sec); | |
g_assert (g_time_val_from_iso8601 (REF_STR_CEST, &date) != FALSE); | |
if (g_test_verbose()) | |
g_print ("\t=> CEST stamp = %ld (should be: %ld) (%ld off)\n", date.tv_sec, ref_date.tv_sec, date.tv_sec - ref_date.tv_sec); | |
g_assert (date.tv_sec == ref_date.tv_sec); | |
g_assert (g_time_val_from_iso8601 (REF_STR_EST, &date) != FALSE); | |
if (g_test_verbose()) | |
g_print ("\t=> EST stamp = %ld (should be: %ld) (%ld off)\n", date.tv_sec, ref_date.tv_sec, date.tv_sec - ref_date.tv_sec); | |
g_assert (date.tv_sec == ref_date.tv_sec); | |
if (g_test_verbose()) | |
g_print ("checking g_time_val_to_iso8601...\n"); | |
ref_date.tv_sec = REF_SEC_UTC; | |
ref_date.tv_usec = 1; | |
date_str = g_time_val_to_iso8601 (&ref_date); | |
g_assert (date_str != NULL); | |
if (g_test_verbose()) | |
g_print ("\t=> date string = %s (should be: %s)\n", date_str, REF_STR_UTC); | |
g_assert (strcmp (date_str, REF_STR_UTC) == 0); | |
g_free (date_str); | |
if (g_test_verbose()) | |
g_print ("checking g_ascii_strcasecmp..."); | |
g_assert (g_ascii_strcasecmp ("FroboZZ", "frobozz") == 0); | |
g_assert (g_ascii_strcasecmp ("frobozz", "frobozz") == 0); | |
g_assert (g_ascii_strcasecmp ("frobozz", "FROBOZZ") == 0); | |
g_assert (g_ascii_strcasecmp ("FROBOZZ", "froboz") > 0); | |
g_assert (g_ascii_strcasecmp ("", "") == 0); | |
g_assert (g_ascii_strcasecmp ("!#%&/()", "!#%&/()") == 0); | |
g_assert (g_ascii_strcasecmp ("a", "b") < 0); | |
g_assert (g_ascii_strcasecmp ("a", "B") < 0); | |
g_assert (g_ascii_strcasecmp ("A", "b") < 0); | |
g_assert (g_ascii_strcasecmp ("A", "B") < 0); | |
g_assert (g_ascii_strcasecmp ("b", "a") > 0); | |
g_assert (g_ascii_strcasecmp ("b", "A") > 0); | |
g_assert (g_ascii_strcasecmp ("B", "a") > 0); | |
g_assert (g_ascii_strcasecmp ("B", "A") > 0); | |
if (g_test_verbose()) | |
g_print ("checking g_strdup...\n"); | |
g_assert (g_strdup (NULL) == NULL); | |
string = g_strdup (GLIB_TEST_STRING); | |
g_assert (string != NULL); | |
g_assert (strcmp(string, GLIB_TEST_STRING) == 0); | |
g_free (string); | |
if (g_test_verbose()) | |
g_print ("checking g_strconcat...\n"); | |
string = g_strconcat (GLIB_TEST_STRING, NULL); | |
g_assert (string != NULL); | |
g_assert (strcmp (string, GLIB_TEST_STRING) == 0); | |
g_free (string); | |
string = g_strconcat (GLIB_TEST_STRING, GLIB_TEST_STRING, | |
GLIB_TEST_STRING, NULL); | |
g_assert (string != NULL); | |
g_assert (strcmp (string, GLIB_TEST_STRING GLIB_TEST_STRING | |
GLIB_TEST_STRING) == 0); | |
g_free (string); | |
if (g_test_verbose()) | |
g_print ("checking g_strlcpy/g_strlcat..."); | |
/* The following is a torture test for strlcpy/strlcat, with lots of | |
* checking; normal users wouldn't use them this way! | |
*/ | |
string = g_malloc (6); | |
*(string + 5) = 'Z'; /* guard value, shouldn't change during test */ | |
*string = 'q'; | |
g_assert (g_strlcpy(string, "" , 5) == 0); | |
g_assert ( *string == '\0' ); | |
*string = 'q'; | |
g_assert (g_strlcpy(string, "abc" , 5) == 3); | |
g_assert ( *(string + 3) == '\0' ); | |
g_assert (g_str_equal(string, "abc")); | |
g_assert (g_strlcpy(string, "abcd" , 5) == 4); | |
g_assert ( *(string + 4) == '\0' ); | |
g_assert ( *(string + 5) == 'Z' ); | |
g_assert (g_str_equal(string, "abcd")); | |
g_assert (g_strlcpy(string, "abcde" , 5) == 5); | |
g_assert ( *(string + 4) == '\0' ); | |
g_assert ( *(string + 5) == 'Z' ); | |
g_assert (g_str_equal(string, "abcd")); | |
g_assert (g_strlcpy(string, "abcdef" , 5) == 6); | |
g_assert ( *(string + 4) == '\0' ); | |
g_assert ( *(string + 5) == 'Z' ); | |
g_assert (g_str_equal(string, "abcd")); | |
*string = 'Y'; | |
*(string + 1)= '\0'; | |
g_assert (g_strlcpy(string, "Hello" , 0) == 5); | |
g_assert (*string == 'Y'); | |
*string = '\0'; | |
g_assert (g_strlcat(string, "123" , 5) == 3); | |
g_assert ( *(string + 3) == '\0' ); | |
g_assert (g_str_equal(string, "123")); | |
g_assert (g_strlcat(string, "" , 5) == 3); | |
g_assert ( *(string + 3) == '\0' ); | |
g_assert (g_str_equal(string, "123")); | |
g_assert (g_strlcat(string, "4", 5) == 4); | |
g_assert (g_str_equal(string, "1234")); | |
g_assert (g_strlcat(string, "5", 5) == 5); | |
g_assert ( *(string + 4) == '\0' ); | |
g_assert (g_str_equal(string, "1234")); | |
g_assert ( *(string + 5) == 'Z' ); | |
*string = 'Y'; | |
*(string + 1)= '\0'; | |
g_assert (g_strlcat(string, "123" , 0) == 3); | |
g_assert (*string == 'Y'); | |
/* A few more tests, demonstrating more "normal" use */ | |
g_assert (g_strlcpy(string, "hi", 5) == 2); | |
g_assert (g_str_equal(string, "hi")); | |
g_assert (g_strlcat(string, "t", 5) == 3); | |
g_assert (g_str_equal(string, "hit")); | |
g_free(string); | |
if (g_test_verbose()) | |
g_print ("checking g_strdup_printf...\n"); | |
string = g_strdup_printf ("%05d %-5s", 21, "test"); | |
g_assert (string != NULL); | |
g_assert (strcmp(string, "00021 test ") == 0); | |
g_free (string); | |
/* g_debug (argv[0]); */ | |
} | |
static void | |
test_mem_chunks (void) | |
{ | |
GMemChunk *mem_chunk = g_mem_chunk_new ("test mem chunk", 50, 100, G_ALLOC_AND_FREE); | |
gchar *mem[10000]; | |
guint i; | |
for (i = 0; i < 10000; i++) | |
{ | |
guint j; | |
mem[i] = g_chunk_new (gchar, mem_chunk); | |
for (j = 0; j < 50; j++) | |
mem[i][j] = i * j; | |
} | |
for (i = 0; i < 10000; i++) | |
g_mem_chunk_free (mem_chunk, mem[i]); | |
} | |
int | |
main (int argc, | |
char *argv[]) | |
{ | |
g_test_init (&argc, &argv, NULL); | |
g_test_add_func ("/testglib/Infos", test_info); | |
g_test_add_func ("/testglib/Types Sizes", type_sizes); | |
g_test_add_func ("/testglib/GStrings", gstring_tests); | |
g_test_add_func ("/testglib/Various Strings", various_string_tests); | |
g_test_add_func ("/testglib/GList", glist_test); | |
g_test_add_func ("/testglib/GSList", gslist_test); | |
g_test_add_func ("/testglib/GNode", gnode_test); | |
g_test_add_func ("/testglib/GTree", binary_tree_test); | |
g_test_add_func ("/testglib/Arrays", test_arrays); | |
g_test_add_func ("/testglib/GHashTable", hash_table_tests); | |
g_test_add_func ("/testglib/Relation", relation_test); | |
g_test_add_func ("/testglib/File Paths", test_paths); | |
g_test_add_func ("/testglib/File Functions", test_file_functions); | |
g_test_add_func ("/testglib/Mkdir", test_g_mkdir_with_parents); | |
g_test_add_func ("/testglib/Parse Debug Strings", test_g_parse_debug_string); | |
g_test_add_func ("/testglib/GMemChunk (deprecated)", test_mem_chunks); | |
g_test_add_func ("/testglib/Warnings & Errors", log_warning_error_tests); | |
g_test_add_func ("/testglib/Timers (slow)", timer_tests); | |
return g_test_run(); | |
} |