diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs index 7937772..24957f5 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs @@ -22,12 +22,12 @@ internal abstract class BaseGenerator protected string GetPropertyType(IPropertySymbol property, out bool isReplaced) { - return GetReplacedType(property.Type, out isReplaced); + return GetReplacedTypeAsString(property.Type, out isReplaced); } protected string GetParameterType(IParameterSymbol property, out bool isReplaced) { - return GetReplacedType(property.Type, out isReplaced); + return GetReplacedTypeAsString(property.Type, out isReplaced); } protected bool TryFindProxyDataByTypeName(string type, [NotNullWhen(true)] out ProxyData? proxyData) @@ -112,7 +112,7 @@ internal abstract class BaseGenerator { if (replaceIt) { - constraints.Add(GetReplacedType(namedTypeSymbol, out _)); + constraints.Add(GetReplacedTypeAsString(namedTypeSymbol, out _)); } else { @@ -136,7 +136,7 @@ internal abstract class BaseGenerator return false; } - protected string GetReplacedType(ITypeSymbol typeSymbol, out bool isReplaced) + protected string GetReplacedTypeAsString(ITypeSymbol typeSymbol, out bool isReplaced) { isReplaced = false; @@ -153,30 +153,39 @@ internal abstract class BaseGenerator return existing.FullInterfaceName; } - if (typeSymbol is INamedTypeSymbol namedTypedSymbol) + ITypeSymbol[] typeArguments; + if (typeSymbol is INamedTypeSymbol namedTypedSymbol1) { - var propertyTypeAsStringToBeModified = typeSymbolAsString; - foreach (var typeArgument in namedTypedSymbol.TypeArguments) - { - var typeArgumentAsString = typeArgument.ToString(); - - if (TryFindProxyDataByTypeName(typeArgumentAsString, out var existingTypeArgument)) - { - isReplaced = true; - - if (!Context.ReplacedTypes.ContainsKey(typeArgumentAsString)) - { - Context.ReplacedTypes.Add(typeArgumentAsString, existingTypeArgument.FullInterfaceName); - } - - propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(typeArgumentAsString, existingTypeArgument.FullInterfaceName); - } - } - - return propertyTypeAsStringToBeModified; + typeArguments = namedTypedSymbol1.TypeArguments.ToArray(); + } + else if (typeSymbol is IArrayTypeSymbol arrayTypeSymbol) + { + typeArguments = new[] { arrayTypeSymbol.ElementType }; + } + else + { + return typeSymbolAsString; } - return typeSymbolAsString; + var propertyTypeAsStringToBeModified = typeSymbolAsString; + foreach (var typeArgument in typeArguments) + { + var typeArgumentAsString = typeArgument.ToString(); + + if (TryFindProxyDataByTypeName(typeArgumentAsString, out var existingTypeArgument)) + { + isReplaced = true; + + if (!Context.ReplacedTypes.ContainsKey(typeArgumentAsString)) + { + Context.ReplacedTypes.Add(typeArgumentAsString, existingTypeArgument.FullInterfaceName); + } + + propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(typeArgumentAsString, existingTypeArgument.FullInterfaceName); + } + } + + return propertyTypeAsStringToBeModified; } protected bool TryGetNamedTypeSymbolByFullName(TypeKind kind, string name, IEnumerable usings, [NotNullWhen(true)] out ClassSymbol? classSymbol) diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs index e183c8b..209611f 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs @@ -135,7 +135,7 @@ using System; str.AppendLine($" {attribute}"); } - str.AppendLine($" {GetReplacedType(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement};"); + str.AppendLine($" {GetReplacedTypeAsString(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement};"); str.AppendLine(); } diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs index 7c2c5e7..176a28e 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs @@ -222,7 +222,7 @@ using System; overrideOrVirtual = "virtual "; } - string returnTypeAsString = GetReplacedType(method.ReturnType, out var returnIsReplaced); + string returnTypeAsString = GetReplacedTypeAsString(method.ReturnType, out var returnIsReplaced); var whereStatement = GetWhereStatementFromMethod(method); @@ -348,7 +348,7 @@ using System; var operatorType = @operator.Name.ToLowerInvariant().Replace("op_", string.Empty); if (operatorType == "explicit") { - var returnTypeAsString = GetReplacedType(@operator.ReturnType, out _); + var returnTypeAsString = GetReplacedTypeAsString(@operator.ReturnType, out _); str.AppendLine($" public static explicit operator {returnTypeAsString}({proxyClassName} {parameter.Name})"); str.AppendLine(@" {"); @@ -357,7 +357,7 @@ using System; } else { - var returnTypeAsString = GetReplacedType(parameter.Type, out _); + var returnTypeAsString = GetReplacedTypeAsString(parameter.Type, out _); str.AppendLine($" public static implicit operator {proxyClassName}({returnTypeAsString} {parameter.Name})"); str.AppendLine(@" {"); diff --git a/src/ProxyInterfaceSourceGenerator/ProxyInterfaceSourceGenerator.csproj b/src/ProxyInterfaceSourceGenerator/ProxyInterfaceSourceGenerator.csproj index cef8174..66f3306 100644 --- a/src/ProxyInterfaceSourceGenerator/ProxyInterfaceSourceGenerator.csproj +++ b/src/ProxyInterfaceSourceGenerator/ProxyInterfaceSourceGenerator.csproj @@ -1,7 +1,7 @@ - 0.0.29 + 0.0.30 netstandard2.0 {12344228-91F4-4502-9595-39584E5ABB34} 10 diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles.verified.txt b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles.verified.txt new file mode 100644 index 0000000..7c8cf35 --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles.verified.txt @@ -0,0 +1,118 @@ +[ + { + HintName: ProxyInterfaceGenerator.ProxyAttribute.g.cs, + Source: +//---------------------------------------------------------------------------------------- +// +// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//---------------------------------------------------------------------------------------- + +using System; + +namespace ProxyInterfaceGenerator +{ + [AttributeUsage(AttributeTargets.Interface)] + public class ProxyAttribute : Attribute + { + public Type Type { get; } + public bool ProxyBaseClasses { get; } + + public ProxyAttribute(Type type, bool proxyBaseClasses = false) + { + Type = type; + ProxyBaseClasses = proxyBaseClasses; + } + } +} + }, + { + HintName: ProxyInterfaceSourceGeneratorTests.Source.IFoo.g.cs, + Source: +//---------------------------------------------------------------------------------------- +// +// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//---------------------------------------------------------------------------------------- + +#nullable enable +using System; + +namespace ProxyInterfaceSourceGeneratorTests.Source +{ + public partial interface IFoo + { + ProxyInterfaceSourceGeneratorTests.Source.Foo _Instance { get; } + + ProxyInterfaceSourceGeneratorTests.Source.IFoo[] Foos { get; set; } + + + + ProxyInterfaceSourceGeneratorTests.Source.IFoo[] DoSomethingAndGetAnArrayOfFoos(); + + + + + } +} +#nullable disable + }, + { + HintName: ProxyInterfaceSourceGeneratorTests.Source.FooProxy.g.cs, + Source: +//---------------------------------------------------------------------------------------- +// +// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//---------------------------------------------------------------------------------------- + +#nullable enable +using System; + +namespace ProxyInterfaceSourceGeneratorTests.Source +{ + public partial class FooProxy : IFoo + { + public ProxyInterfaceSourceGeneratorTests.Source.Foo _Instance { get; } + + + public ProxyInterfaceSourceGeneratorTests.Source.IFoo[] Foos { get => Mapster.TypeAdapter.Adapt(_Instance.Foos); set => _Instance.Foos = Mapster.TypeAdapter.Adapt(value); } + + + + public ProxyInterfaceSourceGeneratorTests.Source.IFoo[] DoSomethingAndGetAnArrayOfFoos() + { + var result_1603865878 = _Instance.DoSomethingAndGetAnArrayOfFoos(); + return Mapster.TypeAdapter.Adapt(result_1603865878); + } + + + + + + + + public FooProxy(ProxyInterfaceSourceGeneratorTests.Source.Foo instance) + { + _Instance = instance; + + + Mapster.TypeAdapterConfig.NewConfig().ConstructUsing(instance242969081 => new ProxyInterfaceSourceGeneratorTests.Source.FooProxy(instance242969081)); + Mapster.TypeAdapterConfig.NewConfig().MapWith(proxy_1660896935 => ((ProxyInterfaceSourceGeneratorTests.Source.FooProxy) proxy_1660896935)._Instance); + + + } + } +} +#nullable disable + } +] \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs index 54e9bc1..174fade 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs @@ -1,364 +1,403 @@ +using System.Runtime.CompilerServices; using CSharp.SourceGenerators.Extensions; using CSharp.SourceGenerators.Extensions.Models; using FluentAssertions; using ProxyInterfaceSourceGenerator; using ProxyInterfaceSourceGeneratorTests.Source; -using Xunit; -namespace ProxyInterfaceSourceGeneratorTests +namespace ProxyInterfaceSourceGeneratorTests; + +[UsesVerify] +public class ProxyInterfaceSourceGeneratorTest { - public class ProxyInterfaceSourceGeneratorTest + [ModuleInitializer] + public static void ModuleInitializer() => VerifySourceGenerators.Enable(); + + private const bool Write = true; + + private readonly ProxyInterfaceCodeGenerator _sut; + + public ProxyInterfaceSourceGeneratorTest() { - private bool Write = true; + _sut = new ProxyInterfaceCodeGenerator(); - private readonly ProxyInterfaceCodeGenerator _sut; - - public ProxyInterfaceSourceGeneratorTest() - { - _sut = new ProxyInterfaceCodeGenerator(); - - var pp = new PersonProxy(new Person()); - - _ = pp.AddHuman(new HumanProxy(new Human())); - } - - [Fact] - public void GenerateFiles_ForStruct_Should_Not_GenerateProxyCode() - { - // Arrange - var path = "./Source/IMyStruct.cs"; - var sourceFile = new SourceFile - { - Path = path, - Text = File.ReadAllText(path), - AttributeToAddToInterface = new ExtraAttribute - { - Name = "ProxyInterfaceGenerator.Proxy", - ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.MyStruct)" - } - }; - - // Act - var result = _sut.Execute(new[] { sourceFile }); - - // Assert - result.Valid.Should().BeTrue(); - result.Files.Should().HaveCount(1); - } - - [Fact] - public void GenerateFiles_ForGenericType_Should_GenerateCorrectFiles() - { - // Arrange - var fileNames = new[] - { - "ProxyInterfaceSourceGeneratorTests.Source.IGeneric.g.cs", - "ProxyInterfaceSourceGeneratorTests.Source.Generic_T__1Proxy.g.cs" - }; - - var path = "./Source/IGeneric.cs"; - var sourceFile = new SourceFile - { - Path = path, - Text = File.ReadAllText(path), - AttributeToAddToInterface = new ExtraAttribute - { - Name = "ProxyInterfaceGenerator.Proxy", - ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.Generic<>)" - } - }; - - // Act - var result = _sut.Execute(new[] - { - sourceFile - }); - - // Assert - result.Valid.Should().BeTrue(); - result.Files.Should().HaveCount(fileNames.Length + 1); - - foreach (var fileName in fileNames.Select((fileName, index) => new { fileName, index })) - { - var builder = result.Files[fileName.index + 1]; // +1 means skip the attribute - builder.Path.Should().EndWith(fileName.fileName); - - if (Write) File.WriteAllText($"../../../Destination/{fileName.fileName}", builder.Text); - builder.Text.Should().Be(File.ReadAllText($"../../../Destination/{fileName.fileName}")); - } - } - - [Fact] - public void GenerateFiles_ForClassWithOperator_Should_GenerateCorrectFiles() - { - // Arrange - var fileNames = new[] - { - "ProxyInterfaceSourceGeneratorTests.Source.IOperatorTest.g.cs", - "ProxyInterfaceSourceGeneratorTests.Source.OperatorTestProxy.g.cs" - }; - - var path = "./Source/IOperatorTest.cs"; - var sourceFile = new SourceFile - { - Path = path, - Text = File.ReadAllText(path), - AttributeToAddToInterface = new ExtraAttribute - { - Name = "ProxyInterfaceGenerator.Proxy", - ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.OperatorTest)" - } - }; - - // Act - var result = _sut.Execute(new[] - { - sourceFile - }); - - // Assert - result.Valid.Should().BeTrue(); - result.Files.Should().HaveCount(fileNames.Length + 1); - - foreach (var fileName in fileNames.Select((fileName, index) => new { fileName, index })) - { - var builder = result.Files[fileName.index + 1]; // +1 means skip the attribute - builder.Path.Should().EndWith(fileName.fileName); - - if (Write) File.WriteAllText($"../../../Destination/{fileName.fileName}", builder.Text); - builder.Text.Should().Be(File.ReadAllText($"../../../Destination/{fileName.fileName}")); - } - - var name = "stef"; - var operatorTest = new OperatorTest - { - Name = name - }; - string name1 = (string) operatorTest; - name1.Should().Be(name); - - var p = new OperatorTestProxy(operatorTest); - string name2 = (string)p; - name2.Should().Be(name); - - var p2 = (OperatorTestProxy)name; - p2.Should().BeEquivalentTo(new OperatorTestProxy(operatorTest)); - } - - [Fact] - public void GenerateFiles_When_NoNamespace_Should_GenerateCorrectFiles() - { - // Arrange - var fileNames = new[] - { - "INoNamespace.g.cs", - "NoNamespaceProxy.g.cs" - }; - - var path = "./Source/INoNamespace.cs"; - var sourceFile = new SourceFile - { - Path = path, - Text = File.ReadAllText(path), - AttributeToAddToInterface = new ExtraAttribute - { - Name = "ProxyInterfaceGenerator.Proxy", - ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.NoNamespace)" - } - }; - - // Act - var result = _sut.Execute(new[] - { - sourceFile - }); - - // Assert - result.Valid.Should().BeTrue(); - result.Files.Should().HaveCount(fileNames.Length + 1); - - foreach (var fileName in fileNames.Select((fileName, index) => new { fileName, index })) - { - var builder = result.Files[fileName.index + 1]; // +1 means skip the attribute - builder.Path.Should().EndWith(fileName.fileName); - - if (Write) File.WriteAllText($"../../../Destination/{fileName.fileName}", builder.Text); - builder.Text.Should().Be(File.ReadAllText($"../../../Destination/{fileName.fileName}")); - } - } - - [Fact] - public void GenerateFiles_When_MixedVisibility_Should_GenerateCorrectFiles() - { - // Arrange - var fileNames = new[] - { - "ProxyInterfaceSourceGeneratorTests.Source.IMixedVisibility.g.cs", - "ProxyInterfaceSourceGeneratorTests.Source.MixedVisibilityProxy.g.cs" - }; - - var path = "./Source/IMixedVisibility.cs"; - var sourceFile = new SourceFile - { - Path = path, - Text = File.ReadAllText(path), - AttributeToAddToInterface = new ExtraAttribute - { - Name = "ProxyInterfaceGenerator.Proxy", - ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.MixedVisibility)" - } - }; - - // Act - var result = _sut.Execute(new[] - { - sourceFile - }); - - // Assert - result.Valid.Should().BeTrue(); - result.Files.Should().HaveCount(fileNames.Length + 1); - - foreach (var fileName in fileNames.Select((fileName, index) => new { fileName, index })) - { - var builder = result.Files[fileName.index + 1]; // +1 means skip the attribute - builder.Path.Should().EndWith(fileName.fileName); - - if (Write) File.WriteAllText($"../../../Destination/{fileName.fileName}", builder.Text); - builder.Text.Should().Be(File.ReadAllText($"../../../Destination/{fileName.fileName}")); - } - } - - [Fact] - public void GenerateFiles_ForSingleClass_Should_GenerateCorrectFiles() - { - // Arrange - var attributeFilename = "ProxyInterfaceGenerator.ProxyAttribute.g.cs"; - var interfaceFilename = "ProxyInterfaceSourceGeneratorTests.Source.IPersonExtends.g.cs"; - var proxyClassFilename = "ProxyInterfaceSourceGeneratorTests.Source.PersonExtendsProxy.g.cs"; - - var path = "./Source/IPersonExtends.cs"; - var sourceFile = new SourceFile - { - Path = path, - Text = File.ReadAllText(path), - AttributeToAddToInterface = new ExtraAttribute - { - Name = "ProxyInterfaceGenerator.Proxy", - ArgumentList = new[] { "typeof(ProxyInterfaceSourceGeneratorTests.Source.PersonExtends)", "true" } - } - }; - - // Act - var result = _sut.Execute(new[] { sourceFile }); - - // Assert - result.Valid.Should().BeTrue(); - result.Files.Should().HaveCount(3); - - // Assert attribute - var attribute = result.Files[0].SyntaxTree; - attribute.FilePath.Should().EndWith(attributeFilename); - - // Assert interface - var @interface = result.Files[1].SyntaxTree; - @interface.FilePath.Should().EndWith(interfaceFilename); - - var interfaceCode = @interface.ToString(); - if (Write) File.WriteAllText($"../../../Destination/{interfaceFilename}", interfaceCode); - interfaceCode.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{interfaceFilename}")); - - // Assert Proxy - var proxyClass = result.Files[2].SyntaxTree; - proxyClass.FilePath.Should().EndWith(proxyClassFilename); - - var proxyCode = proxyClass.ToString(); - if (Write) File.WriteAllText($"../../../Destination/{proxyClassFilename}", proxyCode); - proxyCode.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{proxyClassFilename}")); - } - - [Fact] - public void GenerateFiles_ForTwoClasses_Should_GenerateCorrectFiles() - { - // Arrange - var attributeFilename = "ProxyInterfaceGenerator.ProxyAttribute.g.cs"; - var interfaceHumanFilename = "ProxyInterfaceSourceGeneratorTests.Source.IHuman.g.cs"; - var proxyClassHumanFilename = "ProxyInterfaceSourceGeneratorTests.Source.HumanProxy.g.cs"; - var interfacePersonFilename = "ProxyInterfaceSourceGeneratorTests.Source.IPerson.g.cs"; - var proxyClassPersonFilename = "ProxyInterfaceSourceGeneratorTests.Source.PersonProxy.g.cs"; - - var pathPerson = "./Source/IPerson.cs"; - var sourceFilePerson = new SourceFile - { - Path = pathPerson, - Text = File.ReadAllText(pathPerson), - AttributeToAddToInterface = new ExtraAttribute - { - Name = "ProxyInterfaceGenerator.Proxy", - ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.Person)" - } - }; - - var pathHuman = "./Source/IHuman.cs"; - var sourceFileHuman = new SourceFile - { - Path = pathHuman, - Text = File.ReadAllText(pathHuman), - AttributeToAddToInterface = new ExtraAttribute - { - Name = "ProxyInterfaceGenerator.Proxy", - ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.Human)" - } - }; - - // Act - var result = _sut.Execute(new[] { sourceFileHuman, sourceFilePerson }); - - // Assert - result.Valid.Should().BeTrue(); - result.Files.Should().HaveCount(5); - - // Assert attribute - var attribute = result.Files[0].SyntaxTree; - attribute.FilePath.Should().EndWith(attributeFilename); - - - // Assert interface Human - var interfaceHuman = result.Files[1].SyntaxTree; - interfaceHuman.FilePath.Should().EndWith(interfaceHumanFilename); - - var interfaceCodeHuman = interfaceHuman.ToString(); - if (Write) File.WriteAllText($"../../../Destination/{interfaceHumanFilename}", interfaceCodeHuman); - interfaceCodeHuman.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{interfaceHumanFilename}")); - - - // Assert interface Person - var interfacePerson = result.Files[2].SyntaxTree; - interfacePerson.FilePath.Should().EndWith(interfacePersonFilename); - - var interfaceCodePerson = interfacePerson.ToString(); - if (Write) File.WriteAllText($"../../../Destination/{interfacePersonFilename}", interfaceCodePerson); - interfaceCodePerson.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{interfacePersonFilename}")); - - - // Assert Proxy Human - var proxyClassHuman = result.Files[3].SyntaxTree; - proxyClassHuman.FilePath.Should().EndWith(proxyClassHumanFilename); - - var proxyCodeHuman = proxyClassHuman.ToString(); - if (Write) File.WriteAllText($"../../../Destination/{proxyClassHumanFilename}", proxyCodeHuman); - proxyCodeHuman.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{proxyClassHumanFilename}")); - - - // Assert Proxy Person - var proxyClassPerson = result.Files[4].SyntaxTree; - proxyClassPerson.FilePath.Should().EndWith(proxyClassPersonFilename); - - var proxyCode = proxyClassPerson.ToString(); - if (Write) File.WriteAllText($"../../../Destination/{proxyClassPersonFilename}", proxyCode); - proxyCode.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{proxyClassPersonFilename}")); - } - - + var pp = new PersonProxy(new Person()); + _ = pp.AddHuman(new HumanProxy(new Human())); } + + [Fact] + public void GenerateFiles_ForStruct_Should_Not_GenerateProxyCode() + { + // Arrange + var path = "./Source/IMyStruct.cs"; + var sourceFile = new SourceFile + { + Path = path, + Text = File.ReadAllText(path), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "ProxyInterfaceGenerator.Proxy", + ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.MyStruct)" + } + }; + + // Act + var result = _sut.Execute(new[] { sourceFile }); + + // Assert + result.Valid.Should().BeTrue(); + result.Files.Should().HaveCount(1); + } + + [Fact] + public Task GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles() + { + // Arrange + var fileNames = new[] + { + "ProxyInterfaceSourceGeneratorTests.Source.IFoo.g.cs", + "ProxyInterfaceSourceGeneratorTests.Source.FooProxy.g.cs" + }; + + var path = "./Source/IFoo.cs"; + var sourceFile = new SourceFile + { + Path = path, + Text = File.ReadAllText(path), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "ProxyInterfaceGenerator.Proxy", + ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.Foo)" + } + }; + + // Act + var result = _sut.Execute(new[] + { + sourceFile + }); + + // Assert + result.Valid.Should().BeTrue(); + result.Files.Should().HaveCount(fileNames.Length + 1); + + // Verify + var results = result.GeneratorDriver.GetRunResult().Results.First().GeneratedSources; + return Verify(results); + } + + [Fact] + public void GenerateFiles_ForGenericType_Should_GenerateCorrectFiles() + { + // Arrange + var fileNames = new[] + { + "ProxyInterfaceSourceGeneratorTests.Source.IGeneric.g.cs", + "ProxyInterfaceSourceGeneratorTests.Source.Generic_T__1Proxy.g.cs" + }; + + var path = "./Source/IGeneric.cs"; + var sourceFile = new SourceFile + { + Path = path, + Text = File.ReadAllText(path), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "ProxyInterfaceGenerator.Proxy", + ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.Generic<>)" + } + }; + + // Act + var result = _sut.Execute(new[] + { + sourceFile + }); + + // Assert + result.Valid.Should().BeTrue(); + result.Files.Should().HaveCount(fileNames.Length + 1); + + foreach (var fileName in fileNames.Select((fileName, index) => new { fileName, index })) + { + var builder = result.Files[fileName.index + 1]; // +1 means skip the attribute + builder.Path.Should().EndWith(fileName.fileName); + + if (Write) File.WriteAllText($"../../../Destination/{fileName.fileName}", builder.Text); + builder.Text.Should().Be(File.ReadAllText($"../../../Destination/{fileName.fileName}")); + } + } + + [Fact] + public void GenerateFiles_ForClassWithOperator_Should_GenerateCorrectFiles() + { + // Arrange + var fileNames = new[] + { + "ProxyInterfaceSourceGeneratorTests.Source.IOperatorTest.g.cs", + "ProxyInterfaceSourceGeneratorTests.Source.OperatorTestProxy.g.cs" + }; + + var path = "./Source/IOperatorTest.cs"; + var sourceFile = new SourceFile + { + Path = path, + Text = File.ReadAllText(path), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "ProxyInterfaceGenerator.Proxy", + ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.OperatorTest)" + } + }; + + // Act + var result = _sut.Execute(new[] + { + sourceFile + }); + + // Assert + result.Valid.Should().BeTrue(); + result.Files.Should().HaveCount(fileNames.Length + 1); + + foreach (var fileName in fileNames.Select((fileName, index) => new { fileName, index })) + { + var builder = result.Files[fileName.index + 1]; // +1 means skip the attribute + builder.Path.Should().EndWith(fileName.fileName); + + if (Write) File.WriteAllText($"../../../Destination/{fileName.fileName}", builder.Text); + builder.Text.Should().Be(File.ReadAllText($"../../../Destination/{fileName.fileName}")); + } + + var name = "stef"; + var operatorTest = new OperatorTest + { + Name = name + }; + string name1 = (string)operatorTest; + name1.Should().Be(name); + + var p = new OperatorTestProxy(operatorTest); + string name2 = (string)p; + name2.Should().Be(name); + + var p2 = (OperatorTestProxy)name; + p2.Should().BeEquivalentTo(new OperatorTestProxy(operatorTest)); + } + + [Fact] + public void GenerateFiles_When_NoNamespace_Should_GenerateCorrectFiles() + { + // Arrange + var fileNames = new[] + { + "INoNamespace.g.cs", + "NoNamespaceProxy.g.cs" + }; + + var path = "./Source/INoNamespace.cs"; + var sourceFile = new SourceFile + { + Path = path, + Text = File.ReadAllText(path), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "ProxyInterfaceGenerator.Proxy", + ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.NoNamespace)" + } + }; + + // Act + var result = _sut.Execute(new[] + { + sourceFile + }); + + // Assert + result.Valid.Should().BeTrue(); + result.Files.Should().HaveCount(fileNames.Length + 1); + + foreach (var fileName in fileNames.Select((fileName, index) => new { fileName, index })) + { + var builder = result.Files[fileName.index + 1]; // +1 means skip the attribute + builder.Path.Should().EndWith(fileName.fileName); + + if (Write) File.WriteAllText($"../../../Destination/{fileName.fileName}", builder.Text); + builder.Text.Should().Be(File.ReadAllText($"../../../Destination/{fileName.fileName}")); + } + } + + [Fact] + public void GenerateFiles_When_MixedVisibility_Should_GenerateCorrectFiles() + { + // Arrange + var fileNames = new[] + { + "ProxyInterfaceSourceGeneratorTests.Source.IMixedVisibility.g.cs", + "ProxyInterfaceSourceGeneratorTests.Source.MixedVisibilityProxy.g.cs" + }; + + var path = "./Source/IMixedVisibility.cs"; + var sourceFile = new SourceFile + { + Path = path, + Text = File.ReadAllText(path), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "ProxyInterfaceGenerator.Proxy", + ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.MixedVisibility)" + } + }; + + // Act + var result = _sut.Execute(new[] + { + sourceFile + }); + + // Assert + result.Valid.Should().BeTrue(); + result.Files.Should().HaveCount(fileNames.Length + 1); + + foreach (var fileName in fileNames.Select((fileName, index) => new { fileName, index })) + { + var builder = result.Files[fileName.index + 1]; // +1 means skip the attribute + builder.Path.Should().EndWith(fileName.fileName); + + if (Write) File.WriteAllText($"../../../Destination/{fileName.fileName}", builder.Text); + builder.Text.Should().Be(File.ReadAllText($"../../../Destination/{fileName.fileName}")); + } + } + + [Fact] + public void GenerateFiles_ForSingleClass_Should_GenerateCorrectFiles() + { + // Arrange + var attributeFilename = "ProxyInterfaceGenerator.ProxyAttribute.g.cs"; + var interfaceFilename = "ProxyInterfaceSourceGeneratorTests.Source.IPersonExtends.g.cs"; + var proxyClassFilename = "ProxyInterfaceSourceGeneratorTests.Source.PersonExtendsProxy.g.cs"; + + var path = "./Source/IPersonExtends.cs"; + var sourceFile = new SourceFile + { + Path = path, + Text = File.ReadAllText(path), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "ProxyInterfaceGenerator.Proxy", + ArgumentList = new[] { "typeof(ProxyInterfaceSourceGeneratorTests.Source.PersonExtends)", "true" } + } + }; + + // Act + var result = _sut.Execute(new[] { sourceFile }); + + // Assert + result.Valid.Should().BeTrue(); + result.Files.Should().HaveCount(3); + + // Assert attribute + var attribute = result.Files[0].SyntaxTree; + attribute.FilePath.Should().EndWith(attributeFilename); + + // Assert interface + var @interface = result.Files[1].SyntaxTree; + @interface.FilePath.Should().EndWith(interfaceFilename); + + var interfaceCode = @interface.ToString(); + if (Write) File.WriteAllText($"../../../Destination/{interfaceFilename}", interfaceCode); + interfaceCode.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{interfaceFilename}")); + + // Assert Proxy + var proxyClass = result.Files[2].SyntaxTree; + proxyClass.FilePath.Should().EndWith(proxyClassFilename); + + var proxyCode = proxyClass.ToString(); + if (Write) File.WriteAllText($"../../../Destination/{proxyClassFilename}", proxyCode); + proxyCode.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{proxyClassFilename}")); + } + + [Fact] + public void GenerateFiles_ForTwoClasses_Should_GenerateCorrectFiles() + { + // Arrange + var attributeFilename = "ProxyInterfaceGenerator.ProxyAttribute.g.cs"; + var interfaceHumanFilename = "ProxyInterfaceSourceGeneratorTests.Source.IHuman.g.cs"; + var proxyClassHumanFilename = "ProxyInterfaceSourceGeneratorTests.Source.HumanProxy.g.cs"; + var interfacePersonFilename = "ProxyInterfaceSourceGeneratorTests.Source.IPerson.g.cs"; + var proxyClassPersonFilename = "ProxyInterfaceSourceGeneratorTests.Source.PersonProxy.g.cs"; + + var pathPerson = "./Source/IPerson.cs"; + var sourceFilePerson = new SourceFile + { + Path = pathPerson, + Text = File.ReadAllText(pathPerson), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "ProxyInterfaceGenerator.Proxy", + ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.Person)" + } + }; + + var pathHuman = "./Source/IHuman.cs"; + var sourceFileHuman = new SourceFile + { + Path = pathHuman, + Text = File.ReadAllText(pathHuman), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "ProxyInterfaceGenerator.Proxy", + ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.Human)" + } + }; + + // Act + var result = _sut.Execute(new[] { sourceFileHuman, sourceFilePerson }); + + // Assert + result.Valid.Should().BeTrue(); + result.Files.Should().HaveCount(5); + + // Assert attribute + var attribute = result.Files[0].SyntaxTree; + attribute.FilePath.Should().EndWith(attributeFilename); + + + // Assert interface Human + var interfaceHuman = result.Files[1].SyntaxTree; + interfaceHuman.FilePath.Should().EndWith(interfaceHumanFilename); + + var interfaceCodeHuman = interfaceHuman.ToString(); + if (Write) File.WriteAllText($"../../../Destination/{interfaceHumanFilename}", interfaceCodeHuman); + interfaceCodeHuman.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{interfaceHumanFilename}")); + + + // Assert interface Person + var interfacePerson = result.Files[2].SyntaxTree; + interfacePerson.FilePath.Should().EndWith(interfacePersonFilename); + + var interfaceCodePerson = interfacePerson.ToString(); + if (Write) File.WriteAllText($"../../../Destination/{interfacePersonFilename}", interfaceCodePerson); + interfaceCodePerson.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{interfacePersonFilename}")); + + + // Assert Proxy Human + var proxyClassHuman = result.Files[3].SyntaxTree; + proxyClassHuman.FilePath.Should().EndWith(proxyClassHumanFilename); + + var proxyCodeHuman = proxyClassHuman.ToString(); + if (Write) File.WriteAllText($"../../../Destination/{proxyClassHumanFilename}", proxyCodeHuman); + proxyCodeHuman.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{proxyClassHumanFilename}")); + + + // Assert Proxy Person + var proxyClassPerson = result.Files[4].SyntaxTree; + proxyClassPerson.FilePath.Should().EndWith(proxyClassPersonFilename); + + var proxyCode = proxyClassPerson.ToString(); + if (Write) File.WriteAllText($"../../../Destination/{proxyClassPersonFilename}", proxyCode); + proxyCode.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{proxyClassPersonFilename}")); + } + + } \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTests.csproj b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTests.csproj index 11e7eed..74f8d77 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTests.csproj +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTests.csproj @@ -13,11 +13,13 @@ - + - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -34,7 +36,7 @@ - + diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/Bar.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/Bar.cs new file mode 100644 index 0000000..5c2c681 --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/Bar.cs @@ -0,0 +1,5 @@ +namespace ProxyInterfaceSourceGeneratorTests.Source; + +public class Bar +{ +} \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/Foo.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/Foo.cs new file mode 100644 index 0000000..217f2e8 --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/Foo.cs @@ -0,0 +1,31 @@ +namespace ProxyInterfaceSourceGeneratorTests.Source; + +public class Foo +{ + //public Bar DoSomethingAndGetABar() + //{ + // return new Bar(); + //} + + //public Bar[] DoSomethingAndGetAnArrayOfBars() + //{ + // return new[] { new Bar() }; + //} + + //public Foo DoSomethingAndGetAFoo() + //{ + // return new Foo(); + //} + + public Foo[] Foos { get; set; } + + public Foo[] DoSomethingAndGetAnArrayOfFoos() + { + return new[] { new Foo() }; + } + + //public List DoSomethingAndGetAListOfFoos() + //{ + // return new[] { new Foo() }.ToList(); + //} +} \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/IFoo.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/IFoo.cs new file mode 100644 index 0000000..74e0d49 --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/IFoo.cs @@ -0,0 +1,6 @@ +namespace ProxyInterfaceSourceGeneratorTests.Source +{ + public partial interface IFoo + { + } +} \ No newline at end of file