diff --git a/glib/gqueue.c b/glib/gqueue.c index e8c938a25..0cc7ab200 100644 --- a/glib/gqueue.c +++ b/glib/gqueue.c @@ -519,8 +519,10 @@ g_queue_push_nth_link (GQueue *queue, if (queue->head->prev) queue->head = queue->head->prev; - if (queue->tail->next) - queue->tail = queue->tail->next; + /* The case where we’re pushing @link_ at the end of @queue is handled above + * using g_queue_push_tail_link(), so we should never have to manually adjust + * queue->tail. */ + g_assert (queue->tail->next == NULL); queue->length++; } diff --git a/glib/tests/queue.c b/glib/tests/queue.c index b2faeb14a..dd9dd2127 100644 --- a/glib/tests/queue.c +++ b/glib/tests/queue.c @@ -1083,18 +1083,136 @@ test_clear_full (void) g_assert_true (three->freed); g_assert_true (four->freed); + g_assert_true (g_queue_is_empty (queue)); check_integrity (queue); g_slice_free (QueueItem, one); g_slice_free (QueueItem, two); g_slice_free (QueueItem, three); g_slice_free (QueueItem, four); + g_queue_free (queue); +} + +/* Check that g_queue_clear_full() called with a NULL free_func is equivalent + * to g_queue_clear(). */ +static void +test_clear_full_noop (void) +{ + QueueItem *one, *two, *three, *four; + GQueue *queue; + + queue = g_queue_new (); + g_queue_push_tail (queue, one = new_item (1)); + g_queue_push_tail (queue, two = new_item (2)); + g_queue_push_tail (queue, three = new_item (3)); + g_queue_push_tail (queue, four = new_item (4)); + + g_assert_cmpint (g_queue_get_length (queue), ==, 4); + g_assert_false (one->freed); + g_assert_false (two->freed); + g_assert_false (three->freed); + g_assert_false (four->freed); + + g_queue_clear_full (queue, NULL); g_assert_true (g_queue_is_empty (queue)); + check_integrity (queue); + g_slice_free (QueueItem, one); + g_slice_free (QueueItem, two); + g_slice_free (QueueItem, three); + g_slice_free (QueueItem, four); g_queue_free (queue); } +/* Test g_queue_push_nth_link() with various combinations of position (before, + * in the middle of, or at the end of the queue) and various existing queues + * (empty, single element, multiple elements). */ +static void +test_push_nth_link (void) +{ + GQueue *q; + q = g_queue_new (); + + /* Push onto before the front of an empty queue (which results in it being + * added to the end of the queue). */ + g_queue_push_nth_link (q, -1, g_list_prepend (NULL, GINT_TO_POINTER (1))); + check_integrity (q); + g_assert_cmpint (g_queue_get_length (q), ==, 1); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 0)), ==, 1); + + g_queue_clear (q); + + /* Push onto after the rear of an empty queue. */ + g_queue_push_nth_link (q, 100, g_list_prepend (NULL, GINT_TO_POINTER (2))); + check_integrity (q); + g_assert_cmpint (g_queue_get_length (q), ==, 1); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 0)), ==, 2); + + g_queue_clear (q); + + /* Push onto the front of an empty queue. */ + g_queue_push_nth_link (q, 0, g_list_prepend (NULL, GINT_TO_POINTER (3))); + check_integrity (q); + g_assert_cmpint (g_queue_get_length (q), ==, 1); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 0)), ==, 3); + + g_queue_clear (q); + + /* Push onto before the front of a non-empty queue (which results in it being + * added to the end of the queue). */ + g_queue_push_head (q, GINT_TO_POINTER (4)); + g_queue_push_nth_link (q, -1, g_list_prepend (NULL, GINT_TO_POINTER (5))); + check_integrity (q); + g_assert_cmpint (g_queue_get_length (q), ==, 2); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 0)), ==, 4); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 1)), ==, 5); + + g_queue_clear (q); + + /* Push onto after the rear of a non-empty queue. */ + g_queue_push_head (q, GINT_TO_POINTER (6)); + g_queue_push_nth_link (q, 100, g_list_prepend (NULL, GINT_TO_POINTER (7))); + check_integrity (q); + g_assert_cmpint (g_queue_get_length (q), ==, 2); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 0)), ==, 6); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 1)), ==, 7); + + g_queue_clear (q); + + /* Push onto the rear of a non-empty queue. */ + g_queue_push_head (q, GINT_TO_POINTER (8)); + g_queue_push_nth_link (q, 1, g_list_prepend (NULL, GINT_TO_POINTER (9))); + check_integrity (q); + g_assert_cmpint (g_queue_get_length (q), ==, 2); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 0)), ==, 8); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 1)), ==, 9); + + g_queue_clear (q); + + /* Push onto the front of a non-empty queue. */ + g_queue_push_head (q, GINT_TO_POINTER (10)); + g_queue_push_nth_link (q, 0, g_list_prepend (NULL, GINT_TO_POINTER (11))); + check_integrity (q); + g_assert_cmpint (g_queue_get_length (q), ==, 2); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 0)), ==, 11); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 1)), ==, 10); + + g_queue_clear (q); + + /* Push into the middle of a non-empty queue. */ + g_queue_push_head (q, GINT_TO_POINTER (12)); + g_queue_push_head (q, GINT_TO_POINTER (13)); + g_queue_push_nth_link (q, 1, g_list_prepend (NULL, GINT_TO_POINTER (14))); + check_integrity (q); + g_assert_cmpint (g_queue_get_length (q), ==, 3); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 0)), ==, 13); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 1)), ==, 14); + g_assert_cmpint (GPOINTER_TO_INT (g_queue_peek_nth (q, 2)), ==, 12); + + g_queue_free (q); +} + static void test_free_full (void) { @@ -1167,7 +1285,9 @@ int main (int argc, char *argv[]) g_test_add_func ("/queue/clear", test_clear); g_test_add_func ("/queue/free-full", test_free_full); g_test_add_func ("/queue/clear-full", test_clear_full); + g_test_add_func ("/queue/clear-full/noop", test_clear_full_noop); g_test_add_func ("/queue/insert-sibling-link", test_insert_sibling_link); + g_test_add_func ("/queue/push-nth-link", test_push_nth_link); seed = g_test_rand_int_range (0, G_MAXINT); path = g_strdup_printf ("/queue/random/seed:%u", seed);