Add run-js-test executable to run tests

ST makes use of GTK+ for input methods and for icon themes; therefore
we have need to initialize GTK+ in order to test these parts of Clutter.

Instead of LD_PRELOADING our module, use a separately compiled executable
that links to the UI components in GNOME Shell, initializes Clutter and
GTK+ and hooks them together.

Getting all the symbols from St and the GUI components exported for
use via GJS requires a bit of contortion: we need to actually link the
St convenience library into a shared library and link the executable
to that since there is no way with libtool to take a convenience library
and put all its symbols into an executable --whole-archive style.

https://bugzilla.gnome.org/show_bug.cgi?id=633657
This commit is contained in:
Owen W. Taylor 2010-10-31 15:28:06 -04:00
parent 86f3a637f1
commit c98103ffc8
6 changed files with 182 additions and 6 deletions

1
.gitignore vendored
View File

@ -46,6 +46,7 @@ src/Makefile.in
src/gnomeshell-taskpanel src/gnomeshell-taskpanel
src/gnome-shell src/gnome-shell
src/gnome-shell-clock-preferences src/gnome-shell-clock-preferences
src/run-js-test
src/test-recorder src/test-recorder
src/test-recorder.ogg src/test-recorder.ogg
src/test-theme src/test-theme

View File

@ -93,6 +93,8 @@ PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-3.0)
PKG_CHECK_MODULES(TRAY, gtk+-3.0) PKG_CHECK_MODULES(TRAY, gtk+-3.0)
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0) PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
PKG_CHECK_MODULES(JS_TEST, clutter-x11-1.0 gjs-1.0 gobject-introspection-1.0 gtk+-3.0)
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
# FIXME: metacity-plugins.pc should point directly to its .gir file # FIXME: metacity-plugins.pc should point directly to its .gir file
MUTTER_LIB_DIR=`$PKG_CONFIG --variable=libdir mutter-plugins` MUTTER_LIB_DIR=`$PKG_CONFIG --variable=libdir mutter-plugins`

View File

@ -117,6 +117,8 @@ libgnome_shell_la_SOURCES = \
libgnome_shell_la_gir_sources = \ libgnome_shell_la_gir_sources = \
$(filter-out %-private.h $(shell_recorder_non_gir_sources), $(shell_public_headers_h) $(libgnome_shell_la_SOURCES)) $(filter-out %-private.h $(shell_recorder_non_gir_sources), $(shell_public_headers_h) $(libgnome_shell_la_SOURCES))
########################################
shell_recorder_sources = \ shell_recorder_sources = \
shell-recorder.c \ shell-recorder.c \
shell-recorder.h shell-recorder.h
@ -139,6 +141,35 @@ test_recorder_SOURCES = \
test-recorder.c test-recorder.c
endif BUILD_RECORDER endif BUILD_RECORDER
########################################
# In order to run the interactive tests for GUI components, we need to have
# an executable that exports the St components. Libtool doesn't have a way
# to include all the symbols from a convenience library into a executable
# so what we do is build a small uninstalled library that pulls in the
# St convenience library and link the test running program to that.
noinst_LTLIBRARIES += libjs-test.la
libjs_test_la_LDFLAGS = -rpath $(libdir)
libjs_test_la_CPPFLAGS = $(JS_TEST_CFLAGS)
libjs_test_la_LIBADD = $(JS_TEST_LIBS) libst-1.0.la
# The tests use or reference a couple of Shell classes
libjs_test_la_SOURCES = \
shell-generic-container.c \
shell-perf-log.c
noinst_PROGRAMS += run-js-test
run_js_test_CPPFLAGS = $(JS_TEST_CFLAGS)
run_js_test_LDADD = $(EST_UI_LIBS) libjs-test.la
run_js_test_LDFLAGS = -export-dynamic
run_js_test_SOURCES = \
run-js-test.c
########################################
shell-marshal.h: stamp-shell-marshal.h shell-marshal.h: stamp-shell-marshal.h
@true @true

144
src/run-js-test.c Normal file
View File

@ -0,0 +1,144 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Based on gjs/console.c from GJS
*
* Copyright (c) 2008 litl, LLC
* Copyright (c) 2010 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <config.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <clutter/x11/clutter-x11.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <gjs/gjs.h>
static char **include_path = NULL;
static char *command = NULL;
static GOptionEntry entries[] = {
{ "command", 'c', 0, G_OPTION_ARG_STRING, &command, "Program passed in as a string", "COMMAND" },
{ "include-path", 'I', 0, G_OPTION_ARG_STRING_ARRAY, &include_path, "Add the directory DIR to the list of directories to search for js files.", "DIR" },
{ NULL }
};
static GdkFilterReturn
event_filter (GdkXEvent *xevent,
GdkEvent *event,
gpointer data)
{
XEvent *xev = (XEvent *)xevent;
if (clutter_x11_handle_event (xev) == CLUTTER_X11_FILTER_CONTINUE)
return GDK_FILTER_CONTINUE;
else
return GDK_FILTER_REMOVE;
}
int
main(int argc, char **argv)
{
char *command_line;
GOptionContext *context;
ClutterActor *stage;
GError *error = NULL;
GjsContext *js_context;
char *script;
const char *filename;
char *title;
gsize len;
int code;
g_thread_init (NULL);
gtk_init (&argc, &argv);
clutter_x11_set_display (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
clutter_x11_disable_event_retrieval ();
clutter_init (&argc, &argv);
gdk_window_add_filter (NULL, event_filter, NULL);
context = g_option_context_new (NULL);
/* pass unknown through to the JS script */
g_option_context_set_ignore_unknown_options (context, TRUE);
g_option_context_add_main_entries (context, entries, NULL);
if (!g_option_context_parse (context, &argc, &argv, &error))
g_error ("option parsing failed: %s", error->message);
setlocale (LC_ALL, "");
g_type_init ();
command_line = g_strjoinv (" ", argv);
g_debug ("Command line: %s", command_line);
g_free (command_line);
g_debug ("Creating new context to eval console script");
js_context = gjs_context_new_with_search_path (include_path);
/* prepare command line arguments */
if (!gjs_context_define_string_array (js_context, "ARGV",
argc - 2, (const char**)argv + 2,
&error)) {
g_printerr ("Failed to defined ARGV: %s", error->message);
exit (1);
}
if (command != NULL) {
script = command;
len = strlen (script);
filename = "<command line>";
} else if (argc <= 1) {
script = g_strdup ("const Console = imports.console; Console.interact();");
len = strlen (script);
filename = "<stdin>";
} else /*if (argc >= 2)*/ {
error = NULL;
if (!g_file_get_contents (argv[1], &script, &len, &error)) {
g_printerr ("%s\n", error->message);
exit (1);
}
filename = argv[1];
}
stage = clutter_stage_get_default ();
title = g_filename_display_basename (filename);
clutter_stage_set_title (CLUTTER_STAGE (stage), title);
g_free (title);
/* evaluate the script */
error = NULL;
if (!gjs_context_eval (js_context, script, len,
filename, &code, &error)) {
g_free (script);
g_printerr ("%s\n", error->message);
exit (1);
}
g_free (script);
exit (code);
}

View File

@ -11,7 +11,7 @@ debug=
for arg in $@ ; do for arg in $@ ; do
case $arg in case $arg in
-g|--debug) -g|--debug)
debug="gdb --args" debug="libtool --mode=execute gdb --args"
;; ;;
-v|--verbose) -v|--verbose)
verbose=true verbose=true
@ -34,15 +34,14 @@ GI_TYPELIB_PATH="@MUTTER_LIB_DIR@/mutter:$builddir/../src"
GJS_DEBUG_OUTPUT=stderr GJS_DEBUG_OUTPUT=stderr
$verbose || GJS_DEBUG_TOPICS="JS ERROR;JS LOG" $verbose || GJS_DEBUG_TOPICS="JS ERROR;JS LOG"
GNOME_SHELL_TESTSDIR="$srcdir/" GNOME_SHELL_TESTSDIR="$srcdir/"
LD_PRELOAD="$builddir/../src/.libs/libgnome-shell.so"
export GI_TYPELIB_PATH GJS_DEBUG_OUTPUT GJS_DEBUG_TOPICS GNOME_SHELL_JS GNOME_SHELL_TESTSDIR LD_PRELOAD export GI_TYPELIB_PATH GJS_DEBUG_OUTPUT GJS_DEBUG_TOPICS GNOME_SHELL_JS GNOME_SHELL_TESTSDIR LD_PRELOAD
gjs_args= run_js_test_args=
for i in $srcdir $srcdir/../js @GJS_JS_DIR@ @GJS_JS_NATIVE_DIR@ ; do for i in $srcdir $srcdir/../js @GJS_JS_DIR@ @GJS_JS_NATIVE_DIR@ ; do
gjs_args="$gjs_args -I $i" run_js_test_args="$run_js_test_args -I $i"
done done
for test in $tests ; do for test in $tests ; do
$debug gjs-console $gjs_args $test || exit $? $debug $builddir/../src/run-js-test $run_js_test_args $test || exit $?
done done

View File

@ -8,7 +8,6 @@ const Shell = imports.gi.Shell;
const Environment = imports.ui.environment; const Environment = imports.ui.environment;
function init() { function init() {
Clutter.init(null, null);
Environment.init(); Environment.init();
let stage = Clutter.Stage.get_default(); let stage = Clutter.Stage.get_default();