diff options
Diffstat (limited to 'sources/pyside6/tests/registry/existence_test.py')
-rw-r--r-- | sources/pyside6/tests/registry/existence_test.py | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/sources/pyside6/tests/registry/existence_test.py b/sources/pyside6/tests/registry/existence_test.py new file mode 100644 index 000000000..f08d70278 --- /dev/null +++ b/sources/pyside6/tests/registry/existence_test.py @@ -0,0 +1,253 @@ +############################################################################# +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of Qt for Python. +## +## $QT_BEGIN_LICENSE:LGPL$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 3 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL3 included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 3 requirements +## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 2.0 or (at your option) the GNU General +## Public license version 3 or any later version approved by the KDE Free +## Qt Foundation. The licenses are as published by the Free Software +## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-2.0.html and +## https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +from __future__ import print_function, absolute_import + +""" +existence_test.py +----------------- + +A test that checks all function signatures if they still exist. + +Definition of the rules used: +============================= + +Any entry +--------- + + Exists in file Exists in Binary Result + + + ok + + - error + - + ok + +List entry +---------- + + Arity in file Arity in Binary Result + n n ok + n < n error + n > n ok + +""" + +import os +import re +import sys +from textwrap import dedent +import unittest + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from init_paths import init_all_test_paths +init_all_test_paths() + +from init_platform import enum_all, generate_all +from util import (isolate_warnings, check_warnings, suppress_warnings, warn, + is_ci, qt_version, get_script_dir, get_effective_refpath, + get_refpath, import_refmodule) +from PySide6 import * + +refPath = get_refpath() +effectiveRefPath = get_effective_refpath() +pyc = os.path.splitext(effectiveRefPath)[0] + ".pyc" +if os.path.exists(pyc) and not os.path.exists(effectiveRefPath): + # on Python2 the pyc file would be imported + os.unlink(pyc) + +if refPath != effectiveRefPath: + print("*** Falling back to ", effectiveRefPath, " since expected ", + refPath, " does not exist") + +script_dir = get_script_dir() +shortpath = os.path.relpath(effectiveRefPath, script_dir) +try: + sig_exists = import_refmodule() + print("found:", shortpath) + have_refmodule = True +except ImportError: + print("*** not found:", shortpath) + have_refmodule = False +except SyntaxError: + print("*** not a python file, removed:", shortpath) + os.unlink(effectiveRefPath) + have_refmodule = False +except NameError as e: + if "recreate" in e.args[0]: + print("*** explicit request to recreate:", shortpath) + else: + print("*** unexpected NameError:", e, "- creating", shortpath) + os.unlink(effectiveRefPath) + have_refmodule = False +dict_name = "sig_dict" +if have_refmodule and not hasattr(sig_exists, dict_name): + print(f"*** wrong module without '{dict_name}', removed: {shortpath}") + os.unlink(effectiveRefPath) + have_refmodule = False + + +@unittest.skipIf(not have_refmodule, + "not activated for this platform or version") +class TestSignaturesExists(unittest.TestCase): + """ + This is the current simple attempt to support a signature self test. + You can activate it for your platform by supplying your own reference + file. Simply run init_platform.py and add the generated file to the + repository. + """ + + @staticmethod + def _do_the_test(found_sigs): + + def multi_signature_msg(key, actual, expect): + len_act = len(actual) if type(actual) is list else 1 + len_exp = len(expect) if type(expect) is list else 1 + return (f"multi-signature count mismatch for '{key}'. " + f"Actual {len_act} {actual} vs. expected {len_exp} {expect}") + + for key, value in sig_exists.sig_dict.items(): + name = key.rsplit(".", 1)[-1] + if name in ("next", "__next__"): # ignore problematic cases + continue + if "<" in key: + # Skip over remaining crap in "<...>" + continue + if key.startswith("sample.SampleNamespace"): + # We cannot work with sample namespaces after the change to __qualname__. + continue + if (key.startswith("smart.SharedPtr") or + re.match(r"PySide6\..*?\.QSharedPointer_", key)): + # These mangled names are not supported. + # We should fix them. + continue + if key not in found_sigs: + warn("missing key: '{} value={}'".format(key, value), stacklevel=3) + else: + found_val = found_sigs[key] + if type(value) is list and ( + type(found_val) is tuple or + len(found_val) < len(value)): + # We check that nothing got lost. But it is ok when an older + # registry file does not know all variants, yet! + warn(multi_signature_msg(key, found_val, value), stacklevel=3) + + def test_signatures(self): + found_sigs = enum_all() + with isolate_warnings(): + self._do_the_test(found_sigs) + if is_ci and check_warnings(): + raise RuntimeError("There are errors, see above.") + + def test_error_is_raised(self): + found_sigs = enum_all() + # Make sure that errors are actually raised. + search = list(found_sigs.keys()) + pos = 42 # arbitrary and historycal, could be 0 as well + + # We try all variants: + while type(found_sigs[search[pos]]) is not tuple: + pos += 1 + tuple_key = search[pos] + while type(found_sigs[search[pos]]) is not list: + pos += 1 + list_key = search[pos] + + test_sigs = found_sigs.copy() + test_sigs.pop(tuple_key) + with isolate_warnings(), suppress_warnings(): + self._do_the_test(test_sigs) + self.assertTrue(check_warnings(), "you warn about too few entries") + + test_sigs = found_sigs.copy() + test_sigs["whatnot"] = ("nothing", "real") + with isolate_warnings(), suppress_warnings(): + self._do_the_test(test_sigs) + self.assertFalse(check_warnings(), "you ignore too many entries") + + test_sigs = found_sigs.copy() + repl = test_sigs[list_key] + repl.pop(0) + test_sigs[list_key] = repl + with isolate_warnings(), suppress_warnings(): + self._do_the_test(test_sigs) + # An arity that is now missing is an error. + self.assertTrue(check_warnings(), "you warn when arity got smaller") + + test_sigs = found_sigs.copy() + repl = test_sigs[list_key] + repl = repl[0] + assert type(repl) is tuple + test_sigs[list_key] = repl + with isolate_warnings(), suppress_warnings(): + self._do_the_test(test_sigs) + # An arity that is now missing is an error. + self.assertTrue(check_warnings(), "you warn when list degraded to tuple") + + test_sigs = found_sigs.copy() + repl = test_sigs[list_key] + repl = repl + repl + test_sigs[list_key] = repl + with isolate_warnings(), suppress_warnings(): + self._do_the_test(test_sigs) + # More arities are ignored, because we might test an older version. + self.assertFalse(check_warnings(), "you ignore when arity got bigger") + + +tested_versions = (5, 6), (5, 9), (5, 11), (5, 12), (5, 14) + +if not have_refmodule and is_ci and qt_version()[:2] in tested_versions: + class TestFor_CI_Init(unittest.TestCase): + """ + This helper class generates the reference file for CI. + It creates an output listing that can be used to check + the result back in. + """ + generate_all() + sys.stderr.flush() + print("BEGIN_FILE", shortpath, file=sys.stderr) + with open(refPath) as f: + print(f.read(), file=sys.stderr) + print("END_FILE", shortpath, file=sys.stderr) + sys.stderr.flush() + raise RuntimeError(dedent(""" + {line} + ** This is the initial call. You should check this file in: + ** {} + **""").format(shortpath, line=79 * "*")) + +if __name__ == '__main__': + unittest.main() |