From ab7e5944d1f5e8cd2896fd132a6bfa87e8440a5f Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Mon, 12 Sep 2016 15:13:55 +1200 Subject: [PATCH 1/9] API: Derive BASE_PATH from composer autoloader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The location of composer’s vendor/autoload_real.php file is a good indicator of the root of a project, and can be used to derive a BASE_PATH This gives us more flexibility about where the framework module is installed relative to a project root. It also lets us use the framework module as a project root, e.g. in test runs. THIRDPARTY_PATH and ADMIN_PATH are calculated relative to this, and the FRAMEWORK_DIR, THIRDPARTY_DIR, and ADMIN_DIR are relative to the BASE_PATH. --- Core/Constants.php | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/Core/Constants.php b/Core/Constants.php index 8d3fe5554..563ec6f03 100644 --- a/Core/Constants.php +++ b/Core/Constants.php @@ -175,8 +175,19 @@ if (defined('SS_ALLOWED_HOSTS') && php_sapi_name() !== "cli") { /** * Define system paths */ +// Determine BASE_PATH based on the composer autoloader if(!defined('BASE_PATH')) { - // Assuming that this file is framework/core/Core.php we can then determine the base path + foreach(debug_backtrace() as $backtraceItem) { + if(preg_match('#^(.*)\/vendor/composer/autoload_real.php#', $backtraceItem['file'], $matches)) { + define('BASE_PATH', $matches[1]); + break; + } + } +} + +// Determine BASE_PATH by assuming that this file is framework/core/Core.php +if(!defined('BASE_PATH')) { + // we can then determine the base path $candidateBasePath = rtrim(dirname(dirname(dirname(__FILE__))), DIRECTORY_SEPARATOR); // We can't have an empty BASE_PATH. Making it / means that double-slashes occur in places but that's benign. // This likely only happens on chrooted environemnts @@ -209,21 +220,20 @@ define('THEMES_DIR', 'themes'); define('THEMES_PATH', BASE_PATH . '/' . THEMES_DIR); // Relies on this being in a subdir of the framework. // If it isn't, or is symlinked to a folder with a different name, you must define FRAMEWORK_DIR -if(!defined('FRAMEWORK_DIR')) { - define('FRAMEWORK_DIR', basename(dirname(dirname(__FILE__)))); + +define('FRAMEWORK_PATH', realpath(__DIR__ . '/../')); +if(strpos(FRAMEWORK_PATH, BASE_PATH) === 0) { + define('FRAMEWORK_DIR', trim(substr(FRAMEWORK_PATH, strlen(BASE_PATH)), '/')); + $frameworkDirSlashSuffix = FRAMEWORK_DIR ? FRAMEWORK_DIR . '/' : ''; +} else { + throw new Exception("Path error: FRAMEWORK_PATH " . FRAMEWORK_PATH . " not within BASE_PATH " . BASE_PATH); } -define('FRAMEWORK_PATH', BASE_PATH . '/' . FRAMEWORK_DIR); -define('FRAMEWORK_ADMIN_DIR', FRAMEWORK_DIR . '/admin'); -define('FRAMEWORK_ADMIN_PATH', BASE_PATH . '/' . FRAMEWORK_ADMIN_DIR); -// These are all deprecated. Use the FRAMEWORK_ versions instead. -define('SAPPHIRE_DIR', FRAMEWORK_DIR); -define('SAPPHIRE_PATH', FRAMEWORK_PATH); -define('SAPPHIRE_ADMIN_DIR', FRAMEWORK_ADMIN_DIR); -define('SAPPHIRE_ADMIN_PATH', FRAMEWORK_ADMIN_PATH); +define('FRAMEWORK_ADMIN_DIR', $frameworkDirSlashSuffix . 'admin'); +define('FRAMEWORK_ADMIN_PATH', FRAMEWORK_PATH . '/admin'); -define('THIRDPARTY_DIR', FRAMEWORK_DIR . '/thirdparty'); -define('THIRDPARTY_PATH', BASE_PATH . '/' . THIRDPARTY_DIR); +define('THIRDPARTY_DIR', $frameworkDirSlashSuffix . 'thirdparty'); +define('THIRDPARTY_PATH', FRAMEWORK_PATH . '/thirdparty'); define('ADMIN_THIRDPARTY_DIR', FRAMEWORK_ADMIN_DIR . '/thirdparty'); define('ADMIN_THIRDPARTY_PATH', BASE_PATH . '/' . ADMIN_THIRDPARTY_DIR); From 6b847d36144a5d10aa2eb1bf691a641efa82f73f Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Mon, 12 Sep 2016 15:16:21 +1200 Subject: [PATCH 2/9] NEW: Allow project root to be treated as a module. If the _config folder exists as a top-level directory, treat the project root as a module too. This is useful, e.g. when initialisation a SilverStripe environment within a module. This is only a first cut. Modules in the vendor directory are excluded. Most likely, we will need to search the vendor folder for modules with type = silverstripe-module in their composer.json. --- Core/Manifest/ConfigManifest.php | 1 + Core/Manifest/ManifestFileFinder.php | 7 +++++++ View/ThemeManifest.php | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Core/Manifest/ConfigManifest.php b/Core/Manifest/ConfigManifest.php index be612e181..1f97ace0f 100644 --- a/Core/Manifest/ConfigManifest.php +++ b/Core/Manifest/ConfigManifest.php @@ -226,6 +226,7 @@ class ConfigManifest { $finder = new ManifestFileFinder(); $finder->setOptions(array( + 'min_depth' => 0, 'name_regex' => '/(^|[\/\\\\])_config.php$/', 'ignore_tests' => !$includeTests, 'file_callback' => array($this, 'addSourceConfigFile') diff --git a/Core/Manifest/ManifestFileFinder.php b/Core/Manifest/ManifestFileFinder.php index f081a6240..f5f3b4c71 100644 --- a/Core/Manifest/ManifestFileFinder.php +++ b/Core/Manifest/ManifestFileFinder.php @@ -39,6 +39,11 @@ class ManifestFileFinder extends FileFinder { return false; } + // Skip over the vendor directories + if (($depth == 1 || $depth == 2) && $basename == 'vendor') { + return false; + } + // If we're not in testing mode, then skip over any tests directories. if ($this->getOption('ignore_tests') && $basename == self::TESTS_DIR) { return false; @@ -57,6 +62,8 @@ class ManifestFileFinder extends FileFinder { && !($this->getOption('include_themes') && $basename == THEMES_DIR) && !file_exists($pathname . '/' . self::CONFIG_FILE) && !file_exists($pathname . '/' . self::CONFIG_DIR) + && $basename !== self::CONFIG_DIR // include a root config dir + && !file_exists("$pathname/../" . self::CONFIG_DIR) // include all paths if a root config dir exists ); if ($lackingConfig) { diff --git a/View/ThemeManifest.php b/View/ThemeManifest.php index ea2e9f36f..4f73011ed 100644 --- a/View/ThemeManifest.php +++ b/View/ThemeManifest.php @@ -154,7 +154,7 @@ class ThemeManifest implements ThemeList { $path = '/'.implode('/', $themeParts); // If this is in the project, add to beginning of list. Else add to end. - if ($themeParts[0] == $this->project) { + if ($themeParts && $themeParts[0] == $this->project) { array_unshift($this->themes, $path); } else { From cebcf7fb8c4bedb45cf8360978e95c11a831ff8b Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Thu, 15 Sep 2016 11:33:51 +1200 Subject: [PATCH 3/9] NEW: More flexible theme resolution for framework and cms. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit using ‘silverstripe/framework’ or ‘silverstripe/cms’ will resolve the right path even if these folders are in the project root. ‘vendor/module:/sub/path’ theme references are also supported so that the admin sub-theme can be accessed. --- View/ThemeResourceLoader.php | 41 ++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/View/ThemeResourceLoader.php b/View/ThemeResourceLoader.php index 5ae2bb56a..1f33e1070 100644 --- a/View/ThemeResourceLoader.php +++ b/View/ThemeResourceLoader.php @@ -95,19 +95,42 @@ class ThemeResourceLoader { // is always the name of the install directory, not necessarily the composer name. $parts = explode(':', $identifier, 2); - list($vendor, $module) = explode('/', $parts[0], 2); - $theme = count($parts) > 1 ? $parts[1] : ''; + if(count($parts) > 1) { + $theme = $parts[1]; + // "module/vendor:/sub/path" + if($theme[0] === '/') { + $subpath = $theme; - $path = $module . ($theme ? '/themes/'.$theme : ''); + // "module/vendor:subtheme" + } else { + $subpath = '/themes/' . $theme; + } - // Right now we require $module to be a silverstripe module (in root) or theme (in themes dir) - // If both exist, we prefer theme - if (is_dir(THEMES_PATH . '/' .$path)) { - return THEMES_DIR . '/' . $path; + // "module/vendor" + } else { + $subpath = ''; } - else { - return $path; + + // To do: implement more flexible module path lookup + $package = $parts[0]; + switch($package) { + case 'silverstripe/framework': + $modulePath = FRAMEWORK_DIR; + break; + + case 'silverstripe/cms': + $modulePath = CMS_DIR; + break; + + default: + list($vendor, $modulePath) = explode('/', $parts[0], 2); + // If the module is in the themes// prefer that + if (is_dir(THEMES_PATH . '/' .$modulePath)) { + $modulePath = THEMES_DIR . '/' . $$modulePath; + } } + + return ltrim($modulePath . $subpath, '/'); } // Otherwise it's a (deprecated) old-style "theme" identifier else { From 93a0122c0f61b487cf0cc9d010913e3cdf655597 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Mon, 12 Sep 2016 17:25:08 +1200 Subject: [PATCH 4/9] =?UTF-8?q?FIX:=20Don=E2=80=99t=20treat=20URLs=20as=20?= =?UTF-8?q?root=20relative=20when=20FRAMEWORK=5FDIR=20=3D=20=E2=80=9C?= =?UTF-8?q?=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code was assuming that FRAMEWORK_DIR would always have a value. If it doesn’t (because you’re running a test instance of a naked framework) This caused URLs to be treated as root relative, which creates some duplicate-inclusion bugs. The use of ltrim() works, but is a bit clumsy. A more flexible approach to including front-end assets of given modules would be preferable; ideally something that also let you keep your code outside of the web root. --- Forms/GridField/GridFieldPrintButton.php | 2 +- Forms/HTMLEditor/HTMLEditorField_Toolbar.php | 2 +- Forms/UploadField_ItemHandler.php | 2 +- Forms/UploadField_SelectHandler.php | 2 +- admin/code/LeftAndMain.php | 10 +++++----- admin/code/MemberImportForm.php | 2 +- admin/code/SecurityAdmin.php | 12 ++++++------ tests/control/HTTPTest.php | 3 ++- tests/core/ClassInfoTest.php | 2 +- 9 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Forms/GridField/GridFieldPrintButton.php b/Forms/GridField/GridFieldPrintButton.php index d4d753a78..9b7ae787c 100644 --- a/Forms/GridField/GridFieldPrintButton.php +++ b/Forms/GridField/GridFieldPrintButton.php @@ -119,7 +119,7 @@ class GridFieldPrintButton implements GridField_HTMLProvider, GridField_ActionPr public function handlePrint($gridField, $request = null) { set_time_limit(60); Requirements::clear(); - Requirements::css(FRAMEWORK_DIR . '/client/dist/styles/GridField_print.css'); + Requirements::css(ltrim(FRAMEWORK_DIR . '/client/dist/styles/GridField_print.css', '/')); if($data = $this->generatePrintData($gridField)){ return $data->renderWith(get_class($gridField)."_print"); diff --git a/Forms/HTMLEditor/HTMLEditorField_Toolbar.php b/Forms/HTMLEditor/HTMLEditorField_Toolbar.php index cc43df8cf..2bea2dd10 100644 --- a/Forms/HTMLEditor/HTMLEditorField_Toolbar.php +++ b/Forms/HTMLEditor/HTMLEditorField_Toolbar.php @@ -250,7 +250,7 @@ class HTMLEditorField_Toolbar extends RequestHandler $remoteURL->addExtraClass('remoteurl'); $fromWeb->addExtraClass('content ss-uploadfield htmleditorfield-from-web'); - Requirements::css(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/AssetUploadField.css'); + Requirements::css(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/AssetUploadField.css', '/')); $computerUploadField = UploadField::create('AssetUploadField', ''); $computerUploadField->setConfig('previewMaxWidth', 40); $computerUploadField->setConfig('previewMaxHeight', 30); diff --git a/Forms/UploadField_ItemHandler.php b/Forms/UploadField_ItemHandler.php index 151d07bd4..5ad9dc2f6 100644 --- a/Forms/UploadField_ItemHandler.php +++ b/Forms/UploadField_ItemHandler.php @@ -147,7 +147,7 @@ class UploadField_ItemHandler extends RequestHandler return $this->httpError(403); } - Requirements::css(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/UploadField.css'); + Requirements::css(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/UploadField.css', '/')); return $this->customise(array( 'Form' => $this->EditForm() diff --git a/Forms/UploadField_SelectHandler.php b/Forms/UploadField_SelectHandler.php index f1014302a..7df08fc12 100644 --- a/Forms/UploadField_SelectHandler.php +++ b/Forms/UploadField_SelectHandler.php @@ -60,7 +60,7 @@ class UploadField_SelectHandler extends RequestHandler public function index() { // Requires a separate JS file, because we can't reach into the iframe with entwine. - Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/UploadField_select.js'); + Requirements::javascript(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/js/UploadField_select.js', '/')); return $this->renderWith('SilverStripe\\Admin\\CMSDialog'); } diff --git a/admin/code/LeftAndMain.php b/admin/code/LeftAndMain.php index 09be46df5..9b7a5df54 100644 --- a/admin/code/LeftAndMain.php +++ b/admin/code/LeftAndMain.php @@ -165,7 +165,7 @@ class LeftAndMain extends Controller implements PermissionProvider { * @var array */ private static $admin_themes = [ - '/framework/admin/themes/cms-forms', + 'silverstripe/framework:/admin/themes/cms-forms', SSViewer::DEFAULT_THEME, ]; @@ -536,12 +536,12 @@ class LeftAndMain extends Controller implements PermissionProvider { window.ss.config = " . $this->getCombinedClientConfig() . "; "); - Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-lib.js'); - Requirements::css(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/bundle.css'); + Requirements::javascript(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-lib.js', '/')); + Requirements::css(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/bundle.css', '/')); - Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-legacy.js'); + Requirements::javascript(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-legacy.js', '/')); - Requirements::add_i18n_javascript(FRAMEWORK_DIR . '/client/lang', false, true); + Requirements::add_i18n_javascript(ltrim(FRAMEWORK_DIR . '/client/lang', '/'), false, true); Requirements::add_i18n_javascript(FRAMEWORK_ADMIN_DIR . '/client/lang', false, true); if ($this->config()->session_keepalive_ping) { diff --git a/admin/code/MemberImportForm.php b/admin/code/MemberImportForm.php index 6f170f650..3b844a956 100644 --- a/admin/code/MemberImportForm.php +++ b/admin/code/MemberImportForm.php @@ -71,7 +71,7 @@ class MemberImportForm extends Form { parent::__construct($controller, $name, $fields, $actions, $validator); - Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-lib.js'); + Requirements::javascript(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-lib.js', '/')); Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/MemberImportForm.js'); Requirements::css(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/bundle.css'); diff --git a/admin/code/SecurityAdmin.php b/admin/code/SecurityAdmin.php index f03108cf2..82351fb48 100755 --- a/admin/code/SecurityAdmin.php +++ b/admin/code/SecurityAdmin.php @@ -233,9 +233,9 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { public function memberimport() { Requirements::clear(); - Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-lib.js'); - Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/MemberImportForm.js'); - Requirements::css(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/bundle.css'); + Requirements::javascript(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-lib.js', '/')); + Requirements::javascript(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/js/MemberImportForm.js', '/')); + Requirements::css(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/bundle.css', '/')); return $this->renderWith('BlankPage', array( 'Form' => $this->MemberImportForm()->forTemplate(), @@ -267,9 +267,9 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { public function groupimport() { Requirements::clear(); - Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-lib.js'); - Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/MemberImportForm.js'); - Requirements::css(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/bundle.css'); + Requirements::javascript(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-lib.js', '/')); + Requirements::javascript(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/js/MemberImportForm.js', '/')); + Requirements::css(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/bundle.css', '/')); return $this->renderWith('BlankPage', array( 'Content' => ' ', diff --git a/tests/control/HTTPTest.php b/tests/control/HTTPTest.php index 2b010c0f5..f0c6ed9b3 100644 --- a/tests/control/HTTPTest.php +++ b/tests/control/HTTPTest.php @@ -327,8 +327,9 @@ class HTTPTest extends FunctionalTest { public function testFilename2url() { $this->withBaseURL('http://www.silverstripe.org/', function($test) { + $frameworkTests = ltrim(FRAMEWORK_DIR . '/tests', '/'); $test->assertEquals( - 'http://www.silverstripe.org/framework/tests/control/HTTPTest.php', + "http://www.silverstripe.org/$frameworkTests/control/HTTPTest.php", HTTP::filename2url(__FILE__) ); }); diff --git a/tests/core/ClassInfoTest.php b/tests/core/ClassInfoTest.php index 115f62c15..ba84fae87 100644 --- a/tests/core/ClassInfoTest.php +++ b/tests/core/ClassInfoTest.php @@ -78,7 +78,7 @@ class ClassInfoTest extends SapphireTest { //$baseFolder = Director::baseFolder() . '/' . FRAMEWORK_DIR . '/tests/_ClassInfoTest'; //$manifestInfo = ManifestBuilder::get_manifest_info($baseFolder); - $classes = ClassInfo::classes_for_folder(FRAMEWORK_DIR . '/tests'); + $classes = ClassInfo::classes_for_folder(ltrim(FRAMEWORK_DIR . '/tests', '/')); $this->assertContains( 'classinfotest', $classes, From 6b640f81f2ed4ffdbac6036f5fb099a2c7f47e51 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Mon, 12 Sep 2016 17:26:31 +1200 Subject: [PATCH 5/9] =?UTF-8?q?FIX:=20Don=E2=80=99t=20double-include=20com?= =?UTF-8?q?poser=20autoloader?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If another file is include main.php and has included composer already, code might get weird. In particular, if the parent context includes a different vendor/autoload.php than the one main.php expects. --- main.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/main.php b/main.php index b35ab9f44..27c11e6fc 100644 --- a/main.php +++ b/main.php @@ -57,17 +57,19 @@ if (version_compare(phpversion(), '5.5.0', '<')) { * @see Director::direct() */ -// require composers autoloader -if (file_exists($autoloadPath = dirname(__DIR__) . '/vendor/autoload.php')) { - require_once $autoloadPath; -} -else { - if (!headers_sent()) { - header($_SERVER['SERVER_PROTOCOL'] . " 500 Server Error"); - header('Content-Type: text/plain'); +// require composers autoloader, unless it is already installed +if(!class_exists('Composer\\Autoload\\ClassLoader', false)) { + if (file_exists($autoloadPath = dirname(__DIR__) . '/vendor/autoload.php')) { + require_once $autoloadPath; + } + else { + if (!headers_sent()) { + header($_SERVER['SERVER_PROTOCOL'] . " 500 Server Error"); + header('Content-Type: text/plain'); + } + echo "Failed to include composer's autoloader, unable to continue\n"; + exit(1); } - echo "Failed to include composer's autoloader, unable to continue\n"; - exit(1); } // IIS will sometimes generate this. From 9dd5ebee8cd04fd5b7544c7ca7cad0d065e7b8ed Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Mon, 12 Sep 2016 17:42:05 +1200 Subject: [PATCH 6/9] =?UTF-8?q?NEW:=20Don=E2=80=99t=20set=20up=20SilverStr?= =?UTF-8?q?ipe=20project=20for=20test=20run?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SilverStripe project structure complicates the travis test run, and the goal of this branch is to prevent it from being necessary. - Unit tests can be run simply with PHPUnit. - Behat test can be run with the silverstripe/serve module Note that initially this commit doesn’t cater to the behat tests. As part of this, we allow dev packages to be installed when testing These settings don’t affect projects that use framework, only when framework’s composer install / require calls are used themselves. Since SS4 is pre-stable, these are important. They can probably be removed once SS4 stable (and stable versions of support packages) have been released. --- .gitignore | 3 +++ .travis.yml | 19 ++++++------------ composer.json | 4 +++- phpunit.xml.dist | 35 ++++++++++++++++++++++++++++++++ tests/bootstrap.php | 49 +++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 phpunit.xml.dist diff --git a/.gitignore b/.gitignore index 80f4b1577..17ede5a08 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ node_modules/ coverage/ /**/*.js.map /**/*.css.map +vendor/ +composer.lock +silverstripe-cache/ diff --git a/.travis.yml b/.travis.yml index 1381ed046..47a763504 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,6 @@ addons: env: global: - TRAVIS_NODE_VERSION="4" - - CORE_RELEASE=master - - CORE_RELEASE_VERSION=4.0 - ARTIFACTS_REGION=us-east-1 - ARTIFACTS_BUCKET=silverstripe-travis-artifacts - secure: "jVR0iLTuvVfA6jKX5+A3AdUEs8Ps+r3SbL0zGR687K8IoSp3a/+JLH12zFCEexOuxwCtOhlMq8zoZsptCEduCDq+0payk5k6GjNVywFaWjJCV573JScdaHAtoumoHMUvua+Pxds0qKAD2XEYAcOR4Qu7S4HLJV6E1QqHg9PRW5s=" # Encrypted ARTIFACTS_KEY @@ -44,21 +42,16 @@ before_script: - composer self-update || true - phpenv rehash - phpenv config-rm xdebug.ini - - git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support - - "if [ \"$PHPUNIT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss; fi" - - "if [ \"$BEHAT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/behat-extension; fi" - - "if [ \"$PHPUNIT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"1\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/cms:$CORE_RELEASE_VERSION.x-dev; fi" - - "if [ \"$BEHAT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"1\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/behat-extension,silverstripe/cms:$CORE_RELEASE_VERSION.x-dev; fi" + - "if [ \"$PHPUNIT_TEST\" = \"1\" ]; then composer install; fi" + - "if [ \"$DB\" = \"PGSQL\" ]; then composer require silverstripe/postgresql:^2.0; fi" + - "if [ \"$DB\" = \"SQLITE\" ]; then composer require silverstripe/sqlite3:^2.0; fi" - "if [ \"$NPM_TEST\" = \"1\" ]; then nvm install $TRAVIS_NODE_VERSION && npm install; fi" - - "if [ \"$NPM_TEST\" = \"\" ]; then cd ~/builds/ss; fi" - - "if [ \"$NPM_TEST\" = \"\" ] && [ \"$BEHAT_TEST\" = \"1\" ]; then php ~/travis-support/travis_setup_selenium.php; fi" - - "if [ \"$NPM_TEST\" = \"\" ] && [ \"$BEHAT_TEST\" = \"1\" ]; then php ~/travis-support/travis_setup_php54_webserver.php; fi" + - "if [ \"$BEHAT_TEST\" = \"1\" ]; then php ~/travis-support/travis_setup_selenium.php; fi" script: - - "if [ \"$PHPUNIT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"\" ]; then vendor/bin/phpunit framework/tests; fi" - - "if [ \"$PHPUNIT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"\" ]; then vendor/bin/phpunit framework/admin/tests; fi" - - "if [ \"$BEHAT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"\" ]; then vendor/bin/behat @framework; fi" + - "if [ \"$PHPUNIT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"\" ]; then vendor/bin/phpunit; fi" - "if [ \"$PHPUNIT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"1\" ]; then vendor/bin/phpunit cms/tests; fi" + - "if [ \"$BEHAT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"\" ]; then vendor/bin/behat @framework; fi" - "if [ \"$BEHAT_TEST\" = \"1\" ] && [ \"$CMS_TEST\" = \"1\" ]; then vendor/bin/behat @cms; fi" - "if [ \"$NPM_TEST\" = \"1\" ]; then npm run test; fi" diff --git a/composer.json b/composer.json index ef489f309..dd7c5bb01 100644 --- a/composer.json +++ b/composer.json @@ -54,5 +54,7 @@ "include-path": [ "thirdparty/", "thirdparty/HTML_BBCodeParser2/" - ] + ], + "min-stability": "dev", + "prefer-stable": true } diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 000000000..abb27e8c2 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,35 @@ + + + + + tests + admin/tests + + + + + + + + + sanitychecks + + + diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 2e8e42f01..728ac16bf 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -21,8 +21,6 @@ $frameworkDir = basename($frameworkPath); $_SERVER['SCRIPT_FILENAME'] = $frameworkPath . DIRECTORY_SEPARATOR . 'cli-script.php'; $_SERVER['SCRIPT_NAME'] = '.' . DIRECTORY_SEPARATOR . $frameworkDir . DIRECTORY_SEPARATOR . 'cli-script.php'; -if(!defined('BASE_PATH')) define('BASE_PATH', dirname($frameworkPath)); - // Copied from cli-script.php, to enable same behaviour through phpunit runner. if(isset($_SERVER['argv'][2])) { $args = array_slice($_SERVER['argv'],2); @@ -40,6 +38,53 @@ if(isset($_SERVER['argv'][2])) { $_REQUEST = array_merge($_REQUEST, $_GET); } +// DATABASE BOOTSTRAP + +if (!defined('SS_ENVIRONMENT_TYPE')) { + define('SS_ENVIRONMENT_TYPE', 'dev'); +} + +if (!defined('SS_DATABASE_CLASS') && !defined('SS_DATABASE_USERNAME')) { + // The default settings let us define the database config via environment vars + // Database connection, including PDO and legacy ORM support + switch(getenv('DB')) { + case "PGSQL"; + define('SS_DATABASE_CLASS', getenv('PDO') ? 'PostgrePDODatabase' : 'PostgreSQLDatabase'); + define('SS_DATABASE_USERNAME', 'postgres'); + define('SS_DATABASE_PASSWORD', ''); + break; + + case "SQLITE": + define('SS_DATABASE_CLASS', getenv('PDO') ? 'SQLite3PDODatabase' : 'SQLite3Database'); + define('SS_DATABASE_USERNAME', 'root'); + define('SS_DATABASE_PASSWORD', ''); + define('SS_SQLITE_DATABASE_PATH', ':memory:'); + break; + + default: + define('SS_DATABASE_CLASS', getenv('PDO') ? 'MySQLPDODatabase' : 'MySQLDatabase'); + define('SS_DATABASE_USERNAME', 'root'); + define('SS_DATABASE_PASSWORD', ''); + } + + define('SS_DATABASE_SERVER', '127.0.0.1'); + define('SS_DATABASE_CHOOSE_NAME', true); +} + +// Ensure Director::protocolAndHost() works +if (empty($_SERVER['HTTP_HOST'])) { + $_SERVER['HTTP_HOST'] = 'localhost'; +} + +// Default database settings +global $project; +$project = 'mysite'; + +global $database; +$database = ''; + +require_once(__DIR__ . '/../conf/ConfigureFromEnv.php'); + // Connect to database require_once $frameworkPath . '/Core/Core.php'; require_once $frameworkPath . '/tests/FakeController.php'; From 61d7c3af28d7b657721bb39c7c9632169ec97497 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Mon, 12 Sep 2016 18:16:39 +1200 Subject: [PATCH 7/9] FIX: Fix tests when running directly from framework. --- admin/thirdparty/tinymce/tiny_mce_gzip.php | 4 +- templates/SilverStripe/Control/Controller.ss | 2 +- tests/control/ControllerTest.php | 1 + tests/control/DirectorTest.php | 14 ++---- tests/css/forms/RequirementsTest_a.css | 1 + tests/css/forms/RequirementsTest_b.css | 1 + tests/css/forms/RequirementsTest_c.css | 1 + tests/dev/DeprecationTest.php | 2 +- tests/filesystem/AssetAdapterTest.php | 2 + tests/forms/HTMLEditorConfigTest.php | 4 +- tests/forms/HTMLEditorFieldTest.php | 2 +- tests/forms/RequirementsTest.php | 45 ++++++++++++------- tests/javascript/forms/RequirementsTest_a.js | 1 + tests/javascript/forms/RequirementsTest_b.js | 1 + tests/javascript/forms/RequirementsTest_c.js | 1 + tests/model/DataDifferencerTest.php | 2 +- tests/model/GDImageTest.php | 2 + tests/model/ImageTest.php | 2 +- tests/security/SecurityTest.php | 4 +- .../Includes/SSViewerTestProcessHead.ss | 2 +- .../RequirementsTest_Conditionals.ss | 12 ++--- tests/testing/YamlFixtureTest.php | 8 ++-- 22 files changed, 66 insertions(+), 48 deletions(-) create mode 100644 tests/css/forms/RequirementsTest_a.css create mode 100644 tests/css/forms/RequirementsTest_b.css create mode 100644 tests/css/forms/RequirementsTest_c.css create mode 100644 tests/javascript/forms/RequirementsTest_a.js create mode 100644 tests/javascript/forms/RequirementsTest_b.js create mode 100644 tests/javascript/forms/RequirementsTest_c.js diff --git a/admin/thirdparty/tinymce/tiny_mce_gzip.php b/admin/thirdparty/tinymce/tiny_mce_gzip.php index 9e22e21ab..2b6e600ad 100755 --- a/admin/thirdparty/tinymce/tiny_mce_gzip.php +++ b/admin/thirdparty/tinymce/tiny_mce_gzip.php @@ -9,8 +9,8 @@ * Contributing: http://tinymce.moxiecode.com/contributing */ -$frameworkPath = rtrim(dirname(dirname(dirname(dirname(__FILE__)))), DIRECTORY_SEPARATOR); -$basePath = rtrim(dirname($frameworkPath), DIRECTORY_SEPARATOR); +$frameworkPath = defined('FRAMEWORK_PATH') ? FRAMEWORK_PATH : rtrim(dirname(dirname(dirname(dirname(__FILE__)))), DIRECTORY_SEPARATOR); +$basePath = defined('BASE_PATH') ? BASE_PATH : rtrim(dirname($frameworkPath), DIRECTORY_SEPARATOR); // require composers autoloader if(file_exists($basePath . '/vendor/autoload.php')) { diff --git a/templates/SilverStripe/Control/Controller.ss b/templates/SilverStripe/Control/Controller.ss index 1b0a27ad9..40e172029 100644 --- a/templates/SilverStripe/Control/Controller.ss +++ b/templates/SilverStripe/Control/Controller.ss @@ -6,7 +6,7 @@ $MetaTags - <% require css('framework/client/dist/styles/debug.css') %> + <% require themedCSS('client/dist/styles/debug') %>
diff --git a/tests/control/ControllerTest.php b/tests/control/ControllerTest.php index 6751f5f62..dc9279a22 100644 --- a/tests/control/ControllerTest.php +++ b/tests/control/ControllerTest.php @@ -29,6 +29,7 @@ class ControllerTest extends FunctionalTest { public function setUp() { parent::setUp(); + Config::inst()->update('SilverStripe\\Control\\Director', 'alternate_base_url', '/'); $this->depSettings = Deprecation::dump_settings(); } diff --git a/tests/control/DirectorTest.php b/tests/control/DirectorTest.php index 833d4f1f8..dc99e6847 100644 --- a/tests/control/DirectorTest.php +++ b/tests/control/DirectorTest.php @@ -63,6 +63,8 @@ class DirectorTest extends SapphireTest { $this->originalProtocolHeaders[$header] = $_SERVER[$header]; } } + + Config::inst()->update('SilverStripe\\Control\\Director', 'alternate_base_url', '/'); } public function tearDown() { @@ -197,16 +199,6 @@ class DirectorTest extends SapphireTest { 'http://www.example.org/subfolder/test', Director::absoluteURL('subfolder/test', Director::BASE) ); - - // Setting it to false restores functionality - Config::inst()->update('SilverStripe\\Control\\Director', 'alternate_base_url', false); - $_SERVER['REQUEST_URI'] = $rootURL; - $this->assertEquals(BASE_URL.'/', Director::baseURL()); - $this->assertEquals($rootURL.BASE_URL.'/', Director::absoluteBaseURL(BASE_URL)); - $this->assertEquals( - $rootURL.BASE_URL . '/subfolder/test', - Director::absoluteURL('subfolder/test') - ); } /** @@ -393,7 +385,7 @@ class DirectorTest extends SapphireTest { } public function testForceSSLProtectsEntireSite() { - $_SERVER['REQUEST_URI'] = Director::baseURL() . 'admin'; + $_SERVER['REQUEST_URI'] = '/admin'; $output = Director::forceSSL(); $this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); diff --git a/tests/css/forms/RequirementsTest_a.css b/tests/css/forms/RequirementsTest_a.css new file mode 100644 index 000000000..d54285f0c --- /dev/null +++ b/tests/css/forms/RequirementsTest_a.css @@ -0,0 +1 @@ +.a {color: #f00;} diff --git a/tests/css/forms/RequirementsTest_b.css b/tests/css/forms/RequirementsTest_b.css new file mode 100644 index 000000000..3747a0e8f --- /dev/null +++ b/tests/css/forms/RequirementsTest_b.css @@ -0,0 +1 @@ +.b {color: #0ff;} diff --git a/tests/css/forms/RequirementsTest_c.css b/tests/css/forms/RequirementsTest_c.css new file mode 100644 index 000000000..098858dbc --- /dev/null +++ b/tests/css/forms/RequirementsTest_c.css @@ -0,0 +1 @@ +.c {color: #0ff;} diff --git a/tests/dev/DeprecationTest.php b/tests/dev/DeprecationTest.php index 541b45f8f..8ae59cdee 100644 --- a/tests/dev/DeprecationTest.php +++ b/tests/dev/DeprecationTest.php @@ -105,7 +105,7 @@ class DeprecationTest extends SapphireTest { } protected function callThatOriginatesFromFramework() { - $this->assertEquals(DeprecationTest_Deprecation::get_module(), FRAMEWORK_DIR); + $this->assertEquals(DeprecationTest_Deprecation::get_module(), basename(FRAMEWORK_PATH)); $this->assertNull(Deprecation::notice('2.0', 'Deprecation test passed')); } diff --git a/tests/filesystem/AssetAdapterTest.php b/tests/filesystem/AssetAdapterTest.php index 43d282a56..b15586efe 100644 --- a/tests/filesystem/AssetAdapterTest.php +++ b/tests/filesystem/AssetAdapterTest.php @@ -5,6 +5,7 @@ use SilverStripe\Assets\Flysystem\PublicAssetAdapter; use SilverStripe\Assets\Filesystem; use SilverStripe\Assets\File; use SilverStripe\Dev\SapphireTest; +use SilverStripe\Core\Config\Config; class AssetAdapterTest extends SapphireTest { @@ -18,6 +19,7 @@ class AssetAdapterTest extends SapphireTest { $this->rootDir = ASSETS_PATH . '/AssetAdapterTest'; Filesystem::makeFolder($this->rootDir); + Config::inst()->update('SilverStripe\\Control\\Director', 'alternate_base_url', '/'); $this->originalServer = $_SERVER; } diff --git a/tests/forms/HTMLEditorConfigTest.php b/tests/forms/HTMLEditorConfigTest.php index 99532187e..3cffa50be 100644 --- a/tests/forms/HTMLEditorConfigTest.php +++ b/tests/forms/HTMLEditorConfigTest.php @@ -86,14 +86,14 @@ class HTMLEditorConfigTest extends SapphireTest { // Test plugins included via gzip compresser HTMLEditorField::config()->update('use_gzip', true); $this->assertEquals( - 'framework/admin/thirdparty/tinymce/tiny_mce_gzip.php?js=1&plugins=plugin4,plugin5&themes=modern&languages=es&diskcache=true&src=true', + ADMIN_THIRDPARTY_DIR . '/tinymce/tiny_mce_gzip.php?js=1&plugins=plugin4,plugin5&themes=modern&languages=es&diskcache=true&src=true', $c->getScriptURL() ); // If gzip is disabled only the core plugin is loaded HTMLEditorField::config()->remove('use_gzip'); $this->assertEquals( - 'framework/admin/thirdparty/tinymce/tinymce.min.js', + ADMIN_THIRDPARTY_DIR . '/tinymce/tinymce.min.js', $c->getScriptURL() ); } diff --git a/tests/forms/HTMLEditorFieldTest.php b/tests/forms/HTMLEditorFieldTest.php index ae16043ce..3b8d4b172 100644 --- a/tests/forms/HTMLEditorFieldTest.php +++ b/tests/forms/HTMLEditorFieldTest.php @@ -53,7 +53,7 @@ class HTMLEditorFieldTest extends FunctionalTest { // Create a test files for each of the fixture references $files = File::get()->exclude('ClassName', 'SilverStripe\\Assets\\Folder'); foreach($files as $file) { - $fromPath = BASE_PATH . '/framework/tests/forms/images/' . $file->Name; + $fromPath = FRAMEWORK_PATH . '/tests/forms/images/' . $file->Name; $destPath = AssetStoreTest_SpyStore::getLocalPath($file); // Only correct for test asset store Filesystem::makeFolder(dirname($destPath)); copy($fromPath, $destPath); diff --git a/tests/forms/RequirementsTest.php b/tests/forms/RequirementsTest.php index b011f046f..70b882f39 100644 --- a/tests/forms/RequirementsTest.php +++ b/tests/forms/RequirementsTest.php @@ -162,12 +162,12 @@ class RequirementsTest extends SapphireTest { ]); $backend->javascript($basePath . '/RequirementsTest_b.js'); $result = $backend->includeInHTML(self::$html_template); - $this->assertContains( - '