Skip to content

Commit ba74a0b

Browse files
committed
ACP2E-782: Introduce an alternative way to define fixtures using PHP8 Attributes
1 parent faf57f7 commit ba74a0b

File tree

11 files changed

+312
-60
lines changed

11 files changed

+312
-60
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Indexer\Test\Fixture;
9+
10+
use Magento\Framework\DataObject;
11+
use Magento\Framework\DataObjectFactory;
12+
use Magento\Framework\Indexer\IndexerRegistry;
13+
use Magento\TestFramework\Fixture\RevertibleDataFixtureInterface;
14+
15+
class IndexerMode implements RevertibleDataFixtureInterface
16+
{
17+
private const DEFAULT_DATA = [
18+
'indexer' => null,
19+
'schedule' => true
20+
];
21+
22+
/**
23+
* @var IndexerRegistry
24+
*/
25+
private IndexerRegistry $indexerRegistry;
26+
27+
/**
28+
* @var DataObjectFactory
29+
*/
30+
private DataObjectFactory $dataObjectFactory;
31+
32+
/**
33+
* @param IndexerRegistry $indexerRegistry
34+
* @param DataObjectFactory $dataObjectFactory
35+
*/
36+
public function __construct(
37+
IndexerRegistry $indexerRegistry,
38+
DataObjectFactory $dataObjectFactory
39+
) {
40+
$this->indexerRegistry = $indexerRegistry;
41+
$this->dataObjectFactory = $dataObjectFactory;
42+
}
43+
44+
/**
45+
* @inheritdoc
46+
*/
47+
public function apply(array $data = []): ?DataObject
48+
{
49+
$this->indexerRegistry->get($data['indexer'])->setScheduled($data['schedule']);
50+
51+
return $this->dataObjectFactory->create(['data' => $data]);
52+
}
53+
54+
/**
55+
* @inheritdoc
56+
*/
57+
public function revert(DataObject $data): void
58+
{
59+
$this->indexerRegistry->get($data['indexer'])->setScheduled(false);
60+
}
61+
}

dev/tests/integration/framework/Magento/TestFramework/Annotation/AppArea.php

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,7 @@ protected function _getTestAppArea($annotations)
8181
*/
8282
public function startTest(TestCase $test)
8383
{
84-
$annotations = TestCaseAnnotation::getInstance()->getAnnotations($test);
85-
$parser = Bootstrap::getObjectManager()->create(\Magento\TestFramework\Fixture\Parser\AppArea::class);
86-
$converter = static fn ($info) => $info['area'];
87-
$classAppIsolationState = array_map($converter, $parser->parse($test, ParserInterface::SCOPE_CLASS))
88-
?: ($annotations['class'][self::ANNOTATION_NAME] ?? []);
89-
$methodAppIsolationState = array_map($converter, $parser->parse($test, ParserInterface::SCOPE_METHOD))
90-
?: ($annotations['method'][self::ANNOTATION_NAME] ?? []);
91-
$area = current($methodAppIsolationState ?: $classAppIsolationState) ?: Application::DEFAULT_APP_AREA;
84+
$area = $this->getArea($test);
9285

9386
if (!in_array($area, $this->_allowedAreas, true)) {
9487
throw new LocalizedException(
@@ -107,4 +100,23 @@ public function startTest(TestCase $test)
107100
}
108101
}
109102
}
103+
104+
/**
105+
* Get the configured application area
106+
*
107+
* @param TestCase $test
108+
* @return string
109+
* @throws LocalizedException
110+
*/
111+
private function getArea(TestCase $test): string
112+
{
113+
$annotations = TestCaseAnnotation::getInstance()->getAnnotations($test);
114+
$parser = Bootstrap::getObjectManager()->create(\Magento\TestFramework\Fixture\Parser\AppArea::class);
115+
$converter = static fn ($info) => $info['area'];
116+
$classAppIsolationState = array_map($converter, $parser->parse($test, ParserInterface::SCOPE_CLASS))
117+
?: ($annotations['class'][self::ANNOTATION_NAME] ?? []);
118+
$methodAppIsolationState = array_map($converter, $parser->parse($test, ParserInterface::SCOPE_METHOD))
119+
?: ($annotations['method'][self::ANNOTATION_NAME] ?? []);
120+
return current($methodAppIsolationState ?: $classAppIsolationState) ?: Application::DEFAULT_APP_AREA;
121+
}
110122
}

dev/tests/integration/framework/Magento/TestFramework/Annotation/Cache.php

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@
66

77
namespace Magento\TestFramework\Annotation;
88

9-
use Magento\TestFramework\Annotation\TestCaseAnnotation;
9+
use Magento\Framework\Exception\LocalizedException;
10+
use Magento\TestFramework\Fixture\Parser\Cache as CacheFixtureParser;
11+
use Magento\TestFramework\Fixture\ParserInterface;
1012
use Magento\TestFramework\Helper\Bootstrap;
13+
use PHPUnit\Framework\TestCase;
1114

1215
/**
1316
* Implementation of the @magentoCache DocBlock annotation
1417
*/
1518
class Cache
1619
{
20+
public const ANNOTATION = 'magentoCache';
1721
/**
1822
* Original values for cache type states
1923
*
@@ -24,72 +28,60 @@ class Cache
2428
/**
2529
* Handler for 'startTest' event
2630
*
27-
* @param \PHPUnit\Framework\TestCase $test
31+
* @param TestCase $test
2832
* @return void
2933
*/
30-
public function startTest(\PHPUnit\Framework\TestCase $test)
34+
public function startTest(TestCase $test)
3135
{
32-
$source = TestCaseAnnotation::getInstance()->getAnnotations($test);
33-
if (isset($source['method']['magentoCache'])) {
34-
$annotations = $source['method']['magentoCache'];
35-
} elseif (isset($source['class']['magentoCache'])) {
36-
$annotations = $source['class']['magentoCache'];
37-
} else {
38-
return;
36+
$statusList = array_merge(
37+
$this->getFixturesFromCacheAttribute($test, ParserInterface::SCOPE_METHOD),
38+
$this->getFixturesFromCacheAnnotation($test, ParserInterface::SCOPE_METHOD)
39+
);
40+
if (!$statusList) {
41+
array_merge(
42+
$this->getFixturesFromCacheAttribute($test, ParserInterface::SCOPE_CLASS),
43+
$this->getFixturesFromCacheAnnotation($test, ParserInterface::SCOPE_CLASS)
44+
);
3945
}
40-
$this->setValues($this->parseValues($annotations, $test), $test);
46+
47+
if ($statusList) {
48+
$values = [];
49+
$typeList = self::getTypeList();
50+
foreach ($statusList as $cache) {
51+
if ('all' === $cache['type']) {
52+
foreach ($typeList->getTypes() as $type) {
53+
$values[$type['id']] = $cache['status'];
54+
}
55+
} else {
56+
$values[$cache['type']] = $cache['status'];
57+
}
58+
}
59+
$this->setValues($values, $test);
60+
}
61+
4162
}
4263

4364
/**
4465
* Handler for 'endTest' event
4566
*
46-
* @param \PHPUnit\Framework\TestCase $test
67+
* @param TestCase $test
4768
* @return void
4869
*/
49-
public function endTest(\PHPUnit\Framework\TestCase $test)
70+
public function endTest(TestCase $test)
5071
{
5172
if ($this->origValues) {
5273
$this->setValues($this->origValues, $test);
5374
$this->origValues = [];
5475
}
5576
}
5677

57-
/**
58-
* Determines from docblock annotations which cache types to set
59-
*
60-
* @param array $annotations
61-
* @param \PHPUnit\Framework\TestCase $test
62-
* @return array
63-
*/
64-
private function parseValues($annotations, \PHPUnit\Framework\TestCase $test)
65-
{
66-
$result = [];
67-
$typeList = self::getTypeList();
68-
foreach ($annotations as $subject) {
69-
if (!preg_match('/^([a-z_]+)\s(enabled|disabled)$/', $subject, $matches)) {
70-
self::fail("Invalid @magentoCache declaration: '{$subject}'", $test);
71-
}
72-
list(, $requestedType, $isEnabled) = $matches;
73-
$isEnabled = $isEnabled == 'enabled' ? 1 : 0;
74-
if ('all' === $requestedType) {
75-
$result = [];
76-
foreach ($typeList->getTypes() as $type) {
77-
$result[$type['id']] = $isEnabled;
78-
}
79-
} else {
80-
$result[$requestedType] = $isEnabled;
81-
}
82-
}
83-
return $result;
84-
}
85-
8678
/**
8779
* Sets the values of cache types
8880
*
8981
* @param array $values
90-
* @param \PHPUnit\Framework\TestCase $test
82+
* @param TestCase $test
9183
*/
92-
private function setValues($values, \PHPUnit\Framework\TestCase $test)
84+
private function setValues($values, TestCase $test)
9385
{
9486
$typeList = self::getTypeList();
9587
if (!$this->origValues) {
@@ -122,12 +114,48 @@ private static function getTypeList()
122114
* Fails the test with specified error message
123115
*
124116
* @param string $message
125-
* @param \PHPUnit\Framework\TestCase $test
117+
* @param TestCase $test
126118
* @throws \Exception
127119
*/
128-
private static function fail($message, \PHPUnit\Framework\TestCase $test)
120+
private static function fail($message, TestCase $test)
129121
{
130122
$test->fail("{$message} in the test '{$test->toString()}'");
131123
throw new \Exception('The above line was supposed to throw an exception.');
132124
}
125+
126+
/**
127+
* Returns cache fixtures defined using Cache annotation
128+
*
129+
* @param TestCase $test
130+
* @param string $scope
131+
* @return array
132+
* @throws \Exception
133+
*/
134+
private function getFixturesFromCacheAnnotation(TestCase $test, string $scope): array
135+
{
136+
$annotations = TestCaseAnnotation::getInstance()->getAnnotations($test);
137+
$configs = [];
138+
139+
foreach ($annotations[$scope][self::ANNOTATION] ?? [] as $annotation) {
140+
if (!preg_match('/^([a-z_]+)\s(enabled|disabled)$/', $annotation, $matches)) {
141+
self::fail("Invalid @magentoCache declaration: '{$annotation}'", $test);
142+
}
143+
$configs[] = ['type' => $matches[1], 'status' => $matches[2] === 'enabled'];
144+
}
145+
146+
return $configs;
147+
}
148+
149+
/**
150+
* Returns cache fixtures defined using Cache attribute
151+
*
152+
* @param TestCase $test
153+
* @param string $scope
154+
* @return array
155+
* @throws LocalizedException
156+
*/
157+
private function getFixturesFromCacheAttribute(TestCase $test, string $scope): array
158+
{
159+
return Bootstrap::getObjectManager()->create(CacheFixtureParser::class)->parse($test, $scope);
160+
}
133161
}

dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureBeforeTransaction.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace Magento\TestFramework\Annotation;
88

9+
use Magento\TestFramework\Helper\Bootstrap;
910
use PHPUnit\Framework\TestCase;
1011

1112
/**
@@ -48,4 +49,19 @@ protected function getAnnotation(): string
4849
{
4950
return self::ANNOTATION;
5051
}
52+
53+
/**
54+
* @inheritdoc
55+
*/
56+
protected function getParsers(): array
57+
{
58+
$parsers = [];
59+
$parsers[] = Bootstrap::getObjectManager()->create(
60+
\Magento\TestFramework\Fixture\Parser\DataFixtureBeforeTransaction::class
61+
);
62+
return array_merge(
63+
parent::getParsers(),
64+
$parsers
65+
);
66+
}
5167
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\TestFramework\Fixture;
9+
10+
use Attribute;
11+
12+
13+
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
14+
class Cache
15+
{
16+
/**
17+
* @param string $type
18+
* @param bool $status
19+
*/
20+
public function __construct(
21+
public string $type,
22+
public bool $status,
23+
) {
24+
}
25+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\TestFramework\Fixture;
9+
10+
use Attribute;
11+
12+
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
13+
class DataFixtureBeforeTransaction extends DataFixture
14+
{
15+
}

0 commit comments

Comments
 (0)