diff --git a/admin/tool/unittest/coveragefile.php b/admin/tool/unittest/coveragefile.php
deleted file mode 100644
index d3c8737a4e8..00000000000
--- a/admin/tool/unittest/coveragefile.php
+++ /dev/null
@@ -1,71 +0,0 @@
-.
-
-/**
- * This script serves files from dataroot/codecoverage
- *
- * Syntax: coveragefile.php/path/to/file/file.html
- * coveragefile.php?file=path/to/file/file.html
- *
- * @package tool
- * @subpackage unittest
- * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-// disable moodle specific debug messages and any errors in output
-define('NO_DEBUG_DISPLAY', true);
-
-require(dirname(__FILE__) . '/../../../config.php');
-require_once($CFG->libdir . '/filelib.php');
-
-// basic security, require login + require site config cap
-require_login();
-require_capability('tool/unittest:execute', get_context_instance(CONTEXT_SYSTEM));
-
-// get file requested
-$relativepath = get_file_argument();
-
-// basic check, start by slash
-if (!$relativepath) {
- print_error('invalidargorconf');
-} else if ($relativepath{0} != '/') {
- print_error('pathdoesnotstartslash');
-}
-
-// determine which disk file is going to be served
-// and how it's going to be named
-$filepath = $CFG->dataroot . '/codecoverage' . $relativepath;
-$filename = basename($filepath);
-
-// extract relative path components
-$args = explode('/', ltrim($relativepath, '/'));
-
-// only serve from some controlled subdirs
-$alloweddirs = array('dbtest', 'unittest');
-if (!isset($args[0]) || !in_array($args[0], $alloweddirs)) {
- print_error('invalidarguments');
-}
-
-// only serve some controlled extensions/mimetypes
-if (!file_extension_in_typegroup($filepath, array('web_file', 'web_image'), true)) {
- print_error('invalidarguments');
-}
-
-// arrived here, send the file
-session_get_instance()->write_close(); // unlock session during fileserving
-send_file($filepath, $filename, 0, false);
-
diff --git a/admin/tool/unittest/db/access.php b/admin/tool/unittest/db/access.php
deleted file mode 100644
index 73d07dc1f6f..00000000000
--- a/admin/tool/unittest/db/access.php
+++ /dev/null
@@ -1,38 +0,0 @@
-.
-
-/**
- * Unitest caps.
- *
- * @package tool_unittest
- * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-$capabilities = array(
-
- // Note: do not add managers here, unittests are dangerous and not intended for production sites!!!
-
- 'tool/unittest:execute' => array(
- 'riskbitmask' => RISK_DATALOSS,
- 'captype' => 'write', // it writes into database, really!
- 'contextlevel' => CONTEXT_SYSTEM,
- 'archetypes' => array(
- )
- )
-);
diff --git a/admin/tool/unittest/db/install.php b/admin/tool/unittest/db/install.php
deleted file mode 100644
index 1923960d282..00000000000
--- a/admin/tool/unittest/db/install.php
+++ /dev/null
@@ -1,31 +0,0 @@
-.
-
-/**
- * Post installation and migration code.
- *
- * @package tool
- * @subpackage unittest
- * @copyright 2011 Petr Skoda {@link http://skodak.org}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die;
-
-function xmldb_tool_unittest_install() {
- global $CFG;
-
-}
diff --git a/admin/tool/unittest/ex_reporter.php b/admin/tool/unittest/ex_reporter.php
deleted file mode 100644
index 01476d29329..00000000000
--- a/admin/tool/unittest/ex_reporter.php
+++ /dev/null
@@ -1,297 +0,0 @@
-.
-
-/**
- * A SimpleTest report format for Moodle.
- *
- * @package tool
- * @subpackage unittest
- * @copyright © 2006 The Open University
- * @author N.D.Freear@open.ac.uk, T.J.Hunt@open.ac.uk
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-if (!defined('MOODLE_INTERNAL')) {
- die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
-}
-
-require_once($CFG->libdir . '/simpletestlib/reporter.php');
-
-/**
- * Extended in-browser test displayer. HtmlReporter generates
- * only failure messages and a pass count. ExHtmlReporter also
- * generates pass messages and a time-stamp.
- *
- * @package SimpleTestEx
- */
-class ExHtmlReporter extends HtmlReporter {
-
- // Options set when the class is created.
- var $showpasses;
-
- // Lang strings. Set in the constructor.
- var $strrunonlyfolder;
- var $strrunonlyfile;
-
- var $strseparator;
-
- var $timestart;
-
- /**
- * Constructor.
- *
- * @param bool $showpasses Whether this reporter should output anything for passes.
- */
- function __construct($showpasses) {
- parent::__construct('UTF-8');
- $this->showpasses = $showpasses;
-
- $this->strrunonlyfolder = $this->get_string('runonlyfolder');
- $this->strrunonlyfile = $this->get_string('runonlyfile');
- $this->strseparator = get_separator();
- }
-
- /**
- * Called when a pass needs to be output.
- */
- function paintPass($message) {
- //(Implicitly call grandparent, as parent not implemented.)
- parent::paintPass($message);
- if ($this->showpasses) {
- $this->_paintPassFail('pass', $message);
- }
- }
-
- /**
- * Called when a fail needs to be output.
- */
- function paintFail($message) {
- // Explicitly call grandparent, not parent::paintFail.
- SimpleScorer::paintFail($message);
- $this->_paintPassFail('fail', $message, debug_backtrace());
- }
-
- /**
- * Called when a skip needs to be output.
- */
- function paintSkip($message) {
- // Explicitly call grandparent, not parent::paintFail.
- SimpleScorer::paintSkip($message);
- $this->_paintPassFail('skip', $message);
- }
-
- /**
- * Called when an error (uncaught exception or PHP error) needs to be output.
- */
- function paintError($message) {
- // Explicitly call grandparent, not parent::paintError.
- SimpleScorer::paintError($message);
- $this->_paintPassFail('exception', $message);
- }
-
- /**
- * Called when a caught exception needs to be output.
- */
- function paintException($exception) {
- // Explicitly call grandparent, not parent::paintException.
- SimpleScorer::paintException($exception);
-
- if (is_a($exception, 'moodle_exception') &&
- !get_string_manager()->string_exists($exception->errorcode, $exception->module)) {
- $exceptionmessage = 'Exception with missing language string {' .
- $exception->errorcode . '} from language file {' . $exception->module . '}';
-
- if (!empty($exception->a)) {
- if (is_string($exception->a)) {
- $data = $exception->a;
- } else {
- $data = array();
- foreach ((array)$exception->a as $name => $value) {
- $data[] = $name . ' => [' . $value . ']';
- }
- $data = implode(', ', $data);
- }
- $exceptionmessage .= ' with data {' . $data . '}';
- }
-
- } else {
- $exceptionmessage = $exception->getMessage();
- }
- $message = 'Unexpected exception of type [' . get_class($exception) .
- '] with message ['. $exceptionmessage .
- '] in ['. $exception->getFile() .
- ' line ' . $exception->getLine() . ']';
-
- $debuginfo = null;
- if (!empty($exception->debuginfo)) {
- $debuginfo = $exception->debuginfo;
- }
-
- $this->_paintPassFail('exception', $message, $exception->getTrace(), $debuginfo);
- }
-
- /**
- * Private method. Used by printPass/Fail/Skip/Error.
- */
- function _paintPassFail($passorfail, $message, $stacktrace = null, $debuginfo = null) {
- global $CFG, $OUTPUT;
-
- echo $OUTPUT->box_start($passorfail . ' generalbox ');
-
- $url = $this->_htmlEntities($this->_stripParameterFromUrl(qualified_me(), 'path'));
- echo '', $this->get_string($passorfail), ': ';
- $breadcrumb = $this->getTestList();
- array_shift($breadcrumb);
- $file = array_shift($breadcrumb);
- $pathbits = preg_split('/\/|\\\\/', substr($file, strlen($CFG->dirroot) + 1));
- $file = array_pop($pathbits);
- $folder = '';
- foreach ($pathbits as $pathbit) {
- $folder .= $pathbit . '/';
- echo "strrunonlyfolder\">$pathbit/";
- }
- echo "strrunonlyfile\">$file";
- echo $this->strseparator, implode($this->strseparator, $breadcrumb);
-
- echo '
', $this->_htmlEntities($message), "\n\n";
-
- if (!empty($debuginfo)) {
- print_object('Debug info:');
- print_object($debuginfo);
- }
-
- if ($stacktrace) {
- $dotsadded = false;
- $interestinglines = 0;
- $filteredstacktrace = array();
- foreach ($stacktrace as $frame) {
- if (empty($frame['file']) || (strpos($frame['file'], 'simpletestlib') === false &&
- strpos($frame['file'], 'simpletestcoveragelib') === false
- && strpos($frame['file'], 'tool/unittest') === false)) {
- $filteredstacktrace[] = $frame;
- $interestinglines += 1;
- $dotsadded = false;
- } else if (!$dotsadded) {
- $filteredstacktrace[] = array('line' => '...', 'file' => '...');
- $dotsadded = true;
- }
- }
- if ($interestinglines > 1 || ($passorfail == 'exception' && $interestinglines > 0)) {
- echo '
' . format_backtrace($filteredstacktrace) . "
\n\n";
- }
- }
-
- echo $OUTPUT->box_end();
- flush();
- }
-
- /**
- * Called when a notice needs to be output.
- */
- function paintNotice($message) {
- $this->paintMessage($this->_htmlEntities($message));
- }
-
- /**
- * Paints a simple supplementary message.
- * @param string $message Text to display.
- */
- function paintMessage($message) {
- global $OUTPUT;
- if ($this->showpasses) {
- echo $OUTPUT->box_start();
- echo '', $this->get_string('notice'), ': ';
- $breadcrumb = $this->getTestList();
- array_shift($breadcrumb);
- echo implode($this->strseparator, $breadcrumb);
- echo $this->strseparator, '
', $message, "\n";
- echo $OUTPUT->box_end();
- flush();
- }
- }
-
- /**
- * Output anything that should appear above all the test output.
- */
- function paintHeader($test_name) {
- $this->timestart = time();
- // We do this the moodle way instead.
- }
-
- /**
- * Output anything that should appear below all the test output, e.g. summary information.
- */
- function paintFooter($test_name) {
- $summarydata = new stdClass;
- $summarydata->run = $this->getTestCaseProgress();
- $summarydata->total = $this->getTestCaseCount();
- $summarydata->passes = $this->getPassCount();
- $summarydata->fails = $this->getFailCount();
- $summarydata->exceptions = $this->getExceptionCount();
-
- if ($summarydata->fails == 0 && $summarydata->exceptions == 0) {
- $status = "passed";
- } else {
- $status = "failed";
- }
- echo '';
- echo $this->get_string('summary', $summarydata);
- echo '
';
-
- echo '',
- $this->get_string('runat', userdate($this->timestart)), ' ',
- $this->get_string('timetakes', format_time(time() - $this->timestart)), ' ',
- $this->get_string('version', SimpleTest::getVersion()),
- '
';
- }
-
- /**
- * Strip a specified parameter from the query string of a URL, if present.
- * Adds a separator to the end of the URL, so that a new parameter
- * can easily be appended. For example (assuming $param = 'frog'):
- *
- * http://example.com/index.php -> http://example.com/index.php?
- * http://example.com/index.php?frog=1 -> http://example.com/index.php?
- * http://example.com/index.php?toad=1 -> http://example.com/index.php?toad=1&
- * http://example.com/index.php?frog=1&toad=1 -> http://example.com/index.php?toad=1&
- *
- * @param string $url the URL to modify.
- * @param string $param the parameter to strip from the URL, if present.
- *
- * @return string The modified URL.
- */
- function _stripParameterFromUrl($url, $param) {
- $url = preg_replace('/(\?|&)' . $param . '=[^&]*&?/', '$1', $url);
- if (strpos($url, '?') === false) {
- $url = $url . '?';
- } else {
- $url = $url . '&';
- }
- return $url;
- }
-
- /**
- * Look up a lang string in the appropriate file.
- */
- function get_string($identifier, $a = NULL) {
- return get_string($identifier, 'tool_unittest', $a);
- }
-
- function _htmlEntities($message) {
- // Override subclass message that breaks UTF8.
- return s($message);
- }
-}
diff --git a/admin/tool/unittest/ex_simple_test.php b/admin/tool/unittest/ex_simple_test.php
deleted file mode 100644
index dd6ee8a4391..00000000000
--- a/admin/tool/unittest/ex_simple_test.php
+++ /dev/null
@@ -1,231 +0,0 @@
-.
-
-/**
- * A SimpleTest GroupTest that automatically finds all the
- * test files in a directory tree according to certain rules.
- *
- * @package tool
- * @subpackage unittest
- * @copyright © 2006 The Open University
- * @author N.D.Freear@open.ac.uk, T.J.Hunt@open.ac.uk
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-if (!defined('MOODLE_INTERNAL')) {
- die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
-}
-
-require_once($CFG->libdir . '/simpletestlib/test_case.php');
-
-/**
- * This is a composite test class for finding test cases and
- * other RunnableTest classes in a directory tree and combining
- * them into a group test.
- * @package SimpleTestEx
- */
-class AutoGroupTest extends TestSuite {
-
- var $showsearch;
-
- function AutoGroupTest($showsearch, $test_name = null) {
- $this->TestSuite($test_name);
- $this->showsearch = $showsearch;
- }
-
- function run($reporter) {
- global $UNITTEST;
-
- $UNITTEST->running = true;
- $return = parent::run($reporter);
- unset($UNITTEST->running);
- return $return;
- }
-
- function setLabel($test_name) {
- //:HACK: there is no GroupTest::setLabel, so access parent::_label.
- $this->_label = $test_name;
- }
-
- function addIgnoreFolder($ignorefolder) {
- $this->ignorefolders[]=$ignorefolder;
- }
-
- function _recurseFolders($path) {
- if ($this->showsearch) {
- echo '' . basename(realpath($path)) . '';
- }
-
- $files = scandir($path);
- static $s_count = 0;
-
- foreach ($files as $file) {
- if ($file == '.' || $file == '..') {
- continue;
- }
- $file_path = $path . '/' . $file;
- if (is_dir($file_path)) {
- if ($file != 'CVS' && $file != '.git' && !in_array($file_path, $this->ignorefolders)) {
- $this->_recurseFolders($file_path);
- }
- } elseif (preg_match('/simpletest(\/|\\\\)test.*\.php$/', $file_path)) {
-
- $s_count++;
- // OK, found: this shows as a 'Notice' for any 'simpletest/test*.php' file.
- $this->add(new FindFileNotice($file_path, 'Found unit test file, '. $s_count));
-
- // addTestFile: Unfortunately this doesn't return fail/success (bool).
- $this->addTestFile($file_path, true);
- }
- }
-
- if ($this->showsearch) {
- echo '
';
- }
- return $s_count;
- }
-
- function findTestFiles($dir) {
- if ($this->showsearch) {
- echo 'Searching folder: ' . realpath($dir) . '
';
- }
- $path = $dir;
- $count = $this->_recurseFolders($path);
- if ($count <= 0) {
- $this->add(new BadAutoGroupTest($path, 'Search complete. No unit test files found'));
- } else {
- $this->add(new AutoGroupTestNotice($path, 'Search complete. Total unit test files found: '. $count));
- }
- if ($this->showsearch) {
- echo '
';
- }
- return $count;
- }
-
- function addTestFile($file, $internalcall = false) {
-
- if ($this->showsearch) {
- if ($internalcall) {
- echo '' . basename($file) . '';
- } else {
- echo 'Adding test file: ' . realpath($file) . '
';
- }
- // Make sure that syntax errors show up suring the search, otherwise you often
- // get blank screens because evil people turn down error_reporting elsewhere.
- error_reporting(E_ALL);
- }
- if (!is_file($file) ){
- parent::add(new BadTest($file, 'Not a file or does not exist'));
- }
- parent::addFile($file);
- }
-}
-
-
-/* ======================================================================= */
-// get_class_ex: Insert spaces to prettify the class-name.
-function get_class_ex($object) {
- return preg_replace('/(.?)([A-Z])/', '${1} ${2}', get_class($object));
-}
-
-
-/**
- * A failing test base-class for when a test suite has NOT loaded properly.
- * See class, simple_test.php: BadGroupTest.
- * @package SimpleTestEx
- */
-class BadTest {
-
- var $label;
- var $error;
-
- function BadTest($label, $error) {
- $this->label = $label;
- $this->error = $error;
- }
-
- function getLabel() {
- return $this->label;
- }
-
- function run(&$reporter) {
- $reporter->paintGroupStart(basename(__FILE__), $this->getSize());
- $reporter->paintFail(get_class_ex($this) .' [' . $this->getLabel() .
- '] with error [' . $this->error . ']');
- $reporter->paintGroupEnd($this->getLabel());
- return $reporter->getStatus();
- }
-
- /**
- * @return int the number of test cases starting.
- */
- function getSize() {
- return 0;
- }
-}
-
-/**
- * An informational notice base-class for when a test suite is being processed.
- * See class, simple_test.php: BadGroupTest.
- * @package SimpleTestEx
- */
-class Notice {
-
- var $label;
- var $status;
-
- function Notice($label, $error) {
- $this->label = $label;
- $this->status = $error;
- }
-
- function getLabel() {
- return $this->label;
- }
-
- function run(&$reporter) {
- $reporter->paintGroupStart(basename(__FILE__), $this->getSize());
- $reporter->paintNotice(get_class_ex($this) .
- ' ['. $this->getLabel() .'] with status [' . $this->status . ']');
- $reporter->paintGroupEnd($this->getLabel());
- return $reporter->getStatus();
- }
-
- function getSize() {
- return 0;
- }
-}
-
-/**
- * A failing folder test for when the test-user specifies an invalid directory
- * (run.php?folder=woops).
- * @package SimpleTestEx
- */
-class BadFolderTest extends BadTest { }
-
-/**
- * A failing auto test for when no unit test files are found.
- * @package SimpleTestEx
- */
-class BadAutoGroupTest extends BadTest { }
-
-/**
- * Auto group test notices - 1. Search complete. 2. A test file has been found.
- * @package SimpleTestEx
- */
-class AutoGroupTestNotice extends Notice { }
-
-class FindFileNotice extends Notice { }
diff --git a/admin/tool/unittest/index.php b/admin/tool/unittest/index.php
deleted file mode 100644
index db0bbc73580..00000000000
--- a/admin/tool/unittest/index.php
+++ /dev/null
@@ -1,150 +0,0 @@
-.
-
-/**
- * Run the unit tests.
- *
- * @package tool
- * @subpackage unittest
- * @copyright © 2006 The Open University
- * @author N.D.Freear@open.ac.uk, T.J.Hunt@open.ac.uk
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-define('NO_OUTPUT_BUFFERING', true);
-
-require(dirname(__FILE__) . '/../../../config.php');
-require_once($CFG->libdir.'/adminlib.php');
-require_once('simpletestlib.php');
-require_once('simpletestcoveragelib.php');
-require_once('ex_simple_test.php');
-require_once('ex_reporter.php');
-
-// page parameters
-$path = optional_param('path', null, PARAM_PATH);
-$showpasses = optional_param('showpasses', false, PARAM_BOOL);
-$codecoverage = optional_param('codecoverage', false, PARAM_BOOL);
-$showsearch = optional_param('showsearch', false, PARAM_BOOL);
-
-admin_externalpage_setup('toolsimpletest', '', array('showpasses'=>$showpasses, 'showsearch'=>$showsearch));
-
-raise_memory_limit(MEMORY_EXTRA);
-
-$unittest = true;
-
-global $UNITTEST;
-$UNITTEST = new stdClass();
-
-// This limit is the time allowed per individual test function. Please do not
-// increase this value. If you get a PHP time limit when running unit tests,
-// find the unit test which is running slowly, and either make it faster,
-// split it into multiple tests, or call set_time_limit within that test.
-define('TIME_ALLOWED_PER_UNIT_TEST', 60);
-
-// Print the header.
-$strtitle = get_string('unittests', 'tool_unittest');
-
-if (!is_null($path)) {
- //trim so user doesn't get an error if they include a space on the end of the path (ie by pasting path)
- $path = trim($path);
-
- // Turn off xmlstrictheaders during the unit test run.
- $origxmlstrictheaders = !empty($CFG->xmlstrictheaders);
- $CFG->xmlstrictheaders = false;
- echo $OUTPUT->header();
- $CFG->xmlstrictheaders = $origxmlstrictheaders;
- unset($origxmlstrictheaders);
-
- // Create the group of tests.
- $test = new autogroup_test_coverage($showsearch, true, $codecoverage, 'Moodle Unit Tests Code Coverage Report', 'unittest');
-
- // OU specific. We use the _nonproject folder for stuff we want to
- // keep in CVS, but which is not really relevant. It does no harm
- // to leave this here.
- $test->addIgnoreFolder($CFG->dirroot . '/_nonproject');
-
- // Make the reporter, which is what displays the results.
- $reporter = new ExHtmlReporter($showpasses);
-
- if ($showsearch) {
- echo $OUTPUT->heading('Searching for test cases');
- }
- flush();
-
- // Work out what to test.
- if (substr($path, 0, 1) == '/') {
- $path = substr($path, 1);
- }
- $path = $CFG->dirroot . '/' . $path;
- if (substr($path, -1) == '/') {
- $path = substr($path, 0, -1);
- }
- $displaypath = substr($path, strlen($CFG->dirroot) + 1);
- $ok = true;
- if (is_file($path)) {
- $test->addTestFile($path);
- } else if (is_dir($path)){
- $test->findTestFiles($path);
- } else {
- echo $OUTPUT->box(get_string('pathdoesnotexist', 'tool_unittest', $path), 'errorbox');
- $ok = false;
- }
-
- // If we have something to test, do it.
- if ($ok) {
- if ($path == $CFG->dirroot) {
- $title = get_string('moodleunittests', 'tool_unittest', get_string('all', 'tool_unittest'));
- } else {
- $title = get_string('moodleunittests', 'tool_unittest', $displaypath);
- }
- echo $OUTPUT->heading($title);
- $test->run($reporter);
- }
-
- $formheader = get_string('retest', 'tool_unittest');
-} else {
- $displaypath = '';
- echo $OUTPUT->header();
- $formheader = get_string('rununittests', 'tool_unittest');
-}
-// Print the form for adjusting options.
-echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter');
-echo $OUTPUT->heading($formheader);
-echo '';
-echo $OUTPUT->box_end();
-
-// Print link to latest code coverage for this report type
-if (is_null($path) || !$codecoverage) {
- moodle_coverage_reporter::print_link_to_latest('unittest');
-}
-
-// Footer.
-echo $OUTPUT->footer();
diff --git a/admin/tool/unittest/lang/en/tool_unittest.php b/admin/tool/unittest/lang/en/tool_unittest.php
deleted file mode 100644
index ce4bb3679c1..00000000000
--- a/admin/tool/unittest/lang/en/tool_unittest.php
+++ /dev/null
@@ -1,86 +0,0 @@
-.
-
-/**
- * Strings for component 'tool_unittest', language 'en', branch 'MOODLE_22_STABLE'
- *
- * This file contains strings that were previously located in lang/en/simpletest.php
- *
- * @package tool
- * @subpackage unittest
- * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-$string['addconfigprefix'] = 'Add prefix to config file';
-$string['all'] = 'ALL';
-$string['codecoverageanalysis'] = 'Perform code coverage analysis.';
-$string['codecoveragecompletereport'] = '(view code coverage complete report)';
-$string['codecoveragedisabled'] = 'Cannot enable code coverage in this server (missing xdebug extension).';
-$string['codecoveragelatestdetails'] = '(on {$a->date}, with {$a->files} files, {$a->percentage} covered)';
-$string['codecoveragelatestreport'] = 'view latest code coverage complete report';
-$string['confignonwritable'] = 'The file config.php is not writeable by the web server. Either change its permissions, or edit it with the appropriate user account, and add the following line before the closing php tag:
-$CFG->unittestprefix = \'tst_\' // Change tst_ to a prefix of your choice, different from $CFG->prefix';
-$string['coveredlines'] = 'Covered lines';
-$string['coveredpercentage'] = 'Overall code coverage';
-$string['dbtest'] = 'Functional DB tests';
-$string['deletingnoninsertedrecord'] = 'Trying to delete a record that was not inserted by these unit tests (id {$a->id} in table {$a->table}).';
-$string['deletingnoninsertedrecords'] = 'Trying to delete records that were not inserted by these unit tests (from table {$a->table}).';
-$string['droptesttables'] = 'Drop test tables';
-$string['exception'] = 'Exception';
-$string['executablelines'] = 'Executable lines';
-$string['fail'] = 'Fail';
-$string['ignorefile'] = 'Ignore tests in the file';
-$string['ignorethisfile'] = 'Re-run the tests ignoring this test file.';
-$string['installtesttables'] = 'Install test tables';
-$string['moodleunittests'] = 'Moodle unit tests: {$a}';
-$string['notice'] = 'Notice';
-$string['onlytest'] = 'Only run tests in';
-$string['othertestpages'] = 'Other test pages';
-$string['pass'] = 'Pass';
-$string['pathdoesnotexist'] = 'The path \'{$a}\' does not exist.';
-$string['pluginname'] = 'Unit tests';
-$string['prefix'] = 'Unit test tables prefix';
-$string['prefixnotset'] = 'The unit test database table prefix is not configured. Fill and submit this form to add it to config.php.';
-$string['reinstalltesttables'] = 'Reinstall test tables';
-$string['retest'] = 'Re-run the tests';
-$string['retestonlythisfile'] = 'Re-run only this test file.';
-$string['runall'] = 'Run the tests from all the test files.';
-$string['runat'] = 'Run at {$a}.';
-$string['runonlyfile'] = 'Run only the tests in this file';
-$string['runonlyfolder'] = 'Run only the tests in this folder';
-$string['runtests'] = 'Run tests';
-$string['rununittests'] = 'Run the unit tests';
-$string['showpasses'] = 'Show passes as well as fails.';
-$string['showsearch'] = 'Show the search for test files.';
-$string['skip'] = 'Skip';
-$string['stacktrace'] = 'Stack trace:';
-$string['summary'] = '{$a->run}/{$a->total} test cases complete: {$a->passes} passes, {$a->fails} fails and {$a->exceptions} exceptions.';
-$string['tablesnotsetup'] = 'Unit test tables are not yet built. Do you want to build them now?.';
-$string['testdboperations'] = 'Test database operations';
-$string['testtablescsvfileunwritable'] = 'The test tables CSV file is not writable ({$a->filename})';
-$string['testtablesneedupgrade'] = 'The test DB tables need to be upgraded. Do you wish to proceed with the upgrade now?';
-$string['testtablesok'] = 'The test DB tables were successfully installed.';
-$string['thorough'] = 'Run a thorough test (may be slow).';
-$string['timetakes'] = 'Time taken: {$a}.';
-$string['totallines'] = 'Total lines';
-$string['uncaughtexception'] = 'Uncaught exception [{$a->getMessage()}] in [{$a->getFile()}:{$a->getLine()}] TESTS ABORTED.';
-$string['uncoveredlines'] = 'Uncovered lines';
-$string['unittest:execute'] = 'Execute unit tests';
-$string['unittestprefixsetting'] = 'Unit test prefix: {$a->unittestprefix} (Edit config.php to modify this).';
-$string['unittests'] = 'Unit tests';
-$string['updatingnoninsertedrecord'] = 'Trying to update a record that was not inserted by these unit tests (id {$a->id} in table {$a->table}).';
-$string['version'] = 'Using SimpleTest version {$a}.';
diff --git a/admin/tool/unittest/settings.php b/admin/tool/unittest/settings.php
deleted file mode 100644
index ee3406a7e87..00000000000
--- a/admin/tool/unittest/settings.php
+++ /dev/null
@@ -1,29 +0,0 @@
-.
-
-/**
- * Unittest settings
- *
- * @package tool
- * @subpackage unittest
- * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-
-defined('MOODLE_INTERNAL') || die;
-
-$ADMIN->add('development', new admin_externalpage('toolsimpletest', get_string('pluginname', 'tool_unittest'), "$CFG->wwwroot/$CFG->admin/tool/unittest/index.php", 'tool/unittest:execute', true));
diff --git a/admin/tool/unittest/simpletestcoveragelib.php b/admin/tool/unittest/simpletestcoveragelib.php
deleted file mode 100644
index 306bf2941e7..00000000000
--- a/admin/tool/unittest/simpletestcoveragelib.php
+++ /dev/null
@@ -1,606 +0,0 @@
-.
-
-/**
- * Extend simpletest to support code coverage analysis
- *
- * This package contains a collection of classes that, extending standard simpletest
- * ones, provide code coverage analysis to already existing tests. Also there are some
- * utility functions designed to make the coverage control easier.
- *
- * @package tool
- * @subpackage unittest
- * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- * Includes
- */
-require_once($CFG->libdir.'/tablelib.php');
-
-require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/unittest/simpletestlib.php');
-require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/unittest/ex_simple_test.php');
-
-require_once($CFG->libdir . '/spikephpcoverage/src/CoverageRecorder.php');
-require_once($CFG->libdir . '/spikephpcoverage/src/reporter/HtmlCoverageReporter.php');
-
-/**
- * AutoGroupTest class extension supporting code coverage
- *
- * This class extends AutoGroupTest to add the funcitionalities
- * necessary to run code coverage, allowing its activation and
- * specifying included / excluded files to be analysed
- *
- * @package moodlecore
- * @subpackage simpletestcoverage
- * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class autogroup_test_coverage extends AutoGroupTest {
-
- private $performcoverage; // boolean
- private $coveragename; // title of the coverage report
- private $coveragedir; // dir, relative to dataroot/coverage where the report will be saved
- private $includecoverage; // paths to be analysed by the coverage report
- private $excludecoverage; // paths to be excluded from the coverage report
-
- function __construct($showsearch, $test_name = null,
- $performcoverage = false, $coveragename = 'Code Coverage Report',
- $coveragedir = 'report') {
- parent::__construct($showsearch, $test_name);
- $this->performcoverage = $performcoverage;
- $this->coveragename = $coveragename;
- $this->coveragedir = $coveragedir;
- $this->includecoverage = array();
- $this->excludecoverage = array();
- }
-
- public function addTestFile($file, $internalcall = false) {
- global $CFG;
-
- if ($this->performcoverage) {
- $refinfo = moodle_reflect_file($file);
- require_once($file);
- if ($refinfo->classes) {
- foreach ($refinfo->classes as $class) {
- $reflection = new ReflectionClass($class);
- if ($staticprops = $reflection->getStaticProperties()) {
- if (isset($staticprops['includecoverage']) && is_array($staticprops['includecoverage'])) {
- foreach ($staticprops['includecoverage'] as $toinclude) {
- $this->add_coverage_include_path($toinclude);
- }
- }
- if (isset($staticprops['excludecoverage']) && is_array($staticprops['excludecoverage'])) {
- foreach ($staticprops['excludecoverage'] as $toexclude) {
- $this->add_coverage_exclude_path($toexclude);
- }
- }
- }
- }
- // Automatically add the test dir itself, so nothing will be covered there
- $this->add_coverage_exclude_path(dirname($file));
- }
- }
- parent::addTestFile($file, $internalcall);
- }
-
- public function add_coverage_include_path($path) {
- global $CFG;
-
- $path = $CFG->dirroot . '/' . $path; // Convert to full path
- if (!in_array($path, $this->includecoverage)) {
- array_push($this->includecoverage, $path);
- }
- }
-
- public function add_coverage_exclude_path($path) {
- global $CFG;
-
- $path = $CFG->dirroot . '/' . $path; // Convert to full path
- if (!in_array($path, $this->excludecoverage)) {
- array_push($this->excludecoverage, $path);
- }
- }
-
- /**
- * Run the autogroup_test_coverage using one internally defined code coverage reporter
- * automatically generating the coverage report. Only supports one instrumentation
- * to be executed and reported.
- */
- public function run($simpletestreporter) {
- global $CFG;
-
- if (moodle_coverage_recorder::can_run_codecoverage() && $this->performcoverage) {
- // Testing with coverage
- $covreporter = new moodle_coverage_reporter($this->coveragename, $this->coveragedir);
- $covrecorder = new moodle_coverage_recorder($covreporter);
- $covrecorder->setIncludePaths($this->includecoverage);
- $covrecorder->setExcludePaths($this->excludecoverage);
- $covrecorder->start_instrumentation();
- parent::run($simpletestreporter);
- $covrecorder->stop_instrumentation();
- set_time_limit(60*10); // it may take a long time to generate the report
- $covrecorder->generate_report();
- moodle_coverage_reporter::print_summary_info(basename($this->coveragedir));
- } else {
- // Testing without coverage
- parent::run($simpletestreporter);
- }
- }
-
- /**
- * Run the autogroup_test_coverage tests using one externally defined code coverage reporter
- * allowing further process of coverage data once tests are over. Supports multiple
- * instrumentations (code coverage gathering sessions) to be executed.
- */
- public function run_with_external_coverage($simpletestreporter, $covrecorder) {
-
- if (moodle_coverage_recorder::can_run_codecoverage() && $this->performcoverage) {
- $covrecorder->setIncludePaths($this->includecoverage);
- $covrecorder->setExcludePaths($this->excludecoverage);
- $covrecorder->start_instrumentation();
- parent::run($simpletestreporter);
- $covrecorder->stop_instrumentation();
- } else {
- // Testing without coverage
- parent::run($simpletestreporter);
- }
- }
-}
-
-/**
- * CoverageRecorder class extension supporting multiple
- * coverage instrumentations to be accumulated
- *
- * This class extends CoverageRecorder class in order to
- * support multimple xdebug code coverage sessions to be
- * executed and get acummulated info about all them in order
- * to produce one unique report (default CoverageRecorder
- * resets info on each instrumentation (coverage session)
- *
- * @package moodlecore
- * @subpackage simpletestcoverage
- * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class moodle_coverage_recorder extends CoverageRecorder {
-
- public function __construct($reporter='new moodle_coverage_reporter()') {
- parent::__construct(array(), array(), $reporter);
- }
-
- /**
- * Stop gathering coverage data, saving it for later reporting
- */
- public function stop_instrumentation() {
- if(extension_loaded("xdebug")) {
- $lastcoveragedata = xdebug_get_code_coverage(); // Get last instrumentation coverage data
- xdebug_stop_code_coverage(); // Stop code coverage
- $this->coverageData = self::merge_coverage_data($this->coverageData, $lastcoveragedata); // Append lastcoveragedata
- $this->logger->debug("[moodle_coverage_recorder::stopInstrumentation()] Code coverage: " . print_r($this->coverageData, true),
- __FILE__, __LINE__);
- return true;
- } else {
- $this->logger->critical("[moodle_coverage_recorder::stopInstrumentation()] Xdebug not loaded.", __FILE__, __LINE__);
- }
- return false;
- }
-
- /**
- * Start gathering coverage data
- */
- public function start_instrumentation() {
- $this->startInstrumentation(); /// Simple lowercase wrap over Spike function
- }
-
- /**
- * Generate the code coverage report
- */
- public function generate_report() {
- $this->generateReport(); /// Simple lowercase wrap over Spike function
- }
-
- /**
- * Determines if the server is able to run code coverage analysis
- *
- * @return bool
- */
- static public function can_run_codecoverage() {
- // Only req is xdebug loaded. PEAR XML is already in place and available
- if(!extension_loaded("xdebug")) {
- return false;
- }
- return true;
- }
-
- /**
- * Merge two collections of complete code coverage data
- */
- protected static function merge_coverage_data($cov1, $cov2) {
-
- $result = array();
-
- // protection against empty coverage collections
- if (!is_array($cov1)) {
- $cov1 = array();
- }
- if (!is_array($cov2)) {
- $cov2 = array();
- }
-
- // Get all the files used in both coverage datas
- $files = array_unique(array_merge(array_keys($cov1), array_keys($cov2)));
-
- // Iterate, getting results
- foreach($files as $file) {
- // If file exists in both coverages, let's merge their lines
- if (array_key_exists($file, $cov1) && array_key_exists($file, $cov2)) {
- $result[$file] = self::merge_lines_coverage_data($cov1[$file], $cov2[$file]);
- // Only one of the coverages has the file
- } else if (array_key_exists($file, $cov1)) {
- $result[$file] = $cov1[$file];
- } else {
- $result[$file] = $cov2[$file];
- }
- }
- return $result;
- }
-
- /**
- * Merge two collections of lines of code coverage data belonging to the same file
- *
- * Merge algorithm obtained from Phing: http://phing.info
- */
- protected static function merge_lines_coverage_data($lines1, $lines2) {
-
- $result = array();
-
- reset($lines1);
- reset($lines2);
-
- while (current($lines1) && current($lines2)) {
- $linenr1 = key($lines1);
- $linenr2 = key($lines2);
-
- if ($linenr1 < $linenr2) {
- $result[$linenr1] = current($lines1);
- next($lines1);
- } else if ($linenr2 < $linenr1) {
- $result[$linenr2] = current($lines2);
- next($lines2);
- } else {
- if (current($lines1) < 0) {
- $result[$linenr2] = current($lines2);
- } else if (current($lines2) < 0) {
- $result[$linenr2] = current($lines1);
- } else {
- $result[$linenr2] = current($lines1) + current($lines2);
- }
- next($lines1);
- next($lines2);
- }
- }
-
- while (current($lines1)) {
- $result[key($lines1)] = current($lines1);
- next($lines1);
- }
-
- while (current($lines2)) {
- $result[key($lines2)] = current($lines2);
- next($lines2);
- }
-
- return $result;
- }
-}
-
-/**
- * HtmlCoverageReporter class extension supporting Moodle customizations
- *
- * This class extends the HtmlCoverageReporter class in order to
- * implement Moodle look and feel, inline reporting after executing
- * unit tests, proper linking and other tweaks here and there.
- *
- * @package moodlecore
- * @subpackage simpletestcoverage
- * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class moodle_coverage_reporter extends HtmlCoverageReporter {
-
- public function __construct($heading='Coverage Report', $dir='report') {
- global $CFG;
- parent::__construct($heading, '', $CFG->dataroot . '/codecoverage/' . $dir);
- }
-
- /**
- * Writes one row in the index.html table to display filename
- * and coverage recording.
- *
- * Overrided to transform names and links to shorter format
- *
- * @param $fileLink link to html details file.
- * @param $realFile path to real PHP file.
- * @param $fileCoverage Coverage recording for that file.
- * @return string HTML code for a single row.
- * @access protected
- */
- protected function writeIndexFileTableRow($fileLink, $realFile, $fileCoverage) {
-
- global $CFG;
-
- $fileLink = str_replace($CFG->dirroot, '', $fileLink);
- $realFile = str_replace($CFG->dirroot, '', $realFile);
-
- return parent::writeIndexFileTableRow($fileLink, $realFile, $fileCoverage);;
- }
-
- /**
- * Mark a source code file based on the coverage data gathered
- *
- * Overrided to transform names and links to shorter format
- *
- * @param $phpFile Name of the actual source file
- * @param $fileLink Link to the html mark-up file for the $phpFile
- * @param &$coverageLines Coverage recording for $phpFile
- * @return boolean FALSE on failure
- * @access protected
- */
- protected function markFile($phpFile, $fileLink, &$coverageLines) {
- global $CFG;
-
- $fileLink = str_replace($CFG->dirroot, '', $fileLink);
-
- return parent::markFile($phpFile, $fileLink, $coverageLines);
- }
-
-
- /**
- * Update the grand totals
- *
- * Overrided to avoid the call to recordFileCoverageInfo()
- * because it has been already executed by writeIndexFile() and
- * cause files to be duplicated in the fileCoverage property
- */
- protected function updateGrandTotals(&$coverageCounts) {
- $this->grandTotalLines += $coverageCounts['total'];
- $this->grandTotalCoveredLines += $coverageCounts['covered'];
- $this->grandTotalUncoveredLines += $coverageCounts['uncovered'];
- }
-
- /**
- * Generate the static report
- *
- * Overrided to generate the serialised object to be displayed inline
- * with the test results.
- *
- * @param &$data Reference to Coverage Data
- */
- public function generateReport(&$data) {
- parent::generateReport($data);
-
- // head data
- $data = new stdClass();
- $data->time = time();
- $data->title = $this->heading;
- $data->output = $this->outputDir;
-
- // summary data
- $data->totalfiles = $this->grandTotalFiles;
- $data->totalln = $this->grandTotalLines;
- $data->totalcoveredln = $this->grandTotalCoveredLines;
- $data->totaluncoveredln = $this->grandTotalUncoveredLines;
- $data->totalpercentage = $this->getGrandCodeCoveragePercentage();
-
- // file details data
- $data->coveragedetails = $this->fileCoverage;
-
- // save serialised object
- file_put_contents($data->output . '/codecoverage.ser', serialize($data));
- }
-
- /**
- * Return the html contents for the summary for the last execution of the
- * given test type
- *
- * @param string $type of the test to return last execution summary (dbtest|unittest)
- * @return string html contents of the summary
- */
- static public function get_summary_info($type) {
- global $CFG, $OUTPUT;
-
- $serfilepath = $CFG->dataroot . '/codecoverage/' . $type . '/codecoverage.ser';
- if (file_exists($serfilepath) && is_readable($serfilepath)) {
- if ($data = unserialize(file_get_contents($serfilepath))) {
- // return one table with all the totals (we avoid individual file results here)
- $result = '';
- $table = new html_table();
- $table->align = array('right', 'left');
- $table->tablealign = 'center';
- $table->attributes['class'] = 'codecoveragetable';
- $table->id = 'codecoveragetable_' . $type;
- $table->rowclasses = array('label', 'value');
- $table->data = array(
- array(get_string('date') , userdate($data->time)),
- array(get_string('files') , format_float($data->totalfiles, 0)),
- array(get_string('totallines', 'tool_unittest') , format_float($data->totalln, 0)),
- array(get_string('executablelines', 'tool_unittest') , format_float($data->totalcoveredln + $data->totaluncoveredln, 0)),
- array(get_string('coveredlines', 'tool_unittest') , format_float($data->totalcoveredln, 0)),
- array(get_string('uncoveredlines', 'tool_unittest') , format_float($data->totaluncoveredln, 0)),
- array(get_string('coveredpercentage', 'tool_unittest'), format_float($data->totalpercentage, 2) . '%')
- );
-
- $url = $CFG->wwwroot . '/'.$CFG->admin.'/tool/unittest/coveragefile.php/' . $type . '/index.html';
- $result .= $OUTPUT->heading($data->title, 3, 'main codecoverageheading');
- $result .= $OUTPUT->heading('' . get_string('codecoveragecompletereport', 'tool_unittest') . '', 4, 'main codecoveragelink');
- $result .= html_writer::table($table);
-
- return $OUTPUT->box($result, 'generalbox boxwidthwide boxaligncenter codecoveragebox', '', true);
- }
- }
- return false;
- }
-
- /**
- * Print the html contents for the summary for the last execution of the
- * given test type
- *
- * @param string $type of the test to return last execution summary (dbtest|unittest)
- * @return string html contents of the summary
- */
- static public function print_summary_info($type) {
- echo self::get_summary_info($type);
- }
-
- /**
- * Return the html code needed to browse latest code coverage complete report of the
- * given test type
- *
- * @param string $type of the test to return last execution summary (dbtest|unittest)
- * @return string html contents of the summary
- */
- static public function get_link_to_latest($type) {
- global $CFG, $OUTPUT;
-
- $serfilepath = $CFG->dataroot . '/codecoverage/' . $type . '/codecoverage.ser';
- if (file_exists($serfilepath) && is_readable($serfilepath)) {
- if ($data = unserialize(file_get_contents($serfilepath))) {
- $info = new stdClass();
- $info->date = userdate($data->time);
- $info->files = format_float($data->totalfiles, 0);
- $info->percentage = format_float($data->totalpercentage, 2) . '%';
-
- $strlatestreport = get_string('codecoveragelatestreport', 'tool_unittest');
- $strlatestdetails = get_string('codecoveragelatestdetails', 'tool_unittest', $info);
-
- // return one link to latest complete report
- $result = '';
- $url = $CFG->wwwroot . '/'.$CFG->admin.'/tool/unittest/coveragefile.php/' . $type . '/index.html';
- $result .= $OUTPUT->heading('' . $strlatestreport . '', 3, 'main codecoveragelink');
- $result .= $OUTPUT->heading($strlatestdetails, 4, 'main codecoveragedetails');
- return $OUTPUT->box($result, 'generalbox boxwidthwide boxaligncenter codecoveragebox', '', true);
- }
- }
- return false;
- }
-
- /**
- * Print the html code needed to browse latest code coverage complete report of the
- * given test type
- *
- * @param string $type of the test to return last execution summary (dbtest|unittest)
- * @return string html contents of the summary
- */
- static public function print_link_to_latest($type) {
- echo self::get_link_to_latest($type);
- }
-}
-
-
-/**
- * Return information about classes and functions
- *
- * This function will parse any PHP file, extracting information about the
- * classes and functions defined within it, providing "File Reflection" as
- * PHP standard reflection classes don't support that.
- *
- * The idea and the code has been obtained from the Zend Framework Reflection API
- * http://framework.zend.com/manual/en/zend.reflection.reference.html
- *
- * Usage: $ref_file = moodle_reflect_file($file);
- *
- * @param string $file full path to the php file to introspect
- * @return object object with both 'classes' and 'functions' properties
- */
-function moodle_reflect_file($file) {
-
- $contents = file_get_contents($file);
- $tokens = token_get_all($contents);
-
- $functionTrapped = false;
- $classTrapped = false;
- $openBraces = 0;
-
- $classes = array();
- $functions = array();
-
- foreach ($tokens as $token) {
- /*
- * Tokens are characters representing symbols or arrays
- * representing strings. The keys/values in the arrays are
- *
- * - 0 => token id,
- * - 1 => string,
- * - 2 => line number
- *
- * Token ID's are explained here:
- * http://www.php.net/manual/en/tokens.php.
- */
-
- if (is_array($token)) {
- $type = $token[0];
- $value = $token[1];
- $lineNum = $token[2];
- } else {
- // It's a symbol
- // Maintain the count of open braces
- if ($token == '{') {
- $openBraces++;
- } else if ($token == '}') {
- $openBraces--;
- }
-
- continue;
- }
-
- switch ($type) {
- // Name of something
- case T_STRING:
- if ($functionTrapped) {
- $functions[] = $value;
- $functionTrapped = false;
- } elseif ($classTrapped) {
- $classes[] = $value;
- $classTrapped = false;
- }
- continue;
-
- // Functions
- case T_FUNCTION:
- if ($openBraces == 0) {
- $functionTrapped = true;
- }
- break;
-
- // Classes
- case T_CLASS:
- $classTrapped = true;
- break;
-
- // Default case: do nothing
- default:
- break;
- }
- }
-
- return (object)array('classes' => $classes, 'functions' => $functions);
-}
diff --git a/admin/tool/unittest/simpletestlib.php b/admin/tool/unittest/simpletestlib.php
deleted file mode 100644
index e60faf73ac5..00000000000
--- a/admin/tool/unittest/simpletestlib.php
+++ /dev/null
@@ -1,1371 +0,0 @@
-.
-
-/**
- * Utility functions to make unit testing easier.
- *
- * These functions, particularly the the database ones, are quick and
- * dirty methods for getting things done in test cases. None of these
- * methods should be used outside test code.
- *
- * Major Contirbutors
- * - T.J.Hunt@open.ac.uk
- *
- * @package tool
- * @subpackage unittest
- * @copyright © 2006 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- * Includes
- */
-require_once($CFG->libdir . '/simpletestlib/simpletest.php');
-require_once($CFG->libdir . '/simpletestlib/unit_tester.php');
-require_once($CFG->libdir . '/simpletestlib/expectation.php');
-require_once($CFG->libdir . '/simpletestlib/reporter.php');
-require_once($CFG->libdir . '/simpletestlib/web_tester.php');
-require_once($CFG->libdir . '/simpletestlib/mock_objects.php');
-
-/**
- * Recursively visit all the files in the source tree. Calls the callback
- * function with the pathname of each file found.
- *
- * @param $path the folder to start searching from.
- * @param $callback the function to call with the name of each file found.
- * @param $fileregexp a regexp used to filter the search (optional).
- * @param $exclude If true, pathnames that match the regexp will be ingored. If false,
- * only files that match the regexp will be included. (default false).
- * @param array $ignorefolders will not go into any of these folders (optional).
- */
-function recurseFolders($path, $callback, $fileregexp = '/.*/', $exclude = false, $ignorefolders = array()) {
- $files = scandir($path);
-
- foreach ($files as $file) {
- $filepath = $path .'/'. $file;
- if (strpos($file, '.') === 0) {
- /// Don't check hidden files.
- continue;
- } else if (is_dir($filepath)) {
- if (!in_array($filepath, $ignorefolders)) {
- recurseFolders($filepath, $callback, $fileregexp, $exclude, $ignorefolders);
- }
- } else if ($exclude xor preg_match($fileregexp, $filepath)) {
- call_user_func($callback, $filepath);
- }
- }
-}
-
-/**
- * An expectation for comparing strings ignoring whitespace.
- *
- * @package moodlecore
- * @subpackage simpletestex
- * @copyright © 2006 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class IgnoreWhitespaceExpectation extends SimpleExpectation {
- var $expect;
-
- function __construct($content, $message = '%s') {
- parent::__construct($message);
- $this->expect=$this->normalise($content);
- }
-
- function test($ip) {
- return $this->normalise($ip)==$this->expect;
- }
-
- function normalise($text) {
- return preg_replace('/\s+/m',' ',trim($text));
- }
-
- function testMessage($ip) {
- return "Input string [$ip] doesn't match the required value.";
- }
-}
-
-/**
- * An Expectation that two arrays contain the same list of values.
- *
- * @package moodlecore
- * @subpackage simpletestex
- * @copyright © 2006 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class ArraysHaveSameValuesExpectation extends SimpleExpectation {
- var $expect;
-
- function __construct($expected, $message = '%s') {
- parent::__construct($message);
- if (!is_array($expected)) {
- trigger_error('Attempt to create an ArraysHaveSameValuesExpectation ' .
- 'with an expected value that is not an array.');
- }
- $this->expect = $this->normalise($expected);
- }
-
- function test($actual) {
- return $this->normalise($actual) == $this->expect;
- }
-
- function normalise($array) {
- sort($array);
- return $array;
- }
-
- function testMessage($actual) {
- return 'Array [' . implode(', ', $actual) .
- '] does not contain the expected list of values [' . implode(', ', $this->expect) . '].';
- }
-}
-
-
-/**
- * An Expectation that compares to objects, and ensures that for every field in the
- * expected object, there is a key of the same name in the actual object, with
- * the same value. (The actual object may have other fields to, but we ignore them.)
- *
- * @package moodlecore
- * @subpackage simpletestex
- * @copyright © 2006 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class CheckSpecifiedFieldsExpectation extends SimpleExpectation {
- var $expect;
-
- function __construct($expected, $message = '%s') {
- parent::__construct($message);
- if (!is_object($expected)) {
- trigger_error('Attempt to create a CheckSpecifiedFieldsExpectation ' .
- 'with an expected value that is not an object.');
- }
- $this->expect = $expected;
- }
-
- function test($actual) {
- foreach ($this->expect as $key => $value) {
- if (isset($value) && isset($actual->$key) && $actual->$key == $value) {
- // OK
- } else if (is_null($value) && is_null($actual->$key)) {
- // OK
- } else {
- return false;
- }
- }
- return true;
- }
-
- function testMessage($actual) {
- $mismatches = array();
- foreach ($this->expect as $key => $value) {
- if (isset($value) && isset($actual->$key) && $actual->$key == $value) {
- // OK
- } else if (is_null($value) && is_null($actual->$key)) {
- // OK
- } else if (!isset($actual->$key)) {
- $mismatches[] = $key . ' (expected [' . $value . '] but was missing.';
- } else {
- $mismatches[] = $key . ' (expected [' . $value . '] got [' . $actual->$key . '].';
- }
- }
- return 'Actual object does not have all the same fields with the same values as the expected object (' .
- implode(', ', $mismatches) . ').';
- }
-}
-
-abstract class XMLStructureExpectation extends SimpleExpectation {
- /**
- * Parse a string as XML and return a DOMDocument;
- * @param $html
- * @return unknown_type
- */
- protected function load_xml($html) {
- $prevsetting = libxml_use_internal_errors(true);
- $parser = new DOMDocument();
- if (!$parser->loadXML('' . $html . '')) {
- $parser = new DOMDocument();
- }
- libxml_clear_errors();
- libxml_use_internal_errors($prevsetting);
- return $parser;
- }
-
- function testMessage($html) {
- $parsererrors = $this->load_xml($html);
- if (is_array($parsererrors)) {
- foreach ($parsererrors as $key => $message) {
- $parsererrors[$key] = $message->message;
- }
- return 'Could not parse XML [' . $html . '] errors were [' .
- implode('], [', $parsererrors) . ']';
- }
- return $this->customMessage($html);
- }
-}
-/**
- * An Expectation that looks to see whether some HMTL contains a tag with a certain attribute.
- *
- * @copyright 2009 Tim Hunt
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class ContainsTagWithAttribute extends XMLStructureExpectation {
- protected $tag;
- protected $attribute;
- protected $value;
-
- function __construct($tag, $attribute, $value, $message = '%s') {
- parent::__construct($message);
- $this->tag = $tag;
- $this->attribute = $attribute;
- $this->value = $value;
- }
-
- function test($html) {
- $parser = $this->load_xml($html);
- if (is_array($parser)) {
- return false;
- }
- $list = $parser->getElementsByTagName($this->tag);
-
- foreach ($list as $node) {
- if ($node->attributes->getNamedItem($this->attribute)->nodeValue === (string) $this->value) {
- return true;
- }
- }
- return false;
- }
-
- function customMessage($html) {
- return 'Content [' . $html . '] does not contain the tag [' .
- $this->tag . '] with attribute [' . $this->attribute . '="' . $this->value . '"].';
- }
-}
-
-/**
- * An Expectation that looks to see whether some HMTL contains a tag with an array of attributes.
- * All attributes must be present and their values must match the expected values.
- * A third parameter can be used to specify attribute=>value pairs which must not be present in a positive match.
- *
- * @copyright 2009 Nicolas Connault
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class ContainsTagWithAttributes extends XMLStructureExpectation {
- /**
- * @var string $tag The name of the Tag to search
- */
- protected $tag;
- /**
- * @var array $expectedvalues An associative array of parameters, all of which must be matched
- */
- protected $expectedvalues = array();
- /**
- * @var array $forbiddenvalues An associative array of parameters, none of which must be matched
- */
- protected $forbiddenvalues = array();
- /**
- * @var string $failurereason The reason why the test failed: nomatch or forbiddenmatch
- */
- protected $failurereason = 'nomatch';
-
- function __construct($tag, $expectedvalues, $forbiddenvalues=array(), $message = '%s') {
- parent::__construct($message);
- $this->tag = $tag;
- $this->expectedvalues = $expectedvalues;
- $this->forbiddenvalues = $forbiddenvalues;
- }
-
- function test($html) {
- $parser = $this->load_xml($html);
- if (is_array($parser)) {
- return false;
- }
-
- $list = $parser->getElementsByTagName($this->tag);
- $foundamatch = false;
-
- // Iterating through inputs
- foreach ($list as $node) {
- if (empty($node->attributes) || !is_a($node->attributes, 'DOMNamedNodeMap')) {
- continue;
- }
-
- // For the current expected attribute under consideration, check that values match
- $allattributesmatch = true;
-
- foreach ($this->expectedvalues as $expectedattribute => $expectedvalue) {
- if ($node->getAttribute($expectedattribute) === '' && $expectedvalue !== '') {
- $this->failurereason = 'nomatch';
- continue 2; // Skip this tag, it doesn't have all the expected attributes
- }
- if ($node->getAttribute($expectedattribute) !== (string) $expectedvalue) {
- $allattributesmatch = false;
- $this->failurereason = 'nomatch';
- }
- }
-
- if ($allattributesmatch) {
- $foundamatch = true;
-
- // Now make sure this node doesn't have any of the forbidden attributes either
- $nodeattrlist = $node->attributes;
-
- foreach ($nodeattrlist as $domattrname => $domattr) {
- if (array_key_exists($domattrname, $this->forbiddenvalues) && $node->getAttribute($domattrname) === (string) $this->forbiddenvalues[$domattrname]) {
- $this->failurereason = "forbiddenmatch:$domattrname:" . $node->getAttribute($domattrname);
- $foundamatch = false;
- }
- }
- }
- }
-
- return $foundamatch;
- }
-
- function customMessage($html) {
- $output = 'Content [' . $html . '] ';
-
- if (preg_match('/forbiddenmatch:(.*):(.*)/', $this->failurereason, $matches)) {
- $output .= "contains the tag $this->tag with the forbidden attribute=>value pair: [$matches[1]=>$matches[2]]";
- } else if ($this->failurereason == 'nomatch') {
- $output .= 'does not contain the tag [' . $this->tag . '] with attributes [';
- foreach ($this->expectedvalues as $var => $val) {
- $output .= "$var=\"$val\" ";
- }
- $output = rtrim($output);
- $output .= '].';
- }
-
- return $output;
- }
-}
-
-/**
- * An Expectation that looks to see whether some HMTL contains a tag with an array of attributes.
- * All attributes must be present and their values must match the expected values.
- * A third parameter can be used to specify attribute=>value pairs which must not be present in a positive match.
- *
- * @copyright 2010 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class ContainsSelectExpectation extends XMLStructureExpectation {
- /**
- * @var string $tag The name of the Tag to search
- */
- protected $name;
- /**
- * @var array $expectedvalues An associative array of parameters, all of which must be matched
- */
- protected $choices;
- /**
- * @var array $forbiddenvalues An associative array of parameters, none of which must be matched
- */
- protected $selected;
- /**
- * @var string $failurereason The reason why the test failed: nomatch or forbiddenmatch
- */
- protected $enabled;
-
- function __construct($name, $choices, $selected = null, $enabled = null, $message = '%s') {
- parent::__construct($message);
- $this->name = $name;
- $this->choices = $choices;
- $this->selected = $selected;
- $this->enabled = $enabled;
- }
-
- function test($html) {
- $parser = $this->load_xml($html);
- if (is_array($parser)) {
- return false;
- }
-
- $list = $parser->getElementsByTagName('select');
-
- // Iterating through inputs
- foreach ($list as $node) {
- if (empty($node->attributes) || !is_a($node->attributes, 'DOMNamedNodeMap')) {
- continue;
- }
-
- if ($node->getAttribute('name') != $this->name) {
- continue;
- }
-
- if ($this->enabled === true && $node->getAttribute('disabled')) {
- continue;
- } else if ($this->enabled === false && $node->getAttribute('disabled') != 'disabled') {
- continue;
- }
-
- $options = $node->getElementsByTagName('option');
- reset($this->choices);
- foreach ($options as $option) {
- if ($option->getAttribute('value') != key($this->choices)) {
- continue 2;
- }
- if ($option->firstChild->wholeText != current($this->choices)) {
- continue 2;
- }
- if ($option->getAttribute('value') === $this->selected &&
- !$option->hasAttribute('selected')) {
- continue 2;
- }
- next($this->choices);
- }
- if (current($this->choices) !== false) {
- // The HTML did not contain all the choices.
- return false;
- }
- return true;
- }
- return false;
- }
-
- function customMessage($html) {
- if ($this->enabled === true) {
- $state = 'an enabled';
- } else if ($this->enabled === false) {
- $state = 'a disabled';
- } else {
- $state = 'a';
- }
- $output = 'Content [' . $html . '] does not contain ' . $state .
- '