• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3
2# -*- coding: utf-8 -*-
3#
4# Copyright © 2019 Endless Mobile, Inc.
5#
6# This library is free software; you can redistribute it and/or
7# modify it under the terms of the GNU Lesser General Public
8# License as published by the Free Software Foundation; either
9# version 2.1 of the License, or (at your option) any later version.
10#
11# This library is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14# Lesser General Public License for more details.
15#
16# You should have received a copy of the GNU Lesser General Public
17# License along with this library; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19# MA  02110-1301  USA
20
21"""Integration tests for glib-genmarshal utility."""
22
23import collections
24import os
25import shutil
26import subprocess
27import sys
28import tempfile
29from textwrap import dedent
30import unittest
31
32import taptestrunner
33
34
35Result = collections.namedtuple('Result', ('info', 'out', 'err', 'subs'))
36
37
38class TestGenmarshal(unittest.TestCase):
39    """Integration test for running glib-genmarshal.
40
41    This can be run when installed or uninstalled. When uninstalled, it
42    requires G_TEST_BUILDDIR and G_TEST_SRCDIR to be set.
43
44    The idea with this test harness is to test the glib-genmarshal utility, its
45    handling of command line arguments, its exit statuses, and its handling of
46    various marshaller lists. In future we could split the core glib-genmarshal
47    parsing and generation code out into a library and unit test that, and
48    convert this test to just check command line behaviour.
49    """
50    # Track the cwd, we want to back out to that to clean up our tempdir
51    cwd = ''
52
53    def setUp(self):
54        self.timeout_seconds = 10  # seconds per test
55        self.tmpdir = tempfile.TemporaryDirectory()
56        self.cwd = os.getcwd()
57        os.chdir(self.tmpdir.name)
58        print('tmpdir:', self.tmpdir.name)
59        if 'G_TEST_BUILDDIR' in os.environ:
60            self.__genmarshal = \
61                os.path.join(os.environ['G_TEST_BUILDDIR'], '..',
62                             'glib-genmarshal')
63        else:
64            self.__genmarshal = shutil.which('glib-genmarshal')
65        print('genmarshal:', self.__genmarshal)
66
67    def tearDown(self):
68        os.chdir(self.cwd)
69        self.tmpdir.cleanup()
70
71    def runGenmarshal(self, *args):
72        argv = [self.__genmarshal]
73
74        # shebang lines are not supported on native
75        # Windows consoles
76        if os.name == 'nt':
77            argv.insert(0, sys.executable)
78
79        argv.extend(args)
80        print('Running:', argv)
81
82        env = os.environ.copy()
83        env['LC_ALL'] = 'C.UTF-8'
84        print('Environment:', env)
85
86        # We want to ensure consistent line endings...
87        info = subprocess.run(argv, timeout=self.timeout_seconds,
88                              stdout=subprocess.PIPE,
89                              stderr=subprocess.PIPE,
90                              env=env,
91                              universal_newlines=True)
92        info.check_returncode()
93        out = info.stdout.strip()
94        err = info.stderr.strip()
95
96        # Known substitutions for standard boilerplate
97        subs = {
98            'standard_top_comment':
99                'This file is generated by glib-genmarshal, do not modify '
100                'it. This code is licensed under the same license as the '
101                'containing project. Note that it links to GLib, so must '
102                'comply with the LGPL linking clauses.',
103            'standard_top_pragma': dedent(
104                '''
105                #ifndef __G_CCLOSURE_USER_MARSHAL_MARSHAL_H__
106                #define __G_CCLOSURE_USER_MARSHAL_MARSHAL_H__
107                ''').strip(),
108            'standard_bottom_pragma': dedent(
109                '''
110                #endif /* __G_CCLOSURE_USER_MARSHAL_MARSHAL_H__ */
111                ''').strip(),
112            'standard_includes': dedent(
113                '''
114                #include <glib-object.h>
115                ''').strip(),
116            'standard_marshal_peek_defines': dedent(
117                '''
118                #ifdef G_ENABLE_DEBUG
119                #define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
120                #define g_marshal_value_peek_char(v)     g_value_get_schar (v)
121                #define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
122                #define g_marshal_value_peek_int(v)      g_value_get_int (v)
123                #define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
124                #define g_marshal_value_peek_long(v)     g_value_get_long (v)
125                #define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
126                #define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
127                #define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
128                #define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
129                #define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
130                #define g_marshal_value_peek_float(v)    g_value_get_float (v)
131                #define g_marshal_value_peek_double(v)   g_value_get_double (v)
132                #define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
133                #define g_marshal_value_peek_param(v)    g_value_get_param (v)
134                #define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
135                #define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
136                #define g_marshal_value_peek_object(v)   g_value_get_object (v)
137                #define g_marshal_value_peek_variant(v)  g_value_get_variant (v)
138                #else /* !G_ENABLE_DEBUG */
139                /* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
140                 *          Do not access GValues directly in your code. Instead, use the
141                 *          g_value_get_*() functions
142                 */
143                #define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
144                #define g_marshal_value_peek_char(v)     (v)->data[0].v_int
145                #define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
146                #define g_marshal_value_peek_int(v)      (v)->data[0].v_int
147                #define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
148                #define g_marshal_value_peek_long(v)     (v)->data[0].v_long
149                #define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
150                #define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
151                #define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
152                #define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
153                #define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
154                #define g_marshal_value_peek_float(v)    (v)->data[0].v_float
155                #define g_marshal_value_peek_double(v)   (v)->data[0].v_double
156                #define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
157                #define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
158                #define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
159                #define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
160                #define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
161                #define g_marshal_value_peek_variant(v)  (v)->data[0].v_pointer
162                #endif /* !G_ENABLE_DEBUG */
163                ''').strip(),
164        }
165
166        result = Result(info, out, err, subs)
167
168        print('Output:', result.out)
169        return result
170
171    def runGenmarshalWithList(self, list_contents, *args):
172        with tempfile.NamedTemporaryFile(dir=self.tmpdir.name,
173                                         suffix='.list',
174                                         delete=False) as list_file:
175            # Write out the list.
176            list_file.write(list_contents.encode('utf-8'))
177            print(list_file.name + ':', list_contents)
178            list_file.flush()
179
180            header_result = self.runGenmarshal(list_file.name,
181                                               '--header', *args)
182            body_result = self.runGenmarshal(list_file.name,
183                                             '--body', *args)
184
185            header_result.subs['list_path'] = list_file.name
186            body_result.subs['list_path'] = list_file.name
187
188            return (header_result, body_result)
189
190    def test_help(self):
191        """Test the --help argument."""
192        result = self.runGenmarshal('--help')
193        self.assertIn('usage: glib-genmarshal', result.out)
194
195    def test_no_args(self):
196        """Test running with no arguments at all."""
197        result = self.runGenmarshal()
198        self.assertEqual('', result.err)
199        self.assertEqual('', result.out)
200
201    def test_empty_list(self):
202        """Test running with an empty list."""
203        (header_result, body_result) = \
204            self.runGenmarshalWithList('', '--quiet')
205
206        self.assertEqual('', header_result.err)
207        self.assertEqual('', body_result.err)
208
209        self.assertEqual(dedent(
210            '''
211            /* {standard_top_comment} */
212            {standard_top_pragma}
213
214            {standard_includes}
215
216            G_BEGIN_DECLS
217
218
219            G_END_DECLS
220
221            {standard_bottom_pragma}
222            ''').strip().format(**header_result.subs),
223            header_result.out.strip())
224
225        self.assertEqual(dedent(
226            '''
227            /* {standard_top_comment} */
228            {standard_includes}
229
230            {standard_marshal_peek_defines}
231            ''').strip().format(**body_result.subs),
232            body_result.out.strip())
233
234    def test_void_boolean(self):
235        """Test running with a basic VOID:BOOLEAN list."""
236        (header_result, body_result) = \
237            self.runGenmarshalWithList('VOID:BOOLEAN', '--quiet')
238
239        self.assertEqual('', header_result.err)
240        self.assertEqual('', body_result.err)
241
242        self.assertEqual(dedent(
243            '''
244            /* {standard_top_comment} */
245            {standard_top_pragma}
246
247            {standard_includes}
248
249            G_BEGIN_DECLS
250
251            /* VOID:BOOLEAN ({list_path}:1) */
252            #define g_cclosure_user_marshal_VOID__BOOLEAN	g_cclosure_marshal_VOID__BOOLEAN
253
254
255            G_END_DECLS
256
257            {standard_bottom_pragma}
258            ''').strip().format(**header_result.subs),
259            header_result.out.strip())
260
261        self.assertEqual(dedent(
262            '''
263            /* {standard_top_comment} */
264            {standard_includes}
265
266            {standard_marshal_peek_defines}
267            ''').strip().format(**body_result.subs),
268            body_result.out.strip())
269
270    def test_void_boolean_int64(self):
271        """Test running with a non-trivial VOID:BOOLEAN,INT64 list."""
272        (header_result, body_result) = \
273            self.runGenmarshalWithList('VOID:BOOLEAN,INT64', '--quiet')
274
275        self.assertEqual('', header_result.err)
276        self.assertEqual('', body_result.err)
277
278        self.assertEqual(dedent(
279            '''
280            /* {standard_top_comment} */
281            {standard_top_pragma}
282
283            {standard_includes}
284
285            G_BEGIN_DECLS
286
287            /* VOID:BOOLEAN,INT64 ({list_path}:1) */
288            extern
289            void g_cclosure_user_marshal_VOID__BOOLEAN_INT64 (GClosure     *closure,
290                                                              GValue       *return_value,
291                                                              guint         n_param_values,
292                                                              const GValue *param_values,
293                                                              gpointer      invocation_hint,
294                                                              gpointer      marshal_data);
295
296
297            G_END_DECLS
298
299            {standard_bottom_pragma}
300            ''').strip().format(**header_result.subs),
301            header_result.out.strip())
302
303        self.assertEqual(dedent(
304            '''
305            /* {standard_top_comment} */
306            {standard_includes}
307
308            {standard_marshal_peek_defines}
309
310            /* VOID:BOOLEAN,INT64 ({list_path}:1) */
311            void
312            g_cclosure_user_marshal_VOID__BOOLEAN_INT64 (GClosure     *closure,
313                                                         GValue       *return_value G_GNUC_UNUSED,
314                                                         guint         n_param_values,
315                                                         const GValue *param_values,
316                                                         gpointer      invocation_hint G_GNUC_UNUSED,
317                                                         gpointer      marshal_data)
318            {{
319              typedef void (*GMarshalFunc_VOID__BOOLEAN_INT64) (gpointer data1,
320                                                                gboolean arg1,
321                                                                gint64 arg2,
322                                                                gpointer data2);
323              GCClosure *cc = (GCClosure *) closure;
324              gpointer data1, data2;
325              GMarshalFunc_VOID__BOOLEAN_INT64 callback;
326
327              g_return_if_fail (n_param_values == 3);
328
329              if (G_CCLOSURE_SWAP_DATA (closure))
330                {{
331                  data1 = closure->data;
332                  data2 = g_value_peek_pointer (param_values + 0);
333                }}
334              else
335                {{
336                  data1 = g_value_peek_pointer (param_values + 0);
337                  data2 = closure->data;
338                }}
339              callback = (GMarshalFunc_VOID__BOOLEAN_INT64) (marshal_data ? marshal_data : cc->callback);
340
341              callback (data1,
342                        g_marshal_value_peek_boolean (param_values + 1),
343                        g_marshal_value_peek_int64 (param_values + 2),
344                        data2);
345            }}
346            ''').strip().format(**body_result.subs),
347            body_result.out.strip())
348
349    def test_void_variant_nostdinc_valist_marshaller(self):
350        """Test running with a basic VOID:VARIANT list, but without the
351        standard marshallers, and with valist support enabled. This checks that
352        the valist marshaller for VARIANT correctly sinks floating variants.
353
354        See issue #1793.
355        """
356        (header_result, body_result) = \
357            self.runGenmarshalWithList('VOID:VARIANT', '--quiet', '--nostdinc',
358                                       '--valist-marshaller')
359
360        self.assertEqual('', header_result.err)
361        self.assertEqual('', body_result.err)
362
363        self.assertEqual(dedent(
364            '''
365            /* {standard_top_comment} */
366            {standard_top_pragma}
367
368            G_BEGIN_DECLS
369
370            /* VOID:VARIANT ({list_path}:1) */
371            extern
372            void g_cclosure_user_marshal_VOID__VARIANT (GClosure     *closure,
373                                                        GValue       *return_value,
374                                                        guint         n_param_values,
375                                                        const GValue *param_values,
376                                                        gpointer      invocation_hint,
377                                                        gpointer      marshal_data);
378            extern
379            void g_cclosure_user_marshal_VOID__VARIANTv (GClosure *closure,
380                                                         GValue   *return_value,
381                                                         gpointer  instance,
382                                                         va_list   args,
383                                                         gpointer  marshal_data,
384                                                         int       n_params,
385                                                         GType    *param_types);
386
387
388            G_END_DECLS
389
390            {standard_bottom_pragma}
391            ''').strip().format(**header_result.subs),
392            header_result.out.strip())
393
394        self.assertEqual(dedent(
395            '''
396            /* {standard_top_comment} */
397            {standard_marshal_peek_defines}
398
399            /* VOID:VARIANT ({list_path}:1) */
400            void
401            g_cclosure_user_marshal_VOID__VARIANT (GClosure     *closure,
402                                                   GValue       *return_value G_GNUC_UNUSED,
403                                                   guint         n_param_values,
404                                                   const GValue *param_values,
405                                                   gpointer      invocation_hint G_GNUC_UNUSED,
406                                                   gpointer      marshal_data)
407            {{
408              typedef void (*GMarshalFunc_VOID__VARIANT) (gpointer data1,
409                                                          gpointer arg1,
410                                                          gpointer data2);
411              GCClosure *cc = (GCClosure *) closure;
412              gpointer data1, data2;
413              GMarshalFunc_VOID__VARIANT callback;
414
415              g_return_if_fail (n_param_values == 2);
416
417              if (G_CCLOSURE_SWAP_DATA (closure))
418                {{
419                  data1 = closure->data;
420                  data2 = g_value_peek_pointer (param_values + 0);
421                }}
422              else
423                {{
424                  data1 = g_value_peek_pointer (param_values + 0);
425                  data2 = closure->data;
426                }}
427              callback = (GMarshalFunc_VOID__VARIANT) (marshal_data ? marshal_data : cc->callback);
428
429              callback (data1,
430                        g_marshal_value_peek_variant (param_values + 1),
431                        data2);
432            }}
433
434            void
435            g_cclosure_user_marshal_VOID__VARIANTv (GClosure *closure,
436                                                    GValue   *return_value G_GNUC_UNUSED,
437                                                    gpointer  instance,
438                                                    va_list   args,
439                                                    gpointer  marshal_data,
440                                                    int       n_params,
441                                                    GType    *param_types)
442            {{
443              typedef void (*GMarshalFunc_VOID__VARIANT) (gpointer data1,
444                                                          gpointer arg1,
445                                                          gpointer data2);
446              GCClosure *cc = (GCClosure *) closure;
447              gpointer data1, data2;
448              GMarshalFunc_VOID__VARIANT callback;
449              gpointer arg0;
450              va_list args_copy;
451
452              G_VA_COPY (args_copy, args);
453              arg0 = (gpointer) va_arg (args_copy, gpointer);
454              if ((param_types[0] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && arg0 != NULL)
455                arg0 = g_variant_ref_sink (arg0);
456              va_end (args_copy);
457
458
459              if (G_CCLOSURE_SWAP_DATA (closure))
460                {{
461                  data1 = closure->data;
462                  data2 = instance;
463                }}
464              else
465                {{
466                  data1 = instance;
467                  data2 = closure->data;
468                }}
469              callback = (GMarshalFunc_VOID__VARIANT) (marshal_data ? marshal_data : cc->callback);
470
471              callback (data1,
472                        arg0,
473                        data2);
474              if ((param_types[0] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && arg0 != NULL)
475                g_variant_unref (arg0);
476            }}
477            ''').strip().format(**body_result.subs),
478            body_result.out.strip())
479
480    def test_void_string_nostdinc(self):
481        """Test running with a basic VOID:STRING list, but without the
482        standard marshallers, and with valist support enabled. This checks that
483        the valist marshaller for STRING correctly skips a string copy if the
484        argument is static.
485
486        See issue #1792.
487        """
488        (header_result, body_result) = \
489            self.runGenmarshalWithList('VOID:STRING', '--quiet', '--nostdinc',
490                                       '--valist-marshaller')
491
492        self.assertEqual('', header_result.err)
493        self.assertEqual('', body_result.err)
494
495        self.assertEqual(dedent(
496            '''
497            /* {standard_top_comment} */
498            {standard_top_pragma}
499
500            G_BEGIN_DECLS
501
502            /* VOID:STRING ({list_path}:1) */
503            extern
504            void g_cclosure_user_marshal_VOID__STRING (GClosure     *closure,
505                                                       GValue       *return_value,
506                                                       guint         n_param_values,
507                                                       const GValue *param_values,
508                                                       gpointer      invocation_hint,
509                                                       gpointer      marshal_data);
510            extern
511            void g_cclosure_user_marshal_VOID__STRINGv (GClosure *closure,
512                                                        GValue   *return_value,
513                                                        gpointer  instance,
514                                                        va_list   args,
515                                                        gpointer  marshal_data,
516                                                        int       n_params,
517                                                        GType    *param_types);
518
519
520            G_END_DECLS
521
522            {standard_bottom_pragma}
523            ''').strip().format(**header_result.subs),
524            header_result.out.strip())
525
526        self.assertEqual(dedent(
527            '''
528            /* {standard_top_comment} */
529            {standard_marshal_peek_defines}
530
531            /* VOID:STRING ({list_path}:1) */
532            void
533            g_cclosure_user_marshal_VOID__STRING (GClosure     *closure,
534                                                  GValue       *return_value G_GNUC_UNUSED,
535                                                  guint         n_param_values,
536                                                  const GValue *param_values,
537                                                  gpointer      invocation_hint G_GNUC_UNUSED,
538                                                  gpointer      marshal_data)
539            {{
540              typedef void (*GMarshalFunc_VOID__STRING) (gpointer data1,
541                                                         gpointer arg1,
542                                                         gpointer data2);
543              GCClosure *cc = (GCClosure *) closure;
544              gpointer data1, data2;
545              GMarshalFunc_VOID__STRING callback;
546
547              g_return_if_fail (n_param_values == 2);
548
549              if (G_CCLOSURE_SWAP_DATA (closure))
550                {{
551                  data1 = closure->data;
552                  data2 = g_value_peek_pointer (param_values + 0);
553                }}
554              else
555                {{
556                  data1 = g_value_peek_pointer (param_values + 0);
557                  data2 = closure->data;
558                }}
559              callback = (GMarshalFunc_VOID__STRING) (marshal_data ? marshal_data : cc->callback);
560
561              callback (data1,
562                        g_marshal_value_peek_string (param_values + 1),
563                        data2);
564            }}
565
566            void
567            g_cclosure_user_marshal_VOID__STRINGv (GClosure *closure,
568                                                   GValue   *return_value G_GNUC_UNUSED,
569                                                   gpointer  instance,
570                                                   va_list   args,
571                                                   gpointer  marshal_data,
572                                                   int       n_params,
573                                                   GType    *param_types)
574            {{
575              typedef void (*GMarshalFunc_VOID__STRING) (gpointer data1,
576                                                         gpointer arg1,
577                                                         gpointer data2);
578              GCClosure *cc = (GCClosure *) closure;
579              gpointer data1, data2;
580              GMarshalFunc_VOID__STRING callback;
581              gpointer arg0;
582              va_list args_copy;
583
584              G_VA_COPY (args_copy, args);
585              arg0 = (gpointer) va_arg (args_copy, gpointer);
586              if ((param_types[0] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && arg0 != NULL)
587                arg0 = g_strdup (arg0);
588              va_end (args_copy);
589
590
591              if (G_CCLOSURE_SWAP_DATA (closure))
592                {{
593                  data1 = closure->data;
594                  data2 = instance;
595                }}
596              else
597                {{
598                  data1 = instance;
599                  data2 = closure->data;
600                }}
601              callback = (GMarshalFunc_VOID__STRING) (marshal_data ? marshal_data : cc->callback);
602
603              callback (data1,
604                        arg0,
605                        data2);
606              if ((param_types[0] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && arg0 != NULL)
607                g_free (arg0);
608            }}
609            ''').strip().format(**body_result.subs),
610            body_result.out.strip())
611
612    def test_void_param_nostdinc(self):
613        """Test running with a basic VOID:PARAM list, but without the
614        standard marshallers, and with valist support enabled. This checks that
615        the valist marshaller for PARAM correctly skips a param copy if the
616        argument is static.
617
618        See issue #1792.
619        """
620        self.maxDiff = None  # TODO
621        (header_result, body_result) = \
622            self.runGenmarshalWithList('VOID:PARAM', '--quiet', '--nostdinc',
623                                       '--valist-marshaller')
624
625        self.assertEqual('', header_result.err)
626        self.assertEqual('', body_result.err)
627
628        self.assertEqual(dedent(
629            '''
630            /* {standard_top_comment} */
631            {standard_top_pragma}
632
633            G_BEGIN_DECLS
634
635            /* VOID:PARAM ({list_path}:1) */
636            extern
637            void g_cclosure_user_marshal_VOID__PARAM (GClosure     *closure,
638                                                      GValue       *return_value,
639                                                      guint         n_param_values,
640                                                      const GValue *param_values,
641                                                      gpointer      invocation_hint,
642                                                      gpointer      marshal_data);
643            extern
644            void g_cclosure_user_marshal_VOID__PARAMv (GClosure *closure,
645                                                       GValue   *return_value,
646                                                       gpointer  instance,
647                                                       va_list   args,
648                                                       gpointer  marshal_data,
649                                                       int       n_params,
650                                                       GType    *param_types);
651
652
653            G_END_DECLS
654
655            {standard_bottom_pragma}
656            ''').strip().format(**header_result.subs),
657            header_result.out.strip())
658
659        self.assertEqual(dedent(
660            '''
661            /* {standard_top_comment} */
662            {standard_marshal_peek_defines}
663
664            /* VOID:PARAM ({list_path}:1) */
665            void
666            g_cclosure_user_marshal_VOID__PARAM (GClosure     *closure,
667                                                 GValue       *return_value G_GNUC_UNUSED,
668                                                 guint         n_param_values,
669                                                 const GValue *param_values,
670                                                 gpointer      invocation_hint G_GNUC_UNUSED,
671                                                 gpointer      marshal_data)
672            {{
673              typedef void (*GMarshalFunc_VOID__PARAM) (gpointer data1,
674                                                        gpointer arg1,
675                                                        gpointer data2);
676              GCClosure *cc = (GCClosure *) closure;
677              gpointer data1, data2;
678              GMarshalFunc_VOID__PARAM callback;
679
680              g_return_if_fail (n_param_values == 2);
681
682              if (G_CCLOSURE_SWAP_DATA (closure))
683                {{
684                  data1 = closure->data;
685                  data2 = g_value_peek_pointer (param_values + 0);
686                }}
687              else
688                {{
689                  data1 = g_value_peek_pointer (param_values + 0);
690                  data2 = closure->data;
691                }}
692              callback = (GMarshalFunc_VOID__PARAM) (marshal_data ? marshal_data : cc->callback);
693
694              callback (data1,
695                        g_marshal_value_peek_param (param_values + 1),
696                        data2);
697            }}
698
699            void
700            g_cclosure_user_marshal_VOID__PARAMv (GClosure *closure,
701                                                  GValue   *return_value G_GNUC_UNUSED,
702                                                  gpointer  instance,
703                                                  va_list   args,
704                                                  gpointer  marshal_data,
705                                                  int       n_params,
706                                                  GType    *param_types)
707            {{
708              typedef void (*GMarshalFunc_VOID__PARAM) (gpointer data1,
709                                                        gpointer arg1,
710                                                        gpointer data2);
711              GCClosure *cc = (GCClosure *) closure;
712              gpointer data1, data2;
713              GMarshalFunc_VOID__PARAM callback;
714              gpointer arg0;
715              va_list args_copy;
716
717              G_VA_COPY (args_copy, args);
718              arg0 = (gpointer) va_arg (args_copy, gpointer);
719              if ((param_types[0] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && arg0 != NULL)
720                arg0 = g_param_spec_ref (arg0);
721              va_end (args_copy);
722
723
724              if (G_CCLOSURE_SWAP_DATA (closure))
725                {{
726                  data1 = closure->data;
727                  data2 = instance;
728                }}
729              else
730                {{
731                  data1 = instance;
732                  data2 = closure->data;
733                }}
734              callback = (GMarshalFunc_VOID__PARAM) (marshal_data ? marshal_data : cc->callback);
735
736              callback (data1,
737                        arg0,
738                        data2);
739              if ((param_types[0] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && arg0 != NULL)
740                g_param_spec_unref (arg0);
741            }}
742            ''').strip().format(**body_result.subs),
743            body_result.out.strip())
744
745
746if __name__ == '__main__':
747    unittest.main(testRunner=taptestrunner.TAPTestRunner())
748