#include #include #include /* Keep this in sync with gsequence.c !!! */ typedef struct _GSequenceNode GSequenceNode; struct _GSequence { GSequenceNode * end_node; GDestroyNotify data_destroy_notify; gboolean access_prohibited; GSequence * real_sequence; }; struct _GSequenceNode { gint n_nodes; GSequenceNode * parent; GSequenceNode * left; GSequenceNode * right; gpointer data; }; static guint get_priority (GSequenceNode *node) { guint key = GPOINTER_TO_UINT (node); key = (key << 15) - key - 1; key = key ^ (key >> 12); key = key + (key << 2); key = key ^ (key >> 4); key = key + (key << 3) + (key << 11); key = key ^ (key >> 16); return key? key : 1; } static void check_node (GSequenceNode *node) { if (node) { g_assert (node->parent != node); if (node->parent) g_assert (node->parent->left == node || node->parent->right == node); g_assert (node->n_nodes == 1 + (node->left ? node->left->n_nodes : 0) + (node->right ? node->right->n_nodes : 0)); if (node->left) g_assert (get_priority (node) >= get_priority (node->left)); if (node->right) g_assert (get_priority (node) >= get_priority (node->right)); check_node (node->left); check_node (node->right); } } static void g_sequence_check (GSequence *seq) { GSequenceNode *node = seq->end_node; while (node->parent) node = node->parent; check_node (node); while (node->right) node = node->right; g_assert (seq->end_node == node); g_assert (node->data == seq); } enum { NEW, FREE, GET_LENGTH, FOREACH, FOREACH_RANGE, SORT, SORT_ITER, /* Getting iters */ GET_BEGIN_ITER, GET_END_ITER, GET_ITER_AT_POS, APPEND, PREPEND, INSERT_BEFORE, MOVE, SWAP, INSERT_SORTED, INSERT_SORTED_ITER, SORT_CHANGED, SORT_CHANGED_ITER, REMOVE, REMOVE_RANGE, MOVE_RANGE, SEARCH, SEARCH_ITER, LOOKUP, LOOKUP_ITER, /* dereferencing */ GET, SET, /* operations on GSequenceIter * */ ITER_IS_BEGIN, ITER_IS_END, ITER_NEXT, ITER_PREV, ITER_GET_POSITION, ITER_MOVE, ITER_GET_SEQUENCE, /* search */ ITER_COMPARE, RANGE_GET_MIDPOINT, N_OPS }; typedef struct SequenceInfo { GQueue * queue; GSequence * sequence; int n_items; } SequenceInfo; typedef struct { SequenceInfo *seq; int number; } Item; void g_sequence_check (GSequence *sequence); static Item * fix_pointer (gconstpointer data) { return (Item *)((char *)data - 1); } static Item * get_item (GSequenceIter *iter) { return fix_pointer (g_sequence_get (iter)); } static void check_integrity (SequenceInfo *info) { GList *list; GSequenceIter *iter; int i; g_sequence_check (info->sequence); #if 0 if (g_sequence_get_length (info->sequence) != info->n_items) g_printerr ("%d %d\n", g_sequence_get_length (info->sequence), info->n_items); #endif g_assert (info->n_items == g_queue_get_length (info->queue)); g_assert (g_sequence_get_length (info->sequence) == info->n_items); iter = g_sequence_get_begin_iter (info->sequence); list = info->queue->head; i = 0; while (iter != g_sequence_get_end_iter (info->sequence)) { Item *item; g_assert (list->data == iter); item = get_item (list->data); g_assert (item->seq == info); iter = g_sequence_iter_next (iter); list = list->next; i++; } g_assert (info->n_items == g_queue_get_length (info->queue)); g_assert (g_sequence_get_length (info->sequence) == info->n_items); } static gpointer new_item (SequenceInfo *seq) { Item *item = g_new (Item, 1); seq->n_items++; item->seq = seq; item->number = g_random_int (); /* There have been bugs in the past where the GSequence would * dereference the user pointers. This will make sure such * behavior causes crashes */ return ((char *)item + 1); } static void free_item (gpointer data) { Item *item = fix_pointer (data); item->seq->n_items--; g_free (item); } static void seq_foreach (gpointer data, gpointer user_data) { Item *item = fix_pointer (data); GList **link = user_data; GSequenceIter *iter; g_assert (*link != NULL); iter = (*link)->data; g_assert (get_item (iter) == item); item->number = g_random_int(); *link = (*link)->next; } static gint simple_items_cmp (gconstpointer a, gconstpointer b, gpointer data) { const Item *item_a = fix_pointer (a); const Item *item_b = fix_pointer (b); if (item_a->number > item_b->number) return +1; else if (item_a->number < item_b->number) return -1; else return 0; } static gint simple_iters_cmp (gconstpointer a, gconstpointer b, gpointer data) { GSequence *seq = data; GSequenceIter *iter_a = (GSequenceIter *)a; GSequenceIter *iter_b = (GSequenceIter *)b; gpointer item_a = g_sequence_get (iter_a); gpointer item_b = g_sequence_get (iter_b); if (seq) { g_assert (g_sequence_iter_get_sequence (iter_a) == seq); g_assert (g_sequence_iter_get_sequence (iter_b) == seq); } return simple_items_cmp (item_a, item_b, data); } static gint compare_items (gconstpointer a, gconstpointer b, gpointer data) { const Item *item_a = fix_pointer (a); const Item *item_b = fix_pointer (b); if (item_a->number < item_b->number) { return -1; } else if (item_a->number == item_b->number) { /* Force an arbitrary order on the items * We have to do this, since g_queue_insert_sorted() and * g_sequence_insert_sorted() do not agree on the exact * position the item is inserted if the new item is * equal to an existing one. */ if (item_a < item_b) return -1; else if (item_a == item_b) return 0; else return 1; } else { return 1; } } static void check_sorted (SequenceInfo *info) { GList *list; int last; GSequenceIter *last_iter; check_integrity (info); last = G_MININT; last_iter = NULL; for (list = info->queue->head; list != NULL; list = list->next) { GSequenceIter *iter = list->data; Item *item = get_item (iter); g_assert (item->number >= last); /* Check that the ordering is the same as that of the queue, * ie. that the sort is stable */ if (last_iter) g_assert (iter == g_sequence_iter_next (last_iter)); last = item->number; last_iter = iter; } } static gint compare_iters (gconstpointer a, gconstpointer b, gpointer data) { GSequence *seq = data; GSequenceIter *iter_a = (GSequenceIter *)a; GSequenceIter *iter_b = (GSequenceIter *)b; /* compare_items() will fix up the pointers */ Item *item_a = g_sequence_get (iter_a); Item *item_b = g_sequence_get (iter_b); if (seq) { g_assert (g_sequence_iter_get_sequence (iter_a) == seq); g_assert (g_sequence_iter_get_sequence (iter_b) == seq); } return compare_items (item_a, item_b, data); } /* A version of g_queue_link_index() that treats NULL as just * beyond the queue */ static int queue_link_index (SequenceInfo *seq, GList *link) { if (link) return g_queue_link_index (seq->queue, link); else return g_queue_get_length (seq->queue); } static void get_random_range (SequenceInfo *seq, GSequenceIter **begin_iter, GSequenceIter **end_iter, GList **begin_link, GList **end_link) { int length = g_queue_get_length (seq->queue); int b = g_random_int_range (0, length + 1); int e = g_random_int_range (b, length + 1); g_assert (length == g_sequence_get_length (seq->sequence)); if (begin_iter) *begin_iter = g_sequence_get_iter_at_pos (seq->sequence, b); if (end_iter) *end_iter = g_sequence_get_iter_at_pos (seq->sequence, e); if (begin_link) *begin_link = g_queue_peek_nth_link (seq->queue, b); if (end_link) *end_link = g_queue_peek_nth_link (seq->queue, e); if (begin_iter && begin_link) { g_assert ( queue_link_index (seq, *begin_link) == g_sequence_iter_get_position (*begin_iter)); } if (end_iter && end_link) { g_assert ( queue_link_index (seq, *end_link) == g_sequence_iter_get_position (*end_iter)); } } static gint get_random_position (SequenceInfo *seq) { int length = g_queue_get_length (seq->queue); g_assert (length == g_sequence_get_length (seq->sequence)); return g_random_int_range (-2, length + 5); } static GSequenceIter * get_random_iter (SequenceInfo *seq, GList **link) { GSequenceIter *iter; int pos = get_random_position (seq); if (link) *link = g_queue_peek_nth_link (seq->queue, pos); iter = g_sequence_get_iter_at_pos (seq->sequence, pos); if (link) g_assert (queue_link_index (seq, *link) == g_sequence_iter_get_position (iter)); return iter; } static void dump_info (SequenceInfo *seq) { #if 0 GSequenceIter *iter; GList *list; iter = g_sequence_get_begin_iter (seq->sequence); list = seq->queue->head; while (iter != g_sequence_get_end_iter (seq->sequence)) { Item *item = get_item (iter); g_printerr ("%p %p %d\n", list->data, iter, item->number); iter = g_sequence_iter_next (iter); list = list->next; } #endif } static void run_random_tests (gconstpointer d) { guint32 seed = GPOINTER_TO_UINT (d); #define N_ITERATIONS 60000 #define N_SEQUENCES 8 #define N_TIMES 24 SequenceInfo sequences[N_SEQUENCES]; int k; #if 0 g_printerr (" seed: %u\n", seed); #endif g_random_set_seed (seed); for (k = 0; k < N_SEQUENCES; ++k) { sequences[k].queue = g_queue_new (); sequences[k].sequence = g_sequence_new (free_item); sequences[k].n_items = 0; } #define RANDOM_SEQUENCE() &(sequences[g_random_int_range (0, N_SEQUENCES)]) for (k = 0; k < N_ITERATIONS; ++k) { int i; SequenceInfo *seq = RANDOM_SEQUENCE(); int op = g_random_int_range (0, N_OPS); #if 0 g_printerr ("%d on %p\n", op, seq); #endif switch (op) { case NEW: case FREE: { g_queue_free (seq->queue); g_sequence_free (seq->sequence); g_assert (seq->n_items == 0); seq->queue = g_queue_new (); seq->sequence = g_sequence_new (free_item); check_integrity (seq); } break; case GET_LENGTH: { int slen = g_sequence_get_length (seq->sequence); int qlen = g_queue_get_length (seq->queue); g_assert (slen == qlen); } break; case FOREACH: { GList *link = seq->queue->head; g_sequence_foreach (seq->sequence, seq_foreach, &link); g_assert (link == NULL); } break; case FOREACH_RANGE: { GSequenceIter *begin_iter, *end_iter; GList *begin_link, *end_link; get_random_range (seq, &begin_iter, &end_iter, &begin_link, &end_link); check_integrity (seq); g_sequence_foreach_range (begin_iter, end_iter, seq_foreach, &begin_link); g_assert (begin_link == end_link); } break; case SORT: { dump_info (seq); g_sequence_sort (seq->sequence, compare_items, NULL); g_queue_sort (seq->queue, compare_iters, NULL); check_sorted (seq); dump_info (seq); } break; case SORT_ITER: { check_integrity (seq); g_sequence_sort_iter (seq->sequence, (GSequenceIterCompareFunc)compare_iters, seq->sequence); g_queue_sort (seq->queue, compare_iters, NULL); check_sorted (seq); } break; /* Getting iters */ case GET_END_ITER: case GET_BEGIN_ITER: { GSequenceIter *begin_iter; GSequenceIter *end_iter; GSequenceIter *penultimate_iter; begin_iter = g_sequence_get_begin_iter (seq->sequence); check_integrity (seq); end_iter = g_sequence_get_end_iter (seq->sequence); check_integrity (seq); penultimate_iter = g_sequence_iter_prev (end_iter); check_integrity (seq); if (g_sequence_get_length (seq->sequence) > 0) { g_assert (seq->queue->head); g_assert (seq->queue->head->data == begin_iter); g_assert (seq->queue->tail); g_assert (seq->queue->tail->data == penultimate_iter); } else { g_assert (penultimate_iter == end_iter); g_assert (begin_iter == end_iter); g_assert (penultimate_iter == begin_iter); g_assert (seq->queue->head == NULL); g_assert (seq->queue->tail == NULL); } } break; case GET_ITER_AT_POS: { int i; g_assert (g_queue_get_length (seq->queue) == g_sequence_get_length (seq->sequence)); for (i = 0; i < 10; ++i) { int pos = get_random_position (seq); GSequenceIter *iter = g_sequence_get_iter_at_pos (seq->sequence, pos); GList *link = g_queue_peek_nth_link (seq->queue, pos); check_integrity (seq); if (pos >= g_sequence_get_length (seq->sequence) || pos < 0) { g_assert (iter == g_sequence_get_end_iter (seq->sequence)); g_assert (link == NULL); } else { g_assert (link); g_assert (link->data == iter); } } } break; case APPEND: { for (i = 0; i < 10; ++i) { GSequenceIter *iter = g_sequence_append (seq->sequence, new_item (seq)); g_queue_push_tail (seq->queue, iter); } } break; case PREPEND: { for (i = 0; i < 10; ++i) { GSequenceIter *iter = g_sequence_prepend (seq->sequence, new_item (seq)); g_queue_push_head (seq->queue, iter); } } break; case INSERT_BEFORE: { for (i = 0; i < 10; ++i) { GList *link; GSequenceIter *iter = get_random_iter (seq, &link); GSequenceIter *new_iter; check_integrity (seq); new_iter = g_sequence_insert_before (iter, new_item (seq)); g_queue_insert_before (seq->queue, link, new_iter); } } break; case MOVE: { GList *link1, *link2; SequenceInfo *seq1 = RANDOM_SEQUENCE(); SequenceInfo *seq2 = RANDOM_SEQUENCE(); GSequenceIter *iter1 = get_random_iter (seq1, &link1); GSequenceIter *iter2 = get_random_iter (seq2, &link2); if (!g_sequence_iter_is_end (iter1)) { g_sequence_move (iter1, iter2); if (!link2) g_assert (g_sequence_iter_is_end (iter2)); g_queue_insert_before (seq2->queue, link2, link1->data); g_queue_delete_link (seq1->queue, link1); get_item (iter1)->seq = seq2; seq1->n_items--; seq2->n_items++; } check_integrity (seq); iter1 = get_random_iter (seq, NULL); /* Moving an iter to itself should have no effect */ if (!g_sequence_iter_is_end (iter1)) g_sequence_move (iter1, iter1); } break; case SWAP: { GList *link1, *link2; SequenceInfo *seq1 = RANDOM_SEQUENCE(); SequenceInfo *seq2 = RANDOM_SEQUENCE(); GSequenceIter *iter1 = get_random_iter (seq1, &link1); GSequenceIter *iter2 = get_random_iter (seq2, &link2); if (!g_sequence_iter_is_end (iter1) && !g_sequence_iter_is_end (iter2)) { gpointer tmp; g_sequence_swap (iter1, iter2); get_item (iter1)->seq = seq2; get_item (iter2)->seq = seq1; tmp = link1->data; link1->data = link2->data; link2->data = tmp; } } break; case INSERT_SORTED: { int i; dump_info (seq); g_sequence_sort (seq->sequence, compare_items, NULL); g_queue_sort (seq->queue, compare_iters, NULL); check_sorted (seq); for (i = 0; i < N_TIMES; ++i) { GSequenceIter *iter = g_sequence_insert_sorted (seq->sequence, new_item(seq), compare_items, NULL); g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL); } check_sorted (seq); dump_info (seq); } break; case INSERT_SORTED_ITER: { int i; dump_info (seq); g_sequence_sort (seq->sequence, compare_items, NULL); g_queue_sort (seq->queue, compare_iters, NULL); check_sorted (seq); for (i = 0; i < N_TIMES; ++i) { GSequenceIter *iter; iter = g_sequence_insert_sorted_iter (seq->sequence, new_item (seq), (GSequenceIterCompareFunc)compare_iters, seq->sequence); g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL); } check_sorted (seq); dump_info (seq); } break; case SORT_CHANGED: { int i; g_sequence_sort (seq->sequence, compare_items, NULL); g_queue_sort (seq->queue, compare_iters, NULL); check_sorted (seq); for (i = 0; i < N_TIMES; ++i) { GList *link; GSequenceIter *iter = get_random_iter (seq, &link); if (!g_sequence_iter_is_end (iter)) { g_sequence_set (iter, new_item (seq)); g_sequence_sort_changed (iter, compare_items, NULL); g_queue_delete_link (seq->queue, link); g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL); } check_sorted (seq); } } break; case SORT_CHANGED_ITER: { int i; g_sequence_sort (seq->sequence, compare_items, NULL); g_queue_sort (seq->queue, compare_iters, NULL); check_sorted (seq); for (i = 0; i < N_TIMES; ++i) { GList *link; GSequenceIter *iter = get_random_iter (seq, &link); if (!g_sequence_iter_is_end (iter)) { g_sequence_set (iter, new_item (seq)); g_sequence_sort_changed_iter (iter, (GSequenceIterCompareFunc)compare_iters, seq->sequence); g_queue_delete_link (seq->queue, link); g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL); } check_sorted (seq); } } break; case REMOVE: { int i; for (i = 0; i < N_TIMES; ++i) { GList *link; GSequenceIter *iter = get_random_iter (seq, &link); if (!g_sequence_iter_is_end (iter)) { g_sequence_remove (iter); g_queue_delete_link (seq->queue, link); } } } break; case REMOVE_RANGE: { GSequenceIter *begin_iter, *end_iter; GList *begin_link, *end_link; GList *list; get_random_range (seq, &begin_iter, &end_iter, &begin_link, &end_link); g_sequence_remove_range (begin_iter, end_iter); list = begin_link; while (list != end_link) { GList *next = list->next; g_queue_delete_link (seq->queue, list); list = next; } } break; case MOVE_RANGE: { SequenceInfo *src = RANDOM_SEQUENCE(); SequenceInfo *dst = RANDOM_SEQUENCE(); GSequenceIter *begin_iter, *end_iter; GList *begin_link, *end_link; GSequenceIter *dst_iter; GList *dst_link; GList *list; g_assert (src->queue); g_assert (dst->queue); get_random_range (src, &begin_iter, &end_iter, &begin_link, &end_link); dst_iter = get_random_iter (dst, &dst_link); g_sequence_move_range (dst_iter, begin_iter, end_iter); if (dst_link == begin_link || (src == dst && dst_link == end_link)) { check_integrity (src); check_integrity (dst); break; } if (queue_link_index (src, begin_link) >= queue_link_index (src, end_link)) { break; } if (src == dst && queue_link_index (src, dst_link) >= queue_link_index (src, begin_link) && queue_link_index (src, dst_link) <= queue_link_index (src, end_link)) { break; } list = begin_link; while (list != end_link) { GList *next = list->next; Item *item = get_item (list->data); g_assert (dst->queue); g_queue_insert_before (dst->queue, dst_link, list->data); g_queue_delete_link (src->queue, list); g_assert (item->seq == src); src->n_items--; dst->n_items++; item->seq = dst; list = next; } } break; case SEARCH: { Item *item; GSequenceIter *search_iter; GSequenceIter *insert_iter; g_sequence_sort (seq->sequence, compare_items, NULL); g_queue_sort (seq->queue, compare_iters, NULL); check_sorted (seq); item = new_item (seq); search_iter = g_sequence_search (seq->sequence, item, compare_items, NULL); insert_iter = g_sequence_insert_sorted (seq->sequence, item, compare_items, NULL); g_assert (search_iter == g_sequence_iter_next (insert_iter)); g_queue_insert_sorted (seq->queue, insert_iter, compare_iters, NULL); } break; case SEARCH_ITER: { Item *item; GSequenceIter *search_iter; GSequenceIter *insert_iter; g_sequence_sort (seq->sequence, compare_items, NULL); g_queue_sort (seq->queue, compare_iters, NULL); check_sorted (seq); item = new_item (seq); search_iter = g_sequence_search_iter (seq->sequence, item, (GSequenceIterCompareFunc)compare_iters, seq->sequence); insert_iter = g_sequence_insert_sorted (seq->sequence, item, compare_items, NULL); g_assert (search_iter == g_sequence_iter_next (insert_iter)); g_queue_insert_sorted (seq->queue, insert_iter, compare_iters, NULL); } break; case LOOKUP: { Item *item; GSequenceIter *lookup_iter; GSequenceIter *insert_iter; g_sequence_sort (seq->sequence, compare_items, NULL); g_queue_sort (seq->queue, compare_iters, NULL); check_sorted (seq); item = new_item (seq); insert_iter = g_sequence_insert_sorted (seq->sequence, item, compare_items, NULL); g_queue_insert_sorted (seq->queue, insert_iter, compare_iters, NULL); lookup_iter = g_sequence_lookup (seq->sequence, item, simple_items_cmp, NULL); g_assert (simple_iters_cmp (insert_iter, lookup_iter, NULL) == 0); } break; case LOOKUP_ITER: { Item *item; GSequenceIter *lookup_iter; GSequenceIter *insert_iter; g_sequence_sort (seq->sequence, compare_items, NULL); g_queue_sort (seq->queue, compare_iters, NULL); check_sorted (seq); item = new_item (seq); insert_iter = g_sequence_insert_sorted (seq->sequence, item, compare_items, NULL); g_queue_insert_sorted (seq->queue, insert_iter, compare_iters, NULL); lookup_iter = g_sequence_lookup_iter (seq->sequence, item, (GSequenceIterCompareFunc) simple_iters_cmp, NULL); g_assert (simple_iters_cmp (insert_iter, lookup_iter, NULL) == 0); } break; /* dereferencing */ case GET: case SET: { GSequenceIter *iter; GList *link; iter = get_random_iter (seq, &link); if (!g_sequence_iter_is_end (iter)) { Item *item; int i; check_integrity (seq); /* Test basic functionality */ item = new_item (seq); g_sequence_set (iter, item); g_assert (g_sequence_get (iter) == item); /* Make sure that existing items are freed */ for (i = 0; i < N_TIMES; ++i) g_sequence_set (iter, new_item (seq)); check_integrity (seq); g_sequence_set (iter, new_item (seq)); } } break; /* operations on GSequenceIter * */ case ITER_IS_BEGIN: { GSequenceIter *iter; iter = g_sequence_get_iter_at_pos (seq->sequence, 0); g_assert (g_sequence_iter_is_begin (iter)); check_integrity (seq); if (g_sequence_get_length (seq->sequence) > 0) { g_assert (!g_sequence_iter_is_begin (g_sequence_get_end_iter (seq->sequence))); } else { g_assert (g_sequence_iter_is_begin (g_sequence_get_end_iter (seq->sequence))); } g_assert (g_sequence_iter_is_begin (g_sequence_get_begin_iter (seq->sequence))); } break; case ITER_IS_END: { GSequenceIter *iter; int len = g_sequence_get_length (seq->sequence); iter = g_sequence_get_iter_at_pos (seq->sequence, len); g_assert (g_sequence_iter_is_end (iter)); if (len > 0) { g_assert (!g_sequence_iter_is_end (g_sequence_get_begin_iter (seq->sequence))); } else { g_assert (g_sequence_iter_is_end (g_sequence_get_begin_iter (seq->sequence))); } g_assert (g_sequence_iter_is_end (g_sequence_get_end_iter (seq->sequence))); } break; case ITER_NEXT: { GSequenceIter *iter1, *iter2, *iter3, *end; iter1 = g_sequence_append (seq->sequence, new_item (seq)); iter2 = g_sequence_append (seq->sequence, new_item (seq)); iter3 = g_sequence_append (seq->sequence, new_item (seq)); end = g_sequence_get_end_iter (seq->sequence); g_assert (g_sequence_iter_next (iter1) == iter2); g_assert (g_sequence_iter_next (iter2) == iter3); g_assert (g_sequence_iter_next (iter3) == end); g_assert (g_sequence_iter_next (end) == end); g_queue_push_tail (seq->queue, iter1); g_queue_push_tail (seq->queue, iter2); g_queue_push_tail (seq->queue, iter3); } break; case ITER_PREV: { GSequenceIter *iter1, *iter2, *iter3, *begin; iter1 = g_sequence_prepend (seq->sequence, new_item (seq)); iter2 = g_sequence_prepend (seq->sequence, new_item (seq)); iter3 = g_sequence_prepend (seq->sequence, new_item (seq)); begin = g_sequence_get_begin_iter (seq->sequence); g_assert (g_sequence_iter_prev (iter1) == iter2); g_assert (g_sequence_iter_prev (iter2) == iter3); g_assert (iter3 == begin); g_assert (g_sequence_iter_prev (iter3) == begin); g_assert (g_sequence_iter_prev (begin) == begin); g_queue_push_head (seq->queue, iter1); g_queue_push_head (seq->queue, iter2); g_queue_push_head (seq->queue, iter3); } break; case ITER_GET_POSITION: { GList *link; GSequenceIter *iter = get_random_iter (seq, &link); g_assert (g_sequence_iter_get_position (iter) == queue_link_index (seq, link)); } break; case ITER_MOVE: { int len = g_sequence_get_length (seq->sequence); GSequenceIter *iter; int pos; iter = get_random_iter (seq, NULL); pos = g_sequence_iter_get_position (iter); iter = g_sequence_iter_move (iter, len - pos); g_assert (g_sequence_iter_is_end (iter)); iter = get_random_iter (seq, NULL); pos = g_sequence_iter_get_position (iter); while (pos < len) { g_assert (!g_sequence_iter_is_end (iter)); pos++; iter = g_sequence_iter_move (iter, 1); } g_assert (g_sequence_iter_is_end (iter)); } break; case ITER_GET_SEQUENCE: { GSequenceIter *iter = get_random_iter (seq, NULL); g_assert (g_sequence_iter_get_sequence (iter) == seq->sequence); } break; /* search */ case ITER_COMPARE: { GList *link1, *link2; GSequenceIter *iter1 = get_random_iter (seq, &link1); GSequenceIter *iter2 = get_random_iter (seq, &link2); int cmp = g_sequence_iter_compare (iter1, iter2); int pos1 = queue_link_index (seq, link1); int pos2 = queue_link_index (seq, link2); if (cmp == 0) { g_assert (pos1 == pos2); } else if (cmp < 0) { g_assert (pos1 < pos2); } else { g_assert (pos1 > pos2); } } break; case RANGE_GET_MIDPOINT: { GSequenceIter *iter1 = get_random_iter (seq, NULL); GSequenceIter *iter2 = get_random_iter (seq, NULL); GSequenceIter *iter3; int cmp; cmp = g_sequence_iter_compare (iter1, iter2); if (cmp > 0) { GSequenceIter *tmp; tmp = iter1; iter1 = iter2; iter2 = tmp; } iter3 = g_sequence_range_get_midpoint (iter1, iter2); if (cmp == 0) { g_assert (iter3 == iter1); g_assert (iter3 == iter2); } g_assert (g_sequence_iter_get_position (iter3) >= g_sequence_iter_get_position (iter1)); g_assert (g_sequence_iter_get_position (iter2) >= g_sequence_iter_get_position (iter3)); } break; } check_integrity (seq); } for (k = 0; k < N_SEQUENCES; ++k) { g_queue_free (sequences[k].queue); g_sequence_free (sequences[k].sequence); sequences[k].n_items = 0; } } /* Random seeds known to have failed at one point */ static gulong seeds[] = { 825541564u, 801678400u, 1477639090u, 3369132895u, 1192944867u, 770458294u, 1099575817u, 590523467u, 3583571454u, 579241222u }; /* Single, stand-alone tests */ static void test_out_of_range_jump (void) { GSequence *seq = g_sequence_new (NULL); GSequenceIter *iter = g_sequence_get_begin_iter (seq); g_sequence_iter_move (iter, 5); g_assert (g_sequence_iter_is_begin (iter)); g_assert (g_sequence_iter_is_end (iter)); g_sequence_free (seq); } static void test_iter_move (void) { GSequence *seq = g_sequence_new (NULL); GSequenceIter *iter; gint i; for (i = 0; i < 10; ++i) g_sequence_append (seq, GINT_TO_POINTER (i)); iter = g_sequence_get_begin_iter (seq); iter = g_sequence_iter_move (iter, 5); g_assert_cmpint (GPOINTER_TO_INT (g_sequence_get (iter)), ==, 5); iter = g_sequence_iter_move (iter, -10); g_assert (g_sequence_iter_is_begin (iter)); iter = g_sequence_get_end_iter (seq); iter = g_sequence_iter_move (iter, -5); g_assert_cmpint (GPOINTER_TO_INT (g_sequence_get (iter)), ==, 5); iter = g_sequence_iter_move (iter, 10); g_assert (g_sequence_iter_is_end (iter)); g_sequence_free (seq); } static int compare (gconstpointer a, gconstpointer b, gpointer userdata) { int ai, bi; ai = GPOINTER_TO_INT (a); bi = GPOINTER_TO_INT (b); if (ai < bi) return -1; else if (ai > bi) return 1; else return 0; } static int compare_iter (GSequenceIter *a, GSequenceIter *b, gpointer data) { return compare (g_sequence_get (a), g_sequence_get (b), data); } static void test_insert_sorted_non_pointer (void) { int i; for (i = 0; i < 10; i++) { GSequence *seq = g_sequence_new (NULL); int j; for (j = 0; j < 10000; j++) { g_sequence_insert_sorted (seq, GINT_TO_POINTER (g_random_int()), compare, NULL); g_sequence_insert_sorted_iter (seq, GINT_TO_POINTER (g_random_int()), compare_iter, NULL); } g_sequence_check (seq); g_sequence_free (seq); } } static void test_stable_sort (void) { int i; GSequence *seq = g_sequence_new (NULL); #define N_ITEMS 1000 GSequenceIter *iters[N_ITEMS]; GSequenceIter *iter; for (i = 0; i < N_ITEMS; ++i) { iters[i] = g_sequence_append (seq, GINT_TO_POINTER (3000)); g_sequence_check (seq); g_assert (g_sequence_iter_get_sequence (iters[i]) == seq); } i = 0; iter = g_sequence_get_begin_iter (seq); g_assert (g_sequence_iter_get_sequence (iter) == seq); g_sequence_check (seq); while (!g_sequence_iter_is_end (iter)) { g_assert (g_sequence_iter_get_sequence (iters[i]) == seq); g_assert (iters[i++] == iter); iter = g_sequence_iter_next (iter); g_sequence_check (seq); } g_sequence_sort (seq, compare, NULL); i = 0; iter = g_sequence_get_begin_iter (seq); while (!g_sequence_iter_is_end (iter)) { g_assert (g_sequence_iter_get_sequence (iters[i]) == seq); g_assert (iters[i] == iter); iter = g_sequence_iter_next (iter); g_sequence_check (seq); i++; } for (i = N_ITEMS - 1; i >= 0; --i) { g_sequence_check (seq); g_assert (g_sequence_iter_get_sequence (iters[i]) == seq); g_assert (g_sequence_get_end_iter (seq) != iters[i]); g_sequence_sort_changed (iters[i], compare, NULL); } i = 0; iter = g_sequence_get_begin_iter (seq); while (!g_sequence_iter_is_end (iter)) { g_assert (iters[i++] == iter); iter = g_sequence_iter_next (iter); g_sequence_check (seq); } g_sequence_free (seq); } static void test_empty (void) { GSequence *seq; int i; seq = g_sequence_new (NULL); g_assert_true (g_sequence_is_empty (seq)); for (i = 0; i < 1000; i++) { g_sequence_append (seq, GINT_TO_POINTER (i)); g_assert_false (g_sequence_is_empty (seq)); } for (i = 0; i < 1000; i++) { GSequenceIter *end = g_sequence_get_end_iter (seq); g_assert_false (g_sequence_is_empty (seq)); g_sequence_remove (g_sequence_iter_prev (end)); } g_assert_true (g_sequence_is_empty (seq)); } int main (int argc, char **argv) { gint i; guint32 seed; gchar *path; g_test_init (&argc, &argv, NULL); /* Standalone tests */ g_test_add_func ("/sequence/out-of-range-jump", test_out_of_range_jump); g_test_add_func ("/sequence/iter-move", test_iter_move); g_test_add_func ("/sequence/insert-sorted-non-pointer", test_insert_sorted_non_pointer); g_test_add_func ("/sequence/stable-sort", test_stable_sort); g_test_add_func ("/sequence/is_empty", test_empty); /* Regression tests */ for (i = 0; i < G_N_ELEMENTS (seeds); ++i) { path = g_strdup_printf ("/sequence/random/seed:%lu", seeds[i]); g_test_add_data_func (path, GUINT_TO_POINTER (seeds[i]), run_random_tests); g_free (path); } /* New random seed */ seed = g_test_rand_int_range (0, G_MAXINT); path = g_strdup_printf ("/sequence/random/seed:%u", seed); g_test_add_data_func (path, GUINT_TO_POINTER (seed), run_random_tests); g_free (path); return g_test_run (); }