~ubuntu-branches/ubuntu/natty/libgdata/natty-updates

« back to all changes in this revision

Viewing changes to gdata/tests/common.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2011-01-05 11:09:00 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20110105110900-gkjnbslnr18s45us
Tags: 0.8.0-0ubuntu1
* New upstream release
* debian/control:
  - Use gir1.2 packages
  - Use standards version 3.9.1
  - Add Vcs-Bzr link
  - Rename libgdata10 to libgdata11
* debian/rules:
  - Drop simple-patchsys.mk
* debian/source:
  - Use source version 3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
#include <glib-object.h>
22
22
#include <stdio.h>
23
23
#include <string.h>
 
24
#include <libxml/parser.h>
 
25
#include <libxml/xmlsave.h>
24
26
 
25
27
#include "common.h"
26
28
 
84
86
}
85
87
 
86
88
typedef struct {
 
89
        GDataBatchOperation *operation;
87
90
        guint op_id;
88
91
        GDataBatchOperationType operation_type;
89
92
        GDataEntry *entry;
96
99
static void
97
100
batch_operation_data_free (BatchOperationData *data)
98
101
{
 
102
        if (data->operation != NULL)
 
103
                g_object_unref (data->operation);
99
104
        if (data->entry != NULL)
100
105
                g_object_unref (data->entry);
101
106
        g_free (data->id);
110
115
{
111
116
        BatchOperationData *data = user_data;
112
117
 
 
118
        /* Mark the callback as having been run */
 
119
        g_object_set_data (G_OBJECT (data->operation), "test::called-callbacks",
 
120
                           GUINT_TO_POINTER (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (data->operation), "test::called-callbacks")) + 1));
 
121
 
113
122
        /* Check that the @operation_type and @operation_id matches those stored in @data */
114
123
        g_assert_cmpuint (operation_id, ==, data->op_id);
115
124
        g_assert_cmpuint (operation_type, ==, data->operation_type);
159
168
        BatchOperationData *data;
160
169
 
161
170
        data = g_slice_new (BatchOperationData);
 
171
        data->operation = g_object_ref (operation);
162
172
        data->op_id = 0;
163
173
        data->operation_type = GDATA_BATCH_OPERATION_QUERY;
164
174
        data->entry = g_object_ref (entry);
171
181
 
172
182
        data->op_id = op_id;
173
183
 
 
184
        /* We expect a callback to be called when the operation is run */
 
185
        g_object_set_data (G_OBJECT (operation), "test::expected-callbacks",
 
186
                           GUINT_TO_POINTER (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (operation), "test::expected-callbacks")) + 1));
 
187
 
174
188
        return op_id;
175
189
}
176
190
 
180
194
{
181
195
        BatchOperationData *data = user_data;
182
196
 
 
197
        /* Mark the callback as having been run */
 
198
        g_object_set_data (G_OBJECT (data->operation), "test::called-callbacks",
 
199
                           GUINT_TO_POINTER (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (data->operation), "test::called-callbacks")) + 1));
 
200
 
183
201
        /* Check that the @operation_type and @operation_id matches those stored in @data */
184
202
        g_assert_cmpuint (operation_id, ==, data->op_id);
185
203
        g_assert_cmpuint (operation_type, ==, data->operation_type);
225
243
        BatchOperationData *data;
226
244
 
227
245
        data = g_slice_new (BatchOperationData);
 
246
        data->operation = g_object_ref (operation);
228
247
        data->op_id = 0;
229
248
        data->operation_type = GDATA_BATCH_OPERATION_INSERTION;
230
249
        data->entry = g_object_ref (entry);
237
256
 
238
257
        data->op_id = op_id;
239
258
 
 
259
        /* We expect a callback to be called when the operation is run */
 
260
        g_object_set_data (G_OBJECT (operation), "test::expected-callbacks",
 
261
                           GUINT_TO_POINTER (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (operation), "test::expected-callbacks")) + 1));
 
262
 
240
263
        return op_id;
241
264
}
242
265
 
247
270
        BatchOperationData *data;
248
271
 
249
272
        data = g_slice_new (BatchOperationData);
 
273
        data->operation = g_object_ref (operation);
250
274
        data->op_id = 0;
251
275
        data->operation_type = GDATA_BATCH_OPERATION_UPDATE;
252
276
        data->entry = g_object_ref (entry);
259
283
 
260
284
        data->op_id = op_id;
261
285
 
 
286
        /* We expect a callback to be called when the operation is run */
 
287
        g_object_set_data (G_OBJECT (operation), "test::expected-callbacks",
 
288
                           GUINT_TO_POINTER (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (operation), "test::expected-callbacks")) + 1));
 
289
 
262
290
        return op_id;
263
291
}
264
292
 
267
295
{
268
296
        BatchOperationData *data = user_data;
269
297
 
 
298
        /* Mark the callback as having been run */
 
299
        g_object_set_data (G_OBJECT (data->operation), "test::called-callbacks",
 
300
                           GUINT_TO_POINTER (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (data->operation), "test::called-callbacks")) + 1));
 
301
 
270
302
        /* Check that the @operation_type and @operation_id matches those stored in @data */
271
303
        g_assert_cmpuint (operation_id, ==, data->op_id);
272
304
        g_assert_cmpuint (operation_type, ==, data->operation_type);
291
323
        BatchOperationData *data;
292
324
 
293
325
        data = g_slice_new (BatchOperationData);
 
326
        data->operation = g_object_ref (operation);
294
327
        data->op_id = 0;
295
328
        data->operation_type = GDATA_BATCH_OPERATION_DELETION;
296
329
        data->entry = g_object_ref (entry);
303
336
 
304
337
        data->op_id = op_id;
305
338
 
 
339
        /* We expect a callback to be called when the operation is run */
 
340
        g_object_set_data (G_OBJECT (operation), "test::expected-callbacks",
 
341
                           GUINT_TO_POINTER (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (operation), "test::expected-callbacks")) + 1));
 
342
 
306
343
        return op_id;
307
344
}
 
345
 
 
346
gboolean
 
347
gdata_test_batch_operation_run (GDataBatchOperation *operation, GCancellable *cancellable, GError **error)
 
348
{
 
349
        gboolean success = gdata_batch_operation_run (operation, cancellable, error);
 
350
 
 
351
        /* Assert that callbacks were called exactly once for each operation in the batch operation */
 
352
        g_assert_cmpuint (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (operation), "test::expected-callbacks")), ==,
 
353
                          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (operation), "test::called-callbacks")));
 
354
 
 
355
        return success;
 
356
}
 
357
 
 
358
gboolean
 
359
gdata_test_batch_operation_run_finish (GDataBatchOperation *operation, GAsyncResult *async_result, GError **error)
 
360
{
 
361
        gboolean success = gdata_batch_operation_run_finish (operation, async_result, error);
 
362
 
 
363
        /* Assert that callbacks were called exactly once for each operation in the batch operation */
 
364
        g_assert_cmpuint (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (operation), "test::expected-callbacks")), ==,
 
365
                          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (operation), "test::called-callbacks")));
 
366
 
 
367
        return success;
 
368
}
 
369
 
 
370
static gboolean
 
371
compare_xml_namespaces (xmlNs *ns1, xmlNs *ns2)
 
372
{
 
373
        if (ns1 == ns2)
 
374
                return TRUE;
 
375
 
 
376
        /* Compare various simple properties */
 
377
        if (ns1->type != ns2->type ||
 
378
            xmlStrcmp (ns1->href, ns2->href) != 0 ||
 
379
            xmlStrcmp (ns1->prefix, ns2->prefix) != 0 ||
 
380
            ns1->context != ns2->context) {
 
381
                return FALSE;
 
382
        }
 
383
 
 
384
        return TRUE;
 
385
}
 
386
 
 
387
static gboolean compare_xml_nodes (xmlNode *node1, xmlNode *node2);
 
388
 
 
389
static gboolean
 
390
compare_xml_node_lists (xmlNode *list1, xmlNode *list2)
 
391
{
 
392
        GHashTable *table;
 
393
        xmlNode *child;
 
394
 
 
395
        /* Compare their child elements. We iterate through the first linked list and, for each child node, iterate through the second linked list
 
396
         * comparing it against each node there. We keep a hashed set of nodes in the second linked list which have already been visited and compared
 
397
         * successfully, both for speed and to guarantee that one element in the second linked list doesn't match more than one in the first linked
 
398
         * list. We take this approach because we can't modify the second linked list in place to remove matched nodes.
 
399
         * Finally, we iterate through the second node list and check that all its elements are in the hash table (i.e. they've all been visited
 
400
         * exactly once).
 
401
         * This approach is O(n^2) in the number of nodes in the linked lists, but since we should be dealing with fairly narrow XML trees this should
 
402
         * be OK. */
 
403
        table = g_hash_table_new (g_direct_hash, g_direct_equal);
 
404
 
 
405
        for (child = list1; child != NULL; child = child->next) {
 
406
                xmlNode *other_child;
 
407
                gboolean matched = FALSE;
 
408
 
 
409
                for (other_child = list2; other_child != NULL; other_child = other_child->next) {
 
410
                        if (g_hash_table_lookup (table, other_child) != NULL)
 
411
                                continue;
 
412
 
 
413
                        if (compare_xml_nodes (child, other_child) == TRUE) {
 
414
                                g_hash_table_insert (table, other_child, other_child);
 
415
                                matched = TRUE;
 
416
                                break;
 
417
                        }
 
418
                }
 
419
 
 
420
                if (matched == FALSE) {
 
421
                        g_hash_table_destroy (table);
 
422
                        return FALSE;
 
423
                }
 
424
        }
 
425
 
 
426
        for (child = list2; child != NULL; child = child->next) {
 
427
                if (g_hash_table_lookup (table, child) == NULL) {
 
428
                        g_hash_table_destroy (table);
 
429
                        return FALSE;
 
430
                }
 
431
        }
 
432
 
 
433
        g_hash_table_destroy (table);
 
434
 
 
435
        return TRUE;
 
436
}
 
437
 
 
438
static gboolean
 
439
compare_xml_nodes (xmlNode *node1, xmlNode *node2)
 
440
{
 
441
        GHashTable *table;
 
442
        xmlAttr *attr1, *attr2;
 
443
        xmlNs *ns;
 
444
 
 
445
        if (node1 == node2)
 
446
                return TRUE;
 
447
 
 
448
        /* Compare various simple properties */
 
449
        if (node1->type != node2->type ||
 
450
            xmlStrcmp (node1->name, node2->name) != 0 ||
 
451
            compare_xml_namespaces (node1->ns, node2->ns) == FALSE ||
 
452
            xmlStrcmp (node1->content, node2->content) != 0) {
 
453
                return FALSE;
 
454
        }
 
455
 
 
456
        /* Compare their attributes. This is done in document order, which isn't strictly correct, since XML specifically does not apply an ordering
 
457
         * over attributes. However, it suffices for our needs. */
 
458
        for (attr1 = node1->properties, attr2 = node2->properties; attr1 != NULL && attr2 != NULL; attr1 = attr1->next, attr2 = attr2->next) {
 
459
                /* Compare various simple properties */
 
460
                if (attr1->type != attr2->type ||
 
461
                    xmlStrcmp (attr1->name, attr2->name) != 0 ||
 
462
                    compare_xml_namespaces (attr1->ns, attr2->ns) == FALSE ||
 
463
                    attr1->atype != attr2->atype) {
 
464
                        return FALSE;
 
465
                }
 
466
 
 
467
                /* Compare their child nodes (values represented as text and entity nodes) */
 
468
                if (compare_xml_node_lists (attr1->children, attr2->children) == FALSE)
 
469
                        return FALSE;
 
470
        }
 
471
 
 
472
        /* Stragglers? */
 
473
        if (attr1 != NULL || attr2 != NULL)
 
474
                return FALSE;
 
475
 
 
476
        /* Compare their namespace definitions regardless of order. Do this by inserting all the definitions from node1 into a hash table, then running
 
477
         * through the  definitions in node2 and ensuring they exist in the hash table, removing each one from the table as we go. Check there aren't
 
478
         * any left in the hash table afterwards. */
 
479
        table = g_hash_table_new (g_str_hash, g_str_equal);
 
480
 
 
481
        for (ns = node1->nsDef; ns != NULL; ns = ns->next) {
 
482
                /* Prefixes should be unique, but I trust libxml about as far as I can throw it. */
 
483
                if (g_hash_table_lookup (table, ns->prefix ? ns->prefix : (gpointer) "") != NULL) {
 
484
                        g_hash_table_destroy (table);
 
485
                        return FALSE;
 
486
                }
 
487
 
 
488
                g_hash_table_insert (table, ns->prefix ? (gpointer) ns->prefix : (gpointer) "", ns);
 
489
        }
 
490
 
 
491
        for (ns = node2->nsDef; ns != NULL; ns = ns->next) {
 
492
                xmlNs *original_ns = g_hash_table_lookup (table, ns->prefix ? ns->prefix : (gpointer) "");
 
493
 
 
494
                if (original_ns == NULL ||
 
495
                    compare_xml_namespaces (original_ns, ns) == FALSE) {
 
496
                        g_hash_table_destroy (table);
 
497
                        return FALSE;
 
498
                }
 
499
 
 
500
                g_hash_table_remove (table, ns->prefix ? ns->prefix : (gpointer) "");
 
501
        }
 
502
 
 
503
        if (g_hash_table_size (table) != 0) {
 
504
                g_hash_table_destroy (table);
 
505
                return FALSE;
 
506
        }
 
507
 
 
508
        g_hash_table_destroy (table);
 
509
 
 
510
        /* Compare their child nodes */
 
511
        if (compare_xml_node_lists (node1->children, node2->children) == FALSE)
 
512
                return FALSE;
 
513
 
 
514
        /* Success! */
 
515
        return TRUE;
 
516
}
 
517
 
 
518
gboolean
 
519
gdata_test_compare_xml (GDataParsable *parsable, const gchar *expected_xml, gboolean print_error)
 
520
{
 
521
        gboolean success;
 
522
        gchar *parsable_xml;
 
523
        xmlDoc *parsable_doc, *expected_doc;
 
524
 
 
525
        /* Get an XML string for the GDataParsable */
 
526
        parsable_xml = gdata_parsable_get_xml (parsable);
 
527
 
 
528
        /* Parse both the XML strings */
 
529
        parsable_doc = xmlReadMemory (parsable_xml, strlen (parsable_xml), "/dev/null", NULL, 0);
 
530
        expected_doc = xmlReadMemory (expected_xml, strlen (expected_xml), "/dev/null", NULL, 0);
 
531
 
 
532
        g_assert (parsable_doc != NULL && expected_doc != NULL);
 
533
 
 
534
        /* Recursively compare the two XML trees */
 
535
        success = compare_xml_nodes (xmlDocGetRootElement (parsable_doc), xmlDocGetRootElement (expected_doc));
 
536
        if (success == FALSE && print_error == TRUE) {
 
537
                /* The comparison has failed, so print out the two XML strings for ease of debugging */
 
538
                g_message ("\n\nParsable: %s\n\nExpected: %s\n\n", parsable_xml, expected_xml);
 
539
        }
 
540
 
 
541
        xmlFreeDoc (expected_doc);
 
542
        xmlFreeDoc (parsable_doc);
 
543
        g_free (parsable_xml);
 
544
 
 
545
        return success;
 
546
}