-
Notifications
You must be signed in to change notification settings - Fork 29
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
GetTypeDefinitionFor does not play nicely with runtime generated types (e.g. coverlet code coverage) #82
Comments
G'day @flakey-bit - sorry about the very late response here, I missed this issue 😞. I'll have a read this afternoon and get back to you. |
Okay, so, a fun, but complex problem. One tool uses Cecil to rewrite a module at runtime, and then another uses cecil to try and read module types at runtime. I'm not entirely sure where the bridges aren't meeting here - as you've pointed out, the type is discoverable from the module definition, which means the first tool has modified the module, and we are reading the modified module. I'm not sure if that is the problem to solve here though. We could either:
If we look at the second one, there is an opportunity to register a set of types globally you don't want inspected for any tests. These could be applied in https://github.com/andrewabest/Conventional/blob/master/src/Core/Conventional/Conformist.cs#L16-L35 to filter the set of types being inspected further. With the additional filtering, you wouldn't need to remember to exclude these whenever you picked up a certain type of convention. Would that work for you? |
Hey! Thanks for looking into this.
That certainly would be helpful 👍, however it would probably be more convenient if there was an overload that takes a type predicate (in particular, for the case of types that are generated at runtime). You can always write the overload that takes a set of types to exclude in terms of the type-predicate overload. |
Let me know if I can help out in any way with this 🙂 |
If you want to throw together a spike PR to help me understand your suggestion in a bit more detail we could take it from there. |
All I meant by a type predicate was a public static class ConventionConfiguration
{
public static Action<string> DefaultFailureAssertionCallback { get; set; }
// ...
public static Func<Type, bool> DefaultTypeFilter { get; set; } = t => true;
} where all types are passed through I think it's just the one method of public static WrappedConventionResult MustConformTo(this IEnumerable<Type> types, IConventionSpecification conventionSpecification)
{
var filteredTypes = types.Where(ConventionConfiguration.DefaultTypeFilter).ToArray();
return EnforceConformance(new WrappedConventionResult(
filteredTypes,
filteredTypes.Select(conventionSpecification.IsSatisfiedBy)));
} & public static async Task<WrappedConventionResult> MustConformTo(this IEnumerable<Type> types, IAsyncConventionSpecification conventionSpecification)
{
var filteredTypes = types.Where(ConventionConfiguration.DefaultTypeFilter).ToArray();
return Conformist.EnforceConformance(new WrappedConventionResult(
filteredTypes,
await Task.WhenAll(filteredTypes.Select(conventionSpecification.IsSatisfiedBy))));
} I guess a consideration is that this effectively hides things from |
I don't think that is necessary. We are just further filtering down the types under inspection. I understand what you are saying, but I think we could start without it, viewing it as a potential future optimisation if it bites anyone. |
@flakey-bit did you want to take a look at the PR I've pushed up to see if it will address your issue? |
I've taken a look at the PR - looks good, thanks for putting that together! It will address the issue 🙂 |
Apologies for the vague issue - we've been running into problems with conventions that use
GetTypeDefinitionFor
when types are emitted at runtime.As an example,
MustNotCallMethodConventionSpecification
(and anything that dervies from it) is affected.For us, the emitted types are coming from Coverlet.
Basically, you add a package reference to
coverlet.collector
to your test projects only and then run tests with data collection on and it spits out a code-coverage report.This code (which adds a module tracker) is responsible for emitting the types into the instrumented assembly.
When we run the tests normally (in the IDE or with
dotnet test
) everything is fine. It's when we run the tests with (Coverlet) data collection enableddotnet test --collect="XPlat Code Coverage"
that things break.
We see a test failure like this:
Note that the type it was looking for (
Coverlet.Core.Instrumentation.Tracker.MyCompany.MyApp.BFF.DTOs_cbb8ca5e-3732-4ccd-97be-dc8fcaf369f0
in the example above) was in the list "Types we can see" (and is evidently in the module definition).For whatever reason,
ModuleDefinition::GetType()
(Cecil) refuses to return theTypeDefinition
.We could work around it with something like
moduleDefinition.Types.Single(mt => mt.FullName == type.FullName);
, however that's missing the point - these generated types are an artefact of the tests running with code coverage on. Almost certainly, the fix is to exclude such types from convention checks.An example of a convention test (theory) we had problems with:
(
MustNotAccessNewRelicAgentStatically
is based onMustNotCallMethodConventionSpecification
).We can work-around the problem by further filtering the types (from the assembly) e.g.
Wondering if this is the best approach or whether the Conventional library could help out with this in some way - thoughts?
The text was updated successfully, but these errors were encountered: