559 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			559 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
<?php
 | 
						|
/**
 | 
						|
 * Copyright © Magento, Inc. All rights reserved.
 | 
						|
 * See COPYING.txt for license details.
 | 
						|
 */
 | 
						|
namespace Magento\Test\Integrity;
 | 
						|
 | 
						|
use Magento\Framework\App\Bootstrap;
 | 
						|
use Magento\Framework\Component\ComponentRegistrar;
 | 
						|
use Magento\Framework\Composer\MagentoComponent;
 | 
						|
 | 
						|
/**
 | 
						|
 * A test that enforces validity of composer.json files and any other conventions in Magento components
 | 
						|
 */
 | 
						|
class ComposerTest extends \PHPUnit\Framework\TestCase
 | 
						|
{
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    private static $root;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var \stdClass
 | 
						|
     */
 | 
						|
    private static $rootJson;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var array
 | 
						|
     */
 | 
						|
    private static $dependencies;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var \Magento\Framework\ObjectManagerInterface
 | 
						|
     */
 | 
						|
    private static $objectManager;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var string[]
 | 
						|
     */
 | 
						|
    private static $rootComposerModuleBlacklist = [];
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var string[]
 | 
						|
     */
 | 
						|
    private static $moduleNameBlacklist;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    private static $magentoFrameworkLibraryName = 'magento/framework';
 | 
						|
 | 
						|
    public static function setUpBeforeClass(): void
 | 
						|
    {
 | 
						|
        self::$root = BP;
 | 
						|
        self::$rootJson = json_decode(file_get_contents(self::$root . '/composer.json'), true);
 | 
						|
        self::$dependencies = [];
 | 
						|
        self::$objectManager = Bootstrap::create(BP, $_SERVER)->getObjectManager();
 | 
						|
        // A block can be whitelisted and thus not be required to be public
 | 
						|
        self::$rootComposerModuleBlacklist = self::getBlacklist(
 | 
						|
            __DIR__ . '/_files/blacklist/composer_root_modules*.txt'
 | 
						|
        );
 | 
						|
        self::$moduleNameBlacklist = self::getBlacklist(__DIR__ . '/_files/blacklist/composer_module_names*.txt');
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Return aggregated blacklist
 | 
						|
     *
 | 
						|
     * @param string $pattern
 | 
						|
     * @return string[]
 | 
						|
     */
 | 
						|
    public static function getBlacklist(string $pattern)
 | 
						|
    {
 | 
						|
        $blacklist = [];
 | 
						|
        foreach (glob($pattern) as $list) {
 | 
						|
            $blacklist[] = file($list, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
 | 
						|
        }
 | 
						|
        return array_merge([], ...$blacklist);
 | 
						|
    }
 | 
						|
 | 
						|
    public function testValidComposerJson()
 | 
						|
    {
 | 
						|
        $invoker = new \Magento\Framework\App\Utility\AggregateInvoker($this);
 | 
						|
        $invoker(
 | 
						|
            /**
 | 
						|
             * @param string $dir
 | 
						|
             * @param string $packageType
 | 
						|
             */
 | 
						|
            function ($dir, $packageType) {
 | 
						|
                $file = $dir . '/composer.json';
 | 
						|
                $this->assertFileExists($file);
 | 
						|
                $this->validateComposerJsonFile($dir);
 | 
						|
                $contents = file_get_contents($file);
 | 
						|
                $json = json_decode($contents);
 | 
						|
                $this->assertCodingStyle($contents);
 | 
						|
                $this->assertMagentoConventions($dir, $packageType, $json);
 | 
						|
            },
 | 
						|
            $this->validateComposerJsonDataProvider()
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function validateComposerJsonDataProvider()
 | 
						|
    {
 | 
						|
        $root = BP;
 | 
						|
        $componentRegistrar = new ComponentRegistrar();
 | 
						|
        $result = [];
 | 
						|
        foreach ($componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $dir) {
 | 
						|
            $result[$dir] = [$dir, 'magento2-module'];
 | 
						|
        }
 | 
						|
        foreach ($componentRegistrar->getPaths(ComponentRegistrar::LANGUAGE) as $dir) {
 | 
						|
            $result[$dir] = [$dir, 'magento2-language'];
 | 
						|
        }
 | 
						|
        foreach ($componentRegistrar->getPaths(ComponentRegistrar::THEME) as $dir) {
 | 
						|
            $result[$dir] = [$dir, 'magento2-theme'];
 | 
						|
        }
 | 
						|
        foreach ($componentRegistrar->getPaths(ComponentRegistrar::LIBRARY) as $dir) {
 | 
						|
            $result[$dir] = [$dir, 'magento2-library'];
 | 
						|
        }
 | 
						|
        $result[$root] = [$root, 'project'];
 | 
						|
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Validate a composer.json under the given path
 | 
						|
     *
 | 
						|
     * @param string $path path to composer.json
 | 
						|
     */
 | 
						|
    private function validateComposerJsonFile($path)
 | 
						|
    {
 | 
						|
        /** @var \Magento\Framework\Composer\MagentoComposerApplicationFactory $appFactory */
 | 
						|
        $appFactory = self::$objectManager->get(\Magento\Framework\Composer\MagentoComposerApplicationFactory::class);
 | 
						|
        $app = $appFactory->create();
 | 
						|
 | 
						|
        try {
 | 
						|
            $app->runComposerCommand(['command' => 'validate'], $path);
 | 
						|
        } catch (\RuntimeException $exception) {
 | 
						|
            $this->fail($exception->getMessage());
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Some of coding style conventions
 | 
						|
     *
 | 
						|
     * @param string $contents
 | 
						|
     */
 | 
						|
    private function assertCodingStyle($contents)
 | 
						|
    {
 | 
						|
        $this->assertDoesNotMatchRegularExpression(
 | 
						|
            '/" :\s*["{]/',
 | 
						|
            $contents,
 | 
						|
            'Coding style: there should be no space before colon.'
 | 
						|
        );
 | 
						|
        $this->assertDoesNotMatchRegularExpression(
 | 
						|
            '/":["{]/',
 | 
						|
            $contents,
 | 
						|
            'Coding style: a space is necessary after colon.'
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Enforce Magento-specific conventions to a composer.json file
 | 
						|
     *
 | 
						|
     * @param string $dir
 | 
						|
     * @param string $packageType
 | 
						|
     * @param \StdClass $json
 | 
						|
     * @throws \InvalidArgumentException
 | 
						|
     */
 | 
						|
    private function assertMagentoConventions($dir, $packageType, \StdClass $json)
 | 
						|
    {
 | 
						|
        $this->assertObjectHasAttribute('name', $json);
 | 
						|
        $this->assertObjectHasAttribute('license', $json);
 | 
						|
        $this->assertObjectHasAttribute('type', $json);
 | 
						|
        $this->assertObjectHasAttribute('require', $json);
 | 
						|
        $this->assertEquals($packageType, $json->type);
 | 
						|
        if ($packageType !== 'project') {
 | 
						|
            self::$dependencies[] = $json->name;
 | 
						|
            $this->assertAutoloadRegistrar($json, $dir);
 | 
						|
            $this->assertNoMap($json);
 | 
						|
        }
 | 
						|
        switch ($packageType) {
 | 
						|
            case 'magento2-module':
 | 
						|
                $xml = simplexml_load_file("$dir/etc/module.xml");
 | 
						|
                if ($this->isVendorMagento($json->name)) {
 | 
						|
                    $this->assertConsistentModuleName($xml, $json->name);
 | 
						|
                }
 | 
						|
                $this->assertDependsOnPhp($json->require);
 | 
						|
                $this->assertPhpVersionInSync($json->name, $json->require->php);
 | 
						|
                $this->assertDependsOnFramework($json->require);
 | 
						|
                $this->assertRequireInSync($json);
 | 
						|
                $this->assertAutoload($json);
 | 
						|
                $this->assertNoVersionSpecified($json);
 | 
						|
                break;
 | 
						|
            case 'magento2-language':
 | 
						|
                $this->assertMatchesRegularExpression(
 | 
						|
                    '/^magento\/language\-[a-z]{2}_([a-z]{4}_)?[a-z]{2}$/',
 | 
						|
                    $json->name
 | 
						|
                );
 | 
						|
                $this->assertDependsOnFramework($json->require);
 | 
						|
                $this->assertRequireInSync($json);
 | 
						|
                $this->assertNoVersionSpecified($json);
 | 
						|
                break;
 | 
						|
            case 'magento2-theme':
 | 
						|
                $this->assertMatchesRegularExpression(
 | 
						|
                    '/^magento\/theme-(?:adminhtml|frontend)(\-[a-z0-9_]+)+$/',
 | 
						|
                    $json->name
 | 
						|
                );
 | 
						|
                $this->assertDependsOnPhp($json->require);
 | 
						|
                $this->assertPhpVersionInSync($json->name, $json->require->php);
 | 
						|
                $this->assertDependsOnFramework($json->require);
 | 
						|
                $this->assertRequireInSync($json);
 | 
						|
                $this->assertNoVersionSpecified($json);
 | 
						|
                break;
 | 
						|
            case 'magento2-library':
 | 
						|
                $this->assertDependsOnPhp($json->require);
 | 
						|
                $this->assertMatchesRegularExpression('/^magento\/framework*/', $json->name);
 | 
						|
                $this->assertPhpVersionInSync($json->name, $json->require->php);
 | 
						|
                $this->assertRequireInSync($json);
 | 
						|
                $this->assertAutoload($json);
 | 
						|
                $this->assertNoVersionSpecified($json);
 | 
						|
                break;
 | 
						|
            case 'project':
 | 
						|
                $this->checkProject();
 | 
						|
                $this->assertNoVersionSpecified($json);
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                throw new \InvalidArgumentException("Unknown package type {$packageType}");
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Checks if package vendor is Magento.
 | 
						|
     *
 | 
						|
     * @param string $packageName
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    private function isVendorMagento(string $packageName): bool
 | 
						|
    {
 | 
						|
        return strpos($packageName, 'magento/') === 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Assert that component registrar is autoloaded in composer json
 | 
						|
     *
 | 
						|
     * @param \StdClass $json
 | 
						|
     * @param string $dir
 | 
						|
     */
 | 
						|
    private function assertAutoloadRegistrar(\StdClass $json, $dir)
 | 
						|
    {
 | 
						|
        $error = 'There must be an "autoload->files" node in composer.json of each Magento component.';
 | 
						|
        $this->assertObjectHasAttribute('autoload', $json, $error);
 | 
						|
        $this->assertObjectHasAttribute('files', $json->autoload, $error);
 | 
						|
        $this->assertTrue(in_array("registration.php", $json->autoload->files), $error);
 | 
						|
        $this->assertFileExists("$dir/registration.php");
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Version must not be specified in the root and package composer JSON files in Git.
 | 
						|
     *
 | 
						|
     * All versions are added by tools during release publication by version setter tool.
 | 
						|
     *
 | 
						|
     * @param \StdClass $json
 | 
						|
     */
 | 
						|
    private function assertNoVersionSpecified(\StdClass $json)
 | 
						|
    {
 | 
						|
        if (!in_array($json->name, self::$rootComposerModuleBlacklist)) {
 | 
						|
            $errorMessage = 'Version must not be specified in the root and package composer JSON files in Git';
 | 
						|
            $this->assertObjectNotHasAttribute('version', $json, $errorMessage);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Assert that there is PSR-4 autoload in composer json
 | 
						|
     *
 | 
						|
     * @param \StdClass $json
 | 
						|
     */
 | 
						|
    private function assertAutoload(\StdClass $json)
 | 
						|
    {
 | 
						|
        $errorMessage = 'There must be an "autoload->psr-4" section in composer.json of each Magento component.';
 | 
						|
        $this->assertObjectHasAttribute('autoload', $json, $errorMessage);
 | 
						|
        $this->assertObjectHasAttribute('psr-4', $json->autoload, $errorMessage);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Assert that there is map in specified composer json
 | 
						|
     *
 | 
						|
     * @param \StdClass $json
 | 
						|
     */
 | 
						|
    private function assertNoMap(\StdClass $json)
 | 
						|
    {
 | 
						|
        $error = 'There is no "extra->map" node in composer.json of each Magento component.';
 | 
						|
        $this->assertObjectNotHasAttribute('extra', $json, $error);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Enforce package naming conventions for modules
 | 
						|
     *
 | 
						|
     * @param \SimpleXMLElement $xml
 | 
						|
     * @param string $packageName
 | 
						|
     */
 | 
						|
    private function assertConsistentModuleName(\SimpleXMLElement $xml, $packageName)
 | 
						|
    {
 | 
						|
        if (!in_array($packageName, self::$moduleNameBlacklist)) {
 | 
						|
            $moduleName = (string)$xml->module->attributes()->name;
 | 
						|
            $expectedPackageName = $this->convertModuleToPackageName($moduleName);
 | 
						|
            $this->assertEquals(
 | 
						|
                $expectedPackageName,
 | 
						|
                $packageName,
 | 
						|
                "For the module '{$moduleName}', the expected package name is '{$expectedPackageName}'"
 | 
						|
            );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Make sure a component depends on php version
 | 
						|
     *
 | 
						|
     * @param \StdClass $json
 | 
						|
     */
 | 
						|
    private function assertDependsOnPhp(\StdClass $json)
 | 
						|
    {
 | 
						|
        $this->assertObjectHasAttribute('php', $json, 'This component is expected to depend on certain PHP version(s)');
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Make sure a component depends on magento/framework component
 | 
						|
     *
 | 
						|
     * @param \StdClass $json
 | 
						|
     */
 | 
						|
    private function assertDependsOnFramework(\StdClass $json)
 | 
						|
    {
 | 
						|
        $this->assertObjectHasAttribute(
 | 
						|
            self::$magentoFrameworkLibraryName,
 | 
						|
            $json,
 | 
						|
            'This component is expected to depend on ' . self::$magentoFrameworkLibraryName
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Assert that PHP versions in root composer.json and Magento component's composer.json are not out of sync
 | 
						|
     *
 | 
						|
     * @param string $name
 | 
						|
     * @param string $phpVersion
 | 
						|
     */
 | 
						|
    private function assertPhpVersionInSync($name, $phpVersion)
 | 
						|
    {
 | 
						|
        if (isset(self::$rootJson['require']['php'])) {
 | 
						|
            $composerVersionsPattern = '{\s*\|\|?\s*}';
 | 
						|
            $rootPhpVersions = preg_split($composerVersionsPattern, self::$rootJson['require']['php']);
 | 
						|
            $modulePhpVersions = preg_split($composerVersionsPattern, $phpVersion);
 | 
						|
 | 
						|
            $this->assertEmpty(
 | 
						|
                array_diff($rootPhpVersions, $modulePhpVersions),
 | 
						|
                "PHP version {$phpVersion} in component {$name} is inconsistent with version "
 | 
						|
                . self::$rootJson['require']['php'] . ' in root composer.json'
 | 
						|
            );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Make sure requirements of components are reflected in root composer.json
 | 
						|
     *
 | 
						|
     * @param \StdClass $json
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    private function assertRequireInSync(\StdClass $json)
 | 
						|
    {
 | 
						|
        if (preg_match('/magento\/project-*/', self::$rootJson['name']) == 1) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        if (!in_array($json->name, self::$rootComposerModuleBlacklist) && isset($json->require)) {
 | 
						|
            $this->checkPackageInRootComposer($json);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Check if package is reflected in root composer.json
 | 
						|
     *
 | 
						|
     * @param \StdClass $json
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    private function checkPackageInRootComposer(\StdClass $json)
 | 
						|
    {
 | 
						|
        $name = $json->name;
 | 
						|
        $errors = [];
 | 
						|
        foreach (array_keys((array)$json->require) as $depName) {
 | 
						|
            if ($depName == 'magento/magento-composer-installer') {
 | 
						|
                // Magento Composer Installer is not needed for already existing components
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if (!isset(self::$rootJson['require-dev'][$depName]) && !isset(self::$rootJson['require'][$depName])
 | 
						|
                && !isset(self::$rootJson['replace'][$depName])) {
 | 
						|
                $errors[] = "'$name' depends on '$depName'";
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (!empty($errors)) {
 | 
						|
            $this->fail(
 | 
						|
                "The following dependencies are missing in root 'composer.json',"
 | 
						|
                . " while declared in child components.\n"
 | 
						|
                . "Consider adding them to 'require-dev' section (if needed for child components only),"
 | 
						|
                . " to 'replace' section (if they are present in the project),"
 | 
						|
                . " to 'require' section (if needed for the skeleton).\n"
 | 
						|
                . join("\n", $errors)
 | 
						|
            );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Convert a fully qualified module name to a composer package name according to conventions
 | 
						|
     *
 | 
						|
     * @param string $moduleName
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    private function convertModuleToPackageName($moduleName)
 | 
						|
    {
 | 
						|
        list($vendor, $name) = explode('_', $moduleName, 2);
 | 
						|
        $package = 'module';
 | 
						|
        foreach (preg_split('/([A-Z\d][a-z]*)/', $name, -1, PREG_SPLIT_DELIM_CAPTURE) as $chunk) {
 | 
						|
            $package .= $chunk ? "-{$chunk}" : '';
 | 
						|
        }
 | 
						|
        return strtolower("{$vendor}/{$package}");
 | 
						|
    }
 | 
						|
 | 
						|
    public function testComponentPathsInRoot()
 | 
						|
    {
 | 
						|
        if (!isset(self::$rootJson['extra']) || !isset(self::$rootJson['extra']['component_paths'])) {
 | 
						|
            $this->markTestSkipped("The root composer.json file doesn't mention any extra component paths information");
 | 
						|
        }
 | 
						|
        $this->assertArrayHasKey(
 | 
						|
            'replace',
 | 
						|
            self::$rootJson,
 | 
						|
            "If there are any component paths specified, then they must be reflected in 'replace' section"
 | 
						|
        );
 | 
						|
        $flat = $this->getFlatPathsInfo(self::$rootJson['extra']['component_paths']);
 | 
						|
        foreach ($flat as $item) {
 | 
						|
            list($component, $path) = $item;
 | 
						|
            $this->assertFileExists(
 | 
						|
                self::$root . '/' . $path,
 | 
						|
                "Missing or invalid component path: {$component} -> {$path}"
 | 
						|
            );
 | 
						|
            $this->assertArrayHasKey(
 | 
						|
                $component,
 | 
						|
                self::$rootJson['replace'],
 | 
						|
                "The {$component} is specified in 'extra->component_paths', but missing in 'replace' section"
 | 
						|
            );
 | 
						|
        }
 | 
						|
        foreach (array_keys(self::$rootJson['replace']) as $replace) {
 | 
						|
            if (!MagentoComponent::matchMagentoComponent($replace)) {
 | 
						|
                $this->assertArrayHasKey(
 | 
						|
                    $replace,
 | 
						|
                    self::$rootJson['extra']['component_paths'],
 | 
						|
                    "The {$replace} is specified in 'replace', but missing in 'extra->component_paths' section"
 | 
						|
                );
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param array $info
 | 
						|
     * @return array
 | 
						|
     * @throws \Exception
 | 
						|
     */
 | 
						|
    private function getFlatPathsInfo(array $info)
 | 
						|
    {
 | 
						|
        $flat = [];
 | 
						|
        foreach ($info as $key => $element) {
 | 
						|
            if (is_string($element)) {
 | 
						|
                $flat[] = [$key, $element];
 | 
						|
            } elseif (is_array($element)) {
 | 
						|
                foreach ($element as $path) {
 | 
						|
                    $flat[] = [$key, $path];
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                throw new \Exception("Unexpected element 'in extra->component_paths' section");
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $flat;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    private function checkProject()
 | 
						|
    {
 | 
						|
        sort(self::$dependencies);
 | 
						|
        $dependenciesListed = [];
 | 
						|
        if (strpos(self::$rootJson['name'], 'magento/project-') !== 0) {
 | 
						|
            $this->assertArrayHasKey(
 | 
						|
                'replace',
 | 
						|
                (array)self::$rootJson,
 | 
						|
                'No "replace" section found in root composer.json'
 | 
						|
            );
 | 
						|
            foreach (array_keys((array)self::$rootJson['replace']) as $key) {
 | 
						|
                if (MagentoComponent::matchMagentoComponent($key)) {
 | 
						|
                    $dependenciesListed[] = $key;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            sort($dependenciesListed);
 | 
						|
            $nonDeclaredDependencies = array_diff(
 | 
						|
                self::$dependencies,
 | 
						|
                $dependenciesListed,
 | 
						|
                self::$rootComposerModuleBlacklist
 | 
						|
            );
 | 
						|
            $nonexistentDependencies = array_diff($dependenciesListed, self::$dependencies);
 | 
						|
            $this->assertEmpty(
 | 
						|
                $nonDeclaredDependencies,
 | 
						|
                'Following dependencies are not declared in the root composer.json: '
 | 
						|
                . join(', ', $nonDeclaredDependencies)
 | 
						|
            );
 | 
						|
            $this->assertEmpty(
 | 
						|
                $nonexistentDependencies,
 | 
						|
                'Following dependencies declared in the root composer.json do not exist: '
 | 
						|
                . join(', ', $nonexistentDependencies)
 | 
						|
            );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Check the correspondence between the root composer file and magento/framework composer file.
 | 
						|
     */
 | 
						|
    public function testConsistencyOfDeclarationsInComposerFiles()
 | 
						|
    {
 | 
						|
        if (strpos(self::$rootJson['name'], 'magento/project-') !== false) {
 | 
						|
            // The Dependency test is skipped for vendor/magento build
 | 
						|
            self::markTestSkipped(
 | 
						|
                'The build is running for composer installation. Consistency test for composer files is skipped.'
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        $componentRegistrar = new ComponentRegistrar();
 | 
						|
        $magentoFrameworkLibraryDir =
 | 
						|
            $componentRegistrar->getPath(ComponentRegistrar::LIBRARY, self::$magentoFrameworkLibraryName);
 | 
						|
        $magentoFrameworkComposerFile =
 | 
						|
            json_decode(
 | 
						|
                file_get_contents($magentoFrameworkLibraryDir . DIRECTORY_SEPARATOR . 'composer.json'),
 | 
						|
                true
 | 
						|
            );
 | 
						|
 | 
						|
        $inconsistentDependencies = [];
 | 
						|
        foreach ($magentoFrameworkComposerFile['require'] as $dependency => $constraint) {
 | 
						|
            if (isset(self::$rootJson['require'][$dependency])
 | 
						|
                && self::$rootJson['require'][$dependency] !== $constraint
 | 
						|
            ) {
 | 
						|
                $inconsistentDependencies[] = $dependency;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        $this->assertEmpty(
 | 
						|
            $inconsistentDependencies,
 | 
						|
            'There is a discrepancy between the declared versions of the following modules in "'
 | 
						|
            . self::$magentoFrameworkLibraryName . '" and the root composer.json: '
 | 
						|
            . implode(', ', $inconsistentDependencies)
 | 
						|
        );
 | 
						|
    }
 | 
						|
}
 |