| /* | 
 |  * Licensed to the Apache Software Foundation (ASF) under one | 
 |  * or more contributor license agreements. See the NOTICE file | 
 |  * distributed with this work for additional information | 
 |  * regarding copyright ownership. The ASF licenses this file | 
 |  * to you under the Apache License, Version 2.0 (the | 
 |  * "License"); you may not use this file except in compliance | 
 |  * with the License. You may obtain a copy of the License at | 
 |  * | 
 |  *   http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, | 
 |  * software distributed under the License is distributed on an | 
 |  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
 |  * KIND, either express or implied. See the License for the | 
 |  * specific language governing permissions and limitations | 
 |  * under the License. | 
 |  */ | 
 |  | 
 | #include <glib-object.h> | 
 | #include <inttypes.h> | 
 | #include <signal.h> | 
 | #include <stdio.h> | 
 | #include <string.h> | 
 |  | 
 | #include <sys/time.h> | 
 |  | 
 | #include <thrift/c_glib/thrift.h> | 
 | #include <thrift/c_glib/protocol/thrift_binary_protocol.h> | 
 | #include <thrift/c_glib/protocol/thrift_compact_protocol.h> | 
 | #include <thrift/c_glib/protocol/thrift_multiplexed_protocol.h> | 
 | #include <thrift/c_glib/transport/thrift_buffered_transport.h> | 
 | #include <thrift/c_glib/transport/thrift_framed_transport.h> | 
 | #include <thrift/c_glib/transport/thrift_ssl_socket.h> | 
 | #include <thrift/c_glib/transport/thrift_socket.h> | 
 | #include <thrift/c_glib/transport/thrift_transport.h> | 
 |  | 
 | #include "../gen-c_glib/t_test_second_service.h" | 
 | #include "../gen-c_glib/t_test_thrift_test.h" | 
 |  | 
 | /* Handle SIGPIPE signals (indicating the server has closed the | 
 |    connection prematurely) by outputting an error message before | 
 |    exiting. */ | 
 | static void | 
 | sigpipe_handler (int signal_number) | 
 | { | 
 |   THRIFT_UNUSED_VAR (signal_number); | 
 |  | 
 |   /* Flush standard output to make sure the test results so far are | 
 |      logged */ | 
 |   fflush (stdout); | 
 |  | 
 |   fputs ("Broken pipe (server closed connection prematurely)\n", stderr); | 
 |   fflush (stderr); | 
 |  | 
 |   /* Re-raise the signal, this time invoking the default signal | 
 |      handler, to terminate the program */ | 
 |   raise (SIGPIPE); | 
 | } | 
 |  | 
 | /* Compare two gint32 values. Used for sorting and finding integer | 
 |    values within a GList. */ | 
 | static gint | 
 | gint32_compare (gconstpointer a, gconstpointer b) | 
 | { | 
 |   gint32 int32_a = *(gint32 *)a; | 
 |   gint32 int32_b = *(gint32 *)b; | 
 |   int result = 0; | 
 |  | 
 |   if (int32_a < int32_b) | 
 |     result = -1; | 
 |   else if (int32_a > int32_b) | 
 |     result = 1; | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | /** | 
 |  * It gets a multiplexed protocol which uses a concrete protocol underneath | 
 |  * @param  protocol_name  the fully qualified protocol path (e.g. "binary:multi") | 
 |  * @param  transport      the underlying transport | 
 |  * @param  service_name   the single supported service name | 
 |  * @todo                  need to allow multiple services to fully test multiplexed | 
 |  * @return                a multiplexed protocol wrapping the correct underlying protocol | 
 |  */ | 
 | ThriftProtocol * | 
 | get_multiplexed_protocol(gchar *protocol_name, ThriftTransport *transport, gchar *service_name) | 
 | { | 
 |   ThriftProtocol * multiplexed_protocol = NULL; | 
 |  | 
 |   if ( strncmp(protocol_name, "binary:", 7) == 0) { | 
 |     multiplexed_protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, | 
 |                  "transport", transport, | 
 |                  NULL); | 
 |   } else if ( strncmp(protocol_name, "compact:", 8) == 0) { | 
 |     multiplexed_protocol = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, | 
 |                  "transport", transport, | 
 |                  NULL); | 
 |   } else { | 
 |     fprintf(stderr, "Unknown multiplex protocol name: %s\n", protocol_name); | 
 |     return NULL; | 
 |   } | 
 |  | 
 |   return g_object_new (THRIFT_TYPE_MULTIPLEXED_PROTOCOL, | 
 |           "transport",      transport, | 
 |           "protocol",       multiplexed_protocol, | 
 |           "service-name",   service_name, | 
 |           NULL); | 
 | } | 
 |  | 
 | int | 
 | main (int argc, char **argv) | 
 | { | 
 |   static gchar *  host = NULL; | 
 |   static gint     port = 9090; | 
 |   static gchar *  path = NULL; | 
 |   static gboolean ssl  = FALSE; | 
 |   static gchar *  transport_option = NULL; | 
 |   static gchar *  protocol_option = NULL; | 
 |   static gint     num_tests = 1; | 
 |  | 
 |   static | 
 |     GOptionEntry option_entries[] ={ | 
 |     { "host",            'h', 0, G_OPTION_ARG_STRING,   &host, | 
 |       "Host to connect (=localhost)", NULL }, | 
 |     { "port",            'p', 0, G_OPTION_ARG_INT,      &port, | 
 |       "Port number to connect (=9090)", NULL }, | 
 |     { "domain-socket",    0, 0, G_OPTION_ARG_STRING,   &path, | 
 |       "Unix socket domain path to connect", NULL }, | 
 |     { "ssl",             's', 0, G_OPTION_ARG_NONE,     &ssl, | 
 |       "Enable SSL", NULL }, | 
 |     { "transport",       't', 0, G_OPTION_ARG_STRING,   &transport_option, | 
 |       "Transport: buffered, framed (=buffered)", NULL }, | 
 |     { "protocol",        'r', 0, G_OPTION_ARG_STRING,   &protocol_option, | 
 |       "Protocol: binary, compact, multi, multic (=binary)", NULL }, | 
 |     { "testloops",       'n', 0, G_OPTION_ARG_INT,      &num_tests, | 
 |       "Number of tests (=1)", NULL }, | 
 |     { NULL } | 
 |   }; | 
 |  | 
 |   struct sigaction sigpipe_action; | 
 |  | 
 |   GType  socket_type    = THRIFT_TYPE_SOCKET; | 
 |   gchar *socket_name    = "ip"; | 
 |   GType  transport_type = THRIFT_TYPE_BUFFERED_TRANSPORT; | 
 |   gchar *transport_name = "buffered"; | 
 |   GType  protocol_type  = THRIFT_TYPE_BINARY_PROTOCOL; | 
 |   gchar *protocol_name  = "binary"; | 
 |  | 
 |   ThriftSocket    *socket = NULL; | 
 |   ThriftTransport *transport = NULL; | 
 |   ThriftProtocol  *protocol = NULL; | 
 |   ThriftProtocol  *protocol2 = NULL;            // for multiplexed tests | 
 |  | 
 |   TTestThriftTestIf *test_client = NULL; | 
 |   TTestSecondServiceIf *second_service = NULL;  // for multiplexed tests | 
 |  | 
 |   struct timeval time_start, time_stop, time_elapsed; | 
 |   guint64 time_elapsed_usec, time_total_usec = 0; | 
 |   guint64 time_min_usec = G_MAXUINT64, time_max_usec = 0, time_avg_usec; | 
 |  | 
 |   GOptionContext *option_context; | 
 |   gboolean options_valid = TRUE; | 
 |   int test_num = 0; | 
 |   int fail_count = 0; | 
 |   GError *error = NULL; | 
 |  | 
 | #if (!GLIB_CHECK_VERSION (2, 36, 0)) | 
 |   g_type_init (); | 
 | #endif | 
 |  | 
 |   /* Configure and parse our command-line options */ | 
 |   option_context = g_option_context_new (NULL); | 
 |   g_option_context_add_main_entries (option_context, | 
 |                                      option_entries, | 
 |                                      NULL); | 
 |   if (!g_option_context_parse (option_context, | 
 |                                &argc, | 
 |                                &argv, | 
 |                                &error)) { | 
 |     fprintf (stderr, "%s\n", error->message); | 
 |     return 255; | 
 |   } | 
 |   g_option_context_free (option_context); | 
 |  | 
 |   /* Set remaining default values for unspecified options */ | 
 |   if (host == NULL) | 
 |     host = g_strdup ("localhost"); | 
 |  | 
 |   /* Validate the parsed options */ | 
 |   if (protocol_option != NULL) { | 
 |     if (strncmp (protocol_option, "compact", 8) == 0) { | 
 |       protocol_type = THRIFT_TYPE_COMPACT_PROTOCOL; | 
 |       protocol_name = "compact"; | 
 |     } | 
 |     else if (strncmp (protocol_option, "multi", 6) == 0) { | 
 |       protocol_type = THRIFT_TYPE_MULTIPLEXED_PROTOCOL; | 
 |       protocol_name = "binary:multi"; | 
 |     } | 
 |     else if (strncmp (protocol_option, "multic", 7) == 0) { | 
 |       protocol_type = THRIFT_TYPE_MULTIPLEXED_PROTOCOL; | 
 |       protocol_name = "compact:multic"; | 
 |     } | 
 |     else if (strncmp (protocol_option, "binary", 7) == 0) { | 
 |       printf("We are going with default protocol\n"); | 
 |     } | 
 |     else { | 
 |       fprintf (stderr, "Unknown protocol type %s\n", protocol_option); | 
 |       options_valid = FALSE; | 
 |     } | 
 |   } | 
 |  | 
 |   if (transport_option != NULL) { | 
 |     if (strncmp (transport_option, "framed", 7) == 0) { | 
 |       transport_type = THRIFT_TYPE_FRAMED_TRANSPORT; | 
 |       transport_name = "framed"; | 
 |     } | 
 |     else if (strncmp (transport_option, "buffered", 9) != 0) { | 
 |       fprintf (stderr, "Unknown transport type %s\n", transport_option); | 
 |       options_valid = FALSE; | 
 |     } | 
 |   } | 
 |  | 
 |   if (ssl) { | 
 |     socket_type = THRIFT_TYPE_SSL_SOCKET; | 
 |     socket_name = "ip-ssl"; | 
 |     printf("Type name %s\n", g_type_name (socket_type)); | 
 |   } | 
 |  | 
 |   if (!options_valid) | 
 |     return 254; | 
 |  | 
 |   if (path) { | 
 |     printf ("Connecting (%s/%s) to: %s/%s\n", | 
 |             transport_name, | 
 |             protocol_name, | 
 |             socket_name, | 
 |             path); | 
 |   } else { | 
 |     printf ("Connecting (%s/%s) to: %s/%s:%d\n", | 
 |             transport_name, | 
 |             protocol_name, | 
 |             socket_name, | 
 |             host, | 
 |             port); | 
 |   } | 
 |  | 
 |   /* Install our SIGPIPE handler, which outputs an error message to | 
 |      standard error before exiting so testers can know what | 
 |      happened */ | 
 |   memset (&sigpipe_action, 0, sizeof (sigpipe_action)); | 
 |   sigpipe_action.sa_handler = sigpipe_handler; | 
 |   sigpipe_action.sa_flags = SA_RESETHAND; | 
 |   sigaction (SIGPIPE, &sigpipe_action, NULL); | 
 |  | 
 |   if (ssl) { | 
 |     thrift_ssl_socket_initialize_openssl(); | 
 |   } | 
 |  | 
 |   /* Establish all our connection objects */ | 
 |   if (path) { | 
 |     socket = g_object_new (socket_type, | 
 |                            "path", path, | 
 |                            NULL); | 
 |   } else { | 
 |     socket = g_object_new (socket_type, | 
 |                            "hostname", host, | 
 |                            "port",     port, | 
 |                            NULL); | 
 |   } | 
 |  | 
 |   if (ssl && !thrift_ssl_load_cert_from_file(THRIFT_SSL_SOCKET(socket), "../keys/CA.pem")) { | 
 |     fprintf(stderr, "Unable to load validation certificate ../keys/CA.pem - did you run in the test/c_glib directory?\n"); | 
 |     g_clear_object (&socket); | 
 |     return 253; | 
 |   } | 
 |  | 
 |   transport = g_object_new (transport_type, | 
 |                             "transport", socket, | 
 |                             NULL); | 
 |  | 
 |   if(protocol_type==THRIFT_TYPE_MULTIPLEXED_PROTOCOL) { | 
 |     // TODO: A multiplexed test should also test "Second" (see Java TestServer) | 
 |     // The context comes from the name of the thrift file. If multiple thrift | 
 |     // schemas are used we have to redo the way this is done. | 
 |     protocol = get_multiplexed_protocol(protocol_name, transport, "ThriftTest"); | 
 |     if (NULL == protocol) { | 
 |       g_clear_object (&transport); | 
 |       g_clear_object (&socket); | 
 |       return 252; | 
 |     } | 
 |  | 
 |     // Make a second protocol and client running on the same multiplexed transport | 
 |     protocol2 = get_multiplexed_protocol(protocol_name, transport, "SecondService"); | 
 |     second_service = g_object_new (T_TEST_TYPE_SECOND_SERVICE_CLIENT, | 
 |                                 "input_protocol",  protocol2, | 
 |                                 "output_protocol", protocol2, | 
 |                                 NULL); | 
 |  | 
 |   }else{ | 
 |     protocol = g_object_new (protocol_type, | 
 |            "transport", transport, | 
 |            NULL); | 
 |   } | 
 |  | 
 |   test_client = g_object_new (T_TEST_TYPE_THRIFT_TEST_CLIENT, | 
 |                               "input_protocol",  protocol, | 
 |                               "output_protocol", protocol, | 
 |                               NULL); | 
 |  | 
 |   /* Execute the actual tests */ | 
 |   for (test_num = 0; test_num < num_tests; ++test_num) { | 
 |     if (thrift_transport_open (transport, &error)) { | 
 |       gchar   *string  = NULL; | 
 |       gboolean boolean = 0; | 
 |       gint8    byte    = 0; | 
 |       gint32   int32   = 0; | 
 |       gint64   int64   = 0; | 
 |       gdouble  dub     = 0; | 
 |  | 
 |       gint byte_thing, i32_thing, inner_byte_thing, inner_i32_thing; | 
 |       gint64 i64_thing, inner_i64_thing; | 
 |  | 
 |       TTestXtruct  *xtruct_out,  *xtruct_out2, *xtruct_in,  *inner_xtruct_in; | 
 |       TTestXtruct2 *xtruct2_out, *xtruct2_in; | 
 |  | 
 |       GHashTable *map_out, *map_in, *inner_map_in; | 
 |       GHashTable *set_out, *set_in; | 
 |       gpointer key, value; | 
 |       gint32 *i32_key_ptr, *i32_value_ptr; | 
 |       GHashTableIter hash_table_iter, inner_hash_table_iter; | 
 |       GList *keys_out, *keys_in, *keys_elem; | 
 |  | 
 |       GArray *list_out, *list_in; | 
 |  | 
 |       TTestNumberz numberz; | 
 |       TTestNumberz numberz2; | 
 |  | 
 |       TTestUserId user_id, *user_id_ptr, *user_id_ptr2; | 
 |  | 
 |       TTestInsanity *insanity_out, *insanity_in; | 
 |       GHashTable *user_map; | 
 |       GHashTableIter user_map_iter; | 
 |       GPtrArray *xtructs; | 
 |  | 
 |       TTestXception  *xception  = NULL; | 
 |       TTestXception2 *xception2 = NULL; | 
 |  | 
 |       gboolean oneway_result; | 
 |       struct timeval oneway_start, oneway_end, oneway_elapsed; | 
 |       gint oneway_elapsed_usec; | 
 |  | 
 |       gboolean first; | 
 |       gint32 i, j; | 
 |  | 
 |       if (path) { | 
 |         printf ("Test #%d, connect %s\n", test_num + 1, path); | 
 |       } else { | 
 |         printf ("Test #%d, connect %s:%d\n", test_num + 1, host, port); | 
 |       } | 
 |       gettimeofday (&time_start, NULL); | 
 |  | 
 |       /* These test routines have been ported from the C++ test | 
 |          client, care being taken to ensure their output remains as | 
 |          close as possible to the original to facilitate diffs. | 
 |  | 
 |          For simplicity comments have been omitted, but every routine | 
 |          has the same basic structure: | 
 |  | 
 |          - Create and populate data structures as necessary. | 
 |  | 
 |          - Format and output (to the console) a representation of the | 
 |            outgoing data. | 
 |  | 
 |          - Issue the remote method call to the server. | 
 |  | 
 |          - Format and output a representation of the returned data. | 
 |  | 
 |          - Verify the returned data matches what was expected. | 
 |  | 
 |          - Deallocate any created data structures. | 
 |  | 
 |          Note the recognized values and expected behaviour of each | 
 |          remote method are described in ThriftTest.thrift, which | 
 |          you'll find in the top-level "test" folder. */ | 
 |  | 
 |       /** | 
 |        * VOID TEST | 
 |        */ | 
 |       printf ("testVoid()"); | 
 |       if (t_test_thrift_test_if_test_void (test_client, &error)) { | 
 |         printf (" = void\n"); | 
 |       } | 
 |       else { | 
 |         if(error!=NULL){ | 
 |           printf ("%s\n", error->message); | 
 |           g_error_free (error); | 
 |           error = NULL; | 
 |         } | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       /** | 
 |        * STRING TEST | 
 |        */ | 
 |       printf ("testString(\"Test\")"); | 
 |       if (t_test_thrift_test_if_test_string (test_client, | 
 |                                              &string, | 
 |                                              "Test", | 
 |                                              &error)) { | 
 |         printf (" = \"%s\"\n", string); | 
 |         if (strncmp (string, "Test", 5) != 0) | 
 |           fail_count++; | 
 |  | 
 |         g_free (string); | 
 |         string = NULL; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       /** | 
 |        * Multiplexed Test - do this right in the middle of the normal Test Client run | 
 |        */ | 
 |       if (second_service) { | 
 |         printf ("testSecondServiceMultiplexSecondTestString(\"2nd\")"); | 
 |         if (t_test_second_service_if_secondtest_string (second_service, | 
 |                                                         &string, | 
 |                                                         "2nd", | 
 |                                                         &error)) { | 
 |           printf (" = \"%s\"\n", string); | 
 |           if (strcmp (string, "testString(\"2nd\")") != 0) { | 
 |             ++fail_count; | 
 |           } | 
 |  | 
 |           g_free (string); | 
 |           string = NULL; | 
 |         } else { | 
 |           printf ("%s\n", error->message); | 
 |           g_error_free (error); | 
 |           error = NULL; | 
 |  | 
 |           ++fail_count; | 
 |         } | 
 |       } | 
 |  | 
 |       /** | 
 |        * BOOL TEST | 
 |        */ | 
 |       printf ("testByte(true)"); | 
 |       if (t_test_thrift_test_if_test_bool (test_client, | 
 |                                            &boolean, | 
 |                                            1, | 
 |                                            &error)) { | 
 |         printf (" = %s\n", boolean ? "true" : "false"); | 
 |         if (boolean != 1) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |       printf ("testByte(false)"); | 
 |       if (t_test_thrift_test_if_test_bool (test_client, | 
 |                                            &boolean, | 
 |                                            0, | 
 |                                            &error)) { | 
 |         printf (" = %s\n", boolean ? "true" : "false"); | 
 |         if (boolean != 0) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       /** | 
 |        * BYTE TEST | 
 |        */ | 
 |       printf ("testByte(1)"); | 
 |       if (t_test_thrift_test_if_test_byte (test_client, | 
 |                                            &byte, | 
 |                                            1, | 
 |                                            &error)) { | 
 |         printf (" = %d\n", byte); | 
 |         if (byte != 1) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |       printf ("testByte(-1)"); | 
 |       if (t_test_thrift_test_if_test_byte (test_client, | 
 |                                            &byte, | 
 |                                            -1, | 
 |                                            &error)) { | 
 |         printf (" = %d\n", byte); | 
 |         if (byte != -1) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       /** | 
 |        * I32 TEST | 
 |        */ | 
 |       printf ("testI32(-1)"); | 
 |       if (t_test_thrift_test_if_test_i32 (test_client, | 
 |                                           &int32, | 
 |                                           -1, | 
 |                                           &error)) { | 
 |         printf (" = %d\n", int32); | 
 |         if (int32 != -1) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       /** | 
 |        * I64 TEST | 
 |        */ | 
 |       printf ("testI64(-34359738368)"); | 
 |       if (t_test_thrift_test_if_test_i64 (test_client, | 
 |                                           &int64, | 
 |                                           (gint64)-34359738368, | 
 |                                           &error)) { | 
 |         printf (" = %" PRId64 "\n", int64); | 
 |         if (int64 != (gint64)-34359738368) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       /** | 
 |        * DOUBLE TEST | 
 |        */ | 
 |       printf("testDouble(-5.2098523)"); | 
 |       if (t_test_thrift_test_if_test_double (test_client, | 
 |                                              &dub, | 
 |                                              -5.2098523, | 
 |                                              &error)) { | 
 |         printf (" = %f\n", dub); | 
 |         if ((dub - (-5.2098523)) > 0.001) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       /** | 
 |        * BINARY TEST | 
 |        */ | 
 |       printf ("testBinary(empty)"); | 
 |       GByteArray *emptyArray = g_byte_array_new(); | 
 |       GByteArray *result = NULL; | 
 |       if (t_test_thrift_test_if_test_binary (test_client, | 
 |                                              &result, | 
 |                                              emptyArray, | 
 |                                              &error)) { | 
 |         GBytes *response = g_byte_array_free_to_bytes(result);  // frees result | 
 |         result = NULL; | 
 |         gsize siz = g_bytes_get_size(response); | 
 |         if (siz == 0) { | 
 |           printf(" = empty\n"); | 
 |         } else { | 
 |           printf(" = not empty (%ld bytes)\n", (long)siz); | 
 |           ++fail_count; | 
 |         } | 
 |         g_bytes_unref(response); | 
 |       } else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |       g_byte_array_unref(emptyArray); | 
 |       emptyArray = NULL; | 
 |  | 
 |       // TODO: add testBinary() with data | 
 |       printf ("testBinary([-128..127]) = {"); | 
 |       const signed char bin_data[256] | 
 |         = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, | 
 |            -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, | 
 |            -98,  -97,  -96,  -95,  -94,  -93,  -92,  -91,  -90,  -89,  -88,  -87,  -86,  -85,  -84, | 
 |            -83,  -82,  -81,  -80,  -79,  -78,  -77,  -76,  -75,  -74,  -73,  -72,  -71,  -70,  -69, | 
 |            -68,  -67,  -66,  -65,  -64,  -63,  -62,  -61,  -60,  -59,  -58,  -57,  -56,  -55,  -54, | 
 |            -53,  -52,  -51,  -50,  -49,  -48,  -47,  -46,  -45,  -44,  -43,  -42,  -41,  -40,  -39, | 
 |            -38,  -37,  -36,  -35,  -34,  -33,  -32,  -31,  -30,  -29,  -28,  -27,  -26,  -25,  -24, | 
 |            -23,  -22,  -21,  -20,  -19,  -18,  -17,  -16,  -15,  -14,  -13,  -12,  -11,  -10,  -9, | 
 |            -8,   -7,   -6,   -5,   -4,   -3,   -2,   -1,   0,    1,    2,    3,    4,    5,    6, | 
 |            7,    8,    9,    10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21, | 
 |            22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36, | 
 |            37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51, | 
 |            52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64,   65,   66, | 
 |            67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,   79,   80,   81, | 
 |            82,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,   94,   95,   96, | 
 |            97,   98,   99,   100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,  111, | 
 |            112,  113,  114,  115,  116,  117,  118,  119,  120,  121,  122,  123,  124,  125,  126, | 
 |            127}; | 
 |       GByteArray *fullArray = g_byte_array_new(); | 
 |       g_byte_array_append(fullArray, (guint8 *)(&bin_data[0]), 256); | 
 |       if (t_test_thrift_test_if_test_binary (test_client, | 
 |                                              &result, | 
 |                                              fullArray, | 
 |                                              &error)) { | 
 |         GBytes *response = g_byte_array_free_to_bytes(result);  // frees result | 
 |         result = NULL; | 
 |         gsize siz = g_bytes_get_size(response); | 
 |         gconstpointer ptr = g_bytes_get_data(response, &siz); | 
 |         if (siz == 256) { | 
 |           gboolean first = 1; | 
 |           gboolean failed = 0; | 
 |           int i; | 
 |  | 
 |           for (i = 0; i < 256; ++i) { | 
 |             if (!first) | 
 |               printf(","); | 
 |             else | 
 |               first = 0; | 
 |             int val = ((signed char *)ptr)[i]; | 
 |             printf("%d", val); | 
 |             if (!failed && val != i - 128) { | 
 |               failed = 1; | 
 |             } | 
 |           } | 
 |           printf("} "); | 
 |           if (failed) { | 
 |             printf("FAIL (bad content) size %ld OK\n", (long)siz); | 
 |             ++fail_count; | 
 |           } else { | 
 |             printf("OK size %ld OK\n", (long)siz); | 
 |           } | 
 |         } else { | 
 |           printf(" = bad size %ld\n", (long)siz); | 
 |           ++fail_count; | 
 |         } | 
 |         g_bytes_unref(response); | 
 |       } else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |       g_byte_array_unref(fullArray); | 
 |       fullArray = NULL; | 
 |  | 
 |       /** | 
 |        * STRUCT TEST | 
 |        */ | 
 |       printf ("testStruct({\"Zero\", 1, -3, -5})"); | 
 |       xtruct_out = g_object_new (T_TEST_TYPE_XTRUCT, | 
 |                                  "string_thing", "Zero", | 
 |                                  "byte_thing",        1, | 
 |                                  "i32_thing",        -3, | 
 |                                  "i64_thing",      -5LL, | 
 |                                  NULL); | 
 |       xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); | 
 |  | 
 |       if (t_test_thrift_test_if_test_struct (test_client, | 
 |                                              &xtruct_in, | 
 |                                              xtruct_out, | 
 |                                              &error)) { | 
 |         g_object_get (xtruct_in, | 
 |                       "string_thing", &string, | 
 |                       "byte_thing",   &byte_thing, | 
 |                       "i32_thing",    &i32_thing, | 
 |                       "i64_thing",    &i64_thing, | 
 |                       NULL); | 
 |  | 
 |         printf (" = {\"%s\", %d, %d, %" PRId64 "}\n", | 
 |                 string, | 
 |                 byte_thing, | 
 |                 i32_thing, | 
 |                 i64_thing); | 
 |         if ((string == NULL || strncmp (string, "Zero", 5) != 0) || | 
 |             byte_thing != 1 || | 
 |             i32_thing != -3 || | 
 |             i64_thing != (gint64)-5) | 
 |           fail_count++; | 
 |  | 
 |         if (string) { | 
 |           g_free (string); | 
 |           string = NULL; | 
 |         } | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |       // g_clear_object(&xtruct_out); used below | 
 |       g_clear_object(&xtruct_in); | 
 |  | 
 |       /** | 
 |        * NESTED STRUCT TEST | 
 |        */ | 
 |       printf ("testNest({1, {\"Zero\", 1, -3, -5}), 5}"); | 
 |       xtruct2_out = g_object_new (T_TEST_TYPE_XTRUCT2, | 
 |                                   "byte_thing",            1, | 
 |                                   "struct_thing", xtruct_out, | 
 |                                   "i32_thing",             5, | 
 |                                   NULL); | 
 |       xtruct2_in = g_object_new (T_TEST_TYPE_XTRUCT2, NULL); | 
 |  | 
 |       if (t_test_thrift_test_if_test_nest (test_client, | 
 |                                            &xtruct2_in, | 
 |                                            xtruct2_out, | 
 |                                            &error)) { | 
 |         g_object_get (xtruct2_in, | 
 |                       "byte_thing",   &byte_thing, | 
 |                       "struct_thing", &xtruct_in, | 
 |                       "i32_thing",    &i32_thing, | 
 |                       NULL); | 
 |         g_object_get (xtruct_in, | 
 |                       "string_thing", &string, | 
 |                       "byte_thing",   &inner_byte_thing, | 
 |                       "i32_thing",    &inner_i32_thing, | 
 |                       "i64_thing",    &inner_i64_thing, | 
 |                       NULL); | 
 |  | 
 |         printf (" = {%d, {\"%s\", %d, %d, %" PRId64 "}, %d}\n", | 
 |                 byte_thing, | 
 |                 string, | 
 |                 inner_byte_thing, | 
 |                 inner_i32_thing, | 
 |                 inner_i64_thing, | 
 |                 i32_thing); | 
 |         if (byte_thing != 1 || | 
 |             (string == NULL || strncmp (string, "Zero", 5) != 0) || | 
 |             inner_byte_thing != 1 || | 
 |             inner_i32_thing != -3 || | 
 |             inner_i64_thing != (gint64)-5 || | 
 |             i32_thing != 5) | 
 |           fail_count++; | 
 |  | 
 |         if (string) { | 
 |           g_free(string); | 
 |           string = NULL; | 
 |         } | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       g_clear_object(&xtruct_in); | 
 |       g_clear_object(&xtruct2_in); | 
 |       g_clear_object(&xtruct2_out); | 
 |       g_clear_object(&xtruct_out); | 
 |  | 
 |       /** | 
 |        * MAP TEST | 
 |        */ | 
 |       map_out = g_hash_table_new_full (g_int_hash, | 
 |                                        g_int_equal, | 
 |                                        g_free, | 
 |                                        g_free); | 
 |       for (i = 0; i < 5; ++i) { | 
 |         i32_key_ptr   = g_malloc (sizeof *i32_key_ptr); | 
 |         i32_value_ptr = g_malloc (sizeof *i32_value_ptr); | 
 |  | 
 |         *i32_key_ptr   = i; | 
 |         *i32_value_ptr = i - 10; | 
 |  | 
 |         g_hash_table_insert (map_out, i32_key_ptr, i32_value_ptr); | 
 |       } | 
 |       printf ("testMap({"); | 
 |       first = TRUE; | 
 |       g_hash_table_iter_init (&hash_table_iter, map_out); | 
 |       while (g_hash_table_iter_next (&hash_table_iter, | 
 |                                      &key, | 
 |                                      &value)) { | 
 |         if (first) | 
 |           first = FALSE; | 
 |         else | 
 |           printf (", "); | 
 |  | 
 |         printf ("%d => %d", *(gint32 *)key, *(gint32 *)value); | 
 |       } | 
 |       printf ("})"); | 
 |  | 
 |       map_in = g_hash_table_new_full (g_int_hash, | 
 |                                       g_int_equal, | 
 |                                       g_free, | 
 |                                       g_free); | 
 |  | 
 |       if (t_test_thrift_test_if_test_map (test_client, | 
 |                                           &map_in, | 
 |                                           map_out, | 
 |                                           &error)) { | 
 |         printf (" = {"); | 
 |         first = TRUE; | 
 |         g_hash_table_iter_init (&hash_table_iter, map_in); | 
 |         while (g_hash_table_iter_next (&hash_table_iter, | 
 |                                        &key, | 
 |                                        &value)) { | 
 |           if (first) | 
 |             first = FALSE; | 
 |           else | 
 |             printf (", "); | 
 |  | 
 |           printf ("%d => %d", *(gint32 *)key, *(gint32 *)value); | 
 |         } | 
 |         printf ("}\n"); | 
 |  | 
 |         if (g_hash_table_size (map_in) != g_hash_table_size (map_out)) | 
 |           fail_count++; | 
 |         else { | 
 |           g_hash_table_iter_init (&hash_table_iter, map_out); | 
 |           while (g_hash_table_iter_next (&hash_table_iter, | 
 |                                          &key, | 
 |                                          &value)) { | 
 |             gpointer in_value = g_hash_table_lookup (map_in, key); | 
 |             if (in_value == NULL || | 
 |                 *(gint32 *)in_value != *(gint32 *)value) { | 
 |               fail_count++; | 
 |               break; | 
 |             } | 
 |           } | 
 |         } | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       g_hash_table_unref (map_in); | 
 |       g_hash_table_unref (map_out); | 
 |  | 
 |       /** | 
 |        * STRING MAP TEST | 
 |        */ | 
 |       map_out = g_hash_table_new_full (g_str_hash, | 
 |                                        g_str_equal, | 
 |                                        NULL, | 
 |                                        NULL); | 
 |       g_hash_table_insert (map_out, "a",    "2"); | 
 |       g_hash_table_insert (map_out, "b",    "blah"); | 
 |       g_hash_table_insert (map_out, "some", "thing"); | 
 |       printf ("testStringMap({"); | 
 |       first = TRUE; | 
 |       g_hash_table_iter_init (&hash_table_iter, map_out); | 
 |       while (g_hash_table_iter_next (&hash_table_iter, | 
 |                                      &key, | 
 |                                      &value)) { | 
 |         if (first) | 
 |           first = FALSE; | 
 |         else | 
 |           printf (", "); | 
 |  | 
 |         printf ("\"%s\" => \"%s\"", (gchar *)key, (gchar *)value); | 
 |       } | 
 |       printf (")}"); | 
 |  | 
 |       map_in = g_hash_table_new_full (g_str_hash, | 
 |                                       g_str_equal, | 
 |                                       g_free, | 
 |                                       g_free); | 
 |  | 
 |       if (t_test_thrift_test_if_test_string_map (test_client, | 
 |                                                  &map_in, | 
 |                                                  map_out, | 
 |                                                  &error)) { | 
 |         printf (" = {"); | 
 |         first = TRUE; | 
 |         g_hash_table_iter_init (&hash_table_iter, map_in); | 
 |         while (g_hash_table_iter_next (&hash_table_iter, | 
 |                                        &key, | 
 |                                        &value)) { | 
 |           if (first) | 
 |             first = FALSE; | 
 |           else | 
 |             printf (", "); | 
 |  | 
 |           printf ("\"%s\" => \"%s\"", (gchar *)key, (gchar *)value); | 
 |         } | 
 |         printf ("}\n"); | 
 |  | 
 |         if (g_hash_table_size (map_in) != g_hash_table_size (map_out)) | 
 |           fail_count++; | 
 |         else { | 
 |           g_hash_table_iter_init (&hash_table_iter, map_out); | 
 |           while (g_hash_table_iter_next (&hash_table_iter, | 
 |                                          &key, | 
 |                                          &value)) { | 
 |             gpointer in_value = g_hash_table_lookup (map_in, key); | 
 |             if (in_value == NULL || | 
 |                 strcmp ((gchar *)in_value, (gchar *)value) != 0) { | 
 |               fail_count++; | 
 |               break; | 
 |             } | 
 |           } | 
 |         } | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       g_hash_table_unref (map_in); | 
 |       g_hash_table_unref (map_out); | 
 |  | 
 |       /** | 
 |        * SET TEST | 
 |        */ | 
 |       set_out = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); | 
 |       for (i = -2; i < 3; ++i) { | 
 |         i32_key_ptr = g_malloc (sizeof *i32_key_ptr); | 
 |         *i32_key_ptr = i; | 
 |  | 
 |         g_hash_table_insert (set_out, i32_key_ptr, NULL); | 
 |       } | 
 |       printf ("testSet({"); | 
 |       first = TRUE; | 
 |       keys_out = g_hash_table_get_keys (set_out); | 
 |       keys_elem = keys_out; | 
 |       while (keys_elem != NULL) { | 
 |         if (first) | 
 |           first = FALSE; | 
 |         else | 
 |           printf (", "); | 
 |  | 
 |         printf ("%d", *(gint32 *)keys_elem->data); | 
 |  | 
 |         keys_elem = keys_elem->next; | 
 |       } | 
 |       printf ("})"); | 
 |  | 
 |       set_in = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL); | 
 |  | 
 |       if (t_test_thrift_test_if_test_set (test_client, | 
 |                                           &set_in, | 
 |                                           set_out, | 
 |                                           &error)) { | 
 |         printf(" = {"); | 
 |         first = TRUE; | 
 |         keys_in = g_hash_table_get_keys (set_in); | 
 |         keys_elem = keys_in; | 
 |         while (keys_elem != NULL) { | 
 |           if (first) | 
 |             first = FALSE; | 
 |           else | 
 |             printf (", "); | 
 |  | 
 |           printf ("%d", *(gint32 *)keys_elem->data); | 
 |  | 
 |           keys_elem = keys_elem->next; | 
 |         } | 
 |         printf ("}\n"); | 
 |  | 
 |         if (g_list_length (keys_in) != g_list_length (keys_out)) | 
 |           fail_count++; | 
 |         else { | 
 |           keys_elem = keys_out; | 
 |           while (keys_elem != NULL) { | 
 |             if (g_list_find_custom (keys_in, | 
 |                                     keys_elem->data, | 
 |                                     gint32_compare) == NULL) { | 
 |               fail_count++; | 
 |               break; | 
 |             } | 
 |  | 
 |             keys_elem = keys_elem->next; | 
 |           } | 
 |         } | 
 |  | 
 |         g_list_free (keys_in); | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       g_hash_table_unref (set_in); | 
 |       g_list_free (keys_out); | 
 |       g_hash_table_unref (set_out); | 
 |  | 
 |       /** | 
 |        * LIST TEST | 
 |        */ | 
 |       list_out = g_array_new (FALSE, TRUE, sizeof (gint32)); | 
 |       for (i = -2; i < 3; ++i) { | 
 |         g_array_append_val (list_out, i); | 
 |       } | 
 |       printf ("testList({"); | 
 |       first = TRUE; | 
 |       for (i = 0; i < (gint32)list_out->len; ++i) { | 
 |         if (first) | 
 |           first = FALSE; | 
 |         else | 
 |           printf (", "); | 
 |  | 
 |         printf ("%d", g_array_index (list_out, gint32, i)); | 
 |       } | 
 |       printf ("})"); | 
 |  | 
 |       list_in = g_array_new (FALSE, TRUE, sizeof (gint32)); | 
 |  | 
 |       if (t_test_thrift_test_if_test_list (test_client, | 
 |                                            &list_in, | 
 |                                            list_out, | 
 |                                            &error)) { | 
 |         printf (" = {"); | 
 |         first = TRUE; | 
 |         for (i = 0; i < (gint32)list_in->len; ++i) { | 
 |           if (first) | 
 |             first = FALSE; | 
 |           else | 
 |             printf (", "); | 
 |  | 
 |           printf ("%d", g_array_index (list_in, gint32, i)); | 
 |         } | 
 |         printf ("}\n"); | 
 |  | 
 |         if (list_in->len != list_out->len || | 
 |             memcmp (list_in->data, | 
 |                     list_out->data, | 
 |                     list_in->len * sizeof (gint32)) != 0) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       g_array_unref (list_in); | 
 |       g_array_unref (list_out); | 
 |  | 
 |       /** | 
 |        * ENUM TEST | 
 |        */ | 
 |       printf("testEnum(ONE)"); | 
 |       if (t_test_thrift_test_if_test_enum (test_client, | 
 |                                            &numberz, | 
 |                                            T_TEST_NUMBERZ_ONE, | 
 |                                            &error)) { | 
 |         printf(" = %d\n", numberz); | 
 |         if (numberz != T_TEST_NUMBERZ_ONE) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       printf("testEnum(TWO)"); | 
 |       if (t_test_thrift_test_if_test_enum (test_client, | 
 |                                            &numberz, | 
 |                                            T_TEST_NUMBERZ_TWO, | 
 |                                            &error)) { | 
 |         printf(" = %d\n", numberz); | 
 |         if (numberz != T_TEST_NUMBERZ_TWO) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       printf("testEnum(THREE)"); | 
 |       if (t_test_thrift_test_if_test_enum (test_client, | 
 |                                            &numberz, | 
 |                                            T_TEST_NUMBERZ_THREE, | 
 |                                            &error)) { | 
 |         printf(" = %d\n", numberz); | 
 |         if (numberz != T_TEST_NUMBERZ_THREE) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       printf("testEnum(FIVE)"); | 
 |       if (t_test_thrift_test_if_test_enum (test_client, | 
 |                                            &numberz, | 
 |                                            T_TEST_NUMBERZ_FIVE, | 
 |                                            &error)) { | 
 |         printf(" = %d\n", numberz); | 
 |         if (numberz != T_TEST_NUMBERZ_FIVE) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       printf("testEnum(EIGHT)"); | 
 |       if (t_test_thrift_test_if_test_enum (test_client, | 
 |                                            &numberz, | 
 |                                            T_TEST_NUMBERZ_EIGHT, | 
 |                                            &error)) { | 
 |         printf(" = %d\n", numberz); | 
 |         if (numberz != T_TEST_NUMBERZ_EIGHT) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       /** | 
 |        * TYPEDEF TEST | 
 |        */ | 
 |       printf ("testTypedef(309858235082523)"); | 
 |       if (t_test_thrift_test_if_test_typedef (test_client, | 
 |                                               &user_id, | 
 |                                               309858235082523LL, | 
 |                                               &error)) { | 
 |         printf(" = %" PRId64 "\n", user_id); | 
 |         if (user_id != 309858235082523LL) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       /** | 
 |        * NESTED MAP TEST | 
 |        */ | 
 |       printf ("testMapMap(1)"); | 
 |       map_in = g_hash_table_new_full (g_int_hash, | 
 |                                       g_int_equal, | 
 |                                       g_free, | 
 |                                       (GDestroyNotify)g_hash_table_unref); | 
 |       if (t_test_thrift_test_if_test_map_map (test_client, | 
 |                                               &map_in, | 
 |                                               1, | 
 |                                               &error)) { | 
 |         g_hash_table_iter_init (&hash_table_iter, map_in); | 
 |  | 
 |         printf (" = {"); | 
 |         while (g_hash_table_iter_next (&hash_table_iter, | 
 |                                        &key, | 
 |                                        &value)) { | 
 |           printf ("%d => {", *(gint32 *)key); | 
 |  | 
 |           g_hash_table_iter_init (&inner_hash_table_iter, | 
 |                                   (GHashTable *)value); | 
 |           while (g_hash_table_iter_next (&inner_hash_table_iter, | 
 |                                          &key, | 
 |                                          &value)) { | 
 |             printf ("%d => %d, ", *(gint32 *)key, *(gint32 *)value); | 
 |           } | 
 |  | 
 |           printf ("}, "); | 
 |         } | 
 |         printf ("}\n"); | 
 |  | 
 |         if (g_hash_table_size (map_in) != 2) | 
 |           fail_count++; | 
 |         else { | 
 |           gint32 inner_keys[] = {1, 2, 3, 4}; | 
 |           gint32 i32_key; | 
 |  | 
 |           i32_key = -4; | 
 |           inner_map_in = g_hash_table_lookup (map_in, &i32_key); | 
 |           if (inner_map_in == NULL || | 
 |               g_hash_table_size (inner_map_in) != 4) | 
 |             fail_count++; | 
 |           else { | 
 |             keys_in = g_hash_table_get_keys (inner_map_in); | 
 |             keys_in = g_list_sort (keys_in, gint32_compare); | 
 |  | 
 |             for (i = 0; i < 4; i++) { | 
 |               keys_elem = g_list_nth (keys_in, 3 - i); | 
 |  | 
 |               if (*(gint32 *)keys_elem->data != (-1 * inner_keys[i]) || | 
 |                   *(gint32 *)g_hash_table_lookup (inner_map_in, | 
 |                                                   keys_elem->data) != | 
 |                   (-1 * inner_keys[i])) { | 
 |                 fail_count++; | 
 |                 break; | 
 |               } | 
 |             } | 
 |  | 
 |             g_list_free (keys_in); | 
 |           } | 
 |  | 
 |           i32_key = 4; | 
 |           inner_map_in = g_hash_table_lookup (map_in, &i32_key); | 
 |           if (inner_map_in == NULL || | 
 |               g_hash_table_size (inner_map_in) != 4) | 
 |             fail_count++; | 
 |           else { | 
 |             keys_in = g_hash_table_get_keys (inner_map_in); | 
 |             keys_in = g_list_sort (keys_in, gint32_compare); | 
 |  | 
 |             for (i = 0; i < 4; i++) { | 
 |               keys_elem = g_list_nth (keys_in, i); | 
 |  | 
 |               if (*(gint32 *)keys_elem->data != inner_keys[i] || | 
 |                   *(gint32 *)g_hash_table_lookup (inner_map_in, | 
 |                                                   keys_elem->data) != | 
 |                   inner_keys[i]) { | 
 |                 fail_count++; | 
 |                 break; | 
 |               } | 
 |             } | 
 |  | 
 |             g_list_free (keys_in); | 
 |           } | 
 |         } | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       g_hash_table_unref (map_in); | 
 |  | 
 |       /** | 
 |        * INSANITY TEST | 
 |        */ | 
 |       insanity_out = g_object_new (T_TEST_TYPE_INSANITY, NULL); | 
 |       g_object_get (insanity_out, | 
 |                     "userMap", &user_map, | 
 |                     "xtructs", &xtructs, | 
 |                     NULL); | 
 |  | 
 |       numberz = T_TEST_NUMBERZ_FIVE; | 
 |       numberz2 = T_TEST_NUMBERZ_EIGHT; | 
 |       user_id_ptr = g_malloc (sizeof *user_id_ptr); | 
 |       *user_id_ptr = 5; | 
 |       user_id_ptr2 = g_malloc (sizeof *user_id_ptr); | 
 |       *user_id_ptr2 = 8; | 
 |       g_hash_table_insert (user_map, (gpointer)numberz, user_id_ptr); | 
 |       g_hash_table_insert (user_map, (gpointer)numberz2, user_id_ptr2); | 
 |       g_hash_table_unref (user_map); | 
 |  | 
 |       xtruct_out = g_object_new (T_TEST_TYPE_XTRUCT, | 
 |                                  "string_thing", "Hello2", | 
 |                                  "byte_thing",   2, | 
 |                                  "i32_thing",    2, | 
 |                                  "i64_thing",    2LL, | 
 |                                  NULL); | 
 |       xtruct_out2 = g_object_new (T_TEST_TYPE_XTRUCT, | 
 |                                  "string_thing", "Goodbye4", | 
 |                                  "byte_thing",   4, | 
 |                                  "i32_thing",    4, | 
 |                                  "i64_thing",    4LL, | 
 |                                  NULL); | 
 |       g_ptr_array_add (xtructs, xtruct_out2); | 
 |       g_ptr_array_add (xtructs, xtruct_out); | 
 |       g_ptr_array_unref (xtructs); | 
 |  | 
 |       map_in = g_hash_table_new_full (g_int64_hash, | 
 |                                       g_int64_equal, | 
 |                                       g_free, | 
 |                                       (GDestroyNotify)g_hash_table_unref); | 
 |  | 
 |       printf("testInsanity()"); | 
 |       if (t_test_thrift_test_if_test_insanity (test_client, | 
 |                                                &map_in, | 
 |                                                insanity_out, | 
 |                                                &error)) { | 
 |         printf (" = {"); | 
 |         g_hash_table_iter_init (&hash_table_iter, map_in); | 
 |         while (g_hash_table_iter_next (&hash_table_iter, | 
 |                                        &key, | 
 |                                        &value)) { | 
 |           printf ("%" PRId64 " => {", *(TTestUserId *)key); | 
 |  | 
 |           g_hash_table_iter_init (&inner_hash_table_iter, | 
 |                                   (GHashTable *)value); | 
 |           while (g_hash_table_iter_next (&inner_hash_table_iter, | 
 |                                          &key, | 
 |                                          &value)) { | 
 |             printf ("%d => {", (TTestNumberz)key); | 
 |  | 
 |             g_object_get ((TTestInsanity *)value, | 
 |                           "userMap", &user_map, | 
 |                           "xtructs", &xtructs, | 
 |                           NULL); | 
 |  | 
 |             printf ("{"); | 
 |             g_hash_table_iter_init (&user_map_iter, user_map); | 
 |             while (g_hash_table_iter_next (&user_map_iter, | 
 |                                            &key, | 
 |                                            &value)) { | 
 |               printf ("%d => %" PRId64 ", ", | 
 |                       (TTestNumberz)key, | 
 |                       *(TTestUserId *)value); | 
 |             } | 
 |             printf ("}, "); | 
 |             g_hash_table_unref (user_map); | 
 |  | 
 |             printf("{"); | 
 |             for (i = 0; i < (gint32)xtructs->len; ++i) { | 
 |               xtruct_in = g_ptr_array_index (xtructs, i); | 
 |               g_object_get (xtruct_in, | 
 |                             "string_thing", &string, | 
 |                             "byte_thing",   &byte_thing, | 
 |                             "i32_thing",    &i32_thing, | 
 |                             "i64_thing",    &i64_thing, | 
 |                             NULL); | 
 |  | 
 |               printf ("{\"%s\", %d, %d, %" PRId64 "}, ", | 
 |                       string, | 
 |                       byte_thing, | 
 |                       i32_thing, | 
 |                       i64_thing); | 
 |             } | 
 |             printf ("}"); | 
 |             g_ptr_array_unref (xtructs); | 
 |  | 
 |             printf ("}, "); | 
 |           } | 
 |           printf("}, "); | 
 |         } | 
 |         printf("}\n"); | 
 |  | 
 |         if (g_hash_table_size (map_in) != 2) | 
 |           fail_count++; | 
 |         else { | 
 |           TTestNumberz numberz_key_values[] = { | 
 |             T_TEST_NUMBERZ_TWO, T_TEST_NUMBERZ_THREE | 
 |           }; | 
 |           gint user_map_values[] = { 5, 8 }; | 
 |           TTestUserId user_id_key; | 
 |  | 
 |           user_id_key = 1; | 
 |           inner_map_in = g_hash_table_lookup (map_in, &user_id_key); | 
 |           if (inner_map_in == NULL || | 
 |               g_hash_table_size (inner_map_in) != 2) | 
 |             fail_count++; | 
 |           else { | 
 |             TTestNumberz numberz_key; | 
 |  | 
 |             for (i = 0; i < 2; ++i) { | 
 |               numberz_key = numberz_key_values[i]; | 
 |               insanity_in = | 
 |                 g_hash_table_lookup (inner_map_in, | 
 |                                      (gconstpointer)numberz_key); | 
 |               if (insanity_in == NULL) | 
 |                 fail_count++; | 
 |               else { | 
 |                 g_object_get (insanity_in, | 
 |                               "userMap", &user_map, | 
 |                               "xtructs", &xtructs, | 
 |                               NULL); | 
 |  | 
 |                 if (user_map == NULL) | 
 |                   fail_count++; | 
 |                 else { | 
 |                   if (g_hash_table_size (user_map) != 2) | 
 |                     fail_count++; | 
 |                   else { | 
 |                     for (j = 0; j < 2; ++j) { | 
 |                       numberz_key = (TTestNumberz)user_map_values[j]; | 
 |  | 
 |                       value = | 
 |                         g_hash_table_lookup (user_map, | 
 |                                              (gconstpointer)numberz_key); | 
 |                       if (value == NULL || | 
 |                           *(TTestUserId *)value != (TTestUserId)user_map_values[j]) | 
 |                         fail_count++; | 
 |                     } | 
 |                   } | 
 |  | 
 |                   g_hash_table_unref (user_map); | 
 |                 } | 
 |  | 
 |                 if (xtructs == NULL) | 
 |                   fail_count++; | 
 |                 else { | 
 |                   if (xtructs->len != 2) | 
 |                     fail_count++; | 
 |                   else { | 
 |                     xtruct_in = g_ptr_array_index (xtructs, 0); | 
 |                     g_object_get (xtruct_in, | 
 |                                   "string_thing", &string, | 
 |                                   "byte_thing",   &byte_thing, | 
 |                                   "i32_thing",    &i32_thing, | 
 |                                   "i64_thing",    &i64_thing, | 
 |                                   NULL); | 
 |                     if ((string == NULL || | 
 |                          strncmp (string, "Goodbye4", 9) != 0) || | 
 |                         byte_thing != 4 || | 
 |                         i32_thing != 4 || | 
 |                         i64_thing != 4) | 
 |                       fail_count++; | 
 |  | 
 |                     if (string != NULL) | 
 |                       g_free (string); | 
 |  | 
 |                     xtruct_in = g_ptr_array_index (xtructs, 1); | 
 |                     g_object_get (xtruct_in, | 
 |                                   "string_thing", &string, | 
 |                                   "byte_thing",   &byte_thing, | 
 |                                   "i32_thing",    &i32_thing, | 
 |                                   "i64_thing",    &i64_thing, | 
 |                                   NULL); | 
 |                     if ((string == NULL || | 
 |                          strncmp (string, "Hello2", 7) != 0) || | 
 |                         byte_thing != 2 || | 
 |                         i32_thing != 2 || | 
 |                         i64_thing != 2) | 
 |                       fail_count++; | 
 |  | 
 |                     if (string != NULL) | 
 |                       g_free (string); | 
 |                   } | 
 |  | 
 |                   g_ptr_array_unref (xtructs); | 
 |                 } | 
 |               } | 
 |             } | 
 |           } | 
 |  | 
 |           user_id_key = 2; | 
 |           inner_map_in = g_hash_table_lookup (map_in, &user_id_key); | 
 |           if (inner_map_in == NULL || | 
 |               g_hash_table_size (inner_map_in) != 1) | 
 |             fail_count++; | 
 |           else { | 
 |             insanity_in = | 
 |               g_hash_table_lookup (inner_map_in, | 
 |                                    (gconstpointer)T_TEST_NUMBERZ_SIX); | 
 |             if (insanity_in == NULL) | 
 |               fail_count++; | 
 |             else { | 
 |               g_object_get (insanity_in, | 
 |                             "userMap", &user_map, | 
 |                             "xtructs", &xtructs, | 
 |                             NULL); | 
 |  | 
 |               if (user_map == NULL) | 
 |                 fail_count++; | 
 |               else { | 
 |                 if (g_hash_table_size (user_map) != 0) | 
 |                   fail_count++; | 
 |  | 
 |                 g_hash_table_unref (user_map); | 
 |               } | 
 |  | 
 |               if (xtructs == NULL) | 
 |                 fail_count++; | 
 |               else { | 
 |                 if (xtructs->len != 0) | 
 |                   fail_count++; | 
 |  | 
 |                 g_ptr_array_unref (xtructs); | 
 |               } | 
 |             } | 
 |           } | 
 |         } | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       g_hash_table_unref (map_in); | 
 |       g_clear_object (&insanity_out); | 
 |  | 
 |       /* test exception */ | 
 |       printf ("testClient.testException(\"Xception\") =>"); | 
 |       if (!t_test_thrift_test_if_test_exception (test_client, | 
 |                                                  "Xception", | 
 |                                                  &xception, | 
 |                                                  &error) && | 
 |           xception != NULL) { | 
 |         g_object_get (xception, | 
 |                       "errorCode", &int32, | 
 |                       "message",   &string, | 
 |                       NULL); | 
 |         printf ("  {%u, \"%s\"}\n", int32, string); | 
 |         g_free (string); | 
 |  | 
 |         g_clear_object (&xception); | 
 |  | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |       } | 
 |       else { | 
 |         printf ("  void\nFAILURE\n"); | 
 |         fail_count++; | 
 |  | 
 |         if (xception != NULL) { | 
 |           g_object_unref (xception); | 
 |           xception = NULL; | 
 |         } | 
 |  | 
 |         if (error != NULL) { | 
 |           g_error_free (error); | 
 |           error = NULL; | 
 |         } | 
 |       } | 
 |  | 
 |       printf ("testClient.testException(\"TException\") =>"); | 
 |       if (!t_test_thrift_test_if_test_exception (test_client, | 
 |                                                  "TException", | 
 |                                                  &xception, | 
 |                                                  &error) && | 
 |           xception == NULL && | 
 |           error != NULL) { | 
 |         printf ("  Caught TException\n"); | 
 |  | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |       } | 
 |       else { | 
 |         printf ("  void\nFAILURE\n"); | 
 |         fail_count++; | 
 |  | 
 |         g_clear_object (&xception); | 
 |  | 
 |         if (error != NULL) { | 
 |           g_error_free (error); | 
 |           error = NULL; | 
 |         } | 
 |       } | 
 |  | 
 |       printf ("testClient.testException(\"success\") =>"); | 
 |       if (t_test_thrift_test_if_test_exception (test_client, | 
 |                                                 "success", | 
 |                                                 &xception, | 
 |                                                 &error)) | 
 |         printf ("  void\n"); | 
 |       else { | 
 |         printf ("  void\nFAILURE\n"); | 
 |         fail_count++; | 
 |  | 
 |         g_clear_object (&xception); | 
 |  | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |       } | 
 |  | 
 |       g_assert (error == NULL); | 
 |  | 
 |       /* test multi exception */ | 
 |       printf ("testClient.testMultiException(\"Xception\", \"test 1\") =>"); | 
 |       xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); | 
 |       if (!t_test_thrift_test_if_test_multi_exception (test_client, | 
 |                                                        &xtruct_in, | 
 |                                                        "Xception", | 
 |                                                        "test 1", | 
 |                                                        &xception, | 
 |                                                        &xception2, | 
 |                                                        &error) && | 
 |           xception != NULL && | 
 |           xception2 == NULL) { | 
 |         g_object_get (xception, | 
 |                       "errorCode", &int32, | 
 |                       "message",   &string, | 
 |                       NULL); | 
 |         printf ("  {%u, \"%s\"}\n", int32, string); | 
 |         g_free (string); | 
 |  | 
 |         g_object_unref (xception); | 
 |         xception = NULL; | 
 |  | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |       } | 
 |       else { | 
 |         printf ("  result\nFAILURE\n"); | 
 |         fail_count++; | 
 |  | 
 |         g_clear_object (&xception); | 
 |         g_clear_object (&xception2); | 
 |  | 
 |         if (error != NULL) { | 
 |           g_error_free (error); | 
 |           error = NULL; | 
 |         } | 
 |       } | 
 |       g_object_unref (xtruct_in); | 
 |  | 
 |       printf ("testClient.testMultiException(\"Xception2\", \"test 2\") =>"); | 
 |       xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); | 
 |       if (!t_test_thrift_test_if_test_multi_exception (test_client, | 
 |                                                        &xtruct_in, | 
 |                                                        "Xception2", | 
 |                                                        "test 2", | 
 |                                                        &xception, | 
 |                                                        &xception2, | 
 |                                                        &error) && | 
 |           xception == NULL && | 
 |           xception2 != NULL) { | 
 |         g_object_get (xception2, | 
 |                       "errorCode",    &int32, | 
 |                       "struct_thing", &inner_xtruct_in, | 
 |                       NULL); | 
 |         g_object_get (inner_xtruct_in, | 
 |                       "string_thing", &string, | 
 |                       NULL); | 
 |         printf ("  {%u, {\"%s\"}}\n", int32, string); | 
 |         g_free (string); | 
 |  | 
 |         g_clear_object (&inner_xtruct_in); | 
 |         g_clear_object (&xception2); | 
 |  | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |       } | 
 |       else { | 
 |         printf ("  result\nFAILURE\n"); | 
 |         fail_count++; | 
 |  | 
 |         g_clear_object (&xception); | 
 |         g_clear_object (&xception2); | 
 |  | 
 |         if (error != NULL) { | 
 |           g_error_free (error); | 
 |           error = NULL; | 
 |         } | 
 |       } | 
 |       g_clear_object (&xtruct_in); | 
 |  | 
 |       printf ("testClient.testMultiException(\"success\", \"test 3\") =>"); | 
 |       xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL); | 
 |       if (t_test_thrift_test_if_test_multi_exception (test_client, | 
 |                                                       &xtruct_in, | 
 |                                                       "success", | 
 |                                                       "test 3", | 
 |                                                       &xception, | 
 |                                                       &xception2, | 
 |                                                       &error) && | 
 |           xception == NULL && | 
 |           xception2 == NULL) { | 
 |         g_object_get (xtruct_in, | 
 |                       "string_thing", &string, | 
 |                       NULL); | 
 |         printf ("  {{\"%s\"}}\n", string); | 
 |         g_free (string); | 
 |       } | 
 |       else { | 
 |         printf ("  result\nFAILURE\n"); | 
 |         fail_count++; | 
 |  | 
 |         g_clear_object (&xception); | 
 |         g_clear_object (&xception2); | 
 |  | 
 |         if (error != NULL) { | 
 |           g_error_free (error); | 
 |           error = NULL; | 
 |         } | 
 |       } | 
 |       g_clear_object (&xtruct_in); | 
 |  | 
 |       /* test oneway void */ | 
 |       printf ("testClient.testOneway(1) =>"); | 
 |       gettimeofday (&oneway_start, NULL); | 
 |       oneway_result = t_test_thrift_test_if_test_oneway (test_client, | 
 |                                                          1, | 
 |                                                          &error); | 
 |       gettimeofday (&oneway_end, NULL); | 
 |       timersub (&oneway_end, &oneway_start, &oneway_elapsed); | 
 |       oneway_elapsed_usec = | 
 |         oneway_elapsed.tv_sec * 1000 * 1000 + oneway_elapsed.tv_usec; | 
 |  | 
 |       if (oneway_result) { | 
 |         if (oneway_elapsed_usec > 200 * 1000) { | 
 |           printf ("  FAILURE - took %.2f ms\n", | 
 |                   (double)oneway_elapsed_usec / 1000.0); | 
 |           fail_count++; | 
 |         } | 
 |         else | 
 |           printf ("  success - took %.2f ms\n", | 
 |                   (double)oneway_elapsed_usec / 1000.0); | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       /** | 
 |        * redo a simple test after the oneway to make sure we aren't "off by | 
 |        * one" -- if the server treated oneway void like normal void, this next | 
 |        * test will fail since it will get the void confirmation rather than | 
 |        * the correct result. In this circumstance, the client will receive the | 
 |        * error: | 
 |        * | 
 |        *   application error: Wrong method name | 
 |        */ | 
 |       /** | 
 |        * I32 TEST | 
 |        */ | 
 |       printf ("re-test testI32(-1)"); | 
 |       if (t_test_thrift_test_if_test_i32 (test_client, | 
 |                                           &int32, | 
 |                                           -1, | 
 |                                           &error)) { | 
 |         printf (" = %d\n", int32); | 
 |         if (int32 != -1) | 
 |           fail_count++; | 
 |       } | 
 |       else { | 
 |         printf ("%s\n", error->message); | 
 |         g_error_free (error); | 
 |         error = NULL; | 
 |  | 
 |         fail_count++; | 
 |       } | 
 |  | 
 |       gettimeofday (&time_stop, NULL); | 
 |       timersub (&time_stop, &time_start, &time_elapsed); | 
 |       time_elapsed_usec = | 
 |         time_elapsed.tv_sec * 1000 * 1000 + time_elapsed.tv_usec; | 
 |  | 
 |       printf("Total time: %" PRIu64 " us\n", time_elapsed_usec); | 
 |  | 
 |       time_total_usec += time_elapsed_usec; | 
 |       if (time_elapsed_usec < time_min_usec) | 
 |         time_min_usec = time_elapsed_usec; | 
 |       if (time_elapsed_usec > time_max_usec) | 
 |         time_max_usec = time_elapsed_usec; | 
 |  | 
 |       thrift_transport_close (transport, &error); | 
 |     } | 
 |     else { | 
 |       printf ("Connect failed: %s\n", error->message); | 
 |       g_error_free (error); | 
 |       error = NULL; | 
 |  | 
 |       return 1; | 
 |     } | 
 |   } | 
 |  | 
 |   /* All done---output statistics */ | 
 |   puts ("\nAll tests done."); | 
 |   printf("Number of failures: %d\n", fail_count); | 
 |  | 
 |   time_avg_usec = time_total_usec / num_tests; | 
 |  | 
 |   printf ("Min time: %" PRIu64 " us\n", time_min_usec); | 
 |   printf ("Max time: %" PRIu64 " us\n", time_max_usec); | 
 |   printf ("Avg time: %" PRIu64 " us\n", time_avg_usec); | 
 |  | 
 |   g_clear_object(&second_service); | 
 |   g_clear_object(&protocol2); | 
 |   g_clear_object(&test_client); | 
 |   g_clear_object(&protocol); | 
 |   g_clear_object(&transport); | 
 |   g_clear_object(&socket); | 
 |  | 
 |   if (ssl) { | 
 |     thrift_ssl_socket_finalize_openssl(); | 
 |   } | 
 |  | 
 |   return fail_count; | 
 | } |