libgimp: new unit testing framework for libgimp.

With Python binding, it gets very easy to test new functions. I've been
wondering if we need C counterparts, but really since it's a GObject
Introspection binding, if a function succeeds there, it should also succeed in C
code.

For now, I'm testing a few of GimpPalette API. Not all of it yet. Also I test
both the direct C binding and PDB procedure since in some cases, one or the
other may not properly working. See #10885.
This commit is contained in:
Jehan 2024-02-28 22:27:28 +01:00
parent 3f79f3589d
commit 7b43a7492f
6 changed files with 163 additions and 4 deletions

View file

@ -0,0 +1,27 @@
#!/bin/sh
GIMP_EXE=$1
TEST_FILE=$2
SRC_DIR=`dirname $TEST_FILE`
SRC_DIR=`realpath $SRC_DIR`
if [ ! -f "$TEST_FILE" ]; then
echo "ERROR: file '$TEST_FILE' does not exist!"
return 1;
fi
first_char=`head -c1 "$TEST_FILE"`
if [ $first_char != '#' ]; then
# Note: I don't actually care that it's a shebang, just that it's a comment,
# hence a useless line, because I'm going to remove it and replace it with
# gimp_assert() import line.
# This will make much easier to debug tests with meaningful line numbers.
echo "ERROR: file '$TEST_FILE' should start with a shebang: #!/usr/bin/env python3"
return 1;
fi
header="import os; import sys; sys.path.insert(0, '$SRC_DIR'); from pygimp.utils import gimp_assert;"
header="$header import pygimp.utils; pygimp.utils.gimp_test_filename = '$TEST_FILE'"
(echo "$header" && tail -n +2 "$TEST_FILE") | "$GIMP_EXE" -nis --batch-interpreter "python-fu-eval" -b - --quit

46
libgimp/tests/meson.build Normal file
View file

@ -0,0 +1,46 @@
# XXX: we have a bunch of (manually run?) tests inside libgimp/test/.
# These should either be deleted or transformed into real unit tests.
tests = [
'palette',
]
# make GIMP runnable without being installed.
env=environment()
menu_paths=meson.project_build_root() / 'menus:' + meson.project_source_root() / 'menus'
env.set('GIMP_TESTING_MENUS_PATH', menu_paths)
env.set('GIMP_TESTING_PLUGINDIRS', meson.project_build_root() / 'plug-ins:')
env.append('GIMP_TESTING_PLUGINDIRS', meson.project_build_root() / 'plug-ins/python')
env.append('GIMP_TESTING_PLUGINDIRS', meson.project_build_root() / 'plug-ins/common/test-plug-ins/')
env.prepend('GI_TYPELIB_PATH', meson.project_build_root() / 'libgimp')
env.prepend('LD_LIBRARY_PATH', meson.project_build_root() / 'libgimp')
env.prepend('LD_LIBRARY_PATH', meson.project_build_root() / 'libgimpbase')
env.prepend('LD_LIBRARY_PATH', meson.project_build_root() / 'libgimpcolor')
env.prepend('LD_LIBRARY_PATH', meson.project_build_root() / 'libgimpconfig')
env.prepend('LD_LIBRARY_PATH', meson.project_build_root() / 'libgimpmath')
env.prepend('LD_LIBRARY_PATH', meson.project_build_root() / 'libgimpmodule')
env.prepend('LD_LIBRARY_PATH', meson.project_build_root() / 'libgimpthumb')
env.prepend('LD_LIBRARY_PATH', meson.project_build_root() / 'libgimpwidgets')
env.set('GIMP_TESTING_ABS_TOP_SRCDIR', meson.project_source_root())
if enable_console_bin
gimp_exe=gimpconsole_exe
else
gimp_exe=gimpmain_exe
endif
run_python_test = find_program('./libgimp-run-python-test.sh')
foreach test_name : tests
basename = 'test-' + test_name
py_test = meson.current_source_dir() / basename + '.py'
test(test_name, run_python_test,
args: [ gimp_exe, py_test ],
env: env,
suite: ['libgimp', 'python3'],
timeout: 60)
endforeach

21
libgimp/tests/pygimp/utils.py Executable file
View file

@ -0,0 +1,21 @@
#!/usr/bin/env python3
import inspect
import sys
gimp_test_filename = ''
def gimp_assert(subtest_name, test):
'''
Please call me like this, for instance, if I were testing if gimp_image_new()
succeeded:
gimp_assert("gimp_image_new()", image is not None)
'''
if not test:
frames = inspect.getouterframes(inspect.currentframe())
sys.stderr.write("\n**** START FAILED SUBTEST *****\n")
sys.stderr.write("ERROR: {} - line {}: {}\n".format(gimp_test_filename,
frames[1].lineno,
subtest_name))
sys.stderr.write("***** END FAILED SUBTEST ******\n\n")
assert test

View file

@ -0,0 +1,55 @@
#!/usr/bin/env python3
pal = Gimp.Palette.get_by_name('Bears')
gimp_assert('gimp_palette_get_by_name()', type(pal) == Gimp.Palette)
pal2 = Gimp.Palette.get_by_name('Bears')
gimp_assert('gimp_palette_get_by_name() is unique', pal == pal2)
colors = pal.get_colors()
gimp_assert('gimp_palette_get_colors()', len(colors) == 256 and type(colors[0]) == Gegl.Color)
n_colors = pal.get_color_count()
gimp_assert('gimp_palette_get_color_count()', len(colors) == n_colors)
# Run the same tests through PDB:
proc = Gimp.get_pdb().lookup_procedure('gimp-palette-get-by-name')
config = proc.create_config()
config.set_property('name', 'Bears')
result = proc.run(config)
status = result.index(0)
gimp_assert('gimp-palette-get-by-name', status == Gimp.PDBStatusType.SUCCESS)
pal2 = result.index(1)
gimp_assert('gimp-palette-get-by-name and gimp_palette_get_by_name() get identical result', pal == pal2)
proc = Gimp.get_pdb().lookup_procedure('gimp-palette-get-colors')
config = proc.create_config()
config.set_property('palette', pal)
result = proc.run(config)
status = result.index(0)
gimp_assert('gimp-palette-get-colors', status == Gimp.PDBStatusType.SUCCESS)
colors = result.index(1)
# XXX This test is actually what happens right now, but not what should happen.
# See: https://gitlab.gnome.org/GNOME/gimp/-/issues/10885#note_2030308
# And: https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/492
# If some day this test fails, and in particular if it can return a list of
# GeglColor, then we should remove the test and deprecate
# gimp_value_array_get_color_array() in favor of the generic
# gimp_value_array_index().
gimp_assert('gimp-palette-get-colors', type(colors) == GObject.GBoxed)
colors = result.get_color_array(1)
gimp_assert('gimp_palette_get_colors()', type(colors) == list and len(colors) == 256 and type(colors[0]) == Gegl.Color)
proc = Gimp.get_pdb().lookup_procedure('gimp-palette-get-color-count')
config = proc.create_config()
config.set_property('palette', pal)
result = proc.run(config)
status = result.index(0)
gimp_assert('gimp-palette-get-color-count', status == Gimp.PDBStatusType.SUCCESS)
n_colors = result.index(1)
gimp_assert('gimp_palette_get_color_count()', len(colors) == n_colors)

View file

@ -213,10 +213,17 @@ static gchar * gimp_config_path_unexpand_only (const gchar *path) G_GNUC
gchar *
gimp_config_build_data_path (const gchar *name)
{
return g_strconcat ("${gimp_dir}", G_DIR_SEPARATOR_S, name,
G_SEARCHPATH_SEPARATOR_S,
"${gimp_data_dir}", G_DIR_SEPARATOR_S, name,
NULL);
if (g_getenv ("GIMP_TESTING_ABS_TOP_SRCDIR"))
/* Unit-testing mode: the source directory is where data is found. */
return g_strconcat (g_getenv ("GIMP_TESTING_ABS_TOP_SRCDIR"),
G_DIR_SEPARATOR_S, "data",
G_DIR_SEPARATOR_S, name,
NULL);
else
return g_strconcat ("${gimp_dir}", G_DIR_SEPARATOR_S, name,
G_SEARCHPATH_SEPARATOR_S,
"${gimp_data_dir}", G_DIR_SEPARATOR_S, name,
NULL);
}
/**

View file

@ -1840,6 +1840,9 @@ subdir('plug-ins')
subdir('app')
subdir('app-tools')
# Unit testing
subdir('libgimp/tests')
# Docs
subdir('docs')
subdir('devel-docs')