summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Berg <bberg@redhat.com>2018-04-06 17:01:29 +0200
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2018-05-02 22:29:33 +0000
commit7630bf963e7e29faddc178f9c7ec9b93d6669249 (patch)
tree2e8d66c531da412f73eb9643a81ad754feb6195a
parent8c9be792f25ce4d636e55d0872944936e45517a4 (diff)
downloadgnome-control-center-7630bf963e7e29faddc178f9c7ec9b93d6669249.tar.gz
tests: Add helper for glib based test binaries
This makes running glib based tests inside a dbusmock environment easier and more beautiful (i.e. output is supressed unless an error occurs). This helper has been submitted for inclusion in dbusmock. If it cannot$ live there in some form, then we should try to find a home in the GNOME$ project for it.$
-rw-r--r--tests/shared/gtest.py113
1 files changed, 113 insertions, 0 deletions
diff --git a/tests/shared/gtest.py b/tests/shared/gtest.py
new file mode 100644
index 000000000..bb7130daf
--- /dev/null
+++ b/tests/shared/gtest.py
@@ -0,0 +1,113 @@
+#!/usr/bin/python3
+# Copyright © 2018 Red Hat, Inc
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# Authors: Benjamin Berg <bberg@redhat.com>
+
+import os
+import sys
+import subprocess
+import functools
+
+class _GTestSingleProp(object):
+ """Property which creates a bound method for calling the specified test."""
+ def __init__(self, test):
+ self.test = test
+
+ @staticmethod
+ def __func(self, test):
+ self._gtest_single(test)
+
+ def __get__(self, obj, cls):
+ bound_method = self.__func.__get__(obj, cls)
+ partial_method = functools.partial(bound_method, self.test)
+ partial_method.__doc__ = bound_method.__doc__
+
+ return partial_method
+
+
+class _GTestMeta(type):
+ def __new__(cls, name, bases, namespace, **kwds):
+ result = type.__new__(cls, name, bases, dict(namespace))
+
+ if result.g_test_exe is not None:
+ try:
+ _GTestMeta.make_tests(result.g_test_exe, result)
+ except Exception as e:
+ print('')
+ print(e)
+ print('Error generating separate test funcs, will call binary once.')
+ result.test_all = result._gtest_all
+
+ return result
+
+ @staticmethod
+ def make_tests(exe, result):
+ env = os.environ.copy()
+ env['G_MESSAGES_DEBUG'] = ''
+ test = subprocess.Popen([exe, '-l'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, env=env)
+ stdout, stderr = test.communicate()
+
+ if test.returncode != 0:
+ raise AssertionError('Execution of GTest executable to query the tests returned non-zero exit code!')
+
+ stdout = stdout.decode('utf-8')
+
+ for i, test in enumerate(stdout.split('\n')):
+ if not test:
+ continue
+
+ # Number it and make sure the function name is prefixed with 'test'.
+ # Keep the rest as is, we don't care about the fact that the function
+ # names cannot be typed in.
+ name = 'test_%03d_' % (i + 1) + test
+ setattr(result, name, _GTestSingleProp(test))
+
+
+class GTest(metaclass = _GTestMeta):
+ """Helper class to run GLib test. A test function will be created for each
+ test from the executable.
+
+ Use by using this class as a mixin and setting g_test_exe to an appropriate
+ value.
+ """
+
+ #: The GTest based executable
+ g_test_exe = None
+ #: Timeout when running a single test
+ g_test_single_timeout = None
+ #: Timeout when running all tests in one go
+ g_test_all_timeout = None
+
+ def _gtest_single(self, test):
+ assert(test)
+ p = subprocess.Popen([self.g_test_exe, '-q', '-p', test], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ try:
+ stdout, stderr = p.communicate(timeout=self.g_test_single_timeout)
+ except subprocess.TimeoutExpired:
+ p.kill()
+ stdout, stderr = p.communicate()
+ stdout += b'\n\nTest was aborted due to timeout'
+
+ try:
+ stdout = stdout.decode('utf-8')
+ except UnicodeDecodeError:
+ pass
+
+ if p.returncode != 0:
+ self.fail(stdout)
+
+ def _gtest_all(self):
+ subprocess.check_call([self.g_test_exe], timeout=self.g_test_all_timeout)