Skip to content

IBX-12606: Migrated the test suites to PHPUnit 11 - #831

Merged
ViniTou merged 20 commits into
6.0from
phpunit-11
Sep 18, 2026
Merged

ViniTou merged 20 commits into
6.0from
phpunit-11

Conversation

@ViniTou

@ViniTou ViniTou commented Sep 15, 2026

Copy link
Copy Markdown
Contributor
🎫 Issue IBX-12606
--- ---

Description:

Merge order / consumers: several wave PRs are red only because they inherit core's shared test bases (BaseFieldTypeTestCase, Limitation\Base, BaseIntegrationTestCase/SearchBaseIntegrationTestCase, FieldType/*IntegrationTest::findProvider()), which this PR makes PHPUnit-11-compatible. Merge this first; then ibexa/connector-dam#108, ibexa/workflow#211, ibexa/solr#122, ibexa/personalization#428, ibexa/product-catalog#1599 go green on rerun, and ibexa/fieldtype-richtext must flip six provider overrides in tests/integration/Repository/RichTextFieldTypeIntegrationTest.php (provideInvalidCreationFieldData, provideInvalidUpdateFieldData, provideToHashData, provideFromHashData, providerForTestIsEmptyValue, providerForTestIsNotEmptyValue) to static; richtext#352 does not contain that change yet and will get it once this merges. Rebased onto current 6.0, which now includes #822 (DefaultRouterTest rewrite), #833 (stale @depends targets and outdated ContentService assertions, fixed from 5.0) and IBX-6773 (#476, bookmarks) — their test changes are carried here in PHPUnit 11 form (attributes, static providers).

  • Migrates phpunit/phpunit ^9.6^11.5 and matthiasnoback/symfony-dependency-injection-test
    ^5.0^6.0 (symfony/phpunit-bridge stayed ^7.4, dama/doctrine-test-bundle stayed ^8.0,
    both already correct). Migrated all 4 PHPUnit configs (phpunit.xml, phpunit-integration.xml,
    phpunit-integration-legacy.xml, phpunit-integration-legacy-solr.xml) to the 11.5 schema.
    .gitignore already had .phpunit.cache//.phpunit.result.cache.

  • Rector (PHPUNIT_100, PHPUNIT_110, ANNOTATIONS_TO_ATTRIBUTES) converted 680 files
    (tests/lib 429, tests/bundle 93, tests/integration 158); composer fix-cs touched 138 more.
    WithConsecutiveRector auto-converted nearly all 48 baseline ->withConsecutive() sites into the
    $matcher = self::exactly(N); ->willReturnCallback(...) idiom, except two sites where the source
    had withConsecutive()/willReturnOnConsecutiveCalls() as separate chained calls — Rector merged
    the argument assertions but silently dropped the return-value logic, causing TypeErrors in two
    shared base classes (AbstractInMemoryCacheHandlerTestCase, AbstractCacheHandlerTestCase,
    TrashHandlerTest, IOVariationPurgerTest, ImageFileVariationPurgerTest) that had to be
    restored by hand.

  • self::at() removal — 230 call sites across 33 files (the task's own pattern-inventory said
    "a few"; the actual repo usage is spelled self::at(, not ->at(). Converted to the
    $matcher = self::exactly(N)/self::once() + willReturnCallback idiom, including a
    global-cross-method-invocation-order variant (a shared incrementing counter across two
    differently-named mocked methods) in FieldHandlerTest, RelationProcessorTest, PermissionTest.

  • setMethods() restoration — 69 call sites, resolved by reading PHPUnit's own
    Generator::generateCodeForTestDoubleClass() source (9.6 vs 11.5) rather than guessing: for a
    class target, setMethods(null) = mock nothing (→ onlyMethods([])), setMethods([]) = mock
    everything (→ Rector's deletion was correct), setMethods([...]) = partial mock (→
    onlyMethods([...])); for an interface target, Rector's unconditional deletion is always safe.
    A handful of call sites passed method names that don't exist on the real class (old setMethods()
    silently tolerated this; onlyMethods() throws CannotUseOnlyMethodsException) — fixed with
    addMethods() for the non-existent names, split from onlyMethods() for the real ones.

  • Non-static data providers — statified across ~120 files in tests/lib and
    tests/integration, following the "yield scalars/plain data, build the mock or call the
    repository in the consuming test method" pattern throughout:

    • tests/lib/MVC/Symfony/Matcher/ContentBased/{Id,Identifier}/*Test.php (11 files sharing a
      near-identical matchLocationProvider()/matchContentInfoProvider() shape), Limitation/*,
      voters, PermissionCriterionResolverTest (280-line provider with heavy inline mock
      construction), RelationProcessorTest, ContentTest, PermissionTest (6 providers).
    • Shared bases: BaseFieldTypeTestCase, BaseNumericValidatorTestCase, AbstractServiceTestCase,
      BaseRepositoryFilteringTestCase (this one was an actual PHP fatal at class-load time — a
      half-fixed override was already static while the base wasn't).
    • BackgroundIndexingTerminateListenerTest additionally used self::returnValue() statically,
      which is non-static in PHPUnit 11 — rewritten to willReturn()/willReturnCallback().
    • Empty-provider-as-skip: PHPUnit\Framework\Assert::markTestSkipped() inside a static
      #[DataProvider] is wrapped into a hard InvalidDataProviderException, not a clean skip (root
      cause traced to DataProvider::dataProvidedByMethods() wrapping any Throwable) — fixed with a
      sentinel data row + an explicit skip check inside the consuming test method
      (BaseFieldTypeTestCase, AbstractServiceTestCase, SearchBaseIntegrationTestCase's
      full-text-search provider, CheckboxIntegrationTest::providerForTestIsEmptyValue()).
    • Integration SearchBaseIntegrationTestCase/SearchMultivaluedBaseIntegrationTestCase: a
      much larger blocker than the FieldType-provider pattern elsewhere — findProvider(),
      sortProvider(), fullTextFindProvider(), findMultivaluedProvider() and their supporting
      getSearchTargetValue*()/getValidSearchValue*()/getAdditionallyIndexedFieldData() helpers
      (shared by ~30 FieldType integration test classes) resolve a live Repository at provider time
      to look up fixed system reference data (content types, sections). Added
      BaseTestCase::resolveSetupFactory()/resolveRepository() static-safe variants (mirroring the
      existing instance-cached getSetupFactory()/getRepository() — same env-var/factory
      resolution, just without the per-instance cache, since a provider has no instance to cache on)
      and rewired ~40 files' search-value/target helpers to use them. One resulting bug caught and
      fixed: a helper statified for provider use (RolePolicyLimitationTest) was still called,
      unstatified, from inside the actual test method after the test had created its own role/user
      fixtures — reusing the static, uncached repository resolver there wiped that just-created state
      (getRepository(true) always reinitializes the schema). Split into two methods: the original
      instance-cached one for the test body, a new *ForFreshRepository() static one for the
      provider only.
    • Also fixed the SAME static/non-static mismatch (introduced by the same Rector pass, unrelated
      to FieldType) in tests/integration/Core/Repository/SearchService/Aggregation/* (9 files) and
      a dozen more scattered tests/integration/Core/Repository/* providers
      (RoleServiceTest, PermissionResolverTest, PureNegativeQueryTest, RemoteIdIndexingTest,
      SearchServiceImageTest, SearchServiceContentNameTest, RoleLimitationTest,
      ContentLimitationsMixIntegrationTest, SearchServiceTest's remaining 5 providers) — these
      were causing a hard PHP fatal that killed the entire integration suite before any test ran,
      not something scoped to this migration's task brief but blocking composer integration
      entirely.
  • #[DependsExternal(...)] same-namespace double-resolution bug — 210 sites across 18 files
    in tests/integration/Core/Repository/: an unqualified, fully-spelled FQCN class-const reference
    inside the attribute (no use import, no leading \) gets the current namespace prepended by
    PHP, producing Ibexa\Tests\Integration\Core\Repository\Ibexa\Tests\Integration\Core\Repository\XTest
    and a "this test depends on ... which does not exist" error. A prior session's checkpoint fixed
    only the self-reference case (self::class); this pass added a leading \ for the remaining
    cross-class, same-namespace references.

  • Stale @param/@covers/@uses docblocks surfaced as real errors once Rector turned them into
    attributes (previously inert free text, tolerated by PHPUnit 9's plain-comment parsing):
    14 MVC/Symfony/Matcher/ContentBased/* files kept @param \...\Location $location docblocks
    from before an earlier session's provider refactor moved mock construction into the test body
    (removed, redundant with the native int $contentId type hint); 5 files had a @covers/@uses
    annotation whose trailing free-text prose got swallowed into the attribute's string argument by
    Rector's conversion (BaseTestCase::createCustomUserVersion1 → real UsesMethod, two
    EZP20018*Test regression tests, DynamicPathFilesystemAdapterDecoratorTest); 3 more had a
    pre-existing (present in origin/6.0 already) wrong-namespace @covers target that was harmless
    as a doc comment but a hard class.notFound once attributed
    (LocationArgumentResolverTest...\Converter\... instead of ...\ControllerArgumentResolver\...;
    DoctrineDatabaseTest → global-namespace \DoctrineDatabase instead of the imported class;
    ContentHandlerTest's #[CoversMethod]Contracts\Core\... instead of Core\...).

  • PHPStan: pruned ~39 stale baseline entries whose underlying code (self::at()/setMethods/provider
    patterns) no longer exists; ~26 sites needed array_values() around an array_diff()/
    array_filter() result passed to onlyMethods()/addMethods() (PHPUnit 11's signature is
    list<non-empty-string>, stricter than 9's plain array). Remaining ~84 new baseline entries are
    PHPUnit-11 API-surface changes matching the wave's established precedent for the same repo-wide
    issue classes: mock ->expects() called on an interface-typed variable PHPStan won't widen to
    &MockObject, varTag.nativeType mismatches on mocked properties, two confirmed-safe
    variable.undefined: $this false positives in a closure deferred-bound after construction
    (SiteAccessAware/SearchServiceTest, UrlAliasServiceTest), and onlyMethods() list-strictness
    on parameter-typed (not just array-diff'd) method-name arrays this session didn't touch the
    bodies of. No new ignores added beyond what --generate-baseline produced from these
    PHPUnit-11-caused findings; getMockForAbstractClass() deprecations (97 baseline hits,
    unchanged) are left for the PHPUnit 12 step per the wave's convention.

  • composer check-cs: 0 of 3378 files need fixing (one static_lambda fix applied along the way).
    vendor/bin/rector process --dry-run --clear-cache: clean (only a pre-existing, unrelated
    deprecated-skip-rule warning). composer deptrac: 0 violations, 0 errors/warnings (97
    pre-existing skipped violations, baseline unchanged — no abstract *Test.php bases were renamed
    in this repo, so no FQCN keys needed updating). No removed PHPUnit CLI flags (-v/--verbose)
    in composer.json scripts or .github/workflows/*.yaml.

  • Unit suite (composer unit --display-phpunit-deprecations): 7510 tests, 0 failures/errors,
    1 risky (DownloadControllerTestsymfony/phpunit-bridge's ExpectDeprecationTrait sets a
    static error handler restored by the bridge's own listener lifecycle, not by test code; confirmed
    not fixable from test code), 2520 PHPUnit deprecations (all forward-looking PHPUnit-12 removals —
    getMockForAbstractClass(), ->will($this->returnValue())/returnCallback()/returnValueMap()/
    onConsecutiveCalls(), stub-with-expects() — a much larger count than the wave's smaller repos
    since core's test suite predates all of them; left for the PHPUnit 12 migration per precedent).

  • Integration suite (phpunit-integration-legacy.xml, SQLite): 11417 tests — exactly matches
    the Stage-0 baseline test count
    , 0 failures, only the 5 pre-existing #[Depends]-on-
    renamed/removed-method errors already present and documented at Stage 0
    (ContentServiceTest::testLoadContentDrafts/loadRelationList no longer exist), 1 pre-existing
    risky fixed along the way (BinaryBaseStorageTest — dropped a contradictory
    expectNotToPerformAssertions()). phpunit-integration.xml (modern) is still red at the
    bootstrap step with the exact IBX-12530 UNIQUE constraint failed: ibexa_content_field.id error,
    unchanged from Stage 0 and owned by ibexa/test-core, not by this migration.

  • Carried the tests from IBX-6773 (IBX-6773: Fixed loading Bookmarks for non-accessible content items #476) and [Tests] Fixed stale @depends targets and outdated assertions in ContentService integration tests #833 into PHPUnit 11 form during the rebase: the new
    IsBookmarkedQueryBuilderTest, IdSortClauseQueryBuilderTest and the isBookmarkedProvider()
    providers in ContentFilteringTest/LocationFilteringTest needed static providers + attributes,
    and IdSortClauseQueryBuilderTest used DriverManager::getConnection(['url' => …]) and
    QueryBuilder::getQueryPart(), both gone in DBAL 4 — rewritten with getSQL()-based assertions
    preserving the original intent.

  • Review follow-ups (separate commits on top of the migration commit): constructor overrides removed
    from the two Regression/EZP* classes; ParentContentTypeLimitationTypeTest uses exactly(N)
    expectations for multi-target rows; all #[CoversMethod] attributes replaced by deduplicated
    #[CoversClass] pointing at the Ibexa\Core\* implementations (PHPUnit 11 rejects interface
    targets; verified by reflection); test-double properties use native X&Stub/X&MockObject
    types with imported classes; typed constants for the new sentinels; URLCheckerTest handlers
    are mocks (stubs do not verify expectations); ObjectStateHandlerTest::testDeleteGroup asserts
    the recorded call sequence; the last docblock @dataProvider/@depends/@covers/@group
    annotations (files Rector skipped, incl. traits) converted to attributes.

  • Not in this PR: the deprecation gate. SYMFONY_DEPRECATIONS_HELPER thresholds are dead under
    PHPUnit 10+ (also with phpunit-bridge 8.0); the PHPUnit-native replacement (failOnDeprecation

    • ignoreSuppressionOfDeprecations + restricted <source> with a generated baseline) has to
      land in every wave repo at once and follows in a second pass after CI is unblocked.

For QA:

N/A

Documentation:

N/A

@mikadamczyk mikadamczyk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • Rector kept the old @covers strings verbatim, so ~350 CoversMethod attributes in 34 files still have parentheses or a parameter list in the method name, e.g ContentServiceAuthorizationTest.php:30: 'createContent($contentCreateStruct, $locationCreateStructs)'. PHPUnit 11 errors on this once coverage is collected (CI runs without coverage, hence green). Do we fix it here or leave it for a follow-up?
  • many CoversClass/CoversMethod targets point at Ibexa\Contracts\Core\Repository\* interfaces or at the wrong class, e.g.
    #[CoversMethod(CoveredContentService::class, '__construct')]
    covers the ContentService interface, which has
    no mapFieldsForCreate. PHPUnit 11 rejects interface targets and missing methods once coverage runs. The description mentions fixing wrong @covers targets, so should these be pointed at the Ibexa\Core\Repository\* implementations here, or left for a follow-up?
  • richtext 6.0 still has six non-static overrides of hooks made static here, e.g. https://github.com/ibexa/fieldtype-richtext/blob/6.0/tests/integration/Repository/RichTextFieldTypeIntegrationTest.php#L274, and richtext#352 does not
    touch them. Could we fix the merge-order note?


class EZP22612URLAliasTranslations extends BaseTestCase
{
public function __construct()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This constructor drops the test method name PHPUnit passes in, so the test cannot run. It goes unnoticed only because the file lacks the Test suffix and is never discovered. Could we remove it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 8a125e6. The override was added in this PR and replaced the test name PHPUnit passes in; EZP22840RoleLimitations has the same override and is handled in a separate commit.

@@ -458,27 +460,31 @@ public function providerForTestEvaluate()
protected function assertContentHandlerExpectations($callNo, $persistenceCalled, $contentId, $contentInfo)
{
$this->getPersistenceMock()
->expects(self::at($callNo + ($persistenceCalled ? 1 : 0)))
->expects(self::once())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

once() is registered per target on the same mock method (also 463, 468, 516). With two or more targets the first call violates the other with() and fails; it passes only because every provider row has one target. Could we use exactly(count($targets)) with willReturnCallback, like the other conversions in this PR?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in b402202. Both handler methods now use one exactly(count) expectation with willReturnCallback keyed on the invocation number, and a two-target LocationCreateStruct provider row was added so the multi-target path is exercised.


class ContextualizerTest extends TestCase
{
private const SA_NODE_NAME = 'heyho';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
private const SA_NODE_NAME = 'heyho';
private const string SA_NODE_NAME = 'heyho';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 00bcef6.

Comment on lines +43 to +44
/** @var \PHPUnit\Framework\MockObject\Stub&\Symfony\Component\Console\Command\Command */
private \PHPUnit\Framework\MockObject\Stub $command;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

use Symfony\Component\Console\Command\Command;
use PHPUnit\Framework\MockObject\Stub;

Suggested change
/** @var \PHPUnit\Framework\MockObject\Stub&\Symfony\Component\Console\Command\Command */
private \PHPUnit\Framework\MockObject\Stub $command;
private Command & Stub $command;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 3bafc39. Applied to every property in tests/ that carried the real type only in a docblock, 18 properties in 15 files, and the 5 properties whose docblock said intersection while the native type was plain got the intersection type as well.

Comment on lines +33 to +34
/** @var \PHPUnit\Framework\MockObject\Stub&\Symfony\Component\HttpKernel\HttpKernelInterface */
private \PHPUnit\Framework\MockObject\Stub $httpKernel;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 3bafc39.

Comment on lines +26 to +27
/** @var \PHPUnit\Framework\MockObject\Stub&\Symfony\Component\HttpKernel\HttpKernelInterface */
private \PHPUnit\Framework\MockObject\Stub $httpKernel;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 3bafc39.

Comment on lines +26 to +33
/** @var \PHPUnit\Framework\MockObject\Stub&\Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface */
private \PHPUnit\Framework\MockObject\Stub $configResolver;

/** @var \PHPUnit\Framework\MockObject\MockObject */
private $router;
/** @var \PHPUnit\Framework\MockObject\Stub&\Symfony\Component\Routing\RouterInterface */
private \PHPUnit\Framework\MockObject\Stub $router;

/** @var \PHPUnit\Framework\MockObject\MockObject|\Psr\Log\LoggerInterface */
private $logger;
/** @var \PHPUnit\Framework\MockObject\Stub&\Psr\Log\LoggerInterface */
private \PHPUnit\Framework\MockObject\Stub $logger;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 3bafc39.

Comment on lines +42 to +43
/** @var \Ibexa\Core\FieldType\Validator\FileExtensionBlackListValidator&\PHPUnit\Framework\MockObject\Stub */
protected \PHPUnit\Framework\MockObject\Stub $fileExtensionBlackListValidatorMock;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 3bafc39.

private UrlRedecoratorInterface & MockObject $redecorator;

private PathGenerator & MockObject $pathGenerator;
private PathGenerator&\PHPUnit\Framework\MockObject\Stub $pathGenerator;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't be here and below:

use \PHPUnit\Framework\MockObject\Stub;

Suggested change
private PathGenerator&\PHPUnit\Framework\MockObject\Stub $pathGenerator;
private PathGenerator&Stub $pathGenerator

?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 068e27e, including the other properties in this file.

* field type has no "empty" representation, since PHPUnit 11 treats an empty data provider
* as a hard error rather than a skip.
*/
protected const NO_EMPTY_VALUE_DATA = '__no_empty_value_data__';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should be moved up - under the class declaration

Suggested change
protected const NO_EMPTY_VALUE_DATA = '__no_empty_value_data__';
protected const string NO_EMPTY_VALUE_DATA = '__no_empty_value_data__';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 5c06464. NO_DATA_METHOD in AbstractServiceTestCase got the same treatment.

/** @var \Ibexa\Core\Persistence\Legacy\Content\Language\Handler&\PHPUnit\Framework\MockObject\MockObject */
private Handler $contentLanguageHandler;
/** @var \Ibexa\Core\Persistence\Legacy\Content\Language\Handler&\PHPUnit\Framework\MockObject\Stub */
private \PHPUnit\Framework\MockObject\Stub $contentLanguageHandler;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
private \PHPUnit\Framework\MockObject\Stub $contentLanguageHandler;
private Handler & Stub $contentLanguageHandler;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 3bafc39.

@@ -23,12 +23,12 @@ final class RelationListFacadeTest extends TestCase

private RelationListFacade $relationListFacade;

private VersionInfo&MockObject $versionInfo;
private VersionInfo&\PHPUnit\Framework\MockObject\Stub $versionInfo;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
private VersionInfo&\PHPUnit\Framework\MockObject\Stub $versionInfo;
private VersionInfo & Stub $versionInfo;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 068e27e.

public function __construct()
{
parent::__construct(static::class);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in c8dec07.

@alongosz alongosz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

General finding:

Three files were never converted. HTTPHandlerTest still uses docblock @dataProvider at three places; UniqueIdentifierTest and MultiLanguageTestTrait likewise escaped the Rector pass.

Comment thread tests/bundle/Core/URLChecker/URLCheckerTest.php Outdated
Comment thread phpunit.xml
Comment thread tests/integration/Core/Repository/SettingServiceTest.php Outdated
Comment thread tests/lib/Persistence/Legacy/Content/ObjectState/ObjectStateHandlerTest.php Outdated
@ViniTou

ViniTou commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

Review points addressed in separate commits:

  • Parameter lists stripped from 347 CoversMethod names: 69dbf94.
  • 554 CoversClass/CoversMethod targets pointing at Ibexa\Contracts* interfaces retargeted to the Ibexa\Core* implementations declaring the methods, 5 stale or duplicate targets dropped, 3 method-name typos fixed; verified by reflection, 772 targets, 0 interfaces, 0 missing methods: f2828de.
  • Merge-order note corrected in the description: richtext has six non-static overrides in tests/integration/Repository/RichTextFieldTypeIntegrationTest.php, richtext#352 does not contain that change yet.

@ViniTou

ViniTou commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

Remaining docblock annotations converted in 71e0c1e: HTTPHandlerTest (covers, 3 data providers), UniqueIdentifierTest (covers), MultiLanguageTestTrait (4 depends), RelationSearchBaseIntegrationTestTrait (groups moved to the two consuming classes, including the previously unlisted relation group). rg for @dataProvider/@depends/@covers/@group in tests/ now returns only a prose mention.

@ciastektk ciastektk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ given how heavy this PR already is and how difficult is to reviewing all of these changes.

Following things could be improved as follow-ups:

  • Deprecation gate: phpunit-bridge's bootstrap bails out early on PHPUnit 10+, so SYMFONY_DEPRECATIONS_HELPER is effectively dead now and CI no longer tracks Symfony deprecations. I know it's planned as an org-wide pass, but I'd like to see it tracked somewhere so it doesn't get lost. The leftover env entries in the phpunit*.xml files can go at the same time.
  • PHPUnit 12 prep: will(self::returnValue()), getMockForAbstractClass() and the numberOfInvocations() blocks. A lot of the latter could just be willReturnMap() where order doesn't matter, which would also help with Sonar.
  • Return types on tests Most test methods still lack : void and the related data providers have no return type.
  • ParentDepthLimitationTypeTest has the same once()-in-foreach issue as the one fixed here. Pre-existing, so not for this PR.
  • The two EZP* regression tests still have no Test suffix and never run. Renaming them will tell us if they even pass.
  • RelationIntegrationTest covers BaseIntegrationTestCase — a test base class as a coverage target makes no sense, it's leftover from an old @covers.
  • Test double typing consistency — the pre-existing docblock-only intersections and static:: in final test classes. Might be worth adding self_static_accessor to ibexa/code-style so it stays that way.

@ViniTou

ViniTou commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Deprecation gate: phpunit-bridge's bootstrap bails out early on PHPUnit 10+, so SYMFONY_DEPRECATIONS_HELPER is effectively dead now and CI no longer tracks Symfony deprecations. I know it's planned as an org-wide pass, but I'd like to see it tracked somewhere so it doesn't get lost. The leftover env entries in the phpunit*.xml files can go at the same time.

this is already not tracked, there is limit at 850 in core and the actual number is two order lower.

PHPUnit 12 prep:

this will just introduce additional mess.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
8.2% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@ViniTou
ViniTou merged commit 0adcb7d into 6.0 Sep 18, 2026
12 of 13 checks passed
@ViniTou
ViniTou deleted the phpunit-11 branch September 18, 2026 09:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants