PhpUnitAttributesFixerTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer\Tests\Fixer\PhpUnit;
  13. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  14. /**
  15. * @internal
  16. *
  17. * @covers \PhpCsFixer\Fixer\PhpUnit\PhpUnitAttributesFixer
  18. *
  19. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\PhpUnit\PhpUnitAttributesFixer>
  20. *
  21. * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\PhpUnit\PhpUnitAttributesFixer
  22. */
  23. final class PhpUnitAttributesFixerTest extends AbstractFixerTestCase
  24. {
  25. /**
  26. * @requires PHP 8.0
  27. *
  28. * @dataProvider provideFixCases
  29. *
  30. * @param _AutogeneratedInputConfiguration $configuration
  31. */
  32. public function testFix(string $expected, ?string $input = null, array $configuration = []): void
  33. {
  34. $this->fixer->configure($configuration);
  35. $this->doTest($expected, $input);
  36. }
  37. /**
  38. * @return iterable<array{0: string, 1?: string}>
  39. */
  40. public static function provideFixCases(): iterable
  41. {
  42. yield 'do not fix with wrong values' => [<<<'PHP'
  43. <?php
  44. /**
  45. * @requires
  46. * @uses
  47. */
  48. class FooTest extends \PHPUnit\Framework\TestCase {
  49. /**
  50. * @backupGlobals
  51. * @backupStaticAttributes
  52. * @covers
  53. * @dataProvider
  54. * @depends
  55. * @group
  56. * @preserveGlobalState
  57. * @testDox
  58. * @testWith
  59. * @ticket
  60. */
  61. public function testFoo() { self::assertTrue(true); }
  62. }
  63. PHP];
  64. yield 'do not fix with wrong casing' => [<<<'PHP'
  65. <?php
  66. /**
  67. * @COVERS \Foo
  68. */
  69. class FooTest extends \PHPUnit\Framework\TestCase {
  70. /**
  71. * @dataPROVIDER provideFooCases
  72. * @requires php 8.3
  73. */
  74. public function testFoo() { self::assertTrue(true); }
  75. }
  76. PHP];
  77. yield 'do not fix when not supported by attributes' => [<<<'PHP'
  78. <?php
  79. /**
  80. * @covers FooClass::FooMethod
  81. * @uses ClassName::methodName
  82. */
  83. class FooTest extends \PHPUnit\Framework\TestCase {
  84. public function testFoo() { self::assertTrue(true); }
  85. }
  86. PHP];
  87. yield 'do not fix when there is already attribute of related class' => [<<<'PHP'
  88. <?php
  89. class FooTest extends \PHPUnit\Framework\TestCase {
  90. /**
  91. * @requires PHP ^8.2
  92. */
  93. #[\FirstAttributeToMakeSureMultipleAttributesWorks]
  94. #[\PHPUnit\Framework\Attributes\RequiresPhp('^7.1')]
  95. #[\ThirdAttributeToMakeSureMultipleAttributesWorks]
  96. public function testFoo() {}
  97. }
  98. PHP];
  99. yield 'do not duplicate attribute when used without leading slash' => [<<<'PHP'
  100. <?php
  101. class FooTest extends \PHPUnit\Framework\TestCase {
  102. /**
  103. * @requires PHP ^6.1
  104. */
  105. #[PHPUnit\Framework\Attributes\RequiresPhp('^6.1')]
  106. public function testFoo() {}
  107. }
  108. PHP];
  109. yield 'do not duplicate attribute when used with import' => [<<<'PHP'
  110. <?php
  111. use PHPUnit\Framework\Attributes\RequiresPhp;
  112. class FooTest extends \PHPUnit\Framework\TestCase {
  113. /**
  114. * @requires PHP ^6.2
  115. */
  116. #[RequiresPhp('^6.2')]
  117. public function testFoo() {}
  118. }
  119. PHP];
  120. yield 'do not duplicate attribute when used with partial import' => [<<<'PHP'
  121. <?php
  122. use PHPUnit\Framework\Attributes;
  123. class FooTest extends \PHPUnit\Framework\TestCase {
  124. /**
  125. * @requires PHP ^6.2
  126. */
  127. #[Attributes\RequiresPhp('^6.2')]
  128. public function testFoo() {}
  129. }
  130. PHP];
  131. yield 'do not duplicate attribute when used with alias' => [<<<'PHP'
  132. <?php
  133. use PHPUnit\Framework\Attributes\RequiresPhp as PHPUnitRequiresPhp;
  134. class FooTest extends \PHPUnit\Framework\TestCase {
  135. /**
  136. * @requires PHP ^6.0
  137. */
  138. #[PHPUnitRequiresPhp('^6.0')]
  139. public function testFoo() {}
  140. }
  141. PHP];
  142. yield 'do not duplicate attribute when used with partial alias' => [<<<'PHP'
  143. <?php
  144. use PHPUnit\Framework\Attributes as PHPUnitAttributes;
  145. class FooTest extends \PHPUnit\Framework\TestCase {
  146. /**
  147. * @requires PHP ^6.0
  148. */
  149. #[PHPUnitAttributes\RequiresPhp('^6.0')]
  150. public function testFoo() {}
  151. }
  152. PHP];
  153. yield 'fix multiple annotations' => [
  154. <<<'PHP'
  155. <?php
  156. class FooTest extends \PHPUnit\Framework\TestCase {
  157. /**
  158. * @copyright ACME Corporation
  159. */
  160. #[\PHPUnit\Framework\Attributes\DataProvider('provideFooCases')]
  161. #[\PHPUnit\Framework\Attributes\RequiresPhp('^8.2')]
  162. #[\PHPUnit\Framework\Attributes\RequiresOperatingSystem('Linux|Darwin')]
  163. public function testFoo($x) { self::assertTrue($x); }
  164. public static function provideFooCases() { yield [true]; yield [false]; }
  165. }
  166. PHP,
  167. <<<'PHP'
  168. <?php
  169. class FooTest extends \PHPUnit\Framework\TestCase {
  170. /**
  171. * @copyright ACME Corporation
  172. * @dataProvider provideFooCases
  173. * @requires PHP ^8.2
  174. * @requires OS Linux|Darwin
  175. */
  176. public function testFoo($x) { self::assertTrue($x); }
  177. public static function provideFooCases() { yield [true]; yield [false]; }
  178. }
  179. PHP,
  180. ];
  181. yield 'fix with multiple spaces' => [
  182. <<<'PHP'
  183. <?php
  184. class FooTest extends \PHPUnit\Framework\TestCase {
  185. /**
  186. */
  187. #[\PHPUnit\Framework\Attributes\RequiresPhp('^7.4|^8.1')]
  188. public function testFoo() { self::assertTrue(true); }
  189. }
  190. PHP,
  191. <<<'PHP'
  192. <?php
  193. class FooTest extends \PHPUnit\Framework\TestCase {
  194. /**
  195. * @requires PHP ^7.4|^8.1
  196. */
  197. public function testFoo() { self::assertTrue(true); }
  198. }
  199. PHP,
  200. ];
  201. yield 'fix with > in operator' => [
  202. <<<'PHP'
  203. <?php
  204. class FooTest extends \PHPUnit\Framework\TestCase {
  205. /**
  206. */
  207. #[\PHPUnit\Framework\Attributes\RequiresPhp('>= 8.1')]
  208. public function testFoo() { self::assertTrue(true); }
  209. }
  210. PHP,
  211. <<<'PHP'
  212. <?php
  213. class FooTest extends \PHPUnit\Framework\TestCase {
  214. /**
  215. * @requires PHP >= 8.1
  216. */
  217. public function testFoo() { self::assertTrue(true); }
  218. }
  219. PHP,
  220. ];
  221. yield 'fix with trailing spaces' => self::createCase(
  222. ['class'],
  223. '#[CoversClass(Foo::class)]',
  224. '@covers Foo ',
  225. );
  226. $byte224 = \chr(224);
  227. yield 'fix with non-alphanumeric characters' => [
  228. <<<PHP
  229. <?php
  230. class FooTest extends \\PHPUnit\\Framework\\TestCase {
  231. /**
  232. */
  233. #[\\PHPUnit\\Framework\\Attributes\\TestDox('a\\'b"c')]
  234. public function testFoo() { self::assertTrue(true); }
  235. /**
  236. */
  237. #[\\PHPUnit\\Framework\\Attributes\\TestDox('龍')]
  238. public function testBar() { self::assertTrue(true); }
  239. /**
  240. */
  241. #[\\PHPUnit\\Framework\\Attributes\\TestDox('byte224: {$byte224}')]
  242. public function testBaz() { self::assertTrue(true); }
  243. }
  244. PHP,
  245. <<<PHP
  246. <?php
  247. class FooTest extends \\PHPUnit\\Framework\\TestCase {
  248. /**
  249. * @testDox a'b"c
  250. */
  251. public function testFoo() { self::assertTrue(true); }
  252. /**
  253. * @testDox 龍
  254. */
  255. public function testBar() { self::assertTrue(true); }
  256. /**
  257. * @testDox byte224: {$byte224}
  258. */
  259. public function testBaz() { self::assertTrue(true); }
  260. }
  261. PHP,
  262. ];
  263. yield 'handle After' => self::createCase(
  264. ['method'],
  265. '#[After]',
  266. '@after',
  267. );
  268. yield 'handle AfterClass' => self::createCase(
  269. ['method'],
  270. '#[AfterClass]',
  271. '@afterClass',
  272. );
  273. yield 'handle BackupGlobals enabled' => self::createCase(
  274. ['class', 'method'],
  275. '#[BackupGlobals(true)]',
  276. '@backupGlobals enabled',
  277. );
  278. yield 'handle BackupGlobals disabled' => self::createCase(
  279. ['class', 'method'],
  280. '#[BackupGlobals(false)]',
  281. '@backupGlobals disabled',
  282. );
  283. yield 'handle BackupGlobals no' => self::createCase(
  284. ['class', 'method'],
  285. '#[BackupGlobals(false)]',
  286. '@backupGlobals no',
  287. );
  288. yield 'handle BackupStaticProperties enabled' => self::createCase(
  289. ['class', 'method'],
  290. '#[BackupStaticProperties(true)]',
  291. '@backupStaticAttributes enabled',
  292. );
  293. yield 'handle BackupStaticProperties disabled' => self::createCase(
  294. ['class', 'method'],
  295. '#[BackupStaticProperties(false)]',
  296. '@backupStaticAttributes disabled',
  297. );
  298. yield 'handle Before' => self::createCase(
  299. ['method'],
  300. '#[Before]',
  301. '@before',
  302. );
  303. yield 'handle BeforeClass' => self::createCase(
  304. ['method'],
  305. '#[BeforeClass]',
  306. '@beforeClass',
  307. );
  308. yield 'handle CoversClass' => self::createCase(
  309. ['class'],
  310. '#[CoversClass(\VendorName\ClassName::class)]',
  311. '@covers \VendorName\ClassName',
  312. );
  313. yield 'handle CoversFunction' => self::createCase(
  314. ['class'],
  315. "#[CoversFunction('functionName')]",
  316. '@covers ::functionName',
  317. );
  318. yield 'handle CoversNothing' => self::createCase(
  319. ['class', 'method'],
  320. '#[CoversNothing]',
  321. '@coversNothing',
  322. );
  323. yield 'handle DataProvider' => self::createCase(
  324. ['method'],
  325. "#[DataProvider('provideFooCases')]",
  326. '@dataProvider provideFooCases',
  327. );
  328. yield 'handle DataProviderExternal' => self::createCase(
  329. ['method'],
  330. "#[DataProviderExternal(BarTest::class, 'provideFooCases')]",
  331. '@dataProvider BarTest::provideFooCases',
  332. );
  333. yield 'handle Depends' => self::createCase(
  334. ['method'],
  335. "#[Depends('methodName')]",
  336. '@depends methodName',
  337. );
  338. yield 'handle DependsExternal' => self::createCase(
  339. ['method'],
  340. "#[DependsExternal(ClassName::class, 'methodName')]",
  341. '@depends ClassName::methodName',
  342. );
  343. yield 'handle DependsExternalUsingDeepClone' => self::createCase(
  344. ['method'],
  345. "#[DependsExternalUsingDeepClone(ClassName::class, 'methodName')]",
  346. '@depends clone ClassName::methodName',
  347. );
  348. yield 'handle DependsExternalUsingShallowClone' => self::createCase(
  349. ['method'],
  350. "#[DependsExternalUsingShallowClone(ClassName::class, 'methodName')]",
  351. '@depends shallowClone ClassName::methodName',
  352. );
  353. yield 'handle DependsOnClass' => self::createCase(
  354. ['method'],
  355. '#[DependsOnClass(ClassName::class)]',
  356. '@depends ClassName::class',
  357. );
  358. yield 'handle DependsOnClassUsingDeepClone' => self::createCase(
  359. ['method'],
  360. '#[DependsOnClassUsingDeepClone(ClassName::class)]',
  361. '@depends clone ClassName::class',
  362. );
  363. yield 'handle DependsOnClassUsingShallowClone' => self::createCase(
  364. ['method'],
  365. '#[DependsOnClassUsingShallowClone(ClassName::class)]',
  366. '@depends shallowClone ClassName::class',
  367. );
  368. yield 'handle DependsUsingDeepClone' => self::createCase(
  369. ['method'],
  370. "#[DependsUsingDeepClone('methodName')]",
  371. '@depends clone methodName',
  372. );
  373. yield 'handle DependsUsingShallowClone' => self::createCase(
  374. ['method'],
  375. "#[DependsUsingShallowClone('methodName')]",
  376. '@depends shallowClone methodName',
  377. );
  378. yield 'handle DoesNotPerformAssertions' => self::createCase(
  379. ['class', 'method'],
  380. '#[DoesNotPerformAssertions]',
  381. '@doesNotPerformAssertions',
  382. );
  383. yield 'handle Group' => self::createCase(
  384. ['class', 'method'],
  385. "#[Group('groupName')]",
  386. '@group groupName',
  387. );
  388. yield 'handle Large' => self::createCase(
  389. ['class'],
  390. '#[Large]',
  391. '@large',
  392. );
  393. yield 'handle Medium' => self::createCase(
  394. ['class'],
  395. '#[Medium]',
  396. '@medium',
  397. );
  398. yield 'handle PostCondition' => self::createCase(
  399. ['method'],
  400. '#[PostCondition]',
  401. '@postCondition',
  402. );
  403. yield 'handle PreCondition' => self::createCase(
  404. ['method'],
  405. '#[PreCondition]',
  406. '@preCondition',
  407. );
  408. yield 'handle PreserveGlobalState enabled' => self::createCase(
  409. ['class', 'method'],
  410. '#[PreserveGlobalState(true)]',
  411. '@preserveGlobalState enabled',
  412. );
  413. yield 'handle PreserveGlobalState disabled' => self::createCase(
  414. ['class', 'method'],
  415. '#[PreserveGlobalState(false)]',
  416. '@preserveGlobalState disabled',
  417. );
  418. yield 'handle RequiresFunction' => self::createCase(
  419. ['class', 'method'],
  420. "#[RequiresFunction('imap_open')]",
  421. '@requires function imap_open',
  422. );
  423. yield 'handle RequiresMethod' => self::createCase(
  424. ['class', 'method'],
  425. "#[RequiresMethod(ReflectionMethod::class, 'setAccessible')]",
  426. '@requires function ReflectionMethod::setAccessible',
  427. );
  428. yield 'handle RequiresOperatingSystem' => self::createCase(
  429. ['class', 'method'],
  430. "#[RequiresOperatingSystem('Linux')]",
  431. '@requires OS Linux',
  432. );
  433. yield 'handle RequiresOperatingSystemFamily' => self::createCase(
  434. ['class', 'method'],
  435. "#[RequiresOperatingSystemFamily('Windows')]",
  436. '@requires OSFAMILY Windows',
  437. );
  438. yield 'handle RequiresPhp with only version' => self::createCase(
  439. ['class', 'method'],
  440. "#[RequiresPhp('>= 8.1.20')]",
  441. '@requires PHP 8.1.20',
  442. );
  443. yield 'handle RequiresPhp with caret' => self::createCase(
  444. ['class', 'method'],
  445. "#[RequiresPhp('^8.1.21')]",
  446. '@requires PHP ^8.1.21',
  447. );
  448. yield 'handle RequiresPhp with less than' => self::createCase(
  449. ['class', 'method'],
  450. "#[RequiresPhp('<8.1.22')]",
  451. '@requires PHP <8.1.22',
  452. );
  453. yield 'handle RequiresPhp with less than and space' => self::createCase(
  454. ['class', 'method'],
  455. "#[RequiresPhp('< 8.1.23')]",
  456. '@requires PHP < 8.1.23',
  457. );
  458. yield 'handle RequiresPhp with alternative versions' => self::createCase(
  459. ['class', 'method'],
  460. "#[RequiresPhp('6|8')]",
  461. '@requires PHP 6|8',
  462. );
  463. yield 'handle RequiresPhp with alpha versions' => self::createCase(
  464. ['class', 'method'],
  465. "#[RequiresPhp('>= 5.4.0-alpha1')]",
  466. '@requires PHP 5.4.0-alpha1',
  467. );
  468. yield 'handle RequiresPhpExtension' => self::createCase(
  469. ['class', 'method'],
  470. "#[RequiresPhpExtension('mysqli', '>= 8.3.0')]",
  471. '@requires extension mysqli >= 8.3.0',
  472. );
  473. yield 'handle RequiresPhpExtension with only version' => self::createCase(
  474. ['class', 'method'],
  475. "#[RequiresPhpExtension('mysqli', '>= 8.3.0')]",
  476. '@requires extension mysqli 8.3.0',
  477. );
  478. yield 'handle RequiresPhpunit' => self::createCase(
  479. ['class', 'method'],
  480. "#[RequiresPhpunit('^10.1.0')]",
  481. '@requires PHPUnit ^10.1.0',
  482. );
  483. yield 'handle RequiresPhpunit with only version' => self::createCase(
  484. ['class', 'method'],
  485. "#[RequiresPhpunit('>= 11.1.1')]",
  486. '@requires PHPUnit 11.1.1',
  487. );
  488. yield 'handle RequiresSetting' => self::createCase(
  489. ['class', 'method'],
  490. "#[RequiresSetting('date.timezone', 'Europe/London')]",
  491. '@requires setting date.timezone Europe/London',
  492. );
  493. yield 'handle RunInSeparateProcess' => self::createCase(
  494. ['method'],
  495. '#[RunInSeparateProcess]',
  496. '@runInSeparateProcess',
  497. );
  498. yield 'handle RunTestsInSeparateProcesses' => self::createCase(
  499. ['class'],
  500. '#[RunTestsInSeparateProcesses]',
  501. '@runTestsInSeparateProcesses',
  502. );
  503. yield 'handle Small' => self::createCase(
  504. ['class'],
  505. '#[Small]',
  506. '@small',
  507. );
  508. yield 'handle Test' => self::createCase(
  509. ['method'],
  510. '#[Test]',
  511. '@test',
  512. );
  513. yield 'handle TestDox' => self::createCase(
  514. ['class', 'method'],
  515. "#[TestDox('Hello world!')]",
  516. '@testDox Hello world!',
  517. );
  518. yield 'handle Ticket' => self::createCase(
  519. ['class', 'method'],
  520. "#[Ticket('ABC-123')]",
  521. '@ticket ABC-123',
  522. );
  523. yield 'handle UsesClass' => self::createCase(
  524. ['class'],
  525. '#[UsesClass(ClassName::class)]',
  526. '@uses ClassName',
  527. );
  528. yield 'handle UsesFunction' => self::createCase(
  529. ['class'],
  530. "#[UsesFunction('functionName')]",
  531. '@uses ::functionName',
  532. );
  533. yield 'handle TestWith' => [
  534. <<<'PHP'
  535. <?php
  536. /**
  537. * @testWith [true, false]
  538. */
  539. class FooTest extends \PHPUnit\Framework\TestCase {
  540. /**
  541. */
  542. #[\PHPUnit\Framework\Attributes\TestWithJson('[1, 2]')]
  543. public function testFoo($x) {}
  544. /**
  545. */
  546. #[\PHPUnit\Framework\Attributes\TestWithJson('[3, 4, 5]')]
  547. #[\PHPUnit\Framework\Attributes\TestWithJson('[6, 7, 8]')]
  548. #[\PHPUnit\Framework\Attributes\TestWithJson('["a", "b"]')]
  549. #[\PHPUnit\Framework\Attributes\TestWithJson('["c\'d"]')]
  550. public function testBar($x) {}
  551. }
  552. PHP,
  553. <<<'PHP'
  554. <?php
  555. /**
  556. * @testWith [true, false]
  557. */
  558. class FooTest extends \PHPUnit\Framework\TestCase {
  559. /**
  560. * @testWith [1, 2]
  561. */
  562. public function testFoo($x) {}
  563. /**
  564. * @testWith [3, 4, 5]
  565. * [6, 7, 8]
  566. * ["a", "b"]
  567. * ["c'd"]
  568. */
  569. public function testBar($x) {}
  570. }
  571. PHP,
  572. ];
  573. yield 'handle multiple annotations of the same name' => [
  574. <<<'PHP'
  575. <?php
  576. /**
  577. */
  578. #[\PHPUnit\Framework\Attributes\Group('foo')]
  579. #[\PHPUnit\Framework\Attributes\Group('bar')]
  580. class TheTest extends \PHPUnit\Framework\TestCase {}
  581. PHP,
  582. <<<'PHP'
  583. <?php
  584. /**
  585. * @group foo
  586. * @group bar
  587. */
  588. class TheTest extends \PHPUnit\Framework\TestCase {}
  589. PHP,
  590. ];
  591. yield 'keep annotations' => [
  592. <<<'PHP'
  593. <?php
  594. class FooTest extends \PHPUnit\Framework\TestCase {
  595. /**
  596. * @copyright ACME Corporation
  597. * @dataProvider provideFooCases
  598. * @requires PHP ^8.2
  599. * @requires OS Linux|Darwin
  600. */
  601. #[\PHPUnit\Framework\Attributes\DataProvider('provideFooCases')]
  602. #[\PHPUnit\Framework\Attributes\RequiresPhp('^8.2')]
  603. #[\PHPUnit\Framework\Attributes\RequiresOperatingSystem('Linux|Darwin')]
  604. public function testFoo($x) { self::assertTrue($x); }
  605. public static function provideFooCases() { yield [true]; yield [false]; }
  606. }
  607. PHP,
  608. <<<'PHP'
  609. <?php
  610. class FooTest extends \PHPUnit\Framework\TestCase {
  611. /**
  612. * @copyright ACME Corporation
  613. * @dataProvider provideFooCases
  614. * @requires PHP ^8.2
  615. * @requires OS Linux|Darwin
  616. */
  617. public function testFoo($x) { self::assertTrue($x); }
  618. public static function provideFooCases() { yield [true]; yield [false]; }
  619. }
  620. PHP,
  621. [
  622. 'keep_annotations' => true,
  623. ],
  624. ];
  625. }
  626. /**
  627. * @param non-empty-list<'class'|'method'> $scopes
  628. *
  629. * @return array{string, string}
  630. */
  631. private static function createCase(array $scopes, string $expectedAttribute, string $inputAnnotation): array
  632. {
  633. $expectedAttribute = str_replace('#[', '#[\PHPUnit\Framework\Attributes\\', $expectedAttribute);
  634. return [
  635. \sprintf(
  636. <<<'PHP'
  637. <?php
  638. %s
  639. class FooTest extends \PHPUnit\Framework\TestCase {
  640. %s
  641. public function testFoo($x) {}
  642. %s
  643. public function testBar($x) {}
  644. }
  645. PHP,
  646. \in_array('class', $scopes, true)
  647. ? \sprintf("/**\n */\n%s", $expectedAttribute)
  648. : \sprintf("/**\n * %s\n */", $inputAnnotation),
  649. \in_array('method', $scopes, true)
  650. ? \sprintf("/**\n */\n %s", $expectedAttribute)
  651. : \sprintf("/**\n * %s\n */", $inputAnnotation),
  652. \in_array('method', $scopes, true)
  653. ? \sprintf("\n %s", $expectedAttribute)
  654. : \sprintf('/** %s */', $inputAnnotation),
  655. ),
  656. \sprintf(
  657. <<<'PHP'
  658. <?php
  659. /**
  660. * %s
  661. */
  662. class FooTest extends \PHPUnit\Framework\TestCase {
  663. /**
  664. * %s
  665. */
  666. public function testFoo($x) {}
  667. /** %s */
  668. public function testBar($x) {}
  669. }
  670. PHP,
  671. $inputAnnotation,
  672. $inputAnnotation,
  673. $inputAnnotation,
  674. ),
  675. ];
  676. }
  677. }