-
-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Plugin system to allow pre-/post- filtering and modification of mutations #1323
Comments
Using $filteredMutations = [];
Observable::fromArray(
$arrayOfMutations,
Scheduler::getImmediate()
)->filter(
static fn (Mutation $mutation): bool => $mutation === $yay
)->toArray()->subscribe(
static function (array $mutations) use (&$filteredMutations): void
{
$filteredMutations = $mutations;
}
);
return $filteredMutations; |
I'd argue it'll be better to mark these as skipped, as we have this convenient status. Else they will skew the metrics towards better numbers. |
They're 100% killed, since the mutation is covered by some sort of formal verification (in my case, static analysis). Alternatively, they can be completely removed (not show up in any report at all) if we manage to build pre-filtering, but "skipped" would indicate that something needs to be done, which isn't the case. |
What's the goal of the post-filtering exactly? |
What is the specific use case for the post-filtering? As I see it, if something can be done during post-filtering, it can be done during pre-filtering. Is it not? |
@theofidry @sanmai performing heavy operations that are only worth doing on escaped mutants, for example. An example could be to run pre-existing property testing (expensive) on a mutant, but right now, static analysis is also quite slow for most unit test suites. |
IMO that would require a lot more than a post-filtering hook then. Because the current suggested hook provides a closed (already executed) process and not much more and is currently only used to create the results objects which are used for logging purposes – not something that offers much room for meddling atm. What you are suggesting, if I understand correctly, looks more fit to me as a "retry" or "complement execution" strategy for escaped mutants which could be interested but indeed requires a few architectural changes |
Looking back at this, inplementing pre-filtering/mapping as a start would suffice, leaving post-filtering/mapping for a later point in time. That's already solving all linked issues (for now) |
This would be a great feature, For instance it would avoid having mutation like
reported as uncovered when using phpstan/psalm |
Scope - third-party tools integration
The idea is relatively simple: some mutations don't make sense, according to other tools that are completely third-party to infection.
Such tools could say things like:
Hacks done so far
I've tinkered a lot on https://github.com/Roave/infection-static-analysis-plugin last week.
The tool currently operates through AOP by replacing the
Infection\Mutant\MutantExecutionResultFactory
service. Whenever a mutant result is produced, we analyze it, and decide whether it is valid as an escaped mutant through a third-party tool.If the third-party tool says that the mutation is invalid, it is marked as
KILLED
.Wished API
Plugins can be either very lightweight (#697, for example, is about adding a regex to a mutation) or very heavyweight (running complex static analysis, fuzzy-testing or property tests on top of a mutation).
Therefore, it makes sense to allow both
pre-
andpost-
filtering of mutations.Pre-filtering
The ideal location where pre-filtering could be done is inside
Infection\Process\Runner\MutationTestingRunner#run()
:infection/src/Process/Runner/MutationTestingRunner.php
Lines 90 to 124 in 25582f2
Here, we could have a replaceable filter for mutations with a signature like:
or
(reason for IO here is that external tools are gonna be shitty anyway: embrace the shittyness)
This is where static analysis could be plugged in, or #697 could be solved: invalid code mutations can be filtered with a very quick operation, saving a ton of CPU before runtime.
Note: we could also
->map()
here, to allow replacing aMutant
Post-filtering
Post-filtering is more tricky, because of how mutations are considered "done", and how mutation execution progress is tracked.
This happens through relatively ugly callbacks in
Infection\Process\Runner\MutationTestingRunner#run()
:infection/src/Process/Runner/MutationTestingRunner.php
Lines 117 to 128 in 25582f2
In
Infection\Process\Factory\MutantProcessFactory#createProcessForMutant()
this becomes even more muddy:infection/src/Process/Factory/MutantProcessFactory.php
Lines 95 to 106 in 25582f2
This is very un-manageable: I think it would make sense to use something like an
Observable
(/cc @WyriHaximus if you can help out with a suggestion here) to which we publish the completion of the process, rather than publishing to an event dispatcher.We can then filter said observable exactly like we did with the pre-filtering above:
or
Then:
Note: we could also
->map()
here, to allow replacing aMutantProcess
@internal
and backward compatibility promiseFew things in this issue require some added maintenance effort for @infection maintainers:
Container
API needs to become public: specifically for setting apre-
andpost-
filter callback:infection/src/Container.php
Lines 144 to 147 in 25582f2
Mutant
needs to become public API to some degreeinfection/src/Mutant/Mutant.php
Lines 41 to 45 in 25582f2
MutantProcess
API needs to become publicinfection/src/Process/MutantProcess.php
Lines 43 to 47 in 25582f2
That means that before working on this, there needs to be a clear idea by maintainers of the project whether those symbols can be made public, or whether more work needs to be done around them first (https://twitter.com/tfidry/status/1302896716065144833 /cc @theofidry )
The text was updated successfully, but these errors were encountered: