Skip to content

Commit 1052d28

Browse files
committed
MAGETWO-67626: Auto-generated classes behave differently in unit tests and application
- simplified auto-generation in unit tests
1 parent dba6db3 commit 1052d28

File tree

7 files changed

+197
-176
lines changed

7 files changed

+197
-176
lines changed

dev/tests/unit/framework/autoload.php

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,19 @@
77
use Magento\Framework\App\Filesystem\DirectoryList;
88
use Magento\Framework\Code\Generator\Io;
99
use Magento\Framework\Filesystem\Driver\File;
10-
use Magento\Framework\ObjectManager\Code\Generator\Factory;
11-
use Magento\Framework\TestFramework\Unit\Autoloader\ExtensionGeneratorAutoloader;
10+
use Magento\Framework\TestFramework\Unit\Autoloader\ExtensionAttributesGenerator;
11+
use Magento\Framework\TestFramework\Unit\Autoloader\FactoryGenerator;
1212
use Magento\Framework\TestFramework\Unit\Autoloader\GeneratedClassesAutoloader;
13-
use Magento\Framework\TestFramework\Unit\Autoloader\ObjectManager;
1413

1514
$generatorIo = new Io(
1615
new File(),
1716
TESTS_TEMP_DIR . '/' . DirectoryList::getDefaultConfig()[DirectoryList::GENERATED_CODE][DirectoryList::PATH]
1817
);
19-
spl_autoload_register([new ExtensionGeneratorAutoloader($generatorIo), 'load']);
20-
21-
$codeGenerator = new \Magento\Framework\Code\Generator(
22-
$generatorIo,
23-
[Factory::ENTITY_TYPE => Factory::class]
18+
$generatedCodeAutoloader = new GeneratedClassesAutoloader(
19+
[
20+
new ExtensionAttributesGenerator(),
21+
new FactoryGenerator(),
22+
],
23+
$generatorIo
2424
);
25-
$codeGenerator->setObjectManager(new ObjectManager());
26-
spl_autoload_register([new GeneratedClassesAutoloader($codeGenerator), 'load']);
25+
spl_autoload_register([$generatedCodeAutoloader, 'load']);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Framework\TestFramework\Unit\Autoloader;
8+
9+
/**
10+
* Code generation for the undeclared *Extension and *ExtensionInterface types
11+
*
12+
* These files must be generated since they are referenced in many interfaces/classes and cannot be mocked easily.
13+
* For unit tests, these are just empty type definitions. You should use integration tests if you want to see the real
14+
* types be generated with the properties from the extension attributes config.
15+
*/
16+
class ExtensionAttributesGenerator implements GeneratorInterface
17+
{
18+
/**
19+
* Generates a stub class/interface for classes that follow the convention
20+
*
21+
* The convention is "<SourceClass>ExtensionInterface" or "<SourceClass>Extension"
22+
*
23+
* @param string $className
24+
* @return bool|string
25+
*/
26+
public function generate($className)
27+
{
28+
if (!$this->isExtension($className) && !$this->isExtensionInterface($className)) {
29+
return false;
30+
}
31+
$classNameParts = explode('\\', $className);
32+
33+
/* Split the type name and namespace for the file's contents. */
34+
$justTypeName = $classNameParts[count($classNameParts) - 1];
35+
36+
unset($classNameParts[count($classNameParts) - 1]);
37+
$namespace = implode('\\', $classNameParts);
38+
39+
$content = false;
40+
if ($this->isExtension($className)) {
41+
$content = "namespace $namespace;\n\nclass $justTypeName implements "
42+
. "{$justTypeName}Interface\n{\n\n}";
43+
} elseif ($this->isExtensionInterface($className)) {
44+
$content = "namespace $namespace;\n\ninterface $justTypeName extends "
45+
. "\\Magento\\Framework\\Api\\ExtensionAttributesInterface \n{\n\n}";
46+
}
47+
return $content;
48+
}
49+
50+
/**
51+
* Determines if the passed in class name is an ExtensionInterface type.
52+
*
53+
* @param string $className
54+
* @return bool
55+
*/
56+
private function isExtensionInterface($className)
57+
{
58+
$suffix = "ExtensionInterface";
59+
return substr($className, -strlen($suffix), strlen($suffix)) === $suffix;
60+
}
61+
62+
/**
63+
* Determines if the passed in class name is an Extension type.
64+
*
65+
* @param string $className
66+
* @return bool
67+
*/
68+
private function isExtension($className)
69+
{
70+
$suffix = "Extension";
71+
return substr($className, -strlen($suffix), strlen($suffix)) === $suffix;
72+
}
73+
}

lib/internal/Magento/Framework/TestFramework/Unit/Autoloader/ExtensionGeneratorAutoloader.php

Lines changed: 0 additions & 97 deletions
This file was deleted.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Framework\TestFramework\Unit\Autoloader;
8+
9+
use Magento\Framework\Code\Generator\ClassGenerator;
10+
11+
/**
12+
* Generates a simple factory class with create() method
13+
*/
14+
class FactoryGenerator implements GeneratorInterface
15+
{
16+
/**
17+
* Generates a factory class if it follows "<SourceClass>Factory" convention
18+
*
19+
* @param string $className
20+
* @return bool|string
21+
*/
22+
public function generate($className)
23+
{
24+
if (!$this->isFactory($className)) {
25+
return false;
26+
}
27+
$methods = [[
28+
'name' => 'create',
29+
'parameters' => [['name' => 'data', 'type' => 'array', 'defaultValue' => []]],
30+
'body' => '',
31+
]];
32+
$classGenerator = new ClassGenerator();
33+
$classGenerator->setName($className)
34+
->addMethods($methods);
35+
return $classGenerator->generate();
36+
}
37+
38+
/**
39+
* Check if the class name is a factory by convention "<SourceClass>Factory"
40+
*
41+
* @param string $className
42+
* @return bool
43+
*/
44+
private function isFactory($className)
45+
{
46+
$sourceName = rtrim(substr($className, 0, -strlen('Factory')), '\\');
47+
return $sourceName . 'Factory' == $className;
48+
}
49+
}

lib/internal/Magento/Framework/TestFramework/Unit/Autoloader/GeneratedClassesAutoloader.php

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,70 @@
66

77
namespace Magento\Framework\TestFramework\Unit\Autoloader;
88

9+
use Magento\Framework\Code\Generator\Io;
10+
911
/**
1012
* Autoloader that initiates auto-generation of requested classes
1113
*/
1214
class GeneratedClassesAutoloader
1315
{
1416
/**
15-
* @var \Magento\Framework\Code\Generator
17+
* @var Io
18+
*/
19+
private $generatorIo;
20+
21+
/**
22+
* @var GeneratorInterface[]
1623
*/
17-
private $generator;
24+
private $generators;
1825

1926
/**
20-
* FactoryGeneratorAutoloader constructor.
21-
* @param \Magento\Framework\Code\Generator $generator
27+
* @param GeneratorInterface[] $generators
28+
* @param Io $generatorIo
2229
*/
23-
public function __construct(\Magento\Framework\Code\Generator $generator)
30+
public function __construct(array $generators, Io $generatorIo)
2431
{
25-
$this->generator = $generator;
32+
foreach ($generators as $generator) {
33+
if (!($generator instanceof GeneratorInterface)) {
34+
throw new \InvalidArgumentException(
35+
sprintf(
36+
"Instance of '%s' is expected, instance of '%s' is received",
37+
'\Magento\Framework\TestFramework\Unit\Autoloader\GeneratorInterface',
38+
get_class($generator)
39+
)
40+
);
41+
}
42+
}
43+
$this->generators = $generators;
44+
$this->generatorIo = $generatorIo;
2645
}
2746

2847
/**
2948
* Load class
3049
*
3150
* @param string $className
32-
* @return void
51+
* @return bool
3352
*/
3453
public function load($className)
3554
{
36-
$this->generator->generateClass($className);
55+
$classSourceFile = $this->generatorIo->generateResultFileName($className);
56+
if ($this->generatorIo->fileExists($classSourceFile)) {
57+
include $classSourceFile;
58+
return true;
59+
} else {
60+
61+
foreach ($this->generators as $generator) {
62+
$content = $generator->generate($className);
63+
if ($content) {
64+
$this->generatorIo->makeResultFileDirectory($className);
65+
$this->generatorIo->writeResultFile($classSourceFile, $content);
66+
include $classSourceFile;
67+
return true;
68+
}
69+
};
70+
71+
}
72+
73+
return false;
3774
}
3875
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Framework\TestFramework\Unit\Autoloader;
8+
9+
/**
10+
* Interface for generation of a class of specific type
11+
*/
12+
interface GeneratorInterface
13+
{
14+
/**
15+
* Generate the requested class if it's supported
16+
*
17+
* @param string $className
18+
* @return mixed
19+
*/
20+
public function generate($className);
21+
}

0 commit comments

Comments
 (0)