(root)/
glib-2.79.0/
glib/
tests/
assert-msg-test.py
       1  #!/usr/bin/env python3
       2  # -*- coding: utf-8 -*-
       3  #
       4  # Copyright © 2022 Emmanuel Fleury <emmanuel.fleury@gmail.com>
       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 g_assert() functions. """
      22  
      23  import collections
      24  import os
      25  import shutil
      26  import subprocess
      27  import tempfile
      28  import unittest
      29  
      30  import taptestrunner
      31  
      32  Result = collections.namedtuple("Result", ("info", "out", "err"))
      33  
      34  GDB_SCRIPT = """
      35  # Work around https://sourceware.org/bugzilla/show_bug.cgi?id=22501
      36  set confirm off
      37  set print elements 0
      38  set auto-load safe-path /
      39  run
      40  print *((char**) &__glib_assert_msg)
      41  quit
      42  """
      43  
      44  
      45  class ESC[4;38;5;81mTestAssertMessage(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      46      """Integration test for throwing message on g_assert().
      47  
      48      This can be run when installed or uninstalled. When uninstalled,
      49      it requires G_TEST_BUILDDIR and G_TEST_SRCDIR to be set.
      50  
      51      The idea with this test harness is to test if g_assert() prints
      52      an error message when called, and that it saves this error
      53      message in a global variable accessible to gdb, so that developers
      54      and automated tools can more easily debug assertion failures.
      55      """
      56  
      57      def setUp(self):
      58          self.__gdb = shutil.which("gdb")
      59          self.timeout_seconds = 10  # seconds per test
      60  
      61          ext = ""
      62          if os.name == "nt":
      63              ext = ".exe"
      64          if "G_TEST_BUILDDIR" in os.environ:
      65              self.__assert_msg_test = os.path.join(
      66                  os.environ["G_TEST_BUILDDIR"], "assert-msg-test" + ext
      67              )
      68          else:
      69              self.__assert_msg_test = os.path.join(
      70                  os.path.dirname(__file__), "assert-msg-test" + ext
      71              )
      72          print("assert-msg-test:", self.__assert_msg_test)
      73  
      74      def runAssertMessage(self, *args):
      75          argv = [self.__assert_msg_test]
      76          argv.extend(args)
      77          print("Running:", argv)
      78  
      79          env = os.environ.copy()
      80          env["LC_ALL"] = "C.UTF-8"
      81          print("Environment:", env)
      82  
      83          # We want to ensure consistent line endings...
      84          info = subprocess.run(
      85              argv,
      86              timeout=self.timeout_seconds,
      87              stdout=subprocess.PIPE,
      88              stderr=subprocess.PIPE,
      89              env=env,
      90              universal_newlines=True,
      91          )
      92          out = info.stdout.strip()
      93          err = info.stderr.strip()
      94  
      95          result = Result(info, out, err)
      96  
      97          print("Output:", result.out)
      98          print("Error:", result.err)
      99          return result
     100  
     101      def runGdbAssertMessage(self, *args):
     102          if self.__gdb is None:
     103              return Result(None, "", "")
     104  
     105          argv = ["gdb", "-n", "--batch"]
     106          argv.extend(args)
     107          print("Running:", argv)
     108  
     109          env = os.environ.copy()
     110          env["LC_ALL"] = "C.UTF-8"
     111          print("Environment:", env)
     112  
     113          # We want to ensure consistent line endings...
     114          info = subprocess.run(
     115              argv,
     116              timeout=self.timeout_seconds,
     117              stdout=subprocess.PIPE,
     118              stderr=subprocess.PIPE,
     119              env=env,
     120              universal_newlines=True,
     121          )
     122          out = info.stdout.strip()
     123          err = info.stderr.strip()
     124  
     125          result = Result(info, out, err)
     126  
     127          print("Output:", result.out)
     128          print("Error:", result.err)
     129          print(result.info)
     130          return result
     131  
     132      def test_gassert(self):
     133          """Test running g_assert() and fail the program."""
     134          result = self.runAssertMessage()
     135  
     136          if os.name == "nt":
     137              self.assertEqual(result.info.returncode, 3)
     138          else:
     139              self.assertEqual(result.info.returncode, -6)
     140          self.assertIn("assertion failed: (42 < 0)", result.out)
     141  
     142      def test_gdb_gassert(self):
     143          """Test running g_assert() within gdb and fail the program."""
     144          if self.__gdb is None:
     145              self.skipTest("GDB is not installed, skipping this test!")
     146  
     147          with tempfile.NamedTemporaryFile(
     148              prefix="assert-msg-test-", suffix=".gdb", mode="w", delete=False
     149          ) as tmp:
     150              try:
     151                  tmp.write(GDB_SCRIPT)
     152                  tmp.close()
     153                  result = self.runGdbAssertMessage(
     154                      "-x", tmp.name, self.__assert_msg_test
     155                  )
     156              finally:
     157                  os.unlink(tmp.name)
     158  
     159              # Some CI environments disable ptrace (as they’re running in a
     160              # container). If so, skip the test as there’s nothing we can do.
     161              if result.info.returncode != 0 and (
     162                  "ptrace: Operation not permitted" in result.err
     163                  or "warning: opening /proc/PID/mem file for lwp" in result.err
     164              ):
     165                  self.skipTest("GDB is not functional due to ptrace being disabled")
     166  
     167              self.assertEqual(result.info.returncode, 0)
     168              self.assertIn("$1 = 0x", result.out)
     169              self.assertIn("assertion failed: (42 < 0)", result.out)
     170  
     171  
     172  if __name__ == "__main__":
     173      unittest.main(testRunner=taptestrunner.TAPTestRunner())