Skip to content

Commit

Permalink
Adding support for emitting against generic type contraints struct / …
Browse files Browse the repository at this point in the history
…unmanaged (#249)

* Adding support for emitting against generic type contraints struct / unmanaged

* Fixes to AutoMocker, fixing up unit test matrix

* Updating example
  • Loading branch information
mattwhitfield authored Jul 7, 2024
1 parent 4181137 commit a24b5ed
Show file tree
Hide file tree
Showing 13 changed files with 51 additions and 19 deletions.
3 changes: 3 additions & 0 deletions src/Unitverse.Core.Tests/Resources/UnmanagedConstraint.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public struct Foo<T> where T : unmanaged {
public void Bar() { }
}
11 changes: 11 additions & 0 deletions src/Unitverse.Core.Tests/TestClasses.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Unitverse.Core.Tests/TestClasses.resx
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@
<data name="TypeGenericDisambiguation" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\TypeGenericDisambiguation.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="UnmanagedConstraint" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\UnmanagedConstraint.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="UseConstructorForClassSetup" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\UseConstructorForClassSetup.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
Expand Down
19 changes: 12 additions & 7 deletions src/Unitverse.Core.Tests/UnitTestGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,22 @@ public static IEnumerable<object[]> TestClassResourceNames
entryKeys = entryKeys.Where(x => x.IndexOf("FileScoped", StringComparison.OrdinalIgnoreCase) < 0).ToList();
#endif

var baseSet = entryKeys.Cast<object>().ToArray()
.CrossJoin(frameworks)
var baseSet = entryKeys.Select(x => new List<object> { x });

var secondarySet = frameworks
.CrossJoin(mocks)
.CrossJoin(AssertionFrameworkVariations);
.CrossJoin(AssertionFrameworkVariations)
.CrossJoin(AutoFixtureVariations);

int autoFixtureRow = 0;
int secondaryRow = 0;
foreach (var row in baseSet)
{
autoFixtureRow++;
var autoFixtureValues = AutoFixtureVariations[autoFixtureRow % AutoFixtureVariations.Count];
yield return row.Concat(autoFixtureValues).ToArray();
for (int i = 0; i < 50; i++)
{
secondaryRow++;
var secondaryValues = secondarySet[secondaryRow % secondarySet.Count];
yield return row.Concat(secondaryValues).ToArray();
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Unitverse.Core/Frameworks/IMockingFramework.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ public interface IMockingFramework

ExpressionSyntax GetAssertionFor(IMethodSymbol dependencyMethod, string mockFieldName, SemanticModel model, IFrameworkSet frameworkSet, IEnumerable<string> parameters);

ExpressionSyntax? GetObjectCreationExpression(TypeSyntax typeSyntax);
ExpressionSyntax? GetObjectCreationExpression(TypeSyntax typeSyntax, bool isReferenceType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public TypeSyntax GetFieldType(TypeSyntax type)
return _targetFramework.GetFieldType(type);
}

public ExpressionSyntax GetObjectCreationExpression(TypeSyntax typeSyntax)
public ExpressionSyntax GetObjectCreationExpression(TypeSyntax typeSyntax, bool isReferenceType)
{
return AutoFixtureHelper.Create(typeSyntax, _context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private static ExpressionSyntax ACallTo(ExpressionSyntax methodCall)
return Generate.MemberInvocation("A", "CallTo", Generate.ParenthesizedLambdaExpression(methodCall));
}

public ExpressionSyntax? GetObjectCreationExpression(TypeSyntax type)
public ExpressionSyntax? GetObjectCreationExpression(TypeSyntax type, bool isReferenceType)
{
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private static ExpressionSyntax Mock(string methodName, ExpressionSyntax methodC
return Generate.MemberInvocation("Mock", methodName, Generate.ParenthesizedLambdaExpression(methodCall));
}

public ExpressionSyntax? GetObjectCreationExpression(TypeSyntax type)
public ExpressionSyntax? GetObjectCreationExpression(TypeSyntax type, bool isReferenceType)
{
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,16 @@ public override ExpressionSyntax GetFieldInitializer(TypeSyntax type)
return base.GetFieldInitializer(type);
}

public override ExpressionSyntax? GetObjectCreationExpression(TypeSyntax type)
public override ExpressionSyntax? GetObjectCreationExpression(TypeSyntax type, bool isReferenceType)
{
if (IsActive)
if (IsActive && isReferenceType)
{
_context.MocksUsed = true;
_context.CurrentMethod.AddRequirement(Requirements.AutoMocker);
return Generate.MemberInvocation("mocker", Generate.GenericName("CreateInstance", type));
}

return base.GetObjectCreationExpression(type);
return base.GetObjectCreationExpression(type, isReferenceType);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ private static ExpressionSyntax Mock(string actionName, string mockFieldName, Ex
return Generate.MemberInvocation(mockFieldName, actionName, SyntaxFactory.SimpleLambdaExpression(Generate.Parameter("mock"), methodCall));
}

public virtual ExpressionSyntax? GetObjectCreationExpression(TypeSyntax type)
public virtual ExpressionSyntax? GetObjectCreationExpression(TypeSyntax type, bool isReferenceType)
{
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public ExpressionSyntax GetAssertionFor(IMethodSymbol dependencyMethod, string m
return MockingHelper.GetMethodCall(dependencyMethod, received, MockingHelper.TranslateArgumentFunc(GetArgument, parameters), frameworkSet.Context);
}

public ExpressionSyntax? GetObjectCreationExpression(TypeSyntax type)
public ExpressionSyntax? GetObjectCreationExpression(TypeSyntax type, bool isReferenceType)
{
return null;
}
Expand Down
14 changes: 12 additions & 2 deletions src/Unitverse.Core/Generation/CompilationUnitStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ public void AddTypeParameterAliases(ClassModel classModel, IGenerationContext co

if (constraint != null)
{
var typeConstraints = constraint.Constraints.OfType<TypeConstraintSyntax>().Select(x => x.Type).Select(x => classModel.SemanticModel.GetTypeInfo(x)) ?? Enumerable.Empty<TypeInfo>();
ITypeSymbol[] constrainableTypes = typeConstraints.Select(x => x.Type).WhereNotNull().Where(x => !(x is IErrorTypeSymbol)).ToArray();
var typeConstraints = constraint.Constraints.OfType<TypeConstraintSyntax>().Select(x => x.Type);
var typeConstraintInfo = typeConstraints.Select(x => classModel.SemanticModel.GetTypeInfo(x)) ?? Enumerable.Empty<TypeInfo>();
ITypeSymbol[] constrainableTypes = typeConstraintInfo.Select(x => x.Type).WhereNotNull().Where(x => !(x is IErrorTypeSymbol)).ToArray();
if (constrainableTypes.Any())
{
derivedType = TypeHelper.FindDerivedNonAbstractType(constrainableTypes);
Expand All @@ -100,6 +101,15 @@ public void AddTypeParameterAliases(ClassModel classModel, IGenerationContext co
nameSyntax = SyntaxFactory.IdentifierName(derivedType.ToFullName());
}
}
else
{
var structOrUnmanaged = typeConstraints.OfType<IdentifierNameSyntax>().Select(x => x.Identifier.Text).Any(x =>
string.Equals(x, "struct", StringComparison.OrdinalIgnoreCase) || string.Equals(x, "unmanaged", StringComparison.OrdinalIgnoreCase));
if (structOrUnmanaged)
{
nameSyntax = SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName("System"), SyntaxFactory.IdentifierName("Int32"));
}
}
}

if (!context.GenericTypes.ContainsKey(parameter.Identifier.ValueText))
Expand Down
2 changes: 1 addition & 1 deletion src/Unitverse.Core/Models/ClassModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ public ExpressionSyntax GetObjectCreationExpression(IFrameworkSet frameworkSet,

if (forSetupMethod)
{
var mockedCreationExpression = frameworkSet.MockingFramework.GetObjectCreationExpression(TypeSyntax);
var mockedCreationExpression = frameworkSet.MockingFramework.GetObjectCreationExpression(TypeSyntax, TypeSymbol.IsReferenceType);
if (mockedCreationExpression != null)
{
return mockedCreationExpression;
Expand Down

0 comments on commit a24b5ed

Please sign in to comment.