diff --git a/Makefile.in b/Makefile.in
index 88822a2a36..2d9e96ad1b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -274,6 +274,33 @@ testpackages:
( chmod 777 testpackages.in; ./testpackages.in; rm testpackages.in )
( rm wsp.g )
+testpackage:
+ mkdir -p dev/log
+ ( echo 'SetAssertionLevel( 2 ); ReadGapRoot( "tst/testutil.g" ); \
+ SaveWorkspace( "wsp.g" );' | $(TESTGAP) )
+ ( echo 'CreatePackageTestsInput( "testpackage.in", \
+ "dev/log/testpackage1", \
+ "$(TESTGAP) -L wsp.g", "false", "$(PKGNAME)" );'\
+ | $(TESTGAP) -L wsp.g > /dev/null )
+ ( chmod 777 testpackage.in; ./testpackage.in; rm testpackage.in )
+ ( rm wsp.g )
+ ( echo 'SetAssertionLevel( 2 ); ReadGapRoot( "tst/testutil.g" ); \
+ SaveWorkspace( "wsp.g" );' | $(TESTGAPauto) )
+ ( echo 'CreatePackageTestsInput( "testpackage.in", \
+ "dev/log/testpackageA", \
+ "$(TESTGAPauto) -L wsp.g", "auto", "$(PKGNAME)" );'\
+ | $(TESTGAPauto) -L wsp.g > /dev/null )
+ ( chmod 777 testpackage.in; ./testpackage.in; rm testpackage.in )
+ ( rm wsp.g )
+ ( echo 'SetAssertionLevel( 2 ); ReadGapRoot( "tst/testutil.g" ); \
+ SaveWorkspace( "wsp.g" );' | $(TESTGAP) )
+ ( echo 'CreatePackageTestsInput( "testpackage.in", \
+ "dev/log/testpackage2", \
+ "$(TESTGAP) -L wsp.g", "true", "$(PKGNAME)" );'\
+ | $(TESTGAP) -L wsp.g > /dev/null )
+ ( chmod 777 testpackage.in; ./testpackage.in; rm testpackage.in )
+ ( rm wsp.g )
+
testpackagesload:
mkdir -p dev/log
( echo 'ReadGapRoot( "tst/testutil.g" ); \
diff --git a/doc/ref/debug.xml b/doc/ref/debug.xml
index 648a6d0105..8f144290bc 100644
--- a/doc/ref/debug.xml
+++ b/doc/ref/debug.xml
@@ -769,6 +769,9 @@ gaussian.tst 0 10
<#Include Label="Test">
<#Include Label="TestDirectory">
+
+See also for the information on running standard
+tests for &GAP; packages.
diff --git a/doc/ref/gappkg.xml b/doc/ref/gappkg.xml
index 01583bfdff..7d06a76141 100644
--- a/doc/ref/gappkg.xml
+++ b/doc/ref/gappkg.xml
@@ -95,6 +95,7 @@ package and not by users of a package.
<#Include Label="ReadPackage">
<#Include Label="TestPackageAvailability">
+<#Include Label="TestPackage">
<#Include Label="InstalledPackageVersion">
<#Include Label="DirectoriesPackageLibrary">
<#Include Label="DirectoriesPackagePrograms">
diff --git a/lib/test.gd b/lib/test.gd
index 310e5e22b6..0363f9e5b4 100644
--- a/lib/test.gd
+++ b/lib/test.gd
@@ -12,4 +12,5 @@ DeclareGlobalFunction("ParseTestFile");
DeclareGlobalFunction("RunTests");
DeclareGlobalFunction("Test");
DeclareGlobalFunction("TestDirectory");
+DeclareGlobalFunction("TestPackage");
diff --git a/lib/test.gi b/lib/test.gi
index a43df64c60..9bf022c006 100644
--- a/lib/test.gi
+++ b/lib/test.gi
@@ -760,3 +760,77 @@ InstallGlobalFunction( "TestDirectory", function(arg)
return testTotal;
end);
+
+#############################################################################
+##
+## TestPackage( )
+##
+## <#GAPDoc Label="TestPackage">
+##
+##
+##
+## It is recommended that a &GAP; package specifies a standard test in its
+## PackageInfo.g file. If pkgname is a string with the name of
+## a &GAP; package, then TestDirectory(pkgname) will check if this
+## package is loadable and has the standard test, and will run this test in
+## the current &GAP; session.
+##
+## The output of the test depends on the particular package, and it also
+## may depend on the current &GAP; session (loaded packages, state of the
+## random sources, defined global variables etc.). If you would like to
+## run the test for the same package in the same setting that is used
+## for the testing of &GAP; releases, you have to call
+##
+##
+##
+## in the UNIX shell (without quotes around pkgname). This will run
+## the standard test for the package pkgname three times in different
+## settings, and will write test output to three files in the dev/log
+## directory. These output files will be named in the format
+## testpackageX_timestamp.pkgname, where X=A for the test
+## with packages loaded by default, X=1 for the test without other
+## packages (i.e. when &GAP; is started with -A command line option),
+## and X=2 when the test is run with all packages loaded.
+##
+##
+## <#/GAPDoc>
+##
+InstallGlobalFunction( "TestPackage", function(pkgname)
+local testfile, str;
+if not IsBound( GAPInfo.PackagesInfo.(pkgname) ) then
+ Print("#I No package with the name ", pkgname, " is available\n");
+ return;
+elif LoadPackage( pkgname ) = fail then
+ Print( "#I ", pkgname, " package can not be loaded\n" );
+ return;
+elif not IsBound( GAPInfo.PackagesInfo.(pkgname)[1].TestFile ) then
+ Print("#I No standard tests specified in ", pkgname, " package, version ",
+ GAPInfo.PackagesInfo.(pkgname)[1].Version, "\n");
+ return;
+else
+ testfile := Filename( DirectoriesPackageLibrary( pkgname, "" ),
+ GAPInfo.PackagesInfo.(pkgname)[1].TestFile );
+ str:= StringFile( testfile );
+ if not IsString( str ) then
+ Print( "#I Test file `", testfile, "' for package `", pkgname,
+ " version ", GAPInfo.PackagesInfo.(pkgname)[1].Version, " is not readable\n" );
+ return;
+ fi;
+ if EndsWith(testfile,".tst") then
+ if Test( testfile, rec(compareFunction := "uptowhitespace") ) then
+ Print( "#I No errors detected while testing package ", pkgname,
+ " version ", GAPInfo.PackagesInfo.(pkgname)[1].Version,
+ "\n#I using the test file `", testfile, "'\n");
+ else
+ Print( "#I Errors detected while testing package ", pkgname,
+ " version ", GAPInfo.PackagesInfo.(pkgname)[1].Version,
+ "\n#I using the test file `", testfile, "'\n");
+ fi;
+ elif not READ( testfile ) then
+ Print( "#I Test file `", testfile, "' for package `", pkgname,
+ " version ", GAPInfo.PackagesInfo.(pkgname)[1].Version, " is not readable\n" );
+ fi;
+fi;
+end);
diff --git a/tst/testutil.g b/tst/testutil.g
index a9fe7f6037..1d0f42c6a9 100644
--- a/tst/testutil.g
+++ b/tst/testutil.g
@@ -76,8 +76,8 @@ end;
## is actually managed in the Makefile, and is passed to this function
## just to be printed in the information messages.
##
-BindGlobal( "CreatePackageTestsInput", function( scriptfile, outfile, gap, other )
- local result, name, entry, pair, testfile;
+BindGlobal( "CreatePackageTestsInput", function( scriptfile, outfile, gap, other, pkgname... )
+ local result, name, entry, pair, testfile, packages;
SizeScreen( [ 1000 ] );
InitializePackagesInfoRecords( false );
@@ -85,7 +85,19 @@ BindGlobal( "CreatePackageTestsInput", function( scriptfile, outfile, gap, other
Append( result, "TIMESTAMP=`date -u +_%Y-%m-%d-%H-%M`\n" );
- for name in SortedList(ShallowCopy(RecNames(GAPInfo.PackagesInfo))) do
+ if Length(pkgname)=0 then
+ packages := SortedList(ShallowCopy(RecNames(GAPInfo.PackagesInfo)));
+ else
+ packages := pkgname;
+ if Length(packages) <> 1 or Length(packages[1]) = 0 then
+ Error("Usage: make testpackage PKGNAME=pkgname");
+ fi;
+ if not pkgname[1] in RecNames(GAPInfo.PackagesInfo) then
+ Error("There is no package with the name ", pkgname[1], " installed\n");
+ fi;
+ fi;
+
+ for name in packages do
for entry in GAPInfo.PackagesInfo.( name ) do
if IsBound( entry.InstallationPath ) and IsBound( entry.TestFile ) then
testfile := Filename( DirectoriesPackageLibrary( name, "" ), entry.TestFile );