summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Rothstein <drothstein@gmail.com>2013-04-01 22:50:18 -0400
committerDavid Rothstein <drothstein@gmail.com>2013-04-01 22:50:18 -0400
commit7cbe4b7e265343773c2cd2e50b86c68182a64f8e (patch)
tree482c920dfba10c492cafb9f4aa84034086d56a56
parentde6e29d084adc900fa8c93510efa2679ce82abea (diff)
downloadbrdo-7cbe4b7e265343773c2cd2e50b86c68182a64f8e.tar.gz
brdo-7cbe4b7e265343773c2cd2e50b86c68182a64f8e.tar.bz2
Issue #1693398 by donquixote, pounard, sun, Sylvain Lecoy: Allow PSR-0 test classes to be used in D7.
-rw-r--r--CHANGELOG.txt2
-rw-r--r--modules/simpletest/drupal_web_test_case.php7
-rw-r--r--modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php18
-rw-r--r--modules/simpletest/simpletest.module107
-rw-r--r--modules/simpletest/simpletest.pages.inc3
-rw-r--r--modules/simpletest/simpletest.test89
-rw-r--r--modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/ExampleTest.php18
-rw-r--r--modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php18
-rw-r--r--modules/simpletest/tests/psr_0_test/psr_0_test.info6
-rw-r--r--modules/simpletest/tests/psr_0_test/psr_0_test.module1
-rwxr-xr-xscripts/run-tests.sh4
11 files changed, 269 insertions, 4 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index fc5772139..e6c15c9f3 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,6 +1,8 @@
Drupal 7.22, xxxx-xx-xx (development version)
-----------------------
+- Changed the Simpletest module to allow PSR-0 test classes to be used in
+ Drupal 7.
- Removed an unnecessary "Content-Disposition" header from private file
downloads; it prevented many private files from being viewed inline in a web
browser.
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index a2cc484a2..0853c7d96 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -447,7 +447,8 @@ abstract class DrupalTestCase {
*/
protected function verbose($message) {
if ($id = simpletest_verbose($message)) {
- $url = file_create_url($this->originalFileDirectory . '/simpletest/verbose/' . get_class($this) . '-' . $id . '.html');
+ $class_safe = str_replace('\\', '_', get_class($this));
+ $url = file_create_url($this->originalFileDirectory . '/simpletest/verbose/' . $class_safe . '-' . $id . '.html');
$this->error(l(t('Verbose message'), $url, array('attributes' => array('target' => '_blank'))), 'User notice');
}
}
@@ -466,7 +467,8 @@ abstract class DrupalTestCase {
*/
public function run(array $methods = array()) {
// Initialize verbose debugging.
- simpletest_verbose(NULL, variable_get('file_public_path', conf_path() . '/files'), get_class($this));
+ $class = get_class($this);
+ simpletest_verbose(NULL, variable_get('file_public_path', conf_path() . '/files'), str_replace('\\', '_', $class));
// HTTP auth settings (<username>:<password>) for the simpletest browser
// when sending requests to the test site.
@@ -478,7 +480,6 @@ abstract class DrupalTestCase {
}
set_error_handler(array($this, 'errorHandler'));
- $class = get_class($this);
// Iterate through all the methods in this class, unless a specific list of
// methods to run was passed.
$class_methods = get_class_methods($class);
diff --git a/modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php b/modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php
new file mode 100644
index 000000000..0292956ce
--- /dev/null
+++ b/modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\simpletest\Tests;
+
+class PSR0WebTest extends \DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'PSR0 web test',
+ 'description' => 'We want to assert that this PSR-0 test case is being discovered.',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function testArithmetics() {
+ $this->assert(1 + 1 == 2, '1 + 1 == 2');
+ }
+}
diff --git a/modules/simpletest/simpletest.module b/modules/simpletest/simpletest.module
index f82575573..3103af0e8 100644
--- a/modules/simpletest/simpletest.module
+++ b/modules/simpletest/simpletest.module
@@ -157,6 +157,7 @@ function simpletest_run_tests($test_list, $reporter = 'drupal') {
* Batch operation callback.
*/
function _simpletest_batch_operation($test_list_init, $test_id, &$context) {
+ simpletest_classloader_register();
// Get working values.
if (!isset($context['sandbox']['max'])) {
// First iteration: initialize working values.
@@ -289,6 +290,9 @@ function simpletest_log_read($test_id, $prefix, $test_class, $during_test = FALS
* a static variable. In order to list tests provided by disabled modules
* hook_registry_files_alter() is used to forcefully add them to the registry.
*
+ * PSR-0 classes are found by searching the designated directory for each module
+ * for files matching the PSR-0 standard.
+ *
* @return
* An array of tests keyed with the groups specified in each of the tests
* getInfo() method and then keyed by the test class. An example of the array
@@ -309,6 +313,9 @@ function simpletest_test_get_all() {
$groups = &drupal_static(__FUNCTION__);
if (!$groups) {
+ // Register a simple class loader for PSR-0 test classes.
+ simpletest_classloader_register();
+
// Load test information from cache if available, otherwise retrieve the
// information from each tests getInfo() method.
if ($cache = cache_get('simpletest', 'cache')) {
@@ -318,6 +325,34 @@ function simpletest_test_get_all() {
// Select all clases in files ending with .test.
$classes = db_query("SELECT name FROM {registry} WHERE type = :type AND filename LIKE :name", array(':type' => 'class', ':name' => '%.test'))->fetchCol();
+ // Also discover PSR-0 test classes, if the PHP version allows it.
+ if (version_compare(PHP_VERSION, '5.3') > 0) {
+
+ // Select all PSR-0 classes in the Tests namespace of all modules.
+ $system_list = db_query("SELECT name, filename FROM {system}")->fetchAllKeyed();
+
+ foreach ($system_list as $name => $filename) {
+ // Build directory in which the test files would reside.
+ $tests_dir = DRUPAL_ROOT . '/' . dirname($filename) . '/lib/Drupal/' . $name . '/Tests';
+ // Scan it for test files if it exists.
+ if (is_dir($tests_dir)) {
+ $files = file_scan_directory($tests_dir, '/.*\.php/');
+ if (!empty($files)) {
+ $basedir = DRUPAL_ROOT . '/' . dirname($filename) . '/lib/';
+ foreach ($files as $file) {
+ // Convert the file name into the namespaced class name.
+ $replacements = array(
+ '/' => '\\',
+ $basedir => '',
+ '.php' => '',
+ );
+ $classes[] = strtr($file->uri, $replacements);
+ }
+ }
+ }
+ }
+ }
+
// Check that each class has a getInfo() method and store the information
// in an array keyed with the group specified in the test information.
$groups = array();
@@ -353,6 +388,78 @@ function simpletest_test_get_all() {
return $groups;
}
+/*
+ * Register a simple class loader that can find D8-style PSR-0 test classes.
+ *
+ * Other PSR-0 class loading can happen in contrib, but those contrib class
+ * loader modules will not be enabled when testbot runs. So we need to do this
+ * one in core.
+ */
+function simpletest_classloader_register() {
+
+ // Prevent duplicate classloader registration.
+ static $first_run = TRUE;
+ if (!$first_run) {
+ return;
+ }
+ $first_run = FALSE;
+
+ // Only register PSR-0 class loading if we are on PHP 5.3 or higher.
+ if (version_compare(PHP_VERSION, '5.3') > 0) {
+ spl_autoload_register('_simpletest_autoload_psr0');
+ }
+}
+
+/**
+ * Autoload callback to find PSR-0 test classes.
+ *
+ * This will only work on classes where the namespace is of the pattern
+ * "Drupal\$extension\Tests\.."
+ */
+function _simpletest_autoload_psr0($class) {
+
+ // Static cache for extension paths.
+ // This cache is lazily filled as soon as it is needed.
+ static $extensions;
+
+ // Check that the first namespace fragment is "Drupal\"
+ if (substr($class, 0, 7) === 'Drupal\\') {
+ // Find the position of the second namespace separator.
+ $pos = strpos($class, '\\', 7);
+ // Check that the third namespace fragment is "\Tests\".
+ if (substr($class, $pos, 7) === '\\Tests\\') {
+
+ // Extract the second namespace fragment, which we expect to be the
+ // extension name.
+ $extension = substr($class, 7, $pos - 7);
+
+ // Lazy-load the extension paths, both enabled and disabled.
+ if (!isset($extensions)) {
+ $extensions = db_query("SELECT name, filename FROM {system}")->fetchAllKeyed();
+ }
+
+ // Check if the second namespace fragment is a known extension name.
+ if (isset($extensions[$extension])) {
+
+ // Split the class into namespace and classname.
+ $nspos = strrpos($class, '\\');
+ $namespace = substr($class, 0, $nspos);
+ $classname = substr($class, $nspos + 1);
+
+ // Build the filepath where we expect the class to be defined.
+ $path = dirname($extensions[$extension]) . '/lib/' .
+ str_replace('\\', '/', $namespace) . '/' .
+ str_replace('_', '/', $classname) . '.php';
+
+ // Include the file, if it does exist.
+ if (file_exists($path)) {
+ include $path;
+ }
+ }
+ }
+ }
+}
+
/**
* Implements hook_registry_files_alter().
*
diff --git a/modules/simpletest/simpletest.pages.inc b/modules/simpletest/simpletest.pages.inc
index d1a7e4ade..3127459e2 100644
--- a/modules/simpletest/simpletest.pages.inc
+++ b/modules/simpletest/simpletest.pages.inc
@@ -181,6 +181,7 @@ function theme_simpletest_test_table($variables) {
* Run selected tests.
*/
function simpletest_test_form_submit($form, &$form_state) {
+ simpletest_classloader_register();
// Get list of tests.
$tests_list = array();
foreach ($form_state['values'] as $class_name => $value) {
@@ -233,6 +234,8 @@ function simpletest_result_form($form, &$form_state, $test_id) {
'#debug' => 0,
);
+ simpletest_classloader_register();
+
// Cycle through each test group.
$header = array(t('Message'), t('Group'), t('Filename'), t('Line'), t('Function'), array('colspan' => 2, 'data' => t('Status')));
$form['result']['results'] = array();
diff --git a/modules/simpletest/simpletest.test b/modules/simpletest/simpletest.test
index e7a4f704a..dde162ec7 100644
--- a/modules/simpletest/simpletest.test
+++ b/modules/simpletest/simpletest.test
@@ -655,3 +655,92 @@ class SimpleTestOtherInstallationProfileModuleTestsTestCase extends DrupalWebTes
$this->assertNoText('Installation profile module tests helper');
}
}
+
+/**
+ * Verifies that tests in other installation profiles are not found.
+ *
+ * @see SimpleTestInstallationProfileModuleTestsTestCase
+ */
+class SimpleTestDiscoveryTestCase extends DrupalWebTestCase {
+ /**
+ * Use the Testing profile.
+ *
+ * The Testing profile contains drupal_system_listing_compatible_test.test,
+ * which attempts to:
+ * - run tests using the Minimal profile (which does not contain the
+ * drupal_system_listing_compatible_test.module)
+ * - but still install the drupal_system_listing_compatible_test.module
+ * contained in the Testing profile.
+ *
+ * @see DrupalSystemListingCompatibleTestCase
+ */
+ protected $profile = 'testing';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Discovery of test classes',
+ 'description' => 'Verifies that tests classes are discovered and can be autoloaded (class_exists).',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function setUp() {
+ parent::setUp(array('simpletest'));
+
+ $this->admin_user = $this->drupalCreateUser(array('administer unit tests'));
+ $this->drupalLogin($this->admin_user);
+ }
+
+ /**
+ * Test discovery of PSR-0 test classes.
+ */
+ function testDiscoveryFunctions() {
+ if (version_compare(PHP_VERSION, '5.3') < 0) {
+ // Don't expect PSR-0 tests to be discovered on older PHP versions.
+ return;
+ }
+ // TODO: What if we have cached values? Do we need to force a cache refresh?
+ $classes_all = simpletest_test_get_all();
+ foreach (array(
+ 'Drupal\\simpletest\\Tests\\PSR0WebTest',
+ 'Drupal\\psr_0_test\\Tests\\ExampleTest',
+ ) as $class) {
+ $this->assert(!empty($classes_all['SimpleTest'][$class]), t('Class @class must be discovered by simpletest_test_get_all().', array('@class' => $class)));
+ }
+ }
+
+ /**
+ * Tests existence of test cases.
+ */
+ function testDiscovery() {
+ $this->drupalGet('admin/config/development/testing');
+ // Tests within enabled modules.
+ // (without these, this test wouldn't happen in the first place, so this is
+ // a bit pointless. We still run it for proof-of-concept.)
+ // This one is defined in system module.
+ $this->assertText('Drupal error handlers');
+ // This one is defined in simpletest module.
+ $this->assertText('Discovery of test classes');
+ // Tests within disabled modules.
+ if (version_compare(PHP_VERSION, '5.3') < 0) {
+ // Don't expect PSR-0 tests to be discovered on older PHP versions.
+ return;
+ }
+ // This one is provided by simpletest itself via PSR-0.
+ $this->assertText('PSR0 web test');
+ $this->assertText('PSR0 example test: PSR-0 in disabled modules.');
+ $this->assertText('PSR0 example test: PSR-0 in nested subfolders.');
+
+ // Test each test individually.
+ foreach (array(
+ 'Drupal\\psr_0_test\\Tests\\ExampleTest',
+ 'Drupal\\psr_0_test\\Tests\\Nested\\NestedExampleTest',
+ ) as $class) {
+ $this->drupalGet('admin/config/development/testing');
+ $edit = array($class => TRUE);
+ $this->drupalPost(NULL, $edit, t('Run tests'));
+ $this->assertText('The test run finished', t('Test @class must finish.', array('@class' => $class)));
+ $this->assertText('1 pass, 0 fails, and 0 exceptions', t('Test @class must pass.', array('@class' => $class)));
+ }
+ }
+}
diff --git a/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/ExampleTest.php b/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/ExampleTest.php
new file mode 100644
index 000000000..3098c925f
--- /dev/null
+++ b/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/ExampleTest.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\psr_0_test\Tests;
+
+class ExampleTest extends \DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'PSR0 example test: PSR-0 in disabled modules.',
+ 'description' => 'We want to assert that this test case is being discovered.',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function testArithmetics() {
+ $this->assert(1 + 1 == 2, '1 + 1 == 2');
+ }
+}
diff --git a/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php b/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php
new file mode 100644
index 000000000..324ed439a
--- /dev/null
+++ b/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\psr_0_test\Tests\Nested;
+
+class NestedExampleTest extends \DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'PSR0 example test: PSR-0 in nested subfolders.',
+ 'description' => 'We want to assert that this PSR-0 test case is being discovered.',
+ 'group' => 'SimpleTest',
+ );
+ }
+
+ function testArithmetics() {
+ $this->assert(1 + 1 == 2, '1 + 1 == 2');
+ }
+}
diff --git a/modules/simpletest/tests/psr_0_test/psr_0_test.info b/modules/simpletest/tests/psr_0_test/psr_0_test.info
new file mode 100644
index 000000000..48ca8d850
--- /dev/null
+++ b/modules/simpletest/tests/psr_0_test/psr_0_test.info
@@ -0,0 +1,6 @@
+name = PSR-0 Test cases
+description = Test classes to be discovered by simpletest.
+core = 7.x
+
+hidden = TRUE
+package = Testing
diff --git a/modules/simpletest/tests/psr_0_test/psr_0_test.module b/modules/simpletest/tests/psr_0_test/psr_0_test.module
new file mode 100644
index 000000000..b3d9bbc7f
--- /dev/null
+++ b/modules/simpletest/tests/psr_0_test/psr_0_test.module
@@ -0,0 +1 @@
+<?php
diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh
index 334501527..189d7f2e8 100755
--- a/scripts/run-tests.sh
+++ b/scripts/run-tests.sh
@@ -362,6 +362,8 @@ function simpletest_script_run_one_test($test_id, $test_class) {
// Bootstrap Drupal.
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+ simpletest_classloader_register();
+
$test = new $test_class($test_id);
$test->run();
$info = $test->getInfo();
@@ -395,7 +397,7 @@ function simpletest_script_command($test_id, $test_class) {
if ($args['color']) {
$command .= ' --color';
}
- $command .= " --php " . escapeshellarg($php) . " --test-id $test_id --execute-test $test_class";
+ $command .= " --php " . escapeshellarg($php) . " --test-id $test_id --execute-test " . escapeshellarg($test_class);
return $command;
}