Run Rector fixture cases and #[Group] from the gutter - #72
Merged
xepozz merged 8 commits intoAug 2, 2026
Conversation
Two attributes had no way into a run configuration.
`#[TestRectorFixtures]` marks a Rector rule as a test case: the bridge's harness discovers the
declared fixtures and runs each as a data set of one synthesized test. It gets its own group,
TEST_CASE_ATTRIBUTES, rather than joining TEST_ATTRIBUTES — that array drives
isPublicMethodOfTestoMarkedClass, so `refactor()` and `getRuleDefinition()` would have become
tests. A run started from the attribute narrows to `--type=rector-fixture`; running the class
itself stays untyped and keeps whatever the class holds. The same rule now applies to `#[Test]`
on a class (`--type=test` from the attribute, nothing from the class), which is why
findTestElement accepts an attribute whose owner is a Testo class instead of letting the context
fall back to the class and lose the type.
`#[Group]` is not a test but a selector, so it gets a marker branch of its own and a deliberately
unscoped configuration: ConfigurationFile scope, `--group=<name>` and nothing else — no path, no
name filter, no type. A variadic `#[Group('db', 'slow')]` keeps both names; the persisted
group/excludeGroup fields hold them comma-separated and the handler emits one flag per name,
which Testo ORs. The same fields in the editor now accept a list too.
Assisted-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Versions had drifted (Kotlin, platform SDK, Qodana, Kover, Gradle) and the file tree predated coverage/, the whole tests/console/ package, the history code vision and the util/ move. Beyond fixing that, it now records the things that are expensive to rediscover: the CLI contract (including that `--teamcity` in the default runner options is what makes Testo emit the service messages we parse), the `methodName` selector encoding, the php_qn:// location formats, and a gotchas section for constraints that were paid for in blood — the id-based tree, the channel storage keys, the two reflection sites, why imported history needs our own console properties. Assisted-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The persisted group/excludeGroup fields join several names with commas,
so a group whose own name contains one (#[Group('a,b')]) would split
into two --group flags. joinNames now escapes such commas as \, and
splitNames folds them back, keeping the name a single flag; the escape
never reaches the command line — Testo's --group is VALUE_IS_ARRAY and
does no comma splitting of its own.
Assisted-By: Claude Fable 5 <noreply@anthropic.com>
- A group-only run (ConfigurationFile scope, no config file) tripped the platform's "Configuration file is not specified" validation and never launched; TestoRunConfiguration.checkConfiguration now swallows exactly that error, matched by message so a platform rewording fails closed. - isConfigurationFromContext conflated typed and untyped class runs: an untyped class configuration was reused for a class-level attribute and vice versa, erasing the --type narrowing on the second run. The class comparison now includes testoType. - Running a class-level attribute of an abstract class skipped the inheritor chooser because findTestElement no longer falls back to the class; onFirstRun now unwraps the attribute's owner. - #[Group] without resolvable names no longer gets a gutter icon — the producer refuses such a context, so the icon offered a run that did nothing. - suggestedName no longer renames ApplicationConfig/SuiteConfig runs that happen to have a group typed into them. Assisted-By: Claude Fable 5 <noreply@anthropic.com>
roxblnfk
force-pushed
the
feat/rector-fixtures-and-group-gutter
branch
from
July 31, 2026 22:10
c4dcc13 to
6df9df9
Compare
A group name is free-form PHP, but three shapes of it silently misbehave downstream: a `!` prefix reads as an exclusion on the CLI, a comma is the separator of the run configuration's Group field, and blank or whitespace-padded names cannot be typed back into that field. #[Group] with no names at all selects nothing. The new TestoGroupName inspection surfaces each of these as a warning right on the attribute instead of letting the run quietly do the wrong thing. Constant/expression names are left alone — they cannot be judged statically. Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Three comments narrated the edit ("the branch below", "mirrors the
setup branch", "without this the context would fall back") instead of
stating the constraint. Same facts, said for the next reader.
Assisted-By: Claude Fable 5 <noreply@anthropic.com>
The comma is simply the separator of the persisted group field, and a group name containing one is now reported by TestoGroupNameInspection at the source instead of being silently re-encoded. splitNames is a plain split again; joinNames is gone. Assisted-By: Claude Opus 5 <noreply@anthropic.com>
The comma was the plugin's own invention: a group name is an opaque PHP string, and joining names into one persisted field made the separator part of the data model. TestoRunnerSettings now keeps groups and excludeGroups as @XCollection lists — the same mechanism PhpUnit's own runner settings use for test_patterns — so a name travels from #[Group] to the command line untouched. The comma survives only where a single text field genuinely cannot hold a list: the editor parses and renders it (parseNames/formatNames). Old configurations keep working — migrateLegacyNames folds a saved group="a,b" into the list on load and clears it, so the next save writes the new shape. TestoRunnerSettingsSerializationTest pins the persisted XML, since run configurations live in users' workspace.xml. Assisted-By: Claude Opus 5 <noreply@anthropic.com>
xepozz
approved these changes
Aug 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two attributes you couldn't run before.
#[TestRectorFixtures]— a Rector rule that declares fixtures is a test case now: gutter icon, test-file icon, no "unused" warnings. Running it from the attribute adds--type=rector-fixture. It got its own attribute group instead of joiningTEST_ATTRIBUTES, otherwise the rule's ownrefactor()andgetRuleDefinition()would have shown up as tests.#[Group]— running it means--group=<name>and nothing else: no path, no name filter, no type.#[Group('db', 'slow')]emits one flag per name, and the Group / Exclude group fields in the run configuration now take a comma-separated list too.Along the way the same rule got applied to
#[Test]on a class: from the attribute you get--type=test, from the class itself nothing — running a class should keep its#[Bench]methods.Inspection. A new
TestoGroupNameinspection warns on#[Group]names the toolchain cannot select cleanly: blank or whitespace-padded,!-prefixed (the CLI reads that as an exclusion), containing a comma (the separator of the run configuration's Group field), or no names at all. Names built from constants are left alone.Notable plumbing:
ConfigurationFilescope to keep path/filter flags off the command line, and the platform then demands a configuration file Testo doesn't need.TestoRunConfiguration.checkConfigurationswallows exactly that one error, matched by message — a platform rewording fails closed (the validation error merely comes back).isConfigurationFromContextcomparestestoType, so a run from#[Test]on a class and a run of the class itself get separate configurations instead of silently reusing one another.#[Group]without resolvable names gets no gutter icon — there is nothing such a run could select.Unit tests are green. The PSI tests fail, but they already do on
mainfor an unrelated reason ('filetype.java.module.display.name' is not foundinJavaPsiBundlekills everyBasePlatformTestCase), so the 21 new ones here can only be verified once that's fixed.🤖 Generated with Claude Code