Issue #3163500 by lauriii, jungle, raman.b, JeroenT, catch, longwave, larowlan: Detect when libraries-override or libraries-extend is used on deprecated library

merge-requests/25/head
catch 2020-09-29 15:05:47 +01:00
parent 0774f68936
commit 07daa79e14
10 changed files with 283 additions and 10 deletions

View File

@ -136,6 +136,11 @@ class LibraryDiscoveryCollector extends CacheCollector {
$libraries_extend = $this->themeManager->getActiveTheme()->getLibrariesExtend();
if (!empty($libraries_extend["$extension/$library_name"])) {
foreach ($libraries_extend["$extension/$library_name"] as $library_extend_name) {
if (isset($library_definition['deprecated'])) {
$extend_message = sprintf('Theme "%s" is extending a deprecated library.', $extension);
$library_deprecation = str_replace('%library_id%', "$extension/$library_name", $library_definition['deprecated']);
@trigger_error("$extend_message $library_deprecation", E_USER_DEPRECATED);
}
if (!is_string($library_extend_name)) {
// Only string library names are allowed.
throw new InvalidLibrariesExtendSpecificationException('The libraries-extend specification for each library must be a list of strings.');

View File

@ -382,6 +382,11 @@ class LibraryDiscoveryParser {
foreach ($libraries as $library_name => $library) {
// Process libraries overrides.
if (isset($libraries_overrides["$extension/$library_name"])) {
if (isset($library['deprecated'])) {
$override_message = sprintf('Theme "%s" is overriding a deprecated library.', $extension);
$library_deprecation = str_replace('%library_id%', "$extension/$library_name", $library['deprecated']);
@trigger_error("$override_message $library_deprecation", E_USER_DEPRECATED);
}
// Active theme defines an override for this library.
$override_definition = $libraries_overrides["$extension/$library_name"];
if (is_string($override_definition) || $override_definition === FALSE) {

View File

@ -5,3 +5,17 @@ theme_stylesheets_override_and_remove_test:
css/base-remove.css: {}
css/sub-override.css: {}
css/sub-remove.css: {}
deprecated_library:
version: VERSION
css:
base:
css/foo.css: {}
deprecated: 'The "%library_id%" asset library is deprecated in drupal:X.0.0 and is removed from drupal:Y.0.0. Use another library instead. See https://www.example.com'
another_deprecated_library:
version: VERSION
css:
base:
css/bar.css: {}
deprecated: 'The "%library_id%" asset library is deprecated in drupal:X.0.0 and is removed from drupal:Y.0.0. Use another library instead. See https://www.example.com'

View File

@ -4,3 +4,13 @@ description: 'Test theme to test deprecated functionality.'
version: VERSION
package: Testing
base theme: test_theme
libraries-override:
theme_test/deprecated_library:
css:
base:
css/foo.css: css/bar.css
libraries-extend:
theme_test/another_deprecated_library:
- test_legacy_theme/library

View File

@ -0,0 +1,4 @@
library:
css:
base:
css/baz.css: {}

View File

@ -20,6 +20,11 @@ class LibraryDiscoveryIntegrationTest extends KernelTestBase {
*/
protected $libraryDiscovery;
/**
* {@inheritdoc}
*/
protected static $modules = ['theme_test'];
/**
* {@inheritdoc}
*/
@ -208,6 +213,22 @@ class LibraryDiscoveryIntegrationTest extends KernelTestBase {
}
}
/**
* Test deprecated libraries.
*
* @group legacy
*
* @expectedDeprecation Theme "theme_test" is overriding a deprecated library. The "theme_test/deprecated_library" asset library is deprecated in drupal:X.0.0 and is removed from drupal:Y.0.0. Use another library instead. See https://www.example.com
* @expectedDeprecation Theme "theme_test" is extending a deprecated library. The "theme_test/another_deprecated_library" asset library is deprecated in drupal:X.0.0 and is removed from drupal:Y.0.0. Use another library instead. See https://www.example.com
* @expectedDeprecation The "theme_test/deprecated_library" asset library is deprecated in drupal:X.0.0 and is removed from drupal:Y.0.0. Use another library instead. See https://www.example.com
* @expectedDeprecation The "theme_test/another_deprecated_library" asset library is deprecated in drupal:X.0.0 and is removed from drupal:Y.0.0. Use another library instead. See https://www.example.com
*/
public function testDeprecatedLibrary() {
$this->activateTheme('test_legacy_theme');
$this->libraryDiscovery->getLibraryByName('theme_test', 'deprecated_library');
$this->libraryDiscovery->getLibraryByName('theme_test', 'another_deprecated_library');
}
/**
* Activates a specified theme.
*

View File

@ -4,6 +4,7 @@ namespace Drupal\Tests\Core\Asset;
use Drupal\Core\Asset\LibraryDiscoveryCollector;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Theme\ActiveTheme;
use Drupal\Tests\UnitTestCase;
/**
@ -61,6 +62,23 @@ class LibraryDiscoveryCollectorTest extends UnitTestCase {
'js' => [],
'css' => [],
],
'test_3' => [
'js' => [],
'css' => [
'theme' => [
'foo.css' => [],
],
],
],
'test_4' => [
'js' => [],
'css' => [
'theme' => [
'bar.css' => [],
],
],
'deprecated' => 'The "%library_id%" asset library is deprecated in drupal:X.0.0 and is removed from drupal:Y.0.0. Use the test_3 library instead. See https://www.example.com',
],
];
protected $activeTheme;
@ -77,7 +95,6 @@ class LibraryDiscoveryCollectorTest extends UnitTestCase {
$this->libraryDiscoveryParser = $this->getMockBuilder('Drupal\Core\Asset\LibraryDiscoveryParser')
->disableOriginalConstructor()
->getMock();
}
/**
@ -86,10 +103,10 @@ class LibraryDiscoveryCollectorTest extends UnitTestCase {
* @covers ::resolveCacheMiss
*/
public function testResolveCacheMiss() {
$this->activeTheme = $this->getMockBuilder('Drupal\Core\Theme\ActiveTheme')
$this->activeTheme = $this->getMockBuilder(ActiveTheme::class)
->disableOriginalConstructor()
->getMock();
$this->themeManager->expects($this->exactly(3))
$this->themeManager->expects($this->exactly(5))
->method('getActiveTheme')
->willReturn($this->activeTheme);
$this->activeTheme->expects($this->once())
@ -112,10 +129,10 @@ class LibraryDiscoveryCollectorTest extends UnitTestCase {
* @covers ::destruct
*/
public function testDestruct() {
$this->activeTheme = $this->getMockBuilder('Drupal\Core\Theme\ActiveTheme')
$this->activeTheme = $this->getMockBuilder(ActiveTheme::class)
->disableOriginalConstructor()
->getMock();
$this->themeManager->expects($this->exactly(3))
$this->themeManager->expects($this->exactly(5))
->method('getActiveTheme')
->willReturn($this->activeTheme);
$this->activeTheme->expects($this->once())
@ -150,4 +167,93 @@ class LibraryDiscoveryCollectorTest extends UnitTestCase {
$this->libraryDiscoveryCollector->destruct();
}
/**
* Tests library with an extend.
*
* @covers ::applyLibrariesExtend
*/
public function testLibrariesExtend() {
$this->activeTheme = $this->getMockBuilder(ActiveTheme::class)
->disableOriginalConstructor()
->getMock();
$this->themeManager->expects($this->any())
->method('getActiveTheme')
->willReturn($this->activeTheme);
$this->activeTheme->expects($this->once())
->method('getName')
->willReturn('kitten_theme');
$this->activeTheme->expects($this->atLeastOnce())
->method('getLibrariesExtend')
->willReturn([
'test/test_3' => [
'kitten_theme/extend',
],
]);
$this->libraryDiscoveryParser->expects($this->at(0))
->method('buildByExtension')
->with('test')
->willReturn($this->libraryData);
$this->libraryDiscoveryParser->expects($this->at(1))
->method('buildByExtension')
->with('kitten_theme')
->willReturn([
'extend' => [
'css' => [
'theme' => [
'baz.css' => [],
],
],
],
]);
$library_discovery_collector = new LibraryDiscoveryCollector($this->cache, $this->lock, $this->libraryDiscoveryParser, $this->themeManager);
$libraries = $library_discovery_collector->get('test');
$this->assertSame(['foo.css', 'baz.css'], array_keys($libraries['test_3']['css']['theme']));
}
/**
* Tests a deprecated library with an extend.
*
* @covers ::applyLibrariesExtend
*
* @group legacy
*
* @expectedDeprecation Theme "test" is extending a deprecated library. The "test/test_4" asset library is deprecated in drupal:X.0.0 and is removed from drupal:Y.0.0. Use the test_3 library instead. See https://www.example.com
*/
public function testLibrariesExtendDeprecated() {
$this->activeTheme = $this->getMockBuilder(ActiveTheme::class)
->disableOriginalConstructor()
->getMock();
$this->themeManager->expects($this->any())
->method('getActiveTheme')
->willReturn($this->activeTheme);
$this->activeTheme->expects($this->once())
->method('getName')
->willReturn('kitten_theme');
$this->activeTheme->expects($this->atLeastOnce())
->method('getLibrariesExtend')
->willReturn([
'test/test_4' => [
'kitten_theme/extend',
],
]);
$this->libraryDiscoveryParser->expects($this->at(0))
->method('buildByExtension')
->with('test')
->willReturn($this->libraryData);
$this->libraryDiscoveryParser->expects($this->at(1))
->method('buildByExtension')
->with('kitten_theme')
->willReturn([
'extend' => [
'css' => [
'theme' => [
'baz.css' => [],
],
],
],
]);
$library_discovery_collector = new LibraryDiscoveryCollector($this->cache, $this->lock, $this->libraryDiscoveryParser, $this->themeManager);
$library_discovery_collector->get('test');
}
}

View File

@ -13,6 +13,8 @@ use Drupal\Core\Asset\Exception\LibraryDefinitionMissingLicenseException;
use Drupal\Core\Asset\LibrariesDirectoryFileFinder;
use Drupal\Core\Asset\LibraryDiscoveryParser;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\Core\Theme\ActiveTheme;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\Tests\UnitTestCase;
/**
@ -49,6 +51,13 @@ class LibraryDiscoveryParserTest extends UnitTestCase {
*/
protected $themeManager;
/**
* The mocked active theme.
*
* @var \Drupal\Core\Theme\ActiveTheme|\PHPUnit\Framework\MockObject\MockObject
*/
protected $activeTheme;
/**
* The mocked lock backend.
*
@ -77,16 +86,16 @@ class LibraryDiscoveryParserTest extends UnitTestCase {
parent::setUp();
$this->moduleHandler = $this->createMock('Drupal\Core\Extension\ModuleHandlerInterface');
$this->themeManager = $this->createMock('Drupal\Core\Theme\ThemeManagerInterface');
$mock_active_theme = $this->getMockBuilder('Drupal\Core\Theme\ActiveTheme')
$this->themeManager = $this->createMock(ThemeManagerInterface::class);
$this->activeTheme = $this->getMockBuilder(ActiveTheme::class)
->disableOriginalConstructor()
->getMock();
$mock_active_theme->expects($this->any())
$this->activeTheme->expects($this->any())
->method('getLibrariesOverride')
->willReturn([]);
$this->themeManager->expects($this->any())
->method('getActiveTheme')
->willReturn($mock_active_theme);
->willReturn($this->activeTheme);
$this->streamWrapperManager = $this->createMock(StreamWrapperManagerInterface::class);
$this->librariesDirectoryFileFinder = $this->createMock(LibrariesDirectoryFileFinder::class);
$this->libraryDiscoveryParser = new TestLibraryDiscoveryParser($this->root, $this->moduleHandler, $this->themeManager, $this->streamWrapperManager, $this->librariesDirectoryFileFinder);
@ -111,7 +120,7 @@ class LibraryDiscoveryParserTest extends UnitTestCase {
$library = $libraries['example'];
$this->assertCount(0, $library['js']);
$this->assertCount(1, $library['css']);
$this->assertCount(2, $library['css']);
$this->assertCount(0, $library['dependencies']);
$this->assertEquals($path . '/css/example.css', $library['css'][0]['data']);
@ -544,6 +553,98 @@ class LibraryDiscoveryParserTest extends UnitTestCase {
$this->assertEquals($library['license'], $expected_license);
}
/**
* Tests libraries with overrides.
*
* @covers ::applyLibrariesOverride
*/
public function testLibraryOverride() {
$mock_theme_path = 'mocked_themes/kittens';
$this->themeManager = $this->createMock(ThemeManagerInterface::class);
$this->activeTheme = $this->getMockBuilder(ActiveTheme::class)
->disableOriginalConstructor()
->getMock();
$this->activeTheme->expects($this->atLeastOnce())
->method('getLibrariesOverride')
->willReturn([
$mock_theme_path => [
'example_module/example' => [
'css' => [
'theme' => [
'css/example.css' => 'css/overridden.css',
'css/example2.css' => FALSE,
],
],
],
],
]);
$this->themeManager->expects($this->any())
->method('getActiveTheme')
->willReturn($this->activeTheme);
$this->libraryDiscoveryParser = new TestLibraryDiscoveryParser($this->root, $this->moduleHandler, $this->themeManager, $this->streamWrapperManager, $this->librariesDirectoryFileFinder);
$this->moduleHandler->expects($this->atLeastOnce())
->method('moduleExists')
->with('example_module')
->will($this->returnValue(TRUE));
$path = __DIR__ . '/library_test_files';
$path = substr($path, strlen($this->root) + 1);
$this->libraryDiscoveryParser->setPaths('module', 'example_module', $path);
$libraries = $this->libraryDiscoveryParser->buildByExtension('example_module');
$library = $libraries['example'];
$this->assertCount(0, $library['js']);
$this->assertCount(1, $library['css']);
$this->assertCount(0, $library['dependencies']);
$this->assertEquals($mock_theme_path . '/css/overridden.css', $library['css'][0]['data']);
}
/**
* Tests deprecated library with an override.
*
* @covers ::applyLibrariesOverride
*
* @group legacy
*
* @expectedDeprecation Theme "deprecated" is overriding a deprecated library. The "deprecated/deprecated" asset library is deprecated in drupal:X.0.0 and is removed from drupal:Y.0.0. Use another library instead. See https://www.example.com
*/
public function testLibraryOverrideDeprecated() {
$mock_theme_path = 'mocked_themes/kittens';
$this->themeManager = $this->createMock(ThemeManagerInterface::class);
$this->activeTheme = $this->getMockBuilder(ActiveTheme::class)
->disableOriginalConstructor()
->getMock();
$this->activeTheme->expects($this->atLeastOnce())
->method('getLibrariesOverride')
->willReturn([
$mock_theme_path => [
'deprecated/deprecated' => [
'css' => [
'theme' => [
'css/example.css' => 'css/overridden.css',
],
],
],
],
]);
$this->themeManager->expects($this->any())
->method('getActiveTheme')
->willReturn($this->activeTheme);
$this->libraryDiscoveryParser = new TestLibraryDiscoveryParser($this->root, $this->moduleHandler, $this->themeManager, $this->streamWrapperManager, $this->librariesDirectoryFileFinder);
$this->moduleHandler->expects($this->atLeastOnce())
->method('moduleExists')
->with('deprecated')
->will($this->returnValue(TRUE));
$path = __DIR__ . '/library_test_files';
$path = substr($path, strlen($this->root) + 1);
$this->libraryDiscoveryParser->setPaths('module', 'deprecated', $path);
$this->libraryDiscoveryParser->buildByExtension('deprecated');
}
/**
* Verifies assertions catch invalid CSS declarations.
*

View File

@ -0,0 +1,6 @@
deprecated:
version: VERSION
css:
theme:
css/example.css: {}
deprecated: 'The "%library_id%" asset library is deprecated in drupal:X.0.0 and is removed from drupal:Y.0.0. Use another library instead. See https://www.example.com'

View File

@ -3,3 +3,4 @@ example:
css:
theme:
css/example.css: {}
css/example2.css: {}