304
337
data->op_id = op_id;
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));
347
gdata_test_batch_operation_run (GDataBatchOperation *operation, GCancellable *cancellable, GError **error)
349
gboolean success = gdata_batch_operation_run (operation, cancellable, error);
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")));
359
gdata_test_batch_operation_run_finish (GDataBatchOperation *operation, GAsyncResult *async_result, GError **error)
361
gboolean success = gdata_batch_operation_run_finish (operation, async_result, error);
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")));
371
compare_xml_namespaces (xmlNs *ns1, xmlNs *ns2)
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) {
387
static gboolean compare_xml_nodes (xmlNode *node1, xmlNode *node2);
390
compare_xml_node_lists (xmlNode *list1, xmlNode *list2)
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
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
403
table = g_hash_table_new (g_direct_hash, g_direct_equal);
405
for (child = list1; child != NULL; child = child->next) {
406
xmlNode *other_child;
407
gboolean matched = FALSE;
409
for (other_child = list2; other_child != NULL; other_child = other_child->next) {
410
if (g_hash_table_lookup (table, other_child) != NULL)
413
if (compare_xml_nodes (child, other_child) == TRUE) {
414
g_hash_table_insert (table, other_child, other_child);
420
if (matched == FALSE) {
421
g_hash_table_destroy (table);
426
for (child = list2; child != NULL; child = child->next) {
427
if (g_hash_table_lookup (table, child) == NULL) {
428
g_hash_table_destroy (table);
433
g_hash_table_destroy (table);
439
compare_xml_nodes (xmlNode *node1, xmlNode *node2)
442
xmlAttr *attr1, *attr2;
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) {
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) {
467
/* Compare their child nodes (values represented as text and entity nodes) */
468
if (compare_xml_node_lists (attr1->children, attr2->children) == FALSE)
473
if (attr1 != NULL || attr2 != NULL)
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);
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);
488
g_hash_table_insert (table, ns->prefix ? (gpointer) ns->prefix : (gpointer) "", ns);
491
for (ns = node2->nsDef; ns != NULL; ns = ns->next) {
492
xmlNs *original_ns = g_hash_table_lookup (table, ns->prefix ? ns->prefix : (gpointer) "");
494
if (original_ns == NULL ||
495
compare_xml_namespaces (original_ns, ns) == FALSE) {
496
g_hash_table_destroy (table);
500
g_hash_table_remove (table, ns->prefix ? ns->prefix : (gpointer) "");
503
if (g_hash_table_size (table) != 0) {
504
g_hash_table_destroy (table);
508
g_hash_table_destroy (table);
510
/* Compare their child nodes */
511
if (compare_xml_node_lists (node1->children, node2->children) == FALSE)
519
gdata_test_compare_xml (GDataParsable *parsable, const gchar *expected_xml, gboolean print_error)
523
xmlDoc *parsable_doc, *expected_doc;
525
/* Get an XML string for the GDataParsable */
526
parsable_xml = gdata_parsable_get_xml (parsable);
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);
532
g_assert (parsable_doc != NULL && expected_doc != NULL);
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);
541
xmlFreeDoc (expected_doc);
542
xmlFreeDoc (parsable_doc);
543
g_free (parsable_xml);