summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am155
-rw-r--r--tests/Makefile.in839
-rw-r--r--tests/__init__.py137
-rw-r--r--tests/compat_test_pygtk.py147
-rw-r--r--tests/compathelper.py69
-rw-r--r--tests/conftest.py26
-rw-r--r--tests/gi/__init__.py2
-rw-r--r--tests/gimarshallingtestsextra.c177
-rw-r--r--tests/gimarshallingtestsextra.h69
-rw-r--r--tests/helper.py131
-rw-r--r--tests/meson.build133
-rw-r--r--tests/org.gnome.test.gschema.xml4
-rw-r--r--tests/regressextra.c416
-rw-r--r--tests/regressextra.h82
-rw-r--r--tests/runtests-windows.py52
-rwxr-xr-xtests/runtests.py94
-rw-r--r--tests/te_ST@nouppera50
-rw-r--r--tests/test_atoms.py42
-rw-r--r--tests/test_cairo.py308
-rw-r--r--tests/test_docstring.py129
-rw-r--r--tests/test_error.py157
-rw-r--r--tests/test_everything.py1011
-rw-r--r--tests/test_fields.py185
-rw-r--r--tests/test_gdbus.py45
-rw-r--r--tests/test_generictreemodel.py89
-rw-r--r--tests/test_gi.py1207
-rw-r--r--tests/test_gio.py147
-rw-r--r--tests/test_glib.py157
-rw-r--r--tests/test_gobject.py305
-rw-r--r--tests/test_gtk_template.py721
-rw-r--r--tests/test_gtype.py61
-rw-r--r--tests/test_gtype_instance.py8
-rw-r--r--tests/test_import_machinery.py154
-rw-r--r--tests/test_interface.py4
-rw-r--r--tests/test_internal_api.py65
-rw-r--r--tests/test_iochannel.py159
-rw-r--r--tests/test_mainloop.py71
-rw-r--r--tests/test_object_marshaling.py148
-rw-r--r--tests/test_option.py80
-rw-r--r--tests/test_ossig.py182
-rw-r--r--tests/test_overrides.py58
-rw-r--r--tests/test_overrides_gdk.py228
-rw-r--r--tests/test_overrides_gdkpixbuf.py47
-rw-r--r--tests/test_overrides_gio.py360
-rw-r--r--tests/test_overrides_glib.py255
-rw-r--r--tests/test_overrides_gobject.py423
-rw-r--r--tests/test_overrides_gtk.py1715
-rw-r--r--tests/test_overrides_pango.py32
-rw-r--r--tests/test_properties.py566
-rw-r--r--tests/test_pycapi.py45
-rw-r--r--tests/test_pygtkcompat.py339
-rw-r--r--tests/test_repository.py403
-rw-r--r--tests/test_resulttuple.py89
-rw-r--r--tests/test_signal.py745
-rw-r--r--tests/test_source.py83
-rw-r--r--tests/test_subprocess.py138
-rw-r--r--tests/test_thread.py11
-rw-r--r--tests/test_typeclass.py76
-rw-r--r--tests/test_unknown.py29
-rw-r--r--tests/testhelpermodule.c189
-rw-r--r--tests/testmodule.py22
-rw-r--r--tests/valgrind.supp30
62 files changed, 10773 insertions, 3128 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
deleted file mode 100644
index b845e4b..0000000
--- a/tests/Makefile.am
+++ /dev/null
@@ -1,155 +0,0 @@
-CLEANFILES =
-check_LTLIBRARIES = libgimarshallingtests.la
-test_typelibs = GIMarshallingTests-1.0.typelib
-
-nodist_libgimarshallingtests_la_SOURCES = $(GI_DATADIR)/tests/gimarshallingtests.c $(GI_DATADIR)/tests/gimarshallingtests.h
-libgimarshallingtests_la_CFLAGS = $(GLIB_CFLAGS)
-libgimarshallingtests_la_LDFLAGS = -module -avoid-version $(GLIB_LIBS)
-
-# This is a hack to make sure a shared library is built
-libgimarshallingtests.la: $(libgimarshallingtests_la_OBJECTS) $(libgimarshallingtests_la_DEPENDENCIES)
- $(AM_V_GEN) $(LINK) -rpath $(pkgpyexecdir) $(libgimarshallingtests_la_LDFLAGS) $(libgimarshallingtests_la_OBJECTS) $(libgimarhallingtests_la_LIBADD) $(LIBS)
-
-GIMarshallingTests-1.0.gir: libgimarshallingtests.la Makefile
- $(AM_V_GEN) g-ir-scanner --include=Gio-2.0 \
- --namespace=GIMarshallingTests --nsversion=1.0 --symbol-prefix=gi_marshalling_tests \
- --warn-all --warn-error \
- --library=libgimarshallingtests.la \
- --libtool="$(top_builddir)/libtool" \
- --output $@ \
- $(nodist_libgimarshallingtests_la_SOURCES)
-GIMarshallingTests-1.0.typelib: GIMarshallingTests-1.0.gir Makefile
- $(AM_V_GEN) g-ir-compiler $< -o $@
-
-# regress.c needs cairo
-if ENABLE_CAIRO
-check_LTLIBRARIES += libregress.la
-test_typelibs += Regress-1.0.typelib
-nodist_libregress_la_SOURCES = $(GI_DATADIR)/tests/regress.c $(GI_DATADIR)/tests/regress.h
-libregress_la_CFLAGS = $(GIO_CFLAGS) $(CAIRO_CFLAGS)
-libregress_la_LDFLAGS = -module -avoid-version $(GIO_LIBS) $(CAIRO_LIBS)
-
-libregress.la: $(libregress_la_OBJECTS) $(libregress_la_DEPENDENCIES)
- $(AM_V_GEN) $(LINK) -rpath $(pkgpyexecdir) $(libregress_la_LDFLAGS) $(libregress_la_OBJECTS) $(libregress_la_LIBADD) $(LIBS)
-
-# g-i doesn't ship these as shared libraries anymore; we build them here
-Regress-1.0.gir: libregress.la Makefile
- $(AM_V_GEN) g-ir-scanner --include=cairo-1.0 --include=Gio-2.0 \
- --namespace=Regress --nsversion=1.0 \
- --warn-all --warn-error \
- --library=libregress.la \
- --libtool="$(top_builddir)/libtool" \
- --output $@ \
- $(nodist_libregress_la_SOURCES)
-Regress-1.0.typelib: Regress-1.0.gir Makefile
- $(AM_V_GEN) g-ir-compiler $< -o $@
-
-endif # ENABLE_CAIRO
-
-
-gschemas.compiled: org.gnome.test.gschema.xml
- glib-compile-schemas --targetdir=. --schema-file=$<
-
-CLEANFILES += Regress-1.0.gir Regress-1.0.typelib GIMarshallingTests-1.0.gir GIMarshallingTests-1.0.typelib gschemas.compiled
-
-check_LTLIBRARIES += testhelper.la
-
-testhelper_la_CFLAGS = -I$(top_srcdir)/gi/_gobject -I$(top_srcdir)/gi/_glib $(PYTHON_INCLUDES) $(GLIB_CFLAGS)
-testhelper_la_LDFLAGS = -module -avoid-version
-testhelper_la_LIBADD = $(GLIB_LIBS)
-testhelper_la_SOURCES = \
- testhelpermodule.c \
- test-floating.c \
- test-thread.c \
- test-unknown.c
-
-# This is a hack to make sure a shared library is built
-testhelper.la: $(testhelper_la_OBJECTS) $(testhelper_la_DEPENDENCIES)
- $(AM_V_GEN) $(LINK) -rpath $(pkgpyexecdir) $(testhelper_la_LDFLAGS) $(testhelper_la_OBJECTS) $(testhelper_la_LIBADD) $(LIBS)
-
-
-.la.so:
- test -L $@ || $(LN_S) .libs/$@ $@
-
-
-all: $(check_LTLIBRARIES:.la=.so)
-
-EXTRA_DIST = \
- compathelper.py \
- runtests.py \
- runtests-windows.py \
- testmodule.py \
- test-floating.h \
- test-thread.h \
- test-unknown.h \
- te_ST@nouppera \
- org.gnome.test.gschema.xml \
- test_gio.py \
- test_glib.py \
- test_gobject.py \
- test_gtype.py \
- test_interface.py \
- test_internal_api.py \
- test_iochannel.py \
- test_mainloop.py \
- test_object_marshaling.py \
- test_option.py \
- test_properties.py \
- test_signal.py \
- test_source.py \
- test_subprocess.py \
- test_thread.py \
- test_everything.py \
- test_gi.py \
- test_gdbus.py \
- test_overrides.py \
- test_overrides_glib.py \
- test_overrides_pango.py \
- test_overrides_gdk.py \
- test_overrides_gtk.py \
- test_atoms.py \
- test_generictreemodel.py \
- test_docstring.py \
- compat_test_pygtk.py \
- gi/__init__.py \
- gi/overrides/__init__.py \
- gi/overrides/Regress.py \
- $(NULL)
-
-clean-local:
- rm -f $(check_LTLIBRARIES:.la=.so) file.txt~
-
-DBUS_LAUNCH=$(shell which dbus-launch)
-RUN_TESTS_ENV_VARS= \
- PYTHONPATH=$(top_builddir):$(top_builddir)/tests:$${PYTHONPATH:+:$$PYTHONPATH} \
- LD_LIBRARY_PATH=$(builddir)/.libs:$$LD_LIBRARY_PATH \
- GI_TYPELIB_PATH=$(builddir):$$GI_TYPELIB_PATH \
- XDG_DATA_DIRS=$$XDG_DATA_DIRS:/usr/share \
- MALLOC_PERTURB_=85 \
- MALLOC_CHECK_=3 \
- G_SLICE=debug-blocks \
- TESTS_BUILDDIR=$(builddir)
-
-# pygtkcompat tests need to be run in a separate process as they
-# clobber global name space
-check-local: $(check_LTLIBRARIES:.la=.so) $(test_typelibs) gschemas.compiled
- @echo " CHECK Pyflakes"
- @if type pyflakes >/dev/null 2>&1; then pyflakes $(top_srcdir); else echo "skipped, pyflakes not installed"; fi
- @if test -z "$$SKIP_PEP8"; then \
- echo " CHECK PEP8"; \
- if type pep8 >/dev/null 2>&1; then pep8 --ignore=E501,E123,E124 --repeat --show-source $(top_srcdir); else echo "skipped, pep8 not installed"; fi; \
- fi
- export `$(DBUS_LAUNCH)` && \
- $(RUN_TESTS_ENV_VARS) $(EXEC_NAME) $(PYTHON) -Wd $(srcdir)/runtests.py; rc=$$?; \
- [ "$$rc" -ne 0 ] || [ -n "$$TEST_NAMES" ] || { TEST_NAMES=compat_test_pygtk $(RUN_TESTS_ENV_VARS) $(EXEC_NAME) $(PYTHON) -Wd -Werror::PendingDeprecationWarning -Werror::DeprecationWarning -Werror::RuntimeWarning $(srcdir)/runtests.py; rc=$$?; }; \
- kill $$DBUS_SESSION_BUS_PID; \
- exit $$rc
-
-check.gdb:
- EXEC_NAME="gdb --args" $(MAKE) check
-
-check.nemiver:
- EXEC_NAME="nemiver" $(MAKE) check
-
-check.valgrind:
- EXEC_NAME="valgrind --leak-check=full --show-possibly-lost=no --suppressions=python.supp" G_DEBUG=gc-friendly $(MAKE) check
diff --git a/tests/Makefile.in b/tests/Makefile.in
deleted file mode 100644
index d9b217c..0000000
--- a/tests/Makefile.in
+++ /dev/null
@@ -1,839 +0,0 @@
-# Makefile.in generated by automake 1.13.3 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-
-# regress.c needs cairo
-@ENABLE_CAIRO_TRUE@am__append_1 = libregress.la
-@ENABLE_CAIRO_TRUE@am__append_2 = Regress-1.0.typelib
-subdir = tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
- $(top_srcdir)/depcomp
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \
- $(top_srcdir)/m4/jhflags.m4 $(top_srcdir)/m4/libtool.m4 \
- $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
- $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
- $(top_srcdir)/m4/python.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
- $(ACLOCAL_M4)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-libgimarshallingtests_la_LIBADD =
-nodist_libgimarshallingtests_la_OBJECTS = \
- libgimarshallingtests_la-gimarshallingtests.lo
-libgimarshallingtests_la_OBJECTS = \
- $(nodist_libgimarshallingtests_la_OBJECTS)
-AM_V_lt = $(am__v_lt_@AM_V@)
-am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
-am__v_lt_0 = --silent
-am__v_lt_1 =
-libgimarshallingtests_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
- $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
- $(libgimarshallingtests_la_CFLAGS) $(CFLAGS) \
- $(libgimarshallingtests_la_LDFLAGS) $(LDFLAGS) -o $@
-libregress_la_LIBADD =
-@ENABLE_CAIRO_TRUE@nodist_libregress_la_OBJECTS = \
-@ENABLE_CAIRO_TRUE@ libregress_la-regress.lo
-libregress_la_OBJECTS = $(nodist_libregress_la_OBJECTS)
-libregress_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libregress_la_CFLAGS) \
- $(CFLAGS) $(libregress_la_LDFLAGS) $(LDFLAGS) -o $@
-@ENABLE_CAIRO_TRUE@am_libregress_la_rpath =
-am__DEPENDENCIES_1 =
-testhelper_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
-am_testhelper_la_OBJECTS = testhelper_la-testhelpermodule.lo \
- testhelper_la-test-floating.lo testhelper_la-test-thread.lo \
- testhelper_la-test-unknown.lo
-testhelper_la_OBJECTS = $(am_testhelper_la_OBJECTS)
-testhelper_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=link $(CCLD) $(testhelper_la_CFLAGS) \
- $(CFLAGS) $(testhelper_la_LDFLAGS) $(LDFLAGS) -o $@
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo " GEN " $@;
-am__v_GEN_1 =
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 =
-DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
-depcomp = $(SHELL) $(top_srcdir)/depcomp
-am__depfiles_maybe = depfiles
-am__mv = mv -f
-COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
- $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
- $(AM_CFLAGS) $(CFLAGS)
-AM_V_CC = $(am__v_CC_@AM_V@)
-am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
-am__v_CC_0 = @echo " CC " $@;
-am__v_CC_1 =
-CCLD = $(CC)
-LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(AM_LDFLAGS) $(LDFLAGS) -o $@
-AM_V_CCLD = $(am__v_CCLD_@AM_V@)
-am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
-am__v_CCLD_0 = @echo " CCLD " $@;
-am__v_CCLD_1 =
-SOURCES = $(nodist_libgimarshallingtests_la_SOURCES) \
- $(nodist_libregress_la_SOURCES) $(testhelper_la_SOURCES)
-DIST_SOURCES = $(testhelper_la_SOURCES)
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates. Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
- BEGIN { nonempty = 0; } \
- { items[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique. This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
- list='$(am__tagged_files)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AS = @AS@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CAIRO_CFLAGS = @CAIRO_CFLAGS@
-CAIRO_LIBS = @CAIRO_LIBS@
-CC = @CC@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
-CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
-CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DATADIR = @DATADIR@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FFI_CFLAGS = @FFI_CFLAGS@
-FFI_LIBS = @FFI_LIBS@
-FGREP = @FGREP@
-GENHTML = @GENHTML@
-GIO_CFLAGS = @GIO_CFLAGS@
-GIO_LIBS = @GIO_LIBS@
-GI_CFLAGS = @GI_CFLAGS@
-GI_DATADIR = @GI_DATADIR@
-GI_LIBS = @GI_LIBS@
-GLIB_CFLAGS = @GLIB_CFLAGS@
-GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
-GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
-GLIB_LIBS = @GLIB_LIBS@
-GLIB_MKENUMS = @GLIB_MKENUMS@
-GOBJECT_QUERY = @GOBJECT_QUERY@
-GREP = @GREP@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
-INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
-LCOV = @LCOV@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBFFI_PC = @LIBFFI_PC@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-PKG_CONFIG = @PKG_CONFIG@
-PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
-PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
-PLATFORM = @PLATFORM@
-PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@
-PYCAIRO_LIBS = @PYCAIRO_LIBS@
-PYGOBJECT_MAJOR_VERSION = @PYGOBJECT_MAJOR_VERSION@
-PYGOBJECT_MICRO_VERSION = @PYGOBJECT_MICRO_VERSION@
-PYGOBJECT_MINOR_VERSION = @PYGOBJECT_MINOR_VERSION@
-PYTHON = @PYTHON@
-PYTHON_BASENAME = @PYTHON_BASENAME@
-PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
-PYTHON_INCLUDES = @PYTHON_INCLUDES@
-PYTHON_LIBS = @PYTHON_LIBS@
-PYTHON_LIB_LOC = @PYTHON_LIB_LOC@
-PYTHON_PLATFORM = @PYTHON_PLATFORM@
-PYTHON_PREFIX = @PYTHON_PREFIX@
-PYTHON_SO = @PYTHON_SO@
-PYTHON_VERSION = @PYTHON_VERSION@
-RANLIB = @RANLIB@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-STRIP = @STRIP@
-THREADING_CFLAGS = @THREADING_CFLAGS@
-VERSION = @VERSION@
-WARN_CFLAGS = @WARN_CFLAGS@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-pkgpyexecdir = @pkgpyexecdir@
-pkgpythondir = @pkgpythondir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-pyexecdir = @pyexecdir@
-pythondir = @pythondir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-target_alias = @target_alias@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-CLEANFILES = Regress-1.0.gir Regress-1.0.typelib \
- GIMarshallingTests-1.0.gir GIMarshallingTests-1.0.typelib \
- gschemas.compiled
-check_LTLIBRARIES = libgimarshallingtests.la $(am__append_1) \
- testhelper.la
-test_typelibs = GIMarshallingTests-1.0.typelib $(am__append_2)
-nodist_libgimarshallingtests_la_SOURCES = $(GI_DATADIR)/tests/gimarshallingtests.c $(GI_DATADIR)/tests/gimarshallingtests.h
-libgimarshallingtests_la_CFLAGS = $(GLIB_CFLAGS)
-libgimarshallingtests_la_LDFLAGS = -module -avoid-version $(GLIB_LIBS)
-@ENABLE_CAIRO_TRUE@nodist_libregress_la_SOURCES = $(GI_DATADIR)/tests/regress.c $(GI_DATADIR)/tests/regress.h
-@ENABLE_CAIRO_TRUE@libregress_la_CFLAGS = $(GIO_CFLAGS) $(CAIRO_CFLAGS)
-@ENABLE_CAIRO_TRUE@libregress_la_LDFLAGS = -module -avoid-version $(GIO_LIBS) $(CAIRO_LIBS)
-testhelper_la_CFLAGS = -I$(top_srcdir)/gi/_gobject -I$(top_srcdir)/gi/_glib $(PYTHON_INCLUDES) $(GLIB_CFLAGS)
-testhelper_la_LDFLAGS = -module -avoid-version
-testhelper_la_LIBADD = $(GLIB_LIBS)
-testhelper_la_SOURCES = \
- testhelpermodule.c \
- test-floating.c \
- test-thread.c \
- test-unknown.c
-
-EXTRA_DIST = \
- compathelper.py \
- runtests.py \
- runtests-windows.py \
- testmodule.py \
- test-floating.h \
- test-thread.h \
- test-unknown.h \
- te_ST@nouppera \
- org.gnome.test.gschema.xml \
- test_gio.py \
- test_glib.py \
- test_gobject.py \
- test_gtype.py \
- test_interface.py \
- test_internal_api.py \
- test_iochannel.py \
- test_mainloop.py \
- test_object_marshaling.py \
- test_option.py \
- test_properties.py \
- test_signal.py \
- test_source.py \
- test_subprocess.py \
- test_thread.py \
- test_everything.py \
- test_gi.py \
- test_gdbus.py \
- test_overrides.py \
- test_overrides_glib.py \
- test_overrides_pango.py \
- test_overrides_gdk.py \
- test_overrides_gtk.py \
- test_atoms.py \
- test_generictreemodel.py \
- test_docstring.py \
- compat_test_pygtk.py \
- gi/__init__.py \
- gi/overrides/__init__.py \
- gi/overrides/Regress.py \
- $(NULL)
-
-DBUS_LAUNCH = $(shell which dbus-launch)
-RUN_TESTS_ENV_VARS = \
- PYTHONPATH=$(top_builddir):$(top_builddir)/tests:$${PYTHONPATH:+:$$PYTHONPATH} \
- LD_LIBRARY_PATH=$(builddir)/.libs:$$LD_LIBRARY_PATH \
- GI_TYPELIB_PATH=$(builddir):$$GI_TYPELIB_PATH \
- XDG_DATA_DIRS=$$XDG_DATA_DIRS:/usr/share \
- MALLOC_PERTURB_=85 \
- MALLOC_CHECK_=3 \
- G_SLICE=debug-blocks \
- TESTS_BUILDDIR=$(builddir)
-
-all: all-am
-
-.SUFFIXES:
-.SUFFIXES: .c .la .lo .o .obj .so
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
- @for dep in $?; do \
- case '$(am__configure_deps)' in \
- *$$dep*) \
- ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
- && { if test -f $@; then exit 0; else break; fi; }; \
- exit 1;; \
- esac; \
- done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \
- $(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --foreign tests/Makefile
-.PRECIOUS: Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
- @case '$?' in \
- *config.status*) \
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
- *) \
- echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
- cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
- esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: $(am__configure_deps)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): $(am__aclocal_m4_deps)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-clean-checkLTLIBRARIES:
- -test -z "$(check_LTLIBRARIES)" || rm -f $(check_LTLIBRARIES)
- @list='$(check_LTLIBRARIES)'; \
- locs=`for p in $$list; do echo $$p; done | \
- sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
- sort -u`; \
- test -z "$$locs" || { \
- echo rm -f $${locs}; \
- rm -f $${locs}; \
- }
-
-@ENABLE_CAIRO_FALSE@libregress.la: $(libregress_la_OBJECTS) $(libregress_la_DEPENDENCIES) $(EXTRA_libregress_la_DEPENDENCIES)
-@ENABLE_CAIRO_FALSE@ $(AM_V_CCLD)$(libregress_la_LINK) $(am_libregress_la_rpath) $(libregress_la_OBJECTS) $(libregress_la_LIBADD) $(LIBS)
-
-mostlyclean-compile:
- -rm -f *.$(OBJEXT)
-
-distclean-compile:
- -rm -f *.tab.c
-
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgimarshallingtests_la-gimarshallingtests.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libregress_la-regress.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testhelper_la-test-floating.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testhelper_la-test-thread.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testhelper_la-test-unknown.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testhelper_la-testhelpermodule.Plo@am__quote@
-
-.c.o:
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
-
-.c.obj:
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
-
-.c.lo:
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
-
-libgimarshallingtests_la-gimarshallingtests.lo: $(GI_DATADIR)/tests/gimarshallingtests.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgimarshallingtests_la_CFLAGS) $(CFLAGS) -MT libgimarshallingtests_la-gimarshallingtests.lo -MD -MP -MF $(DEPDIR)/libgimarshallingtests_la-gimarshallingtests.Tpo -c -o libgimarshallingtests_la-gimarshallingtests.lo `test -f '$(GI_DATADIR)/tests/gimarshallingtests.c' || echo '$(srcdir)/'`$(GI_DATADIR)/tests/gimarshallingtests.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgimarshallingtests_la-gimarshallingtests.Tpo $(DEPDIR)/libgimarshallingtests_la-gimarshallingtests.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(GI_DATADIR)/tests/gimarshallingtests.c' object='libgimarshallingtests_la-gimarshallingtests.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgimarshallingtests_la_CFLAGS) $(CFLAGS) -c -o libgimarshallingtests_la-gimarshallingtests.lo `test -f '$(GI_DATADIR)/tests/gimarshallingtests.c' || echo '$(srcdir)/'`$(GI_DATADIR)/tests/gimarshallingtests.c
-
-libregress_la-regress.lo: $(GI_DATADIR)/tests/regress.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libregress_la_CFLAGS) $(CFLAGS) -MT libregress_la-regress.lo -MD -MP -MF $(DEPDIR)/libregress_la-regress.Tpo -c -o libregress_la-regress.lo `test -f '$(GI_DATADIR)/tests/regress.c' || echo '$(srcdir)/'`$(GI_DATADIR)/tests/regress.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libregress_la-regress.Tpo $(DEPDIR)/libregress_la-regress.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(GI_DATADIR)/tests/regress.c' object='libregress_la-regress.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libregress_la_CFLAGS) $(CFLAGS) -c -o libregress_la-regress.lo `test -f '$(GI_DATADIR)/tests/regress.c' || echo '$(srcdir)/'`$(GI_DATADIR)/tests/regress.c
-
-testhelper_la-testhelpermodule.lo: testhelpermodule.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testhelper_la_CFLAGS) $(CFLAGS) -MT testhelper_la-testhelpermodule.lo -MD -MP -MF $(DEPDIR)/testhelper_la-testhelpermodule.Tpo -c -o testhelper_la-testhelpermodule.lo `test -f 'testhelpermodule.c' || echo '$(srcdir)/'`testhelpermodule.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/testhelper_la-testhelpermodule.Tpo $(DEPDIR)/testhelper_la-testhelpermodule.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='testhelpermodule.c' object='testhelper_la-testhelpermodule.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testhelper_la_CFLAGS) $(CFLAGS) -c -o testhelper_la-testhelpermodule.lo `test -f 'testhelpermodule.c' || echo '$(srcdir)/'`testhelpermodule.c
-
-testhelper_la-test-floating.lo: test-floating.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testhelper_la_CFLAGS) $(CFLAGS) -MT testhelper_la-test-floating.lo -MD -MP -MF $(DEPDIR)/testhelper_la-test-floating.Tpo -c -o testhelper_la-test-floating.lo `test -f 'test-floating.c' || echo '$(srcdir)/'`test-floating.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/testhelper_la-test-floating.Tpo $(DEPDIR)/testhelper_la-test-floating.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-floating.c' object='testhelper_la-test-floating.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testhelper_la_CFLAGS) $(CFLAGS) -c -o testhelper_la-test-floating.lo `test -f 'test-floating.c' || echo '$(srcdir)/'`test-floating.c
-
-testhelper_la-test-thread.lo: test-thread.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testhelper_la_CFLAGS) $(CFLAGS) -MT testhelper_la-test-thread.lo -MD -MP -MF $(DEPDIR)/testhelper_la-test-thread.Tpo -c -o testhelper_la-test-thread.lo `test -f 'test-thread.c' || echo '$(srcdir)/'`test-thread.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/testhelper_la-test-thread.Tpo $(DEPDIR)/testhelper_la-test-thread.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-thread.c' object='testhelper_la-test-thread.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testhelper_la_CFLAGS) $(CFLAGS) -c -o testhelper_la-test-thread.lo `test -f 'test-thread.c' || echo '$(srcdir)/'`test-thread.c
-
-testhelper_la-test-unknown.lo: test-unknown.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testhelper_la_CFLAGS) $(CFLAGS) -MT testhelper_la-test-unknown.lo -MD -MP -MF $(DEPDIR)/testhelper_la-test-unknown.Tpo -c -o testhelper_la-test-unknown.lo `test -f 'test-unknown.c' || echo '$(srcdir)/'`test-unknown.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/testhelper_la-test-unknown.Tpo $(DEPDIR)/testhelper_la-test-unknown.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-unknown.c' object='testhelper_la-test-unknown.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testhelper_la_CFLAGS) $(CFLAGS) -c -o testhelper_la-test-unknown.lo `test -f 'test-unknown.c' || echo '$(srcdir)/'`test-unknown.c
-
-mostlyclean-libtool:
- -rm -f *.lo
-
-clean-libtool:
- -rm -rf .libs _libs
-
-ID: $(am__tagged_files)
- $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-am
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
- set x; \
- here=`pwd`; \
- $(am__define_uniq_tagged_files); \
- shift; \
- if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
- test -n "$$unique" || unique=$$empty_fix; \
- if test $$# -gt 0; then \
- $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
- "$$@" $$unique; \
- else \
- $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
- $$unique; \
- fi; \
- fi
-ctags: ctags-am
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
- $(am__define_uniq_tagged_files); \
- test -z "$(CTAGS_ARGS)$$unique" \
- || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
- $$unique
-
-GTAGS:
- here=`$(am__cd) $(top_builddir) && pwd` \
- && $(am__cd) $(top_srcdir) \
- && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-am
-
-cscopelist-am: $(am__tagged_files)
- list='$(am__tagged_files)'; \
- case "$(srcdir)" in \
- [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
- *) sdir=$(subdir)/$(srcdir) ;; \
- esac; \
- for i in $$list; do \
- if test -f "$$i"; then \
- echo "$(subdir)/$$i"; \
- else \
- echo "$$sdir/$$i"; \
- fi; \
- done >> $(top_builddir)/cscope.files
-
-distclean-tags:
- -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
- @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
- topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
- list='$(DISTFILES)'; \
- dist_files=`for file in $$list; do echo $$file; done | \
- sed -e "s|^$$srcdirstrip/||;t" \
- -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
- case $$dist_files in \
- */*) $(MKDIR_P) `echo "$$dist_files" | \
- sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
- sort -u` ;; \
- esac; \
- for file in $$dist_files; do \
- if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
- if test -d $$d/$$file; then \
- dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
- if test -d "$(distdir)/$$file"; then \
- find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
- fi; \
- if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
- cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
- find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
- fi; \
- cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
- else \
- test -f "$(distdir)/$$file" \
- || cp -p $$d/$$file "$(distdir)/$$file" \
- || exit 1; \
- fi; \
- done
-check-am: all-am
- $(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES)
- $(MAKE) $(AM_MAKEFLAGS) check-local
-check: check-am
-all-am: Makefile
-installdirs:
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
- @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
- if test -z '$(STRIP)'; then \
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
- install; \
- else \
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
- "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
- fi
-mostlyclean-generic:
-
-clean-generic:
- -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
-
-distclean-generic:
- -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
- -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
- @echo "This command is intended for maintainers to use"
- @echo "it deletes files that may require special tools to rebuild."
-clean: clean-am
-
-clean-am: clean-checkLTLIBRARIES clean-generic clean-libtool \
- clean-local mostlyclean-am
-
-distclean: distclean-am
- -rm -rf ./$(DEPDIR)
- -rm -f Makefile
-distclean-am: clean-am distclean-compile distclean-generic \
- distclean-tags
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am:
-
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
- -rm -rf ./$(DEPDIR)
- -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-compile mostlyclean-generic \
- mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am:
-
-.MAKE: check-am install-am install-strip
-
-.PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \
- clean-checkLTLIBRARIES clean-generic clean-libtool clean-local \
- cscopelist-am ctags ctags-am distclean distclean-compile \
- distclean-generic distclean-libtool distclean-tags distdir dvi \
- dvi-am html html-am info info-am install install-am \
- install-data install-data-am install-dvi install-dvi-am \
- install-exec install-exec-am install-html install-html-am \
- install-info install-info-am install-man install-pdf \
- install-pdf-am install-ps install-ps-am install-strip \
- installcheck installcheck-am installdirs maintainer-clean \
- maintainer-clean-generic mostlyclean mostlyclean-compile \
- mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
- tags tags-am uninstall uninstall-am
-
-
-# This is a hack to make sure a shared library is built
-libgimarshallingtests.la: $(libgimarshallingtests_la_OBJECTS) $(libgimarshallingtests_la_DEPENDENCIES)
- $(AM_V_GEN) $(LINK) -rpath $(pkgpyexecdir) $(libgimarshallingtests_la_LDFLAGS) $(libgimarshallingtests_la_OBJECTS) $(libgimarhallingtests_la_LIBADD) $(LIBS)
-
-GIMarshallingTests-1.0.gir: libgimarshallingtests.la Makefile
- $(AM_V_GEN) g-ir-scanner --include=Gio-2.0 \
- --namespace=GIMarshallingTests --nsversion=1.0 --symbol-prefix=gi_marshalling_tests \
- --warn-all --warn-error \
- --library=libgimarshallingtests.la \
- --libtool="$(top_builddir)/libtool" \
- --output $@ \
- $(nodist_libgimarshallingtests_la_SOURCES)
-GIMarshallingTests-1.0.typelib: GIMarshallingTests-1.0.gir Makefile
- $(AM_V_GEN) g-ir-compiler $< -o $@
-
-@ENABLE_CAIRO_TRUE@libregress.la: $(libregress_la_OBJECTS) $(libregress_la_DEPENDENCIES)
-@ENABLE_CAIRO_TRUE@ $(AM_V_GEN) $(LINK) -rpath $(pkgpyexecdir) $(libregress_la_LDFLAGS) $(libregress_la_OBJECTS) $(libregress_la_LIBADD) $(LIBS)
-
-# g-i doesn't ship these as shared libraries anymore; we build them here
-@ENABLE_CAIRO_TRUE@Regress-1.0.gir: libregress.la Makefile
-@ENABLE_CAIRO_TRUE@ $(AM_V_GEN) g-ir-scanner --include=cairo-1.0 --include=Gio-2.0 \
-@ENABLE_CAIRO_TRUE@ --namespace=Regress --nsversion=1.0 \
-@ENABLE_CAIRO_TRUE@ --warn-all --warn-error \
-@ENABLE_CAIRO_TRUE@ --library=libregress.la \
-@ENABLE_CAIRO_TRUE@ --libtool="$(top_builddir)/libtool" \
-@ENABLE_CAIRO_TRUE@ --output $@ \
-@ENABLE_CAIRO_TRUE@ $(nodist_libregress_la_SOURCES)
-@ENABLE_CAIRO_TRUE@Regress-1.0.typelib: Regress-1.0.gir Makefile
-@ENABLE_CAIRO_TRUE@ $(AM_V_GEN) g-ir-compiler $< -o $@
-
-gschemas.compiled: org.gnome.test.gschema.xml
- glib-compile-schemas --targetdir=. --schema-file=$<
-
-# This is a hack to make sure a shared library is built
-testhelper.la: $(testhelper_la_OBJECTS) $(testhelper_la_DEPENDENCIES)
- $(AM_V_GEN) $(LINK) -rpath $(pkgpyexecdir) $(testhelper_la_LDFLAGS) $(testhelper_la_OBJECTS) $(testhelper_la_LIBADD) $(LIBS)
-
-.la.so:
- test -L $@ || $(LN_S) .libs/$@ $@
-
-all: $(check_LTLIBRARIES:.la=.so)
-
-clean-local:
- rm -f $(check_LTLIBRARIES:.la=.so) file.txt~
-
-# pygtkcompat tests need to be run in a separate process as they
-# clobber global name space
-check-local: $(check_LTLIBRARIES:.la=.so) $(test_typelibs) gschemas.compiled
- @echo " CHECK Pyflakes"
- @if type pyflakes >/dev/null 2>&1; then pyflakes $(top_srcdir); else echo "skipped, pyflakes not installed"; fi
- @if test -z "$$SKIP_PEP8"; then \
- echo " CHECK PEP8"; \
- if type pep8 >/dev/null 2>&1; then pep8 --ignore=E501,E123,E124 --repeat --show-source $(top_srcdir); else echo "skipped, pep8 not installed"; fi; \
- fi
- export `$(DBUS_LAUNCH)` && \
- $(RUN_TESTS_ENV_VARS) $(EXEC_NAME) $(PYTHON) -Wd $(srcdir)/runtests.py; rc=$$?; \
- [ "$$rc" -ne 0 ] || [ -n "$$TEST_NAMES" ] || { TEST_NAMES=compat_test_pygtk $(RUN_TESTS_ENV_VARS) $(EXEC_NAME) $(PYTHON) -Wd -Werror::PendingDeprecationWarning -Werror::DeprecationWarning -Werror::RuntimeWarning $(srcdir)/runtests.py; rc=$$?; }; \
- kill $$DBUS_SESSION_BUS_PID; \
- exit $$rc
-
-check.gdb:
- EXEC_NAME="gdb --args" $(MAKE) check
-
-check.nemiver:
- EXEC_NAME="nemiver" $(MAKE) check
-
-check.valgrind:
- EXEC_NAME="valgrind --leak-check=full --show-possibly-lost=no --suppressions=python.supp" G_DEBUG=gc-friendly $(MAKE) check
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..a7b7ff2
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,137 @@
+import os
+import sys
+import signal
+import subprocess
+import atexit
+import warnings
+
+
+def set_dll_search_path():
+ # Python 3.8 no longer searches for DLLs in PATH, so we have to add
+ # everything in PATH manually. Note that unlike PATH add_dll_directory
+ # has no defined order, so if there are two cairo DLLs in PATH we
+ # might get a random one.
+ if os.name != "nt" or not hasattr(os, "add_dll_directory"):
+ return
+ for p in os.environ.get("PATH", "").split(os.pathsep):
+ try:
+ os.add_dll_directory(p)
+ except OSError:
+ pass
+
+
+def init_test_environ():
+
+ set_dll_search_path()
+
+ def dbus_launch_session():
+ if os.name == "nt" or sys.platform == "darwin":
+ return (-1, "")
+
+ try:
+ out = subprocess.check_output([
+ "dbus-daemon", "--session", "--fork", "--print-address=1",
+ "--print-pid=1"])
+ except (subprocess.CalledProcessError, OSError):
+ return (-1, "")
+ else:
+ out = out.decode("utf-8")
+ addr, pid = out.splitlines()
+ return int(pid), addr
+
+ pid, addr = dbus_launch_session()
+ if pid >= 0:
+ os.environ["DBUS_SESSION_BUS_ADDRESS"] = addr
+ atexit.register(os.kill, pid, signal.SIGKILL)
+ else:
+ os.environ["DBUS_SESSION_BUS_ADDRESS"] = "."
+
+ tests_builddir = os.path.abspath(os.environ.get('TESTS_BUILDDIR', os.path.dirname(__file__)))
+ builddir = os.path.dirname(tests_builddir)
+ tests_srcdir = os.path.abspath(os.path.dirname(__file__))
+ srcdir = os.path.dirname(tests_srcdir)
+
+ sys.path.insert(0, os.path.join(builddir, 'gi'))
+ sys.path.insert(0, tests_srcdir)
+ sys.path.insert(0, srcdir)
+ sys.path.insert(0, tests_builddir)
+ sys.path.insert(0, builddir)
+
+ # force untranslated messages, as we check for them in some tests
+ os.environ['LC_MESSAGES'] = 'C'
+ os.environ['G_DEBUG'] = 'fatal-warnings fatal-criticals'
+ if sys.platform == "darwin" or os.name == "nt":
+ # gtk 3.22 has warnings and ciriticals on OS X, ignore for now.
+ # On Windows glib will create an error dialog which will block tests
+ # so it's never a good idea there to make things fatal.
+ os.environ['G_DEBUG'] = ''
+
+ # make Gio able to find our gschemas.compiled in tests/. This needs to be set
+ # before importing Gio. Support a separate build tree, so look in build dir
+ # first.
+ os.environ['GSETTINGS_BACKEND'] = 'memory'
+ os.environ['GSETTINGS_SCHEMA_DIR'] = tests_builddir
+ os.environ['G_FILENAME_ENCODING'] = 'UTF-8'
+
+ # Avoid accessibility dbus warnings
+ os.environ['NO_AT_BRIDGE'] = '1'
+
+ # A workaround for https://gitlab.gnome.org/GNOME/glib/-/issues/2251
+ # The gtk4 a11y stack calls get_dbus_object_path() on the default app
+ os.environ['GTK_A11Y'] = 'none'
+
+ # Force the default theme so broken themes don't affect the tests
+ os.environ['GTK_THEME'] = 'Adwaita'
+
+ import gi
+ gi.require_version("GIRepository", "2.0")
+ from gi.repository import GIRepository
+ repo = GIRepository.Repository.get_default()
+ repo.prepend_library_path(os.path.join(tests_builddir))
+ repo.prepend_search_path(tests_builddir)
+
+ def try_require_version(namespace, version):
+ try:
+ gi.require_version(namespace, version)
+ except ValueError:
+ # prevent tests from running with the wrong version
+ sys.modules["gi.repository." + namespace] = None
+
+ # Optional
+ try_require_version("Gtk", os.environ.get("TEST_GTK_VERSION", "3.0"))
+ try_require_version("Gdk", os.environ.get("TEST_GTK_VERSION", "3.0"))
+ try_require_version("GdkPixbuf", "2.0")
+ try_require_version("Pango", "1.0")
+ try_require_version("PangoCairo", "1.0")
+ try_require_version("Atk", "1.0")
+
+ # Required
+ gi.require_versions({
+ "GIMarshallingTests": "1.0",
+ "Regress": "1.0",
+ "GLib": "2.0",
+ "Gio": "2.0",
+ "GObject": "2.0",
+ })
+
+ # It's disabled for stable releases by default, this makes sure it's
+ # always on for the tests.
+ warnings.simplefilter('default', gi.PyGIDeprecationWarning)
+
+ # Otherwise we crash on the first gtk use when e.g. DISPLAY isn't set
+ try:
+ from gi.repository import Gtk
+ except ImportError:
+ pass
+ else:
+ if Gtk._version == "4.0":
+ res = Gtk.init_check()
+ else:
+ res = Gtk.init_check([])[0]
+ if not res:
+ raise RuntimeError("Gtk available, but Gtk.init_check() failed")
+
+
+init_test_environ()
+
+__path__ = __import__('pkgutil').extend_path(__path__, __name__)
diff --git a/tests/compat_test_pygtk.py b/tests/compat_test_pygtk.py
deleted file mode 100644
index 10be6a3..0000000
--- a/tests/compat_test_pygtk.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# -*- Mode: Python; py-indent-offset: 4 -*-
-# vim: tabstop=4 shiftwidth=4 expandtab
-
-import unittest
-
-from gi.repository import GLib
-
-try:
- from gi.repository import Pango
- from gi.repository import Atk
- from gi.repository import Gdk
- from gi.repository import Gtk
- (Atk, Gtk, Pango) # pyflakes
-
- import pygtkcompat
-
- pygtkcompat.enable()
- pygtkcompat.enable_gtk(version='3.0')
-
- import atk
- import pango
- import pangocairo
- import gtk
- import gtk.gdk
-except ImportError:
- Gtk = None
-
-
-@unittest.skipUnless(Gtk, 'Gtk not available')
-class TestATKCompat(unittest.TestCase):
- def test_object(self):
- self.assertTrue(hasattr(atk, 'Object'))
-
-
-@unittest.skipUnless(Gtk, 'Gtk not available')
-class TestPangoCompat(unittest.TestCase):
- def test_layout(self):
- self.assertTrue(hasattr(pango, 'Layout'))
-
-
-@unittest.skipUnless(Gtk, 'Gtk not available')
-class TestPangoCairoCompat(unittest.TestCase):
- def test_error_underline_path(self):
- self.assertTrue(hasattr(pangocairo, 'error_underline_path'))
-
-
-@unittest.skipUnless(Gtk, 'Gtk not available')
-class TestGTKCompat(unittest.TestCase):
- def test_buttons(self):
- self.assertEqual(Gdk._2BUTTON_PRESS, 5)
- self.assertEqual(Gdk.BUTTON_PRESS, 4)
-
- def test_enums(self):
- self.assertEqual(gtk.WINDOW_TOPLEVEL, Gtk.WindowType.TOPLEVEL)
- self.assertEqual(gtk.PACK_START, Gtk.PackType.START)
-
- def test_flags(self):
- self.assertEqual(gtk.EXPAND, Gtk.AttachOptions.EXPAND)
- self.assertEqual(gtk.gdk.SHIFT_MASK, Gdk.ModifierType.SHIFT_MASK)
-
- def test_keysyms(self):
- import gtk.keysyms
- self.assertEqual(gtk.keysyms.Escape, Gdk.KEY_Escape)
- self.assertTrue(gtk.keysyms._0, Gdk.KEY_0)
-
- def test_style(self):
- widget = gtk.Button()
- self.assertTrue(isinstance(widget.style.base[gtk.STATE_NORMAL],
- gtk.gdk.Color))
-
- def test_alignment(self):
- a = gtk.Alignment()
- self.assertEqual(a.props.xalign, 0.0)
- self.assertEqual(a.props.yalign, 0.0)
- self.assertEqual(a.props.xscale, 0.0)
- self.assertEqual(a.props.yscale, 0.0)
-
- def test_box(self):
- box = gtk.Box()
- child = gtk.Button()
-
- box.pack_start(child)
- expand, fill, padding, pack_type = box.query_child_packing(child)
- self.assertTrue(expand)
- self.assertTrue(fill)
- self.assertEqual(padding, 0)
- self.assertEqual(pack_type, gtk.PACK_START)
-
- child = gtk.Button()
- box.pack_end(child)
- expand, fill, padding, pack_type = box.query_child_packing(child)
- self.assertTrue(expand)
- self.assertTrue(fill)
- self.assertEqual(padding, 0)
- self.assertEqual(pack_type, gtk.PACK_END)
-
- def test_combobox_entry(self):
- liststore = gtk.ListStore(int, str)
- liststore.append((1, 'One'))
- liststore.append((2, 'Two'))
- liststore.append((3, 'Three'))
- # might cause a Pango warning, do not break on this
- old_mask = GLib.log_set_always_fatal(
- GLib.LogLevelFlags.LEVEL_CRITICAL | GLib.LogLevelFlags.LEVEL_ERROR)
- try:
- combo = gtk.ComboBoxEntry(model=liststore)
- finally:
- GLib.log_set_always_fatal(old_mask)
- combo.set_text_column(1)
- combo.set_active(0)
- self.assertEqual(combo.get_text_column(), 1)
- self.assertEqual(combo.get_child().get_text(), 'One')
- combo = gtk.combo_box_entry_new()
- combo.set_model(liststore)
- combo.set_text_column(1)
- combo.set_active(0)
- self.assertEqual(combo.get_text_column(), 1)
- self.assertEqual(combo.get_child().get_text(), 'One')
- combo = gtk.combo_box_entry_new_with_model(liststore)
- combo.set_text_column(1)
- combo.set_active(0)
- self.assertEqual(combo.get_text_column(), 1)
- self.assertEqual(combo.get_child().get_text(), 'One')
-
- def test_size_request(self):
- box = gtk.Box()
- self.assertEqual(box.size_request(), [0, 0])
-
- def test_pixbuf(self):
- gtk.gdk.Pixbuf()
-
- def test_pixbuf_loader(self):
- loader = gtk.gdk.PixbufLoader('png')
- loader.close()
-
- def test_pixbuf_formats(self):
- formats = gtk.gdk.pixbuf_get_formats()
- self.assertEqual(type(formats[0]), dict)
- self.assertTrue('name' in formats[0])
- self.assertTrue('description' in formats[0])
- self.assertTrue('mime_types' in formats[0])
- self.assertEqual(type(formats[0]['extensions']), list)
-
- def test_gdk_window(self):
- w = gtk.Window()
- w.realize()
- self.assertEqual(w.get_window().get_origin(), (0, 0))
diff --git a/tests/compathelper.py b/tests/compathelper.py
deleted file mode 100644
index 668e60a..0000000
--- a/tests/compathelper.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import sys
-
-if sys.version_info >= (3, 0):
- '''
- for tests that need to test long values in python 2
-
- python 3 does not differentiate between long and int
- and does not supply a long keyword
-
- instead of testing longs by using values such as 10L
- test writters should do this:
-
- from compathelper import _long
- _long(10)
- '''
- _long = int
-
- '''
- for tests that need to test string values in python 2
-
- python 3 does differentiate between str and bytes
- and does not supply a basestring keyword
-
- any tests that use basestring should do this:
-
- from compathelper import _basestring
- isinstance(_basestring, "hello")
- '''
- _basestring = str
-
- '''
- for tests that need to write to intefaces that take bytes in
- python 3
-
- python 3 has a seperate bytes type for low level functions like os.write
-
- python 2 treats these as strings
-
- any tests that need to write a string of bytes should do something like
- this:
-
- from compathelper import _bytes
- os.write(_bytes("hello"))
- '''
-
- _bytes = lambda s: s.encode()
-
- '''
- for tests that need to write to intefaces that take unicode in
- python 2
-
- python 3 strings are unicode encoded as UTF-8 so the unicode object
- doesn't exist
-
- python 2 differs between a string an unicode string and you must specify
- an encoding. This macro will specify UTF-8 in python 2
-
- any tests that need to use unicode should do this
-
- from compathelper import _unicode
- unicode_string = _unicode('this is a unicode string')
- '''
-
- _unicode = lambda s: str(s)
-else:
- _long = long
- _basestring = basestring
- _bytes = str
- _unicode = lambda s: unicode(s, 'UTF-8')
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..254a721
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,26 @@
+import sys
+
+import pytest
+
+
+@pytest.hookimpl(hookwrapper=True, tryfirst=True)
+def pytest_runtest_call(item):
+ """A pytest hook which takes over sys.excepthook and raises any uncaught
+ exception (with PyGObject this happesn often when we get called from C,
+ like any signal handler, vfuncs tc)
+ """
+
+ exceptions = []
+
+ def on_hook(type_, value, tback):
+ exceptions.append((type_, value, tback))
+
+ orig_excepthook = sys.excepthook
+ sys.excepthook = on_hook
+ try:
+ yield
+ finally:
+ sys.excepthook = orig_excepthook
+ if exceptions:
+ tp, value, tb = exceptions[0]
+ raise tp(value).with_traceback(tb)
diff --git a/tests/gi/__init__.py b/tests/gi/__init__.py
deleted file mode 100644
index 3ad9513..0000000
--- a/tests/gi/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from pkgutil import extend_path
-__path__ = extend_path(__path__, __name__)
diff --git a/tests/gimarshallingtestsextra.c b/tests/gimarshallingtestsextra.c
new file mode 100644
index 0000000..d4d6189
--- /dev/null
+++ b/tests/gimarshallingtestsextra.c
@@ -0,0 +1,177 @@
+/* gimarshallingtestsextra.c
+ *
+ * Copyright (C) 2016 Thibault Saunier <tsaunier@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gimarshallingtestsextra.h"
+#include <string.h>
+
+void
+gi_marshalling_tests_compare_two_gerrors_in_gvalue (GValue *v, GValue *v1)
+{
+ GError *error, * error1;
+
+ g_assert_cmpstr (g_type_name (G_VALUE_TYPE (v)), ==,
+ g_type_name (G_TYPE_ERROR));
+ g_assert_cmpstr (g_type_name (G_VALUE_TYPE (v1)), ==,
+ g_type_name (G_TYPE_ERROR));
+
+ error = (GError*) g_value_get_boxed (v);
+ error1 = (GError*) g_value_get_boxed (v1);
+
+ g_assert_cmpint (error->domain, ==, error1->domain);
+ g_assert_cmpint (error->code, ==, error1->code);
+ g_assert_cmpstr (error->message, ==, error1->message);
+}
+
+/**
+ * gi_marshalling_tests_ghashtable_enum_none_in:
+ * @hash_table: (element-type gint GIMarshallingTestsExtraEnum) (transfer none):
+ */
+void
+gi_marshalling_tests_ghashtable_enum_none_in (GHashTable *hash_table)
+{
+ g_assert_cmpint (GPOINTER_TO_INT (g_hash_table_lookup (hash_table, GINT_TO_POINTER (1))), ==, GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE1);
+ g_assert_cmpint (GPOINTER_TO_INT (g_hash_table_lookup (hash_table, GINT_TO_POINTER (2))), ==, GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE2);
+ g_assert_cmpint (GPOINTER_TO_INT (g_hash_table_lookup (hash_table, GINT_TO_POINTER (3))), ==, GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE3);
+}
+
+/**
+ * gi_marshalling_tests_ghashtable_enum_none_return:
+ *
+ * Returns: (element-type gint GIMarshallingTestsExtraEnum) (transfer none):
+ */
+GHashTable *
+gi_marshalling_tests_ghashtable_enum_none_return (void)
+{
+ static GHashTable *hash_table = NULL;
+
+ if (hash_table == NULL)
+ {
+ hash_table = g_hash_table_new (NULL, NULL);
+ g_hash_table_insert (hash_table, GINT_TO_POINTER (1), GINT_TO_POINTER (GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE1));
+ g_hash_table_insert (hash_table, GINT_TO_POINTER (2), GINT_TO_POINTER (GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE2));
+ g_hash_table_insert (hash_table, GINT_TO_POINTER (3), GINT_TO_POINTER (GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE3));
+ }
+
+ return hash_table;
+}
+
+/**
+ * gi_marshalling_tests_filename_copy:
+ * @path_in: (type filename) (nullable)
+ *
+ * Returns: (type filename) (nullable)
+ */
+gchar *
+gi_marshalling_tests_filename_copy (gchar *path_in)
+{
+ return g_strdup (path_in);
+}
+
+/**
+ * gi_marshalling_tests_filename_to_glib_repr:
+ * @path_in: (type filename) (nullable)
+ *
+ * Returns: (array length=len) (element-type guint8)
+ */
+gchar *
+gi_marshalling_tests_filename_to_glib_repr (gchar *path_in, gsize *len)
+{
+ *len = strlen(path_in);
+ return g_strdup (path_in);
+}
+
+/**
+ * gi_marshalling_tests_filename_exists:
+ * @path: (type filename)
+ */
+gboolean
+gi_marshalling_tests_filename_exists (gchar *path)
+{
+ return g_file_test (path, G_FILE_TEST_EXISTS);
+}
+
+
+/**
+ * gi_marshalling_tests_enum_array_return_type:
+ * @n_members: (out): The number of members
+ *
+ * Returns: (array length=n_members) (transfer full): An array of enum values
+ */
+GIMarshallingTestsExtraEnum *
+gi_marshalling_tests_enum_array_return_type (gsize *n_members)
+{
+ GIMarshallingTestsExtraEnum *res = g_new0(GIMarshallingTestsExtraEnum, 3);
+
+ *n_members = 3;
+
+ res[0] = GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE1;
+ res[1] = GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE2;
+ res[2] = GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE3;
+
+ return res;
+}
+
+GType
+gi_marshalling_tests_extra_flags_get_type (void)
+{
+ static GType type = 0;
+ if (G_UNLIKELY (type == 0))
+ {
+ static const GFlagsValue values[] = {
+ {GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE1,
+ "GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE1", "value1"},
+ {GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE2,
+ "GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE2", "value2"},
+ {0, NULL, NULL}
+ };
+ type = g_flags_register_static (
+ g_intern_static_string ("GIMarshallingTestsExtraFlags"), values);
+ }
+
+ return type;
+}
+
+/**
+ * gi_marshalling_tests_extra_flags_large_in:
+ */
+void
+gi_marshalling_tests_extra_flags_large_in (GIMarshallingTestsExtraFlags value)
+{
+ g_assert_cmpint (value, ==, GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE2);
+}
+
+
+/**
+ * gi_marshalling_tests_extra_utf8_full_return_invalid:
+ */
+gchar *
+gi_marshalling_tests_extra_utf8_full_return_invalid (void)
+{
+ return g_strdup ("invalid utf8 \xff\xfe");
+}
+
+
+/**
+ * gi_marshalling_tests_extra_utf8_full_out_invalid:
+ * @utf8: (out) (transfer full):
+ */
+void
+gi_marshalling_tests_extra_utf8_full_out_invalid (gchar **utf8)
+{
+ *utf8 = g_strdup ("invalid utf8 \xff\xfe");
+}
diff --git a/tests/gimarshallingtestsextra.h b/tests/gimarshallingtestsextra.h
new file mode 100644
index 0000000..68ce1d1
--- /dev/null
+++ b/tests/gimarshallingtestsextra.h
@@ -0,0 +1,69 @@
+/* gimarshallingtestsextra.h
+ *
+ * Copyright (C) 2016 Thibault Saunier <tsaunier@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EXTRA_TESTS
+#define EXTRA_TESTS
+
+#include <glib-object.h>
+#include <gitestmacros.h>
+
+typedef enum
+{
+ GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE1,
+ GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE2,
+ GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE3 = 42
+} GIMarshallingTestsExtraEnum;
+
+
+typedef enum
+{
+ GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE1 = 0,
+ GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE2 = (gint)(1 << 31),
+} GIMarshallingTestsExtraFlags;
+
+
+_GI_TEST_EXTERN
+GType gi_marshalling_tests_extra_flags_get_type (void) G_GNUC_CONST;
+#define GI_MARSHALLING_TESTS_TYPE_EXTRA_FLAGS (gi_marshalling_tests_extra_flags_get_type ())
+
+_GI_TEST_EXTERN
+void gi_marshalling_tests_compare_two_gerrors_in_gvalue (GValue *v, GValue *v1);
+_GI_TEST_EXTERN
+void gi_marshalling_tests_ghashtable_enum_none_in (GHashTable *hash_table);
+_GI_TEST_EXTERN
+GHashTable * gi_marshalling_tests_ghashtable_enum_none_return (void);
+
+_GI_TEST_EXTERN
+gchar * gi_marshalling_tests_filename_copy (gchar *path_in);
+_GI_TEST_EXTERN
+gboolean gi_marshalling_tests_filename_exists (gchar *path);
+_GI_TEST_EXTERN
+gchar * gi_marshalling_tests_filename_to_glib_repr (gchar *path_in, gsize *len);
+
+_GI_TEST_EXTERN
+GIMarshallingTestsExtraEnum * gi_marshalling_tests_enum_array_return_type (gsize *n_members);
+
+_GI_TEST_EXTERN
+void gi_marshalling_tests_extra_flags_large_in (GIMarshallingTestsExtraFlags value);
+
+_GI_TEST_EXTERN
+gchar *gi_marshalling_tests_extra_utf8_full_return_invalid (void);
+_GI_TEST_EXTERN
+void gi_marshalling_tests_extra_utf8_full_out_invalid (gchar **utf8);
+
+#endif /* EXTRA_TESTS */
diff --git a/tests/helper.py b/tests/helper.py
new file mode 100644
index 0000000..bed51e8
--- /dev/null
+++ b/tests/helper.py
@@ -0,0 +1,131 @@
+import contextlib
+import unittest
+import inspect
+import warnings
+import functools
+import sys
+from collections import namedtuple
+from io import StringIO
+
+import gi
+from gi import PyGIDeprecationWarning
+from gi.repository import GLib
+
+
+ExceptionInfo = namedtuple("ExceptionInfo", ["type", "value", "traceback"])
+"""The type used for storing exceptions used by capture_exceptions()"""
+
+
+@contextlib.contextmanager
+def capture_exceptions():
+ """Installs a temporary sys.excepthook which records all exceptions
+ instead of printing them.
+ """
+
+ exceptions = []
+
+ def custom_excepthook(*args):
+ exceptions.append(ExceptionInfo(*args))
+
+ old_hook = sys.excepthook
+ sys.excepthook = custom_excepthook
+ try:
+ yield exceptions
+ finally:
+ sys.excepthook = old_hook
+
+
+def ignore_gi_deprecation_warnings(func_or_class):
+ """A unittest class and function decorator which makes them ignore
+ PyGIDeprecationWarning.
+ """
+
+ if inspect.isclass(func_or_class):
+ assert issubclass(func_or_class, unittest.TestCase)
+ cls = func_or_class
+ for name, value in cls.__dict__.items():
+ if callable(value) and name.startswith("test_"):
+ new_value = ignore_gi_deprecation_warnings(value)
+ setattr(cls, name, new_value)
+ return cls
+ else:
+ func = func_or_class
+
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ with capture_gi_deprecation_warnings():
+ return func(*args, **kwargs)
+
+ return wrapper
+
+
+@contextlib.contextmanager
+def capture_gi_deprecation_warnings():
+ """Temporarily suppress PyGIDeprecationWarning output and record them"""
+
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always', category=PyGIDeprecationWarning)
+ yield warn
+
+
+@contextlib.contextmanager
+def capture_glib_warnings(allow_warnings=False, allow_criticals=False):
+ """Temporarily suppress glib warning output and record them.
+
+ The test suite is run with G_DEBUG="fatal-warnings fatal-criticals"
+ by default. Setting allow_warnings and allow_criticals will temporarily
+ allow warnings or criticals without terminating the test run.
+ """
+
+ old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags(0))
+
+ new_mask = old_mask
+ if allow_warnings:
+ new_mask &= ~GLib.LogLevelFlags.LEVEL_WARNING
+ if allow_criticals:
+ new_mask &= ~GLib.LogLevelFlags.LEVEL_CRITICAL
+
+ GLib.log_set_always_fatal(GLib.LogLevelFlags(new_mask))
+
+ GLibWarning = gi._gi.Warning
+ try:
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.filterwarnings('always', category=GLibWarning)
+ yield warn
+ finally:
+ GLib.log_set_always_fatal(old_mask)
+
+
+@contextlib.contextmanager
+def capture_glib_deprecation_warnings():
+ """Temporarily suppress glib deprecation warning output and record them"""
+
+ GLibWarning = gi._gi.Warning
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.filterwarnings(
+ 'always', category=GLibWarning,
+ message=".+ is deprecated and shouldn't be used anymore\\. "
+ "It will be removed in a future version\\.")
+ yield warn
+
+
+@contextlib.contextmanager
+def capture_output():
+ """
+ with capture_output() as (stdout, stderr):
+ some_action()
+ print(stdout.getvalue(), stderr.getvalue())
+ """
+
+ err = StringIO()
+ out = StringIO()
+ old_err = sys.stderr
+ old_out = sys.stdout
+ sys.stderr = err
+ sys.stdout = out
+
+ try:
+ yield (out, err)
+ finally:
+ sys.stderr = old_err
+ sys.stdout = old_out
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 0000000..0a56ac5
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,133 @@
+gnome = import('gnome')
+
+host_system = host_machine.system()
+
+cc = meson.get_compiler('c')
+
+visibility_args = []
+if get_option('default_library') != 'static'
+ if host_system == 'windows'
+ visibility_args += ['-DDLL_EXPORT']
+ if cc.get_id() == 'msvc'
+ visibility_args += ['-D_GI_EXTERN=__declspec(dllexport) extern']
+ elif cc.has_argument('-fvisibility=hidden')
+ visibility_args += ['-D_GI_EXTERN=__attribute__((visibility("default"))) __declspec(dllexport) extern']
+ visibility_args += ['-fvisibility=hidden']
+ endif
+ elif cc.has_argument('-fvisibility=hidden')
+ visibility_args += ['-D_GI_EXTERN=__attribute__((visibility("default"))) extern']
+ visibility_args += ['-fvisibility=hidden']
+ endif
+endif
+
+if gi_dep.type_name() == 'pkgconfig'
+ gi_datadir = gi_dep.get_variable(pkgconfig : 'gidatadir')
+ regress_sources = [join_paths(gi_datadir, 'tests', 'regress.c')]
+ regress_headers = [join_paths(gi_datadir, 'tests', 'regress.h')]
+ regress_incdir = include_directories(join_paths(gi_datadir, 'tests'))
+ marshalling_sources = [join_paths(gi_datadir, 'tests', 'gimarshallingtests.c')]
+ marshalling_headers = [join_paths(gi_datadir, 'tests', 'gimarshallingtests.h')]
+else
+ gi_subproject = subproject('gobject-introspection')
+ regress_sources = gi_subproject.get_variable('test_regress_sources')
+ regress_headers = gi_subproject.get_variable('test_regress_headers')
+ regress_incdir = gi_subproject.get_variable('test_regress_incdirs')
+ marshalling_sources = gi_subproject.get_variable('test_marshalling_sources')
+ marshalling_headers = gi_subproject.get_variable('test_marshalling_headers')
+ gi_datadir = join_paths(meson.source_root(), 'subprojects', 'gobject-introspection', 'tests')
+endif
+
+marshalling_sources += ['gimarshallingtestsextra.c']
+
+marshalling_headers += ['gimarshallingtestsextra.h']
+
+marshalling_lib = library(
+ 'gimarshallingtests',
+ sources : marshalling_sources,
+ dependencies : [glib_dep, gobject_dep, gio_dep, gmodule_dep],
+ include_directories : regress_incdir,
+ c_args: visibility_args,
+)
+
+gnome.generate_gir(
+ marshalling_lib,
+ sources : marshalling_sources + marshalling_headers,
+ nsversion : '1.0',
+ namespace : 'GIMarshallingTests',
+ dependencies : [glib_dep, gobject_dep, gio_dep, gmodule_dep],
+ symbol_prefix : 'gi_marshalling_tests',
+ includes : ['Gio-2.0'],
+ build_by_default : true,
+ extra_args: ['--quiet'],
+)
+
+regress_sources += ['regressextra.c']
+
+regress_headers += ['regressextra.h']
+
+regress_deps = [glib_dep, gobject_dep, gio_dep, gmodule_dep]
+regress_c_args = []
+
+if cairo_dep.found()
+ regress_deps += [cairo_dep, cairo_gobject_dep]
+else
+ regress_c_args += ['-D_GI_DISABLE_CAIRO']
+endif
+
+regress_lib = library(
+ 'regress',
+ sources : regress_sources,
+ dependencies : regress_deps,
+ include_directories : regress_incdir,
+ c_args: regress_c_args + visibility_args,
+)
+
+gnome.generate_gir(
+ regress_lib,
+ sources : regress_sources + regress_headers,
+ nsversion : '1.0',
+ namespace : 'Regress',
+ includes : ['Gio-2.0', 'cairo-1.0'],
+ build_by_default : true,
+ dependencies : regress_deps,
+ extra_args: regress_c_args + ['--quiet'],
+)
+
+helper_sources = [
+ 'testhelpermodule.c',
+ 'test-floating.c',
+ 'test-thread.c',
+ 'test-unknown.c']
+
+helperext = python.extension_module('testhelper', helper_sources,
+ dependencies : [python_dep, glib_dep, gobject_dep],
+ c_args: pyext_c_args + main_c_args,
+ include_directories: include_directories(join_paths('..', 'gi'))
+)
+
+schemas = gnome.compile_schemas(build_by_default: true)
+
+envdata = environment()
+envdata.append('GI_TYPELIB_PATH', meson.current_build_dir())
+if gi_dep.type_name() == 'internal'
+ envdata.append('GI_TYPELIB_PATH', join_paths(meson.project_build_root(), 'subprojects', 'gobject-introspection', 'gir'))
+endif
+
+if host_machine.system() == 'linux'
+ envdata.prepend('LD_LIBRARY_PATH', meson.current_build_dir())
+endif
+if host_machine.system() == 'windows'
+ envdata.prepend('PATH', join_paths(get_option('prefix'), get_option('bindir')))
+endif
+
+python_paths = [join_paths(meson.current_build_dir(), '..')]
+if pycairo_dep.found() and pycairo_dep.type_name() == 'internal'
+ python_paths += [join_paths(meson.project_build_root(), 'subprojects', 'pycairo')]
+endif
+envdata.append('PYTHONPATH', python_paths)
+envdata.append('TESTS_BUILDDIR', meson.current_build_dir())
+
+test('pygobject-test-suite', python,
+ args : [join_paths(meson.current_source_dir(), 'runtests.py')],
+ env : envdata,
+ timeout : 90)
diff --git a/tests/org.gnome.test.gschema.xml b/tests/org.gnome.test.gschema.xml
index eb9aab8..0c1e5c4 100644
--- a/tests/org.gnome.test.gschema.xml
+++ b/tests/org.gnome.test.gschema.xml
@@ -21,6 +21,10 @@
<key name="test-enum" enum="org.gnome.test.FruitType">
<default>'banana'</default>
</key>
+ <key name="test-range" type="i">
+ <range min="7" max="65535"/>
+ <default>123</default>
+ </key>
</schema>
<schema id="org.gnome.nopathtest">
diff --git a/tests/regressextra.c b/tests/regressextra.c
new file mode 100644
index 0000000..41fdb84
--- /dev/null
+++ b/tests/regressextra.c
@@ -0,0 +1,416 @@
+#include "regress.h"
+#include "regressextra.h"
+
+#include <glib-object.h>
+
+struct _RegressTestBoxedCWrapper
+{
+ RegressTestBoxedC * cptr;
+};
+
+RegressTestBoxedCWrapper *
+regress_test_boxed_c_wrapper_new (void)
+{
+ RegressTestBoxedCWrapper *boxed;
+ boxed = g_slice_new (RegressTestBoxedCWrapper);
+ boxed->cptr = regress_test_boxed_c_new ();
+ return boxed;
+}
+
+RegressTestBoxedCWrapper *
+regress_test_boxed_c_wrapper_copy (RegressTestBoxedCWrapper *self)
+{
+ RegressTestBoxedCWrapper *ret_boxed;
+ ret_boxed = g_slice_new (RegressTestBoxedCWrapper);
+ ret_boxed->cptr = g_boxed_copy (regress_test_boxed_c_get_type(), self->cptr);
+ return ret_boxed;
+}
+
+static void
+regress_test_boxed_c_wrapper_free (RegressTestBoxedCWrapper *boxed)
+{
+ g_boxed_free (regress_test_boxed_c_get_type(), boxed->cptr);
+ g_slice_free (RegressTestBoxedCWrapper, boxed);
+}
+
+G_DEFINE_BOXED_TYPE(RegressTestBoxedCWrapper,
+ regress_test_boxed_c_wrapper,
+ regress_test_boxed_c_wrapper_copy,
+ regress_test_boxed_c_wrapper_free);
+
+/**
+ * regress_test_boxed_c_wrapper_get
+ * @self: a #RegressTestBoxedCWrapper objects
+ *
+ * Returns: (transfer none): associated #RegressTestBoxedC
+**/
+RegressTestBoxedC *
+regress_test_boxed_c_wrapper_get (RegressTestBoxedCWrapper *self)
+{
+ return self->cptr;
+}
+
+/**
+ * regress_test_array_fixed_boxed_none_out
+ * @objs: (out) (array fixed-size=2) (transfer none): An array of #RegressTestBoxedC
+**/
+void
+regress_test_array_fixed_boxed_none_out (RegressTestBoxedC ***objs)
+{
+ static RegressTestBoxedC **arr;
+
+ if (arr == NULL) {
+ arr = g_new0 (RegressTestBoxedC *, 3);
+ arr[0] = regress_test_boxed_c_new ();
+ arr[1] = regress_test_boxed_c_new ();
+ }
+
+ *objs = arr;
+}
+
+/**
+ * regress_test_gvalue_out_boxed:
+ * @value: (out) (transfer full): the output gvalue
+ * @init: (in): the initialisation value
+**/
+void
+regress_test_gvalue_out_boxed (GValue *value, int init)
+{
+ RegressTestBoxed rtb;
+ GValue v = G_VALUE_INIT;
+
+ memset(&rtb, 0, sizeof (rtb));
+ rtb.some_int8 = init;
+ g_value_init (&v, REGRESS_TEST_TYPE_BOXED);
+ g_value_set_boxed (&v, &rtb);
+ *value = v;
+}
+
+/**
+ * regress_test_glist_boxed_none_return
+ * Return value: (element-type RegressTestBoxedC) (transfer none):
+**/
+GList *
+regress_test_glist_boxed_none_return (guint count)
+{
+ static GList *list = NULL;
+ if (!list) {
+ while (count > 0) {
+ list = g_list_prepend (list, regress_test_boxed_c_new ());
+ count--;
+ }
+ }
+
+ return list;
+}
+
+/**
+ * regress_test_glist_boxed_full_return
+ * Return value: (element-type RegressTestBoxedC) (transfer full):
+**/
+GList *
+regress_test_glist_boxed_full_return (guint count)
+{
+ GList *list = NULL;
+ while (count > 0) {
+ list = g_list_prepend (list, regress_test_boxed_c_new ());
+ count--;
+ }
+ return list;
+}
+
+
+#ifndef _GI_DISABLE_CAIRO
+
+/**
+ * regress_test_cairo_context_none_return:
+ *
+ * Returns: (transfer none):
+ */
+cairo_t *
+regress_test_cairo_context_none_return (void)
+{
+ static cairo_t *cr;
+
+ if (cr == NULL) {
+ cairo_surface_t *surface;
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 10, 10);
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+ }
+
+ return cr;
+}
+
+/**
+ * regress_test_cairo_context_full_in:
+ * @context: (transfer full):
+ */
+void
+regress_test_cairo_context_full_in (cairo_t *context)
+{
+ cairo_destroy (context);
+}
+
+
+/**
+ * regress_test_cairo_path_full_return:
+ *
+ * Returns: (transfer full):
+ */
+cairo_path_t *
+regress_test_cairo_path_full_return (void)
+{
+ cairo_t *cr = regress_test_cairo_context_none_return ();
+
+ return cairo_copy_path (cr);
+}
+
+/**
+ * regress_test_cairo_path_none_in:
+ * @path: (transfer none):
+ */
+void
+regress_test_cairo_path_none_in (cairo_path_t *path)
+{
+ cairo_t *cr = regress_test_cairo_context_full_return ();
+ cairo_append_path (cr, path);
+ g_assert (cairo_status (cr) == CAIRO_STATUS_SUCCESS);
+ cairo_destroy (cr);
+}
+
+/**
+ * regress_test_cairo_path_full_in_full_return:
+ * @path: (transfer full):
+ *
+ * Returns: (transfer full):
+ */
+cairo_path_t *
+regress_test_cairo_path_full_in_full_return (cairo_path_t *path)
+{
+ return path;
+}
+
+/**
+ * regress_test_cairo_pattern_full_in:
+ * @pattern: (transfer full):
+ */
+void
+regress_test_cairo_pattern_full_in (cairo_pattern_t *pattern)
+{
+ cairo_pattern_destroy (pattern);
+}
+
+/**
+ * regress_test_cairo_pattern_none_in:
+ * @pattern: (transfer none):
+ */
+void
+regress_test_cairo_pattern_none_in (cairo_pattern_t *pattern)
+{
+ cairo_t *cr = regress_test_cairo_context_full_return ();
+ cairo_set_source (cr, pattern);
+ g_assert (cairo_status (cr) == CAIRO_STATUS_SUCCESS);
+ cairo_destroy (cr);
+}
+
+/**
+ * regress_test_cairo_pattern_none_return:
+ *
+ * Returns: (transfer none):
+ */
+cairo_pattern_t*
+regress_test_cairo_pattern_none_return (void)
+{
+ static cairo_pattern_t *pattern;
+
+ if (pattern == NULL) {
+ pattern = cairo_pattern_create_rgb(0.1, 0.2, 0.3);
+ }
+
+ return pattern;
+}
+
+/**
+ * regress_test_cairo_pattern_full_return:
+ *
+ * Returns: (transfer full):
+ */
+cairo_pattern_t *
+regress_test_cairo_pattern_full_return (void)
+{
+ cairo_pattern_t *pattern = cairo_pattern_create_rgb(0.5, 0.6, 0.7);
+ return pattern;
+}
+
+/**
+ * regress_test_cairo_region_full_in:
+ * @region: (transfer full):
+ */
+void
+regress_test_cairo_region_full_in (cairo_region_t *region)
+{
+ cairo_region_destroy (region);
+}
+
+/**
+ * regress_test_cairo_surface_full_in:
+ * @surface: (transfer full):
+ */
+void
+regress_test_cairo_surface_full_in (cairo_surface_t *surface)
+{
+ g_assert (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32);
+ g_assert (cairo_image_surface_get_width (surface) == 10);
+ g_assert (cairo_image_surface_get_height (surface) == 10);
+ cairo_surface_destroy (surface);
+}
+
+/**
+ * regress_test_cairo_font_options_full_return:
+ *
+ * Returns: (transfer full):
+ */
+cairo_font_options_t *
+regress_test_cairo_font_options_full_return (void)
+{
+ return cairo_font_options_create ();
+}
+
+/**
+ * regress_test_cairo_font_options_none_return:
+ *
+ * Returns: (transfer none):
+ */
+cairo_font_options_t *
+regress_test_cairo_font_options_none_return (void)
+{
+ static cairo_font_options_t *options;
+
+ if (options == NULL)
+ options = cairo_font_options_create ();
+
+ return options;
+}
+
+/**
+ * regress_test_cairo_font_options_full_in:
+ * @options: (transfer full):
+ */
+void
+regress_test_cairo_font_options_full_in (cairo_font_options_t *options)
+{
+ cairo_font_options_destroy (options);
+}
+
+/**
+ * regress_test_cairo_font_options_none_in:
+ * @options: (transfer none):
+ */
+void
+regress_test_cairo_font_options_none_in (cairo_font_options_t *options)
+{
+}
+
+
+/**
+ * regress_test_cairo_matrix_none_in:
+ * @matrix: (transfer none):
+ */
+void
+regress_test_cairo_matrix_none_in (const cairo_matrix_t *matrix)
+{
+ cairo_matrix_t m = *matrix;
+ g_assert (m.x0 == 0);
+ g_assert (m.y0 == 0);
+ g_assert (m.xx == 1);
+ g_assert (m.xy == 0);
+ g_assert (m.yy == 1);
+ g_assert (m.yx == 0);
+}
+
+/**
+ * regress_test_cairo_matrix_none_return:
+ * Returns: (transfer none):
+ */
+cairo_matrix_t *
+regress_test_cairo_matrix_none_return (void)
+{
+ static cairo_matrix_t matrix;
+ cairo_matrix_init_identity (&matrix);
+ return &matrix;
+}
+
+/**
+ * regress_test_cairo_matrix_out_caller_allocates:
+ * @matrix: (out):
+ */
+void
+regress_test_cairo_matrix_out_caller_allocates (cairo_matrix_t *matrix)
+{
+ cairo_matrix_t m;
+ cairo_matrix_init_identity (&m);
+ *matrix = m;
+}
+
+#endif
+
+G_DEFINE_TYPE (RegressTestAction, regress_test_action, G_TYPE_INITIALLY_UNOWNED)
+
+enum
+{
+ SIGNAL_0,
+ ACTION_SIGNAL,
+ ACTION2_SIGNAL,
+ LAST_SIGNAL
+};
+
+static guint regress_test_action_signals[LAST_SIGNAL] = { 0 };
+
+static RegressTestAction *
+regress_test_action_do_action (RegressTestAction *self)
+{
+ RegressTestAction *ret = g_object_new (regress_test_action_get_type (), NULL);
+
+ return ret;
+}
+
+static RegressTestAction *
+regress_test_action_do_action2 (RegressTestAction *self)
+{
+ return NULL;
+}
+
+static void
+regress_test_action_init (RegressTestAction *self)
+{
+}
+
+static void regress_test_action_class_init (RegressTestActionClass *klass)
+{
+ /**
+ * RegressTestAction::action:
+ *
+ * An action signal.
+ *
+ * Returns: (transfer full): another #RegressTestAction
+ */
+ regress_test_action_signals[ACTION_SIGNAL] =
+ g_signal_new_class_handler ("action",
+ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_CALLBACK (regress_test_action_do_action), NULL, NULL,
+ NULL, regress_test_action_get_type (), 0);
+
+ /**
+ * RegressTestAction::action2:
+ *
+ * Another action signal.
+ *
+ * Returns: (transfer full): another #RegressTestAction
+ */
+ regress_test_action_signals[ACTION2_SIGNAL] =
+ g_signal_new_class_handler ("action2",
+ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_CALLBACK (regress_test_action_do_action2), NULL, NULL,
+ NULL, regress_test_action_get_type (), 0);
+}
diff --git a/tests/regressextra.h b/tests/regressextra.h
new file mode 100644
index 0000000..8834eb7
--- /dev/null
+++ b/tests/regressextra.h
@@ -0,0 +1,82 @@
+#ifndef REGRESS_EXTRA_H
+#define REGRESS_EXTRA_H
+
+#include <glib-object.h>
+
+typedef struct _RegressTestBoxedC RegressTestBoxedC;
+typedef struct _RegressTestBoxedCWrapper RegressTestBoxedCWrapper;
+
+_GI_TEST_EXTERN
+GType regress_test_boxed_c_wrapper_get_type (void);
+
+_GI_TEST_EXTERN
+RegressTestBoxedCWrapper *regress_test_boxed_c_wrapper_new (void);
+_GI_TEST_EXTERN
+RegressTestBoxedCWrapper * regress_test_boxed_c_wrapper_copy (RegressTestBoxedCWrapper *self);
+_GI_TEST_EXTERN
+RegressTestBoxedC *regress_test_boxed_c_wrapper_get (RegressTestBoxedCWrapper *self);
+
+_GI_TEST_EXTERN
+void regress_test_array_fixed_boxed_none_out (RegressTestBoxedC ***objs);
+_GI_TEST_EXTERN
+void regress_test_gvalue_out_boxed (GValue *value, int init);
+_GI_TEST_EXTERN
+GList *regress_test_glist_boxed_none_return (guint count);
+_GI_TEST_EXTERN
+GList *regress_test_glist_boxed_full_return (guint count);
+
+#ifndef _GI_DISABLE_CAIRO
+
+_GI_TEST_EXTERN
+cairo_t *regress_test_cairo_context_none_return (void);
+_GI_TEST_EXTERN
+void regress_test_cairo_context_full_in (cairo_t *context);
+_GI_TEST_EXTERN
+cairo_path_t *regress_test_cairo_path_full_return (void);
+_GI_TEST_EXTERN
+void regress_test_cairo_path_none_in (cairo_path_t *path);
+_GI_TEST_EXTERN
+cairo_path_t * regress_test_cairo_path_full_in_full_return (cairo_path_t *path);
+_GI_TEST_EXTERN
+void regress_test_cairo_pattern_full_in (cairo_pattern_t *pattern);
+_GI_TEST_EXTERN
+void regress_test_cairo_pattern_none_in (cairo_pattern_t *pattern);
+_GI_TEST_EXTERN
+cairo_pattern_t* regress_test_cairo_pattern_none_return (void);
+_GI_TEST_EXTERN
+cairo_pattern_t * regress_test_cairo_pattern_full_return (void);
+_GI_TEST_EXTERN
+cairo_font_options_t *regress_test_cairo_font_options_full_return (void);
+_GI_TEST_EXTERN
+cairo_font_options_t *regress_test_cairo_font_options_none_return (void);
+_GI_TEST_EXTERN
+void regress_test_cairo_font_options_full_in (cairo_font_options_t *options);
+_GI_TEST_EXTERN
+void regress_test_cairo_font_options_none_in (cairo_font_options_t *options);
+_GI_TEST_EXTERN
+void regress_test_cairo_region_full_in (cairo_region_t *region);
+_GI_TEST_EXTERN
+void regress_test_cairo_surface_full_in (cairo_surface_t *surface);
+_GI_TEST_EXTERN
+void regress_test_cairo_matrix_none_in (const cairo_matrix_t *matrix);
+_GI_TEST_EXTERN
+cairo_matrix_t *regress_test_cairo_matrix_none_return (void);
+_GI_TEST_EXTERN
+void regress_test_cairo_matrix_out_caller_allocates (cairo_matrix_t *matrix);
+
+#endif
+
+/* RegressTestAction */
+
+typedef struct {
+ GInitiallyUnowned parent;
+} RegressTestAction;
+
+typedef struct {
+ GInitiallyUnownedClass parent_class;
+} RegressTestActionClass;
+
+_GI_TEST_EXTERN
+GType regress_test_action_get_type (void);
+
+#endif /* REGRESS_EXTRA_H */
diff --git a/tests/runtests-windows.py b/tests/runtests-windows.py
deleted file mode 100644
index 36ab9e1..0000000
--- a/tests/runtests-windows.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-
-import os
-import sys
-import glob
-import unittest
-
-mydir = os.path.dirname(os.path.abspath(__file__))
-tests_builddir = os.path.abspath(os.environ.get('TESTS_BUILDDIR', os.path.dirname(__file__)))
-builddir = os.path.dirname(tests_builddir)
-
-# we have to do this here instead of Makefile.am so that the implicitly added
-# directory for the source file comes after the builddir
-sys.path.insert(0, tests_builddir)
-sys.path.insert(0, builddir)
-
-os.environ['PYGTK_USE_GIL_STATE_API'] = ''
-sys.argv.append('--g-fatal-warnings')
-
-from gi.repository import GObject
-GObject.threads_init()
-
-
-SKIP_FILES = ['runtests',
- 'test_mainloop', # no os.fork on windows
- 'test_subprocess'] # blocks on testChildWatch
-
-
-if __name__ == '__main__':
- testdir = os.path.split(os.path.abspath(__file__))[0]
- os.chdir(testdir)
-
- def gettestnames():
- files = glob.glob('*.py')
- names = map(lambda x: x[:-3], files)
- map(names.remove, SKIP_FILES)
- return names
-
- suite = unittest.TestSuite()
- loader = unittest.TestLoader()
-
- for name in gettestnames():
- try:
- suite.addTest(loader.loadTestsFromName(name))
- except Exception, e:
- print 'Could not load %s: %s' % (name, e)
-
- testRunner = unittest.TextTestRunner()
- testRunner.verbosity = 2
- testRunner.run(suite)
diff --git a/tests/runtests.py b/tests/runtests.py
index 6085ff9..721b5d8 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -2,61 +2,43 @@
# -*- Mode: Python -*-
import os
-import glob
import sys
-import unittest
-
-# this was renamed in Python 3, provide backwards compatible name
-if sys.version_info[:2] == (2, 7):
- unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
-
-if '--help' in sys.argv:
- print("Usage: ./runtests.py <testfiles>")
- sys.exit(0)
-
-mydir = os.path.dirname(os.path.abspath(__file__))
-tests_builddir = os.path.abspath(os.environ.get('TESTS_BUILDDIR', os.path.dirname(__file__)))
-builddir = os.path.dirname(tests_builddir)
-
-# we have to do this here instead of Makefile.am so that the implicitly added
-# directory for the source file comes after the builddir
-sys.path.insert(0, tests_builddir)
-sys.path.insert(0, builddir)
-
-# force untranslated messages, as we check for them in some tests
-os.environ['LC_MESSAGES'] = 'C'
-os.environ['G_DEBUG'] = 'fatal-warnings fatal-criticals'
-
-# make Gio able to find our gschemas.compiled in tests/. This needs to be set
-# before importing Gio. Support a separate build tree, so look in build dir
-# first.
-os.environ['GSETTINGS_BACKEND'] = 'memory'
-os.environ['GSETTINGS_SCHEMA_DIR'] = tests_builddir
-os.environ['G_FILENAME_ENCODING'] = 'UTF-8'
-
-# Load tests.
-if 'TEST_NAMES' in os.environ:
- names = os.environ['TEST_NAMES'].split()
-elif 'TEST_FILES' in os.environ:
- names = []
- for filename in os.environ['TEST_FILES'].split():
- names.append(filename[:-3])
-elif len(sys.argv) > 1:
- names = []
- for filename in sys.argv[1:]:
- names.append(filename.replace('.py', ''))
-else:
- names = []
- for filename in glob.iglob(os.path.join(mydir, 'test_*.py')):
- names.append(os.path.basename(filename)[:-3])
-
-loader = unittest.TestLoader()
-suite = loader.loadTestsFromNames(names)
-
-
-# Run tests.
-runner = unittest.TextTestRunner(verbosity=2)
-result = runner.run(suite)
-if not result.wasSuccessful():
- sys.exit(1) # exit code so "make check" reports error
+import pytest
+
+
+def main(argv):
+ if '--help' in argv:
+ print("Usage: ./runtests.py <testfiles>")
+ return
+
+ mydir = os.path.dirname(os.path.abspath(__file__))
+
+ verbosity_args = []
+
+ if 'PYGI_TEST_VERBOSE' in os.environ:
+ verbosity_args += ['--capture=no']
+
+ if 'TEST_NAMES' in os.environ:
+ names = os.environ['TEST_NAMES'].split()
+ elif 'TEST_FILES' in os.environ:
+ names = []
+ for filename in os.environ['TEST_FILES'].split():
+ names.append(filename[:-3])
+ elif len(argv) > 1:
+ names = []
+ for filename in argv[1:]:
+ names.append(filename.replace('.py', ''))
+ else:
+ return pytest.main([mydir] + verbosity_args)
+
+ def unittest_to_pytest_name(name):
+ parts = name.split(".")
+ parts[0] = os.path.join(mydir, parts[0] + ".py")
+ return "::".join(parts)
+
+ return pytest.main([unittest_to_pytest_name(n) for n in names] + verbosity_args)
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv))
diff --git a/tests/te_ST@nouppera b/tests/te_ST@nouppera
deleted file mode 100644
index a511e90..0000000
--- a/tests/te_ST@nouppera
+++ /dev/null
@@ -1,50 +0,0 @@
-LC_IDENTIFICATION
-title "pygobject test locale"
-END LC_IDENTIFICATION
-
-LC_COLLATE
-copy "POSIX"
-END LC_COLLATE
-
-LC_CTYPE
-# a → a, other characters normally
-toupper (<U0061>,<U0061>); (<U0062>,<U0042>); (<U0063>,<U0043>); \
- (<U0076>,<U0056>); (<U006C>,<U004C>); (<U0075>,<U0055>); \
- (<U0065>,<U0045>);
-END LC_CTYPE
-
-LC_MESSAGES
-copy "en_US"
-END LC_MESSAGES
-
-LC_MONETARY
-copy "en_US"
-END LC_MONETARY
-
-LC_NUMERIC
-copy "POSIX"
-END LC_NUMERIC
-
-LC_TIME
-copy "POSIX"
-END LC_TIME
-
-LC_PAPER
-copy "en_US"
-END LC_PAPER
-
-LC_TELEPHONE
-copy "en_US"
-END LC_TELEPHONE
-
-LC_MEASUREMENT
-copy "en_US"
-END LC_MEASUREMENT
-
-LC_NAME
-copy "en_US"
-END LC_NAME
-
-LC_ADDRESS
-copy "en_US"
-END LC_ADDRESS
diff --git a/tests/test_atoms.py b/tests/test_atoms.py
index 1561dbd..a74db38 100644
--- a/tests/test_atoms.py
+++ b/tests/test_atoms.py
@@ -1,13 +1,28 @@
+import os
import unittest
try:
- from gi.repository import Atk, Gdk, Gtk
- (Atk, Gdk) # pyflakes
-except:
+ from gi.repository import Gtk, Atk, Gdk
+except ImportError:
Gdk = None
+ Atk = None
+ Gtk = None
+
+from .helper import capture_glib_deprecation_warnings
+
+
+def is_X11():
+ try:
+ from gi.repository import Gdk, GdkX11
+ except ImportError:
+ return False
+
+ display = Gdk.Display.get_default()
+ return isinstance(display, GdkX11.X11Display)
@unittest.skipUnless(Gdk, 'Gdk not available')
+@unittest.skipIf(Gdk._version == "4.0", 'Gdk4 doesn\'t have GdkAtom')
class TestGdkAtom(unittest.TestCase):
def test_create(self):
atom = Gdk.Atom.intern('my_string', False)
@@ -20,11 +35,15 @@ class TestGdkAtom(unittest.TestCase):
self.assertEqual(str(Gdk.SELECTION_CLIPBOARD), 'CLIPBOARD')
def test_repr(self):
+ # __repr__ should generate a string which is parsable when possible
+ # http://docs.python.org/2/reference/datamodel.html#object.__repr__
atom = Gdk.Atom.intern('my_string', False)
- self.assertEqual(repr(atom), 'Gdk.Atom<my_string>')
+ self.assertEqual(repr(atom), 'Gdk.Atom.intern("my_string", False)')
+ self.assertEqual(eval(repr(atom)), atom)
- self.assertEqual(repr(Gdk.SELECTION_CLIPBOARD), 'Gdk.Atom<CLIPBOARD>')
+ self.assertEqual(repr(Gdk.SELECTION_CLIPBOARD), 'Gdk.Atom.intern("CLIPBOARD", False)')
+ @unittest.skipUnless(os.name != "nt", "not on Windows")
def test_in_single(self):
a_selection = Gdk.Atom.intern('test_clipboard', False)
clipboard = Gtk.Clipboard.get(a_selection)
@@ -48,6 +67,7 @@ class TestGdkAtom(unittest.TestCase):
self.assertTrue(Gtk.targets_include_image([a_jpeg], False))
self.assertTrue(Gtk.targets_include_image([a_jpeg, a_plain], False))
+ @unittest.skipUnless(is_X11(), "only on X11")
def test_out_array(self):
a_selection = Gdk.Atom.intern('my_clipboard', False)
clipboard = Gtk.Clipboard.get(a_selection)
@@ -67,11 +87,13 @@ class TestGdkAtom(unittest.TestCase):
self.assertFalse(None in names, names)
self.assertTrue('TEXT' in names, names)
+ @unittest.skipUnless(is_X11(), "only on X11")
+ @unittest.skipIf(not Gdk or Gdk._version == "4.0", "not in gdk4")
def test_out_glist(self):
display = Gdk.Display.get_default()
- dm = display.get_device_manager()
- device = dm.get_client_pointer()
+ with capture_glib_deprecation_warnings():
+ dm = display.get_device_manager()
+ device = dm.get_client_pointer()
axes = device.list_axes()
- axes_names = [atom.name() for atom in axes]
- self.assertNotEqual(axes_names, [])
- self.assertTrue('Rel X' in axes_names)
+ axes_names = [atom.name() for atom in axes if atom is not None]
+ assert all(isinstance(name, str) for name in axes_names)
diff --git a/tests/test_cairo.py b/tests/test_cairo.py
new file mode 100644
index 0000000..d73037e
--- /dev/null
+++ b/tests/test_cairo.py
@@ -0,0 +1,308 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+
+import unittest
+import pytest
+
+import gi
+
+try:
+ gi.require_foreign('cairo')
+ import cairo
+ has_cairo = True
+except ImportError:
+ has_cairo = False
+
+has_region = has_cairo and hasattr(cairo, "Region")
+
+try:
+ from gi.repository import Gtk, Gdk
+ Gtk, Gdk # pyflakes
+except:
+ Gtk = None
+ Gdk = None
+
+from gi.repository import GObject, Regress
+
+
+@unittest.skipUnless(has_cairo, 'built without cairo support')
+class Test(unittest.TestCase):
+
+ def test_gvalue_converters(self):
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ context = cairo.Context(surface)
+ matrix = cairo.Matrix()
+ objects = {
+ 'CairoContext': context,
+ 'CairoSurface': surface,
+ 'CairoFontFace': context.get_font_face(),
+ 'CairoScaledFont': context.get_scaled_font(),
+ 'CairoPattern': context.get_source(),
+ 'CairoMatrix': matrix,
+ }
+ for type_name, cairo_obj in objects.items():
+ gtype = GObject.type_from_name(type_name)
+ v = GObject.Value()
+ assert v.init(gtype) is None
+ assert v.get_value() is None
+ v.set_value(None)
+ assert v.get_value() is None
+ v.set_value(cairo_obj)
+ assert v.get_value() == cairo_obj
+
+ def test_cairo_context(self):
+ context = Regress.test_cairo_context_full_return()
+ self.assertTrue(isinstance(context, cairo.Context))
+
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ context = cairo.Context(surface)
+ Regress.test_cairo_context_none_in(context)
+
+ def test_cairo_context_full_in(self):
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ context = cairo.Context(surface)
+ Regress.test_cairo_context_full_in(context)
+
+ with pytest.raises(TypeError):
+ Regress.test_cairo_context_full_in(object())
+
+ def test_cairo_context_none_return(self):
+ context = Regress.test_cairo_context_none_return()
+ self.assertTrue(isinstance(context, cairo.Context))
+
+ def test_cairo_path_full_return(self):
+ path = Regress.test_cairo_path_full_return()
+ if hasattr(cairo, "Path"): # pycairo 1.15.1+
+ assert isinstance(path, cairo.Path)
+
+ def test_cairo_path_none_in(self):
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ context = cairo.Context(surface)
+ path = context.copy_path()
+ Regress.test_cairo_path_none_in(path)
+ surface.finish()
+
+ with pytest.raises(TypeError):
+ Regress.test_cairo_path_none_in(object())
+
+ def test_cairo_path_full_in_full_return(self):
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ context = cairo.Context(surface)
+ context.move_to(10, 10)
+ context.curve_to(10, 10, 3, 4, 5, 6)
+ path = context.copy_path()
+ new_path = Regress.test_cairo_path_full_in_full_return(path)
+ assert list(path) == list(new_path)
+ surface.finish()
+
+ def test_cairo_font_options_full_return(self):
+ options = Regress.test_cairo_font_options_full_return()
+ assert isinstance(options, cairo.FontOptions)
+
+ def test_cairo_font_options_none_return(self):
+ options = Regress.test_cairo_font_options_none_return()
+ assert isinstance(options, cairo.FontOptions)
+
+ def test_cairo_font_options_full_in(self):
+ options = cairo.FontOptions()
+ Regress.test_cairo_font_options_full_in(options)
+
+ with pytest.raises(TypeError):
+ Regress.test_cairo_font_options_full_in(object())
+
+ def test_cairo_font_options_none_in(self):
+ options = cairo.FontOptions()
+ Regress.test_cairo_font_options_none_in(options)
+
+ def test_cairo_pattern_full_in(self):
+ pattern = cairo.SolidPattern(1, 1, 1, 1)
+ Regress.test_cairo_pattern_full_in(pattern)
+
+ with pytest.raises(TypeError):
+ Regress.test_cairo_pattern_full_in(object())
+
+ def test_cairo_pattern_none_in(self):
+ pattern = cairo.SolidPattern(1, 1, 1, 1)
+ Regress.test_cairo_pattern_none_in(pattern)
+
+ def test_cairo_pattern_full_return(self):
+ pattern = Regress.test_cairo_pattern_full_return()
+ self.assertTrue(isinstance(pattern, cairo.Pattern))
+ self.assertTrue(isinstance(pattern, cairo.SolidPattern))
+
+ def test_cairo_pattern_none_return(self):
+ pattern = Regress.test_cairo_pattern_none_return()
+ self.assertTrue(isinstance(pattern, cairo.Pattern))
+ self.assertTrue(isinstance(pattern, cairo.SolidPattern))
+
+ def test_cairo_region_full_in(self):
+ region = cairo.Region()
+ Regress.test_cairo_region_full_in(region)
+
+ with pytest.raises(TypeError):
+ Regress.test_cairo_region_full_in(object())
+
+ def test_cairo_matrix_none_in(self):
+ matrix = cairo.Matrix()
+ Regress.test_cairo_matrix_none_in(matrix)
+
+ with pytest.raises(TypeError):
+ Regress.test_cairo_matrix_none_in(object())
+
+ def test_cairo_matrix_none_return(self):
+ matrix = Regress.test_cairo_matrix_none_return()
+ assert matrix == cairo.Matrix()
+
+ def test_cairo_matrix_out_caller_allocates(self):
+ matrix = Regress.test_cairo_matrix_out_caller_allocates()
+ assert matrix == cairo.Matrix()
+
+ def test_cairo_surface(self):
+ surface = Regress.test_cairo_surface_none_return()
+ self.assertTrue(isinstance(surface, cairo.ImageSurface))
+ self.assertTrue(isinstance(surface, cairo.Surface))
+ self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32)
+ self.assertEqual(surface.get_width(), 10)
+ self.assertEqual(surface.get_height(), 10)
+
+ surface = Regress.test_cairo_surface_full_return()
+ self.assertTrue(isinstance(surface, cairo.ImageSurface))
+ self.assertTrue(isinstance(surface, cairo.Surface))
+ self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32)
+ self.assertEqual(surface.get_width(), 10)
+ self.assertEqual(surface.get_height(), 10)
+
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ Regress.test_cairo_surface_none_in(surface)
+
+ surface = Regress.test_cairo_surface_full_out()
+ self.assertTrue(isinstance(surface, cairo.ImageSurface))
+ self.assertTrue(isinstance(surface, cairo.Surface))
+ self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32)
+ self.assertEqual(surface.get_width(), 10)
+ self.assertEqual(surface.get_height(), 10)
+
+ def test_cairo_surface_full_in(self):
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ Regress.test_cairo_surface_full_in(surface)
+
+ with pytest.raises(TypeError):
+ Regress.test_cairo_surface_full_in(object())
+
+ def test_require_foreign(self):
+ self.assertEqual(gi.require_foreign('cairo'), None)
+ self.assertEqual(gi.require_foreign('cairo', 'Context'), None)
+ self.assertRaises(ImportError, gi.require_foreign, 'invalid_module')
+ self.assertRaises(ImportError, gi.require_foreign, 'invalid_module', 'invalid_symbol')
+ self.assertRaises(ImportError, gi.require_foreign, 'cairo', 'invalid_symbol')
+
+
+@unittest.skipUnless(has_cairo, 'built without cairo support')
+@unittest.skipUnless(has_region, 'built without cairo.Region support')
+@unittest.skipUnless(Gdk, 'Gdk not available')
+class TestRegion(unittest.TestCase):
+
+ def test_region_to_py(self):
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ context = cairo.Context(surface)
+ context.paint()
+ region = Gdk.cairo_region_create_from_surface(surface)
+ r = region.get_extents()
+ self.assertEqual((r.height, r.width), (10, 10))
+
+ def test_region_from_py(self):
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ context = cairo.Context(surface)
+ region = cairo.Region(cairo.RectangleInt(0, 0, 42, 42))
+ Gdk.cairo_region(context, region)
+ self.assertTrue("42" in repr(list(context.copy_path())))
+
+
+@unittest.skipUnless(has_cairo, 'built without cairo support')
+@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestPango(unittest.TestCase):
+
+ def test_cairo_font_options(self):
+ window = Gtk.Window()
+ if Gtk._version == "4.0":
+ window.set_font_options(cairo.FontOptions())
+ font_opts = window.get_font_options()
+ else:
+ screen = window.get_screen()
+ font_opts = screen.get_font_options()
+ assert font_opts is not None
+ self.assertTrue(isinstance(font_opts.get_subpixel_order(), int))
+
+
+if has_cairo:
+ from gi.repository import cairo as CairoGObject
+
+ # Use PyGI signals to test non-introspected foreign marshaling.
+ class CairoSignalTester(GObject.Object):
+ sig_context = GObject.Signal(arg_types=[CairoGObject.Context])
+ sig_surface = GObject.Signal(arg_types=[CairoGObject.Surface])
+ sig_font_face = GObject.Signal(arg_types=[CairoGObject.FontFace])
+ sig_scaled_font = GObject.Signal(arg_types=[CairoGObject.ScaledFont])
+ sig_pattern = GObject.Signal(arg_types=[CairoGObject.Pattern])
+
+
+@unittest.skipUnless(has_cairo, 'built without cairo support')
+class TestSignalMarshaling(unittest.TestCase):
+ # Tests round tripping of cairo objects through non-introspected signals.
+
+ def setUp(self):
+ self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+ self.context = cairo.Context(self.surface)
+ self.tester = CairoSignalTester()
+
+ def pass_object_through_signal(self, obj, signal):
+ """Pass the given `obj` through the `signal` emission storing the
+ `obj` passed through the signal and returning it."""
+ passthrough_result = []
+
+ def callback(instance, passthrough):
+ passthrough_result.append(passthrough)
+
+ signal.connect(callback)
+ signal.emit(obj)
+
+ return passthrough_result[0]
+
+ def test_context(self):
+ result = self.pass_object_through_signal(self.context, self.tester.sig_context)
+ self.assertTrue(isinstance(result, cairo.Context))
+
+ with pytest.raises(TypeError):
+ self.pass_object_through_signal(object(), self.tester.sig_context)
+
+ def test_surface(self):
+ result = self.pass_object_through_signal(self.surface, self.tester.sig_surface)
+ self.assertTrue(isinstance(result, cairo.Surface))
+
+ def test_font_face(self):
+ font_face = self.context.get_font_face()
+ result = self.pass_object_through_signal(font_face, self.tester.sig_font_face)
+ self.assertTrue(isinstance(result, cairo.FontFace))
+
+ with pytest.raises(TypeError):
+ self.pass_object_through_signal(object(), self.tester.sig_font_face)
+
+ def test_scaled_font(self):
+ scaled_font = cairo.ScaledFont(self.context.get_font_face(),
+ cairo.Matrix(),
+ cairo.Matrix(),
+ self.context.get_font_options())
+ result = self.pass_object_through_signal(scaled_font, self.tester.sig_scaled_font)
+ self.assertTrue(isinstance(result, cairo.ScaledFont))
+
+ with pytest.raises(TypeError):
+ result = self.pass_object_through_signal(object(), self.tester.sig_scaled_font)
+
+ def test_pattern(self):
+ pattern = cairo.SolidPattern(1, 1, 1, 1)
+ result = self.pass_object_through_signal(pattern, self.tester.sig_pattern)
+ self.assertTrue(isinstance(result, cairo.Pattern))
+ self.assertTrue(isinstance(result, cairo.SolidPattern))
+
+ with pytest.raises(TypeError):
+ result = self.pass_object_through_signal(object(), self.tester.sig_pattern)
diff --git a/tests/test_docstring.py b/tests/test_docstring.py
index 1628295..527d2a1 100644
--- a/tests/test_docstring.py
+++ b/tests/test_docstring.py
@@ -1,7 +1,17 @@
import unittest
import gi.docstring
+
+from gi.repository import Regress
from gi.repository import GIMarshallingTests
+from gi.repository import Gio
+from gi.repository import GObject
+from gi.repository import GLib
+
+try:
+ from gi.repository import Gtk
+except ImportError:
+ Gtk = None
class Test(unittest.TestCase):
@@ -20,26 +30,6 @@ class Test(unittest.TestCase):
self.assertEqual(gi.docstring.get_doc_string_generator(),
old_func)
- def test_split_args_multi_out(self):
- in_args, out_args = gi.docstring.split_function_info_args(GIMarshallingTests.int_out_out)
- self.assertEqual(len(in_args), 0)
- self.assertEqual(len(out_args), 2)
- self.assertEqual(out_args[0].get_pytype_hint(), 'int')
- self.assertEqual(out_args[1].get_pytype_hint(), 'int')
-
- def test_split_args_inout(self):
- in_args, out_args = gi.docstring.split_function_info_args(GIMarshallingTests.long_inout_max_min)
- self.assertEqual(len(in_args), 1)
- self.assertEqual(len(out_args), 1)
- self.assertEqual(in_args[0].get_name(), out_args[0].get_name())
- self.assertEqual(in_args[0].get_pytype_hint(), out_args[0].get_pytype_hint())
-
- def test_split_args_none(self):
- obj = GIMarshallingTests.Object(int=33)
- in_args, out_args = gi.docstring.split_function_info_args(obj.none_inout)
- self.assertEqual(len(in_args), 1)
- self.assertEqual(len(out_args), 1)
-
def test_final_signature_with_full_inout(self):
self.assertEqual(GIMarshallingTests.Object.full_inout.__doc__,
'full_inout(object:GIMarshallingTests.Object) -> object:GIMarshallingTests.Object')
@@ -47,3 +37,102 @@ class Test(unittest.TestCase):
def test_overridden_doc_is_not_clobbered(self):
self.assertEqual(GIMarshallingTests.OverridesObject.method.__doc__,
'Overridden doc string.')
+
+ def test_allow_none_with_user_data_defaults(self):
+ g_file_copy_doc = 'copy(self, destination:Gio.File, ' \
+ 'flags:Gio.FileCopyFlags, ' \
+ 'cancellable:Gio.Cancellable=None, ' \
+ 'progress_callback:Gio.FileProgressCallback=None, ' \
+ 'progress_callback_data=None) -> bool'
+
+ self.assertEqual(Gio.File.copy.__doc__, g_file_copy_doc)
+
+ def test_array_length_arg(self):
+ self.assertEqual(GIMarshallingTests.array_in.__doc__,
+ 'array_in(ints:list)')
+
+ def test_init_function(self):
+ # This tests implicit array length args along with skipping a
+ # boolean return
+ self.assertEqual(GIMarshallingTests.init_function.__doc__,
+ 'init_function(argv:list=None) -> bool, argv:list')
+
+ def test_boolean_return(self):
+ self.assertEqual(GIMarshallingTests.boolean_return_true.__doc__,
+ 'boolean_return_true() -> bool')
+
+ @unittest.skipUnless((GLib.MAJOR_VERSION, GLib.MINOR_VERSION) >= (2, 42),
+ "nullable was added in newer glib/gi")
+ # https://bugzilla.gnome.org/show_bug.cgi?id=740301
+ def test_may_return_none(self):
+ self.assertEqual(Gio.File.get_basename.__doc__,
+ 'get_basename(self) -> str or None')
+
+ def test_class_doc_constructors(self):
+ doc = GIMarshallingTests.Object.__doc__
+ self.assertTrue('new(int_:int)' in doc)
+
+ def test_struct_doc_constructors(self):
+ doc = GIMarshallingTests.BoxedStruct.__doc__
+ self.assertTrue('new()' in doc)
+ self.assertTrue('BoxedStruct()' in doc)
+
+ def test_private_struct_constructors(self):
+ # Structs without a size or constructor should have no constructor docs.
+ doc = Regress.TestBoxedPrivate.__doc__
+ self.assertEqual(doc, '')
+
+ def test_array_inout_etc(self):
+ self.assertEqual(GIMarshallingTests.array_inout_etc.__doc__,
+ 'array_inout_etc(first:int, ints:list, last:int) -> ints:list, sum:int')
+
+ def test_array_out_etc(self):
+ self.assertEqual(GIMarshallingTests.array_out_etc.__doc__,
+ 'array_out_etc(first:int, last:int) -> ints:list, sum:int')
+
+ @unittest.skipUnless(Gtk, 'no Gtk')
+ def test_shared_array_length_with_prior_out_arg(self):
+ # Test the 'iter' out argument does not effect length argument skipping.
+ self.assertRegex(
+ Gtk.ListStore.insert_with_valuesv.__doc__,
+ 'insert_with_values.*\\(self, position:int, columns:list, values:list\\) -> iter:Gtk.TreeIter')
+
+ def test_sub_class_doc(self):
+ class A(GObject.Object):
+ """first doc"""
+ pass
+
+ class B(A):
+ """second doc"""
+ pass
+
+ self.assertEqual(A.__doc__, "first doc")
+ self.assertEqual(B.__doc__, "second doc")
+
+ def test_sub_class_no_doc(self):
+ class A(GObject.Object):
+ pass
+
+ class B(A):
+ """sub-class doc"""
+
+ self.assertEqual(A.__doc__, None)
+ self.assertEqual(B.__doc__, "sub-class doc")
+
+ @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=734926
+ def test_sub_class_doc_setattr(self):
+ class A(GObject.Object):
+ pass
+
+ class B(A):
+ pass
+
+ A.__doc__ = 'custom doc'
+
+ self.assertEqual(A.__doc__, "custom doc")
+ self.assertEqual(B.__doc__, "custom doc")
+
+ def test_return_array_with_length_argument(self):
+ self.assertEqual(
+ GIMarshallingTests.enum_array_return_type.__doc__,
+ "enum_array_return_type() -> list")
diff --git a/tests/test_error.py b/tests/test_error.py
new file mode 100644
index 0000000..6bcad38
--- /dev/null
+++ b/tests/test_error.py
@@ -0,0 +1,157 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# test_error.py: Tests for GError wrapper implementation
+#
+# Copyright (C) 2012 Will Thompson
+# Copyright (C) 2013 Martin Pitt
+# Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+import unittest
+import pickle
+
+from gi.repository import GLib
+from gi.repository import GIMarshallingTests
+
+
+class TestType(unittest.TestCase):
+ def test_attributes(self):
+ e = GLib.Error('test message', 'mydomain', 42)
+ self.assertEqual(e.message, 'test message')
+ self.assertEqual(e.domain, 'mydomain')
+ self.assertEqual(e.code, 42)
+
+ def test_new_literal(self):
+ mydomain = GLib.quark_from_string('mydomain')
+ e = GLib.Error.new_literal(mydomain, 'test message', 42)
+ self.assertEqual(e.message, 'test message')
+ self.assertEqual(e.domain, 'mydomain')
+ self.assertEqual(e.code, 42)
+
+ def test_matches(self):
+ mydomain = GLib.quark_from_string('mydomain')
+ notmydomain = GLib.quark_from_string('notmydomain')
+ e = GLib.Error('test message', 'mydomain', 42)
+ self.assertTrue(e.matches(mydomain, 42))
+ self.assertFalse(e.matches(notmydomain, 42))
+ self.assertFalse(e.matches(mydomain, 40))
+
+ def test_str(self):
+ e = GLib.Error('test message', 'mydomain', 42)
+ self.assertEqual(str(e),
+ 'mydomain: test message (42)')
+
+ def test_repr(self):
+ e = GLib.Error('test message', 'mydomain', 42)
+ self.assertEqual(repr(e),
+ "GLib.Error('test message', 'mydomain', 42)")
+
+ def test_inheritance(self):
+ self.assertTrue(issubclass(GLib.Error, RuntimeError))
+
+ def test_pickle(self):
+
+ def check_pickle(e):
+ assert isinstance(e, GLib.Error)
+ new_e = pickle.loads(pickle.dumps(e))
+ assert type(new_e) is type(e)
+ assert repr(e) == repr(new_e)
+
+ e = GLib.Error('test message', 'mydomain', 42)
+ check_pickle(e)
+
+ try:
+ GLib.file_get_contents("")
+ except Exception as e:
+ check_pickle(e)
+
+
+class ObjectWithVFuncException(GIMarshallingTests.Object):
+ def do_vfunc_meth_with_err(self, x):
+ if x == 42:
+ return True
+
+ raise GLib.Error('unexpected value %d' % x, 'mydomain', 42)
+
+
+class TestMarshalling(unittest.TestCase):
+ def test_array_in_crash(self):
+ # Previously there was a bug in invoke, in which C arrays were unwrapped
+ # from inside GArrays to be passed to the C function. But when a GError was
+ # set, invoke would attempt to free the C array as if it were a GArray.
+ # This crash is only for C arrays. It does not happen for C functions which
+ # take in GArrays. See https://bugzilla.gnome.org/show_bug.cgi?id=642708
+ self.assertRaises(GLib.Error, GIMarshallingTests.gerror_array_in, [1, 2, 3])
+
+ def test_out(self):
+ # See https://bugzilla.gnome.org/show_bug.cgi?id=666098
+ error, debug = GIMarshallingTests.gerror_out()
+
+ self.assertIsInstance(error, GLib.Error)
+ self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
+ self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
+ self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
+ self.assertEqual(debug, GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE)
+
+ def test_out_transfer_none(self):
+ # See https://bugzilla.gnome.org/show_bug.cgi?id=666098
+ error, debug = GIMarshallingTests.gerror_out_transfer_none()
+
+ self.assertIsInstance(error, GLib.Error)
+ self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
+ self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
+ self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
+ self.assertEqual(GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE, debug)
+
+ def test_return(self):
+ # See https://bugzilla.gnome.org/show_bug.cgi?id=666098
+ error = GIMarshallingTests.gerror_return()
+
+ self.assertIsInstance(error, GLib.Error)
+ self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
+ self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
+ self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
+
+ def test_exception(self):
+ with self.assertRaises(GLib.Error) as context:
+ GIMarshallingTests.gerror()
+
+ e = context.exception
+ self.assertEqual(e.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
+ self.assertEqual(e.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
+ self.assertEqual(e.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
+
+ def test_vfunc_no_exception(self):
+ obj = ObjectWithVFuncException()
+ self.assertTrue(obj.vfunc_meth_with_error(42))
+
+ def test_vfunc_gerror_exception(self):
+ obj = ObjectWithVFuncException()
+ with self.assertRaises(GLib.Error) as context:
+ obj.vfunc_meth_with_error(-1)
+
+ e = context.exception
+ self.assertEqual(e.message, 'unexpected value -1')
+ self.assertEqual(e.domain, 'mydomain')
+ self.assertEqual(e.code, 42)
+
+ def tests_compare_two_gerrors_in_gvalue(self):
+ error = GLib.Error.new_literal(1, "error", 1)
+ error1 = GLib.Error.new_literal(1, "error", 1)
+
+ GIMarshallingTests.compare_two_gerrors_in_gvalue(error, error1)
diff --git a/tests/test_everything.py b/tests/test_everything.py
index b2f0528..0eaa522 100644
--- a/tests/test_everything.py
+++ b/tests/test_everything.py
@@ -1,5 +1,4 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
-# coding=utf-8
# vim: tabstop=4 shiftwidth=4 expandtab
import unittest
@@ -7,15 +6,16 @@ import traceback
import ctypes
import warnings
import sys
+import os
+import re
+import platform
+import gc
+import timeit
+import random
-try:
- import cairo
- has_cairo = True
- from gi.repository import Regress as Everything
-except ImportError:
- has_cairo = False
+import pytest
-#import gi
+from gi.repository import Regress as Everything
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gio
@@ -26,11 +26,11 @@ try:
except:
Gtk = None
-if sys.version_info < (3, 0):
- UNICHAR = "\xe2\x99\xa5"
- PY2_UNICODE_UNICHAR = unicode(UNICHAR, 'UTF-8')
-else:
- UNICHAR = "♥"
+from .helper import capture_exceptions
+
+
+const_str = b'const \xe2\x99\xa5 utf8'.decode('UTF-8')
+noconst_str = 'non' + const_str
class RawGList(ctypes.Structure):
@@ -44,41 +44,15 @@ class RawGList(ctypes.Structure):
return ctypes.POINTER(cls).from_address(id(obj) + offset)
-@unittest.skipUnless(has_cairo, 'built without cairo support')
-class TestEverything(unittest.TestCase):
+class TestInstanceTransfer(unittest.TestCase):
+
+ def test_main(self):
+ obj = Everything.TestObj()
+ for _ in range(10):
+ obj.instance_method_full()
+
- def test_cairo_context(self):
- context = Everything.test_cairo_context_full_return()
- self.assertTrue(isinstance(context, cairo.Context))
-
- surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
- context = cairo.Context(surface)
- Everything.test_cairo_context_none_in(context)
-
- def test_cairo_surface(self):
- surface = Everything.test_cairo_surface_none_return()
- self.assertTrue(isinstance(surface, cairo.ImageSurface))
- self.assertTrue(isinstance(surface, cairo.Surface))
- self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32)
- self.assertEqual(surface.get_width(), 10)
- self.assertEqual(surface.get_height(), 10)
-
- surface = Everything.test_cairo_surface_full_return()
- self.assertTrue(isinstance(surface, cairo.ImageSurface))
- self.assertTrue(isinstance(surface, cairo.Surface))
- self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32)
- self.assertEqual(surface.get_width(), 10)
- self.assertEqual(surface.get_height(), 10)
-
- surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
- Everything.test_cairo_surface_none_in(surface)
-
- surface = Everything.test_cairo_surface_full_out()
- self.assertTrue(isinstance(surface, cairo.ImageSurface))
- self.assertTrue(isinstance(surface, cairo.Surface))
- self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32)
- self.assertEqual(surface.get_width(), 10)
- self.assertEqual(surface.get_height(), 10)
+class TestEverything(unittest.TestCase):
def test_bool(self):
self.assertEqual(Everything.test_boolean(False), False)
@@ -90,142 +64,334 @@ class TestEverything(unittest.TestCase):
self.assertEqual(Everything.test_boolean_false(False), False)
def test_int8(self):
- self.assertEqual(Everything.test_int8(GObject.G_MAXINT8),
- GObject.G_MAXINT8)
- self.assertEqual(Everything.test_int8(GObject.G_MININT8),
- GObject.G_MININT8)
- self.assertRaises(OverflowError, Everything.test_int8, GObject.G_MAXINT8 + 1)
-
- self.assertEqual(Everything.test_uint8(GObject.G_MAXUINT8),
- GObject.G_MAXUINT8)
+ self.assertEqual(Everything.test_int8(GLib.MAXINT8),
+ GLib.MAXINT8)
+ self.assertEqual(Everything.test_int8(GLib.MININT8),
+ GLib.MININT8)
+ self.assertRaises(OverflowError, Everything.test_int8, GLib.MAXINT8 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXINT8 + 1, GLib.MININT8, GLib.MAXINT8)):
+ Everything.test_int8(GLib.MAXINT8 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MININT8, GLib.MAXINT8)):
+ Everything.test_int8(GLib.MAXUINT64 * 2)
+
+ def test_uint8(self):
+ self.assertEqual(Everything.test_uint8(GLib.MAXUINT8),
+ GLib.MAXUINT8)
self.assertEqual(Everything.test_uint8(0), 0)
self.assertRaises(OverflowError, Everything.test_uint8, -1)
- self.assertRaises(OverflowError, Everything.test_uint8, GObject.G_MAXUINT8 + 1)
+ self.assertRaises(OverflowError, Everything.test_uint8, GLib.MAXUINT8 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT8 + 1, GLib.MAXUINT8)):
+ Everything.test_uint8(GLib.MAXUINT8 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MAXUINT8)):
+ Everything.test_uint8(GLib.MAXUINT64 * 2)
def test_int16(self):
- self.assertEqual(Everything.test_int16(GObject.G_MAXINT16),
- GObject.G_MAXINT16)
- self.assertEqual(Everything.test_int16(GObject.G_MININT16),
- GObject.G_MININT16)
- self.assertRaises(OverflowError, Everything.test_int16, GObject.G_MAXINT16 + 1)
-
- self.assertEqual(Everything.test_uint16(GObject.G_MAXUINT16),
- GObject.G_MAXUINT16)
+ self.assertEqual(Everything.test_int16(GLib.MAXINT16),
+ GLib.MAXINT16)
+ self.assertEqual(Everything.test_int16(GLib.MININT16),
+ GLib.MININT16)
+
+ with pytest.raises(
+ OverflowError,
+ match="32768 not in range -32768 to 32767"):
+ Everything.test_int16(GLib.MAXINT16 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="36893488147419103230 not in range -32768 to 32767"):
+ Everything.test_int16(GLib.MAXUINT64 * 2)
+
+ def test_uint16(self):
+ self.assertEqual(Everything.test_uint16(GLib.MAXUINT16),
+ GLib.MAXUINT16)
self.assertEqual(Everything.test_uint16(0), 0)
self.assertRaises(OverflowError, Everything.test_uint16, -1)
- self.assertRaises(OverflowError, Everything.test_uint16, GObject.G_MAXUINT16 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT16 + 1, GLib.MAXUINT16)):
+ Everything.test_uint16(GLib.MAXUINT16 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MAXUINT16)):
+ Everything.test_uint16(GLib.MAXUINT64 * 2)
def test_int32(self):
- self.assertEqual(Everything.test_int32(GObject.G_MAXINT32),
- GObject.G_MAXINT32)
- self.assertEqual(Everything.test_int32(GObject.G_MININT32),
- GObject.G_MININT32)
- self.assertRaises(OverflowError, Everything.test_int32, GObject.G_MAXINT32 + 1)
-
- self.assertEqual(Everything.test_uint32(GObject.G_MAXUINT32),
- GObject.G_MAXUINT32)
+ self.assertEqual(Everything.test_int32(GLib.MAXINT32),
+ GLib.MAXINT32)
+ self.assertEqual(Everything.test_int32(GLib.MININT32),
+ GLib.MININT32)
+
+ with pytest.raises(
+ OverflowError,
+ match="2147483648 not in range -2147483648 to 2147483647"):
+ Everything.test_int32(GLib.MAXINT32 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range -2147483648 to 2147483647" % (
+ GLib.MAXINT64 + 1,)):
+ Everything.test_int32(GLib.MAXINT64 + 1)
+
+ def test_uint32(self):
+ self.assertEqual(Everything.test_uint32(GLib.MAXUINT32),
+ GLib.MAXUINT32)
self.assertEqual(Everything.test_uint32(0), 0)
self.assertRaises(OverflowError, Everything.test_uint32, -1)
- self.assertRaises(OverflowError, Everything.test_uint32, GObject.G_MAXUINT32 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT32 + 1, GLib.MAXUINT32)):
+ Everything.test_uint32(GLib.MAXUINT32 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MAXUINT32)):
+ Everything.test_uint32(GLib.MAXUINT64 * 2)
def test_int64(self):
- self.assertEqual(Everything.test_int64(GObject.G_MAXINT64),
- GObject.G_MAXINT64)
- self.assertEqual(Everything.test_int64(GObject.G_MININT64),
- GObject.G_MININT64)
- self.assertRaises(OverflowError, Everything.test_int64, GObject.G_MAXINT64 + 1)
-
- self.assertEqual(Everything.test_uint64(GObject.G_MAXUINT64),
- GObject.G_MAXUINT64)
+ self.assertEqual(Everything.test_int64(GLib.MAXINT64),
+ GLib.MAXINT64)
+ self.assertEqual(Everything.test_int64(GLib.MININT64),
+ GLib.MININT64)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXINT64 + 1, GLib.MININT64, GLib.MAXINT64)):
+ Everything.test_int64(GLib.MAXINT64 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MININT64, GLib.MAXINT64)):
+ Everything.test_int64(GLib.MAXUINT64 * 2)
+
+ def test_uint64(self):
+ self.assertEqual(Everything.test_uint64(GLib.MAXUINT64),
+ GLib.MAXUINT64)
self.assertEqual(Everything.test_uint64(0), 0)
self.assertRaises(OverflowError, Everything.test_uint64, -1)
- self.assertRaises(OverflowError, Everything.test_uint64, GObject.G_MAXUINT64 + 1)
+ self.assertRaises(OverflowError, Everything.test_uint64, GLib.MAXUINT64 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT64 + 1, GLib.MAXUINT64)):
+ Everything.test_uint64(GLib.MAXUINT64 + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MAXUINT64)):
+ Everything.test_uint64(GLib.MAXUINT64 * 2)
def test_int(self):
- self.assertEqual(Everything.test_int(GObject.G_MAXINT),
- GObject.G_MAXINT)
- self.assertEqual(Everything.test_int(GObject.G_MININT),
- GObject.G_MININT)
- self.assertRaises(OverflowError, Everything.test_int, GObject.G_MAXINT + 1)
-
- self.assertEqual(Everything.test_uint(GObject.G_MAXUINT),
- GObject.G_MAXUINT)
+ self.assertEqual(Everything.test_int(GLib.MAXINT),
+ GLib.MAXINT)
+ self.assertEqual(Everything.test_int(GLib.MININT),
+ GLib.MININT)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXINT + 1, GLib.MININT, GLib.MAXINT)):
+ Everything.test_int(GLib.MAXINT + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MININT, GLib.MAXINT)):
+ Everything.test_int(GLib.MAXUINT64 * 2)
+
+ def test_uint(self):
+ self.assertEqual(Everything.test_uint(GLib.MAXUINT),
+ GLib.MAXUINT)
self.assertEqual(Everything.test_uint(0), 0)
self.assertRaises(OverflowError, Everything.test_uint, -1)
- self.assertRaises(OverflowError, Everything.test_uint, GObject.G_MAXUINT + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT + 1, GLib.MAXUINT)):
+ Everything.test_uint(GLib.MAXUINT + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MAXUINT)):
+ Everything.test_uint(GLib.MAXUINT64 * 2)
def test_short(self):
- self.assertEqual(Everything.test_short(GObject.G_MAXSHORT),
- GObject.G_MAXSHORT)
- self.assertEqual(Everything.test_short(GObject.G_MINSHORT),
- GObject.G_MINSHORT)
- self.assertRaises(OverflowError, Everything.test_short, GObject.G_MAXSHORT + 1)
-
- self.assertEqual(Everything.test_ushort(GObject.G_MAXUSHORT),
- GObject.G_MAXUSHORT)
+ self.assertEqual(Everything.test_short(GLib.MAXSHORT),
+ GLib.MAXSHORT)
+ self.assertEqual(Everything.test_short(GLib.MINSHORT),
+ GLib.MINSHORT)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXSHORT + 1, GLib.MINSHORT, GLib.MAXSHORT)):
+ Everything.test_short(GLib.MAXSHORT + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MINSHORT, GLib.MAXSHORT)):
+ Everything.test_short(GLib.MAXUINT64 * 2)
+
+ def test_ushort(self):
+ self.assertEqual(Everything.test_ushort(GLib.MAXUSHORT),
+ GLib.MAXUSHORT)
self.assertEqual(Everything.test_ushort(0), 0)
self.assertRaises(OverflowError, Everything.test_ushort, -1)
- self.assertRaises(OverflowError, Everything.test_ushort, GObject.G_MAXUSHORT + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUSHORT + 1, GLib.MAXUSHORT)):
+ Everything.test_ushort(GLib.MAXUSHORT + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MAXUSHORT)):
+ Everything.test_ushort(GLib.MAXUINT64 * 2)
def test_long(self):
- self.assertEqual(Everything.test_long(GObject.G_MAXLONG),
- GObject.G_MAXLONG)
- self.assertEqual(Everything.test_long(GObject.G_MINLONG),
- GObject.G_MINLONG)
- self.assertRaises(OverflowError, Everything.test_long, GObject.G_MAXLONG + 1)
-
- self.assertEqual(Everything.test_ulong(GObject.G_MAXULONG),
- GObject.G_MAXULONG)
+ self.assertEqual(Everything.test_long(GLib.MAXLONG),
+ GLib.MAXLONG)
+ self.assertEqual(Everything.test_long(GLib.MINLONG),
+ GLib.MINLONG)
+ self.assertRaises(OverflowError, Everything.test_long, GLib.MAXLONG + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXLONG + 1, GLib.MINLONG, GLib.MAXLONG)):
+ Everything.test_long(GLib.MAXLONG + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MINLONG, GLib.MAXLONG)):
+ Everything.test_long(GLib.MAXUINT64 * 2)
+
+ def test_ulong(self):
+ self.assertEqual(Everything.test_ulong(GLib.MAXULONG),
+ GLib.MAXULONG)
self.assertEqual(Everything.test_ulong(0), 0)
self.assertRaises(OverflowError, Everything.test_ulong, -1)
- self.assertRaises(OverflowError, Everything.test_ulong, GObject.G_MAXULONG + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXULONG + 1, GLib.MAXULONG)):
+ Everything.test_ulong(GLib.MAXULONG + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MAXULONG)):
+ Everything.test_ulong(GLib.MAXUINT64 * 2)
+
+ def test_ssize(self):
+ self.assertEqual(Everything.test_ssize(GLib.MAXSSIZE),
+ GLib.MAXSSIZE)
+ self.assertEqual(Everything.test_ssize(GLib.MINSSIZE),
+ GLib.MINSSIZE)
+ self.assertRaises(OverflowError, Everything.test_ssize, GLib.MAXSSIZE + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXSSIZE + 1, GLib.MINSSIZE, GLib.MAXSSIZE)):
+ Everything.test_ssize(GLib.MAXSSIZE + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range %s to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MINSSIZE, GLib.MAXSSIZE)):
+ Everything.test_ssize(GLib.MAXUINT64 * 2)
def test_size(self):
- self.assertEqual(Everything.test_ssize(GObject.G_MAXSSIZE),
- GObject.G_MAXSSIZE)
- self.assertEqual(Everything.test_ssize(GObject.G_MINSSIZE),
- GObject.G_MINSSIZE)
- self.assertRaises(OverflowError, Everything.test_ssize, GObject.G_MAXSSIZE + 1)
-
- self.assertEqual(Everything.test_size(GObject.G_MAXSIZE),
- GObject.G_MAXSIZE)
+ self.assertEqual(Everything.test_size(GLib.MAXSIZE),
+ GLib.MAXSIZE)
self.assertEqual(Everything.test_size(0), 0)
self.assertRaises(OverflowError, Everything.test_size, -1)
- self.assertRaises(OverflowError, Everything.test_size, GObject.G_MAXSIZE + 1)
+ self.assertRaises(OverflowError, Everything.test_size, GLib.MAXSIZE + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXSIZE + 1, GLib.MAXSIZE)):
+ Everything.test_size(GLib.MAXSIZE + 1)
+
+ with pytest.raises(
+ OverflowError,
+ match="%s not in range 0 to %s" % (
+ GLib.MAXUINT64 * 2, GLib.MAXSIZE)):
+ Everything.test_size(GLib.MAXUINT64 * 2)
def test_timet(self):
self.assertEqual(Everything.test_timet(42), 42)
- self.assertRaises(OverflowError, Everything.test_timet, GObject.G_MAXUINT64 + 1)
+ self.assertRaises(OverflowError, Everything.test_timet, GLib.MAXUINT64 + 1)
def test_unichar(self):
self.assertEqual("c", Everything.test_unichar("c"))
+ self.assertEqual(chr(sys.maxunicode), Everything.test_unichar(chr(sys.maxunicode)))
- if sys.version_info < (3, 0):
- self.assertEqual(UNICHAR, Everything.test_unichar(PY2_UNICODE_UNICHAR))
- self.assertEqual(UNICHAR, Everything.test_unichar(UNICHAR))
+ self.assertEqual(u"♥", Everything.test_unichar(u"♥"))
self.assertRaises(TypeError, Everything.test_unichar, "")
self.assertRaises(TypeError, Everything.test_unichar, "morethanonechar")
def test_float(self):
- self.assertEqual(Everything.test_float(GObject.G_MAXFLOAT),
- GObject.G_MAXFLOAT)
- self.assertEqual(Everything.test_float(GObject.G_MINFLOAT),
- GObject.G_MINFLOAT)
- self.assertRaises(OverflowError, Everything.test_float, GObject.G_MAXFLOAT * 2)
+ self.assertEqual(Everything.test_float(GLib.MAXFLOAT),
+ GLib.MAXFLOAT)
+ self.assertEqual(Everything.test_float(GLib.MINFLOAT),
+ GLib.MINFLOAT)
+ self.assertRaises(OverflowError, Everything.test_float, GLib.MAXFLOAT * 2)
+
+ with pytest.raises(
+ OverflowError,
+ match=re.escape("%s not in range %s to %s" % (
+ GLib.MAXFLOAT * 2, -GLib.MAXFLOAT, GLib.MAXFLOAT))):
+ Everything.test_float(GLib.MAXFLOAT * 2)
def test_double(self):
- self.assertEqual(Everything.test_double(GObject.G_MAXDOUBLE),
- GObject.G_MAXDOUBLE)
- self.assertEqual(Everything.test_double(GObject.G_MINDOUBLE),
- GObject.G_MINDOUBLE)
+ self.assertEqual(Everything.test_double(GLib.MAXDOUBLE),
+ GLib.MAXDOUBLE)
+ self.assertEqual(Everything.test_double(GLib.MINDOUBLE),
+ GLib.MINDOUBLE)
(two, three) = Everything.test_multi_double_args(2.5)
self.assertAlmostEqual(two, 5.0)
self.assertAlmostEqual(three, 7.5)
def test_value(self):
- self.assertEqual(Everything.test_int_value_arg(GObject.G_MAXINT), GObject.G_MAXINT)
- self.assertEqual(Everything.test_value_return(GObject.G_MAXINT), GObject.G_MAXINT)
+ self.assertEqual(Everything.test_int_value_arg(GLib.MAXINT), GLib.MAXINT)
+ self.assertEqual(Everything.test_value_return(GLib.MAXINT), GLib.MAXINT)
def test_variant(self):
v = Everything.test_gvariant_i()
@@ -254,27 +420,38 @@ class TestEverything(unittest.TestCase):
timeout = v.lookup_value('timeout', None)
self.assertEqual(timeout.get_int32(), 10)
- def test_string(self):
- const_str = b'const \xe2\x99\xa5 utf8'
- if sys.version_info >= (3, 0):
- const_str = const_str.decode('UTF-8')
- noconst_str = 'non' + const_str
-
+ def test_utf8_const_return(self):
self.assertEqual(Everything.test_utf8_const_return(), const_str)
+
+ def test_utf8_nonconst_return(self):
self.assertEqual(Everything.test_utf8_nonconst_return(), noconst_str)
+
+ def test_utf8_out(self):
self.assertEqual(Everything.test_utf8_out(), noconst_str)
+ def test_utf8_const_in(self):
Everything.test_utf8_const_in(const_str)
+
+ def test_utf8_inout(self):
self.assertEqual(Everything.test_utf8_inout(const_str), noconst_str)
- self.assertEqual(Everything.test_filename_return(), ['åäö', '/etc/fstab'])
+ def test_filename_return(self):
+ if os.name != "nt":
+ result = [os.fsdecode(b'\xc3\xa5\xc3\xa4\xc3\xb6'), '/etc/fstab']
+ else:
+ result = ['åäö', '/etc/fstab']
+ self.assertEqual(Everything.test_filename_return(), result)
+ def test_int_out_utf8(self):
# returns g_utf8_strlen() in out argument
self.assertEqual(Everything.test_int_out_utf8(''), 0)
self.assertEqual(Everything.test_int_out_utf8('hello world'), 11)
self.assertEqual(Everything.test_int_out_utf8('åäö'), 3)
+ def test_utf8_out_out(self):
self.assertEqual(Everything.test_utf8_out_out(), ('first', 'second'))
+
+ def test_utf8_out_nonconst_return(self):
self.assertEqual(Everything.test_utf8_out_nonconst_return(), ('first', 'second'))
def test_enum(self):
@@ -342,7 +519,7 @@ class TestEverything(unittest.TestCase):
Everything.test_int8()
except TypeError:
(e_type, e) = sys.exc_info()[:2]
- self.assertEqual(e.args, ("test_int8() takes exactly 1 argument (0 given)",))
+ self.assertEqual(e.args, ("Regress.test_int8() takes exactly 1 argument (0 given)",))
def test_gtypes(self):
gchararray_gtype = GObject.type_from_name('gchararray')
@@ -389,53 +566,87 @@ class TestEverything(unittest.TestCase):
# test that there are no duplicates returned
self.assertEqual(len(attr_list), len(set(attr_list)))
- def test_array(self):
+ def test_array_int_in_empty(self):
self.assertEqual(Everything.test_array_int_in([]), 0)
+
+ def test_array_int_in(self):
self.assertEqual(Everything.test_array_int_in([1, 5, -2]), 4)
+
+ def test_array_int_out(self):
self.assertEqual(Everything.test_array_int_out(), [0, 1, 2, 3, 4])
+
+ def test_array_int_full_out(self):
self.assertEqual(Everything.test_array_int_full_out(), [0, 1, 2, 3, 4])
+
+ def test_array_int_none_out(self):
self.assertEqual(Everything.test_array_int_none_out(), [1, 2, 3, 4, 5])
+
+ def test_array_int_inout(self):
self.assertEqual(Everything.test_array_int_inout([1, 5, 42, -8]), [6, 43, -7])
- if sys.version_info >= (3, 0):
- self.assertEqual(Everything.test_array_gint8_in(b'\x01\x03\x05'), 9)
+ def test_array_int_inout_empty(self):
+ self.assertEqual(Everything.test_array_int_inout([]), [])
+
+ def test_array_gint8_in(self):
+ self.assertEqual(Everything.test_array_gint8_in(b'\x01\x03\x05'), 9)
self.assertEqual(Everything.test_array_gint8_in([1, 3, 5, -50]), -41)
+
+ def test_array_gint16_in(self):
self.assertEqual(Everything.test_array_gint16_in([256, 257, -1000, 10000]), 9513)
+
+ def test_array_gint32_in(self):
self.assertEqual(Everything.test_array_gint32_in([30000, 1, -2]), 29999)
+
+ def test_array_gint64_in(self):
self.assertEqual(Everything.test_array_gint64_in([2 ** 33, 2 ** 34]), 2 ** 33 + 2 ** 34)
+ def test_array_gtype_in(self):
self.assertEqual(Everything.test_array_gtype_in(
[GObject.TYPE_STRING, GObject.TYPE_UINT64, GObject.TYPE_VARIANT]),
'[gchararray,guint64,GVariant,]')
- def test_array_fixed_size(self):
+ def test_array_fixed_size_int_in(self):
# fixed length of 5
self.assertEqual(Everything.test_array_fixed_size_int_in([1, 2, -10, 5, 3]), 1)
+
+ def test_array_fixed_size_int_in_error(self):
self.assertRaises(ValueError, Everything.test_array_fixed_size_int_in, [1, 2, 3, 4])
self.assertRaises(ValueError, Everything.test_array_fixed_size_int_in, [1, 2, 3, 4, 5, 6])
+ def test_array_fixed_size_int_out(self):
self.assertEqual(Everything.test_array_fixed_size_int_out(), [0, 1, 2, 3, 4])
+
+ def test_array_fixed_size_int_return(self):
self.assertEqual(Everything.test_array_fixed_size_int_return(), [0, 1, 2, 3, 4])
- def test_ptrarray(self):
- # transfer container
+ def test_garray_container_return(self):
+ # GPtrArray transfer container
result = Everything.test_garray_container_return()
self.assertEqual(result, ['regress'])
result = None
- # transfer full
+ def test_garray_full_return(self):
+ # GPtrArray transfer full
result = Everything.test_garray_full_return()
self.assertEqual(result, ['regress'])
result = None
- def test_strv(self):
+ def test_strv_out(self):
self.assertEqual(Everything.test_strv_out(), ['thanks', 'for', 'all', 'the', 'fish'])
+
+ def test_strv_out_c(self):
self.assertEqual(Everything.test_strv_out_c(), ['thanks', 'for', 'all', 'the', 'fish'])
+
+ def test_strv_out_container(self):
self.assertEqual(Everything.test_strv_out_container(), ['1', '2', '3'])
+
+ def test_strv_outarg(self):
self.assertEqual(Everything.test_strv_outarg(), ['1', '2', '3'])
+ def test_strv_in_gvalue(self):
self.assertEqual(Everything.test_strv_in_gvalue(), ['one', 'two', 'three'])
+ def test_strv_in(self):
Everything.test_strv_in(['1', '2', '3'])
def test_glist(self):
@@ -447,6 +658,12 @@ class TestEverything(unittest.TestCase):
Everything.test_glist_nothing_in(['1', '2', '3'])
Everything.test_glist_nothing_in2(['1', '2', '3'])
+ @unittest.skipUnless(hasattr(Everything, 'test_glist_gtype_container_in'),
+ 'Requires newer version of GI')
+ def test_glist_gtype(self):
+ Everything.test_glist_gtype_container_in(
+ [Everything.TestObj, Everything.TestSubObj])
+
def test_gslist(self):
self.assertEqual(Everything.test_gslist_nothing_return(), ['1', '2', '3'])
self.assertEqual(Everything.test_gslist_nothing_return2(), ['1', '2', '3'])
@@ -510,6 +727,7 @@ class TestEverything(unittest.TestCase):
Everything.test_ghash_gvalue_in(data)
data = None
+ @unittest.skipIf(platform.python_implementation() == "PyPy", "CPython only")
def test_struct_gpointer(self):
glist = GLib.List()
raw = RawGList.from_wrapped(glist)
@@ -540,13 +758,11 @@ class TestEverything(unittest.TestCase):
(e_type, e_value, e_tb) = sys.exc_info()
self.assertEqual(e_type, TypeError)
self.assertTrue('TestBoxedPrivate' in str(e_value), str(e_value))
- self.assertTrue('override' in str(e_value), str(e_value))
self.assertTrue('constructor' in str(e_value), str(e_value))
tb = ''.join(traceback.format_exception(e_type, e_value, e_tb))
- self.assertTrue('tests/test_everything.py", line' in tb, tb)
+ self.assertTrue('test_everything.py", line' in tb, tb)
-@unittest.skipUnless(has_cairo, 'built without cairo support')
class TestNullableArgs(unittest.TestCase):
def test_in_nullable_hash(self):
Everything.test_ghash_null_in(None)
@@ -584,7 +800,6 @@ class TestNullableArgs(unittest.TestCase):
self.assertEqual(None, Everything.TestObj.null_out())
-@unittest.skipUnless(has_cairo, 'built without cairo support')
class TestCallbacks(unittest.TestCase):
called = False
main_loop = GLib.MainLoop()
@@ -610,7 +825,10 @@ class TestCallbacks(unittest.TestCase):
# note that we do NOT expect the ZeroDivisionError to be propagated
# through from the callback, as it crosses the Python<->C boundary
# twice. (See GNOME #616279)
- Everything.test_simple_callback(callback)
+ with capture_exceptions() as exc:
+ Everything.test_simple_callback(callback)
+ self.assertTrue(exc)
+ self.assertEqual(exc[0].type, ZeroDivisionError)
def test_double_callback_exception(self):
"""
@@ -629,7 +847,10 @@ class TestCallbacks(unittest.TestCase):
# note that we do NOT expect the ZeroDivisionError to be propagated
# through from the callback, as it crosses the Python<->C boundary
# twice. (See GNOME #616279)
- Everything.test_simple_callback(callback)
+ with capture_exceptions() as exc:
+ Everything.test_simple_callback(callback)
+ self.assertTrue(exc)
+ self.assertEqual(exc[0].type, ZeroDivisionError)
def test_return_value_callback(self):
TestCallbacks.called = False
@@ -650,14 +871,17 @@ class TestCallbacks(unittest.TestCase):
TestCallbacks.called = True
return 44
- ud_refcount = sys.getrefcount(ud)
- callback_refcount = sys.getrefcount(callback)
+ if hasattr(sys, "getrefcount"):
+ ud_refcount = sys.getrefcount(ud)
+ callback_refcount = sys.getrefcount(callback)
self.assertEqual(Everything.test_callback_async(callback, ud), None)
# Callback should not have run and the ref count is increased by 1
self.assertEqual(TestCallbacks.called, False)
- self.assertEqual(sys.getrefcount(callback), callback_refcount + 1)
- self.assertEqual(sys.getrefcount(ud), ud_refcount + 1)
+
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(callback), callback_refcount + 1)
+ self.assertEqual(sys.getrefcount(ud), ud_refcount + 1)
# test_callback_thaw_async will run the callback previously supplied.
# references should be auto decremented after this call.
@@ -665,8 +889,9 @@ class TestCallbacks(unittest.TestCase):
self.assertTrue(TestCallbacks.called)
# Make sure refcounts are returned to normal
- self.assertEqual(sys.getrefcount(callback), callback_refcount)
- self.assertEqual(sys.getrefcount(ud), ud_refcount)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(callback), callback_refcount)
+ self.assertEqual(sys.getrefcount(ud), ud_refcount)
def test_callback_scope_call_multi(self):
# This tests a callback that gets called multiple times from a
@@ -677,12 +902,15 @@ class TestCallbacks(unittest.TestCase):
TestCallbacks.called += 1
return TestCallbacks.called
- refcount = sys.getrefcount(callback)
+ if hasattr(sys, "getrefcount"):
+ refcount = sys.getrefcount(callback)
result = Everything.test_multi_callback(callback)
# first callback should give 1, second 2, and the function sums them up
self.assertEqual(result, 3)
self.assertEqual(TestCallbacks.called, 2)
- self.assertEqual(sys.getrefcount(callback), refcount)
+
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(callback), refcount)
def test_callback_scope_call_array(self):
# This tests a callback that gets called multiple times from a
@@ -695,13 +923,37 @@ class TestCallbacks(unittest.TestCase):
TestCallbacks.callargs.append((one, two))
return len(TestCallbacks.callargs)
- refcount = sys.getrefcount(callback)
+ if hasattr(sys, "getrefcount"):
+ refcount = sys.getrefcount(callback)
result = Everything.test_array_callback(callback)
# first callback should give 1, second 2, and the function sums them up
self.assertEqual(result, 3)
self.assertEqual(TestCallbacks.callargs,
[([-1, 0, 1, 2], ['one', 'two', 'three'])] * 2)
- self.assertEqual(sys.getrefcount(callback), refcount)
+
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(callback), refcount)
+
+ @unittest.skipUnless(hasattr(Everything, 'test_array_inout_callback'),
+ 'Requires newer version of GI')
+ def test_callback_scope_call_array_inout(self):
+ # This tests a callback that gets called multiple times from a
+ # single scope call in python with inout array arguments
+ TestCallbacks.callargs = []
+
+ def callback(ints, ints_length):
+ TestCallbacks.callargs.append(ints)
+ return ints[1:], len(ints[1:])
+
+ if hasattr(sys, "getrefcount"):
+ refcount = sys.getrefcount(callback)
+ result = Everything.test_array_inout_callback(callback)
+ self.assertEqual(TestCallbacks.callargs,
+ [[-2, -1, 0, 1, 2], [-1, 0, 1, 2]])
+ # first callback should give 4, second 3
+ self.assertEqual(result, 3)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(callback), refcount)
def test_callback_userdata(self):
TestCallbacks.called = 0
@@ -717,6 +969,99 @@ class TestCallbacks(unittest.TestCase):
self.assertEqual(TestCallbacks.called, 100)
+ def test_callback_userdata_no_user_data(self):
+ TestCallbacks.called = 0
+
+ def callback():
+ TestCallbacks.called += 1
+ return TestCallbacks.called
+
+ for i in range(100):
+ val = Everything.test_callback_user_data(callback)
+ self.assertEqual(val, i + 1)
+
+ self.assertEqual(TestCallbacks.called, 100)
+
+ def test_callback_userdata_varargs(self):
+ TestCallbacks.called = 0
+ collected_user_data = []
+
+ def callback(a, b):
+ collected_user_data.extend([a, b])
+ TestCallbacks.called += 1
+ return TestCallbacks.called
+
+ for i in range(10):
+ val = Everything.test_callback_user_data(callback, 1, 2)
+ self.assertEqual(val, i + 1)
+
+ self.assertEqual(TestCallbacks.called, 10)
+ self.assertSequenceEqual(collected_user_data, [1, 2] * 10)
+
+ def test_callback_userdata_as_kwarg_tuple(self):
+ TestCallbacks.called = 0
+ collected_user_data = []
+
+ def callback(user_data):
+ collected_user_data.extend(user_data)
+ TestCallbacks.called += 1
+ return TestCallbacks.called
+
+ for i in range(10):
+ val = Everything.test_callback_user_data(callback, user_data=(1, 2))
+ self.assertEqual(val, i + 1)
+
+ self.assertEqual(TestCallbacks.called, 10)
+ self.assertSequenceEqual(collected_user_data, [1, 2] * 10)
+
+ def test_callback_user_data_middle_none(self):
+ cb_info = {}
+
+ def callback(userdata):
+ cb_info['called'] = True
+ cb_info['userdata'] = userdata
+ return 1
+
+ (y, z, q) = Everything.test_torture_signature_2(
+ 42, callback, None, 'some string', 3)
+ self.assertEqual(y, 42)
+ self.assertEqual(z, 84)
+ self.assertEqual(q, 14)
+ self.assertTrue(cb_info['called'])
+ self.assertEqual(cb_info['userdata'], None)
+
+ def test_callback_user_data_middle_single(self):
+ cb_info = {}
+
+ def callback(userdata):
+ cb_info['called'] = True
+ cb_info['userdata'] = userdata
+ return 1
+
+ (y, z, q) = Everything.test_torture_signature_2(
+ 42, callback, 'User Data', 'some string', 3)
+ self.assertEqual(y, 42)
+ self.assertEqual(z, 84)
+ self.assertEqual(q, 14)
+ self.assertTrue(cb_info['called'])
+ self.assertEqual(cb_info['userdata'], 'User Data')
+
+ def test_callback_user_data_middle_tuple(self):
+ cb_info = {}
+
+ def callback(userdata):
+ cb_info['called'] = True
+ cb_info['userdata'] = userdata
+ return 1
+
+ (y, z, q) = Everything.test_torture_signature_2(
+ 42, callback, (-5, 'User Data'), 'some string', 3)
+ self.assertEqual(y, 42)
+ self.assertEqual(z, 84)
+ self.assertEqual(q, 14)
+ self.assertTrue(cb_info['called'])
+ self.assertEqual(cb_info['userdata'], (-5, 'User Data'))
+
def test_async_ready_callback(self):
TestCallbacks.called = False
TestCallbacks.main_loop = GLib.MainLoop()
@@ -740,8 +1085,9 @@ class TestCallbacks(unittest.TestCase):
TestCallbacks.called += 1
return 33
- value_refcount = sys.getrefcount(ud)
- callback_refcount = sys.getrefcount(callback)
+ if hasattr(sys, "getrefcount"):
+ value_refcount = sys.getrefcount(ud)
+ callback_refcount = sys.getrefcount(callback)
# Callback is immediately called.
for i in range(100):
@@ -749,14 +1095,16 @@ class TestCallbacks(unittest.TestCase):
self.assertEqual(res, 33)
self.assertEqual(TestCallbacks.called, 100)
- self.assertEqual(sys.getrefcount(callback), callback_refcount + 100)
- self.assertEqual(sys.getrefcount(ud), value_refcount + 100)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(callback), callback_refcount + 100)
+ self.assertEqual(sys.getrefcount(ud), value_refcount + 100)
# thaw will call the callback again, this time resources should be freed
self.assertEqual(Everything.test_callback_thaw_notifications(), 33 * 100)
self.assertEqual(TestCallbacks.called, 200)
- self.assertEqual(sys.getrefcount(callback), callback_refcount)
- self.assertEqual(sys.getrefcount(ud), value_refcount)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(callback), callback_refcount)
+ self.assertEqual(sys.getrefcount(ud), value_refcount)
def test_callback_scope_notified_with_destroy_no_user_data(self):
TestCallbacks.called = 0
@@ -766,7 +1114,8 @@ class TestCallbacks(unittest.TestCase):
TestCallbacks.called += 1
return 34
- callback_refcount = sys.getrefcount(callback)
+ if hasattr(sys, "getrefcount"):
+ callback_refcount = sys.getrefcount(callback)
# Run with warning as exception
with warnings.catch_warnings(record=True) as w:
@@ -776,7 +1125,8 @@ class TestCallbacks(unittest.TestCase):
callback)
self.assertEqual(TestCallbacks.called, 0)
- self.assertEqual(sys.getrefcount(callback), callback_refcount)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(callback), callback_refcount)
# Run with warning as warning
with warnings.catch_warnings(record=True) as w:
@@ -791,13 +1141,15 @@ class TestCallbacks(unittest.TestCase):
self.assertEqual(res, 34)
self.assertEqual(TestCallbacks.called, 1)
- self.assertEqual(sys.getrefcount(callback), callback_refcount + 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(callback), callback_refcount + 1)
# thaw will call the callback again,
# refcount will not go down without user_data parameter
self.assertEqual(Everything.test_callback_thaw_notifications(), 34)
self.assertEqual(TestCallbacks.called, 2)
- self.assertEqual(sys.getrefcount(callback), callback_refcount + 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(callback), callback_refcount + 1)
def test_callback_in_methods(self):
object_ = Everything.TestObj()
@@ -875,7 +1227,6 @@ class TestCallbacks(unittest.TestCase):
self.assertEqual(mydict, {'foo': 1, 'bar': 2, 'new': 42})
-@unittest.skipUnless(has_cairo, 'built without cairo support')
class TestClosures(unittest.TestCase):
def test_no_arg(self):
def callback():
@@ -924,65 +1275,19 @@ class TestClosures(unittest.TestCase):
def callback(variant):
return 'no_variant'
- # reset last error
- sys.last_type = None
-
- # this does not directly raise an exception (see
- # https://bugzilla.gnome.org/show_bug.cgi?id=616279)
- result = Everything.test_closure_variant(callback, GLib.Variant('i', 42))
+ with capture_exceptions() as exc:
+ # this does not directly raise an exception (see
+ # https://bugzilla.gnome.org/show_bug.cgi?id=616279)
+ result = Everything.test_closure_variant(callback, GLib.Variant('i', 42))
# ... but the result shouldn't be a string
self.assertEqual(result, None)
# and the error should be shown
- self.assertEqual(sys.last_type, TypeError)
- self.assertTrue('return value' in str(sys.last_value), sys.last_value)
-
-
-@unittest.skipUnless(has_cairo, 'built without cairo support')
-class TestProperties(unittest.TestCase):
-
- def test_basic(self):
- object_ = Everything.TestObj()
+ self.assertEqual(len(exc), 1)
+ self.assertEqual(exc[0].type, TypeError)
+ self.assertTrue('return value' in str(exc[0].value), exc[0].value)
- self.assertEqual(object_.props.int, 0)
- object_.props.int = 42
- self.assertTrue(isinstance(object_.props.int, int))
- self.assertEqual(object_.props.int, 42)
-
- self.assertEqual(object_.props.float, 0.0)
- object_.props.float = 42.42
- self.assertTrue(isinstance(object_.props.float, float))
- self.assertAlmostEqual(object_.props.float, 42.42, places=5)
-
- self.assertEqual(object_.props.double, 0.0)
- object_.props.double = 42.42
- self.assertTrue(isinstance(object_.props.double, float))
- self.assertAlmostEqual(object_.props.double, 42.42, places=5)
-
- self.assertEqual(object_.props.string, None)
- object_.props.string = 'mec'
- self.assertTrue(isinstance(object_.props.string, str))
- self.assertEqual(object_.props.string, 'mec')
-
- self.assertEqual(object_.props.gtype, GObject.TYPE_INVALID)
- object_.props.gtype = int
- self.assertEqual(object_.props.gtype, GObject.TYPE_INT)
-
- def test_hash_table(self):
- object_ = Everything.TestObj()
- self.assertEqual(object_.props.hash_table, None)
-
- object_.props.hash_table = {'mec': 56}
- self.assertTrue(isinstance(object_.props.hash_table, dict))
- self.assertEqual(list(object_.props.hash_table.items())[0], ('mec', 56))
-
- def test_list(self):
- object_ = Everything.TestObj()
- self.assertEqual(object_.props.list, [])
-
- object_.props.list = ['1', '2', '3']
- self.assertTrue(isinstance(object_.props.list, list))
- self.assertEqual(object_.props.list, ['1', '2', '3'])
+class TestBoxed(unittest.TestCase):
def test_boxed(self):
object_ = Everything.TestObj()
self.assertEqual(object_.props.boxed, None)
@@ -1014,6 +1319,15 @@ class TestProperties(unittest.TestCase):
self.assertTrue(boxed42_2.equals(boxed42))
self.assertTrue(boxed42.equals(boxed42))
+ def test_boxed_b_constructor(self):
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ boxed = Everything.TestBoxedB(42, 47)
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
+
+ self.assertEqual(boxed.some_int8, 0)
+ self.assertEqual(boxed.some_long, 0)
+
def test_boxed_c_equality(self):
boxed = Everything.TestBoxedC()
# TestBoxedC uses refcounting, so we know that
@@ -1022,71 +1336,111 @@ class TestProperties(unittest.TestCase):
self.assertEqual(boxed, copy)
self.assertNotEqual(id(boxed), id(copy))
- def test_gtype(self):
- object_ = Everything.TestObj()
- self.assertEqual(object_.props.gtype, GObject.TYPE_INVALID)
- object_.props.gtype = int
- self.assertEqual(object_.props.gtype, GObject.TYPE_INT)
-
- object_ = Everything.TestObj(gtype=int)
- self.assertEqual(object_.props.gtype, GObject.TYPE_INT)
- object_.props.gtype = str
- self.assertEqual(object_.props.gtype, GObject.TYPE_STRING)
-
- def test_parent_class(self):
- class A(Everything.TestObj):
- prop1 = GObject.Property(type=int)
+ def test_boxed_c_wrapper(self):
+ wrapper = Everything.TestBoxedCWrapper()
+ obj = wrapper.get()
- a = A()
- a.props.int = 20
- self.assertEqual(a.props.int, 20)
+ # TestBoxedC uses refcounting, so we know that
+ # it should be 2 at this point:
+ # - one owned by @wrapper
+ # - another owned by @obj
+ self.assertEqual(obj.refcount, 2)
+ del wrapper
+ gc.collect()
+ gc.collect()
+ self.assertEqual(obj.refcount, 1)
+
+ def test_boxed_c_wrapper_copy(self):
+ wrapper = Everything.TestBoxedCWrapper()
+ wrapper_copy = wrapper.copy()
+ obj = wrapper.get()
- # test parent property which needs introspection
- a.props.list = ("str1", "str2")
- self.assertEqual(a.props.list, ["str1", "str2"])
+ # TestBoxedC uses refcounting, so we know that
+ # it should be 3 at this point:
+ # - one owned by @wrapper
+ # - one owned by @wrapper_copy
+ # - another owned by @obj
+ self.assertEqual(obj.refcount, 3)
+ del wrapper
+ gc.collect()
+ gc.collect()
+ self.assertEqual(obj.refcount, 2)
+ del wrapper_copy
+ gc.collect()
+ gc.collect()
+ self.assertEqual(obj.refcount, 1)
+ del obj
+ gc.collect()
+ gc.collect()
+
+ def test_array_fixed_boxed_none_out(self):
+ arr = Everything.test_array_fixed_boxed_none_out()
+ assert len(arr) == 2
+ assert arr[0].refcount == 2
+ assert arr[1].refcount == 2
+
+ def test_gvalue_out_boxed(self):
+ # As corruption is random data, check several times.
+ for i in range(10):
+ int8 = random.randint(GLib.MININT8, GLib.MAXINT8)
+ assert Everything.test_gvalue_out_boxed(int8).some_int8 == int8
+
+ def test_glist_boxed_none_return(self):
+ assert len(Everything.test_glist_boxed_none_return(0)) == 0
+
+ list_ = Everything.test_glist_boxed_none_return(2)
+ assert len(list_) == 2
+ assert list_[0].refcount == 2
+ assert list_[1].refcount == 2
+
+ def test_glist_boxed_full_return(self):
+ assert len(Everything.test_glist_boxed_full_return(0)) == 0
+
+ list_ = Everything.test_glist_boxed_full_return(2)
+ assert len(list_) == 2
+ assert list_[0].refcount == 1
+ assert list_[1].refcount == 1
-@unittest.skipUnless(has_cairo, 'built without cairo support')
class TestTortureProfile(unittest.TestCase):
def test_torture_profile(self):
- import time
total_time = 0
print("")
object_ = Everything.TestObj()
sys.stdout.write("\ttorture test 1 (10000 iterations): ")
- start_time = time.clock()
+ start_time = timeit.default_timer()
for i in range(10000):
(y, z, q) = object_.torture_signature_0(5000,
"Torture Test 1",
12345)
- end_time = time.clock()
+ end_time = timeit.default_timer()
delta_time = end_time - start_time
total_time += delta_time
print("%f secs" % delta_time)
sys.stdout.write("\ttorture test 2 (10000 iterations): ")
- start_time = time.clock()
+ start_time = timeit.default_timer()
for i in range(10000):
(y, z, q) = Everything.TestObj().torture_signature_0(
5000, "Torture Test 2", 12345)
- end_time = time.clock()
+ end_time = timeit.default_timer()
delta_time = end_time - start_time
total_time += delta_time
print("%f secs" % delta_time)
sys.stdout.write("\ttorture test 3 (10000 iterations): ")
- start_time = time.clock()
+ start_time = timeit.default_timer()
for i in range(10000):
try:
(y, z, q) = object_.torture_signature_1(
5000, "Torture Test 3", 12345)
except:
pass
- end_time = time.clock()
+ end_time = timeit.default_timer()
delta_time = end_time - start_time
total_time += delta_time
print("%f secs" % delta_time)
@@ -1094,14 +1448,14 @@ class TestTortureProfile(unittest.TestCase):
sys.stdout.write("\ttorture test 4 (10000 iterations): ")
def callback(userdata):
- pass
+ return 0
userdata = [1, 2, 3, 4]
- start_time = time.clock()
+ start_time = timeit.default_timer()
for i in range(10000):
(y, z, q) = Everything.test_torture_signature_2(
5000, callback, userdata, "Torture Test 4", 12345)
- end_time = time.clock()
+ end_time = timeit.default_timer()
delta_time = end_time - start_time
total_time += delta_time
print("%f secs" % delta_time)
@@ -1109,7 +1463,6 @@ class TestTortureProfile(unittest.TestCase):
print("\tTotal: %f sec" % total_time)
-@unittest.skipUnless(has_cairo, 'built without cairo support')
class TestAdvancedInterfaces(unittest.TestCase):
def test_array_objs(self):
obj1, obj2 = Everything.test_array_fixed_out_objects()
@@ -1132,135 +1485,3 @@ class TestAdvancedInterfaces(unittest.TestCase):
ret = obj.skip_return_val_no_out(1)
self.assertEqual(ret, None)
-
-
-@unittest.skipUnless(has_cairo, 'built without cairo support')
-class TestSignals(unittest.TestCase):
- def test_object_param_signal(self):
- obj = Everything.TestObj()
-
- def callback(obj, obj_param):
- self.assertEqual(obj_param.props.int, 3)
- self.assertGreater(obj_param.__grefcount__, 1)
- obj.called = True
-
- obj.called = False
- obj.connect('sig-with-obj', callback)
- obj.emit_sig_with_obj()
- self.assertTrue(obj.called)
-
- def test_connect_after(self):
- obj = Everything.TestObj()
-
- def callback(obj, obj_param):
- obj.called = True
-
- obj.called = False
- obj.connect_after('sig-with-obj', callback)
- obj.emit_sig_with_obj()
- self.assertTrue(obj.called)
-
- def test_connect_object(self):
- obj = Everything.TestObj()
-
- def callback(obj, obj_param):
- obj.called = True
-
- obj.called = False
- obj.connect_object('sig-with-obj', callback, obj)
- obj.emit_sig_with_obj()
- self.assertTrue(obj.called)
-
- def test_connect_object_after(self):
- obj = Everything.TestObj()
-
- def callback(obj, obj_param):
- obj.called = True
-
- obj.called = False
- obj.connect_object_after('sig-with-obj', callback, obj)
- obj.emit_sig_with_obj()
- self.assertTrue(obj.called)
-
- def test_int64_param_from_py(self):
- obj = Everything.TestObj()
-
- def callback(obj, i):
- obj.callback_i = i
- return i
-
- obj.callback_i = None
- obj.connect('sig-with-int64-prop', callback)
- rv = obj.emit('sig-with-int64-prop', GObject.G_MAXINT64)
- self.assertEqual(rv, GObject.G_MAXINT64)
- self.assertEqual(obj.callback_i, GObject.G_MAXINT64)
-
- def test_uint64_param_from_py(self):
- obj = Everything.TestObj()
-
- def callback(obj, i):
- obj.callback_i = i
- return i
-
- obj.callback_i = None
- obj.connect('sig-with-uint64-prop', callback)
- rv = obj.emit('sig-with-uint64-prop', GObject.G_MAXUINT64)
- self.assertEqual(rv, GObject.G_MAXUINT64)
- self.assertEqual(obj.callback_i, GObject.G_MAXUINT64)
-
- def test_int64_param_from_c(self):
- obj = Everything.TestObj()
-
- def callback(obj, i):
- obj.callback_i = i
- return i
-
- obj.callback_i = None
-
- obj.connect('sig-with-int64-prop', callback)
- obj.emit_sig_with_int64()
- self.assertEqual(obj.callback_i, GObject.G_MAXINT64)
-
- def test_uint64_param_from_c(self):
- obj = Everything.TestObj()
-
- def callback(obj, i):
- obj.callback_i = i
- return i
-
- obj.callback_i = None
-
- obj.connect('sig-with-uint64-prop', callback)
- obj.emit_sig_with_uint64()
- self.assertEqual(obj.callback_i, GObject.G_MAXUINT64)
-
- def test_intarray_ret(self):
- obj = Everything.TestObj()
-
- def callback(obj, i):
- obj.callback_i = i
- return [i, i + 1]
-
- obj.callback_i = None
-
- try:
- obj.connect('sig-with-intarray-ret', callback)
- except TypeError as e:
- # compat with g-i 1.34.x
- if 'unknown signal' in str(e):
- return
- raise
-
- rv = obj.emit('sig-with-intarray-ret', 42)
- self.assertEqual(obj.callback_i, 42)
- self.assertEqual(type(rv), GLib.Array)
- self.assertEqual(rv.len, 2)
-
-
-@unittest.skipUnless(has_cairo, 'built without cairo support')
-@unittest.skipUnless(Gtk, 'Gtk not available')
-class TestPango(unittest.TestCase):
- def test_cairo_font_options(self):
- screen = Gtk.Window().get_screen()
- font_opts = screen.get_font_options()
- self.assertEqual(type(font_opts.get_subpixel_order()), int)
diff --git a/tests/test_fields.py b/tests/test_fields.py
new file mode 100644
index 0000000..b9a06e2
--- /dev/null
+++ b/tests/test_fields.py
@@ -0,0 +1,185 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+
+import math
+import unittest
+
+from gi.repository import GLib
+from gi.repository import Regress
+from gi.repository import GIMarshallingTests
+
+
+class Number(object):
+
+ def __init__(self, value):
+ self.value = value
+
+ def __int__(self):
+ return int(self.value)
+
+ def __float__(self):
+ return float(self.value)
+
+
+class TestFields(unittest.TestCase):
+
+ def test_int8(self):
+ s = Regress.TestStructA()
+ s.some_int8 = 21
+ self.assertEqual(s.some_int8, 21)
+
+ s.some_int8 = b"\x42"
+ self.assertEqual(s.some_int8, 0x42)
+
+ self.assertRaises(TypeError, setattr, s, "some_int8", b"ab")
+ self.assertRaises(TypeError, setattr, s, "some_int8", None)
+ self.assertRaises(OverflowError, setattr, s, "some_int8", 128)
+ self.assertRaises(OverflowError, setattr, s, "some_int8", -129)
+
+ s.some_int8 = 3.6
+ self.assertEqual(s.some_int8, 3)
+
+ s.some_int8 = Number(55)
+ self.assertEqual(s.some_int8, 55)
+
+ def test_int(self):
+ s = Regress.TestStructA()
+ s.some_int = GLib.MAXINT
+ self.assertEqual(s.some_int, GLib.MAXINT)
+
+ self.assertRaises(TypeError, setattr, s, "some_int", b"a")
+ self.assertRaises(TypeError, setattr, s, "some_int", None)
+ self.assertRaises(
+ OverflowError, setattr, s, "some_int", GLib.MAXINT + 1)
+ self.assertRaises(
+ OverflowError, setattr, s, "some_int", GLib.MININT - 1)
+
+ s.some_int = 3.6
+ self.assertEqual(s.some_int, 3)
+
+ s.some_int = Number(GLib.MININT)
+ self.assertEqual(s.some_int, GLib.MININT)
+
+ def test_long(self):
+ s = GIMarshallingTests.SimpleStruct()
+ s.long_ = GLib.MAXLONG
+ self.assertEqual(s.long_, GLib.MAXLONG)
+
+ self.assertRaises(TypeError, setattr, s, "long_", b"a")
+ self.assertRaises(TypeError, setattr, s, "long_", None)
+ self.assertRaises(OverflowError, setattr, s, "long_", GLib.MAXLONG + 1)
+ self.assertRaises(OverflowError, setattr, s, "long_", GLib.MINLONG - 1)
+
+ s.long_ = 3.6
+ self.assertEqual(s.long_, 3)
+
+ s.long_ = Number(GLib.MINLONG)
+ self.assertEqual(s.long_, GLib.MINLONG)
+
+ def test_double(self):
+ s = Regress.TestStructA()
+ s.some_double = GLib.MAXDOUBLE
+ self.assertEqual(s.some_double, GLib.MAXDOUBLE)
+ s.some_double = GLib.MINDOUBLE
+ self.assertEqual(s.some_double, GLib.MINDOUBLE)
+
+ s.some_double = float("nan")
+ self.assertTrue(math.isnan(s.some_double))
+
+ self.assertRaises(TypeError, setattr, s, "some_double", b"a")
+ self.assertRaises(TypeError, setattr, s, "some_double", None)
+
+ def test_gtype(self):
+ s = Regress.TestStructE()
+
+ s.some_type = Regress.TestObj
+ self.assertEqual(s.some_type, Regress.TestObj.__gtype__)
+
+ self.assertRaises(TypeError, setattr, s, "some_type", 42)
+
+ def test_unichar(self):
+ # I can't find a unichar field..
+ pass
+
+ def test_utf8(self):
+ s = GIMarshallingTests.BoxedStruct()
+ s.string_ = "hello"
+ self.assertEqual(s.string_, "hello")
+
+ s.string_ = u"hello"
+ self.assertEqual(s.string_, u"hello")
+
+ s.string_ = None
+ self.assertEqual(s.string_, None)
+
+ self.assertRaises(TypeError, setattr, s, "string_", 42)
+
+ def test_array_of_structs(self):
+ s = Regress.TestStructD()
+ self.assertEqual(s.array1, [])
+ self.assertEqual(s.array2, [])
+
+ def test_interface(self):
+ s = Regress.TestStructC()
+
+ obj = Regress.TestObj()
+ s.obj = obj
+ self.assertTrue(s.obj is obj)
+
+ s.obj = None
+ self.assertTrue(s.obj is None)
+
+ self.assertRaises(TypeError, setattr, s, "obj", object())
+
+ def test_glist(self):
+ s = Regress.TestStructD()
+ self.assertEqual(s.list, [])
+
+ self.assertRaises(TypeError, setattr, s, "list", [object()])
+
+ def test_gpointer(self):
+ glist = GLib.List()
+
+ glist.data = 123
+ self.assertEqual(glist.data, 123)
+
+ glist.data = None
+ self.assertEqual(glist.data, 0)
+
+ def test_gptrarray(self):
+ s = Regress.TestStructD()
+ self.assertEqual(s.garray, [])
+
+ self.assertRaises(TypeError, setattr, s, "garray", [object()])
+
+ def test_enum(self):
+ s = Regress.TestStructA()
+
+ s.some_enum = Regress.TestEnum.VALUE3
+ self.assertEqual(s.some_enum, Regress.TestEnum.VALUE3)
+
+ self.assertRaises(TypeError, setattr, s, "some_enum", object())
+
+ s.some_enum = 0
+ self.assertEqual(s.some_enum, Regress.TestEnum.VALUE1)
+
+ def test_union(self):
+ s = Regress.TestStructE()
+ self.assertEqual(s.some_union, [None, None])
+
+ def test_struct(self):
+ s = GIMarshallingTests.NestedStruct()
+
+ # FIXME: segfaults
+ # https://bugzilla.gnome.org/show_bug.cgi?id=747002
+ # s.simple_struct = None
+
+ self.assertRaises(TypeError, setattr, s, "simple_struct", object())
+
+ sub = GIMarshallingTests.SimpleStruct()
+ sub.long_ = 42
+ s.simple_struct = sub
+ self.assertEqual(s.simple_struct.long_, 42)
+
+ def test_ghashtable(self):
+ obj = Regress.TestObj()
+ self.assertTrue(obj.hash_table is None)
diff --git a/tests/test_gdbus.py b/tests/test_gdbus.py
index 805633a..6c9afb0 100644
--- a/tests/test_gdbus.py
+++ b/tests/test_gdbus.py
@@ -7,6 +7,44 @@ from gi.repository import GLib
from gi.repository import Gio
+try:
+ Gio.bus_get_sync(Gio.BusType.SESSION, None)
+except GLib.Error:
+ has_dbus = False
+else:
+ has_dbus = True
+
+
+class TestDBusNodeInfo(unittest.TestCase):
+
+ def test_new_for_xml(self):
+ info = Gio.DBusNodeInfo.new_for_xml("""
+<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
+ 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
+<node>
+ <interface name='org.freedesktop.DBus.Introspectable'>
+ <method name='Introspect'>
+ <arg name='data' direction='out' type='s'/>
+ </method>
+ </interface>
+</node>
+""")
+
+ interfaces = info.interfaces
+ del info
+ assert len(interfaces) == 1
+ assert interfaces[0].name == "org.freedesktop.DBus.Introspectable"
+ methods = interfaces[0].methods
+ del interfaces
+ assert len(methods) == 1
+ assert methods[0].name == "Introspect"
+ out_args = methods[0].out_args
+ assert len(out_args)
+ del methods
+ assert out_args[0].name == "data"
+
+
+@unittest.skipUnless(has_dbus, "no dbus running")
class TestGDBusClient(unittest.TestCase):
def setUp(self):
self.bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
@@ -208,3 +246,10 @@ class TestGDBusClient(unittest.TestCase):
self.assertTrue(isinstance(data['error'], Exception))
self.assertTrue('InvalidArgs' in str(data['error']), str(data['error']))
+
+ def test_instantiate_custom_proxy(self):
+ class SomeProxy(Gio.DBusProxy):
+ def __init__(self):
+ Gio.DBusProxy.__init__(self)
+
+ SomeProxy()
diff --git a/tests/test_generictreemodel.py b/tests/test_generictreemodel.py
index 9fa89ff..ab31579 100644
--- a/tests/test_generictreemodel.py
+++ b/tests/test_generictreemodel.py
@@ -15,22 +15,26 @@
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
-# USA
-
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
# system
import gc
import sys
import weakref
import unittest
+import platform
# pygobject
from gi.repository import GObject
-from gi.repository import Gtk
-from pygtkcompat.generictreemodel import GenericTreeModel
-from pygtkcompat.generictreemodel import _get_user_data_as_pyobject
+
+try:
+ from gi.repository import Gtk
+ from pygtkcompat.generictreemodel import GenericTreeModel
+ from pygtkcompat.generictreemodel import _get_user_data_as_pyobject
+ has_gtk = True
+except ImportError:
+ GenericTreeModel = object
+ has_gtk = False
class Node(object):
@@ -51,9 +55,9 @@ class Node(object):
return 'Node("%s", %s)' % (self.name, self.value)
-class TesterModel(GenericTreeModel):
+class ATesterModel(GenericTreeModel):
def __init__(self):
- super(TesterModel, self).__init__()
+ super(ATesterModel, self).__init__()
self.root = Node('root', 0,
Node('spam', 1,
Node('sushi', 2),
@@ -127,10 +131,12 @@ class TesterModel(GenericTreeModel):
return child.parent()
+@unittest.skipUnless(has_gtk, 'Gtk not available')
class TestReferences(unittest.TestCase):
def setUp(self):
pass
+ @unittest.skipIf(platform.python_implementation() == "PyPy", "not with PyPy")
def test_c_tree_iter_user_data_as_pyobject(self):
obj = object()
obj_id = id(obj)
@@ -145,27 +151,31 @@ class TestReferences(unittest.TestCase):
self.assertEqual(sys.getrefcount(obj), ref_count + 1)
def test_leak_references_on(self):
- model = TesterModel()
+ model = ATesterModel()
obj_ref = weakref.ref(model.root)
# Initial refcount is 1 for model.root + the temporary
- self.assertEqual(sys.getrefcount(model.root), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(model.root), 2)
# Iter increases by 1 do to assignment to iter.user_data
res, it = model.do_get_iter([0])
self.assertEqual(id(model.root), it.user_data)
- self.assertEqual(sys.getrefcount(model.root), 3)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(model.root), 3)
# Verify getting a TreeIter more then once does not further increase
# the ref count.
res2, it2 = model.do_get_iter([0])
self.assertEqual(id(model.root), it2.user_data)
- self.assertEqual(sys.getrefcount(model.root), 3)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(model.root), 3)
# Deleting the iter does not decrease refcount because references
# leak by default (they are stored in the held_refs pool)
del it
gc.collect()
- self.assertEqual(sys.getrefcount(model.root), 3)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(model.root), 3)
# Deleting a model should free all held references to user data
# stored by TreeIters
@@ -174,20 +184,23 @@ class TestReferences(unittest.TestCase):
self.assertEqual(obj_ref(), None)
def test_row_deleted_frees_refs(self):
- model = TesterModel()
+ model = ATesterModel()
obj_ref = weakref.ref(model.root)
# Initial refcount is 1 for model.root + the temporary
- self.assertEqual(sys.getrefcount(model.root), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(model.root), 2)
# Iter increases by 1 do to assignment to iter.user_data
res, it = model.do_get_iter([0])
self.assertEqual(id(model.root), it.user_data)
- self.assertEqual(sys.getrefcount(model.root), 3)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(model.root), 3)
# Notifying the underlying model of a row_deleted should decrease the
# ref count.
model.row_deleted(Gtk.TreePath('0'), model.root)
- self.assertEqual(sys.getrefcount(model.root), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(model.root), 2)
# Finally deleting the actual object should collect it completely
del model.root
@@ -195,23 +208,26 @@ class TestReferences(unittest.TestCase):
self.assertEqual(obj_ref(), None)
def test_leak_references_off(self):
- model = TesterModel()
+ model = ATesterModel()
model.leak_references = False
obj_ref = weakref.ref(model.root)
# Initial refcount is 1 for model.root + the temporary
- self.assertEqual(sys.getrefcount(model.root), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(model.root), 2)
# Iter does not increas count by 1 when leak_references is false
res, it = model.do_get_iter([0])
self.assertEqual(id(model.root), it.user_data)
- self.assertEqual(sys.getrefcount(model.root), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(model.root), 2)
# Deleting the iter does not decrease refcount because assigning user_data
# eats references and does not release them.
del it
gc.collect()
- self.assertEqual(sys.getrefcount(model.root), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(model.root), 2)
# Deleting the model decreases the final ref, and the object is collected
del model
@@ -221,7 +237,7 @@ class TestReferences(unittest.TestCase):
def test_iteration_refs(self):
# Pull iterators off the model using the wrapped C API which will
# then call back into the python overrides.
- model = TesterModel()
+ model = ATesterModel()
nodes = [node for node in model.iter_depth_first()]
values = [node.value for node in nodes]
@@ -236,14 +252,16 @@ class TestReferences(unittest.TestCase):
# 4 - ref held by the root/children graph itself
# 5 - ref held by the model "held_refs" instance var
for node in nodes:
- self.assertEqual(sys.getrefcount(node), 5)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(node), 5)
# A second iteration and storage of the nodes in a new list
# should only increase refcounts by 1 even though new
# iterators are created and assigned.
nodes2 = [node for node in model.iter_depth_first()]
for node in nodes2:
- self.assertEqual(sys.getrefcount(node), 6)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(node), 6)
# Hold weak refs and start verifying ref collection.
node_refs = [weakref.ref(node) for node in nodes]
@@ -252,14 +270,16 @@ class TestReferences(unittest.TestCase):
del nodes2
gc.collect()
for node in nodes:
- self.assertEqual(sys.getrefcount(node), 5)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(node), 5)
# Second round of collection, no more local lists of nodes.
del nodes
gc.collect()
for ref in node_refs:
node = ref()
- self.assertEqual(sys.getrefcount(node), 4)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(node), 4)
# Using invalidate_iters or row_deleted(path, node) will clear out
# the pooled refs held internal to the GenericTreeModel implementation.
@@ -268,7 +288,8 @@ class TestReferences(unittest.TestCase):
gc.collect()
for ref in node_refs:
node = ref()
- self.assertEqual(sys.getrefcount(node), 3)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(node), 3)
# Deleting the root node at this point should allow all nodes to be collected
# as there is no longer a way to reach the children
@@ -279,9 +300,10 @@ class TestReferences(unittest.TestCase):
self.assertEqual(ref(), None)
+@unittest.skipUnless(has_gtk, 'Gtk not available')
class TestIteration(unittest.TestCase):
def test_iter_next_root(self):
- model = TesterModel()
+ model = ATesterModel()
it = model.get_iter([0])
self.assertEqual(it.user_data, id(model.root))
self.assertEqual(model.root.next, None)
@@ -290,7 +312,7 @@ class TestIteration(unittest.TestCase):
self.assertEqual(it, None)
def test_iter_next_multiple(self):
- model = TesterModel()
+ model = ATesterModel()
it = model.get_iter([0, 0])
self.assertEqual(it.user_data, id(model.root.children[0]))
@@ -306,6 +328,7 @@ class ErrorModel(GenericTreeModel):
pass
+@unittest.skipUnless(has_gtk, 'Gtk not available')
class ExceptHook(object):
"""
Temporarily installs an exception hook in a context which
@@ -337,6 +360,7 @@ class ExceptHook(object):
assert issubclass(got, expected), error_message
+@unittest.skipUnless(has_gtk, 'Gtk not available')
class TestReturnsAfterError(unittest.TestCase):
def setUp(self):
self.model = ErrorModel()
@@ -352,7 +376,7 @@ class TestReturnsAfterError(unittest.TestCase):
self.assertEqual(count, 0)
def test_get_column_type(self):
- with ExceptHook(NotImplementedError, TypeError):
+ with ExceptHook(NotImplementedError, ValueError):
col_type = self.model.get_column_type(0)
self.assertEqual(col_type, GObject.TYPE_INVALID)
@@ -406,6 +430,3 @@ class TestReturnsAfterError(unittest.TestCase):
with ExceptHook(NotImplementedError):
res = self.model.iter_parent(child)
self.assertEqual(res, None)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/tests/test_gi.py b/tests/test_gi.py
index c47ac57..261d8b2 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -1,5 +1,4 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
-# coding=utf-8
# vim: tabstop=4 shiftwidth=4 expandtab
import sys
@@ -8,29 +7,25 @@ import unittest
import tempfile
import shutil
import os
-import locale
-import subprocess
import gc
import weakref
import warnings
-from io import StringIO, BytesIO
+import pickle
+import platform
import gi
+import gi.overrides
+from gi import PyGIWarning
+from gi import PyGIDeprecationWarning
from gi.repository import GObject, GLib, Gio
-
from gi.repository import GIMarshallingTests
+import pytest
-from compathelper import _bytes, _unicode
+from .helper import capture_exceptions, capture_output
-if sys.version_info < (3, 0):
- CONSTANT_UTF8 = "const \xe2\x99\xa5 utf8"
- PY2_UNICODE_UTF8 = unicode(CONSTANT_UTF8, 'UTF-8')
- CHAR_255 = '\xff'
-else:
- CONSTANT_UTF8 = "const ♥ utf8"
- CHAR_255 = bytes([255])
-CONSTANT_NUMBER = 42
+CONSTANT_UTF8 = "const ♥ utf8"
+CONSTANT_UCS4 = u"const ♥ utf8"
class Number(object):
@@ -59,12 +54,11 @@ class Sequence(object):
class TestConstant(unittest.TestCase):
-# Blocked by https://bugzilla.gnome.org/show_bug.cgi?id=595773
-# def test_constant_utf8(self):
-# self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.CONSTANT_UTF8)
+ def test_constant_utf8(self):
+ self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.CONSTANT_UTF8)
def test_constant_number(self):
- self.assertEqual(CONSTANT_NUMBER, GIMarshallingTests.CONSTANT_NUMBER)
+ self.assertEqual(42, GIMarshallingTests.CONSTANT_NUMBER)
def test_min_max_int(self):
self.assertEqual(GLib.MAXINT32, 2 ** 31 - 1)
@@ -89,6 +83,11 @@ class TestBoolean(unittest.TestCase):
GIMarshallingTests.boolean_in_true(1)
GIMarshallingTests.boolean_in_false(0)
+ def test_boolean_in_other_types(self):
+ GIMarshallingTests.boolean_in_true([""])
+ GIMarshallingTests.boolean_in_false([])
+ GIMarshallingTests.boolean_in_false(None)
+
def test_boolean_out(self):
self.assertEqual(True, GIMarshallingTests.boolean_out_true())
self.assertEqual(False, GIMarshallingTests.boolean_out_false())
@@ -100,8 +99,8 @@ class TestBoolean(unittest.TestCase):
class TestInt8(unittest.TestCase):
- MAX = GObject.G_MAXINT8
- MIN = GObject.G_MININT8
+ MAX = GLib.MAXINT8
+ MIN = GLib.MININT8
def test_int8_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.int8_return_max())
@@ -133,7 +132,7 @@ class TestInt8(unittest.TestCase):
class TestUInt8(unittest.TestCase):
- MAX = GObject.G_MAXUINT8
+ MAX = GLib.MAXUINT8
def test_uint8_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.uint8_return())
@@ -142,7 +141,7 @@ class TestUInt8(unittest.TestCase):
number = Number(self.MAX)
GIMarshallingTests.uint8_in(number)
- GIMarshallingTests.uint8_in(CHAR_255)
+ GIMarshallingTests.uint8_in(b'\xff')
number.value += 1
self.assertRaises(OverflowError, GIMarshallingTests.uint8_in, number)
@@ -159,8 +158,8 @@ class TestUInt8(unittest.TestCase):
class TestInt16(unittest.TestCase):
- MAX = GObject.G_MAXINT16
- MIN = GObject.G_MININT16
+ MAX = GLib.MAXINT16
+ MIN = GLib.MININT16
def test_int16_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.int16_return_max())
@@ -192,7 +191,7 @@ class TestInt16(unittest.TestCase):
class TestUInt16(unittest.TestCase):
- MAX = GObject.G_MAXUINT16
+ MAX = GLib.MAXUINT16
def test_uint16_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.uint16_return())
@@ -218,8 +217,8 @@ class TestUInt16(unittest.TestCase):
class TestInt32(unittest.TestCase):
- MAX = GObject.G_MAXINT32
- MIN = GObject.G_MININT32
+ MAX = GLib.MAXINT32
+ MIN = GLib.MININT32
def test_int32_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.int32_return_max())
@@ -251,7 +250,7 @@ class TestInt32(unittest.TestCase):
class TestUInt32(unittest.TestCase):
- MAX = GObject.G_MAXUINT32
+ MAX = GLib.MAXUINT32
def test_uint32_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.uint32_return())
@@ -336,8 +335,8 @@ class TestUInt64(unittest.TestCase):
class TestShort(unittest.TestCase):
- MAX = GObject.G_MAXSHORT
- MIN = GObject.G_MINSHORT
+ MAX = GLib.MAXSHORT
+ MIN = GLib.MINSHORT
def test_short_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.short_return_max())
@@ -369,7 +368,7 @@ class TestShort(unittest.TestCase):
class TestUShort(unittest.TestCase):
- MAX = GObject.G_MAXUSHORT
+ MAX = GLib.MAXUSHORT
def test_ushort_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.ushort_return())
@@ -395,8 +394,8 @@ class TestUShort(unittest.TestCase):
class TestInt(unittest.TestCase):
- MAX = GObject.G_MAXINT
- MIN = GObject.G_MININT
+ MAX = GLib.MAXINT
+ MIN = GLib.MININT
def test_int_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.int_return_max())
@@ -424,12 +423,12 @@ class TestInt(unittest.TestCase):
def test_int_inout(self):
self.assertEqual(self.MIN, GIMarshallingTests.int_inout_max_min(Number(self.MAX)))
self.assertEqual(self.MAX, GIMarshallingTests.int_inout_min_max(Number(self.MIN)))
- self.assertRaises(TypeError, GIMarshallingTests.int_inout_min_max, Number(self.MIN), CONSTANT_NUMBER)
+ self.assertRaises(TypeError, GIMarshallingTests.int_inout_min_max, Number(self.MIN), 42)
class TestUInt(unittest.TestCase):
- MAX = GObject.G_MAXUINT
+ MAX = GLib.MAXUINT
def test_uint_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.uint_return())
@@ -455,8 +454,8 @@ class TestUInt(unittest.TestCase):
class TestLong(unittest.TestCase):
- MAX = GObject.G_MAXLONG
- MIN = GObject.G_MINLONG
+ MAX = GLib.MAXLONG
+ MIN = GLib.MINLONG
def test_long_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.long_return_max())
@@ -488,7 +487,7 @@ class TestLong(unittest.TestCase):
class TestULong(unittest.TestCase):
- MAX = GObject.G_MAXULONG
+ MAX = GLib.MAXULONG
def test_ulong_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.ulong_return())
@@ -514,8 +513,8 @@ class TestULong(unittest.TestCase):
class TestSSize(unittest.TestCase):
- MAX = GObject.G_MAXLONG
- MIN = GObject.G_MINLONG
+ MAX = GLib.MAXSSIZE
+ MIN = GLib.MINSSIZE
def test_ssize_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.ssize_return_max())
@@ -547,7 +546,7 @@ class TestSSize(unittest.TestCase):
class TestSize(unittest.TestCase):
- MAX = GObject.G_MAXULONG
+ MAX = GLib.MAXSIZE
def test_size_return(self):
self.assertEqual(self.MAX, GIMarshallingTests.size_return())
@@ -589,8 +588,8 @@ class TestTimet(unittest.TestCase):
class TestFloat(unittest.TestCase):
- MAX = GObject.G_MAXFLOAT
- MIN = GObject.G_MINFLOAT
+ MAX = GLib.MAXFLOAT
+ MIN = GLib.MINFLOAT
def test_float_return(self):
self.assertAlmostEqual(self.MAX, GIMarshallingTests.float_return())
@@ -609,8 +608,8 @@ class TestFloat(unittest.TestCase):
class TestDouble(unittest.TestCase):
- MAX = GObject.G_MAXDOUBLE
- MIN = GObject.G_MINDOUBLE
+ MAX = GLib.MAXDOUBLE
+ MIN = GLib.MINDOUBLE
def test_double_return(self):
self.assertAlmostEqual(self.MAX, GIMarshallingTests.double_return())
@@ -636,8 +635,13 @@ class TestGType(unittest.TestCase):
def check_readonly(gtype):
gtype.name = "foo"
- self.assertRaises(AttributeError, check_readonly, GObject.TYPE_NONE)
- self.assertRaises(AttributeError, check_readonly, GObject.TYPE_STRING)
+ errors = (AttributeError,)
+ if platform.python_implementation() == "PyPy":
+ # https://foss.heptapod.net/pypy/pypy/-/issues/2788
+ errors = (AttributeError, TypeError)
+
+ self.assertRaises(errors, check_readonly, GObject.TYPE_NONE)
+ self.assertRaises(errors, check_readonly, GObject.TYPE_STRING)
def test_gtype_return(self):
self.assertEqual(GObject.TYPE_NONE, GIMarshallingTests.gtype_return())
@@ -659,18 +663,29 @@ class TestGType(unittest.TestCase):
class TestUtf8(unittest.TestCase):
+ def test_utf8_as_uint8array_in(self):
+ data = CONSTANT_UTF8
+ if not isinstance(data, bytes):
+ data = data.encode("utf-8")
+ GIMarshallingTests.utf8_as_uint8array_in(data)
+
def test_utf8_none_return(self):
self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.utf8_none_return())
def test_utf8_full_return(self):
self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.utf8_full_return())
+ def test_extra_utf8_full_return_invalid(self):
+ with pytest.raises(UnicodeDecodeError):
+ GIMarshallingTests.extra_utf8_full_return_invalid()
+
+ def test_extra_utf8_full_out_invalid(self):
+ with pytest.raises(UnicodeDecodeError):
+ GIMarshallingTests.extra_utf8_full_out_invalid()
+
def test_utf8_none_in(self):
GIMarshallingTests.utf8_none_in(CONSTANT_UTF8)
- if sys.version_info < (3, 0):
- GIMarshallingTests.utf8_none_in(PY2_UNICODE_UTF8)
-
- self.assertRaises(TypeError, GIMarshallingTests.utf8_none_in, CONSTANT_NUMBER)
+ self.assertRaises(TypeError, GIMarshallingTests.utf8_none_in, 42)
self.assertRaises(TypeError, GIMarshallingTests.utf8_none_in, None)
def test_utf8_none_out(self):
@@ -696,8 +711,19 @@ class TestFilename(unittest.TestCase):
def tearDown(self):
shutil.rmtree(self.workdir)
+ def tests_filename_list_return(self):
+ assert GIMarshallingTests.filename_list_return() == []
+
+ @unittest.skipIf(os.name == "nt", "fixme")
def test_filename_in(self):
- fname = os.path.join(self.workdir, _unicode('testäø.txt'))
+ fname = os.path.join(self.workdir, u'testäø.txt')
+
+ try:
+ os.path.exists(fname)
+ except ValueError:
+ # non-unicode fs encoding
+ return
+
self.assertRaises(GLib.GError, GLib.file_get_contents, fname)
with open(fname.encode('UTF-8'), 'wb') as f:
@@ -707,21 +733,197 @@ class TestFilename(unittest.TestCase):
self.assertEqual(result, True)
self.assertEqual(contents, b'hello world!\n\x01\x02')
+ def test_filename_in_nullable(self):
+ self.assertTrue(GIMarshallingTests.filename_copy(None) is None)
+ self.assertRaises(TypeError, GIMarshallingTests.filename_exists, None)
+
+ @unittest.skipIf(os.name == "nt", "fixme")
def test_filename_out(self):
self.assertRaises(GLib.GError, GLib.Dir.make_tmp, 'test')
+ name = 'testäø.XXXXXX'
- dirname = GLib.Dir.make_tmp('testäø.XXXXXX')
- self.assertTrue('/testäø.' in dirname, dirname)
- dirname = _bytes(dirname)
+ try:
+ os.path.exists(name)
+ except ValueError:
+ # non-unicode fs encoding
+ return
+
+ dirname = GLib.Dir.make_tmp(name)
+ self.assertTrue(os.path.sep + 'testäø.' in dirname, dirname)
self.assertTrue(os.path.isdir(dirname))
os.rmdir(dirname)
- def test_filename_type_error(self):
- self.assertRaises(TypeError, GLib.file_get_contents, 23)
+ def test_wrong_types(self):
+ self.assertRaises(TypeError, GIMarshallingTests.filename_copy, 23)
+ self.assertRaises(TypeError, GIMarshallingTests.filename_copy, [])
+
+ def test_null(self):
+ self.assertTrue(GIMarshallingTests.filename_copy(None) is None)
+ self.assertRaises(TypeError, GIMarshallingTests.filename_exists, None)
+
+ def test_round_trip(self):
+ self.assertEqual(GIMarshallingTests.filename_copy(u"foo"), "foo")
+ self.assertEqual(GIMarshallingTests.filename_copy(b"foo"), "foo")
+
+ def test_contains_null(self):
+ self.assertRaises(
+ (ValueError, TypeError),
+ GIMarshallingTests.filename_copy, b"foo\x00")
+ self.assertRaises(
+ (ValueError, TypeError),
+ GIMarshallingTests.filename_copy, u"foo\x00")
+
+ def test_win32_surrogates(self):
+ if os.name != "nt":
+ return
+
+ copy = GIMarshallingTests.filename_copy
+ glib_repr = GIMarshallingTests.filename_to_glib_repr
+
+ self.assertEqual(copy(u"\ud83d"), u"\ud83d")
+ self.assertEqual(copy(u"\x61\uDC00"), u"\x61\uDC00")
+ self.assertEqual(copy(u"\uD800\uDC01"), u"\U00010001")
+ self.assertEqual(copy(u"\uD83D\x20\uDCA9"), u"\uD83D\x20\uDCA9")
+
+ self.assertEqual(glib_repr(u"\ud83d"), b"\xed\xa0\xbd")
+ self.assertEqual(glib_repr(u"\uD800\uDC01"), b"\xf0\x90\x80\x81")
+
+ self.assertEqual(
+ glib_repr(u"\uD800\uDBFF"), b"\xED\xA0\x80\xED\xAF\xBF")
+ self.assertEqual(
+ glib_repr(u"\uD800\uE000"), b"\xED\xA0\x80\xEE\x80\x80")
+ self.assertEqual(
+ glib_repr(u"\uD7FF\uDC00"), b"\xED\x9F\xBF\xED\xB0\x80")
+ self.assertEqual(glib_repr(u"\x61\uDC00"), b"\x61\xED\xB0\x80")
+ self.assertEqual(glib_repr(u"\uDC00"), b"\xED\xB0\x80")
+
+ def test_win32_bytes_py3(self):
+ if not (os.name == "nt"):
+ return
+
+ values = [
+ b"foo",
+ b"\xff\xff",
+ b"\xc3\xb6\xc3\xa4\xc3\xbc",
+ b"\xed\xa0\xbd",
+ b"\xf0\x90\x80\x81",
+ ]
+
+ for v in values:
+ try:
+ uni = v.decode(sys.getfilesystemencoding(), "surrogatepass")
+ except UnicodeDecodeError:
+ continue
+ self.assertEqual(GIMarshallingTests.filename_copy(v), uni)
+
+ def test_unix_various(self):
+ if os.name == "nt":
+ return
+
+ copy = GIMarshallingTests.filename_copy
+ glib_repr = GIMarshallingTests.filename_to_glib_repr
+
+ try:
+ os.fsdecode(b"\xff\xfe")
+ except UnicodeDecodeError:
+ self.assertRaises(UnicodeDecodeError, copy, b"\xff\xfe")
+ else:
+ str_path = copy(b"\xff\xfe")
+ self.assertTrue(isinstance(str_path, str))
+ self.assertEqual(str_path, os.fsdecode(b"\xff\xfe"))
+ self.assertEqual(copy(str_path), str_path)
+ self.assertEqual(glib_repr(b"\xff\xfe"), b"\xff\xfe")
+ self.assertEqual(glib_repr(str_path), b"\xff\xfe")
+
+ # if getfilesystemencoding is ASCII, then we should fail like
+ # os.fsencode
+ try:
+ byte_path = os.fsencode(u"ä")
+ except UnicodeEncodeError:
+ self.assertRaises(UnicodeEncodeError, copy, u"ä")
+ else:
+ self.assertEqual(copy(u"ä"), u"ä")
+ self.assertEqual(glib_repr(u"ä"), byte_path)
+
+ @unittest.skip("glib can't handle non-unicode paths")
+ def test_win32_surrogates_exists(self):
+ if os.name != "nt":
+ return
+
+ path = os.path.join(self.workdir, u"\ud83d")
+ with open(path, "wb"):
+ self.assertTrue(os.path.exists(path))
+ self.assertTrue(GIMarshallingTests.filename_exists(path))
+ os.unlink(path)
+
+ def test_path_exists_various_types(self):
+ wd = self.workdir
+ wdb = os.fsencode(wd)
+
+ paths = [(wdb, b"foo-1"), (wd, u"foo-2"), (wd, u"öäü-3")]
+
+ try:
+ paths.append((wd, os.fsdecode(b"\xff\xfe-4")))
+ except UnicodeDecodeError:
+ # depends on the code page
+ pass
+
+ if os.name != "nt":
+ paths.append((wdb, b"\xff\xfe-5"))
+
+ def valid_path(p):
+ try:
+ os.path.exists(p)
+ except ValueError:
+ return False
+ return True
+
+ for (d, path) in paths:
+ if not valid_path(path):
+ continue
+ path = os.path.join(d, path)
+ with open(path, "wb"):
+ self.assertTrue(GIMarshallingTests.filename_exists(path))
class TestArray(unittest.TestCase):
+ @unittest.skipUnless(
+ hasattr(GIMarshallingTests, "array_bool_in"), "too old gi")
+ def test_array_bool_in(self):
+ GIMarshallingTests.array_bool_in([True, False, True, True])
+
+ @unittest.skipUnless(
+ hasattr(GIMarshallingTests, "array_bool_out"), "too old gi")
+ def test_array_bool_out(self):
+ assert GIMarshallingTests.array_bool_out() == [True, False, True, True]
+
+ @unittest.skipUnless(
+ hasattr(GIMarshallingTests, "array_int64_in"), "too old gi")
+ def test_array_int64_in(self):
+ GIMarshallingTests.array_int64_in([-1, 0, 1, 2])
+
+ @unittest.skipUnless(
+ hasattr(GIMarshallingTests, "array_uint64_in"), "too old gi")
+ def test_array_uint64_in(self):
+ GIMarshallingTests.array_uint64_in([GLib.MAXUINT64, 0, 1, 2])
+
+ @unittest.skipUnless(
+ hasattr(GIMarshallingTests, "array_unichar_in"), "too old gi")
+ def test_array_unichar_in(self):
+ GIMarshallingTests.array_unichar_in(list(CONSTANT_UCS4))
+ GIMarshallingTests.array_unichar_in(CONSTANT_UCS4)
+
+ @unittest.skipUnless(
+ hasattr(GIMarshallingTests, "array_unichar_out"), "too old gi")
+ def test_array_unichar_out(self):
+ result = list(CONSTANT_UCS4)
+ assert GIMarshallingTests.array_unichar_out() == result
+
+ def test_array_zero_terminated_return_unichar(self):
+ assert GIMarshallingTests.array_zero_terminated_return_unichar() == \
+ list(CONSTANT_UCS4)
+
def test_array_fixed_int_return(self):
self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_fixed_int_return())
@@ -764,7 +966,7 @@ class TestArray(unittest.TestCase):
def test_array_uint8_in(self):
GIMarshallingTests.array_uint8_in(Sequence([97, 98, 99, 100]))
- GIMarshallingTests.array_uint8_in(_bytes("abcd"))
+ GIMarshallingTests.array_uint8_in(b"abcd")
def test_array_string_in(self):
GIMarshallingTests.array_string_in(['foo', 'bar'])
@@ -813,6 +1015,15 @@ class TestArray(unittest.TestCase):
GIMarshallingTests.array_struct_in([struct1, struct2, struct3])
+ def test_array_boxed_struct_in_item_marshal_failure(self):
+ struct1 = GIMarshallingTests.BoxedStruct()
+ struct1.long_ = 1
+ struct2 = GIMarshallingTests.BoxedStruct()
+ struct2.long_ = 2
+
+ self.assertRaises(TypeError, GIMarshallingTests.array_struct_in,
+ [struct1, struct2, 'not_a_struct'])
+
def test_array_boxed_struct_value_in(self):
struct1 = GIMarshallingTests.BoxedStruct()
struct1.long_ = 1
@@ -823,6 +1034,15 @@ class TestArray(unittest.TestCase):
GIMarshallingTests.array_struct_value_in([struct1, struct2, struct3])
+ def test_array_boxed_struct_value_in_item_marshal_failure(self):
+ struct1 = GIMarshallingTests.BoxedStruct()
+ struct1.long_ = 1
+ struct2 = GIMarshallingTests.BoxedStruct()
+ struct2.long_ = 2
+
+ self.assertRaises(TypeError, GIMarshallingTests.array_struct_value_in,
+ [struct1, struct2, 'not_a_struct'])
+
def test_array_boxed_struct_take_in(self):
struct1 = GIMarshallingTests.BoxedStruct()
struct1.long_ = 1
@@ -854,6 +1074,15 @@ class TestArray(unittest.TestCase):
GIMarshallingTests.array_simple_struct_in([struct1, struct2, struct3])
+ def test_array_simple_struct_in_item_marshal_failure(self):
+ struct1 = GIMarshallingTests.SimpleStruct()
+ struct1.long_ = 1
+ struct2 = GIMarshallingTests.SimpleStruct()
+ struct2.long_ = 2
+
+ self.assertRaises(TypeError, GIMarshallingTests.array_simple_struct_in,
+ [struct1, struct2, 'not_a_struct'])
+
def test_array_multi_array_key_value_in(self):
GIMarshallingTests.multi_array_key_value_in(["one", "two", "three"],
[1, 2, 3])
@@ -890,6 +1119,12 @@ class TestArray(unittest.TestCase):
self.assertEqual((True, ['hello']),
GIMarshallingTests.init_function(['hello', 'world']))
+ def test_enum_array_return_type(self):
+ self.assertEqual(GIMarshallingTests.enum_array_return_type(),
+ [GIMarshallingTests.ExtraEnum.VALUE1,
+ GIMarshallingTests.ExtraEnum.VALUE2,
+ GIMarshallingTests.ExtraEnum.VALUE3])
+
class TestGStrv(unittest.TestCase):
@@ -930,11 +1165,22 @@ class TestArrayGVariant(unittest.TestCase):
class TestGArray(unittest.TestCase):
+ @unittest.skipUnless(
+ hasattr(GIMarshallingTests, "garray_bool_none_in"), "too old gi")
+ def test_garray_bool_none_in(self):
+ GIMarshallingTests.garray_bool_none_in([True, False, True, True])
+
+ @unittest.skipUnless(
+ hasattr(GIMarshallingTests, "garray_unichar_none_in"), "too old gi")
+ def test_garray_unichar_none_in(self):
+ GIMarshallingTests.garray_unichar_none_in(CONSTANT_UCS4)
+ GIMarshallingTests.garray_unichar_none_in(list(CONSTANT_UCS4))
+
def test_garray_int_none_return(self):
self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.garray_int_none_return())
def test_garray_uint64_none_return(self):
- self.assertEqual([0, GObject.G_MAXUINT64], GIMarshallingTests.garray_uint64_none_return())
+ self.assertEqual([0, GLib.MAXUINT64], GIMarshallingTests.garray_uint64_none_return())
def test_garray_utf8_none_return(self):
self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_none_return())
@@ -954,7 +1200,7 @@ class TestGArray(unittest.TestCase):
self.assertRaises(TypeError, GIMarshallingTests.garray_int_none_in, None)
def test_garray_uint64_none_in(self):
- GIMarshallingTests.garray_uint64_none_in(Sequence([0, GObject.G_MAXUINT64]))
+ GIMarshallingTests.garray_uint64_none_in(Sequence([0, GLib.MAXUINT64]))
def test_garray_utf8_none_in(self):
GIMarshallingTests.garray_utf8_none_in(Sequence(['0', '1', '2']))
@@ -1061,7 +1307,18 @@ class TestGByteArray(unittest.TestCase):
self.assertEqual(b'\x001\xFF3', GIMarshallingTests.bytearray_full_return())
def test_bytearray_none_in(self):
- GIMarshallingTests.bytearray_none_in(b'\x00\x31\xFF\x33')
+ b = b'\x00\x31\xFF\x33'
+ ba = GLib.ByteArray.new_take(b)
+
+ # b should always have the same value even
+ # though the generated GByteArray is being modified
+ GIMarshallingTests.bytearray_none_in(b)
+ GIMarshallingTests.bytearray_none_in(b)
+
+ # The GByteArray is just a bytes
+ # thus it will not reflect any changes
+ GIMarshallingTests.bytearray_none_in(ba)
+ GIMarshallingTests.bytearray_none_in(ba)
class TestGList(unittest.TestCase):
@@ -1070,7 +1327,7 @@ class TestGList(unittest.TestCase):
self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.glist_int_none_return())
def test_glist_uint32_none_return(self):
- self.assertEqual([0, GObject.G_MAXUINT32], GIMarshallingTests.glist_uint32_none_return())
+ self.assertEqual([0, GLib.MAXUINT32], GIMarshallingTests.glist_uint32_none_return())
def test_glist_utf8_none_return(self):
self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_none_return())
@@ -1089,8 +1346,16 @@ class TestGList(unittest.TestCase):
self.assertRaises(TypeError, GIMarshallingTests.glist_int_none_in, 42)
self.assertRaises(TypeError, GIMarshallingTests.glist_int_none_in, None)
+ def test_glist_int_none_in_error_getitem(self):
+
+ class FailingSequence(Sequence):
+ def __getitem__(self, key):
+ raise Exception
+
+ self.assertRaises(Exception, GIMarshallingTests.glist_int_none_in, FailingSequence((-1, 0, 1, 2)))
+
def test_glist_uint32_none_in(self):
- GIMarshallingTests.glist_uint32_none_in(Sequence((0, GObject.G_MAXUINT32)))
+ GIMarshallingTests.glist_uint32_none_in(Sequence((0, GLib.MAXUINT32)))
def test_glist_utf8_none_in(self):
GIMarshallingTests.glist_utf8_none_in(Sequence(('0', '1', '2')))
@@ -1136,6 +1401,14 @@ class TestGSList(unittest.TestCase):
self.assertRaises(TypeError, GIMarshallingTests.gslist_int_none_in, 42)
self.assertRaises(TypeError, GIMarshallingTests.gslist_int_none_in, None)
+ def test_gslist_int_none_in_error_getitem(self):
+
+ class FailingSequence(Sequence):
+ def __getitem__(self, key):
+ raise Exception
+
+ self.assertRaises(Exception, GIMarshallingTests.gslist_int_none_in, FailingSequence((-1, 0, 1, 2)))
+
def test_gslist_utf8_none_in(self):
GIMarshallingTests.gslist_utf8_none_in(Sequence(('0', '1', '2')))
@@ -1160,6 +1433,26 @@ class TestGSList(unittest.TestCase):
class TestGHashTable(unittest.TestCase):
+ @unittest.skip("broken")
+ def test_ghashtable_double_in(self):
+ GIMarshallingTests.ghashtable_double_in(
+ {"-1": -0.1, "0": 0.0, "1": 0.1, "2": 0.2})
+
+ @unittest.skip("broken")
+ def test_ghashtable_float_in(self):
+ GIMarshallingTests.ghashtable_float_in(
+ {"-1": -0.1, "0": 0.0, "1": 0.1, "2": 0.2})
+
+ @unittest.skip("broken")
+ def test_ghashtable_int64_in(self):
+ GIMarshallingTests.ghashtable_int64_in(
+ {"-1": GLib.MAXUINT32 + 1, "0": 0, "1": 1, "2": 2})
+
+ @unittest.skip("broken")
+ def test_ghashtable_uint64_in(self):
+ GIMarshallingTests.ghashtable_uint64_in(
+ {"-1": GLib.MAXUINT32 + 1, "0": 0, "1": 1, "2": 2})
+
def test_ghashtable_int_none_return(self):
self.assertEqual({-1: 1, 0: 0, 1: -1, 2: -2}, GIMarshallingTests.ghashtable_int_none_return())
@@ -1208,6 +1501,17 @@ class TestGHashTable(unittest.TestCase):
self.assertEqual({'-1': '1', '0': '0', '1': '1'},
GIMarshallingTests.ghashtable_utf8_full_inout(i))
+ def test_ghashtable_enum_none_in(self):
+ GIMarshallingTests.ghashtable_enum_none_in({1: GIMarshallingTests.ExtraEnum.VALUE1,
+ 2: GIMarshallingTests.ExtraEnum.VALUE2,
+ 3: GIMarshallingTests.ExtraEnum.VALUE3})
+
+ def test_ghashtable_enum_none_return(self):
+ self.assertEqual({1: GIMarshallingTests.ExtraEnum.VALUE1,
+ 2: GIMarshallingTests.ExtraEnum.VALUE2,
+ 3: GIMarshallingTests.ExtraEnum.VALUE3},
+ GIMarshallingTests.ghashtable_enum_none_return())
+
class TestGValue(unittest.TestCase):
@@ -1219,15 +1523,13 @@ class TestGValue(unittest.TestCase):
value = GObject.Value(GObject.TYPE_INT, 42)
GIMarshallingTests.gvalue_in(value)
- @unittest.skipUnless(hasattr(GIMarshallingTests, 'gvalue_in_with_modification'),
- 'Newer version of gi needed.')
def test_gvalue_in_with_modification(self):
value = GObject.Value(GObject.TYPE_INT, 42)
GIMarshallingTests.gvalue_in_with_modification(value)
self.assertEqual(value.get_int(), 24)
def test_gvalue_int64_in(self):
- value = GObject.Value(GObject.TYPE_INT64, GObject.G_MAXINT64)
+ value = GObject.Value(GObject.TYPE_INT64, GLib.MAXINT64)
GIMarshallingTests.gvalue_int64_in(value)
def test_gvalue_in_with_type(self):
@@ -1247,7 +1549,7 @@ class TestGValue(unittest.TestCase):
self.assertEqual(42, GIMarshallingTests.gvalue_out())
def test_gvalue_int64_out(self):
- self.assertEqual(GObject.G_MAXINT64, GIMarshallingTests.gvalue_int64_out())
+ self.assertEqual(GLib.MAXINT64, GIMarshallingTests.gvalue_int64_out())
def test_gvalue_out_caller_allocates(self):
self.assertEqual(42, GIMarshallingTests.gvalue_out_caller_allocates())
@@ -1261,10 +1563,46 @@ class TestGValue(unittest.TestCase):
# the function already asserts the correct values
GIMarshallingTests.gvalue_flat_array([42, "42", True])
+ def test_gvalue_flat_array_in_item_marshal_failure(self):
+ # Tests the failure to marshal 2^256 to a GValue mid-way through the array marshaling.
+ self.assertRaises(OverflowError, GIMarshallingTests.gvalue_flat_array,
+ [42, 2 ** 256, True])
+
+ self.assertRaises(OverflowError, GIMarshallingTests.gvalue_flat_array,
+ [GLib.MAXINT + 1, "42", True])
+ self.assertRaises(OverflowError, GIMarshallingTests.gvalue_flat_array,
+ [GLib.MININT - 1, "42", True])
+
+ # FIXME: https://gitlab.gnome.org/GNOME/pygobject/-/issues/582#note_1764164
+ exc_prefix = "Item 0: " if sys.version_info[:2] < (3, 12) else ""
+
+ with pytest.raises(
+ OverflowError,
+ match=exc_prefix + '%d not in range %d to %d' % (
+ GLib.MAXINT + 1, GLib.MININT, GLib.MAXINT)):
+ GIMarshallingTests.gvalue_flat_array([GLib.MAXINT + 1, "42", True])
+
+ min_, max_ = GLib.MININT, GLib.MAXINT
+
+ with pytest.raises(
+ OverflowError,
+ match=exc_prefix + '%d not in range %d to %d' % (
+ GLib.MAXUINT64 * 2, min_, max_)):
+ GIMarshallingTests.gvalue_flat_array([GLib.MAXUINT64 * 2, "42", True])
+
def test_gvalue_flat_array_out(self):
values = GIMarshallingTests.return_gvalue_flat_array()
self.assertEqual(values, [42, '42', True])
+ def test_gvalue_gobject_ref_counts_simple(self):
+ obj = GObject.Object()
+ grefcount = obj.__grefcount__
+ value = GObject.Value(GObject.TYPE_OBJECT, obj)
+ del value
+ gc.collect()
+ gc.collect()
+ assert obj.__grefcount__ == grefcount
+
def test_gvalue_gobject_ref_counts(self):
# Tests a GObject held by a GValue
obj = GObject.Object()
@@ -1296,12 +1634,14 @@ class TestGValue(unittest.TestCase):
del res
del value
gc.collect()
+ gc.collect()
self.assertEqual(obj.__grefcount__, grefcount)
del obj
gc.collect()
self.assertEqual(ref(), None)
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount")
def test_gvalue_boxed_ref_counts(self):
# Tests a boxed type wrapping a python object pointer (TYPE_PYOBJECT)
# held by a GValue
@@ -1342,8 +1682,8 @@ class TestGValue(unittest.TestCase):
gc.collect()
self.assertEqual(ref(), None)
- # FIXME: crashes
- def disabled_test_gvalue_flat_array_round_trip(self):
+ @unittest.skip("broken")
+ def test_gvalue_flat_array_round_trip(self):
self.assertEqual([42, '42', True],
GIMarshallingTests.gvalue_flat_array_round_trip(42, '42', True))
@@ -1353,6 +1693,22 @@ class TestGClosure(unittest.TestCase):
def test_in(self):
GIMarshallingTests.gclosure_in(lambda: 42)
+ def test_in_partial(self):
+ from functools import partial
+
+ called_args = []
+ called_kwargs = {}
+
+ def callback(*args, **kwargs):
+ called_args.extend(args)
+ called_kwargs.update(kwargs)
+ return 42
+
+ func = partial(callback, 1, 2, 3, foo=42)
+ GIMarshallingTests.gclosure_in(func)
+ assert called_args == [1, 2, 3]
+ assert called_kwargs["foo"] == 42
+
def test_pass(self):
# test passing a closure between two C calls
closure = GIMarshallingTests.gclosure_return()
@@ -1402,31 +1758,6 @@ class TestPointer(unittest.TestCase):
class TestEnum(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
- '''Run tests under a test locale.
-
- Upper case conversion of member names should not be locale specific
- e. g. in Turkish, "i".upper() == "i", which gives results like "iNVALiD"
-
- Run test under a locale which defines toupper('a') == 'a'
- '''
- cls.locale_dir = tempfile.mkdtemp()
- src = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'te_ST@nouppera')
- dest = os.path.join(cls.locale_dir, 'te_ST.UTF-8@nouppera')
- subprocess.check_call(['localedef', '-i', src, '-c', '-f', 'UTF-8', dest])
- os.environ['LOCPATH'] = cls.locale_dir
- locale.setlocale(locale.LC_ALL, 'te_ST.UTF-8@nouppera')
-
- @classmethod
- def tearDownClass(cls):
- locale.setlocale(locale.LC_ALL, 'C')
- shutil.rmtree(cls.locale_dir)
- try:
- del os.environ['LOCPATH']
- except KeyError:
- pass
-
def test_enum(self):
self.assertTrue(issubclass(GIMarshallingTests.Enum, int))
self.assertTrue(isinstance(GIMarshallingTests.Enum.VALUE1, GIMarshallingTests.Enum))
@@ -1479,22 +1810,25 @@ class TestEnum(unittest.TestCase):
self.assertEqual(GIMarshallingTests.Enum.__gtype__.name,
'PyGIMarshallingTestsEnum')
- def test_enum_double_registration_error(self):
- # a warning is printed for double registration and pygobject will
- # also raise a RuntimeError.
- old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_ERROR)
- try:
- self.assertRaises(RuntimeError,
- gi._gi.enum_register_new_gtype_and_add,
- GIMarshallingTests.Enum.__info__)
- finally:
- GLib.log_set_always_fatal(old_mask)
-
def test_enum_add_type_error(self):
self.assertRaises(TypeError,
gi._gi.enum_add,
GIMarshallingTests.NoTypeFlags.__gtype__)
+ def test_type_module_name(self):
+ self.assertEqual(GIMarshallingTests.Enum.__name__, "Enum")
+ self.assertEqual(GIMarshallingTests.Enum.__module__,
+ "gi.repository.GIMarshallingTests")
+
+ def test_hash(self):
+ assert (hash(GIMarshallingTests.Enum.VALUE1) ==
+ hash(GIMarshallingTests.Enum(GIMarshallingTests.Enum.VALUE1)))
+
+ def test_repr(self):
+ self.assertEqual(repr(GIMarshallingTests.Enum.VALUE3),
+ "<enum GI_MARSHALLING_TESTS_ENUM_VALUE3 of type "
+ "GIMarshallingTests.Enum>")
+
class TestEnumVFuncResults(unittest.TestCase):
class EnumTester(GIMarshallingTests.Object):
@@ -1522,6 +1856,12 @@ class TestGEnum(unittest.TestCase):
self.assertTrue(isinstance(GIMarshallingTests.GEnum.VALUE3, GIMarshallingTests.GEnum))
self.assertEqual(42, GIMarshallingTests.GEnum.VALUE3)
+ def test_pickle(self):
+ v = GIMarshallingTests.GEnum.VALUE3
+ new_v = pickle.loads(pickle.dumps(v))
+ assert new_v == v
+ assert isinstance(new_v, GIMarshallingTests.GEnum)
+
def test_value_nick_and_name(self):
self.assertEqual(GIMarshallingTests.GEnum.VALUE1.value_nick, 'value1')
self.assertEqual(GIMarshallingTests.GEnum.VALUE2.value_nick, 'value2')
@@ -1534,6 +1874,7 @@ class TestGEnum(unittest.TestCase):
def test_genum_in(self):
GIMarshallingTests.genum_in(GIMarshallingTests.GEnum.VALUE3)
GIMarshallingTests.genum_in(42)
+ GIMarshallingTests.GEnum.in_(42)
self.assertRaises(TypeError, GIMarshallingTests.genum_in, 43)
self.assertRaises(TypeError, GIMarshallingTests.genum_in, 'GIMarshallingTests.GEnum.VALUE3')
@@ -1545,6 +1886,7 @@ class TestGEnum(unittest.TestCase):
def test_genum_out(self):
genum = GIMarshallingTests.genum_out()
+ genum = GIMarshallingTests.GEnum.out()
self.assertTrue(isinstance(genum, GIMarshallingTests.GEnum))
self.assertEqual(genum, GIMarshallingTests.GEnum.VALUE3)
@@ -1553,6 +1895,20 @@ class TestGEnum(unittest.TestCase):
self.assertTrue(isinstance(genum, GIMarshallingTests.GEnum))
self.assertEqual(genum, GIMarshallingTests.GEnum.VALUE1)
+ def test_type_module_name(self):
+ self.assertEqual(GIMarshallingTests.GEnum.__name__, "GEnum")
+ self.assertEqual(GIMarshallingTests.GEnum.__module__,
+ "gi.repository.GIMarshallingTests")
+
+ def test_hash(self):
+ assert (hash(GIMarshallingTests.GEnum.VALUE3) ==
+ hash(GIMarshallingTests.GEnum(GIMarshallingTests.GEnum.VALUE3)))
+
+ def test_repr(self):
+ self.assertEqual(repr(GIMarshallingTests.GEnum.VALUE3),
+ "<enum GI_MARSHALLING_TESTS_GENUM_VALUE3 of type "
+ "GIMarshallingTests.GEnum>")
+
class TestGFlags(unittest.TestCase):
@@ -1577,9 +1933,11 @@ class TestGFlags(unittest.TestCase):
def test_flags_in(self):
GIMarshallingTests.flags_in(GIMarshallingTests.Flags.VALUE2)
+ GIMarshallingTests.Flags.in_(GIMarshallingTests.Flags.VALUE2)
# result of __or__() operation should still be valid instance, not an int.
GIMarshallingTests.flags_in(GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE2)
GIMarshallingTests.flags_in_zero(Number(0))
+ GIMarshallingTests.Flags.in_zero(Number(0))
self.assertRaises(TypeError, GIMarshallingTests.flags_in, 1 << 1)
self.assertRaises(TypeError, GIMarshallingTests.flags_in, 'GIMarshallingTests.Flags.VALUE2')
@@ -1589,6 +1947,11 @@ class TestGFlags(unittest.TestCase):
self.assertTrue(isinstance(flags, GIMarshallingTests.Flags))
self.assertEqual(flags, GIMarshallingTests.Flags.VALUE2)
+ def test_flags_return_method(self):
+ flags = GIMarshallingTests.Flags.returnv()
+ self.assertTrue(isinstance(flags, GIMarshallingTests.Flags))
+ self.assertEqual(flags, GIMarshallingTests.Flags.VALUE2)
+
def test_flags_out(self):
flags = GIMarshallingTests.flags_out()
self.assertTrue(isinstance(flags, GIMarshallingTests.Flags))
@@ -1599,6 +1962,24 @@ class TestGFlags(unittest.TestCase):
self.assertTrue(isinstance(flags, GIMarshallingTests.Flags))
self.assertEqual(flags, GIMarshallingTests.Flags.VALUE1)
+ def test_type_module_name(self):
+ self.assertEqual(GIMarshallingTests.Flags.__name__, "Flags")
+ self.assertEqual(GIMarshallingTests.Flags.__module__,
+ "gi.repository.GIMarshallingTests")
+
+ def test_repr(self):
+ self.assertEqual(repr(GIMarshallingTests.Flags.VALUE2),
+ "<flags GI_MARSHALLING_TESTS_FLAGS_VALUE2 of type "
+ "GIMarshallingTests.Flags>")
+
+ def test_hash(self):
+ assert (hash(GIMarshallingTests.Flags.VALUE2) ==
+ hash(GIMarshallingTests.Flags(GIMarshallingTests.Flags.VALUE2)))
+
+ def test_flags_large_in(self):
+ GIMarshallingTests.extra_flags_large_in(
+ GIMarshallingTests.ExtraFlags.VALUE2)
+
class TestNoTypeFlags(unittest.TestCase):
@@ -1648,16 +2029,16 @@ class TestNoTypeFlags(unittest.TestCase):
self.assertEqual(GIMarshallingTests.NoTypeFlags.__gtype__.name,
'PyGIMarshallingTestsNoTypeFlags')
- def test_flags_double_registration_error(self):
- # a warning is printed for double registration and pygobject will
- # also raise a RuntimeError.
- old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_ERROR)
- try:
- self.assertRaises(RuntimeError,
- gi._gi.flags_register_new_gtype_and_add,
- GIMarshallingTests.NoTypeFlags.__info__)
- finally:
- GLib.log_set_always_fatal(old_mask)
+ def test_type_module_name(self):
+ self.assertEqual(GIMarshallingTests.NoTypeFlags.__name__,
+ "NoTypeFlags")
+ self.assertEqual(GIMarshallingTests.NoTypeFlags.__module__,
+ "gi.repository.GIMarshallingTests")
+
+ def test_repr(self):
+ self.assertEqual(repr(GIMarshallingTests.NoTypeFlags.VALUE2),
+ "<flags GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE2 of "
+ "type GIMarshallingTests.NoTypeFlags>")
class TestStructure(unittest.TestCase):
@@ -1833,6 +2214,19 @@ class TestStructure(unittest.TestCase):
self.assertEqual(struct.long_, 42)
self.assertEqual(struct.string_, 'hello')
+ def test_union_init(self):
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ GIMarshallingTests.Union(42)
+
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
+
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ GIMarshallingTests.Union(f=42)
+
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
+
def test_union(self):
union = GIMarshallingTests.Union()
@@ -1870,6 +2264,27 @@ class TestStructure(unittest.TestCase):
self.assertRaises(TypeError, GIMarshallingTests.Union.method)
+ def test_repr(self):
+ self.assertRegex(
+ repr(GIMarshallingTests.PointerStruct()),
+ r"<GIMarshallingTests.PointerStruct object at 0x[^\s]+ "
+ r"\(void at 0x[^\s]+\)>")
+
+ self.assertRegex(
+ repr(GIMarshallingTests.SimpleStruct()),
+ r"<GIMarshallingTests.SimpleStruct object at 0x[^\s]+ "
+ r"\(void at 0x[^\s]+\)>")
+
+ self.assertRegex(
+ repr(GIMarshallingTests.Union()),
+ r"<GIMarshallingTests.Union object at 0x[^\s]+ "
+ r"\(GIMarshallingTestsUnion at 0x[^\s]+\)>")
+
+ self.assertRegex(
+ repr(GIMarshallingTests.BoxedStruct()),
+ r"<GIMarshallingTests.BoxedStruct object at 0x[^\s]+ "
+ r"\(GIMarshallingTestsBoxedStruct at 0x[^\s]+\)>")
+
class TestGObject(unittest.TestCase):
@@ -1987,6 +2402,9 @@ class TestGObject(unittest.TestCase):
GIMarshallingTests.Object.none_inout(GIMarshallingTests.SubObject(int=42))
def test_object_full_inout(self):
+ # Using gimarshallingtests.c from GI versions > 1.38.0 will show this
+ # test as an "unexpected success" due to reference leak fixes in that file.
+ # TODO: remove the expectedFailure once PyGI relies on GI > 1.38.0.
object_ = GIMarshallingTests.Object(int=42)
new_object = GIMarshallingTests.Object.full_inout(object_)
@@ -1994,9 +2412,21 @@ class TestGObject(unittest.TestCase):
self.assertFalse(object_ is new_object)
- self.assertEqual(object_.__grefcount__, 2)
+ self.assertEqual(object_.__grefcount__, 1)
self.assertEqual(new_object.__grefcount__, 1)
+ def test_repr(self):
+ self.assertRegex(
+ repr(GIMarshallingTests.Object(int=42)),
+ r"<GIMarshallingTests.Object object at 0x[^\s]+ "
+ r"\(GIMarshallingTestsObject at 0x[^\s]+\)>")
+
+ def test_nongir_repr(self):
+ self.assertRegex(
+ repr(Gio.File.new_for_path("/")),
+ r"<__gi__.GLocalFile object at 0x[^\s]+ "
+ r"\(GLocalFile at 0x[^\s]+\)>")
+
# FIXME: Doesn't actually return the same object.
# def test_object_inout_same(self):
# object_ = GIMarshallingTests.Object()
@@ -2086,6 +2516,12 @@ class TestPythonGObject(unittest.TestCase):
object_ = self.Object(int=42)
self.assertTrue(isinstance(object_, self.Object))
+ @unittest.skipUnless(hasattr(GIMarshallingTests.Object, 'new_fail'),
+ 'Requires newer version of GI')
+ def test_object_fail(self):
+ with self.assertRaises(GLib.Error):
+ GIMarshallingTests.Object.new_fail(int_=42)
+
def test_object_method(self):
self.Object(int=0).method()
@@ -2125,6 +2561,7 @@ class TestPythonGObject(unittest.TestCase):
object_.method_with_default_implementation(84)
self.assertEqual(object_.props.int, 84)
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount")
def test_vfunc_return_ref_count(self):
obj = self.Object(int=42)
ref_count = sys.getrefcount(obj.return_for_caller_allocated_out_parameter)
@@ -2138,6 +2575,12 @@ class TestPythonGObject(unittest.TestCase):
self.assertEqual(sys.getrefcount(obj.return_for_caller_allocated_out_parameter),
ref_count)
+ def test_vfunc_return_no_ref_count(self):
+ obj = self.Object(int=42)
+ ret = obj.vfunc_caller_allocated_out_parameter()
+ self.assertEqual(ret, obj.return_for_caller_allocated_out_parameter)
+ self.assertFalse(ret is obj.return_for_caller_allocated_out_parameter)
+
def test_subobject_parent_vfunc(self):
object_ = self.SubObject(int=81)
object_.method_with_default_implementation(87)
@@ -2147,10 +2590,6 @@ class TestPythonGObject(unittest.TestCase):
object_ = self.SubObject(int=1)
self.assertEqual(object_.vfunc_return_value_only(), 2121)
- def test_dynamic_module(self):
- from gi.module import DynamicModule
- self.assertTrue(isinstance(GObject, DynamicModule))
-
def test_subobject_non_vfunc_do_method(self):
class PythonObjectWithNonVFuncDoMethod(object):
def do_not_a_vfunc(self):
@@ -2241,7 +2680,23 @@ class TestPythonGObject(unittest.TestCase):
def test_exception_in_vfunc_return_value(self):
obj = self.ErrorObject()
- self.assertEqual(obj.vfunc_return_value_only(), 0)
+ with capture_exceptions() as exc:
+ self.assertEqual(obj.vfunc_return_value_only(), 0)
+ self.assertEqual(len(exc), 1)
+ self.assertEqual(exc[0].type, ValueError)
+
+ @unittest.skipUnless(hasattr(GIMarshallingTests, 'callback_owned_boxed'),
+ 'requires newer version of GI')
+ def test_callback_owned_box(self):
+ def callback(box, data):
+ self.box = box
+
+ def nop_callback(box, data):
+ pass
+
+ GIMarshallingTests.callback_owned_boxed(callback, None)
+ GIMarshallingTests.callback_owned_boxed(nop_callback, None)
+ self.assertEqual(self.box.long_, 1)
class TestMultiOutputArgs(unittest.TestCase):
@@ -2268,6 +2723,11 @@ class TestInterfaces(unittest.TestCase):
def setUp(self):
self.instance = self.TestInterfaceImpl()
+ def test_iface_impl(self):
+ instance = GIMarshallingTests.InterfaceImpl()
+ assert instance.get_as_interface() is instance
+ instance.test_int8_in(42)
+
def test_wrapper(self):
self.assertTrue(issubclass(GIMarshallingTests.Interface, GObject.GInterface))
self.assertEqual(GIMarshallingTests.Interface.__gtype__.name, 'GIMarshallingTestsInterface')
@@ -2383,7 +2843,7 @@ class TestMRO(unittest.TestCase):
pass
expected = (E, D, B, C, A, GIMarshallingTests.Object,
- GObject.Object, GObject.Object.__base__, gi._gobject.GObject,
+ GObject.Object, GObject.Object.__base__, gi._gi.GObject,
object)
self.assertEqual(expected, E.__mro__)
@@ -2415,10 +2875,7 @@ class TestMRO(unittest.TestCase):
# style mixin.
type('GIWithOldStyleMixin', (GIMarshallingTests.Object, Mixin), {})
- if sys.version_info < (3, 0):
- self.assertTrue(issubclass(warn[0].category, RuntimeWarning))
- else:
- self.assertEqual(len(warn), 0)
+ self.assertEqual(len(warn), 0)
class TestInterfaceClash(unittest.TestCase):
@@ -2483,9 +2940,7 @@ class TestOverrides(unittest.TestCase):
# not overridden
self.assertEqual(GIMarshallingTests.SubObject.__module__, 'gi.repository.GIMarshallingTests')
- # FIXME: does not work with TEST_NAMES='test_thread test_gi.TestOverrides',
- # it is importlib._bootstrap then
- #self.assertEqual(GObject.InitiallyUnowned.__module__, 'gi.repository.GObject')
+ self.assertEqual(GObject.InitiallyUnowned.__module__, 'gi.repository.GObject')
class TestDir(unittest.TestCase):
@@ -2513,55 +2968,6 @@ class TestDir(unittest.TestCase):
# self.assertTrue('DoNotImportDummyTests' in list)
-class TestGError(unittest.TestCase):
- def test_array_in_crash(self):
- # Previously there was a bug in invoke, in which C arrays were unwrapped
- # from inside GArrays to be passed to the C function. But when a GError was
- # set, invoke would attempt to free the C array as if it were a GArray.
- # This crash is only for C arrays. It does not happen for C functions which
- # take in GArrays. See https://bugzilla.gnome.org/show_bug.cgi?id=642708
- self.assertRaises(GObject.GError, GIMarshallingTests.gerror_array_in, [1, 2, 3])
-
- def test_out(self):
- # See https://bugzilla.gnome.org/show_bug.cgi?id=666098
- error, debug = GIMarshallingTests.gerror_out()
-
- self.assertIsInstance(error, GObject.GError)
- self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
- self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
- self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
- self.assertEqual(debug, GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE)
-
- def test_out_transfer_none(self):
- # See https://bugzilla.gnome.org/show_bug.cgi?id=666098
- error, debug = GIMarshallingTests.gerror_out_transfer_none()
-
- self.assertIsInstance(error, GObject.GError)
- self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
- self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
- self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
- self.assertEqual(GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE, debug)
-
- def test_return(self):
- # See https://bugzilla.gnome.org/show_bug.cgi?id=666098
- error = GIMarshallingTests.gerror_return()
-
- self.assertIsInstance(error, GObject.GError)
- self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
- self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
- self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
-
- def test_exception(self):
- self.assertRaises(GObject.GError, GIMarshallingTests.gerror)
- try:
- GIMarshallingTests.gerror()
- except Exception:
- etype, e = sys.exc_info()[:2]
- self.assertEqual(e.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN)
- self.assertEqual(e.code, GIMarshallingTests.CONSTANT_GERROR_CODE)
- self.assertEqual(e.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE)
-
-
class TestParamSpec(unittest.TestCase):
# https://bugzilla.gnome.org/show_bug.cgi?id=682355
@unittest.expectedFailure
@@ -2611,29 +3017,29 @@ class TestKeywordArgs(unittest.TestCase):
def test_type_errors(self):
# test too few args
- self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 arguments (0 given)",
+ self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 arguments (0 given)",
GIMarshallingTests.int_three_in_three_out)
- self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 arguments (1 given)",
+ self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 arguments (1 given)",
GIMarshallingTests.int_three_in_three_out, 1)
- self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 arguments (0 given)",
+ self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 arguments (0 given)",
GIMarshallingTests.int_three_in_three_out, *())
- self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 arguments (0 given)",
+ self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 arguments (0 given)",
GIMarshallingTests.int_three_in_three_out, *(), **{})
- self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 non-keyword arguments (0 given)",
+ self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 non-keyword arguments (0 given)",
GIMarshallingTests.int_three_in_three_out, *(), **{'c': 4})
# test too many args
- self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 arguments (4 given)",
+ self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 arguments (4 given)",
GIMarshallingTests.int_three_in_three_out, *(1, 2, 3, 4))
- self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 non-keyword arguments (4 given)",
+ self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 non-keyword arguments (4 given)",
GIMarshallingTests.int_three_in_three_out, *(1, 2, 3, 4), c=6)
# test too many keyword args
- self.assertRaisesMessage(TypeError, "int_three_in_three_out() got multiple values for keyword argument 'a'",
+ self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() got multiple values for keyword argument 'a'",
GIMarshallingTests.int_three_in_three_out, 1, 2, 3, **{'a': 4, 'b': 5})
- self.assertRaisesMessage(TypeError, "int_three_in_three_out() got an unexpected keyword argument 'd'",
+ self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() got an unexpected keyword argument 'd'",
GIMarshallingTests.int_three_in_three_out, d=4)
- self.assertRaisesMessage(TypeError, "int_three_in_three_out() got an unexpected keyword argument 'e'",
+ self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() got an unexpected keyword argument 'e'",
GIMarshallingTests.int_three_in_three_out, **{'e': 2})
def test_kwargs_are_not_modified(self):
@@ -2642,214 +3048,35 @@ class TestKeywordArgs(unittest.TestCase):
GIMarshallingTests.int_three_in_three_out(1, c=4, **d)
self.assertEqual(d, d2)
+ @unittest.skipUnless(hasattr(GIMarshallingTests, 'int_one_in_utf8_two_in_one_allows_none'),
+ 'Requires newer GIMarshallingTests')
+ def test_allow_none_as_default(self):
+ GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2, '3', '4')
+ GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2, '3')
+ GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2)
+ GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2, d='4')
-class TestPropertiesObject(unittest.TestCase):
-
- def setUp(self):
- self.obj = GIMarshallingTests.PropertiesObject()
-
- def test_boolean(self):
- self.assertEqual(self.obj.props.some_boolean, False)
- self.obj.props.some_boolean = True
- self.assertEqual(self.obj.props.some_boolean, True)
-
- obj = GIMarshallingTests.PropertiesObject(some_boolean=True)
- self.assertEqual(obj.props.some_boolean, True)
-
- def test_char(self):
- self.assertEqual(self.obj.props.some_char, 0)
- self.obj.props.some_char = GObject.G_MAXINT8
- self.assertEqual(self.obj.props.some_char, GObject.G_MAXINT8)
-
- obj = GIMarshallingTests.PropertiesObject(some_char=-42)
- self.assertEqual(obj.props.some_char, -42)
-
- def test_uchar(self):
- self.assertEqual(self.obj.props.some_uchar, 0)
- self.obj.props.some_uchar = GObject.G_MAXUINT8
- self.assertEqual(self.obj.props.some_uchar, GObject.G_MAXUINT8)
-
- obj = GIMarshallingTests.PropertiesObject(some_uchar=42)
- self.assertEqual(obj.props.some_uchar, 42)
-
- def test_int(self):
- self.assertEqual(self.obj.props.some_int, 0)
- self.obj.props.some_int = GObject.G_MAXINT
- self.assertEqual(self.obj.props.some_int, GObject.G_MAXINT)
-
- obj = GIMarshallingTests.PropertiesObject(some_int=-42)
- self.assertEqual(obj.props.some_int, -42)
-
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_int', 'foo')
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_int', None)
-
- self.assertEqual(obj.props.some_int, -42)
-
- def test_uint(self):
- self.assertEqual(self.obj.props.some_uint, 0)
- self.obj.props.some_uint = GObject.G_MAXUINT
- self.assertEqual(self.obj.props.some_uint, GObject.G_MAXUINT)
-
- obj = GIMarshallingTests.PropertiesObject(some_uint=42)
- self.assertEqual(obj.props.some_uint, 42)
-
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_uint', 'foo')
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_uint', None)
-
- self.assertEqual(obj.props.some_uint, 42)
-
- def test_long(self):
- self.assertEqual(self.obj.props.some_long, 0)
- self.obj.props.some_long = GObject.G_MAXLONG
- self.assertEqual(self.obj.props.some_long, GObject.G_MAXLONG)
-
- obj = GIMarshallingTests.PropertiesObject(some_long=-42)
- self.assertEqual(obj.props.some_long, -42)
-
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_long', 'foo')
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_long', None)
-
- self.assertEqual(obj.props.some_long, -42)
-
- def test_ulong(self):
- self.assertEqual(self.obj.props.some_ulong, 0)
- self.obj.props.some_ulong = GObject.G_MAXULONG
- self.assertEqual(self.obj.props.some_ulong, GObject.G_MAXULONG)
-
- obj = GIMarshallingTests.PropertiesObject(some_ulong=42)
- self.assertEqual(obj.props.some_ulong, 42)
-
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_ulong', 'foo')
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_ulong', None)
-
- self.assertEqual(obj.props.some_ulong, 42)
-
- def test_int64(self):
- self.assertEqual(self.obj.props.some_int64, 0)
- self.obj.props.some_int64 = GObject.G_MAXINT64
- self.assertEqual(self.obj.props.some_int64, GObject.G_MAXINT64)
-
- obj = GIMarshallingTests.PropertiesObject(some_int64=-4200000000000000)
- self.assertEqual(obj.props.some_int64, -4200000000000000)
-
- def test_uint64(self):
- self.assertEqual(self.obj.props.some_uint64, 0)
- self.obj.props.some_uint64 = GObject.G_MAXUINT64
- self.assertEqual(self.obj.props.some_uint64, GObject.G_MAXUINT64)
-
- obj = GIMarshallingTests.PropertiesObject(some_uint64=4200000000000000)
- self.assertEqual(obj.props.some_uint64, 4200000000000000)
-
- def test_float(self):
- self.assertEqual(self.obj.props.some_float, 0)
- self.obj.props.some_float = GObject.G_MAXFLOAT
- self.assertEqual(self.obj.props.some_float, GObject.G_MAXFLOAT)
-
- obj = GIMarshallingTests.PropertiesObject(some_float=42.42)
- self.assertAlmostEqual(obj.props.some_float, 42.42, 4)
-
- obj = GIMarshallingTests.PropertiesObject(some_float=42)
- self.assertAlmostEqual(obj.props.some_float, 42.0, 4)
-
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_float', 'foo')
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_float', None)
-
- self.assertAlmostEqual(obj.props.some_float, 42.0, 4)
-
- def test_double(self):
- self.assertEqual(self.obj.props.some_double, 0)
- self.obj.props.some_double = GObject.G_MAXDOUBLE
- self.assertEqual(self.obj.props.some_double, GObject.G_MAXDOUBLE)
-
- obj = GIMarshallingTests.PropertiesObject(some_double=42.42)
- self.assertAlmostEqual(obj.props.some_double, 42.42)
-
- obj = GIMarshallingTests.PropertiesObject(some_double=42)
- self.assertAlmostEqual(obj.props.some_double, 42.0)
-
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_double', 'foo')
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_double', None)
-
- self.assertAlmostEqual(obj.props.some_double, 42.0)
-
- def test_strv(self):
- self.assertEqual(self.obj.props.some_strv, [])
- self.obj.props.some_strv = ['hello', 'world']
- self.assertEqual(self.obj.props.some_strv, ['hello', 'world'])
-
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_strv', 1)
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_strv', 'foo')
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_strv', [1, 2])
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_strv', ['foo', 1])
-
- self.assertEqual(self.obj.props.some_strv, ['hello', 'world'])
-
- obj = GIMarshallingTests.PropertiesObject(some_strv=['hello', 'world'])
- self.assertEqual(obj.props.some_strv, ['hello', 'world'])
-
- def test_boxed_struct(self):
- self.assertEqual(self.obj.props.some_boxed_struct, None)
-
- class GStrv(list):
- __gtype__ = GObject.TYPE_STRV
-
- struct1 = GIMarshallingTests.BoxedStruct()
- struct1.long_ = 1
-
- self.obj.props.some_boxed_struct = struct1
- self.assertEqual(self.obj.props.some_boxed_struct.long_, 1)
- self.assertEqual(self.obj.some_boxed_struct.long_, 1)
-
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_boxed_struct', 1)
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_boxed_struct', 'foo')
-
- obj = GIMarshallingTests.PropertiesObject(some_boxed_struct=struct1)
- self.assertEqual(obj.props.some_boxed_struct.long_, 1)
-
- def test_boxed_glist(self):
- self.assertEqual(self.obj.props.some_boxed_glist, [])
-
- l = [GObject.G_MININT, 42, GObject.G_MAXINT]
- self.obj.props.some_boxed_glist = l
- self.assertEqual(self.obj.props.some_boxed_glist, l)
- self.obj.props.some_boxed_glist = []
- self.assertEqual(self.obj.props.some_boxed_glist, [])
-
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_boxed_glist', 1)
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_boxed_glist', 'foo')
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_boxed_glist', ['a'])
-
- @unittest.expectedFailure
- def test_boxed_glist_ctor(self):
- l = [GObject.G_MININT, 42, GObject.G_MAXINT]
- obj = GIMarshallingTests.PropertiesObject(some_boxed_glist=l)
- self.assertEqual(obj.props.some_boxed_glist, l)
-
- def test_variant(self):
- self.assertEqual(self.obj.props.some_variant, None)
-
- self.obj.props.some_variant = GLib.Variant('o', '/myobj')
- self.assertEqual(self.obj.props.some_variant.get_type_string(), 'o')
- self.assertEqual(self.obj.props.some_variant.print_(False), "'/myobj'")
-
- self.obj.props.some_variant = None
- self.assertEqual(self.obj.props.some_variant, None)
-
- obj = GIMarshallingTests.PropertiesObject(some_variant=GLib.Variant('b', True))
- self.assertEqual(obj.props.some_variant.get_type_string(), 'b')
- self.assertEqual(obj.props.some_variant.get_boolean(), True)
-
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_variant', 'foo')
- self.assertRaises(TypeError, setattr, self.obj.props, 'some_variant', 23)
+ GIMarshallingTests.array_in_utf8_two_in_out_of_order('1', [-1, 0, 1, 2])
+ GIMarshallingTests.array_in_utf8_two_in_out_of_order('1', [-1, 0, 1, 2], '2')
+ self.assertRaises(TypeError,
+ GIMarshallingTests.array_in_utf8_two_in_out_of_order,
+ [-1, 0, 1, 2], a='1')
+ self.assertRaises(TypeError,
+ GIMarshallingTests.array_in_utf8_two_in_out_of_order,
+ [-1, 0, 1, 2])
- self.assertEqual(obj.props.some_variant.get_type_string(), 'b')
- self.assertEqual(obj.props.some_variant.get_boolean(), True)
+ GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2], '1', '2')
+ GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2], '1')
+ GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2])
+ GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2], b='2')
- def test_setting_several_properties(self):
- obj = GIMarshallingTests.PropertiesObject()
- obj.set_properties(some_uchar=54, some_int=42)
- self.assertEqual(42, obj.props.some_int)
- self.assertEqual(54, obj.props.some_uchar)
+ GIMarshallingTests.int_one_in_utf8_two_in_one_allows_none(1, '2', '3')
+ self.assertRaises(TypeError,
+ GIMarshallingTests.int_one_in_utf8_two_in_one_allows_none,
+ 1, '3')
+ self.assertRaises(TypeError,
+ GIMarshallingTests.int_one_in_utf8_two_in_one_allows_none,
+ 1, c='3')
class TestKeywords(unittest.TestCase):
@@ -2874,8 +3101,10 @@ class TestKeywords(unittest.TestCase):
class TestModule(unittest.TestCase):
def test_path(self):
- self.assertTrue(GIMarshallingTests.__path__.endswith('GIMarshallingTests-1.0.typelib'),
- GIMarshallingTests.__path__)
+ path = GIMarshallingTests.__path__
+ assert isinstance(path, list)
+ assert len(path) == 1
+ assert path[0].endswith('GIMarshallingTests-1.0.typelib')
def test_str(self):
self.assertTrue("'GIMarshallingTests' from '" in str(GIMarshallingTests),
@@ -2896,16 +3125,9 @@ class TestModule(unittest.TestCase):
self.assertTrue(hasattr(item, '__class__'))
def test_help(self):
- orig_stdout = sys.stdout
- try:
- if sys.version_info < (3, 0):
- sys.stdout = BytesIO()
- else:
- sys.stdout = StringIO()
+ with capture_output() as (stdout, stderr):
help(GIMarshallingTests)
- output = sys.stdout.getvalue()
- finally:
- sys.stdout = orig_stdout
+ output = stdout.getvalue()
self.assertTrue('SimpleStruct' in output, output)
self.assertTrue('Interface2' in output, output)
@@ -2914,7 +3136,7 @@ class TestModule(unittest.TestCase):
class TestProjectVersion(unittest.TestCase):
def test_version_str(self):
- self.assertGreaterEqual(gi.__version__, "3.3.5")
+ self.assertGreater(gi.__version__, "3.")
def test_version_info(self):
self.assertEqual(len(gi.version_info), 3)
@@ -2927,20 +3149,18 @@ class TestProjectVersion(unittest.TestCase):
gi.check_version("3.3.5")
-class TestObjectInfo(unittest.TestCase):
- def test_get_abstract_with_abstract(self):
- repo = gi.gi.Repository.get_default()
- info = repo.find_by_name('GObject', 'TypeModule')
- self.assertTrue(info.get_abstract())
+class TestGIWarning(unittest.TestCase):
- def test_get_abstract_with_concrete(self):
- repo = gi.gi.Repository.get_default()
- info = repo.find_by_name('GObject', 'Object')
- self.assertFalse(info.get_abstract())
+ def test_warning(self):
+ ignored_by_default = (DeprecationWarning, PendingDeprecationWarning,
+ ImportWarning)
- def test_get_class_struct(self):
- self.assertEqual(GObject.Object.__info__.get_class_struct(),
- GObject.ObjectClass.__info__)
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ warnings.warn("test", PyGIWarning)
+ self.assertTrue(issubclass(warn[0].category, Warning))
+ # We don't want PyGIWarning get ignored by default
+ self.assertFalse(issubclass(warn[0].category, ignored_by_default))
class TestDeprecation(unittest.TestCase):
@@ -2950,3 +3170,156 @@ class TestDeprecation(unittest.TestCase):
warnings.simplefilter('always')
d.set_time(1)
self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
+ self.assertEqual(str(warn[0].message), "GLib.Date.set_time is deprecated")
+
+ def test_function(self):
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ GLib.strcasecmp("foo", "bar")
+ self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
+ self.assertEqual(str(warn[0].message), "GLib.strcasecmp is deprecated")
+
+ def test_deprecated_attribute_compat(self):
+ # test if the deprecation descriptor behaves like an instance attribute
+
+ # save the descriptor
+ desc = type(GLib).__dict__["IO_STATUS_ERROR"]
+
+ # the descriptor raises AttributeError for itself
+ self.assertFalse(hasattr(type(GLib), "IO_STATUS_ERROR"))
+
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', PyGIDeprecationWarning)
+ self.assertTrue(hasattr(GLib, "IO_STATUS_ERROR"))
+
+ try:
+ # check if replacing works
+ GLib.IO_STATUS_ERROR = "foo"
+ self.assertEqual(GLib.IO_STATUS_ERROR, "foo")
+ finally:
+ # restore descriptor
+ try:
+ del GLib.IO_STATUS_ERROR
+ except AttributeError:
+ pass
+ setattr(type(GLib), "IO_STATUS_ERROR", desc)
+
+ try:
+ # check if deleting works
+ del GLib.IO_STATUS_ERROR
+ self.assertFalse(hasattr(GLib, "IO_STATUS_ERROR"))
+ finally:
+ # restore descriptor
+ try:
+ del GLib.IO_STATUS_ERROR
+ except AttributeError:
+ pass
+ setattr(type(GLib), "IO_STATUS_ERROR", desc)
+
+ def test_deprecated_attribute_warning(self):
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ self.assertEqual(GLib.IO_STATUS_ERROR, GLib.IOStatus.ERROR)
+ GLib.IO_STATUS_ERROR
+ GLib.IO_STATUS_ERROR
+ self.assertEqual(len(warn), 3)
+ self.assertTrue(
+ issubclass(warn[0].category, PyGIDeprecationWarning))
+ self.assertRegex(
+ str(warn[0].message),
+ ".*GLib.IO_STATUS_ERROR.*GLib.IOStatus.ERROR.*")
+
+ def test_deprecated_attribute_warning_coverage(self):
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ GObject.markup_escape_text
+ GObject.PRIORITY_DEFAULT
+ GObject.GError
+ GObject.PARAM_CONSTRUCT
+ GObject.SIGNAL_ACTION
+ GObject.property
+ GObject.IO_STATUS_ERROR
+ GObject.G_MAXUINT64
+ GLib.IO_STATUS_ERROR
+ GLib.SPAWN_SEARCH_PATH
+ GLib.OPTION_FLAG_HIDDEN
+ GLib.IO_FLAG_IS_WRITEABLE
+ GLib.IO_FLAG_NONBLOCK
+ GLib.USER_DIRECTORY_DESKTOP
+ GLib.OPTION_ERROR_BAD_VALUE
+ GLib.glib_version
+ GLib.pyglib_version
+ self.assertEqual(len(warn), 17)
+
+ def test_deprecated_init_no_keywords(self):
+ def init(self, **kwargs):
+ self.assertDictEqual(kwargs, {'a': 1, 'b': 2, 'c': 3})
+
+ fn = gi.overrides.deprecated_init(init, arg_names=('a', 'b', 'c'))
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ fn(self, 1, 2, 3)
+ self.assertEqual(len(warn), 1)
+ self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
+ self.assertRegex(str(warn[0].message),
+ '.*keyword.*a, b, c.*')
+
+ def test_deprecated_init_no_keywords_out_of_order(self):
+ def init(self, **kwargs):
+ self.assertDictEqual(kwargs, {'a': 1, 'b': 2, 'c': 3})
+
+ fn = gi.overrides.deprecated_init(init, arg_names=('b', 'a', 'c'))
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ fn(self, 2, 1, 3)
+ self.assertEqual(len(warn), 1)
+ self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
+ self.assertRegex(str(warn[0].message),
+ '.*keyword.*b, a, c.*')
+
+ def test_deprecated_init_ignored_keyword(self):
+ def init(self, **kwargs):
+ self.assertDictEqual(kwargs, {'a': 1, 'c': 3})
+
+ fn = gi.overrides.deprecated_init(init,
+ arg_names=('a', 'b', 'c'),
+ ignore=('b',))
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ fn(self, 1, 2, 3)
+ self.assertEqual(len(warn), 1)
+ self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
+ self.assertRegex(str(warn[0].message),
+ '.*keyword.*a, b, c.*')
+
+ def test_deprecated_init_with_aliases(self):
+ def init(self, **kwargs):
+ self.assertDictEqual(kwargs, {'a': 1, 'b': 2, 'c': 3})
+
+ fn = gi.overrides.deprecated_init(init,
+ arg_names=('a', 'b', 'c'),
+ deprecated_aliases={'b': 'bb', 'c': 'cc'})
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+
+ fn(self, a=1, bb=2, cc=3)
+ self.assertEqual(len(warn), 1)
+ self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
+ self.assertRegex(str(warn[0].message),
+ '.*keyword.*"bb, cc".*deprecated.*"b, c" respectively')
+
+ def test_deprecated_init_with_defaults(self):
+ def init(self, **kwargs):
+ self.assertDictEqual(kwargs, {'a': 1, 'b': 2, 'c': 3})
+
+ fn = gi.overrides.deprecated_init(init,
+ arg_names=('a', 'b', 'c'),
+ deprecated_defaults={'b': 2, 'c': 3})
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ fn(self, a=1)
+ self.assertEqual(len(warn), 1)
+ self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
+ self.assertRegex(str(warn[0].message),
+ '.*relying on deprecated non-standard defaults.*'
+ 'explicitly use: b=2, c=3')
diff --git a/tests/test_gio.py b/tests/test_gio.py
index 57ab013..07ee506 100644
--- a/tests/test_gio.py
+++ b/tests/test_gio.py
@@ -1,11 +1,18 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
# vim: tabstop=4 shiftwidth=4 expandtab
+import os
import unittest
+import warnings
+
+import pytest
import gi.overrides
+from gi import PyGIWarning
from gi.repository import GLib, Gio
+from .helper import ignore_gi_deprecation_warnings
+
class TestGio(unittest.TestCase):
def test_file_enumerator(self):
@@ -37,10 +44,19 @@ class TestGio(unittest.TestCase):
value = menu.get_item_attribute_value(0, "action", GLib.VariantType.new("s"))
self.assertEqual("app.test", value.unpack())
+ def test_volume_monitor_warning(self):
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ Gio.VolumeMonitor()
+ self.assertEqual(len(warn), 1)
+ self.assertTrue(issubclass(warn[0].category, PyGIWarning))
+ self.assertRegex(str(warn[0].message),
+ '.*Gio\\.VolumeMonitor\\.get\\(\\).*')
+
class TestGSettings(unittest.TestCase):
def setUp(self):
- self.settings = Gio.Settings('org.gnome.test')
+ self.settings = Gio.Settings.new('org.gnome.test')
# we change the values in the tests, so set them to predictable start
# value
self.settings.reset('test-string')
@@ -48,6 +64,17 @@ class TestGSettings(unittest.TestCase):
self.settings.reset('test-boolean')
self.settings.reset('test-enum')
+ def test_iter(self):
+ assert set(list(self.settings)) == set([
+ 'test-tuple', 'test-array', 'test-boolean', 'test-string',
+ 'test-enum', 'test-range'])
+
+ def test_get_set(self):
+ for key in self.settings:
+ old_value = self.settings[key]
+ self.settings[key] = old_value
+ assert self.settings[key] == old_value
+
def test_native(self):
self.assertTrue('test-array' in self.settings.list_keys())
@@ -66,6 +93,9 @@ class TestGSettings(unittest.TestCase):
v = self.settings.get_value('test-tuple')
self.assertEqual(v.unpack(), (1, 2))
+ v = self.settings.get_value('test-range')
+ assert v.unpack() == 123
+
# set a value
self.settings.set_string('test-string', 'World')
self.assertEqual(self.settings.get_string('test-string'), 'World')
@@ -78,12 +108,12 @@ class TestGSettings(unittest.TestCase):
self.assertEqual(self.settings.get_property('path'), '/tests/')
# optional constructor arguments
- with_path = Gio.Settings('org.gnome.nopathtest', path='/mypath/')
+ with_path = Gio.Settings.new_with_path('org.gnome.nopathtest', '/mypath/')
self.assertEqual(with_path.get_property('path'), '/mypath/')
self.assertEqual(with_path['np-int'], 42)
def test_dictionary_api(self):
- self.assertEqual(len(self.settings), 5)
+ self.assertEqual(len(self.settings), 6)
self.assertTrue('test-array' in self.settings)
self.assertTrue('test-array' in self.settings.keys())
self.assertFalse('nonexisting' in self.settings)
@@ -114,12 +144,25 @@ class TestGSettings(unittest.TestCase):
self.assertRaises(ValueError, self.settings.__setitem__, 'test-enum', 'plum')
self.assertRaises(KeyError, self.settings.__setitem__, 'unknown', 'moo')
+ def test_set_range(self):
+ self.settings['test-range'] = 7
+ assert self.settings['test-range'] == 7
+ self.settings['test-range'] = 65535
+ assert self.settings['test-range'] == 65535
+
+ with pytest.raises(ValueError, match=".*7 - 65535.*"):
+ self.settings['test-range'] = 7 - 1
+
+ with pytest.raises(ValueError, match=".*7 - 65535.*"):
+ self.settings['test-range'] = 65535 + 1
+
def test_empty(self):
- empty = Gio.Settings('org.gnome.empty', path='/tests/')
+ empty = Gio.Settings.new_with_path('org.gnome.empty', '/tests/')
self.assertEqual(len(empty), 0)
self.assertEqual(bool(empty), True)
self.assertEqual(empty.keys(), [])
+ @ignore_gi_deprecation_warnings
def test_change_event(self):
changed_log = []
change_event_log = []
@@ -139,6 +182,7 @@ class TestGSettings(unittest.TestCase):
1)])
+@unittest.skipIf(os.name == "nt", "FIXME")
class TestGFile(unittest.TestCase):
def setUp(self):
self.file, self.io_stream = Gio.File.new_tmp('TestGFile.XXXXXX')
@@ -201,3 +245,98 @@ class TestGFile(unittest.TestCase):
main_loop = GLib.MainLoop()
main_loop.run()
self.assertFalse(self.file.query_exists(None))
+
+
+@unittest.skipIf(os.name == "nt", "crashes on Windows")
+class TestGApplication(unittest.TestCase):
+ def test_command_line(self):
+ class App(Gio.Application):
+ args = None
+
+ def __init__(self):
+ super(App, self).__init__(flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
+
+ def do_command_line(self, cmdline):
+ self.args = cmdline.get_arguments()
+ return 42
+
+ app = App()
+ res = app.run(['spam', 'eggs'])
+
+ self.assertEqual(res, 42)
+ self.assertSequenceEqual(app.args, ['spam', 'eggs'])
+
+ def test_local_command_line(self):
+ class App(Gio.Application):
+ local_args = None
+
+ def __init__(self):
+ super(App, self).__init__(flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
+
+ def do_local_command_line(self, args):
+ self.local_args = args[:] # copy
+ args.remove('eggs')
+
+ # True skips do_command_line being called.
+ return True, args, 42
+
+ app = App()
+ res = app.run(['spam', 'eggs'])
+
+ self.assertEqual(res, 42)
+ self.assertSequenceEqual(app.local_args, ['spam', 'eggs'])
+
+ def test_local_and_remote_command_line(self):
+ class App(Gio.Application):
+ args = None
+ local_args = None
+
+ def __init__(self):
+ super(App, self).__init__(flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
+
+ def do_command_line(self, cmdline):
+ self.args = cmdline.get_arguments()
+ return 42
+
+ def do_local_command_line(self, args):
+ self.local_args = args[:] # copy
+ args.remove('eggs')
+
+ # False causes do_command_line to be called with args.
+ return False, args, 0
+
+ app = App()
+ res = app.run(['spam', 'eggs'])
+
+ self.assertEqual(res, 42)
+ self.assertSequenceEqual(app.args, ['spam'])
+ self.assertSequenceEqual(app.local_args, ['spam', 'eggs'])
+
+ @unittest.skipUnless(hasattr(Gio.Application, 'add_main_option'),
+ 'Requires newer version of GLib')
+ def test_add_main_option(self):
+ stored_options = []
+
+ def on_handle_local_options(app, options):
+ stored_options.append(options)
+ return 0 # Return 0 if options have been handled
+
+ def on_activate(app):
+ pass
+
+ app = Gio.Application()
+ app.add_main_option(long_name='string',
+ short_name=b's',
+ flags=0,
+ arg=GLib.OptionArg.STRING,
+ description='some string')
+
+ app.connect('activate', on_activate)
+ app.connect('handle-local-options', on_handle_local_options)
+ app.run(['app', '-s', 'test string'])
+
+ self.assertEqual(len(stored_options), 1)
+ options = stored_options[0]
+ self.assertTrue(options.contains('string'))
+ self.assertEqual(options.lookup_value('string').unpack(),
+ 'test string')
diff --git a/tests/test_glib.py b/tests/test_glib.py
index 3cde168..19eff7f 100644
--- a/tests/test_glib.py
+++ b/tests/test_glib.py
@@ -1,31 +1,45 @@
# -*- Mode: Python -*-
-# encoding: UTF-8
+import os
+import sys
import unittest
import os.path
import warnings
import subprocess
+import pytest
from gi.repository import GLib
from gi import PyGIDeprecationWarning
-from compathelper import _unicode, _bytes
-
class TestGLib(unittest.TestCase):
+
+ @pytest.mark.xfail()
+ def test_pytest_capture_error_in_closure(self):
+ # this test is supposed to fail
+ ml = GLib.MainLoop()
+
+ def callback():
+ ml.quit()
+ raise Exception("expected")
+
+ GLib.idle_add(callback)
+ ml.run()
+
+ @unittest.skipIf(os.name == "nt", "no bash on Windows")
def test_find_program_in_path(self):
bash_path = GLib.find_program_in_path('bash')
- self.assertTrue(bash_path.endswith('/bash'))
+ self.assertTrue(bash_path.endswith(os.path.sep + 'bash'))
self.assertTrue(os.path.exists(bash_path))
self.assertEqual(GLib.find_program_in_path('non existing'), None)
def test_markup_escape_text(self):
- self.assertEqual(GLib.markup_escape_text(_unicode('a&bä')), 'a&amp;bä')
- self.assertEqual(GLib.markup_escape_text(_bytes('a&b\x05')), 'a&amp;b&#x5;')
+ self.assertEqual(GLib.markup_escape_text(u'a&bä'), 'a&amp;bä')
+ self.assertEqual(GLib.markup_escape_text(b'a&b\x05'), 'a&amp;b&#x5;')
# with explicit length argument
- self.assertEqual(GLib.markup_escape_text(_bytes('a\x05\x01\x02'), 2), 'a&#x5;')
+ self.assertEqual(GLib.markup_escape_text(b'a\x05\x01\x02', 2), 'a&#x5;')
def test_progname(self):
GLib.set_prgname('moo')
@@ -37,15 +51,18 @@ class TestGLib(unittest.TestCase):
def test_xdg_dirs(self):
d = GLib.get_user_data_dir()
- self.assertTrue('/' in d, d)
- d = GLib.get_user_special_dir(GLib.USER_DIRECTORY_DESKTOP)
- self.assertTrue('/' in d, d)
- # also works with backwards compatible enum names
- self.assertEqual(GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_MUSIC),
- GLib.get_user_special_dir(GLib.USER_DIRECTORY_MUSIC))
+ self.assertTrue(os.path.sep in d, d)
+ d = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP)
+ self.assertTrue(os.path.sep in d, d)
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', PyGIDeprecationWarning)
+
+ # also works with backwards compatible enum names
+ self.assertEqual(GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_MUSIC),
+ GLib.get_user_special_dir(GLib.USER_DIRECTORY_MUSIC))
for d in GLib.get_system_config_dirs():
- self.assertTrue('/' in d, d)
+ self.assertTrue(os.path.sep in d, d)
for d in GLib.get_system_data_dirs():
self.assertTrue(isinstance(d, str), d)
@@ -56,13 +73,26 @@ class TestGLib(unittest.TestCase):
self.assertEqual(GLib.filename_display_name('foo'), 'foo')
self.assertEqual(GLib.filename_display_basename('bar/foo'), 'foo')
+ def glibfsencode(f):
+ # the annotations of filename_from_utf8() was changed in
+ # https://bugzilla.gnome.org/show_bug.cgi?id=756128
+ if isinstance(f, bytes):
+ return f
+ if os.name == "nt":
+ return f.encode("utf-8", "surrogatepass")
+ else:
+ return os.fsencode(f)
+
# this is locale dependent, so we cannot completely verify the result
- res = GLib.filename_from_utf8(_unicode('aäb'))
+ res = GLib.filename_from_utf8(u'aäb')
+ res = glibfsencode(res)
self.assertTrue(isinstance(res, bytes))
self.assertGreaterEqual(len(res), 3)
# with explicit length argument
- self.assertEqual(GLib.filename_from_utf8(_unicode('aäb'), 1), b'a')
+ res = GLib.filename_from_utf8(u'aäb', 1)
+ res = glibfsencode(res)
+ self.assertEqual(res, b'a')
def test_uri_extract(self):
res = GLib.uri_list_extract_uris('''# some comment
@@ -82,6 +112,7 @@ https://my.org/q?x=1&y=2
self.assertTrue(isinstance(tm, float))
self.assertGreater(tm, 1350000000.0)
+ @unittest.skipIf(sys.platform == "darwin", "fails on OSX")
def test_main_loop(self):
# note we do not test run() here, as we use this in countless other
# tests
@@ -119,57 +150,96 @@ https://my.org/q?x=1&y=2
self.assertTrue(context.pending() in [True, False])
self.assertTrue(context.iteration(False) in [True, False])
+ @unittest.skipIf(os.name == "nt", "hangs")
def test_io_add_watch_no_data(self):
(r, w) = os.pipe()
call_data = []
def cb(fd, condition):
call_data.append((fd, condition, os.read(fd, 1)))
+ if len(call_data) == 2:
+ ml.quit()
return True
# io_add_watch() takes an IOChannel, calling with an fd is deprecated
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
- GLib.io_add_watch(r, GLib.IOCondition.IN, cb)
+ GLib.io_add_watch(r, GLib.IOCondition.IN, cb,
+ priority=GLib.PRIORITY_HIGH)
self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
+ def write():
+ os.write(w, b'a')
+ GLib.idle_add(lambda: os.write(w, b'b') and False)
+
ml = GLib.MainLoop()
- GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
- GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
- GLib.timeout_add(200, ml.quit)
+ GLib.idle_add(write)
+ GLib.timeout_add(2000, ml.quit)
ml.run()
self.assertEqual(call_data, [(r, GLib.IOCondition.IN, b'a'),
(r, GLib.IOCondition.IN, b'b')])
+ @unittest.skipIf(os.name == "nt", "hangs")
def test_io_add_watch_with_data(self):
(r, w) = os.pipe()
call_data = []
def cb(fd, condition, data):
call_data.append((fd, condition, os.read(fd, 1), data))
+ if len(call_data) == 2:
+ ml.quit()
return True
# io_add_watch() takes an IOChannel, calling with an fd is deprecated
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
- GLib.io_add_watch(r, GLib.IOCondition.IN, cb, 'moo')
+ GLib.io_add_watch(r, GLib.IOCondition.IN, cb, 'moo',
+ priority=GLib.PRIORITY_HIGH)
self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
+ def write():
+ os.write(w, b'a')
+ GLib.idle_add(lambda: os.write(w, b'b') and False)
+
ml = GLib.MainLoop()
- GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
- GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
- GLib.timeout_add(200, ml.quit)
+ GLib.idle_add(write)
+ GLib.timeout_add(2000, ml.quit)
ml.run()
self.assertEqual(call_data, [(r, GLib.IOCondition.IN, b'a', 'moo'),
(r, GLib.IOCondition.IN, b'b', 'moo')])
+ @unittest.skipIf(os.name == "nt", "hangs")
+ def test_io_add_watch_with_multiple_data(self):
+ (r, w) = os.pipe()
+ call_data = []
+
+ def cb(fd, condition, *user_data):
+ call_data.append((fd, condition, os.read(fd, 1), user_data))
+ ml.quit()
+ return True
+
+ # io_add_watch() takes an IOChannel, calling with an fd is deprecated
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ GLib.io_add_watch(r, GLib.IOCondition.IN, cb, 'moo', 'foo')
+ self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
+
+ ml = GLib.MainLoop()
+ GLib.idle_add(lambda: os.write(w, b'a') and False)
+ GLib.timeout_add(2000, ml.quit)
+ ml.run()
+
+ self.assertEqual(call_data, [(r, GLib.IOCondition.IN, b'a', ('moo', 'foo'))])
+
+ @unittest.skipIf(sys.platform == "darwin", "fails")
+ @unittest.skipIf(os.name == "nt", "no shell on Windows")
def test_io_add_watch_pyfile(self):
call_data = []
- cmd = subprocess.Popen('sleep 0.1; echo hello; sleep 0.2; echo world',
- shell=True, stdout=subprocess.PIPE)
+ cmd = subprocess.Popen('echo hello; echo world',
+ shell=True, bufsize=0, stdout=subprocess.PIPE)
def cb(file, condition):
call_data.append((file, condition, file.readline()))
@@ -194,13 +264,32 @@ https://my.org/q?x=1&y=2
(cmd.stdout, GLib.IOCondition.IN, b'world\n')])
def test_glib_version(self):
- (major, minor, micro) = GLib.glib_version
- self.assertGreaterEqual(major, 2)
- self.assertGreaterEqual(minor, 0)
- self.assertGreaterEqual(micro, 0)
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', PyGIDeprecationWarning)
+
+ (major, minor, micro) = GLib.glib_version
+ self.assertGreaterEqual(major, 2)
+ self.assertGreaterEqual(minor, 0)
+ self.assertGreaterEqual(micro, 0)
def test_pyglib_version(self):
- (major, minor, micro) = GLib.pyglib_version
- self.assertGreaterEqual(major, 3)
- self.assertGreaterEqual(minor, 0)
- self.assertGreaterEqual(micro, 0)
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', PyGIDeprecationWarning)
+
+ (major, minor, micro) = GLib.pyglib_version
+ self.assertGreaterEqual(major, 3)
+ self.assertGreaterEqual(minor, 0)
+ self.assertGreaterEqual(micro, 0)
+
+ def test_timezone_constructor(self):
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', DeprecationWarning)
+ timezone = GLib.TimeZone("+05:21")
+ self.assertEqual(timezone.get_offset(0), ((5 * 60) + 21) * 60)
+
+ def test_source_attach_implicit_context(self):
+ context = GLib.MainContext.default()
+ source = GLib.Idle()
+ source_id = source.attach()
+ self.assertEqual(context, source.get_context())
+ self.assertTrue(GLib.Source.remove(source_id))
diff --git a/tests/test_gobject.py b/tests/test_gobject.py
index 57d3822..fbc3bb7 100644
--- a/tests/test_gobject.py
+++ b/tests/test_gobject.py
@@ -4,24 +4,101 @@ import sys
import gc
import unittest
import warnings
+import weakref
+import platform
-from gi.repository import GObject, GLib
+import pytest
+
+from gi.repository import GObject, GLib, Gio
from gi import PyGIDeprecationWarning
from gi.module import get_introspection_module
-from gi._gobject import _gobject
+from gi import _gi
import testhelper
+from .helper import capture_glib_deprecation_warnings
+
+
+@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="crashes")
+def test_gobject_weak_ref():
+
+ called = []
+
+ def callback(*args):
+ called.extend(args)
+
+ # object gets finalized
+ obj = GObject.Object()
+ obj.weak_ref(callback, 1)
+ del obj
+ gc.collect()
+ gc.collect()
+ assert called == [1]
+ del called[:]
+
+ # wrapper gets finalized first
+ obj = GObject.Object()
+ pyref = weakref.ref(obj, lambda x: callback(-2))
+ value = GObject.Value(GObject.Object, obj)
+ ref = obj.weak_ref(callback, 2)
+ del obj
+ gc.collect()
+ assert called == [-2]
+ del pyref
+ value.unset()
+ gc.collect()
+ assert called == [-2, 2]
+ del called[:]
+
+ # weakref gets unregistered first
+ obj = GObject.Object()
+ ref = obj.weak_ref(callback, 3)
+ ref.unref()
+ del obj
+ gc.collect()
+ assert not called
+
+ # weakref gets GCed
+ obj = GObject.Object()
+ obj.weak_ref(callback, 4)
+ gc.collect()
+ del obj
+ assert called == [4]
class TestGObjectAPI(unittest.TestCase):
+
+ def test_run_dispose(self):
+ class TestObject(GObject.GObject):
+ int_prop = GObject.Property(default=0, type=int)
+
+ obj = TestObject()
+ called = []
+
+ def on_notify(*args):
+ called.append(args)
+
+ obj.connect('notify::int-prop', on_notify)
+ obj.notify("int-prop")
+ obj.notify("int-prop")
+ # after this everything should be disconnected
+ obj.run_dispose()
+ obj.notify("int-prop")
+ obj.notify("int-prop")
+ assert len(called) == 2
+
+ def test_call_method_uninitialized_instance(self):
+ obj = GObject.Object.__new__(GObject.Object)
+ with self.assertRaisesRegex(RuntimeError, '.*is not initialized'):
+ obj.notify("foo")
+
def test_gobject_inheritance(self):
# GObject.Object is a class hierarchy as follows:
# overrides.Object -> introspection.Object -> static.GObject
GIObjectModule = get_introspection_module('GObject')
self.assertTrue(issubclass(GObject.Object, GIObjectModule.Object))
- self.assertTrue(issubclass(GIObjectModule.Object, _gobject.GObject))
+ self.assertTrue(issubclass(GIObjectModule.Object, _gi.GObject))
- self.assertEqual(_gobject.GObject.__gtype__, GObject.TYPE_OBJECT)
+ self.assertEqual(_gi.GObject.__gtype__, GObject.TYPE_OBJECT)
self.assertEqual(GIObjectModule.Object.__gtype__, GObject.TYPE_OBJECT)
self.assertEqual(GObject.Object.__gtype__, GObject.TYPE_OBJECT)
@@ -58,17 +135,20 @@ class TestGObjectAPI(unittest.TestCase):
self.assertLess(GObject.PRIORITY_HIGH, GObject.PRIORITY_DEFAULT)
def test_min_max_int(self):
- self.assertEqual(GObject.G_MAXINT16, 2 ** 15 - 1)
- self.assertEqual(GObject.G_MININT16, -2 ** 15)
- self.assertEqual(GObject.G_MAXUINT16, 2 ** 16 - 1)
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', PyGIDeprecationWarning)
- self.assertEqual(GObject.G_MAXINT32, 2 ** 31 - 1)
- self.assertEqual(GObject.G_MININT32, -2 ** 31)
- self.assertEqual(GObject.G_MAXUINT32, 2 ** 32 - 1)
+ self.assertEqual(GObject.G_MAXINT16, 2 ** 15 - 1)
+ self.assertEqual(GObject.G_MININT16, -2 ** 15)
+ self.assertEqual(GObject.G_MAXUINT16, 2 ** 16 - 1)
- self.assertEqual(GObject.G_MAXINT64, 2 ** 63 - 1)
- self.assertEqual(GObject.G_MININT64, -2 ** 63)
- self.assertEqual(GObject.G_MAXUINT64, 2 ** 64 - 1)
+ self.assertEqual(GObject.G_MAXINT32, 2 ** 31 - 1)
+ self.assertEqual(GObject.G_MININT32, -2 ** 31)
+ self.assertEqual(GObject.G_MAXUINT32, 2 ** 32 - 1)
+
+ self.assertEqual(GObject.G_MAXINT64, 2 ** 63 - 1)
+ self.assertEqual(GObject.G_MININT64, -2 ** 63)
+ self.assertEqual(GObject.G_MAXUINT64, 2 ** 64 - 1)
class TestReferenceCounting(unittest.TestCase):
@@ -233,19 +313,23 @@ class TestPythonReferenceCounting(unittest.TestCase):
def test_new_instance_has_two_refs(self):
obj = GObject.GObject()
- self.assertEqual(sys.getrefcount(obj), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(obj), 2)
def test_new_instance_has_two_refs_using_gobject_new(self):
obj = GObject.new(GObject.GObject)
- self.assertEqual(sys.getrefcount(obj), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(obj), 2)
def test_new_subclass_instance_has_two_refs(self):
obj = A()
- self.assertEqual(sys.getrefcount(obj), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(obj), 2)
def test_new_subclass_instance_has_two_refs_using_gobject_new(self):
obj = GObject.new(A)
- self.assertEqual(sys.getrefcount(obj), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(obj), 2)
class TestContextManagers(unittest.TestCase):
@@ -270,14 +354,16 @@ class TestContextManagers(unittest.TestCase):
self.assertEqual(self.tracking, [1, 2])
self.assertEqual(self.obj.__grefcount__, 1)
- pyref_count = sys.getrefcount(self.obj)
+ if hasattr(sys, "getrefcount"):
+ pyref_count = sys.getrefcount(self.obj)
# Using the context manager the tracking list should not be affected.
# The GObject reference count should stay the same and the python
# object ref-count should go up.
with self.obj.freeze_notify():
self.assertEqual(self.obj.__grefcount__, 1)
- self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1)
self.obj.props.prop = 3
self.assertEqual(self.obj.props.prop, 3)
self.assertEqual(self.tracking, [1, 2])
@@ -289,7 +375,8 @@ class TestContextManagers(unittest.TestCase):
self.assertEqual(self.obj.props.prop, 3)
self.assertEqual(self.tracking, [1, 2, 3])
self.assertEqual(self.obj.__grefcount__, 1)
- self.assertEqual(sys.getrefcount(self.obj), pyref_count)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(self.obj), pyref_count)
def test_handler_block_context(self):
# Verify prop tracking list
@@ -300,14 +387,16 @@ class TestContextManagers(unittest.TestCase):
self.assertEqual(self.tracking, [1, 2])
self.assertEqual(self.obj.__grefcount__, 1)
- pyref_count = sys.getrefcount(self.obj)
+ if hasattr(sys, "getrefcount"):
+ pyref_count = sys.getrefcount(self.obj)
# Using the context manager the tracking list should not be affected.
# The GObject reference count should stay the same and the python
# object ref-count should go up.
with self.obj.handler_block(self.handler):
self.assertEqual(self.obj.__grefcount__, 1)
- self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1)
self.obj.props.prop = 3
self.assertEqual(self.obj.props.prop, 3)
self.assertEqual(self.tracking, [1, 2])
@@ -319,7 +408,8 @@ class TestContextManagers(unittest.TestCase):
self.assertEqual(self.obj.props.prop, 3)
self.assertEqual(self.tracking, [1, 2])
self.assertEqual(self.obj.__grefcount__, 1)
- self.assertEqual(sys.getrefcount(self.obj), pyref_count)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(self.obj), pyref_count)
def test_freeze_notify_context_nested(self):
self.assertEqual(self.tracking, [])
@@ -415,6 +505,8 @@ class TestContextManagers(unittest.TestCase):
self.assertEqual(self.tracking, [2])
+@unittest.skipUnless(hasattr(GObject.Binding, 'unbind'),
+ 'Requires newer GLib which has g_binding_unbind')
class TestPropertyBindings(unittest.TestCase):
class TestObject(GObject.GObject):
int_prop = GObject.Property(default=0, type=int)
@@ -438,6 +530,14 @@ class TestPropertyBindings(unittest.TestCase):
self.assertEqual(self.source.int_prop, 1)
self.assertEqual(self.target.int_prop, 2)
+ def test_call_binding(self):
+ binding = self.source.bind_property('int_prop', self.target, 'int_prop',
+ GObject.BindingFlags.DEFAULT)
+ with capture_glib_deprecation_warnings() as warn:
+ result = binding()
+ assert len(warn)
+ assert result is binding
+
def test_bidirectional_binding(self):
binding = self.source.bind_property('int_prop', self.target, 'int_prop',
GObject.BindingFlags.BIDIRECTIONAL)
@@ -500,17 +600,19 @@ class TestPropertyBindings(unittest.TestCase):
self.assertEqual(user_data, test_data)
return value // 2
- test_data_ref_count = sys.getrefcount(test_data)
- transform_to_ref_count = sys.getrefcount(transform_to)
- transform_from_ref_count = sys.getrefcount(transform_from)
+ if hasattr(sys, "getrefcount"):
+ test_data_ref_count = sys.getrefcount(test_data)
+ transform_to_ref_count = sys.getrefcount(transform_to)
+ transform_from_ref_count = sys.getrefcount(transform_from)
# bidirectional bindings
binding = self.source.bind_property('int_prop', self.target, 'int_prop',
GObject.BindingFlags.BIDIRECTIONAL,
transform_to, transform_from, test_data)
binding = binding # PyFlakes
- binding_ref_count = sys.getrefcount(binding())
- binding_gref_count = binding().__grefcount__
+ if hasattr(sys, "getrefcount"):
+ binding_ref_count = sys.getrefcount(binding)
+ binding_gref_count = binding.__grefcount__
self.source.int_prop = 1
self.assertEqual(self.source.int_prop, 1)
@@ -520,19 +622,18 @@ class TestPropertyBindings(unittest.TestCase):
self.assertEqual(self.source.int_prop, 2)
self.assertEqual(self.target.int_prop, 4)
- self.assertEqual(sys.getrefcount(binding()), binding_ref_count)
- self.assertEqual(binding().__grefcount__, binding_gref_count)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(binding), binding_ref_count)
+ self.assertEqual(binding.__grefcount__, binding_gref_count)
# test_data ref count increases by 2, once for each callback.
- self.assertEqual(sys.getrefcount(test_data), test_data_ref_count + 2)
- self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count + 1)
- self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count + 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(test_data), test_data_ref_count + 2)
+ self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count + 1)
+ self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count + 1)
# Unbind should clear out the binding and its transforms
binding.unbind()
- self.assertEqual(binding(), None)
- del binding
- gc.collect()
# Setting source or target should not change the other.
self.target.int_prop = 3
@@ -540,9 +641,10 @@ class TestPropertyBindings(unittest.TestCase):
self.assertEqual(self.target.int_prop, 3)
self.assertEqual(self.source.int_prop, 5)
- self.assertEqual(sys.getrefcount(test_data), test_data_ref_count)
- self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count)
- self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(test_data), test_data_ref_count)
+ self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count)
+ self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count)
def test_explicit_unbind_clears_connection(self):
self.assertEqual(self.source.int_prop, 0)
@@ -554,15 +656,24 @@ class TestPropertyBindings(unittest.TestCase):
self.assertEqual(self.source.int_prop, 1)
self.assertEqual(self.target.int_prop, 1)
+ # unbind should clear out the bindings self reference
binding.unbind()
- self.assertEqual(binding(), None)
+ self.assertEqual(binding.__grefcount__, 1)
self.source.int_prop = 10
self.assertEqual(self.source.int_prop, 10)
self.assertEqual(self.target.int_prop, 1)
- # An already unbound BindingWeakRef will raise if unbind is attempted a second time.
- self.assertRaises(ValueError, binding.unbind)
+ glib_version = (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION)
+
+ # calling unbind() on an already unbound binding
+ if glib_version >= (2, 57, 3):
+ # Fixed in newer glib:
+ # https://gitlab.gnome.org/GNOME/glib/merge_requests/244
+ for i in range(10):
+ binding.unbind()
+ else:
+ self.assertRaises(ValueError, binding.unbind)
def test_reference_counts(self):
self.assertEqual(self.source.__grefcount__, 1)
@@ -572,7 +683,7 @@ class TestPropertyBindings(unittest.TestCase):
# the act of binding and the ref incurred by using __call__ to generate
# a wrapper from the weak binding ref within python.
binding = self.source.bind_property('int_prop', self.target, 'int_prop')
- self.assertEqual(binding().__grefcount__, 2)
+ self.assertEqual(binding.__grefcount__, 2)
# Creating a binding does not inc refs on source and target (they are weak
# on the binding object itself)
@@ -581,18 +692,25 @@ class TestPropertyBindings(unittest.TestCase):
# Use GObject.get_property because the "props" accessor leaks.
# Note property names are canonicalized.
- self.assertEqual(binding().get_property('source'), self.source)
- self.assertEqual(binding().get_property('source_property'), 'int-prop')
- self.assertEqual(binding().get_property('target'), self.target)
- self.assertEqual(binding().get_property('target_property'), 'int-prop')
- self.assertEqual(binding().get_property('flags'), GObject.BindingFlags.DEFAULT)
-
- # Delete reference to source or target and the binding should listen.
+ self.assertEqual(binding.get_property('source'), self.source)
+ self.assertEqual(binding.get_property('source_property'), 'int-prop')
+ self.assertEqual(binding.get_property('target'), self.target)
+ self.assertEqual(binding.get_property('target_property'), 'int-prop')
+ self.assertEqual(binding.get_property('flags'), GObject.BindingFlags.DEFAULT)
+
+ # Delete reference to source or target and the binding will remove its own
+ # "self reference".
ref = self.source.weak_ref()
del self.source
gc.collect()
self.assertEqual(ref(), None)
- self.assertEqual(binding(), None)
+ self.assertEqual(binding.__grefcount__, 1)
+
+ # Finally clear out the last ref held by the python wrapper
+ ref = binding.weak_ref()
+ del binding
+ gc.collect()
+ self.assertEqual(ref(), None)
class TestGValue(unittest.TestCase):
@@ -657,5 +775,86 @@ class TestGValue(unittest.TestCase):
value = GObject.Value(GObject.TYPE_OBJECT, obj)
self.assertEqual(value.get_value(), obj)
-if __name__ == '__main__':
- unittest.main()
+ def test_value_array(self):
+ value = GObject.Value(GObject.ValueArray)
+ self.assertEqual(value.g_type, GObject.type_from_name('GValueArray'))
+ value.set_value([32, 'foo_bar', 0.3])
+ self.assertEqual(value.get_value(), [32, 'foo_bar', 0.3])
+
+ def test_value_array_from_gvalue_list(self):
+ value = GObject.Value(GObject.ValueArray, [
+ GObject.Value(GObject.TYPE_UINT, 0xffffffff),
+ GObject.Value(GObject.TYPE_STRING, 'foo_bar')])
+ self.assertEqual(value.g_type, GObject.type_from_name('GValueArray'))
+ self.assertEqual(value.get_value(), [0xffffffff, 'foo_bar'])
+ self.assertEqual(testhelper.value_array_get_nth_type(value, 0), GObject.TYPE_UINT)
+ self.assertEqual(testhelper.value_array_get_nth_type(value, 1), GObject.TYPE_STRING)
+
+ def test_value_array_append_gvalue(self):
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', DeprecationWarning)
+
+ arr = GObject.ValueArray.new(0)
+ arr.append(GObject.Value(GObject.TYPE_UINT, 0xffffffff))
+ arr.append(GObject.Value(GObject.TYPE_STRING, 'foo_bar'))
+ self.assertEqual(arr.get_nth(0), 0xffffffff)
+ self.assertEqual(arr.get_nth(1), 'foo_bar')
+ self.assertEqual(testhelper.value_array_get_nth_type(arr, 0), GObject.TYPE_UINT)
+ self.assertEqual(testhelper.value_array_get_nth_type(arr, 1), GObject.TYPE_STRING)
+
+ def test_gerror_boxing(self):
+ error = GLib.Error('test message', domain='mydomain', code=42)
+ value = GObject.Value(GLib.Error, error)
+ self.assertEqual(value.g_type, GObject.type_from_name('GError'))
+
+ unboxed = value.get_value()
+ self.assertEqual(unboxed.message, error.message)
+ self.assertEqual(unboxed.domain, error.domain)
+ self.assertEqual(unboxed.code, error.code)
+
+ def test_gerror_novalue(self):
+ GLib.Error('test message', domain='mydomain', code=42)
+ value = GObject.Value(GLib.Error)
+ self.assertEqual(value.g_type, GObject.type_from_name('GError'))
+ self.assertEqual(value.get_value(), None)
+
+
+def test_list_properties():
+
+ def find_param(props, name):
+ for param in props:
+ if param.name == name:
+ return param
+ return
+
+ list_props = GObject.list_properties
+
+ props = list_props(Gio.Action)
+ param = find_param(props, "enabled")
+ assert param
+ assert param.value_type == GObject.TYPE_BOOLEAN
+ assert list_props("GAction") == list_props(Gio.Action)
+ assert list_props(Gio.Action.__gtype__) == list_props(Gio.Action)
+
+ props = list_props(Gio.SimpleAction)
+ assert find_param(props, "enabled")
+
+ def names(props):
+ return [p.name for p in props]
+
+ assert (set(names(list_props(Gio.Action))) <=
+ set(names(list_props(Gio.SimpleAction))))
+
+ props = list_props(Gio.FileIcon)
+ param = find_param(props, "file")
+ assert param
+ assert param.value_type == Gio.File.__gtype__
+
+ assert list_props("GFileIcon") == list_props(Gio.FileIcon)
+ assert list_props(Gio.FileIcon.__gtype__) == list_props(Gio.FileIcon)
+ assert list_props(Gio.FileIcon(
+ file=Gio.File.new_for_path('.'))) == list_props(Gio.FileIcon)
+
+ for obj in [Gio.ActionEntry, Gio.DBusError, 0, object()]:
+ with pytest.raises(TypeError):
+ list_props(obj)
diff --git a/tests/test_gtk_template.py b/tests/test_gtk_template.py
new file mode 100644
index 0000000..9dd7a90
--- /dev/null
+++ b/tests/test_gtk_template.py
@@ -0,0 +1,721 @@
+import tempfile
+import os
+import pytest
+
+Gtk = pytest.importorskip("gi.repository.Gtk")
+GLib = pytest.importorskip("gi.repository.GLib")
+GObject = pytest.importorskip("gi.repository.GObject")
+Gio = pytest.importorskip("gi.repository.Gio")
+
+from .helper import capture_exceptions
+
+GTK4 = (Gtk._version == "4.0")
+
+
+def new_gtype_name(_count=[0]):
+ _count[0] += 1
+ return "GtkTemplateTest%d" % _count[0]
+
+
+def ensure_resource_registered():
+ resource_path = "/org/gnome/pygobject/test/a.ui"
+
+ def is_registered(path):
+ try:
+ Gio.resources_get_info(path, Gio.ResourceLookupFlags.NONE)
+ except GLib.Error:
+ return False
+ return True
+
+ if is_registered(resource_path):
+ return resource_path
+
+ gresource_data = (
+ b'GVariant\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00'
+ b'\xc8\x00\x00\x00\x00\x00\x00(\x06\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00'
+ b'\x06\x00\x00\x00KP\x90\x0b\x03\x00\x00\x00\xc8\x00\x00\x00'
+ b'\x04\x00L\x00\xcc\x00\x00\x00\xd0\x00\x00\x00\xb0\xb7$0'
+ b'\x00\x00\x00\x00\xd0\x00\x00\x00\x06\x00L\x00\xd8\x00\x00\x00'
+ b'\xdc\x00\x00\x00f\xc30\xd1\x01\x00\x00\x00\xdc\x00\x00\x00'
+ b'\n\x00L\x00\xe8\x00\x00\x00\xec\x00\x00\x00\xd4\xb5\x02\x00'
+ b'\xff\xff\xff\xff\xec\x00\x00\x00\x01\x00L\x00\xf0\x00\x00\x00'
+ b'\xf4\x00\x00\x005H}\xe3\x02\x00\x00\x00\xf4\x00\x00\x00'
+ b'\x05\x00L\x00\xfc\x00\x00\x00\x00\x01\x00\x00\xa2^\xd6t'
+ b'\x04\x00\x00\x00\x00\x01\x00\x00\x04\x00v\x00\x08\x01\x00\x00'
+ b'\xa5\x01\x00\x00org/\x01\x00\x00\x00gnome/\x00\x00\x02\x00\x00\x00'
+ b'pygobject/\x00\x00\x04\x00\x00\x00/\x00\x00\x00\x00\x00\x00\x00'
+ b'test/\x00\x00\x00\x05\x00\x00\x00a.ui\x00\x00\x00\x00'
+ b'\x8d\x00\x00\x00\x00\x00\x00\x00<interface>\n <template class="G'
+ b'tkTemplateTestResource" parent="GtkBox">\n <property name="spaci'
+ b'ng">42</property>\n </template>\n</interface>\n\x00\x00(uuay)'
+ )
+
+ resource = Gio.Resource.new_from_data(GLib.Bytes.new(gresource_data))
+ Gio.resources_register(resource)
+ assert is_registered(resource_path)
+ return resource_path
+
+
+def test_allow_init_template_call():
+
+ type_name = new_gtype_name()
+
+ xml = """\
+<interface>
+ <template class="{0}" parent="GtkBox">
+ </template>
+</interface>
+""".format(type_name)
+
+ @Gtk.Template.from_string(xml)
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ def __init__(self):
+ super(Foo, self).__init__()
+ self.init_template()
+
+ # Stop current pygobject from handling the initialisation
+ del Foo.__dontuse_ginstance_init__
+
+ Foo()
+
+
+def test_init_template_second_instance():
+ type_name = new_gtype_name()
+
+ xml = """\
+<interface>
+ <template class="{0}" parent="GtkBox">
+ <child>
+ <object class="GtkLabel" id="label">
+ </object>
+ </child>
+ </template>
+</interface>
+""".format(type_name)
+
+ @Gtk.Template.from_string(xml)
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ label = Gtk.Template.Child("label")
+
+ def __init__(self):
+ super(Foo, self).__init__()
+ self.init_template()
+
+ # Stop current pygobject from handling the initialisation
+ del Foo.__dontuse_ginstance_init__
+
+ foo = Foo()
+ assert isinstance(foo.label, Gtk.Label)
+
+ foo2 = Foo()
+ assert isinstance(foo2.label, Gtk.Label)
+
+
+def test_main_example():
+
+ type_name = new_gtype_name()
+
+ example_xml = """\
+<interface>
+ <template class="{0}" parent="GtkBox">
+ <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkButton" id="hello_button">
+ <property name="label">Hello World</property>
+ <signal name="clicked" handler="hello_button_clicked"
+ object="{0}" swapped="no"/>
+ <signal name="clicked" handler="hello_button_clicked_after"
+ object="{0}" swapped="no" after="yes"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="goodbye_button">
+ <property name="label">Goodbye World</property>
+ <signal name="clicked" handler="goodbye_button_clicked"/>
+ <signal name="clicked" handler="goodbye_button_clicked_after"
+ after="yes"/>
+ </object>
+ </child>
+ </template>
+</interface>
+""".format(type_name)
+
+ @Gtk.Template.from_string(example_xml)
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ def __init__(self):
+ super(Foo, self).__init__()
+ self.callback_hello = []
+ self.callback_hello_after = []
+ self.callback_goodbye = []
+ self.callback_goodbye_after = []
+
+ @Gtk.Template.Callback("hello_button_clicked")
+ def _hello_button_clicked(self, *args):
+ self.callback_hello.append(args)
+
+ @Gtk.Template.Callback("hello_button_clicked_after")
+ def _hello_after(self, *args):
+ self.callback_hello_after.append(args)
+
+ _hello_button = Gtk.Template.Child("hello_button")
+
+ goodbye_button = Gtk.Template.Child()
+
+ @Gtk.Template.Callback("goodbye_button_clicked")
+ def _goodbye_button_clicked(self, *args):
+ self.callback_goodbye.append(args)
+
+ @Gtk.Template.Callback("goodbye_button_clicked_after")
+ def _goodbye_after(self, *args):
+ self.callback_goodbye_after.append(args)
+
+ w = Foo()
+ assert w.__gtype__.name == type_name
+ assert w.props.orientation == Gtk.Orientation.HORIZONTAL
+ assert w.props.spacing == 4
+ assert isinstance(w._hello_button, Gtk.Button)
+ assert w._hello_button.props.label == "Hello World"
+ assert isinstance(w.goodbye_button, Gtk.Button)
+ assert w.goodbye_button.props.label == "Goodbye World"
+
+ assert w.callback_hello == []
+ w._hello_button.emit("clicked")
+ assert w.callback_hello == [(w,)]
+ assert w.callback_hello_after == [(w,)]
+
+ assert w.callback_goodbye == []
+ w.goodbye_button.emit("clicked")
+ assert w.callback_goodbye == [(w.goodbye_button,)]
+ assert w.callback_goodbye_after == [(w.goodbye_button,)]
+
+
+def test_duplicate_handler():
+ type_name = new_gtype_name()
+
+ xml = """\
+<interface>
+ <template class="{0}" parent="GtkBox">
+ <child>
+ <object class="GtkButton" id="hello_button">
+ <signal name="clicked" handler="hello_button_clicked" />
+ </object>
+ </child>
+ </template>
+</interface>
+""".format(type_name)
+
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ @Gtk.Template.Callback("hello_button_clicked")
+ def _hello_button_clicked(self, *args):
+ pass
+
+ @Gtk.Template.Callback()
+ def hello_button_clicked(self, *args):
+ pass
+
+ with pytest.raises(RuntimeError, match=".*hello_button_clicked.*"):
+ Gtk.Template.from_string(xml)(Foo)
+
+
+def test_duplicate_child():
+ type_name = new_gtype_name()
+
+ xml = """\
+<interface>
+ <template class="{0}" parent="GtkBox">
+ <child>
+ <object class="GtkButton" id="hello_button" />
+ </child>
+ </template>
+</interface>
+""".format(type_name)
+
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ foo = Gtk.Template.Child("hello_button")
+ hello_button = Gtk.Template.Child()
+
+ with pytest.raises(RuntimeError, match=".*hello_button.*"):
+ Gtk.Template.from_string(xml)(Foo)
+
+
+def test_nonexist_handler():
+ type_name = new_gtype_name()
+
+ xml = """\
+<interface>
+ <template class="{0}" parent="GtkBox">
+ </template>
+</interface>
+""".format(type_name)
+
+ @Gtk.Template.from_string(xml)
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ @Gtk.Template.Callback("nonexit")
+ def foo(self, *args):
+ pass
+
+ with capture_exceptions() as exc_info:
+ Foo()
+ assert "nonexit" in str(exc_info[0].value)
+ assert exc_info[0].type is RuntimeError
+
+
+def test_missing_handler_callback():
+ type_name = new_gtype_name()
+
+ xml = """\
+<interface>
+ <template class="{0}" parent="GtkBox">
+ <child>
+ <object class="GtkButton" id="hello_button">
+ <signal name="clicked" handler="i_am_not_used_in_python" />
+ </object>
+ </child>
+ </template>
+</interface>
+""".format(type_name)
+
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ Gtk.Template.from_string(xml)(Foo)()
+
+
+def test_handler_swapped_not_supported():
+ type_name = new_gtype_name()
+
+ xml = """\
+<interface>
+ <template class="{0}" parent="GtkBox">
+ <child>
+ <object class="GtkButton" id="hello_button">
+ <signal name="clicked" handler="hello_button_clicked"
+ object="{0}" swapped="yes" />
+ </object>
+ </child>
+ </template>
+</interface>
+""".format(type_name)
+
+ @Gtk.Template.from_string(xml)
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ hello_button = Gtk.Template.Child()
+
+ @Gtk.Template.Callback("hello_button_clicked")
+ def foo(self, *args):
+ pass
+
+ with capture_exceptions() as exc_info:
+ Foo()
+ assert "G_CONNECT_SWAPPED" in str(exc_info[0].value)
+
+
+def test_handler_class_staticmethod():
+ type_name = new_gtype_name()
+
+ xml = """\
+<interface>
+ <template class="{0}" parent="GtkBox">
+ <child>
+ <object class="GtkButton" id="hello_button">
+ <signal name="clicked" handler="clicked_class" />
+ <signal name="clicked" handler="clicked_static" />
+ </object>
+ </child>
+ </template>
+</interface>
+""".format(type_name)
+
+ signal_args_class = []
+ signal_args_static = []
+
+ @Gtk.Template.from_string(xml)
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ hello_button = Gtk.Template.Child()
+
+ @Gtk.Template.Callback("clicked_class")
+ @classmethod
+ def cb1(*args):
+ signal_args_class.append(args)
+
+ @Gtk.Template.Callback("clicked_static")
+ @staticmethod
+ def cb2(*args):
+ signal_args_static.append(args)
+
+ foo = Foo()
+ foo.hello_button.emit("clicked")
+ assert signal_args_class == [(Foo, foo.hello_button)]
+ assert signal_args_static == [(foo.hello_button,)]
+
+
+@pytest.mark.skipif(Gtk._version == "4.0", reason="errors out first with gtk4")
+def test_check_decorated_class():
+ NonWidget = type("Foo", (object,), {})
+ with pytest.raises(TypeError, match=".*on Widgets.*"):
+ Gtk.Template.from_string("")(NonWidget)
+
+ Widget = type("Foo", (Gtk.Widget,), {"__gtype_name__": new_gtype_name()})
+ with pytest.raises(TypeError, match=".*Cannot nest.*"):
+ Gtk.Template.from_string("")(Gtk.Template.from_string("")(Widget))
+
+ Widget = type("Foo", (Gtk.Widget,), {})
+ with pytest.raises(TypeError, match=".*__gtype_name__.*"):
+ Gtk.Template.from_string("")(Widget)
+
+ with pytest.raises(TypeError, match=".*on Widgets.*"):
+ Gtk.Template.from_string("")(object())
+
+
+@pytest.mark.skipif(Gtk._version == "4.0", reason="errors out first with gtk4")
+def test_subclass_fail():
+ @Gtk.Template.from_string("")
+ class Base(Gtk.Widget):
+ __gtype_name__ = new_gtype_name()
+
+ with capture_exceptions() as exc_info:
+ type("Sub", (Base,), {})()
+ assert "not allowed at this time" in str(exc_info[0].value)
+ assert exc_info[0].type is TypeError
+
+
+def test_from_file():
+ fd, name = tempfile.mkstemp()
+ try:
+ os.close(fd)
+
+ type_name = new_gtype_name()
+
+ with open(name, "wb") as h:
+ h.write(u"""\
+ <interface>
+ <template class="{0}" parent="GtkBox">
+ <property name="spacing">42</property>
+ </template>
+ </interface>
+ """.format(type_name).encode())
+
+ @Gtk.Template.from_file(name)
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ foo = Foo()
+ assert foo.props.spacing == 42
+ finally:
+ os.remove(name)
+
+
+def test_property_override():
+ type_name = new_gtype_name()
+
+ xml = """\
+ <interface>
+ <template class="{0}" parent="GtkBox">
+ <property name="spacing">42</property>
+ </template>
+ </interface>
+""".format(type_name)
+
+ @Gtk.Template.from_string(xml)
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ foo = Foo()
+ assert foo.props.spacing == 42
+
+ foo = Foo(spacing=124)
+ assert foo.props.spacing == 124
+
+
+def test_from_file_non_exist():
+ dirname = tempfile.mkdtemp()
+ try:
+ path = os.path.join(dirname, "noexist")
+
+ Widget = type(
+ "Foo", (Gtk.Widget,), {"__gtype_name__": new_gtype_name()})
+ with pytest.raises(GLib.Error, match=".*No such file.*"):
+ Gtk.Template.from_file(path)(Widget)
+ finally:
+ os.rmdir(dirname)
+
+
+def test_from_string_bytes():
+ type_name = new_gtype_name()
+
+ xml = u"""\
+ <interface>
+ <template class="{0}" parent="GtkBox">
+ <property name="spacing">42</property>
+ </template>
+ </interface>
+ """.format(type_name).encode()
+
+ @Gtk.Template.from_string(xml)
+ class Foo(Gtk.Box):
+ __gtype_name__ = type_name
+
+ foo = Foo()
+ assert foo.props.spacing == 42
+
+
+def test_from_resource():
+ resource_path = ensure_resource_registered()
+
+ @Gtk.Template.from_resource(resource_path)
+ class Foo(Gtk.Box):
+ __gtype_name__ = "GtkTemplateTestResource"
+
+ foo = Foo()
+ assert foo.props.spacing == 42
+
+
+def test_from_resource_non_exit():
+ Widget = type("Foo", (Gtk.Widget,), {"__gtype_name__": new_gtype_name()})
+ with pytest.raises(GLib.Error, match=".*/or/gnome/pygobject/noexit.*"):
+ Gtk.Template.from_resource("/or/gnome/pygobject/noexit")(Widget)
+
+
+def test_constructors():
+ with pytest.raises(TypeError):
+ Gtk.Template()
+
+ with pytest.raises(TypeError):
+ Gtk.Template(foo=1)
+
+ Gtk.Template(filename="foo")
+ Gtk.Template(resource_path="foo")
+ Gtk.Template(string="foo")
+
+ with pytest.raises(TypeError):
+ Gtk.Template(filename="foo", resource_path="bar")
+
+ with pytest.raises(TypeError):
+ Gtk.Template(filename="foo", nope="bar")
+
+ Gtk.Template.from_string("bla")
+ Gtk.Template.from_resource("foo")
+ Gtk.Template.from_file("foo")
+
+
+def test_child_construct():
+ Gtk.Template.Child()
+ Gtk.Template.Child("name")
+ with pytest.raises(TypeError):
+ Gtk.Template.Child("name", True)
+ Gtk.Template.Child("name", internal=True)
+ with pytest.raises(TypeError):
+ Gtk.Template.Child("name", internal=True, something=False)
+
+
+def test_internal_child():
+
+ main_type_name = new_gtype_name()
+
+ xml = """\
+ <interface>
+ <template class="{0}" parent="GtkBox">
+ <child>
+ <object class="GtkBox" id="somechild">
+ <property name="margin-top">42</property>
+ </object>
+ </child>
+ </template>
+ </interface>
+ """.format(main_type_name)
+
+ @Gtk.Template.from_string(xml)
+ class MainThing(Gtk.Box):
+ __gtype_name__ = main_type_name
+
+ somechild = Gtk.Template.Child(internal=True)
+
+ thing = MainThing()
+ assert thing.somechild.props.margin_top == 42
+
+ other_type_name = new_gtype_name()
+
+ xml = """\
+ <interface>
+ <template class="{0}" parent="GtkBox">
+ <child>
+ <object class="{1}">
+ <child internal-child="somechild">
+ <object class="GtkBox">
+ <property name="margin-top">24</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="label">foo</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ </interface>
+ """.format(other_type_name, main_type_name)
+
+ @Gtk.Template.from_string(xml)
+ class OtherThing(Gtk.Box):
+ __gtype_name__ = other_type_name
+
+ other = OtherThing()
+ if not GTK4:
+ child = other.get_children()[0]
+ else:
+ child = other.get_first_child()
+
+ assert isinstance(child, MainThing)
+
+ if not GTK4:
+ child = child.get_children()[0]
+ else:
+ child = child.get_first_child()
+
+ assert isinstance(child, Gtk.Box)
+ assert child.props.margin_top == 24
+
+ if not GTK4:
+ child = child.get_children()[0]
+ else:
+ child = child.get_first_child()
+
+ assert isinstance(child, Gtk.Label)
+ assert child.props.label == "foo"
+
+
+def test_template_hierarchy():
+ testlabel = """
+ <interface>
+ <template class="TestLabel" parent="GtkLabel">
+ </template>
+ </interface>
+ """
+
+ @Gtk.Template(string=testlabel)
+ class TestLabel(Gtk.Label):
+
+ __gtype_name__ = "TestLabel"
+
+ def __init__(self):
+ super().__init__()
+ self.props.label = "TestLabel"
+
+ testbox = """
+ <interface>
+ <template class="TestBox" parent="GtkBox">
+ <child>
+ <object class="TestLabel" id="_testlabel"/>
+ </child>
+ </template>
+ </interface>
+ """
+
+ @Gtk.Template(string=testbox)
+ class TestBox(Gtk.Box):
+
+ __gtype_name__ = "TestBox"
+
+ _testlabel = Gtk.Template.Child()
+
+ def __init__(self):
+ super().__init__()
+
+ assert isinstance(self._testlabel, TestLabel)
+
+ window = """
+ <interface>
+ <template class="MyWindow" parent="GtkWindow">
+ <property name="title">"Hellow World"</property>
+ <child>
+ <object class="TestBox" id="_testbox">
+ <child>
+ <object class="TestLabel" id="_testlabel"/>
+ </child>
+ </object>
+ </child>
+ </template>
+ </interface>
+ """
+
+ @Gtk.Template(string=window)
+ class MyWindow(Gtk.Window):
+
+ __gtype_name__ = "MyWindow"
+
+ _testbox = Gtk.Template.Child()
+ _testlabel = Gtk.Template.Child()
+
+ def __init__(self):
+ super().__init__()
+
+ assert isinstance(self._testbox, TestBox)
+ assert isinstance(self._testlabel, TestLabel)
+ if not GTK4:
+ children = self._testbox.get_children()
+ else:
+ children = list(self._testbox)
+
+ assert len(children) == 2
+
+ win = MyWindow()
+ assert isinstance(win, MyWindow)
+
+
+def test_multiple_init_template_calls():
+ xml = """
+ <interface>
+ <template class="MyBox" parent="GtkBox">
+ <child>
+ <object class="GtkLabel" id="_label"/>
+ </child>
+ </template>
+ </interface>
+ """
+
+ @Gtk.Template(string=xml)
+ class MyBox(Gtk.Box):
+
+ __gtype_name__ = "MyBox"
+
+ _label = Gtk.Template.Child()
+
+ def __init__(self):
+ super().__init__()
+ self._label.props.label = "awesome label"
+
+ my_box = MyBox()
+ assert isinstance(my_box, MyBox)
+ if not GTK4:
+ children = my_box.get_children()
+ else:
+ children = list(my_box)
+
+ assert len(children) == 1
+ my_box.init_template()
+ assert isinstance(my_box, MyBox)
+ if not GTK4:
+ children = my_box.get_children()
+ else:
+ children = list(my_box)
+
+ assert len(children) == 1
diff --git a/tests/test_gtype.py b/tests/test_gtype.py
index 8099101..1d24f9f 100644
--- a/tests/test_gtype.py
+++ b/tests/test_gtype.py
@@ -49,3 +49,64 @@ class TestTypeModuleLevelFunctions(unittest.TestCase):
self.assertEqual(GObject.type_parent(CustomChild), CustomBase.__gtype__)
self.assertEqual(GObject.type_parent(CustomBase), GObject.TYPE_OBJECT)
self.assertRaises(RuntimeError, GObject.type_parent, GObject.GObject)
+
+
+def test_gtype_has_value_table():
+ assert CustomBase.__gtype__.has_value_table()
+ assert not GIMarshallingTests.Interface.__gtype__.has_value_table()
+ assert CustomChild.__gtype__.has_value_table()
+
+
+def test_gtype_is_abstract():
+ assert not CustomBase.__gtype__.is_abstract()
+ assert not GIMarshallingTests.Interface.__gtype__.is_abstract()
+ assert not CustomChild.__gtype__.is_abstract()
+
+
+def test_gtype_is_classed():
+ assert CustomBase.__gtype__.is_classed()
+ assert not GIMarshallingTests.Interface.__gtype__.is_classed()
+ assert CustomChild.__gtype__.is_classed()
+
+
+def test_gtype_is_deep_derivable():
+ assert CustomBase.__gtype__.is_deep_derivable()
+ assert not GIMarshallingTests.Interface.__gtype__.is_deep_derivable()
+ assert CustomChild.__gtype__.is_deep_derivable()
+
+
+def test_gtype_is_derivable():
+ assert CustomBase.__gtype__.is_derivable()
+ assert GIMarshallingTests.Interface.__gtype__.is_derivable()
+ assert CustomChild.__gtype__.is_derivable()
+
+
+def test_gtype_is_value_abstract():
+ assert not CustomBase.__gtype__.is_value_abstract()
+ assert not GIMarshallingTests.Interface.__gtype__.is_value_abstract()
+ assert not CustomChild.__gtype__.is_value_abstract()
+
+
+def test_gtype_is_value_type():
+ assert CustomBase.__gtype__.is_value_type()
+ assert not GIMarshallingTests.Interface.__gtype__.is_value_type()
+ assert CustomChild.__gtype__.is_value_type()
+
+
+def test_gtype_children():
+ assert CustomBase.__gtype__.children == [CustomChild.__gtype__]
+ assert GIMarshallingTests.Interface.__gtype__.children == []
+ assert CustomChild.__gtype__.children == []
+
+
+def test_gtype_depth():
+ assert CustomBase.__gtype__.depth == 2
+ assert GIMarshallingTests.Interface.__gtype__.depth == 2
+ assert CustomChild.__gtype__.depth == 3
+
+
+def test_gtype_interfaces():
+ assert CustomBase.__gtype__.interfaces == []
+ assert GIMarshallingTests.Interface.__gtype__.interfaces == []
+ assert CustomChild.__gtype__.interfaces == \
+ [GIMarshallingTests.Interface.__gtype__]
diff --git a/tests/test_gtype_instance.py b/tests/test_gtype_instance.py
new file mode 100644
index 0000000..a2f7eec
--- /dev/null
+++ b/tests/test_gtype_instance.py
@@ -0,0 +1,8 @@
+
+import pytest
+from gi.repository import Regress
+
+
+def test_fundamental_type_instantiation_fails():
+ with pytest.raises(TypeError, match="No means to translate argument or return value for 'RegressTestFundamentalSubObject'"):
+ Regress.TestFundamentalSubObject.new("data")
diff --git a/tests/test_import_machinery.py b/tests/test_import_machinery.py
new file mode 100644
index 0000000..a8d5005
--- /dev/null
+++ b/tests/test_import_machinery.py
@@ -0,0 +1,154 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+
+import sys
+import unittest
+
+import gi.overrides
+import gi.module
+import gi.importer
+
+from gi.repository import Regress
+
+
+class TestOverrides(unittest.TestCase):
+
+ def test_non_gi(self):
+ class MyClass:
+ pass
+
+ try:
+ gi.overrides.override(MyClass)
+ self.fail('unexpected success of overriding non-GI class')
+ except TypeError as e:
+ self.assertTrue('Can not override a type MyClass' in str(e))
+
+ def test_separate_path(self):
+ # Regress override is in tests/gi/overrides, separate from gi/overrides
+ # https://bugzilla.gnome.org/show_bug.cgi?id=680913
+ self.assertEqual(Regress.REGRESS_OVERRIDE, 42)
+
+ def test_load_overrides(self):
+ mod = gi.module.get_introspection_module('GIMarshallingTests')
+ mod_override = gi.overrides.load_overrides(mod)
+ self.assertTrue(mod_override is not mod)
+ self.assertTrue(mod_override._introspection_module is mod)
+ self.assertEqual(mod_override.OVERRIDES_CONSTANT, 7)
+ self.assertEqual(mod.OVERRIDES_CONSTANT, 42)
+
+ def test_load_no_overrides(self):
+ mod_key = "gi.overrides.GIMarshallingTests"
+ had_mod = mod_key in sys.modules
+ old_mod = sys.modules.get(mod_key)
+ try:
+ # this makes override import fail
+ sys.modules[mod_key] = None
+ mod = gi.module.get_introspection_module('GIMarshallingTests')
+ mod_override = gi.overrides.load_overrides(mod)
+ self.assertTrue(mod_override is mod)
+ finally:
+ del sys.modules[mod_key]
+ if had_mod:
+ sys.modules[mod_key] = old_mod
+
+
+class TestModule(unittest.TestCase):
+ # Tests for gi.module
+
+ def test_get_introspection_module_caching(self):
+ # This test attempts to minimize side effects by
+ # using a DynamicModule directly instead of going though:
+ # from gi.repository import Foo
+
+ # Clear out introspection module cache before running this test.
+ old_modules = gi.module._introspection_modules
+ gi.module._introspection_modules = {}
+
+ mod_name = 'GIMarshallingTests'
+ mod1 = gi.module.get_introspection_module(mod_name)
+ mod2 = gi.module.get_introspection_module(mod_name)
+ self.assertTrue(mod1 is mod2)
+
+ # Restore the previous cache
+ gi.module._introspection_modules = old_modules
+
+ def test_module_dependency_loading(self):
+ # Difficult to because this generally need to run in isolation to make
+ # sure GIMarshallingTests has not yet been loaded. But we can do this with:
+ # make check TEST_NAMES=test_import_machinery.TestModule.test_module_dependency_loading
+ if 'gi.repository.Gio' in sys.modules:
+ return
+
+ from gi.repository import GIMarshallingTests
+ GIMarshallingTests # PyFlakes
+
+ self.assertIn('gi.repository.Gio', sys.modules)
+ self.assertIn('gi.repository.GIMarshallingTests', sys.modules)
+
+ def test_static_binding_protection(self):
+ # Importing old static bindings once gi has been imported should not
+ # crash but instead give back a dummy module which produces RuntimeErrors
+ # on access.
+ with self.assertRaises(AttributeError):
+ import gobject
+ gobject.anything
+
+ with self.assertRaises(AttributeError):
+ import glib
+ glib.anything
+
+ with self.assertRaises(AttributeError):
+ import gio
+ gio.anything
+
+ with self.assertRaises(AttributeError):
+ import gtk
+ gtk.anything
+
+ with self.assertRaises(AttributeError):
+ import gtk.gdk
+ gtk.gdk.anything
+
+
+class TestImporter(unittest.TestCase):
+ def test_invalid_repository_module_name(self):
+ with self.assertRaises(ImportError) as context:
+ from gi.repository import InvalidGObjectRepositoryModuleName
+ InvalidGObjectRepositoryModuleName # pyflakes
+
+ exception_string = str(context.exception)
+
+ self.assertTrue('InvalidGObjectRepositoryModuleName' in exception_string)
+ self.assertTrue('introspection typelib' in exception_string)
+
+ def test_require_version_warning(self):
+ check = gi.importer._check_require_version
+
+ # make sure it doesn't fail at least
+ with check("GLib", 1):
+ from gi.repository import GLib
+ GLib
+
+ # make sure the exception propagates
+ with self.assertRaises(ImportError):
+ with check("InvalidGObjectRepositoryModuleName", 1):
+ from gi.repository import InvalidGObjectRepositoryModuleName
+ InvalidGObjectRepositoryModuleName
+
+ def test_require_version_versiontype(self):
+ import gi
+ with self.assertRaises(ValueError):
+ gi.require_version('GLib', 2.0)
+
+ with self.assertRaises(ValueError):
+ gi.require_version('GLib', b'2.0')
+
+ def test_require_versions(self):
+ import gi
+ gi.require_versions({'GLib': '2.0', 'Gio': '2.0', 'GObject': '2.0'})
+ from gi.repository import GLib
+ GLib
+
+ def test_get_import_stacklevel(self):
+ gi.importer.get_import_stacklevel(import_hook=True)
+ gi.importer.get_import_stacklevel(import_hook=False)
diff --git a/tests/test_interface.py b/tests/test_interface.py
index dd01af8..ba20cb4 100644
--- a/tests/test_interface.py
+++ b/tests/test_interface.py
@@ -20,6 +20,8 @@ class MyUnknown(Unknown, testhelper.Interface):
def do_iface_method(self):
self.called = True
Unknown.do_iface_method(self)
+
+
GObject.type_register(MyUnknown)
@@ -32,6 +34,8 @@ class MyObject(GObject.GObject, testhelper.Interface):
def do_iface_method(self):
self.called = True
+
+
GObject.type_register(MyObject)
diff --git a/tests/test_internal_api.py b/tests/test_internal_api.py
index ca50f6b..5136037 100644
--- a/tests/test_internal_api.py
+++ b/tests/test_internal_api.py
@@ -1,18 +1,44 @@
# -*- Mode: Python -*-
import unittest
+import pytest
from gi.repository import GLib, GObject
import testhelper
-import testmodule
+
+
+class PyGObject(GObject.GObject):
+ __gtype_name__ = 'PyGObject'
+ __gproperties__ = {
+ 'label': (GObject.TYPE_STRING,
+ 'label property',
+ 'the label of the object',
+ 'default',
+ GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE),
+ }
+
+ def __init__(self):
+ self._props = {}
+ GObject.GObject.__init__(self)
+ self.set_property('label', 'hello')
+
+ def do_set_property(self, name, value):
+ self._props[name] = value
+
+ def do_get_property(self, name):
+ return self._props[name]
+
+
+def test_parse_constructor_args():
+ assert testhelper.test_parse_constructor_args("foo") == 1
class TestObject(unittest.TestCase):
def test_create_ctor(self):
- o = testmodule.PyGObject()
+ o = PyGObject()
self.assertTrue(isinstance(o, GObject.Object))
- self.assertTrue(isinstance(o, testmodule.PyGObject))
+ self.assertTrue(isinstance(o, PyGObject))
# has expected property
self.assertEqual(o.props.label, 'hello')
@@ -22,7 +48,7 @@ class TestObject(unittest.TestCase):
def test_pyobject_new_test_type(self):
o = testhelper.create_test_type()
- self.assertTrue(isinstance(o, testmodule.PyGObject))
+ self.assertTrue(isinstance(o, PyGObject))
# has expected property
self.assertEqual(o.props.label, 'hello')
@@ -40,8 +66,8 @@ class TestGValueConversion(unittest.TestCase):
self.assertEqual(testhelper.test_value(0), 0)
self.assertEqual(testhelper.test_value(5), 5)
self.assertEqual(testhelper.test_value(-5), -5)
- self.assertEqual(testhelper.test_value(GObject.G_MAXINT32), GObject.G_MAXINT32)
- self.assertEqual(testhelper.test_value(GObject.G_MININT32), GObject.G_MININT32)
+ self.assertEqual(testhelper.test_value(GLib.MAXINT32), GLib.MAXINT32)
+ self.assertEqual(testhelper.test_value(GLib.MININT32), GLib.MININT32)
def test_str(self):
self.assertEqual(testhelper.test_value('hello'), 'hello')
@@ -69,5 +95,28 @@ class TestErrors(unittest.TestCase):
self.assertEqual(testhelper.test_gerror_exception(callable_), None)
-if __name__ == '__main__':
- unittest.main()
+def test_to_unichar_conv():
+ assert testhelper.test_to_unichar_conv(u"A") == 65
+ assert testhelper.test_to_unichar_conv(u"Ä") == 196
+
+ with pytest.raises(TypeError):
+ assert testhelper.test_to_unichar_conv(b"\x65")
+
+ with pytest.raises(TypeError):
+ testhelper.test_to_unichar_conv(object())
+
+ with pytest.raises(TypeError):
+ testhelper.test_to_unichar_conv(u"AA")
+
+
+def test_constant_strip_prefix():
+ assert testhelper.constant_strip_prefix("foo", "bar") == "foo"
+ assert testhelper.constant_strip_prefix("foo", "f") == "oo"
+ assert testhelper.constant_strip_prefix("foo", "f") == "oo"
+ assert testhelper.constant_strip_prefix("ha2foo", "ha") == "a2foo"
+ assert testhelper.constant_strip_prefix("2foo", "ha") == "2foo"
+ assert testhelper.constant_strip_prefix("bla_foo", "bla") == "_foo"
+
+
+def test_state_ensure_release():
+ testhelper.test_state_ensure_release()
diff --git a/tests/test_iochannel.py b/tests/test_iochannel.py
index 0cc1b4b..c4c6e3d 100644
--- a/tests/test_iochannel.py
+++ b/tests/test_iochannel.py
@@ -1,19 +1,20 @@
# -*- Mode: Python -*-
-# encoding: UTF-8
-from __future__ import unicode_literals
+import os
import unittest
import tempfile
import os.path
-import fcntl
import shutil
import warnings
+try:
+ import fcntl
+except ImportError:
+ fcntl = None
+
from gi.repository import GLib
from gi import PyGIDeprecationWarning
-from compathelper import _unicode
-
class IOChannel(unittest.TestCase):
def setUp(self):
@@ -21,7 +22,7 @@ class IOChannel(unittest.TestCase):
self.testutf8 = os.path.join(self.workdir, 'testutf8.txt')
with open(self.testutf8, 'wb') as f:
- f.write('''hello ♥ world
+ f.write(u'''hello ♥ world
second line
À demain!'''.encode('UTF-8'))
@@ -42,24 +43,24 @@ second line
ch = GLib.IOChannel(filename=self.testutf8)
self.assertEqual(ch.get_encoding(), 'UTF-8')
self.assertTrue(ch.get_close_on_unref())
- self.assertEqual(_unicode(ch.readline()), 'hello ♥ world\n')
+ self.assertEqual(ch.readline(), 'hello ♥ world\n')
self.assertEqual(ch.get_buffer_condition(), GLib.IOCondition.IN)
self.assertEqual(ch.readline(), 'second line\n')
self.assertEqual(ch.readline(), '\n')
- self.assertEqual(_unicode(ch.readline()), 'À demain!')
+ self.assertEqual(ch.readline(), 'À demain!')
self.assertEqual(ch.get_buffer_condition(), 0)
self.assertEqual(ch.readline(), '')
- ch.close()
+ ch.shutdown(True)
def test_file_readline_latin1(self):
ch = GLib.IOChannel(filename=self.testlatin1, mode='r')
ch.set_encoding('latin1')
self.assertEqual(ch.get_encoding(), 'latin1')
- self.assertEqual(_unicode(ch.readline()), 'hellø world\n')
+ self.assertEqual(ch.readline(), 'hellø world\n')
self.assertEqual(ch.readline(), 'second line\n')
self.assertEqual(ch.readline(), '\n')
- self.assertEqual(_unicode(ch.readline()), 'À demain!')
- ch.close()
+ self.assertEqual(ch.readline(), 'À demain!')
+ ch.shutdown(True)
def test_file_iter(self):
items = []
@@ -67,8 +68,8 @@ second line
for item in ch:
items.append(item)
self.assertEqual(len(items), 4)
- self.assertEqual(_unicode(items[0]), 'hello ♥ world\n')
- ch.close()
+ self.assertEqual(items[0], 'hello ♥ world\n')
+ ch.shutdown(True)
def test_file_readlines(self):
ch = GLib.IOChannel(filename=self.testutf8)
@@ -77,8 +78,8 @@ second line
# empty one
self.assertGreaterEqual(len(lines), 4)
self.assertLessEqual(len(lines), 5)
- self.assertEqual(_unicode(lines[0]), 'hello ♥ world\n')
- self.assertEqual(_unicode(lines[3]), 'À demain!')
+ self.assertEqual(lines[0], 'hello ♥ world\n')
+ self.assertEqual(lines[3], 'À demain!')
if len(lines) == 4:
self.assertEqual(lines[4], '')
@@ -108,28 +109,29 @@ second line
ch.seek(2, 2) # SEEK_END
# FIXME: does not work currently
- #self.assertEqual(ch.read(2), b'n!')
+ # self.assertEqual(ch.read(2), b'n!')
# invalid whence value
self.assertRaises(ValueError, ch.seek, 0, 3)
+ ch.shutdown(True)
def test_file_write(self):
ch = GLib.IOChannel(filename=self.testout, mode='w')
ch.set_encoding('latin1')
ch.write('hellø world\n')
- ch.close()
+ ch.shutdown(True)
ch = GLib.IOChannel(filename=self.testout, mode='a')
ch.set_encoding('latin1')
ch.write('À demain!')
- ch.close()
+ ch.shutdown(True)
with open(self.testout, 'rb') as f:
- self.assertEqual(f.read().decode('latin1'), 'hellø world\nÀ demain!')
+ self.assertEqual(f.read().decode('latin1'), u'hellø world\nÀ demain!')
def test_file_writelines(self):
ch = GLib.IOChannel(filename=self.testout, mode='w')
ch.writelines(['foo', 'bar\n', 'baz\n', 'end'])
- ch.close()
+ ch.shutdown(True)
with open(self.testout, 'r') as f:
self.assertEqual(f.read(), 'foobar\nbaz\nend')
@@ -163,10 +165,11 @@ second line
# closing flushes
writer.set_buffered(True)
writer.write('ghi')
- writer.close()
+ writer.shutdown(True)
self.assertEqual(reader.read(), b'ghi')
- reader.close()
+ reader.shutdown(True)
+ @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows")
def test_fd_read(self):
(r, w) = os.pipe()
@@ -184,8 +187,9 @@ second line
os.close(w)
self.assertEqual(ch.read(), b'\x03\x04')
- ch.close()
+ ch.shutdown(True)
+ @unittest.skipUnless(fcntl, "no fcntl")
def test_fd_write(self):
(r, w) = os.pipe()
fcntl.fcntl(r, fcntl.F_SETFL, fcntl.fcntl(r, fcntl.F_GETFL) | os.O_NONBLOCK)
@@ -199,10 +203,11 @@ second line
# now test blocking case, after closing the write end
fcntl.fcntl(r, fcntl.F_SETFL, fcntl.fcntl(r, fcntl.F_GETFL) & ~os.O_NONBLOCK)
ch.write(b'\x03\x04')
- ch.close()
+ ch.shutdown(True)
self.assertEqual(os.read(r, 10), b'\x03\x04')
os.close(r)
+ @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows")
def test_deprecated_method_add_watch_no_data(self):
(r, w) = os.pipe()
@@ -216,23 +221,28 @@ second line
self.assertEqual(channel, ch)
self.assertEqual(condition, GLib.IOCondition.IN)
cb_reads.append(channel.read())
+ if len(cb_reads) == 2:
+ ml.quit()
return True
# io_add_watch() method is deprecated, use GLib.io_add_watch
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
- ch.add_watch(GLib.IOCondition.IN, cb)
+ ch.add_watch(GLib.IOCondition.IN, cb, priority=GLib.PRIORITY_HIGH)
self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
- ml = GLib.MainLoop()
+ def write():
+ os.write(w, b'a')
+ GLib.idle_add(lambda: os.write(w, b'b') and False)
- GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
- GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
- GLib.timeout_add(200, ml.quit)
+ ml = GLib.MainLoop()
+ GLib.idle_add(write)
+ GLib.timeout_add(2000, ml.quit)
ml.run()
self.assertEqual(cb_reads, [b'a', b'b'])
+ @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows")
def test_deprecated_method_add_watch_data_priority(self):
(r, w) = os.pipe()
@@ -247,6 +257,8 @@ second line
self.assertEqual(condition, GLib.IOCondition.IN)
self.assertEqual(data, 'hello')
cb_reads.append(channel.read())
+ if len(cb_reads) == 2:
+ ml.quit()
return True
ml = GLib.MainLoop()
@@ -259,13 +271,17 @@ second line
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_HIGH)
- GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
- GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
- GLib.timeout_add(200, ml.quit)
+ def write():
+ os.write(w, b'a')
+ GLib.idle_add(lambda: os.write(w, b'b') and False)
+
+ GLib.idle_add(write)
+ GLib.timeout_add(2000, ml.quit)
ml.run()
self.assertEqual(cb_reads, [b'a', b'b'])
+ @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows")
def test_add_watch_no_data(self):
(r, w) = os.pipe()
@@ -279,6 +295,8 @@ second line
self.assertEqual(channel, ch)
self.assertEqual(condition, GLib.IOCondition.IN)
cb_reads.append(channel.read())
+ if len(cb_reads) == 2:
+ ml.quit()
return True
id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb)
@@ -286,13 +304,18 @@ second line
ml = GLib.MainLoop()
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_HIGH)
- GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
- GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
- GLib.timeout_add(200, ml.quit)
+
+ def write():
+ os.write(w, b'a')
+ GLib.idle_add(lambda: os.write(w, b'b') and False)
+
+ GLib.idle_add(write)
+ GLib.timeout_add(2000, ml.quit)
ml.run()
self.assertEqual(cb_reads, [b'a', b'b'])
+ @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows")
def test_add_watch_with_data(self):
(r, w) = os.pipe()
@@ -307,6 +330,8 @@ second line
self.assertEqual(condition, GLib.IOCondition.IN)
self.assertEqual(data, 'hello')
cb_reads.append(channel.read())
+ if len(cb_reads) == 2:
+ ml.quit()
return True
id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb, 'hello')
@@ -314,13 +339,18 @@ second line
ml = GLib.MainLoop()
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_HIGH)
- GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
- GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
- GLib.timeout_add(200, ml.quit)
+
+ def write():
+ os.write(w, b'a')
+ GLib.idle_add(lambda: os.write(w, b'b') and False)
+
+ GLib.idle_add(write)
+ GLib.timeout_add(2000, ml.quit)
ml.run()
self.assertEqual(cb_reads, [b'a', b'b'])
+ @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows")
def test_add_watch_with_multi_data(self):
(r, w) = os.pipe()
@@ -337,6 +367,8 @@ second line
self.assertEqual(data2, 'b')
self.assertEqual(data3, 'c')
cb_reads.append(channel.read())
+ if len(cb_reads) == 2:
+ ml.quit()
return True
id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb,
@@ -345,13 +377,18 @@ second line
ml = GLib.MainLoop()
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_HIGH)
- GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
- GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
- GLib.timeout_add(200, ml.quit)
+
+ def write():
+ os.write(w, b'a')
+ GLib.idle_add(lambda: os.write(w, b'b') and False)
+
+ GLib.idle_add(write)
+ GLib.timeout_add(2000, ml.quit)
ml.run()
self.assertEqual(cb_reads, [b'a', b'b'])
+ @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows")
def test_deprecated_add_watch_no_data(self):
(r, w) = os.pipe()
@@ -365,6 +402,8 @@ second line
self.assertEqual(channel, ch)
self.assertEqual(condition, GLib.IOCondition.IN)
cb_reads.append(channel.read())
+ if len(cb_reads) == 2:
+ ml.quit()
return True
with warnings.catch_warnings(record=True) as warn:
@@ -375,13 +414,18 @@ second line
ml = GLib.MainLoop()
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_HIGH)
- GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
- GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
- GLib.timeout_add(200, ml.quit)
+
+ def write():
+ os.write(w, b'a')
+ GLib.idle_add(lambda: os.write(w, b'b') and False)
+
+ GLib.idle_add(write)
+ GLib.timeout_add(2000, ml.quit)
ml.run()
self.assertEqual(cb_reads, [b'a', b'b'])
+ @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows")
def test_deprecated_add_watch_with_data(self):
(r, w) = os.pipe()
@@ -396,6 +440,8 @@ second line
self.assertEqual(condition, GLib.IOCondition.IN)
self.assertEqual(data, 'hello')
cb_reads.append(channel.read())
+ if len(cb_reads) == 2:
+ ml.quit()
return True
with warnings.catch_warnings(record=True) as warn:
@@ -407,18 +453,23 @@ second line
ml = GLib.MainLoop()
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_HIGH)
- GLib.timeout_add(10, lambda: os.write(w, b'a') and False)
- GLib.timeout_add(100, lambda: os.write(w, b'b') and False)
- GLib.timeout_add(200, ml.quit)
+
+ def write():
+ os.write(w, b'a')
+ GLib.idle_add(lambda: os.write(w, b'b') and False)
+
+ GLib.idle_add(write)
+
+ GLib.timeout_add(2000, ml.quit)
ml.run()
self.assertEqual(cb_reads, [b'a', b'b'])
def test_backwards_compat_flags(self):
- self.assertEqual(GLib.IOCondition.IN, GLib.IO_IN)
- self.assertEqual(GLib.IOFlags.NONBLOCK, GLib.IO_FLAG_NONBLOCK)
- self.assertEqual(GLib.IOFlags.IS_SEEKABLE, GLib.IO_FLAG_IS_SEEKABLE)
- self.assertEqual(GLib.IOStatus.NORMAL, GLib.IO_STATUS_NORMAL)
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', PyGIDeprecationWarning)
-if __name__ == '__main__':
- unittest.main()
+ self.assertEqual(GLib.IOCondition.IN, GLib.IO_IN)
+ self.assertEqual(GLib.IOFlags.NONBLOCK, GLib.IO_FLAG_NONBLOCK)
+ self.assertEqual(GLib.IOFlags.IS_SEEKABLE, GLib.IO_FLAG_IS_SEEKABLE)
+ self.assertEqual(GLib.IOStatus.NORMAL, GLib.IO_STATUS_NORMAL)
diff --git a/tests/test_mainloop.py b/tests/test_mainloop.py
index 44197b3..48399d1 100644
--- a/tests/test_mainloop.py
+++ b/tests/test_mainloop.py
@@ -1,24 +1,18 @@
# -*- Mode: Python -*-
import os
-import sys
import select
import signal
-import time
import unittest
-try:
- from _thread import start_new_thread
- start_new_thread # pyflakes
-except ImportError:
- # Python 2
- from thread import start_new_thread
from gi.repository import GLib
-from compathelper import _bytes
+from .helper import capture_exceptions
class TestMainLoop(unittest.TestCase):
+
+ @unittest.skipUnless(hasattr(os, "fork"), "no os.fork available")
def test_exception_handling(self):
pipe_r, pipe_w = os.pipe()
@@ -37,56 +31,35 @@ class TestMainLoop(unittest.TestCase):
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, child_died, loop)
os.close(pipe_r)
- os.write(pipe_w, _bytes("Y"))
+ os.write(pipe_w, b"Y")
os.close(pipe_w)
- def excepthook(type, value, traceback):
- self.assertTrue(type is Exception)
- self.assertEqual(value.args[0], "deadbabe")
- sys.excepthook = excepthook
- try:
- got_exception = False
- try:
- loop.run()
- except:
- got_exception = True
- finally:
- sys.excepthook = sys.__excepthook__
-
- #
- # The exception should be handled (by printing it)
- # immediately on return from child_died() rather
- # than here. See bug #303573
- #
- self.assertFalse(got_exception)
-
- def test_concurrency(self):
- def on_usr1(signum, frame):
- pass
+ with capture_exceptions() as exc:
+ loop.run()
- try:
- # create a thread which will terminate upon SIGUSR1 by way of
- # interrupting sleep()
- orig_handler = signal.signal(signal.SIGUSR1, on_usr1)
- start_new_thread(time.sleep, (10,))
-
- # now create two main loops
- loop1 = GLib.MainLoop()
- loop2 = GLib.MainLoop()
- GLib.timeout_add(100, lambda: os.kill(os.getpid(), signal.SIGUSR1))
- GLib.timeout_add(500, loop1.quit)
- loop1.run()
- loop2.quit()
- finally:
- signal.signal(signal.SIGUSR1, orig_handler)
+ assert len(exc) == 1
+ assert exc[0].type is Exception
+ assert exc[0].value.args[0] == "deadbabe"
+ @unittest.skipUnless(hasattr(os, "fork"), "no os.fork available")
+ @unittest.skipIf(os.environ.get("PYGI_TEST_GDB"), "SIGINT stops gdb")
def test_sigint(self):
+ r, w = os.pipe()
pid = os.fork()
if pid == 0:
- time.sleep(0.5)
+ # wait for the parent process loop to start
+ os.read(r, 1)
+ os.close(r)
+
os.kill(os.getppid(), signal.SIGINT)
os._exit(0)
+ def notify_child():
+ # tell the child that it can kill the parent
+ os.write(w, b"X")
+ os.close(w)
+
+ GLib.idle_add(notify_child)
loop = GLib.MainLoop()
try:
loop.run()
diff --git a/tests/test_object_marshaling.py b/tests/test_object_marshaling.py
index 624ed9d..d52ff54 100644
--- a/tests/test_object_marshaling.py
+++ b/tests/test_object_marshaling.py
@@ -10,6 +10,11 @@ import warnings
from gi.repository import GObject
from gi.repository import GIMarshallingTests
+try:
+ from gi.repository import Regress
+except ImportError:
+ Regress = None
+
class StrongRef(object):
# A class that behaves like weakref.ref but holds a strong reference.
@@ -103,7 +108,8 @@ class TestVFuncsWithObjectArg(unittest.TestCase):
vfuncs.get_ref_info_for_vfunc_return_object_transfer_full() # Use any vfunc to test this.
gc.collect()
- self.assertEqual(sys.getrefcount(vfuncs), 2)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(sys.getrefcount(vfuncs), 2)
self.assertEqual(vfuncs.__grefcount__, 1)
del vfuncs
@@ -120,11 +126,13 @@ class TestVFuncsWithObjectArg(unittest.TestCase):
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none()
- self.assertTrue(issubclass(warn[0].category, RuntimeWarning))
+ if hasattr(sys, "getrefcount"):
+ self.assertTrue(issubclass(warn[0].category, RuntimeWarning))
# The ref count of the GObject returned to the caller (get_ref_info_for_vfunc_return_object_transfer_none)
# should be a single floating ref
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
@@ -136,9 +144,11 @@ class TestVFuncsWithObjectArg(unittest.TestCase):
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter('always')
ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none()
- self.assertTrue(issubclass(warn[0].category, RuntimeWarning))
+ if hasattr(sys, "getrefcount"):
+ self.assertTrue(issubclass(warn[0].category, RuntimeWarning))
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
@@ -150,7 +160,8 @@ class TestVFuncsWithObjectArg(unittest.TestCase):
# The vfunc caller receives full ownership of a single ref which should not
# be floating.
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
@@ -161,7 +172,8 @@ class TestVFuncsWithObjectArg(unittest.TestCase):
vfuncs = self.VFuncs()
ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full()
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
@@ -175,9 +187,12 @@ class TestVFuncsWithObjectArg(unittest.TestCase):
self.assertEqual(vfuncs.in_object_grefcount, 2) # initial + python wrapper
self.assertFalse(vfuncs.in_object_is_floating)
- self.assertEqual(ref_count, 1) # ensure python wrapper released
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1) # ensure python wrapper released
self.assertFalse(is_floating)
+ gc.collect()
+ gc.collect()
self.assertTrue(vfuncs.object_ref() is None)
def test_vfunc_in_object_transfer_full(self):
@@ -191,9 +206,12 @@ class TestVFuncsWithObjectArg(unittest.TestCase):
self.assertFalse(vfuncs.in_object_is_floating)
# ensure python wrapper took ownership and released, after vfunc was complete
- self.assertEqual(ref_count, 0)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 0)
self.assertFalse(is_floating)
+ gc.collect()
+ gc.collect()
self.assertTrue(vfuncs.object_ref() is None)
@@ -205,6 +223,7 @@ class TestVFuncsWithFloatingArg(unittest.TestCase):
Object = GObject.InitiallyUnowned
ObjectRef = weakref.ref
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "refcount specific")
def test_vfunc_return_object_transfer_none_with_floating(self):
# Python is expected to return a single floating reference without warning.
vfuncs = self.VFuncs()
@@ -218,6 +237,7 @@ class TestVFuncsWithFloatingArg(unittest.TestCase):
gc.collect()
self.assertTrue(vfuncs.object_ref() is None)
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "refcount specific")
def test_vfunc_out_object_transfer_none_with_floating(self):
# Same as above except uses out arg instead of return
vfuncs = self.VFuncs()
@@ -234,7 +254,8 @@ class TestVFuncsWithFloatingArg(unittest.TestCase):
ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_full()
# The vfunc caller receives full ownership of a single ref.
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
@@ -245,7 +266,8 @@ class TestVFuncsWithFloatingArg(unittest.TestCase):
vfuncs = self.VFuncs()
ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full()
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertFalse(is_floating)
gc.collect()
@@ -262,9 +284,12 @@ class TestVFuncsWithFloatingArg(unittest.TestCase):
self.assertTrue(vfuncs.in_object_is_floating)
# vfunc caller should only have a single floating ref after the vfunc finishes
- self.assertEqual(ref_count, 1)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 1)
self.assertTrue(is_floating)
+ gc.collect()
+ gc.collect()
self.assertTrue(vfuncs.object_ref() is None)
def test_vfunc_in_object_transfer_full_with_floating(self):
@@ -278,9 +303,12 @@ class TestVFuncsWithFloatingArg(unittest.TestCase):
self.assertFalse(vfuncs.in_object_is_floating)
# ensure python wrapper took ownership and released
- self.assertEqual(ref_count, 0)
+ if hasattr(sys, "getrefcount"):
+ self.assertEqual(ref_count, 0)
self.assertFalse(is_floating)
+ gc.collect()
+ gc.collect()
self.assertTrue(vfuncs.object_ref() is None)
@@ -535,69 +563,31 @@ class TestVFuncsWithHeldFloatingArg(unittest.TestCase):
self.assertTrue(held_object_ref() is None)
-class TestPropertyHoldingObject(unittest.TestCase):
- def test_props_getter_holding_object_ref_count(self):
- holder = GIMarshallingTests.PropertiesObject()
- held = GObject.Object()
-
- self.assertEqual(holder.__grefcount__, 1)
- self.assertEqual(held.__grefcount__, 1)
-
- holder.set_property('some-object', held)
- self.assertEqual(holder.__grefcount__, 1)
-
- initial_ref_count = held.__grefcount__
- holder.props.some_object
- gc.collect()
- self.assertEqual(held.__grefcount__, initial_ref_count)
-
- def test_get_property_holding_object_ref_count(self):
- holder = GIMarshallingTests.PropertiesObject()
- held = GObject.Object()
-
- self.assertEqual(holder.__grefcount__, 1)
- self.assertEqual(held.__grefcount__, 1)
-
- holder.set_property('some-object', held)
- self.assertEqual(holder.__grefcount__, 1)
-
- initial_ref_count = held.__grefcount__
- holder.get_property('some-object')
- gc.collect()
- self.assertEqual(held.__grefcount__, initial_ref_count)
-
- def test_props_setter_holding_object_ref_count(self):
- holder = GIMarshallingTests.PropertiesObject()
- held = GObject.Object()
-
- self.assertEqual(holder.__grefcount__, 1)
- self.assertEqual(held.__grefcount__, 1)
-
- # Setting property should only increase ref count by 1
- holder.props.some_object = held
- self.assertEqual(holder.__grefcount__, 1)
- self.assertEqual(held.__grefcount__, 2)
-
- # Clearing should pull it back down
- holder.props.some_object = None
- self.assertEqual(held.__grefcount__, 1)
-
- def test_set_property_holding_object_ref_count(self):
- holder = GIMarshallingTests.PropertiesObject()
- held = GObject.Object()
-
- self.assertEqual(holder.__grefcount__, 1)
- self.assertEqual(held.__grefcount__, 1)
-
- # Setting property should only increase ref count by 1
- holder.set_property('some-object', held)
- self.assertEqual(holder.__grefcount__, 1)
- self.assertEqual(held.__grefcount__, 2)
-
- # Clearing should pull it back down
- holder.set_property('some-object', None)
- self.assertEqual(held.__grefcount__, 1)
-
- def test_set_object_property_to_invalid_type(self):
- obj = GIMarshallingTests.PropertiesObject()
- self.assertRaises(TypeError, obj.set_property, 'some-object', 'not_an_object')
+@unittest.skipIf(Regress is None, 'Regress is required')
+class TestArgumentTypeErrors(unittest.TestCase):
+ def test_object_argument_type_error(self):
+ # ensure TypeError is raised for things which are not GObjects
+ obj = Regress.TestObj()
+ obj.set_bare(GObject.Object())
+ obj.set_bare(None)
+
+ self.assertRaises(TypeError, obj.set_bare, object())
+ self.assertRaises(TypeError, obj.set_bare, 42)
+ self.assertRaises(TypeError, obj.set_bare, 'not an object')
+
+ def test_instance_argument_error(self):
+ # ensure TypeError is raised for non Regress.TestObj instances.
+ obj = Regress.TestObj()
+ self.assertEqual(Regress.TestObj.instance_method(obj), -1)
+ self.assertRaises(TypeError, Regress.TestObj.instance_method, object())
+ self.assertRaises(TypeError, Regress.TestObj.instance_method, GObject.Object())
+ self.assertRaises(TypeError, Regress.TestObj.instance_method, 42)
+ self.assertRaises(TypeError, Regress.TestObj.instance_method, 'not an object')
+
+ def test_instance_argument_base_type_error(self):
+ # ensure TypeError is raised when a base type is passed to something
+ # expecting a derived type
+ obj = Regress.TestSubObj()
+ self.assertEqual(Regress.TestSubObj.instance_method(obj), 0)
+ self.assertRaises(TypeError, Regress.TestSubObj.instance_method, GObject.Object())
+ self.assertRaises(TypeError, Regress.TestSubObj.instance_method, Regress.TestObj())
diff --git a/tests/test_option.py b/tests/test_option.py
index 2900edd..1dc496a 100644
--- a/tests/test_option.py
+++ b/tests/test_option.py
@@ -1,20 +1,13 @@
#!/usr/bin/env python
import unittest
-import sys
-
-# py3k has StringIO in a different module
-try:
- from StringIO import StringIO
- StringIO # pyflakes
-except ImportError:
- from io import StringIO
from gi.repository import GLib
+from .helper import capture_exceptions
+
class TestOption(unittest.TestCase):
- EXCEPTION_MESSAGE = "This callback fails"
def setUp(self):
self.parser = GLib.option.OptionParser("NAMES...",
@@ -28,7 +21,7 @@ class TestOption(unittest.TestCase):
def _create_group(self):
def option_callback(option, opt, value, parser):
- raise Exception(self.EXCEPTION_MESSAGE)
+ raise Exception("foo")
group = GLib.option.OptionGroup(
"unittest", "Unit test options", "Show all unittest options",
@@ -55,29 +48,53 @@ class TestOption(unittest.TestCase):
self.parser.add_option_group(group)
return group
- def test_parse_args(self):
+ def test_integer(self):
+ self._create_group()
options, args = self.parser.parse_args(
- ["test_option.py"])
- self.assertFalse(args)
+ ["--test-integer", "42", "bla"])
+ assert options.test_integer == 42
+ assert args == ["bla"]
+
+ def test_file(self):
+ self._create_group()
options, args = self.parser.parse_args(
- ["test_option.py", "foo"])
- self.assertEqual(args, [])
+ ["--file", "fn", "bla"])
+ assert options.unit_file == "fn"
+ assert args == ["bla"]
+
+ def test_mixed(self):
+ self._create_group()
options, args = self.parser.parse_args(
- ["test_option.py", "foo", "bar"])
- self.assertEqual(args, [])
+ ["--file", "fn", "--test-integer", "12", "--test",
+ "--g-fatal-warnings", "nope"])
+
+ assert options.unit_file == "fn"
+ assert options.test_integer == 12
+ assert options.test is False
+ assert options.fatal_warnings is True
+ assert args == ["nope"]
+
+ def test_parse_args(self):
+ options, args = self.parser.parse_args([])
+ self.assertFalse(args)
+
+ options, args = self.parser.parse_args(["foo"])
+ self.assertEqual(args, ["foo"])
+
+ options, args = self.parser.parse_args(["foo", "bar"])
+ self.assertEqual(args, ["foo", "bar"])
def test_parse_args_double_dash(self):
- options, args = self.parser.parse_args(
- ["test_option.py", "--", "-xxx"])
- #self.assertEqual(args, ["-xxx"])
+ options, args = self.parser.parse_args(["--", "-xxx"])
+ self.assertEqual(args, ["--", "-xxx"])
def test_parse_args_group(self):
group = self._create_group()
options, args = self.parser.parse_args(
- ["test_option.py", "--test", "-f", "test"])
+ ["--test", "-f", "test"])
self.assertFalse(options.test)
self.assertEqual(options.unit_file, "test")
@@ -90,26 +107,21 @@ class TestOption(unittest.TestCase):
def test_option_value_error(self):
self._create_group()
self.assertRaises(GLib.option.OptionValueError, self.parser.parse_args,
- ["test_option.py", "--test-integer=text"])
+ ["--test-integer=text"])
def test_bad_option_error(self):
self.assertRaises(GLib.option.BadOptionError,
self.parser.parse_args,
- ["test_option.py", "--unknwon-option"])
+ ["--unknwon-option"])
def test_option_group_constructor(self):
self.assertRaises(TypeError, GLib.option.OptionGroup)
def test_standard_error(self):
self._create_group()
- sio = StringIO()
- old_stderr = sys.stderr
- sys.stderr = sio
- try:
- self.parser.parse_args(
- ["test_option.py", "--callback-failure-test"])
- finally:
- sys.stderr = old_stderr
-
- assert (sio.getvalue().split('\n')[-2] ==
- "Exception: " + self.EXCEPTION_MESSAGE)
+
+ with capture_exceptions() as exc:
+ self.parser.parse_args(["--callback-failure-test"])
+
+ assert len(exc) == 1
+ assert exc[0].value.args[0] == "foo"
diff --git a/tests/test_ossig.py b/tests/test_ossig.py
new file mode 100644
index 0000000..bdd7f70
--- /dev/null
+++ b/tests/test_ossig.py
@@ -0,0 +1,182 @@
+# Copyright 2017 Christoph Reiter
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import
+
+import os
+import signal
+import unittest
+import threading
+from contextlib import contextmanager
+
+try:
+ from gi.repository import Gtk
+ Gtk_version = Gtk._version
+except ImportError:
+ Gtk = None
+ Gtk_version = None
+from gi.repository import Gio, GLib
+from gi._ossighelper import wakeup_on_signal, register_sigint_fallback
+
+
+class TestOverridesWakeupOnAlarm(unittest.TestCase):
+
+ @contextmanager
+ def _run_with_timeout(self, timeout, abort_func):
+ failed = []
+
+ def fail():
+ abort_func()
+ failed.append(1)
+ return True
+
+ fail_id = GLib.timeout_add(timeout, fail)
+ try:
+ yield
+ finally:
+ GLib.source_remove(fail_id)
+ self.assertFalse(failed)
+
+ def test_basic(self):
+ self.assertEqual(signal.set_wakeup_fd(-1), -1)
+ with wakeup_on_signal():
+ pass
+ self.assertEqual(signal.set_wakeup_fd(-1), -1)
+
+ def test_in_thread(self):
+ failed = []
+
+ def target():
+ try:
+ with wakeup_on_signal():
+ pass
+ except:
+ failed.append(1)
+
+ t = threading.Thread(target=target)
+ t.start()
+ t.join(5)
+ self.assertFalse(failed)
+
+ @unittest.skipIf(os.name == "nt", "not on Windows")
+ def test_glib_mainloop(self):
+ loop = GLib.MainLoop()
+ signal.signal(signal.SIGALRM, lambda *args: loop.quit())
+ GLib.idle_add(signal.setitimer, signal.ITIMER_REAL, 0.001)
+
+ with self._run_with_timeout(2000, loop.quit):
+ loop.run()
+
+ @unittest.skipIf(os.name == "nt", "not on Windows")
+ def test_gio_application(self):
+ app = Gio.Application()
+ signal.signal(signal.SIGALRM, lambda *args: app.quit())
+ GLib.idle_add(signal.setitimer, signal.ITIMER_REAL, 0.001)
+
+ with self._run_with_timeout(2000, app.quit):
+ app.hold()
+ app.connect("activate", lambda *args: None)
+ app.run()
+
+ @unittest.skipIf(Gtk is None or os.name == "nt", "not on Windows")
+ @unittest.skipIf(Gtk is None or Gtk_version == "4.0", "not in gtk4")
+ def test_gtk_main(self):
+ signal.signal(signal.SIGALRM, lambda *args: Gtk.main_quit())
+ GLib.idle_add(signal.setitimer, signal.ITIMER_REAL, 0.001)
+
+ with self._run_with_timeout(2000, Gtk.main_quit):
+ Gtk.main()
+
+ @unittest.skipIf(Gtk is None or os.name == "nt", "not on Windows")
+ @unittest.skipIf(Gtk is None or Gtk_version == "4.0", "not in gtk4")
+ def test_gtk_dialog_run(self):
+ w = Gtk.Window()
+ d = Gtk.Dialog(transient_for=w)
+ signal.signal(signal.SIGALRM, lambda *args: d.destroy())
+ GLib.idle_add(signal.setitimer, signal.ITIMER_REAL, 0.001)
+
+ with self._run_with_timeout(2000, d.destroy):
+ d.run()
+
+
+class TestSigintFallback(unittest.TestCase):
+
+ def setUp(self):
+ self.assertEqual(
+ signal.getsignal(signal.SIGINT), signal.default_int_handler)
+
+ def tearDown(self):
+ self.assertEqual(
+ signal.getsignal(signal.SIGINT), signal.default_int_handler)
+
+ def test_replace_handler_and_restore_nested(self):
+ with register_sigint_fallback(lambda: None):
+ new_handler = signal.getsignal(signal.SIGINT)
+ self.assertNotEqual(new_handler, signal.default_int_handler)
+ with register_sigint_fallback(lambda: None):
+ self.assertTrue(signal.getsignal(signal.SIGINT) is new_handler)
+ self.assertEqual(
+ signal.getsignal(signal.SIGINT), signal.default_int_handler)
+
+ def test_no_replace_if_not_default(self):
+ new_handler = lambda *args: None
+ signal.signal(signal.SIGINT, new_handler)
+ try:
+ with register_sigint_fallback(lambda: None):
+ self.assertTrue(signal.getsignal(signal.SIGINT) is new_handler)
+ with register_sigint_fallback(lambda: None):
+ self.assertTrue(
+ signal.getsignal(signal.SIGINT) is new_handler)
+ self.assertTrue(signal.getsignal(signal.SIGINT) is new_handler)
+ finally:
+ signal.signal(signal.SIGINT, signal.default_int_handler)
+
+ def test_noop_in_threads(self):
+ failed = []
+
+ def target():
+ try:
+ with register_sigint_fallback(lambda: None):
+ with register_sigint_fallback(lambda: None):
+ self.assertTrue(
+ signal.getsignal(signal.SIGINT) is
+ signal.default_int_handler)
+ except:
+ failed.append(1)
+
+ t = threading.Thread(target=target)
+ t.start()
+ t.join(5)
+ self.assertFalse(failed)
+
+ @unittest.skipIf(os.name == "nt", "not on Windows")
+ def test_no_replace_if_set_by_glib(self):
+ id_ = GLib.unix_signal_add(
+ GLib.PRIORITY_DEFAULT, signal.SIGINT, lambda *args: None)
+ try:
+ # signal.getsignal() doesn't pick up that unix_signal_add()
+ # has changed the handler, but we should anyway.
+ self.assertEqual(
+ signal.getsignal(signal.SIGINT), signal.default_int_handler)
+ with register_sigint_fallback(lambda: None):
+ self.assertEqual(
+ signal.getsignal(signal.SIGINT),
+ signal.default_int_handler)
+ self.assertEqual(
+ signal.getsignal(signal.SIGINT), signal.default_int_handler)
+ finally:
+ GLib.source_remove(id_)
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ signal.signal(signal.SIGINT, signal.default_int_handler)
diff --git a/tests/test_overrides.py b/tests/test_overrides.py
deleted file mode 100644
index e1af1f1..0000000
--- a/tests/test_overrides.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# -*- Mode: Python; py-indent-offset: 4 -*-
-# vim: tabstop=4 shiftwidth=4 expandtab
-
-import unittest
-
-import gi.overrides
-import gi.module
-
-try:
- from gi.repository import Regress
- Regress # pyflakes
-except ImportError:
- Regress = None
-
-
-class TestRegistry(unittest.TestCase):
- def test_non_gi(self):
- class MyClass:
- pass
-
- try:
- gi.overrides.override(MyClass)
- self.fail('unexpected success of overriding non-GI class')
- except TypeError as e:
- self.assertTrue('Can not override a type MyClass' in str(e))
-
- @unittest.skipUnless(Regress, 'built without cairo support')
- def test_separate_path(self):
- # Regress override is in tests/gi/overrides, separate from gi/overrides
- # https://bugzilla.gnome.org/show_bug.cgi?id=680913
- self.assertEqual(Regress.REGRESS_OVERRIDE, 42)
-
-
-class TestModule(unittest.TestCase):
- # Tests for gi.module
-
- def test_get_introspection_module_caching(self):
- # This test attempts to minimize side effects by
- # using a DynamicModule directly instead of going though:
- # from gi.repository import Foo
-
- # Clear out introspection module cache before running this test.
- old_modules = gi.module._introspection_modules
- gi.module._introspection_modules = {}
-
- mod_name = 'GIMarshallingTests'
- mod1 = gi.module.get_introspection_module(mod_name)
- mod2 = gi.module.get_introspection_module(mod_name)
- self.assertTrue(mod1 is mod2)
-
- # Using a DynamicModule will use get_introspection_module internally
- # in its _load method.
- mod_overridden = gi.module.DynamicModule(mod_name)
- mod_overridden._load()
- self.assertTrue(mod1 is mod_overridden._introspection_module)
-
- # Restore the previous cache
- gi.module._introspection_modules = old_modules
diff --git a/tests/test_overrides_gdk.py b/tests/test_overrides_gdk.py
index 46f0a38..119e56b 100644
--- a/tests/test_overrides_gdk.py
+++ b/tests/test_overrides_gdk.py
@@ -1,19 +1,46 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
# vim: tabstop=4 shiftwidth=4 expandtab
+import re
+import os
+import sys
import unittest
+import pytest
+import gi
import gi.overrides
+from gi import PyGIDeprecationWarning
try:
- from gi.repository import Gdk, GdkPixbuf, Gtk
- Gdk # pyflakes
+ from gi.repository import Gio, Gdk, GdkPixbuf, Gtk
+ GDK4 = Gdk._version == "4.0"
except ImportError:
Gdk = None
+ GDK4 = False
+
+
+def gtkver():
+ if Gtk is None:
+ return (0, 0, 0)
+ return (Gtk.get_major_version(),
+ Gtk.get_minor_version(),
+ Gtk.get_micro_version())
+
+
+try:
+ gi.require_foreign('cairo')
+ has_cairo = True
+except ImportError:
+ has_cairo = False
+
+from .helper import capture_glib_deprecation_warnings
@unittest.skipUnless(Gdk, 'Gdk not available')
class TestGdk(unittest.TestCase):
+
+ @unittest.skipIf(sys.platform == "darwin" or os.name == "nt", "crashes")
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_constructor(self):
attribute = Gdk.WindowAttr()
attribute.window_type = Gdk.WindowType.CHILD
@@ -22,14 +49,21 @@ class TestGdk(unittest.TestCase):
window = Gdk.Window(None, attribute, attributes_mask)
self.assertEqual(window.get_window_type(), Gdk.WindowType.CHILD)
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_color(self):
color = Gdk.Color(100, 200, 300)
self.assertEqual(color.red, 100)
self.assertEqual(color.green, 200)
self.assertEqual(color.blue, 300)
- self.assertEqual(color, Gdk.Color(100, 200, 300))
+ with capture_glib_deprecation_warnings():
+ self.assertEqual(color, Gdk.Color(100, 200, 300))
self.assertNotEqual(color, Gdk.Color(1, 2, 3))
+ self.assertNotEqual(color, None)
+ # assertNotEqual only tests __ne__. Following line explicitly
+ # tests __eq__ with objects of other types
+ self.assertFalse(color == object())
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_color_floats(self):
self.assertEqual(Gdk.Color(13107, 21845, 65535),
Gdk.Color.from_floats(0.2, 1.0 / 3.0, 1.0))
@@ -43,6 +77,20 @@ class TestGdk(unittest.TestCase):
self.assertEqual(Gdk.RGBA.from_color(Gdk.Color(13107, 21845, 65535)),
Gdk.RGBA(0.2, 1.0 / 3.0, 1.0, 1.0))
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_color_to_floats_attrs(self):
+ color = Gdk.Color(13107, 21845, 65535)
+ assert color.red_float == 0.2
+ color.red_float = 0
+ assert color.red_float == 0
+ assert color.green_float == 1.0 / 3.0
+ color.green_float = 0
+ assert color.green_float == 0
+ assert color.blue_float == 1.0
+ color.blue_float = 0
+ assert color.blue_float == 0
+
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_rgba(self):
self.assertEqual(Gdk.RGBA, gi.overrides.Gdk.RGBA)
rgba = Gdk.RGBA(0.1, 0.2, 0.3, 0.4)
@@ -54,25 +102,98 @@ class TestGdk(unittest.TestCase):
self.assertEqual(rgba.alpha, 0.4)
rgba.green = 0.9
self.assertEqual(rgba.green, 0.9)
+ self.assertNotEqual(rgba, None)
+ # assertNotEqual only tests __ne__. Following line explicitly
+ # tests __eq__ with objects of other types
+ self.assertFalse(rgba == object())
# Iterator/tuple convsersion
self.assertEqual(tuple(Gdk.RGBA(0.1, 0.2, 0.3, 0.4)),
(0.1, 0.2, 0.3, 0.4))
+ @unittest.skipUnless(GDK4, "only in gdk4")
+ def test_rgba_gtk4(self):
+ c = Gdk.RGBA()
+ assert c.to_string() == "rgba(0,0,0,0)"
+
+ @unittest.skipIf(not has_cairo or GDK4, "not in gdk4")
+ def test_window(self):
+ w = Gtk.Window()
+ w.realize()
+ window = w.get_window()
+ with capture_glib_deprecation_warnings():
+ assert window.cairo_create() is not None
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_drag_context(self):
+ context = Gdk.DragContext()
+ # using it this way crashes..
+ assert hasattr(context, "finish")
+
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_event(self):
event = Gdk.Event.new(Gdk.EventType.CONFIGURE)
self.assertEqual(event.type, Gdk.EventType.CONFIGURE)
self.assertEqual(event.send_event, 0)
+ event = Gdk.Event()
+ event.type = Gdk.EventType.SCROLL
+ self.assertRaises(AttributeError, lambda: getattr(event, 'foo_bar'))
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_scroll_event(self):
+ event = Gdk.Event.new(Gdk.EventType.SCROLL)
+ assert event.direction == Gdk.ScrollDirection.UP
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_event_strip_boolean(self):
+ ev = Gdk.EventButton()
+ ev.type = Gdk.EventType.BUTTON_PRESS
+ assert ev.get_coords() == (0.0, 0.0)
+
+ # https://gitlab.gnome.org/GNOME/pygobject/issues/85
+ ev = Gdk.Event.new(Gdk.EventType.BUTTON_PRESS)
+ assert ev.get_coords() == (True, 0.0, 0.0)
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_event_touch(self):
+ event = Gdk.Event.new(Gdk.EventType.TOUCH_BEGIN)
+ self.assertEqual(event.type, Gdk.EventType.TOUCH_BEGIN)
+
+ # emulating_pointer is unique to touch events
+ self.assertFalse(event.emulating_pointer)
+ self.assertFalse(event.touch.emulating_pointer)
+
+ event.emulating_pointer = True
+ self.assertTrue(event.emulating_pointer)
+ self.assertTrue(event.touch.emulating_pointer)
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_event_setattr(self):
event = Gdk.Event.new(Gdk.EventType.DRAG_MOTION)
event.x_root, event.y_root = 0, 5
+ self.assertEqual(event.dnd.x_root, 0)
+ self.assertEqual(event.dnd.y_root, 5)
self.assertEqual(event.x_root, 0)
self.assertEqual(event.y_root, 5)
- event = Gdk.Event()
- event.type = Gdk.EventType.SCROLL
- self.assertRaises(AttributeError, lambda: getattr(event, 'foo_bar'))
+ # this used to work, keep it that way
+ self.assertFalse(hasattr(event, "foo_bar"))
+ event.foo_bar = 42
+
+ # unhandled type
+ event.type = Gdk.EventType.EVENT_LAST
+ with pytest.raises(AttributeError):
+ event.foo_bar
+ event.foo_bar = 42
+ assert event.foo_bar == 42
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_event_repr(self):
+ event = Gdk.Event.new(Gdk.EventType.CONFIGURE)
+ self.assertTrue("CONFIGURE" in repr(event))
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_event_structures(self):
def button_press_cb(button, event):
self.assertTrue(isinstance(event, Gdk.EventButton))
@@ -88,18 +209,22 @@ class TestGdk(unittest.TestCase):
b = Gtk.Button()
b.connect('button-press-event', button_press_cb)
w.add(b)
- w.show_all()
+ b.show()
+ b.realize()
Gdk.test_simulate_button(b.get_window(),
2, 5,
0,
Gdk.ModifierType.CONTROL_MASK,
Gdk.EventType.BUTTON_PRESS)
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_cursor(self):
self.assertEqual(Gdk.Cursor, gi.overrides.Gdk.Cursor)
- c = Gdk.Cursor(Gdk.CursorType.WATCH)
+ with capture_glib_deprecation_warnings():
+ c = Gdk.Cursor(Gdk.CursorType.WATCH)
self.assertNotEqual(c, None)
- c = Gdk.Cursor(cursor_type=Gdk.CursorType.WATCH)
+ with capture_glib_deprecation_warnings():
+ c = Gdk.Cursor(cursor_type=Gdk.CursorType.WATCH)
self.assertNotEqual(c, None)
display_manager = Gdk.DisplayManager.get()
@@ -111,31 +236,90 @@ class TestGdk(unittest.TestCase):
5,
10)
- c = Gdk.Cursor(display,
- test_pixbuf,
- y=0, x=0)
+ with capture_glib_deprecation_warnings() as warn:
+ c = Gdk.Cursor(display,
+ test_pixbuf,
+ y=0, x=0)
+ self.assertNotEqual(c, None)
+
+ self.assertEqual(len(warn), 1)
+ self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning))
+ self.assertRegex(str(warn[0].message),
+ '.*new_from_pixbuf.*')
- self.assertNotEqual(c, None)
self.assertRaises(ValueError, Gdk.Cursor, 1, 2, 3)
+ with capture_glib_deprecation_warnings() as warn:
+ c = Gdk.Cursor(display, Gdk.CursorType.WATCH)
+ assert len(warn) == 1
+ # on macOS the type is switched to PIXMAP behind the scenes
+ assert c.props.cursor_type in (
+ Gdk.CursorType.WATCH, Gdk.CursorType.CURSOR_IS_PIXMAP)
+ assert c.props.display == display
+
+ @unittest.skipUnless(GDK4, "only gdk4")
+ def test_cursor_gdk4(self):
+ Gdk.Cursor()
+ Gdk.Cursor(name="foo")
+ Gdk.Cursor(fallback=Gdk.Cursor())
+
def test_flags(self):
self.assertEqual(Gdk.ModifierType.META_MASK | 0, 0x10000000)
self.assertEqual(hex(Gdk.ModifierType.META_MASK), '0x10000000')
self.assertEqual(str(Gdk.ModifierType.META_MASK),
- '<flags GDK_META_MASK of type GdkModifierType>')
+ '<flags GDK_META_MASK of type Gdk.ModifierType>')
- self.assertEqual(Gdk.ModifierType.RELEASE_MASK | 0, 0x40000000)
- self.assertEqual(hex(Gdk.ModifierType.RELEASE_MASK), '0x40000000')
- self.assertEqual(str(Gdk.ModifierType.RELEASE_MASK),
- '<flags GDK_RELEASE_MASK of type GdkModifierType>')
+ # RELEASE_MASK does not exist in gdk4
+ if not GDK4:
+ self.assertEqual(Gdk.ModifierType.RELEASE_MASK | 0, 0x40000000)
+ self.assertEqual(hex(Gdk.ModifierType.RELEASE_MASK), '0x40000000')
+ self.assertEqual(str(Gdk.ModifierType.RELEASE_MASK),
+ '<flags GDK_RELEASE_MASK of type Gdk.ModifierType>')
- self.assertEqual(Gdk.ModifierType.RELEASE_MASK | Gdk.ModifierType.META_MASK, 0x50000000)
- self.assertEqual(str(Gdk.ModifierType.RELEASE_MASK | Gdk.ModifierType.META_MASK),
- '<flags GDK_META_MASK | GDK_RELEASE_MASK of type GdkModifierType>')
+ self.assertEqual(Gdk.ModifierType.RELEASE_MASK | Gdk.ModifierType.META_MASK, 0x50000000)
+ self.assertEqual(str(Gdk.ModifierType.RELEASE_MASK | Gdk.ModifierType.META_MASK),
+ '<flags GDK_META_MASK | GDK_RELEASE_MASK of type Gdk.ModifierType>')
+ @unittest.skipIf(GDK4, "not in gdk4")
def test_color_parse(self):
- c = Gdk.color_parse('#00FF80')
+ with capture_glib_deprecation_warnings():
+ c = Gdk.color_parse('#00FF80')
self.assertEqual(c.red, 0)
self.assertEqual(c.green, 65535)
self.assertEqual(c.blue, 32896)
self.assertEqual(Gdk.color_parse('bogus'), None)
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_color_representations(self):
+ # __repr__ should generate a string which is parsable when possible
+ # http://docs.python.org/2/reference/datamodel.html#object.__repr__
+ color = Gdk.Color(red=65535, green=32896, blue=1)
+ self.assertEqual(eval(repr(color)), color)
+
+ rgba = Gdk.RGBA(red=1.0, green=0.8, blue=0.6, alpha=0.4)
+ self.assertEqual(eval(repr(rgba)), rgba)
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_rectangle_functions(self):
+ # https://bugzilla.gnome.org/show_bug.cgi?id=756364
+ a = Gdk.Rectangle()
+ b = Gdk.Rectangle()
+ self.assertTrue(isinstance(Gdk.rectangle_union(a, b), Gdk.Rectangle))
+ intersect, rect = Gdk.rectangle_intersect(a, b)
+ self.assertTrue(isinstance(rect, Gdk.Rectangle))
+ self.assertTrue(isinstance(intersect, bool))
+
+ @unittest.skipIf(GDK4, "not in gdk4")
+ def test_atom_repr_str(self):
+ atom = Gdk.atom_intern("", True)
+ assert re.match(r"<Gdk.Atom\(\d+\)>", repr(atom))
+ assert re.match(r"Gdk.Atom<\d+>", str(atom))
+
+ @unittest.skipUnless(GDK4, "only in gdk4")
+ @unittest.skipUnless(gtkver() >= (4, 8, 0), "constructor available since 4.8")
+ def test_file_list(self):
+ f = Gio.File.new_for_path("/tmp")
+ filelist = Gdk.FileList([f])
+ self.assertTrue(isinstance(filelist, Gdk.FileList))
+ self.assertEqual(len(filelist), 1)
+ self.assertEqual(filelist[0], f)
diff --git a/tests/test_overrides_gdkpixbuf.py b/tests/test_overrides_gdkpixbuf.py
new file mode 100644
index 0000000..4edd9bf
--- /dev/null
+++ b/tests/test_overrides_gdkpixbuf.py
@@ -0,0 +1,47 @@
+# Copyright 2018 Christoph Reiter <reiter.christoph@gmail.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+import pytest
+
+from gi import PyGIDeprecationWarning
+GdkPixbuf = pytest.importorskip("gi.repository.GdkPixbuf")
+
+
+def test_new_from_data():
+ width = 600
+ height = 32769
+ pixbuf = GdkPixbuf.Pixbuf.new(
+ GdkPixbuf.Colorspace.RGB, True, 8, width, height)
+ pixels = pixbuf.get_pixels()
+ new_pixbuf = GdkPixbuf.Pixbuf.new_from_data(
+ pixels, GdkPixbuf.Colorspace.RGB, True, 8,
+ pixbuf.get_width(), pixbuf.get_height(), pixbuf.get_rowstride())
+ del pixbuf
+ del pixels
+ new_pixels = new_pixbuf.get_pixels()
+ assert len(new_pixels) == width * height * 4
+
+
+def test_new_from_data_deprecated_args():
+ GdkPixbuf.Pixbuf.new_from_data(b"1234", 0, True, 8, 1, 1, 4)
+ GdkPixbuf.Pixbuf.new_from_data(b"1234", 0, True, 8, 1, 1, 4, None)
+ with pytest.warns(PyGIDeprecationWarning, match=".*destroy_fn.*"):
+ GdkPixbuf.Pixbuf.new_from_data(
+ b"1234", 0, True, 8, 1, 1, 4, object(), object(), object())
+ with pytest.warns(PyGIDeprecationWarning, match=".*destroy_fn_data.*"):
+ GdkPixbuf.Pixbuf.new_from_data(
+ b"1234", 0, True, 8, 1, 1, 4, object(), object(), object())
diff --git a/tests/test_overrides_gio.py b/tests/test_overrides_gio.py
new file mode 100644
index 0000000..db09859
--- /dev/null
+++ b/tests/test_overrides_gio.py
@@ -0,0 +1,360 @@
+import random
+import platform
+import warnings
+
+import pytest
+
+from gi.repository import Gio, GObject
+from gi import PyGIWarning
+
+
+class Item(GObject.Object):
+ _id = 0
+
+ def __init__(self, **kwargs):
+ super(Item, self).__init__(**kwargs)
+ Item._id += 1
+ self._id = self._id
+
+ def __repr__(self):
+ return str(self._id)
+
+
+class NamedItem(Item):
+
+ name = GObject.Property(type=str, default='')
+
+ def __repr__(self):
+ return self.props.name
+
+
+def test_list_store_sort():
+ store = Gio.ListStore()
+ items = [NamedItem(name=n) for n in "cabx"]
+ sorted_items = sorted(items, key=lambda i: i.props.name)
+
+ user_data = [object(), object()]
+
+ def sort_func(a, b, *args):
+ assert list(args) == user_data
+ assert isinstance(a, NamedItem)
+ assert isinstance(b, NamedItem)
+ cmp = lambda a, b: (a > b) - (a < b)
+ return cmp(a.props.name, b.props.name)
+
+ store[:] = items
+ assert store[:] != sorted_items
+ store.sort(sort_func, *user_data)
+ assert store[:] == sorted_items
+
+
+def test_list_store_insert_sorted():
+ store = Gio.ListStore()
+ items = [NamedItem(name=n) for n in "cabx"]
+ sorted_items = sorted(items, key=lambda i: i.props.name)
+
+ user_data = [object(), object()]
+
+ def sort_func(a, b, *args):
+ assert list(args) == user_data
+ assert isinstance(a, NamedItem)
+ assert isinstance(b, NamedItem)
+ cmp = lambda a, b: (a > b) - (a < b)
+ return cmp(a.props.name, b.props.name)
+
+ for item in items:
+ index = store.insert_sorted(item, sort_func, *user_data)
+ assert isinstance(index, int)
+ assert store[:] == sorted_items
+
+
+def test_list_model_len():
+ model = Gio.ListStore.new(Item)
+ assert len(model) == 0
+ assert not model
+ for i in range(1, 10):
+ model.append(Item())
+ assert len(model) == i
+ assert model
+ model.remove_all()
+ assert not model
+ assert len(model) == 0
+
+
+def test_list_model_get_item_simple():
+ model = Gio.ListStore.new(Item)
+ with pytest.raises(IndexError):
+ model[0]
+ first_item = Item()
+ model.append(first_item)
+ assert model[0] is first_item
+ assert model[-1] is first_item
+ second_item = Item()
+ model.append(second_item)
+ assert model[1] is second_item
+ assert model[-1] is second_item
+ assert model[-2] is first_item
+ with pytest.raises(IndexError):
+ model[-3]
+
+ with pytest.raises(TypeError):
+ model[object()]
+
+
+def test_list_model_get_item_slice():
+ model = Gio.ListStore.new(Item)
+ source = [Item() for i in range(30)]
+ for i in source:
+ model.append(i)
+ assert model[1:10] == source[1:10]
+ assert model[1:-2] == source[1:-2]
+ assert model[-4:-1] == source[-4:-1]
+ assert model[-100:-1] == source[-100:-1]
+ assert model[::-1] == source[::-1]
+ assert model[:] == source[:]
+
+
+def test_list_model_contains():
+ model = Gio.ListStore.new(Item)
+ item = Item()
+ model.append(item)
+ assert item in model
+ assert Item() not in model
+ with pytest.raises(TypeError):
+ object() in model
+ with pytest.raises(TypeError):
+ None in model
+
+
+def test_list_model_iter():
+ model = Gio.ListStore.new(Item)
+ item = Item()
+ model.append(item)
+
+ it = iter(model)
+ assert next(it) is item
+ repr(item)
+
+
+def test_list_store_delitem_simple():
+ store = Gio.ListStore.new(Item)
+ store.append(Item())
+ del store[0]
+ assert not store
+ with pytest.raises(IndexError):
+ del store[0]
+ with pytest.raises(IndexError):
+ del store[-1]
+
+ store.append(Item())
+ with pytest.raises(IndexError):
+ del store[-2]
+ del store[-1]
+ assert not store
+
+ source = [Item(), Item()]
+ store.append(source[0])
+ store.append(source[1])
+ del store[-1]
+ assert store[:] == [source[0]]
+
+ with pytest.raises(TypeError):
+ del store[object()]
+
+
+def test_list_store_delitem_slice():
+
+ def do_del(count, key):
+
+ events = []
+
+ def on_changed(m, *args):
+ events.append(args)
+
+ store = Gio.ListStore.new(Item)
+ source = [Item() for i in range(count)]
+ for item in source:
+ store.append(item)
+ store.connect("items-changed", on_changed)
+ source.__delitem__(key)
+ store.__delitem__(key)
+ assert source == store[:]
+ return events
+
+ values = [None, 1, -15, 3, -2, 0, -3, 5, 7]
+ variants = set()
+ for i in range(500):
+ start = random.choice(values)
+ stop = random.choice(values)
+ step = random.choice(values)
+ length = abs(random.choice(values) or 0)
+ if step == 0:
+ step += 1
+ variants.add((length, start, stop, step))
+
+ for length, start, stop, step in variants:
+ do_del(length, slice(start, stop, step))
+
+ # basics
+ do_del(10, slice(None, None, None))
+ do_del(10, slice(None, None, None))
+ do_del(10, slice(None, None, -1))
+ do_del(10, slice(0, 5, None))
+ do_del(10, slice(0, 10, 1))
+ do_del(10, slice(0, 10, 2))
+ do_del(10, slice(14, 2, -1))
+
+ # test some fast paths
+ assert do_del(100, slice(None, None, None)) == [(0, 100, 0)]
+ assert do_del(100, slice(None, None, -1)) == [(0, 100, 0)]
+ assert do_del(100, slice(0, 50, 1)) == [(0, 50, 0)]
+
+
+def test_list_store_setitem_simple():
+
+ store = Gio.ListStore.new(Item)
+ first = Item()
+ store.append(first)
+
+ class Wrong(GObject.Object):
+ pass
+
+ with pytest.raises(TypeError):
+ store[0] = object()
+ with pytest.raises(TypeError):
+ store[0] = None
+ with pytest.raises(TypeError):
+ store[0] = Wrong()
+
+ assert store[:] == [first]
+
+ new = Item()
+ store[0] = new
+ assert len(store) == 1
+ store[-1] = Item()
+ assert len(store) == 1
+
+ with pytest.raises(IndexError):
+ store[1] = Item()
+ with pytest.raises(IndexError):
+ store[-2] = Item()
+
+ store = Gio.ListStore.new(Item)
+ source = [Item(), Item(), Item()]
+ for item in source:
+ store.append(item)
+ new = Item()
+ store[1] = new
+ assert store[:] == [source[0], new, source[2]]
+
+ with pytest.raises(TypeError):
+ store[object()] = Item()
+
+
+def test_list_store_setitem_slice():
+
+ def do_set(count, key, new_count):
+ if count == 0 and key.step is not None \
+ and platform.python_implementation() == "PyPy":
+ # https://foss.heptapod.net/pypy/pypy/-/issues/2804
+ return
+ store = Gio.ListStore.new(Item)
+ source = [Item() for i in range(count)]
+ new = [Item() for i in range(new_count)]
+ for item in source:
+ store.append(item)
+ source_error = None
+ try:
+ source.__setitem__(key, new)
+ except ValueError as e:
+ source_error = type(e)
+
+ store_error = None
+ try:
+ store.__setitem__(key, new)
+ except Exception as e:
+ store_error = type(e)
+
+ assert source_error == store_error
+ assert source == store[:]
+
+ values = [None, 1, -15, 3, -2, 0, 3, 4, 100]
+ variants = set()
+ for i in range(500):
+ start = random.choice(values)
+ stop = random.choice(values)
+ step = random.choice(values)
+ length = abs(random.choice(values) or 0)
+ new = random.choice(values) or 0
+ if step == 0:
+ step += 1
+ variants.add((length, start, stop, step, new))
+
+ for length, start, stop, step, new in variants:
+ do_set(length, slice(start, stop, step), new)
+
+ # basics
+ do_set(10, slice(None, None, None), 20)
+ do_set(10, slice(None, None, None), 0)
+ do_set(10, slice(None, None, -1), 20)
+ do_set(10, slice(None, None, -1), 10)
+ do_set(10, slice(0, 5, None), 20)
+ do_set(10, slice(0, 10, 1), 0)
+
+ # test iterators
+ store = Gio.ListStore.new(Item)
+ store[:] = iter([Item() for i in range(10)])
+ assert len(store) == 10
+
+ # make sure we do all or nothing
+ store = Gio.ListStore.new(Item)
+ with pytest.raises(TypeError):
+ store[:] = [Item(), object()]
+ assert len(store) == 0
+
+
+def test_action_map_add_action_entries():
+ actionmap = Gio.SimpleActionGroup()
+
+ test_data = []
+
+ def f(action, parameter, data):
+ test_data.append('test back')
+
+ actionmap.add_action_entries((
+ ("simple", f),
+ ("with_type", f, "i"),
+ ("with_state", f, "s", "'left'", f),
+ ))
+ assert actionmap.has_action("simple")
+ assert actionmap.has_action("with_type")
+ assert actionmap.has_action("with_state")
+ actionmap.add_action_entries((
+ ("with_user_data", f),
+ ), "user_data")
+ assert actionmap.has_action("with_user_data")
+
+ with pytest.raises(TypeError):
+ actionmap.add_action_entries((
+ ("invaild_type_string", f, 'asdf'),
+ ))
+ with pytest.raises(ValueError):
+ actionmap.add_action_entries((
+ ("stateless_with_change_state", f, None, None, f),
+ ))
+
+ actionmap.activate_action("simple")
+ assert test_data[0] == 'test back'
+
+
+def test_types_init_warn():
+ types = [
+ Gio.DBusAnnotationInfo, Gio.DBusArgInfo, Gio.DBusMethodInfo,
+ Gio.DBusSignalInfo, Gio.DBusInterfaceInfo, Gio.DBusNodeInfo,
+ ]
+
+ for t in types:
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ t()
+ assert issubclass(warn[0].category, PyGIWarning)
diff --git a/tests/test_overrides_glib.py b/tests/test_overrides_glib.py
index 4d7e63a..08c41ae 100644
--- a/tests/test_overrides_glib.py
+++ b/tests/test_overrides_glib.py
@@ -1,11 +1,121 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
# vim: tabstop=4 shiftwidth=4 expandtab
+import os
+import gc
import unittest
+import tempfile
+import socket
+
+import pytest
import gi
from gi.repository import GLib
-from compathelper import _long
+
+from .helper import capture_gi_deprecation_warnings
+
+
+def test_io_add_watch_get_args():
+ get_args = GLib._io_add_watch_get_args
+ func = lambda: None
+
+ # create a closed channel for testing
+ fd, fn = tempfile.mkstemp()
+ os.close(fd)
+ try:
+ chan = GLib.IOChannel(filename=fn)
+ chan.shutdown(True)
+ finally:
+ os.remove(fn)
+
+ # old way
+ with capture_gi_deprecation_warnings():
+ assert get_args(chan, GLib.IOCondition.IN, func) == (
+ chan, 0, GLib.IOCondition.IN, func, tuple())
+
+ with pytest.raises(TypeError):
+ get_args(chan, GLib.IOCondition.IN, object())
+
+ # new way
+ prio = GLib.PRIORITY_DEFAULT
+ with capture_gi_deprecation_warnings():
+ assert get_args(chan, prio, GLib.IOCondition.IN, func, 99) == \
+ (chan, prio, GLib.IOCondition.IN, func, (99,))
+
+ with pytest.raises(TypeError):
+ assert get_args(chan, prio, GLib.IOCondition.IN)
+
+ with pytest.raises(TypeError):
+ assert get_args(chan, prio, 99)
+
+
+@pytest.mark.skipif(os.name != "nt", reason="windows only")
+def test_io_add_watch_get_args_win32_socket():
+ get_args = GLib._io_add_watch_get_args
+
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ func = lambda: None
+ prio = GLib.PRIORITY_DEFAULT
+ chan = get_args(s, prio, GLib.IOCondition.IN, func)[0]
+ assert isinstance(chan, GLib.IOChannel)
+ chan.shutdown(False)
+
+
+def test_threads_init():
+ with capture_gi_deprecation_warnings() as w:
+ GLib.threads_init()
+ assert len(w)
+
+
+def test_gerror_matches():
+ e = GLib.Error(domain=42, code=24)
+ assert e.matches(42, 24)
+
+
+def test_timeout_add_seconds():
+ h = GLib.timeout_add_seconds(
+ 100, lambda *x: None, 1, 2, 3, priority=GLib.PRIORITY_HIGH_IDLE)
+ GLib.source_remove(h)
+
+
+def test_iochannel():
+ with pytest.raises(TypeError):
+ GLib.IOChannel()
+
+
+def test_iochannel_write():
+ fd, fn = tempfile.mkstemp()
+ os.close(fd)
+ chan = GLib.IOChannel(filename=fn, mode="r+")
+ try:
+ assert chan.write(b"foo", 2) == 2
+ chan.seek(0)
+ assert chan.read() == b"fo"
+ finally:
+ chan.shutdown(True)
+
+
+@pytest.mark.skipif(os.name == "nt", reason="unix only")
+def test_has_unix_signal_add():
+ with capture_gi_deprecation_warnings():
+ GLib.unix_signal_add == GLib.unix_signal_add_full
+
+
+@pytest.mark.skipif(os.name != "nt", reason="windows only")
+def test_iochannel_win32():
+ fd, fn = tempfile.mkstemp()
+ closed = False
+ try:
+ channel = GLib.IOChannel(hwnd=fd)
+ try:
+ assert channel.read() == b""
+ finally:
+ closed = True
+ channel.shutdown(True)
+ finally:
+ if not closed:
+ os.close(fd)
+ os.remove(fn)
class TestGVariant(unittest.TestCase):
@@ -22,6 +132,17 @@ class TestGVariant(unittest.TestCase):
self.assertTrue(isinstance(variant, GLib.Variant))
self.assertEqual(variant.get_string(), 'hello')
+ def test_simple_invalid_ops(self):
+ variant = GLib.Variant('i', 42)
+ with pytest.raises(TypeError):
+ len(variant)
+
+ with pytest.raises(TypeError):
+ variant[0]
+
+ with pytest.raises(TypeError):
+ variant.keys()
+
def test_create_variant(self):
variant = GLib.Variant('v', GLib.Variant('i', 42))
self.assertTrue(isinstance(variant, GLib.Variant))
@@ -59,7 +180,13 @@ class TestGVariant(unittest.TestCase):
# nested tuples
variant = GLib.Variant('((si)(ub))', (('hello', -1), (42, True)))
self.assertEqual(variant.get_type_string(), '((si)(ub))')
- self.assertEqual(variant.unpack(), (('hello', -1), (_long(42), True)))
+ self.assertEqual(variant.unpack(), (('hello', -1), (42, True)))
+
+ def test_new_tuple_sink(self):
+ # https://bugzilla.gnome.org/show_bug.cgi?id=735166
+ variant = GLib.Variant.new_tuple(GLib.Variant.new_tuple())
+ del variant
+ gc.collect()
def test_create_dictionary(self):
variant = GLib.Variant('a{si}', {})
@@ -88,6 +215,15 @@ class TestGVariant(unittest.TestCase):
self.assertTrue(isinstance(variant, GLib.Variant))
self.assertEqual(variant.unpack(), d)
+ # init with an iterable
+ variant = GLib.Variant('a{si}', [("foo", 2)])
+ assert variant.unpack() == {'foo': 2}
+
+ with pytest.raises(TypeError):
+ GLib.Variant('a{si}', [("foo",)])
+ with pytest.raises(TypeError):
+ GLib.Variant('a{si}', [("foo", 1, 2)])
+
def test_create_array(self):
variant = GLib.Variant('ai', [])
self.assertEqual(variant.get_type_string(), 'ai')
@@ -133,6 +269,50 @@ class TestGVariant(unittest.TestCase):
self.assertEqual(variant.get_type_string(), 'aai')
self.assertEqual(variant.unpack(), [[1, 2], [3, 4, 5]])
+ def test_create_array_guchar(self):
+ variant = GLib.Variant('ay', [97, 97, 97])
+ assert variant.unpack() == [97, 97, 97]
+
+ variant = GLib.Variant('ay', b'aaa')
+ assert variant.unpack() == [97, 97, 97]
+
+ variant = GLib.Variant('ay', iter([1, 2, 3]))
+ assert variant.unpack() == [1, 2, 3]
+
+ with self.assertRaises(TypeError):
+ GLib.Variant('ay', u'aaa')
+
+ with self.assertRaises(TypeError):
+ GLib.Variant('ay', object())
+
+ def test_create_maybe(self):
+ variant = GLib.Variant('mai', None)
+ self.assertEqual(variant.get_type_string(), 'mai')
+ self.assertEqual(variant.n_children(), 0)
+ self.assertEqual(variant.unpack(), None)
+
+ variant = GLib.Variant('mai', [])
+ self.assertEqual(variant.get_type_string(), 'mai')
+ self.assertEqual(variant.n_children(), 1)
+
+ variant = GLib.Variant('mami', [None])
+ self.assertEqual(variant.get_type_string(), 'mami')
+ self.assertEqual(variant.n_children(), 1)
+
+ variant = GLib.Variant('mami', [None, 13, None])
+ self.assertEqual(variant.get_type_string(), 'mami')
+ self.assertEqual(variant.n_children(), 1)
+ array = variant.get_child_value(0)
+ self.assertEqual(array.n_children(), 3)
+
+ element = array.get_child_value(0)
+ self.assertEqual(element.n_children(), 0)
+ element = array.get_child_value(1)
+ self.assertEqual(element.n_children(), 1)
+ self.assertEqual(element.get_child_value(0).get_int32(), 13)
+ element = array.get_child_value(2)
+ self.assertEqual(element.n_children(), 0)
+
def test_create_complex(self):
variant = GLib.Variant('(as)', ([],))
self.assertEqual(variant.get_type_string(), '(as)')
@@ -225,8 +405,8 @@ class TestGVariant(unittest.TestCase):
self.assertRaises(TypeError, GLib.Variant, '(ss)', 'mec', 'mac')
self.assertRaises(TypeError, GLib.Variant, '(s)', 'hello')
- # unimplemented data type
- self.assertRaises(NotImplementedError, GLib.Variant, 'Q', 1)
+ # invalid format string
+ self.assertRaises(TypeError, GLib.Variant, 'Q', 1)
# invalid types
self.assertRaises(TypeError, GLib.Variant, '(ii', (42, 3))
@@ -273,12 +453,16 @@ class TestGVariant(unittest.TestCase):
self.assertEqual(res, {'key1': 1, 'key2': 2})
# maybe
- v = GLib.Variant.new_maybe(GLib.VariantType.new('i'), GLib.Variant('i', 1))
- res = v.unpack()
- self.assertEqual(res, 1)
- v = GLib.Variant.new_maybe(GLib.VariantType.new('i'), None)
- res = v.unpack()
- self.assertEqual(res, None)
+ v = GLib.Variant('mi', 1)
+ self.assertEqual(v.unpack(), 1)
+ v = GLib.Variant('mi', None)
+ self.assertEqual(v.unpack(), None)
+ v = GLib.Variant('mai', [])
+ self.assertEqual(v.unpack(), [])
+ v = GLib.Variant('m()', ())
+ self.assertEqual(v.unpack(), ())
+ v = GLib.Variant('mami', [None, 1, None])
+ self.assertEqual(v.unpack(), [None, 1, None])
def test_iteration(self):
# array index access
@@ -414,6 +598,9 @@ class TestGVariant(unittest.TestCase):
assert_equal('v', GLib.Variant('i', 42))
assert_not_equal('v', GLib.Variant('i', 42), 'v', GLib.Variant('i', 43))
+ assert GLib.Variant('i', 42) != object()
+ assert not GLib.Variant('i', 42) == object()
+
def test_bool(self):
# Check if the GVariant bool matches the unpacked Pythonic bool
@@ -470,6 +657,11 @@ class TestGVariant(unittest.TestCase):
assert_equals_bool('v', GLib.Variant('i', 0))
assert_equals_bool('v', GLib.Variant('i', 1))
+ # maybe types
+ assert_equals_bool('mi', 42)
+ assert_equals_bool('mi', 0)
+ assert_equals_bool('mi', None)
+
def test_repr(self):
# with C constructor
v = GLib.Variant.new_uint32(42)
@@ -487,3 +679,46 @@ class TestGVariant(unittest.TestCase):
# with override constructor
v = GLib.Variant('(is)', (1, 'somestring'))
self.assertEqual(str(v), "(1, 'somestring')")
+
+ def test_parse_error(self):
+ # This test doubles as a test for GLib.Error marshaling.
+ source_str = 'abc'
+ with self.assertRaises(GLib.Error) as context:
+ GLib.Variant.parse(None, source_str, None, None)
+ e = context.exception
+ text = GLib.Variant.parse_error_print_context(e, source_str)
+ self.assertTrue(source_str in text)
+
+ def test_parse_error_exceptions(self):
+ source_str = 'abc'
+ self.assertRaisesRegex(TypeError, 'Must be GLib.Error, not int',
+ GLib.Variant.parse_error_print_context,
+ 42, source_str)
+
+ gerror = GLib.Error(message=42) # not a string
+ self.assertRaisesRegex(TypeError, ".*Must be string, not int.*",
+ GLib.Variant.parse_error_print_context,
+ gerror, source_str)
+
+ gerror = GLib.Error(domain=42) # not a string
+ self.assertRaisesRegex(TypeError, ".*Must be string, not int.*",
+ GLib.Variant.parse_error_print_context,
+ gerror, source_str)
+
+ gerror = GLib.Error(code='not an int')
+ self.assertRaisesRegex(TypeError, ".*Must be number, not str.*",
+ GLib.Variant.parse_error_print_context,
+ gerror, source_str)
+
+ gerror = GLib.Error(code=GLib.MAXUINT)
+ self.assertRaisesRegex(OverflowError,
+ ".*not in range.*",
+ GLib.Variant.parse_error_print_context,
+ gerror, source_str)
+
+
+class TestConstants(unittest.TestCase):
+
+ def test_basic_types_limits(self):
+ self.assertTrue(isinstance(GLib.MINFLOAT, float))
+ self.assertTrue(isinstance(GLib.MAXLONG, int))
diff --git a/tests/test_overrides_gobject.py b/tests/test_overrides_gobject.py
new file mode 100644
index 0000000..dc26596
--- /dev/null
+++ b/tests/test_overrides_gobject.py
@@ -0,0 +1,423 @@
+import pytest
+
+from gi import PyGIDeprecationWarning
+from gi.repository import GObject, GLib, GIMarshallingTests
+
+from .helper import ignore_gi_deprecation_warnings
+
+
+def test_stop_emission_deprec():
+ class TestObject(GObject.GObject):
+ int_prop = GObject.Property(default=0, type=int)
+
+ obj = TestObject()
+
+ def notify_callback(obj, *args):
+ with pytest.warns(PyGIDeprecationWarning):
+ obj.stop_emission("notify::int-prop")
+
+ with pytest.warns(PyGIDeprecationWarning):
+ obj.emit_stop_by_name("notify::int-prop")
+
+ obj.stop_emission_by_name("notify::int-prop")
+
+ obj.connect("notify::int-prop", notify_callback)
+ obj.notify("int-prop")
+
+
+def test_signal_parse_name():
+ obj = GObject.GObject()
+ assert GObject.signal_parse_name("notify", obj, True) == (1, 0)
+
+ with pytest.raises(ValueError):
+ GObject.signal_parse_name("foobar", obj, True)
+
+
+def test_signal_query():
+ obj = GObject.GObject()
+ res = GObject.signal_query("notify", obj)
+ assert res.signal_name == "notify"
+ assert res.itype == obj.__gtype__
+
+ res = GObject.signal_query("foobar", obj)
+ assert res is None
+
+
+def test_value_repr():
+ v = GObject.Value()
+ assert repr(v) == "<Value (invalid) None>"
+
+ v = GObject.Value(int, 0)
+ assert repr(v) == "<Value (gint) 0>"
+
+
+def test_value_no_init():
+ v = GObject.Value()
+ with pytest.raises(TypeError):
+ v.set_value(0)
+ v.init(GObject.TYPE_LONG)
+ assert v.get_value() == 0
+ v.set_value(0)
+
+
+def test_value_invalid_type():
+ v = GObject.Value()
+ assert v.g_type == GObject.TYPE_INVALID
+ assert isinstance(GObject.TYPE_INVALID, GObject.GType)
+ with pytest.raises(ValueError, match="Invalid GType"):
+ v.init(GObject.TYPE_INVALID)
+
+ with pytest.raises(
+ TypeError, match="GObject.Value needs to be initialized first"):
+ v.set_value(None)
+
+ assert v.get_value() is None
+
+
+def test_value_long():
+ v = GObject.Value(GObject.TYPE_LONG)
+ assert v.get_value() == 0
+ v.set_value(0)
+ assert v.get_value() == 0
+
+ v.set_value(GLib.MAXLONG)
+ assert v.get_value() == GLib.MAXLONG
+
+ v.set_value(GLib.MINLONG)
+ assert v.get_value() == GLib.MINLONG
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MAXLONG + 1)
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MINLONG - 1)
+
+
+def test_value_ulong():
+ v = GObject.Value(GObject.TYPE_ULONG)
+ assert v.get_value() == 0
+ v.set_value(0)
+ assert v.get_value() == 0
+
+ v.set_value(GLib.MAXULONG)
+ assert v.get_value() == GLib.MAXULONG
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MAXULONG + 1)
+
+ with pytest.raises(OverflowError):
+ v.set_value(-1)
+
+ with pytest.raises(TypeError):
+ v.set_value(object())
+
+ with pytest.raises(TypeError):
+ v.set_value(None)
+
+
+def test_value_float():
+ v = GObject.Value(GObject.TYPE_FLOAT)
+
+ for getter, setter in [(v.get_value, v.set_value),
+ (v.get_float, v.set_float)]:
+
+ assert getter() == 0.0
+ setter(0)
+ assert getter() == 0
+
+ setter(GLib.MAXFLOAT)
+ assert getter() == GLib.MAXFLOAT
+
+ setter(GLib.MINFLOAT)
+ assert getter() == GLib.MINFLOAT
+
+ setter(-GLib.MAXFLOAT)
+ assert getter() == -GLib.MAXFLOAT
+
+ with pytest.raises(OverflowError):
+ setter(GLib.MAXFLOAT * 2)
+
+ with pytest.raises(OverflowError):
+ setter(-GLib.MAXFLOAT * 2)
+
+ with pytest.raises(TypeError):
+ setter(object())
+
+ with pytest.raises(TypeError):
+ setter(None)
+
+ with pytest.raises(TypeError):
+ setter(1j)
+
+ v.reset()
+
+
+def test_value_double():
+ v = GObject.Value(GObject.TYPE_DOUBLE)
+ assert v.get_value() == 0.0
+ v.set_value(0)
+ assert v.get_value() == 0
+
+ v.set_value(GLib.MAXDOUBLE)
+ assert v.get_value() == GLib.MAXDOUBLE
+
+ v.set_value(GLib.MINDOUBLE)
+ assert v.get_value() == GLib.MINDOUBLE
+
+ v.set_value(-GLib.MAXDOUBLE)
+ assert v.get_value() == -GLib.MAXDOUBLE
+
+ with pytest.raises(TypeError):
+ v.set_value(object())
+
+ with pytest.raises(TypeError):
+ v.set_value(None)
+
+ with pytest.raises(TypeError):
+ v.set_value(1j)
+
+
+def test_value_uint64():
+ v = GObject.Value(GObject.TYPE_UINT64)
+ assert v.get_value() == 0
+ v.set_value(0)
+ assert v.get_value() == 0
+
+ v.set_value(GLib.MAXUINT64)
+ assert v.get_value() == GLib.MAXUINT64
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MAXUINT64 + 1)
+
+ with pytest.raises(OverflowError):
+ v.set_value(-1)
+
+
+def test_value_int64():
+ v = GObject.Value(GObject.TYPE_INT64)
+ assert v.get_value() == 0
+ v.set_value(0)
+ assert v.get_value() == 0
+
+ v.set_value(GLib.MAXINT64)
+ assert v.get_value() == GLib.MAXINT64
+ v.set_value(GLib.MININT64)
+ assert v.get_value() == GLib.MININT64
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MAXINT64 + 1)
+
+ with pytest.raises(OverflowError):
+ v.set_value(GLib.MININT64 - 1)
+
+ with pytest.raises(TypeError):
+ v.set_value(object())
+
+ with pytest.raises(TypeError):
+ v.set_value(None)
+
+
+def test_value_pointer():
+ v = GObject.Value(GObject.TYPE_POINTER)
+ assert v.get_value() == 0
+ v.set_value(42)
+ assert v.get_value() == 42
+ v.set_value(0)
+ assert v.get_value() == 0
+
+
+def test_value_unichar():
+ assert GObject.TYPE_UNICHAR == GObject.TYPE_UINT
+
+ v = GObject.Value(GObject.TYPE_UNICHAR)
+ assert v.get_value() == 0
+ v.set_value(42)
+ assert v.get_value() == 42
+
+ v.set_value(GLib.MAXUINT)
+ assert v.get_value() == GLib.MAXUINT
+
+
+def test_value_gtype():
+ class TestObject(GObject.GObject):
+ pass
+
+ v = GObject.Value(GObject.TYPE_GTYPE)
+ assert v.get_value() == GObject.TYPE_INVALID
+ v.set_value(TestObject.__gtype__)
+ assert v.get_value() == TestObject.__gtype__
+ v.set_value(TestObject)
+ assert v.get_value() == TestObject.__gtype__
+
+ with pytest.raises(TypeError):
+ v.set_value(None)
+
+
+def test_value_variant():
+ v = GObject.Value(GObject.TYPE_VARIANT)
+ assert v.get_value() is None
+ variant = GLib.Variant('i', 42)
+ v.set_value(variant)
+ assert v.get_value() == variant
+
+ v.set_value(None)
+ assert v.get_value() is None
+
+ with pytest.raises(TypeError):
+ v.set_value(object())
+
+
+def test_value_param():
+ # FIXME: set_value and get_value trigger a critical
+ # GObject.Value(GObject.TYPE_PARAM)
+ pass
+
+
+def test_value_string():
+ v = GObject.Value(GObject.TYPE_STRING)
+ for getter, setter in [(v.get_value, v.set_value),
+ (v.get_string, v.set_string)]:
+
+ assert getter() is None
+
+ with pytest.raises(TypeError):
+ setter(b"bar")
+
+ setter(u"quux")
+ assert getter() == u"quux"
+ assert isinstance(getter(), str)
+
+ setter(None)
+ assert getter() is None
+
+ v.reset()
+
+
+def test_value_pyobject():
+ class Foo(object):
+ pass
+
+ v = GObject.Value(GObject.TYPE_PYOBJECT)
+ assert v.get_value() is None
+ for obj in [Foo(), None, 42, "foo"]:
+ v.set_value(obj)
+ assert v.get_value() == obj
+
+
+@ignore_gi_deprecation_warnings
+def test_value_char():
+ v = GObject.Value(GObject.TYPE_CHAR)
+ assert v.get_value() == 0
+ v.set_value(42)
+ assert v.get_value() == 42
+ v.set_value(-1)
+ assert v.get_value() == -1
+ v.set_value(b"a")
+ assert v.get_value() == 97
+ v.set_value(b"\x00")
+ assert v.get_value() == 0
+
+ with pytest.raises(TypeError):
+ v.set_value(u"a")
+
+ with pytest.raises(OverflowError):
+ v.set_value(128)
+
+
+def test_value_uchar():
+ v = GObject.Value(GObject.TYPE_UCHAR)
+ assert v.get_value() == 0
+ v.set_value(200)
+ assert v.get_value() == 200
+ v.set_value(b"a")
+ assert v.get_value() == 97
+ v.set_value(b"\x00")
+ assert v.get_value() == 0
+
+ with pytest.raises(TypeError):
+ v.set_value(u"a")
+
+ with pytest.raises(OverflowError):
+ v.set_value(256)
+
+
+def test_value_set_boxed_deprecate_non_boxed():
+ v = GObject.Value(GObject.TYPE_POINTER)
+ with pytest.warns(PyGIDeprecationWarning):
+ v.get_boxed()
+ with pytest.warns(PyGIDeprecationWarning):
+ v.set_boxed(None)
+
+
+def test_value_boolean():
+ v = GObject.Value(GObject.TYPE_BOOLEAN)
+ for getter, setter in [(v.get_value, v.set_value),
+ (v.get_boolean, v.set_boolean)]:
+ assert getter() is False
+ assert isinstance(getter(), bool)
+
+ setter(42)
+ assert getter() is True
+ setter(-1)
+ assert getter() is True
+ setter(0)
+ assert getter() is False
+
+ setter([])
+ assert getter() is False
+ setter(["foo"])
+ assert getter() is True
+
+ setter(None)
+ assert getter() is False
+ v.reset()
+
+
+def test_value_enum():
+ t = GIMarshallingTests.GEnum
+ v = GObject.Value(t)
+
+ for getter, setter in [(v.get_value, v.set_value),
+ (v.get_enum, v.set_enum)]:
+ assert v.g_type == t.__gtype__
+ assert getter() == 0
+
+ setter(t.VALUE1)
+ assert getter() == t.VALUE1
+ # FIXME: we should try to return an enum type
+ assert type(getter()) is int
+
+ setter(2424242)
+ assert getter() == 2424242
+
+ setter(-1)
+ assert getter() == -1
+
+ with pytest.raises(TypeError):
+ setter(object())
+
+ with pytest.raises(TypeError):
+ setter(None)
+
+ v.reset()
+
+
+def test_value_object():
+ v = GObject.Value(GIMarshallingTests.Object)
+ assert v.g_type.is_a(GObject.TYPE_OBJECT)
+
+ for getter, setter in [(v.get_value, v.set_value),
+ (v.get_object, v.set_object)]:
+ assert getter() is None
+
+ setter(None)
+ assert getter() is None
+
+ obj = GIMarshallingTests.Object()
+ setter(obj)
+ assert getter() is obj
+
+ with pytest.raises(TypeError):
+ setter(object())
+
+ v.reset()
diff --git a/tests/test_overrides_gtk.py b/tests/test_overrides_gtk.py
index fbe51ec..04ab718 100644
--- a/tests/test_overrides_gtk.py
+++ b/tests/test_overrides_gtk.py
@@ -1,23 +1,42 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
-# coding: UTF-8
# vim: tabstop=4 shiftwidth=4 expandtab
import contextlib
import unittest
-import time
import sys
+import gc
+import warnings
+import timeit
-from compathelper import _unicode, _bytes
+import pytest
+
+from .helper import ignore_gi_deprecation_warnings, capture_glib_warnings
import gi.overrides
import gi.types
-from gi.repository import GLib, GObject
+from gi.repository import Gio, GLib, GObject
try:
- from gi.repository import GdkPixbuf, Gdk, Gtk
- Gtk # pyflakes
+ from gi.repository import Gtk, GdkPixbuf, Gdk
+ PyGTKDeprecationWarning = Gtk.PyGTKDeprecationWarning
+ Gtk_version = Gtk._version
except ImportError:
Gtk = None
+ Gtk_version = None
+ PyGTKDeprecationWarning = None
+ GdkPixbuf = None
+ Gdk = None
+
+
+def gtkver():
+ if Gtk is None:
+ return (0, 0, 0)
+ return (Gtk.get_major_version(),
+ Gtk.get_minor_version(),
+ Gtk.get_micro_version())
+
+
+GTK4 = (Gtk._version == "4.0")
@contextlib.contextmanager
@@ -32,28 +51,132 @@ def realized(widget):
if isinstance(widget, Gtk.Window):
toplevel = widget
else:
- toplevel = widget.get_parent_window()
+ if Gtk._version == "4.0":
+ toplevel = widget.get_parent()
+ else:
+ toplevel = widget.get_parent_window()
if toplevel is None:
window = Gtk.Window()
- window.add(widget)
+ if Gtk._version == "4.0":
+ window.set_child(widget)
+ else:
+ window.add(widget)
+ window.show()
widget.realize()
- while Gtk.events_pending():
- Gtk.main_iteration()
+ if Gtk._version == "4.0":
+ context = GLib.MainContext()
+ while context.pending():
+ context.iteration(False)
+ else:
+ while Gtk.events_pending():
+ Gtk.main_iteration()
+
assert widget.get_realized()
yield widget
if toplevel is None:
- window.remove(widget)
+ if Gtk._version == "4.0":
+ window.set_child(None)
+ else:
+ window.remove(widget)
+
window.destroy()
- while Gtk.events_pending():
- Gtk.main_iteration()
+ if Gtk._version == "4.0":
+ context = GLib.MainContext()
+ while context.pending():
+ context.iteration(False)
+ else:
+ while Gtk.events_pending():
+ Gtk.main_iteration()
@unittest.skipUnless(Gtk, 'Gtk not available')
+@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+def test_freeze_child_notif():
+
+ events = []
+
+ def on_notify(widget, spec):
+ events.append(spec.name)
+
+ b = Gtk.Box()
+ c = Gtk.Button()
+ c.connect("child-notify", on_notify)
+ c.freeze_child_notify()
+ b.pack_start(c, True, True, 0)
+ b.child_set_property(c, "pack-type", Gtk.PackType.END)
+ b.child_set_property(c, "pack-type", Gtk.PackType.START)
+ c.thaw_child_notify()
+ assert events.count("pack-type") == 1
+ del events[:]
+
+ with c.freeze_child_notify():
+ b.child_set_property(c, "pack-type", Gtk.PackType.END)
+ b.child_set_property(c, "pack-type", Gtk.PackType.START)
+
+ assert events.count("pack-type") == 1
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+def test_menu_popup():
+ m = Gtk.Menu()
+ with capture_glib_warnings():
+ m.popup(None, None, None, None, 0, 0)
+ m.popdown()
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+def test_button_stock():
+ with capture_glib_warnings():
+ button = Gtk.Button(stock=Gtk.STOCK_OK)
+ assert button.props.label == Gtk.STOCK_OK
+ assert button.props.use_stock
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+def test_wrapper_toggle_refs():
+ if not GTK4:
+ BASE = Gtk.Button
+ else:
+ BASE = Gtk.Widget
+
+ class MyWidget(BASE):
+ def __init__(self, height):
+ BASE.__init__(self)
+ self._height = height
+
+ def do_measure(self, orientation, for_size):
+ if orientation == Gtk.Orientation.VERTICAL:
+ return (self._height, self._height, -1, -1)
+ else:
+ return (0, 0, -1, -1)
+
+ def do_get_preferred_height(self):
+ return (self._height, self._height)
+
+ height = 142
+ w = Gtk.Window()
+ b = MyWidget(height)
+ if not GTK4:
+ w.add(b)
+ b.show_all()
+ else:
+ w.set_child(b)
+ del b
+ gc.collect()
+ gc.collect()
+ assert w.get_preferred_size().minimum_size.height >= height
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+@ignore_gi_deprecation_warnings
class TestGtk(unittest.TestCase):
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_container(self):
box = Gtk.Box()
self.assertTrue(isinstance(box, Gtk.Box))
@@ -68,30 +191,29 @@ class TestGtk(unittest.TestCase):
self.assertTrue(label2 in box)
self.assertEqual(len(box), 2)
self.assertTrue(box)
- l = [x for x in box]
- self.assertEqual(l, [label, label2])
+ labels = [x for x in box]
+ self.assertEqual(labels, [label, label2])
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_actions(self):
self.assertEqual(Gtk.Action, gi.overrides.Gtk.Action)
- self.assertRaises(TypeError, Gtk.Action)
- action = Gtk.Action("test", "Test", "Test Action", Gtk.STOCK_COPY)
+ action = Gtk.Action(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY)
self.assertEqual(action.get_name(), "test")
self.assertEqual(action.get_label(), "Test")
self.assertEqual(action.get_tooltip(), "Test Action")
self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
self.assertEqual(Gtk.RadioAction, gi.overrides.Gtk.RadioAction)
- self.assertRaises(TypeError, Gtk.RadioAction)
- action = Gtk.RadioAction("test", "Test", "Test Action", Gtk.STOCK_COPY, 1)
+ action = Gtk.RadioAction(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY, value=1)
self.assertEqual(action.get_name(), "test")
self.assertEqual(action.get_label(), "Test")
self.assertEqual(action.get_tooltip(), "Test Action")
self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY)
self.assertEqual(action.get_current_value(), 1)
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_actiongroup(self):
self.assertEqual(Gtk.ActionGroup, gi.overrides.Gtk.ActionGroup)
- self.assertRaises(TypeError, Gtk.ActionGroup)
action_group = Gtk.ActionGroup(name='TestActionGroup')
callback_data = "callback data"
@@ -131,14 +253,61 @@ class TestGtk(unittest.TestCase):
expected_results.remove(a)
action.activate()
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_action_group_error_handling(self):
+ action_group = Gtk.ActionGroup(name='TestActionGroup')
+ with pytest.raises(TypeError):
+ action_group.add_actions(42)
+
+ with pytest.raises(TypeError):
+ action_group.add_toggle_actions(42)
+
+ with pytest.raises(TypeError):
+ action_group.add_radio_actions(42)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_action_group_no_user_data(self):
+ action_group = Gtk.ActionGroup(name='TestActionGroup')
+
+ called = []
+
+ def test_action_callback_no_data(action):
+ called.append(action)
+
+ action_group.add_actions([
+ ('test-action1', None, 'Test Action 1',
+ None, None, test_action_callback_no_data)])
+ action_group.add_actions([('test2-action1',)])
+ action_group.get_action('test-action1').activate()
+
+ action_group.add_toggle_actions([
+ ('test-action2', None, 'Test Action 2',
+ None, None, test_action_callback_no_data)])
+ action_group.add_toggle_actions([('test2-action2',)])
+ action_group.get_action('test-action2').activate()
+
+ def test_action_callback_no_data_radio(action, current):
+ called.append(action)
+
+ action_group.add_radio_actions([
+ ('test-action3', None, 'Test Action 3', None, None, 0),
+ ('test-action4', None, 'Test Action 4', None, None, 1)],
+ 1, test_action_callback_no_data_radio)
+ action_group.add_radio_actions([('test2-action3',)])
+ action = action_group.get_action('test-action3')
+ assert action.get_current_value() == 1
+ action.activate()
+
+ assert len(called) == 3
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_uimanager(self):
self.assertEqual(Gtk.UIManager, gi.overrides.Gtk.UIManager)
ui = Gtk.UIManager()
ui.add_ui_from_string("""<ui>
<menubar name="menubar1"></menubar>
</ui>
-"""
-)
+""")
menubar = ui.get_widget("/menubar1")
self.assertEqual(type(menubar), Gtk.MenuBar)
@@ -150,13 +319,18 @@ class TestGtk(unittest.TestCase):
self.assertEqual(ag, groups[-2])
self.assertEqual(ag2, groups[-1])
+ with pytest.raises(TypeError):
+ ui.add_ui_from_string(42)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_uimanager_nonascii(self):
ui = Gtk.UIManager()
ui.add_ui_from_string(b'<ui><menubar name="menub\xc3\xa6r1" /></ui>'.decode('UTF-8'))
mi = ui.get_widget("/menubær1")
self.assertEqual(type(mi), Gtk.MenuBar)
- def test_window(self):
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_window_gtk3(self):
# standard Window
w = Gtk.Window()
self.assertEqual(w.get_property('type'), Gtk.WindowType.TOPLEVEL)
@@ -165,10 +339,6 @@ class TestGtk(unittest.TestCase):
w = Gtk.Window(type=Gtk.WindowType.POPUP)
self.assertEqual(w.get_property('type'), Gtk.WindowType.POPUP)
- # pygtk compatible positional argument
- w = Gtk.Window(Gtk.WindowType.POPUP)
- self.assertEqual(w.get_property('type'), Gtk.WindowType.POPUP)
-
class TestWindow(Gtk.Window):
__gtype_name__ = "TestWindow"
@@ -192,43 +362,146 @@ class TestGtk(unittest.TestCase):
self.assertEqual(builder.get_object('testpop').get_property('type'),
Gtk.WindowType.POPUP)
- def test_dialogs(self):
+ @unittest.skipUnless(Gtk_version == "4.0", "no GtkWindowType in gtk4")
+ def test_window_gtk4(self):
+ w = Gtk.Window()
+
+ # check that setting default size works
+ w.set_default_size(300, 300)
+ self.assertEqual(w.get_default_size(), (300, 300))
+
+ class TestWindow(Gtk.Window):
+ __gtype_name__ = "TestWindow"
+
+ # works from builder
+ builder = Gtk.Builder()
+ builder.add_from_string('''
+<interface>
+ <object class="GtkWindow" id="win">
+ <property name="css-name">amazing</property>
+ </object>
+ <object class="TestWindow" id="testwin">
+ <property name="css-name">amazing-test</property>
+ </object>
+</interface>''')
+ self.assertEqual(builder.get_object("win").get_property("css-name"),
+ "amazing")
+ self.assertEqual(builder.get_object("testwin").get_property("css-name"),
+ "amazing-test")
+
+ def test_dialog_classes(self):
self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
- self.assertEqual(Gtk.AboutDialog, gi.overrides.Gtk.AboutDialog)
- self.assertEqual(Gtk.MessageDialog, gi.overrides.Gtk.MessageDialog)
- self.assertEqual(Gtk.ColorSelectionDialog, gi.overrides.Gtk.ColorSelectionDialog)
- self.assertEqual(Gtk.FileChooserDialog, gi.overrides.Gtk.FileChooserDialog)
- self.assertEqual(Gtk.FontSelectionDialog, gi.overrides.Gtk.FontSelectionDialog)
- self.assertEqual(Gtk.RecentChooserDialog, gi.overrides.Gtk.RecentChooserDialog)
-
- # Gtk.Dialog
- dialog = Gtk.Dialog(title='Foo',
- flags=Gtk.DialogFlags.MODAL,
- buttons=('test-button1', 1))
+ if not GTK4:
+ self.assertEqual(Gtk.FileChooserDialog, gi.overrides.Gtk.FileChooserDialog)
+ self.assertEqual(Gtk.RecentChooserDialog, gi.overrides.Gtk.RecentChooserDialog)
+ self.assertEqual(Gtk.ColorSelectionDialog, gi.overrides.Gtk.ColorSelectionDialog)
+ self.assertEqual(Gtk.FontSelectionDialog, gi.overrides.Gtk.FontSelectionDialog)
+
+ def test_dialog_base(self):
+ dialog = Gtk.Dialog(title='Foo', modal=True)
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
-
- dialog.add_buttons('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
-
self.assertEqual('Foo', dialog.get_title())
self.assertTrue(dialog.get_modal())
+
+ @unittest.skipIf(GTK4, "flags not in gtk4")
+ def test_dialog_deprecations(self):
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.MODAL)
+ self.assertTrue(dialog.get_modal())
+ self.assertEqual(len(warn), 1)
+ self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
+ self.assertRegex(str(warn[0].message),
+ '.*flags.*modal.*')
+
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.DESTROY_WITH_PARENT)
+ self.assertTrue(dialog.get_destroy_with_parent())
+ self.assertEqual(len(warn), 1)
+ self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
+ self.assertRegex(str(warn[0].message),
+ '.*flags.*destroy_with_parent.*')
+
+ @unittest.skipIf(GTK4, "flags not in gtk4")
+ def test_dialog_deprecation_stacklevels(self):
+ # Test warning levels are setup to give the correct filename for
+ # deprecations in different classes in the inheritance hierarchy.
+
+ # Base class
+ self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog)
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ Gtk.Dialog(flags=Gtk.DialogFlags.MODAL)
+ self.assertEqual(len(warn), 1)
+ self.assertRegex(warn[0].filename, '.*test_overrides_gtk.*')
+
+ # Validate overridden base with overridden sub-class.
+ self.assertEqual(Gtk.MessageDialog, gi.overrides.Gtk.MessageDialog)
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL)
+ self.assertEqual(len(warn), 1)
+ self.assertRegex(warn[0].filename, '.*test_overrides_gtk.*')
+
+ # Validate overridden base with non-overridden sub-class.
+ self.assertEqual(Gtk.AboutDialog, gi.repository.Gtk.AboutDialog)
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ Gtk.AboutDialog(flags=Gtk.DialogFlags.MODAL)
+ self.assertEqual(len(warn), 1)
+ self.assertRegex(warn[0].filename, '.*test_overrides_gtk.*')
+
+ def test_dialog_add_buttons(self):
+ if not GTK4:
+ # The overloaded "buttons" keyword gives a warning when attempting
+ # to use it for adding buttons as was available in PyGTK.
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ dialog = Gtk.Dialog(title='Foo', modal=True,
+ buttons=('test-button1', 1))
+ self.assertEqual(len(warn), 1)
+ self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning))
+ self.assertRegex(str(warn[0].message),
+ '.*ButtonsType.*add_buttons.*')
+ else:
+ dialog = Gtk.Dialog()
+ dialog.add_buttons('test-button1', 1)
+
+ dialog.add_buttons('test-button2', 2, 'gtk-close', Gtk.ResponseType.CLOSE)
button = dialog.get_widget_for_response(1)
self.assertEqual('test-button1', button.get_label())
button = dialog.get_widget_for_response(2)
self.assertEqual('test-button2', button.get_label())
button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
- self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
+ self.assertEqual('gtk-close', button.get_label())
+
+ with pytest.raises(ValueError, match="even number"):
+ dialog.add_buttons('test-button2', 2, 'gtk-close')
- # Gtk.AboutDialog
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_dialog_deprecated_attributes(self):
+ dialog = Gtk.Dialog()
+ assert dialog.action_area == dialog.get_action_area()
+ assert dialog.vbox == dialog.get_content_area()
+
+ def test_about_dialog(self):
dialog = Gtk.AboutDialog()
- self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
- # Gtk.MessageDialog
+ if not GTK4:
+ self.assertTrue(isinstance(dialog, Gtk.Dialog))
+
+ # AboutDialog is not sub-classed in overrides, make sure
+ # the mro still injects the base class "add_buttons" override.
+ self.assertTrue(hasattr(dialog, 'add_buttons'))
+
+ def test_message_dialog(self):
dialog = Gtk.MessageDialog(title='message dialog test',
- flags=Gtk.DialogFlags.MODAL,
+ modal=True,
buttons=Gtk.ButtonsType.OK,
- message_format='dude!')
+ text='dude!')
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
@@ -237,66 +510,58 @@ class TestGtk(unittest.TestCase):
text = dialog.get_property('text')
self.assertEqual('dude!', text)
- dialog.format_secondary_text('2nd text')
- self.assertEqual(dialog.get_property('secondary-text'), '2nd text')
- self.assertFalse(dialog.get_property('secondary-use-markup'))
+ if not GTK4:
+ dialog.format_secondary_text('2nd text')
+ self.assertEqual(dialog.get_property('secondary-text'), '2nd text')
+ self.assertFalse(dialog.get_property('secondary-use-markup'))
- dialog.format_secondary_markup('2nd markup')
- self.assertEqual(dialog.get_property('secondary-text'), '2nd markup')
- self.assertTrue(dialog.get_property('secondary-use-markup'))
+ dialog.format_secondary_markup('2nd markup')
+ self.assertEqual(dialog.get_property('secondary-text'), '2nd markup')
+ self.assertTrue(dialog.get_property('secondary-use-markup'))
- # Gtk.ColorSelectionDialog
- dialog = Gtk.ColorSelectionDialog("color selection dialog test")
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_color_selection_dialog(self):
+ dialog = Gtk.ColorSelectionDialog(title="color selection dialog test")
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
self.assertEqual('color selection dialog test', dialog.get_title())
- # Gtk.FileChooserDialog
+ def test_file_chooser_dialog(self):
# might cause a GVFS warning, do not break on this
- old_mask = GLib.log_set_always_fatal(
- GLib.LogLevelFlags.LEVEL_CRITICAL | GLib.LogLevelFlags.LEVEL_ERROR)
- try:
+ with capture_glib_warnings(allow_warnings=True):
dialog = Gtk.FileChooserDialog(title='file chooser dialog test',
- buttons=('test-button1', 1),
action=Gtk.FileChooserAction.SAVE)
- finally:
- GLib.log_set_always_fatal(old_mask)
+
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
-
- dialog.add_buttons('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
self.assertEqual('file chooser dialog test', dialog.get_title())
- button = dialog.get_widget_for_response(1)
- self.assertEqual('test-button1', button.get_label())
- button = dialog.get_widget_for_response(2)
- self.assertEqual('test-button2', button.get_label())
- button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
- self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
+
action = dialog.get_property('action')
self.assertEqual(Gtk.FileChooserAction.SAVE, action)
- # Gtk.FontSelectionDialog
- dialog = Gtk.ColorSelectionDialog("font selection dialog test")
+ def test_file_chooser_dialog_default_action(self):
+ # might cause a GVFS warning, do not break on this
+ with capture_glib_warnings(allow_warnings=True):
+ dialog = Gtk.FileChooserDialog(title='file chooser dialog test')
+
+ action = dialog.get_property('action')
+ self.assertEqual(Gtk.FileChooserAction.OPEN, action)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_font_selection_dialog(self):
+ dialog = Gtk.FontSelectionDialog(title="font selection dialog test")
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
self.assertEqual('font selection dialog test', dialog.get_title())
- # Gtk.RecentChooserDialog
+ @unittest.skipIf(GTK4, "not in gtk4")
+ def test_recent_chooser_dialog(self):
test_manager = Gtk.RecentManager()
dialog = Gtk.RecentChooserDialog(title='recent chooser dialog test',
- buttons=('test-button1', 1),
- manager=test_manager)
+ recent_manager=test_manager)
self.assertTrue(isinstance(dialog, Gtk.Dialog))
self.assertTrue(isinstance(dialog, Gtk.Window))
-
- dialog.add_buttons('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
self.assertEqual('recent chooser dialog test', dialog.get_title())
- button = dialog.get_widget_for_response(1)
- self.assertEqual('test-button1', button.get_label())
- button = dialog.get_widget_for_response(2)
- self.assertEqual('test-button2', button.get_label())
- button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE)
- self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
class TestClass(GObject.GObject):
__gtype_name__ = "GIOverrideTreeAPITest"
@@ -312,29 +577,37 @@ class TestGtk(unittest.TestCase):
self.tester.assertEqual(string_value, self.string_value)
def test_buttons(self):
- self.assertEqual(Gtk.Button, gi.overrides.Gtk.Button)
+ if not GTK4:
+ self.assertEqual(Gtk.Button, gi.overrides.Gtk.Button)
# test Gtk.Button
button = Gtk.Button()
self.assertTrue(isinstance(button, Gtk.Button))
- self.assertTrue(isinstance(button, Gtk.Container))
+ if Gtk._version != "4.0":
+ self.assertTrue(isinstance(button, Gtk.Container))
self.assertTrue(isinstance(button, Gtk.Widget))
- button = Gtk.Button(stock=Gtk.STOCK_CLOSE)
- self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
- self.assertTrue(button.get_use_stock())
- self.assertTrue(button.get_use_underline())
- # test Gtk.Button use_stock
- button = Gtk.Button(label=Gtk.STOCK_CLOSE, use_stock=True, use_underline=True)
- self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
- self.assertTrue(button.get_use_stock())
- self.assertTrue(button.get_use_underline())
+ if Gtk_version != "4.0":
+ # Using stock items causes hard warning in devel versions of GTK.
+ with capture_glib_warnings(allow_warnings=True):
+ button = Gtk.Button.new_from_stock(Gtk.STOCK_CLOSE)
+
+ self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
+ self.assertTrue(button.get_use_stock())
+ self.assertTrue(button.get_use_underline())
+
+ # test Gtk.Button use_stock
+ button = Gtk.Button(label=Gtk.STOCK_CLOSE, use_stock=True,
+ use_underline=True)
+ self.assertEqual(Gtk.STOCK_CLOSE, button.get_label())
+ self.assertTrue(button.get_use_stock())
+ self.assertTrue(button.get_use_underline())
# test Gtk.LinkButton
- self.assertRaises(TypeError, Gtk.LinkButton)
- button = Gtk.LinkButton('http://www.Gtk.org', 'Gtk')
+ button = Gtk.LinkButton(uri='http://www.Gtk.org', label='Gtk')
self.assertTrue(isinstance(button, Gtk.Button))
- self.assertTrue(isinstance(button, Gtk.Container))
+ if Gtk._version != "4.0":
+ self.assertTrue(isinstance(button, Gtk.Container))
self.assertTrue(isinstance(button, Gtk.Widget))
self.assertEqual('http://www.Gtk.org', button.get_uri())
self.assertEqual('Gtk', button.get_label())
@@ -353,7 +626,7 @@ class TestGtk(unittest.TestCase):
if isinstance(info, gi.types.ObjectInfo):
classes = list(info.get_interfaces())
parent = info.get_parent()
- while parent.get_name() != "Object":
+ while parent is not None and parent.get_name() != "Object":
classes.append(parent)
parent = parent.get_parent()
classes = [kl for kl in classes if kl.get_namespace() == "Gtk"]
@@ -392,43 +665,42 @@ class TestGtk(unittest.TestCase):
self.assertEqual(adjustment.get_page_size(), page_size)
def test_adjustment(self):
- adjustment = Gtk.Adjustment(1, 0, 6, 4, 5, 3)
- self.adjustment_check(adjustment, 1, 0, 6, 4, 5, 3)
+ adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3)
+ self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3)
- adjustment = Gtk.Adjustment(1, 0, 6, 4, 5)
- self.adjustment_check(adjustment, 1, 0, 6, 4, 5)
+ adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5)
+ self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5)
- adjustment = Gtk.Adjustment(1, 0, 6, 4)
- self.adjustment_check(adjustment, 1, 0, 6, 4)
+ adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4)
+ self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4)
- adjustment = Gtk.Adjustment(1, 0, 6)
- self.adjustment_check(adjustment, 1, 0, 6)
+ adjustment = Gtk.Adjustment(value=1, lower=0, upper=6)
+ self.adjustment_check(adjustment, value=1, lower=0, upper=6)
adjustment = Gtk.Adjustment()
self.adjustment_check(adjustment)
- adjustment = Gtk.Adjustment(value=1, lower=0, upper=6,
- step_increment=4, page_increment=5, page_size=3)
- self.adjustment_check(adjustment, 1, 0, 6, 4, 5, 3)
+ if not GTK4:
+ adjustment = Gtk.Adjustment(1, -1, 3, 0, 0, 0)
+ self.adjustment_check(adjustment, value=1, lower=-1, upper=3)
+ adjustment = Gtk.Adjustment(1, -1, 3, 0, 0, 0, value=2)
+ self.adjustment_check(adjustment, value=2, lower=-1, upper=3)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_table(self):
table = Gtk.Table()
self.assertTrue(isinstance(table, Gtk.Table))
- self.assertTrue(isinstance(table, Gtk.Container))
+ if Gtk._version != "4.0":
+ self.assertTrue(isinstance(table, Gtk.Container))
self.assertTrue(isinstance(table, Gtk.Widget))
self.assertEqual(table.get_size(), (1, 1))
self.assertEqual(table.get_homogeneous(), False)
- table = Gtk.Table(2, 3)
+
+ table = Gtk.Table(n_rows=2, n_columns=3)
self.assertEqual(table.get_size(), (2, 3))
self.assertEqual(table.get_homogeneous(), False)
- table = Gtk.Table(2, 3, True)
- self.assertEqual(table.get_size(), (2, 3))
- self.assertEqual(table.get_homogeneous(), True)
- # Test PyGTK interface
- table = Gtk.Table(rows=3, columns=2)
- self.assertEqual(table.get_size(), (3, 2))
- # Test using the actual property names
table = Gtk.Table(n_rows=2, n_columns=3, homogeneous=True)
self.assertEqual(table.get_size(), (2, 3))
self.assertEqual(table.get_homogeneous(), True)
@@ -441,13 +713,15 @@ class TestGtk(unittest.TestCase):
def test_scrolledwindow(self):
sw = Gtk.ScrolledWindow()
self.assertTrue(isinstance(sw, Gtk.ScrolledWindow))
- self.assertTrue(isinstance(sw, Gtk.Container))
+ if Gtk._version != "4.0":
+ self.assertTrue(isinstance(sw, Gtk.Container))
self.assertTrue(isinstance(sw, Gtk.Widget))
sb = sw.get_hscrollbar()
self.assertEqual(sw.get_hadjustment(), sb.get_adjustment())
sb = sw.get_vscrollbar()
self.assertEqual(sw.get_vadjustment(), sb.get_adjustment())
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_widget_drag_methods(self):
widget = Gtk.Button()
@@ -464,6 +738,8 @@ class TestGtk(unittest.TestCase):
widget.drag_dest_get_track_motion()
widget.drag_dest_set_track_motion(True)
widget.drag_dest_get_target_list()
+ widget.drag_dest_set_target_list(None)
+
widget.drag_dest_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
widget.drag_dest_unset()
@@ -475,10 +751,11 @@ class TestGtk(unittest.TestCase):
widget.drag_source_add_image_targets()
widget.drag_source_add_text_targets()
widget.drag_source_add_uri_targets()
- widget.drag_source_set_icon_name("")
+ widget.drag_source_set_icon_name("_About")
widget.drag_source_set_icon_pixbuf(GdkPixbuf.Pixbuf())
- widget.drag_source_set_icon_stock("")
+ widget.drag_source_set_icon_stock(Gtk.STOCK_ABOUT)
widget.drag_source_get_target_list()
+ widget.drag_source_set_target_list(None)
widget.drag_source_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)]))
widget.drag_source_unset()
@@ -487,7 +764,30 @@ class TestGtk(unittest.TestCase):
self.assertTrue(hasattr(widget, 'drag_dest_set_proxy'))
self.assertTrue(hasattr(widget, 'drag_get_data'))
- def test_drag_target_list(self):
+ @unittest.skipIf(Gtk_version != "4.0", "gtk4 only")
+ def test_widget_drag_methods_gtk4(self):
+ widget = Gtk.Button()
+ widget.drag_check_threshold(0, 0, 0, 0)
+
+ # drag source
+ drag_source = Gtk.DragSource()
+ content = Gdk.ContentProvider.new_for_value("data")
+ drag_source.set_content(content)
+ drag_source.set_actions(Gdk.DragAction.COPY)
+ image = Gtk.Image.new_from_icon_name("dialog-warning")
+ drag_source.set_icon(image.get_paintable(), 0, 0)
+ widget.add_controller(drag_source)
+
+ # drop target
+ drop_target = Gtk.DropTarget.new(Gdk.ContentFormats.new([]), Gdk.DragAction.COPY)
+ widget.add_controller(drop_target)
+
+ widget.remove_controller(drag_source)
+ widget.remove_controller(drop_target)
+
+ @unittest.skipIf(sys.platform == "darwin", "crashes")
+ @unittest.skipIf(GTK4, "uses lots of gtk3 only api")
+ def test_tree_view_drag_target_list_gtk3(self):
mixed_target_list = [Gtk.TargetEntry.new('test0', 0, 0),
('test1', 1, 1),
Gtk.TargetEntry.new('test2', 2, 2),
@@ -519,8 +819,21 @@ class TestGtk(unittest.TestCase):
treeview.enable_model_drag_dest(mixed_target_list,
Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
+ @unittest.skipUnless(GTK4, "gtk4 only")
+ def test_tree_view_drag_content_formats_gtk4(self):
+ content_formats = Gdk.ContentFormats.new(
+ ["application/json", "GTK_TREE_MODEL_ROW"]
+ )
+ treeview = Gtk.TreeView()
+ treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
+ content_formats,
+ Gdk.DragAction.MOVE)
+
+ treeview.enable_model_drag_dest(content_formats,
+ Gdk.DragAction.MOVE)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_scrollbar(self):
- # PyGTK compat
adjustment = Gtk.Adjustment()
hscrollbar = Gtk.HScrollbar()
@@ -528,8 +841,8 @@ class TestGtk(unittest.TestCase):
self.assertNotEqual(hscrollbar.props.adjustment, adjustment)
self.assertNotEqual(vscrollbar.props.adjustment, adjustment)
- hscrollbar = Gtk.HScrollbar(adjustment)
- vscrollbar = Gtk.VScrollbar(adjustment)
+ hscrollbar = Gtk.HScrollbar(adjustment=adjustment)
+ vscrollbar = Gtk.VScrollbar(adjustment=adjustment)
self.assertEqual(hscrollbar.props.adjustment, adjustment)
self.assertEqual(vscrollbar.props.adjustment, adjustment)
@@ -539,31 +852,38 @@ class TestGtk(unittest.TestCase):
self.assertEqual(iconview.props.model, None)
model = Gtk.ListStore(str)
- iconview = Gtk.IconView(model)
+ iconview = Gtk.IconView(model=model)
self.assertEqual(iconview.props.model, model)
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_toolbutton(self):
# PyGTK compat
- button = Gtk.ToolButton()
- self.assertEqual(button.props.stock_id, None)
- button = Gtk.ToolButton('gtk-new')
- self.assertEqual(button.props.stock_id, 'gtk-new')
+ # Using stock items causes hard warning in devel versions of GTK.
+ with capture_glib_warnings(allow_warnings=True):
+ button = Gtk.ToolButton()
+ self.assertEqual(button.props.stock_id, None)
- icon = Gtk.Image.new_from_stock(Gtk.STOCK_OPEN, Gtk.IconSize.SMALL_TOOLBAR)
+ button = Gtk.ToolButton(stock_id='gtk-new')
+ self.assertEqual(button.props.stock_id, 'gtk-new')
+ icon = Gtk.Image.new_from_stock(Gtk.STOCK_OPEN, Gtk.IconSize.SMALL_TOOLBAR)
button = Gtk.ToolButton(label='mylabel', icon_widget=icon)
self.assertEqual(button.props.label, 'mylabel')
self.assertEqual(button.props.icon_widget, icon)
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_iconset(self):
- # PyGTK compat
Gtk.IconSet()
pixbuf = GdkPixbuf.Pixbuf()
- Gtk.IconSet(pixbuf)
+ Gtk.IconSet.new_from_pixbuf(pixbuf)
+
+ with warnings.catch_warnings(record=True) as warn:
+ warnings.simplefilter('always')
+ Gtk.IconSet(pixbuf)
+ assert issubclass(warn[0].category, PyGTKDeprecationWarning)
def test_viewport(self):
- # PyGTK compat
vadjustment = Gtk.Adjustment()
hadjustment = Gtk.Adjustment()
@@ -573,55 +893,169 @@ class TestGtk(unittest.TestCase):
self.assertEqual(viewport.props.vadjustment, vadjustment)
self.assertEqual(viewport.props.hadjustment, hadjustment)
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_stock_lookup(self):
- l = Gtk.stock_lookup('gtk-ok')
- self.assertEqual(type(l), Gtk.StockItem)
- self.assertEqual(l.stock_id, 'gtk-ok')
+ stock_item = Gtk.stock_lookup('gtk-ok')
+ self.assertEqual(type(stock_item), Gtk.StockItem)
+ self.assertEqual(stock_item.stock_id, 'gtk-ok')
self.assertEqual(Gtk.stock_lookup('nosuchthing'), None)
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
def test_gtk_main(self):
# with no arguments
- GLib.timeout_add(100, Gtk.main_quit)
+ GLib.idle_add(Gtk.main_quit)
Gtk.main()
# overridden function ignores its arguments
- GLib.timeout_add(100, Gtk.main_quit, 'hello')
+ GLib.idle_add(Gtk.main_quit, 'hello')
Gtk.main()
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_widget_render_icon(self):
+ button = Gtk.Button(label='OK')
+ pixbuf = button.render_icon(Gtk.STOCK_OK, Gtk.IconSize.BUTTON)
+ self.assertTrue(pixbuf is not None)
+
+ @unittest.skipUnless(
+ Gtk_version == "4.0", "GtkWidget prior to gtk4 is not iterable")
+ def test_widget_iterable(self):
+ widget = Gtk.Box()
+
+ children = [child for child in widget]
+ self.assertEqual(len(children), 0)
+
+ nr_children = 7
+ for i in range(nr_children):
+ widget.append(Gtk.Label())
+
+ children = [child for child in widget]
+ self.assertEqual(len(children), nr_children)
+
+ first_child = children[0]
+ last_child = children[-1]
+ self.assertEqual(first_child, widget.get_first_child())
+ self.assertEqual(last_child, widget.get_last_child())
+
+ self.assertTrue(first_child in widget)
+ self.assertTrue(last_child in widget)
+
+ widget.remove(first_child)
+ self.assertTrue(first_child not in widget)
+ self.assertTrue(last_child in widget)
+
+ widget.remove(last_child)
+ self.assertTrue(first_child not in widget)
+ self.assertTrue(last_child not in widget)
+
@unittest.skipUnless(Gtk, 'Gtk not available')
-class TestSignals(unittest.TestCase):
- class WindowWithSizeAllocOverride(Gtk.ScrolledWindow):
- __gsignals__ = {'size-allocate': 'override'}
+class TestWidget(unittest.TestCase):
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_style_get_property_gvalue(self):
+ button = Gtk.Button()
+ value = GObject.Value(int, -42)
+ button.style_get_property('focus-padding', value)
+ # Test only that the style property changed since we can't actuall
+ # set it.
+ self.assertNotEqual(value.get_int(), -42)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_style_get_property_return_with_explicit_gvalue(self):
+ button = Gtk.Button()
+ value = GObject.Value(int, -42)
+ result = button.style_get_property('focus-padding', value)
+ self.assertIsInstance(result, int)
+ self.assertNotEqual(result, -42)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_style_get_property_return_with_implicit_gvalue(self):
+ button = Gtk.Button()
+ result = button.style_get_property('focus-padding')
+ self.assertIsInstance(result, int)
+ self.assertNotEqual(result, -42)
- def __init__(self):
- Gtk.ScrolledWindow.__init__(self)
- self._alloc_called = False
- self._alloc_value = None
- self._alloc_error = None
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_style_get_property_error(self):
+ button = Gtk.Button()
+ with self.assertRaises(ValueError):
+ button.style_get_property('not-a-valid-style-property')
- def do_size_allocate(self, alloc):
- self._alloc_called = True
- self._alloc_value = alloc
+ @unittest.skipIf(Gtk_version != "4.0", "only in gtk4")
+ def test_translate_coordinates(self):
+ box = Gtk.Box()
+ child = Gtk.Button()
+ box.append(child)
+ with realized(box):
+ assert box.translate_coordinates(child, 42, 24) == (42.0, 24.0)
+ assert box.translate_coordinates(Gtk.Button(), 0, 0) is None
- try:
- Gtk.ScrolledWindow.do_size_allocate(self, alloc)
- except Exception as e:
- self._alloc_error = e
+@unittest.skipIf(sys.platform == "darwin", "hangs")
+@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestSignals(unittest.TestCase):
def test_class_closure_override_with_aliased_type(self):
- win = self.WindowWithSizeAllocOverride()
+ class WindowWithSizeAllocOverride(Gtk.ScrolledWindow):
+ if not GTK4:
+ __gsignals__ = {'size-allocate': 'override'}
+
+ def __init__(self):
+ Gtk.ScrolledWindow.__init__(self)
+ self._alloc_called = False
+ self._alloc_value = None
+ self._alloc_error = None
+
+ def do_size_allocate(self, *args):
+ self._alloc_called = True
+ self._alloc_value = args[0]
+
+ try:
+ Gtk.ScrolledWindow.do_size_allocate(self, *args)
+ except Exception as e:
+ self._alloc_error = e
+
+ win = WindowWithSizeAllocOverride()
rect = Gdk.Rectangle()
rect.width = 100
rect.height = 100
with realized(win):
win.show()
- win.size_allocate(rect)
+ win.get_preferred_size()
+ if GTK4:
+ win.size_allocate(rect, 0)
+ else:
+ win.size_allocate(rect)
self.assertTrue(win._alloc_called)
- self.assertIsInstance(win._alloc_value, Gdk.Rectangle)
+ if GTK4:
+ self.assertIsInstance(win._alloc_value, int)
+ else:
+ self.assertIsInstance(win._alloc_value, Gdk.Rectangle)
self.assertTrue(win._alloc_error is None, win._alloc_error)
+ @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=735693
+ def test_overlay_child_position(self):
+ def get_child_position(overlay, widget, rect, user_data=None):
+ rect.x = 1
+ rect.y = 2
+ rect.width = 3
+ rect.height = 4
+ return True
+
+ overlay = Gtk.Overlay()
+ overlay.connect('get-child-position', get_child_position)
+
+ rect = Gdk.Rectangle()
+ rect.x = -1
+ rect.y = -1
+ rect.width = -1
+ rect.height = -1
+
+ overlay.emit('get-child-position', None, rect)
+ self.assertEqual(rect.x, 1)
+ self.assertEqual(rect.y, 2)
+ self.assertEqual(rect.width, 3)
+ self.assertEqual(rect.height, 4)
+
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestBuilder(unittest.TestCase):
@@ -633,6 +1067,40 @@ class TestBuilder(unittest.TestCase):
[]),
}
+ class SignalTestObject(GObject.GObject):
+ __gtype_name__ = "GIOverrideSignalTestObject"
+
+ def test_add_from_string(self):
+ builder = Gtk.Builder()
+
+ with pytest.raises(TypeError):
+ builder.add_from_string(object())
+
+ builder.add_from_string(u"")
+ builder.add_from_string("")
+
+ def get_example(string):
+ return u"""\
+<interface>
+ <menu id="appmenu">
+ <section>
+ <item>
+ <attribute name="label">%s</attribute>
+ </item>
+ </section>
+ </menu>
+</interface>""" % string
+
+ builder.add_from_string(get_example(u"ä" * 1000))
+
+ builder = Gtk.Builder()
+ builder.add_objects_from_string(u"", [''])
+ builder.add_objects_from_string("", [''])
+ builder.add_objects_from_string(get_example(u"ä" * 1000), [''])
+
+ with pytest.raises(TypeError):
+ builder.add_objects_from_string(object(), [])
+
def test_extract_handler_and_args_object(self):
class Obj():
pass
@@ -640,32 +1108,51 @@ class TestBuilder(unittest.TestCase):
obj = Obj()
obj.foo = lambda: None
- handler, args = Gtk.Builder._extract_handler_and_args(obj, 'foo')
+ handler, args = Gtk._extract_handler_and_args(obj, 'foo')
self.assertEqual(handler, obj.foo)
self.assertEqual(len(args), 0)
def test_extract_handler_and_args_dict(self):
obj = {'foo': lambda: None}
- handler, args = Gtk.Builder._extract_handler_and_args(obj, 'foo')
+ handler, args = Gtk._extract_handler_and_args(obj, 'foo')
self.assertEqual(handler, obj['foo'])
self.assertEqual(len(args), 0)
def test_extract_handler_and_args_with_seq(self):
obj = {'foo': (lambda: None, 1, 2)}
- handler, args = Gtk.Builder._extract_handler_and_args(obj, 'foo')
+ handler, args = Gtk._extract_handler_and_args(obj, 'foo')
self.assertEqual(handler, obj['foo'][0])
self.assertSequenceEqual(args, [1, 2])
def test_extract_handler_and_args_no_handler_error(self):
obj = dict(foo=lambda: None)
self.assertRaises(AttributeError,
- Gtk.Builder._extract_handler_and_args,
+ Gtk._extract_handler_and_args,
obj, 'not_a_handler')
+ def test_extract_handler_and_args_type_mismatch(self):
+ with pytest.raises(TypeError):
+ Gtk._extract_handler_and_args({"foo": object()}, "foo")
+
+ with pytest.raises(TypeError):
+ Gtk._extract_handler_and_args({"foo": []}, "foo")
+
def test_builder_with_handler_and_args(self):
- builder = Gtk.Builder()
+ args_collector = []
+
+ def on_signal(*args):
+ args_collector.append(args)
+
+ signals_dict = {'on_signal1': (on_signal, 1, 2),
+ 'on_signal2': on_signal}
+
+ if GTK4:
+ builder = Gtk.Builder(signals_dict)
+ else:
+ builder = Gtk.Builder()
+
builder.add_from_string("""
<interface>
<object class="GIOverrideSignalTest" id="object_sig_test">
@@ -675,13 +1162,8 @@ class TestBuilder(unittest.TestCase):
</interface>
""")
- args_collector = []
-
- def on_signal(*args):
- args_collector.append(args)
-
- builder.connect_signals({'on_signal1': (on_signal, 1, 2),
- 'on_signal2': on_signal})
+ if not GTK4:
+ builder.connect_signals(signals_dict)
objects = builder.get_objects()
self.assertEqual(len(objects), 1)
@@ -692,6 +1174,40 @@ class TestBuilder(unittest.TestCase):
self.assertSequenceEqual(args_collector[0], (obj, 1, 2))
self.assertSequenceEqual(args_collector[1], (obj, ))
+ def test_builder_with_handler_object(self):
+ args_collector = []
+
+ def on_signal(*args):
+ args_collector.append(args)
+
+ signals_dict = {'on_signal1': (on_signal, 1, 2),
+ 'on_signal2': on_signal}
+
+ if GTK4:
+ builder = Gtk.Builder(signals_dict)
+ else:
+ builder = Gtk.Builder()
+
+ builder.add_from_string("""
+ <interface>
+ <object class="GIOverrideSignalTestObject" id="foo"/>
+ <object class="GIOverrideSignalTest" id="object_sig_test">
+ <signal name="test-signal" handler="on_signal1" object="foo" swapped="no"/>
+ <signal name="test-signal" handler="on_signal2" after="yes" object="foo" swapped="no"/>
+ </object>
+ </interface>
+ """)
+
+ if not GTK4:
+ builder.connect_signals(signals_dict)
+
+ obj = builder.get_object("foo")
+ emitter = builder.get_object("object_sig_test")
+ emitter.emit("test-signal")
+ assert len(args_collector) == 2
+ assert args_collector[0] == (obj, 1, 2)
+ assert args_collector[1] == (obj, )
+
def test_builder(self):
self.assertEqual(Gtk.Builder, gi.overrides.Gtk.Builder)
@@ -712,7 +1228,11 @@ class TestBuilder(unittest.TestCase):
self.after_sentinel += 1
signal_checker = SignalCheck()
- builder = Gtk.Builder()
+ signal_checker = SignalCheck()
+ if GTK4:
+ builder = Gtk.Builder(signal_checker)
+ else:
+ builder = Gtk.Builder()
# add object1 to the builder
builder.add_from_string("""
@@ -739,8 +1259,9 @@ class TestBuilder(unittest.TestCase):
</interface>
""", ['object3'])
- # hook up signals
- builder.connect_signals(signal_checker)
+ # hook up signals for Gtk3
+ if not GTK4:
+ builder.connect_signals(signal_checker)
# call their notify signals and check sentinel
objects = builder.get_objects()
@@ -753,12 +1274,161 @@ class TestBuilder(unittest.TestCase):
@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestTreeModelRow(unittest.TestCase):
+ def test_tree_model_row(self):
+ model = Gtk.TreeStore(int)
+ iter_ = model.append(None, [42])
+ path = model.get_path(iter_)
+ Gtk.TreeModelRow(model, iter_)
+ row = Gtk.TreeModelRow(model, path)
+
+ with pytest.raises(TypeError):
+ row["foo"]
+
+ with pytest.raises(TypeError):
+ Gtk.TreeModelRow(model, 42)
+
+ with pytest.raises(TypeError):
+ Gtk.TreeModelRow(42, path)
+
+ iter_ = model.append(None, [24])
+ row = Gtk.TreeModelRow(model, iter_)
+ assert row.previous[0] == 42
+ assert row.get_previous()[0] == 42
+ assert row.previous.previous is None
+
+
+@unittest.skipUnless(Gtk, "Gtk not available")
+class TestCustomSorter():
+ class Person(GObject.GObject):
+
+ name = GObject.Property(type=str, default="")
+
+ def __init__(self, name):
+ super().__init__()
+ self.props.name = name
+
+ user_data = "user_data"
+
+ def names_sort(self, name_a, name_b, user_data):
+ assert user_data is None
+ if name_a.props.name < name_b.props.name:
+ return Gtk.Ordering.SMALLER
+ elif name_a.props.name > name_b.props.name:
+ return Gtk.Ordering.LARGER
+ else:
+ return Gtk.Ordering.EQUAL
+
+ def names_invert_sort(self, name_a, name_b, user_data):
+ assert user_data == self.user_data
+ if name_a.props.name < name_b.props.name:
+ return Gtk.Ordering.LARGER
+ elif name_a.props.name > name_b.props.name:
+ return Gtk.Ordering.SMALLER
+ else:
+ return Gtk.Ordering.EQUAL
+
+ @unittest.skipIf(Gtk_version != "4.0", "gtk4 only")
+ def test_custom_sorter_init(self):
+ custom_sorter_empty = Gtk.CustomSorter()
+ assert isinstance(custom_sorter_empty, Gtk.CustomSorter)
+
+ custom_sorter_empty.set_sort_func(self.names_sort)
+ assert isinstance(custom_sorter_empty, Gtk.CustomSorter)
+
+ custom_sorter_empty.set_sort_func(
+ self.names_invert_sort, self.user_data)
+ assert isinstance(custom_sorter_empty, Gtk.CustomSorter)
+
+ custom_sorter_empty_sort = Gtk.CustomSorter.new(None)
+ assert isinstance(custom_sorter_empty_sort, Gtk.CustomSorter)
+
+ custom_sorter_with_sort = Gtk.CustomSorter.new(self.names_sort, None)
+ assert isinstance(custom_sorter_with_sort, Gtk.CustomSorter)
+
+ custom_sorter_with_sort_ud = Gtk.CustomSorter.new(
+ self.names_invert_sort, self.user_data)
+ assert isinstance(custom_sorter_with_sort_ud, Gtk.CustomSorter)
+
+ @unittest.skipIf(Gtk_version != "4.0", "gtk4 only")
+ def test_custom_sorter_with_model(self):
+ model = Gio.ListStore.new(self.Person)
+ sort_model = Gtk.SortListModel.new(model)
+ assert sort_model.props.sorter is None
+
+ empty_sorter = Gtk.CustomSorter()
+ empty_sorter.set_sort_func(self.names_sort, None)
+ sort_model.set_sorter(empty_sorter)
+ assert sort_model.props.sorter is empty_sorter
+
+ john = self.Person("john")
+ bob = self.Person("bob")
+ model.append(john)
+ model.append(bob)
+ assert sort_model[0] == bob
+ assert sort_model[1] == john
+
+ alice = self.Person("alice")
+ model.append(alice)
+ assert sort_model[0] == alice
+ assert sort_model[2] == john
+
+ new_model = Gio.ListStore.new(self.Person)
+ new_sort_model = Gtk.SortListModel.new(new_model)
+ assert new_sort_model.props.sorter is None
+
+ invert_sorter = Gtk.CustomSorter.new(
+ self.names_invert_sort, self.user_data)
+ new_sort_model.set_sorter(invert_sorter)
+ assert new_sort_model.props.sorter is invert_sorter
+
+ beatles = ["john", "paul", "george", "ringo"]
+ for member in beatles:
+ new_model.append(self.Person(member))
+
+ expected_result = ["ringo", "paul", "john", "george"]
+ for result, member in zip(new_sort_model, expected_result):
+ assert result.props.name == member
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestListStore(unittest.TestCase):
+
+ def test_insert_with_values(self):
+ model = Gtk.ListStore(int)
+ assert hasattr(model, 'insert_with_values')
+ iter_ = model.insert_with_values(0, (0,), [42])
+ assert isinstance(iter_, Gtk.TreeIter)
+ assert hasattr(model, 'insert_with_valuesv')
+ iter_ = model.insert_with_valuesv(0, (0,), [43])
+ assert isinstance(iter_, Gtk.TreeIter)
+ assert len(model) == 2
+
+
+@ignore_gi_deprecation_warnings
+@unittest.skipUnless(Gtk, 'Gtk not available')
class TestTreeModel(unittest.TestCase):
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_tree_model_sort_new_with_model_old(self):
+ # https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/1134
+ model = Gtk.TreeStore(int)
+ sort_model = model.sort_new_with_model()
+ assert isinstance(sort_model, Gtk.TreeModelSort)
+ assert sort_model.get_model() == model
+
+ def test_tree_model_sort_new_with_model_new(self):
+ # https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/1134
+ model = Gtk.TreeStore(int)
+ sort_model = Gtk.TreeModelSort.new_with_model(child_model=model)
+ assert isinstance(sort_model, Gtk.TreeModelSort)
+ assert sort_model.get_model() == model
+
def test_tree_model_sort(self):
- self.assertEqual(Gtk.TreeModelSort, gi.overrides.Gtk.TreeModelSort)
- self.assertRaises(TypeError, Gtk.TreeModelSort)
+ if not GTK4:
+ self.assertEqual(Gtk.TreeModelSort, gi.overrides.Gtk.TreeModelSort)
model = Gtk.TreeStore(int, bool)
- model_sort = Gtk.TreeModelSort(model)
+ model_sort = Gtk.TreeModelSort(model=model)
self.assertEqual(model_sort.get_model(), model)
def test_tree_store(self):
@@ -803,11 +1473,11 @@ class TestTreeModel(unittest.TestCase):
i % 2,
bool(i % 2),
i,
- GObject.G_MAXULONG,
- GObject.G_MININT64,
+ GLib.MAXULONG,
+ GLib.MININT64,
0xffffffffffffffff,
254,
- _bytes('a')
+ b'a'
))
# test set
parent = tree_store.append(parent)
@@ -825,11 +1495,11 @@ class TestTreeModel(unittest.TestCase):
7, i % 2,
8, bool(i % 2),
9, i,
- 10, GObject.G_MAXULONG,
- 11, GObject.G_MININT64,
+ 10, GLib.MAXULONG,
+ 11, GLib.MININT64,
12, 0xffffffffffffffff,
13, 254,
- 14, _bytes('a'))
+ 14, b'a')
parent = tree_store.append(parent)
i = 98
@@ -845,11 +1515,11 @@ class TestTreeModel(unittest.TestCase):
7: i % 2,
8: bool(i % 2),
9: i,
- 10: GObject.G_MAXULONG,
- 11: GObject.G_MININT64,
+ 10: GLib.MAXULONG,
+ 11: GLib.MININT64,
12: 0xffffffffffffffff,
13: 254,
- 14: _bytes('a')})
+ 14: b'a'})
parent = tree_store.append(parent)
i = 99
@@ -866,11 +1536,11 @@ class TestTreeModel(unittest.TestCase):
i % 2,
bool(i % 2),
i,
- GObject.G_MAXULONG,
- GObject.G_MININT64,
+ GLib.MAXULONG,
+ GLib.MININT64,
0xffffffffffffffff,
254,
- _bytes('a')))
+ b'a'))
# len gets the number of children in the root node
# since we kept appending to the previous node
@@ -906,9 +1576,9 @@ class TestTreeModel(unittest.TestCase):
uint_ = tree_store.get_value(treeiter, 9)
self.assertEqual(uint_, i)
ulong_ = tree_store.get_value(treeiter, 10)
- self.assertEqual(ulong_, GObject.G_MAXULONG)
+ self.assertEqual(ulong_, GLib.MAXULONG)
int64_ = tree_store.get_value(treeiter, 11)
- self.assertEqual(int64_, GObject.G_MININT64)
+ self.assertEqual(int64_, GLib.MININT64)
uint64_ = tree_store.get_value(treeiter, 12)
self.assertEqual(uint64_, 0xffffffffffffffff)
uchar_ = tree_store.get_value(treeiter, 13)
@@ -958,6 +1628,12 @@ class TestTreeModel(unittest.TestCase):
tree_store.insert(None, 1)
self.assertEqual(signals, ['row-inserted'])
+ # One set one signal
+ signals.pop()
+ tree_iter = tree_store.append(None, (10, False))
+ tree_store.set(tree_iter, (0, 1), (20, True))
+ self.assertEqual(signals, ['row-inserted', 'row-changed'])
+
def test_list_store(self):
class TestPyObject(object):
pass
@@ -980,7 +1656,7 @@ class TestTreeModel(unittest.TestCase):
bool(i % 2)))
i = 93
- label = _unicode('this is row #93')
+ label = u'this is row #93'
treeiter = list_store.append()
list_store.set_value(treeiter, 0, i)
list_store.set_value(treeiter, 1, label)
@@ -1004,7 +1680,7 @@ class TestTreeModel(unittest.TestCase):
# test automatic unicode->str conversion
i = 94
- label = _unicode('this is row #94')
+ label = u'this is row #94'
treeiter = list_store.append((i,
label,
TestGtk.TestClass(self, i, label),
@@ -1215,6 +1891,269 @@ class TestTreeModel(unittest.TestCase):
list_store.insert(1)
self.assertEqual(signals, ['row-inserted'])
+ # One set one signal
+ signals.pop()
+ tree_iter = list_store.append((10, False))
+ list_store.set(tree_iter, (0, 1), (20, True))
+ self.assertEqual(signals, ['row-inserted', 'row-changed'])
+
+ def test_list_store_insert_before(self):
+ store = Gtk.ListStore(object)
+ signals = []
+
+ def on_row_inserted(store, tree_path, tree_iter, signal_list):
+ signal_list.append('row-inserted')
+
+ def on_row_changed(store, tree_path, tree_iter, signal_list):
+ signal_list.append('row-changed')
+
+ store.connect('row-inserted', on_row_inserted, signals)
+ store.connect('row-changed', on_row_changed, signals)
+
+ iter_ = store.append([0])
+ assert store.get_value(iter_, 0) == 0
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # append empty
+ iter_ = store.insert_before(None)
+ assert store.get_path(iter_).get_indices() == [1]
+ assert store.get_value(iter_, 0) is None
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # insert empty
+ iter_ = store.insert_before(iter_)
+ assert store.get_path(iter_).get_indices() == [1]
+ assert store.get_value(iter_, 0) is None
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # append non-empty
+ iter_ = store.insert_before(None, [1234])
+ assert store.get_path(iter_).get_indices() == [3]
+ assert store.get_value(iter_, 0) == 1234
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # insert non-empty
+ iter_ = store.insert_before(iter_, [4321])
+ assert store.get_path(iter_).get_indices() == [3]
+ assert store.get_value(iter_, 0) == 4321
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ assert [r[0] for r in store] == [0, None, None, 4321, 1234]
+
+ def test_list_store_insert_after(self):
+ store = Gtk.ListStore(object)
+ signals = []
+
+ def on_row_inserted(store, tree_path, tree_iter, signal_list):
+ signal_list.append('row-inserted')
+
+ def on_row_changed(store, tree_path, tree_iter, signal_list):
+ signal_list.append('row-changed')
+
+ store.connect('row-inserted', on_row_inserted, signals)
+ store.connect('row-changed', on_row_changed, signals)
+
+ iter_ = store.append([0])
+ assert store.get_value(iter_, 0) == 0
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # prepend empty
+ iter_ = store.insert_after(None)
+ assert store.get_path(iter_).get_indices() == [0]
+ assert store.get_value(iter_, 0) is None
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # insert empty
+ iter_ = store.insert_after(iter_)
+ assert store.get_path(iter_).get_indices() == [1]
+ assert store.get_value(iter_, 0) is None
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # prepend non-empty
+ iter_ = store.insert_after(None, [1234])
+ assert store.get_path(iter_).get_indices() == [0]
+ assert store.get_value(iter_, 0) == 1234
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # insert non-empty
+ iter_ = store.insert_after(iter_, [4321])
+ assert store.get_path(iter_).get_indices() == [1]
+ assert store.get_value(iter_, 0) == 4321
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ assert [r[0] for r in store] == [1234, 4321, None, None, 0]
+
+ def test_tree_store_insert_before(self):
+ store = Gtk.TreeStore(object)
+ signals = []
+
+ def on_row_inserted(store, tree_path, tree_iter, signal_list):
+ signal_list.append('row-inserted')
+
+ def on_row_changed(store, tree_path, tree_iter, signal_list):
+ signal_list.append('row-changed')
+
+ store.connect('row-inserted', on_row_inserted, signals)
+ store.connect('row-changed', on_row_changed, signals)
+
+ parent = store.append(None, [-1])
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ iter_ = store.append(parent, [0])
+ assert store.get_path(iter_).get_indices() == [0, 0]
+ assert store.get_value(iter_, 0) == 0
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # append empty
+ iter_ = store.insert_before(parent, None)
+ assert store.get_path(iter_).get_indices() == [0, 1]
+ assert store.get_value(iter_, 0) is None
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # insert empty
+ iter_ = store.insert_before(parent, iter_)
+ assert store.get_path(iter_).get_indices() == [0, 1]
+ assert store.get_value(iter_, 0) is None
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # append non-empty
+ iter_ = store.insert_before(parent, None, [1234])
+ assert store.get_path(iter_).get_indices() == [0, 3]
+ assert store.get_value(iter_, 0) == 1234
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # insert non-empty
+ iter_ = store.insert_before(parent, iter_, [4321])
+ assert store.get_path(iter_).get_indices() == [0, 3]
+ assert store.get_value(iter_, 0) == 4321
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ def func(model, path, iter_, rows):
+ rows.append((path.get_indices(), model[iter_][:]))
+
+ rows = []
+ store.foreach(func, rows)
+ assert rows == [
+ ([0], [-1]), ([0, 0], [0]), ([0, 1], [None]), ([0, 2], [None]),
+ ([0, 3], [4321]), ([0, 4], [1234])]
+
+ def test_tree_store_insert_before_none(self):
+ store = Gtk.TreeStore(object)
+ root = store.append(None)
+ sub = store.append(root)
+
+ iter_ = store.insert_before(None, None, [1])
+ assert store.get_path(iter_).get_indices() == [1]
+
+ iter_ = store.insert_before(root, None, [1])
+ assert store.get_path(iter_).get_indices() == [0, 1]
+
+ iter_ = store.insert_before(sub, None, [1])
+ assert store.get_path(iter_).get_indices() == [0, 0, 0]
+
+ iter_ = store.insert_before(None, root, [1])
+ assert store.get_path(iter_).get_indices() == [0]
+
+ iter_ = store.insert_before(None, sub, [1])
+ assert store.get_path(iter_).get_indices() == [1, 0]
+
+ def test_tree_store_insert_after(self):
+ store = Gtk.TreeStore(object)
+ signals = []
+
+ def on_row_inserted(store, tree_path, tree_iter, signal_list):
+ signal_list.append('row-inserted')
+
+ def on_row_changed(store, tree_path, tree_iter, signal_list):
+ signal_list.append('row-changed')
+
+ store.connect('row-inserted', on_row_inserted, signals)
+ store.connect('row-changed', on_row_changed, signals)
+
+ parent = store.append(None, [-1])
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ iter_ = store.append(parent, [0])
+ assert store.get_path(iter_).get_indices() == [0, 0]
+ assert store.get_value(iter_, 0) == 0
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # append empty
+ iter_ = store.insert_after(parent, None)
+ assert store.get_path(iter_).get_indices() == [0, 0]
+ assert store.get_value(iter_, 0) is None
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # insert empty
+ iter_ = store.insert_after(parent, iter_)
+ assert store.get_path(iter_).get_indices() == [0, 1]
+ assert store.get_value(iter_, 0) is None
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # append non-empty
+ iter_ = store.insert_after(parent, None, [1234])
+ assert store.get_path(iter_).get_indices() == [0, 0]
+ assert store.get_value(iter_, 0) == 1234
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ # insert non-empty
+ iter_ = store.insert_after(parent, iter_, [4321])
+ assert store.get_path(iter_).get_indices() == [0, 1]
+ assert store.get_value(iter_, 0) == 4321
+ assert signals == ['row-inserted']
+ del signals[:]
+
+ def func(model, path, iter_, rows):
+ rows.append((path.get_indices(), model[iter_][:]))
+
+ rows = []
+ store.foreach(func, rows)
+
+ assert rows == [
+ ([0], [-1]), ([0, 0], [1234]), ([0, 1], [4321]),
+ ([0, 2], [None]), ([0, 3], [None]), ([0, 4], [0])]
+
+ def test_tree_store_insert_after_none(self):
+ store = Gtk.TreeStore(object)
+ root = store.append(None)
+ sub = store.append(root)
+
+ iter_ = store.insert_after(None, None, [1])
+ assert store.get_path(iter_).get_indices() == [0]
+
+ iter_ = store.insert_after(root, None, [1])
+ assert store.get_path(iter_).get_indices() == [1, 0]
+
+ iter_ = store.insert_after(sub, None, [1])
+ assert store.get_path(iter_).get_indices() == [1, 1, 0]
+
+ iter_ = store.insert_after(None, root, [1])
+ assert store.get_path(iter_).get_indices() == [2]
+
+ iter_ = store.insert_after(None, sub, [1])
+ assert store.get_path(iter_).get_indices() == [1, 2]
+
def test_tree_path(self):
p1 = Gtk.TreePath()
p2 = Gtk.TreePath.new_first()
@@ -1248,6 +2187,10 @@ class TestTreeModel(unittest.TestCase):
self.assertEqual(p1[2], 3)
self.assertRaises(IndexError, p1.__getitem__, 3)
+ def test_tree_path_empty(self):
+ p1 = Gtk.TreePath.new()
+ assert str(p1) == ""
+
def test_tree_model(self):
tree_store = Gtk.TreeStore(int, str)
@@ -1487,6 +2430,52 @@ class TestTreeModel(unittest.TestCase):
self.assertRaises(TypeError, set_row3)
+ def test_tree_row_sequence(self):
+ model = Gtk.ListStore(int, str, float)
+ model.append([1, "one", -0.1])
+
+ self.assertEqual([1, "one", -0.1], model[0][0, 1, 2])
+ self.assertEqual([1, "one"], model[0][0, 1])
+ self.assertEqual(["one", -0.1], model[0][1, 2])
+ self.assertEqual("one", model[0][1])
+ self.assertEqual([1, -0.1], model[0][0, 2])
+ self.assertEqual([-0.1, 1], model[0][2, 0])
+
+ model[0][0, 1, 2] = (2, "two", -0.2)
+ self.assertEqual([2, "two", -0.2], model[0][0, 1, 2])
+
+ model[0][0, 1] = (3, "three")
+ self.assertEqual([3, "three"], model[0][0, 1])
+
+ model[0][1, 2] = ("four", -0.4)
+ self.assertEqual(["four", -0.4], model[0][1, 2])
+
+ model[0][0, 2] = (5, -0.5)
+ self.assertEqual([5, -0.5], model[0][0, 2])
+
+ model[0][0, 1, 2] = (6, "six", -0.6)
+ self.assertEqual([-0.6, 6, "six"], model[0][2, 0, 1])
+
+ def set_row1():
+ model[0][4, 5] = ("shouldn't", "work",)
+
+ self.assertRaises(IndexError, set_row1)
+
+ def set_row2():
+ model[0][0, 1] = (0, "zero", 0)
+
+ self.assertRaises(ValueError, set_row2)
+
+ def set_row3():
+ model[0][0, 1] = ("shouldn't", 0)
+
+ self.assertRaises(TypeError, set_row3)
+
+ def set_row4():
+ model[0][0, "two"] = (0, "zero")
+
+ self.assertRaises(TypeError, set_row4)
+
def test_tree_model_set_value_to_none(self):
# Tests allowing the usage of None to set an empty value on a model.
store = Gtk.ListStore(str)
@@ -1533,19 +2522,118 @@ class TestTreeModel(unittest.TestCase):
filtered[0][1] = 'ONE'
self.assertEqual(filtered[0][1], 'ONE')
+ def foo(store, iter_, data):
+ assert data is None
+ return False
+
+ filtered.set_visible_func(foo)
+ filtered.refilter()
+ assert len(filtered) == 0
+
def test_list_store_performance(self):
model = Gtk.ListStore(int, str)
iterations = 2000
- start = time.clock()
+ start = timeit.default_timer()
i = iterations
while i > 0:
model.append([1, 'hello'])
i -= 1
- end = time.clock()
+ end = timeit.default_timer()
sys.stderr.write('[%.0f µs/append] ' % ((end - start) * 1000000 / iterations))
-
+ def test_filter_new_default(self):
+ # Test filter_new accepts implicit default of None
+ model = Gtk.ListStore(int)
+ filt = model.filter_new()
+ self.assertTrue(filt is not None)
+
+ def test_tree_store_set(self):
+ tree_store = Gtk.TreeStore(int, int)
+ iter_ = tree_store.append(None)
+ tree_store.set(iter_)
+ assert tree_store.get_value(iter_, 0) == 0
+ tree_store.set(iter_, 0, 42)
+ assert tree_store.get_value(iter_, 0) == 42
+ assert tree_store.get_value(iter_, 1) == 0
+ tree_store.set(iter_, 0, 42, 1, 24)
+ assert tree_store.get_value(iter_, 1) == 24
+ tree_store.set(iter_, 1, 124)
+ assert tree_store.get_value(iter_, 1) == 124
+
+ with pytest.raises(TypeError):
+ tree_store.set(iter_, 0, 42, "foo", 24)
+ with pytest.raises(TypeError):
+ tree_store.set(iter_, "foo")
+ with pytest.raises(TypeError):
+ tree_store.set(iter_, [1, 2, 3])
+ with pytest.raises(TypeError):
+ tree_store.set(iter_, 0, 42, 24)
+
+ def test_list_store_set(self):
+ list_store = Gtk.ListStore(int, int)
+ iter_ = list_store.append()
+ list_store.set(iter_)
+ assert list_store.get_value(iter_, 0) == 0
+ list_store.set(iter_, 0, 42)
+ assert list_store.get_value(iter_, 0) == 42
+ assert list_store.get_value(iter_, 1) == 0
+ list_store.set(iter_, 0, 42, 1, 24)
+ assert list_store.get_value(iter_, 1) == 24
+ list_store.set(iter_, 1, 124)
+ assert list_store.get_value(iter_, 1) == 124
+
+ with pytest.raises(TypeError):
+ list_store.set(iter_, 0, 42, "foo", 24)
+ with pytest.raises(TypeError):
+ list_store.set(iter_, "foo")
+ with pytest.raises(TypeError):
+ list_store.set(iter_, [1, 2, 3])
+ with pytest.raises(TypeError):
+ list_store.set(iter_, 0, 42, 24)
+
+ def test_set_default_sort_func(self):
+ list_store = Gtk.ListStore(int)
+ list_store.append([2])
+ list_store.append([1])
+
+ def sort_func(store, iter1, iter2, data):
+ assert data is None
+ cmp = lambda a, b: (a > b) - (a < b)
+ return cmp(store[iter1][0], store[iter2][0])
+
+ list_store.set_default_sort_func(sort_func)
+ list_store.set_sort_column_id(
+ Gtk.TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, Gtk.SortType.ASCENDING)
+ assert [v[0] for v in list_store] == [1, 2]
+
+ def test_model_rows_reordered(self):
+ list_store = Gtk.ListStore(int)
+ list_store.append([2])
+ list_store.append([1])
+ list_store.rows_reordered(Gtk.TreePath.new_first(), None, [0, 1])
+ list_store.rows_reordered(0, None, [0, 1])
+
+ def test_model_set_row(self):
+ list_store = Gtk.ListStore(int, int)
+ list_store.append([1, 2])
+ iter_ = list_store.get_iter_first()
+ list_store.set_row(iter_, [3, 4])
+ assert list_store[0][:] == [3, 4]
+ list_store.set_row(iter_, [None, 7])
+ assert list_store[0][:] == [3, 7]
+ list_store.set_row(iter_, [None, GObject.Value(int, 9)])
+ assert list_store[0][:] == [3, 9]
+
+ def test_model_set_row_skip_on_none(self):
+ list_store = Gtk.ListStore(int, int, int, int)
+ list_store.append([1, 2, 3, 4])
+ iter_ = list_store.get_iter_first()
+ list_store.set_row(iter_, [None, 7, None, 9])
+ assert list_store[0][:] == [1, 7, 3, 9]
+
+
+@unittest.skipIf(sys.platform == "darwin", "hangs")
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestTreeView(unittest.TestCase):
def test_tree_view(self):
@@ -1563,10 +2651,13 @@ class TestTreeView(unittest.TestCase):
def test_tree_view_column(self):
cell = Gtk.CellRendererText()
- Gtk.TreeViewColumn(title='This is just a test',
- cell_renderer=cell,
- text=0,
- style=2)
+ col = Gtk.TreeViewColumn(title='This is just a test',
+ cell_renderer=cell,
+ text=0,
+ style=2)
+
+ # Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=711173
+ col.set_cell_data_func(cell, None, None)
def test_tree_view_add_column_with_attributes(self):
model = Gtk.ListStore(str, str, str)
@@ -1575,7 +2666,7 @@ class TestTreeView(unittest.TestCase):
model.append(['cell13', 'cell11', 'cell12'])
model.append(['cell23', 'cell21', 'cell22'])
- tree = Gtk.TreeView(model)
+ tree = Gtk.TreeView(model=model)
cell1 = Gtk.CellRendererText()
cell2 = Gtk.CellRendererText()
cell3 = Gtk.CellRendererText()
@@ -1589,8 +2680,13 @@ class TestTreeView(unittest.TestCase):
with realized(tree):
tree.set_cursor(model[0].path)
- while Gtk.events_pending():
- Gtk.main_iteration()
+ if Gtk._version == "4.0":
+ context = GLib.MainContext()
+ while context.pending():
+ context.iteration(False)
+ else:
+ while Gtk.events_pending():
+ Gtk.main_iteration()
self.assertEqual(tree.get_column(0).get_title(), 'Head1')
self.assertEqual(tree.get_column(1).get_title(), 'Head2')
@@ -1598,10 +2694,12 @@ class TestTreeView(unittest.TestCase):
self.assertEqual(tree.get_column(3).get_title(), 'Head4')
# cursor should be at the first row
- self.assertEqual(cell1.props.text, 'cell11')
- self.assertEqual(cell2.props.text, 'cell12')
- self.assertEqual(cell3.props.text, 'cell13')
- self.assertEqual(cell4.props.text, None)
+ if not GTK4:
+ # not sure why this doesn't work with gtk4
+ self.assertEqual(cell1.props.text, 'cell11')
+ self.assertEqual(cell2.props.text, 'cell12')
+ self.assertEqual(cell3.props.text, 'cell13')
+ self.assertEqual(cell4.props.text, None)
def test_tree_view_column_set_attributes(self):
store = Gtk.ListStore(int, str)
@@ -1620,7 +2718,9 @@ class TestTreeView(unittest.TestCase):
column.set_attributes(cell, text=1)
with realized(treeview):
- self.assertTrue(cell.props.text in directors)
+ if not GTK4:
+ # not sure why this doesn't work with gtk4
+ self.assertTrue(cell.props.text in directors)
def test_tree_selection(self):
store = Gtk.ListStore(int, str)
@@ -1651,12 +2751,31 @@ class TestTreeView(unittest.TestCase):
self.assertEqual(m, store)
self.assertEqual(store.get_path(s), firstpath)
+ sel.unselect_all()
+ (m, s) = sel.get_selected()
+ assert s is None
+
+ sel.select_path(0)
+ m, r = sel.get_selected_rows()
+ assert m == store
+ assert len(r) == 1
+ assert r[0] == store[0].path
+
+ def test_scroll_to_cell(self):
+ store = Gtk.ListStore(int, str)
+ store.append((0, "foo"))
+ view = Gtk.TreeView()
+ view.set_model(store)
+ view.scroll_to_cell(store[0].path)
+ view.scroll_to_cell(0)
+
@unittest.skipUnless(Gtk, 'Gtk not available')
class TestTextBuffer(unittest.TestCase):
def test_text_buffer(self):
self.assertEqual(Gtk.TextBuffer, gi.overrides.Gtk.TextBuffer)
buffer = Gtk.TextBuffer()
+ assert buffer.get_tag_table() is not None
tag = buffer.create_tag('title', font='Sans 18')
self.assertEqual(tag.props.name, 'title')
@@ -1697,21 +2816,52 @@ class TestTextBuffer(unittest.TestCase):
self.assertTrue(sel[1].equal(end))
buffer.set_text('')
+ buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello')
+ start, end = buffer.get_bounds()
+ text = buffer.get_text(start, end, False)
+ self.assertEqual(text, 'HelloHello')
+
+ buffer.set_text('')
+ buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello')
+ start, end = buffer.get_bounds()
+ text = buffer.get_text(start, end, False)
+ self.assertEqual(text, 'HelloHello')
+
+ try:
+ starts_tag = Gtk.TextIter.starts_tag
+ except AttributeError:
+ starts_tag = Gtk.TextIter.begins_tag
+
+ buffer.set_text('')
buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello', tag)
(start, end) = buffer.get_bounds()
- self.assertTrue(start.begins_tag(tag))
+ self.assertTrue(starts_tag(start, tag))
self.assertTrue(start.has_tag(tag))
buffer.set_text('')
buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello', 'title')
(start, end) = buffer.get_bounds()
- self.assertTrue(start.begins_tag(tag))
+ self.assertTrue(starts_tag(start, tag))
self.assertTrue(start.has_tag(tag))
self.assertRaises(ValueError, buffer.insert_with_tags_by_name,
buffer.get_start_iter(), 'HelloHello', 'unknowntag')
+ def test_insert(self):
+ buffer = Gtk.TextBuffer()
+ start = buffer.get_bounds()[0]
+ with pytest.raises(TypeError):
+ buffer.insert(start, 42)
+
+ with pytest.raises(TypeError):
+ buffer.insert_at_cursor(42)
+
def test_text_iter(self):
+ try:
+ starts_tag = Gtk.TextIter.starts_tag
+ except AttributeError:
+ starts_tag = Gtk.TextIter.begins_tag
+
self.assertEqual(Gtk.TextIter, gi.overrides.Gtk.TextIter)
buffer = Gtk.TextBuffer()
buffer.set_text('Hello Jane Hello Bob')
@@ -1719,12 +2869,12 @@ class TestTextBuffer(unittest.TestCase):
(start, end) = buffer.get_bounds()
start.forward_chars(10)
buffer.apply_tag(tag, start, end)
- self.assertTrue(start.begins_tag())
+ self.assertTrue(starts_tag(start))
self.assertTrue(end.ends_tag())
self.assertTrue(start.toggles_tag())
self.assertTrue(end.toggles_tag())
start.backward_chars(1)
- self.assertFalse(start.begins_tag())
+ self.assertFalse(starts_tag(start))
self.assertFalse(start.ends_tag())
self.assertFalse(start.toggles_tag())
@@ -1746,3 +2896,146 @@ class TestTextBuffer(unittest.TestCase):
None)
self.assertEqual(start.get_offset(), 6)
self.assertEqual(end.get_offset(), 11)
+
+ def test_insert_text_signal_location_modification(self):
+ # Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=736175
+
+ def callback(buffer, location, text, length):
+ location.assign(buffer.get_end_iter())
+
+ buffer = Gtk.TextBuffer()
+ buffer.set_text('first line\n')
+ buffer.connect('insert-text', callback)
+
+ # attempt insertion at the beginning of the buffer, the callback will
+ # modify the insert location to the end.
+ buffer.place_cursor(buffer.get_start_iter())
+ buffer.insert_at_cursor('second line\n')
+
+ self.assertEqual(buffer.get_property('text'),
+ 'first line\nsecond line\n')
+
+ @unittest.skipIf(gtkver() < (3, 20, 0), "broken with older gtk")
+ def test_backward_find_char(self):
+ buffer = Gtk.TextBuffer()
+ buffer.set_text('abc')
+ res = buffer.get_iter_at_line(99)
+ if GTK4:
+ end = res.iter
+ else:
+ end = res
+
+ values = []
+
+ def pred_func(ch, user_data):
+ values.append(ch)
+ return ch == u"a"
+
+ self.assertTrue(end.backward_find_char(pred_func))
+ self.assertEqual(values, [u"c", u"b", u"a"])
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+@unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+class TestPaned(unittest.TestCase):
+
+ def test_pack_defaults(self):
+ p = Gtk.Paned()
+ l1 = Gtk.Label()
+ l2 = Gtk.Label()
+ p.pack1(l1)
+ p.pack2(l2)
+ assert p.get_children() == [l1, l2]
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestContainer(unittest.TestCase):
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_child_set_property(self):
+ box = Gtk.Box()
+ child = Gtk.Button()
+ box.pack_start(child, expand=False, fill=True, padding=0)
+
+ box.child_set_property(child, 'padding', 42)
+
+ value = GObject.Value(int)
+ box.child_get_property(child, 'padding', value)
+ self.assertEqual(value.get_int(), 42)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_child_get_property_gvalue(self):
+ box = Gtk.Box()
+ child = Gtk.Button()
+ box.pack_start(child, expand=False, fill=True, padding=42)
+
+ value = GObject.Value(int)
+ box.child_get_property(child, 'padding', value)
+ self.assertEqual(value.get_int(), 42)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_child_get_property_return_with_explicit_gvalue(self):
+ box = Gtk.Box()
+ child = Gtk.Button()
+ box.pack_start(child, expand=False, fill=True, padding=42)
+
+ value = GObject.Value(int)
+ result = box.child_get_property(child, 'padding', value)
+ self.assertEqual(result, 42)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_child_get_property_return_with_implicit_gvalue(self):
+ box = Gtk.Box()
+ child = Gtk.Button()
+ box.pack_start(child, expand=False, fill=True, padding=42)
+
+ result = box.child_get_property(child, 'padding')
+ self.assertEqual(result, 42)
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_child_get_property_error(self):
+ box = Gtk.Box()
+ child = Gtk.Button()
+ if Gtk_version == "4.0":
+ box.add(child)
+ else:
+ box.pack_start(child, expand=False, fill=True, padding=42)
+ with self.assertRaises(ValueError):
+ box.child_get_property(child, 'not-a-valid-child-property')
+
+ @unittest.skipIf(Gtk_version == "4.0", "not in gtk4")
+ def test_child_get_and_set(self):
+ box = Gtk.Box()
+ child = Gtk.Button()
+ box.pack_start(child, expand=True, fill=True, padding=42)
+
+ expand, fill, padding = box.child_get(child, 'expand', 'fill', 'padding')
+ self.assertEqual(expand, True)
+ self.assertEqual(fill, True)
+ self.assertEqual(padding, 42)
+
+ box.child_set(child, expand=False, fill=False, padding=21, pack_type=1)
+ expand, fill, padding, pack_type = box.child_get(child, 'expand', 'fill', 'padding', 'pack-type')
+ self.assertEqual(expand, False)
+ self.assertEqual(fill, False)
+ self.assertEqual(padding, 21)
+
+
+def test_button_focus_on_click():
+ b = Gtk.Button()
+ b.set_focus_on_click(True)
+ assert b.get_focus_on_click()
+ b.set_focus_on_click(False)
+ assert not b.get_focus_on_click()
+
+
+@pytest.mark.parametrize(
+ "data",
+ [
+ "* { background: white; }",
+ "* { background: white; }".encode()
+ ]
+)
+def test_css_provider_load_from_data(data):
+ provider = Gtk.CssProvider.new()
+ provider.load_from_data(data)
diff --git a/tests/test_overrides_pango.py b/tests/test_overrides_pango.py
index 42d4de9..2ec4cb1 100644
--- a/tests/test_overrides_pango.py
+++ b/tests/test_overrides_pango.py
@@ -5,9 +5,10 @@ import unittest
try:
from gi.repository import Pango
- Pango
+ from gi.repository import PangoCairo
except ImportError:
Pango = None
+ PangoCairo = None
@unittest.skipUnless(Pango, 'Pango not available')
@@ -31,7 +32,36 @@ class TestPango(unittest.TestCase):
layout.set_markup("Foobar")
self.assertEqual(layout.get_text(), "Foobar")
+ def test_layout_set_markup(self):
+ context = Pango.Context()
+ layout = Pango.Layout(context)
+ layout.set_markup("abc")
+ assert layout.get_text() == "abc"
+ layout.set_markup("abc", -1)
+ assert layout.get_text() == "abc"
+ layout.set_markup("abc", 2)
+ assert layout.get_text() == "ab"
+
+ def test_layout_set_test(self):
+ context = Pango.Context()
+ layout = Pango.Layout(context)
+ layout.set_text("abc")
+ assert layout.get_text() == "abc"
+ layout.set_text("abc", -1)
+ assert layout.get_text() == "abc"
+ layout.set_text("abc", 2)
+ assert layout.get_text() == "ab"
+
def test_break_keyword_escape(self):
# https://bugzilla.gnome.org/show_bug.cgi?id=697363
self.assertTrue(hasattr(Pango, 'break_'))
self.assertTrue(Pango.break_ is not None)
+
+ def test_context_get_metrics(self):
+ # Test default "language" argument
+ font_map = PangoCairo.font_map_get_default()
+ context = font_map.create_context()
+ desc = Pango.FontDescription('monospace')
+ metrics1 = context.get_metrics(desc)
+ metrics2 = context.get_metrics(desc, context.get_language())
+ self.assertEqual(metrics1.get_ascent(), metrics2.get_ascent())
diff --git a/tests/test_properties.py b/tests/test_properties.py
index ef6b867..f8b7823 100644
--- a/tests/test_properties.py
+++ b/tests/test_properties.py
@@ -1,13 +1,15 @@
-# coding=utf-8
-
+import os
+import gc
import sys
import struct
import types
import unittest
+import tempfile
+
+import pytest
from gi.repository import GObject
-from gi.repository.GObject import GType, new, PARAM_READWRITE, \
- PARAM_CONSTRUCT, PARAM_READABLE, PARAM_WRITABLE, PARAM_CONSTRUCT_ONLY
+from gi.repository.GObject import ParamFlags, GType, new
from gi.repository.GObject import \
TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_INT64, \
TYPE_UINT64, TYPE_GTYPE, TYPE_INVALID, TYPE_NONE, TYPE_STRV, \
@@ -15,62 +17,66 @@ from gi.repository.GObject import \
TYPE_DOUBLE, TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, \
TYPE_STRING, TYPE_PYOBJECT, TYPE_VARIANT
-from gi.repository.GObject import \
- G_MININT, G_MAXINT, G_MAXUINT, G_MINLONG, G_MAXLONG, G_MAXULONG, \
- G_MAXUINT64, G_MAXINT64, G_MININT64
+from gi.repository.GLib import \
+ MININT, MAXINT, MAXUINT, MINLONG, MAXLONG, MAXULONG, \
+ MAXUINT64, MAXINT64, MININT64
from gi.repository import Gio
from gi.repository import GLib
-from gi.repository import Regress
from gi.repository import GIMarshallingTests
-from gi._gobject import propertyhelper
-
-if sys.version_info < (3, 0):
- TEST_UTF8 = "\xe2\x99\xa5"
- UNICODE_UTF8 = unicode(TEST_UTF8, 'UTF-8')
-else:
- TEST_UTF8 = "♥"
- UNICODE_UTF8 = TEST_UTF8
+from gi.repository import Regress
+from gi import _propertyhelper as propertyhelper
-from compathelper import _long
+from .helper import capture_glib_warnings
class PropertyObject(GObject.GObject):
normal = GObject.Property(type=str)
construct = GObject.Property(
type=str,
- flags=PARAM_READWRITE | PARAM_CONSTRUCT, default='default')
+ flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT,
+ default='default')
+
construct_only = GObject.Property(
type=str,
- flags=PARAM_READWRITE | PARAM_CONSTRUCT_ONLY)
+ flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT_ONLY)
+
uint64 = GObject.Property(
- type=TYPE_UINT64, flags=PARAM_READWRITE | PARAM_CONSTRUCT)
+ type=TYPE_UINT64,
+ flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
enum = GObject.Property(
type=Gio.SocketType, default=Gio.SocketType.STREAM)
boxed = GObject.Property(
- type=GLib.Regex, flags=PARAM_READWRITE | PARAM_CONSTRUCT)
+ type=GLib.Regex,
+ flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
flags = GObject.Property(
- type=GIMarshallingTests.Flags, flags=PARAM_READWRITE | PARAM_CONSTRUCT,
+ type=GIMarshallingTests.Flags,
+ flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT,
default=GIMarshallingTests.Flags.VALUE1)
gtype = GObject.Property(
- type=TYPE_GTYPE, flags=PARAM_READWRITE | PARAM_CONSTRUCT)
+ type=TYPE_GTYPE,
+ flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
strings = GObject.Property(
- type=TYPE_STRV, flags=PARAM_READWRITE | PARAM_CONSTRUCT)
+ type=TYPE_STRV,
+ flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
variant = GObject.Property(
- type=TYPE_VARIANT, flags=PARAM_READWRITE | PARAM_CONSTRUCT)
+ type=TYPE_VARIANT,
+ flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
variant_def = GObject.Property(
- type=TYPE_VARIANT, flags=PARAM_READWRITE | PARAM_CONSTRUCT,
+ type=TYPE_VARIANT,
+ flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT,
default=GLib.Variant('i', 42))
interface = GObject.Property(
- type=Gio.File, flags=PARAM_READWRITE | PARAM_CONSTRUCT)
+ type=Gio.File,
+ flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT)
class PropertyInheritanceObject(Regress.TestObj):
@@ -160,12 +166,19 @@ class TestPropertyObject(unittest.TestCase):
self.assertEqual(obj.props.construct, "789")
def test_utf8(self):
- obj = new(PropertyObject, construct_only=UNICODE_UTF8)
- self.assertEqual(obj.props.construct_only, TEST_UTF8)
- obj.set_property('construct', UNICODE_UTF8)
- self.assertEqual(obj.props.construct, TEST_UTF8)
- obj.props.normal = UNICODE_UTF8
- self.assertEqual(obj.props.normal, TEST_UTF8)
+ test_utf8 = "♥"
+ unicode_utf8 = u"♥"
+ obj = new(PropertyObject, construct_only=unicode_utf8)
+ self.assertEqual(obj.props.construct_only, test_utf8)
+ obj.set_property('construct', unicode_utf8)
+ self.assertEqual(obj.props.construct, test_utf8)
+ obj.props.normal = unicode_utf8
+ self.assertEqual(obj.props.normal, test_utf8)
+
+ def test_utf8_lone_surrogate(self):
+ obj = PropertyObject()
+ with pytest.raises(TypeError):
+ obj.set_property('construct', '\ud83d')
def test_int_to_str(self):
obj = new(PropertyObject, construct_only=1)
@@ -186,12 +199,12 @@ class TestPropertyObject(unittest.TestCase):
def test_uint64(self):
obj = new(PropertyObject)
self.assertEqual(obj.props.uint64, 0)
- obj.props.uint64 = _long(1)
- self.assertEqual(obj.props.uint64, _long(1))
obj.props.uint64 = 1
- self.assertEqual(obj.props.uint64, _long(1))
+ self.assertEqual(obj.props.uint64, 1)
+ obj.props.uint64 = 1
+ self.assertEqual(obj.props.uint64, 1)
- self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", _long(-1))
+ self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", -1)
self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", -1)
def test_uint64_default_value(self):
@@ -199,8 +212,8 @@ class TestPropertyObject(unittest.TestCase):
class TimeControl(GObject.GObject):
__gproperties__ = {
'time': (TYPE_UINT64, 'Time', 'Time',
- _long(0), (1 << 64) - 1, _long(0),
- PARAM_READABLE)
+ 0, (1 << 64) - 1, 0,
+ ParamFlags.READABLE)
}
except OverflowError:
(etype, ex) = sys.exc_info()[2:]
@@ -234,6 +247,10 @@ class TestPropertyObject(unittest.TestCase):
self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType,
default=1)
+ def test_repr(self):
+ prop = GObject.Property(type=int)
+ assert repr(prop) == "<GObject Property (uninitialized) (gint)>"
+
def test_flags(self):
obj = new(PropertyObject)
self.assertEqual(obj.props.flags, GIMarshallingTests.Flags.VALUE1)
@@ -396,10 +413,11 @@ class TestPropertyObject(unittest.TestCase):
def test_interface(self):
obj = new(PropertyObject)
- file = Gio.File.new_for_path('/some/path')
+ path = os.path.join(tempfile.gettempdir(), "some", "path")
+ file = Gio.File.new_for_path(path)
obj.props.interface = file
- self.assertEqual(obj.props.interface.get_path(), '/some/path')
- self.assertEqual(obj.interface.get_path(), '/some/path')
+ self.assertEqual(obj.props.interface.get_path(), path)
+ self.assertEqual(obj.interface.get_path(), path)
self.assertRaises(TypeError, setattr, obj, 'interface', 'foo')
self.assertRaises(TypeError, setattr, obj, 'interface', object())
@@ -433,7 +451,7 @@ class TestPropertyObject(unittest.TestCase):
d = {}
for key, (gtype, min, max) in types_.items():
d[key] = (gtype, 'blurb', 'desc', min, max, 0,
- PARAM_READABLE | PARAM_WRITABLE)
+ ParamFlags.READABLE | ParamFlags.WRITABLE)
return d
class RangeCheck(GObject.GObject):
@@ -486,9 +504,9 @@ class TestProperty(unittest.TestCase):
def test_simple(self):
class C(GObject.GObject):
str = GObject.Property(type=str)
- int = GObject.Property(type=int)
float = GObject.Property(type=float)
- long = GObject.Property(type=_long)
+ long = GObject.Property(type=int)
+ int = GObject.Property(type=int)
self.assertTrue(hasattr(C.props, 'str'))
self.assertTrue(hasattr(C.props, 'int'))
@@ -508,9 +526,9 @@ class TestProperty(unittest.TestCase):
o.float = 3.14
self.assertEqual(o.float, 3.14)
- self.assertEqual(o.long, _long(0))
- o.long = _long(100)
- self.assertEqual(o.long, _long(100))
+ self.assertEqual(o.long, 0)
+ o.long = 100
+ self.assertEqual(o.long, 100)
def test_custom_getter(self):
class C(GObject.GObject):
@@ -522,6 +540,23 @@ class TestProperty(unittest.TestCase):
self.assertEqual(o.prop, 'value')
self.assertRaises(TypeError, setattr, o, 'prop', 'xxx')
+ def test_getter_exception(self):
+ class C(GObject.Object):
+ @GObject.Property(type=int)
+ def prop(self):
+ raise ValueError('something bad happend')
+
+ o = C()
+
+ with self.assertRaisesRegex(ValueError, 'something bad happend'):
+ o.prop
+
+ with self.assertRaisesRegex(ValueError, 'something bad happend'):
+ o.get_property('prop')
+
+ with self.assertRaisesRegex(ValueError, 'something bad happend'):
+ o.props.prop
+
def test_custom_setter(self):
class C(GObject.GObject):
def set_prop(self, value):
@@ -618,12 +653,12 @@ class TestProperty(unittest.TestCase):
def test_range(self):
types_ = [
- (TYPE_INT, G_MININT, G_MAXINT),
- (TYPE_UINT, 0, G_MAXUINT),
- (TYPE_LONG, G_MINLONG, G_MAXLONG),
- (TYPE_ULONG, 0, G_MAXULONG),
- (TYPE_INT64, G_MININT64, G_MAXINT64),
- (TYPE_UINT64, 0, G_MAXUINT64),
+ (TYPE_INT, MININT, MAXINT),
+ (TYPE_UINT, 0, MAXUINT),
+ (TYPE_LONG, MINLONG, MAXLONG),
+ (TYPE_ULONG, 0, MAXULONG),
+ (TYPE_INT64, MININT64, MAXINT64),
+ (TYPE_UINT64, 0, MAXUINT64),
]
for gtype, min, max in types_:
@@ -653,8 +688,7 @@ class TestProperty(unittest.TestCase):
# we test known-bad values here which cause Gtk-WARNING logs.
# Explicitly allow these for this test.
- old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_CRITICAL)
- try:
+ with capture_glib_warnings(allow_warnings=True, allow_criticals=True):
o = C()
self.assertEqual(o.prop_int, 1)
@@ -677,8 +711,6 @@ class TestProperty(unittest.TestCase):
o.prop_float = 10.51
self.assertEqual(o.prop_float, 7.75)
- finally:
- GLib.log_set_always_fatal(old_mask)
def test_multiple_instances(self):
class C(GObject.GObject):
@@ -791,7 +823,7 @@ class TestProperty(unittest.TestCase):
GObject.Property(type=GObject.TYPE_DOUBLE, minimum=-1)
# Bug 644039
-
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount")
def test_reference_count(self):
# We can check directly if an object gets finalized, so we will
# observe it indirectly through the refcount of a member object.
@@ -831,8 +863,6 @@ class TestProperty(unittest.TestCase):
def test_python_to_glib_type_mapping(self):
tester = GObject.Property()
self.assertEqual(tester._type_from_python(int), GObject.TYPE_INT)
- if sys.version_info < (3, 0):
- self.assertEqual(tester._type_from_python(long), GObject.TYPE_LONG)
self.assertEqual(tester._type_from_python(bool), GObject.TYPE_BOOLEAN)
self.assertEqual(tester._type_from_python(float), GObject.TYPE_DOUBLE)
self.assertEqual(tester._type_from_python(str), GObject.TYPE_STRING)
@@ -918,5 +948,415 @@ class TestInstallProperties(unittest.TestCase):
self.assertRaises(ValueError, propertyhelper.install_properties,
self.ClassWithPropertyRedefined)
-if __name__ == '__main__':
- unittest.main()
+
+class CPropertiesTestBase(object):
+ # Tests for properties implemented in C not Python.
+
+ def setUp(self):
+ self.obj = GIMarshallingTests.PropertiesObject()
+
+ def get_prop(self, obj, name):
+ raise NotImplementedError
+
+ def set_prop(self, obj, name, value):
+ raise NotImplementedError
+
+ # https://bugzilla.gnome.org/show_bug.cgi?id=780652
+ @unittest.skipUnless(
+ "some_flags" in dir(GIMarshallingTests.PropertiesObject.props),
+ "tool old gi")
+ def test_flags(self):
+ self.assertEqual(
+ self.get_prop(self.obj, 'some-flags'),
+ GIMarshallingTests.Flags.VALUE1)
+ self.set_prop(self.obj, 'some-flags', GIMarshallingTests.Flags.VALUE2)
+ self.assertEqual(self.get_prop(self.obj, 'some-flags'),
+ GIMarshallingTests.Flags.VALUE2)
+
+ obj = GIMarshallingTests.PropertiesObject(
+ some_flags=GIMarshallingTests.Flags.VALUE3)
+ self.assertEqual(self.get_prop(obj, 'some-flags'),
+ GIMarshallingTests.Flags.VALUE3)
+
+ # https://bugzilla.gnome.org/show_bug.cgi?id=780652
+ @unittest.skipUnless(
+ "some_enum" in dir(GIMarshallingTests.PropertiesObject.props),
+ "tool old gi")
+ def test_enum(self):
+ self.assertEqual(
+ self.get_prop(self.obj, 'some-enum'),
+ GIMarshallingTests.GEnum.VALUE1)
+ self.set_prop(self.obj, 'some-enum', GIMarshallingTests.GEnum.VALUE2)
+ self.assertEqual(self.get_prop(self.obj, 'some-enum'),
+ GIMarshallingTests.GEnum.VALUE2)
+
+ obj = GIMarshallingTests.PropertiesObject(
+ some_enum=GIMarshallingTests.GEnum.VALUE3)
+ self.assertEqual(self.get_prop(obj, 'some-enum'),
+ GIMarshallingTests.GEnum.VALUE3)
+
+ def test_boolean(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-boolean'), False)
+ self.set_prop(self.obj, 'some-boolean', True)
+ self.assertEqual(self.get_prop(self.obj, 'some-boolean'), True)
+
+ obj = GIMarshallingTests.PropertiesObject(some_boolean=True)
+ self.assertEqual(self.get_prop(obj, 'some-boolean'), True)
+
+ def test_char(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-char'), 0)
+ self.set_prop(self.obj, 'some-char', GLib.MAXINT8)
+ self.assertEqual(self.get_prop(self.obj, 'some-char'), GLib.MAXINT8)
+
+ obj = GIMarshallingTests.PropertiesObject(some_char=-42)
+ self.assertEqual(self.get_prop(obj, 'some-char'), -42)
+
+ with pytest.raises(OverflowError):
+ self.set_prop(obj, 'some-char', GLib.MAXINT8 + 1)
+ with pytest.raises(OverflowError):
+ self.set_prop(obj, 'some-char', GLib.MININT8 - 1)
+
+ self.set_prop(obj, 'some-char', b"\x44")
+ assert self.get_prop(obj, 'some-char') == 0x44
+
+ self.set_prop(obj, 'some-char', b"\xff")
+ assert self.get_prop(obj, 'some-char') == -1
+
+ obj = GIMarshallingTests.PropertiesObject(some_char=u"\x7f")
+ assert self.get_prop(obj, 'some-char') == 0x7f
+
+ with pytest.raises(TypeError):
+ GIMarshallingTests.PropertiesObject(some_char=u"€")
+
+ with pytest.raises(TypeError):
+ GIMarshallingTests.PropertiesObject(some_char=u"\ud83d")
+
+ def test_uchar(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-uchar'), 0)
+ self.set_prop(self.obj, 'some-uchar', GLib.MAXUINT8)
+ self.assertEqual(self.get_prop(self.obj, 'some-uchar'), GLib.MAXUINT8)
+
+ obj = GIMarshallingTests.PropertiesObject(some_uchar=42)
+ self.assertEqual(self.get_prop(obj, 'some-uchar'), 42)
+
+ with pytest.raises(OverflowError):
+ self.set_prop(obj, 'some-uchar', GLib.MAXUINT8 + 1)
+ with pytest.raises(OverflowError):
+ self.set_prop(obj, 'some-uchar', -1)
+
+ self.set_prop(obj, 'some-uchar', b"\x57")
+ assert self.get_prop(obj, 'some-uchar') == 0x57
+
+ self.set_prop(obj, 'some-uchar', b"\xff")
+ assert self.get_prop(obj, 'some-uchar') == 255
+
+ obj = GIMarshallingTests.PropertiesObject(some_uchar=u"\x7f")
+ assert self.get_prop(obj, 'some-uchar') == 127
+
+ with pytest.raises(TypeError):
+ GIMarshallingTests.PropertiesObject(some_uchar=u"\x80")
+
+ with pytest.raises(TypeError):
+ GIMarshallingTests.PropertiesObject(some_uchar=u"\ud83d")
+
+ def test_int(self):
+ self.assertEqual(self.get_prop(self.obj, 'some_int'), 0)
+ self.set_prop(self.obj, 'some-int', GLib.MAXINT)
+ self.assertEqual(self.get_prop(self.obj, 'some_int'), GLib.MAXINT)
+
+ obj = GIMarshallingTests.PropertiesObject(some_int=-42)
+ self.assertEqual(self.get_prop(obj, 'some-int'), -42)
+
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-int', 'foo')
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-int', None)
+
+ self.assertEqual(self.get_prop(obj, 'some-int'), -42)
+
+ def test_uint(self):
+ self.assertEqual(self.get_prop(self.obj, 'some_uint'), 0)
+ self.set_prop(self.obj, 'some-uint', GLib.MAXUINT)
+ self.assertEqual(self.get_prop(self.obj, 'some_uint'), GLib.MAXUINT)
+
+ obj = GIMarshallingTests.PropertiesObject(some_uint=42)
+ self.assertEqual(self.get_prop(obj, 'some-uint'), 42)
+
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-uint', 'foo')
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-uint', None)
+
+ self.assertEqual(self.get_prop(obj, 'some-uint'), 42)
+
+ def test_long(self):
+ self.assertEqual(self.get_prop(self.obj, 'some_long'), 0)
+ self.set_prop(self.obj, 'some-long', GLib.MAXLONG)
+ self.assertEqual(self.get_prop(self.obj, 'some_long'), GLib.MAXLONG)
+
+ obj = GIMarshallingTests.PropertiesObject(some_long=-42)
+ self.assertEqual(self.get_prop(obj, 'some-long'), -42)
+
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-long', 'foo')
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-long', None)
+
+ self.assertEqual(self.get_prop(obj, 'some-long'), -42)
+
+ def test_ulong(self):
+ self.assertEqual(self.get_prop(self.obj, 'some_ulong'), 0)
+ self.set_prop(self.obj, 'some-ulong', GLib.MAXULONG)
+ self.assertEqual(self.get_prop(self.obj, 'some_ulong'), GLib.MAXULONG)
+
+ obj = GIMarshallingTests.PropertiesObject(some_ulong=42)
+ self.assertEqual(self.get_prop(obj, 'some-ulong'), 42)
+
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-ulong', 'foo')
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-ulong', None)
+
+ self.assertEqual(self.get_prop(obj, 'some-ulong'), 42)
+
+ def test_int64(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-int64'), 0)
+ self.set_prop(self.obj, 'some-int64', GLib.MAXINT64)
+ self.assertEqual(self.get_prop(self.obj, 'some-int64'), GLib.MAXINT64)
+
+ obj = GIMarshallingTests.PropertiesObject(some_int64=-4200000000000000)
+ self.assertEqual(self.get_prop(obj, 'some-int64'), -4200000000000000)
+
+ def test_uint64(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-uint64'), 0)
+ self.set_prop(self.obj, 'some-uint64', GLib.MAXUINT64)
+ self.assertEqual(self.get_prop(self.obj, 'some-uint64'), GLib.MAXUINT64)
+
+ obj = GIMarshallingTests.PropertiesObject(some_uint64=4200000000000000)
+ self.assertEqual(self.get_prop(obj, 'some-uint64'), 4200000000000000)
+
+ def test_float(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-float'), 0)
+ self.set_prop(self.obj, 'some-float', GLib.MAXFLOAT)
+ self.assertEqual(self.get_prop(self.obj, 'some-float'), GLib.MAXFLOAT)
+
+ obj = GIMarshallingTests.PropertiesObject(some_float=42.42)
+ self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.42, places=4)
+
+ obj = GIMarshallingTests.PropertiesObject(some_float=42)
+ self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.0, places=4)
+
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-float', 'foo')
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-float', None)
+
+ self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.0, places=4)
+
+ def test_double(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-double'), 0)
+ self.set_prop(self.obj, 'some-double', GLib.MAXDOUBLE)
+ self.assertEqual(self.get_prop(self.obj, 'some-double'), GLib.MAXDOUBLE)
+
+ obj = GIMarshallingTests.PropertiesObject(some_double=42.42)
+ self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.42)
+
+ obj = GIMarshallingTests.PropertiesObject(some_double=42)
+ self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.0)
+
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-double', 'foo')
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-double', None)
+
+ self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.0)
+
+ def test_strv(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-strv'), [])
+ self.set_prop(self.obj, 'some-strv', ['hello', 'world'])
+ self.assertEqual(self.get_prop(self.obj, 'some-strv'), ['hello', 'world'])
+
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', 1)
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', 'foo')
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', [1, 2])
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', ['foo', 1])
+
+ self.assertEqual(self.get_prop(self.obj, 'some-strv'), ['hello', 'world'])
+
+ obj = GIMarshallingTests.PropertiesObject(some_strv=['hello', 'world'])
+ self.assertEqual(self.get_prop(obj, 'some-strv'), ['hello', 'world'])
+
+ # unicode on py2
+ obj = GIMarshallingTests.PropertiesObject(some_strv=[u'foo'])
+ self.assertEqual(self.get_prop(obj, 'some-strv'), [u'foo'])
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv',
+ [u'foo', 1])
+
+ def test_boxed_struct(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-boxed-struct'), None)
+
+ class GStrv(list):
+ __gtype__ = GObject.TYPE_STRV
+
+ struct1 = GIMarshallingTests.BoxedStruct()
+ struct1.long_ = 1
+
+ self.set_prop(self.obj, 'some-boxed-struct', struct1)
+ self.assertEqual(self.get_prop(self.obj, 'some-boxed-struct').long_, 1)
+ self.assertEqual(self.obj.some_boxed_struct.long_, 1)
+
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-struct', 1)
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-struct', 'foo')
+
+ obj = GIMarshallingTests.PropertiesObject(some_boxed_struct=struct1)
+ self.assertEqual(self.get_prop(obj, 'some-boxed-struct').long_, 1)
+
+ def test_boxed_glist(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), [])
+
+ list_ = [GLib.MININT, 42, GLib.MAXINT]
+ self.set_prop(self.obj, 'some-boxed-glist', list_)
+ self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), list_)
+ self.set_prop(self.obj, 'some-boxed-glist', [])
+ self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), [])
+
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', 1)
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', 'foo')
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', ['a'])
+
+ def test_annotated_glist(self):
+ obj = Regress.TestObj()
+ self.assertEqual(self.get_prop(obj, 'list'), [])
+
+ self.set_prop(obj, 'list', ['1', '2', '3'])
+ self.assertTrue(isinstance(self.get_prop(obj, 'list'), list))
+ self.assertEqual(self.get_prop(obj, 'list'), ['1', '2', '3'])
+
+ @unittest.expectedFailure
+ def test_boxed_glist_ctor(self):
+ list_ = [GLib.MININT, 42, GLib.MAXINT]
+ obj = GIMarshallingTests.PropertiesObject(some_boxed_glist=list_)
+ self.assertEqual(self.get_prop(obj, 'some-boxed-glist'), list_)
+
+ def test_variant(self):
+ self.assertEqual(self.get_prop(self.obj, 'some-variant'), None)
+
+ self.set_prop(self.obj, 'some-variant', GLib.Variant('o', '/myobj'))
+ self.assertEqual(self.get_prop(self.obj, 'some-variant').get_type_string(), 'o')
+ self.assertEqual(self.get_prop(self.obj, 'some-variant').print_(False), "'/myobj'")
+
+ self.set_prop(self.obj, 'some-variant', None)
+ self.assertEqual(self.get_prop(self.obj, 'some-variant'), None)
+
+ obj = GIMarshallingTests.PropertiesObject(some_variant=GLib.Variant('b', True))
+ self.assertEqual(self.get_prop(obj, 'some-variant').get_type_string(), 'b')
+ self.assertEqual(self.get_prop(obj, 'some-variant').get_boolean(), True)
+
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-variant', 'foo')
+ self.assertRaises(TypeError, self.set_prop, self.obj, 'some-variant', 23)
+
+ self.assertEqual(self.get_prop(obj, 'some-variant').get_type_string(), 'b')
+ self.assertEqual(self.get_prop(obj, 'some-variant').get_boolean(), True)
+
+ def test_setting_several_properties(self):
+ obj = GIMarshallingTests.PropertiesObject()
+ obj.set_properties(some_uchar=54, some_int=42)
+ self.assertEqual(42, self.get_prop(obj, 'some-int'))
+ self.assertEqual(54, self.get_prop(obj, 'some-uchar'))
+
+ def test_gtype(self):
+ obj = Regress.TestObj()
+ self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INVALID)
+ self.set_prop(obj, 'gtype', int)
+ self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INT)
+
+ obj = Regress.TestObj(gtype=int)
+ self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INT)
+ self.set_prop(obj, 'gtype', str)
+ self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_STRING)
+
+ def test_hash_table(self):
+ obj = Regress.TestObj()
+ self.assertEqual(self.get_prop(obj, 'hash-table'), None)
+
+ self.set_prop(obj, 'hash-table', {'mec': 56})
+ self.assertTrue(isinstance(self.get_prop(obj, 'hash-table'), dict))
+ self.assertEqual(list(self.get_prop(obj, 'hash-table').items())[0],
+ ('mec', 56))
+
+ def test_parent_class(self):
+ class A(Regress.TestObj):
+ prop1 = GObject.Property(type=int)
+
+ a = A()
+ self.set_prop(a, 'int', 20)
+ self.assertEqual(self.get_prop(a, 'int'), 20)
+
+ # test parent property which needs introspection
+ self.set_prop(a, 'list', ("str1", "str2"))
+ self.assertEqual(self.get_prop(a, 'list'), ["str1", "str2"])
+
+ def test_held_object_ref_count_getter(self):
+ holder = GIMarshallingTests.PropertiesObject()
+ held = GObject.Object()
+
+ self.assertEqual(holder.__grefcount__, 1)
+ self.assertEqual(held.__grefcount__, 1)
+
+ self.set_prop(holder, 'some-object', held)
+ self.assertEqual(holder.__grefcount__, 1)
+
+ initial_ref_count = held.__grefcount__
+ self.get_prop(holder, 'some-object')
+ gc.collect()
+ self.assertEqual(held.__grefcount__, initial_ref_count)
+
+ def test_held_object_ref_count_setter(self):
+ holder = GIMarshallingTests.PropertiesObject()
+ held = GObject.Object()
+
+ self.assertEqual(holder.__grefcount__, 1)
+ self.assertEqual(held.__grefcount__, 1)
+
+ # Setting property should only increase ref count by 1
+ self.set_prop(holder, 'some-object', held)
+ self.assertEqual(holder.__grefcount__, 1)
+ self.assertEqual(held.__grefcount__, 2)
+
+ # Clearing should pull it back down
+ self.set_prop(holder, 'some-object', None)
+ self.assertEqual(held.__grefcount__, 1)
+
+ def test_set_object_property_to_invalid_type(self):
+ obj = GIMarshallingTests.PropertiesObject()
+ self.assertRaises(TypeError, self.set_prop, obj, 'some-object', 'not_an_object')
+
+
+class TestCPropsAccessor(CPropertiesTestBase, unittest.TestCase):
+ # C property tests using the "props" accessor.
+ def get_prop(self, obj, name):
+ return getattr(obj.props, name.replace('-', '_'))
+
+ def set_prop(self, obj, name, value):
+ setattr(obj.props, name.replace('-', '_'), value)
+
+ def test_props_accessor_dir(self):
+ # Test class
+ props = dir(GIMarshallingTests.PropertiesObject.props)
+ self.assertTrue('some_float' in props)
+ self.assertTrue('some_double' in props)
+ self.assertTrue('some_variant' in props)
+
+ # Test instance
+ obj = GIMarshallingTests.PropertiesObject()
+ props = dir(obj.props)
+ self.assertTrue('some_float' in props)
+ self.assertTrue('some_double' in props)
+ self.assertTrue('some_variant' in props)
+
+ def test_param_spec_dir(self):
+ attrs = dir(GIMarshallingTests.PropertiesObject.props.some_float)
+ self.assertTrue('name' in attrs)
+ self.assertTrue('nick' in attrs)
+ self.assertTrue('blurb' in attrs)
+ self.assertTrue('flags' in attrs)
+ self.assertTrue('default_value' in attrs)
+ self.assertTrue('minimum' in attrs)
+ self.assertTrue('maximum' in attrs)
+
+
+class TestCGetPropertyMethod(CPropertiesTestBase, unittest.TestCase):
+ # C property tests using the "props" accessor.
+ def get_prop(self, obj, name):
+ return obj.get_property(name)
+
+ def set_prop(self, obj, name, value):
+ obj.set_property(name, value)
diff --git a/tests/test_pycapi.py b/tests/test_pycapi.py
new file mode 100644
index 0000000..d049a8d
--- /dev/null
+++ b/tests/test_pycapi.py
@@ -0,0 +1,45 @@
+import unittest
+import ctypes
+from ctypes import c_void_p, py_object, c_char_p
+
+import gi
+from gi.repository import Gio
+
+
+def get_capi():
+
+ if not hasattr(ctypes, "pythonapi"):
+ return
+
+ class CAPI(ctypes.Structure):
+ _fields_ = [
+ ("", c_void_p),
+ ("", c_void_p),
+ ("", c_void_p),
+ ("newgobj", ctypes.PYFUNCTYPE(py_object, c_void_p)),
+ ]
+
+ api_obj = gi._gobject._PyGObject_API
+ func_type = ctypes.PYFUNCTYPE(c_void_p, py_object, c_char_p)
+ PyCapsule_GetPointer = func_type(
+ ('PyCapsule_GetPointer', ctypes.pythonapi))
+ ptr = PyCapsule_GetPointer(api_obj, b"gobject._PyGObject_API")
+
+ ptr = ctypes.cast(ptr, ctypes.POINTER(CAPI))
+ return ptr.contents
+
+
+API = get_capi()
+
+
+@unittest.skipUnless(API, "no pythonapi support")
+class TestPythonCAPI(unittest.TestCase):
+
+ def test_newgobj(self):
+ w = Gio.FileInfo()
+ # XXX: ugh :/
+ ptr = int(repr(w).split()[-1].split(")")[0], 16)
+
+ capi = get_capi()
+ new_w = capi.newgobj(ptr)
+ assert w == new_w
diff --git a/tests/test_pygtkcompat.py b/tests/test_pygtkcompat.py
new file mode 100644
index 0000000..c01892a
--- /dev/null
+++ b/tests/test_pygtkcompat.py
@@ -0,0 +1,339 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+
+import unittest
+import base64
+
+import pytest
+import gi
+import pygtkcompat
+from pygtkcompat.pygtkcompat import _disable_all as disable_all
+
+from .helper import capture_gi_deprecation_warnings, capture_glib_warnings
+
+try:
+ from gi.repository import Gtk, Gdk
+except ImportError:
+ Gtk = None
+else:
+ if Gtk._version != "3.0":
+ Gtk = None
+
+
+class TestGlibCompat(unittest.TestCase):
+
+ def setUp(self):
+ pygtkcompat.enable()
+
+ def tearDown(self):
+ disable_all()
+
+ def test_import(self):
+ import glib
+ import gio
+ glib, gio
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestMultipleEnable(unittest.TestCase):
+
+ def tearDown(self):
+ disable_all()
+
+ def test_main(self):
+ pygtkcompat.enable()
+ pygtkcompat.enable()
+
+ def test_gtk(self):
+ pygtkcompat.enable_gtk("3.0")
+ pygtkcompat.enable_gtk("3.0")
+ import gtk
+
+ # https://bugzilla.gnome.org/show_bug.cgi?id=759009
+ w = gtk.Window()
+ w.realize()
+ self.assertEqual(len(w.window.get_origin()), 2)
+ w.destroy()
+
+ def test_gtk_no_4(self):
+ self.assertRaises(ValueError, pygtkcompat.enable_gtk, version='4.0')
+
+ def test_gtk_version_conflict(self):
+ pygtkcompat.enable_gtk("3.0")
+ self.assertRaises(ValueError, pygtkcompat.enable_gtk, version='2.0')
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestATKCompat(unittest.TestCase):
+
+ def setUp(self):
+ pygtkcompat.enable_gtk("3.0")
+
+ def tearDown(self):
+ disable_all()
+
+ def test_object(self):
+ import atk
+ self.assertTrue(hasattr(atk, 'Object'))
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestPangoCompat(unittest.TestCase):
+
+ def setUp(self):
+ pygtkcompat.enable_gtk("3.0")
+
+ def tearDown(self):
+ disable_all()
+
+ def test_layout(self):
+ import pango
+ self.assertTrue(hasattr(pango, 'Layout'))
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestPangoCairoCompat(unittest.TestCase):
+
+ def setUp(self):
+ pygtkcompat.enable_gtk("3.0")
+
+ def tearDown(self):
+ disable_all()
+
+ def test_error_underline_path(self):
+ import pangocairo
+ self.assertTrue(hasattr(pangocairo, 'error_underline_path'))
+
+
+@unittest.skipUnless(Gtk, 'Gtk not available')
+class TestGTKCompat(unittest.TestCase):
+
+ def setUp(self):
+ pygtkcompat.enable_gtk("3.0")
+
+ def tearDown(self):
+ disable_all()
+
+ def test_window_get_frame_extents(self):
+ import gtk
+ import gtk.gdk
+ w = gtk.Window()
+ w.realize()
+ rect = w.window.get_frame_extents()
+ assert isinstance(rect, gtk.gdk.Rectangle)
+
+ def test_window_get_geometry(self):
+ import gtk
+ w = gtk.Window()
+ w.realize()
+ with capture_gi_deprecation_warnings():
+ geo = w.window.get_geometry()
+ assert isinstance(geo, tuple)
+ assert len(geo) == 5
+
+ def test_action_set_tool_item_type(self):
+ import gtk
+ with pytest.warns(gi.PyGIDeprecationWarning):
+ gtk.Action().set_tool_item_type(gtk.Action)
+
+ def test_treeviewcolumn_pack(self):
+ import gtk
+ col = gtk.TreeViewColumn()
+ col.pack_end(gtk.CellRendererText())
+ col.pack_start(gtk.CellRendererText())
+
+ def test_cell_layout_pack(self):
+ import gtk
+ layout = gtk.EntryCompletion()
+ layout.pack_end(gtk.CellRendererText())
+ layout.pack_start(gtk.CellRendererText())
+
+ def test_cell_layout_cell_data_func(self):
+ import gtk
+
+ def func(*args):
+ pass
+
+ layout = gtk.EntryCompletion()
+ render = gtk.CellRendererText()
+ layout.set_cell_data_func(render, func)
+
+ def test_combo_row_separator_func(self):
+ import gtk
+
+ def func(*args):
+ pass
+
+ combo = gtk.ComboBox()
+ combo.set_row_separator_func(func)
+
+ def test_container_install_child_property(self):
+ import gtk
+
+ box = gtk.Box()
+ with pytest.warns(gi.PyGIDeprecationWarning):
+ box.install_child_property(0, None)
+
+ def test_combo_box_new_text(self):
+ import gtk
+
+ combo = gtk.combo_box_new_text()
+ assert isinstance(combo, gtk.ComboBox)
+ combo.append_text("foo")
+
+ def test_scale(self):
+ import gtk
+
+ adjustment = gtk.Adjustment()
+ assert gtk.HScale()
+ assert gtk.HScale(adjustment).get_adjustment() == adjustment
+ adjustment = gtk.Adjustment()
+ assert gtk.VScale()
+ assert gtk.VScale(adjustment).get_adjustment() == adjustment
+
+ def test_stock_add(self):
+ import gtk
+
+ gtk.stock_add([])
+
+ def test_text_view_scroll_to_mark(self):
+ import gtk
+
+ view = gtk.TextView()
+ buf = view.get_buffer()
+ mark = gtk.TextMark(name="foo")
+ buf.add_mark(mark, buf.get_end_iter())
+ view.scroll_to_mark(mark, 0.0)
+
+ def test_window_set_geometry_hints(self):
+ import gtk
+
+ w = gtk.Window()
+ w.set_geometry_hints(None, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ w.set_geometry_hints(None, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1)
+ with pytest.raises(TypeError):
+ w.set_geometry_hints(None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+ def test_buttons(self):
+ import gtk.gdk
+ self.assertEqual(gtk.gdk._2BUTTON_PRESS, 5)
+ self.assertEqual(gtk.gdk.BUTTON_PRESS, 4)
+
+ def test_enums(self):
+ import gtk
+ self.assertEqual(gtk.WINDOW_TOPLEVEL, Gtk.WindowType.TOPLEVEL)
+ self.assertEqual(gtk.PACK_START, Gtk.PackType.START)
+
+ def test_flags(self):
+ import gtk
+ self.assertEqual(gtk.EXPAND, Gtk.AttachOptions.EXPAND)
+ self.assertEqual(gtk.gdk.SHIFT_MASK, Gdk.ModifierType.SHIFT_MASK)
+
+ def test_keysyms(self):
+ import gtk.keysyms
+ self.assertEqual(gtk.keysyms.Escape, Gdk.KEY_Escape)
+ self.assertTrue(gtk.keysyms._0, Gdk.KEY_0)
+
+ def test_style(self):
+ import gtk
+ widget = gtk.Button()
+ with capture_gi_deprecation_warnings():
+ widget.get_style_context().set_state(gtk.STATE_NORMAL)
+ self.assertTrue(isinstance(widget.style.base[gtk.STATE_NORMAL],
+ gtk.gdk.Color))
+
+ def test_alignment(self):
+ import gtk
+ # Creation of pygtk.Alignment causes hard warnings, ignore this in testing.
+ with capture_glib_warnings(allow_warnings=True):
+ a = gtk.Alignment()
+
+ self.assertEqual(a.props.xalign, 0.0)
+ self.assertEqual(a.props.yalign, 0.0)
+ self.assertEqual(a.props.xscale, 0.0)
+ self.assertEqual(a.props.yscale, 0.0)
+
+ def test_box(self):
+ import gtk
+ box = gtk.Box()
+ child = gtk.Button()
+
+ box.pack_start(child)
+ expand, fill, padding, pack_type = box.query_child_packing(child)
+ self.assertTrue(expand)
+ self.assertTrue(fill)
+ self.assertEqual(padding, 0)
+ self.assertEqual(pack_type, gtk.PACK_START)
+
+ child = gtk.Button()
+ box.pack_end(child)
+ expand, fill, padding, pack_type = box.query_child_packing(child)
+ self.assertTrue(expand)
+ self.assertTrue(fill)
+ self.assertEqual(padding, 0)
+ self.assertEqual(pack_type, gtk.PACK_END)
+
+ def test_combobox_entry(self):
+ import gtk
+ liststore = gtk.ListStore(int, str)
+ liststore.append((1, 'One'))
+ liststore.append((2, 'Two'))
+ liststore.append((3, 'Three'))
+ # might cause a Pango warning, do not break on this
+ with capture_glib_warnings(allow_warnings=True):
+ combo = gtk.ComboBoxEntry(model=liststore)
+ combo.set_text_column(1)
+ combo.set_active(0)
+ self.assertEqual(combo.get_text_column(), 1)
+ self.assertEqual(combo.get_child().get_text(), 'One')
+ combo = gtk.combo_box_entry_new()
+ combo.set_model(liststore)
+ combo.set_text_column(1)
+ combo.set_active(0)
+ self.assertEqual(combo.get_text_column(), 1)
+ self.assertEqual(combo.get_child().get_text(), 'One')
+ combo = gtk.combo_box_entry_new_with_model(liststore)
+ combo.set_text_column(1)
+ combo.set_active(0)
+ self.assertEqual(combo.get_text_column(), 1)
+ self.assertEqual(combo.get_child().get_text(), 'One')
+
+ def test_size_request(self):
+ import gtk
+ box = gtk.Box()
+ with capture_gi_deprecation_warnings():
+ self.assertEqual(box.size_request(), [0, 0])
+
+ def test_pixbuf(self):
+ import gtk.gdk
+ gtk.gdk.Pixbuf()
+
+ def test_pixbuf_loader(self):
+ import gtk.gdk
+ # load a 1x1 pixel PNG from memory
+ data = base64.b64decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP4n8Dw'
+ 'HwAGIAJf85Z3XgAAAABJRU5ErkJggg==')
+ loader = gtk.gdk.PixbufLoader('png')
+ loader.write(data)
+ loader.close()
+
+ pixbuf = loader.get_pixbuf()
+ self.assertEqual(pixbuf.get_width(), 1)
+ self.assertEqual(pixbuf.get_height(), 1)
+
+ def test_pixbuf_formats(self):
+ import gtk.gdk
+ formats = gtk.gdk.pixbuf_get_formats()
+ self.assertEqual(type(formats[0]), dict)
+ self.assertTrue('name' in formats[0])
+ self.assertTrue('description' in formats[0])
+ self.assertTrue('mime_types' in formats[0])
+ self.assertEqual(type(formats[0]['extensions']), list)
+
+ def test_gdk_window(self):
+ import gtk
+ w = gtk.Window()
+ w.realize()
+ origin = w.get_window().get_origin()
+ self.assertTrue(isinstance(origin, tuple))
+ self.assertEqual(len(origin), 2)
diff --git a/tests/test_repository.py b/tests/test_repository.py
new file mode 100644
index 0000000..4390ff0
--- /dev/null
+++ b/tests/test_repository.py
@@ -0,0 +1,403 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2013 Simon Feltman <sfeltman@gnome.org>
+#
+# test_repository.py: Test for the GIRepository module
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+
+import unittest
+from collections import abc
+
+import gi._gi as GIRepository
+from gi.module import repository as repo
+from gi.repository import GObject
+from gi.repository import GIMarshallingTests
+from gi.repository import GIRepository as IntrospectedRepository
+
+from .helper import capture_glib_warnings
+
+
+def find_child_info(info, getter_name, name):
+ getter = getattr(info, getter_name)
+ for child in getter():
+ if child.get_name() == name:
+ return child
+ else:
+ raise ValueError('child info %s not found' % name)
+
+
+class Test(unittest.TestCase):
+ def setUp(self):
+ repo.require('GLib')
+ repo.require('GObject')
+ repo.require('GIMarshallingTests')
+
+ def test_repo_get_dependencies(self):
+ self.assertRaises(TypeError, repo.get_dependencies)
+ self.assertEqual(repo.get_dependencies("GLib"), [])
+ self.assertEqual(repo.get_dependencies("GObject"), ["GLib-2.0"])
+
+ def test_repo_is_registered(self):
+ self.assertRaises(TypeError, repo.is_registered)
+ self.assertRaises(TypeError, repo.is_registered, None)
+ self.assertTrue(repo.is_registered("GIRepository"))
+ self.assertTrue(repo.is_registered("GIRepository", None))
+ self.assertTrue(isinstance(repo.is_registered("GIRepository"), bool))
+ self.assertTrue(repo.is_registered("GIRepository", "2.0"))
+ self.assertFalse(repo.is_registered("GIRepository", ""))
+ self.assertFalse(repo.is_registered("GIRepository", "99.0"))
+ self.assertFalse(repo.is_registered("GIRepository", "1.0"))
+
+ def test_repo_get_immediate_dependencies(self):
+ self.assertRaises(TypeError, repo.get_immediate_dependencies)
+ self.assertEqual(repo.get_immediate_dependencies("GLib"), [])
+ self.assertEqual(
+ repo.get_immediate_dependencies("GObject"), ["GLib-2.0"])
+ self.assertEqual(
+ repo.get_immediate_dependencies(namespace="GObject"), ["GLib-2.0"])
+ self.assertEqual(
+ repo.get_immediate_dependencies("GIMarshallingTests"), ["Gio-2.0"])
+
+ def test_arg_info(self):
+ func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct')
+ args = func_info.get_arguments()
+ self.assertTrue(len(args), 1)
+
+ arg = args[0]
+ self.assertEqual(arg.get_container(), func_info)
+ self.assertEqual(arg.get_direction(), GIRepository.Direction.OUT)
+ self.assertEqual(arg.get_name(), 'structs')
+ self.assertEqual(arg.get_namespace(), 'GIMarshallingTests')
+ self.assertFalse(arg.is_caller_allocates())
+ self.assertFalse(arg.is_optional())
+ self.assertFalse(arg.is_return_value())
+ self.assertFalse(arg.may_be_null())
+ self.assertEqual(arg.get_destroy(), -1)
+ self.assertEqual(arg.get_ownership_transfer(), GIRepository.Transfer.NOTHING)
+ self.assertEqual(arg.get_scope(), GIRepository.ScopeType.INVALID)
+ self.assertEqual(arg.get_type().get_tag(), GIRepository.TypeTag.ARRAY)
+
+ def test_base_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'Object')
+ self.assertEqual(info.__name__, 'Object')
+ self.assertEqual(info.get_name(), 'Object')
+ self.assertEqual(info.__module__, 'gi.repository.GIMarshallingTests')
+ self.assertEqual(info.get_name_unescaped(), 'Object')
+ self.assertEqual(info.get_namespace(), 'GIMarshallingTests')
+ self.assertEqual(info.get_container(), None)
+ info2 = repo.find_by_name('GIMarshallingTests', 'Object')
+ self.assertFalse(info is info2)
+ self.assertEqual(info, info2)
+ self.assertTrue(info.equal(info2))
+ assert isinstance(info.is_deprecated(), bool)
+ assert isinstance(info.get_type(), int)
+ assert info.get_attribute("nopenope") is None
+
+ def test_object_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'Object')
+ self.assertEqual(info.get_parent(), repo.find_by_name('GObject', 'Object'))
+ self.assertTrue(isinstance(info.get_methods(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_fields(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_interfaces(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_constants(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_vfuncs(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_properties(), abc.Iterable))
+ self.assertFalse(info.get_abstract())
+ self.assertEqual(info.get_class_struct(), repo.find_by_name('GIMarshallingTests', 'ObjectClass'))
+ self.assertEqual(info.get_type_name(), 'GIMarshallingTestsObject')
+ self.assertEqual(info.get_type_init(), 'gi_marshalling_tests_object_get_type')
+ self.assertFalse(info.get_fundamental())
+ self.assertEqual(info.get_parent(), repo.find_by_name('GObject', 'Object'))
+ assert info.find_vfunc("nopenope") is None
+ vfunc = info.find_vfunc("method_int8_out")
+ assert isinstance(vfunc, GIRepository.VFuncInfo)
+
+ def test_callable_inheritance(self):
+ self.assertTrue(issubclass(GIRepository.CallableInfo, GIRepository.BaseInfo))
+ self.assertTrue(issubclass(GIRepository.CallbackInfo, GIRepository.CallableInfo))
+ self.assertTrue(issubclass(GIRepository.FunctionInfo, GIRepository.CallableInfo))
+ self.assertTrue(issubclass(GIRepository.VFuncInfo, GIRepository.CallableInfo))
+ self.assertTrue(issubclass(GIRepository.SignalInfo, GIRepository.CallableInfo))
+
+ def test_registered_type_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'Object')
+ # Call these from the class because GIObjectInfo overrides them
+ self.assertEqual(GIRepository.RegisteredTypeInfo.get_g_type(info),
+ GObject.type_from_name('GIMarshallingTestsObject'))
+ self.assertEqual(GIRepository.RegisteredTypeInfo.get_type_name(info),
+ 'GIMarshallingTestsObject')
+ self.assertEqual(GIRepository.RegisteredTypeInfo.get_type_init(info),
+ 'gi_marshalling_tests_object_get_type')
+
+ def test_fundamental_object_info(self):
+ repo.require('Regress')
+ info = repo.find_by_name('Regress', 'TestFundamentalObject')
+ self.assertTrue(info.get_abstract())
+ self.assertTrue(info.get_fundamental())
+ self.assertEqual(info.get_ref_function(), 'regress_test_fundamental_object_ref')
+ self.assertEqual(info.get_unref_function(), 'regress_test_fundamental_object_unref')
+ self.assertEqual(info.get_get_value_function(), 'regress_test_value_get_fundamental_object')
+ self.assertEqual(info.get_set_value_function(), 'regress_test_value_set_fundamental_object')
+
+ def test_interface_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'Interface')
+ self.assertTrue(isinstance(info.get_methods(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_vfuncs(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_constants(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_prerequisites(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_properties(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_signals(), abc.Iterable))
+
+ method = info.find_method('test_int8_in')
+ vfunc = info.find_vfunc('test_int8_in')
+ self.assertEqual(method.get_name(), 'test_int8_in')
+ self.assertEqual(vfunc.get_invoker(), method)
+ self.assertEqual(method.get_vfunc(), vfunc)
+
+ iface = info.get_iface_struct()
+ self.assertEqual(iface, repo.find_by_name('GIMarshallingTests', 'InterfaceIface'))
+
+ assert info.find_signal("nopenope") is None
+
+ def test_struct_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'InterfaceIface')
+ self.assertTrue(isinstance(info, GIRepository.StructInfo))
+ self.assertTrue(isinstance(info.get_fields(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_methods(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_size(), int))
+ self.assertTrue(isinstance(info.get_alignment(), int))
+ self.assertTrue(info.is_gtype_struct())
+ self.assertFalse(info.is_foreign())
+
+ info = repo.find_by_name('GIMarshallingTests', 'SimpleStruct')
+ assert info.find_method("nope") is None
+ assert isinstance(info.find_method("method"), GIRepository.FunctionInfo)
+
+ assert info.find_field("nope") is None
+ assert isinstance(info.find_field("int8"), GIRepository.FieldInfo)
+
+ def test_enum_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'Enum')
+ self.assertTrue(isinstance(info, GIRepository.EnumInfo))
+ self.assertTrue(isinstance(info.get_values(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_methods(), abc.Iterable))
+ self.assertFalse(info.is_flags())
+ self.assertTrue(info.get_storage_type() > 0) # might be platform dependent
+
+ def test_union_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'Union')
+ self.assertTrue(isinstance(info, GIRepository.UnionInfo))
+ self.assertTrue(isinstance(info.get_fields(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_methods(), abc.Iterable))
+ self.assertTrue(isinstance(info.get_size(), int))
+ self.assertTrue(isinstance(info.get_alignment(), int))
+
+ def test_type_info(self):
+ func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct')
+ arg_info, = func_info.get_arguments()
+ type_info = arg_info.get_type()
+
+ self.assertTrue(type_info.is_pointer())
+ self.assertEqual(type_info.get_tag(), GIRepository.TypeTag.ARRAY)
+ self.assertEqual(type_info.get_tag_as_string(), 'array')
+ self.assertEqual(type_info.get_param_type(0).get_tag(),
+ GIRepository.TypeTag.INTERFACE)
+ self.assertEqual(type_info.get_param_type(0).get_interface(),
+ repo.find_by_name('GIMarshallingTests', 'SimpleStruct'))
+ self.assertEqual(type_info.get_interface(), None)
+ self.assertEqual(type_info.get_array_length(), -1)
+ self.assertEqual(type_info.get_array_fixed_size(), 2)
+ self.assertFalse(type_info.is_zero_terminated())
+ self.assertEqual(type_info.get_array_type(), GIRepository.ArrayType.C)
+
+ def test_field_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'InterfaceIface')
+ field = find_child_info(info, 'get_fields', 'test_int8_in')
+ self.assertEqual(field.get_name(), 'test_int8_in')
+ self.assertTrue(field.get_flags() & GIRepository.FieldInfoFlags.IS_READABLE)
+ self.assertFalse(field.get_flags() & GIRepository.FieldInfoFlags.IS_WRITABLE)
+ self.assertEqual(field.get_type().get_tag(), GIRepository.TypeTag.INTERFACE)
+
+ # don't test actual values because that might fail with architecture differences
+ self.assertTrue(isinstance(field.get_size(), int))
+ self.assertTrue(isinstance(field.get_offset(), int))
+
+ def test_property_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'PropertiesObject')
+ prop = find_child_info(info, 'get_properties', 'some-object')
+
+ flags = GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE | GObject.ParamFlags.CONSTRUCT
+ self.assertEqual(prop.get_flags(), flags)
+ self.assertEqual(prop.get_type().get_tag(), GIRepository.TypeTag.INTERFACE)
+ self.assertEqual(prop.get_type().get_interface(),
+ repo.find_by_name('GObject', 'Object'))
+ self.assertEqual(prop.get_ownership_transfer(), GIRepository.Transfer.NOTHING)
+
+ def test_callable_info(self):
+ func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct')
+ self.assertTrue(hasattr(func_info, 'invoke'))
+ self.assertTrue(isinstance(func_info.get_arguments(), abc.Iterable))
+ self.assertEqual(func_info.get_caller_owns(), GIRepository.Transfer.NOTHING)
+ self.assertFalse(func_info.may_return_null())
+ self.assertEqual(func_info.get_return_type().get_tag(), GIRepository.TypeTag.VOID)
+ self.assertRaises(AttributeError, func_info.get_return_attribute, '_not_an_attr')
+
+ def test_signal_info(self):
+ repo.require('Regress')
+ info = repo.find_by_name('Regress', 'TestObj')
+ sig_info = find_child_info(info, 'get_signals', 'test')
+
+ sig_flags = GObject.SignalFlags.RUN_LAST | \
+ GObject.SignalFlags.NO_RECURSE | GObject.SignalFlags.NO_HOOKS
+
+ self.assertTrue(sig_info is not None)
+ self.assertTrue(isinstance(sig_info, GIRepository.CallableInfo))
+ self.assertTrue(isinstance(sig_info, GIRepository.SignalInfo))
+ self.assertEqual(sig_info.get_name(), 'test')
+ self.assertEqual(sig_info.get_class_closure(), None)
+ self.assertFalse(sig_info.true_stops_emit())
+ self.assertEqual(sig_info.get_flags(), sig_flags)
+
+ def test_notify_signal_info_with_obj(self):
+ repo.require('Regress')
+ info = repo.find_by_name('Regress', 'TestObj')
+ sig_info = find_child_info(info, 'get_signals', 'sig-with-array-prop')
+
+ sig_flags = GObject.SignalFlags.RUN_LAST
+
+ self.assertTrue(sig_info is not None)
+ self.assertTrue(isinstance(sig_info, GIRepository.CallableInfo))
+ self.assertTrue(isinstance(sig_info, GIRepository.SignalInfo))
+ self.assertEqual(sig_info.get_name(), 'sig-with-array-prop')
+ self.assertEqual(sig_info.get_class_closure(), None)
+ self.assertFalse(sig_info.true_stops_emit())
+ self.assertEqual(sig_info.get_flags(), sig_flags)
+
+ def test_object_constructor(self):
+ info = repo.find_by_name('GIMarshallingTests', 'Object')
+ method = find_child_info(info, 'get_methods', 'new')
+
+ self.assertTrue(isinstance(method, GIRepository.CallableInfo))
+ self.assertTrue(isinstance(method, GIRepository.FunctionInfo))
+ self.assertTrue(method in info.get_methods())
+ self.assertEqual(method.get_name(), 'new')
+ self.assertFalse(method.is_method())
+ self.assertTrue(method.is_constructor())
+ self.assertEqual(method.get_symbol(), 'gi_marshalling_tests_object_new')
+
+ flags = method.get_flags()
+ self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_METHOD)
+ self.assertTrue(flags & GIRepository.FunctionInfoFlags.IS_CONSTRUCTOR)
+ self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_GETTER)
+ self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_SETTER)
+ self.assertFalse(flags & GIRepository.FunctionInfoFlags.WRAPS_VFUNC)
+ self.assertFalse(flags & GIRepository.FunctionInfoFlags.THROWS)
+
+ def test_method_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'Object')
+ method = find_child_info(info, 'get_methods', 'vfunc_return_value_only')
+
+ self.assertTrue(isinstance(method, GIRepository.CallableInfo))
+ self.assertTrue(isinstance(method, GIRepository.FunctionInfo))
+ self.assertTrue(method in info.get_methods())
+ self.assertEqual(method.get_name(), 'vfunc_return_value_only')
+ self.assertFalse(method.is_constructor())
+ self.assertEqual(method.get_symbol(), 'gi_marshalling_tests_object_vfunc_return_value_only')
+ self.assertTrue(method.is_method())
+
+ flags = method.get_flags()
+ self.assertTrue(flags & GIRepository.FunctionInfoFlags.IS_METHOD)
+ self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_CONSTRUCTOR)
+ self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_GETTER)
+ self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_SETTER)
+ self.assertFalse(flags & GIRepository.FunctionInfoFlags.WRAPS_VFUNC)
+ self.assertFalse(flags & GIRepository.FunctionInfoFlags.THROWS)
+
+ def test_vfunc_info(self):
+ info = repo.find_by_name('GIMarshallingTests', 'Object')
+ invoker = find_child_info(info, 'get_methods', 'vfunc_return_value_only')
+ vfunc = find_child_info(info, 'get_vfuncs', 'vfunc_return_value_only')
+
+ self.assertTrue(isinstance(vfunc, GIRepository.CallableInfo))
+ self.assertTrue(isinstance(vfunc, GIRepository.VFuncInfo))
+ self.assertEqual(vfunc.get_name(), 'vfunc_return_value_only')
+ self.assertEqual(vfunc.get_invoker(), invoker)
+ self.assertEqual(invoker, info.find_method('vfunc_return_value_only'))
+ self.assertEqual(vfunc.get_flags(), 0)
+ self.assertEqual(vfunc.get_offset(), 0xFFFF) # unknown offset
+ self.assertEqual(vfunc.get_signal(), None)
+
+ def test_callable_can_throw_gerror(self):
+ info = repo.find_by_name('GIMarshallingTests', 'Object')
+ invoker = find_child_info(info, 'get_methods', 'vfunc_meth_with_error')
+ vfunc = find_child_info(info, 'get_vfuncs', 'vfunc_meth_with_err')
+
+ self.assertTrue(invoker.can_throw_gerror())
+ self.assertTrue(vfunc.can_throw_gerror())
+
+ # Test that args do not include the GError**
+ self.assertEqual(len(invoker.get_arguments()), 1)
+ self.assertEqual(len(vfunc.get_arguments()), 1)
+
+ # Sanity check method that does not throw.
+ invoker_no_throws = find_child_info(info, 'get_methods', 'method_int8_in')
+ self.assertFalse(invoker_no_throws.can_throw_gerror())
+
+ def test_flags_double_registration_error(self):
+ # a warning is printed for double registration and pygobject will
+ # also raise a RuntimeError.
+ GIMarshallingTests.NoTypeFlags # cause flags registration
+ info = repo.find_by_name('GIMarshallingTests', 'NoTypeFlags')
+ with capture_glib_warnings(allow_warnings=True, allow_criticals=True):
+ self.assertRaises(RuntimeError,
+ GIRepository.flags_register_new_gtype_and_add,
+ info)
+
+ def test_enum_double_registration_error(self):
+ # a warning is printed for double registration and pygobject will
+ # also raise a RuntimeError.
+ GIMarshallingTests.Enum # cause enum registration
+ info = repo.find_by_name('GIMarshallingTests', 'Enum')
+ with capture_glib_warnings(allow_warnings=True, allow_criticals=True):
+ self.assertRaises(RuntimeError,
+ GIRepository.enum_register_new_gtype_and_add,
+ info)
+
+ def test_enums(self):
+ self.assertTrue(hasattr(GIRepository, 'Direction'))
+ self.assertTrue(hasattr(GIRepository, 'Transfer'))
+ self.assertTrue(hasattr(GIRepository, 'ArrayType'))
+ self.assertTrue(hasattr(GIRepository, 'ScopeType'))
+ self.assertTrue(hasattr(GIRepository, 'VFuncInfoFlags'))
+ self.assertTrue(hasattr(GIRepository, 'FieldInfoFlags'))
+ self.assertTrue(hasattr(GIRepository, 'FunctionInfoFlags'))
+ self.assertTrue(hasattr(GIRepository, 'TypeTag'))
+ self.assertTrue(hasattr(GIRepository, 'InfoType'))
+
+ def test_introspected_argument_info(self):
+ self.assertTrue(isinstance(IntrospectedRepository.Argument.__info__,
+ GIRepository.UnionInfo))
+
+ arg = IntrospectedRepository.Argument()
+ self.assertTrue(isinstance(arg.__info__, GIRepository.UnionInfo))
+
+ old_info = IntrospectedRepository.Argument.__info__
+ IntrospectedRepository.Argument.__info__ = 'not an info'
+ self.assertRaises(TypeError, IntrospectedRepository.Argument)
+ IntrospectedRepository.Argument.__info__ = old_info
diff --git a/tests/test_resulttuple.py b/tests/test_resulttuple.py
new file mode 100644
index 0000000..00daa7b
--- /dev/null
+++ b/tests/test_resulttuple.py
@@ -0,0 +1,89 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2015 Christoph Reiter <reiter.christoph@gmail.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+import unittest
+import pickle
+
+import gi
+from gi.repository import GIMarshallingTests
+from gi.repository import Regress
+
+
+ResultTuple = gi._gi.ResultTuple
+
+
+class TestResultTuple(unittest.TestCase):
+
+ def test_base(self):
+ self.assertTrue(issubclass(ResultTuple, tuple))
+
+ def test_create(self):
+ names = [None, "foo", None, "bar"]
+ for i in range(10):
+ new = ResultTuple._new_type(names)
+ self.assertTrue(issubclass(new, ResultTuple))
+
+ def test_repr_dir(self):
+ new = ResultTuple._new_type([None, "foo", None, "bar"])
+ inst = new([1, 2, 3, "a"])
+
+ self.assertEqual(repr(inst), "(1, foo=2, 3, bar='a')")
+ self.assertTrue("foo" in dir(inst))
+
+ def test_repr_dir_empty(self):
+ new = ResultTuple._new_type([])
+ inst = new()
+ self.assertEqual(repr(inst), "()")
+ dir(inst)
+
+ def test_getatttr(self):
+ new = ResultTuple._new_type([None, "foo", None, "bar"])
+ inst = new([1, 2, 3, "a"])
+
+ self.assertTrue(hasattr(inst, "foo"))
+ self.assertEqual(inst.foo, inst[1])
+ self.assertRaises(AttributeError, getattr, inst, "nope")
+
+ def test_pickle(self):
+ new = ResultTuple._new_type([None, "foo", None, "bar"])
+ inst = new([1, 2, 3, "a"])
+
+ inst2 = pickle.loads(pickle.dumps(inst))
+ self.assertEqual(inst2, inst)
+ self.assertTrue(isinstance(inst2, tuple))
+ self.assertFalse(isinstance(inst2, new))
+
+ def test_gi(self):
+ res = GIMarshallingTests.init_function([])
+ self.assertEqual(repr(res), "(True, argv=[])")
+
+ res = GIMarshallingTests.array_return_etc(5, 9)
+ self.assertEqual(repr(res), "([5, 0, 1, 9], sum=14)")
+
+ res = GIMarshallingTests.array_out_etc(-5, 9)
+ self.assertEqual(repr(res), "(ints=[-5, 0, 1, 9], sum=4)")
+
+ cb = lambda: (1, 2)
+ res = GIMarshallingTests.callback_multiple_out_parameters(cb)
+ self.assertEqual(repr(res), "(a=1.0, b=2.0)")
+
+ def test_regress(self):
+ res = Regress.TestObj().skip_return_val(50, 42.0, 60, 2, 3)
+ self.assertEqual(repr(res), "(out_b=51, inout_d=61, out_sum=32)")
diff --git a/tests/test_signal.py b/tests/test_signal.py
index ec13896..8a935fd 100644
--- a/tests/test_signal.py
+++ b/tests/test_signal.py
@@ -3,11 +3,16 @@
import gc
import unittest
import sys
+import weakref
+import threading
+import time
+
+from gi.repository import GObject, GLib, Regress, Gio
+from gi import _signalhelper as signalhelper
+from gi.module import repository as repo
-from gi.repository import GObject, GLib
-from gi._gobject import signalhelper
import testhelper
-from compathelper import _long
+from .helper import capture_glib_warnings, capture_gi_deprecation_warnings
class C(GObject.GObject):
@@ -74,13 +79,9 @@ class TestGSignalsError(unittest.TestCase):
def foo():
class Foo(GObject.GObject):
__gsignals__ = {'not-exists': 'override'}
- # do not stumble over the warning thrown by GLib
- old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_CRITICAL |
- GLib.LogLevelFlags.LEVEL_ERROR)
- try:
+
+ with capture_glib_warnings(allow_warnings=True):
self.assertRaises(TypeError, foo)
- finally:
- GLib.log_set_always_fatal(old_mask)
gc.collect()
@@ -136,9 +137,9 @@ class TestAccumulator(unittest.TestCase):
inst = Foo()
inst.my_acc_signal.connect(lambda obj: 1)
inst.my_acc_signal.connect(lambda obj: 2)
- ## the value returned in the following handler will not be
- ## considered, because at this point the accumulator already
- ## reached its limit.
+ # the value returned in the following handler will not be
+ # considered, because at this point the accumulator already
+ # reached its limit.
inst.my_acc_signal.connect(lambda obj: 3)
retval = inst.my_acc_signal.emit()
self.assertEqual(retval, 3)
@@ -147,8 +148,8 @@ class TestAccumulator(unittest.TestCase):
inst = Foo()
inst.my_other_acc_signal.connect(self._true_handler1)
inst.my_other_acc_signal.connect(self._true_handler2)
- ## the following handler will not be called because handler2
- ## returns True, so it should stop the emission.
+ # the following handler will not be called because handler2
+ # returns True, so it should stop the emission.
inst.my_other_acc_signal.connect(self._true_handler3)
self.__true_val = None
inst.my_other_acc_signal.emit()
@@ -327,9 +328,6 @@ class TestMatching(unittest.TestCase):
self.assertEqual(obj.status, 2)
def test_signal_handler_find(self):
- def dummy(*args):
- "Hack to work around: "
-
def foo(obj):
obj.status += 1
@@ -340,7 +338,7 @@ class TestMatching(unittest.TestCase):
found_id = GObject.signal_handler_find(obj,
GObject.SignalMatchType.ID,
signal_id=signal_id, detail=detail,
- closure=None, func=dummy, data=dummy)
+ closure=None, func=0, data=0)
self.assertEqual(handler_id, found_id)
@@ -367,15 +365,10 @@ class TestClosures(unittest.TestCase):
self.count += 1
def _callback_invalid_stop_emission_name(self, obj, prop):
- # We expect a GLib warning but there currently is no way to test that
- # This can at least make sure we don't crash
- old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_CRITICAL |
- GLib.LogLevelFlags.LEVEL_ERROR)
- try:
+ with capture_glib_warnings(allow_warnings=True, allow_criticals=True) as warn:
obj.stop_emission_by_name('notasignal::baddetail')
- finally:
- GLib.log_set_always_fatal(old_mask)
self.emission_error = True
+ self.assertTrue(warn)
def test_disconnect_by_func(self):
e = E()
@@ -410,7 +403,8 @@ class TestClosures(unittest.TestCase):
e = E()
e.connect('notify::prop', self._callback_invalid_stop_emission_name)
- e.set_property('prop', 1234)
+ with capture_glib_warnings():
+ e.set_property('prop', 1234)
self.assertTrue(self.emission_error)
def test_handler_block(self):
@@ -494,7 +488,8 @@ class SigPropClass(GObject.GObject):
(GObject.TYPE_INT,))}
__gproperties__ = {
- 'foo': (str, None, None, '', GObject.PARAM_WRITABLE | GObject.PARAM_CONSTRUCT),
+ 'foo': (str, None, None, '',
+ GObject.ParamFlags.WRITABLE | GObject.ParamFlags.CONSTRUCT),
}
signal_emission_failed = False
@@ -525,7 +520,7 @@ class CM(GObject.GObject):
test2=(GObject.SignalFlags.RUN_LAST, None, (str,)),
test3=(GObject.SignalFlags.RUN_LAST, int, (GObject.TYPE_DOUBLE,)),
test4=(GObject.SignalFlags.RUN_FIRST, None,
- (bool, _long, GObject.TYPE_FLOAT, GObject.TYPE_DOUBLE, int,
+ (bool, int, GObject.TYPE_FLOAT, GObject.TYPE_DOUBLE, int,
GObject.TYPE_UINT, GObject.TYPE_ULONG)),
test_float=(GObject.SignalFlags.RUN_LAST, GObject.TYPE_FLOAT, (GObject.TYPE_FLOAT,)),
test_double=(GObject.SignalFlags.RUN_LAST, GObject.TYPE_DOUBLE, (GObject.TYPE_DOUBLE,)),
@@ -557,7 +552,7 @@ class _TestCMarshaller:
self.assertEqual(rv, 20)
def test_test4(self):
- self.obj.emit("test4", True, _long(10), 3.14, 1.78, 20, _long(30), _long(31))
+ self.obj.emit("test4", True, 10, 3.14, 1.78, 20, 30, 31)
def test_float(self):
rv = self.obj.emit("test-float", 1.234)
@@ -571,11 +566,11 @@ class _TestCMarshaller:
rv = self.obj.emit("test-int64", 102030405)
self.assertEqual(rv, 102030405)
- rv = self.obj.emit("test-int64", GObject.G_MAXINT64)
- self.assertEqual(rv, GObject.G_MAXINT64 - 1)
+ rv = self.obj.emit("test-int64", GLib.MAXINT64)
+ self.assertEqual(rv, GLib.MAXINT64 - 1)
- rv = self.obj.emit("test-int64", GObject.G_MININT64)
- self.assertEqual(rv, GObject.G_MININT64)
+ rv = self.obj.emit("test-int64", GLib.MININT64)
+ self.assertEqual(rv, GLib.MININT64)
def test_string(self):
rv = self.obj.emit("test-string", "str")
@@ -621,51 +616,48 @@ class _TestCMarshaller:
# explicit float
v = GObject.Value(GObject.TYPE_FLOAT, 1.234)
rv = self.obj.emit("test-gvalue", v)
- self.assertAlmostEqual(rv, 1.234, 4)
+ self.assertAlmostEqual(rv, 1.234, places=4)
# implicit float
rv = self.obj.emit("test-gvalue", 1.234)
- self.assertAlmostEqual(rv, 1.234, 4)
+ self.assertAlmostEqual(rv, 1.234, places=4)
# explicit int64
- v = GObject.Value(GObject.TYPE_INT64, GObject.G_MAXINT64)
+ v = GObject.Value(GObject.TYPE_INT64, GLib.MAXINT64)
rv = self.obj.emit("test-gvalue", v)
- self.assertEqual(rv, GObject.G_MAXINT64)
-
- # implicit int64
- # does not work, see https://bugzilla.gnome.org/show_bug.cgi?id=683775
- #rv = self.obj.emit("test-gvalue", GObject.G_MAXINT64)
- #self.assertEqual(rv, GObject.G_MAXINT64)
+ self.assertEqual(rv, GLib.MAXINT64)
# explicit uint64
- v = GObject.Value(GObject.TYPE_UINT64, GObject.G_MAXUINT64)
+ v = GObject.Value(GObject.TYPE_UINT64, GLib.MAXUINT64)
rv = self.obj.emit("test-gvalue", v)
- self.assertEqual(rv, GObject.G_MAXUINT64)
+ self.assertEqual(rv, GLib.MAXUINT64)
+
+ @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=705291
+ def test_gvalue_implicit_int64(self):
+ # implicit int64
+ rv = self.obj.emit("test-gvalue", GLib.MAXINT64)
+ self.assertEqual(rv, GLib.MAXINT64)
# implicit uint64
- # does not work, see https://bugzilla.gnome.org/show_bug.cgi?id=683775
- #rv = self.obj.emit("test-gvalue", GObject.G_MAXUINT64)
- #self.assertEqual(rv, GObject.G_MAXUINT64)
+ rv = self.obj.emit("test-gvalue", GLib.MAXUINT64)
+ self.assertEqual(rv, GLib.MAXUINT64)
def test_gvalue_ret(self):
self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_INT),
- GObject.G_MAXINT)
+ GLib.MAXINT)
self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_UINT),
- GObject.G_MAXUINT)
+ GLib.MAXUINT)
self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_INT64),
- GObject.G_MAXINT64)
+ GLib.MAXINT64)
self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_UINT64),
- GObject.G_MAXUINT64)
+ GLib.MAXUINT64)
self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_STRING),
"hello")
-if 'generic-c-marshaller' in GObject.features:
- class TestCMarshaller(_TestCMarshaller, unittest.TestCase):
- pass
-else:
- print()
- print('** WARNING: LIBFFI disabled, not testing')
- print()
+
+class TestCMarshaller(_TestCMarshaller, unittest.TestCase):
+ pass
+
# Test for 374653
@@ -697,6 +689,10 @@ class TestSignalDecorator(unittest.TestCase):
def pulled(self):
self.value -= 1
+ @GObject.Signal(flags=GObject.SignalFlags.DETAILED)
+ def detailed(self):
+ self.value -= 1
+
stomped = GObject.Signal('stomped', arg_types=(int,), doc='this will stomp')
unnamed = GObject.Signal()
@@ -708,7 +704,6 @@ class TestSignalDecorator(unittest.TestCase):
@GObject.SignalOverride
def notify(self, *args, **kargs):
self.overridden_closure_called = True
- #GObject.GObject.notify(self, *args, **kargs)
def on_notify(self, obj, prop):
self.notify_called = True
@@ -719,6 +714,26 @@ class TestSignalDecorator(unittest.TestCase):
def onUnnamed(self, obj):
self.unnamedCalled = True
+ def test_disconnect(self):
+ decorated = self.Decorated()
+ id_ = decorated.pushed.connect(lambda *args: None)
+ decorated.pushed.disconnect(id_)
+
+ def test_signal_repr(self):
+ decorated = self.Decorated()
+ assert repr(decorated.pushed) == 'BoundSignal("pushed")'
+
+ def test_signal_call(self):
+ decorated = self.Decorated()
+ assert decorated.value == 0
+ decorated.pushed()
+ assert decorated.value == 1
+
+ def test_connect_detailed(self):
+ decorated = self.Decorated()
+ id_ = decorated.detailed.connect_detailed(lambda *args: None, "foo")
+ decorated.pushed.disconnect(id_)
+
def test_get_signal_args(self):
self.assertEqual(self.Decorated.pushed.get_signal_args(),
(GObject.SignalFlags.RUN_FIRST, None, tuple(), None, None))
@@ -760,13 +775,12 @@ class TestSignalDecorator(unittest.TestCase):
obj.emit('unnamed')
self.assertEqual(self.unnamedCalled, True)
- def NOtest_overridden_signal(self):
+ def test_overridden_signal(self):
# Test that the pushed signal is called in with super and the override
# which should both increment the "value" to 3
obj = self.DecoratedOverride()
obj.connect("notify", obj.on_notify)
self.assertEqual(obj.value, 0)
- #obj.notify.emit()
obj.value = 1
self.assertEqual(obj.value, 1)
self.assertTrue(obj.overridden_closure_called)
@@ -847,6 +861,114 @@ class TestSignalConnectors(unittest.TestCase):
self.assertEqual(self.value, 3)
+class _ConnectDataTestBase(object):
+ # Notes:
+ # - self.Object is overridden in sub-classes.
+ # - Numeric suffixes indicate the number of user data args passed in.
+ Object = None
+
+ def run_connect_test(self, emit_args, user_data, flags=0):
+ obj = self.Object()
+ callback_args = []
+
+ def callback(*args):
+ callback_args.append(args)
+ return 0
+
+ obj.connect_data('sig-with-int64-prop', callback, connect_flags=flags, *user_data)
+ obj.emit('sig-with-int64-prop', *emit_args)
+ self.assertEqual(len(callback_args), 1)
+ return callback_args[0]
+
+ def test_0(self):
+ obj, value = self.run_connect_test([GLib.MAXINT64], user_data=[])
+ self.assertIsInstance(obj, self.Object)
+ self.assertEqual(value, GLib.MAXINT64)
+
+ def test_1(self):
+ obj, value, data = self.run_connect_test([GLib.MAXINT64],
+ user_data=['mydata'])
+ self.assertIsInstance(obj, self.Object)
+ self.assertEqual(value, GLib.MAXINT64)
+ self.assertEqual(data, 'mydata')
+
+ def test_after_0(self):
+ obj, value = self.run_connect_test([GLib.MAXINT64],
+ user_data=[],
+ flags=GObject.ConnectFlags.AFTER)
+ self.assertIsInstance(obj, self.Object)
+ self.assertEqual(value, GLib.MAXINT64)
+
+ def test_after_1(self):
+ obj, value, data = self.run_connect_test([GLib.MAXINT64],
+ user_data=['mydata'],
+ flags=GObject.ConnectFlags.AFTER)
+ self.assertIsInstance(obj, self.Object)
+ self.assertEqual(value, GLib.MAXINT64)
+ self.assertEqual(data, 'mydata')
+
+ def test_swaped_0(self):
+ # Swapped only works with a single user data argument.
+ with self.assertRaises(ValueError):
+ self.run_connect_test([GLib.MAXINT64],
+ user_data=[],
+ flags=GObject.ConnectFlags.SWAPPED)
+
+ def test_swaped_1(self):
+ # Notice obj and data are reversed in the return.
+ data, value, obj = self.run_connect_test([GLib.MAXINT64],
+ user_data=['mydata'],
+ flags=GObject.ConnectFlags.SWAPPED)
+ self.assertIsInstance(obj, self.Object)
+ self.assertEqual(value, GLib.MAXINT64)
+ self.assertEqual(data, 'mydata')
+
+ def test_swaped_2(self):
+ # Swapped only works with a single user data argument.
+ with self.assertRaises(ValueError):
+ self.run_connect_test([GLib.MAXINT64],
+ user_data=[1, 2],
+ flags=GObject.ConnectFlags.SWAPPED)
+
+ def test_after_and_swapped_0(self):
+ # Swapped only works with a single user data argument.
+ with self.assertRaises(ValueError):
+ self.run_connect_test([GLib.MAXINT64],
+ user_data=[],
+ flags=GObject.ConnectFlags.AFTER | GObject.ConnectFlags.SWAPPED)
+
+ def test_after_and_swapped_1(self):
+ # Notice obj and data are reversed in the return.
+ data, value, obj = self.run_connect_test([GLib.MAXINT64],
+ user_data=['mydata'],
+ flags=GObject.ConnectFlags.AFTER | GObject.ConnectFlags.SWAPPED)
+ self.assertIsInstance(obj, self.Object)
+ self.assertEqual(value, GLib.MAXINT64)
+ self.assertEqual(data, 'mydata')
+
+ def test_after_and_swapped_2(self):
+ # Swapped only works with a single user data argument.
+ with self.assertRaises(ValueError):
+ self.run_connect_test([GLib.MAXINT64],
+ user_data=[],
+ flags=GObject.ConnectFlags.AFTER | GObject.ConnectFlags.SWAPPED)
+
+
+class TestConnectDataNonIntrospected(unittest.TestCase, _ConnectDataTestBase):
+ # This tests connect_data with non-introspected signals
+ # (created in Python in this case).
+ class Object(GObject.Object):
+ test = GObject.Signal()
+ sig_with_int64_prop = GObject.Signal(return_type=GObject.TYPE_INT64,
+ arg_types=[GObject.TYPE_INT64],
+ flags=GObject.SignalFlags.RUN_LAST)
+
+
+class TestConnectDataIntrospected(unittest.TestCase, _ConnectDataTestBase):
+ # This tests connect_data with introspected signals brought in from Regress.
+ Object = Regress.TestObj
+
+
class TestInstallSignals(unittest.TestCase):
# These tests only test how signalhelper.install_signals works
# with the __gsignals__ dict and therefore does not need to use
@@ -890,29 +1012,16 @@ class TestInstallSignals(unittest.TestCase):
self.assertTrue(hasattr(self.Sub2, 'do_sub2test'))
-# For this test to work with both python2 and 3 we need to dynamically
-# exec the given code due to the new syntax causing an error in python 2.
-annotated_class_code = """
-class AnnotatedSignalClass(GObject.GObject):
- @GObject.Signal
- def sig1(self, a:int, b:float):
- pass
-
- @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST)
- def sig2_with_return(self, a:int, b:float) -> str:
- return "test"
-"""
-
-
-@unittest.skipUnless(sys.version_info >= (3, 0),
- 'Argument annotations require Python 3')
class TestPython3Signals(unittest.TestCase):
- AnnotatedClass = None
- def setUp(self):
- exec(annotated_class_code, globals(), globals())
- self.assertTrue('AnnotatedSignalClass' in globals())
- self.AnnotatedClass = globals()['AnnotatedSignalClass']
+ class AnnotatedClass(GObject.GObject):
+ @GObject.Signal
+ def sig1(self, a: int, b: float):
+ pass
+
+ @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST)
+ def sig2_with_return(self, a: int, b: float) -> str:
+ return "test"
def test_annotations(self):
self.assertEqual(signalhelper.get_signal_annotations(self.AnnotatedClass.sig1.func),
@@ -981,5 +1090,473 @@ class TestSignalModuleLevelFunctions(unittest.TestCase):
None)
-if __name__ == '__main__':
- unittest.main()
+class TestIntrospectedSignals(unittest.TestCase):
+ def test_object_param_signal(self):
+ obj = Regress.TestObj()
+
+ def callback(obj, obj_param):
+ self.assertEqual(obj_param.props.int, 3)
+ self.assertGreater(obj_param.__grefcount__, 1)
+ obj.called = True
+
+ obj.called = False
+ obj.connect('sig-with-obj', callback)
+ obj.emit_sig_with_obj()
+ self.assertTrue(obj.called)
+
+ def test_connect_after(self):
+ obj = Regress.TestObj()
+
+ def callback(obj, obj_param):
+ obj.called = True
+
+ obj.called = False
+ obj.connect_after('sig-with-obj', callback)
+ obj.emit_sig_with_obj()
+ self.assertTrue(obj.called)
+
+ def test_int64_param_from_py(self):
+ obj = Regress.TestObj()
+
+ def callback(obj, i):
+ obj.callback_i = i
+ return i
+
+ obj.callback_i = None
+ obj.connect('sig-with-int64-prop', callback)
+ rv = obj.emit('sig-with-int64-prop', GLib.MAXINT64)
+ self.assertEqual(rv, GLib.MAXINT64)
+ self.assertEqual(obj.callback_i, GLib.MAXINT64)
+
+ def test_uint64_param_from_py(self):
+ obj = Regress.TestObj()
+
+ def callback(obj, i):
+ obj.callback_i = i
+ return i
+
+ obj.callback_i = None
+ obj.connect('sig-with-uint64-prop', callback)
+ rv = obj.emit('sig-with-uint64-prop', GLib.MAXUINT64)
+ self.assertEqual(rv, GLib.MAXUINT64)
+ self.assertEqual(obj.callback_i, GLib.MAXUINT64)
+
+ def test_int64_param_from_c(self):
+ obj = Regress.TestObj()
+
+ def callback(obj, i):
+ obj.callback_i = i
+ return i
+
+ obj.callback_i = None
+
+ obj.connect('sig-with-int64-prop', callback)
+ obj.emit_sig_with_int64()
+ self.assertEqual(obj.callback_i, GLib.MAXINT64)
+
+ def test_uint64_param_from_c(self):
+ obj = Regress.TestObj()
+
+ def callback(obj, i):
+ obj.callback_i = i
+ return i
+
+ obj.callback_i = None
+
+ obj.connect('sig-with-uint64-prop', callback)
+ obj.emit_sig_with_uint64()
+ self.assertEqual(obj.callback_i, GLib.MAXUINT64)
+
+ def test_intarray_ret(self):
+ obj = Regress.TestObj()
+
+ def callback(obj, i):
+ obj.callback_i = i
+ return [i, i + 1]
+
+ obj.callback_i = None
+
+ try:
+ obj.connect('sig-with-intarray-ret', callback)
+ except TypeError as e:
+ # compat with g-i 1.34.x
+ if 'unknown signal' in str(e):
+ return
+ raise
+
+ rv = obj.emit('sig-with-intarray-ret', 42)
+ self.assertEqual(obj.callback_i, 42)
+ self.assertEqual(type(rv), GLib.Array)
+ self.assertEqual(rv.len, 2)
+
+ @unittest.skip('https://bugzilla.gnome.org/show_bug.cgi?id=669496')
+ def test_array_parm(self):
+ obj = Regress.TestObj()
+
+ def callback(obj, arr):
+ obj.callback_arr = arr
+
+ obj.connect('sig-with-array-prop', callback)
+ obj.callback_arr = None
+ self.assertEqual(obj.emit('sig-with-array-prop', [1, 2, GLib.MAXUINT]), None)
+ self.assertEqual(obj.callback_arr, [1, 2, GLib.MAXUINT])
+
+ def test_held_struct_ref(self):
+ held_structs = []
+
+ def callback(obj, struct):
+ # The struct held by Python will become a copy after this callback exits.
+ struct.some_int = 42
+ struct.some_int8 = 42
+ held_structs.append(struct)
+
+ struct = Regress.TestSimpleBoxedA()
+ obj = Regress.TestObj()
+
+ self.assertEqual(struct.some_int, 0)
+ self.assertEqual(struct.some_int8, 0)
+
+ obj.connect('test-with-static-scope-arg', callback)
+ obj.emit('test-with-static-scope-arg', struct)
+
+ # The held struct will be a copy of the modified struct.
+ self.assertEqual(len(held_structs), 1)
+ held_struct = held_structs[0]
+ self.assertEqual(held_struct.some_int, 42)
+ self.assertEqual(held_struct.some_int8, 42)
+
+ # Boxed equality checks pointers by default.
+ self.assertNotEqual(struct, held_struct)
+
+ def test_action(self):
+ obj = Regress.TestAction()
+ other_obj = obj.emit('action')
+ self.assertEqual(other_obj.__grefcount__, 1)
+ other_obj2 = obj.emit('action2')
+ self.assertIsNone(other_obj2)
+
+
+class TestIntrospectedSignalsIssue158(unittest.TestCase):
+ """
+ The test for https://gitlab.gnome.org/GNOME/pygobject/issues/158
+ """
+ _obj_sig_names = [sig.get_name() for sig in repo.find_by_name('Regress', 'TestObj').get_signals()]
+
+ def __init__(self, *args):
+ unittest.TestCase.__init__(self, *args)
+ self._gc_thread_stop = False
+
+ def _gc_thread(self):
+ while not self._gc_thread_stop:
+ gc.collect()
+ time.sleep(0.010)
+
+ def _callback(self, *args):
+ pass
+
+ def test_run(self):
+ """
+ Manually trigger GC from a different thread periodicaly
+ while the main thread keeps connecting/disconnecting to/from signals.
+
+ It takes a lot of time to reproduce the issue. It is possible to make it
+ fail reliably by changing the code of pygobject_unwatch_closure slightly from:
+ PyGObjectData *inst_data = data;
+ inst_data->closures = g_slist_remove (inst_data->closures, closure);
+ to
+ PyGObjectData *inst_data = data;
+ GSList *tmp = g_slist_remove (inst_data->closures, closure);
+ g_usleep(G_USEC_PER_SEC/10);
+ inst_data->closures = tmp;
+ """
+ obj = Regress.TestObj()
+ gc_thread = threading.Thread(target=self._gc_thread)
+ gc_thread.start()
+
+ for _ in range(8):
+ handlers = [obj.connect(sig, self._callback) for sig in self._obj_sig_names]
+ time.sleep(0.010)
+ while len(handlers) > 0:
+ obj.disconnect(handlers.pop())
+
+ self._gc_thread_stop = True
+ gc_thread.join()
+
+
+class _ConnectObjectTestBase(object):
+ # Notes:
+ # - self.Object is overridden in sub-classes.
+ # - Numeric suffixes indicate the number of user data args passed in.
+ Object = None
+ SwapObject = None
+
+ def run_connect_test(self, emit_args, user_data, flags=0):
+ obj = self.Object()
+ callback_args = []
+ swap_obj = self.SwapObject()
+
+ def callback(*args):
+ callback_args.append(args)
+ return 0
+
+ if flags & GObject.ConnectFlags.AFTER:
+ connect_func = obj.connect_object_after
+ else:
+ connect_func = obj.connect_object
+
+ with capture_gi_deprecation_warnings():
+ connect_func('sig-with-int64-prop', callback, swap_obj, *user_data)
+ obj.emit('sig-with-int64-prop', *emit_args)
+ self.assertEqual(len(callback_args), 1)
+ return callback_args[0]
+
+ def test_0(self):
+ obj, value = self.run_connect_test([GLib.MAXINT64], user_data=[])
+ self.assertIsInstance(obj, self.SwapObject)
+ self.assertEqual(value, GLib.MAXINT64)
+
+ def test_1(self):
+ obj, value, data = self.run_connect_test([GLib.MAXINT64],
+ user_data=['mydata'])
+ self.assertIsInstance(obj, self.SwapObject)
+ self.assertEqual(value, GLib.MAXINT64)
+ self.assertEqual(data, 'mydata')
+
+ def test_2(self):
+ obj, value, data1, data2 = self.run_connect_test([GLib.MAXINT64],
+ user_data=['mydata1', 'mydata2'])
+ self.assertIsInstance(obj, self.SwapObject)
+ self.assertEqual(value, GLib.MAXINT64)
+ self.assertEqual(data1, 'mydata1')
+ self.assertEqual(data2, 'mydata2')
+
+ def test_after_0(self):
+ obj, value = self.run_connect_test([GLib.MAXINT64],
+ user_data=[],
+ flags=GObject.ConnectFlags.AFTER)
+ self.assertIsInstance(obj, self.SwapObject)
+ self.assertEqual(value, GLib.MAXINT64)
+
+ def test_after_1(self):
+ obj, value, data = self.run_connect_test([GLib.MAXINT64],
+ user_data=['mydata'],
+ flags=GObject.ConnectFlags.AFTER)
+ self.assertIsInstance(obj, self.SwapObject)
+ self.assertEqual(value, GLib.MAXINT64)
+ self.assertEqual(data, 'mydata')
+
+ def test_after_2(self):
+ obj, value, data1, data2 = self.run_connect_test([GLib.MAXINT64],
+ user_data=['mydata1', 'mydata2'],
+ flags=GObject.ConnectFlags.AFTER)
+ self.assertIsInstance(obj, self.SwapObject)
+ self.assertEqual(value, GLib.MAXINT64)
+ self.assertEqual(data1, 'mydata1')
+ self.assertEqual(data2, 'mydata2')
+
+
+class TestConnectGObjectNonIntrospected(unittest.TestCase, _ConnectObjectTestBase):
+ # This tests connect_object with non-introspected signals
+ # (created in Python in this case).
+ class Object(GObject.Object):
+ test = GObject.Signal()
+ sig_with_int64_prop = GObject.Signal(return_type=GObject.TYPE_INT64,
+ arg_types=[GObject.TYPE_INT64],
+ flags=GObject.SignalFlags.RUN_LAST)
+
+ # Object passed for swapping is GObject based.
+ class SwapObject(GObject.Object):
+ pass
+
+
+class TestConnectGObjectIntrospected(unittest.TestCase, _ConnectObjectTestBase):
+ # This tests connect_object with introspected signals brought in from Regress.
+ Object = Regress.TestObj
+
+ # Object passed for swapping is GObject based.
+ class SwapObject(GObject.Object):
+ pass
+
+
+class TestConnectPyObjectNonIntrospected(unittest.TestCase, _ConnectObjectTestBase):
+ # This tests connect_object with non-introspected signals
+ # (created in Python in this case).
+ class Object(GObject.Object):
+ test = GObject.Signal()
+ sig_with_int64_prop = GObject.Signal(return_type=GObject.TYPE_INT64,
+ arg_types=[GObject.TYPE_INT64],
+ flags=GObject.SignalFlags.RUN_LAST)
+
+ # Object passed for swapping is pure Python
+ SwapObject = object
+
+
+class TestConnectPyObjectIntrospected(unittest.TestCase, _ConnectObjectTestBase):
+ # This tests connect_object with introspected signals brought in from Regress.
+ Object = Regress.TestObj
+
+ # Object passed for swapping is pure Python
+ SwapObject = object
+
+
+class _RefCountTestBase(object):
+ # NOTE: ref counts are always one more than expected because the getrefcount()
+ # function adds a ref for the input argument.
+
+ # Sub-classes set this
+ Object = None
+
+ class PyData(object):
+ pass
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount")
+ def test_callback_ref_count_del(self):
+ def callback(obj, value):
+ return value // 2
+
+ callback_ref = weakref.ref(callback)
+ self.assertEqual(sys.getrefcount(callback), 2)
+
+ obj = self.Object()
+ obj.connect('sig-with-int64-prop', callback)
+ self.assertEqual(sys.getrefcount(callback), 3)
+
+ del callback
+ self.assertEqual(sys.getrefcount(callback_ref()), 2)
+
+ res = obj.emit('sig-with-int64-prop', 42)
+ self.assertEqual(res, 21)
+ self.assertEqual(sys.getrefcount(callback_ref), 2)
+
+ del obj
+ self.assertIsNone(callback_ref())
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount")
+ def test_callback_ref_count_disconnect(self):
+ def callback(obj, value):
+ return value // 2
+
+ callback_ref = weakref.ref(callback)
+ self.assertEqual(sys.getrefcount(callback), 2)
+
+ obj = self.Object()
+ handler_id = obj.connect('sig-with-int64-prop', callback)
+ self.assertEqual(sys.getrefcount(callback), 3)
+
+ del callback
+ self.assertEqual(sys.getrefcount(callback_ref()), 2)
+
+ res = obj.emit('sig-with-int64-prop', 42)
+ self.assertEqual(res, 21)
+ self.assertEqual(sys.getrefcount(callback_ref), 2)
+
+ obj.disconnect(handler_id)
+ self.assertIsNone(callback_ref())
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount")
+ def test_callback_ref_count_disconnect_by_func(self):
+ def callback(obj, value):
+ return value // 2
+
+ callback_ref = weakref.ref(callback)
+ self.assertEqual(sys.getrefcount(callback), 2)
+
+ obj = self.Object()
+ obj.connect('sig-with-int64-prop', callback)
+ self.assertEqual(sys.getrefcount(callback), 3)
+
+ del callback
+ self.assertEqual(sys.getrefcount(callback_ref()), 2)
+
+ res = obj.emit('sig-with-int64-prop', 42)
+ self.assertEqual(res, 21)
+ self.assertEqual(sys.getrefcount(callback_ref), 2)
+
+ obj.disconnect_by_func(callback_ref())
+ self.assertIsNone(callback_ref())
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount")
+ def test_user_data_ref_count(self):
+ def callback(obj, value, data):
+ return value // 2
+
+ data = self.PyData()
+ data_ref = weakref.ref(data)
+ self.assertEqual(sys.getrefcount(data), 2)
+
+ obj = self.Object()
+ obj.connect('sig-with-int64-prop', callback, data)
+ self.assertEqual(sys.getrefcount(data), 3)
+
+ del data
+ self.assertEqual(sys.getrefcount(data_ref()), 2)
+
+ res = obj.emit('sig-with-int64-prop', 42)
+ self.assertEqual(res, 21)
+ self.assertEqual(sys.getrefcount(data_ref()), 2)
+
+ del obj
+ self.assertIsNone(data_ref())
+
+ @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount")
+ @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=688064
+ def test_object_ref_count(self):
+ # connect_object() should only weakly reference the object passed in
+ # and auto-disconnect the signal when the object is destroyed.
+ def callback(data, value):
+ return value // 2
+
+ data = GObject.Object()
+ data_ref = weakref.ref(data)
+ self.assertEqual(sys.getrefcount(data), 2)
+
+ obj = self.Object()
+ handler_id = obj.connect_object('sig-with-int64-prop', callback, data)
+ self.assertEqual(sys.getrefcount(data), 2)
+
+ res = obj.emit('sig-with-int64-prop', 42)
+ self.assertEqual(res, 21)
+ self.assertEqual(sys.getrefcount(data), 2)
+
+ del data
+
+ self.assertIsNone(data_ref())
+ self.assertFalse(obj.handler_is_connected(handler_id))
+
+
+class TestRefCountsNonIntrospected(unittest.TestCase, _RefCountTestBase):
+ class Object(GObject.Object):
+ sig_with_int64_prop = GObject.Signal(return_type=GObject.TYPE_INT64,
+ arg_types=[GObject.TYPE_INT64],
+ flags=GObject.SignalFlags.RUN_LAST)
+
+
+class TestRefCountsIntrospected(unittest.TestCase, _RefCountTestBase):
+ Object = Regress.TestObj
+
+
+class TestClosureRefCycle(unittest.TestCase):
+
+ def test_closure_ref_cycle_unreachable(self):
+ # https://bugzilla.gnome.org/show_bug.cgi?id=731501
+
+ called = []
+
+ def on_add(store, *args):
+ called.append(store)
+
+ store = Gio.ListStore()
+ store.connect_object('items-changed', on_add, store)
+
+ # Remove all Python references to the object and keep it alive
+ # on the C level.
+ x = Gio.FileInfo()
+ x.set_attribute_object('store', store)
+ del store
+ gc.collect()
+
+ # get it back and trigger the signal
+ x.get_attribute_object('store').append(Gio.FileInfo())
+
+ self.assertEqual(len(called), 1)
+ self.assertTrue(called[0].__grefcount__ > 0)
diff --git a/tests/test_source.py b/tests/test_source.py
index d0e28e4..9249892 100644
--- a/tests/test_source.py
+++ b/tests/test_source.py
@@ -1,11 +1,15 @@
# -*- Mode: Python -*-
+import sys
+import gc
import unittest
import warnings
-from gi.repository import GLib, GObject
+from gi.repository import GLib
from gi import PyGIDeprecationWarning
+from .helper import capture_glib_warnings
+
class Idle(GLib.Idle):
def __init__(self, loop):
@@ -123,18 +127,24 @@ class TestSource(unittest.TestCase):
return s
s = f()
+ gc.collect()
+ gc.collect()
self.assertTrue(s.is_destroyed())
def test_remove(self):
s = GLib.idle_add(dir)
self.assertEqual(GLib.source_remove(s), True)
- # s is now removed, should fail now
- self.assertEqual(GLib.source_remove(s), False)
- # accepts large source IDs (they are unsigned)
- self.assertEqual(GLib.source_remove(GObject.G_MAXINT32), False)
- self.assertEqual(GLib.source_remove(GObject.G_MAXINT32 + 1), False)
- self.assertEqual(GLib.source_remove(GObject.G_MAXUINT32), False)
+ # Removing sources not found cause critical
+ with capture_glib_warnings(allow_criticals=True):
+
+ # s is now removed, should fail now
+ self.assertEqual(GLib.source_remove(s), False)
+
+ # accepts large source IDs (they are unsigned)
+ self.assertEqual(GLib.source_remove(GLib.MAXINT32), False)
+ self.assertEqual(GLib.source_remove(GLib.MAXINT32 + 1), False)
+ self.assertEqual(GLib.source_remove(GLib.MAXUINT32), False)
def test_recurse_property(self):
s = GLib.Idle()
@@ -183,6 +193,7 @@ class TestSource(unittest.TestCase):
GLib.Timeout(20)
GLib.Idle()
+ @unittest.skipIf(sys.platform == "darwin", "hangs")
def test_finalize(self):
self.dispatched = False
self.finalized = False
@@ -199,8 +210,7 @@ class TestSource(unittest.TestCase):
self.finalized = True
source = S()
- id = source.attach()
- print('source id:', id)
+ source.attach()
self.assertFalse(self.finalized)
self.assertFalse(source.is_destroyed())
@@ -212,8 +222,48 @@ class TestSource(unittest.TestCase):
self.assertFalse(self.finalized)
self.assertTrue(source.is_destroyed())
del source
+ gc.collect()
+ gc.collect()
self.assertTrue(self.finalized)
+ def test_python_unref_with_active_source(self):
+ # Tests a Python derived Source which is free'd in the context of
+ # Python, but which was attached to a MainContext (via source.attach())
+ self.dispatched = False
+ self.finalized = False
+
+ class S(GLib.Source):
+ def prepare(s):
+ return (True, 1)
+
+ def check(s):
+ pass
+
+ def dispatch(s, callback, args):
+ self.dispatched = True
+ return False
+
+ def finalize(s):
+ self.finalized = True
+
+ context = GLib.MainContext.new()
+ source = S()
+ id_ = source.attach(context)
+ self.assertFalse(self.finalized)
+ self.assertFalse(source.is_destroyed())
+
+ # Delete the source from Python, it should detach
+ del source
+ gc.collect()
+ gc.collect()
+
+ while context.iteration(may_block=False):
+ pass
+
+ assert self.finalized
+ assert not self.dispatched
+ assert context.find_source_by_id(id_) is None
+
def test_extra_init_args(self):
class SourceWithInitArgs(GLib.Source):
def __init__(self, arg, kwarg=None):
@@ -226,6 +276,7 @@ class TestSource(unittest.TestCase):
self.assertEqual(source.kwarg, 2)
+@unittest.skipIf(sys.platform == "darwin", "hangs")
class TestUserData(unittest.TestCase):
def test_idle_no_data(self):
ml = GLib.MainLoop()
@@ -242,7 +293,7 @@ class TestUserData(unittest.TestCase):
def cb():
ml.quit()
- id = GLib.timeout_add(50, cb)
+ id = GLib.timeout_add(1, cb)
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_DEFAULT)
ml.run()
@@ -282,7 +333,7 @@ class TestUserData(unittest.TestCase):
data['called'] = True
ml.quit()
data = {}
- id = GLib.timeout_add(50, cb, data)
+ id = GLib.timeout_add(1, cb, data)
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_DEFAULT)
ml.run()
@@ -296,7 +347,7 @@ class TestUserData(unittest.TestCase):
data['data2'] = data2
ml.quit()
data = {}
- id = GLib.timeout_add(50, cb, data, 'hello')
+ id = GLib.timeout_add(1, cb, data, 'hello')
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_DEFAULT)
ml.run()
@@ -318,7 +369,7 @@ class TestUserData(unittest.TestCase):
def cb():
ml.quit()
- id = GLib.timeout_add(50, cb, priority=GLib.PRIORITY_HIGH)
+ id = GLib.timeout_add(1, cb, priority=GLib.PRIORITY_HIGH)
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_HIGH)
ml.run()
@@ -343,7 +394,7 @@ class TestUserData(unittest.TestCase):
data['called'] = True
ml.quit()
data = {}
- id = GLib.timeout_add(50, cb, data, priority=GLib.PRIORITY_HIGH)
+ id = GLib.timeout_add(1, cb, data, priority=GLib.PRIORITY_HIGH)
self.assertEqual(ml.get_context().find_source_by_id(id).priority,
GLib.PRIORITY_HIGH)
ml.run()
@@ -367,7 +418,3 @@ class TestUserData(unittest.TestCase):
GLib.idle_add(self.cb_with_data, data)
self.loop.run()
self.assertTrue(data['called'])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/tests/test_subprocess.py b/tests/test_subprocess.py
index ef4c35e..274a501 100644
--- a/tests/test_subprocess.py
+++ b/tests/test_subprocess.py
@@ -5,75 +5,91 @@ import os
import unittest
import warnings
+import pytest
+
from gi.repository import GLib
from gi import PyGIDeprecationWarning
+from .helper import capture_gi_deprecation_warnings
+
+
+def test_child_watch_add_get_args_various():
+ cb = lambda pid, status: None
+ get_args = GLib._child_watch_add_get_args
+ pid = 42
+ with capture_gi_deprecation_warnings():
+ assert get_args(pid, cb, 2) == (0, pid, cb, (2,))
+
+ with pytest.raises(TypeError):
+ get_args(pid, cb, 2, 3, 4)
+
+ assert get_args(0, pid, 2, 3, function=cb) == (0, pid, cb, (2, 3))
+ assert get_args(0, pid, cb, 2, 3) == (0, pid, cb, (2, 3))
+ assert get_args(0, pid, cb, data=99) == (0, pid, cb, (99,))
+ with pytest.raises(TypeError):
+ get_args(0, pid, 24)
+
+ with pytest.raises(TypeError):
+ get_args(0, pid, cb, 2, 3, data=99)
+
+
+@unittest.skipIf(os.name == "nt", "not on Windows")
class TestProcess(unittest.TestCase):
def test_deprecated_child_watch_no_data(self):
- def cb(pid, status):
- self.status = status
- self.loop.quit()
-
- self.status = None
- self.loop = GLib.MainLoop()
- argv = [sys.executable, '-c', 'import sys']
- pid, stdin, stdout, stderr = GLib.spawn_async(
- argv, flags=GLib.SpawnFlags.DO_NOT_REAP_CHILD)
- pid.close()
+ cb = lambda pid, status: None
+ pid = object()
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
- GLib.child_watch_add(pid, cb)
+ res = GLib._child_watch_add_get_args(pid, cb)
self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning))
- self.loop.run()
- self.assertEqual(self.status, 0)
- def test_deprecated_child_watch_data_priority(self):
- def cb(pid, status, data):
- self.data = data
- self.status = status
- self.loop.quit()
+ self.assertEqual(len(res), 4)
+ self.assertEqual(res[0], GLib.PRIORITY_DEFAULT)
+ self.assertEqual(res[1], pid)
+ self.assertTrue(callable(cb))
+ self.assertSequenceEqual(res[3], [])
- self.status = None
- self.data = None
- self.loop = GLib.MainLoop()
- argv = [sys.executable, '-c', 'import sys']
- pid, stdin, stdout, stderr = GLib.spawn_async(
- argv, flags=GLib.SpawnFlags.DO_NOT_REAP_CHILD)
- pid.close()
+ def test_deprecated_child_watch_data_priority(self):
+ cb = lambda pid, status: None
+ pid = object()
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
- id = GLib.child_watch_add(pid, cb, 12345, GLib.PRIORITY_HIGH)
+ res = GLib._child_watch_add_get_args(pid, cb, 12345, GLib.PRIORITY_HIGH)
self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning))
- self.assertEqual(self.loop.get_context().find_source_by_id(id).priority,
- GLib.PRIORITY_HIGH)
- self.loop.run()
- self.assertEqual(self.data, 12345)
- self.assertEqual(self.status, 0)
- def test_deprecated_child_watch_data_priority_kwargs(self):
- def cb(pid, status, data):
- self.data = data
- self.status = status
- self.loop.quit()
+ self.assertEqual(len(res), 4)
+ self.assertEqual(res[0], GLib.PRIORITY_HIGH)
+ self.assertEqual(res[1], pid)
+ self.assertEqual(res[2], cb)
+ self.assertSequenceEqual(res[3], [12345])
- self.status = None
- self.data = None
- self.loop = GLib.MainLoop()
- argv = [sys.executable, '-c', 'import sys']
- pid, stdin, stdout, stderr = GLib.spawn_async(
- argv, flags=GLib.SpawnFlags.DO_NOT_REAP_CHILD)
- pid.close()
+ def test_deprecated_child_watch_data_priority_kwargs(self):
+ cb = lambda pid, status: None
+ pid = object()
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
- id = GLib.child_watch_add(pid, cb, priority=GLib.PRIORITY_HIGH, data=12345)
+ res = GLib._child_watch_add_get_args(pid, cb, priority=GLib.PRIORITY_HIGH, data=12345)
self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning))
- self.assertEqual(self.loop.get_context().find_source_by_id(id).priority,
- GLib.PRIORITY_HIGH)
- self.loop.run()
- self.assertEqual(self.data, 12345)
- self.assertEqual(self.status, 0)
+
+ self.assertEqual(len(res), 4)
+ self.assertEqual(res[0], GLib.PRIORITY_HIGH)
+ self.assertEqual(res[1], pid)
+ self.assertEqual(res[2], cb)
+ self.assertSequenceEqual(res[3], [12345])
+
+ @unittest.expectedFailure # using keyword args is fully supported by PyGObject machinery
+ def test_child_watch_all_kwargs(self):
+ cb = lambda pid, status: None
+ pid = object()
+
+ res = GLib._child_watch_add_get_args(priority=GLib.PRIORITY_HIGH, pid=pid, function=cb, data=12345)
+ self.assertEqual(len(res), 4)
+ self.assertEqual(res[0], GLib.PRIORITY_HIGH)
+ self.assertEqual(res[1], pid)
+ self.assertEqual(res[2], cb)
+ self.assertSequenceEqual(res[3], [12345])
def test_child_watch_no_data(self):
def cb(pid, status):
@@ -130,6 +146,23 @@ class TestProcess(unittest.TestCase):
self.assertEqual(out, b'hello world!\n')
self.assertEqual(err, b'')
+ def test_spawn_async_with_pipes(self):
+ res, pid, stdin, stdout, stderr = GLib.spawn_async_with_pipes(
+ working_directory=None,
+ argv=['cat'],
+ envp=None,
+ flags=GLib.SpawnFlags.SEARCH_PATH)
+
+ os.write(stdin, b'hello world!\n')
+ os.close(stdin)
+ out = os.read(stdout, 50)
+ os.close(stdout)
+ err = os.read(stderr, 50)
+ os.close(stderr)
+ GLib.spawn_close_pid(pid)
+ self.assertEqual(out, b'hello world!\n')
+ self.assertEqual(err, b'')
+
def test_spawn_async_envp(self):
pid, stdin, stdout, stderr = GLib.spawn_async(
['sh', '-c', 'echo $TEST_VAR'], ['TEST_VAR=moo!'],
@@ -142,5 +175,8 @@ class TestProcess(unittest.TestCase):
self.assertEqual(out, b'moo!\n')
def test_backwards_compat_flags(self):
- self.assertEqual(GLib.SpawnFlags.DO_NOT_REAP_CHILD,
- GLib.SPAWN_DO_NOT_REAP_CHILD)
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', PyGIDeprecationWarning)
+
+ self.assertEqual(GLib.SpawnFlags.DO_NOT_REAP_CHILD,
+ GLib.SPAWN_DO_NOT_REAP_CHILD)
diff --git a/tests/test_thread.py b/tests/test_thread.py
index 3d0557e..8c2d639 100644
--- a/tests/test_thread.py
+++ b/tests/test_thread.py
@@ -1,19 +1,23 @@
# -*- Mode: Python -*-
import unittest
-import testhelper
from gi.repository import GLib
+import testhelper
+
class TestThread(unittest.TestCase):
def setUp(self):
self.main = GLib.MainLoop()
+ self.called = False
def from_thread_cb(self, test, enum):
assert test == self.obj
assert int(enum) == 0
- assert type(enum) != int
+ assert type(enum) is not int
+ self.called = True
+ GLib.idle_add(self.timeout_cb)
def idle_cb(self):
self.obj = testhelper.get_test_thread()
@@ -22,8 +26,9 @@ class TestThread(unittest.TestCase):
def test_extension_module(self):
GLib.idle_add(self.idle_cb)
- GLib.timeout_add(50, self.timeout_cb)
+ GLib.timeout_add(2000, self.timeout_cb)
self.main.run()
+ self.assertTrue(self.called)
def timeout_cb(self):
self.main.quit()
diff --git a/tests/test_typeclass.py b/tests/test_typeclass.py
new file mode 100644
index 0000000..1f34a09
--- /dev/null
+++ b/tests/test_typeclass.py
@@ -0,0 +1,76 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# test_typeclass.py: Tests for GTypeClass related methods and marshalling.
+#
+# Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+import unittest
+
+from gi.repository import GObject
+from gi.repository import GIMarshallingTests
+
+
+class TestCoercion(unittest.TestCase):
+ def test_coerce_from_class(self):
+ prop = GObject.ObjectClass.find_property(GIMarshallingTests.PropertiesObject,
+ 'some-int')
+
+ self.assertIsInstance(prop, GObject.GParamSpec)
+ self.assertEqual(prop.name, 'some-int')
+ self.assertEqual(prop.value_type, GObject.TYPE_INT)
+ self.assertEqual(prop.owner_type,
+ GIMarshallingTests.PropertiesObject.__gtype__)
+
+ def test_coerce_from_gtype(self):
+ gtype = GIMarshallingTests.PropertiesObject.__gtype__
+ prop = GObject.ObjectClass.find_property(gtype, 'some-int')
+
+ self.assertIsInstance(prop, GObject.GParamSpec)
+ self.assertEqual(prop.name, 'some-int')
+ self.assertEqual(prop.value_type, GObject.TYPE_INT)
+ self.assertEqual(prop.owner_type, gtype)
+
+ def test_coerce_from_instance(self):
+ obj = GIMarshallingTests.PropertiesObject()
+ prop = GObject.ObjectClass.find_property(obj, 'some-int')
+
+ self.assertIsInstance(prop, GObject.GParamSpec)
+ self.assertEqual(prop.name, 'some-int')
+ self.assertEqual(prop.value_type, GObject.TYPE_INT)
+ self.assertEqual(prop.owner_type, obj.__gtype__)
+
+ def test_marshalling_error(self):
+ with self.assertRaises(TypeError):
+ GObject.ObjectClass.find_property(object, 'some-int')
+
+ with self.assertRaises(TypeError):
+ GObject.ObjectClass.find_property(42, 'some-int')
+
+
+class TestTypeClassMethodsMovedToClass(unittest.TestCase):
+ def test_list_child_properties(self):
+ pspecs = GIMarshallingTests.PropertiesObject.list_properties()
+ pnames = [pspec.name for pspec in pspecs]
+ self.assertTrue('some-int' in pnames)
+ self.assertTrue('some-float' in pnames)
+ self.assertTrue('some-char' in pnames)
+
+ def test_find_child_property(self):
+ pspec = GIMarshallingTests.PropertiesObject.find_property('some-int')
+ self.assertEqual(pspec.name, 'some-int')
diff --git a/tests/test_unknown.py b/tests/test_unknown.py
new file mode 100644
index 0000000..76fa185
--- /dev/null
+++ b/tests/test_unknown.py
@@ -0,0 +1,29 @@
+# -*- Mode: Python -*-
+
+import unittest
+
+from gi.repository import GObject
+
+import testhelper
+
+
+TestInterface = GObject.GType.from_name('TestInterface')
+
+
+class TestUnknown(unittest.TestCase):
+ def test_unknown_interface(self):
+ obj = testhelper.get_unknown()
+ TestUnknownGType = GObject.GType.from_name('TestUnknown')
+ TestUnknown = GObject.new(TestUnknownGType).__class__
+ assert isinstance(obj, testhelper.Interface)
+ assert isinstance(obj, TestUnknown)
+
+ def test_property(self):
+ obj = testhelper.get_unknown()
+ self.assertEqual(obj.get_property('some-property'), None)
+ obj.set_property('some-property', 'foo')
+
+ def test_unknown_property(self):
+ obj = testhelper.get_unknown()
+ self.assertRaises(TypeError, obj.get_property, 'unknown')
+ self.assertRaises(TypeError, obj.set_property, 'unknown', '1')
diff --git a/tests/testhelpermodule.c b/tests/testhelpermodule.c
index 9b198c3..eb17af8 100644
--- a/tests/testhelpermodule.c
+++ b/tests/testhelpermodule.c
@@ -5,7 +5,12 @@
#include "test-unknown.h"
#include "test-floating.h"
-#include <pyglib-python-compat.h>
+#define PYGI_DEFINE_TYPE(typename, symbol, csymbol) \
+PyTypeObject symbol = { \
+ PyVarObject_HEAD_INIT(NULL, 0) \
+ typename, \
+ sizeof(csymbol) \
+};
static PyObject * _wrap_TestInterface__do_iface_method(PyObject *cls,
PyObject *args,
@@ -29,8 +34,8 @@ test_type_get_type(void)
type_info = (GTypeInfo *)g_new0(GTypeInfo, 1);
g_type_query(parent_type, &query);
- type_info->class_size = query.class_size;
- type_info->instance_size = query.instance_size;
+ type_info->class_size = (guint16)query.class_size;
+ type_info->instance_size = (guint16)query.instance_size;
gtype = g_type_register_static(parent_type,
"TestType", type_info, 0);
@@ -82,7 +87,7 @@ _wrap_test_g_object_new (PyObject * self)
PyObject *rv;
obj = g_object_new(g_type_from_name("PyGObject"), NULL);
- rv = PYGLIB_PyLong_FromLong(obj->ref_count); /* should be == 2 at this point */
+ rv = PyLong_FromLong(obj->ref_count); /* should be == 2 at this point */
g_object_unref(obj);
return rv;
}
@@ -111,7 +116,7 @@ static const PyMethodDef _PyTestInterface_methods[] = {
};
/* TestInterface */
-PYGLIB_DEFINE_TYPE("test.Interface", PyTestInterface_Type, PyObject);
+PYGI_DEFINE_TYPE("test.Interface", PyTestInterface_Type, PyObject);
static PyObject *
_wrap_TestInterface__do_iface_method(PyObject *cls, PyObject *args, PyObject *kwargs)
@@ -136,7 +141,7 @@ _wrap_TestInterface__do_iface_method(PyObject *cls, PyObject *args, PyObject *kw
return Py_None;
}
-PYGLIB_DEFINE_TYPE("testhelper.Unknown", PyTestUnknown_Type, PyGObject);
+PYGI_DEFINE_TYPE("testhelper.Unknown", PyTestUnknown_Type, PyGObject);
static void
_wrap_TestInterface__proxy_do_iface_method(TestInterface *self)
@@ -147,12 +152,12 @@ _wrap_TestInterface__proxy_do_iface_method(TestInterface *self)
PyObject *py_args;
PyObject *py_method;
- __py_state = pyg_gil_state_ensure();
+ __py_state = PyGILState_Ensure();
py_self = pygobject_new((GObject *) self);
if (!py_self) {
if (PyErr_Occurred())
PyErr_Print();
- pyg_gil_state_release(__py_state);
+ PyGILState_Release(__py_state);
return;
}
py_args = PyTuple_New(0);
@@ -162,7 +167,7 @@ _wrap_TestInterface__proxy_do_iface_method(TestInterface *self)
PyErr_Print();
Py_DECREF(py_args);
Py_DECREF(py_self);
- pyg_gil_state_release(__py_state);
+ PyGILState_Release(__py_state);
return;
}
py_retval = PyObject_CallObject(py_method, py_args);
@@ -172,7 +177,7 @@ _wrap_TestInterface__proxy_do_iface_method(TestInterface *self)
Py_DECREF(py_method);
Py_DECREF(py_args);
Py_DECREF(py_self);
- pyg_gil_state_release(__py_state);
+ PyGILState_Release(__py_state);
return;
}
if (py_retval != Py_None) {
@@ -183,7 +188,7 @@ _wrap_TestInterface__proxy_do_iface_method(TestInterface *self)
Py_DECREF(py_method);
Py_DECREF(py_args);
Py_DECREF(py_self);
- pyg_gil_state_release(__py_state);
+ PyGILState_Release(__py_state);
return;
}
@@ -191,7 +196,7 @@ _wrap_TestInterface__proxy_do_iface_method(TestInterface *self)
Py_DECREF(py_method);
Py_DECREF(py_args);
Py_DECREF(py_self);
- pyg_gil_state_release(__py_state);
+ PyGILState_Release(__py_state);
}
static void
@@ -222,10 +227,10 @@ static const GInterfaceInfo __TestInterface__iinfo = {
};
/* TestFloating */
-PYGLIB_DEFINE_TYPE("testhelper.Floating", PyTestFloating_Type, PyGObject);
+PYGI_DEFINE_TYPE("testhelper.Floating", PyTestFloating_Type, PyGObject);
/* TestOwnedByLibrary */
-PYGLIB_DEFINE_TYPE("testhelper.OwnedByLibrary", PyTestOwnedByLibrary_Type, PyGObject);
+PYGI_DEFINE_TYPE("testhelper.OwnedByLibrary", PyTestOwnedByLibrary_Type, PyGObject);
static PyObject *
_wrap_test_owned_by_library_release (PyGObject *self)
@@ -240,7 +245,7 @@ static const PyMethodDef _PyTestOwnedByLibrary_methods[] = {
};
/* TestFloatingAndSunk */
-PYGLIB_DEFINE_TYPE("testhelper.FloatingAndSunk", PyTestFloatingAndSunk_Type, PyGObject);
+PYGI_DEFINE_TYPE("testhelper.FloatingAndSunk", PyTestFloatingAndSunk_Type, PyGObject);
static PyObject *
_wrap_test_floating_and_sunk_release (PyGObject *self)
@@ -357,11 +362,12 @@ test_paramspec_callback (GObject *object)
static GValue *
test_gvalue_callback (GObject *object, const GValue *v)
{
- GValue *ret = g_malloc0 (sizeof (GValue));
+ GValue *ret;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
g_return_val_if_fail (G_IS_VALUE (v), NULL);
+ ret = g_malloc0 (sizeof (GValue));
g_value_init (ret, G_VALUE_TYPE (v));
g_value_copy (v, ret);
return ret;
@@ -370,10 +376,11 @@ test_gvalue_callback (GObject *object, const GValue *v)
static GValue *
test_gvalue_ret_callback (GObject *object, GType type)
{
- GValue *ret = g_malloc0 (sizeof (GValue));
+ GValue *ret;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
+ ret = g_malloc0 (sizeof (GValue));
g_value_init (ret, type);
switch (type) {
@@ -505,6 +512,17 @@ _wrap_test_value(PyObject *self, PyObject *args)
}
static PyObject *
+_wrap_test_state_ensure_release(PyObject *self, PyObject *args)
+{
+ int state = pyg_gil_state_ensure ();
+ pyg_gil_state_release (state);
+
+ Py_RETURN_NONE;
+}
+
+#define PYGI_TYPE_VALUE_ARRAY (g_value_array_get_type())
+
+static PyObject *
_wrap_test_value_array(PyObject *self, PyObject *args)
{
GValue tvalue = {0,}, *value = &tvalue;
@@ -513,7 +531,10 @@ _wrap_test_value_array(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O", &obj))
return NULL;
- g_value_init(value, G_TYPE_VALUE_ARRAY);
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ g_value_init(value, PYGI_TYPE_VALUE_ARRAY);
+ G_GNUC_END_IGNORE_DEPRECATIONS
+
if (pyg_value_from_pyobject(value, obj)) {
PyErr_SetString(PyExc_TypeError, "Could not convert to GValueArray");
return NULL;
@@ -522,6 +543,56 @@ _wrap_test_value_array(PyObject *self, PyObject *args)
return pyg_value_as_pyobject(value, FALSE);
}
+
+static PyObject *
+_wrap_value_array_get_nth_type(PyObject *self, PyObject *args)
+{
+ guint n;
+ GType type;
+ GValue *nth;
+ GValueArray *arr;
+ PyObject *obj;
+
+ if (!PyArg_ParseTuple(args, "OI", &obj, &n))
+ return NULL;
+
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+ if (pyg_boxed_check(obj, G_TYPE_VALUE) &&
+ G_VALUE_HOLDS(pyg_boxed_get(obj, GValue), PYGI_TYPE_VALUE_ARRAY)) {
+ arr = g_value_get_boxed(pyg_boxed_get(obj, GValue));
+ } else if (pyg_boxed_check(obj, PYGI_TYPE_VALUE_ARRAY)) {
+ arr = pyg_boxed_get(obj, GValueArray);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "First argument is not GValueArray");
+ return NULL;
+ }
+
+ if (n >= arr->n_values) {
+ PyErr_SetString(PyExc_TypeError, "Index is out of bounds");
+ return NULL;
+ }
+ nth = g_value_array_get_nth(arr, n);
+ type = G_VALUE_TYPE(nth);
+
+ G_GNUC_END_IGNORE_DEPRECATIONS
+
+ return pyg_type_wrapper_new(type);
+}
+
+static PyObject *
+_wrap_constant_strip_prefix(PyObject *self, PyObject *args)
+{
+ const char *name, *strip_prefix;
+ const gchar *result;
+
+ if (!PyArg_ParseTuple (args, "ss", &name, &strip_prefix))
+ return NULL;
+
+ result = pyg_constant_strip_prefix (name, strip_prefix);
+ return PyUnicode_FromString (result);
+}
+
static PyObject *
_wrap_test_gerror_exception(PyObject *self, PyObject *args)
{
@@ -593,32 +664,101 @@ _wrap_test_floating_and_sunk_get_instance_list (PyObject *self)
return py_list;
}
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+static PyObject *
+_wrap_test_parse_constructor_args (PyObject *self, PyObject *args)
+{
+ char *arg_names[] = {"label", NULL};
+ char *prop_names[] = {"label", NULL};
+ GParameter params[1] = {{0}};
+ PyObject *parsed_args[1];
+ guint nparams = 0;
+
+ if (!PyArg_ParseTuple(args, "O", &(parsed_args[0])))
+ return NULL;
+
+ if (!pyg_parse_constructor_args (
+ TYPE_TEST, arg_names, prop_names, params, &nparams, parsed_args)) {
+ return NULL;
+ }
+
+ return PyLong_FromLong (nparams);
+}
+
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+static PyObject *
+_wrap_test_to_unichar_conv (PyObject * self, PyObject *args)
+{
+ PyObject *obj;
+ gunichar result;
+
+ if (!PyArg_ParseTuple(args, "O", &obj))
+ return NULL;
+
+ if (!pyg_pyobj_to_unichar_conv (obj, &result))
+ return NULL;
+
+ return PyLong_FromLong (result);
+}
+
static PyMethodDef testhelper_functions[] = {
+ { "test_parse_constructor_args", (PyCFunction)_wrap_test_parse_constructor_args, METH_VARARGS },
{ "get_test_thread", (PyCFunction)_wrap_get_test_thread, METH_NOARGS },
+ { "test_to_unichar_conv", (PyCFunction)_wrap_test_to_unichar_conv, METH_VARARGS },
{ "get_unknown", (PyCFunction)_wrap_get_unknown, METH_NOARGS },
{ "create_test_type", (PyCFunction)_wrap_create_test_type, METH_NOARGS },
+ { "test_state_ensure_release", (PyCFunction)_wrap_test_state_ensure_release, METH_NOARGS },
{ "test_g_object_new", (PyCFunction)_wrap_test_g_object_new, METH_NOARGS },
{ "connectcallbacks", (PyCFunction)_wrap_connectcallbacks, METH_VARARGS },
{ "test_value", (PyCFunction)_wrap_test_value, METH_VARARGS },
{ "test_value_array", (PyCFunction)_wrap_test_value_array, METH_VARARGS },
+ { "value_array_get_nth_type", (PyCFunction)_wrap_value_array_get_nth_type, METH_VARARGS },
+ { "constant_strip_prefix", (PyCFunction)_wrap_constant_strip_prefix, METH_VARARGS },
{ "test_gerror_exception", (PyCFunction)_wrap_test_gerror_exception, METH_VARARGS },
{ "owned_by_library_get_instance_list", (PyCFunction)_wrap_test_owned_by_library_get_instance_list, METH_NOARGS },
{ "floating_and_sunk_get_instance_list", (PyCFunction)_wrap_test_floating_and_sunk_get_instance_list, METH_NOARGS },
{ NULL, NULL }
};
-PYGLIB_MODULE_START(testhelper, "testhelper")
-{
+static struct PyModuleDef _testhelpermodule = {
+ PyModuleDef_HEAD_INIT,
+ "testhelper",
+ NULL,
+ -1,
+ testhelper_functions,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+#ifdef __GNUC__
+#define PYGI_MODINIT_FUNC __attribute__((visibility("default"))) PyMODINIT_FUNC
+#else
+#define PYGI_MODINIT_FUNC PyMODINIT_FUNC
+#endif
+
+PYGI_MODINIT_FUNC PyInit_testhelper(void);
+
+PYGI_MODINIT_FUNC PyInit_testhelper(void) {
+ PyObject *module;
+ PyObject *gobject_module;
PyObject *m, *d;
-
- pygobject_init(-1, -1, -1);
+
+ module = PyModule_Create(&_testhelpermodule);
+
+ if ((gobject_module = pygobject_init(-1, -1, -1)) == NULL)
+ return NULL;
+ Py_DECREF (gobject_module);
d = PyModule_GetDict(module);
if ((m = PyImport_ImportModule("gi.repository.GObject")) == NULL) {
PyErr_SetString(PyExc_ImportError,
"could not import gobject");
- return PYGLIB_MODULE_ERROR_RETURN;
+ return NULL;
}
/* TestInterface */
@@ -667,6 +807,7 @@ PYGLIB_MODULE_START(testhelper, "testhelper")
&PyTestFloatingAndSunk_Type,
Py_BuildValue("(O)",
&PyGObject_Type));
+
+ return module;
}
-PYGLIB_MODULE_END
diff --git a/tests/testmodule.py b/tests/testmodule.py
deleted file mode 100644
index 3da8ed5..0000000
--- a/tests/testmodule.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from gi.repository import GObject
-
-
-class PyGObject(GObject.GObject):
- __gtype_name__ = 'PyGObject'
- __gproperties__ = {
- 'label': (GObject.TYPE_STRING,
- 'label property',
- 'the label of the object',
- 'default', GObject.PARAM_READWRITE),
- }
-
- def __init__(self):
- self._props = {}
- GObject.GObject.__init__(self)
- self.set_property('label', 'hello')
-
- def do_set_property(self, name, value):
- self._props[name] = value
-
- def do_get_property(self, name):
- return self._props[name]
diff --git a/tests/valgrind.supp b/tests/valgrind.supp
new file mode 100644
index 0000000..5792a7c
--- /dev/null
+++ b/tests/valgrind.supp
@@ -0,0 +1,30 @@
+# https://bugzilla.redhat.com/show_bug.cgi?id=1538073
+
+{
+ <py36-start1>
+ Memcheck:Cond
+ fun:__wcsnlen_sse4_1
+ fun:wcsrtombs
+ fun:wcstombs
+ fun:wcstombs
+ fun:encode_current_locale*
+}
+
+{
+ <fontconfig>
+ Memcheck:Leak
+ match-leak-kinds: definite
+ fun:malloc
+ fun:FcPatternObjectInsertElt
+ fun:FcPatternObjectAddWithBinding
+}
+
+{
+ <fontconfig-2>
+ Memcheck:Leak
+ match-leak-kinds: definite
+ fun:malloc
+ fun:FcPatternCreate
+ fun:FcParsePattern
+ fun:FcEndElement
+}