API CHANGE Added FunctionalTest::

API CHANGE Added ->session()
API CHANGE Added FunctionalTest::
API CHANGE Improved FunctionalTest's match by selector commands to produce less brittle output (rationalises whitespace)


git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@55134 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Sam Minnee 2008-05-26 06:21:30 +00:00
parent 5562885c69
commit 5dff780a5d
7 changed files with 104 additions and 12 deletions

View File

@ -581,6 +581,11 @@ class ManifestBuilder {
die("Cannot write manifest file! Check permissions of " . MANIFEST_FILE);
}
}
static function includeEverything() {
global $_CLASS_MANIFEST;
foreach($_CLASS_MANIFEST as $classFile) require_once($classFile);
}
}

View File

@ -107,7 +107,7 @@ class ContentController extends Controller {
}
// Draft/Archive security check - only CMS users should be able to look at stage/archived content
if($this->URLSegment != 'Security' && (Versioned::current_archived_date() || (Versioned::current_stage() && Versioned::current_stage() != 'Live'))) {
if($this->URLSegment != 'Security' && !Session::get('unsecuredDraftSite') && (Versioned::current_archived_date() || (Versioned::current_stage() && Versioned::current_stage() != 'Live'))) {
if(!Permission::check('CMS_ACCESS_CMSMain')) {
$link = $this->Link();
$message = _t("ContentController.DRAFT_SITE_ACCESS_RESTRICTION", "You must log in with your CMS password in order to view the draft or archived content. <a href=\"%s\">Click here to go back to the published site.</a>");

View File

@ -413,12 +413,15 @@ class Director {
static function makeRelative($url) {
$base1 = self::absoluteBaseURL();
$base2 = self::baseFolder();
$base3 = self::baseURL();
// Allow for the accidental inclusion of a // in the URL
$url = ereg_replace('([^:])//','\\1/',$url);
if(substr($url,0,strlen($base1)) == $base1) return substr($url,strlen($base1));
if(substr($url,0,strlen($base2)) == $base2) return substr($url,strlen($base2));
else if(substr($url,0,strlen($base2)) == $base2) return substr($url,strlen($base2));
else if(substr($url,0,strlen($base3)) == $base3) return substr($url,strlen($base3));
return $url;
}

View File

@ -233,7 +233,7 @@ class PDODatabase extends Database {
* @return boolean Returns true if successful
* @todo This shouldn't take any arguments; it should take the information given in the constructor instead.
*/
public function createDatabase($connect, $username, $password, $database) {
public function createDatabase() {
try {
$dbh = new PDO($connect, $username, $password);
$stmt = $dbh->prepare("CREATE DATABASE $database");

View File

@ -20,21 +20,58 @@
* </code>
*/
class FunctionalTest extends SapphireTest {
/**
* Set this to true on your sub-class to disable the use of themes in this test.
* This can be handy for functional testing of modules without having to worry about whether a user has changed
* behaviour by replacing the theme.
*/
static $disable_themes = false;
/**
* Set this to true on your sub-class to use the draft site by default for every test in this class.
*/
static $use_draft_site = false;
protected $mainSession = null;
/**
* CSSContentParser for the most recently requested page.
*/
protected $cssParser = null;
private $originalTheme = null;
/**
* Returns the {@link Session} object for this test
*/
function session() {
return $this->mainSession->session();
}
function setUp() {
parent::setUp();
$this->mainSession = new TestSession();
// Disable theme, if necessary
if($this->stat('disable_themes')) {
$this->originalTheme = SSViewer::current_theme();
SSViewer::set_theme(null);
}
// Switch to draft site, if necessary
if($this->stat('use_draft_site')) {
$this->useDraftSite();
}
}
function tearDown() {
parent::tearDown();
$this->mainSession = null;
// Re-enable theme, if previously disabled
if($this->stat('disable_themes')) {
SSViewer::set_theme($this->originalTheme);
}
}
/**
@ -42,7 +79,9 @@ class FunctionalTest extends SapphireTest {
*/
function get($url) {
$this->cssParser = null;
return $this->mainSession->get($url);
$response = $this->mainSession->get($url);
if(is_object($response) && $response->getHeader('Location')) $response = $this->mainSession->followRedirection();
return $response;
}
/**
@ -50,7 +89,9 @@ class FunctionalTest extends SapphireTest {
*/
function post($url, $data) {
$this->cssParser = null;
return $this->mainSession->post($url, $data);
$response = $this->mainSession->post($url, $data);
if(is_object($response) && $response->getHeader('Location')) $response = $this->mainSession->followRedirection();
return $response;
}
/**
@ -59,7 +100,9 @@ class FunctionalTest extends SapphireTest {
*/
function submitForm($formID, $button = null, $data = array()) {
$this->cssParser = null;
return $this->mainSession->submitForm($formID, $button, $data);
$response = $this->mainSession->submitForm($formID, $button, $data);
if(is_object($response) && $response->getHeader('Location')) $response = $this->mainSession->followRedirection();
return $response;
}
/**
@ -89,7 +132,7 @@ class FunctionalTest extends SapphireTest {
*/
function assertPartialMatchBySelector($selector, $expectedMatches) {
$items = $this->cssParser()->getBySelector($selector);
foreach($items as $item) $actuals[$item . ''] = true;
foreach($items as $item) $actuals[] = trim(preg_replace("/[ \n\r\t]+/", " ", $item. ''));
foreach($expectedMatches as $match) {
if(!isset($actuals[$match])) {
@ -115,7 +158,7 @@ class FunctionalTest extends SapphireTest {
*/
function assertExactMatchBySelector($selector, $expectedMatches) {
$items = $this->cssParser()->getBySelector($selector);
foreach($items as $item) $actuals[] = $item . '';
foreach($items as $item) $actuals[] = trim(preg_replace("/[ \n\r\t]+/", " ", $item. ''));
if($expectedMatches != $actuals) {
throw new PHPUnit_Framework_AssertionFailedError(
@ -172,4 +215,22 @@ class FunctionalTest extends SapphireTest {
);
}
}
/**
* Use the draft (stage) site for testing.
* This is helpful if you're not testing publication functionality and don't want "stage management" cluttering your test.
*/
function useDraftSite() {
$this->session()->inst_set('currentStage', 'Stage');
$this->session()->inst_set('unsecuredDraftSite', true);
}
/**
* Return a static variable from this class.
* Gets around PHP's lack of late static binding.
*/
function stat($varName) {
$className = get_class($this);
return eval("return {$className}::\$$varName;");
}
}

View File

@ -60,6 +60,19 @@ class TestRunner extends Controller {
echo "Please install PHPUnit using pear";
}
}
function coverage() {
if(hasPhpUnit()) {
ManifestBuilder::includeEverything();
$tests = ClassInfo::subclassesFor('SapphireTest');
array_shift($tests);
unset($tests['FunctionalTest']);
$this->runTests($tests, true);
} else {
echo "Please install PHPUnit using pear";
}
}
/**
* Run only a single test class
@ -75,7 +88,7 @@ class TestRunner extends Controller {
}
function runTests($classList) {
function runTests($classList, $coverage = false) {
if(!Director::is_cli()) {
self::$default_reporter->writeHeader();
echo '<div class="info">';
@ -100,7 +113,16 @@ class TestRunner extends Controller {
}
/*, array("reportDirectory" => "/Users/sminnee/phpunit-report")*/
$testResult = PHPUnit_TextUI_TestRunner::run($suite);
if($coverage) {
$testResult = PHPUnit_TextUI_TestRunner::run($suite, array("reportDirectory" => "../assets/coverage-report"));
} else {
$testResult = PHPUnit_TextUI_TestRunner::run($suite);
}
if($coverage) {
$coverageURL = Director::absoluteURL('assets/coverage-report');
echo "<p><a href=\"$coverageURL\">Coverage report available here</a></p>";
}
if(!Director::is_cli()) echo '</div>';

View File

@ -80,7 +80,8 @@ class TestSession {
* Get the most recent response's content
*/
function lastContent() {
return $this->lastResponse->getBody();
if(is_string($this->lastResponse)) return $this->lastResponse;
else return $this->lastResponse->getBody();
}
function cssParser() {