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