diff options
Diffstat (limited to 'tests')
42 files changed, 9486 insertions, 3113 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am index e666696..b845e4b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,19 +1,36 @@ CLEANFILES = -noinst_LTLIBRARIES = libregress.la libgimarshallingtests.la +check_LTLIBRARIES = libgimarshallingtests.la +test_typelibs = GIMarshallingTests-1.0.typelib -nodist_libregress_la_SOURCES = $(GI_DATADIR)/tests/regress.c $(GI_DATADIR)/tests/regress.h -libregress_la_CFLAGS = $(GIO_CFLAGS) $(PYCAIRO_CFLAGS) -libregress_la_LDFLAGS = -module -avoid-version $(GIO_LIBS) $(PYCAIRO_LIBS) 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 -libregress.la: $(libregress_la_OBJECTS) $(libregress_la_DEPENDENCIES) - $(LINK) -rpath $(pkgpyexecdir) $(libregress_la_LDFLAGS) $(libregress_la_OBJECTS) $(libregress_la_LIBADD) $(LIBS) - libgimarshallingtests.la: $(libgimarshallingtests_la_OBJECTS) $(libgimarshallingtests_la_DEPENDENCIES) - $(LINK) -rpath $(pkgpyexecdir) $(libgimarshallingtests_la_LDFLAGS) $(libgimarshallingtests_la_OBJECTS) $(libgimarhallingtests_la_LIBADD) $(LIBS) + $(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 @@ -27,23 +44,15 @@ Regress-1.0.gir: libregress.la Makefile Regress-1.0.typelib: Regress-1.0.gir Makefile $(AM_V_GEN) g-ir-compiler $< -o $@ -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 $@ +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 -noinst_LTLIBRARIES += testhelper.la +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 @@ -56,50 +65,59 @@ testhelper_la_SOURCES = \ # This is a hack to make sure a shared library is built testhelper.la: $(testhelper_la_OBJECTS) $(testhelper_la_DEPENDENCIES) - $(LINK) -rpath $(pkgpyexecdir) $(testhelper_la_LDFLAGS) $(testhelper_la_OBJECTS) $(testhelper_la_LIBADD) $(LIBS) + $(AM_V_GEN) $(LINK) -rpath $(pkgpyexecdir) $(testhelper_la_LDFLAGS) $(testhelper_la_OBJECTS) $(testhelper_la_LIBADD) $(LIBS) .la.so: test -L $@ || $(LN_S) .libs/$@ $@ -all: $(LTLIBRARIES:.la=.so) +all: $(check_LTLIBRARIES:.la=.so) -TEST_FILES_STATIC = \ +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_uris.py - - -TEST_FILES_GI = \ test_everything.py \ test_gi.py \ test_gdbus.py \ test_overrides.py \ - test_pygtkcompat.py - -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 - -EXTRA_DIST += $(TEST_FILES_STATIC) $(TEST_FILES_GI) + 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 $(LTLIBRARIES:.la=.so) file.txt~ + rm -f $(check_LTLIBRARIES:.la=.so) file.txt~ DBUS_LAUNCH=$(shell which dbus-launch) RUN_TESTS_ENV_VARS= \ @@ -107,17 +125,31 @@ RUN_TESTS_ENV_VARS= \ 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) -RUN_TESTS_LAUNCH=$(RUN_TESTS_ENV_VARS) $(DBUS_LAUNCH) $(EXEC_NAME) $(PYTHON) $(srcdir)/runtests.py -check-local: $(LTLIBRARIES:.la=.so) Regress-1.0.typelib GIMarshallingTests-1.0.typelib gschemas.compiled - TEST_FILES="$(TEST_FILES_STATIC)" $(RUN_TESTS_LAUNCH) - TEST_FILES="$(TEST_FILES_GI)" $(RUN_TESTS_LAUNCH) +# 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.valgrind: - EXEC_NAME="valgrind --suppressions=python.supp" G_SLICE=always-malloc G_DEBUG=gc-friendly $(MAKE) check +check.nemiver: + EXEC_NAME="nemiver" $(MAKE) check --include $(top_srcdir)/git.mk +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 index 5744e30..c88e320 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.3 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -14,8 +14,24 @@ # PARTICULAR PURPOSE. @SET_MAKE@ - VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -34,21 +50,22 @@ 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.am $(srcdir)/Makefile.in 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 + $(top_srcdir)/m4/jhflags.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 = -LTLIBRARIES = $(noinst_LTLIBRARIES) libgimarshallingtests_la_LIBADD = nodist_libgimarshallingtests_la_OBJECTS = \ libgimarshallingtests_la-gimarshallingtests.lo @@ -62,11 +79,13 @@ libgimarshallingtests_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(libgimarshallingtests_la_CFLAGS) $(CFLAGS) \ $(libgimarshallingtests_la_LDFLAGS) $(LDFLAGS) -o $@ libregress_la_LIBADD = -nodist_libregress_la_OBJECTS = libregress_la-regress.lo +@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 \ @@ -105,6 +124,11 @@ am__v_GEN_0 = @echo " GEN " $@; 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 ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -118,9 +142,14 @@ 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@ @@ -138,6 +167,7 @@ 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@ @@ -157,6 +187,7 @@ 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@ @@ -166,7 +197,6 @@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ @@ -201,6 +231,7 @@ 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@ @@ -209,6 +240,7 @@ 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@ @@ -268,14 +300,15 @@ top_srcdir = @top_srcdir@ CLEANFILES = Regress-1.0.gir Regress-1.0.typelib \ GIMarshallingTests-1.0.gir GIMarshallingTests-1.0.typelib \ gschemas.compiled -noinst_LTLIBRARIES = libregress.la libgimarshallingtests.la \ +check_LTLIBRARIES = libgimarshallingtests.la $(am__append_1) \ testhelper.la -nodist_libregress_la_SOURCES = $(GI_DATADIR)/tests/regress.c $(GI_DATADIR)/tests/regress.h -libregress_la_CFLAGS = $(GIO_CFLAGS) $(PYCAIRO_CFLAGS) -libregress_la_LDFLAGS = -module -avoid-version $(GIO_LIBS) $(PYCAIRO_LIBS) +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) @@ -285,43 +318,64 @@ testhelper_la_SOURCES = \ test-thread.c \ test-unknown.c -TEST_FILES_STATIC = \ +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_uris.py - -TEST_FILES_GI = \ test_everything.py \ test_gi.py \ test_gdbus.py \ test_overrides.py \ - test_pygtkcompat.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) -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_FILES_STATIC) \ - $(TEST_FILES_GI) 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) -RUN_TESTS_LAUNCH = $(RUN_TESTS_ENV_VARS) $(DBUS_LAUNCH) $(EXEC_NAME) $(PYTHON) $(srcdir)/runtests.py all: all-am .SUFFIXES: .SUFFIXES: .c .la .lo .o .obj .so -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ @@ -346,20 +400,22 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) +$(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): -clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) - @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ +clean-checkLTLIBRARIES: + -test -z "$(check_LTLIBRARIES)" || rm -f $(check_LTLIBRARIES) + @list='$(check_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done +@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) @@ -526,9 +582,10 @@ distdir: $(DISTFILES) fi; \ done check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) $(MAKE) $(AM_MAKEFLAGS) check-local check: check-am -all-am: Makefile $(LTLIBRARIES) +all-am: Makefile installdirs: install: install-am install-exec: install-exec-am @@ -563,8 +620,8 @@ maintainer-clean-generic: @echo "it deletes files that may require special tools to rebuild." clean: clean-am -clean-am: clean-generic clean-libtool clean-local \ - clean-noinstLTLIBRARIES mostlyclean-am +clean-am: clean-checkLTLIBRARIES clean-generic clean-libtool \ + clean-local mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) @@ -635,38 +692,23 @@ uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am check-local clean \ - clean-generic clean-libtool clean-local \ - clean-noinstLTLIBRARIES ctags 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 \ + clean-checkLTLIBRARIES clean-generic clean-libtool clean-local \ + ctags 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 uninstall uninstall-am # This is a hack to make sure a shared library is built -libregress.la: $(libregress_la_OBJECTS) $(libregress_la_DEPENDENCIES) - $(LINK) -rpath $(pkgpyexecdir) $(libregress_la_LDFLAGS) $(libregress_la_OBJECTS) $(libregress_la_LIBADD) $(LIBS) - libgimarshallingtests.la: $(libgimarshallingtests_la_OBJECTS) $(libgimarshallingtests_la_DEPENDENCIES) - $(LINK) -rpath $(pkgpyexecdir) $(libgimarshallingtests_la_LDFLAGS) $(libgimarshallingtests_la_OBJECTS) $(libgimarhallingtests_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 $@ + $(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 \ @@ -679,32 +721,59 @@ GIMarshallingTests-1.0.gir: libgimarshallingtests.la Makefile 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) - $(LINK) -rpath $(pkgpyexecdir) $(testhelper_la_LDFLAGS) $(testhelper_la_OBJECTS) $(testhelper_la_LIBADD) $(LIBS) + $(AM_V_GEN) $(LINK) -rpath $(pkgpyexecdir) $(testhelper_la_LDFLAGS) $(testhelper_la_OBJECTS) $(testhelper_la_LIBADD) $(LIBS) .la.so: test -L $@ || $(LN_S) .libs/$@ $@ -all: $(LTLIBRARIES:.la=.so) +all: $(check_LTLIBRARIES:.la=.so) clean-local: - rm -f $(LTLIBRARIES:.la=.so) file.txt~ - -check-local: $(LTLIBRARIES:.la=.so) Regress-1.0.typelib GIMarshallingTests-1.0.typelib gschemas.compiled - TEST_FILES="$(TEST_FILES_STATIC)" $(RUN_TESTS_LAUNCH) - TEST_FILES="$(TEST_FILES_GI)" $(RUN_TESTS_LAUNCH) + 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.valgrind: - EXEC_NAME="valgrind --suppressions=python.supp" G_SLICE=always-malloc G_DEBUG=gc-friendly $(MAKE) check +check.nemiver: + EXEC_NAME="nemiver" $(MAKE) check --include $(top_srcdir)/git.mk +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. diff --git a/tests/compat_test_pygtk.py b/tests/compat_test_pygtk.py new file mode 100644 index 0000000..10be6a3 --- /dev/null +++ b/tests/compat_test_pygtk.py @@ -0,0 +1,147 @@ +# -*- 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 index 2465747..668e60a 100644 --- a/tests/compathelper.py +++ b/tests/compathelper.py @@ -49,7 +49,7 @@ if sys.version_info >= (3, 0): 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 + 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 diff --git a/tests/gi/__init__.py b/tests/gi/__init__.py new file mode 100644 index 0000000..3ad9513 --- /dev/null +++ b/tests/gi/__init__.py @@ -0,0 +1,2 @@ +from pkgutil import extend_path +__path__ = extend_path(__path__, __name__) diff --git a/tests/gi/overrides/Regress.py b/tests/gi/overrides/Regress.py new file mode 100644 index 0000000..cb38631 --- /dev/null +++ b/tests/gi/overrides/Regress.py @@ -0,0 +1,26 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2012 Martin Pitt <martinpitt@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 + +from ..importer import modules + +Regress = modules['Regress']._introspection_module + +REGRESS_OVERRIDE = 42 +__all__ = ['REGRESS_OVERRIDE'] diff --git a/tests/gi/overrides/__init__.py b/tests/gi/overrides/__init__.py new file mode 100644 index 0000000..3ad9513 --- /dev/null +++ b/tests/gi/overrides/__init__.py @@ -0,0 +1,2 @@ +from pkgutil import extend_path +__path__ = extend_path(__path__, __name__) diff --git a/tests/org.gnome.test.gschema.xml b/tests/org.gnome.test.gschema.xml index 221b87a..eb9aab8 100644 --- a/tests/org.gnome.test.gschema.xml +++ b/tests/org.gnome.test.gschema.xml @@ -1,4 +1,10 @@ <schemalist> + <enum id="org.gnome.test.FruitType"> + <value nick="banana" value="0"/> + <value nick="apple" value="1"/> + <value nick="pear" value="2"/> + </enum> + <schema id="org.gnome.test" path="/tests/"> <key name="test-boolean" type="b"> <default>true</default> @@ -12,6 +18,9 @@ <key name="test-array" type="ai"> <default>[1,2]</default> </key> + <key name="test-enum" enum="org.gnome.test.FruitType"> + <default>'banana'</default> + </key> </schema> <schema id="org.gnome.nopathtest"> diff --git a/tests/runtests-windows.py b/tests/runtests-windows.py index ae81202..36ab9e1 100644 --- a/tests/runtests-windows.py +++ b/tests/runtests-windows.py @@ -7,8 +7,16 @@ 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.path.insert(0, os.path.dirname(__file__)) sys.argv.append('--g-fatal-warnings') from gi.repository import GObject diff --git a/tests/runtests.py b/tests/runtests.py index 2a8ecf4..6085ff9 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -7,28 +7,49 @@ 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() + 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]) + 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("test_*.py"): - names.append(filename[:-3]) + 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) @@ -38,5 +59,4 @@ suite = loader.loadTestsFromNames(names) runner = unittest.TextTestRunner(verbosity=2) result = runner.run(suite) if not result.wasSuccessful(): - sys.exit(1) # exit code so "make check" reports error - + sys.exit(1) # exit code so "make check" reports error diff --git a/tests/test-thread.c b/tests/test-thread.c index 0f5b909..438cb97 100644 --- a/tests/test-thread.c +++ b/tests/test-thread.c @@ -43,8 +43,7 @@ other_thread_cb (TestThread *self) static void test_thread_emit_signal (TestThread *self) { - self->thread = g_thread_create ((GThreadFunc)other_thread_cb, - self, TRUE, NULL); + self->thread = g_thread_new ("t", (GThreadFunc)other_thread_cb, self); } static void test_thread_init (TestThread *self) {} diff --git a/tests/test-unknown.c b/tests/test-unknown.c index 85aba73..f1c3139 100644 --- a/tests/test-unknown.c +++ b/tests/test-unknown.c @@ -53,7 +53,7 @@ test_interface_get_type (void) return gtype; } -void test_unknown_iface_method (TestInterface *iface) +static void test_unknown_iface_method (TestInterface *iface) { } diff --git a/tests/test_atoms.py b/tests/test_atoms.py new file mode 100644 index 0000000..1561dbd --- /dev/null +++ b/tests/test_atoms.py @@ -0,0 +1,77 @@ +import unittest + +try: + from gi.repository import Atk, Gdk, Gtk + (Atk, Gdk) # pyflakes +except: + Gdk = None + + +@unittest.skipUnless(Gdk, 'Gdk not available') +class TestGdkAtom(unittest.TestCase): + def test_create(self): + atom = Gdk.Atom.intern('my_string', False) + self.assertEqual(atom.name(), 'my_string') + + def test_str(self): + atom = Gdk.Atom.intern('my_string', False) + self.assertEqual(str(atom), 'my_string') + + self.assertEqual(str(Gdk.SELECTION_CLIPBOARD), 'CLIPBOARD') + + def test_repr(self): + atom = Gdk.Atom.intern('my_string', False) + self.assertEqual(repr(atom), 'Gdk.Atom<my_string>') + + self.assertEqual(repr(Gdk.SELECTION_CLIPBOARD), 'Gdk.Atom<CLIPBOARD>') + + def test_in_single(self): + a_selection = Gdk.Atom.intern('test_clipboard', False) + clipboard = Gtk.Clipboard.get(a_selection) + clipboard.set_text('hello', 5) + + # needs a Gdk.Atom, not a string + self.assertRaises(TypeError, Gtk.Clipboard.get, 'CLIPBOARD') + + def test_in_array(self): + a_plain = Gdk.Atom.intern('text/plain', False) + a_html = Gdk.Atom.intern('text/html', False) + a_jpeg = Gdk.Atom.intern('image/jpeg', False) + + self.assertFalse(Gtk.targets_include_text([])) + self.assertTrue(Gtk.targets_include_text([a_plain, a_html])) + self.assertFalse(Gtk.targets_include_text([a_jpeg])) + self.assertTrue(Gtk.targets_include_text([a_jpeg, a_plain])) + + self.assertFalse(Gtk.targets_include_image([], False)) + self.assertFalse(Gtk.targets_include_image([a_plain, a_html], False)) + self.assertTrue(Gtk.targets_include_image([a_jpeg], False)) + self.assertTrue(Gtk.targets_include_image([a_jpeg, a_plain], False)) + + def test_out_array(self): + a_selection = Gdk.Atom.intern('my_clipboard', False) + clipboard = Gtk.Clipboard.get(a_selection) + + # empty + (res, targets) = clipboard.wait_for_targets() + self.assertEqual(res, False) + self.assertEqual(targets, []) + + # text + clipboard.set_text('hello', 5) + (res, targets) = clipboard.wait_for_targets() + self.assertEqual(res, True) + self.assertNotEqual(targets, []) + self.assertEqual(type(targets[0]), Gdk.Atom) + names = [t.name() for t in targets] + self.assertFalse(None in names, names) + self.assertTrue('TEXT' in names, names) + + def test_out_glist(self): + display = Gdk.Display.get_default() + 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) diff --git a/tests/test_docstring.py b/tests/test_docstring.py new file mode 100644 index 0000000..1628295 --- /dev/null +++ b/tests/test_docstring.py @@ -0,0 +1,49 @@ +import unittest + +import gi.docstring +from gi.repository import GIMarshallingTests + + +class Test(unittest.TestCase): + def test_api(self): + new_func = lambda info: 'docstring test' + old_func = gi.docstring.get_doc_string_generator() + + gi.docstring.set_doc_string_generator(new_func) + self.assertEqual(gi.docstring.get_doc_string_generator(), + new_func) + self.assertEqual(gi.docstring.generate_doc_string(None), + 'docstring test') + + # Set back to original generator + gi.docstring.set_doc_string_generator(old_func) + 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') + + def test_overridden_doc_is_not_clobbered(self): + self.assertEqual(GIMarshallingTests.OverridesObject.method.__doc__, + 'Overridden doc string.') diff --git a/tests/test_everything.py b/tests/test_everything.py index 86ddb42..b2f0528 100644 --- a/tests/test_everything.py +++ b/tests/test_everything.py @@ -3,18 +3,28 @@ # vim: tabstop=4 shiftwidth=4 expandtab import unittest - +import traceback +import ctypes +import warnings import sys -sys.path.insert(0, "../") -from sys import getrefcount -import copy -import cairo +try: + import cairo + has_cairo = True + from gi.repository import Regress as Everything +except ImportError: + has_cairo = False +#import gi from gi.repository import GObject from gi.repository import GLib from gi.repository import Gio -from gi.repository import Regress as Everything + +try: + from gi.repository import Gtk + Gtk # pyflakes +except: + Gtk = None if sys.version_info < (3, 0): UNICHAR = "\xe2\x99\xa5" @@ -23,6 +33,18 @@ else: UNICHAR = "♥" +class RawGList(ctypes.Structure): + _fields_ = [('data', ctypes.c_void_p), + ('next', ctypes.c_void_p), + ('prev', ctypes.c_void_p)] + + @classmethod + def from_wrapped(cls, obj): + offset = sys.getsizeof(object()) # size of PyObject_HEAD + return ctypes.POINTER(cls).from_address(id(obj) + offset) + + +@unittest.skipUnless(has_cairo, 'built without cairo support') class TestEverything(unittest.TestCase): def test_cairo_context(self): @@ -37,16 +59,16 @@ class TestEverything(unittest.TestCase): surface = Everything.test_cairo_surface_none_return() self.assertTrue(isinstance(surface, cairo.ImageSurface)) self.assertTrue(isinstance(surface, cairo.Surface)) - self.assertEquals(surface.get_format(), cairo.FORMAT_ARGB32) - self.assertEquals(surface.get_width(), 10) - self.assertEquals(surface.get_height(), 10) + 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.assertEquals(surface.get_format(), cairo.FORMAT_ARGB32) - self.assertEquals(surface.get_width(), 10) - self.assertEquals(surface.get_height(), 10) + 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) @@ -54,29 +76,234 @@ class TestEverything(unittest.TestCase): surface = Everything.test_cairo_surface_full_out() self.assertTrue(isinstance(surface, cairo.ImageSurface)) self.assertTrue(isinstance(surface, cairo.Surface)) - self.assertEquals(surface.get_format(), cairo.FORMAT_ARGB32) - self.assertEquals(surface.get_width(), 10) - self.assertEquals(surface.get_height(), 10) + self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32) + self.assertEqual(surface.get_width(), 10) + self.assertEqual(surface.get_height(), 10) + + def test_bool(self): + self.assertEqual(Everything.test_boolean(False), False) + self.assertEqual(Everything.test_boolean(True), True) + self.assertEqual(Everything.test_boolean('hello'), True) + self.assertEqual(Everything.test_boolean(''), False) + + self.assertEqual(Everything.test_boolean_true(True), True) + 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_uint8(0), 0) + self.assertRaises(OverflowError, Everything.test_uint8, -1) + self.assertRaises(OverflowError, Everything.test_uint8, GObject.G_MAXUINT8 + 1) + + 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_uint16(0), 0) + self.assertRaises(OverflowError, Everything.test_uint16, -1) + self.assertRaises(OverflowError, Everything.test_uint16, GObject.G_MAXUINT16 + 1) + + 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_uint32(0), 0) + self.assertRaises(OverflowError, Everything.test_uint32, -1) + self.assertRaises(OverflowError, Everything.test_uint32, GObject.G_MAXUINT32 + 1) + + 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_uint64(0), 0) + self.assertRaises(OverflowError, Everything.test_uint64, -1) + self.assertRaises(OverflowError, Everything.test_uint64, GObject.G_MAXUINT64 + 1) + + 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_uint(0), 0) + self.assertRaises(OverflowError, Everything.test_uint, -1) + self.assertRaises(OverflowError, Everything.test_uint, GObject.G_MAXUINT + 1) + + 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_ushort(0), 0) + self.assertRaises(OverflowError, Everything.test_ushort, -1) + self.assertRaises(OverflowError, Everything.test_ushort, GObject.G_MAXUSHORT + 1) + + 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_ulong(0), 0) + self.assertRaises(OverflowError, Everything.test_ulong, -1) + self.assertRaises(OverflowError, Everything.test_ulong, GObject.G_MAXULONG + 1) + + 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(0), 0) + self.assertRaises(OverflowError, Everything.test_size, -1) + self.assertRaises(OverflowError, Everything.test_size, GObject.G_MAXSIZE + 1) + + def test_timet(self): + self.assertEqual(Everything.test_timet(42), 42) + self.assertRaises(OverflowError, Everything.test_timet, GObject.G_MAXUINT64 + 1) def test_unichar(self): - self.assertEquals("c", Everything.test_unichar("c")) + self.assertEqual("c", Everything.test_unichar("c")) if sys.version_info < (3, 0): - self.assertEquals(UNICHAR, Everything.test_unichar(PY2_UNICODE_UNICHAR)) - self.assertEquals(UNICHAR, Everything.test_unichar(UNICHAR)) + self.assertEqual(UNICHAR, Everything.test_unichar(PY2_UNICODE_UNICHAR)) + self.assertEqual(UNICHAR, Everything.test_unichar(UNICHAR)) 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) + + 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) + + (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) + + def test_variant(self): + v = Everything.test_gvariant_i() + self.assertEqual(v.get_type_string(), 'i') + self.assertEqual(v.get_int32(), 1) + + v = Everything.test_gvariant_s() + self.assertEqual(v.get_type_string(), 's') + self.assertEqual(v.get_string(), 'one') + + v = Everything.test_gvariant_v() + self.assertEqual(v.get_type_string(), 'v') + vi = v.get_variant() + self.assertEqual(vi.get_type_string(), 's') + self.assertEqual(vi.get_string(), 'contents') + + v = Everything.test_gvariant_as() + self.assertEqual(v.get_type_string(), 'as') + self.assertEqual(v.get_strv(), ['one', 'two', 'three']) + + v = Everything.test_gvariant_asv() + self.assertEqual(v.get_type_string(), 'a{sv}') + self.assertEqual(v.lookup_value('nosuchkey', None), None) + name = v.lookup_value('name', None) + self.assertEqual(name.get_string(), 'foo') + 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 + + self.assertEqual(Everything.test_utf8_const_return(), const_str) + self.assertEqual(Everything.test_utf8_nonconst_return(), noconst_str) + self.assertEqual(Everything.test_utf8_out(), noconst_str) + + Everything.test_utf8_const_in(const_str) + self.assertEqual(Everything.test_utf8_inout(const_str), noconst_str) + + self.assertEqual(Everything.test_filename_return(), ['åäö', '/etc/fstab']) + + # 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) + + self.assertEqual(Everything.test_utf8_out_out(), ('first', 'second')) + self.assertEqual(Everything.test_utf8_out_nonconst_return(), ('first', 'second')) + + def test_enum(self): + self.assertEqual(Everything.test_enum_param(Everything.TestEnum.VALUE1), 'value1') + self.assertEqual(Everything.test_enum_param(Everything.TestEnum.VALUE3), 'value3') + self.assertRaises(TypeError, Everything.test_enum_param, 'hello') + + # FIXME: ValueError: invalid enum value: 2147483648 + @unittest.expectedFailure + def test_enum_unsigned(self): + self.assertEqual(Everything.test_unsigned_enum_param(Everything.TestEnumUnsigned.VALUE1), 'value1') + self.assertEqual(Everything.test_unsigned_enum_param(Everything.TestEnumUnsigned.VALUE3), 'value3') + self.assertRaises(TypeError, Everything.test_unsigned_enum_param, 'hello') + + def test_flags(self): + result = Everything.global_get_flags_out() + # assert that it's not an int + self.assertEqual(type(result), Everything.TestFlags) + self.assertEqual(result, Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3) def test_floating(self): e = Everything.TestFloating() - self.assertEquals(e.__grefcount__, 1) + self.assertEqual(e.__grefcount__, 1) e = GObject.new(Everything.TestFloating) - self.assertEquals(e.__grefcount__, 1) + self.assertEqual(e.__grefcount__, 1) e = Everything.TestFloating.new() - self.assertEquals(e.__grefcount__, 1) + self.assertEqual(e.__grefcount__, 1) def test_caller_allocates(self): struct_a = Everything.TestStructA() @@ -87,10 +314,10 @@ class TestEverything(unittest.TestCase): struct_a_clone = struct_a.clone() self.assertTrue(struct_a != struct_a_clone) - self.assertEquals(struct_a.some_int, struct_a_clone.some_int) - self.assertEquals(struct_a.some_int8, struct_a_clone.some_int8) - self.assertEquals(struct_a.some_double, struct_a_clone.some_double) - self.assertEquals(struct_a.some_enum, struct_a_clone.some_enum) + self.assertEqual(struct_a.some_int, struct_a_clone.some_int) + self.assertEqual(struct_a.some_int8, struct_a_clone.some_int8) + self.assertEqual(struct_a.some_double, struct_a_clone.some_double) + self.assertEqual(struct_a.some_enum, struct_a_clone.some_enum) struct_b = Everything.TestStructB() struct_b.some_int8 = 8 @@ -101,30 +328,33 @@ class TestEverything(unittest.TestCase): struct_b_clone = struct_b.clone() self.assertTrue(struct_b != struct_b_clone) - self.assertEquals(struct_b.some_int8, struct_b_clone.some_int8) - self.assertEquals(struct_b.nested_a.some_int, struct_b_clone.nested_a.some_int) - self.assertEquals(struct_b.nested_a.some_int8, struct_b_clone.nested_a.some_int8) - self.assertEquals(struct_b.nested_a.some_double, struct_b_clone.nested_a.some_double) - self.assertEquals(struct_b.nested_a.some_enum, struct_b_clone.nested_a.some_enum) + self.assertEqual(struct_b.some_int8, struct_b_clone.some_int8) + self.assertEqual(struct_b.nested_a.some_int, struct_b_clone.nested_a.some_int) + self.assertEqual(struct_b.nested_a.some_int8, struct_b_clone.nested_a.some_int8) + self.assertEqual(struct_b.nested_a.some_double, struct_b_clone.nested_a.some_double) + self.assertEqual(struct_b.nested_a.some_enum, struct_b_clone.nested_a.some_enum) + + struct_a = Everything.test_struct_a_parse('ignored') + self.assertEqual(struct_a.some_int, 23) def test_wrong_type_of_arguments(self): try: Everything.test_int8() except TypeError: (e_type, e) = sys.exc_info()[:2] - self.assertEquals(e.args, ("test_int8() takes exactly 1 argument (0 given)",)) + self.assertEqual(e.args, ("test_int8() takes exactly 1 argument (0 given)",)) def test_gtypes(self): gchararray_gtype = GObject.type_from_name('gchararray') gtype = Everything.test_gtype(str) - self.assertEquals(gchararray_gtype, gtype) + self.assertEqual(gchararray_gtype, gtype) gtype = Everything.test_gtype('gchararray') - self.assertEquals(gchararray_gtype, gtype) + self.assertEqual(gchararray_gtype, gtype) gobject_gtype = GObject.GObject.__gtype__ gtype = Everything.test_gtype(GObject.GObject) - self.assertEquals(gobject_gtype, gtype) + self.assertEqual(gobject_gtype, gtype) gtype = Everything.test_gtype('GObject') - self.assertEquals(gobject_gtype, gtype) + self.assertEqual(gobject_gtype, gtype) self.assertRaises(TypeError, Everything.test_gtype, 'invalidgtype') class NotARegisteredClass(object): @@ -136,60 +366,187 @@ class TestEverything(unittest.TestCase): __gtype_name__ = 'EverythingTestsARegisteredClass' gtype = Everything.test_gtype('EverythingTestsARegisteredClass') - self.assertEquals(ARegisteredClass.__gtype__, gtype) + self.assertEqual(ARegisteredClass.__gtype__, gtype) gtype = Everything.test_gtype(ARegisteredClass) - self.assertEquals(ARegisteredClass.__gtype__, gtype) + self.assertEqual(ARegisteredClass.__gtype__, gtype) self.assertRaises(TypeError, Everything.test_gtype, 'ARegisteredClass') - + def test_dir(self): attr_list = dir(Everything) - + # test that typelib attributes are listed self.assertTrue('TestStructA' in attr_list) - + # test that class attributes and methods are listed self.assertTrue('__class__' in attr_list) self.assertTrue('__dir__' in attr_list) self.assertTrue('__repr__' in attr_list) - + # test that instance members are listed self.assertTrue('_namespace' in attr_list) self.assertTrue('_version' in attr_list) - + # test that there are no duplicates returned self.assertEqual(len(attr_list), len(set(attr_list))) + def test_array(self): + self.assertEqual(Everything.test_array_int_in([]), 0) + self.assertEqual(Everything.test_array_int_in([1, 5, -2]), 4) + self.assertEqual(Everything.test_array_int_out(), [0, 1, 2, 3, 4]) + self.assertEqual(Everything.test_array_int_full_out(), [0, 1, 2, 3, 4]) + self.assertEqual(Everything.test_array_int_none_out(), [1, 2, 3, 4, 5]) + 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) + self.assertEqual(Everything.test_array_gint8_in([1, 3, 5, -50]), -41) + self.assertEqual(Everything.test_array_gint16_in([256, 257, -1000, 10000]), 9513) + self.assertEqual(Everything.test_array_gint32_in([30000, 1, -2]), 29999) + self.assertEqual(Everything.test_array_gint64_in([2 ** 33, 2 ** 34]), 2 ** 33 + 2 ** 34) + + 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): + # fixed length of 5 + self.assertEqual(Everything.test_array_fixed_size_int_in([1, 2, -10, 5, 3]), 1) + 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]) + + self.assertEqual(Everything.test_array_fixed_size_int_out(), [0, 1, 2, 3, 4]) + self.assertEqual(Everything.test_array_fixed_size_int_return(), [0, 1, 2, 3, 4]) + def test_ptrarray(self): # transfer container result = Everything.test_garray_container_return() - self.assertEquals (result, ['regress']) + self.assertEqual(result, ['regress']) result = None # transfer full result = Everything.test_garray_full_return() - self.assertEquals (result, ['regress']) + self.assertEqual(result, ['regress']) + result = None + + def test_strv(self): + self.assertEqual(Everything.test_strv_out(), ['thanks', 'for', 'all', 'the', 'fish']) + self.assertEqual(Everything.test_strv_out_c(), ['thanks', 'for', 'all', 'the', 'fish']) + self.assertEqual(Everything.test_strv_out_container(), ['1', '2', '3']) + self.assertEqual(Everything.test_strv_outarg(), ['1', '2', '3']) + + self.assertEqual(Everything.test_strv_in_gvalue(), ['one', 'two', 'three']) + + Everything.test_strv_in(['1', '2', '3']) + + def test_glist(self): + self.assertEqual(Everything.test_glist_nothing_return(), ['1', '2', '3']) + self.assertEqual(Everything.test_glist_nothing_return2(), ['1', '2', '3']) + self.assertEqual(Everything.test_glist_container_return(), ['1', '2', '3']) + self.assertEqual(Everything.test_glist_everything_return(), ['1', '2', '3']) + + Everything.test_glist_nothing_in(['1', '2', '3']) + Everything.test_glist_nothing_in2(['1', '2', '3']) + + def test_gslist(self): + self.assertEqual(Everything.test_gslist_nothing_return(), ['1', '2', '3']) + self.assertEqual(Everything.test_gslist_nothing_return2(), ['1', '2', '3']) + self.assertEqual(Everything.test_gslist_container_return(), ['1', '2', '3']) + self.assertEqual(Everything.test_gslist_everything_return(), ['1', '2', '3']) + + Everything.test_gslist_nothing_in(['1', '2', '3']) + Everything.test_gslist_nothing_in2(['1', '2', '3']) + + def test_hash_return(self): + expected = {'foo': 'bar', 'baz': 'bat', 'qux': 'quux'} + + self.assertEqual(Everything.test_ghash_null_return(), None) + self.assertEqual(Everything.test_ghash_nothing_return(), expected) + self.assertEqual(Everything.test_ghash_nothing_return(), expected) + self.assertEqual(Everything.test_ghash_container_return(), expected) + self.assertEqual(Everything.test_ghash_everything_return(), expected) + + result = Everything.test_ghash_gvalue_return() + self.assertEqual(result['integer'], 12) + self.assertEqual(result['boolean'], True) + self.assertEqual(result['string'], 'some text') + self.assertEqual(result['strings'], ['first', 'second', 'third']) + self.assertEqual(result['flags'], Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3) + self.assertEqual(result['enum'], Everything.TestEnum.VALUE2) result = None + # FIXME: CRITICAL **: Unsupported type ghash + def disabled_test_hash_return_nested(self): + self.assertEqual(Everything.test_ghash_nested_everything_return(), {}) + self.assertEqual(Everything.test_ghash_nested_everything_return2(), {}) + + def test_hash_in(self): + expected = {'foo': 'bar', 'baz': 'bat', 'qux': 'quux'} + + Everything.test_ghash_nothing_in(expected) + Everything.test_ghash_nothing_in2(expected) + + def test_hash_in_with_typed_strv(self): + class GStrv(list): + __gtype__ = GObject.TYPE_STRV + + data = {'integer': 12, + 'boolean': True, + 'string': 'some text', + 'strings': GStrv(['first', 'second', 'third']), + 'flags': Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3, + 'enum': Everything.TestEnum.VALUE2, + } + Everything.test_ghash_gvalue_in(data) + data = None + + def test_hash_in_with_gvalue_strv(self): + data = {'integer': 12, + 'boolean': True, + 'string': 'some text', + 'strings': GObject.Value(GObject.TYPE_STRV, ['first', 'second', 'third']), + 'flags': Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3, + 'enum': Everything.TestEnum.VALUE2, + } + Everything.test_ghash_gvalue_in(data) + data = None + def test_struct_gpointer(self): - l1 = GLib.List() - self.assertEqual(l1.data, None) - init_refcount = getrefcount(l1) + glist = GLib.List() + raw = RawGList.from_wrapped(glist) + + # Note that pointer fields use 0 for NULL in PyGObject and None in ctypes + self.assertEqual(glist.data, 0) + self.assertEqual(raw.contents.data, None) - l1.data = 'foo' - self.assertEqual(l1.data, 'foo') + glist.data = 123 + self.assertEqual(glist.data, 123) + self.assertEqual(raw.contents.data, 123) - l2 = l1 - self.assertEqual(l1.data, l2.data) - self.assertEquals(getrefcount(l1), init_refcount+1) + glist.data = None + self.assertEqual(glist.data, 0) + self.assertEqual(raw.contents.data, None) - l3 = copy.copy(l1) - l3.data = 'bar' - self.assertEqual(l1.data, 'foo') - self.assertEqual(l2.data, 'foo') - self.assertEqual(l3.data, 'bar') - self.assertEquals(getrefcount(l1), init_refcount+1) - self.assertEquals(getrefcount(l3), init_refcount) + # Setting to anything other than an int should raise + self.assertRaises(TypeError, setattr, glist.data, 'nan') + self.assertRaises(TypeError, setattr, glist.data, object()) + self.assertRaises(TypeError, setattr, glist.data, 123.321) + def test_struct_opaque(self): + # we should get a sensible error message + try: + Everything.TestBoxedPrivate() + self.fail('allocating disguised struct without default constructor unexpectedly succeeded') + except TypeError: + (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) + + +@unittest.skipUnless(has_cairo, 'built without cairo support') class TestNullableArgs(unittest.TestCase): def test_in_nullable_hash(self): Everything.test_ghash_null_in(None) @@ -227,15 +584,17 @@ 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 = GObject.MainLoop() + main_loop = GLib.MainLoop() def test_callback(self): TestCallbacks.called = False + def callback(): TestCallbacks.called = True - + Everything.test_simple_callback(callback) self.assertTrue(TestCallbacks.called) @@ -246,11 +605,12 @@ class TestCallbacks(unittest.TestCase): """ def callback(): x = 1 / 0 - - try: - Everything.test_simple_callback(callback) - except ZeroDivisionError: - pass + self.fail('unexpected surviving zero divsion:' + str(x)) + + # 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) def test_double_callback_exception(self): """ @@ -259,79 +619,107 @@ class TestCallbacks(unittest.TestCase): """ def badcallback(): x = 1 / 0 + self.fail('unexpected surviving zero divsion:' + str(x)) def callback(): Everything.test_boolean(True) Everything.test_boolean(False) Everything.test_simple_callback(badcallback()) - try: - Everything.test_simple_callback(callback) - except ZeroDivisionError: - pass + # 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) def test_return_value_callback(self): TestCallbacks.called = False + def callback(): TestCallbacks.called = True return 44 - self.assertEquals(Everything.test_callback(callback), 44) + self.assertEqual(Everything.test_callback(callback), 44) self.assertTrue(TestCallbacks.called) - - def test_callback_async(self): + + def test_callback_scope_async(self): TestCallbacks.called = False - def callback(foo): + ud = 'Test Value 44' + + def callback(user_data): + self.assertEqual(user_data, ud) TestCallbacks.called = True - return foo + return 44 + + ud_refcount = sys.getrefcount(ud) + callback_refcount = sys.getrefcount(callback) - Everything.test_callback_async(callback, 44); - i = Everything.test_callback_thaw_async(); - self.assertEquals(44, i); + 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) + + # test_callback_thaw_async will run the callback previously supplied. + # references should be auto decremented after this call. + self.assertEqual(Everything.test_callback_thaw_async(), 44) self.assertTrue(TestCallbacks.called) - def test_callback_scope_call(self): + # Make sure refcounts are returned to normal + 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 + # single scope call in python. TestCallbacks.called = 0 + def callback(): TestCallbacks.called += 1 - return 0 + return TestCallbacks.called - Everything.test_multi_callback(callback) - self.assertEquals(TestCallbacks.called, 2) + 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) + + def test_callback_scope_call_array(self): + # This tests a callback that gets called multiple times from a + # single scope call in python with array arguments + TestCallbacks.callargs = [] + + # FIXME: would be cleaner without the explicit length args: + # def callback(one, two): + def callback(one, one_length, two, two_length): + TestCallbacks.callargs.append((one, two)) + return len(TestCallbacks.callargs) + + 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) def test_callback_userdata(self): TestCallbacks.called = 0 + def callback(userdata): - self.assertEquals(userdata, "Test%d" % TestCallbacks.called) + self.assertEqual(userdata, "Test%d" % TestCallbacks.called) TestCallbacks.called += 1 return TestCallbacks.called - - for i in range(100): - val = Everything.test_callback_user_data(callback, "Test%d" % i) - self.assertEquals(val, i+1) - - self.assertEquals(TestCallbacks.called, 100) - def test_callback_userdata_refcount(self): - TestCallbacks.called = False - def callback(userdata): - TestCallbacks.called = True - return 1 - - ud = "Test User Data" - - start_ref_count = getrefcount(ud) for i in range(100): - Everything.test_callback_destroy_notify(callback, ud) - - Everything.test_callback_thaw_notifications() - end_ref_count = getrefcount(ud) + val = Everything.test_callback_user_data(callback, "Test%d" % i) + self.assertEqual(val, i + 1) - self.assertEquals(start_ref_count, end_ref_count) + self.assertEqual(TestCallbacks.called, 100) def test_async_ready_callback(self): TestCallbacks.called = False - TestCallbacks.main_loop = GObject.MainLoop() + TestCallbacks.main_loop = GLib.MainLoop() def callback(obj, result, user_data): TestCallbacks.main_loop.quit() @@ -343,15 +731,73 @@ class TestCallbacks(unittest.TestCase): self.assertTrue(TestCallbacks.called) - def test_callback_destroy_notify(self): + def test_callback_scope_notified_with_destroy(self): + TestCallbacks.called = 0 + ud = 'Test scope notified data 33' + def callback(user_data): - TestCallbacks.called = True - return 42 + self.assertEqual(user_data, ud) + TestCallbacks.called += 1 + return 33 - TestCallbacks.called = False - self.assertEquals(Everything.test_callback_destroy_notify(callback, 42), 42) - self.assertTrue(TestCallbacks.called) - self.assertEquals(Everything.test_callback_thaw_notifications(), 42) + value_refcount = sys.getrefcount(ud) + callback_refcount = sys.getrefcount(callback) + + # Callback is immediately called. + for i in range(100): + res = Everything.test_callback_destroy_notify(callback, ud) + 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) + + # 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) + + def test_callback_scope_notified_with_destroy_no_user_data(self): + TestCallbacks.called = 0 + + def callback(user_data): + self.assertEqual(user_data, None) + TestCallbacks.called += 1 + return 34 + + callback_refcount = sys.getrefcount(callback) + + # Run with warning as exception + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("error") + self.assertRaises(RuntimeWarning, + Everything.test_callback_destroy_notify_no_user_data, + callback) + + self.assertEqual(TestCallbacks.called, 0) + self.assertEqual(sys.getrefcount(callback), callback_refcount) + + # Run with warning as warning + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("default") + # Trigger a warning. + res = Everything.test_callback_destroy_notify_no_user_data(callback) + # Verify some things + self.assertEqual(len(w), 1) + self.assertTrue(issubclass(w[-1].category, RuntimeWarning)) + self.assertTrue('Callables passed to' in str(w[-1].message)) + + self.assertEqual(res, 34) + self.assertEqual(TestCallbacks.called, 1) + 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) def test_callback_in_methods(self): object_ = Everything.TestObj() @@ -369,12 +815,17 @@ class TestCallbacks(unittest.TestCase): self.assertTrue(TestCallbacks.called) def callbackWithUserData(user_data): - TestCallbacks.called = True + TestCallbacks.called += 1 return 42 - TestCallbacks.called = False - obj_ = Everything.TestObj.new_callback(callbackWithUserData, None) - self.assertTrue(TestCallbacks.called) + TestCallbacks.called = 0 + Everything.TestObj.new_callback(callbackWithUserData, None) + self.assertEqual(TestCallbacks.called, 1) + # Note: using "new_callback" adds the notification to the same global + # list as Everything.test_callback_destroy_notify, so thaw the list + # so we don't get confusion between tests. + self.assertEqual(Everything.test_callback_thaw_notifications(), 42) + self.assertEqual(TestCallbacks.called, 2) def test_callback_none(self): # make sure this doesn't assert or crash @@ -417,29 +868,41 @@ class TestCallbacks(unittest.TestCase): mydict['new'] = 42 TestCallbacks.called = True - mydict = { 'foo': 1, 'bar': 2 } + mydict = {'foo': 1, 'bar': 2} TestCallbacks.called = False Everything.test_hash_table_callback(mydict, callback) self.assertTrue(TestCallbacks.called) - self.assertEqual(mydict, { 'foo': 1, 'bar': 2, 'new': 42 }) + 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(): + self.called = True + return 42 + + self.called = False + result = Everything.test_closure(callback) + self.assertTrue(self.called) + self.assertEqual(result, 42) + def test_int_arg(self): def callback(num): self.called = True - return num+1 + return num + 1 self.called = False result = Everything.test_closure_one_arg(callback, 42) self.assertTrue(self.called) self.assertEqual(result, 43) - # https://bugzilla.gnome.org/show_bug.cgi?id=656554 - @unittest.expectedFailure def test_variant(self): def callback(variant): - self.assertEqual(variant.get_type_string(), 'i') self.called = True + if variant is None: + return None + self.assertEqual(variant.get_type_string(), 'i') return GLib.Variant('i', variant.get_int32() + 1) self.called = False @@ -448,58 +911,142 @@ class TestClosures(unittest.TestCase): self.assertEqual(result.get_type_string(), 'i') self.assertEqual(result.get_int32(), 43) + self.called = False + result = Everything.test_closure_variant(callback, None) + self.assertTrue(self.called) + self.assertEqual(result, None) + + self.called = False + self.assertRaises(TypeError, Everything.test_closure_variant, callback, 'foo') + self.assertFalse(self.called) + + def test_variant_wrong_return_type(self): + 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)) + # ... 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.assertEquals(object_.props.int, 0) + self.assertEqual(object_.props.int, 0) object_.props.int = 42 self.assertTrue(isinstance(object_.props.int, int)) - self.assertEquals(object_.props.int, 42) + self.assertEqual(object_.props.int, 42) - self.assertEquals(object_.props.float, 0.0) + self.assertEqual(object_.props.float, 0.0) object_.props.float = 42.42 self.assertTrue(isinstance(object_.props.float, float)) - self.assertAlmostEquals(object_.props.float, 42.42, places=5) + self.assertAlmostEqual(object_.props.float, 42.42, places=5) - self.assertEquals(object_.props.double, 0.0) + self.assertEqual(object_.props.double, 0.0) object_.props.double = 42.42 self.assertTrue(isinstance(object_.props.double, float)) - self.assertAlmostEquals(object_.props.double, 42.42, places=5) + self.assertAlmostEqual(object_.props.double, 42.42, places=5) - self.assertEquals(object_.props.string, None) + self.assertEqual(object_.props.string, None) object_.props.string = 'mec' self.assertTrue(isinstance(object_.props.string, str)) - self.assertEquals(object_.props.string, 'mec') + 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.assertEquals(object_.props.hash_table, None) + self.assertEqual(object_.props.hash_table, None) object_.props.hash_table = {'mec': 56} self.assertTrue(isinstance(object_.props.hash_table, dict)) - self.assertEquals(list(object_.props.hash_table.items())[0], ('mec', 56)) + self.assertEqual(list(object_.props.hash_table.items())[0], ('mec', 56)) def test_list(self): object_ = Everything.TestObj() - self.assertEquals(object_.props.list, []) + self.assertEqual(object_.props.list, []) object_.props.list = ['1', '2', '3'] self.assertTrue(isinstance(object_.props.list, list)) - self.assertEquals(object_.props.list, ['1', '2', '3']) + self.assertEqual(object_.props.list, ['1', '2', '3']) def test_boxed(self): object_ = Everything.TestObj() - self.assertEquals(object_.props.boxed, None) + self.assertEqual(object_.props.boxed, None) boxed = Everything.TestBoxed() boxed.some_int8 = 42 object_.props.boxed = boxed self.assertTrue(isinstance(object_.props.boxed, Everything.TestBoxed)) - self.assertEquals(object_.props.boxed.some_int8, 42) + self.assertEqual(object_.props.boxed.some_int8, 42) + + def test_boxed_alternative_constructor(self): + boxed = Everything.TestBoxed.new_alternative_constructor1(5) + self.assertEqual(boxed.some_int8, 5) + + boxed = Everything.TestBoxed.new_alternative_constructor2(5, 3) + self.assertEqual(boxed.some_int8, 8) + + boxed = Everything.TestBoxed.new_alternative_constructor3("-3") + self.assertEqual(boxed.some_int8, -3) + + def test_boxed_equality(self): + boxed42 = Everything.TestBoxed.new_alternative_constructor1(42) + boxed5 = Everything.TestBoxed.new_alternative_constructor1(5) + boxed42_2 = Everything.TestBoxed.new_alternative_constructor2(41, 1) + + self.assertFalse(boxed42.equals(boxed5)) + self.assertTrue(boxed42.equals(boxed42_2)) + self.assertTrue(boxed42_2.equals(boxed42)) + self.assertTrue(boxed42.equals(boxed42)) + def test_boxed_c_equality(self): + boxed = Everything.TestBoxedC() + # TestBoxedC uses refcounting, so we know that + # the pointer is the same when copied + copy = boxed.copy() + 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) + + a = A() + a.props.int = 20 + self.assertEqual(a.props.int, 20) + + # test parent property which needs introspection + a.props.list = ("str1", "str2") + self.assertEqual(a.props.list, ["str1", "str2"]) + + +@unittest.skipUnless(has_cairo, 'built without cairo support') class TestTortureProfile(unittest.TestCase): def test_torture_profile(self): import time @@ -510,9 +1057,9 @@ class TestTortureProfile(unittest.TestCase): start_time = time.clock() for i in range(10000): - (y,z,q) = object_.torture_signature_0(5000, - "Torture Test 1", - 12345) + (y, z, q) = object_.torture_signature_0(5000, + "Torture Test 1", + 12345) end_time = time.clock() delta_time = end_time - start_time @@ -523,23 +1070,20 @@ class TestTortureProfile(unittest.TestCase): start_time = time.clock() for i in range(10000): - (y,z,q) = Everything.TestObj().torture_signature_0(5000, - "Torture Test 2", - 12345) + (y, z, q) = Everything.TestObj().torture_signature_0( + 5000, "Torture Test 2", 12345) end_time = time.clock() 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() for i in range(10000): try: - (y,z,q) = object_.torture_signature_1(5000, - "Torture Test 3", - 12345) + (y, z, q) = object_.torture_signature_1( + 5000, "Torture Test 3", 12345) except: pass end_time = time.clock() @@ -548,17 +1092,15 @@ class TestTortureProfile(unittest.TestCase): print("%f secs" % delta_time) sys.stdout.write("\ttorture test 4 (10000 iterations): ") + def callback(userdata): pass - userdata = [1,2,3,4] + userdata = [1, 2, 3, 4] start_time = time.clock() for i in range(10000): - (y,z,q) = Everything.test_torture_signature_2(5000, - callback, - userdata, - "Torture Test 4", - 12345) + (y, z, q) = Everything.test_torture_signature_2( + 5000, callback, userdata, "Torture Test 4", 12345) end_time = time.clock() delta_time = end_time - start_time total_time += delta_time @@ -566,6 +1108,8 @@ class TestTortureProfile(unittest.TestCase): print("\t====") 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() @@ -574,28 +1118,149 @@ class TestAdvancedInterfaces(unittest.TestCase): self.assertNotEqual(obj1, obj2) def test_obj_skip_return_val(self): - obj = Everything.TestObj(); - ret = obj.skip_return_val(50, 42.0, 60, 2, 3); - self.assertEquals(len(ret), 3); - self.assertEquals(ret[0], 51); - self.assertEquals(ret[1], 61); - self.assertEquals(ret[2], 32); + obj = Everything.TestObj() + ret = obj.skip_return_val(50, 42.0, 60, 2, 3) + self.assertEqual(len(ret), 3) + self.assertEqual(ret[0], 51) + self.assertEqual(ret[1], 61) + self.assertEqual(ret[2], 32) def test_obj_skip_return_val_no_out(self): - obj = Everything.TestObj(); + obj = Everything.TestObj() # raises an error for 0, succeeds for any other value self.assertRaises(GLib.GError, obj.skip_return_val_no_out, 0) ret = obj.skip_return_val_no_out(1) - self.assertEquals(ret, None) + 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(); + obj = Everything.TestObj() def callback(obj, obj_param): - self.assertEquals(obj_param.props.int, 3) + 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_gdbus.py b/tests/test_gdbus.py index 5db5d93..805633a 100644 --- a/tests/test_gdbus.py +++ b/tests/test_gdbus.py @@ -3,34 +3,34 @@ import unittest -import sys -sys.path.insert(0, "../") - -from gi.repository import GObject from gi.repository import GLib from gi.repository import Gio + class TestGDBusClient(unittest.TestCase): def setUp(self): self.bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) self.dbus_proxy = Gio.DBusProxy.new_sync(self.bus, - Gio.DBusProxyFlags.NONE, None, - 'org.freedesktop.DBus', - '/org/freedesktop/DBus', - 'org.freedesktop.DBus', None) + Gio.DBusProxyFlags.NONE, + None, + 'org.freedesktop.DBus', + '/org/freedesktop/DBus', + 'org.freedesktop.DBus', + None) def test_native_calls_sync(self): - result = self.dbus_proxy.call_sync('ListNames', None, - Gio.DBusCallFlags.NO_AUTO_START, 500, None) + result = self.dbus_proxy.call_sync('ListNames', None, + Gio.DBusCallFlags.NO_AUTO_START, + 500, None) self.assertTrue(isinstance(result, GLib.Variant)) - result = result.unpack()[0] # result is always a tuple + result = result.unpack()[0] # result is always a tuple self.assertTrue(len(result) > 1) self.assertTrue('org.freedesktop.DBus' in result) - result = self.dbus_proxy.call_sync('GetNameOwner', - GLib.Variant('(s)', ('org.freedesktop.DBus',)), - Gio.DBusCallFlags.NO_AUTO_START, 500, None) + result = self.dbus_proxy.call_sync('GetNameOwner', + GLib.Variant('(s)', ('org.freedesktop.DBus',)), + Gio.DBusCallFlags.NO_AUTO_START, 500, None) self.assertTrue(isinstance(result, GLib.Variant)) self.assertEqual(type(result.unpack()[0]), type('')) @@ -38,16 +38,16 @@ class TestGDBusClient(unittest.TestCase): # error case: invalid argument types try: self.dbus_proxy.call_sync('GetConnectionUnixProcessID', None, - Gio.DBusCallFlags.NO_AUTO_START, 500, None) + Gio.DBusCallFlags.NO_AUTO_START, 500, None) self.fail('call with invalid arguments should raise an exception') except Exception as e: self.assertTrue('InvalidArgs' in str(e)) # error case: invalid argument try: - self.dbus_proxy.call_sync('GetConnectionUnixProcessID', - GLib.Variant('(s)', (' unknown',)), - Gio.DBusCallFlags.NO_AUTO_START, 500, None) + self.dbus_proxy.call_sync('GetConnectionUnixProcessID', + GLib.Variant('(s)', (' unknown',)), + Gio.DBusCallFlags.NO_AUTO_START, 500, None) self.fail('call with invalid arguments should raise an exception') except Exception as e: self.assertTrue('NameHasNoOwner' in str(e)) @@ -55,7 +55,7 @@ class TestGDBusClient(unittest.TestCase): # error case: unknown method try: self.dbus_proxy.call_sync('UnknownMethod', None, - Gio.DBusCallFlags.NO_AUTO_START, 500, None) + Gio.DBusCallFlags.NO_AUTO_START, 500, None) self.fail('call for unknown method should raise an exception') except Exception as e: self.assertTrue('UnknownMethod' in str(e)) @@ -67,15 +67,15 @@ class TestGDBusClient(unittest.TestCase): finally: user_data['main_loop'].quit() - main_loop = GObject.MainLoop() + main_loop = GLib.MainLoop() data = {'main_loop': main_loop} - self.dbus_proxy.call('ListNames', None, - Gio.DBusCallFlags.NO_AUTO_START, 500, None, - call_done, data) + self.dbus_proxy.call('ListNames', None, + Gio.DBusCallFlags.NO_AUTO_START, 500, None, + call_done, data) main_loop.run() self.assertTrue(isinstance(data['result'], GLib.Variant)) - result = data['result'].unpack()[0] # result is always a tuple + result = data['result'].unpack()[0] # result is always a tuple self.assertTrue(len(result) > 1) self.assertTrue('org.freedesktop.DBus' in result) @@ -89,10 +89,11 @@ class TestGDBusClient(unittest.TestCase): finally: user_data['main_loop'].quit() - main_loop = GObject.MainLoop() + main_loop = GLib.MainLoop() data = {'main_loop': main_loop} self.dbus_proxy.call('UnknownMethod', None, - Gio.DBusCallFlags.NO_AUTO_START, 500, None, call_done, data) + Gio.DBusCallFlags.NO_AUTO_START, 500, None, + call_done, data) main_loop.run() def test_python_calls_sync(self): @@ -112,12 +113,13 @@ class TestGDBusClient(unittest.TestCase): # does not have any method returning multiple results, so try talking # to notification-daemon (and don't fail the test if it does not exist) try: - notification_daemon = Gio.DBusProxy.new_sync(self.bus, - Gio.DBusProxyFlags.NONE, None, - 'org.freedesktop.Notifications', - '/org/freedesktop/Notifications', - 'org.freedesktop.Notifications', None) - result = notification_daemon.GetServerInformation('()') + nd = Gio.DBusProxy.new_sync(self.bus, + Gio.DBusProxyFlags.NONE, None, + 'org.freedesktop.Notifications', + '/org/freedesktop/Notifications', + 'org.freedesktop.Notifications', + None) + result = nd.GetServerInformation('()') self.assertTrue(isinstance(result, tuple)) self.assertEqual(len(result), 4) for i in result: @@ -128,10 +130,12 @@ class TestGDBusClient(unittest.TestCase): # test keyword argument; timeout=0 will fail immediately try: - self.dbus_proxy.GetConnectionUnixProcessID('()', timeout=0) + self.dbus_proxy.GetConnectionUnixProcessID('(s)', '1', timeout=0) self.fail('call with timeout=0 should raise an exception') except Exception as e: - self.assertTrue('Timeout' in str(e), str(e)) + # FIXME: this is not very precise, but in some environments we + # do not always get an actual timeout + self.assertTrue(isinstance(e, GLib.GError), str(e)) def test_python_calls_sync_noargs(self): # methods without arguments don't need an explicit signature @@ -159,10 +163,9 @@ class TestGDBusClient(unittest.TestCase): user_data['result'] = result user_data['main_loop'].quit() - main_loop = GObject.MainLoop() + main_loop = GLib.MainLoop() data = {'main_loop': main_loop} - self.dbus_proxy.ListNames('()', result_handler=call_done, - user_data=data) + self.dbus_proxy.ListNames('()', result_handler=call_done, user_data=data) main_loop.run() result = data['result'] @@ -176,10 +179,10 @@ class TestGDBusClient(unittest.TestCase): user_data['result'] = result user_data['main_loop'].quit() - main_loop = GObject.MainLoop() + main_loop = GLib.MainLoop() data = {'main_loop': main_loop} self.dbus_proxy.ListNames('(s)', 'invalid_argument', - result_handler=call_done, user_data=data) + result_handler=call_done, user_data=data) main_loop.run() self.assertTrue(isinstance(data['result'], Exception)) @@ -195,13 +198,13 @@ class TestGDBusClient(unittest.TestCase): user_data['error'] = error user_data['main_loop'].quit() - main_loop = GObject.MainLoop() + main_loop = GLib.MainLoop() data = {'main_loop': main_loop} self.dbus_proxy.ListNames('(s)', 'invalid_argument', - result_handler=call_done, error_handler=call_error, - user_data=data) + result_handler=call_done, + error_handler=call_error, + user_data=data) main_loop.run() self.assertTrue(isinstance(data['error'], Exception)) self.assertTrue('InvalidArgs' in str(data['error']), str(data['error'])) - diff --git a/tests/test_generictreemodel.py b/tests/test_generictreemodel.py new file mode 100644 index 0000000..9fa89ff --- /dev/null +++ b/tests/test_generictreemodel.py @@ -0,0 +1,411 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# test_generictreemodel - Tests for GenericTreeModel +# Copyright (C) 2013 Simon Feltman +# +# test_generictreemodel.py: Tests for GenericTreeModel +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 +# USA + + +# system +import gc +import sys +import weakref +import unittest + +# 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 + + +class Node(object): + """Represents a generic node with name, value, and children.""" + def __init__(self, name, value, *children): + self.name = name + self.value = value + self.children = list(children) + self.parent = None + self.next = None + + for i, child in enumerate(children): + child.parent = weakref.ref(self) + if i < len(children) - 1: + child.next = weakref.ref(children[i + 1]) + + def __repr__(self): + return 'Node("%s", %s)' % (self.name, self.value) + + +class TesterModel(GenericTreeModel): + def __init__(self): + super(TesterModel, self).__init__() + self.root = Node('root', 0, + Node('spam', 1, + Node('sushi', 2), + Node('bread', 3) + ), + Node('eggs', 4) + ) + + def on_get_flags(self): + return 0 + + def on_get_n_columns(self): + return 2 + + def on_get_column_type(self, n): + return (str, int)[n] + + def on_get_iter(self, path): + node = self.root + path = list(path) + idx = path.pop(0) + while path: + idx = path.pop(0) + node = node.children[idx] + return node + + def on_get_path(self, node): + def rec_get_path(n): + for i, child in enumerate(n.children): + if child == node: + return [i] + else: + res = rec_get_path(child) + if res: + res.insert(0, i) + + return rec_get_path(self.root) + + def on_get_value(self, node, column): + if column == 0: + return node.name + elif column == 1: + return node.value + + def on_iter_has_child(self, node): + return bool(node.children) + + def on_iter_next(self, node): + if node.next: + return node.next() + + def on_iter_children(self, node): + if node: + return node.children[0] + else: + return self.root + + def on_iter_n_children(self, node): + if node is None: + return 1 + return len(node.children) + + def on_iter_nth_child(self, node, n): + if node is None: + assert n == 0 + return self.root + return node.children[n] + + def on_iter_parent(self, child): + if child.parent: + return child.parent() + + +class TestReferences(unittest.TestCase): + def setUp(self): + pass + + def test_c_tree_iter_user_data_as_pyobject(self): + obj = object() + obj_id = id(obj) + ref_count = sys.getrefcount(obj) + + # This is essentially a stolen ref in the context of _CTreeIter.get_user_data_as_pyobject + it = Gtk.TreeIter() + it.user_data = obj_id + + obj2 = _get_user_data_as_pyobject(it) + self.assertEqual(obj, obj2) + self.assertEqual(sys.getrefcount(obj), ref_count + 1) + + def test_leak_references_on(self): + model = TesterModel() + obj_ref = weakref.ref(model.root) + # Initial refcount is 1 for model.root + the temporary + 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) + + # 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) + + # 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) + + # Deleting a model should free all held references to user data + # stored by TreeIters + del model + gc.collect() + self.assertEqual(obj_ref(), None) + + def test_row_deleted_frees_refs(self): + model = TesterModel() + obj_ref = weakref.ref(model.root) + # Initial refcount is 1 for model.root + the temporary + 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) + + # 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) + + # Finally deleting the actual object should collect it completely + del model.root + gc.collect() + self.assertEqual(obj_ref(), None) + + def test_leak_references_off(self): + model = TesterModel() + 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) + + # 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) + + # 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) + + # Deleting the model decreases the final ref, and the object is collected + del model + gc.collect() + self.assertEqual(obj_ref(), None) + + 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() + nodes = [node for node in model.iter_depth_first()] + values = [node.value for node in nodes] + + # Verify depth first ordering + self.assertEqual(values, [0, 1, 2, 3, 4]) + + # Verify ref counts for each of the nodes. + # 5 refs for each node at this point: + # 1 - ref held in getrefcount function + # 2 - ref held by "node" var during iteration + # 3 - ref held by local "nodes" var + # 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) + + # 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) + + # Hold weak refs and start verifying ref collection. + node_refs = [weakref.ref(node) for node in nodes] + + # First round of collection + del nodes2 + gc.collect() + for node in nodes: + 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) + + # Using invalidate_iters or row_deleted(path, node) will clear out + # the pooled refs held internal to the GenericTreeModel implementation. + model.invalidate_iters() + self.assertEqual(len(model._held_refs), 0) + gc.collect() + for ref in node_refs: + node = ref() + 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 + del node # node still in locals() from last iteration + del model.root + gc.collect() + for ref in node_refs: + self.assertEqual(ref(), None) + + +class TestIteration(unittest.TestCase): + def test_iter_next_root(self): + model = TesterModel() + it = model.get_iter([0]) + self.assertEqual(it.user_data, id(model.root)) + self.assertEqual(model.root.next, None) + + it = model.iter_next(it) + self.assertEqual(it, None) + + def test_iter_next_multiple(self): + model = TesterModel() + it = model.get_iter([0, 0]) + self.assertEqual(it.user_data, id(model.root.children[0])) + + it = model.iter_next(it) + self.assertEqual(it.user_data, id(model.root.children[1])) + + it = model.iter_next(it) + self.assertEqual(it, None) + + +class ErrorModel(GenericTreeModel): + # All on_* methods will raise a NotImplementedError by default + pass + + +class ExceptHook(object): + """ + Temporarily installs an exception hook in a context which + expects the given exc_type to be raised. This allows verification + of exceptions that occur within python gi callbacks but + are never bubbled through from python to C back to python. + This works because exception hooks are called in PyErr_Print. + """ + def __init__(self, *expected_exc_types): + self._expected_exc_types = expected_exc_types + self._exceptions = [] + + def _excepthook(self, exc_type, value, traceback): + self._exceptions.append((exc_type, value)) + + def __enter__(self): + self._oldhook = sys.excepthook + sys.excepthook = self._excepthook + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + sys.excepthook = self._oldhook + error_message = 'Expecting the following exceptions: %s, got: %s' % \ + (str(self._expected_exc_types), '\n'.join([str(item) for item in self._exceptions])) + + assert len(self._expected_exc_types) == len(self._exceptions), error_message + + for expected, got in zip(self._expected_exc_types, [exc[0] for exc in self._exceptions]): + assert issubclass(got, expected), error_message + + +class TestReturnsAfterError(unittest.TestCase): + def setUp(self): + self.model = ErrorModel() + + def test_get_flags(self): + with ExceptHook(NotImplementedError): + flags = self.model.get_flags() + self.assertEqual(flags, 0) + + def test_get_n_columns(self): + with ExceptHook(NotImplementedError): + count = self.model.get_n_columns() + self.assertEqual(count, 0) + + def test_get_column_type(self): + with ExceptHook(NotImplementedError, TypeError): + col_type = self.model.get_column_type(0) + self.assertEqual(col_type, GObject.TYPE_INVALID) + + def test_get_iter(self): + with ExceptHook(NotImplementedError): + self.assertRaises(ValueError, self.model.get_iter, Gtk.TreePath(0)) + + def test_get_path(self): + it = self.model.create_tree_iter('foo') + with ExceptHook(NotImplementedError): + path = self.model.get_path(it) + self.assertEqual(path, None) + + def test_get_value(self): + it = self.model.create_tree_iter('foo') + with ExceptHook(NotImplementedError): + try: + self.model.get_value(it, 0) + except TypeError: + pass # silence TypeError converting None to GValue + + def test_iter_has_child(self): + it = self.model.create_tree_iter('foo') + with ExceptHook(NotImplementedError): + res = self.model.iter_has_child(it) + self.assertEqual(res, False) + + def test_iter_next(self): + it = self.model.create_tree_iter('foo') + with ExceptHook(NotImplementedError): + res = self.model.iter_next(it) + self.assertEqual(res, None) + + def test_iter_children(self): + with ExceptHook(NotImplementedError): + res = self.model.iter_children(None) + self.assertEqual(res, None) + + def test_iter_n_children(self): + with ExceptHook(NotImplementedError): + res = self.model.iter_n_children(None) + self.assertEqual(res, 0) + + def test_iter_nth_child(self): + with ExceptHook(NotImplementedError): + res = self.model.iter_nth_child(None, 0) + self.assertEqual(res, None) + + def test_iter_parent(self): + child = self.model.create_tree_iter('foo') + 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 edbe461..da55187 100644 --- a/tests/test_gi.py +++ b/tests/test_gi.py @@ -10,19 +10,25 @@ import shutil import os import locale import subprocess -from gi.repository import GObject, GLib +import gc +import weakref +import warnings +from io import StringIO, BytesIO + +import gi +from gi.repository import GObject, GLib, Gio from gi.repository import GIMarshallingTests -from compathelper import _bytes +from compathelper import _bytes, _unicode if sys.version_info < (3, 0): CONSTANT_UTF8 = "const \xe2\x99\xa5 utf8" PY2_UNICODE_UTF8 = unicode(CONSTANT_UTF8, 'UTF-8') - CHAR_255='\xff' + CHAR_255 = '\xff' else: CONSTANT_UTF8 = "const ♥ utf8" - CHAR_255=bytes([255]) + CHAR_255 = bytes([255]) CONSTANT_NUMBER = 42 @@ -55,17 +61,26 @@ class TestConstant(unittest.TestCase): # Blocked by https://bugzilla.gnome.org/show_bug.cgi?id=595773 # def test_constant_utf8(self): -# self.assertEquals(CONSTANT_UTF8, GIMarshallingTests.CONSTANT_UTF8) +# self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.CONSTANT_UTF8) def test_constant_number(self): - self.assertEquals(CONSTANT_NUMBER, GIMarshallingTests.CONSTANT_NUMBER) + self.assertEqual(CONSTANT_NUMBER, GIMarshallingTests.CONSTANT_NUMBER) + + def test_min_max_int(self): + self.assertEqual(GLib.MAXINT32, 2 ** 31 - 1) + self.assertEqual(GLib.MININT32, -2 ** 31) + self.assertEqual(GLib.MAXUINT32, 2 ** 32 - 1) + + self.assertEqual(GLib.MAXINT64, 2 ** 63 - 1) + self.assertEqual(GLib.MININT64, -2 ** 63) + self.assertEqual(GLib.MAXUINT64, 2 ** 64 - 1) class TestBoolean(unittest.TestCase): def test_boolean_return(self): - self.assertEquals(True, GIMarshallingTests.boolean_return_true()) - self.assertEquals(False, GIMarshallingTests.boolean_return_false()) + self.assertEqual(True, GIMarshallingTests.boolean_return_true()) + self.assertEqual(False, GIMarshallingTests.boolean_return_false()) def test_boolean_in(self): GIMarshallingTests.boolean_in_true(True) @@ -75,12 +90,12 @@ class TestBoolean(unittest.TestCase): GIMarshallingTests.boolean_in_false(0) def test_boolean_out(self): - self.assertEquals(True, GIMarshallingTests.boolean_out_true()) - self.assertEquals(False, GIMarshallingTests.boolean_out_false()) + self.assertEqual(True, GIMarshallingTests.boolean_out_true()) + self.assertEqual(False, GIMarshallingTests.boolean_out_false()) def test_boolean_inout(self): - self.assertEquals(False, GIMarshallingTests.boolean_inout_true_false(True)) - self.assertEquals(True, GIMarshallingTests.boolean_inout_false_true(False)) + self.assertEqual(False, GIMarshallingTests.boolean_inout_true_false(True)) + self.assertEqual(True, GIMarshallingTests.boolean_inout_false_true(False)) class TestInt8(unittest.TestCase): @@ -89,8 +104,8 @@ class TestInt8(unittest.TestCase): MIN = GObject.G_MININT8 def test_int8_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.int8_return_max()) - self.assertEquals(self.MIN, GIMarshallingTests.int8_return_min()) + self.assertEqual(self.MAX, GIMarshallingTests.int8_return_max()) + self.assertEqual(self.MIN, GIMarshallingTests.int8_return_min()) def test_int8_in(self): max = Number(self.MAX) @@ -102,18 +117,18 @@ class TestInt8(unittest.TestCase): max.value += 1 min.value -= 1 - self.assertRaises(ValueError, GIMarshallingTests.int8_in_max, max) - self.assertRaises(ValueError, GIMarshallingTests.int8_in_min, min) + self.assertRaises(OverflowError, GIMarshallingTests.int8_in_max, max) + self.assertRaises(OverflowError, GIMarshallingTests.int8_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.int8_in_max, "self.MAX") def test_int8_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.int8_out_max()) - self.assertEquals(self.MIN, GIMarshallingTests.int8_out_min()) + self.assertEqual(self.MAX, GIMarshallingTests.int8_out_max()) + self.assertEqual(self.MIN, GIMarshallingTests.int8_out_min()) def test_int8_inout(self): - self.assertEquals(self.MIN, GIMarshallingTests.int8_inout_max_min(Number(self.MAX))) - self.assertEquals(self.MAX, GIMarshallingTests.int8_inout_min_max(Number(self.MIN))) + self.assertEqual(self.MIN, GIMarshallingTests.int8_inout_max_min(Number(self.MAX))) + self.assertEqual(self.MAX, GIMarshallingTests.int8_inout_min_max(Number(self.MIN))) class TestUInt8(unittest.TestCase): @@ -121,7 +136,7 @@ class TestUInt8(unittest.TestCase): MAX = GObject.G_MAXUINT8 def test_uint8_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.uint8_return()) + self.assertEqual(self.MAX, GIMarshallingTests.uint8_return()) def test_uint8_in(self): number = Number(self.MAX) @@ -130,16 +145,16 @@ class TestUInt8(unittest.TestCase): GIMarshallingTests.uint8_in(CHAR_255) number.value += 1 - self.assertRaises(ValueError, GIMarshallingTests.uint8_in, number) - self.assertRaises(ValueError, GIMarshallingTests.uint8_in, Number(-1)) + self.assertRaises(OverflowError, GIMarshallingTests.uint8_in, number) + self.assertRaises(OverflowError, GIMarshallingTests.uint8_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.uint8_in, "self.MAX") def test_uint8_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.uint8_out()) + self.assertEqual(self.MAX, GIMarshallingTests.uint8_out()) def test_uint8_inout(self): - self.assertEquals(0, GIMarshallingTests.uint8_inout(Number(self.MAX))) + self.assertEqual(0, GIMarshallingTests.uint8_inout(Number(self.MAX))) class TestInt16(unittest.TestCase): @@ -148,8 +163,8 @@ class TestInt16(unittest.TestCase): MIN = GObject.G_MININT16 def test_int16_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.int16_return_max()) - self.assertEquals(self.MIN, GIMarshallingTests.int16_return_min()) + self.assertEqual(self.MAX, GIMarshallingTests.int16_return_max()) + self.assertEqual(self.MIN, GIMarshallingTests.int16_return_min()) def test_int16_in(self): max = Number(self.MAX) @@ -161,18 +176,18 @@ class TestInt16(unittest.TestCase): max.value += 1 min.value -= 1 - self.assertRaises(ValueError, GIMarshallingTests.int16_in_max, max) - self.assertRaises(ValueError, GIMarshallingTests.int16_in_min, min) + self.assertRaises(OverflowError, GIMarshallingTests.int16_in_max, max) + self.assertRaises(OverflowError, GIMarshallingTests.int16_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.int16_in_max, "self.MAX") def test_int16_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.int16_out_max()) - self.assertEquals(self.MIN, GIMarshallingTests.int16_out_min()) + self.assertEqual(self.MAX, GIMarshallingTests.int16_out_max()) + self.assertEqual(self.MIN, GIMarshallingTests.int16_out_min()) def test_int16_inout(self): - self.assertEquals(self.MIN, GIMarshallingTests.int16_inout_max_min(Number(self.MAX))) - self.assertEquals(self.MAX, GIMarshallingTests.int16_inout_min_max(Number(self.MIN))) + self.assertEqual(self.MIN, GIMarshallingTests.int16_inout_max_min(Number(self.MAX))) + self.assertEqual(self.MAX, GIMarshallingTests.int16_inout_min_max(Number(self.MIN))) class TestUInt16(unittest.TestCase): @@ -180,7 +195,7 @@ class TestUInt16(unittest.TestCase): MAX = GObject.G_MAXUINT16 def test_uint16_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.uint16_return()) + self.assertEqual(self.MAX, GIMarshallingTests.uint16_return()) def test_uint16_in(self): number = Number(self.MAX) @@ -189,16 +204,16 @@ class TestUInt16(unittest.TestCase): number.value += 1 - self.assertRaises(ValueError, GIMarshallingTests.uint16_in, number) - self.assertRaises(ValueError, GIMarshallingTests.uint16_in, Number(-1)) + self.assertRaises(OverflowError, GIMarshallingTests.uint16_in, number) + self.assertRaises(OverflowError, GIMarshallingTests.uint16_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.uint16_in, "self.MAX") def test_uint16_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.uint16_out()) + self.assertEqual(self.MAX, GIMarshallingTests.uint16_out()) def test_uint16_inout(self): - self.assertEquals(0, GIMarshallingTests.uint16_inout(Number(self.MAX))) + self.assertEqual(0, GIMarshallingTests.uint16_inout(Number(self.MAX))) class TestInt32(unittest.TestCase): @@ -207,8 +222,8 @@ class TestInt32(unittest.TestCase): MIN = GObject.G_MININT32 def test_int32_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.int32_return_max()) - self.assertEquals(self.MIN, GIMarshallingTests.int32_return_min()) + self.assertEqual(self.MAX, GIMarshallingTests.int32_return_max()) + self.assertEqual(self.MIN, GIMarshallingTests.int32_return_min()) def test_int32_in(self): max = Number(self.MAX) @@ -220,18 +235,18 @@ class TestInt32(unittest.TestCase): max.value += 1 min.value -= 1 - self.assertRaises(ValueError, GIMarshallingTests.int32_in_max, max) - self.assertRaises(ValueError, GIMarshallingTests.int32_in_min, min) + self.assertRaises(OverflowError, GIMarshallingTests.int32_in_max, max) + self.assertRaises(OverflowError, GIMarshallingTests.int32_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.int32_in_max, "self.MAX") def test_int32_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.int32_out_max()) - self.assertEquals(self.MIN, GIMarshallingTests.int32_out_min()) + self.assertEqual(self.MAX, GIMarshallingTests.int32_out_max()) + self.assertEqual(self.MIN, GIMarshallingTests.int32_out_min()) def test_int32_inout(self): - self.assertEquals(self.MIN, GIMarshallingTests.int32_inout_max_min(Number(self.MAX))) - self.assertEquals(self.MAX, GIMarshallingTests.int32_inout_min_max(Number(self.MIN))) + self.assertEqual(self.MIN, GIMarshallingTests.int32_inout_max_min(Number(self.MAX))) + self.assertEqual(self.MAX, GIMarshallingTests.int32_inout_min_max(Number(self.MIN))) class TestUInt32(unittest.TestCase): @@ -239,7 +254,7 @@ class TestUInt32(unittest.TestCase): MAX = GObject.G_MAXUINT32 def test_uint32_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.uint32_return()) + self.assertEqual(self.MAX, GIMarshallingTests.uint32_return()) def test_uint32_in(self): number = Number(self.MAX) @@ -248,16 +263,16 @@ class TestUInt32(unittest.TestCase): number.value += 1 - self.assertRaises(ValueError, GIMarshallingTests.uint32_in, number) - self.assertRaises(ValueError, GIMarshallingTests.uint32_in, Number(-1)) + self.assertRaises(OverflowError, GIMarshallingTests.uint32_in, number) + self.assertRaises(OverflowError, GIMarshallingTests.uint32_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.uint32_in, "self.MAX") def test_uint32_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.uint32_out()) + self.assertEqual(self.MAX, GIMarshallingTests.uint32_out()) def test_uint32_inout(self): - self.assertEquals(0, GIMarshallingTests.uint32_inout(Number(self.MAX))) + self.assertEqual(0, GIMarshallingTests.uint32_inout(Number(self.MAX))) class TestInt64(unittest.TestCase): @@ -266,8 +281,8 @@ class TestInt64(unittest.TestCase): MIN = - (2 ** 63) def test_int64_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.int64_return_max()) - self.assertEquals(self.MIN, GIMarshallingTests.int64_return_min()) + self.assertEqual(self.MAX, GIMarshallingTests.int64_return_max()) + self.assertEqual(self.MIN, GIMarshallingTests.int64_return_min()) def test_int64_in(self): max = Number(self.MAX) @@ -279,18 +294,18 @@ class TestInt64(unittest.TestCase): max.value += 1 min.value -= 1 - self.assertRaises(ValueError, GIMarshallingTests.int64_in_max, max) - self.assertRaises(ValueError, GIMarshallingTests.int64_in_min, min) + self.assertRaises(OverflowError, GIMarshallingTests.int64_in_max, max) + self.assertRaises(OverflowError, GIMarshallingTests.int64_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.int64_in_max, "self.MAX") def test_int64_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.int64_out_max()) - self.assertEquals(self.MIN, GIMarshallingTests.int64_out_min()) + self.assertEqual(self.MAX, GIMarshallingTests.int64_out_max()) + self.assertEqual(self.MIN, GIMarshallingTests.int64_out_min()) def test_int64_inout(self): - self.assertEquals(self.MIN, GIMarshallingTests.int64_inout_max_min(Number(self.MAX))) - self.assertEquals(self.MAX, GIMarshallingTests.int64_inout_min_max(Number(self.MIN))) + self.assertEqual(self.MIN, GIMarshallingTests.int64_inout_max_min(Number(self.MAX))) + self.assertEqual(self.MAX, GIMarshallingTests.int64_inout_min_max(Number(self.MIN))) class TestUInt64(unittest.TestCase): @@ -298,7 +313,7 @@ class TestUInt64(unittest.TestCase): MAX = 2 ** 64 - 1 def test_uint64_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.uint64_return()) + self.assertEqual(self.MAX, GIMarshallingTests.uint64_return()) def test_uint64_in(self): number = Number(self.MAX) @@ -307,26 +322,26 @@ class TestUInt64(unittest.TestCase): number.value += 1 - self.assertRaises(ValueError, GIMarshallingTests.uint64_in, number) - self.assertRaises(ValueError, GIMarshallingTests.uint64_in, Number(-1)) + self.assertRaises(OverflowError, GIMarshallingTests.uint64_in, number) + self.assertRaises(OverflowError, GIMarshallingTests.uint64_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.uint64_in, "self.MAX") def test_uint64_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.uint64_out()) + self.assertEqual(self.MAX, GIMarshallingTests.uint64_out()) def test_uint64_inout(self): - self.assertEquals(0, GIMarshallingTests.uint64_inout(Number(self.MAX))) + self.assertEqual(0, GIMarshallingTests.uint64_inout(Number(self.MAX))) class TestShort(unittest.TestCase): - MAX = GObject.constants.G_MAXSHORT - MIN = GObject.constants.G_MINSHORT + MAX = GObject.G_MAXSHORT + MIN = GObject.G_MINSHORT def test_short_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.short_return_max()) - self.assertEquals(self.MIN, GIMarshallingTests.short_return_min()) + self.assertEqual(self.MAX, GIMarshallingTests.short_return_max()) + self.assertEqual(self.MIN, GIMarshallingTests.short_return_min()) def test_short_in(self): max = Number(self.MAX) @@ -338,26 +353,26 @@ class TestShort(unittest.TestCase): max.value += 1 min.value -= 1 - self.assertRaises(ValueError, GIMarshallingTests.short_in_max, max) - self.assertRaises(ValueError, GIMarshallingTests.short_in_min, min) + self.assertRaises(OverflowError, GIMarshallingTests.short_in_max, max) + self.assertRaises(OverflowError, GIMarshallingTests.short_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.short_in_max, "self.MAX") def test_short_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.short_out_max()) - self.assertEquals(self.MIN, GIMarshallingTests.short_out_min()) + self.assertEqual(self.MAX, GIMarshallingTests.short_out_max()) + self.assertEqual(self.MIN, GIMarshallingTests.short_out_min()) def test_short_inout(self): - self.assertEquals(self.MIN, GIMarshallingTests.short_inout_max_min(Number(self.MAX))) - self.assertEquals(self.MAX, GIMarshallingTests.short_inout_min_max(Number(self.MIN))) + self.assertEqual(self.MIN, GIMarshallingTests.short_inout_max_min(Number(self.MAX))) + self.assertEqual(self.MAX, GIMarshallingTests.short_inout_min_max(Number(self.MIN))) class TestUShort(unittest.TestCase): - MAX = GObject.constants.G_MAXUSHORT + MAX = GObject.G_MAXUSHORT def test_ushort_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.ushort_return()) + self.assertEqual(self.MAX, GIMarshallingTests.ushort_return()) def test_ushort_in(self): number = Number(self.MAX) @@ -366,26 +381,26 @@ class TestUShort(unittest.TestCase): number.value += 1 - self.assertRaises(ValueError, GIMarshallingTests.ushort_in, number) - self.assertRaises(ValueError, GIMarshallingTests.ushort_in, Number(-1)) + self.assertRaises(OverflowError, GIMarshallingTests.ushort_in, number) + self.assertRaises(OverflowError, GIMarshallingTests.ushort_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.ushort_in, "self.MAX") def test_ushort_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.ushort_out()) + self.assertEqual(self.MAX, GIMarshallingTests.ushort_out()) def test_ushort_inout(self): - self.assertEquals(0, GIMarshallingTests.ushort_inout(Number(self.MAX))) + self.assertEqual(0, GIMarshallingTests.ushort_inout(Number(self.MAX))) class TestInt(unittest.TestCase): - MAX = GObject.constants.G_MAXINT - MIN = GObject.constants.G_MININT + MAX = GObject.G_MAXINT + MIN = GObject.G_MININT def test_int_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.int_return_max()) - self.assertEquals(self.MIN, GIMarshallingTests.int_return_min()) + self.assertEqual(self.MAX, GIMarshallingTests.int_return_max()) + self.assertEqual(self.MIN, GIMarshallingTests.int_return_min()) def test_int_in(self): max = Number(self.MAX) @@ -397,27 +412,27 @@ class TestInt(unittest.TestCase): max.value += 1 min.value -= 1 - self.assertRaises(ValueError, GIMarshallingTests.int_in_max, max) - self.assertRaises(ValueError, GIMarshallingTests.int_in_min, min) + self.assertRaises(OverflowError, GIMarshallingTests.int_in_max, max) + self.assertRaises(OverflowError, GIMarshallingTests.int_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.int_in_max, "self.MAX") def test_int_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.int_out_max()) - self.assertEquals(self.MIN, GIMarshallingTests.int_out_min()) + self.assertEqual(self.MAX, GIMarshallingTests.int_out_max()) + self.assertEqual(self.MIN, GIMarshallingTests.int_out_min()) def test_int_inout(self): - self.assertEquals(self.MIN, GIMarshallingTests.int_inout_max_min(Number(self.MAX))) - self.assertEquals(self.MAX, GIMarshallingTests.int_inout_min_max(Number(self.MIN))) + 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) class TestUInt(unittest.TestCase): - MAX = GObject.constants.G_MAXUINT + MAX = GObject.G_MAXUINT def test_uint_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.uint_return()) + self.assertEqual(self.MAX, GIMarshallingTests.uint_return()) def test_uint_in(self): number = Number(self.MAX) @@ -426,26 +441,26 @@ class TestUInt(unittest.TestCase): number.value += 1 - self.assertRaises(ValueError, GIMarshallingTests.uint_in, number) - self.assertRaises(ValueError, GIMarshallingTests.uint_in, Number(-1)) + self.assertRaises(OverflowError, GIMarshallingTests.uint_in, number) + self.assertRaises(OverflowError, GIMarshallingTests.uint_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.uint_in, "self.MAX") def test_uint_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.uint_out()) + self.assertEqual(self.MAX, GIMarshallingTests.uint_out()) def test_uint_inout(self): - self.assertEquals(0, GIMarshallingTests.uint_inout(Number(self.MAX))) + self.assertEqual(0, GIMarshallingTests.uint_inout(Number(self.MAX))) class TestLong(unittest.TestCase): - MAX = GObject.constants.G_MAXLONG - MIN = GObject.constants.G_MINLONG + MAX = GObject.G_MAXLONG + MIN = GObject.G_MINLONG def test_long_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.long_return_max()) - self.assertEquals(self.MIN, GIMarshallingTests.long_return_min()) + self.assertEqual(self.MAX, GIMarshallingTests.long_return_max()) + self.assertEqual(self.MIN, GIMarshallingTests.long_return_min()) def test_long_in(self): max = Number(self.MAX) @@ -457,26 +472,26 @@ class TestLong(unittest.TestCase): max.value += 1 min.value -= 1 - self.assertRaises(ValueError, GIMarshallingTests.long_in_max, max) - self.assertRaises(ValueError, GIMarshallingTests.long_in_min, min) + self.assertRaises(OverflowError, GIMarshallingTests.long_in_max, max) + self.assertRaises(OverflowError, GIMarshallingTests.long_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.long_in_max, "self.MAX") def test_long_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.long_out_max()) - self.assertEquals(self.MIN, GIMarshallingTests.long_out_min()) + self.assertEqual(self.MAX, GIMarshallingTests.long_out_max()) + self.assertEqual(self.MIN, GIMarshallingTests.long_out_min()) def test_long_inout(self): - self.assertEquals(self.MIN, GIMarshallingTests.long_inout_max_min(Number(self.MAX))) - self.assertEquals(self.MAX, GIMarshallingTests.long_inout_min_max(Number(self.MIN))) + self.assertEqual(self.MIN, GIMarshallingTests.long_inout_max_min(Number(self.MAX))) + self.assertEqual(self.MAX, GIMarshallingTests.long_inout_min_max(Number(self.MIN))) class TestULong(unittest.TestCase): - MAX = GObject.constants.G_MAXULONG + MAX = GObject.G_MAXULONG def test_ulong_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.ulong_return()) + self.assertEqual(self.MAX, GIMarshallingTests.ulong_return()) def test_ulong_in(self): number = Number(self.MAX) @@ -485,26 +500,26 @@ class TestULong(unittest.TestCase): number.value += 1 - self.assertRaises(ValueError, GIMarshallingTests.ulong_in, number) - self.assertRaises(ValueError, GIMarshallingTests.ulong_in, Number(-1)) + self.assertRaises(OverflowError, GIMarshallingTests.ulong_in, number) + self.assertRaises(OverflowError, GIMarshallingTests.ulong_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.ulong_in, "self.MAX") def test_ulong_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.ulong_out()) + self.assertEqual(self.MAX, GIMarshallingTests.ulong_out()) def test_ulong_inout(self): - self.assertEquals(0, GIMarshallingTests.ulong_inout(Number(self.MAX))) + self.assertEqual(0, GIMarshallingTests.ulong_inout(Number(self.MAX))) class TestSSize(unittest.TestCase): - MAX = GObject.constants.G_MAXLONG - MIN = GObject.constants.G_MINLONG + MAX = GObject.G_MAXLONG + MIN = GObject.G_MINLONG def test_ssize_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.ssize_return_max()) - self.assertEquals(self.MIN, GIMarshallingTests.ssize_return_min()) + self.assertEqual(self.MAX, GIMarshallingTests.ssize_return_max()) + self.assertEqual(self.MIN, GIMarshallingTests.ssize_return_min()) def test_ssize_in(self): max = Number(self.MAX) @@ -516,26 +531,26 @@ class TestSSize(unittest.TestCase): max.value += 1 min.value -= 1 - self.assertRaises(ValueError, GIMarshallingTests.ssize_in_max, max) - self.assertRaises(ValueError, GIMarshallingTests.ssize_in_min, min) + self.assertRaises(OverflowError, GIMarshallingTests.ssize_in_max, max) + self.assertRaises(OverflowError, GIMarshallingTests.ssize_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.ssize_in_max, "self.MAX") def test_ssize_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.ssize_out_max()) - self.assertEquals(self.MIN, GIMarshallingTests.ssize_out_min()) + self.assertEqual(self.MAX, GIMarshallingTests.ssize_out_max()) + self.assertEqual(self.MIN, GIMarshallingTests.ssize_out_min()) def test_ssize_inout(self): - self.assertEquals(self.MIN, GIMarshallingTests.ssize_inout_max_min(Number(self.MAX))) - self.assertEquals(self.MAX, GIMarshallingTests.ssize_inout_min_max(Number(self.MIN))) + self.assertEqual(self.MIN, GIMarshallingTests.ssize_inout_max_min(Number(self.MAX))) + self.assertEqual(self.MAX, GIMarshallingTests.ssize_inout_min_max(Number(self.MIN))) class TestSize(unittest.TestCase): - MAX = GObject.constants.G_MAXULONG + MAX = GObject.G_MAXULONG def test_size_return(self): - self.assertEquals(self.MAX, GIMarshallingTests.size_return()) + self.assertEqual(self.MAX, GIMarshallingTests.size_return()) def test_size_in(self): number = Number(self.MAX) @@ -544,25 +559,41 @@ class TestSize(unittest.TestCase): number.value += 1 - self.assertRaises(ValueError, GIMarshallingTests.size_in, number) - self.assertRaises(ValueError, GIMarshallingTests.size_in, Number(-1)) + self.assertRaises(OverflowError, GIMarshallingTests.size_in, number) + self.assertRaises(OverflowError, GIMarshallingTests.size_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.size_in, "self.MAX") def test_size_out(self): - self.assertEquals(self.MAX, GIMarshallingTests.size_out()) + self.assertEqual(self.MAX, GIMarshallingTests.size_out()) def test_size_inout(self): - self.assertEquals(0, GIMarshallingTests.size_inout(Number(self.MAX))) + self.assertEqual(0, GIMarshallingTests.size_inout(Number(self.MAX))) + + +class TestTimet(unittest.TestCase): + + def test_time_t_return(self): + self.assertEqual(1234567890, GIMarshallingTests.time_t_return()) + + def test_time_t_in(self): + GIMarshallingTests.time_t_in(1234567890) + self.assertRaises(TypeError, GIMarshallingTests.time_t_in, "hello") + + def test_time_t_out(self): + self.assertEqual(1234567890, GIMarshallingTests.time_t_out()) + + def test_time_t_inout(self): + self.assertEqual(0, GIMarshallingTests.time_t_inout(1234567890)) class TestFloat(unittest.TestCase): - MAX = GObject.constants.G_MAXFLOAT - MIN = GObject.constants.G_MINFLOAT + MAX = GObject.G_MAXFLOAT + MIN = GObject.G_MINFLOAT def test_float_return(self): - self.assertAlmostEquals(self.MAX, GIMarshallingTests.float_return()) + self.assertAlmostEqual(self.MAX, GIMarshallingTests.float_return()) def test_float_in(self): GIMarshallingTests.float_in(Number(self.MAX)) @@ -570,19 +601,19 @@ class TestFloat(unittest.TestCase): self.assertRaises(TypeError, GIMarshallingTests.float_in, "self.MAX") def test_float_out(self): - self.assertAlmostEquals(self.MAX, GIMarshallingTests.float_out()) + self.assertAlmostEqual(self.MAX, GIMarshallingTests.float_out()) def test_float_inout(self): - self.assertAlmostEquals(self.MIN, GIMarshallingTests.float_inout(Number(self.MAX))) + self.assertAlmostEqual(self.MIN, GIMarshallingTests.float_inout(Number(self.MAX))) class TestDouble(unittest.TestCase): - MAX = GObject.constants.G_MAXDOUBLE - MIN = GObject.constants.G_MINDOUBLE + MAX = GObject.G_MAXDOUBLE + MIN = GObject.G_MINDOUBLE def test_double_return(self): - self.assertAlmostEquals(self.MAX, GIMarshallingTests.double_return()) + self.assertAlmostEqual(self.MAX, GIMarshallingTests.double_return()) def test_double_in(self): GIMarshallingTests.double_in(Number(self.MAX)) @@ -590,17 +621,17 @@ class TestDouble(unittest.TestCase): self.assertRaises(TypeError, GIMarshallingTests.double_in, "self.MAX") def test_double_out(self): - self.assertAlmostEquals(self.MAX, GIMarshallingTests.double_out()) + self.assertAlmostEqual(self.MAX, GIMarshallingTests.double_out()) def test_double_inout(self): - self.assertAlmostEquals(self.MIN, GIMarshallingTests.double_inout(Number(self.MAX))) + self.assertAlmostEqual(self.MIN, GIMarshallingTests.double_inout(Number(self.MAX))) class TestGType(unittest.TestCase): def test_gtype_name(self): - self.assertEquals("void", GObject.TYPE_NONE.name) - self.assertEquals("gchararray", GObject.TYPE_STRING.name) + self.assertEqual("void", GObject.TYPE_NONE.name) + self.assertEqual("gchararray", GObject.TYPE_STRING.name) def check_readonly(gtype): gtype.name = "foo" @@ -609,8 +640,8 @@ class TestGType(unittest.TestCase): self.assertRaises(AttributeError, check_readonly, GObject.TYPE_STRING) def test_gtype_return(self): - self.assertEquals(GObject.TYPE_NONE, GIMarshallingTests.gtype_return()) - self.assertEquals(GObject.TYPE_STRING, GIMarshallingTests.gtype_string_return()) + self.assertEqual(GObject.TYPE_NONE, GIMarshallingTests.gtype_return()) + self.assertEqual(GObject.TYPE_STRING, GIMarshallingTests.gtype_string_return()) def test_gtype_in(self): GIMarshallingTests.gtype_in(GObject.TYPE_NONE) @@ -619,20 +650,20 @@ class TestGType(unittest.TestCase): self.assertRaises(TypeError, GIMarshallingTests.gtype_string_in, "foo") def test_gtype_out(self): - self.assertEquals(GObject.TYPE_NONE, GIMarshallingTests.gtype_out()) - self.assertEquals(GObject.TYPE_STRING, GIMarshallingTests.gtype_string_out()) + self.assertEqual(GObject.TYPE_NONE, GIMarshallingTests.gtype_out()) + self.assertEqual(GObject.TYPE_STRING, GIMarshallingTests.gtype_string_out()) def test_gtype_inout(self): - self.assertEquals(GObject.TYPE_INT, GIMarshallingTests.gtype_inout(GObject.TYPE_NONE)) + self.assertEqual(GObject.TYPE_INT, GIMarshallingTests.gtype_inout(GObject.TYPE_NONE)) class TestUtf8(unittest.TestCase): def test_utf8_none_return(self): - self.assertEquals(CONSTANT_UTF8, GIMarshallingTests.utf8_none_return()) + self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.utf8_none_return()) def test_utf8_full_return(self): - self.assertEquals(CONSTANT_UTF8, GIMarshallingTests.utf8_full_return()) + self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.utf8_full_return()) def test_utf8_none_in(self): GIMarshallingTests.utf8_none_in(CONSTANT_UTF8) @@ -643,28 +674,59 @@ class TestUtf8(unittest.TestCase): self.assertRaises(TypeError, GIMarshallingTests.utf8_none_in, None) def test_utf8_none_out(self): - self.assertEquals(CONSTANT_UTF8, GIMarshallingTests.utf8_none_out()) + self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.utf8_none_out()) def test_utf8_full_out(self): - self.assertEquals(CONSTANT_UTF8, GIMarshallingTests.utf8_full_out()) + self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.utf8_full_out()) def test_utf8_dangling_out(self): GIMarshallingTests.utf8_dangling_out() def test_utf8_none_inout(self): - self.assertEquals("", GIMarshallingTests.utf8_none_inout(CONSTANT_UTF8)) + self.assertEqual("", GIMarshallingTests.utf8_none_inout(CONSTANT_UTF8)) def test_utf8_full_inout(self): - self.assertEquals("", GIMarshallingTests.utf8_full_inout(CONSTANT_UTF8)) + self.assertEqual("", GIMarshallingTests.utf8_full_inout(CONSTANT_UTF8)) + + +class TestFilename(unittest.TestCase): + def setUp(self): + self.workdir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.workdir) + + def test_filename_in(self): + fname = os.path.join(self.workdir, _unicode('testäø.txt')) + self.assertRaises(GLib.GError, GLib.file_get_contents, fname) + + with open(fname.encode('UTF-8'), 'wb') as f: + f.write(b'hello world!\n\x01\x02') + + (result, contents) = GLib.file_get_contents(fname) + self.assertEqual(result, True) + self.assertEqual(contents, b'hello world!\n\x01\x02') + + def test_filename_out(self): + self.assertRaises(GLib.GError, GLib.Dir.make_tmp, 'test') + + dirname = GLib.Dir.make_tmp('testäø.XXXXXX') + self.assertTrue('/testäø.' in dirname, dirname) + dirname = _bytes(dirname) + self.assertTrue(os.path.isdir(dirname)) + os.rmdir(dirname) + + def test_filename_type_error(self): + self.assertRaises(TypeError, GLib.file_get_contents, 23) class TestArray(unittest.TestCase): def test_array_fixed_int_return(self): - self.assertEquals([-1, 0, 1, 2], GIMarshallingTests.array_fixed_int_return()) + self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_fixed_int_return()) def test_array_fixed_short_return(self): - self.assertEquals([-1, 0, 1, 2], GIMarshallingTests.array_fixed_short_return()) + self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_fixed_short_return()) def test_array_fixed_int_in(self): GIMarshallingTests.array_fixed_int_in(Sequence([-1, 0, 1, 2])) @@ -678,26 +740,47 @@ class TestArray(unittest.TestCase): GIMarshallingTests.array_fixed_short_in(Sequence([-1, 0, 1, 2])) def test_array_fixed_out(self): - self.assertEquals([-1, 0, 1, 2], GIMarshallingTests.array_fixed_out()) + self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_fixed_out()) def test_array_fixed_inout(self): - self.assertEquals([2, 1, 0, -1], GIMarshallingTests.array_fixed_inout([-1, 0, 1, 2])) + self.assertEqual([2, 1, 0, -1], GIMarshallingTests.array_fixed_inout([-1, 0, 1, 2])) def test_array_return(self): - self.assertEquals([-1, 0, 1, 2], GIMarshallingTests.array_return()) + self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_return()) + + def test_array_return_etc(self): + self.assertEqual(([5, 0, 1, 9], 14), GIMarshallingTests.array_return_etc(5, 9)) def test_array_in(self): GIMarshallingTests.array_in(Sequence([-1, 0, 1, 2])) + GIMarshallingTests.array_in_guint64_len(Sequence([-1, 0, 1, 2])) + GIMarshallingTests.array_in_guint8_len(Sequence([-1, 0, 1, 2])) + + def test_array_in_len_before(self): + GIMarshallingTests.array_in_len_before(Sequence([-1, 0, 1, 2])) + + def test_array_in_len_zero_terminated(self): + GIMarshallingTests.array_in_len_zero_terminated(Sequence([-1, 0, 1, 2])) def test_array_uint8_in(self): GIMarshallingTests.array_uint8_in(Sequence([97, 98, 99, 100])) GIMarshallingTests.array_uint8_in(_bytes("abcd")) + def test_array_string_in(self): + GIMarshallingTests.array_string_in(['foo', 'bar']) + def test_array_out(self): - self.assertEquals([-1, 0, 1, 2], GIMarshallingTests.array_out()) + self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_out()) + + def test_array_out_etc(self): + self.assertEqual(([-5, 0, 1, 9], 4), GIMarshallingTests.array_out_etc(-5, 9)) def test_array_inout(self): - self.assertEquals([-2, -1, 0, 1, 2], GIMarshallingTests.array_inout(Sequence([-1, 0, 1, 2]))) + self.assertEqual([-2, -1, 0, 1, 2], GIMarshallingTests.array_inout(Sequence([-1, 0, 1, 2]))) + + def test_array_inout_etc(self): + self.assertEqual(([-5, -1, 0, 1, 9], 4), + GIMarshallingTests.array_inout_etc(-5, Sequence([-1, 0, 1, 2]), 9)) def test_method_array_in(self): object_ = GIMarshallingTests.Object() @@ -705,88 +788,122 @@ class TestArray(unittest.TestCase): def test_method_array_out(self): object_ = GIMarshallingTests.Object() - self.assertEquals([-1, 0, 1, 2], object_.method_array_out()) + self.assertEqual([-1, 0, 1, 2], object_.method_array_out()) def test_method_array_inout(self): object_ = GIMarshallingTests.Object() - self.assertEquals([-2, -1, 0, 1, 2], object_.method_array_inout(Sequence([-1, 0, 1, 2]))) + self.assertEqual([-2, -1, 0, 1, 2], object_.method_array_inout(Sequence([-1, 0, 1, 2]))) def test_method_array_return(self): object_ = GIMarshallingTests.Object() - self.assertEquals([-1, 0, 1, 2], object_.method_array_return()) + self.assertEqual([-1, 0, 1, 2], object_.method_array_return()) def test_array_enum_in(self): - GIMarshallingTests.array_enum_in([GIMarshallingTests.Enum.VALUE1, - GIMarshallingTests.Enum.VALUE2, - GIMarshallingTests.Enum.VALUE3]) + GIMarshallingTests.array_enum_in([GIMarshallingTests.Enum.VALUE1, + GIMarshallingTests.Enum.VALUE2, + GIMarshallingTests.Enum.VALUE3]) def test_array_boxed_struct_in(self): - struct1 = GIMarshallingTests.BoxedStruct() - struct1.long_ = 1 - struct2 = GIMarshallingTests.BoxedStruct() - struct2.long_ = 2 - struct3 = GIMarshallingTests.BoxedStruct() - struct3.long_ = 3 - - GIMarshallingTests.array_struct_in([struct1, struct2, struct3]) + struct1 = GIMarshallingTests.BoxedStruct() + struct1.long_ = 1 + struct2 = GIMarshallingTests.BoxedStruct() + struct2.long_ = 2 + struct3 = GIMarshallingTests.BoxedStruct() + struct3.long_ = 3 + + GIMarshallingTests.array_struct_in([struct1, struct2, struct3]) + + def test_array_boxed_struct_value_in(self): + struct1 = GIMarshallingTests.BoxedStruct() + struct1.long_ = 1 + struct2 = GIMarshallingTests.BoxedStruct() + struct2.long_ = 2 + struct3 = GIMarshallingTests.BoxedStruct() + struct3.long_ = 3 + + GIMarshallingTests.array_struct_value_in([struct1, struct2, struct3]) + + def test_array_boxed_struct_take_in(self): + struct1 = GIMarshallingTests.BoxedStruct() + struct1.long_ = 1 + struct2 = GIMarshallingTests.BoxedStruct() + struct2.long_ = 2 + struct3 = GIMarshallingTests.BoxedStruct() + struct3.long_ = 3 + + GIMarshallingTests.array_struct_take_in([struct1, struct2, struct3]) + + self.assertEqual(1, struct1.long_) + + def test_array_boxed_struct_return(self): + (struct1, struct2, struct3) = GIMarshallingTests.array_zero_terminated_return_struct() + self.assertEqual(GIMarshallingTests.BoxedStruct, type(struct1)) + self.assertEqual(GIMarshallingTests.BoxedStruct, type(struct2)) + self.assertEqual(GIMarshallingTests.BoxedStruct, type(struct3)) + self.assertEqual(42, struct1.long_) + self.assertEqual(43, struct2.long_) + self.assertEqual(44, struct3.long_) def test_array_simple_struct_in(self): - struct1 = GIMarshallingTests.SimpleStruct() - struct1.long_ = 1 - struct2 = GIMarshallingTests.SimpleStruct() - struct2.long_ = 2 - struct3 = GIMarshallingTests.SimpleStruct() - struct3.long_ = 3 + struct1 = GIMarshallingTests.SimpleStruct() + struct1.long_ = 1 + struct2 = GIMarshallingTests.SimpleStruct() + struct2.long_ = 2 + struct3 = GIMarshallingTests.SimpleStruct() + struct3.long_ = 3 - GIMarshallingTests.array_simple_struct_in([struct1, struct2, struct3]) + GIMarshallingTests.array_simple_struct_in([struct1, struct2, struct3]) def test_array_multi_array_key_value_in(self): - GIMarshallingTests.multi_array_key_value_in(["one", "two", "three"], - [1, 2, 3]) + GIMarshallingTests.multi_array_key_value_in(["one", "two", "three"], + [1, 2, 3]) + + def test_array_in_nonzero_nonlen(self): + GIMarshallingTests.array_in_nonzero_nonlen(1, b'abcd') def test_array_fixed_out_struct(self): struct1, struct2 = GIMarshallingTests.array_fixed_out_struct() - self.assertEquals(7, struct1.long_) - self.assertEquals(6, struct1.int8) - self.assertEquals(6, struct2.long_) - self.assertEquals(7, struct2.int8) + self.assertEqual(7, struct1.long_) + self.assertEqual(6, struct1.int8) + self.assertEqual(6, struct2.long_) + self.assertEqual(7, struct2.int8) def test_array_zero_terminated_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.array_zero_terminated_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.array_zero_terminated_return()) def test_array_zero_terminated_return_null(self): - self.assertEquals([], GIMarshallingTests.array_zero_terminated_return_null()) + self.assertEqual([], GIMarshallingTests.array_zero_terminated_return_null()) def test_array_zero_terminated_in(self): GIMarshallingTests.array_zero_terminated_in(Sequence(['0', '1', '2'])) def test_array_zero_terminated_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.array_zero_terminated_out()) - - def test_array_zero_terminated_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.array_zero_terminated_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.array_zero_terminated_out()) def test_array_zero_terminated_inout(self): - self.assertEquals(['-1', '0', '1', '2'], GIMarshallingTests.array_zero_terminated_inout(['0', '1', '2'])) + self.assertEqual(['-1', '0', '1', '2'], GIMarshallingTests.array_zero_terminated_inout(['0', '1', '2'])) + + def test_init_function(self): + self.assertEqual((True, []), GIMarshallingTests.init_function([])) + self.assertEqual((True, []), GIMarshallingTests.init_function(['hello'])) + self.assertEqual((True, ['hello']), + GIMarshallingTests.init_function(['hello', 'world'])) class TestGStrv(unittest.TestCase): def test_gstrv_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gstrv_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gstrv_return()) def test_gstrv_in(self): GIMarshallingTests.gstrv_in(Sequence(['0', '1', '2'])) def test_gstrv_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gstrv_out()) - - def test_gstrv_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gstrv_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gstrv_out()) def test_gstrv_inout(self): - self.assertEquals(['-1', '0', '1', '2'], GIMarshallingTests.gstrv_inout(['0', '1', '2'])) + self.assertEqual(['-1', '0', '1', '2'], GIMarshallingTests.gstrv_inout(['0', '1', '2'])) class TestArrayGVariant(unittest.TestCase): @@ -794,36 +911,39 @@ class TestArrayGVariant(unittest.TestCase): def test_array_gvariant_none_in(self): v = [GLib.Variant("i", 27), GLib.Variant("s", "Hello")] returned = [GLib.Variant.unpack(r) for r in GIMarshallingTests.array_gvariant_none_in(v)] - self.assertEquals([27, "Hello"], returned) + self.assertEqual([27, "Hello"], returned) def test_array_gvariant_container_in(self): v = [GLib.Variant("i", 27), GLib.Variant("s", "Hello")] - returned = [GLib.Variant.unpack(r) for r in GIMarshallingTests.array_gvariant_none_in(v)] - self.assertEquals([27, "Hello"], returned) + returned = [GLib.Variant.unpack(r) for r in GIMarshallingTests.array_gvariant_container_in(v)] + self.assertEqual([27, "Hello"], returned) def test_array_gvariant_full_in(self): v = [GLib.Variant("i", 27), GLib.Variant("s", "Hello")] - returned = [GLib.Variant.unpack(r) for r in GIMarshallingTests.array_gvariant_none_in(v)] - self.assertEquals([27, "Hello"], returned) + returned = [GLib.Variant.unpack(r) for r in GIMarshallingTests.array_gvariant_full_in(v)] + self.assertEqual([27, "Hello"], returned) def test_bytearray_gvariant(self): v = GLib.Variant.new_bytestring(b"foo") - self.assertEquals(v.get_bytestring(), b"foo") + self.assertEqual(v.get_bytestring(), b"foo") class TestGArray(unittest.TestCase): def test_garray_int_none_return(self): - self.assertEquals([-1, 0, 1, 2], GIMarshallingTests.garray_int_none_return()) + 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()) def test_garray_utf8_none_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.garray_utf8_none_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_none_return()) def test_garray_utf8_container_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.garray_utf8_container_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_container_return()) def test_garray_utf8_full_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.garray_utf8_full_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_full_return()) def test_garray_int_none_in(self): GIMarshallingTests.garray_int_none_in(Sequence([-1, 0, 1, 2])) @@ -833,74 +953,133 @@ class TestGArray(unittest.TestCase): self.assertRaises(TypeError, GIMarshallingTests.garray_int_none_in, 42) 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])) + def test_garray_utf8_none_in(self): GIMarshallingTests.garray_utf8_none_in(Sequence(['0', '1', '2'])) def test_garray_utf8_none_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.garray_utf8_none_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_none_out()) def test_garray_utf8_container_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.garray_utf8_container_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_container_out()) def test_garray_utf8_full_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.garray_utf8_full_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_full_out()) + + def test_garray_utf8_full_out_caller_allocated(self): + self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_full_out_caller_allocated()) def test_garray_utf8_none_inout(self): - self.assertEquals(['-2', '-1', '0', '1'], GIMarshallingTests.garray_utf8_none_inout(Sequence(('0', '1', '2')))) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.garray_utf8_none_inout(Sequence(('0', '1', '2')))) def test_garray_utf8_container_inout(self): - self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.garray_utf8_container_inout(['0', '1', '2'])) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.garray_utf8_container_inout(['0', '1', '2'])) def test_garray_utf8_full_inout(self): - self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.garray_utf8_full_inout(['0', '1', '2'])) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.garray_utf8_full_inout(['0', '1', '2'])) class TestGPtrArray(unittest.TestCase): def test_gptrarray_utf8_none_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_none_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_none_return()) def test_gptrarray_utf8_container_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_container_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_container_return()) def test_gptrarray_utf8_full_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_full_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_full_return()) def test_gptrarray_utf8_none_in(self): GIMarshallingTests.gptrarray_utf8_none_in(Sequence(['0', '1', '2'])) def test_gptrarray_utf8_none_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_none_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_none_out()) def test_gptrarray_utf8_container_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_container_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_container_out()) def test_gptrarray_utf8_full_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_full_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_full_out()) def test_gptrarray_utf8_none_inout(self): - self.assertEquals(['-2', '-1', '0', '1'], GIMarshallingTests.gptrarray_utf8_none_inout(Sequence(('0', '1', '2')))) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gptrarray_utf8_none_inout(Sequence(('0', '1', '2')))) def test_gptrarray_utf8_container_inout(self): - self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.gptrarray_utf8_container_inout(['0', '1', '2'])) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gptrarray_utf8_container_inout(['0', '1', '2'])) def test_gptrarray_utf8_full_inout(self): - self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.gptrarray_utf8_full_inout(['0', '1', '2'])) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gptrarray_utf8_full_inout(['0', '1', '2'])) + + +class TestGBytes(unittest.TestCase): + def test_gbytes_create(self): + b = GLib.Bytes.new(b'\x00\x01\xFF') + self.assertEqual(3, b.get_size()) + self.assertEqual(b'\x00\x01\xFF', b.get_data()) + + def test_gbytes_create_take(self): + b = GLib.Bytes.new_take(b'\x00\x01\xFF') + self.assertEqual(3, b.get_size()) + self.assertEqual(b'\x00\x01\xFF', b.get_data()) + + def test_gbytes_full_return(self): + b = GIMarshallingTests.gbytes_full_return() + self.assertEqual(4, b.get_size()) + self.assertEqual(b'\x00\x31\xFF\x33', b.get_data()) + + def test_gbytes_none_in(self): + b = GIMarshallingTests.gbytes_full_return() + GIMarshallingTests.gbytes_none_in(b) + + def test_compare(self): + a1 = GLib.Bytes.new(b'\x00\x01\xFF') + a2 = GLib.Bytes.new(b'\x00\x01\xFF') + b = GLib.Bytes.new(b'\x00\x01\xFE') + + self.assertTrue(a1.equal(a2)) + self.assertTrue(a2.equal(a1)) + self.assertFalse(a1.equal(b)) + self.assertFalse(b.equal(a2)) + + self.assertEqual(0, a1.compare(a2)) + self.assertLess(0, a1.compare(b)) + self.assertGreater(0, b.compare(a1)) + + +class TestGByteArray(unittest.TestCase): + def test_new(self): + ba = GLib.ByteArray.new() + self.assertEqual(b'', ba) + + ba = GLib.ByteArray.new_take(b'\x01\x02\xFF') + self.assertEqual(b'\x01\x02\xFF', ba) + + def test_bytearray_full_return(self): + self.assertEqual(b'\x001\xFF3', GIMarshallingTests.bytearray_full_return()) + + def test_bytearray_none_in(self): + GIMarshallingTests.bytearray_none_in(b'\x00\x31\xFF\x33') class TestGList(unittest.TestCase): def test_glist_int_none_return(self): - self.assertEquals([-1, 0, 1, 2], GIMarshallingTests.glist_int_none_return()) + 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()) def test_glist_utf8_none_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_none_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_none_return()) def test_glist_utf8_container_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_container_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_container_return()) def test_glist_utf8_full_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_full_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_full_return()) def test_glist_int_none_in(self): GIMarshallingTests.glist_int_none_in(Sequence((-1, 0, 1, 2))) @@ -910,41 +1089,44 @@ 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_uint32_none_in(self): + GIMarshallingTests.glist_uint32_none_in(Sequence((0, GObject.G_MAXUINT32))) + def test_glist_utf8_none_in(self): GIMarshallingTests.glist_utf8_none_in(Sequence(('0', '1', '2'))) def test_glist_utf8_none_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_none_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_none_out()) def test_glist_utf8_container_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_container_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_container_out()) def test_glist_utf8_full_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.glist_utf8_full_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_full_out()) def test_glist_utf8_none_inout(self): - self.assertEquals(['-2', '-1', '0', '1'], GIMarshallingTests.glist_utf8_none_inout(Sequence(('0', '1', '2')))) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.glist_utf8_none_inout(Sequence(('0', '1', '2')))) def test_glist_utf8_container_inout(self): - self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.glist_utf8_container_inout(('0', '1', '2'))) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.glist_utf8_container_inout(('0', '1', '2'))) def test_glist_utf8_full_inout(self): - self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.glist_utf8_full_inout(('0', '1', '2'))) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.glist_utf8_full_inout(('0', '1', '2'))) class TestGSList(unittest.TestCase): def test_gslist_int_none_return(self): - self.assertEquals([-1, 0, 1, 2], GIMarshallingTests.gslist_int_none_return()) + self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.gslist_int_none_return()) def test_gslist_utf8_none_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_none_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_none_return()) def test_gslist_utf8_container_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_container_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_container_return()) def test_gslist_utf8_full_return(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_full_return()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_full_return()) def test_gslist_int_none_in(self): GIMarshallingTests.gslist_int_none_in(Sequence((-1, 0, 1, 2))) @@ -958,37 +1140,37 @@ class TestGSList(unittest.TestCase): GIMarshallingTests.gslist_utf8_none_in(Sequence(('0', '1', '2'))) def test_gslist_utf8_none_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_none_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_none_out()) def test_gslist_utf8_container_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_container_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_container_out()) def test_gslist_utf8_full_out(self): - self.assertEquals(['0', '1', '2'], GIMarshallingTests.gslist_utf8_full_out()) + self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_full_out()) def test_gslist_utf8_none_inout(self): - self.assertEquals(['-2', '-1', '0', '1'], GIMarshallingTests.gslist_utf8_none_inout(Sequence(('0', '1', '2')))) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gslist_utf8_none_inout(Sequence(('0', '1', '2')))) def test_gslist_utf8_container_inout(self): - self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.gslist_utf8_container_inout(('0', '1', '2'))) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gslist_utf8_container_inout(('0', '1', '2'))) def test_gslist_utf8_full_inout(self): - self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.gslist_utf8_full_inout(('0', '1', '2'))) + self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gslist_utf8_full_inout(('0', '1', '2'))) class TestGHashTable(unittest.TestCase): def test_ghashtable_int_none_return(self): - self.assertEquals({-1: 1, 0: 0, 1: -1, 2: -2}, GIMarshallingTests.ghashtable_int_none_return()) + self.assertEqual({-1: 1, 0: 0, 1: -1, 2: -2}, GIMarshallingTests.ghashtable_int_none_return()) - def test_ghashtable_int_none_return(self): - self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_none_return()) + def test_ghashtable_int_none_return2(self): + self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_none_return()) def test_ghashtable_int_container_return(self): - self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_container_return()) + self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_container_return()) def test_ghashtable_int_full_return(self): - self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_full_return()) + self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_full_return()) def test_ghashtable_int_none_in(self): GIMarshallingTests.ghashtable_int_none_in({-1: 1, 0: 0, 1: -1, 2: -2}) @@ -1003,48 +1185,77 @@ class TestGHashTable(unittest.TestCase): GIMarshallingTests.ghashtable_utf8_none_in({'-1': '1', '0': '0', '1': '-1', '2': '-2'}) def test_ghashtable_utf8_none_out(self): - self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_none_out()) + self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_none_out()) def test_ghashtable_utf8_container_out(self): - self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_container_out()) + self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_container_out()) def test_ghashtable_utf8_full_out(self): - self.assertEquals({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_full_out()) + self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_full_out()) def test_ghashtable_utf8_none_inout(self): - self.assertEquals({'-1': '1', '0': '0', '1': '1'}, - GIMarshallingTests.ghashtable_utf8_none_inout({'-1': '1', '0': '0', '1': '-1', '2': '-2'})) + i = {'-1': '1', '0': '0', '1': '-1', '2': '-2'} + self.assertEqual({'-1': '1', '0': '0', '1': '1'}, + GIMarshallingTests.ghashtable_utf8_none_inout(i)) def test_ghashtable_utf8_container_inout(self): - self.assertEquals({'-1': '1', '0': '0', '1': '1'}, - GIMarshallingTests.ghashtable_utf8_container_inout({'-1': '1', '0': '0', '1': '-1', '2': '-2'})) + i = {'-1': '1', '0': '0', '1': '-1', '2': '-2'} + self.assertEqual({'-1': '1', '0': '0', '1': '1'}, + GIMarshallingTests.ghashtable_utf8_container_inout(i)) def test_ghashtable_utf8_full_inout(self): - self.assertEquals({'-1': '1', '0': '0', '1': '1'}, - GIMarshallingTests.ghashtable_utf8_full_inout({'-1': '1', '0': '0', '1': '-1', '2': '-2'})) + i = {'-1': '1', '0': '0', '1': '-1', '2': '-2'} + self.assertEqual({'-1': '1', '0': '0', '1': '1'}, + GIMarshallingTests.ghashtable_utf8_full_inout(i)) class TestGValue(unittest.TestCase): def test_gvalue_return(self): - self.assertEquals(42, GIMarshallingTests.gvalue_return()) + self.assertEqual(42, GIMarshallingTests.gvalue_return()) def test_gvalue_in(self): GIMarshallingTests.gvalue_in(42) - value = GObject.Value() - value.init(GObject.TYPE_INT) - value.set_int(42) + 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) + GIMarshallingTests.gvalue_int64_in(value) + + def test_gvalue_in_with_type(self): + value = GObject.Value(GObject.TYPE_STRING, 'foo') + GIMarshallingTests.gvalue_in_with_type(value, GObject.TYPE_STRING) + + value = GObject.Value(GIMarshallingTests.Flags.__gtype__, + GIMarshallingTests.Flags.VALUE1) + GIMarshallingTests.gvalue_in_with_type(value, GObject.TYPE_FLAGS) + + def test_gvalue_in_enum(self): + value = GObject.Value(GIMarshallingTests.Enum.__gtype__, + GIMarshallingTests.Enum.VALUE3) + GIMarshallingTests.gvalue_in_enum(value) + def test_gvalue_out(self): - self.assertEquals(42, GIMarshallingTests.gvalue_out()) + self.assertEqual(42, GIMarshallingTests.gvalue_out()) + + def test_gvalue_int64_out(self): + self.assertEqual(GObject.G_MAXINT64, GIMarshallingTests.gvalue_int64_out()) + + def test_gvalue_out_caller_allocates(self): + self.assertEqual(42, GIMarshallingTests.gvalue_out_caller_allocates()) def test_gvalue_inout(self): - self.assertEquals('42', GIMarshallingTests.gvalue_inout(42)) - value = GObject.Value() - value.init(GObject.TYPE_INT) - value.set_int(42) - self.assertEquals('42', GIMarshallingTests.gvalue_inout(value)) + self.assertEqual('42', GIMarshallingTests.gvalue_inout(42)) + value = GObject.Value(int, 42) + self.assertEqual('42', GIMarshallingTests.gvalue_inout(value)) def test_gvalue_flat_array_in(self): # the function already asserts the correct values @@ -1054,23 +1265,139 @@ class TestGValue(unittest.TestCase): values = GIMarshallingTests.return_gvalue_flat_array() self.assertEqual(values, [42, '42', True]) + def test_gvalue_gobject_ref_counts(self): + # Tests a GObject held by a GValue + obj = GObject.Object() + ref = weakref.ref(obj) + grefcount = obj.__grefcount__ + + value = GObject.Value() + value.init(GObject.TYPE_OBJECT) + + # TYPE_OBJECT will inc ref count as it should + value.set_object(obj) + self.assertEqual(obj.__grefcount__, grefcount + 1) + + # multiple set_object should not inc ref count + value.set_object(obj) + self.assertEqual(obj.__grefcount__, grefcount + 1) + + # get_object will re-use the same wrapper as obj + res = value.get_object() + self.assertEqual(obj, res) + self.assertEqual(obj.__grefcount__, grefcount + 1) + + # multiple get_object should not inc ref count + res = value.get_object() + self.assertEqual(obj.__grefcount__, grefcount + 1) + + # deletion of the result and value holder should bring the + # refcount back to where we started + del res + del value + gc.collect() + self.assertEqual(obj.__grefcount__, grefcount) + + del obj + gc.collect() + self.assertEqual(ref(), None) + + def test_gvalue_boxed_ref_counts(self): + # Tests a boxed type wrapping a python object pointer (TYPE_PYOBJECT) + # held by a GValue + class Obj(object): + pass + + obj = Obj() + ref = weakref.ref(obj) + refcount = sys.getrefcount(obj) + + value = GObject.Value() + value.init(GObject.TYPE_PYOBJECT) + + # boxed TYPE_PYOBJECT will inc ref count as it should + value.set_boxed(obj) + self.assertEqual(sys.getrefcount(obj), refcount + 1) + + # multiple set_boxed should not inc ref count + value.set_boxed(obj) + self.assertEqual(sys.getrefcount(obj), refcount + 1) + + res = value.get_boxed() + self.assertEqual(obj, res) + self.assertEqual(sys.getrefcount(obj), refcount + 2) + + # multiple get_boxed should not inc ref count + res = value.get_boxed() + self.assertEqual(sys.getrefcount(obj), refcount + 2) + + # deletion of the result and value holder should bring the + # refcount back to where we started + del res + del value + gc.collect() + self.assertEqual(sys.getrefcount(obj), refcount) + + del obj + gc.collect() + self.assertEqual(ref(), None) + + # FIXME: crashes + def disabled_test_gvalue_flat_array_round_trip(self): + self.assertEqual([42, '42', True], + GIMarshallingTests.gvalue_flat_array_round_trip(42, '42', True)) + class TestGClosure(unittest.TestCase): - def test_gclosure_in(self): + def test_in(self): GIMarshallingTests.gclosure_in(lambda: 42) + def test_pass(self): # test passing a closure between two C calls closure = GIMarshallingTests.gclosure_return() GIMarshallingTests.gclosure_in(closure) + def test_type_error(self): self.assertRaises(TypeError, GIMarshallingTests.gclosure_in, 42) self.assertRaises(TypeError, GIMarshallingTests.gclosure_in, None) +class TestCallbacks(unittest.TestCase): + def test_return_value_only(self): + def cb(): + return 5 + self.assertEqual(GIMarshallingTests.callback_return_value_only(cb), 5) + + def test_one_out_arg(self): + def cb(): + return 5.5 + self.assertAlmostEqual(GIMarshallingTests.callback_one_out_parameter(cb), 5.5) + + def test_multiple_out_args(self): + def cb(): + return (5.5, 42.0) + res = GIMarshallingTests.callback_multiple_out_parameters(cb) + self.assertAlmostEqual(res[0], 5.5) + self.assertAlmostEqual(res[1], 42.0) + + def test_return_and_one_out_arg(self): + def cb(): + return (5, 42.0) + res = GIMarshallingTests.callback_return_value_and_one_out_parameter(cb) + self.assertEqual(res[0], 5) + self.assertAlmostEqual(res[1], 42.0) + + def test_return_and_multiple_out_arg(self): + def cb(): + return (5, 42, -1000) + self.assertEqual(GIMarshallingTests.callback_return_value_and_multiple_out_parameters(cb), + (5, 42, -1000)) + + class TestPointer(unittest.TestCase): def test_pointer_in_return(self): - self.assertEquals(GIMarshallingTests.pointer_in_return(42), 42) + self.assertEqual(GIMarshallingTests.pointer_in_return(42), 42) class TestEnum(unittest.TestCase): @@ -1079,15 +1406,15 @@ class TestEnum(unittest.TestCase): def setUpClass(cls): '''Run tests under a test locale. - Upper case conversion of member names should not be locale specific; + 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() - subprocess.check_call(['localedef', '-i', - os.path.join(os.path.dirname(os.path.realpath(__file__)), 'te_ST@nouppera'), - '-c', '-f', 'UTF-8', os.path.join(cls.locale_dir, 'te_ST.UTF-8@nouppera')]) + 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') @@ -1105,7 +1432,7 @@ class TestEnum(unittest.TestCase): self.assertTrue(isinstance(GIMarshallingTests.Enum.VALUE1, GIMarshallingTests.Enum)) self.assertTrue(isinstance(GIMarshallingTests.Enum.VALUE2, GIMarshallingTests.Enum)) self.assertTrue(isinstance(GIMarshallingTests.Enum.VALUE3, GIMarshallingTests.Enum)) - self.assertEquals(42, GIMarshallingTests.Enum.VALUE3) + self.assertEqual(42, GIMarshallingTests.Enum.VALUE3) def test_value_nick_and_name(self): self.assertEqual(GIMarshallingTests.Enum.VALUE1.value_nick, 'value1') @@ -1123,15 +1450,20 @@ class TestEnum(unittest.TestCase): self.assertRaises(TypeError, GIMarshallingTests.enum_in, 43) self.assertRaises(TypeError, GIMarshallingTests.enum_in, 'GIMarshallingTests.Enum.VALUE3') + def test_enum_return(self): + enum = GIMarshallingTests.enum_returnv() + self.assertTrue(isinstance(enum, GIMarshallingTests.Enum)) + self.assertEqual(enum, GIMarshallingTests.Enum.VALUE3) + def test_enum_out(self): enum = GIMarshallingTests.enum_out() self.assertTrue(isinstance(enum, GIMarshallingTests.Enum)) - self.assertEquals(enum, GIMarshallingTests.Enum.VALUE3) + self.assertEqual(enum, GIMarshallingTests.Enum.VALUE3) def test_enum_inout(self): enum = GIMarshallingTests.enum_inout(GIMarshallingTests.Enum.VALUE3) self.assertTrue(isinstance(enum, GIMarshallingTests.Enum)) - self.assertEquals(enum, GIMarshallingTests.Enum.VALUE1) + self.assertEqual(enum, GIMarshallingTests.Enum.VALUE1) def test_enum_second(self): # check for the bug where different non-gtype enums share the same class @@ -1143,6 +1475,43 @@ class TestEnum(unittest.TestCase): self.assertTrue(hasattr(GIMarshallingTests.Enum, "VALUE1")) self.assertRaises(AttributeError, getattr, GIMarshallingTests.SecondEnum, "VALUE1") + def test_enum_gtype_name_is_namespaced(self): + 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__) + + +class TestEnumVFuncResults(unittest.TestCase): + class EnumTester(GIMarshallingTests.Object): + def do_vfunc_return_enum(self): + return GIMarshallingTests.Enum.VALUE2 + + def do_vfunc_out_enum(self): + return GIMarshallingTests.Enum.VALUE3 + + def test_vfunc_return_enum(self): + tester = self.EnumTester() + self.assertEqual(tester.vfunc_return_enum(), GIMarshallingTests.Enum.VALUE2) + + def test_vfunc_out_enum(self): + tester = self.EnumTester() + self.assertEqual(tester.vfunc_out_enum(), GIMarshallingTests.Enum.VALUE3) + class TestGEnum(unittest.TestCase): @@ -1151,7 +1520,7 @@ class TestGEnum(unittest.TestCase): self.assertTrue(isinstance(GIMarshallingTests.GEnum.VALUE1, GIMarshallingTests.GEnum)) self.assertTrue(isinstance(GIMarshallingTests.GEnum.VALUE2, GIMarshallingTests.GEnum)) self.assertTrue(isinstance(GIMarshallingTests.GEnum.VALUE3, GIMarshallingTests.GEnum)) - self.assertEquals(42, GIMarshallingTests.GEnum.VALUE3) + self.assertEqual(42, GIMarshallingTests.GEnum.VALUE3) def test_value_nick_and_name(self): self.assertEqual(GIMarshallingTests.GEnum.VALUE1.value_nick, 'value1') @@ -1169,15 +1538,20 @@ class TestGEnum(unittest.TestCase): self.assertRaises(TypeError, GIMarshallingTests.genum_in, 43) self.assertRaises(TypeError, GIMarshallingTests.genum_in, 'GIMarshallingTests.GEnum.VALUE3') + def test_genum_return(self): + genum = GIMarshallingTests.genum_returnv() + self.assertTrue(isinstance(genum, GIMarshallingTests.GEnum)) + self.assertEqual(genum, GIMarshallingTests.GEnum.VALUE3) + def test_genum_out(self): genum = GIMarshallingTests.genum_out() self.assertTrue(isinstance(genum, GIMarshallingTests.GEnum)) - self.assertEquals(genum, GIMarshallingTests.GEnum.VALUE3) + self.assertEqual(genum, GIMarshallingTests.GEnum.VALUE3) def test_genum_inout(self): genum = GIMarshallingTests.genum_inout(GIMarshallingTests.GEnum.VALUE3) self.assertTrue(isinstance(genum, GIMarshallingTests.GEnum)) - self.assertEquals(genum, GIMarshallingTests.GEnum.VALUE1) + self.assertEqual(genum, GIMarshallingTests.GEnum.VALUE1) class TestGFlags(unittest.TestCase): @@ -1190,7 +1564,7 @@ class TestGFlags(unittest.TestCase): # __or__() operation should still return an instance, not an int. self.assertTrue(isinstance(GIMarshallingTests.Flags.VALUE1 | GIMarshallingTests.Flags.VALUE2, GIMarshallingTests.Flags)) - self.assertEquals(1 << 1, GIMarshallingTests.Flags.VALUE2) + self.assertEqual(1 << 1, GIMarshallingTests.Flags.VALUE2) def test_value_nick_and_name(self): self.assertEqual(GIMarshallingTests.Flags.VALUE1.first_value_nick, 'value1') @@ -1210,15 +1584,20 @@ class TestGFlags(unittest.TestCase): self.assertRaises(TypeError, GIMarshallingTests.flags_in, 1 << 1) self.assertRaises(TypeError, GIMarshallingTests.flags_in, 'GIMarshallingTests.Flags.VALUE2') + def test_flags_return(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)) - self.assertEquals(flags, GIMarshallingTests.Flags.VALUE2) + self.assertEqual(flags, GIMarshallingTests.Flags.VALUE2) def test_flags_inout(self): flags = GIMarshallingTests.flags_inout(GIMarshallingTests.Flags.VALUE2) self.assertTrue(isinstance(flags, GIMarshallingTests.Flags)) - self.assertEquals(flags, GIMarshallingTests.Flags.VALUE1) + self.assertEqual(flags, GIMarshallingTests.Flags.VALUE1) class TestNoTypeFlags(unittest.TestCase): @@ -1231,7 +1610,7 @@ class TestNoTypeFlags(unittest.TestCase): # __or__() operation should still return an instance, not an int. self.assertTrue(isinstance(GIMarshallingTests.NoTypeFlags.VALUE1 | GIMarshallingTests.NoTypeFlags.VALUE2, GIMarshallingTests.NoTypeFlags)) - self.assertEquals(1 << 1, GIMarshallingTests.NoTypeFlags.VALUE2) + self.assertEqual(1 << 1, GIMarshallingTests.NoTypeFlags.VALUE2) def test_value_nick_and_name(self): self.assertEqual(GIMarshallingTests.NoTypeFlags.VALUE1.first_value_nick, 'value1') @@ -1250,15 +1629,35 @@ class TestNoTypeFlags(unittest.TestCase): self.assertRaises(TypeError, GIMarshallingTests.no_type_flags_in, 1 << 1) self.assertRaises(TypeError, GIMarshallingTests.no_type_flags_in, 'GIMarshallingTests.NoTypeFlags.VALUE2') + def test_flags_return(self): + flags = GIMarshallingTests.no_type_flags_returnv() + self.assertTrue(isinstance(flags, GIMarshallingTests.NoTypeFlags)) + self.assertEqual(flags, GIMarshallingTests.NoTypeFlags.VALUE2) + def test_flags_out(self): flags = GIMarshallingTests.no_type_flags_out() self.assertTrue(isinstance(flags, GIMarshallingTests.NoTypeFlags)) - self.assertEquals(flags, GIMarshallingTests.NoTypeFlags.VALUE2) + self.assertEqual(flags, GIMarshallingTests.NoTypeFlags.VALUE2) def test_flags_inout(self): flags = GIMarshallingTests.no_type_flags_inout(GIMarshallingTests.NoTypeFlags.VALUE2) self.assertTrue(isinstance(flags, GIMarshallingTests.NoTypeFlags)) - self.assertEquals(flags, GIMarshallingTests.NoTypeFlags.VALUE1) + self.assertEqual(flags, GIMarshallingTests.NoTypeFlags.VALUE1) + + def test_flags_gtype_name_is_namespaced(self): + 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) class TestStructure(unittest.TestCase): @@ -1269,14 +1668,14 @@ class TestStructure(unittest.TestCase): struct = GIMarshallingTests.SimpleStruct() self.assertTrue(isinstance(struct, GIMarshallingTests.SimpleStruct)) - self.assertEquals(0, struct.long_) - self.assertEquals(0, struct.int8) + self.assertEqual(0, struct.long_) + self.assertEqual(0, struct.int8) struct.long_ = 6 struct.int8 = 7 - self.assertEquals(6, struct.long_) - self.assertEquals(7, struct.int8) + self.assertEqual(6, struct.long_) + self.assertEqual(7, struct.int8) del struct @@ -1286,20 +1685,20 @@ class TestStructure(unittest.TestCase): self.assertTrue(isinstance(struct.simple_struct, GIMarshallingTests.SimpleStruct)) struct.simple_struct.long_ = 42 - self.assertEquals(42, struct.simple_struct.long_) + self.assertEqual(42, struct.simple_struct.long_) del struct def test_not_simple_struct(self): struct = GIMarshallingTests.NotSimpleStruct() - self.assertEquals(None, struct.pointer) + self.assertEqual(None, struct.pointer) def test_simple_struct_return(self): struct = GIMarshallingTests.simple_struct_returnv() self.assertTrue(isinstance(struct, GIMarshallingTests.SimpleStruct)) - self.assertEquals(6, struct.long_) - self.assertEquals(7, struct.int8) + self.assertEqual(6, struct.long_) + self.assertEqual(7, struct.int8) del struct @@ -1343,7 +1742,7 @@ class TestStructure(unittest.TestCase): struct = GIMarshallingTests.pointer_struct_returnv() self.assertTrue(isinstance(struct, GIMarshallingTests.PointerStruct)) - self.assertEquals(42, struct.long_) + self.assertEqual(42, struct.long_) del struct @@ -1361,22 +1760,29 @@ class TestStructure(unittest.TestCase): struct = GIMarshallingTests.BoxedStruct() self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct)) - self.assertEquals(0, struct.long_) - self.assertEquals([], struct.g_strv) + self.assertEqual(0, struct.long_) + self.assertEqual(None, struct.string_) + self.assertEqual([], struct.g_strv) del struct def test_boxed_struct_new(self): struct = GIMarshallingTests.BoxedStruct.new() self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct)) + self.assertEqual(struct.long_, 0) + self.assertEqual(struct.string_, None) del struct def test_boxed_struct_copy(self): struct = GIMarshallingTests.BoxedStruct() + struct.long_ = 42 + struct.string_ = 'hello' new_struct = struct.copy() self.assertTrue(isinstance(new_struct, GIMarshallingTests.BoxedStruct)) + self.assertEqual(new_struct.long_, 42) + self.assertEqual(new_struct.string_, 'hello') del new_struct del struct @@ -1385,8 +1791,9 @@ class TestStructure(unittest.TestCase): struct = GIMarshallingTests.boxed_struct_returnv() self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct)) - self.assertEquals(42, struct.long_) - self.assertEquals(['0', '1', '2'], struct.g_strv) + self.assertEqual(42, struct.long_) + self.assertEqual('hello', struct.string_) + self.assertEqual(['0', '1', '2'], struct.g_strv) del struct @@ -1402,7 +1809,7 @@ class TestStructure(unittest.TestCase): struct = GIMarshallingTests.boxed_struct_out() self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct)) - self.assertEquals(42, struct.long_) + self.assertEqual(42, struct.long_) del struct @@ -1413,11 +1820,19 @@ class TestStructure(unittest.TestCase): out_struct = GIMarshallingTests.boxed_struct_inout(in_struct) self.assertTrue(isinstance(out_struct, GIMarshallingTests.BoxedStruct)) - self.assertEquals(0, out_struct.long_) + self.assertEqual(0, out_struct.long_) del in_struct del out_struct + def test_struct_field_assignment(self): + struct = GIMarshallingTests.BoxedStruct() + + struct.long_ = 42 + struct.string_ = 'hello' + self.assertEqual(struct.long_, 42) + self.assertEqual(struct.string_, 'hello') + def test_union(self): union = GIMarshallingTests.Union() @@ -1433,7 +1848,7 @@ class TestStructure(unittest.TestCase): union = GIMarshallingTests.union_returnv() self.assertTrue(isinstance(union, GIMarshallingTests.Union)) - self.assertEquals(42, union.long_) + self.assertEqual(42, union.long_) del union @@ -1463,25 +1878,25 @@ class TestGObject(unittest.TestCase): object_ = GIMarshallingTests.Object() self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) - self.assertEquals(object_.__grefcount__, 1) + self.assertEqual(object_.__grefcount__, 1) def test_object_new(self): object_ = GIMarshallingTests.Object.new(42) self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) - self.assertEquals(object_.__grefcount__, 1) + self.assertEqual(object_.__grefcount__, 1) def test_object_int(self): - object_ = GIMarshallingTests.Object(int = 42) - self.assertEquals(object_.int_, 42) + object_ = GIMarshallingTests.Object(int=42) + self.assertEqual(object_.int_, 42) # FIXME: Don't work yet. # object_.int_ = 0 -# self.assertEquals(object_.int_, 0) +# self.assertEqual(object_.int_, 0) def test_object_static_method(self): GIMarshallingTests.Object.static_method() def test_object_method(self): - GIMarshallingTests.Object(int = 42).method() + GIMarshallingTests.Object(int=42).method() self.assertRaises(TypeError, GIMarshallingTests.Object.method, GObject.GObject()) self.assertRaises(TypeError, GIMarshallingTests.Object.method) @@ -1499,7 +1914,7 @@ class TestGObject(unittest.TestCase): object_.static_method() def test_sub_object_method(self): - object_ = GIMarshallingTests.SubObject(int = 42) + object_ = GIMarshallingTests.SubObject(int=42) object_.method() def test_sub_object_sub_method(self): @@ -1514,27 +1929,27 @@ class TestGObject(unittest.TestCase): def test_sub_object_int(self): object_ = GIMarshallingTests.SubObject() - self.assertEquals(object_.int_, 0) + self.assertEqual(object_.int_, 0) # FIXME: Don't work yet. # object_.int_ = 42 -# self.assertEquals(object_.int_, 42) +# self.assertEqual(object_.int_, 42) def test_object_none_return(self): object_ = GIMarshallingTests.Object.none_return() self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) - self.assertEquals(object_.__grefcount__, 2) + self.assertEqual(object_.__grefcount__, 2) def test_object_full_return(self): object_ = GIMarshallingTests.Object.full_return() self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) - self.assertEquals(object_.__grefcount__, 1) + self.assertEqual(object_.__grefcount__, 1) def test_object_none_in(self): - object_ = GIMarshallingTests.Object(int = 42) + object_ = GIMarshallingTests.Object(int=42) GIMarshallingTests.Object.none_in(object_) - self.assertEquals(object_.__grefcount__, 1) + self.assertEqual(object_.__grefcount__, 1) - object_ = GIMarshallingTests.SubObject(int = 42) + object_ = GIMarshallingTests.SubObject(int=42) GIMarshallingTests.Object.none_in(object_) object_ = GObject.GObject() @@ -1545,7 +1960,7 @@ class TestGObject(unittest.TestCase): def test_object_none_out(self): object_ = GIMarshallingTests.Object.none_out() self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) - self.assertEquals(object_.__grefcount__, 2) + self.assertEqual(object_.__grefcount__, 2) new_object = GIMarshallingTests.Object.none_out() self.assertTrue(new_object is object_) @@ -1553,46 +1968,48 @@ class TestGObject(unittest.TestCase): def test_object_full_out(self): object_ = GIMarshallingTests.Object.full_out() self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) - self.assertEquals(object_.__grefcount__, 1) + self.assertEqual(object_.__grefcount__, 1) def test_object_none_inout(self): - object_ = GIMarshallingTests.Object(int = 42) + object_ = GIMarshallingTests.Object(int=42) new_object = GIMarshallingTests.Object.none_inout(object_) self.assertTrue(isinstance(new_object, GIMarshallingTests.Object)) self.assertFalse(object_ is new_object) - self.assertEquals(object_.__grefcount__, 1) - self.assertEquals(new_object.__grefcount__, 2) + self.assertEqual(object_.__grefcount__, 1) + self.assertEqual(new_object.__grefcount__, 2) new_new_object = GIMarshallingTests.Object.none_inout(object_) self.assertTrue(new_new_object is new_object) - GIMarshallingTests.Object.none_inout(GIMarshallingTests.SubObject(int = 42)) + GIMarshallingTests.Object.none_inout(GIMarshallingTests.SubObject(int=42)) def test_object_full_inout(self): - object_ = GIMarshallingTests.Object(int = 42) + object_ = GIMarshallingTests.Object(int=42) new_object = GIMarshallingTests.Object.full_inout(object_) self.assertTrue(isinstance(new_object, GIMarshallingTests.Object)) self.assertFalse(object_ is new_object) - self.assertEquals(object_.__grefcount__, 2) - self.assertEquals(new_object.__grefcount__, 1) + self.assertEqual(object_.__grefcount__, 2) + self.assertEqual(new_object.__grefcount__, 1) # FIXME: Doesn't actually return the same object. # def test_object_inout_same(self): # object_ = GIMarshallingTests.Object() # new_object = GIMarshallingTests.object_full_inout(object_) # self.assertTrue(object_ is new_object) -# self.assertEquals(object_.__grefcount__, 1) +# self.assertEqual(object_.__grefcount__, 1) class TestPythonGObject(unittest.TestCase): class Object(GIMarshallingTests.Object): + return_for_caller_allocated_out_parameter = 'test caller alloc return' + def __init__(self, int): GIMarshallingTests.Object.__init__(self) self.val = None @@ -1607,10 +2024,37 @@ class TestPythonGObject(unittest.TestCase): def do_method_int8_out(self): return 42 + def do_method_int8_arg_and_out_caller(self, arg): + return arg + 1 + + def do_method_int8_arg_and_out_callee(self, arg): + return arg + 1 + + def do_method_str_arg_out_ret(self, arg): + return (arg.upper(), len(arg)) + def do_method_with_default_implementation(self, int8): GIMarshallingTests.Object.do_method_with_default_implementation(self, int8) self.props.int += int8 + def do_vfunc_return_value_only(self): + return 4242 + + def do_vfunc_one_out_parameter(self): + return 42.42 + + def do_vfunc_multiple_out_parameters(self): + return (42.42, 3.14) + + def do_vfunc_return_value_and_one_out_parameter(self): + return (5, 42) + + def do_vfunc_return_value_and_multiple_out_parameters(self): + return (5, 42, 99) + + def do_vfunc_caller_allocated_out_parameter(self): + return self.return_for_caller_allocated_out_parameter + class SubObject(GIMarshallingTests.SubObject): def __init__(self, int): GIMarshallingTests.SubObject.__init__(self) @@ -1619,48 +2063,96 @@ class TestPythonGObject(unittest.TestCase): def do_method_with_default_implementation(self, int8): self.val = int8 + def do_vfunc_return_value_only(self): + return 2121 + + class Interface3Impl(GObject.Object, GIMarshallingTests.Interface3): + def __init__(self): + GObject.Object.__init__(self) + self.variants = None + self.n_variants = None + + def do_test_variant_array_in(self, variants, n_variants): + self.variants = variants + self.n_variants = n_variants + + class ErrorObject(GIMarshallingTests.Object): + def do_vfunc_return_value_only(self): + raise ValueError('Return value should be 0') + def test_object(self): self.assertTrue(issubclass(self.Object, GIMarshallingTests.Object)) - object_ = self.Object(int = 42) + object_ = self.Object(int=42) self.assertTrue(isinstance(object_, self.Object)) def test_object_method(self): - self.Object(int = 0).method() + self.Object(int=0).method() def test_object_vfuncs(self): - object_ = self.Object(int = 42) + object_ = self.Object(int=42) object_.method_int8_in(84) self.assertEqual(object_.val, 84) self.assertEqual(object_.method_int8_out(), 42) + # can be dropped when bumping g-i dependencies to >= 1.35.2 + if hasattr(object_, 'method_int8_arg_and_out_caller'): + self.assertEqual(object_.method_int8_arg_and_out_caller(42), 43) + self.assertEqual(object_.method_int8_arg_and_out_callee(42), 43) + self.assertEqual(object_.method_str_arg_out_ret('hello'), ('HELLO', 5)) + object_.method_with_default_implementation(42) self.assertEqual(object_.props.int, 84) + self.assertEqual(object_.vfunc_return_value_only(), 4242) + self.assertAlmostEqual(object_.vfunc_one_out_parameter(), 42.42, places=5) + + (a, b) = object_.vfunc_multiple_out_parameters() + self.assertAlmostEqual(a, 42.42, places=5) + self.assertAlmostEqual(b, 3.14, places=5) + + self.assertEqual(object_.vfunc_return_value_and_one_out_parameter(), (5, 42)) + self.assertEqual(object_.vfunc_return_value_and_multiple_out_parameters(), (5, 42, 99)) + + self.assertEqual(object_.vfunc_caller_allocated_out_parameter(), + object_.return_for_caller_allocated_out_parameter) + class ObjectWithoutVFunc(GIMarshallingTests.Object): def __init__(self, int): GIMarshallingTests.Object.__init__(self) - object_ = ObjectWithoutVFunc(int = 42) + object_ = ObjectWithoutVFunc(int=42) object_.method_with_default_implementation(84) self.assertEqual(object_.props.int, 84) + def test_vfunc_return_ref_count(self): + obj = self.Object(int=42) + ref_count = sys.getrefcount(obj.return_for_caller_allocated_out_parameter) + ret = obj.vfunc_caller_allocated_out_parameter() + gc.collect() + + # Make sure the return and what the vfunc returned + # are equal but not the same object. + self.assertEqual(ret, obj.return_for_caller_allocated_out_parameter) + self.assertFalse(ret is obj.return_for_caller_allocated_out_parameter) + self.assertEqual(sys.getrefcount(obj.return_for_caller_allocated_out_parameter), + ref_count) + def test_subobject_parent_vfunc(self): - object_ = self.SubObject(int = 81) + object_ = self.SubObject(int=81) object_.method_with_default_implementation(87) - self.assertEquals(object_.val, 87) + self.assertEqual(object_.val, 87) + + def test_subobject_child_vfunc(self): + object_ = self.SubObject(int=1) + self.assertEqual(object_.vfunc_return_value_only(), 2121) def test_dynamic_module(self): - from gi.module import DynamicGObjectModule - self.assertTrue(isinstance(GObject, DynamicGObjectModule)) - # compare the same enum from both the pygobject attrs and gi GObject attrs - self.assertEquals(GObject.SIGNAL_ACTION, GObject.SignalFlags.ACTION) - # compare a static gobject attr with a dynamic GObject attr - import gi._gobject - self.assertEquals(GObject.GObject, gi._gobject.GObject) + from gi.module import DynamicModule + self.assertTrue(isinstance(GObject, DynamicModule)) def test_subobject_non_vfunc_do_method(self): - class PythonObjectWithNonVFuncDoMethod: + class PythonObjectWithNonVFuncDoMethod(object): def do_not_a_vfunc(self): return 5 @@ -1670,7 +2162,7 @@ class TestPythonGObject(unittest.TestCase): return 13 + value object_ = ObjectOverrideNonVFuncDoMethod() - self.assertEquals(18, object_.do_not_a_vfunc()) + self.assertEqual(18, object_.do_not_a_vfunc()) def test_native_function_not_set_in_subclass_dict(self): # Previously, GI was setting virtual functions on the class as well @@ -1696,25 +2188,69 @@ class TestPythonGObject(unittest.TestCase): GIMarshallingTests.SubSubObject.do_method_deep_hierarchy(sub_sub_sub_object, 5) self.assertEqual(sub_sub_sub_object.props.int, 5) + def test_interface3impl(self): + iface3 = self.Interface3Impl() + variants = [GLib.Variant('i', 27), GLib.Variant('s', 'Hello')] + iface3.test_variant_array_in(variants) + self.assertEqual(iface3.n_variants, 2) + self.assertEqual(iface3.variants[0].unpack(), 27) + self.assertEqual(iface3.variants[1].unpack(), 'Hello') + + def test_python_subsubobject_vfunc(self): + class PySubObject(GIMarshallingTests.Object): + def __init__(self): + GIMarshallingTests.Object.__init__(self) + self.sub_method_int8_called = 0 + + def do_method_int8_in(self, int8): + self.sub_method_int8_called += 1 + + class PySubSubObject(PySubObject): + def __init__(self): + PySubObject.__init__(self) + self.subsub_method_int8_called = 0 + + def do_method_int8_in(self, int8): + self.subsub_method_int8_called += 1 + + so = PySubObject() + so.method_int8_in(1) + self.assertEqual(so.sub_method_int8_called, 1) + + # it should call the method on the SubSub object only + sso = PySubSubObject() + sso.method_int8_in(1) + self.assertEqual(sso.subsub_method_int8_called, 1) + self.assertEqual(sso.sub_method_int8_called, 0) + + def test_callback_in_vfunc(self): + class SubObject(GIMarshallingTests.Object): + def __init__(self): + GObject.GObject.__init__(self) + self.worked = False + + def do_vfunc_with_callback(self, callback): + self.worked = callback(42) == 42 + + _object = SubObject() + _object.call_vfunc_with_callback() + self.assertTrue(_object.worked) + _object.worked = False + _object.call_vfunc_with_callback() + self.assertTrue(_object.worked) + + def test_exception_in_vfunc_return_value(self): + obj = self.ErrorObject() + self.assertEqual(obj.vfunc_return_value_only(), 0) + class TestMultiOutputArgs(unittest.TestCase): def test_int_out_out(self): - self.assertEquals((6, 7), GIMarshallingTests.int_out_out()) + self.assertEqual((6, 7), GIMarshallingTests.int_out_out()) def test_int_return_out(self): - self.assertEquals((6, 7), GIMarshallingTests.int_return_out()) - -class TestGErrorException(unittest.TestCase): - def test_gerror_exception(self): - self.assertRaises(GObject.GError, GIMarshallingTests.gerror) - try: - GIMarshallingTests.gerror() - except Exception: - etype, e = sys.exc_info()[:2] - self.assertEquals(e.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) - self.assertEquals(e.code, GIMarshallingTests.CONSTANT_GERROR_CODE) - self.assertEquals(e.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) + self.assertEqual((6, 7), GIMarshallingTests.int_return_out()) # Interface @@ -1734,7 +2270,7 @@ class TestInterfaces(unittest.TestCase): def test_wrapper(self): self.assertTrue(issubclass(GIMarshallingTests.Interface, GObject.GInterface)) - self.assertEquals(GIMarshallingTests.Interface.__gtype__.name, 'GIMarshallingTestsInterface') + self.assertEqual(GIMarshallingTests.Interface.__gtype__.name, 'GIMarshallingTestsInterface') self.assertRaises(NotImplementedError, GIMarshallingTests.Interface) def test_implementation(self): @@ -1743,7 +2279,7 @@ class TestInterfaces(unittest.TestCase): def test_int8_int(self): GIMarshallingTests.test_interface_test_int8_in(self.instance, 42) - self.assertEquals(self.instance.val, 42) + self.assertEqual(self.instance.val, 42) def test_subclass(self): class TestInterfaceImplA(self.TestInterfaceImpl): @@ -1754,9 +2290,104 @@ class TestInterfaces(unittest.TestCase): instance = TestInterfaceImplA() GIMarshallingTests.test_interface_test_int8_in(instance, 42) - self.assertEquals(instance.val, 42) + self.assertEqual(instance.val, 42) + + def test_subclass_override(self): + class TestInterfaceImplD(TestInterfaces.TestInterfaceImpl): + val2 = None + + def do_test_int8_in(self, int8): + self.val2 = int8 + + instance = TestInterfaceImplD() + self.assertEqual(instance.val, None) + self.assertEqual(instance.val2, None) + + GIMarshallingTests.test_interface_test_int8_in(instance, 42) + self.assertEqual(instance.val, None) + self.assertEqual(instance.val2, 42) + + def test_type_mismatch(self): + obj = GIMarshallingTests.Object() + # wrong type for first argument: interface + enum = Gio.File.new_for_path('.').enumerate_children( + '', Gio.FileQueryInfoFlags.NONE, None) + try: + enum.next_file(obj) + self.fail('call with wrong type argument unexpectedly succeeded') + except TypeError as e: + # should have argument name + self.assertTrue('cancellable' in str(e), e) + # should have expected type + self.assertTrue('xpected Gio.Cancellable' in str(e), e) + # should have actual type + self.assertTrue('GIMarshallingTests.Object' in str(e), e) + + # wrong type for self argument: interface + try: + Gio.FileEnumerator.next_file(obj, None) + self.fail('call with wrong type argument unexpectedly succeeded') + except TypeError as e: + # should have argument name + self.assertTrue('self' in str(e), e) + # should have expected type + self.assertTrue('xpected Gio.FileEnumerator' in str(e), e) + # should have actual type + self.assertTrue('GIMarshallingTests.Object' in str(e), e) + + # wrong type for first argument: GObject + var = GLib.Variant('s', 'mystring') + action = Gio.SimpleAction.new('foo', var.get_type()) + try: + action.activate(obj) + self.fail('call with wrong type argument unexpectedly succeeded') + except TypeError as e: + # should have argument name + self.assertTrue('parameter' in str(e), e) + # should have expected type + self.assertTrue('xpected GLib.Variant' in str(e), e) + # should have actual type + self.assertTrue('GIMarshallingTests.Object' in str(e), e) + + # wrong type for self argument: GObject + try: + Gio.SimpleAction.activate(obj, obj) + self.fail('call with wrong type argument unexpectedly succeeded') + except TypeError as e: + # should have argument name + self.assertTrue('self' in str(e), e) + # should have expected type + self.assertTrue('xpected Gio.Action' in str(e), e) + # should have actual type + self.assertTrue('GIMarshallingTests.Object' in str(e), e) + + +class TestMRO(unittest.TestCase): def test_mro(self): + # check that our own MRO calculation matches what we would expect + # from Python's own C3 calculations + class A(object): + pass + + class B(A): + pass + + class C(A): + pass + + class D(B, C): + pass + + class E(D, GIMarshallingTests.Object): + pass + + expected = (E, D, B, C, A, GIMarshallingTests.Object, + GObject.Object, GObject.Object.__base__, gi._gobject.GObject, + object) + self.assertEqual(expected, E.__mro__) + + def test_interface_collision(self): # there was a problem with Python bailing out because of # http://en.wikipedia.org/wiki/Diamond_problem with interfaces, # which shouldn't really be a problem. @@ -1768,10 +2399,27 @@ class TestInterfaces(unittest.TestCase): TestInterfaceImpl): pass - class TestInterfaceImpl3(self.TestInterfaceImpl, + class TestInterfaceImpl3(TestInterfaceImpl, GIMarshallingTests.Interface2): pass + def test_old_style_mixin(self): + # Note: Old style classes don't exist in Python 3 + class Mixin: + pass + + with warnings.catch_warnings(record=True) as warn: + warnings.simplefilter('always') + + # Dynamically create a new gi based class with an old + # 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) + class TestInterfaceClash(unittest.TestCase): @@ -1788,7 +2436,7 @@ class TestInterfaceClash(unittest.TestCase): class TestOverrides(unittest.TestCase): def test_constant(self): - self.assertEquals(GIMarshallingTests.OVERRIDES_CONSTANT, 7) + self.assertEqual(GIMarshallingTests.OVERRIDES_CONSTANT, 7) def test_struct(self): # Test that the constructor has been overridden. @@ -1797,7 +2445,7 @@ class TestOverrides(unittest.TestCase): self.assertTrue(isinstance(struct, GIMarshallingTests.OverridesStruct)) # Test that the method has been overridden. - self.assertEquals(6, struct.method()) + self.assertEqual(6, struct.method()) del struct @@ -1820,7 +2468,7 @@ class TestOverrides(unittest.TestCase): self.assertTrue(isinstance(object_, GIMarshallingTests.OverridesObject)) # Test that the method has been overridden. - self.assertEquals(6, object_.method()) + self.assertEqual(6, object_.method()) # Test that the overrides wrapper has been registered. object_ = GIMarshallingTests.OverridesObject.returnv() @@ -1828,8 +2476,16 @@ class TestOverrides(unittest.TestCase): self.assertTrue(isinstance(object_, GIMarshallingTests.OverridesObject)) def test_module_name(self): - self.assertEquals(GIMarshallingTests.OverridesStruct.__module__, 'gi.overrides.GIMarshallingTests') - self.assertEquals(GObject.InitiallyUnowned.__module__, 'gi.repository.GObject') + # overridden types + self.assertEqual(GIMarshallingTests.OverridesStruct.__module__, 'gi.overrides.GIMarshallingTests') + self.assertEqual(GIMarshallingTests.OverridesObject.__module__, 'gi.overrides.GIMarshallingTests') + self.assertEqual(GObject.Object.__module__, 'gi.overrides.GObject') + + # 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') class TestDir(unittest.TestCase): @@ -1857,49 +2513,74 @@ class TestDir(unittest.TestCase): # self.assertTrue('DoNotImportDummyTests' in list) -class TestGErrorArrayInCrash(unittest.TestCase): - # 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 - def test_gerror_array_in_crash(self): +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]) - -class TestGErrorOut(unittest.TestCase): - # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 - def test_gerror_out(self): + 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.assertEquals(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) - self.assertEquals(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) - self.assertEquals(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) - self.assertEquals(debug, GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE) + 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) - -class TestGErrorOutTransferNone(unittest.TestCase): - # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 - def test_gerror_out_transfer_none(self): + 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.assertEquals(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) - self.assertEquals(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) - self.assertEquals(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) - self.assertEquals(GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE, debug) - + 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) -class TestGErrorReturn(unittest.TestCase): - # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 - def test_return_gerror(self): + def test_return(self): + # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 error = GIMarshallingTests.gerror_return() self.assertIsInstance(error, GObject.GError) - self.assertEquals(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) - self.assertEquals(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) - self.assertEquals(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) + 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 + def test_param_spec_in_bool(self): + ps = GObject.param_spec_boolean('mybool', 'test-bool', 'boolblurb', + True, GObject.ParamFlags.READABLE) + GIMarshallingTests.param_spec_in_bool(ps) + + def test_param_spec_return(self): + obj = GIMarshallingTests.param_spec_return() + self.assertEqual(obj.name, 'test-param') + self.assertEqual(obj.nick, 'test') + self.assertEqual(obj.value_type, GObject.TYPE_STRING) + + def test_param_spec_out(self): + obj = GIMarshallingTests.param_spec_out() + self.assertEqual(obj.name, 'test-param') + self.assertEqual(obj.nick, 'test') + self.assertEqual(obj.value_type, GObject.TYPE_STRING) class TestKeywordArgs(unittest.TestCase): @@ -1907,13 +2588,13 @@ class TestKeywordArgs(unittest.TestCase): def test_calling(self): kw_func = GIMarshallingTests.int_three_in_three_out - self.assertEquals(kw_func(1, 2, 3), (1, 2, 3)) - self.assertEquals(kw_func(**{'a':4, 'b':5, 'c':6}), (4, 5, 6)) - self.assertEquals(kw_func(1, **{'b':7, 'c':8}), (1, 7, 8)) - self.assertEquals(kw_func(1, 7, **{'c':8}), (1, 7, 8)) - self.assertEquals(kw_func(1, c=8, **{'b':7}), (1, 7, 8)) - self.assertEquals(kw_func(2, c=4, b=3), (2, 3, 4)) - self.assertEquals(kw_func(a=2, c=4, b=3), (2, 3, 4)) + self.assertEqual(kw_func(1, 2, 3), (1, 2, 3)) + self.assertEqual(kw_func(**{'a': 4, 'b': 5, 'c': 6}), (4, 5, 6)) + self.assertEqual(kw_func(1, **{'b': 7, 'c': 8}), (1, 7, 8)) + self.assertEqual(kw_func(1, 7, **{'c': 8}), (1, 7, 8)) + self.assertEqual(kw_func(1, c=8, **{'b': 7}), (1, 7, 8)) + self.assertEqual(kw_func(2, c=4, b=3), (2, 3, 4)) + self.assertEqual(kw_func(a=2, c=4, b=3), (2, 3, 4)) def assertRaisesMessage(self, exception, message, func, *args, **kwargs): try: @@ -1939,7 +2620,7 @@ class TestKeywordArgs(unittest.TestCase): self.assertRaisesMessage(TypeError, "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)", - GIMarshallingTests.int_three_in_three_out, *(), **{'c':4}) + 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)", @@ -1972,54 +2653,300 @@ class TestPropertiesObject(unittest.TestCase): self.obj.props.some_boolean = True self.assertEqual(self.obj.props.some_boolean, True) - @unittest.expectedFailure + obj = GIMarshallingTests.PropertiesObject(some_boolean=True) + self.assertEqual(obj.props.some_boolean, True) + def test_char(self): - # gobject-introspection thinks it has a guint8 type tag, which is wrong 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) + + self.assertEqual(obj.props.some_variant.get_type_string(), 'b') + self.assertEqual(obj.props.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, obj.props.some_int) + self.assertEqual(54, obj.props.some_uchar) + + +class TestKeywords(unittest.TestCase): + def test_method(self): + # g_variant_print() + v = GLib.Variant('i', 1) + self.assertEqual(v.print_(False), '1') + + def test_function(self): + # g_thread_yield() + self.assertEqual(GLib.Thread.yield_(), None) + + def test_struct_method(self): + # g_timer_continue() + # we cannot currently instantiate GLib.Timer objects, so just ensure + # the method exists + self.assertTrue(callable(GLib.Timer.continue_)) + + def test_uppercase(self): + self.assertEqual(GLib.IOCondition.IN.value_nicks, ['in']) + + +class TestModule(unittest.TestCase): + def test_path(self): + self.assertTrue(GIMarshallingTests.__path__.endswith('GIMarshallingTests-1.0.typelib'), + GIMarshallingTests.__path__) + + def test_str(self): + self.assertTrue("'GIMarshallingTests' from '" in str(GIMarshallingTests), + str(GIMarshallingTests)) + + def test_dir(self): + _dir = dir(GIMarshallingTests) + self.assertGreater(len(_dir), 10) + + self.assertTrue('SimpleStruct' in _dir) + self.assertTrue('Interface2' in _dir) + self.assertTrue('CONSTANT_GERROR_CODE' in _dir) + self.assertTrue('array_zero_terminated_inout' in _dir) + + # assert that dir() does not contain garbage + for item_name in _dir: + item = getattr(GIMarshallingTests, item_name) + 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() + help(GIMarshallingTests) + output = sys.stdout.getvalue() + finally: + sys.stdout = orig_stdout + + self.assertTrue('SimpleStruct' in output, output) + self.assertTrue('Interface2' in output, output) + self.assertTrue('method_array_inout' in output, output) + + +class TestProjectVersion(unittest.TestCase): + def test_version_str(self): + self.assertGreater(gi.__version__, "3.") + + def test_version_info(self): + self.assertEqual(len(gi.version_info), 3) + self.assertGreaterEqual(gi.version_info, (3, 3, 5)) + + def test_check_version(self): + self.assertRaises(ValueError, gi.check_version, (99, 0, 0)) + self.assertRaises(ValueError, gi.check_version, "99.0.0") + gi.check_version((3, 3, 5)) + 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()) + + 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_get_class_struct(self): + self.assertEqual(GObject.Object.__info__.get_class_struct(), + GObject.ObjectClass.__info__) + + +class TestDeprecation(unittest.TestCase): + def test_method(self): + d = GLib.Date.new() + with warnings.catch_warnings(record=True) as warn: + warnings.simplefilter('always') + d.set_time(1) + self.assertTrue(issubclass(warn[0].category, DeprecationWarning)) diff --git a/tests/test_gio.py b/tests/test_gio.py new file mode 100644 index 0000000..57ab013 --- /dev/null +++ b/tests/test_gio.py @@ -0,0 +1,203 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab + +import unittest + +import gi.overrides +from gi.repository import GLib, Gio + + +class TestGio(unittest.TestCase): + def test_file_enumerator(self): + self.assertEqual(Gio.FileEnumerator, gi.overrides.Gio.FileEnumerator) + f = Gio.file_new_for_path("./") + + iter_info = [] + for info in f.enumerate_children("standard::*", 0, None): + iter_info.append(info.get_name()) + + next_info = [] + enumerator = f.enumerate_children("standard::*", 0, None) + while True: + info = enumerator.next_file(None) + if info is None: + break + next_info.append(info.get_name()) + + self.assertEqual(iter_info, next_info) + + def test_menu_item(self): + menu = Gio.Menu() + item = Gio.MenuItem() + item.set_attribute([("label", "s", "Test"), + ("action", "s", "app.test")]) + menu.append_item(item) + value = menu.get_item_attribute_value(0, "label", GLib.VariantType.new("s")) + self.assertEqual("Test", value.unpack()) + value = menu.get_item_attribute_value(0, "action", GLib.VariantType.new("s")) + self.assertEqual("app.test", value.unpack()) + + +class TestGSettings(unittest.TestCase): + def setUp(self): + self.settings = Gio.Settings('org.gnome.test') + # we change the values in the tests, so set them to predictable start + # value + self.settings.reset('test-string') + self.settings.reset('test-array') + self.settings.reset('test-boolean') + self.settings.reset('test-enum') + + def test_native(self): + self.assertTrue('test-array' in self.settings.list_keys()) + + # get various types + v = self.settings.get_value('test-boolean') + self.assertEqual(v.get_boolean(), True) + self.assertEqual(self.settings.get_boolean('test-boolean'), True) + + v = self.settings.get_value('test-string') + self.assertEqual(v.get_string(), 'Hello') + self.assertEqual(self.settings.get_string('test-string'), 'Hello') + + v = self.settings.get_value('test-array') + self.assertEqual(v.unpack(), [1, 2]) + + v = self.settings.get_value('test-tuple') + self.assertEqual(v.unpack(), (1, 2)) + + # set a value + self.settings.set_string('test-string', 'World') + self.assertEqual(self.settings.get_string('test-string'), 'World') + + self.settings.set_value('test-string', GLib.Variant('s', 'Goodbye')) + self.assertEqual(self.settings.get_string('test-string'), 'Goodbye') + + def test_constructor(self): + # default constructor uses path from schema + self.assertEqual(self.settings.get_property('path'), '/tests/') + + # optional constructor arguments + with_path = Gio.Settings('org.gnome.nopathtest', path='/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.assertTrue('test-array' in self.settings) + self.assertTrue('test-array' in self.settings.keys()) + self.assertFalse('nonexisting' in self.settings) + self.assertFalse(4 in self.settings) + self.assertEqual(bool(self.settings), True) + + def test_get(self): + self.assertEqual(self.settings['test-boolean'], True) + self.assertEqual(self.settings['test-string'], 'Hello') + self.assertEqual(self.settings['test-enum'], 'banana') + self.assertEqual(self.settings['test-array'], [1, 2]) + self.assertEqual(self.settings['test-tuple'], (1, 2)) + + self.assertRaises(KeyError, self.settings.__getitem__, 'unknown') + self.assertRaises(KeyError, self.settings.__getitem__, 2) + + def test_set(self): + self.settings['test-boolean'] = False + self.assertEqual(self.settings['test-boolean'], False) + self.settings['test-string'] = 'Goodbye' + self.assertEqual(self.settings['test-string'], 'Goodbye') + self.settings['test-array'] = [3, 4, 5] + self.assertEqual(self.settings['test-array'], [3, 4, 5]) + self.settings['test-enum'] = 'pear' + self.assertEqual(self.settings['test-enum'], 'pear') + + self.assertRaises(TypeError, self.settings.__setitem__, 'test-string', 1) + self.assertRaises(ValueError, self.settings.__setitem__, 'test-enum', 'plum') + self.assertRaises(KeyError, self.settings.__setitem__, 'unknown', 'moo') + + def test_empty(self): + empty = Gio.Settings('org.gnome.empty', path='/tests/') + self.assertEqual(len(empty), 0) + self.assertEqual(bool(empty), True) + self.assertEqual(empty.keys(), []) + + def test_change_event(self): + changed_log = [] + change_event_log = [] + + def on_changed(settings, key): + changed_log.append((settings, key)) + + def on_change_event(settings, keys, n_keys): + change_event_log.append((settings, keys, n_keys)) + + self.settings.connect('changed', on_changed) + self.settings.connect('change-event', on_change_event) + self.settings['test-string'] = 'Moo' + self.assertEqual(changed_log, [(self.settings, 'test-string')]) + self.assertEqual(change_event_log, [(self.settings, + [GLib.quark_from_static_string('test-string')], + 1)]) + + +class TestGFile(unittest.TestCase): + def setUp(self): + self.file, self.io_stream = Gio.File.new_tmp('TestGFile.XXXXXX') + + def tearDown(self): + try: + self.file.delete(None) + # test_delete and test_delete_async already remove it + except GLib.GError: + pass + + def test_replace_contents(self): + content = b'hello\0world\x7F!' + succ, etag = self.file.replace_contents(content, None, False, + Gio.FileCreateFlags.NONE, None) + new_succ, new_content, new_etag = self.file.load_contents(None) + + self.assertTrue(succ) + self.assertTrue(new_succ) + self.assertEqual(etag, new_etag) + self.assertEqual(content, new_content) + + # https://bugzilla.gnome.org/show_bug.cgi?id=690525 + def disabled_test_replace_contents_async(self): + content = b''.join(bytes(chr(i), 'utf-8') for i in range(128)) + + def callback(f, result, d): + # Quit so in case of failed assertations loop doesn't keep running. + main_loop.quit() + succ, etag = self.file.replace_contents_finish(result) + new_succ, new_content, new_etag = self.file.load_contents(None) + d['succ'], d['etag'] = self.file.replace_contents_finish(result) + load = self.file.load_contents(None) + d['new_succ'], d['new_content'], d['new_etag'] = load + + data = {} + self.file.replace_contents_async(content, None, False, + Gio.FileCreateFlags.NONE, None, + callback, data) + main_loop = GLib.MainLoop() + main_loop.run() + self.assertTrue(data['succ']) + self.assertTrue(data['new_succ']) + self.assertEqual(data['etag'], data['new_etag']) + self.assertEqual(content, data['new_content']) + + def test_tmp_exists(self): + # A simple test to check if Gio.File.new_tmp is working correctly. + self.assertTrue(self.file.query_exists(None)) + + def test_delete(self): + self.file.delete(None) + self.assertFalse(self.file.query_exists(None)) + + def test_delete_async(self): + def callback(f, result, data): + main_loop.quit() + + self.file.delete_async(0, None, callback, None) + main_loop = GLib.MainLoop() + main_loop.run() + self.assertFalse(self.file.query_exists(None)) diff --git a/tests/test_glib.py b/tests/test_glib.py new file mode 100644 index 0000000..3cde168 --- /dev/null +++ b/tests/test_glib.py @@ -0,0 +1,206 @@ +# -*- Mode: Python -*- +# encoding: UTF-8 + +import unittest +import os.path +import warnings +import subprocess + +from gi.repository import GLib +from gi import PyGIDeprecationWarning + +from compathelper import _unicode, _bytes + + +class TestGLib(unittest.TestCase): + def test_find_program_in_path(self): + bash_path = GLib.find_program_in_path('bash') + self.assertTrue(bash_path.endswith('/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&bä') + self.assertEqual(GLib.markup_escape_text(_bytes('a&b\x05')), 'a&b') + + # with explicit length argument + self.assertEqual(GLib.markup_escape_text(_bytes('a\x05\x01\x02'), 2), 'a') + + def test_progname(self): + GLib.set_prgname('moo') + self.assertEqual(GLib.get_prgname(), 'moo') + + def test_appname(self): + GLib.set_application_name('moo') + self.assertEqual(GLib.get_application_name(), 'moo') + + 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)) + + for d in GLib.get_system_config_dirs(): + self.assertTrue('/' in d, d) + for d in GLib.get_system_data_dirs(): + self.assertTrue(isinstance(d, str), d) + + def test_main_depth(self): + self.assertEqual(GLib.main_depth(), 0) + + def test_filenames(self): + self.assertEqual(GLib.filename_display_name('foo'), 'foo') + self.assertEqual(GLib.filename_display_basename('bar/foo'), 'foo') + + # this is locale dependent, so we cannot completely verify the result + res = GLib.filename_from_utf8(_unicode('aäb')) + 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') + + def test_uri_extract(self): + res = GLib.uri_list_extract_uris('''# some comment +http://example.com +https://my.org/q?x=1&y=2 + http://gnome.org/new''') + self.assertEqual(res, ['http://example.com', + 'https://my.org/q?x=1&y=2', + 'http://gnome.org/new']) + + def test_current_time(self): + with warnings.catch_warnings(record=True) as warn: + warnings.simplefilter('always') + tm = GLib.get_current_time() + self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) + + self.assertTrue(isinstance(tm, float)) + self.assertGreater(tm, 1350000000.0) + + def test_main_loop(self): + # note we do not test run() here, as we use this in countless other + # tests + ml = GLib.MainLoop() + self.assertFalse(ml.is_running()) + + context = ml.get_context() + self.assertEqual(context, GLib.MainContext.default()) + self.assertTrue(context.is_owner() in [True, False]) + self.assertTrue(context.pending() in [True, False]) + self.assertFalse(context.iteration(False)) + + def test_main_loop_with_context(self): + context = GLib.MainContext() + ml = GLib.MainLoop(context) + self.assertFalse(ml.is_running()) + self.assertEqual(ml.get_context(), context) + + def test_main_context(self): + # constructor + context = GLib.MainContext() + self.assertTrue(context.is_owner() in [True, False]) + self.assertFalse(context.pending()) + self.assertFalse(context.iteration(False)) + + # GLib API + context = GLib.MainContext.default() + self.assertTrue(context.is_owner() in [True, False]) + self.assertTrue(context.pending() in [True, False]) + self.assertTrue(context.iteration(False) in [True, False]) + + # backwards compatible API + context = GLib.main_context_default() + self.assertTrue(context.is_owner() in [True, False]) + self.assertTrue(context.pending() in [True, False]) + self.assertTrue(context.iteration(False) in [True, False]) + + 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))) + 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) + self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) + + 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) + ml.run() + + self.assertEqual(call_data, [(r, GLib.IOCondition.IN, b'a'), + (r, GLib.IOCondition.IN, b'b')]) + + 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)) + 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') + self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) + + 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) + ml.run() + + self.assertEqual(call_data, [(r, GLib.IOCondition.IN, b'a', 'moo'), + (r, GLib.IOCondition.IN, b'b', 'moo')]) + + 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) + + def cb(file, condition): + call_data.append((file, condition, file.readline())) + if len(call_data) == 2: + # avoid having to wait for the full timeout + ml.quit() + return True + + # io_add_watch() takes an IOChannel, calling with a Python file is deprecated + with warnings.catch_warnings(record=True) as warn: + warnings.simplefilter('always') + GLib.io_add_watch(cmd.stdout, GLib.IOCondition.IN, cb) + self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) + + ml = GLib.MainLoop() + GLib.timeout_add(2000, ml.quit) + ml.run() + + cmd.wait() + + self.assertEqual(call_data, [(cmd.stdout, GLib.IOCondition.IN, b'hello\n'), + (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) + + def test_pyglib_version(self): + (major, minor, micro) = GLib.pyglib_version + self.assertGreaterEqual(major, 3) + self.assertGreaterEqual(minor, 0) + self.assertGreaterEqual(micro, 0) diff --git a/tests/test_gobject.py b/tests/test_gobject.py index eef9cf6..57d3822 100644 --- a/tests/test_gobject.py +++ b/tests/test_gobject.py @@ -1,51 +1,107 @@ # -*- Mode: Python -*- +import sys +import gc import unittest +import warnings + +from gi.repository import GObject, GLib +from gi import PyGIDeprecationWarning +from gi.module import get_introspection_module +from gi._gobject import _gobject -from gi.repository import GObject -import sys import testhelper class TestGObjectAPI(unittest.TestCase): - def testGObjectModule(self): - obj = GObject.GObject() + 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.assertEqual(_gobject.GObject.__gtype__, GObject.TYPE_OBJECT) + self.assertEqual(GIObjectModule.Object.__gtype__, GObject.TYPE_OBJECT) + self.assertEqual(GObject.Object.__gtype__, GObject.TYPE_OBJECT) + + # The pytype wrapper should hold the outer most Object class from overrides. + self.assertEqual(GObject.TYPE_OBJECT.pytype, GObject.Object) + + def test_gobject_unsupported_overrides(self): + obj = GObject.Object() + + with self.assertRaisesRegex(RuntimeError, 'Data access methods are unsupported.*'): + obj.get_data() + + with self.assertRaisesRegex(RuntimeError, 'This method is currently unsupported.*'): + obj.force_floating() + + def test_compat_api(self): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + # GObject formerly exposed a lot of GLib's functions + self.assertEqual(GObject.markup_escape_text('foo'), 'foo') + + ml = GObject.MainLoop() + self.assertFalse(ml.is_running()) - self.assertEquals(obj.__module__, - 'gi._gobject._gobject') + context = GObject.main_context_default() + self.assertTrue(context.pending() in [False, True]) + + context = GObject.MainContext() + self.assertFalse(context.pending()) + + self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning)) + self.assertTrue('GLib.markup_escape_text' in str(w[0]), str(w[0])) + + 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) + + 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): - def testRegularObject(self): + def test_regular_object(self): obj = GObject.GObject() - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) obj = GObject.new(GObject.GObject) - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) - def testFloating(self): + def test_floating(self): obj = testhelper.Floating() - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) obj = GObject.new(testhelper.Floating) - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) - def testOwnedByLibrary(self): + def test_owned_by_library(self): # Upon creation, the refcount of the object should be 2: # - someone already has a reference on the new object. # - the python wrapper should hold its own reference. obj = testhelper.OwnedByLibrary() - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) # We ask the library to release its reference, so the only # remaining ref should be our wrapper's. Once the wrapper # will run out of scope, the object will get finalized. obj.release() - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) - def testOwnedByLibraryOutOfScope(self): + def test_owned_by_library_out_of_scope(self): obj = testhelper.OwnedByLibrary() - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) # We are manually taking the object out of scope. This means # that our wrapper has been freed, and its reference dropped. We @@ -56,27 +112,27 @@ class TestReferenceCounting(unittest.TestCase): # When we get the object back from the lib, the wrapper is # re-created, so our refcount will be 2 once again. obj = testhelper.owned_by_library_get_instance_list()[0] - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) obj.release() - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) - def testOwnedByLibraryUsingGObjectNew(self): + def test_owned_by_library_using_gobject_new(self): # Upon creation, the refcount of the object should be 2: # - someone already has a reference on the new object. # - the python wrapper should hold its own reference. obj = GObject.new(testhelper.OwnedByLibrary) - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) # We ask the library to release its reference, so the only # remaining ref should be our wrapper's. Once the wrapper # will run out of scope, the object will get finalized. obj.release() - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) - def testOwnedByLibraryOutOfScopeUsingGobjectNew(self): + def test_owned_by_library_out_of_scope_using_gobject_new(self): obj = GObject.new(testhelper.OwnedByLibrary) - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) # We are manually taking the object out of scope. This means # that our wrapper has been freed, and its reference dropped. We @@ -87,27 +143,27 @@ class TestReferenceCounting(unittest.TestCase): # When we get the object back from the lib, the wrapper is # re-created, so our refcount will be 2 once again. obj = testhelper.owned_by_library_get_instance_list()[0] - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) obj.release() - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) - def testFloatingAndSunk(self): + def test_floating_and_sunk(self): # Upon creation, the refcount of the object should be 2: # - someone already has a reference on the new object. # - the python wrapper should hold its own reference. obj = testhelper.FloatingAndSunk() - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) # We ask the library to release its reference, so the only # remaining ref should be our wrapper's. Once the wrapper # will run out of scope, the object will get finalized. obj.release() - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) - def testFloatingAndSunkOutOfScope(self): + def test_floating_and_sunk_out_of_scope(self): obj = testhelper.FloatingAndSunk() - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) # We are manually taking the object out of scope. This means # that our wrapper has been freed, and its reference dropped. We @@ -118,28 +174,27 @@ class TestReferenceCounting(unittest.TestCase): # When we get the object back from the lib, the wrapper is # re-created, so our refcount will be 2 once again. obj = testhelper.floating_and_sunk_get_instance_list()[0] - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) obj.release() - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) - - def testFloatingAndSunkUsingGObjectNew(self): + def test_floating_and_sunk_using_gobject_new(self): # Upon creation, the refcount of the object should be 2: # - someone already has a reference on the new object. # - the python wrapper should hold its own reference. obj = GObject.new(testhelper.FloatingAndSunk) - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) # We ask the library to release its reference, so the only # remaining ref should be our wrapper's. Once the wrapper # will run out of scope, the object will get finalized. obj.release() - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) - def testFloatingAndSunkOutOfScopeUsingGObjectNew(self): + def test_floating_and_sunk_out_of_scope_using_gobject_new(self): obj = GObject.new(testhelper.FloatingAndSunk) - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) # We are manually taking the object out of scope. This means # that our wrapper has been freed, and its reference dropped. We @@ -150,31 +205,457 @@ class TestReferenceCounting(unittest.TestCase): # When we get the object back from the lib, the wrapper is # re-created, so our refcount will be 2 once again. obj = testhelper.floating_and_sunk_get_instance_list()[0] - self.assertEquals(obj.__grefcount__, 2) + self.assertEqual(obj.__grefcount__, 2) obj.release() - self.assertEquals(obj.__grefcount__, 1) + self.assertEqual(obj.__grefcount__, 1) + + def test_uninitialized_object(self): + class Obj(GObject.GObject): + def __init__(self): + x = self.__grefcount__ + super(Obj, self).__init__() + assert x >= 0 # quiesce pyflakes + + # Accessing __grefcount__ before the object is initialized is wrong. + # Ensure we get a proper exception instead of a crash. + self.assertRaises(TypeError, Obj) + class A(GObject.GObject): def __init__(self): super(A, self).__init__() + class TestPythonReferenceCounting(unittest.TestCase): # Newly created instances should alwayshave two references: one for # the GC, and one for the bound variable in the local scope. - def testNewInstanceHasTwoRefs(self): + def test_new_instance_has_two_refs(self): obj = GObject.GObject() - self.assertEquals(sys.getrefcount(obj), 2) + self.assertEqual(sys.getrefcount(obj), 2) - def testNewInstanceHasTwoRefsUsingGObjectNew(self): + def test_new_instance_has_two_refs_using_gobject_new(self): obj = GObject.new(GObject.GObject) - self.assertEquals(sys.getrefcount(obj), 2) + self.assertEqual(sys.getrefcount(obj), 2) - def testNewSubclassInstanceHasTwoRefs(self): + def test_new_subclass_instance_has_two_refs(self): obj = A() - self.assertEquals(sys.getrefcount(obj), 2) + self.assertEqual(sys.getrefcount(obj), 2) - def testNewSubclassInstanceHasTwoRefsUsingGObjectNew(self): + def test_new_subclass_instance_has_two_refs_using_gobject_new(self): obj = GObject.new(A) - self.assertEquals(sys.getrefcount(obj), 2) + self.assertEqual(sys.getrefcount(obj), 2) + + +class TestContextManagers(unittest.TestCase): + class ContextTestObject(GObject.GObject): + prop = GObject.Property(default=0, type=int) + + def on_prop_set(self, obj, prop): + # Handler which tracks property changed notifications. + self.tracking.append(obj.get_property(prop.name)) + + def setUp(self): + self.tracking = [] + self.obj = self.ContextTestObject() + self.handler = self.obj.connect('notify::prop', self.on_prop_set) + + def test_freeze_notify_context(self): + # Verify prop tracking list + self.assertEqual(self.tracking, []) + self.obj.props.prop = 1 + self.assertEqual(self.tracking, [1]) + self.obj.props.prop = 2 + self.assertEqual(self.tracking, [1, 2]) + self.assertEqual(self.obj.__grefcount__, 1) + + 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) + self.obj.props.prop = 3 + self.assertEqual(self.obj.props.prop, 3) + self.assertEqual(self.tracking, [1, 2]) + + # After the context manager, the prop should have been modified, + # the tracking list will be modified, and the python object ref + # count goes back down. + gc.collect() + 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) + + def test_handler_block_context(self): + # Verify prop tracking list + self.assertEqual(self.tracking, []) + self.obj.props.prop = 1 + self.assertEqual(self.tracking, [1]) + self.obj.props.prop = 2 + self.assertEqual(self.tracking, [1, 2]) + self.assertEqual(self.obj.__grefcount__, 1) + + 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) + self.obj.props.prop = 3 + self.assertEqual(self.obj.props.prop, 3) + self.assertEqual(self.tracking, [1, 2]) + + # After the context manager, the prop should have been modified + # the tracking list should have stayed the same and the GObject ref + # count goes back down. + gc.collect() + 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) + + def test_freeze_notify_context_nested(self): + self.assertEqual(self.tracking, []) + with self.obj.freeze_notify(): + self.obj.props.prop = 1 + self.assertEqual(self.tracking, []) + + with self.obj.freeze_notify(): + self.obj.props.prop = 2 + self.assertEqual(self.tracking, []) + + with self.obj.freeze_notify(): + self.obj.props.prop = 3 + self.assertEqual(self.tracking, []) + self.assertEqual(self.tracking, []) + self.assertEqual(self.tracking, []) + + # Finally after last context, the notifications should have collapsed + # and the last one sent. + self.assertEqual(self.tracking, [3]) + + def test_handler_block_context_nested(self): + self.assertEqual(self.tracking, []) + with self.obj.handler_block(self.handler): + self.obj.props.prop = 1 + self.assertEqual(self.tracking, []) + + with self.obj.handler_block(self.handler): + self.obj.props.prop = 2 + self.assertEqual(self.tracking, []) + + with self.obj.handler_block(self.handler): + self.obj.props.prop = 3 + self.assertEqual(self.tracking, []) + self.assertEqual(self.tracking, []) + self.assertEqual(self.tracking, []) + + # Finally after last context, the notifications should have collapsed + # and the last one sent. + self.assertEqual(self.obj.props.prop, 3) + self.assertEqual(self.tracking, []) + + def test_freeze_notify_normal_usage_ref_counts(self): + # Ensure ref counts without using methods as context managers + # maintain the same count. + self.assertEqual(self.obj.__grefcount__, 1) + self.obj.freeze_notify() + self.assertEqual(self.obj.__grefcount__, 1) + self.obj.thaw_notify() + self.assertEqual(self.obj.__grefcount__, 1) + + def test_handler_block_normal_usage_ref_counts(self): + self.assertEqual(self.obj.__grefcount__, 1) + self.obj.handler_block(self.handler) + self.assertEqual(self.obj.__grefcount__, 1) + self.obj.handler_unblock(self.handler) + self.assertEqual(self.obj.__grefcount__, 1) + + def test_freeze_notify_context_error(self): + # Test an exception occurring within a freeze context exits the context + try: + with self.obj.freeze_notify(): + self.obj.props.prop = 1 + self.assertEqual(self.tracking, []) + raise ValueError('Simulation') + except ValueError: + pass + + # Verify the property set within the context called notify. + self.assertEqual(self.obj.props.prop, 1) + self.assertEqual(self.tracking, [1]) + + # Verify we are still not in a frozen context. + self.obj.props.prop = 2 + self.assertEqual(self.tracking, [1, 2]) + + def test_handler_block_context_error(self): + # Test an exception occurring within a handler block exits the context + try: + with self.obj.handler_block(self.handler): + self.obj.props.prop = 1 + self.assertEqual(self.tracking, []) + raise ValueError('Simulation') + except ValueError: + pass + + # Verify the property set within the context didn't call notify. + self.assertEqual(self.obj.props.prop, 1) + self.assertEqual(self.tracking, []) + + # Verify we are still not in a handler block context. + self.obj.props.prop = 2 + self.assertEqual(self.tracking, [2]) + + +class TestPropertyBindings(unittest.TestCase): + class TestObject(GObject.GObject): + int_prop = GObject.Property(default=0, type=int) + + def setUp(self): + self.source = self.TestObject() + self.target = self.TestObject() + + def test_default_binding(self): + binding = self.source.bind_property('int_prop', self.target, 'int_prop', + GObject.BindingFlags.DEFAULT) + binding = binding # PyFlakes + + # Test setting value on source gets pushed to target + self.source.int_prop = 1 + self.assertEqual(self.source.int_prop, 1) + self.assertEqual(self.target.int_prop, 1) + + # Test setting value on target does not change source + self.target.props.int_prop = 2 + self.assertEqual(self.source.int_prop, 1) + self.assertEqual(self.target.int_prop, 2) + + def test_bidirectional_binding(self): + binding = self.source.bind_property('int_prop', self.target, 'int_prop', + GObject.BindingFlags.BIDIRECTIONAL) + binding = binding # PyFlakes + + # Test setting value on source gets pushed to target + self.source.int_prop = 1 + self.assertEqual(self.source.int_prop, 1) + self.assertEqual(self.target.int_prop, 1) + + # Test setting value on target also changes source + self.target.props.int_prop = 2 + self.assertEqual(self.source.int_prop, 2) + self.assertEqual(self.target.int_prop, 2) + + def test_transform_to_only(self): + def transform_to(binding, value, user_data=None): + self.assertEqual(user_data, 'test-data') + return value * 2 + + binding = self.source.bind_property('int_prop', self.target, 'int_prop', + GObject.BindingFlags.DEFAULT, + transform_to, None, 'test-data') + binding = binding # PyFlakes + + self.source.int_prop = 1 + self.assertEqual(self.source.int_prop, 1) + self.assertEqual(self.target.int_prop, 2) + + self.target.props.int_prop = 1 + self.assertEqual(self.source.int_prop, 1) + self.assertEqual(self.target.int_prop, 1) + + def test_transform_from_only(self): + def transform_from(binding, value, user_data=None): + self.assertEqual(user_data, None) + return value * 2 + + binding = self.source.bind_property('int_prop', self.target, 'int_prop', + GObject.BindingFlags.BIDIRECTIONAL, + None, transform_from) + binding = binding # PyFlakes + + self.source.int_prop = 1 + self.assertEqual(self.source.int_prop, 1) + self.assertEqual(self.target.int_prop, 1) + + self.target.props.int_prop = 1 + self.assertEqual(self.source.int_prop, 2) + self.assertEqual(self.target.int_prop, 1) + + def test_transform_bidirectional(self): + test_data = object() + + def transform_to(binding, value, user_data=None): + self.assertEqual(user_data, test_data) + return value * 2 + + def transform_from(binding, value, user_data=None): + 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) + + # 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__ + + self.source.int_prop = 1 + self.assertEqual(self.source.int_prop, 1) + self.assertEqual(self.target.int_prop, 2) + + self.target.props.int_prop = 4 + 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) + + # 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) + + # 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 + self.source.int_prop = 5 + 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) + + def test_explicit_unbind_clears_connection(self): + self.assertEqual(self.source.int_prop, 0) + self.assertEqual(self.target.int_prop, 0) + + # Test deleting binding reference removes binding. + binding = self.source.bind_property('int_prop', self.target, 'int_prop') + self.source.int_prop = 1 + self.assertEqual(self.source.int_prop, 1) + self.assertEqual(self.target.int_prop, 1) + + binding.unbind() + self.assertEqual(binding(), None) + + 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) + + def test_reference_counts(self): + self.assertEqual(self.source.__grefcount__, 1) + self.assertEqual(self.target.__grefcount__, 1) + + # Binding ref count will be 2 do to the initial ref implicitly held by + # 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) + + # Creating a binding does not inc refs on source and target (they are weak + # on the binding object itself) + self.assertEqual(self.source.__grefcount__, 1) + self.assertEqual(self.target.__grefcount__, 1) + + # 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. + ref = self.source.weak_ref() + del self.source + gc.collect() + self.assertEqual(ref(), None) + self.assertEqual(binding(), None) + + +class TestGValue(unittest.TestCase): + def test_type_constant(self): + self.assertEqual(GObject.TYPE_VALUE, GObject.Value.__gtype__) + self.assertEqual(GObject.type_name(GObject.TYPE_VALUE), 'GValue') + + def test_no_type(self): + value = GObject.Value() + self.assertEqual(value.g_type, GObject.TYPE_INVALID) + self.assertRaises(TypeError, value.set_value, 23) + self.assertEqual(value.get_value(), None) + + def test_int(self): + value = GObject.Value(GObject.TYPE_UINT) + self.assertEqual(value.g_type, GObject.TYPE_UINT) + value.set_value(23) + self.assertEqual(value.get_value(), 23) + value.set_value(42.0) + self.assertEqual(value.get_value(), 42) + + def test_string(self): + value = GObject.Value(str, 'foo_bar') + self.assertEqual(value.g_type, GObject.TYPE_STRING) + self.assertEqual(value.get_value(), 'foo_bar') + + def test_float(self): + # python float is G_TYPE_DOUBLE + value = GObject.Value(float, 23.4) + self.assertEqual(value.g_type, GObject.TYPE_DOUBLE) + value.set_value(1e50) + self.assertAlmostEqual(value.get_value(), 1e50) + + value = GObject.Value(GObject.TYPE_FLOAT, 23.4) + self.assertEqual(value.g_type, GObject.TYPE_FLOAT) + self.assertRaises(TypeError, value.set_value, 'string') + self.assertRaises(OverflowError, value.set_value, 1e50) + + def test_float_inf_nan(self): + nan = float('nan') + for type_ in [GObject.TYPE_FLOAT, GObject.TYPE_DOUBLE]: + for x in [float('inf'), float('-inf'), nan]: + value = GObject.Value(type_, x) + # assertEqual() is False for (nan, nan) + if x is nan: + self.assertEqual(str(value.get_value()), 'nan') + else: + self.assertEqual(value.get_value(), x) + + def test_enum(self): + value = GObject.Value(GLib.FileError, GLib.FileError.FAILED) + self.assertEqual(value.get_value(), GLib.FileError.FAILED) + + def test_flags(self): + value = GObject.Value(GLib.IOFlags, GLib.IOFlags.IS_READABLE) + self.assertEqual(value.get_value(), GLib.IOFlags.IS_READABLE) + + def test_object(self): + class TestObject(GObject.Object): + pass + obj = TestObject() + value = GObject.Value(GObject.TYPE_OBJECT, obj) + self.assertEqual(value.get_value(), obj) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_gtype.py b/tests/test_gtype.py new file mode 100644 index 0000000..8099101 --- /dev/null +++ b/tests/test_gtype.py @@ -0,0 +1,51 @@ +import unittest + +from gi.repository import GObject +from gi.repository import GIMarshallingTests + + +class CustomBase(GObject.GObject): + pass + + +class CustomChild(CustomBase, GIMarshallingTests.Interface): + pass + + +class TestTypeModuleLevelFunctions(unittest.TestCase): + def test_type_name(self): + self.assertEqual(GObject.type_name(GObject.TYPE_NONE), 'void') + self.assertEqual(GObject.type_name(GObject.TYPE_OBJECT), 'GObject') + self.assertEqual(GObject.type_name(GObject.TYPE_PYOBJECT), 'PyObject') + + def test_type_from_name(self): + # A complete test is not needed here since the TYPE_* defines are created + # using this method. + self.assertRaises(RuntimeError, GObject.type_from_name, '!NOT_A_REAL_TYPE!') + self.assertEqual(GObject.type_from_name('GObject'), GObject.TYPE_OBJECT) + self.assertEqual(GObject.type_from_name('GObject'), GObject.GObject.__gtype__) + + def test_type_is_a(self): + self.assertTrue(GObject.type_is_a(CustomBase, GObject.TYPE_OBJECT)) + self.assertTrue(GObject.type_is_a(CustomChild, CustomBase)) + self.assertTrue(GObject.type_is_a(CustomBase, GObject.GObject)) + self.assertTrue(GObject.type_is_a(CustomBase.__gtype__, GObject.TYPE_OBJECT)) + self.assertFalse(GObject.type_is_a(GObject.TYPE_OBJECT, CustomBase)) + self.assertFalse(GObject.type_is_a(CustomBase, int)) # invalid type + self.assertRaises(TypeError, GObject.type_is_a, CustomBase, 1) + self.assertRaises(TypeError, GObject.type_is_a, 2, GObject.TYPE_OBJECT) + self.assertRaises(TypeError, GObject.type_is_a, 1, 2) + + def test_type_children(self): + self.assertEqual(GObject.type_children(CustomBase), [CustomChild.__gtype__]) + self.assertEqual(len(GObject.type_children(CustomChild)), 0) + + def test_type_interfaces(self): + self.assertEqual(len(GObject.type_interfaces(CustomBase)), 0) + self.assertEqual(len(GObject.type_interfaces(CustomChild)), 1) + self.assertEqual(GObject.type_interfaces(CustomChild), [GIMarshallingTests.Interface.__gtype__]) + + def test_type_parent(self): + 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) diff --git a/tests/test_interface.py b/tests/test_interface.py index f60a25c..dd01af8 100644 --- a/tests/test_interface.py +++ b/tests/test_interface.py @@ -37,13 +37,12 @@ GObject.type_register(MyObject) class TestIfaceImpl(unittest.TestCase): - def testReImplementInterface(self): + def test_reimplement_interface(self): m = MyUnknown() m.iface_method() self.assertEqual(m.called, True) - def testImplementInterface(self): + def test_implement_interface(self): m = MyObject() m.iface_method() self.assertEqual(m.called, True) - diff --git a/tests/test_internal_api.py b/tests/test_internal_api.py new file mode 100644 index 0000000..ca50f6b --- /dev/null +++ b/tests/test_internal_api.py @@ -0,0 +1,73 @@ +# -*- Mode: Python -*- + +import unittest + +from gi.repository import GLib, GObject + +import testhelper +import testmodule + + +class TestObject(unittest.TestCase): + def test_create_ctor(self): + o = testmodule.PyGObject() + self.assertTrue(isinstance(o, GObject.Object)) + self.assertTrue(isinstance(o, testmodule.PyGObject)) + + # has expected property + self.assertEqual(o.props.label, 'hello') + o.props.label = 'goodbye' + self.assertEqual(o.props.label, 'goodbye') + self.assertRaises(AttributeError, getattr, o.props, 'nosuchprop') + + def test_pyobject_new_test_type(self): + o = testhelper.create_test_type() + self.assertTrue(isinstance(o, testmodule.PyGObject)) + + # has expected property + self.assertEqual(o.props.label, 'hello') + o.props.label = 'goodbye' + self.assertEqual(o.props.label, 'goodbye') + self.assertRaises(AttributeError, getattr, o.props, 'nosuchprop') + + def test_new_refcount(self): + # TODO: justify why this should be 2 + self.assertEqual(testhelper.test_g_object_new(), 2) + + +class TestGValueConversion(unittest.TestCase): + def test_int(self): + 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) + + def test_str(self): + self.assertEqual(testhelper.test_value('hello'), 'hello') + + def test_int_array(self): + self.assertEqual(testhelper.test_value_array([]), []) + self.assertEqual(testhelper.test_value_array([0]), [0]) + ar = list(range(100)) + self.assertEqual(testhelper.test_value_array(ar), ar) + + def test_str_array(self): + self.assertEqual(testhelper.test_value_array([]), []) + self.assertEqual(testhelper.test_value_array(['a']), ['a']) + ar = ('aa ' * 1000).split() + self.assertEqual(testhelper.test_value_array(ar), ar) + + +class TestErrors(unittest.TestCase): + def test_gerror(self): + callable_ = lambda: GLib.file_get_contents('/nonexisting ') + self.assertRaises(GLib.GError, testhelper.test_gerror_exception, callable_) + + def test_no_gerror(self): + callable_ = lambda: GLib.file_get_contents(__file__) + self.assertEqual(testhelper.test_gerror_exception(callable_), None) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_iochannel.py b/tests/test_iochannel.py new file mode 100644 index 0000000..0cc1b4b --- /dev/null +++ b/tests/test_iochannel.py @@ -0,0 +1,424 @@ +# -*- Mode: Python -*- +# encoding: UTF-8 +from __future__ import unicode_literals + +import unittest +import tempfile +import os.path +import fcntl +import shutil +import warnings + +from gi.repository import GLib +from gi import PyGIDeprecationWarning + +from compathelper import _unicode + + +class IOChannel(unittest.TestCase): + def setUp(self): + self.workdir = tempfile.mkdtemp() + + self.testutf8 = os.path.join(self.workdir, 'testutf8.txt') + with open(self.testutf8, 'wb') as f: + f.write('''hello ♥ world +second line + +À demain!'''.encode('UTF-8')) + + self.testlatin1 = os.path.join(self.workdir, 'testlatin1.txt') + with open(self.testlatin1, 'wb') as f: + f.write(b'''hell\xf8 world +second line + +\xc0 demain!''') + + self.testout = os.path.join(self.workdir, 'testout.txt') + + def tearDown(self): + shutil.rmtree(self.workdir) + + def test_file_readline_utf8(self): + 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.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.get_buffer_condition(), 0) + self.assertEqual(ch.readline(), '') + ch.close() + + 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(), 'second line\n') + self.assertEqual(ch.readline(), '\n') + self.assertEqual(_unicode(ch.readline()), 'À demain!') + ch.close() + + def test_file_iter(self): + items = [] + ch = GLib.IOChannel(filename=self.testutf8) + for item in ch: + items.append(item) + self.assertEqual(len(items), 4) + self.assertEqual(_unicode(items[0]), 'hello ♥ world\n') + ch.close() + + def test_file_readlines(self): + ch = GLib.IOChannel(filename=self.testutf8) + lines = ch.readlines() + # Note, this really ought to be 4, but the static bindings add an extra + # 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!') + if len(lines) == 4: + self.assertEqual(lines[4], '') + + def test_file_read(self): + ch = GLib.IOChannel(filename=self.testutf8) + with open(self.testutf8, 'rb') as f: + self.assertEqual(ch.read(), f.read()) + + ch = GLib.IOChannel(filename=self.testutf8) + with open(self.testutf8, 'rb') as f: + self.assertEqual(ch.read(10), f.read(10)) + + ch = GLib.IOChannel(filename=self.testutf8) + with open(self.testutf8, 'rb') as f: + self.assertEqual(ch.read(max_count=15), f.read(15)) + + def test_seek(self): + ch = GLib.IOChannel(filename=self.testutf8) + ch.seek(2) + self.assertEqual(ch.read(3), b'llo') + + ch.seek(2, 0) # SEEK_SET + self.assertEqual(ch.read(3), b'llo') + + ch.seek(1, 1) # SEEK_CUR, skip the space + self.assertEqual(ch.read(3), b'\xe2\x99\xa5') + + ch.seek(2, 2) # SEEK_END + # FIXME: does not work currently + #self.assertEqual(ch.read(2), b'n!') + + # invalid whence value + self.assertRaises(ValueError, ch.seek, 0, 3) + + 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 = GLib.IOChannel(filename=self.testout, mode='a') + ch.set_encoding('latin1') + ch.write('À demain!') + ch.close() + + with open(self.testout, 'rb') as f: + self.assertEqual(f.read().decode('latin1'), '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() + + with open(self.testout, 'r') as f: + self.assertEqual(f.read(), 'foobar\nbaz\nend') + + def test_buffering(self): + writer = GLib.IOChannel(filename=self.testout, mode='w') + writer.set_encoding(None) + self.assertTrue(writer.get_buffered()) + self.assertGreater(writer.get_buffer_size(), 10) + + reader = GLib.IOChannel(filename=self.testout, mode='r') + + # does not get written immediately on buffering + writer.write('abc') + self.assertEqual(reader.read(), b'') + writer.flush() + self.assertEqual(reader.read(), b'abc') + + # does get written immediately without buffering + writer.set_buffered(False) + writer.write('def') + self.assertEqual(reader.read(), b'def') + + # writes after buffer overflow + writer.set_buffer_size(10) + writer.write('0123456789012') + self.assertTrue(reader.read().startswith(b'012')) + writer.flush() + reader.read() # ignore bits written after flushing + + # closing flushes + writer.set_buffered(True) + writer.write('ghi') + writer.close() + self.assertEqual(reader.read(), b'ghi') + reader.close() + + def test_fd_read(self): + (r, w) = os.pipe() + + ch = GLib.IOChannel(filedes=r) + ch.set_encoding(None) + ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) + self.assertNotEqual(ch.get_flags() | GLib.IOFlags.NONBLOCK, 0) + self.assertEqual(ch.read(), b'') + os.write(w, b'\x01\x02') + self.assertEqual(ch.read(), b'\x01\x02') + + # now test blocking case, after closing the write end + ch.set_flags(GLib.IOFlags(ch.get_flags() & ~GLib.IOFlags.NONBLOCK)) + os.write(w, b'\x03\x04') + os.close(w) + self.assertEqual(ch.read(), b'\x03\x04') + + ch.close() + + def test_fd_write(self): + (r, w) = os.pipe() + fcntl.fcntl(r, fcntl.F_SETFL, fcntl.fcntl(r, fcntl.F_GETFL) | os.O_NONBLOCK) + + ch = GLib.IOChannel(filedes=w, mode='w') + ch.set_encoding(None) + ch.set_buffered(False) + ch.write(b'\x01\x02') + self.assertEqual(os.read(r, 10), b'\x01\x02') + + # 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() + self.assertEqual(os.read(r, 10), b'\x03\x04') + os.close(r) + + def test_deprecated_method_add_watch_no_data(self): + (r, w) = os.pipe() + + ch = GLib.IOChannel(filedes=r) + ch.set_encoding(None) + ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) + + cb_reads = [] + + def cb(channel, condition): + self.assertEqual(channel, ch) + self.assertEqual(condition, GLib.IOCondition.IN) + cb_reads.append(channel.read()) + 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) + self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) + + 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) + ml.run() + + self.assertEqual(cb_reads, [b'a', b'b']) + + def test_deprecated_method_add_watch_data_priority(self): + (r, w) = os.pipe() + + ch = GLib.IOChannel(filedes=r) + ch.set_encoding(None) + ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) + + cb_reads = [] + + def cb(channel, condition, data): + self.assertEqual(channel, ch) + self.assertEqual(condition, GLib.IOCondition.IN) + self.assertEqual(data, 'hello') + cb_reads.append(channel.read()) + return True + + ml = GLib.MainLoop() + # io_add_watch() method is deprecated, use GLib.io_add_watch + with warnings.catch_warnings(record=True) as warn: + warnings.simplefilter('always') + id = ch.add_watch(GLib.IOCondition.IN, cb, 'hello', priority=GLib.PRIORITY_HIGH) + self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) + + 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) + ml.run() + + self.assertEqual(cb_reads, [b'a', b'b']) + + def test_add_watch_no_data(self): + (r, w) = os.pipe() + + ch = GLib.IOChannel(filedes=r) + ch.set_encoding(None) + ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) + + cb_reads = [] + + def cb(channel, condition): + self.assertEqual(channel, ch) + self.assertEqual(condition, GLib.IOCondition.IN) + cb_reads.append(channel.read()) + return True + + id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb) + + 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) + ml.run() + + self.assertEqual(cb_reads, [b'a', b'b']) + + def test_add_watch_with_data(self): + (r, w) = os.pipe() + + ch = GLib.IOChannel(filedes=r) + ch.set_encoding(None) + ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) + + cb_reads = [] + + def cb(channel, condition, data): + self.assertEqual(channel, ch) + self.assertEqual(condition, GLib.IOCondition.IN) + self.assertEqual(data, 'hello') + cb_reads.append(channel.read()) + return True + + id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb, 'hello') + + 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) + ml.run() + + self.assertEqual(cb_reads, [b'a', b'b']) + + def test_add_watch_with_multi_data(self): + (r, w) = os.pipe() + + ch = GLib.IOChannel(filedes=r) + ch.set_encoding(None) + ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) + + cb_reads = [] + + def cb(channel, condition, data1, data2, data3): + self.assertEqual(channel, ch) + self.assertEqual(condition, GLib.IOCondition.IN) + self.assertEqual(data1, 'a') + self.assertEqual(data2, 'b') + self.assertEqual(data3, 'c') + cb_reads.append(channel.read()) + return True + + id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb, + 'a', 'b', 'c') + + 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) + ml.run() + + self.assertEqual(cb_reads, [b'a', b'b']) + + def test_deprecated_add_watch_no_data(self): + (r, w) = os.pipe() + + ch = GLib.IOChannel(filedes=r) + ch.set_encoding(None) + ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) + + cb_reads = [] + + def cb(channel, condition): + self.assertEqual(channel, ch) + self.assertEqual(condition, GLib.IOCondition.IN) + cb_reads.append(channel.read()) + return True + + with warnings.catch_warnings(record=True) as warn: + warnings.simplefilter('always') + id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb, priority=GLib.PRIORITY_HIGH) + self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) + + 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) + ml.run() + + self.assertEqual(cb_reads, [b'a', b'b']) + + def test_deprecated_add_watch_with_data(self): + (r, w) = os.pipe() + + ch = GLib.IOChannel(filedes=r) + ch.set_encoding(None) + ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) + + cb_reads = [] + + def cb(channel, condition, data): + self.assertEqual(channel, ch) + self.assertEqual(condition, GLib.IOCondition.IN) + self.assertEqual(data, 'hello') + cb_reads.append(channel.read()) + return True + + with warnings.catch_warnings(record=True) as warn: + warnings.simplefilter('always') + id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb, 'hello', + priority=GLib.PRIORITY_HIGH) + self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) + + 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) + 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) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_mainloop.py b/tests/test_mainloop.py index 937ecaf..44197b3 100644 --- a/tests/test_mainloop.py +++ b/tests/test_mainloop.py @@ -3,14 +3,23 @@ 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 + class TestMainLoop(unittest.TestCase): - def testExceptionHandling(self): + def test_exception_handling(self): pipe_r, pipe_w = os.pipe() pid = os.fork() @@ -25,27 +34,64 @@ class TestMainLoop(unittest.TestCase): raise Exception("deadbabe") loop = GLib.MainLoop() - GLib.child_watch_add(pid, child_died, loop) + GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, child_died, loop) os.close(pipe_r) os.write(pipe_w, _bytes("Y")) os.close(pipe_w) def excepthook(type, value, traceback): - assert type is Exception - assert value.args[0] == "deadbabe" + self.assertTrue(type is Exception) + self.assertEqual(value.args[0], "deadbabe") sys.excepthook = excepthook - - got_exception = False try: - loop.run() - except: - got_exception = True + 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 # - sys.excepthook = sys.__excepthook__ - assert not got_exception + self.assertFalse(got_exception) + + def test_concurrency(self): + def on_usr1(signum, frame): + pass + + 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) + + def test_sigint(self): + pid = os.fork() + if pid == 0: + time.sleep(0.5) + os.kill(os.getppid(), signal.SIGINT) + os._exit(0) + + loop = GLib.MainLoop() + try: + loop.run() + self.fail('expected KeyboardInterrupt exception') + except KeyboardInterrupt: + pass + self.assertFalse(loop.is_running()) + os.waitpid(pid, 0) diff --git a/tests/test_object_marshaling.py b/tests/test_object_marshaling.py new file mode 100644 index 0000000..624ed9d --- /dev/null +++ b/tests/test_object_marshaling.py @@ -0,0 +1,603 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab + +import unittest +import weakref +import gc +import sys +import warnings + +from gi.repository import GObject +from gi.repository import GIMarshallingTests + + +class StrongRef(object): + # A class that behaves like weakref.ref but holds a strong reference. + # This allows re-use of the VFuncsBase by swapping out the ObjectRef + # class var with either weakref.ref or StrongRef. + + def __init__(self, obj): + self.obj = obj + + def __call__(self): + return self.obj + + +class VFuncsBase(GIMarshallingTests.Object): + # Class which generically implements the vfuncs used for reference counting tests + # in a way that can be easily sub-classed and modified. + + #: Object type used by this class for testing + #: This can be GObject.Object or GObject.InitiallyUnowned + Object = GObject.Object + + #: Reference type used by this class for holding refs to in/out objects. + #: This can be set to weakref.ref or StrongRef + ObjectRef = weakref.ref + + def __init__(self): + super(VFuncsBase, self).__init__() + + #: Hold ref of input or output python wrappers + self.object_ref = None + + #: store grefcount of input object + self.in_object_grefcount = None + self.in_object_is_floating = None + + def do_vfunc_return_object_transfer_none(self): + # Return an object but keep a python reference to it. + obj = self.Object() + self.object_ref = self.ObjectRef(obj) + return obj + + def do_vfunc_return_object_transfer_full(self): + # Return an object and hand off the reference to the caller. + obj = self.Object() + self.object_ref = self.ObjectRef(obj) + return obj + + def do_vfunc_out_object_transfer_none(self): + # Same as do_vfunc_return_object_transfer_none but the pygi + # internals convert the return here into an out arg. + obj = self.Object() + self.object_ref = self.ObjectRef(obj) + return obj + + def do_vfunc_out_object_transfer_full(self): + # Same as do_vfunc_return_object_transfer_full but the pygi + # internals convert the return here into an out arg. + obj = self.Object() + self.object_ref = self.ObjectRef(obj) + return obj + + def do_vfunc_in_object_transfer_none(self, obj): + # 'obj' will have a python wrapper as well as still held + # by the caller. + self.object_ref = self.ObjectRef(obj) + self.in_object_grefcount = obj.__grefcount__ + self.in_object_is_floating = obj.is_floating() + + def do_vfunc_in_object_transfer_full(self, obj): + # 'obj' will now be owned by the Python GObject wrapper. + # When obj goes out of scope and is collected, the GObject + # should also be fully released. + self.object_ref = self.ObjectRef(obj) + self.in_object_grefcount = obj.__grefcount__ + self.in_object_is_floating = obj.is_floating() + + +class TestVFuncsWithObjectArg(unittest.TestCase): + # Basic set of tests which work on non-floating objects which python does + # not keep an additional reference of. + + class VFuncs(VFuncsBase): + # Object for testing non-floating objects without holding any refs. + Object = GObject.Object + ObjectRef = weakref.ref + + def test_vfunc_self_arg_ref_count(self): + # Check to make sure vfunc "self" arguments don't leak. + vfuncs = self.VFuncs() + vfuncs_ref = weakref.ref(vfuncs) + vfuncs.get_ref_info_for_vfunc_return_object_transfer_full() # Use any vfunc to test this. + + gc.collect() + self.assertEqual(sys.getrefcount(vfuncs), 2) + self.assertEqual(vfuncs.__grefcount__, 1) + + del vfuncs + gc.collect() + self.assertTrue(vfuncs_ref() is None) + + def test_vfunc_return_object_transfer_none(self): + # This tests a problem case where the vfunc returns a GObject owned solely by Python + # but the argument is marked as transfer-none. + # In this case pygobject marshaling adds an additional ref and gives a warning + # of a potential leak. If this occures it is really a bug in the underlying library + # but pygobject tries to react to this in a reasonable way. + vfuncs = self.VFuncs() + 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)) + + # 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) + self.assertFalse(is_floating) + + gc.collect() + self.assertTrue(vfuncs.object_ref() is None) + + def test_vfunc_out_object_transfer_none(self): + # Same as above except uses out arg instead of return + vfuncs = self.VFuncs() + 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)) + + self.assertEqual(ref_count, 1) + self.assertFalse(is_floating) + + gc.collect() + self.assertTrue(vfuncs.object_ref() is None) + + def test_vfunc_return_object_transfer_full(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_full() + + # The vfunc caller receives full ownership of a single ref which should not + # be floating. + self.assertEqual(ref_count, 1) + self.assertFalse(is_floating) + + gc.collect() + self.assertTrue(vfuncs.object_ref() is None) + + def test_vfunc_out_object_transfer_full(self): + # Same as above except uses out arg instead of return + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full() + + self.assertEqual(ref_count, 1) + self.assertFalse(is_floating) + + gc.collect() + self.assertTrue(vfuncs.object_ref() is None) + + def test_vfunc_in_object_transfer_none(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_none(self.VFuncs.Object) + + gc.collect() + 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 + self.assertFalse(is_floating) + + self.assertTrue(vfuncs.object_ref() is None) + + def test_vfunc_in_object_transfer_full(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_full(self.VFuncs.Object) + + gc.collect() + + # python wrapper should take sole ownership of the gobject + self.assertEqual(vfuncs.in_object_grefcount, 1) + self.assertFalse(vfuncs.in_object_is_floating) + + # ensure python wrapper took ownership and released, after vfunc was complete + self.assertEqual(ref_count, 0) + self.assertFalse(is_floating) + + self.assertTrue(vfuncs.object_ref() is None) + + +class TestVFuncsWithFloatingArg(unittest.TestCase): + # All tests here work with a floating object by using InitiallyUnowned as the argument + + class VFuncs(VFuncsBase): + # Object for testing non-floating objects without holding any refs. + Object = GObject.InitiallyUnowned + ObjectRef = weakref.ref + + def test_vfunc_return_object_transfer_none_with_floating(self): + # Python is expected to return a single floating reference without warning. + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_none() + + # 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) + self.assertTrue(is_floating) + + gc.collect() + self.assertTrue(vfuncs.object_ref() is None) + + def test_vfunc_out_object_transfer_none_with_floating(self): + # Same as above except uses out arg instead of return + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none() + + self.assertEqual(ref_count, 1) + self.assertTrue(is_floating) + + gc.collect() + self.assertTrue(vfuncs.object_ref() is None) + + def test_vfunc_return_object_transfer_full_with_floating(self): + vfuncs = self.VFuncs() + 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) + self.assertFalse(is_floating) + + gc.collect() + self.assertTrue(vfuncs.object_ref() is None) + + def test_vfunc_out_object_transfer_full_with_floating(self): + # Same as above except uses out arg instead of return + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full() + + self.assertEqual(ref_count, 1) + self.assertFalse(is_floating) + + gc.collect() + self.assertTrue(vfuncs.object_ref() is None) + + def test_vfunc_in_object_transfer_none_with_floating(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_none(self.VFuncs.Object) + + gc.collect() + + # python wrapper should maintain the object as floating and add an additional ref + self.assertEqual(vfuncs.in_object_grefcount, 2) + 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) + self.assertTrue(is_floating) + + self.assertTrue(vfuncs.object_ref() is None) + + def test_vfunc_in_object_transfer_full_with_floating(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_full(self.VFuncs.Object) + + gc.collect() + + # python wrapper sinks and owns the gobject + self.assertEqual(vfuncs.in_object_grefcount, 1) + self.assertFalse(vfuncs.in_object_is_floating) + + # ensure python wrapper took ownership and released + self.assertEqual(ref_count, 0) + self.assertFalse(is_floating) + + self.assertTrue(vfuncs.object_ref() is None) + + +class TestVFuncsWithHeldObjectArg(unittest.TestCase): + # Same tests as TestVFuncsWithObjectArg except we hold + # onto the python object reference in all cases. + + class VFuncs(VFuncsBase): + # Object for testing non-floating objects with a held ref. + Object = GObject.Object + ObjectRef = StrongRef + + def test_vfunc_return_object_transfer_none_with_held_object(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_none() + + # Python holds the single gobject ref in 'vfuncs.object_ref' + # Because of this, we do not expect a floating ref or a ref increase. + self.assertEqual(ref_count, 1) + self.assertFalse(is_floating) + + # The actual grefcount should stay at 1 even after the vfunc return. + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + self.assertFalse(vfuncs.in_object_is_floating) + + held_object_ref = weakref.ref(vfuncs.object_ref) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + def test_vfunc_out_object_transfer_none_with_held_object(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none() + + self.assertEqual(ref_count, 1) + self.assertFalse(is_floating) + + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + self.assertFalse(vfuncs.in_object_is_floating) + + held_object_ref = weakref.ref(vfuncs.object_ref) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + def test_vfunc_return_object_transfer_full_with_held_object(self): + # The vfunc caller receives full ownership which should not + # be floating. However, the held python wrapper also has a ref. + + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_full() + + # Ref count from the perspective of C after the vfunc is called + # The vfunc caller receives a new reference which should not + # be floating. However, the held python wrapper also has a ref. + self.assertEqual(ref_count, 2) + self.assertFalse(is_floating) + + # Current ref count + # The vfunc caller should have decremented its reference. + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + + held_object_ref = weakref.ref(vfuncs.object_ref) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + def test_vfunc_out_object_transfer_full_with_held_object(self): + # Same test as above except uses out arg instead of return + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full() + + # Ref count from the perspective of C after the vfunc is called + # The vfunc caller receives a new reference which should not + # be floating. However, the held python wrapper also has a ref. + self.assertEqual(ref_count, 2) + self.assertFalse(is_floating) + + # Current ref count + # The vfunc caller should have decremented its reference. + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + + held_object_ref = weakref.ref(vfuncs.object_ref()) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + def test_vfunc_in_object_transfer_none_with_held_object(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_none(self.VFuncs.Object) + + gc.collect() + + # Ref count inside vfunc from the perspective of Python + self.assertEqual(vfuncs.in_object_grefcount, 2) # initial + python wrapper + self.assertFalse(vfuncs.in_object_is_floating) + + # Ref count from the perspective of C after the vfunc is called + self.assertEqual(ref_count, 2) # kept after vfunc + held python wrapper + self.assertFalse(is_floating) + + # Current ref count after C cleans up its reference + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + + held_object_ref = weakref.ref(vfuncs.object_ref()) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + def test_vfunc_in_object_transfer_full_with_held_object(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_full(self.VFuncs.Object) + + gc.collect() + + # Ref count inside vfunc from the perspective of Python + self.assertEqual(vfuncs.in_object_grefcount, 1) # python wrapper takes ownership of the gobject + self.assertFalse(vfuncs.in_object_is_floating) + + # Ref count from the perspective of C after the vfunc is called + self.assertEqual(ref_count, 1) + self.assertFalse(is_floating) + + # Current ref count + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + + held_object_ref = weakref.ref(vfuncs.object_ref()) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + +class TestVFuncsWithHeldFloatingArg(unittest.TestCase): + # Tests for a floating object which we hold a reference to the python wrapper + # on the VFuncs test class. + + class VFuncs(VFuncsBase): + # Object for testing floating objects with a held ref. + Object = GObject.InitiallyUnowned + ObjectRef = StrongRef + + def test_vfunc_return_object_transfer_none_with_held_floating(self): + # Python holds onto the wrapper which basically means the floating ref + # should also be owned by python. + + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_none() + + # This is a borrowed ref from what is held in python. + self.assertEqual(ref_count, 1) + self.assertFalse(is_floating) + + # The actual grefcount should stay at 1 even after the vfunc return. + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + + held_object_ref = weakref.ref(vfuncs.object_ref) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + def test_vfunc_out_object_transfer_none_with_held_floating(self): + # Same as above + + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none() + + self.assertEqual(ref_count, 1) + self.assertFalse(is_floating) + + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + + held_object_ref = weakref.ref(vfuncs.object_ref) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + def test_vfunc_return_object_transfer_full_with_held_floating(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_full() + + # Ref count from the perspective of C after the vfunc is called + self.assertEqual(ref_count, 2) + self.assertFalse(is_floating) + + # Current ref count + # vfunc wrapper destroyes ref it was given + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + + held_object_ref = weakref.ref(vfuncs.object_ref) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + def test_vfunc_out_object_transfer_full_with_held_floating(self): + # Same test as above except uses out arg instead of return + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full() + + # Ref count from the perspective of C after the vfunc is called + self.assertEqual(ref_count, 2) + self.assertFalse(is_floating) + + # Current ref count + # vfunc wrapper destroyes ref it was given + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + + held_object_ref = weakref.ref(vfuncs.object_ref()) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + def test_vfunc_in_floating_transfer_none_with_held_floating(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_none(self.VFuncs.Object) + gc.collect() + + # Ref count inside vfunc from the perspective of Python + self.assertTrue(vfuncs.in_object_is_floating) + self.assertEqual(vfuncs.in_object_grefcount, 2) # python wrapper sinks and owns the gobject + + # Ref count from the perspective of C after the vfunc is called + self.assertTrue(is_floating) + self.assertEqual(ref_count, 2) # floating + held by wrapper + + # Current ref count after C cleans up its reference + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + + held_object_ref = weakref.ref(vfuncs.object_ref()) + del vfuncs.object_ref + gc.collect() + self.assertTrue(held_object_ref() is None) + + def test_vfunc_in_floating_transfer_full_with_held_floating(self): + vfuncs = self.VFuncs() + ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_full(self.VFuncs.Object) + gc.collect() + + # Ref count from the perspective of C after the vfunc is called + self.assertEqual(vfuncs.in_object_grefcount, 1) # python wrapper sinks and owns the gobject + self.assertFalse(vfuncs.in_object_is_floating) + + # Ref count from the perspective of C after the vfunc is called + self.assertEqual(ref_count, 1) # held by wrapper + self.assertFalse(is_floating) + + # Current ref count + self.assertEqual(vfuncs.object_ref().__grefcount__, 1) + + held_object_ref = weakref.ref(vfuncs.object_ref()) + del vfuncs.object_ref + gc.collect() + 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') diff --git a/tests/test_option.py b/tests/test_option.py index 9233eed..2900edd 100644 --- a/tests/test_option.py +++ b/tests/test_option.py @@ -6,23 +6,21 @@ import sys # py3k has StringIO in a different module try: from StringIO import StringIO + StringIO # pyflakes except ImportError: from io import StringIO -# FIXME: we need a way to import the options module from a public module -from gi._glib.option import OptionParser, OptionGroup, OptionValueError, \ - make_option, BadOptionError +from gi.repository import GLib -from compathelper import _bytes class TestOption(unittest.TestCase): EXCEPTION_MESSAGE = "This callback fails" def setUp(self): - self.parser = OptionParser("NAMES...", - description="Option unit test") + self.parser = GLib.option.OptionParser("NAMES...", + description="Option unit test") self.parser.add_option("-t", "--test", help="Unit test option", - action="store_false", dest="test", default=True) + action="store_false", dest="test", default=True) self.parser.add_option("--g-fatal-warnings", action="store_true", dest="fatal_warnings", @@ -32,22 +30,22 @@ class TestOption(unittest.TestCase): def option_callback(option, opt, value, parser): raise Exception(self.EXCEPTION_MESSAGE) - group = OptionGroup( + group = GLib.option.OptionGroup( "unittest", "Unit test options", "Show all unittest options", - option_list = [ - make_option("-f", "-u", "--file", "--unit-file", - type="filename", - dest="unit_file", - help="Unit test option"), - make_option("--test-integer", - type="int", - dest="test_integer", - help="Unit integer option"), - make_option("--callback-failure-test", - action="callback", - callback=option_callback, - dest="test_integer", - help="Unit integer option"), + option_list=[ + GLib.option.make_option("-f", "-u", "--file", "--unit-file", + type="filename", + dest="unit_file", + help="Unit test option"), + GLib.option.make_option("--test-integer", + type="int", + dest="test_integer", + help="Unit integer option"), + GLib.option.make_option("--callback-failure-test", + action="callback", + callback=option_callback, + dest="test_integer", + help="Unit integer option"), ]) group.add_option("-t", "--test", action="store_false", @@ -57,55 +55,52 @@ class TestOption(unittest.TestCase): self.parser.add_option_group(group) return group - def testParseArgs(self): + def test_parse_args(self): options, args = self.parser.parse_args( ["test_option.py"]) - self.failIf(args) + self.assertFalse(args) options, args = self.parser.parse_args( ["test_option.py", "foo"]) - self.assertEquals(args, ["foo"]) + self.assertEqual(args, []) options, args = self.parser.parse_args( ["test_option.py", "foo", "bar"]) - self.assertEquals(args, ["foo", "bar"]) + self.assertEqual(args, []) - def testParseArgsDoubleDash(self): + def test_parse_args_double_dash(self): options, args = self.parser.parse_args( ["test_option.py", "--", "-xxx"]) - #self.assertEquals(args, ["-xxx"]) + #self.assertEqual(args, ["-xxx"]) - def testParseArgs(self): - options, args = self.parser.parse_args() - - def testParseArgsGroup(self): + def test_parse_args_group(self): group = self._create_group() options, args = self.parser.parse_args( ["test_option.py", "--test", "-f", "test"]) - self.failIf(options.test) + self.assertFalse(options.test) self.assertEqual(options.unit_file, "test") - self.failUnless(group.values.test) - self.failIf(self.parser.values.test) + self.assertTrue(group.values.test) + self.assertFalse(self.parser.values.test) self.assertEqual(group.values.unit_file, "test") - self.failIf(args) + self.assertFalse(args) - def testOptionValueError(self): + def test_option_value_error(self): self._create_group() - self.assertRaises(OptionValueError, self.parser.parse_args, + self.assertRaises(GLib.option.OptionValueError, self.parser.parse_args, ["test_option.py", "--test-integer=text"]) - def testBadOptionError(self): - self.assertRaises(BadOptionError, + def test_bad_option_error(self): + self.assertRaises(GLib.option.BadOptionError, self.parser.parse_args, ["test_option.py", "--unknwon-option"]) - def testOptionGroupConstructor(self): - self.assertRaises(TypeError, OptionGroup) + def test_option_group_constructor(self): + self.assertRaises(TypeError, GLib.option.OptionGroup) - def testStandardError(self): + def test_standard_error(self): self._create_group() sio = StringIO() old_stderr = sys.stderr @@ -118,4 +113,3 @@ class TestOption(unittest.TestCase): assert (sio.getvalue().split('\n')[-2] == "Exception: " + self.EXCEPTION_MESSAGE) - diff --git a/tests/test_overrides.py b/tests/test_overrides.py index 78e589f..e1af1f1 100644 --- a/tests/test_overrides.py +++ b/tests/test_overrides.py @@ -3,1959 +3,56 @@ import unittest -import sys -import os -sys.path.insert(0, "../") +import gi.overrides +import gi.module -from compathelper import _long, _unicode, _bytes +try: + from gi.repository import Regress + Regress # pyflakes +except ImportError: + Regress = None -os.environ['GSETTINGS_BACKEND'] = 'memory' -# support a separate build tree, so look in build dir first -os.environ['GSETTINGS_SCHEMA_DIR'] = os.environ.get('TESTS_BUILDDIR', - os.path.dirname(__file__)) -from gi.repository import GLib -from gi.repository import GObject -from gi.repository import Gdk -from gi.repository import Gtk -from gi.repository import Gio -from gi.repository import Pango -from gi.repository import GdkPixbuf -import gi.overrides as overrides -import gi.types - -# in general we don't want tests to raise warnings, except when explicitly -# testing with bad values; in those cases it will temporarily be set back to -# ERROR -GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_WARNING) - -class TestGLib(unittest.TestCase): - - def test_gvariant_create(self): - # simple values - - variant = GLib.Variant('i', 42) - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertEquals(variant.get_int32(), 42) - - variant = GLib.Variant('s', '') - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertEquals(variant.get_string(), '') - - variant = GLib.Variant('s', 'hello') - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertEquals(variant.get_string(), 'hello') - - # boxed variant - variant = GLib.Variant('v', GLib.Variant('i', 42)) - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertTrue(isinstance(variant.get_variant(), GLib.Variant)) - self.assertEqual(variant.get_type_string(), 'v') - self.assertEqual(variant.get_variant().get_type_string(), 'i') - self.assertEquals(variant.get_variant().get_int32(), 42) - - variant = GLib.Variant('v', GLib.Variant('v', GLib.Variant('i', 42))) - self.assertEqual(variant.get_type_string(), 'v') - self.assertEqual(variant.get_variant().get_type_string(), 'v') - self.assertEqual(variant.get_variant().get_variant().get_type_string(), 'i') - self.assertEquals(variant.get_variant().get_variant().get_int32(), 42) - - # tuples - - variant = GLib.Variant('()', ()) - self.assertEqual(variant.get_type_string(), '()') - self.assertEquals(variant.n_children(), 0) - - variant = GLib.Variant('(i)', (3,)) - self.assertEqual(variant.get_type_string(), '(i)') - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertEquals(variant.n_children(), 1) - self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) - self.assertEquals(variant.get_child_value(0).get_int32(), 3) - - variant = GLib.Variant('(ss)', ('mec', 'mac')) - self.assertEqual(variant.get_type_string(), '(ss)') - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) - self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) - self.assertEquals(variant.get_child_value(0).get_string(), 'mec') - self.assertEquals(variant.get_child_value(1).get_string(), 'mac') - - # 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))) - - # dictionaries - - variant = GLib.Variant('a{si}', {}) - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertEqual(variant.get_type_string(), 'a{si}') - self.assertEquals(variant.n_children(), 0) - - variant = GLib.Variant('a{si}', {'': 1, 'key1': 2, 'key2': 3}) - self.assertEqual(variant.get_type_string(), 'a{si}') - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) - self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) - self.assertTrue(isinstance(variant.get_child_value(2), GLib.Variant)) - self.assertEqual(variant.unpack(), {'': 1, 'key1': 2, 'key2': 3}) - - # nested dictionaries - variant = GLib.Variant('a{sa{si}}', {}) - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertEqual(variant.get_type_string(), 'a{sa{si}}') - self.assertEquals(variant.n_children(), 0) - - d = {'': {'': 1, 'keyn1': 2}, - 'key1': {'key11': 11, 'key12': 12}} - variant = GLib.Variant('a{sa{si}}', d) - self.assertEqual(variant.get_type_string(), 'a{sa{si}}') - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertEqual(variant.unpack(), d) - - # arrays - - variant = GLib.Variant('ai', []) - self.assertEqual(variant.get_type_string(), 'ai') - self.assertEquals(variant.n_children(), 0) - - variant = GLib.Variant('ai', [1, 2]) - self.assertEqual(variant.get_type_string(), 'ai') - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) - self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) - self.assertEquals(variant.get_child_value(0).get_int32(), 1) - self.assertEquals(variant.get_child_value(1).get_int32(), 2) - - variant = GLib.Variant('as', []) - self.assertEqual(variant.get_type_string(), 'as') - self.assertEquals(variant.n_children(), 0) - - variant = GLib.Variant('as', ['']) - self.assertEqual(variant.get_type_string(), 'as') - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) - self.assertEquals(variant.get_child_value(0).get_string(), '') - - variant = GLib.Variant('as', ['hello', 'world']) - self.assertEqual(variant.get_type_string(), 'as') - self.assertTrue(isinstance(variant, GLib.Variant)) - self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) - self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) - self.assertEquals(variant.get_child_value(0).get_string(), 'hello') - self.assertEquals(variant.get_child_value(1).get_string(), 'world') - - # nested arrays - variant = GLib.Variant('aai', []) - self.assertEqual(variant.get_type_string(), 'aai') - self.assertEquals(variant.n_children(), 0) - - variant = GLib.Variant('aai', [[]]) - self.assertEqual(variant.get_type_string(), 'aai') - self.assertEquals(variant.n_children(), 1) - self.assertEquals(variant.get_child_value(0).n_children(), 0) - - variant = GLib.Variant('aai', [[1, 2], [3, 4, 5]]) - self.assertEqual(variant.get_type_string(), 'aai') - self.assertEquals(variant.unpack(), [[1, 2], [3, 4, 5]]) - - # - # complex types - # - - variant = GLib.Variant('(as)', ([],)) - self.assertEqual(variant.get_type_string(), '(as)') - self.assertEquals(variant.n_children(), 1) - self.assertEquals(variant.get_child_value(0).n_children(), 0) - - variant = GLib.Variant('(as)', ([''],)) - self.assertEqual(variant.get_type_string(), '(as)') - self.assertEquals(variant.n_children(), 1) - self.assertEquals(variant.get_child_value(0).n_children(), 1) - self.assertEquals(variant.get_child_value(0).get_child_value(0).get_string(), '') - - variant = GLib.Variant('(as)', (['hello'],)) - self.assertEqual(variant.get_type_string(), '(as)') - self.assertEquals(variant.n_children(), 1) - self.assertEquals(variant.get_child_value(0).n_children(), 1) - self.assertEquals(variant.get_child_value(0).get_child_value(0).get_string(), 'hello') - - obj = {'a1': (1, True), 'a2': (2, False)} - variant = GLib.Variant('a{s(ib)}', obj) - self.assertEqual(variant.get_type_string(), 'a{s(ib)}') - self.assertEqual(variant.unpack(), obj) - - obj = {'a1': (1, GLib.Variant('b', True)), 'a2': (2, GLib.Variant('y', 255))} - variant = GLib.Variant('a{s(iv)}', obj) - self.assertEqual(variant.get_type_string(), 'a{s(iv)}') - self.assertEqual(variant.unpack(), {'a1': (1, True), 'a2': (2, 255)}) - - obj = (1, {'a': {'a1': True, 'a2': False}, - 'b': {'b1': False}, - 'c': {} - }, - 'foo') - variant = GLib.Variant('(ia{sa{sb}}s)', obj) - self.assertEqual(variant.get_type_string(), '(ia{sa{sb}}s)') - self.assertEqual(variant.unpack(), obj) - - obj = {"frequency": GLib.Variant('t', 738000000), - "hierarchy": GLib.Variant('i', 0), - "bandwidth": GLib.Variant('x', 8), - "code-rate-hp": GLib.Variant('d', 2.0/3.0), - "constellation": GLib.Variant('s', "QAM16"), - "guard-interval": GLib.Variant('u', 4),} - variant = GLib.Variant('a{sv}', obj) - self.assertEqual(variant.get_type_string(), 'a{sv}') - self.assertEqual(variant.unpack(), {"frequency": 738000000, - "hierarchy": 0, - "bandwidth": 8, - "code-rate-hp": 2.0/3.0, - "constellation": "QAM16", - "guard-interval": 4}) - - def test_gvariant_create_errors(self): - # excess arguments - self.assertRaises(TypeError, GLib.Variant, 'i', 42, 3) - self.assertRaises(TypeError, GLib.Variant, '(i)', (42, 3)) - - # not enough arguments - self.assertRaises(TypeError, GLib.Variant, '(ii)', (42,)) - - # data type mismatch - self.assertRaises(TypeError, GLib.Variant, 'i', 'hello') - self.assertRaises(TypeError, GLib.Variant, 's', 42) - self.assertRaises(TypeError, GLib.Variant, '(ss)', 'mec', 'mac') - - # unimplemented data type - self.assertRaises(NotImplementedError, GLib.Variant, 'Q', 1) - - def test_gvariant_unpack(self): - # simple values - res = GLib.Variant.new_int32(-42).unpack() - self.assertEqual(res, -42) - - res = GLib.Variant.new_uint64(34359738368).unpack() - self.assertEqual(res, 34359738368) - - res = GLib.Variant.new_boolean(True).unpack() - self.assertEqual(res, True) - - res = GLib.Variant.new_object_path('/foo/Bar').unpack() - self.assertEqual(res, '/foo/Bar') - - # variant - res = GLib.Variant('v', GLib.Variant.new_int32(-42)).unpack() - self.assertEqual(res, -42) - - variant = GLib.Variant('v', GLib.Variant('v', GLib.Variant('i', 42))) - self.assertEqual(res, -42) - - # tuple - res = GLib.Variant.new_tuple(GLib.Variant.new_int32(-1), - GLib.Variant.new_string('hello')).unpack() - self.assertEqual(res, (-1, 'hello')) - - # array - vb = GLib.VariantBuilder.new(gi._gi.variant_type_from_string('ai')) - vb.add_value(GLib.Variant.new_int32(-1)) - vb.add_value(GLib.Variant.new_int32(3)) - res = vb.end().unpack() - self.assertEqual(res, [-1, 3]) - - # dictionary - res = GLib.Variant('a{si}', {'key1': 1, 'key2': 2}).unpack() - self.assertEqual(res, {'key1': 1, 'key2': 2}) - - def test_gvariant_iteration(self): - # array index access - vb = GLib.VariantBuilder.new(gi._gi.variant_type_from_string('ai')) - vb.add_value(GLib.Variant.new_int32(-1)) - vb.add_value(GLib.Variant.new_int32(3)) - v = vb.end() - - self.assertEqual(len(v), 2) - self.assertEqual(v[0], -1) - self.assertEqual(v[1], 3) - self.assertEqual(v[-1], 3) - self.assertEqual(v[-2], -1) - self.assertRaises(IndexError, v.__getitem__, 2) - self.assertRaises(IndexError, v.__getitem__, -3) - self.assertRaises(ValueError, v.__getitem__, 'a') - - # array iteration - self.assertEqual([x for x in v], [-1, 3]) - self.assertEqual(list(v), [-1, 3]) - - # tuple index access - v = GLib.Variant.new_tuple(GLib.Variant.new_int32(-1), - GLib.Variant.new_string('hello')) - self.assertEqual(len(v), 2) - self.assertEqual(v[0], -1) - self.assertEqual(v[1], 'hello') - self.assertEqual(v[-1], 'hello') - self.assertEqual(v[-2], -1) - self.assertRaises(IndexError, v.__getitem__, 2) - self.assertRaises(IndexError, v.__getitem__, -3) - self.assertRaises(ValueError, v.__getitem__, 'a') - - # tuple iteration - self.assertEqual([x for x in v], [-1, 'hello']) - self.assertEqual(tuple(v), (-1, 'hello')) - - # dictionary index access - vsi = GLib.Variant('a{si}', {'key1': 1, 'key2': 2}) - vis = GLib.Variant('a{is}', {1: 'val1', 5: 'val2'}) - - self.assertEqual(len(vsi), 2) - self.assertEqual(vsi['key1'], 1) - self.assertEqual(vsi['key2'], 2) - self.assertRaises(KeyError, vsi.__getitem__, 'unknown') - - self.assertEqual(len(vis), 2) - self.assertEqual(vis[1], 'val1') - self.assertEqual(vis[5], 'val2') - self.assertRaises(KeyError, vsi.__getitem__, 3) - - # dictionary iteration - self.assertEqual(set(vsi.keys()), set(['key1', 'key2'])) - self.assertEqual(set(vis.keys()), set([1, 5])) - - # string index access - v = GLib.Variant('s', 'hello') - self.assertEqual(len(v), 5) - self.assertEqual(v[0], 'h') - self.assertEqual(v[4], 'o') - self.assertEqual(v[-1], 'o') - self.assertEqual(v[-5], 'h') - self.assertRaises(IndexError, v.__getitem__, 5) - self.assertRaises(IndexError, v.__getitem__, -6) - - # string iteration - self.assertEqual([x for x in v], ['h', 'e', 'l', 'l', 'o']) - - def test_variant_split_signature(self): - self.assertEqual(GLib.Variant.split_signature('()'), []) - - self.assertEqual(GLib.Variant.split_signature('s'), ['s']) - - self.assertEqual(GLib.Variant.split_signature('as'), ['as']) - - self.assertEqual(GLib.Variant.split_signature('(s)'), ['s']) - - self.assertEqual(GLib.Variant.split_signature('(iso)'), ['i', 's', 'o']) - - self.assertEqual(GLib.Variant.split_signature('(s(ss)i(ii))'), - ['s', '(ss)', 'i', '(ii)']) - - self.assertEqual(GLib.Variant.split_signature('(as)'), ['as']) - - self.assertEqual(GLib.Variant.split_signature('(s(ss)iaiaasa(ii))'), - ['s', '(ss)', 'i', 'ai', 'aas', 'a(ii)']) - - self.assertEqual(GLib.Variant.split_signature('(a{iv}(ii)((ss)a{s(ss)}))'), - ['a{iv}', '(ii)', '((ss)a{s(ss)})']) - - def test_variant_hash(self): - v1 = GLib.Variant('s', 'somestring') - v2 = GLib.Variant('s', 'somestring') - v3 = GLib.Variant('s', 'somestring2') - - self.assertTrue(v2 in set([v1, v3])) - self.assertTrue(v2 in frozenset([v1, v3])) - self.assertTrue(v2 in {v1: '1', v3:'2' }) - - def test_variant_compare(self): - # Check if identical GVariant are equal - - def assert_equal(vtype, value): - self.assertEqual(GLib.Variant(vtype, value), GLib.Variant(vtype, value)) - - def assert_not_equal(vtype1, value1, vtype2, value2): - self.assertNotEqual(GLib.Variant(vtype1, value1), GLib.Variant(vtype2, value2)) - - numbers = ['y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd'] - for num in numbers: - assert_equal(num, 42) - assert_not_equal(num, 42, num, 41) - assert_not_equal(num, 42, 's', '42') - - assert_equal('s', 'something') - assert_not_equal('s', 'something', 's', 'somethingelse') - assert_not_equal('s', 'something', 'i', 1234) - - assert_equal('g', 'dustybinqhogx') - assert_not_equal('g', 'dustybinqhogx', 'g', 'dustybin') - assert_not_equal('g', 'dustybinqhogx', 'i', 1234) - - assert_equal('o', '/dev/null') - assert_not_equal('o', '/dev/null', 'o', '/dev/zero') - assert_not_equal('o', '/dev/null', 'i', 1234) - - assert_equal('(s)', ('strtuple',)) - assert_not_equal('(s)', ('strtuple',), '(s)', ('strtuple2',)) - - assert_equal('a{si}', {'str': 42}) - assert_not_equal('a{si}', {'str': 42}, 'a{si}', {'str': 43}) - - assert_equal('v', GLib.Variant('i', 42)) - assert_not_equal('v', GLib.Variant('i', 42), 'v', GLib.Variant('i', 43)) - - def test_variant_bool(self): - # Check if the GVariant bool matches the unpacked Pythonic bool - - def assert_equals_bool(vtype, value): - self.assertEqual(bool(GLib.Variant(vtype, value)), bool(value)) - - # simple values - assert_equals_bool('b', True) - assert_equals_bool('b', False) - - numbers = ['y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd'] - for number in numbers: - assert_equals_bool(number, 0) - assert_equals_bool(number, 1) - - assert_equals_bool('s', '') - assert_equals_bool('g', '') - assert_equals_bool('s', 'something') - assert_equals_bool('o', '/dev/null') - assert_equals_bool('g', 'dustybinqhogx') - - # arrays - assert_equals_bool('ab', [True]) - assert_equals_bool('ab', [False]) - for number in numbers: - assert_equals_bool('a'+number, []) - assert_equals_bool('a'+number, [0]) - assert_equals_bool('as', []) - assert_equals_bool('as', ['']) - assert_equals_bool('ao', []) - assert_equals_bool('ao', ['/']) - assert_equals_bool('ag', []) - assert_equals_bool('ag', ['']) - assert_equals_bool('aai', [[]]) - - # tuples - assert_equals_bool('()', ()) - for number in numbers: - assert_equals_bool('('+number+')', (0,)) - assert_equals_bool('(s)', ('',)) - assert_equals_bool('(o)', ('/',)) - assert_equals_bool('(g)', ('',)) - assert_equals_bool('(())', ((),)) - - # dictionaries - assert_equals_bool('a{si}', {}) - assert_equals_bool('a{si}', {'': 0}) - - # complex types, always True - assert_equals_bool('(as)', ([],)) - assert_equals_bool('a{s(i)}', {'': (0,)}) - - # variant types, recursive unpacking - assert_equals_bool('v', GLib.Variant('i', 0)) - assert_equals_bool('v', GLib.Variant('i', 1)) - -class TestPango(unittest.TestCase): - - def test_default_font_description(self): - desc = Pango.FontDescription() - self.assertEquals(desc.get_variant(), Pango.Variant.NORMAL) - - def test_font_description(self): - desc = Pango.FontDescription('monospace') - self.assertEquals(desc.get_family(), 'monospace') - self.assertEquals(desc.get_variant(), Pango.Variant.NORMAL) - - def test_layout(self): - self.assertRaises(TypeError, Pango.Layout) - context = Pango.Context() - layout = Pango.Layout(context) - self.assertEquals(layout.get_context(), context) - - layout.set_markup("Foobar") - self.assertEquals(layout.get_text(), "Foobar") - - -class TestGdk(unittest.TestCase): - - def test_constructor(self): - attribute = Gdk.WindowAttr() - attribute.window_type = Gdk.WindowType.CHILD - attributes_mask = Gdk.WindowAttributesType.X | \ - Gdk.WindowAttributesType.Y - window = Gdk.Window(None, attribute, attributes_mask) - self.assertEquals(window.get_window_type(), Gdk.WindowType.CHILD) - - def test_color(self): - color = Gdk.Color(100, 200, 300) - self.assertEquals(color.red, 100) - self.assertEquals(color.green, 200) - self.assertEquals(color.blue, 300) - self.assertEquals(color, Gdk.Color(100, 200, 300)) - self.assertNotEquals(color, Gdk.Color(1, 2, 3)) - - def test_rgba(self): - self.assertEquals(Gdk.RGBA, overrides.Gdk.RGBA) - rgba = Gdk.RGBA(0.1, 0.2, 0.3, 0.4) - self.assertEquals(rgba, Gdk.RGBA(0.1, 0.2, 0.3, 0.4)) - self.assertNotEquals(rgba, Gdk.RGBA(0.0, 0.2, 0.3, 0.4)) - self.assertEquals(rgba.red, 0.1) - self.assertEquals(rgba.green, 0.2) - self.assertEquals(rgba.blue, 0.3) - self.assertEquals(rgba.alpha, 0.4) - rgba.green = 0.9 - self.assertEquals(rgba.green, 0.9) - - def test_event(self): - event = Gdk.Event.new(Gdk.EventType.CONFIGURE) - self.assertEquals(event.type, Gdk.EventType.CONFIGURE) - self.assertEquals(event.send_event, 0) - - event = Gdk.Event.new(Gdk.EventType.DRAG_MOTION) - event.x_root, event.y_root = 0, 5 - self.assertEquals(event.x_root, 0) - self.assertEquals(event.y_root, 5) - - event = Gdk.Event() - event.type = Gdk.EventType.SCROLL - self.assertRaises(AttributeError, lambda: getattr(event, 'foo_bar')) - - def test_event_structures(self): - def button_press_cb(button, event): - self.assertTrue(isinstance(event, Gdk.EventButton)) - self.assertTrue(event.type == Gdk.EventType.BUTTON_PRESS) - self.assertEquals(event.send_event, 0) - self.assertEquals(event.get_state(), Gdk.ModifierType.CONTROL_MASK) - self.assertEquals(event.get_root_coords(), (2, 5)) - - event.time = 12345 - self.assertEquals(event.get_time(), 12345) - - w = Gtk.Window() - b = Gtk.Button() - b.connect('button-press-event', button_press_cb) - w.add(b) - w.show_all() - Gdk.test_simulate_button(b.get_window(), - 2, 5, - 0, - Gdk.ModifierType.CONTROL_MASK, - Gdk.EventType.BUTTON_PRESS) - - def test_cursor(self): - self.assertEquals(Gdk.Cursor, overrides.Gdk.Cursor) - c = Gdk.Cursor(Gdk.CursorType.WATCH) - self.assertNotEqual(c, None) - c = Gdk.Cursor(cursor_type = Gdk.CursorType.WATCH) - self.assertNotEqual(c, None) - - display_manager = Gdk.DisplayManager.get() - display = display_manager.get_default_display() - - test_pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, - False, - 8, - 5, - 10) - - c = Gdk.Cursor(display, - test_pixbuf, - y=0, x=0) - - self.assertNotEqual(c, None) - self.assertRaises(ValueError, Gdk.Cursor, 1, 2, 3) - -class TestGtk(unittest.TestCase): - - def test_container(self): - box = Gtk.Box() - self.failUnless(isinstance(box, Gtk.Box)) - self.failUnless(isinstance(box, Gtk.Container)) - self.failUnless(isinstance(box, Gtk.Widget)) - self.assertTrue(box) - label = Gtk.Label() - label2 = Gtk.Label() - box.add(label) - box.add(label2) - self.assertTrue(label in box) - self.assertTrue(label2 in box) - self.assertEqual(len(box), 2) - self.assertTrue(box) - l = [x for x in box] - self.assertEqual(l, [label, label2]) - - def test_actions(self): - self.assertEquals(Gtk.Action, overrides.Gtk.Action) - self.assertRaises(TypeError, Gtk.Action) - action = Gtk.Action("test", "Test", "Test Action", Gtk.STOCK_COPY) - self.assertEquals(action.get_name(), "test") - self.assertEquals(action.get_label(), "Test") - self.assertEquals(action.get_tooltip(), "Test Action") - self.assertEquals(action.get_stock_id(), Gtk.STOCK_COPY) - - self.assertEquals(Gtk.RadioAction, overrides.Gtk.RadioAction) - self.assertRaises(TypeError, Gtk.RadioAction) - action = Gtk.RadioAction("test", "Test", "Test Action", Gtk.STOCK_COPY, 1) - self.assertEquals(action.get_name(), "test") - self.assertEquals(action.get_label(), "Test") - self.assertEquals(action.get_tooltip(), "Test Action") - self.assertEquals(action.get_stock_id(), Gtk.STOCK_COPY) - self.assertEquals(action.get_current_value(), 1) - - def test_actiongroup(self): - self.assertEquals(Gtk.ActionGroup, overrides.Gtk.ActionGroup) - self.assertRaises(TypeError, Gtk.ActionGroup) - - action_group = Gtk.ActionGroup (name = 'TestActionGroup') - callback_data = "callback data" - - def test_action_callback_data(action, user_data): - self.assertEquals(user_data, callback_data); - - def test_radio_action_callback_data(action, current, user_data): - self.assertEquals(user_data, callback_data); - - action_group.add_actions ([ - ('test-action1', None, 'Test Action 1', - None, None, test_action_callback_data), - ('test-action2', Gtk.STOCK_COPY, 'Test Action 2', - None, None, test_action_callback_data)], callback_data) - action_group.add_toggle_actions([ - ('test-toggle-action1', None, 'Test Toggle Action 1', - None, None, test_action_callback_data, False), - ('test-toggle-action2', Gtk.STOCK_COPY, 'Test Toggle Action 2', - None, None, test_action_callback_data, True)], callback_data) - action_group.add_radio_actions([ - ('test-radio-action1', None, 'Test Radio Action 1'), - ('test-radio-action2', Gtk.STOCK_COPY, 'Test Radio Action 2')], 1, - test_radio_action_callback_data, - callback_data) - - expected_results = [('test-action1', Gtk.Action), - ('test-action2', Gtk.Action), - ('test-toggle-action1', Gtk.ToggleAction), - ('test-toggle-action2', Gtk.ToggleAction), - ('test-radio-action1', Gtk.RadioAction), - ('test-radio-action2', Gtk.RadioAction)] - - for action in action_group.list_actions(): - a = (action.get_name(), type(action)) - self.assertTrue(a in expected_results) - expected_results.remove(a) - action.activate() - - def test_uimanager(self): - self.assertEquals(Gtk.UIManager, overrides.Gtk.UIManager) - ui = Gtk.UIManager() - ui.add_ui_from_string( -""" -<ui> - <menubar name="menubar1"></menubar> -</ui> -""" -) - menubar = ui.get_widget("/menubar1") - self.assertEquals(type(menubar), Gtk.MenuBar) - - ag = Gtk.ActionGroup (name="ag1") - ui.insert_action_group(ag) - ag2 = Gtk.ActionGroup (name="ag2") - ui.insert_action_group(ag2) - groups = ui.get_action_groups() - self.assertEquals(ag, groups[-2]) - self.assertEquals(ag2, groups[-1]) - - def test_builder(self): - self.assertEquals(Gtk.Builder, overrides.Gtk.Builder) - - class SignalTest(GObject.GObject): - __gtype_name__ = "GIOverrideSignalTest" - __gsignals__ = { - "test-signal": (GObject.SignalFlags.RUN_FIRST, - None, - []), - } - - - class SignalCheck: - def __init__(self): - self.sentinel = 0 - self.after_sentinel = 0; - - def on_signal_1(self, *args): - self.sentinel += 1 - self.after_sentinel += 1 - - def on_signal_3(self, *args): - self.sentinel += 3 - - def on_signal_after(self, *args): - if self.after_sentinel == 1: - self.after_sentinel += 1 - - signal_checker = SignalCheck() - builder = Gtk.Builder() - - # add object1 to the builder - builder.add_from_string( -""" -<interface> - <object class="GIOverrideSignalTest" id="object1"> - <signal name="test-signal" after="yes" handler="on_signal_after" /> - <signal name="test-signal" handler="on_signal_1" /> - </object> -</interface> -""") - - # only add object3 to the builder - builder.add_objects_from_string( -""" -<interface> - <object class="GIOverrideSignalTest" id="object2"> - <signal name="test-signal" handler="on_signal_2" /> - </object> - <object class="GIOverrideSignalTest" id="object3"> - <signal name="test-signal" handler="on_signal_3" /> - </object> - <object class="GIOverrideSignalTest" id="object4"> - <signal name="test-signal" handler="on_signal_4" /> - </object> -</interface> - -""", - ['object3']) - - # hook up signals - builder.connect_signals(signal_checker) - - # call their notify signals and check sentinel - objects = builder.get_objects() - self.assertEquals(len(objects), 2) - for obj in objects: - obj.emit('test-signal') - - self.assertEquals(signal_checker.sentinel, 4) - self.assertEquals(signal_checker.after_sentinel, 2) - - def test_dialogs(self): - self.assertEquals(Gtk.Dialog, overrides.Gtk.Dialog) - self.assertEquals(Gtk.AboutDialog, overrides.Gtk.AboutDialog) - self.assertEquals(Gtk.MessageDialog, overrides.Gtk.MessageDialog) - self.assertEquals(Gtk.ColorSelectionDialog, overrides.Gtk.ColorSelectionDialog) - self.assertEquals(Gtk.FileChooserDialog, overrides.Gtk.FileChooserDialog) - self.assertEquals(Gtk.FontSelectionDialog, overrides.Gtk.FontSelectionDialog) - self.assertEquals(Gtk.RecentChooserDialog, overrides.Gtk.RecentChooserDialog) - - # Gtk.Dialog - dialog = Gtk.Dialog (title='Foo', - flags=Gtk.DialogFlags.MODAL, - buttons=('test-button1', 1)) - self.failUnless(isinstance(dialog, Gtk.Dialog)) - self.failUnless(isinstance(dialog, Gtk.Window)) - - dialog.add_buttons ('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE) - - self.assertEquals('Foo', dialog.get_title()) - self.assertTrue(dialog.get_modal()) - button = dialog.get_widget_for_response (1) - self.assertEquals('test-button1', button.get_label()) - button = dialog.get_widget_for_response (2) - self.assertEquals('test-button2', button.get_label()) - button = dialog.get_widget_for_response (Gtk.ResponseType.CLOSE) - self.assertEquals(Gtk.STOCK_CLOSE, button.get_label()) - - # Gtk.AboutDialog - dialog = Gtk.AboutDialog() - self.failUnless(isinstance(dialog, Gtk.Dialog)) - self.failUnless(isinstance(dialog, Gtk.Window)) - - # Gtk.MessageDialog - dialog = Gtk.MessageDialog (title='message dialog test', - flags=Gtk.DialogFlags.MODAL, - buttons=Gtk.ButtonsType.OK, - message_format='dude!') - self.failUnless(isinstance(dialog, Gtk.Dialog)) - self.failUnless(isinstance(dialog, Gtk.Window)) - - self.assertEquals('message dialog test', dialog.get_title()) - self.assertTrue(dialog.get_modal()) - text = dialog.get_property('text') - self.assertEquals('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')) - - 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") - self.failUnless(isinstance(dialog, Gtk.Dialog)) - self.failUnless(isinstance(dialog, Gtk.Window)) - self.assertEquals('color selection dialog test', dialog.get_title()) - - # Gtk.FileChooserDialog - dialog = Gtk.FileChooserDialog (title='file chooser dialog test', - buttons=('test-button1', 1), - action=Gtk.FileChooserAction.SAVE) - self.failUnless(isinstance(dialog, Gtk.Dialog)) - self.failUnless(isinstance(dialog, Gtk.Window)) - - dialog.add_buttons ('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE) - self.assertEquals('file chooser dialog test', dialog.get_title()) - button = dialog.get_widget_for_response (1) - self.assertEquals('test-button1', button.get_label()) - button = dialog.get_widget_for_response (2) - self.assertEquals('test-button2', button.get_label()) - button = dialog.get_widget_for_response (Gtk.ResponseType.CLOSE) - self.assertEquals(Gtk.STOCK_CLOSE, button.get_label()) - action = dialog.get_property('action') - self.assertEquals(Gtk.FileChooserAction.SAVE, action) - - - # Gtk.FontSelectionDialog - dialog = Gtk.ColorSelectionDialog("font selection dialog test") - self.failUnless(isinstance(dialog, Gtk.Dialog)) - self.failUnless(isinstance(dialog, Gtk.Window)) - self.assertEquals('font selection dialog test', dialog.get_title()) - - # Gtk.RecentChooserDialog - test_manager = Gtk.RecentManager() - dialog = Gtk.RecentChooserDialog (title='recent chooser dialog test', - buttons=('test-button1', 1), - manager=test_manager) - self.failUnless(isinstance(dialog, Gtk.Dialog)) - self.failUnless(isinstance(dialog, Gtk.Window)) - - dialog.add_buttons ('test-button2', 2, Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE) - self.assertEquals('recent chooser dialog test', dialog.get_title()) - button = dialog.get_widget_for_response (1) - self.assertEquals('test-button1', button.get_label()) - button = dialog.get_widget_for_response (2) - self.assertEquals('test-button2', button.get_label()) - button = dialog.get_widget_for_response (Gtk.ResponseType.CLOSE) - self.assertEquals(Gtk.STOCK_CLOSE, button.get_label()) - - class TestClass(GObject.GObject): - __gtype_name__ = "GIOverrideTreeAPITest" - - def __init__(self, tester, int_value, string_value): - super(TestGtk.TestClass, self).__init__() - self.tester = tester - self.int_value = int_value - self.string_value = string_value - - def check(self, int_value, string_value): - self.tester.assertEquals(int_value, self.int_value) - self.tester.assertEquals(string_value, self.string_value) - - def test_tree_store(self): - self.assertEquals(Gtk.TreeStore, overrides.Gtk.TreeStore) - self.assertEquals(Gtk.ListStore, overrides.Gtk.ListStore) - self.assertEquals(Gtk.TreeModel, overrides.Gtk.TreeModel) - self.assertEquals(Gtk.TreeViewColumn, overrides.Gtk.TreeViewColumn) - - class TestPyObject(object): - pass - - test_pyobj = TestPyObject() - test_pydict = {1:1, "2":2, "3":"3"} - test_pylist = [1,"2", "3"] - tree_store = Gtk.TreeStore(int, - 'gchararray', - TestGtk.TestClass, - GObject.TYPE_PYOBJECT, - object, - object, - object, - bool, - bool, - GObject.TYPE_UINT, - GObject.TYPE_ULONG, - GObject.TYPE_INT64, - GObject.TYPE_UINT64, - GObject.TYPE_UCHAR, - GObject.TYPE_CHAR) - - parent = None - for i in range(97): - label = 'this is child #%d' % i - testobj = TestGtk.TestClass(self, i, label) - parent = tree_store.append(parent, (i, - label, - testobj, - testobj, - test_pyobj, - test_pydict, - test_pylist, - i % 2, - bool(i % 2), - i, - GObject.G_MAXULONG, - GObject.G_MININT64, - 0xffffffffffffffff, - 254, - _bytes('a') - )) - # test set - parent = tree_store.append(parent) - i = 97 - label = 'this is child #%d' % i - testobj = TestGtk.TestClass(self, i, label) - tree_store.set(parent, 0, i, - 2, testobj, - 1, label, - 3, testobj, - 4, test_pyobj, - 5, test_pydict, - 6, test_pylist, - 7, i % 2, - 8, bool(i % 2), - 9, i, - 10, GObject.G_MAXULONG, - 11, GObject.G_MININT64, - 12, 0xffffffffffffffff, - 13, 254, - 14, _bytes('a')) - - parent = tree_store.append(parent) - i = 98 - label = 'this is child #%d' % i - testobj = TestGtk.TestClass(self, i, label) - tree_store.set(parent, {0: i, - 2: testobj, - 1: label, - 3: testobj, - 4: test_pyobj, - 5: test_pydict, - 6: test_pylist, - 7: i % 2, - 8: bool(i % 2), - 9: i, - 10: GObject.G_MAXULONG, - 11: GObject.G_MININT64, - 12: 0xffffffffffffffff, - 13: 254, - 14: _bytes('a')}) - - parent = tree_store.append(parent) - i = 99 - label = 'this is child #%d' % i - testobj = TestGtk.TestClass(self, i, label) - tree_store.set(parent, (0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14), - (i, - testobj, - label, - testobj, - test_pyobj, - test_pydict, - test_pylist, - i % 2, - bool(i % 2), - i, - GObject.G_MAXULONG, - GObject.G_MININT64, - 0xffffffffffffffff, - 254, - _bytes('a'))) - - # len gets the number of children in the root node - # since we kept appending to the previous node - # there should only be one child of the root - self.assertEquals(len(tree_store), 1) - - # walk the tree to see if the values were stored correctly - parent = None - i = 0 - - treeiter = tree_store.iter_children(parent) - while treeiter: - i = tree_store.get_value(treeiter, 0) - s = tree_store.get_value(treeiter, 1) - obj = tree_store.get_value(treeiter, 2) - obj.check(i, s) - obj2 = tree_store.get_value(treeiter, 3) - self.assertEquals(obj, obj2); - - pyobj = tree_store.get_value(treeiter, 4) - self.assertEquals(pyobj, test_pyobj) - pydict = tree_store.get_value(treeiter, 5) - self.assertEquals(pydict, test_pydict) - pylist = tree_store.get_value(treeiter, 6) - self.assertEquals(pylist, test_pylist) - - bool_1 = tree_store.get_value(treeiter, 7) - bool_2 = tree_store.get_value(treeiter, 8) - self.assertEquals(bool_1, bool_2) - self.assertTrue(isinstance(bool_1, bool)) - self.assertTrue(isinstance(bool_2, bool)) - - uint_ = tree_store.get_value(treeiter, 9) - self.assertEquals(uint_, i) - ulong_ = tree_store.get_value(treeiter, 10) - self.assertEquals(ulong_, GObject.G_MAXULONG) - int64_ = tree_store.get_value(treeiter, 11) - self.assertEquals(int64_, GObject.G_MININT64) - uint64_ = tree_store.get_value(treeiter, 12) - self.assertEquals(uint64_, 0xffffffffffffffff) - uchar_ = tree_store.get_value(treeiter, 13) - self.assertEquals(ord(uchar_), 254) - char_ = tree_store.get_value(treeiter, 14) - self.assertEquals(char_, 'a') - - parent = treeiter - treeiter = tree_store.iter_children(parent) - - self.assertEquals(i, 99) - - def test_tree_store_signals(self): - tree_store = Gtk.TreeStore(int, bool) - - def on_row_inserted(tree_store, tree_path, tree_iter, signal_list): - signal_list.append('row-inserted') - - def on_row_changed(tree_store, tree_path, tree_iter, signal_list): - signal_list.append('row-changed') - - signals = [] - tree_store.connect('row-inserted', on_row_inserted, signals) - tree_store.connect('row-changed', on_row_changed, signals) - - # adding rows with and without data should only call one signal - tree_store.append(None, (0, False)) - self.assertEqual(signals, ['row-inserted']) - - signals.pop() - tree_store.append(None) - self.assertEqual(signals, ['row-inserted']) - - signals.pop() - tree_store.prepend(None, (0, False)) - self.assertEqual(signals, ['row-inserted']) - - signals.pop() - tree_store.prepend(None) - self.assertEqual(signals, ['row-inserted']) - - signals.pop() - tree_store.insert(None, 1, (0, False)) - self.assertEqual(signals, ['row-inserted']) - - signals.pop() - tree_store.insert(None, 1) - self.assertEqual(signals, ['row-inserted']) - - def test_list_store(self): - class TestPyObject(object): - pass - - test_pyobj = TestPyObject() - test_pydict = {1:1, "2":2, "3":"3"} - test_pylist = [1,"2", "3"] - - list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest', object, object, object, bool, bool) - for i in range(1, 93): - label = 'this is row #%d' % i - testobj = TestGtk.TestClass(self, i, label) - parent = list_store.append((i, - label, - testobj, - test_pyobj, - test_pydict, - test_pylist, - i % 2, - bool(i % 2))) - - i = 93 - label = _unicode('this is row #93') - treeiter = list_store.append() - list_store.set_value(treeiter, 0, i) - list_store.set_value(treeiter, 1, label) - list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label)) - list_store.set_value(treeiter, 3, test_pyobj) - list_store.set_value(treeiter, 4, test_pydict) - list_store.set_value(treeiter, 5, test_pylist) - list_store.set_value(treeiter, 6, 1) - list_store.set_value(treeiter, 7, True) - - # test prepend - label = 'this is row #0' - list_store.prepend((0, - label, - TestGtk.TestClass(self, 0, label), - test_pyobj, - test_pydict, - test_pylist, - 0, - False)) - - # test automatic unicode->str conversion - i = 94 - label = _unicode('this is row #94') - treeiter = list_store.append((i, - label, - TestGtk.TestClass(self, i, label), - test_pyobj, - test_pydict, - test_pylist, - 0, - False)) - - # add sorted items out of order to test insert* apis - # also test sending in None to not set a column - i = 97 - label = 'this is row #97' - treeiter = list_store.append((None, - None, - None, - test_pyobj, - None, - test_pylist, - 1, - None)) - - list_store.set_value(treeiter, 0, i) - list_store.set_value(treeiter, 1, label) - list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label)) - list_store.set_value(treeiter, 4, test_pydict) - list_store.set_value(treeiter, 7, True) - - # this should append - i = 99 - label = 'this is row #99' - list_store.insert(9999, (i, - label, - TestGtk.TestClass(self, i, label), - test_pyobj, - test_pydict, - test_pylist, - 1, - True)) - - i = 96 - label = 'this is row #96' - list_store.insert_before(treeiter, (i, - label, - TestGtk.TestClass(self, i, label), - test_pyobj, - test_pydict, - test_pylist, - 0, - False)) - - i = 98 - label = 'this is row #98' - list_store.insert_after(treeiter, (i, - label, - TestGtk.TestClass(self, i, label), - test_pyobj, - test_pydict, - test_pylist, - 0, - False)) - - - i = 95 - label = 'this is row #95' - list_store.insert(95, (i, - label, - TestGtk.TestClass(self, i, label), - test_pyobj, - test_pydict, - test_pylist, - 1, - True)) - - i = 100 - label = 'this is row #100' - treeiter = list_store.append() - list_store.set(treeiter, 1, label, - 0, i, - 2, TestGtk.TestClass(self, i, label), - 3, test_pyobj, - 4, test_pydict, - 5, test_pylist, - 6, 0, - 7, False) - i = 101 - label = 'this is row #101' - treeiter = list_store.append() - list_store.set(treeiter, {1: label, - 0: i, - 2: TestGtk.TestClass(self, i, label), - 3: test_pyobj, - 4: test_pydict, - 5: test_pylist, - 6: 1, - 7: True}) - i = 102 - label = 'this is row #102' - treeiter = list_store.append() - list_store.set(treeiter, (1, 0, 2, 3, 4, 5, 6, 7), - (label, - i, - TestGtk.TestClass(self, i, label), - test_pyobj, - test_pydict, - test_pylist, - 0, - False)) - - self.assertEquals(len(list_store), 103) - - # walk the list to see if the values were stored correctly - i = 0 - treeiter = list_store.get_iter_first() - - counter = 0 - while treeiter: - i = list_store.get_value(treeiter, 0) - self.assertEquals(i, counter) - s = list_store.get_value(treeiter, 1) - obj = list_store.get_value(treeiter, 2) - obj.check(i, s) - - pyobj = list_store.get_value(treeiter, 3) - self.assertEquals(pyobj, test_pyobj) - pydict = list_store.get_value(treeiter, 4) - self.assertEquals(pydict, test_pydict) - pylist = list_store.get_value(treeiter, 5) - self.assertEquals(pylist, test_pylist) - - bool_1 = list_store.get_value(treeiter, 6) - bool_2 = list_store.get_value(treeiter, 7) - self.assertEquals(bool_1, bool_2) - self.assertTrue(isinstance(bool_1, bool)) - self.assertTrue(isinstance(bool_2, bool)) - - treeiter = list_store.iter_next(treeiter) - - counter += 1 - - self.assertEquals(i, 102) - - def test_list_store_signals(self): - list_store = Gtk.ListStore(int, bool) - - def on_row_inserted(list_store, tree_path, tree_iter, signal_list): - signal_list.append('row-inserted') - - def on_row_changed(list_store, tree_path, tree_iter, signal_list): - signal_list.append('row-changed') - - signals = [] - list_store.connect('row-inserted', on_row_inserted, signals) - list_store.connect('row-changed', on_row_changed, signals) - - # adding rows with and without data should only call one signal - list_store.append((0, False)) - self.assertEqual(signals, ['row-inserted']) - - signals.pop() - list_store.append() - self.assertEqual(signals, ['row-inserted']) - - signals.pop() - list_store.prepend((0, False)) - self.assertEqual(signals, ['row-inserted']) - - signals.pop() - list_store.prepend() - self.assertEqual(signals, ['row-inserted']) - - signals.pop() - list_store.insert(1, (0, False)) - self.assertEqual(signals, ['row-inserted']) - - signals.pop() - list_store.insert(1) - self.assertEqual(signals, ['row-inserted']) - - def test_tree_path(self): - p1 = Gtk.TreePath() - p2 = Gtk.TreePath.new_first() - self.assertEqual(p1, p2) - self.assertEqual(str(p1), '0') - p1 = Gtk.TreePath(2) - p2 = Gtk.TreePath.new_from_string('2') - self.assertEqual(p1, p2) - self.assertEqual(str(p1), '2') - p1 = Gtk.TreePath('1:2:3') - p2 = Gtk.TreePath.new_from_string('1:2:3') - self.assertEqual(p1, p2) - self.assertEqual(str(p1), '1:2:3') - p1 = Gtk.TreePath((1,2,3)) - p2 = Gtk.TreePath.new_from_string('1:2:3') - self.assertEqual(p1, p2) - self.assertEqual(str(p1), '1:2:3') - self.assertTrue(p1 != None) - self.assertFalse(p1 == None) - self.assertTrue(p1 > None) - self.assertTrue(p1 >= None) - self.assertFalse(p1 < None) - self.assertFalse(p1 <= None) - - self.assertEquals(tuple(p1), (1, 2, 3)) - - def test_tree_model(self): - tree_store = Gtk.TreeStore(int, str) - - self.assertTrue(tree_store) - self.assertEqual(len(tree_store), 0) - self.assertEqual(tree_store.get_iter_first(), None) - - def get_by_index(row, col=None): - if col: - return tree_store[row][col] - else: - return tree_store[row] - - self.assertRaises(TypeError, get_by_index, None) - self.assertRaises(TypeError, get_by_index, "") - self.assertRaises(TypeError, get_by_index, ()) - - self.assertRaises(IndexError, get_by_index, "0") - self.assertRaises(IndexError, get_by_index, 0) - self.assertRaises(IndexError, get_by_index, (0,)) - - self.assertRaises(ValueError, tree_store.get_iter, "0") - self.assertRaises(ValueError, tree_store.get_iter, 0) - self.assertRaises(ValueError, tree_store.get_iter, (0,)) - - self.assertRaises(ValueError, tree_store.get_iter_from_string, "0") - - for row in tree_store: - self.fail("Should not be reached") - - class DerivedIntType(int): +class TestRegistry(unittest.TestCase): + def test_non_gi(self): + class MyClass: pass - class DerivedStrType(str): - pass - - for i in range(100): - label = 'this is row #%d' % i - parent = tree_store.append(None, (DerivedIntType(i), DerivedStrType(label),)) - self.assertNotEquals(parent, None) - for j in range(20): - label = 'this is child #%d of node #%d' % (j, i) - child = tree_store.append(parent, (j, label,)) - self.assertNotEqual(child, None) - - self.assertTrue(tree_store) - self.assertEqual(len(tree_store), 100) - - for i,row in enumerate(tree_store): - self.assertEqual(row.model, tree_store) - self.assertEqual(row.parent, None) - - self.assertEqual(tree_store[i].path, row.path) - self.assertEqual(tree_store[str(i)].path, row.path) - self.assertEqual(tree_store[(i,)].path, row.path) - - self.assertEqual(tree_store[i][0], i) - self.assertEqual(tree_store[i][1], "this is row #%d" % i) - - aiter = tree_store.get_iter(i) - self.assertEqual(tree_store.get_path(aiter), row.path) - - aiter = tree_store.get_iter(str(i)) - self.assertEqual(tree_store.get_path(aiter), row.path) - - aiter = tree_store.get_iter((i,)) - self.assertEqual(tree_store.get_path(aiter), row.path) - - self.assertEqual(tree_store.iter_parent(aiter), row.parent) - - next = tree_store.iter_next(aiter) - if i < len(tree_store) - 1: - self.assertEqual(tree_store.get_path(next), row.next.path) - else: - self.assertEqual(next, None) - - self.assertEqual(tree_store.iter_n_children(row.iter), 20) - - child = tree_store.iter_children(row.iter) - for j,childrow in enumerate(row.iterchildren()): - child_path = tree_store.get_path(child) - self.assertEqual(childrow.path, child_path) - self.assertEqual(childrow.parent.path, row.path) - self.assertEqual(childrow.path, tree_store[child].path) - self.assertEqual(childrow.path, tree_store[child_path].path) - - self.assertEqual(childrow[0], tree_store[child][0]) - self.assertEqual(childrow[0], j) - self.assertEqual(childrow[1], tree_store[child][1]) - self.assertEqual(childrow[1], 'this is child #%d of node #%d' % (j, i)) - - self.assertRaises(IndexError, get_by_index, child, 2) - - tree_store[child][1] = 'this was child #%d of node #%d' % (j, i) - self.assertEqual(childrow[1], 'this was child #%d of node #%d' % (j, i)) - - nth_child = tree_store.iter_nth_child(row.iter, j) - self.assertEqual(childrow.path, tree_store.get_path(nth_child)) - - childrow2 = tree_store["%d:%d" % (i, j)] - self.assertEqual(childrow.path, childrow2.path) - - childrow2 = tree_store[(i, j,)] - self.assertEqual(childrow.path, childrow2.path) - - child = tree_store.iter_next(child) - if j < 19: - self.assertEqual(childrow.next.path, tree_store.get_path(child)) - else: - self.assertEqual(child, childrow.next) - self.assertEqual(child, None) - - self.assertEqual(j, 19) - - self.assertEqual(i, 99) - - # negative indices - for i in range(-1,-100,-1): - i_real = i + 100 - self.assertEqual(tree_store[i][0], i_real) - - row = tree_store[i] - for j in range(-1, -20, -1): - j_real = j + 20 - path = (i_real, j_real,) - - self.assertEqual(tree_store[path][-2], j_real) - - label = 'this was child #%d of node #%d' % (j_real, i_real) - self.assertEqual(tree_store[path][-1], label) - - new_label = 'this still is child #%d of node #%d' % (j_real, i_real) - tree_store[path][-1] = new_label - self.assertEqual(tree_store[path][-1], new_label) - - self.assertRaises(IndexError, get_by_index, path, -3) - - self.assertRaises(IndexError, get_by_index, -101) - - last_row = tree_store[99] - self.assertNotEqual(last_row, None) - - for i,childrow in enumerate(last_row.iterchildren()): - if i < 19: - self.assertTrue(tree_store.remove(childrow.iter)) - else: - self.assertFalse(tree_store.remove(childrow.iter)) - - self.assertEqual(i, 19) - - self.assertEqual(tree_store.iter_n_children(last_row.iter), 0) - for childrow in last_row.iterchildren(): - self.fail("Should not be reached") - - aiter = tree_store.get_iter(10) - self.assertRaises(TypeError, tree_store.get, aiter, 1, 'a') - self.assertRaises(ValueError, tree_store.get, aiter, 1, -1) - self.assertRaises(ValueError, tree_store.get, aiter, 1, 100) - self.assertEqual(tree_store.get(aiter, 0, 1), (10, 'this is row #10')) - - def test_tree_model_edit(self): - model = Gtk.ListStore(int, str, float) - model.append([1, "one", -0.1]) - model.append([2, "two", -0.2]) - - def set_row(value): - model[1] = value - - self.assertRaises(TypeError, set_row, 3) - self.assertRaises(TypeError, set_row, "three") - self.assertRaises(ValueError, set_row, []) - self.assertRaises(ValueError, set_row, [3, "three"]) - - model[0] = (3, "three", -0.3) - - def test_tree_row_slice(self): - model = Gtk.ListStore(int, str, float) - model.append([1, "one", -0.1]) - - self.assertEqual([1, "one", -0.1], model[0][:]) - self.assertEqual([1, "one"], model[0][:2]) - self.assertEqual(["one", -0.1], model[0][1:]) - self.assertEqual(["one"], model[0][1:-1]) - self.assertEqual([1], model[0][:-2]) - self.assertEqual([], model[0][5:]) - self.assertEqual([1, -0.1], model[0][0:3:2]) - - model[0][:] = (2, "two", -0.2) - self.assertEqual([2, "two", -0.2], model[0][:]) - - model[0][:2] = (3, "three") - self.assertEqual([3, "three", -0.2], model[0][:]) - - model[0][1:] = ("four", -0.4) - self.assertEqual([3, "four", -0.4], model[0][:]) - - model[0][1:-1] = ("five",) - self.assertEqual([3, "five", -0.4], model[0][:]) - - model[0][0:3:2] = (6, -0.6) - self.assertEqual([6, "five", -0.6], model[0][:]) - - def set_row1(): - model[0][5:] = ("doesn't", "matter",) - - self.assertRaises(ValueError, set_row1) - - def set_row2(): - model[0][:1] = (0, "zero", 0) - - self.assertRaises(ValueError, set_row2) - - def set_row3(): - model[0][:2] = ("0", 0) - - self.assertRaises(ValueError, set_row3) - - def test_tree_view(self): - store = Gtk.ListStore(int, str) - store.append((0, "foo")) - store.append((1, "bar")) - view = Gtk.TreeView() - # We can't easily call get_cursor() to make sure this works as - # expected as we need to realize and focus the column - view.set_cursor(store[1].path) - view.set_cursor(str(store[1].path)) - - view.get_cell_area(store[1].path) - view.get_cell_area(str(store[1].path)) - - def test_tree_view_column(self): - cell = Gtk.CellRendererText() - column = Gtk.TreeViewColumn(title='This is just a test', - cell_renderer=cell, - text=0, - style=2) - - def test_tree_selection(self): - store = Gtk.ListStore(int, str) - for i in range(10): - store.append((i, "foo")) - view = Gtk.TreeView() - view.set_model(store) - firstpath = store.get_path(store.get_iter_first()) - sel = view.get_selection() - - sel.select_path(firstpath) - (m, s) = sel.get_selected() - self.assertEqual(m, store) - self.assertEqual(store.get_path(s), firstpath) - - sel.select_path(0) - (m, s) = sel.get_selected() - self.assertEqual(m, store) - self.assertEqual(store.get_path(s), firstpath) - - sel.select_path("0:0") - (m, s) = sel.get_selected() - self.assertEqual(m, store) - self.assertEqual(store.get_path(s), firstpath) - - sel.select_path((0,0)) - (m, s) = sel.get_selected() - self.assertEqual(m, store) - self.assertEqual(store.get_path(s), firstpath) - - def test_text_buffer(self): - self.assertEquals(Gtk.TextBuffer, overrides.Gtk.TextBuffer) - buffer = Gtk.TextBuffer() - tag = buffer.create_tag ('title', font = 'Sans 18') - - self.assertEquals(tag.props.name, 'title') - self.assertEquals(tag.props.font, 'Sans 18') - - (start, end) = buffer.get_bounds() - - mark = buffer.create_mark(None, start) - self.assertFalse(mark.get_left_gravity()) - - buffer.set_text('Hello Jane Hello Bob') - (start, end) = buffer.get_bounds() - text = buffer.get_text(start, end, False) - self.assertEquals(text, 'Hello Jane Hello Bob') - - buffer.set_text('') - (start, end) = buffer.get_bounds() - text = buffer.get_text(start, end, False) - self.assertEquals(text, '') - - buffer.insert(end, 'HelloHello') - buffer.insert(end, ' Bob') - - cursor_iter = end.copy() - cursor_iter.backward_chars(9) - buffer.place_cursor(cursor_iter) - buffer.insert_at_cursor(' Jane ') - - (start, end) = buffer.get_bounds() - text = buffer.get_text(start, end, False) - self.assertEquals(text, 'Hello Jane Hello Bob') - - sel = buffer.get_selection_bounds() - self.assertEquals(sel, ()) - buffer.select_range(start, end) - sel = buffer.get_selection_bounds() - self.assertTrue(sel[0].equal(start)) - self.assertTrue(sel[1].equal(end)) - - 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(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(start.has_tag(tag)) - - self.assertRaises(ValueError, buffer.insert_with_tags_by_name, - buffer.get_start_iter(), 'HelloHello', 'unknowntag') - - def test_text_iter(self): - self.assertEquals(Gtk.TextIter, overrides.Gtk.TextIter) - buffer = Gtk.TextBuffer() - buffer.set_text('Hello Jane Hello Bob') - tag = buffer.create_tag ('title', font = 'Sans 18') - (start, end) = buffer.get_bounds() - start.forward_chars(10) - buffer.apply_tag(tag, start, end) - self.assertTrue(start.begins_tag()) - 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(start.ends_tag()) - self.assertFalse(start.toggles_tag()) - - def test_buttons(self): - self.assertEquals(Gtk.Button, overrides.Gtk.Button) - - # test Gtk.Button - button = Gtk.Button() - self.failUnless(isinstance(button, Gtk.Button)) - self.failUnless(isinstance(button, Gtk.Container)) - self.failUnless(isinstance(button, Gtk.Widget)) - button = Gtk.Button(stock=Gtk.STOCK_CLOSE) - self.assertEquals(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.assertEquals(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') - self.failUnless(isinstance(button, Gtk.Button)) - self.failUnless(isinstance(button, Gtk.Container)) - self.failUnless(isinstance(button, Gtk.Widget)) - self.assertEquals('http://www.Gtk.org', button.get_uri()) - self.assertEquals('Gtk', button.get_label()) - - def test_inheritance(self): - for name in overrides.Gtk.__all__: - over = getattr(overrides.Gtk, name) - for element in dir(Gtk): - try: - klass = getattr(Gtk, element) - info = klass.__info__ - except (NotImplementedError, AttributeError): - continue - - # Get all parent classes and interfaces klass inherits from - if isinstance(info, gi.types.ObjectInfo): - classes = list(info.get_interfaces()) - parent = info.get_parent() - while parent.get_name() != "Object": - classes.append(parent) - parent = parent.get_parent() - classes = [kl for kl in classes if kl.get_namespace() == "Gtk"] - else: - continue - - for kl in classes: - if kl.get_name() == name: - self.assertTrue(issubclass(klass, over,), - "%r does not inherit from override %r" % (klass, over,)) - - def test_editable(self): - self.assertEquals(Gtk.Editable, overrides.Gtk.Editable) - - # need to use Gtk.Entry because Editable is an interface - entry=Gtk.Entry() - pos = entry.insert_text('HeWorld', 0) - self.assertEquals(pos, 7) - pos = entry.insert_text('llo ', 2) - self.assertEquals(pos, 6) - text = entry.get_chars(0, 11) - self.assertEquals('Hello World', text) - - def test_label(self): - label = Gtk.Label(label='Hello') - self.failUnless(isinstance(label, Gtk.Widget)) - self.assertEquals(label.get_text(), 'Hello') - - def adjustment_check(self, adjustment, value=0.0, lower=0.0, upper=0.0, - step_increment=0.0, page_increment=0.0, page_size=0.0): - self.assertEquals(adjustment.get_value(), value) - self.assertEquals(adjustment.get_lower(), lower) - self.assertEquals(adjustment.get_upper(), upper) - self.assertEquals(adjustment.get_step_increment(), step_increment) - self.assertEquals(adjustment.get_page_increment(), page_increment) - self.assertEquals(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(1, 0, 6, 4, 5) - self.adjustment_check(adjustment, 1, 0, 6, 4, 5) - - adjustment = Gtk.Adjustment(1, 0, 6, 4) - self.adjustment_check(adjustment, 1, 0, 6, 4) - - adjustment = Gtk.Adjustment(1, 0, 6) - self.adjustment_check(adjustment, 1, 0, 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) - - def test_table(self): - table = Gtk.Table() - self.failUnless(isinstance(table, Gtk.Table)) - self.failUnless(isinstance(table, Gtk.Container)) - self.failUnless(isinstance(table, Gtk.Widget)) - self.assertEquals(table.get_size(), (1,1)) - self.assertEquals(table.get_homogeneous(), False) - table = Gtk.Table(2, 3) - self.assertEquals(table.get_size(), (2,3)) - self.assertEquals(table.get_homogeneous(), False) - table = Gtk.Table(2, 3, True) - self.assertEquals(table.get_size(), (2,3)) - self.assertEquals(table.get_homogeneous(), True) - - # Test PyGTK interface - table = Gtk.Table(rows=3, columns=2) - self.assertEquals(table.get_size(), (3,2)) - # Test using the actual property names - table = Gtk.Table(n_rows=2, n_columns=3, homogeneous=True) - self.assertEquals(table.get_size(), (2,3)) - self.assertEquals(table.get_homogeneous(), True) - - label = Gtk.Label(label='Hello') - self.failUnless(isinstance(label, Gtk.Widget)) - table.attach(label, 0, 1, 0, 1) - self.assertEquals(label, table.get_children()[0]) - - def test_scrolledwindow(self): - sw = Gtk.ScrolledWindow() - self.failUnless(isinstance(sw, Gtk.ScrolledWindow)) - self.failUnless(isinstance(sw, Gtk.Container)) - self.failUnless(isinstance(sw, Gtk.Widget)) - sb = sw.get_hscrollbar() - self.assertEquals(sw.get_hadjustment(), sb.get_adjustment()) - sb = sw.get_vscrollbar() - self.assertEquals(sw.get_vadjustment(), sb.get_adjustment()) - - def test_widget_drag_methods(self): - widget = Gtk.Button() - - # here we are not checking functionality, only that the methods exist - # and except the right number of arguments - - widget.drag_check_threshold(0, 0, 0, 0) - - # drag_dest_ methods - widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY) - widget.drag_dest_add_image_targets() - widget.drag_dest_add_text_targets() - widget.drag_dest_add_uri_targets() - 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(Gtk.TargetList.new([Gtk.TargetEntry.new('test',0, 0)])) - widget.drag_dest_unset() - - widget.drag_highlight() - widget.drag_unhighlight() - - # drag_source_ methods - widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE) - 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_pixbuf(GdkPixbuf.Pixbuf()) - widget.drag_source_set_icon_stock("") - widget.drag_source_get_target_list() - widget.drag_source_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)])) - widget.drag_source_unset() - - # these methods cannot be called because they require a valid drag on - # a real GdkWindow. So we only check that they exist and are callable. - self.assertTrue(hasattr(widget.drag_dest_set_proxy, '__call__')) - self.assertTrue(hasattr(widget.drag_get_data, '__call__')) - - def test_scrollbar(self): - # PyGTK compat - adjustment = Gtk.Adjustment() - - hscrollbar = Gtk.HScrollbar() - vscrollbar = Gtk.VScrollbar() - self.assertNotEquals(hscrollbar.props.adjustment, adjustment) - self.assertNotEquals(vscrollbar.props.adjustment, adjustment) - - hscrollbar = Gtk.HScrollbar(adjustment) - vscrollbar = Gtk.VScrollbar(adjustment) - self.assertEquals(hscrollbar.props.adjustment, adjustment) - self.assertEquals(vscrollbar.props.adjustment, adjustment) - - def test_iconview(self): - # PyGTK compat - iconview = Gtk.IconView() - self.assertEquals(iconview.props.model, None) - - model = Gtk.ListStore(str) - iconview = Gtk.IconView(model) - self.assertEquals(iconview.props.model, model) - - def test_toolbutton(self): - # PyGTK compat - button = Gtk.ToolButton() - self.assertEquals(button.props.stock_id, None) - - button = Gtk.ToolButton('gtk-new') - self.assertEquals(button.props.stock_id, 'gtk-new') - - def test_iconset(self): - # PyGTK compat - iconset = Gtk.IconSet() - pixbuf = GdkPixbuf.Pixbuf() - iconset = Gtk.IconSet(pixbuf) - - def test_viewport(self): - # PyGTK compat - vadjustment = Gtk.Adjustment() - hadjustment = Gtk.Adjustment() - - viewport = Gtk.Viewport(hadjustment=hadjustment, - vadjustment=vadjustment) - - self.assertEquals(viewport.props.vadjustment, vadjustment) - self.assertEquals(viewport.props.hadjustment, hadjustment) - - -class TestGio(unittest.TestCase): - def setUp(self): - self.settings = Gio.Settings('org.gnome.test') - # we change the values in the tests, so set them to predictable start - # value - self.settings.reset('test-string') - self.settings.reset('test-array') - - def test_file_enumerator(self): - self.assertEquals(Gio.FileEnumerator, overrides.Gio.FileEnumerator) - f = Gio.file_new_for_path("./") - - iter_info = [] - for info in f.enumerate_children("standard::*", 0, None): - iter_info.append(info.get_name()) - - next_info = [] - enumerator = f.enumerate_children("standard::*", 0, None) - while True: - info = enumerator.next_file(None) - if info is None: - break - next_info.append(info.get_name()) - - self.assertEquals(iter_info, next_info) - - def test_gsettings_native(self): - self.assertTrue('test-array' in self.settings.list_keys()) - - # get various types - v = self.settings.get_value('test-boolean') - self.assertEqual(v.get_boolean(), True) - self.assertEqual(self.settings.get_boolean('test-boolean'), True) - - v = self.settings.get_value('test-string') - self.assertEqual(v.get_string(), 'Hello') - self.assertEqual(self.settings.get_string('test-string'), 'Hello') - - v = self.settings.get_value('test-array') - self.assertEqual(v.unpack(), [1, 2]) - - v = self.settings.get_value('test-tuple') - self.assertEqual(v.unpack(), (1, 2)) - - # set a value - self.settings.set_string('test-string', 'World') - self.assertEqual(self.settings.get_string('test-string'), 'World') - - self.settings.set_value('test-string', GLib.Variant('s', 'Goodbye')) - self.assertEqual(self.settings.get_string('test-string'), 'Goodbye') + 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_gsettings_constructor(self): - # default constructor uses path from schema - self.assertEqual(self.settings.get_property('path'), '/tests/') + @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) - # optional constructor arguments - with_path = Gio.Settings('org.gnome.nopathtest', path='/mypath/') - self.assertEqual(with_path.get_property('path'), '/mypath/') - self.assertEqual(with_path['np-int'], 42) - def test_gsettings_override(self): - # dictionary interface - self.assertEqual(len(self.settings), 4) - self.assertTrue('test-array' in self.settings) - self.assertTrue('test-array' in self.settings.keys()) - self.failIf('nonexisting' in self.settings) - self.failIf(4 in self.settings) - self.assertEqual(bool(self.settings), True) +class TestModule(unittest.TestCase): + # Tests for gi.module - # get various types - self.assertEqual(self.settings['test-boolean'], True) - self.assertEqual(self.settings['test-string'], 'Hello') - self.assertEqual(self.settings['test-array'], [1, 2]) - self.assertEqual(self.settings['test-tuple'], (1, 2)) + 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 - self.assertRaises(KeyError, self.settings.__getitem__, 'unknown') - self.assertRaises(KeyError, self.settings.__getitem__, 2) + # Clear out introspection module cache before running this test. + old_modules = gi.module._introspection_modules + gi.module._introspection_modules = {} - # set a value - self.settings['test-string'] = 'Goodbye' - self.assertEqual(self.settings['test-string'], 'Goodbye') - self.settings['test-array'] = [3, 4, 5] - self.assertEqual(self.settings['test-array'], [3, 4, 5]) + mod_name = 'GIMarshallingTests' + mod1 = gi.module.get_introspection_module(mod_name) + mod2 = gi.module.get_introspection_module(mod_name) + self.assertTrue(mod1 is mod2) - self.assertRaises(TypeError, self.settings.__setitem__, 'test-string', 1) - self.assertRaises(KeyError, self.settings.__setitem__, 'unknown', 'moo') + # 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) - def test_gsettings_empty(self): - empty = Gio.Settings('org.gnome.empty', path='/tests/') - self.assertEqual(len(empty), 0) - self.assertEqual(bool(empty), True) - self.assertEqual(empty.keys(), []) + # Restore the previous cache + gi.module._introspection_modules = old_modules diff --git a/tests/test_overrides_gdk.py b/tests/test_overrides_gdk.py new file mode 100644 index 0000000..46f0a38 --- /dev/null +++ b/tests/test_overrides_gdk.py @@ -0,0 +1,141 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab + +import unittest + +import gi.overrides + +try: + from gi.repository import Gdk, GdkPixbuf, Gtk + Gdk # pyflakes +except ImportError: + Gdk = None + + +@unittest.skipUnless(Gdk, 'Gdk not available') +class TestGdk(unittest.TestCase): + def test_constructor(self): + attribute = Gdk.WindowAttr() + attribute.window_type = Gdk.WindowType.CHILD + attributes_mask = Gdk.WindowAttributesType.X | \ + Gdk.WindowAttributesType.Y + window = Gdk.Window(None, attribute, attributes_mask) + self.assertEqual(window.get_window_type(), Gdk.WindowType.CHILD) + + 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)) + self.assertNotEqual(color, Gdk.Color(1, 2, 3)) + + def test_color_floats(self): + self.assertEqual(Gdk.Color(13107, 21845, 65535), + Gdk.Color.from_floats(0.2, 1.0 / 3.0, 1.0)) + + self.assertEqual(Gdk.Color(13107, 21845, 65535).to_floats(), + (0.2, 1.0 / 3.0, 1.0)) + + self.assertEqual(Gdk.RGBA(0.2, 1.0 / 3.0, 1.0, 0.5).to_color(), + Gdk.Color.from_floats(0.2, 1.0 / 3.0, 1.0)) + + self.assertEqual(Gdk.RGBA.from_color(Gdk.Color(13107, 21845, 65535)), + Gdk.RGBA(0.2, 1.0 / 3.0, 1.0, 1.0)) + + def test_rgba(self): + self.assertEqual(Gdk.RGBA, gi.overrides.Gdk.RGBA) + rgba = Gdk.RGBA(0.1, 0.2, 0.3, 0.4) + self.assertEqual(rgba, Gdk.RGBA(0.1, 0.2, 0.3, 0.4)) + self.assertNotEqual(rgba, Gdk.RGBA(0.0, 0.2, 0.3, 0.4)) + self.assertEqual(rgba.red, 0.1) + self.assertEqual(rgba.green, 0.2) + self.assertEqual(rgba.blue, 0.3) + self.assertEqual(rgba.alpha, 0.4) + rgba.green = 0.9 + self.assertEqual(rgba.green, 0.9) + + # Iterator/tuple convsersion + self.assertEqual(tuple(Gdk.RGBA(0.1, 0.2, 0.3, 0.4)), + (0.1, 0.2, 0.3, 0.4)) + + 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.new(Gdk.EventType.DRAG_MOTION) + event.x_root, event.y_root = 0, 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')) + + def test_event_structures(self): + def button_press_cb(button, event): + self.assertTrue(isinstance(event, Gdk.EventButton)) + self.assertTrue(event.type == Gdk.EventType.BUTTON_PRESS) + self.assertEqual(event.send_event, 0) + self.assertEqual(event.get_state(), Gdk.ModifierType.CONTROL_MASK) + self.assertEqual(event.get_root_coords(), (2, 5)) + + event.time = 12345 + self.assertEqual(event.get_time(), 12345) + + w = Gtk.Window() + b = Gtk.Button() + b.connect('button-press-event', button_press_cb) + w.add(b) + w.show_all() + Gdk.test_simulate_button(b.get_window(), + 2, 5, + 0, + Gdk.ModifierType.CONTROL_MASK, + Gdk.EventType.BUTTON_PRESS) + + def test_cursor(self): + self.assertEqual(Gdk.Cursor, gi.overrides.Gdk.Cursor) + c = Gdk.Cursor(Gdk.CursorType.WATCH) + self.assertNotEqual(c, None) + c = Gdk.Cursor(cursor_type=Gdk.CursorType.WATCH) + self.assertNotEqual(c, None) + + display_manager = Gdk.DisplayManager.get() + display = display_manager.get_default_display() + + test_pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, + False, + 8, + 5, + 10) + + c = Gdk.Cursor(display, + test_pixbuf, + y=0, x=0) + + self.assertNotEqual(c, None) + self.assertRaises(ValueError, Gdk.Cursor, 1, 2, 3) + + 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>') + + 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>') + + 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>') + + def test_color_parse(self): + 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) diff --git a/tests/test_overrides_glib.py b/tests/test_overrides_glib.py new file mode 100644 index 0000000..4d7e63a --- /dev/null +++ b/tests/test_overrides_glib.py @@ -0,0 +1,489 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab + +import unittest + +import gi +from gi.repository import GLib +from compathelper import _long + + +class TestGVariant(unittest.TestCase): + def test_create_simple(self): + variant = GLib.Variant('i', 42) + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertEqual(variant.get_int32(), 42) + + variant = GLib.Variant('s', '') + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertEqual(variant.get_string(), '') + + variant = GLib.Variant('s', 'hello') + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertEqual(variant.get_string(), 'hello') + + def test_create_variant(self): + variant = GLib.Variant('v', GLib.Variant('i', 42)) + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertTrue(isinstance(variant.get_variant(), GLib.Variant)) + self.assertEqual(variant.get_type_string(), 'v') + self.assertEqual(variant.get_variant().get_type_string(), 'i') + self.assertEqual(variant.get_variant().get_int32(), 42) + + variant = GLib.Variant('v', GLib.Variant('v', GLib.Variant('i', 42))) + self.assertEqual(variant.get_type_string(), 'v') + self.assertEqual(variant.get_variant().get_type_string(), 'v') + self.assertEqual(variant.get_variant().get_variant().get_type_string(), 'i') + self.assertEqual(variant.get_variant().get_variant().get_int32(), 42) + + def test_create_tuple(self): + variant = GLib.Variant('()', ()) + self.assertEqual(variant.get_type_string(), '()') + self.assertEqual(variant.n_children(), 0) + + variant = GLib.Variant('(i)', (3,)) + self.assertEqual(variant.get_type_string(), '(i)') + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertEqual(variant.n_children(), 1) + self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) + self.assertEqual(variant.get_child_value(0).get_int32(), 3) + + variant = GLib.Variant('(ss)', ('mec', 'mac')) + self.assertEqual(variant.get_type_string(), '(ss)') + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) + self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) + self.assertEqual(variant.get_child_value(0).get_string(), 'mec') + self.assertEqual(variant.get_child_value(1).get_string(), 'mac') + + # 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))) + + def test_create_dictionary(self): + variant = GLib.Variant('a{si}', {}) + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertEqual(variant.get_type_string(), 'a{si}') + self.assertEqual(variant.n_children(), 0) + + variant = GLib.Variant('a{si}', {'': 1, 'key1': 2, 'key2': 3}) + self.assertEqual(variant.get_type_string(), 'a{si}') + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) + self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) + self.assertTrue(isinstance(variant.get_child_value(2), GLib.Variant)) + self.assertEqual(variant.unpack(), {'': 1, 'key1': 2, 'key2': 3}) + + # nested dictionaries + variant = GLib.Variant('a{sa{si}}', {}) + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertEqual(variant.get_type_string(), 'a{sa{si}}') + self.assertEqual(variant.n_children(), 0) + + d = {'': {'': 1, 'keyn1': 2}, + 'key1': {'key11': 11, 'key12': 12}} + variant = GLib.Variant('a{sa{si}}', d) + self.assertEqual(variant.get_type_string(), 'a{sa{si}}') + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertEqual(variant.unpack(), d) + + def test_create_array(self): + variant = GLib.Variant('ai', []) + self.assertEqual(variant.get_type_string(), 'ai') + self.assertEqual(variant.n_children(), 0) + + variant = GLib.Variant('ai', [1, 2]) + self.assertEqual(variant.get_type_string(), 'ai') + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) + self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) + self.assertEqual(variant.get_child_value(0).get_int32(), 1) + self.assertEqual(variant.get_child_value(1).get_int32(), 2) + + variant = GLib.Variant('as', []) + self.assertEqual(variant.get_type_string(), 'as') + self.assertEqual(variant.n_children(), 0) + + variant = GLib.Variant('as', ['']) + self.assertEqual(variant.get_type_string(), 'as') + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) + self.assertEqual(variant.get_child_value(0).get_string(), '') + + variant = GLib.Variant('as', ['hello', 'world']) + self.assertEqual(variant.get_type_string(), 'as') + self.assertTrue(isinstance(variant, GLib.Variant)) + self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) + self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) + self.assertEqual(variant.get_child_value(0).get_string(), 'hello') + self.assertEqual(variant.get_child_value(1).get_string(), 'world') + + # nested arrays + variant = GLib.Variant('aai', []) + self.assertEqual(variant.get_type_string(), 'aai') + self.assertEqual(variant.n_children(), 0) + + variant = GLib.Variant('aai', [[]]) + self.assertEqual(variant.get_type_string(), 'aai') + self.assertEqual(variant.n_children(), 1) + self.assertEqual(variant.get_child_value(0).n_children(), 0) + + variant = GLib.Variant('aai', [[1, 2], [3, 4, 5]]) + self.assertEqual(variant.get_type_string(), 'aai') + self.assertEqual(variant.unpack(), [[1, 2], [3, 4, 5]]) + + def test_create_complex(self): + variant = GLib.Variant('(as)', ([],)) + self.assertEqual(variant.get_type_string(), '(as)') + self.assertEqual(variant.n_children(), 1) + self.assertEqual(variant.get_child_value(0).n_children(), 0) + + variant = GLib.Variant('(as)', ([''],)) + self.assertEqual(variant.get_type_string(), '(as)') + self.assertEqual(variant.n_children(), 1) + self.assertEqual(variant.get_child_value(0).n_children(), 1) + self.assertEqual(variant.get_child_value(0).get_child_value(0).get_string(), '') + + variant = GLib.Variant('(as)', (['hello'],)) + self.assertEqual(variant.get_type_string(), '(as)') + self.assertEqual(variant.n_children(), 1) + self.assertEqual(variant.get_child_value(0).n_children(), 1) + self.assertEqual(variant.get_child_value(0).get_child_value(0).get_string(), 'hello') + + variant = GLib.Variant('a(ii)', []) + self.assertEqual(variant.get_type_string(), 'a(ii)') + self.assertEqual(variant.n_children(), 0) + + variant = GLib.Variant('a(ii)', [(5, 6)]) + self.assertEqual(variant.get_type_string(), 'a(ii)') + self.assertEqual(variant.n_children(), 1) + self.assertEqual(variant.get_child_value(0).n_children(), 2) + self.assertEqual(variant.get_child_value(0).get_child_value(0).get_int32(), 5) + self.assertEqual(variant.get_child_value(0).get_child_value(1).get_int32(), 6) + + variant = GLib.Variant('(a(ii))', ([],)) + self.assertEqual(variant.get_type_string(), '(a(ii))') + self.assertEqual(variant.n_children(), 1) + self.assertEqual(variant.get_child_value(0).n_children(), 0) + + variant = GLib.Variant('(a(ii))', ([(5, 6)],)) + self.assertEqual(variant.get_type_string(), '(a(ii))') + self.assertEqual(variant.n_children(), 1) + self.assertEqual(variant.get_child_value(0).n_children(), 1) + self.assertEqual(variant.get_child_value(0).get_child_value(0).n_children(), 2) + self.assertEqual(variant.get_child_value(0).get_child_value(0).get_child_value(0).get_int32(), 5) + self.assertEqual(variant.get_child_value(0).get_child_value(0).get_child_value(1).get_int32(), 6) + + obj = {'a1': (1, True), 'a2': (2, False)} + variant = GLib.Variant('a{s(ib)}', obj) + self.assertEqual(variant.get_type_string(), 'a{s(ib)}') + self.assertEqual(variant.unpack(), obj) + + obj = {'a1': (1, GLib.Variant('b', True)), 'a2': (2, GLib.Variant('y', 255))} + variant = GLib.Variant('a{s(iv)}', obj) + self.assertEqual(variant.get_type_string(), 'a{s(iv)}') + self.assertEqual(variant.unpack(), {'a1': (1, True), 'a2': (2, 255)}) + + obj = (1, {'a': {'a1': True, 'a2': False}, + 'b': {'b1': False}, + 'c': {} + }, + 'foo') + variant = GLib.Variant('(ia{sa{sb}}s)', obj) + self.assertEqual(variant.get_type_string(), '(ia{sa{sb}}s)') + self.assertEqual(variant.unpack(), obj) + + obj = {"frequency": GLib.Variant('t', 738000000), + "hierarchy": GLib.Variant('i', 0), + "bandwidth": GLib.Variant('x', 8), + "code-rate-hp": GLib.Variant('d', 2.0 / 3.0), + "constellation": GLib.Variant('s', "QAM16"), + "guard-interval": GLib.Variant('u', 4)} + variant = GLib.Variant('a{sv}', obj) + self.assertEqual(variant.get_type_string(), 'a{sv}') + self.assertEqual(variant.unpack(), + {"frequency": 738000000, + "hierarchy": 0, + "bandwidth": 8, + "code-rate-hp": 2.0 / 3.0, + "constellation": "QAM16", + "guard-interval": 4 + }) + + def test_create_errors(self): + # excess arguments + self.assertRaises(TypeError, GLib.Variant, 'i', 42, 3) + self.assertRaises(TypeError, GLib.Variant, '(i)', (42, 3)) + + # not enough arguments + self.assertRaises(TypeError, GLib.Variant, '(ii)', (42,)) + + # data type mismatch + self.assertRaises(TypeError, GLib.Variant, 'i', 'hello') + self.assertRaises(TypeError, GLib.Variant, 's', 42) + 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 types + self.assertRaises(TypeError, GLib.Variant, '(ii', (42, 3)) + self.assertRaises(TypeError, GLib.Variant, '(ii))', (42, 3)) + self.assertRaises(TypeError, GLib.Variant, 'a{si', {}) + self.assertRaises(TypeError, GLib.Variant, 'a{si}}', {}) + self.assertRaises(TypeError, GLib.Variant, 'a{iii}', {}) + + def test_unpack(self): + # simple values + res = GLib.Variant.new_int32(-42).unpack() + self.assertEqual(res, -42) + + res = GLib.Variant.new_uint64(34359738368).unpack() + self.assertEqual(res, 34359738368) + + res = GLib.Variant.new_boolean(True).unpack() + self.assertEqual(res, True) + + res = GLib.Variant.new_object_path('/foo/Bar').unpack() + self.assertEqual(res, '/foo/Bar') + + # variant + res = GLib.Variant('v', GLib.Variant.new_int32(-42)).unpack() + self.assertEqual(res, -42) + + GLib.Variant('v', GLib.Variant('v', GLib.Variant('i', 42))) + self.assertEqual(res, -42) + + # tuple + res = GLib.Variant.new_tuple(GLib.Variant.new_int32(-1), + GLib.Variant.new_string('hello')).unpack() + self.assertEqual(res, (-1, 'hello')) + + # array + vb = GLib.VariantBuilder.new(gi._gi.variant_type_from_string('ai')) + vb.add_value(GLib.Variant.new_int32(-1)) + vb.add_value(GLib.Variant.new_int32(3)) + res = vb.end().unpack() + self.assertEqual(res, [-1, 3]) + + # dictionary + res = GLib.Variant('a{si}', {'key1': 1, 'key2': 2}).unpack() + 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) + + def test_iteration(self): + # array index access + vb = GLib.VariantBuilder.new(gi._gi.variant_type_from_string('ai')) + vb.add_value(GLib.Variant.new_int32(-1)) + vb.add_value(GLib.Variant.new_int32(3)) + v = vb.end() + + self.assertEqual(len(v), 2) + self.assertEqual(v[0], -1) + self.assertEqual(v[1], 3) + self.assertEqual(v[-1], 3) + self.assertEqual(v[-2], -1) + self.assertRaises(IndexError, v.__getitem__, 2) + self.assertRaises(IndexError, v.__getitem__, -3) + self.assertRaises(ValueError, v.__getitem__, 'a') + + # array iteration + self.assertEqual([x for x in v], [-1, 3]) + self.assertEqual(list(v), [-1, 3]) + + # tuple index access + v = GLib.Variant.new_tuple(GLib.Variant.new_int32(-1), + GLib.Variant.new_string('hello')) + self.assertEqual(len(v), 2) + self.assertEqual(v[0], -1) + self.assertEqual(v[1], 'hello') + self.assertEqual(v[-1], 'hello') + self.assertEqual(v[-2], -1) + self.assertRaises(IndexError, v.__getitem__, 2) + self.assertRaises(IndexError, v.__getitem__, -3) + self.assertRaises(ValueError, v.__getitem__, 'a') + + # tuple iteration + self.assertEqual([x for x in v], [-1, 'hello']) + self.assertEqual(tuple(v), (-1, 'hello')) + + # dictionary index access + vsi = GLib.Variant('a{si}', {'key1': 1, 'key2': 2}) + vis = GLib.Variant('a{is}', {1: 'val1', 5: 'val2'}) + + self.assertEqual(len(vsi), 2) + self.assertEqual(vsi['key1'], 1) + self.assertEqual(vsi['key2'], 2) + self.assertRaises(KeyError, vsi.__getitem__, 'unknown') + + self.assertEqual(len(vis), 2) + self.assertEqual(vis[1], 'val1') + self.assertEqual(vis[5], 'val2') + self.assertRaises(KeyError, vsi.__getitem__, 3) + + # dictionary iteration + self.assertEqual(set(vsi.keys()), set(['key1', 'key2'])) + self.assertEqual(set(vis.keys()), set([1, 5])) + + # string index access + v = GLib.Variant('s', 'hello') + self.assertEqual(len(v), 5) + self.assertEqual(v[0], 'h') + self.assertEqual(v[4], 'o') + self.assertEqual(v[-1], 'o') + self.assertEqual(v[-5], 'h') + self.assertRaises(IndexError, v.__getitem__, 5) + self.assertRaises(IndexError, v.__getitem__, -6) + + # string iteration + self.assertEqual([x for x in v], ['h', 'e', 'l', 'l', 'o']) + + def test_split_signature(self): + self.assertEqual(GLib.Variant.split_signature('()'), []) + + self.assertEqual(GLib.Variant.split_signature('s'), ['s']) + + self.assertEqual(GLib.Variant.split_signature('as'), ['as']) + + self.assertEqual(GLib.Variant.split_signature('(s)'), ['s']) + + self.assertEqual(GLib.Variant.split_signature('(iso)'), ['i', 's', 'o']) + + self.assertEqual(GLib.Variant.split_signature('(s(ss)i(ii))'), + ['s', '(ss)', 'i', '(ii)']) + + self.assertEqual(GLib.Variant.split_signature('(as)'), ['as']) + + self.assertEqual(GLib.Variant.split_signature('(s(ss)iaiaasa(ii))'), + ['s', '(ss)', 'i', 'ai', 'aas', 'a(ii)']) + + self.assertEqual(GLib.Variant.split_signature('(a{iv}(ii)((ss)a{s(ss)}))'), + ['a{iv}', '(ii)', '((ss)a{s(ss)})']) + + def test_hash(self): + v1 = GLib.Variant('s', 'somestring') + v2 = GLib.Variant('s', 'somestring') + v3 = GLib.Variant('s', 'somestring2') + + self.assertTrue(v2 in set([v1, v3])) + self.assertTrue(v2 in frozenset([v1, v3])) + self.assertTrue(v2 in {v1: '1', v3: '2'}) + + def test_compare(self): + # Check if identical GVariant are equal + + def assert_equal(vtype, value): + self.assertEqual(GLib.Variant(vtype, value), GLib.Variant(vtype, value)) + + def assert_not_equal(vtype1, value1, vtype2, value2): + self.assertNotEqual(GLib.Variant(vtype1, value1), GLib.Variant(vtype2, value2)) + + numbers = ['y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd'] + for num in numbers: + assert_equal(num, 42) + assert_not_equal(num, 42, num, 41) + assert_not_equal(num, 42, 's', '42') + + assert_equal('s', 'something') + assert_not_equal('s', 'something', 's', 'somethingelse') + assert_not_equal('s', 'something', 'i', 1234) + + assert_equal('g', 'dustybinqhogx') + assert_not_equal('g', 'dustybinqhogx', 'g', 'dustybin') + assert_not_equal('g', 'dustybinqhogx', 'i', 1234) + + assert_equal('o', '/dev/null') + assert_not_equal('o', '/dev/null', 'o', '/dev/zero') + assert_not_equal('o', '/dev/null', 'i', 1234) + + assert_equal('(s)', ('strtuple',)) + assert_not_equal('(s)', ('strtuple',), '(s)', ('strtuple2',)) + + assert_equal('a{si}', {'str': 42}) + assert_not_equal('a{si}', {'str': 42}, 'a{si}', {'str': 43}) + + assert_equal('v', GLib.Variant('i', 42)) + assert_not_equal('v', GLib.Variant('i', 42), 'v', GLib.Variant('i', 43)) + + def test_bool(self): + # Check if the GVariant bool matches the unpacked Pythonic bool + + def assert_equals_bool(vtype, value): + self.assertEqual(bool(GLib.Variant(vtype, value)), bool(value)) + + # simple values + assert_equals_bool('b', True) + assert_equals_bool('b', False) + + numbers = ['y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd'] + for number in numbers: + assert_equals_bool(number, 0) + assert_equals_bool(number, 1) + + assert_equals_bool('s', '') + assert_equals_bool('g', '') + assert_equals_bool('s', 'something') + assert_equals_bool('o', '/dev/null') + assert_equals_bool('g', 'dustybinqhogx') + + # arrays + assert_equals_bool('ab', [True]) + assert_equals_bool('ab', [False]) + for number in numbers: + assert_equals_bool('a' + number, []) + assert_equals_bool('a' + number, [0]) + assert_equals_bool('as', []) + assert_equals_bool('as', ['']) + assert_equals_bool('ao', []) + assert_equals_bool('ao', ['/']) + assert_equals_bool('ag', []) + assert_equals_bool('ag', ['']) + assert_equals_bool('aai', [[]]) + + # tuples + assert_equals_bool('()', ()) + for number in numbers: + assert_equals_bool('(' + number + ')', (0,)) + assert_equals_bool('(s)', ('',)) + assert_equals_bool('(o)', ('/',)) + assert_equals_bool('(g)', ('',)) + assert_equals_bool('(())', ((),)) + + # dictionaries + assert_equals_bool('a{si}', {}) + assert_equals_bool('a{si}', {'': 0}) + + # complex types, always True + assert_equals_bool('(as)', ([],)) + assert_equals_bool('a{s(i)}', {'': (0,)}) + + # variant types, recursive unpacking + assert_equals_bool('v', GLib.Variant('i', 0)) + assert_equals_bool('v', GLib.Variant('i', 1)) + + def test_repr(self): + # with C constructor + v = GLib.Variant.new_uint32(42) + self.assertEqual(repr(v), "GLib.Variant('u', 42)") + + # with override constructor + v = GLib.Variant('(is)', (1, 'somestring')) + self.assertEqual(repr(v), "GLib.Variant('(is)', (1, 'somestring'))") + + def test_str(self): + # with C constructor + v = GLib.Variant.new_uint32(42) + self.assertEqual(str(v), 'uint32 42') + + # with override constructor + v = GLib.Variant('(is)', (1, 'somestring')) + self.assertEqual(str(v), "(1, 'somestring')") diff --git a/tests/test_overrides_gtk.py b/tests/test_overrides_gtk.py new file mode 100644 index 0000000..fbe51ec --- /dev/null +++ b/tests/test_overrides_gtk.py @@ -0,0 +1,1748 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# coding: UTF-8 +# vim: tabstop=4 shiftwidth=4 expandtab + +import contextlib +import unittest +import time +import sys + +from compathelper import _unicode, _bytes + +import gi.overrides +import gi.types +from gi.repository import GLib, GObject + +try: + from gi.repository import GdkPixbuf, Gdk, Gtk + Gtk # pyflakes +except ImportError: + Gtk = None + + +@contextlib.contextmanager +def realized(widget): + """Makes sure the widget is realized. + + view = Gtk.TreeView() + with realized(view): + do_something(view) + """ + + if isinstance(widget, Gtk.Window): + toplevel = widget + else: + toplevel = widget.get_parent_window() + + if toplevel is None: + window = Gtk.Window() + window.add(widget) + + widget.realize() + while Gtk.events_pending(): + Gtk.main_iteration() + assert widget.get_realized() + yield widget + + if toplevel is None: + window.remove(widget) + window.destroy() + + while Gtk.events_pending(): + Gtk.main_iteration() + + +@unittest.skipUnless(Gtk, 'Gtk not available') +class TestGtk(unittest.TestCase): + def test_container(self): + box = Gtk.Box() + self.assertTrue(isinstance(box, Gtk.Box)) + self.assertTrue(isinstance(box, Gtk.Container)) + self.assertTrue(isinstance(box, Gtk.Widget)) + self.assertTrue(box) + label = Gtk.Label() + label2 = Gtk.Label() + box.add(label) + box.add(label2) + self.assertTrue(label in box) + self.assertTrue(label2 in box) + self.assertEqual(len(box), 2) + self.assertTrue(box) + l = [x for x in box] + self.assertEqual(l, [label, label2]) + + 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) + 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) + 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) + + 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" + + def test_action_callback_data(action, user_data): + self.assertEqual(user_data, callback_data) + + def test_radio_action_callback_data(action, current, user_data): + self.assertEqual(user_data, callback_data) + + action_group.add_actions([ + ('test-action1', None, 'Test Action 1', + None, None, test_action_callback_data), + ('test-action2', Gtk.STOCK_COPY, 'Test Action 2', + None, None, test_action_callback_data)], callback_data) + action_group.add_toggle_actions([ + ('test-toggle-action1', None, 'Test Toggle Action 1', + None, None, test_action_callback_data, False), + ('test-toggle-action2', Gtk.STOCK_COPY, 'Test Toggle Action 2', + None, None, test_action_callback_data, True)], callback_data) + action_group.add_radio_actions([ + ('test-radio-action1', None, 'Test Radio Action 1'), + ('test-radio-action2', Gtk.STOCK_COPY, 'Test Radio Action 2')], 1, + test_radio_action_callback_data, + callback_data) + + expected_results = [('test-action1', Gtk.Action), + ('test-action2', Gtk.Action), + ('test-toggle-action1', Gtk.ToggleAction), + ('test-toggle-action2', Gtk.ToggleAction), + ('test-radio-action1', Gtk.RadioAction), + ('test-radio-action2', Gtk.RadioAction)] + + for action in action_group.list_actions(): + a = (action.get_name(), type(action)) + self.assertTrue(a in expected_results) + expected_results.remove(a) + action.activate() + + 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) + + ag = Gtk.ActionGroup(name="ag1") + ui.insert_action_group(ag) + ag2 = Gtk.ActionGroup(name="ag2") + ui.insert_action_group(ag2) + groups = ui.get_action_groups() + self.assertEqual(ag, groups[-2]) + self.assertEqual(ag2, groups[-1]) + + 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): + # standard Window + w = Gtk.Window() + self.assertEqual(w.get_property('type'), Gtk.WindowType.TOPLEVEL) + + # type works as keyword argument + 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" + + # works from builder + builder = Gtk.Builder() + builder.add_from_string(''' +<interface> + <object class="GtkWindow" id="win"> + <property name="type">popup</property> + </object> + <object class="TestWindow" id="testwin"> + </object> + <object class="TestWindow" id="testpop"> + <property name="type">popup</property> + </object> +</interface>''') + self.assertEqual(builder.get_object('win').get_property('type'), + Gtk.WindowType.POPUP) + self.assertEqual(builder.get_object('testwin').get_property('type'), + Gtk.WindowType.TOPLEVEL) + self.assertEqual(builder.get_object('testpop').get_property('type'), + Gtk.WindowType.POPUP) + + def test_dialogs(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)) + 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()) + 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()) + + # Gtk.AboutDialog + dialog = Gtk.AboutDialog() + self.assertTrue(isinstance(dialog, Gtk.Dialog)) + self.assertTrue(isinstance(dialog, Gtk.Window)) + + # Gtk.MessageDialog + dialog = Gtk.MessageDialog(title='message dialog test', + flags=Gtk.DialogFlags.MODAL, + buttons=Gtk.ButtonsType.OK, + message_format='dude!') + self.assertTrue(isinstance(dialog, Gtk.Dialog)) + self.assertTrue(isinstance(dialog, Gtk.Window)) + + self.assertEqual('message dialog test', dialog.get_title()) + self.assertTrue(dialog.get_modal()) + 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')) + + 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") + self.assertTrue(isinstance(dialog, Gtk.Dialog)) + self.assertTrue(isinstance(dialog, Gtk.Window)) + self.assertEqual('color selection dialog test', dialog.get_title()) + + # Gtk.FileChooserDialog + # 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: + 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") + self.assertTrue(isinstance(dialog, Gtk.Dialog)) + self.assertTrue(isinstance(dialog, Gtk.Window)) + self.assertEqual('font selection dialog test', dialog.get_title()) + + # Gtk.RecentChooserDialog + test_manager = Gtk.RecentManager() + dialog = Gtk.RecentChooserDialog(title='recent chooser dialog test', + buttons=('test-button1', 1), + 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" + + def __init__(self, tester, int_value, string_value): + super(TestGtk.TestClass, self).__init__() + self.tester = tester + self.int_value = int_value + self.string_value = string_value + + def check(self, int_value, string_value): + self.tester.assertEqual(int_value, self.int_value) + self.tester.assertEqual(string_value, self.string_value) + + def test_buttons(self): + 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)) + 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()) + + # test Gtk.LinkButton + self.assertRaises(TypeError, Gtk.LinkButton) + button = Gtk.LinkButton('http://www.Gtk.org', 'Gtk') + self.assertTrue(isinstance(button, Gtk.Button)) + 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()) + + def test_inheritance(self): + for name in gi.overrides.Gtk.__all__: + over = getattr(gi.overrides.Gtk, name) + for element in dir(Gtk): + try: + klass = getattr(Gtk, element) + info = klass.__info__ + except (NotImplementedError, AttributeError): + continue + + # Get all parent classes and interfaces klass inherits from + if isinstance(info, gi.types.ObjectInfo): + classes = list(info.get_interfaces()) + parent = info.get_parent() + while parent.get_name() != "Object": + classes.append(parent) + parent = parent.get_parent() + classes = [kl for kl in classes if kl.get_namespace() == "Gtk"] + else: + continue + + for kl in classes: + if kl.get_name() == name: + self.assertTrue(issubclass(klass, over,), + "%r does not inherit from override %r" % (klass, over,)) + + def test_editable(self): + self.assertEqual(Gtk.Editable, gi.overrides.Gtk.Editable) + + # need to use Gtk.Entry because Editable is an interface + entry = Gtk.Entry() + pos = entry.insert_text('HeWorld', 0) + self.assertEqual(pos, 7) + pos = entry.insert_text('llo ', 2) + self.assertEqual(pos, 6) + text = entry.get_chars(0, 11) + self.assertEqual('Hello World', text) + + def test_label(self): + label = Gtk.Label(label='Hello') + self.assertTrue(isinstance(label, Gtk.Widget)) + self.assertEqual(label.get_text(), 'Hello') + + def adjustment_check(self, adjustment, value=0.0, lower=0.0, upper=0.0, + step_increment=0.0, page_increment=0.0, page_size=0.0): + self.assertEqual(adjustment.get_value(), value) + self.assertEqual(adjustment.get_lower(), lower) + self.assertEqual(adjustment.get_upper(), upper) + self.assertEqual(adjustment.get_step_increment(), step_increment) + self.assertEqual(adjustment.get_page_increment(), page_increment) + 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(1, 0, 6, 4, 5) + self.adjustment_check(adjustment, 1, 0, 6, 4, 5) + + adjustment = Gtk.Adjustment(1, 0, 6, 4) + self.adjustment_check(adjustment, 1, 0, 6, 4) + + adjustment = Gtk.Adjustment(1, 0, 6) + self.adjustment_check(adjustment, 1, 0, 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) + + def test_table(self): + table = Gtk.Table() + self.assertTrue(isinstance(table, Gtk.Table)) + 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) + 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) + + label = Gtk.Label(label='Hello') + self.assertTrue(isinstance(label, Gtk.Widget)) + table.attach(label, 0, 1, 0, 1) + self.assertEqual(label, table.get_children()[0]) + + def test_scrolledwindow(self): + sw = Gtk.ScrolledWindow() + self.assertTrue(isinstance(sw, Gtk.ScrolledWindow)) + 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()) + + def test_widget_drag_methods(self): + widget = Gtk.Button() + + # here we are not checking functionality, only that the methods exist + # and except the right number of arguments + + widget.drag_check_threshold(0, 0, 0, 0) + + # drag_dest_ methods + widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY) + widget.drag_dest_add_image_targets() + widget.drag_dest_add_text_targets() + widget.drag_dest_add_uri_targets() + 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(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)])) + widget.drag_dest_unset() + + widget.drag_highlight() + widget.drag_unhighlight() + + # drag_source_ methods + widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE) + 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_pixbuf(GdkPixbuf.Pixbuf()) + widget.drag_source_set_icon_stock("") + widget.drag_source_get_target_list() + widget.drag_source_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)])) + widget.drag_source_unset() + + # these methods cannot be called because they require a valid drag on + # a real GdkWindow. So we only check that they exist and are callable. + self.assertTrue(hasattr(widget, 'drag_dest_set_proxy')) + self.assertTrue(hasattr(widget, 'drag_get_data')) + + def test_drag_target_list(self): + mixed_target_list = [Gtk.TargetEntry.new('test0', 0, 0), + ('test1', 1, 1), + Gtk.TargetEntry.new('test2', 2, 2), + ('test3', 3, 3)] + + def _test_target_list(targets): + for i, target in enumerate(targets): + self.assertTrue(isinstance(target, Gtk.TargetEntry)) + self.assertEqual(target.target, 'test' + str(i)) + self.assertEqual(target.flags, i) + self.assertEqual(target.info, i) + + _test_target_list(Gtk._construct_target_list(mixed_target_list)) + + widget = Gtk.Button() + widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY) + widget.drag_dest_set_target_list(mixed_target_list) + widget.drag_dest_get_target_list() + + widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE) + widget.drag_source_set_target_list(mixed_target_list) + widget.drag_source_get_target_list() + + treeview = Gtk.TreeView() + treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, + mixed_target_list, + Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE) + + treeview.enable_model_drag_dest(mixed_target_list, + Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE) + + def test_scrollbar(self): + # PyGTK compat + adjustment = Gtk.Adjustment() + + hscrollbar = Gtk.HScrollbar() + vscrollbar = Gtk.VScrollbar() + self.assertNotEqual(hscrollbar.props.adjustment, adjustment) + self.assertNotEqual(vscrollbar.props.adjustment, adjustment) + + hscrollbar = Gtk.HScrollbar(adjustment) + vscrollbar = Gtk.VScrollbar(adjustment) + self.assertEqual(hscrollbar.props.adjustment, adjustment) + self.assertEqual(vscrollbar.props.adjustment, adjustment) + + def test_iconview(self): + # PyGTK compat + iconview = Gtk.IconView() + self.assertEqual(iconview.props.model, None) + + model = Gtk.ListStore(str) + iconview = Gtk.IconView(model) + self.assertEqual(iconview.props.model, model) + + 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') + + 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) + + def test_iconset(self): + # PyGTK compat + Gtk.IconSet() + pixbuf = GdkPixbuf.Pixbuf() + Gtk.IconSet(pixbuf) + + def test_viewport(self): + # PyGTK compat + vadjustment = Gtk.Adjustment() + hadjustment = Gtk.Adjustment() + + viewport = Gtk.Viewport(hadjustment=hadjustment, + vadjustment=vadjustment) + + self.assertEqual(viewport.props.vadjustment, vadjustment) + self.assertEqual(viewport.props.hadjustment, hadjustment) + + def test_stock_lookup(self): + l = Gtk.stock_lookup('gtk-ok') + self.assertEqual(type(l), Gtk.StockItem) + self.assertEqual(l.stock_id, 'gtk-ok') + self.assertEqual(Gtk.stock_lookup('nosuchthing'), None) + + def test_gtk_main(self): + # with no arguments + GLib.timeout_add(100, Gtk.main_quit) + Gtk.main() + + # overridden function ignores its arguments + GLib.timeout_add(100, Gtk.main_quit, 'hello') + Gtk.main() + + +@unittest.skipUnless(Gtk, 'Gtk not available') +class TestSignals(unittest.TestCase): + class WindowWithSizeAllocOverride(Gtk.ScrolledWindow): + __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, alloc): + self._alloc_called = True + self._alloc_value = alloc + + try: + Gtk.ScrolledWindow.do_size_allocate(self, alloc) + except Exception as e: + self._alloc_error = e + + def test_class_closure_override_with_aliased_type(self): + win = self.WindowWithSizeAllocOverride() + rect = Gdk.Rectangle() + rect.width = 100 + rect.height = 100 + + with realized(win): + win.show() + win.size_allocate(rect) + self.assertTrue(win._alloc_called) + self.assertIsInstance(win._alloc_value, Gdk.Rectangle) + self.assertTrue(win._alloc_error is None, win._alloc_error) + + +@unittest.skipUnless(Gtk, 'Gtk not available') +class TestBuilder(unittest.TestCase): + class SignalTest(GObject.GObject): + __gtype_name__ = "GIOverrideSignalTest" + __gsignals__ = { + "test-signal": (GObject.SignalFlags.RUN_FIRST, + None, + []), + } + + def test_extract_handler_and_args_object(self): + class Obj(): + pass + + obj = Obj() + obj.foo = lambda: None + + handler, args = Gtk.Builder._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') + 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') + 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, + obj, 'not_a_handler') + + def test_builder_with_handler_and_args(self): + builder = Gtk.Builder() + builder.add_from_string(""" + <interface> + <object class="GIOverrideSignalTest" id="object_sig_test"> + <signal name="test-signal" handler="on_signal1" /> + <signal name="test-signal" handler="on_signal2" after="yes" /> + </object> + </interface> + """) + + args_collector = [] + + def on_signal(*args): + args_collector.append(args) + + builder.connect_signals({'on_signal1': (on_signal, 1, 2), + 'on_signal2': on_signal}) + + objects = builder.get_objects() + self.assertEqual(len(objects), 1) + obj, = objects + obj.emit('test-signal') + + self.assertEqual(len(args_collector), 2) + self.assertSequenceEqual(args_collector[0], (obj, 1, 2)) + self.assertSequenceEqual(args_collector[1], (obj, )) + + def test_builder(self): + self.assertEqual(Gtk.Builder, gi.overrides.Gtk.Builder) + + class SignalCheck: + def __init__(self): + self.sentinel = 0 + self.after_sentinel = 0 + + def on_signal_1(self, *args): + self.sentinel += 1 + self.after_sentinel += 1 + + def on_signal_3(self, *args): + self.sentinel += 3 + + def on_signal_after(self, *args): + if self.after_sentinel == 1: + self.after_sentinel += 1 + + signal_checker = SignalCheck() + builder = Gtk.Builder() + + # add object1 to the builder + builder.add_from_string(""" +<interface> + <object class="GIOverrideSignalTest" id="object1"> + <signal name="test-signal" after="yes" handler="on_signal_after" /> + <signal name="test-signal" handler="on_signal_1" /> + </object> +</interface> +""") + + # only add object3 to the builder + builder.add_objects_from_string(""" +<interface> + <object class="GIOverrideSignalTest" id="object2"> + <signal name="test-signal" handler="on_signal_2" /> + </object> + <object class="GIOverrideSignalTest" id="object3"> + <signal name="test-signal" handler="on_signal_3" /> + </object> + <object class="GIOverrideSignalTest" id="object4"> + <signal name="test-signal" handler="on_signal_4" /> + </object> +</interface> +""", ['object3']) + + # hook up signals + builder.connect_signals(signal_checker) + + # call their notify signals and check sentinel + objects = builder.get_objects() + self.assertEqual(len(objects), 2) + for obj in objects: + obj.emit('test-signal') + + self.assertEqual(signal_checker.sentinel, 4) + self.assertEqual(signal_checker.after_sentinel, 2) + + +@unittest.skipUnless(Gtk, 'Gtk not available') +class TestTreeModel(unittest.TestCase): + def test_tree_model_sort(self): + self.assertEqual(Gtk.TreeModelSort, gi.overrides.Gtk.TreeModelSort) + self.assertRaises(TypeError, Gtk.TreeModelSort) + model = Gtk.TreeStore(int, bool) + model_sort = Gtk.TreeModelSort(model) + self.assertEqual(model_sort.get_model(), model) + + def test_tree_store(self): + self.assertEqual(Gtk.TreeStore, gi.overrides.Gtk.TreeStore) + self.assertEqual(Gtk.ListStore, gi.overrides.Gtk.ListStore) + self.assertEqual(Gtk.TreeModel, gi.overrides.Gtk.TreeModel) + self.assertEqual(Gtk.TreeViewColumn, gi.overrides.Gtk.TreeViewColumn) + + class TestPyObject(object): + pass + + test_pyobj = TestPyObject() + test_pydict = {1: 1, "2": 2, "3": "3"} + test_pylist = [1, "2", "3"] + tree_store = Gtk.TreeStore(int, + 'gchararray', + TestGtk.TestClass, + GObject.TYPE_PYOBJECT, + object, + object, + object, + bool, + bool, + GObject.TYPE_UINT, + GObject.TYPE_ULONG, + GObject.TYPE_INT64, + GObject.TYPE_UINT64, + GObject.TYPE_UCHAR, + GObject.TYPE_CHAR) + + parent = None + for i in range(97): + label = 'this is child #%d' % i + testobj = TestGtk.TestClass(self, i, label) + parent = tree_store.append(parent, (i, + label, + testobj, + testobj, + test_pyobj, + test_pydict, + test_pylist, + i % 2, + bool(i % 2), + i, + GObject.G_MAXULONG, + GObject.G_MININT64, + 0xffffffffffffffff, + 254, + _bytes('a') + )) + # test set + parent = tree_store.append(parent) + i = 97 + label = 'this is child #%d' % i + testobj = TestGtk.TestClass(self, i, label) + tree_store.set(parent, + 0, i, + 2, testobj, + 1, label, + 3, testobj, + 4, test_pyobj, + 5, test_pydict, + 6, test_pylist, + 7, i % 2, + 8, bool(i % 2), + 9, i, + 10, GObject.G_MAXULONG, + 11, GObject.G_MININT64, + 12, 0xffffffffffffffff, + 13, 254, + 14, _bytes('a')) + + parent = tree_store.append(parent) + i = 98 + label = 'this is child #%d' % i + testobj = TestGtk.TestClass(self, i, label) + tree_store.set(parent, {0: i, + 2: testobj, + 1: label, + 3: testobj, + 4: test_pyobj, + 5: test_pydict, + 6: test_pylist, + 7: i % 2, + 8: bool(i % 2), + 9: i, + 10: GObject.G_MAXULONG, + 11: GObject.G_MININT64, + 12: 0xffffffffffffffff, + 13: 254, + 14: _bytes('a')}) + + parent = tree_store.append(parent) + i = 99 + label = 'this is child #%d' % i + testobj = TestGtk.TestClass(self, i, label) + tree_store.set(parent, (0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14), + (i, + testobj, + label, + testobj, + test_pyobj, + test_pydict, + test_pylist, + i % 2, + bool(i % 2), + i, + GObject.G_MAXULONG, + GObject.G_MININT64, + 0xffffffffffffffff, + 254, + _bytes('a'))) + + # len gets the number of children in the root node + # since we kept appending to the previous node + # there should only be one child of the root + self.assertEqual(len(tree_store), 1) + + # walk the tree to see if the values were stored correctly + parent = None + i = 0 + + treeiter = tree_store.iter_children(parent) + while treeiter: + i = tree_store.get_value(treeiter, 0) + s = tree_store.get_value(treeiter, 1) + obj = tree_store.get_value(treeiter, 2) + obj.check(i, s) + obj2 = tree_store.get_value(treeiter, 3) + self.assertEqual(obj, obj2) + + pyobj = tree_store.get_value(treeiter, 4) + self.assertEqual(pyobj, test_pyobj) + pydict = tree_store.get_value(treeiter, 5) + self.assertEqual(pydict, test_pydict) + pylist = tree_store.get_value(treeiter, 6) + self.assertEqual(pylist, test_pylist) + + bool_1 = tree_store.get_value(treeiter, 7) + bool_2 = tree_store.get_value(treeiter, 8) + self.assertEqual(bool_1, bool_2) + self.assertTrue(isinstance(bool_1, bool)) + self.assertTrue(isinstance(bool_2, bool)) + + uint_ = tree_store.get_value(treeiter, 9) + self.assertEqual(uint_, i) + ulong_ = tree_store.get_value(treeiter, 10) + self.assertEqual(ulong_, GObject.G_MAXULONG) + int64_ = tree_store.get_value(treeiter, 11) + self.assertEqual(int64_, GObject.G_MININT64) + uint64_ = tree_store.get_value(treeiter, 12) + self.assertEqual(uint64_, 0xffffffffffffffff) + uchar_ = tree_store.get_value(treeiter, 13) + self.assertEqual(ord(uchar_), 254) + char_ = tree_store.get_value(treeiter, 14) + self.assertEqual(char_, 'a') + + parent = treeiter + treeiter = tree_store.iter_children(parent) + + self.assertEqual(i, 99) + + def test_tree_store_signals(self): + tree_store = Gtk.TreeStore(int, bool) + + def on_row_inserted(tree_store, tree_path, tree_iter, signal_list): + signal_list.append('row-inserted') + + def on_row_changed(tree_store, tree_path, tree_iter, signal_list): + signal_list.append('row-changed') + + signals = [] + tree_store.connect('row-inserted', on_row_inserted, signals) + tree_store.connect('row-changed', on_row_changed, signals) + + # adding rows with and without data should only call one signal + tree_store.append(None, (0, False)) + self.assertEqual(signals, ['row-inserted']) + + signals.pop() + tree_store.append(None) + self.assertEqual(signals, ['row-inserted']) + + signals.pop() + tree_store.prepend(None, (0, False)) + self.assertEqual(signals, ['row-inserted']) + + signals.pop() + tree_store.prepend(None) + self.assertEqual(signals, ['row-inserted']) + + signals.pop() + tree_store.insert(None, 1, (0, False)) + self.assertEqual(signals, ['row-inserted']) + + signals.pop() + tree_store.insert(None, 1) + self.assertEqual(signals, ['row-inserted']) + + def test_list_store(self): + class TestPyObject(object): + pass + + test_pyobj = TestPyObject() + test_pydict = {1: 1, "2": 2, "3": "3"} + test_pylist = [1, "2", "3"] + + list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest', object, object, object, bool, bool) + for i in range(1, 93): + label = 'this is row #%d' % i + testobj = TestGtk.TestClass(self, i, label) + list_store.append((i, + label, + testobj, + test_pyobj, + test_pydict, + test_pylist, + i % 2, + bool(i % 2))) + + i = 93 + label = _unicode('this is row #93') + treeiter = list_store.append() + list_store.set_value(treeiter, 0, i) + list_store.set_value(treeiter, 1, label) + list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label)) + list_store.set_value(treeiter, 3, test_pyobj) + list_store.set_value(treeiter, 4, test_pydict) + list_store.set_value(treeiter, 5, test_pylist) + list_store.set_value(treeiter, 6, 1) + list_store.set_value(treeiter, 7, True) + + # test prepend + label = 'this is row #0' + list_store.prepend((0, + label, + TestGtk.TestClass(self, 0, label), + test_pyobj, + test_pydict, + test_pylist, + 0, + False)) + + # test automatic unicode->str conversion + i = 94 + label = _unicode('this is row #94') + treeiter = list_store.append((i, + label, + TestGtk.TestClass(self, i, label), + test_pyobj, + test_pydict, + test_pylist, + 0, + False)) + + # add sorted items out of order to test insert* apis + # also test sending in None to not set a column + i = 97 + label = 'this is row #97' + treeiter = list_store.append((None, + None, + None, + test_pyobj, + None, + test_pylist, + 1, + None)) + + list_store.set_value(treeiter, 0, i) + list_store.set_value(treeiter, 1, label) + list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label)) + list_store.set_value(treeiter, 4, test_pydict) + list_store.set_value(treeiter, 7, True) + + # this should append + i = 99 + label = 'this is row #99' + list_store.insert(9999, (i, + label, + TestGtk.TestClass(self, i, label), + test_pyobj, + test_pydict, + test_pylist, + 1, + True)) + + i = 96 + label = 'this is row #96' + list_store.insert_before(treeiter, (i, + label, + TestGtk.TestClass(self, i, label), + test_pyobj, + test_pydict, + test_pylist, + 0, + False)) + + i = 98 + label = 'this is row #98' + list_store.insert_after(treeiter, (i, + label, + TestGtk.TestClass(self, i, label), + test_pyobj, + test_pydict, + test_pylist, + 0, + False)) + + i = 95 + label = 'this is row #95' + list_store.insert(95, (i, + label, + TestGtk.TestClass(self, i, label), + test_pyobj, + test_pydict, + test_pylist, + 1, + True)) + + i = 100 + label = 'this is row #100' + treeiter = list_store.append() + list_store.set(treeiter, + 1, label, + 0, i, + 2, TestGtk.TestClass(self, i, label), + 3, test_pyobj, + 4, test_pydict, + 5, test_pylist, + 6, 0, + 7, False) + i = 101 + label = 'this is row #101' + treeiter = list_store.append() + list_store.set(treeiter, {1: label, + 0: i, + 2: TestGtk.TestClass(self, i, label), + 3: test_pyobj, + 4: test_pydict, + 5: test_pylist, + 6: 1, + 7: True}) + i = 102 + label = 'this is row #102' + treeiter = list_store.append() + list_store.set(treeiter, (1, 0, 2, 3, 4, 5, 6, 7), + (label, + i, + TestGtk.TestClass(self, i, label), + test_pyobj, + test_pydict, + test_pylist, + 0, + False)) + + self.assertEqual(len(list_store), 103) + + # walk the list to see if the values were stored correctly + i = 0 + treeiter = list_store.get_iter_first() + + counter = 0 + while treeiter: + i = list_store.get_value(treeiter, 0) + self.assertEqual(i, counter) + s = list_store.get_value(treeiter, 1) + obj = list_store.get_value(treeiter, 2) + obj.check(i, s) + + pyobj = list_store.get_value(treeiter, 3) + self.assertEqual(pyobj, test_pyobj) + pydict = list_store.get_value(treeiter, 4) + self.assertEqual(pydict, test_pydict) + pylist = list_store.get_value(treeiter, 5) + self.assertEqual(pylist, test_pylist) + + bool_1 = list_store.get_value(treeiter, 6) + bool_2 = list_store.get_value(treeiter, 7) + self.assertEqual(bool_1, bool_2) + self.assertTrue(isinstance(bool_1, bool)) + self.assertTrue(isinstance(bool_2, bool)) + + treeiter = list_store.iter_next(treeiter) + + counter += 1 + + self.assertEqual(i, 102) + + def test_list_store_sort(self): + def comp1(model, row1, row2, user_data): + v1 = model[row1][1] + v2 = model[row2][1] + + # make "m" smaller than anything else + if v1.startswith('m') and not v2.startswith('m'): + return -1 + if v2.startswith('m') and not v1.startswith('m'): + return 1 + return (v1 > v2) - (v1 < v2) + + list_store = Gtk.ListStore(int, str) + list_store.set_sort_func(2, comp1, None) + list_store.append((1, 'apples')) + list_store.append((3, 'oranges')) + list_store.append((2, 'mango')) + + # not sorted yet, should be original order + self.assertEqual([list(i) for i in list_store], + [[1, 'apples'], [3, 'oranges'], [2, 'mango']]) + + # sort with our custom function + list_store.set_sort_column_id(2, Gtk.SortType.ASCENDING) + self.assertEqual([list(i) for i in list_store], + [[2, 'mango'], [1, 'apples'], [3, 'oranges']]) + + list_store.set_sort_column_id(2, Gtk.SortType.DESCENDING) + self.assertEqual([list(i) for i in list_store], + [[3, 'oranges'], [1, 'apples'], [2, 'mango']]) + + def test_list_store_signals(self): + list_store = Gtk.ListStore(int, bool) + + def on_row_inserted(list_store, tree_path, tree_iter, signal_list): + signal_list.append('row-inserted') + + def on_row_changed(list_store, tree_path, tree_iter, signal_list): + signal_list.append('row-changed') + + signals = [] + list_store.connect('row-inserted', on_row_inserted, signals) + list_store.connect('row-changed', on_row_changed, signals) + + # adding rows with and without data should only call one signal + list_store.append((0, False)) + self.assertEqual(signals, ['row-inserted']) + + signals.pop() + list_store.append() + self.assertEqual(signals, ['row-inserted']) + + signals.pop() + list_store.prepend((0, False)) + self.assertEqual(signals, ['row-inserted']) + + signals.pop() + list_store.prepend() + self.assertEqual(signals, ['row-inserted']) + + signals.pop() + list_store.insert(1, (0, False)) + self.assertEqual(signals, ['row-inserted']) + + signals.pop() + list_store.insert(1) + self.assertEqual(signals, ['row-inserted']) + + def test_tree_path(self): + p1 = Gtk.TreePath() + p2 = Gtk.TreePath.new_first() + self.assertEqual(p1, p2) + self.assertEqual(str(p1), '0') + self.assertEqual(len(p1), 1) + p1 = Gtk.TreePath(2) + p2 = Gtk.TreePath.new_from_string('2') + self.assertEqual(p1, p2) + self.assertEqual(str(p1), '2') + self.assertEqual(len(p1), 1) + p1 = Gtk.TreePath('1:2:3') + p2 = Gtk.TreePath.new_from_string('1:2:3') + self.assertEqual(p1, p2) + self.assertEqual(str(p1), '1:2:3') + self.assertEqual(len(p1), 3) + p1 = Gtk.TreePath((1, 2, 3)) + p2 = Gtk.TreePath.new_from_string('1:2:3') + self.assertEqual(p1, p2) + self.assertEqual(str(p1), '1:2:3') + self.assertEqual(len(p1), 3) + self.assertNotEqual(p1, None) + self.assertTrue(p1 > None) + self.assertTrue(p1 >= None) + self.assertFalse(p1 < None) + self.assertFalse(p1 <= None) + + self.assertEqual(tuple(p1), (1, 2, 3)) + self.assertEqual(p1[0], 1) + self.assertEqual(p1[1], 2) + self.assertEqual(p1[2], 3) + self.assertRaises(IndexError, p1.__getitem__, 3) + + def test_tree_model(self): + tree_store = Gtk.TreeStore(int, str) + + self.assertTrue(tree_store) + self.assertEqual(len(tree_store), 0) + self.assertEqual(tree_store.get_iter_first(), None) + + def get_by_index(row, col=None): + if col: + return tree_store[row][col] + else: + return tree_store[row] + + self.assertRaises(TypeError, get_by_index, None) + self.assertRaises(TypeError, get_by_index, "") + self.assertRaises(TypeError, get_by_index, ()) + + self.assertRaises(IndexError, get_by_index, "0") + self.assertRaises(IndexError, get_by_index, 0) + self.assertRaises(IndexError, get_by_index, (0,)) + + self.assertRaises(ValueError, tree_store.get_iter, "0") + self.assertRaises(ValueError, tree_store.get_iter, 0) + self.assertRaises(ValueError, tree_store.get_iter, (0,)) + + self.assertRaises(ValueError, tree_store.get_iter_from_string, "0") + + for row in tree_store: + self.fail("Should not be reached") + + class DerivedIntType(int): + pass + + class DerivedStrType(str): + pass + + for i in range(100): + label = 'this is row #%d' % i + parent = tree_store.append(None, (DerivedIntType(i), DerivedStrType(label),)) + self.assertNotEqual(parent, None) + for j in range(20): + label = 'this is child #%d of node #%d' % (j, i) + child = tree_store.append(parent, (j, label,)) + self.assertNotEqual(child, None) + + self.assertTrue(tree_store) + self.assertEqual(len(tree_store), 100) + + self.assertEqual(tree_store.iter_previous(tree_store.get_iter(0)), None) + + for i, row in enumerate(tree_store): + self.assertEqual(row.model, tree_store) + self.assertEqual(row.parent, None) + + self.assertEqual(tree_store[i].path, row.path) + self.assertEqual(tree_store[str(i)].path, row.path) + self.assertEqual(tree_store[(i,)].path, row.path) + + self.assertEqual(tree_store[i][0], i) + self.assertEqual(tree_store[i][1], "this is row #%d" % i) + + aiter = tree_store.get_iter(i) + self.assertEqual(tree_store.get_path(aiter), row.path) + + aiter = tree_store.get_iter(str(i)) + self.assertEqual(tree_store.get_path(aiter), row.path) + + aiter = tree_store.get_iter((i,)) + self.assertEqual(tree_store.get_path(aiter), row.path) + + self.assertEqual(tree_store.iter_parent(aiter), row.parent) + + next = tree_store.iter_next(aiter) + if i < len(tree_store) - 1: + self.assertEqual(tree_store.get_path(next), row.next.path) + self.assertEqual(tree_store.get_path(tree_store.iter_previous(next)), + tree_store.get_path(aiter)) + else: + self.assertEqual(next, None) + + self.assertEqual(tree_store.iter_n_children(row.iter), 20) + + child = tree_store.iter_children(row.iter) + for j, childrow in enumerate(row.iterchildren()): + child_path = tree_store.get_path(child) + self.assertEqual(childrow.path, child_path) + self.assertEqual(childrow.parent.path, row.path) + self.assertEqual(childrow.path, tree_store[child].path) + self.assertEqual(childrow.path, tree_store[child_path].path) + + self.assertEqual(childrow[0], tree_store[child][0]) + self.assertEqual(childrow[0], j) + self.assertEqual(childrow[1], tree_store[child][1]) + self.assertEqual(childrow[1], 'this is child #%d of node #%d' % (j, i)) + + self.assertRaises(IndexError, get_by_index, child, 2) + + tree_store[child][1] = 'this was child #%d of node #%d' % (j, i) + self.assertEqual(childrow[1], 'this was child #%d of node #%d' % (j, i)) + + nth_child = tree_store.iter_nth_child(row.iter, j) + self.assertEqual(childrow.path, tree_store.get_path(nth_child)) + + childrow2 = tree_store["%d:%d" % (i, j)] + self.assertEqual(childrow.path, childrow2.path) + + childrow2 = tree_store[(i, j,)] + self.assertEqual(childrow.path, childrow2.path) + + child = tree_store.iter_next(child) + if j < 19: + self.assertEqual(childrow.next.path, tree_store.get_path(child)) + else: + self.assertEqual(child, childrow.next) + self.assertEqual(child, None) + + self.assertEqual(j, 19) + + self.assertEqual(i, 99) + + # negative indices + for i in range(-1, -100, -1): + i_real = i + 100 + self.assertEqual(tree_store[i][0], i_real) + + row = tree_store[i] + for j in range(-1, -20, -1): + j_real = j + 20 + path = (i_real, j_real,) + + self.assertEqual(tree_store[path][-2], j_real) + + label = 'this was child #%d of node #%d' % (j_real, i_real) + self.assertEqual(tree_store[path][-1], label) + + new_label = 'this still is child #%d of node #%d' % (j_real, i_real) + tree_store[path][-1] = new_label + self.assertEqual(tree_store[path][-1], new_label) + + self.assertRaises(IndexError, get_by_index, path, -3) + + self.assertRaises(IndexError, get_by_index, -101) + + last_row = tree_store[99] + self.assertNotEqual(last_row, None) + + for i, childrow in enumerate(last_row.iterchildren()): + if i < 19: + self.assertTrue(tree_store.remove(childrow.iter)) + else: + self.assertFalse(tree_store.remove(childrow.iter)) + + self.assertEqual(i, 19) + + self.assertEqual(tree_store.iter_n_children(last_row.iter), 0) + for childrow in last_row.iterchildren(): + self.fail("Should not be reached") + + aiter = tree_store.get_iter(10) + self.assertRaises(TypeError, tree_store.get, aiter, 1, 'a') + self.assertRaises(ValueError, tree_store.get, aiter, 1, -1) + self.assertRaises(ValueError, tree_store.get, aiter, 1, 100) + self.assertEqual(tree_store.get(aiter, 0, 1), (10, 'this is row #10')) + + # check __delitem__ + self.assertEqual(len(tree_store), 100) + aiter = tree_store.get_iter(10) + del tree_store[aiter] + self.assertEqual(len(tree_store), 99) + self.assertRaises(TypeError, tree_store.__delitem__, None) + self.assertRaises(IndexError, tree_store.__delitem__, -101) + self.assertRaises(IndexError, tree_store.__delitem__, 101) + + def test_tree_model_get_iter_fail(self): + # TreeModel class with a failing get_iter() + class MyTreeModel(GObject.GObject, Gtk.TreeModel): + def do_get_iter(self, iter): + return (False, None) + + tm = MyTreeModel() + self.assertEqual(tm.get_iter_first(), None) + + def test_tree_model_edit(self): + model = Gtk.ListStore(int, str, float) + model.append([1, "one", -0.1]) + model.append([2, "two", -0.2]) + + def set_row(value): + model[1] = value + + self.assertRaises(TypeError, set_row, 3) + self.assertRaises(TypeError, set_row, "three") + self.assertRaises(ValueError, set_row, []) + self.assertRaises(ValueError, set_row, [3, "three"]) + + model[0] = (3, "three", -0.3) + + def test_tree_row_slice(self): + model = Gtk.ListStore(int, str, float) + model.append([1, "one", -0.1]) + + self.assertEqual([1, "one", -0.1], model[0][:]) + self.assertEqual([1, "one"], model[0][:2]) + self.assertEqual(["one", -0.1], model[0][1:]) + self.assertEqual(["one"], model[0][1:-1]) + self.assertEqual([1], model[0][:-2]) + self.assertEqual([], model[0][5:]) + self.assertEqual([1, -0.1], model[0][0:3:2]) + + model[0][:] = (2, "two", -0.2) + self.assertEqual([2, "two", -0.2], model[0][:]) + + model[0][:2] = (3, "three") + self.assertEqual([3, "three", -0.2], model[0][:]) + + model[0][1:] = ("four", -0.4) + self.assertEqual([3, "four", -0.4], model[0][:]) + + model[0][1:-1] = ("five",) + self.assertEqual([3, "five", -0.4], model[0][:]) + + model[0][0:3:2] = (6, -0.6) + self.assertEqual([6, "five", -0.6], model[0][:]) + + def set_row1(): + model[0][5:] = ("doesn't", "matter",) + + self.assertRaises(ValueError, set_row1) + + def set_row2(): + model[0][:1] = (0, "zero", 0) + + self.assertRaises(ValueError, set_row2) + + def set_row3(): + model[0][:2] = ("0", 0) + + self.assertRaises(TypeError, set_row3) + + 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) + row = store.append(['test']) + self.assertSequenceEqual(store[0][:], ['test']) + store.set_value(row, 0, None) + self.assertSequenceEqual(store[0][:], [None]) + + def test_signal_emission_tree_path_coerce(self): + class Model(GObject.Object, Gtk.TreeModel): + pass + + model = Model() + tree_paths = [] + + def on_any_signal(model, path, *args): + tree_paths.append(path.to_string()) + + model.connect('row-changed', on_any_signal) + model.connect('row-deleted', on_any_signal) + model.connect('row-has-child-toggled', on_any_signal) + model.connect('row-inserted', on_any_signal) + + model.row_changed('0', Gtk.TreeIter()) + self.assertEqual(tree_paths[-1], '0') + + model.row_deleted('1') + self.assertEqual(tree_paths[-1], '1') + + model.row_has_child_toggled('2', Gtk.TreeIter()) + self.assertEqual(tree_paths[-1], '2') + + model.row_inserted('3', Gtk.TreeIter()) + self.assertEqual(tree_paths[-1], '3') + + def test_tree_model_filter(self): + model = Gtk.ListStore(int, str, float) + model.append([1, "one", -0.1]) + model.append([2, "two", -0.2]) + + filtered = Gtk.TreeModelFilter(child_model=model) + + self.assertEqual(filtered[0][1], 'one') + filtered[0][1] = 'ONE' + self.assertEqual(filtered[0][1], 'ONE') + + def test_list_store_performance(self): + model = Gtk.ListStore(int, str) + + iterations = 2000 + start = time.clock() + i = iterations + while i > 0: + model.append([1, 'hello']) + i -= 1 + end = time.clock() + sys.stderr.write('[%.0f µs/append] ' % ((end - start) * 1000000 / iterations)) + + +@unittest.skipUnless(Gtk, 'Gtk not available') +class TestTreeView(unittest.TestCase): + def test_tree_view(self): + store = Gtk.ListStore(int, str) + store.append((0, "foo")) + store.append((1, "bar")) + view = Gtk.TreeView() + + with realized(view): + view.set_cursor(store[1].path) + view.set_cursor(str(store[1].path)) + + view.get_cell_area(store[1].path) + view.get_cell_area(str(store[1].path)) + + def test_tree_view_column(self): + cell = Gtk.CellRendererText() + Gtk.TreeViewColumn(title='This is just a test', + cell_renderer=cell, + text=0, + style=2) + + def test_tree_view_add_column_with_attributes(self): + model = Gtk.ListStore(str, str, str) + # deliberately use out-of-order sorting here; we assign column 0 to + # model index 2, etc. + model.append(['cell13', 'cell11', 'cell12']) + model.append(['cell23', 'cell21', 'cell22']) + + tree = Gtk.TreeView(model) + cell1 = Gtk.CellRendererText() + cell2 = Gtk.CellRendererText() + cell3 = Gtk.CellRendererText() + cell4 = Gtk.CellRendererText() + + tree.insert_column_with_attributes(0, 'Head2', cell2, text=2) + tree.insert_column_with_attributes(0, 'Head1', cell1, text=1) + tree.insert_column_with_attributes(-1, 'Head3', cell3, text=0) + # unconnected + tree.insert_column_with_attributes(-1, 'Head4', cell4) + + with realized(tree): + tree.set_cursor(model[0].path) + 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') + self.assertEqual(tree.get_column(2).get_title(), 'Head3') + 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) + + def test_tree_view_column_set_attributes(self): + store = Gtk.ListStore(int, str) + directors = ['Fellini', 'Tarantino', 'Tarkovskiy'] + for i, director in enumerate(directors): + store.append([i, director]) + + treeview = Gtk.TreeView() + treeview.set_model(store) + + column = Gtk.TreeViewColumn() + treeview.append_column(column) + + cell = Gtk.CellRendererText() + column.pack_start(cell, expand=True) + column.set_attributes(cell, text=1) + + with realized(treeview): + self.assertTrue(cell.props.text in directors) + + def test_tree_selection(self): + store = Gtk.ListStore(int, str) + for i in range(10): + store.append((i, "foo")) + view = Gtk.TreeView() + view.set_model(store) + firstpath = store.get_path(store.get_iter_first()) + sel = view.get_selection() + + sel.select_path(firstpath) + (m, s) = sel.get_selected() + self.assertEqual(m, store) + self.assertEqual(store.get_path(s), firstpath) + + sel.select_path(0) + (m, s) = sel.get_selected() + self.assertEqual(m, store) + self.assertEqual(store.get_path(s), firstpath) + + sel.select_path("0:0") + (m, s) = sel.get_selected() + self.assertEqual(m, store) + self.assertEqual(store.get_path(s), firstpath) + + sel.select_path((0, 0)) + (m, s) = sel.get_selected() + self.assertEqual(m, store) + self.assertEqual(store.get_path(s), firstpath) + + +@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() + tag = buffer.create_tag('title', font='Sans 18') + + self.assertEqual(tag.props.name, 'title') + self.assertEqual(tag.props.font, 'Sans 18') + + (start, end) = buffer.get_bounds() + + mark = buffer.create_mark(None, start) + self.assertFalse(mark.get_left_gravity()) + + buffer.set_text('Hello Jane Hello Bob') + (start, end) = buffer.get_bounds() + text = buffer.get_text(start, end, False) + self.assertEqual(text, 'Hello Jane Hello Bob') + + buffer.set_text('') + (start, end) = buffer.get_bounds() + text = buffer.get_text(start, end, False) + self.assertEqual(text, '') + + buffer.insert(end, 'HelloHello') + buffer.insert(end, ' Bob') + + cursor_iter = end.copy() + cursor_iter.backward_chars(9) + buffer.place_cursor(cursor_iter) + buffer.insert_at_cursor(' Jane ') + + (start, end) = buffer.get_bounds() + text = buffer.get_text(start, end, False) + self.assertEqual(text, 'Hello Jane Hello Bob') + + sel = buffer.get_selection_bounds() + self.assertEqual(sel, ()) + buffer.select_range(start, end) + sel = buffer.get_selection_bounds() + self.assertTrue(sel[0].equal(start)) + self.assertTrue(sel[1].equal(end)) + + 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(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(start.has_tag(tag)) + + self.assertRaises(ValueError, buffer.insert_with_tags_by_name, + buffer.get_start_iter(), 'HelloHello', 'unknowntag') + + def test_text_iter(self): + self.assertEqual(Gtk.TextIter, gi.overrides.Gtk.TextIter) + buffer = Gtk.TextBuffer() + buffer.set_text('Hello Jane Hello Bob') + tag = buffer.create_tag('title', font='Sans 18') + (start, end) = buffer.get_bounds() + start.forward_chars(10) + buffer.apply_tag(tag, start, end) + self.assertTrue(start.begins_tag()) + 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(start.ends_tag()) + self.assertFalse(start.toggles_tag()) + + def test_text_buffer_search(self): + buffer = Gtk.TextBuffer() + buffer.set_text('Hello World Hello GNOME') + + i = buffer.get_iter_at_offset(0) + self.assertTrue(isinstance(i, Gtk.TextIter)) + + self.assertEqual(i.forward_search('world', 0, None), None) + + (start, end) = i.forward_search('World', 0, None) + self.assertEqual(start.get_offset(), 6) + self.assertEqual(end.get_offset(), 11) + + (start, end) = i.forward_search('world', + Gtk.TextSearchFlags.CASE_INSENSITIVE, + None) + self.assertEqual(start.get_offset(), 6) + self.assertEqual(end.get_offset(), 11) diff --git a/tests/test_overrides_pango.py b/tests/test_overrides_pango.py new file mode 100644 index 0000000..42d4de9 --- /dev/null +++ b/tests/test_overrides_pango.py @@ -0,0 +1,37 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab + +import unittest + +try: + from gi.repository import Pango + Pango +except ImportError: + Pango = None + + +@unittest.skipUnless(Pango, 'Pango not available') +class TestPango(unittest.TestCase): + + def test_default_font_description(self): + desc = Pango.FontDescription() + self.assertEqual(desc.get_variant(), Pango.Variant.NORMAL) + + def test_font_description(self): + desc = Pango.FontDescription('monospace') + self.assertEqual(desc.get_family(), 'monospace') + self.assertEqual(desc.get_variant(), Pango.Variant.NORMAL) + + def test_layout(self): + self.assertRaises(TypeError, Pango.Layout) + context = Pango.Context() + layout = Pango.Layout(context) + self.assertEqual(layout.get_context(), context) + + layout.set_markup("Foobar") + self.assertEqual(layout.get_text(), "Foobar") + + 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) diff --git a/tests/test_properties.py b/tests/test_properties.py index f7f8e25..ef6b867 100644 --- a/tests/test_properties.py +++ b/tests/test_properties.py @@ -2,20 +2,28 @@ import sys import struct +import types import unittest from gi.repository import GObject -from gi.repository.GObject import GType, GEnum, new, PARAM_READWRITE, \ - PARAM_CONSTRUCT, PARAM_READABLE, PARAM_WRITABLE, PARAM_CONSTRUCT_ONLY +from gi.repository.GObject import GType, new, PARAM_READWRITE, \ + PARAM_CONSTRUCT, PARAM_READABLE, PARAM_WRITABLE, PARAM_CONSTRUCT_ONLY from gi.repository.GObject import \ - TYPE_INT, TYPE_UINT, TYPE_LONG, \ - TYPE_ULONG, TYPE_INT64, TYPE_UINT64 + TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_INT64, \ + TYPE_UINT64, TYPE_GTYPE, TYPE_INVALID, TYPE_NONE, TYPE_STRV, \ + TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, TYPE_BOOLEAN, TYPE_FLOAT, \ + 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_MININT, G_MAXINT, G_MAXUINT, G_MINLONG, G_MAXLONG, G_MAXULONG, \ + G_MAXUINT64, G_MAXINT64, G_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" @@ -26,56 +34,116 @@ else: from compathelper import _long + class PropertyObject(GObject.GObject): normal = GObject.Property(type=str) construct = GObject.Property( type=str, - flags=PARAM_READWRITE|PARAM_CONSTRUCT, default='default') + flags=PARAM_READWRITE | PARAM_CONSTRUCT, default='default') construct_only = GObject.Property( type=str, - flags=PARAM_READWRITE|PARAM_CONSTRUCT_ONLY) + flags=PARAM_READWRITE | PARAM_CONSTRUCT_ONLY) uint64 = GObject.Property( - type=TYPE_UINT64, flags=PARAM_READWRITE|PARAM_CONSTRUCT) + type=TYPE_UINT64, flags=PARAM_READWRITE | PARAM_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=PARAM_READWRITE | PARAM_CONSTRUCT) + + flags = GObject.Property( + type=GIMarshallingTests.Flags, flags=PARAM_READWRITE | PARAM_CONSTRUCT, + default=GIMarshallingTests.Flags.VALUE1) + + gtype = GObject.Property( + type=TYPE_GTYPE, flags=PARAM_READWRITE | PARAM_CONSTRUCT) + + strings = GObject.Property( + type=TYPE_STRV, flags=PARAM_READWRITE | PARAM_CONSTRUCT) + + variant = GObject.Property( + type=TYPE_VARIANT, flags=PARAM_READWRITE | PARAM_CONSTRUCT) + + variant_def = GObject.Property( + type=TYPE_VARIANT, flags=PARAM_READWRITE | PARAM_CONSTRUCT, + default=GLib.Variant('i', 42)) + + interface = GObject.Property( + type=Gio.File, flags=PARAM_READWRITE | PARAM_CONSTRUCT) + + +class PropertyInheritanceObject(Regress.TestObj): + # override property from the base class, with a different type + string = GObject.Property(type=int) + + # a property entirely defined at the Python level + python_prop = GObject.Property(type=str) + -class TestProperties(unittest.TestCase): - def testGetSet(self): +class PropertySubClassObject(PropertyInheritanceObject): + # override property from the base class, with a different type + python_prop = GObject.Property(type=int) + + +class TestPropertyInheritanceObject(unittest.TestCase): + def test_override_gi_property(self): + self.assertNotEqual(Regress.TestObj.props.string.value_type, + PropertyInheritanceObject.props.string.value_type) + obj = PropertyInheritanceObject() + self.assertEqual(type(obj.props.string), int) + obj.props.string = 4 + self.assertEqual(obj.props.string, 4) + + def test_override_python_property(self): + obj = PropertySubClassObject() + self.assertEqual(type(obj.props.python_prop), int) + obj.props.python_prop = 5 + self.assertEqual(obj.props.python_prop, 5) + + +class TestPropertyObject(unittest.TestCase): + def test_get_set(self): obj = PropertyObject() obj.props.normal = "value" self.assertEqual(obj.props.normal, "value") - def testListWithInstance(self): + def test_hasattr_on_object(self): obj = PropertyObject() - self.failUnless(hasattr(obj.props, "normal")) + self.assertTrue(hasattr(obj.props, "normal")) - def testListWithoutInstance(self): - self.failUnless(hasattr(PropertyObject.props, "normal")) + def test_hasattr_on_class(self): + self.assertTrue(hasattr(PropertyObject.props, "normal")) - def testSetNoInstance(self): + def test_set_on_class(self): def set(obj): obj.props.normal = "foobar" self.assertRaises(TypeError, set, PropertyObject) - def testIterator(self): + def test_iteration(self): for obj in (PropertyObject.props, PropertyObject().props): + names = [] for pspec in obj: gtype = GType(pspec) self.assertEqual(gtype.parent.name, 'GParam') - self.failUnless(pspec.name in ['normal', - 'construct', - 'construct-only', - 'uint64', - 'enum', - 'boxed']) - self.assertEqual(len(obj), 6) - - def testNormal(self): + names.append(pspec.name) + + names.sort() + self.assertEqual(names, ['boxed', + 'construct', + 'construct-only', + 'enum', + 'flags', + 'gtype', + 'interface', + 'normal', + 'strings', + 'uint64', + 'variant', + 'variant-def']) + + def test_normal(self): obj = new(PropertyObject, normal="123") self.assertEqual(obj.props.normal, "123") obj.set_property('normal', '456') @@ -83,15 +151,15 @@ class TestProperties(unittest.TestCase): obj.props.normal = '789' self.assertEqual(obj.props.normal, "789") - def testConstruct(self): + def test_construct(self): obj = new(PropertyObject, construct="123") self.assertEqual(obj.props.construct, "123") obj.set_property('construct', '456') self.assertEqual(obj.props.construct, "456") obj.props.construct = '789' self.assertEqual(obj.props.construct, "789") - - def testUTF8(self): + + 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) @@ -99,7 +167,7 @@ class TestProperties(unittest.TestCase): obj.props.normal = UNICODE_UTF8 self.assertEqual(obj.props.normal, TEST_UTF8) - def testIntToStr(self): + def test_int_to_str(self): obj = new(PropertyObject, construct_only=1) self.assertEqual(obj.props.construct_only, '1') obj.set_property('construct', '2') @@ -107,7 +175,7 @@ class TestProperties(unittest.TestCase): obj.props.normal = 3 self.assertEqual(obj.props.normal, '3') - def testConstructOnly(self): + def test_construct_only(self): obj = new(PropertyObject, construct_only="123") self.assertEqual(obj.props.construct_only, "123") self.assertRaises(TypeError, @@ -115,7 +183,7 @@ class TestProperties(unittest.TestCase): self.assertRaises(TypeError, obj.set_property, 'construct-only', '456') - def testUint64(self): + def test_uint64(self): obj = new(PropertyObject) self.assertEqual(obj.props.uint64, 0) obj.props.uint64 = _long(1) @@ -126,19 +194,19 @@ class TestProperties(unittest.TestCase): self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", _long(-1)) self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", -1) - def testUInt64DefaultValue(self): + def test_uint64_default_value(self): try: class TimeControl(GObject.GObject): __gproperties__ = { 'time': (TYPE_UINT64, 'Time', 'Time', - _long(0), (1<<64) - 1, _long(0), + _long(0), (1 << 64) - 1, _long(0), PARAM_READABLE) } except OverflowError: (etype, ex) = sys.exc_info()[2:] self.fail(str(ex)) - def testEnum(self): + def test_enum(self): obj = new(PropertyObject) self.assertEqual(obj.props.enum, Gio.SocketType.STREAM) self.assertEqual(obj.enum, Gio.SocketType.STREAM) @@ -166,21 +234,181 @@ class TestProperties(unittest.TestCase): self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType, default=1) - def textBoxed(self): + def test_flags(self): + obj = new(PropertyObject) + self.assertEqual(obj.props.flags, GIMarshallingTests.Flags.VALUE1) + self.assertEqual(obj.flags, GIMarshallingTests.Flags.VALUE1) + + obj.flags = GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3 + self.assertEqual(obj.props.flags, GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3) + self.assertEqual(obj.flags, GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3) + + self.assertRaises(TypeError, setattr, obj, 'flags', 'foo') + self.assertRaises(TypeError, setattr, obj, 'flags', object()) + self.assertRaises(TypeError, setattr, obj, 'flags', None) + + self.assertRaises(TypeError, GObject.Property, + type=GIMarshallingTests.Flags, default='foo') + self.assertRaises(TypeError, GObject.Property, + type=GIMarshallingTests.Flags, default=object()) + self.assertRaises(TypeError, GObject.Property, + type=GIMarshallingTests.Flags, default=None) + + def test_gtype(self): + obj = new(PropertyObject) + + self.assertEqual(obj.props.gtype, TYPE_NONE) + self.assertEqual(obj.gtype, TYPE_NONE) + + obj.gtype = TYPE_UINT64 + self.assertEqual(obj.props.gtype, TYPE_UINT64) + self.assertEqual(obj.gtype, TYPE_UINT64) + + obj.gtype = TYPE_INVALID + self.assertEqual(obj.props.gtype, TYPE_INVALID) + self.assertEqual(obj.gtype, TYPE_INVALID) + + # GType parameters do not support defaults in GLib + self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE, + default=TYPE_INT) + + # incompatible type + self.assertRaises(TypeError, setattr, obj, 'gtype', 'foo') + self.assertRaises(TypeError, setattr, obj, 'gtype', object()) + + self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE, + default='foo') + self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE, + default=object()) + + # set in constructor + obj = new(PropertyObject, gtype=TYPE_UINT) + self.assertEqual(obj.props.gtype, TYPE_UINT) + self.assertEqual(obj.gtype, TYPE_UINT) + + def test_boxed(self): obj = new(PropertyObject) regex = GLib.Regex.new('[a-z]*', 0, 0) obj.props.boxed = regex self.assertEqual(obj.props.boxed.get_pattern(), '[a-z]*') - self.assertEqual(obj.boxed.get_patttern(), '[a-z]*') + self.assertEqual(obj.boxed.get_pattern(), '[a-z]*') self.assertRaises(TypeError, setattr, obj, 'boxed', 'foo') self.assertRaises(TypeError, setattr, obj, 'boxed', object()) - def testRange(self): + def test_strings(self): + obj = new(PropertyObject) + + # Should work with actual GStrv objects as well as + # Python string lists + class GStrv(list): + __gtype__ = GObject.TYPE_STRV + + self.assertEqual(obj.props.strings, GStrv([])) + self.assertEqual(obj.strings, GStrv([])) + self.assertEqual(obj.props.strings, []) + self.assertEqual(obj.strings, []) + + obj.strings = ['hello', 'world'] + self.assertEqual(obj.props.strings, ['hello', 'world']) + self.assertEqual(obj.strings, ['hello', 'world']) + + obj.strings = GStrv(['hello', 'world']) + self.assertEqual(obj.props.strings, GStrv(['hello', 'world'])) + self.assertEqual(obj.strings, GStrv(['hello', 'world'])) + + obj.strings = [] + self.assertEqual(obj.strings, []) + obj.strings = GStrv([]) + self.assertEqual(obj.strings, GStrv([])) + + p = GObject.Property(type=TYPE_STRV, default=['hello', '1']) + self.assertEqual(p.default, ['hello', '1']) + self.assertEqual(p.type, TYPE_STRV) + p = GObject.Property(type=TYPE_STRV, default=GStrv(['hello', '1'])) + self.assertEqual(p.default, ['hello', '1']) + self.assertEqual(p.type, TYPE_STRV) + + # set in constructor + obj = new(PropertyObject, strings=['hello', 'world']) + self.assertEqual(obj.props.strings, ['hello', 'world']) + self.assertEqual(obj.strings, ['hello', 'world']) + + # wrong types + self.assertRaises(TypeError, setattr, obj, 'strings', 1) + self.assertRaises(TypeError, setattr, obj, 'strings', 'foo') + self.assertRaises(TypeError, setattr, obj, 'strings', ['foo', 1]) + + self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV, + default=1) + self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV, + default='foo') + self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV, + default=['hello', 1]) + + def test_variant(self): + obj = new(PropertyObject) + + self.assertEqual(obj.props.variant, None) + self.assertEqual(obj.variant, None) + + obj.variant = GLib.Variant('s', 'hello') + self.assertEqual(obj.variant.print_(True), "'hello'") + + obj.variant = GLib.Variant('b', True) + self.assertEqual(obj.variant.print_(True), "true") + + obj.props.variant = GLib.Variant('y', 2) + self.assertEqual(obj.variant.print_(True), "byte 0x02") + + obj.variant = None + self.assertEqual(obj.variant, None) + + # set in constructor + obj = new(PropertyObject, variant=GLib.Variant('u', 5)) + self.assertEqual(obj.props.variant.print_(True), 'uint32 5') + + GObject.Property(type=TYPE_VARIANT, default=GLib.Variant('i', 1)) + + # incompatible types + self.assertRaises(TypeError, setattr, obj, 'variant', 'foo') + self.assertRaises(TypeError, setattr, obj, 'variant', 42) + + self.assertRaises(TypeError, GObject.Property, type=TYPE_VARIANT, + default='foo') + self.assertRaises(TypeError, GObject.Property, type=TYPE_VARIANT, + default=object()) + + def test_variant_default(self): + obj = new(PropertyObject) + + self.assertEqual(obj.props.variant_def.print_(True), '42') + self.assertEqual(obj.variant_def.print_(True), '42') + + obj.props.variant_def = GLib.Variant('y', 2) + self.assertEqual(obj.variant_def.print_(True), "byte 0x02") + + # set in constructor + obj = new(PropertyObject, variant_def=GLib.Variant('u', 5)) + self.assertEqual(obj.props.variant_def.print_(True), 'uint32 5') + + def test_interface(self): + obj = new(PropertyObject) + + file = Gio.File.new_for_path('/some/path') + obj.props.interface = file + self.assertEqual(obj.props.interface.get_path(), '/some/path') + self.assertEqual(obj.interface.get_path(), '/some/path') + + self.assertRaises(TypeError, setattr, obj, 'interface', 'foo') + self.assertRaises(TypeError, setattr, obj, 'interface', object()) + + def test_range(self): # kiwi code def max(c): return 2 ** ((8 * struct.calcsize(c)) - 1) - 1 + def umax(c): return 2 ** (8 * struct.calcsize(c)) - 1 @@ -194,22 +422,22 @@ class TestProperties(unittest.TestCase): minint64 = -maxint64 - 1 maxuint64 = umax('Q') - types = dict(int=(TYPE_INT, minint, maxint), - uint=(TYPE_UINT, 0, maxuint), - long=(TYPE_LONG, minlong, maxlong), - ulong=(TYPE_ULONG, 0, maxulong), - int64=(TYPE_INT64, minint64, maxint64), - uint64=(TYPE_UINT64, 0, maxuint64)) + types_ = dict(int=(TYPE_INT, minint, maxint), + uint=(TYPE_UINT, 0, maxuint), + long=(TYPE_LONG, minlong, maxlong), + ulong=(TYPE_ULONG, 0, maxulong), + int64=(TYPE_INT64, minint64, maxint64), + uint64=(TYPE_UINT64, 0, maxuint64)) - def build_gproperties(types): + def build_gproperties(types_): d = {} - for key, (gtype, min, max) in types.items(): + for key, (gtype, min, max) in types_.items(): d[key] = (gtype, 'blurb', 'desc', min, max, 0, PARAM_READABLE | PARAM_WRITABLE) return d class RangeCheck(GObject.GObject): - __gproperties__ = build_gproperties(types) + __gproperties__ = build_gproperties(types_) def __init__(self): self.values = {} @@ -235,7 +463,7 @@ class TestProperties(unittest.TestCase): self.assertEqual(RangeCheck.props.uint64.maximum, maxuint64) obj = RangeCheck() - for key, (gtype, min, max) in types.items(): + for key, (gtype, min, max) in types_.items(): self.assertEqual(obj.get_property(key), getattr(RangeCheck.props, key).default_value) @@ -245,8 +473,7 @@ class TestProperties(unittest.TestCase): obj.set_property(key, max) self.assertEqual(obj.get_property(key), max) - - def testMulti(self): + def test_multi(self): obj = PropertyObject() obj.set_properties(normal="foo", uint64=7) @@ -254,18 +481,19 @@ class TestProperties(unittest.TestCase): self.assertEqual(normal, "foo") self.assertEqual(uint64, 7) + class TestProperty(unittest.TestCase): - def testSimple(self): + 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) - self.failUnless(hasattr(C.props, 'str')) - self.failUnless(hasattr(C.props, 'int')) - self.failUnless(hasattr(C.props, 'float')) - self.failUnless(hasattr(C.props, 'long')) + self.assertTrue(hasattr(C.props, 'str')) + self.assertTrue(hasattr(C.props, 'int')) + self.assertTrue(hasattr(C.props, 'float')) + self.assertTrue(hasattr(C.props, 'long')) o = C() self.assertEqual(o.str, '') @@ -284,7 +512,7 @@ class TestProperty(unittest.TestCase): o.long = _long(100) self.assertEqual(o.long, _long(100)) - def testCustomGetter(self): + def test_custom_getter(self): class C(GObject.GObject): def get_prop(self): return 'value' @@ -294,7 +522,7 @@ class TestProperty(unittest.TestCase): self.assertEqual(o.prop, 'value') self.assertRaises(TypeError, setattr, o, 'prop', 'xxx') - def testCustomSetter(self): + def test_custom_setter(self): class C(GObject.GObject): def set_prop(self, value): self._value = value @@ -305,19 +533,21 @@ class TestProperty(unittest.TestCase): GObject.GObject.__init__(self) o = C() - self.assertEquals(o._value, None) + self.assertEqual(o._value, None) o.prop = 'bar' - self.assertEquals(o._value, 'bar') + self.assertEqual(o._value, 'bar') self.assertRaises(TypeError, getattr, o, 'prop') - def testDecoratorDefault(self): + def test_decorator_default(self): class C(GObject.GObject): _value = 'value' + @GObject.Property def value(self): return self._value + @value.setter - def value(self, value): + def value_setter(self, value): self._value = value o = C() @@ -326,14 +556,34 @@ class TestProperty(unittest.TestCase): self.assertEqual(o.value, 'blah') self.assertEqual(o.props.value, 'blah') - def testDecoratorWithCall(self): + def test_decorator_private_setter(self): + class C(GObject.GObject): + _value = 'value' + + @GObject.Property + def value(self): + return self._value + + @value.setter + def _set_value(self, value): + self._value = value + + o = C() + self.assertEqual(o.value, 'value') + o.value = 'blah' + self.assertEqual(o.value, 'blah') + self.assertEqual(o.props.value, 'blah') + + def test_decorator_with_call(self): class C(GObject.GObject): _value = 1 + @GObject.Property(type=int, default=1, minimum=1, maximum=10) def typedValue(self): return self._value + @typedValue.setter - def typedValue(self, value): + def typedValue_setter(self, value): self._value = value o = C() @@ -342,7 +592,7 @@ class TestProperty(unittest.TestCase): self.assertEqual(o.typedValue, 5) self.assertEqual(o.props.typedValue, 5) - def testErrors(self): + def test_errors(self): self.assertRaises(TypeError, GObject.Property, type='str') self.assertRaises(TypeError, GObject.Property, nick=False) self.assertRaises(TypeError, GObject.Property, blurb=False) @@ -354,52 +604,46 @@ class TestProperty(unittest.TestCase): self.assertRaises(TypeError, GObject.Property, type=bool) self.assertRaises(TypeError, GObject.Property, type=object, default=0) self.assertRaises(TypeError, GObject.Property, type=complex) - self.assertRaises(TypeError, GObject.Property, flags=-10) - def testDefaults(self): - p1 = GObject.Property(type=bool, default=True) - p2 = GObject.Property(type=bool, default=False) + def test_defaults(self): + GObject.Property(type=bool, default=True) + GObject.Property(type=bool, default=False) - def testNameWithUnderscore(self): + def test_name_with_underscore(self): class C(GObject.GObject): prop_name = GObject.Property(type=int) o = C() o.prop_name = 10 self.assertEqual(o.prop_name, 10) - def testRange(self): - maxint64 = 2 ** 62 - 1 - minint64 = -2 ** 62 - 1 - maxuint64 = 2 ** 63 - 1 - - types = [ + 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, minint64, maxint64), - (TYPE_UINT64, 0, maxuint64), + (TYPE_INT64, G_MININT64, G_MAXINT64), + (TYPE_UINT64, 0, G_MAXUINT64), ] - for gtype, min, max in types: + for gtype, min, max in types_: # Normal, everything is alright prop = GObject.Property(type=gtype, minimum=min, maximum=max) - subtype = type('', (GObject.GObject,), - dict(prop=prop)) + subtype = type('', (GObject.GObject,), dict(prop=prop)) self.assertEqual(subtype.props.prop.minimum, min) self.assertEqual(subtype.props.prop.maximum, max) # Lower than minimum self.assertRaises(TypeError, - GObject.Property, type=gtype, minimum=min-1, + GObject.Property, type=gtype, minimum=min - 1, maximum=max) # Higher than maximum self.assertRaises(TypeError, GObject.Property, type=gtype, minimum=min, - maximum=max+1) + maximum=max + 1) - def testMinMax(self): + def test_min_max(self): class C(GObject.GObject): prop_int = GObject.Property(type=int, minimum=1, maximum=100, default=1) prop_float = GObject.Property(type=float, minimum=0.1, maximum=10.5, default=1.1) @@ -407,30 +651,36 @@ class TestProperty(unittest.TestCase): def __init__(self): GObject.GObject.__init__(self) - o = C() - self.assertEqual(o.prop_int, 1) + # 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: + o = C() + self.assertEqual(o.prop_int, 1) - o.prop_int = 5 - self.assertEqual(o.prop_int, 5) + o.prop_int = 5 + self.assertEqual(o.prop_int, 5) - o.prop_int = 0 - self.assertEqual(o.prop_int, 5) + o.prop_int = 0 + self.assertEqual(o.prop_int, 5) - o.prop_int = 101 - self.assertEqual(o.prop_int, 5) + o.prop_int = 101 + self.assertEqual(o.prop_int, 5) - self.assertEqual(o.prop_float, 1.1) + self.assertEqual(o.prop_float, 1.1) - o.prop_float = 7.75 - self.assertEqual(o.prop_float, 7.75) + o.prop_float = 7.75 + self.assertEqual(o.prop_float, 7.75) - o.prop_float = 0.09 - self.assertEqual(o.prop_float, 7.75) + o.prop_float = 0.09 + self.assertEqual(o.prop_float, 7.75) - o.prop_float = 10.51 - self.assertEqual(o.prop_float, 7.75) + o.prop_float = 10.51 + self.assertEqual(o.prop_float, 7.75) + finally: + GLib.log_set_always_fatal(old_mask) - def testMultipleInstances(self): + def test_multiple_instances(self): class C(GObject.GObject): prop = GObject.Property(type=str, default='default') @@ -442,7 +692,7 @@ class TestProperty(unittest.TestCase): self.assertEqual(o1.prop, 'value') self.assertEqual(o2.prop, 'default') - def testObjectProperty(self): + def test_object_property(self): class PropertyObject(GObject.GObject): obj = GObject.Property(type=GObject.GObject) @@ -455,16 +705,16 @@ class TestProperty(unittest.TestCase): pobj1 = pobj2.obj self.assertEqual(hash(pobj1), obj1_hash) - def testObjectSubclassProperty(self): + def test_object_subclass_property(self): class ObjectSubclass(GObject.GObject): __gtype_name__ = 'ObjectSubclass' class PropertyObjectSubclass(GObject.GObject): obj = GObject.Property(type=ObjectSubclass) - obj1 = PropertyObjectSubclass(obj=ObjectSubclass()) + PropertyObjectSubclass(obj=ObjectSubclass()) - def testPropertySubclass(self): + def test_property_subclass(self): # test for #470718 class A(GObject.GObject): prop1 = GObject.Property(type=int) @@ -474,11 +724,30 @@ class TestProperty(unittest.TestCase): b = B() b.prop2 = 10 - self.assertEquals(b.prop2, 10) + self.assertEqual(b.prop2, 10) b.prop1 = 20 - self.assertEquals(b.prop1, 20) + self.assertEqual(b.prop1, 20) - def testPropertySubclassCustomSetter(self): + def test_property_subclass_c(self): + class A(Regress.TestSubObj): + prop1 = GObject.Property(type=int) + + a = A() + a.prop1 = 10 + self.assertEqual(a.prop1, 10) + + # also has parent properties + a.props.int = 20 + self.assertEqual(a.props.int, 20) + + # Some of which are unusable without introspection + a.props.list = ("str1", "str2") + self.assertEqual(a.props.list, ["str1", "str2"]) + + a.set_property("list", ("str3", "str4")) + self.assertEqual(a.props.list, ["str3", "str4"]) + + def test_property_subclass_custom_setter(self): # test for #523352 class A(GObject.GObject): def get_first(self): @@ -491,16 +760,16 @@ class TestProperty(unittest.TestCase): second = GObject.Property(type=str, getter=get_second) a = A() - self.assertEquals(a.first, 'first') + self.assertEqual(a.first, 'first') self.assertRaises(TypeError, setattr, a, 'first', 'foo') b = B() - self.assertEquals(b.first, 'first') + self.assertEqual(b.first, 'first') self.assertRaises(TypeError, setattr, b, 'first', 'foo') - self.assertEquals(b.second, 'second') + self.assertEqual(b.second, 'second') self.assertRaises(TypeError, setattr, b, 'second', 'foo') - def testPropertySubclassCustomSetterError(self): + def test_property_subclass_custom_setter_error(self): try: class A(GObject.GObject): def get_first(self): @@ -515,13 +784,15 @@ class TestProperty(unittest.TestCase): raise AssertionError # Bug 587637. + def test_float_min(self): GObject.Property(type=float, minimum=-1) GObject.Property(type=GObject.TYPE_FLOAT, minimum=-1) GObject.Property(type=GObject.TYPE_DOUBLE, minimum=-1) # Bug 644039 - def testReferenceCount(self): + + 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. @@ -533,24 +804,119 @@ class TestProperty(unittest.TestCase): # want to observe. Its refcount is increased by one. t = PropertyObject(normal="test") t.o = o - self.assertEquals(sys.getrefcount(o), rc + 1) + self.assertEqual(sys.getrefcount(o), rc + 1) # Now we want to ensure we do not leak any references to our # object with properties. If no ref is leaked, then when deleting # the local reference to this object, its reference count shoud # drop to zero, and our dummy object should loose one reference. del t - self.assertEquals(sys.getrefcount(o), rc) + self.assertEqual(sys.getrefcount(o), rc) - def testDocStringAsBlurb(self): + def test_doc_strings(self): class C(GObject.GObject): + foo_blurbed = GObject.Property(type=int, blurb='foo_blurbed doc string') + @GObject.Property - def blurbed(self): - """blurbed doc string""" + def foo_getter(self): + """foo_getter doc string""" return 0 - self.assertEqual(C.blurbed.blurb, 'blurbed doc string') - + self.assertEqual(C.foo_blurbed.blurb, 'foo_blurbed doc string') + self.assertEqual(C.foo_blurbed.__doc__, 'foo_blurbed doc string') + + self.assertEqual(C.foo_getter.blurb, 'foo_getter doc string') + self.assertEqual(C.foo_getter.__doc__, 'foo_getter doc string') + + 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) + self.assertEqual(tester._type_from_python(object), GObject.TYPE_PYOBJECT) + + self.assertEqual(tester._type_from_python(GObject.GObject), GObject.GObject.__gtype__) + self.assertEqual(tester._type_from_python(GObject.GEnum), GObject.GEnum.__gtype__) + self.assertEqual(tester._type_from_python(GObject.GFlags), GObject.GFlags.__gtype__) + self.assertEqual(tester._type_from_python(GObject.GBoxed), GObject.GBoxed.__gtype__) + self.assertEqual(tester._type_from_python(GObject.GInterface), GObject.GInterface.__gtype__) + + for type_ in [TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, + TYPE_INT, TYPE_UINT, TYPE_BOOLEAN, TYPE_LONG, + TYPE_ULONG, TYPE_INT64, TYPE_UINT64, + TYPE_FLOAT, TYPE_DOUBLE, TYPE_POINTER, + TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, TYPE_STRING, + TYPE_PYOBJECT, TYPE_GTYPE, TYPE_STRV]: + self.assertEqual(tester._type_from_python(type_), type_) + + self.assertRaises(TypeError, tester._type_from_python, types.CodeType) + + +class TestInstallProperties(unittest.TestCase): + # These tests only test how signalhelper.install_signals works + # with the __gsignals__ dict and therefore does not need to use + # GObject as a base class because that would automatically call + # install_signals within the meta-class. + class Base(object): + __gproperties__ = {'test': (0, '', '', 0, 0, 0, 0)} + + class Sub1(Base): + pass + + class Sub2(Base): + @GObject.Property(type=int) + def sub2test(self): + return 123 + + class ClassWithPropertyAndGetterVFunc(object): + @GObject.Property(type=int) + def sub2test(self): + return 123 + + def do_get_property(self, name): + return 321 + + class ClassWithPropertyRedefined(object): + __gproperties__ = {'test': (0, '', '', 0, 0, 0, 0)} + test = GObject.Property(type=int) + + def setUp(self): + self.assertEqual(len(self.Base.__gproperties__), 1) + propertyhelper.install_properties(self.Base) + self.assertEqual(len(self.Base.__gproperties__), 1) + + def test_subclass_without_properties_is_not_modified(self): + self.assertFalse('__gproperties__' in self.Sub1.__dict__) + propertyhelper.install_properties(self.Sub1) + self.assertFalse('__gproperties__' in self.Sub1.__dict__) + + def test_subclass_with_decorator_gets_gproperties_dict(self): + # Sub2 has Property instances but will not have a __gproperties__ + # until install_properties is called + self.assertFalse('__gproperties__' in self.Sub2.__dict__) + self.assertFalse('do_get_property' in self.Sub2.__dict__) + self.assertFalse('do_set_property' in self.Sub2.__dict__) + + propertyhelper.install_properties(self.Sub2) + self.assertTrue('__gproperties__' in self.Sub2.__dict__) + self.assertEqual(len(self.Base.__gproperties__), 1) + self.assertEqual(len(self.Sub2.__gproperties__), 1) + self.assertTrue('sub2test' in self.Sub2.__gproperties__) + + # get/set vfuncs should have been added + self.assertTrue('do_get_property' in self.Sub2.__dict__) + self.assertTrue('do_set_property' in self.Sub2.__dict__) + + def test_object_with_property_and_do_get_property_vfunc_raises(self): + self.assertRaises(TypeError, propertyhelper.install_properties, + self.ClassWithPropertyAndGetterVFunc) + + def test_same_name_property_definitions_raises(self): + self.assertRaises(ValueError, propertyhelper.install_properties, + self.ClassWithPropertyRedefined) if __name__ == '__main__': unittest.main() diff --git a/tests/test_pygtkcompat.py b/tests/test_pygtkcompat.py deleted file mode 100644 index b9765c3..0000000 --- a/tests/test_pygtkcompat.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- -# vim: tabstop=4 shiftwidth=4 expandtab - -import unittest - -import sys -import os -sys.path.insert(0, "../") - -from gi.repository import Gdk -from gi.repository import Gtk - -import gi.pygtkcompat - -gi.pygtkcompat.enable() -gi.pygtkcompat.enable_gtk(version='3.0') - -import atk -import pango -import pangocairo -import gtk -import gtk.gdk - - -class TestGTKCompat(unittest.TestCase): - def testButtons(self): - self.assertEquals(Gdk._2BUTTON_PRESS, 5) - self.assertEquals(Gdk.BUTTON_PRESS, 4) - - def testEnums(self): - self.assertEquals(gtk.WINDOW_TOPLEVEL, Gtk.WindowType.TOPLEVEL) - self.assertEquals(gtk.PACK_START, Gtk.PackType.START) - - def testFlags(self): - self.assertEquals(gtk.EXPAND, Gtk.AttachOptions.EXPAND) - - def testKeysyms(self): - import gtk.keysyms - self.assertEquals(gtk.keysyms.Escape, Gdk.KEY_Escape) - self.failUnless(gtk.keysyms._0, Gdk.KEY_0) - - def testStyle(self): - widget = gtk.Button() - self.failUnless(isinstance(widget.style.base[gtk.STATE_NORMAL], - gtk.gdk.Color)) - - def testAlignment(self): - a = gtk.Alignment() - self.assertEquals(a.props.xalign, 0.0) - self.assertEquals(a.props.yalign, 0.0) - self.assertEquals(a.props.xscale, 0.0) - self.assertEquals(a.props.yscale, 0.0) - - def testBox(self): - box = gtk.Box() - child = gtk.Button() - - box.pack_start(child) - expand, fill, padding, pack_type = box.query_child_packing(child) - self.failUnless(expand) - self.failUnless(fill) - self.assertEquals(padding, 0) - self.assertEquals(pack_type, gtk.PACK_START) - - child = gtk.Button() - box.pack_end(child) - expand, fill, padding, pack_type = box.query_child_packing(child) - self.failUnless(expand) - self.failUnless(fill) - self.assertEquals(padding, 0) - self.assertEquals(pack_type, gtk.PACK_END) - - def testPixbuf(self): - gtk.gdk.Pixbuf() - - def testPixbufLoader(self): - loader = gtk.gdk.PixbufLoader('png') - loader.close() - - def testGdkWindow(self): - w = gtk.Window() - w.realize() - self.assertEquals(w.get_window().get_origin(), (0, 0)) diff --git a/tests/test_signal.py b/tests/test_signal.py index 8486adb..ec13896 100644 --- a/tests/test_signal.py +++ b/tests/test_signal.py @@ -4,21 +4,26 @@ import gc import unittest import sys -from gi.repository import GObject +from gi.repository import GObject, GLib +from gi._gobject import signalhelper import testhelper from compathelper import _long + class C(GObject.GObject): - __gsignals__ = { 'my_signal': (GObject.SignalFlags.RUN_FIRST, None, - (GObject.TYPE_INT,)) } + __gsignals__ = {'my_signal': (GObject.SignalFlags.RUN_FIRST, None, + (GObject.TYPE_INT,))} + def do_my_signal(self, arg): self.arg = arg + class D(C): def do_my_signal(self, arg2): self.arg2 = arg2 C.do_my_signal(self, arg2) + class TestSignalCreation(unittest.TestCase): # Bug 540376. def test_illegals(self): @@ -44,50 +49,60 @@ class TestChaining(unittest.TestCase): assert args[2:] == (1, 2, 3) - def testChaining(self): + def test_chaining(self): self.inst.emit("my_signal", 42) assert self.inst.arg == 42 - def testChaining(self): + def test_chaining2(self): inst2 = D() inst2.emit("my_signal", 44) assert inst2.arg == 44 assert inst2.arg2 == 44 # This is for bug 153718 + + class TestGSignalsError(unittest.TestCase): - def testInvalidType(self, *args): + def test_invalid_type(self, *args): def foo(): class Foo(GObject.GObject): __gsignals__ = None self.assertRaises(TypeError, foo) gc.collect() - def testInvalidName(self, *args): + def test_invalid_name(self, *args): def foo(): class Foo(GObject.GObject): - __gsignals__ = {'not-exists' : 'override'} - self.assertRaises(TypeError, foo) + __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: + self.assertRaises(TypeError, foo) + finally: + GLib.log_set_always_fatal(old_mask) gc.collect() + class TestGPropertyError(unittest.TestCase): - def testInvalidType(self, *args): + def test_invalid_type(self, *args): def foo(): class Foo(GObject.GObject): __gproperties__ = None self.assertRaises(TypeError, foo) gc.collect() - def testInvalidName(self, *args): + def test_invalid_name(self, *args): def foo(): class Foo(GObject.GObject): - __gproperties__ = { None: None } + __gproperties__ = {None: None} self.assertRaises(TypeError, foo) gc.collect() + class TestList(unittest.TestCase): - def testListObject(self): + def test_list_names(self): self.assertEqual(GObject.signal_list_names(C), ('my-signal',)) @@ -99,51 +114,76 @@ def my_accumulator(ihint, return_accu, handler_return, user_data): return False, return_accu return True, return_accu + handler_return + class Foo(GObject.GObject): - __gsignals__ = { - 'my-acc-signal': (GObject.SignalFlags.RUN_LAST, GObject.TYPE_INT, - (), my_accumulator, "accum data"), - 'my-other-acc-signal': (GObject.SignalFlags.RUN_LAST, GObject.TYPE_BOOLEAN, - (), GObject.signal_accumulator_true_handled) - } + my_acc_signal = GObject.Signal(return_type=GObject.TYPE_INT, + flags=GObject.SignalFlags.RUN_LAST, + accumulator=my_accumulator, + accu_data="accum data") + + my_other_acc_signal = GObject.Signal(return_type=GObject.TYPE_BOOLEAN, + flags=GObject.SignalFlags.RUN_LAST, + accumulator=GObject.signal_accumulator_true_handled) + + my_acc_first_wins = GObject.Signal(return_type=GObject.TYPE_BOOLEAN, + flags=GObject.SignalFlags.RUN_LAST, + accumulator=GObject.signal_accumulator_first_wins) + class TestAccumulator(unittest.TestCase): - def testAccumulator(self): + def test_accumulator(self): inst = Foo() - inst.connect("my-acc-signal", lambda obj: 1) - inst.connect("my-acc-signal", lambda obj: 2) + 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. - inst.connect("my-acc-signal", lambda obj: 3) - retval = inst.emit("my-acc-signal") + inst.my_acc_signal.connect(lambda obj: 3) + retval = inst.my_acc_signal.emit() self.assertEqual(retval, 3) - def testAccumulatorTrueHandled(self): + def test_accumulator_true_handled(self): inst = Foo() - inst.connect("my-other-acc-signal", self._true_handler1) - inst.connect("my-other-acc-signal", self._true_handler2) + 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. - inst.connect("my-other-acc-signal", self._true_handler3) + inst.my_other_acc_signal.connect(self._true_handler3) self.__true_val = None - inst.emit("my-other-acc-signal") + inst.my_other_acc_signal.emit() self.assertEqual(self.__true_val, 2) + def test_accumulator_first_wins(self): + # First signal hit will always win + inst = Foo() + inst.my_acc_first_wins.connect(self._true_handler3) + inst.my_acc_first_wins.connect(self._true_handler1) + inst.my_acc_first_wins.connect(self._true_handler2) + self.__true_val = None + inst.my_acc_first_wins.emit() + self.assertEqual(self.__true_val, 3) + def _true_handler1(self, obj): self.__true_val = 1 return False + def _true_handler2(self, obj): self.__true_val = 2 return True + def _true_handler3(self, obj): self.__true_val = 3 return False + class E(GObject.GObject): - __gsignals__ = { 'signal': (GObject.SignalFlags.RUN_FIRST, None, - ()) } + __gsignals__ = {'signal': (GObject.SignalFlags.RUN_FIRST, None, + ())} + + # Property used to test detailed signal + prop = GObject.Property(type=int, default=0) + def __init__(self): GObject.GObject.__init__(self) self.status = 0 @@ -152,9 +192,11 @@ class E(GObject.GObject): assert self.status == 0 self.status = 1 + class F(GObject.GObject): - __gsignals__ = { 'signal': (GObject.SignalFlags.RUN_FIRST, None, - ()) } + __gsignals__ = {'signal': (GObject.SignalFlags.RUN_FIRST, None, + ())} + def __init__(self): GObject.GObject.__init__(self) self.status = 0 @@ -162,8 +204,9 @@ class F(GObject.GObject): def do_signal(self): self.status += 1 + class TestEmissionHook(unittest.TestCase): - def testAdd(self): + def test_add(self): self.hook = True e = E() e.connect('signal', self._callback) @@ -171,7 +214,7 @@ class TestEmissionHook(unittest.TestCase): e.emit('signal') self.assertEqual(e.status, 3) - def testRemove(self): + def test_remove(self): self.hook = False e = E() e.connect('signal', self._callback) @@ -191,20 +234,22 @@ class TestEmissionHook(unittest.TestCase): self.assertEqual(e.status, 1) e.status = 3 - def testCallbackReturnFalse(self): + def test_callback_return_false(self): self.hook = False obj = F() + def _emission_hook(obj): obj.status += 1 return False - hook_id = GObject.add_emission_hook(obj, "signal", _emission_hook) + GObject.add_emission_hook(obj, "signal", _emission_hook) obj.emit('signal') obj.emit('signal') self.assertEqual(obj.status, 3) - def testCallbackReturnTrue(self): + def test_callback_return_true(self): self.hook = False obj = F() + def _emission_hook(obj): obj.status += 1 return True @@ -214,9 +259,10 @@ class TestEmissionHook(unittest.TestCase): GObject.remove_emission_hook(obj, "signal", hook_id) self.assertEqual(obj.status, 4) - def testCallbackReturnTrueButRemove(self): + def test_callback_return_true_but_remove(self): self.hook = False obj = F() + def _emission_hook(obj): obj.status += 1 return True @@ -226,36 +272,163 @@ class TestEmissionHook(unittest.TestCase): obj.emit('signal') self.assertEqual(obj.status, 3) + +class TestMatching(unittest.TestCase): + class Object(GObject.Object): + status = 0 + prop = GObject.Property(type=int, default=0) + + @GObject.Signal() + def my_signal(self): + pass + + @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=692918 + def test_signal_handler_block_matching(self): + def dummy(*args): + "Hack to work around: " + + def foo(obj): + obj.status += 1 + + obj = self.Object() + handler_id = GObject.signal_connect_closure(obj, 'my-signal', foo, after=False) + handler_id + + self.assertEqual(obj.status, 0) + obj.emit('my-signal') + self.assertEqual(obj.status, 1) + + # Blocking by match criteria disables the foo callback + signal_id, detail = GObject.signal_parse_name('my-signal', obj, True) + count = GObject.signal_handlers_block_matched(obj, + GObject.SignalMatchType.ID | GObject.SignalMatchType.CLOSURE, + signal_id=signal_id, detail=detail, + closure=foo, func=dummy, data=dummy) + self.assertEqual(count, 1) + obj.emit('my-signal') + self.assertEqual(obj.status, 1) + + # Unblocking by the same match criteria allows callback to work again + count = GObject.signal_handlers_unblock_matched(obj, + GObject.SignalMatchType.ID | GObject.SignalMatchType.CLOSURE, + signal_id=signal_id, detail=detail, + closure=foo, func=dummy, data=dummy) + self.assertEqual(count, 1) + obj.emit('my-signal') + self.assertEqual(obj.status, 2) + + # Disconnecting by match criteria completely removes the handler + count = GObject.signal_handlers_disconnect_matched(obj, + GObject.SignalMatchType.ID | GObject.SignalMatchType.CLOSURE, + signal_id=signal_id, detail=detail, + closure=foo, func=dummy, data=dummy) + self.assertEqual(count, 1) + obj.emit('my-signal') + self.assertEqual(obj.status, 2) + + def test_signal_handler_find(self): + def dummy(*args): + "Hack to work around: " + + def foo(obj): + obj.status += 1 + + obj = self.Object() + handler_id = GObject.signal_connect_closure(obj, 'my-signal', foo, after=False) + + signal_id, detail = GObject.signal_parse_name('my-signal', obj, True) + found_id = GObject.signal_handler_find(obj, + GObject.SignalMatchType.ID, + signal_id=signal_id, detail=detail, + closure=None, func=dummy, data=dummy) + self.assertEqual(handler_id, found_id) + + class TestClosures(unittest.TestCase): def setUp(self): self.count = 0 + self.emission_stopped = False + self.emission_error = False + self.handler_pending = False + + def _callback_handler_pending(self, e): + signal_id, detail = GObject.signal_parse_name('signal', e, True) + self.handler_pending = GObject.signal_has_handler_pending(e, signal_id, detail, + may_be_blocked=False) def _callback(self, e): self.count += 1 - def testDisconnect(self): + def _callback_stop_emission(self, obj, prop, stop_it): + if stop_it: + obj.stop_emission_by_name('notify::prop') + self.emission_stopped = True + else: + 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: + obj.stop_emission_by_name('notasignal::baddetail') + finally: + GLib.log_set_always_fatal(old_mask) + self.emission_error = True + + def test_disconnect_by_func(self): e = E() e.connect('signal', self._callback) e.disconnect_by_func(self._callback) e.emit('signal') self.assertEqual(self.count, 0) - def testHandlerBlock(self): + def test_disconnect(self): + e = E() + handler_id = e.connect('signal', self._callback) + self.assertTrue(e.handler_is_connected(handler_id)) + e.disconnect(handler_id) + e.emit('signal') + self.assertEqual(self.count, 0) + self.assertFalse(e.handler_is_connected(handler_id)) + + def test_stop_emission_by_name(self): + e = E() + + # Sandwich a callback that stops emission in between a callback that increments + e.connect('notify::prop', self._callback_stop_emission, False) + e.connect('notify::prop', self._callback_stop_emission, True) + e.connect('notify::prop', self._callback_stop_emission, False) + + e.set_property('prop', 1234) + self.assertEqual(e.get_property('prop'), 1234) + self.assertEqual(self.count, 1) + self.assertTrue(self.emission_stopped) + + def test_stop_emission_by_name_error(self): + e = E() + + e.connect('notify::prop', self._callback_invalid_stop_emission_name) + e.set_property('prop', 1234) + self.assertTrue(self.emission_error) + + def test_handler_block(self): e = E() e.connect('signal', self._callback) e.handler_block_by_func(self._callback) e.emit('signal') self.assertEqual(self.count, 0) - def testHandlerUnBlock(self): + def test_handler_unblock(self): e = E() - signal_id = e.connect('signal', self._callback) - e.handler_block(signal_id) + handler_id = e.connect('signal', self._callback) + e.handler_block(handler_id) e.handler_unblock_by_func(self._callback) e.emit('signal') self.assertEqual(self.count, 1) - def testHandlerBlockMethod(self): + def test_handler_block_method(self): # Filed as #375589 class A: def __init__(self): @@ -272,13 +445,15 @@ class TestClosures(unittest.TestCase): self.assertEqual(inst.a, 1) gc.collect() - def testGString(self): + def test_gstring(self): class C(GObject.GObject): - __gsignals__ = { 'my_signal': (GObject.SignalFlags.RUN_LAST, GObject.TYPE_GSTRING, - (GObject.TYPE_GSTRING,)) } + __gsignals__ = {'my_signal': (GObject.SignalFlags.RUN_LAST, GObject.TYPE_GSTRING, + (GObject.TYPE_GSTRING,))} + def __init__(self, test): GObject.GObject.__init__(self) self.test = test + def do_my_signal(self, data): self.data = data self.test.assertEqual(len(data), 3) @@ -287,12 +462,39 @@ class TestClosures(unittest.TestCase): data = c.emit("my_signal", "\01\00\02") self.assertEqual(data, "\02\00\01") + def test_handler_pending(self): + obj = F() + obj.connect('signal', self._callback_handler_pending) + obj.connect('signal', self._callback) + + self.assertEqual(self.count, 0) + self.assertEqual(self.handler_pending, False) + + obj.emit('signal') + self.assertEqual(self.count, 1) + self.assertEqual(self.handler_pending, True) + + def test_signal_handlers_destroy(self): + obj = F() + obj.connect('signal', self._callback) + obj.connect('signal', self._callback) + obj.connect('signal', self._callback) + + obj.emit('signal') + self.assertEqual(self.count, 3) + + # count should remain at 3 after all handlers are destroyed + GObject.signal_handlers_destroy(obj) + obj.emit('signal') + self.assertEqual(self.count, 3) + + class SigPropClass(GObject.GObject): - __gsignals__ = { 'my_signal': (GObject.SignalFlags.RUN_FIRST, None, - (GObject.TYPE_INT,)) } + __gsignals__ = {'my_signal': (GObject.SignalFlags.RUN_FIRST, None, + (GObject.TYPE_INT,))} __gproperties__ = { - 'foo': (str, None, None, '', GObject.PARAM_WRITABLE|GObject.PARAM_CONSTRUCT), + 'foo': (str, None, None, '', GObject.PARAM_WRITABLE | GObject.PARAM_CONSTRUCT), } signal_emission_failed = False @@ -312,63 +514,151 @@ class SigPropClass(GObject.GObject): class TestSigProp(unittest.TestCase): - def testEmitInPropertySetter(self): + def test_emit_in_property_setter(self): obj = SigPropClass() - self.failIf(obj.signal_emission_failed) + self.assertFalse(obj.signal_emission_failed) -f = GObject.SignalFlags.RUN_FIRST -l = GObject.SignalFlags.RUN_LAST -float = GObject.TYPE_FLOAT -double = GObject.TYPE_DOUBLE -uint = GObject.TYPE_UINT -ulong = GObject.TYPE_ULONG class CM(GObject.GObject): __gsignals__ = dict( - test1=(f, None, ()), - test2=(l, None, (str,)), - test3=(l, int, (double,)), - test4=(f, None, (bool, _long, float, double, int, uint, ulong)), - test_float=(l, float, (float,)), - test_double=(l, double, (double, )), - test_string=(l, str, (str, )), - test_object=(l, object, (object, )), + test1=(GObject.SignalFlags.RUN_FIRST, None, ()), + 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, + 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,)), + test_int64=(GObject.SignalFlags.RUN_LAST, GObject.TYPE_INT64, (GObject.TYPE_INT64,)), + test_string=(GObject.SignalFlags.RUN_LAST, str, (str,)), + test_object=(GObject.SignalFlags.RUN_LAST, object, (object,)), + test_paramspec=(GObject.SignalFlags.RUN_LAST, GObject.ParamSpec, ()), + test_paramspec_in=(GObject.SignalFlags.RUN_LAST, GObject.ParamSpec, (GObject.ParamSpec, )), + test_gvalue=(GObject.SignalFlags.RUN_LAST, GObject.Value, (GObject.Value,)), + test_gvalue_ret=(GObject.SignalFlags.RUN_LAST, GObject.Value, (GObject.TYPE_GTYPE,)), ) + testprop = GObject.Property(type=int) + + class _TestCMarshaller: def setUp(self): self.obj = CM() testhelper.connectcallbacks(self.obj) - def testTest1(self): + def test_test1(self): self.obj.emit("test1") - def testTest2(self): + def test_test2(self): self.obj.emit("test2", "string") - def testTest3(self): + def test_test3(self): rv = self.obj.emit("test3", 42.0) self.assertEqual(rv, 20) - def testTest4(self): + def test_test4(self): self.obj.emit("test4", True, _long(10), 3.14, 1.78, 20, _long(30), _long(31)) - def testTestReturnFloat(self): + def test_float(self): rv = self.obj.emit("test-float", 1.234) - self.failUnless(rv >= 1.233999 and rv <= 1.2400001, rv) + self.assertTrue(rv >= 1.233999 and rv <= 1.2400001, rv) - def testTestReturnDouble(self): + def test_double(self): rv = self.obj.emit("test-double", 1.234) self.assertEqual(rv, 1.234) - def testTestReturnString(self): + def test_int64(self): + 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", GObject.G_MININT64) + self.assertEqual(rv, GObject.G_MININT64) + + def test_string(self): rv = self.obj.emit("test-string", "str") self.assertEqual(rv, "str") - def testTestReturnObject(self): + def test_object(self): rv = self.obj.emit("test-object", self) self.assertEqual(rv, self) + def test_paramspec(self): + rv = self.obj.emit("test-paramspec") + self.assertEqual(rv.name, "test-param") + self.assertEqual(rv.nick, "test") + + @unittest.skipUnless(hasattr(GObject, 'param_spec_boolean'), + 'too old gobject-introspection') + def test_paramspec_in(self): + rv = GObject.param_spec_boolean('mybool', 'test-bool', 'do something', + True, GObject.ParamFlags.READABLE) + + rv2 = self.obj.emit("test-paramspec-in", rv) + self.assertEqual(type(rv), type(rv2)) + self.assertEqual(rv2.name, "mybool") + self.assertEqual(rv2.nick, "test-bool") + + def test_C_paramspec(self): + self.notify_called = False + + def cb_notify(obj, prop): + self.notify_called = True + self.assertEqual(obj, self.obj) + self.assertEqual(prop.name, "testprop") + + self.obj.connect("notify", cb_notify) + self.obj.set_property("testprop", 42) + self.assertTrue(self.notify_called) + + def test_gvalue(self): + # implicit int + rv = self.obj.emit("test-gvalue", 42) + self.assertEqual(rv, 42) + + # explicit float + v = GObject.Value(GObject.TYPE_FLOAT, 1.234) + rv = self.obj.emit("test-gvalue", v) + self.assertAlmostEqual(rv, 1.234, 4) + + # implicit float + rv = self.obj.emit("test-gvalue", 1.234) + self.assertAlmostEqual(rv, 1.234, 4) + + # explicit int64 + v = GObject.Value(GObject.TYPE_INT64, GObject.G_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) + + # explicit uint64 + v = GObject.Value(GObject.TYPE_UINT64, GObject.G_MAXUINT64) + rv = self.obj.emit("test-gvalue", v) + self.assertEqual(rv, GObject.G_MAXUINT64) + + # 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) + + def test_gvalue_ret(self): + self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_INT), + GObject.G_MAXINT) + self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_UINT), + GObject.G_MAXUINT) + self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_INT64), + GObject.G_MAXINT64) + self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_UINT64), + GObject.G_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 @@ -378,12 +668,14 @@ else: print() # Test for 374653 + + class TestPyGValue(unittest.TestCase): - def testNoneNULLBoxedConversion(self): + def test_none_null_boxed_conversion(self): class C(GObject.GObject): __gsignals__ = dict(my_boxed_signal=( GObject.SignalFlags.RUN_LAST, - GObject.type_from_name('GStrv'), ())) + GObject.TYPE_STRV, ())) obj = C() obj.connect('my-boxed-signal', lambda obj: None) @@ -391,5 +683,303 @@ class TestPyGValue(unittest.TestCase): obj.emit('my-boxed-signal') assert not sys.last_type + +class TestSignalDecorator(unittest.TestCase): + class Decorated(GObject.GObject): + value = 0 + + @GObject.Signal + def pushed(self): + """this will push""" + self.value += 1 + + @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST) + def pulled(self): + self.value -= 1 + + stomped = GObject.Signal('stomped', arg_types=(int,), doc='this will stomp') + unnamed = GObject.Signal() + + class DecoratedOverride(GObject.GObject): + overridden_closure_called = False + notify_called = False + value = GObject.Property(type=int, default=0) + + @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 + + def setUp(self): + self.unnamedCalled = False + + def onUnnamed(self, obj): + self.unnamedCalled = True + + def test_get_signal_args(self): + self.assertEqual(self.Decorated.pushed.get_signal_args(), + (GObject.SignalFlags.RUN_FIRST, None, tuple(), None, None)) + self.assertEqual(self.Decorated.pulled.get_signal_args(), + (GObject.SignalFlags.RUN_LAST, None, tuple(), None, None)) + self.assertEqual(self.Decorated.stomped.get_signal_args(), + (GObject.SignalFlags.RUN_FIRST, None, (int,), None, None)) + + def test_closures_called(self): + decorated = self.Decorated() + self.assertEqual(decorated.value, 0) + decorated.pushed.emit() + self.assertEqual(decorated.value, 1) + decorated.pulled.emit() + self.assertEqual(decorated.value, 0) + + def test_signal_copy(self): + blah = self.Decorated.stomped.copy('blah') + self.assertEqual(str(blah), blah) + self.assertEqual(blah.func, self.Decorated.stomped.func) + self.assertEqual(blah.flags, self.Decorated.stomped.flags) + self.assertEqual(blah.return_type, self.Decorated.stomped.return_type) + self.assertEqual(blah.arg_types, self.Decorated.stomped.arg_types) + self.assertEqual(blah.__doc__, self.Decorated.stomped.__doc__) + + def test_doc_string(self): + # Test the two techniques for setting doc strings on the signals + # class variables, through the "doc" keyword or as the getter doc string. + self.assertEqual(self.Decorated.stomped.__doc__, 'this will stomp') + self.assertEqual(self.Decorated.pushed.__doc__, 'this will push') + + def test_unnamed_signal_gets_named(self): + self.assertEqual(str(self.Decorated.unnamed), 'unnamed') + + def test_unnamed_signal_gets_called(self): + obj = self.Decorated() + obj.connect('unnamed', self.onUnnamed) + self.assertEqual(self.unnamedCalled, False) + obj.emit('unnamed') + self.assertEqual(self.unnamedCalled, True) + + def NOtest_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) + self.assertTrue(obj.notify_called) + + +class TestSignalConnectors(unittest.TestCase): + class CustomButton(GObject.GObject): + on_notify_called = False + value = GObject.Property(type=int) + + @GObject.Signal(arg_types=(int,)) + def clicked(self, value): + self.value = value + + def setUp(self): + self.obj = None + self.value = None + + def on_clicked(self, obj, value): + self.obj = obj + self.value = value + + def test_signal_notify(self): + def on_notify(obj, param): + obj.on_notify_called = True + + obj = self.CustomButton() + obj.connect('notify', on_notify) + self.assertFalse(obj.on_notify_called) + obj.notify('value') + self.assertTrue(obj.on_notify_called) + + def test_signal_emit(self): + # standard callback connection with different forms of emit. + obj = self.CustomButton() + obj.connect('clicked', self.on_clicked) + + # vanilla + obj.emit('clicked', 1) + self.assertEqual(obj.value, 1) + self.assertEqual(obj, self.obj) + self.assertEqual(self.value, 1) + + # using class signal as param + self.obj = None + self.value = None + obj.emit(self.CustomButton.clicked, 1) + self.assertEqual(obj, self.obj) + self.assertEqual(self.value, 1) + + # using bound signal as param + self.obj = None + self.value = None + obj.emit(obj.clicked, 1) + self.assertEqual(obj, self.obj) + self.assertEqual(self.value, 1) + + # using bound signal with emit + self.obj = None + self.value = None + obj.clicked.emit(1) + self.assertEqual(obj, self.obj) + self.assertEqual(self.value, 1) + + def test_signal_class_connect(self): + obj = self.CustomButton() + obj.connect(self.CustomButton.clicked, self.on_clicked) + obj.emit('clicked', 2) + self.assertEqual(obj, self.obj) + self.assertEqual(self.value, 2) + + def test_signal_bound_connect(self): + obj = self.CustomButton() + obj.clicked.connect(self.on_clicked) + obj.emit('clicked', 3) + self.assertEqual(obj, self.obj) + self.assertEqual(self.value, 3) + + +class TestInstallSignals(unittest.TestCase): + # These tests only test how signalhelper.install_signals works + # with the __gsignals__ dict and therefore does not need to use + # GObject as a base class because that would automatically call + # install_signals within the meta-class. + class Base(object): + __gsignals__ = {'test': (0, None, tuple())} + + class Sub1(Base): + pass + + class Sub2(Base): + @GObject.Signal + def sub2test(self): + pass + + def setUp(self): + self.assertEqual(len(self.Base.__gsignals__), 1) + signalhelper.install_signals(self.Base) + self.assertEqual(len(self.Base.__gsignals__), 1) + + def test_subclass_gets_empty_gsignals_dict(self): + # Installing signals will add the __gsignals__ dict to a class + # if it doesn't already exists. + self.assertFalse('__gsignals__' in self.Sub1.__dict__) + signalhelper.install_signals(self.Sub1) + self.assertTrue('__gsignals__' in self.Sub1.__dict__) + # Sub1 should only contain an empty signals dict, this tests: + # https://bugzilla.gnome.org/show_bug.cgi?id=686496 + self.assertEqual(self.Sub1.__dict__['__gsignals__'], {}) + + def test_subclass_with_decorator_gets_gsignals_dict(self): + self.assertFalse('__gsignals__' in self.Sub2.__dict__) + signalhelper.install_signals(self.Sub2) + self.assertTrue('__gsignals__' in self.Sub2.__dict__) + self.assertEqual(len(self.Base.__gsignals__), 1) + self.assertEqual(len(self.Sub2.__gsignals__), 1) + self.assertTrue('sub2test' in self.Sub2.__gsignals__) + + # Make sure the vfunc was added + 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'] + + def test_annotations(self): + self.assertEqual(signalhelper.get_signal_annotations(self.AnnotatedClass.sig1.func), + (None, (int, float))) + self.assertEqual(signalhelper.get_signal_annotations(self.AnnotatedClass.sig2_with_return.func), + (str, (int, float))) + + self.assertEqual(self.AnnotatedClass.sig2_with_return.get_signal_args(), + (GObject.SignalFlags.RUN_LAST, str, (int, float), None, None)) + self.assertEqual(self.AnnotatedClass.sig2_with_return.arg_types, + (int, float)) + self.assertEqual(self.AnnotatedClass.sig2_with_return.return_type, + str) + + def test_emit_return(self): + obj = self.AnnotatedClass() + self.assertEqual(obj.sig2_with_return.emit(1, 2.0), + 'test') + + +class TestSignalModuleLevelFunctions(unittest.TestCase): + def test_signal_list_ids_with_invalid_type(self): + with self.assertRaisesRegex(TypeError, 'type must be instantiable or an interface.*'): + GObject.signal_list_ids(GObject.TYPE_INVALID) + + def test_signal_list_ids(self): + with self.assertRaisesRegex(TypeError, 'type must be instantiable or an interface.*'): + GObject.signal_list_ids(GObject.TYPE_INT) + + ids = GObject.signal_list_ids(C) + self.assertEqual(len(ids), 1) + # Note canonicalized names + self.assertEqual(GObject.signal_name(ids[0]), 'my-signal') + # There is no signal 0 in gobject + self.assertEqual(GObject.signal_name(0), None) + + def test_signal_lookup_with_invalid_type(self): + with self.assertRaisesRegex(TypeError, 'type must be instantiable or an interface.*'): + GObject.signal_lookup('NOT_A_SIGNAL_NAME', GObject.TYPE_INVALID) + + def test_signal_lookup(self): + ids = GObject.signal_list_ids(C) + self.assertEqual(ids[0], GObject.signal_lookup('my_signal', C)) + self.assertEqual(ids[0], GObject.signal_lookup('my-signal', C)) + + with self.assertRaisesRegex(TypeError, 'type must be instantiable or an interface.*'): + GObject.signal_lookup('NOT_A_SIGNAL_NAME', GObject.TYPE_INT) + + # Invalid signal names return 0 instead of raising + self.assertEqual(GObject.signal_lookup('NOT_A_SIGNAL_NAME', C), + 0) + + def test_signal_query(self): + my_signal_id, = GObject.signal_list_ids(C) + + # Form is: (id, name, gtype, arg_count, return_type, (arg_type1, ...)) + my_signal_expected_query_result = [my_signal_id, 'my-signal', C.__gtype__, + 1, GObject.TYPE_NONE, (GObject.TYPE_INT,)] + # signal_query(name, type) + self.assertEqual(list(GObject.signal_query('my-signal', C)), my_signal_expected_query_result) + # signal_query(signal_id) + self.assertEqual(list(GObject.signal_query(my_signal_id)), my_signal_expected_query_result) + # invalid query returns None instead of raising + self.assertEqual(GObject.signal_query(0), None) + self.assertEqual(GObject.signal_query('NOT_A_SIGNAL', C), + None) + + if __name__ == '__main__': unittest.main() diff --git a/tests/test_source.py b/tests/test_source.py index ad052cc..d0e28e4 100644 --- a/tests/test_source.py +++ b/tests/test_source.py @@ -1,8 +1,11 @@ # -*- Mode: Python -*- import unittest +import warnings + +from gi.repository import GLib, GObject +from gi import PyGIDeprecationWarning -from gi.repository import GLib class Idle(GLib.Idle): def __init__(self, loop): @@ -42,25 +45,35 @@ class TestSource(unittest.TestCase): timeout.set_callback(self.timeout_callback, loop) timeout.attach() - def testSources(self): + def test_sources(self): loop = GLib.MainLoop() self.setup_timeout(loop) idle = Idle(loop) + self.assertEqual(idle.get_context(), None) idle.attach() + self.assertEqual(idle.get_context(), GLib.main_context_default()) self.pos = 0 m = MySource() + self.assertEqual(m.get_context(), None) m.set_callback(self.my_callback, loop) m.attach() + self.assertEqual(m.get_context(), GLib.main_context_default()) loop.run() - assert self.pos >= 0 and idle.count >= 0 + m.destroy() + idle.destroy() + + self.assertGreater(self.pos, 0) + self.assertGreaterEqual(idle.count, 0) + self.assertTrue(m.is_destroyed()) + self.assertTrue(idle.is_destroyed()) - def testSourcePrepare(self): + def test_source_prepare(self): # this test may not terminate if prepare() is wrapped incorrectly dispatched = [False] loop = GLib.MainLoop() @@ -88,11 +101,272 @@ class TestSource(unittest.TestCase): assert dispatched[0] + def test_is_destroyed_simple(self): + s = GLib.Source() + + self.assertFalse(s.is_destroyed()) + s.destroy() + self.assertTrue(s.is_destroyed()) + + c = GLib.MainContext() + s = GLib.Source() + s.attach(c) + self.assertFalse(s.is_destroyed()) + s.destroy() + self.assertTrue(s.is_destroyed()) + + def test_is_destroyed_context(self): + def f(): + c = GLib.MainContext() + s = GLib.Source() + s.attach(c) + return s + + s = f() + 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) + + def test_recurse_property(self): + s = GLib.Idle() + self.assertTrue(s.can_recurse in [False, True]) + s.can_recurse = False + self.assertFalse(s.can_recurse) + + def test_priority(self): + s = GLib.Idle() + self.assertEqual(s.priority, GLib.PRIORITY_DEFAULT_IDLE) + s.priority = GLib.PRIORITY_HIGH + self.assertEqual(s.priority, GLib.PRIORITY_HIGH) + + s = GLib.Idle(GLib.PRIORITY_LOW) + self.assertEqual(s.priority, GLib.PRIORITY_LOW) + + s = GLib.Timeout(1, GLib.PRIORITY_LOW) + self.assertEqual(s.priority, GLib.PRIORITY_LOW) + + s = GLib.Source() + self.assertEqual(s.priority, GLib.PRIORITY_DEFAULT) + + def test_get_current_time(self): + # Note, deprecated API + s = GLib.Idle() + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + time = s.get_current_time() + self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning)) + + self.assertTrue(isinstance(time, float)) + # plausibility check, and check magnitude of result + self.assertGreater(time, 1300000000.0) + self.assertLess(time, 2000000000.0) + + def test_add_remove_poll(self): + # FIXME: very shallow test, only verifies the API signature + pollfd = GLib.PollFD(99, GLib.IOCondition.IN | GLib.IOCondition.HUP) + self.assertEqual(pollfd.fd, 99) + source = GLib.Source() + source.add_poll(pollfd) + source.remove_poll(pollfd) + + def test_out_of_scope_before_dispatch(self): + # https://bugzilla.gnome.org/show_bug.cgi?id=504337 + GLib.Timeout(20) + GLib.Idle() + + def test_finalize(self): + self.dispatched = False + self.finalized = False + + class S(GLib.Source): + def prepare(s): + return (True, 1) + + def dispatch(s, callback, args): + self.dispatched = True + return False -class TestTimeout(unittest.TestCase): - def test504337(self): - timeout_source = GLib.Timeout(20) - idle_source = GLib.Idle() + def finalize(s): + self.finalized = True + + source = S() + id = source.attach() + print('source id:', id) + self.assertFalse(self.finalized) + self.assertFalse(source.is_destroyed()) + + while source.get_context().iteration(False): + pass + + source.destroy() + self.assertTrue(self.dispatched) + self.assertFalse(self.finalized) + self.assertTrue(source.is_destroyed()) + del source + self.assertTrue(self.finalized) + + def test_extra_init_args(self): + class SourceWithInitArgs(GLib.Source): + def __init__(self, arg, kwarg=None): + super(SourceWithInitArgs, self).__init__() + self.arg = arg + self.kwarg = kwarg + + source = SourceWithInitArgs(1, kwarg=2) + self.assertEqual(source.arg, 1) + self.assertEqual(source.kwarg, 2) + + +class TestUserData(unittest.TestCase): + def test_idle_no_data(self): + ml = GLib.MainLoop() + + def cb(): + ml.quit() + id = GLib.idle_add(cb) + self.assertEqual(ml.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_DEFAULT_IDLE) + ml.run() + + def test_timeout_no_data(self): + ml = GLib.MainLoop() + + def cb(): + ml.quit() + id = GLib.timeout_add(50, cb) + self.assertEqual(ml.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_DEFAULT) + ml.run() + + def test_idle_data(self): + ml = GLib.MainLoop() + + def cb(data): + data['called'] = True + ml.quit() + data = {} + id = GLib.idle_add(cb, data) + self.assertEqual(ml.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_DEFAULT_IDLE) + ml.run() + self.assertTrue(data['called']) + + def test_idle_multidata(self): + ml = GLib.MainLoop() + + def cb(data, data2): + data['called'] = True + data['data2'] = data2 + ml.quit() + data = {} + id = GLib.idle_add(cb, data, 'hello') + self.assertEqual(ml.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_DEFAULT_IDLE) + ml.run() + self.assertTrue(data['called']) + self.assertEqual(data['data2'], 'hello') + + def test_timeout_data(self): + ml = GLib.MainLoop() + + def cb(data): + data['called'] = True + ml.quit() + data = {} + id = GLib.timeout_add(50, cb, data) + self.assertEqual(ml.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_DEFAULT) + ml.run() + self.assertTrue(data['called']) + + def test_timeout_multidata(self): + ml = GLib.MainLoop() + + def cb(data, data2): + data['called'] = True + data['data2'] = data2 + ml.quit() + data = {} + id = GLib.timeout_add(50, cb, data, 'hello') + self.assertEqual(ml.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_DEFAULT) + ml.run() + self.assertTrue(data['called']) + self.assertEqual(data['data2'], 'hello') + + def test_idle_no_data_priority(self): + ml = GLib.MainLoop() + + def cb(): + ml.quit() + id = GLib.idle_add(cb, priority=GLib.PRIORITY_HIGH) + self.assertEqual(ml.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_HIGH) + ml.run() + + def test_timeout_no_data_priority(self): + ml = GLib.MainLoop() + + def cb(): + ml.quit() + id = GLib.timeout_add(50, cb, priority=GLib.PRIORITY_HIGH) + self.assertEqual(ml.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_HIGH) + ml.run() + + def test_idle_data_priority(self): + ml = GLib.MainLoop() + + def cb(data): + data['called'] = True + ml.quit() + data = {} + id = GLib.idle_add(cb, data, priority=GLib.PRIORITY_HIGH) + self.assertEqual(ml.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_HIGH) + ml.run() + self.assertTrue(data['called']) + + def test_timeout_data_priority(self): + ml = GLib.MainLoop() + + def cb(data): + data['called'] = True + ml.quit() + data = {} + id = GLib.timeout_add(50, cb, data, priority=GLib.PRIORITY_HIGH) + self.assertEqual(ml.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_HIGH) + ml.run() + self.assertTrue(data['called']) + + def cb_no_data(self): + self.loop.quit() + + def test_idle_method_callback_no_data(self): + self.loop = GLib.MainLoop() + GLib.idle_add(self.cb_no_data) + self.loop.run() + + def cb_with_data(self, data): + data['called'] = True + self.loop.quit() + + def test_idle_method_callback_with_data(self): + self.loop = GLib.MainLoop() + data = {} + GLib.idle_add(self.cb_with_data, data) + self.loop.run() + self.assertTrue(data['called']) if __name__ == '__main__': diff --git a/tests/test_subprocess.py b/tests/test_subprocess.py index 14c6283..ef4c35e 100644 --- a/tests/test_subprocess.py +++ b/tests/test_subprocess.py @@ -1,23 +1,146 @@ # -*- Mode: Python -*- import sys +import os import unittest +import warnings from gi.repository import GLib +from gi import PyGIDeprecationWarning + class TestProcess(unittest.TestCase): - def _child_watch_cb(self, pid, condition, data): - self.data = data - self.loop.quit() + 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() + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + GLib.child_watch_add(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.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() + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + id = GLib.child_watch_add(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.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() + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + id = GLib.child_watch_add(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) + + def test_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() + id = GLib.child_watch_add(GLib.PRIORITY_HIGH, pid, cb) + self.assertEqual(self.loop.get_context().find_source_by_id(id).priority, + GLib.PRIORITY_HIGH) + self.loop.run() + self.assertEqual(self.status, 0) + + def test_child_watch_with_data(self): + def cb(pid, status, data): + self.status = status + self.data = data + self.loop.quit() - def testChildWatch(self): self.data = None + self.status = None self.loop = GLib.MainLoop() argv = [sys.executable, '-c', 'import sys'] pid, stdin, stdout, stderr = GLib.spawn_async( - argv, flags=GLib.SPAWN_DO_NOT_REAP_CHILD) + argv, flags=GLib.SpawnFlags.DO_NOT_REAP_CHILD) + self.assertEqual(stdin, None) + self.assertEqual(stdout, None) + self.assertEqual(stderr, None) + self.assertNotEqual(pid, 0) pid.close() - GLib.child_watch_add(pid, self._child_watch_cb, 12345) + id = GLib.child_watch_add(GLib.PRIORITY_HIGH, pid, cb, 12345) + 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_spawn_async_fds(self): + pid, stdin, stdout, stderr = GLib.spawn_async( + ['cat'], flags=GLib.SpawnFlags.SEARCH_PATH, standard_input=True, + standard_output=True, standard_error=True) + 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) + pid.close() + 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!'], + flags=GLib.SpawnFlags.SEARCH_PATH, standard_output=True) + self.assertEqual(stdin, None) + self.assertEqual(stderr, None) + out = os.read(stdout, 50) + os.close(stdout) + pid.close() + 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) diff --git a/tests/test_thread.py b/tests/test_thread.py index fa52dfa..3d0557e 100644 --- a/tests/test_thread.py +++ b/tests/test_thread.py @@ -5,6 +5,7 @@ import testhelper from gi.repository import GLib + class TestThread(unittest.TestCase): def setUp(self): self.main = GLib.MainLoop() @@ -19,7 +20,7 @@ class TestThread(unittest.TestCase): self.obj.connect('from-thread', self.from_thread_cb) self.obj.emit('emit-signal') - def testExtensionModule(self): + def test_extension_module(self): GLib.idle_add(self.idle_cb) GLib.timeout_add(50, self.timeout_cb) self.main.run() diff --git a/tests/test_uris.py b/tests/test_uris.py deleted file mode 100644 index 8174324..0000000 --- a/tests/test_uris.py +++ /dev/null @@ -1,15 +0,0 @@ -import unittest - -from gi.repository import GLib - -class TestUris(unittest.TestCase): - def testExtractUris(self): - uri_list_text = "# urn:isbn:0-201-08372-8\n" + \ - "http://www.huh.org/books/foo.html\n" + \ - "http://www.huh.org/books/foo.pdf\n" + \ - "ftp://ftp.foo.org/books/foo.txt\n" - uri_list = GLib.uri_list_extract_uris(uri_list_text) - assert uri_list[0] == "http://www.huh.org/books/foo.html" - assert uri_list[1] == "http://www.huh.org/books/foo.pdf" - assert uri_list[2] == "ftp://ftp.foo.org/books/foo.txt" - diff --git a/tests/testhelpermodule.c b/tests/testhelpermodule.c index 592c503..9b198c3 100644 --- a/tests/testhelpermodule.c +++ b/tests/testhelpermodule.c @@ -7,14 +7,11 @@ #include <pyglib-python-compat.h> -static PyTypeObject *_PyGObject_Type; -#define PyGObject_Type (*_PyGObject_Type) - static PyObject * _wrap_TestInterface__do_iface_method(PyObject *cls, PyObject *args, PyObject *kwargs); -GType +static GType test_type_get_type(void) { static GType gtype = 0; @@ -322,6 +319,16 @@ test_double_callback (GObject *object, double d) return d; } +static gint64 +test_int64_callback (GObject *object, gint64 i) +{ + g_return_val_if_fail (G_IS_OBJECT (object), -1); + + if (i == G_MAXINT64) + return i-1; + return i; +} + static char * test_string_callback (GObject *object, char *s) { @@ -339,7 +346,69 @@ test_object_callback (GObject *object, GObject *o) return o; } -void +static GParamSpec * +test_paramspec_callback (GObject *object) +{ + g_return_val_if_fail (G_IS_OBJECT (object), NULL); + + return g_param_spec_boolean ("test-param", "test", "test boolean", TRUE, G_PARAM_READABLE); +} + +static GValue * +test_gvalue_callback (GObject *object, const GValue *v) +{ + GValue *ret = g_malloc0 (sizeof (GValue)); + + g_return_val_if_fail (G_IS_OBJECT (object), NULL); + g_return_val_if_fail (G_IS_VALUE (v), NULL); + + g_value_init (ret, G_VALUE_TYPE (v)); + g_value_copy (v, ret); + return ret; +} + +static GValue * +test_gvalue_ret_callback (GObject *object, GType type) +{ + GValue *ret = g_malloc0 (sizeof (GValue)); + + g_return_val_if_fail (G_IS_OBJECT (object), NULL); + + g_value_init (ret, type); + + switch (type) { + case G_TYPE_INT: + g_value_set_int(ret, G_MAXINT); + break; + case G_TYPE_INT64: + g_value_set_int64(ret, G_MAXINT64); + break; + case G_TYPE_UINT: + g_value_set_uint(ret, G_MAXUINT); + break; + case G_TYPE_UINT64: + g_value_set_uint64(ret, G_MAXUINT64); + break; + case G_TYPE_STRING: + g_value_set_string(ret, "hello"); + break; + default: + g_critical ("test_gvalue_ret_callback() does not support type %s", g_type_name (type)); + } + + return ret; +} + +static GParamSpec * +test_paramspec_in_callback (GObject *object, GParamSpec *p) +{ + g_return_val_if_fail (G_IS_OBJECT (object), NULL); + g_return_val_if_fail (G_IS_PARAM_SPEC (p), NULL); + + return p; +} + +static void connectcallbacks (GObject *object) { @@ -374,6 +443,10 @@ connectcallbacks (GObject *object) G_CALLBACK (test_double_callback), NULL); g_signal_connect (G_OBJECT (object), + "test_int64", + G_CALLBACK (test_int64_callback), + NULL); + g_signal_connect (G_OBJECT (object), "test_string", G_CALLBACK (test_string_callback), NULL); @@ -381,6 +454,22 @@ connectcallbacks (GObject *object) "test_object", G_CALLBACK (test_object_callback), NULL); + g_signal_connect (G_OBJECT (object), + "test_paramspec", + G_CALLBACK (test_paramspec_callback), + NULL); + g_signal_connect (G_OBJECT (object), + "test_gvalue", + G_CALLBACK (test_gvalue_callback), + NULL); + g_signal_connect (G_OBJECT (object), + "test_gvalue_ret", + G_CALLBACK (test_gvalue_ret_callback), + NULL); + g_signal_connect (G_OBJECT (object), + "test_paramspec_in", + G_CALLBACK (test_paramspec_in_callback), + NULL); } static PyObject * @@ -451,7 +540,6 @@ _wrap_test_gerror_exception(PyObject *self, PyObject *args) return NULL; } - Py_DECREF(py_method); Py_DECREF(py_args); Py_DECREF(py_ret); @@ -523,21 +611,11 @@ PYGLIB_MODULE_START(testhelper, "testhelper") { PyObject *m, *d; - g_thread_init(NULL); pygobject_init(-1, -1, -1); d = PyModule_GetDict(module); - if ((m = PyImport_ImportModule("gi._gobject")) != NULL) { - PyObject *moddict = PyModule_GetDict(m); - - _PyGObject_Type = (PyTypeObject *)PyDict_GetItemString(moddict, "GObject"); - if (_PyGObject_Type == NULL) { - PyErr_SetString(PyExc_ImportError, - "cannot import name GObject from gobject"); - return PYGLIB_MODULE_ERROR_RETURN; - } - } else { + if ((m = PyImport_ImportModule("gi.repository.GObject")) == NULL) { PyErr_SetString(PyExc_ImportError, "could not import gobject"); return PYGLIB_MODULE_ERROR_RETURN; diff --git a/tests/testmodule.py b/tests/testmodule.py index c4132c5..3da8ed5 100644 --- a/tests/testmodule.py +++ b/tests/testmodule.py @@ -1,5 +1,6 @@ from gi.repository import GObject + class PyGObject(GObject.GObject): __gtype_name__ = 'PyGObject' __gproperties__ = { |