Describe the solution you'd like
Right now, if Rocks encounters a type that it needs to generate code for (e.g. a pointer), it puts all that code into a Projections static class within the expectations class. However, this means that if a pointer type (e.g. int*) is encountered more than once in two different mock types, that code is generated for each mock type, even though it is identical.
What I could do is create models for projected code. Meaning, for each type that needs projected code (like delegates for callback or return types or custom Argument types), it would create a separate model + code file that would be in its own namespace. So, for example, if int* was used in a mock type, Rocks currently does something like this:
namespace MockTests
{
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal sealed class IHavePointersCreateExpectations
: global::Rocks.Expectations
{
internal static class Projections
{
internal unsafe delegate void Callback_675345066879799784342630291957923402524406707040(int* @value);
internal unsafe delegate bool ArgumentEvaluationForintPointer(int* @value);
internal unsafe sealed class ArgumentForintPointer
: global::Rocks.Argument
{
// ...argument implementation goes here....
}
}
internal sealed class Handler0
: global::Rocks.Handler<global::MockTests.IHavePointersCreateExpectations.Projections.Callback_675345066879799784342630291957923402524406707040>
{
public global::MockTests.IHavePointersCreateExpectations.Projections.ArgumentForintPointer @value { get; set; }
}
private global::Rocks.Handlers<global::MockTests.IHavePointersCreateExpectations.Handler0>? @handlers0;
// Other Rocks code-gen goes here...
}
}
What it would do instead is generate this separately:
namespace System
{
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal partial static class Projections
{
internal unsafe delegate void Callback_675345066879799784342630291957923402524406707040(int* @value);
internal unsafe delegate bool ArgumentEvaluationForintPointer(int* @value);
internal unsafe sealed class ArgumentForintPointer
: global::Rocks.Argument
{
// ...argument implementation goes here....
}
}
Then, the generated code would reference these types:
internal sealed class Handler0
: global::Rocks.Handler<global::System.Projections.Callback_675345066879799784342630291957923402524406707040>
{
public global::System.Projections.ArgumentForintPointer @value { get; set; }
}
private global::Rocks.Handlers<global::MockTests.IHavePointersCreateExpectations.Handler0>? @handlers0;
Since these would also be immutable models, they would only be generated once.
There would need to be further design work to determine if the generated Projections class should be partial (I'm going with that for now as there may be other types within that namespace that needs projections), along with figuring out how to create models with these types such that they're handled correctly by the compilation pipeline for caching purposes. Also, the namespace naming needs to be validated in terms of what is the "best" approach.
Describe the solution you'd like
Right now, if Rocks encounters a type that it needs to generate code for (e.g. a pointer), it puts all that code into a
Projectionsstatic class within the expectations class. However, this means that if a pointer type (e.g.int*) is encountered more than once in two different mock types, that code is generated for each mock type, even though it is identical.What I could do is create models for projected code. Meaning, for each type that needs projected code (like delegates for callback or return types or custom
Argumenttypes), it would create a separate model + code file that would be in its own namespace. So, for example, ifint*was used in a mock type, Rocks currently does something like this:What it would do instead is generate this separately:
Then, the generated code would reference these types:
Since these would also be immutable models, they would only be generated once.
There would need to be further design work to determine if the generated
Projectionsclass should bepartial(I'm going with that for now as there may be other types within that namespace that needs projections), along with figuring out how to create models with these types such that they're handled correctly by the compilation pipeline for caching purposes. Also, the namespace naming needs to be validated in terms of what is the "best" approach.