Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
* Copyright 2020 Adobe
* All Rights Reserved.
*/

declare(strict_types=1);

namespace Magento\Csp\Model\Collector\CspWhitelistXml;

use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Config\CompositeFileIteratorFactory;
use Magento\Framework\Config\FileResolverInterface;
use Magento\Framework\Filesystem;
use Magento\Framework\View\Design\ThemeInterface;
use Magento\Framework\View\DesignInterface;
use Magento\Framework\Filesystem\Directory\ReadInterface as DirectoryRead;
use Magento\Framework\View\Design\Theme\CustomizationInterface;
use Magento\Framework\View\Design\Theme\CustomizationInterfaceFactory;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem\Directory\ReadInterface as DirectoryRead;
use Magento\Framework\Config\CompositeFileIteratorFactory;
use Magento\Framework\View\Design\ThemeInterface;
use Magento\Framework\View\DesignInterface;

/**
* Combines configuration files from both modules and current theme.
Expand Down Expand Up @@ -74,22 +74,29 @@ public function __construct(
*/
public function get($filename, $scope)
{
$configs = $this->moduleFileResolver->get($filename, $scope);
if ($scope === 'global') {
$files = [];
$theme = $this->theme;
while ($theme) {
/** @var CustomizationInterface $info */
$info = $this->themeInfoFactory->create(['theme' => $theme]);
$file = $info->getThemeFilesPath() .'/etc/' .$filename;
if ($this->rootDir->isExist($file)) {
$files[] = $file;
$configs = $this->moduleFileResolver->get($filename, $scope);

switch ($scope) {
case 'frontend':
case 'adminhtml':
$files = [];
$theme = $this->theme;
while ($theme) {
/** @var CustomizationInterface $info */
$info = $this->themeInfoFactory->create(['theme' => $theme]);
$file = $info->getThemeFilesPath() . '/etc/' . $filename;
if ($this->rootDir->isExist($file)) {
$files[] = $file;
}
$theme = $theme->getParentTheme();
}
$theme = $theme->getParentTheme();
}
$configs = $this->iteratorFactory->create(
['paths' => array_reverse($files), 'existingIterator' => $configs]
);
$configs = $this->iteratorFactory->create(
['paths' => array_reverse($files), 'existingIterator' => $configs]
);
break;
case 'global':
default:
break;
}

return $configs;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
<?php
/**
* Copyright 2025 Adobe
* All Rights Reserved.
*/

declare(strict_types=1);

namespace Magento\Csp\Test\Unit\Model\Collector\CspWhitelistXml;

use Magento\Framework\Filesystem;
use Magento\Framework\View\Design\Theme\CustomizationInterface;
use Magento\Framework\View\Design\ThemeInterface;
use PHPUnit\Framework\TestCase;
use Magento\Framework\Config\FileResolverInterface;
use Magento\Csp\Model\Collector\CspWhitelistXml\FileResolver;
use Magento\Framework\View\DesignInterface;
use Magento\Framework\Config\CompositeFileIteratorFactory;
use Magento\Framework\View\Design\Theme\CustomizationInterfaceFactory;
use Magento\Framework\Filesystem\Directory\ReadInterface;
use Magento\Framework\App\Filesystem\DirectoryList;

class FileResolverTest extends TestCase
{
/**
* @var FileResolver
*/
private $model;

/**
* @var FileResolverInterface
*/
private $moduleFileResolverMock;

/**
* @var DesignInterface
*/
private $designMock;

/**
* @var CustomizationInterfaceFactory
*/
private $customizationFactoryMock;

/**
* @var Filesystem
*/
private $filesystemMock;

/**
* @var CompositeFileIteratorFactory
*/
private $iteratorFactoryMock;

/**
* @var ReadInterface
*/
private $readInterfaceMock;

/**
* @var ThemeInterface
*/
private $themeInterFaceMock;

/**
* @var CustomizationInterface
*/
private $customizationInterfaceMock;

protected function setUp(): void
{
$this->moduleFileResolverMock = $this->getMockBuilder(FileResolverInterface::class)
->disableOriginalConstructor()
->getMock();

$this->designMock = $this->getMockBuilder(DesignInterface::class)
->disableOriginalConstructor()
->getMock();

$this->themeInterFaceMock = $this->getMockBuilder(ThemeInterface::class)
->disableOriginalConstructor()
->getMock();

$this->designMock->expects($this->once())
->method('getDesignTheme')
->willReturn($this->themeInterFaceMock);

$this->customizationFactoryMock = $this->getMockBuilder(CustomizationInterfaceFactory::class)
->disableOriginalConstructor()
->onlyMethods(['create'])
->getMock();

$this->customizationInterfaceMock = $this->getMockBuilder(CustomizationInterface::class)
->disableOriginalConstructor()
->getMock();

$this->filesystemMock = $this->createPartialMock(Filesystem::class, ['getDirectoryRead']);

$this->readInterfaceMock = $this->getMockBuilder(ReadInterface::class)
->disableOriginalConstructor()
->getMock();

$this->filesystemMock->expects($this->once())
->method('getDirectoryRead')
->with(DirectoryList::ROOT)
->willReturn($this->readInterfaceMock);

$this->iteratorFactoryMock = $this->getMockBuilder(CompositeFileIteratorFactory::class)
->disableOriginalConstructor()
->getMock();

$this->model = new FileResolver(
$this->moduleFileResolverMock,
$this->designMock,
$this->customizationFactoryMock,
$this->filesystemMock,
$this->iteratorFactoryMock
);
}

/**
* Test for get method with frontend scope.
*
* @param string $scope
* @param string $fileName
* @param array $fileList
* @param string $themeFilesPath
*
* @return void
* @dataProvider providerGetFrontend
*/
public function testGetFrontend(string $scope, string $fileName, array $fileList, string $themeFilesPath): void
{
$this->moduleFileResolverMock->expects($this->once())
->method('get')
->with($fileName, $scope)
->willReturn($fileList);

$this->customizationFactoryMock->expects($this->any())
->method('create')
->with(['theme' => $this->themeInterFaceMock])
->willReturn($this->customizationInterfaceMock);

$this->customizationInterfaceMock->expects($this->once())
->method('getThemeFilesPath')
->willReturn($themeFilesPath);

$this->readInterfaceMock->expects($this->once())
->method('isExist')
->with($themeFilesPath.'/etc/'.$fileName)
->willReturn(true);

$this->iteratorFactoryMock->expects($this->once())
->method('create')
->with(
[
'paths' => array_reverse([$themeFilesPath.'/etc/'.$fileName]),
'existingIterator' => $fileList
]
)
->willReturn($fileList);

$this->assertEquals($fileList, $this->model->get($fileName, $scope));
}

/**
* Test for get method with global scope.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PHPDoc comment signature is not complete

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

*
* @param string $scope
* @param string $fileName
* @param array $fileList
*
* @return void
* @dataProvider providerGetGlobal
*/
public function testGetGlobal(string $scope, string $fileName, array $fileList): void
{
$this->moduleFileResolverMock->expects($this->once())
->method('get')
->with($fileName, $scope)
->willReturn($fileList);
$this->assertEquals($fileList, $this->model->get($fileName, $scope));
}

/**
* Data provider for get global scope tests.
*
* @return array
*/
public static function providerGetGlobal(): array
{
return [
[
'global',
'csp_whitelist.xml',
['anyvendor/anymodule/etc/csp_whitelist.xml']
]
];
}

/**
* Data provider for get frontend & adminhtml scope tests.
*
* @return array
*/
public static function providerGetFrontend(): array
{
return [
[
'frontend',
'csp_whitelist.xml',
['themevendor/theme/etc/csp_whitelist.xml'],
'themevendor/theme'
],
[
'adminhtml',
'csp_whitelist.xml',
['adminthemevendor/admintheme/etc/csp_whitelist.xml'],
'adminthemevendor/admintheme'
]
];
}
}