diff --git a/MattSourceGenHelpers.Abstractions/Assembly.cs b/MattSourceGenHelpers.Abstractions/Assembly.cs new file mode 100644 index 0000000..c019b5c --- /dev/null +++ b/MattSourceGenHelpers.Abstractions/Assembly.cs @@ -0,0 +1,2 @@ +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MattSourceGenHelpers.Tests")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MattSourceGenHelpers.Generators")] \ No newline at end of file diff --git a/MattSourceGenHelpers.Abstractions/Generate.cs b/MattSourceGenHelpers.Abstractions/Generate.cs index 5f4cba2..eace84a 100644 --- a/MattSourceGenHelpers.Abstractions/Generate.cs +++ b/MattSourceGenHelpers.Abstractions/Generate.cs @@ -1,78 +1,10 @@ -namespace MattSourceGenHelpers.Abstractions; +using JetBrains.Annotations; -public static class Generate -{ - public static IGeneratorsFactory CurrentGenerator { get; set; } = new RecordingGeneratorsFactory(); - - public static IMethodBuilder Method() => new MethodBuilder(CurrentGenerator); -} - -public interface IMethodBuilder -{ - IMethodBuilder WithParameter(); - IMethodImplementationGenerator WithReturnType(); -} - -public interface IMethodBuilder -{ - IMethodImplementationGenerator WithReturnType(); -} - -public class MethodBuilder : IMethodBuilder -{ - private readonly IGeneratorsFactory _generatorsFactory; - - public MethodBuilder(IGeneratorsFactory generatorsFactory) - { - _generatorsFactory = generatorsFactory; - } - - public IMethodBuilder WithParameter() => new MethodBuilder(_generatorsFactory); - - public IMethodImplementationGenerator WithReturnType() => _generatorsFactory.CreateImplementation(); -} +namespace MattSourceGenHelpers.Abstractions; -public class MethodBuilder : IMethodBuilder -{ - private readonly IGeneratorsFactory _generatorsFactory; - - public MethodBuilder(IGeneratorsFactory generatorsFactory) - { - _generatorsFactory = generatorsFactory; - } - - public IMethodImplementationGenerator WithReturnType() => _generatorsFactory.CreateImplementation(); -} - -public class EmptyGeneratorsFactory : IGeneratorsFactory -{ - public IMethodImplementationGenerator CreateImplementation() => new EmptyMethodImplementationGenerator(); - public IMethodImplementationGenerator CreateImplementation() => new EmptyMethodImplementationGenerator(); - public IMethodImplementationGenerator CreateImplementation() => new EmptyMethodImplementationGenerator(); -} - -public class EmptyMethodImplementationGenerator : IMethodImplementationGenerator -{ - public IMethodImplementationGenerator WithBody(Action body) => this; - public IMethodImplementationGenerator WithBody(Func body) => this; -} - -public class EmptyMethodImplementationGenerator : IMethodImplementationGenerator -{ - public IMethodImplementationGenerator UseBody(Func body) => this; -} - -public class EmptyMethodImplementationGenerator : IMethodImplementationGenerator +public static class Generate { - public IMethodImplementationGeneratorSwitchBody WithSwitchBody() => - new RecordingMethodImplementationGeneratorSwitchBody(new SwitchBodyRecord()); - public IMethodImplementationGenerator WithBody(Action body) => this; - public IMethodImplementationGenerator WithBody(Func body) => this; -} + internal static IGeneratorsFactory CurrentGenerator { get; [UsedImplicitly] set; } = new MockGeneratorsFactory(); -public interface IGeneratorsFactory -{ - IMethodImplementationGenerator CreateImplementation(); - IMethodImplementationGenerator CreateImplementation(); - IMethodImplementationGenerator CreateImplementation(); -} + public static IMethodBuilder Method() => CurrentGenerator.ForMethod(); +} \ No newline at end of file diff --git a/MattSourceGenHelpers.Abstractions/IGeneratorsFactory.cs b/MattSourceGenHelpers.Abstractions/IGeneratorsFactory.cs new file mode 100644 index 0000000..5bcb75b --- /dev/null +++ b/MattSourceGenHelpers.Abstractions/IGeneratorsFactory.cs @@ -0,0 +1,9 @@ +namespace MattSourceGenHelpers.Abstractions; + +public interface IGeneratorsFactory +{ + IMethodBuilder ForMethod(); + + IMethodImplementationGenerator CreateImplementation(); + IMethodImplementationGenerator CreateImplementation(); +} \ No newline at end of file diff --git a/MattSourceGenHelpers.Abstractions/IMethodBuilder.cs b/MattSourceGenHelpers.Abstractions/IMethodBuilder.cs new file mode 100644 index 0000000..6ca5c08 --- /dev/null +++ b/MattSourceGenHelpers.Abstractions/IMethodBuilder.cs @@ -0,0 +1,12 @@ +namespace MattSourceGenHelpers.Abstractions; + +public interface IMethodBuilder +{ + IMethodBuilder WithParameter(); + IMethodImplementationGenerator WithReturnType(); +} + +public interface IMethodBuilder +{ + IMethodImplementationGenerator WithReturnType(); +} \ No newline at end of file diff --git a/MattSourceGenHelpers.Abstractions/IMethodGenerator.cs b/MattSourceGenHelpers.Abstractions/IMethodGenerator.cs deleted file mode 100644 index 71e3f83..0000000 --- a/MattSourceGenHelpers.Abstractions/IMethodGenerator.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace MattSourceGenHelpers.Abstractions; - -public interface IMethodGenerator -{ - -} \ No newline at end of file diff --git a/MattSourceGenHelpers.Abstractions/IMethodImplementationGenerator.cs b/MattSourceGenHelpers.Abstractions/IMethodImplementationGenerator.cs index 653adf2..cfd6515 100644 --- a/MattSourceGenHelpers.Abstractions/IMethodImplementationGenerator.cs +++ b/MattSourceGenHelpers.Abstractions/IMethodImplementationGenerator.cs @@ -1,8 +1,10 @@ -namespace MattSourceGenHelpers.Abstractions; +using JetBrains.Annotations; -public interface IMethodImplementationGenerator : IMethodImplementationGenerator +namespace MattSourceGenHelpers.Abstractions; + +public interface IMethodImplementationGenerator<[UsedImplicitly] TReturnType> : IMethodImplementationGenerator { - IMethodImplementationGenerator UseBody(Func body); + IMethodImplementationGenerator UseBody([UsedImplicitly] Func body); } public interface IMethodImplementationGenerator : IMethodImplementationGenerator @@ -10,10 +12,4 @@ public interface IMethodImplementationGenerator : IMethodImp IMethodImplementationGeneratorSwitchBody WithSwitchBody(); } -public interface IMethodImplementationGeneratorVoid -{ - IMethodImplementationGenerator CompileTimeBody(Action func); - IMethodImplementationGenerator RuntimeBody(Action func); -} - public interface IMethodImplementationGenerator; \ No newline at end of file diff --git a/MattSourceGenHelpers.Abstractions/Integer.cs b/MattSourceGenHelpers.Abstractions/Integer.cs deleted file mode 100644 index 882f572..0000000 --- a/MattSourceGenHelpers.Abstractions/Integer.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace MattSourceGenHelpers.Abstractions; - -public static class Integer -{ - public static int[] Range(int start, int end) => Enumerable.Range(start, end - start + 1).ToArray(); -} \ No newline at end of file diff --git a/MattSourceGenHelpers.Abstractions/MethodBuilder.cs b/MattSourceGenHelpers.Abstractions/MethodBuilder.cs new file mode 100644 index 0000000..990b17b --- /dev/null +++ b/MattSourceGenHelpers.Abstractions/MethodBuilder.cs @@ -0,0 +1,13 @@ +namespace MattSourceGenHelpers.Abstractions; + +public class MethodBuilder(IGeneratorsFactory generatorsFactory) : IMethodBuilder +{ + public IMethodBuilder WithParameter() => new MethodBuilder(generatorsFactory); + + public IMethodImplementationGenerator WithReturnType() => generatorsFactory.CreateImplementation(); +} + +public class MethodBuilder(IGeneratorsFactory generatorsFactory) : IMethodBuilder +{ + public IMethodImplementationGenerator WithReturnType() => generatorsFactory.CreateImplementation(); +} \ No newline at end of file diff --git a/MattSourceGenHelpers.Abstractions/Mocks.cs b/MattSourceGenHelpers.Abstractions/Mocks.cs new file mode 100644 index 0000000..9a9de72 --- /dev/null +++ b/MattSourceGenHelpers.Abstractions/Mocks.cs @@ -0,0 +1,68 @@ +namespace MattSourceGenHelpers.Abstractions; + +public class MockGeneratorsFactory : IGeneratorsFactory +{ + public IMethodBuilder ForMethod() => new MockMethodBuilder(); + + public IMethodImplementationGenerator CreateImplementation() => new MockMethodImplementationGenerator(); + + public IMethodImplementationGenerator CreateImplementation() => + new MockMethodImplementationGenerator(); +} + +public class MockMethodImplementationGenerator : IMethodImplementationGenerator +{ + public IMethodImplementationGenerator UseBody(Func body) => this; +} + +public class MockMethodImplementationGenerator : IMethodImplementationGenerator +{ + public IMethodImplementationGeneratorSwitchBody WithSwitchBody() => + new MockMethodImplementationGeneratorSwitchBody(); +} + +public class MockMethodImplementationGeneratorSwitchBody : IMethodImplementationGeneratorSwitchBody +{ + public IMethodImplementationGeneratorSwitchBodyCase ForCases(params object[] cases) + => new MockMethodImplementationGeneratorSwitchBodyCase(); + + public IMethodImplementationGeneratorSwitchBodyDefaultCase ForDefaultCase() + => new MockMethodImplementationGeneratorSwitchBodyDefaultCase(); +} + +public class MockMethodImplementationGeneratorSwitchBodyDefaultCase : IMethodImplementationGeneratorSwitchBodyDefaultCase +{ + public IMethodImplementationGenerator ReturnConstantValue(Func func) + => new MockMethodImplementationGenerator(); + + public IMethodImplementationGenerator UseBody(Func> func) + => new MockMethodImplementationGenerator(); +} + +public class MockMethodImplementationGeneratorSwitchBodyCase : IMethodImplementationGeneratorSwitchBodyCase +{ + public IMethodImplementationGeneratorSwitchBody ReturnConstantValue(Func constantValueFactory) + => new MockMethodImplementationGeneratorSwitchBody(); + + public IMethodImplementationGeneratorSwitchBody UseBody(Func> body) + => new MockMethodImplementationGeneratorSwitchBody(); +} + +public class MockMethodBuilder : IMethodBuilder +{ + public IMethodBuilder WithParameter() => new MockMethodBuilder(); + + public IMethodImplementationGenerator WithReturnType() => new MockImplementationGenerator(); +} + +public class MockImplementationGenerator : IMethodImplementationGenerator +{ + public IMethodImplementationGenerator UseBody(Func body) => this; +} + +public class MockMethodBuilder : IMethodBuilder +{ + public IMethodImplementationGenerator WithReturnType() + => new MockMethodImplementationGenerator(); +} \ No newline at end of file diff --git a/MattSourceGenHelpers.Abstractions/PartialMethodCalledDuringGenerationException.cs b/MattSourceGenHelpers.Abstractions/PartialMethodCalledDuringGenerationException.cs index bb1a49f..59711e1 100644 --- a/MattSourceGenHelpers.Abstractions/PartialMethodCalledDuringGenerationException.cs +++ b/MattSourceGenHelpers.Abstractions/PartialMethodCalledDuringGenerationException.cs @@ -1,3 +1,5 @@ +using JetBrains.Annotations; + namespace MattSourceGenHelpers.Abstractions; /// @@ -5,13 +7,8 @@ namespace MattSourceGenHelpers.Abstractions; /// Partial methods cannot be invoked inside generator methods because they are the /// methods being generated — they do not have an implementation yet at generation time. /// -public class PartialMethodCalledDuringGenerationException : InvalidOperationException -{ - public PartialMethodCalledDuringGenerationException(string methodName, string typeName) - : base( - $"Partial method '{typeName}.{methodName}' was called during source generation. " + - $"Partial methods cannot be invoked inside generator methods because their implementations " + - $"are what is being generated. Remove the call to '{methodName}' from your generator method.") - { - } -} +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)] +public class PartialMethodCalledDuringGenerationException(string methodName, string typeName) : InvalidOperationException( + $"Partial method '{typeName}.{methodName}' was called during source generation. " + + $"Partial methods cannot be invoked inside generator methods because their implementations " + + $"are what is being generated. Remove the call to '{methodName}' from your generator method."); diff --git a/MattSourceGenHelpers.Abstractions/RecordingGeneratorsFactory.cs b/MattSourceGenHelpers.Abstractions/RecordingGeneratorsFactory.cs index 3a39fcf..491f316 100644 --- a/MattSourceGenHelpers.Abstractions/RecordingGeneratorsFactory.cs +++ b/MattSourceGenHelpers.Abstractions/RecordingGeneratorsFactory.cs @@ -1,8 +1,12 @@ +using JetBrains.Annotations; + namespace MattSourceGenHelpers.Abstractions; public class SwitchBodyRecord { + [UsedImplicitly] public List CaseKeys { get; } = new(); + [UsedImplicitly] public List CaseValues { get; } = new(); public bool HasDefaultCase { get; set; } } @@ -13,165 +17,117 @@ public class RecordingGeneratorsFactory : IGeneratorsFactory public IMethodImplementationGenerator CreateImplementation() { - var record = new SwitchBodyRecord(); + SwitchBodyRecord record = new SwitchBodyRecord(); LastRecord = record; - return new RecordingMethodImplementationGenerator(record); + return new RecordingMethodImplementationGenerator(); } + public IMethodBuilder ForMethod() => new MethodBuilder(this); + public IMethodImplementationGenerator CreateImplementation() { - var record = new SwitchBodyRecord(); + SwitchBodyRecord record = new SwitchBodyRecord(); LastRecord = record; - return new RecordingMethodImplementationGeneratorTyped(record); + return new RecordingMethodImplementationGeneratorTyped(); } public IMethodImplementationGenerator CreateImplementation() { - var record = new SwitchBodyRecord(); + SwitchBodyRecord record = new SwitchBodyRecord(); LastRecord = record; return new RecordingMethodImplementationGenerator(record); } } -public class RecordingMethodImplementationGenerator : IMethodImplementationGenerator -{ - private readonly SwitchBodyRecord _record; - - public RecordingMethodImplementationGenerator(SwitchBodyRecord record) - { - _record = record; - } - - public IMethodImplementationGenerator WithBody(Action body) => this; - public IMethodImplementationGenerator WithBody(Func body) => this; -} +public class RecordingMethodImplementationGenerator : IMethodImplementationGenerator; public class RecordingMethodImplementationGeneratorTyped : IMethodImplementationGenerator { - private readonly SwitchBodyRecord _record; - - public RecordingMethodImplementationGeneratorTyped(SwitchBodyRecord record) - { - _record = record; - } - public IMethodImplementationGenerator UseBody(Func body) => this; } -public class RecordingMethodImplementationGenerator - : IMethodImplementationGenerator +public class RecordingMethodImplementationGenerator(SwitchBodyRecord record) : IMethodImplementationGenerator { - private readonly SwitchBodyRecord _record; - - public RecordingMethodImplementationGenerator(SwitchBodyRecord record) - { - _record = record; - } - public IMethodImplementationGeneratorSwitchBody WithSwitchBody() { - return new RecordingMethodImplementationGeneratorSwitchBody(_record); + return new RecordingMethodImplementationGeneratorSwitchBody(record); } - - public IMethodImplementationGenerator WithBody(Action body) => this; - public IMethodImplementationGenerator WithBody(Func body) => this; } -public class RecordingMethodImplementationGeneratorSwitchBody +public class RecordingMethodImplementationGeneratorSwitchBody(SwitchBodyRecord record) : IMethodImplementationGeneratorSwitchBody { - private readonly SwitchBodyRecord _record; - - public RecordingMethodImplementationGeneratorSwitchBody(SwitchBodyRecord record) - { - _record = record; - } - public IMethodImplementationGeneratorSwitchBodyCase ForCases(params object[] cases) { - var flatCases = FlattenCases(cases).ToList(); - return new RecordingMethodImplementationGeneratorSwitchBodyCase(_record, flatCases); + List flatCases = FlattenCases(cases).ToList(); + return new RecordingMethodImplementationGeneratorSwitchBodyCase(record, flatCases); } public IMethodImplementationGeneratorSwitchBodyDefaultCase ForDefaultCase() { - return new RecordingMethodImplementationGeneratorSwitchBodyDefaultCase(_record); + return new RecordingMethodImplementationGeneratorSwitchBodyDefaultCase(record); } private static IEnumerable FlattenCases(object[] cases) { - foreach (var c in cases) + foreach (object oneCase in cases) { - if (c is TArg1[] arr) - { - foreach (var item in arr) - yield return item; - } - else if (c is TArg1 val) + switch (oneCase) { - yield return val; - } - else - { - yield return (TArg1)Convert.ChangeType(c, typeof(TArg1)); + case TArg1[] arr: + { + foreach (TArg1 item in arr) + yield return item; + break; + } + case TArg1 val: + yield return val; + break; + default: + yield return (TArg1)Convert.ChangeType(oneCase, typeof(TArg1)); + break; } } } } -public class RecordingMethodImplementationGeneratorSwitchBodyCase +public class RecordingMethodImplementationGeneratorSwitchBodyCase(SwitchBodyRecord record, List cases) : IMethodImplementationGeneratorSwitchBodyCase { - private readonly SwitchBodyRecord _record; - private readonly List _cases; - - public RecordingMethodImplementationGeneratorSwitchBodyCase(SwitchBodyRecord record, List cases) - { - _record = record; - _cases = cases; - } - public IMethodImplementationGeneratorSwitchBody ReturnConstantValue(Func constantValueFactory) { - foreach (var caseValue in _cases) + foreach (TArg1? caseValue in cases) { - var result = constantValueFactory(caseValue); - _record.CaseKeys.Add((object?)caseValue ?? throw new InvalidOperationException("Switch case value cannot be null")); - _record.CaseValues.Add(result); + TReturnType result = constantValueFactory(caseValue); + record.CaseKeys.Add((object?)caseValue ?? throw new InvalidOperationException("Switch case value cannot be null")); + record.CaseValues.Add(result); } - return new RecordingMethodImplementationGeneratorSwitchBody(_record); + return new RecordingMethodImplementationGeneratorSwitchBody(record); } public IMethodImplementationGeneratorSwitchBody UseBody(Func> body) { - foreach (var caseValue in _cases) + foreach (TArg1? caseValue in cases) { - _record.CaseKeys.Add((object?)caseValue ?? throw new InvalidOperationException("Switch case value cannot be null")); - _record.CaseValues.Add(null); + record.CaseKeys.Add((object?)caseValue ?? throw new InvalidOperationException("Switch case value cannot be null")); + record.CaseValues.Add(null); } - return new RecordingMethodImplementationGeneratorSwitchBody(_record); + return new RecordingMethodImplementationGeneratorSwitchBody(record); } } -public class RecordingMethodImplementationGeneratorSwitchBodyDefaultCase +public class RecordingMethodImplementationGeneratorSwitchBodyDefaultCase(SwitchBodyRecord record) : IMethodImplementationGeneratorSwitchBodyDefaultCase { - private readonly SwitchBodyRecord _record; - - public RecordingMethodImplementationGeneratorSwitchBodyDefaultCase(SwitchBodyRecord record) - { - _record = record; - } - public IMethodImplementationGenerator ReturnConstantValue(Func func) { - _record.HasDefaultCase = true; - return new RecordingMethodImplementationGenerator(_record); + record.HasDefaultCase = true; + return new RecordingMethodImplementationGenerator(record); } public IMethodImplementationGenerator UseBody(Func> func) { - _record.HasDefaultCase = true; - return new RecordingMethodImplementationGenerator(_record); + record.HasDefaultCase = true; + return new RecordingMethodImplementationGenerator(record); } } diff --git a/MattSourceGenHelpers.Abstractions/SwitchCase.cs b/MattSourceGenHelpers.Abstractions/SwitchCase.cs index 3357508..ba6bcd7 100644 --- a/MattSourceGenHelpers.Abstractions/SwitchCase.cs +++ b/MattSourceGenHelpers.Abstractions/SwitchCase.cs @@ -1,10 +1,7 @@ namespace MattSourceGenHelpers.Abstractions; [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] -public class SwitchCase( - object? arg1 = null - ) - : Attribute +public class SwitchCase(object? arg1) : Attribute { public object? Arg1 { get; } = arg1; -} +} \ No newline at end of file diff --git a/MattSourceGenHelpers.Examples/PiExampleFluent.cs b/MattSourceGenHelpers.Examples/PiExampleFluent.cs index e8f4610..3aaf019 100644 --- a/MattSourceGenHelpers.Examples/PiExampleFluent.cs +++ b/MattSourceGenHelpers.Examples/PiExampleFluent.cs @@ -12,7 +12,7 @@ static IMethodImplementationGenerator GetPiDecimal_Generator_Specialized() => Generate .Method().WithParameter().WithReturnType() .WithSwitchBody() - .ForCases(0, 1, 2, Integer.Range(300, 303)).ReturnConstantValue(decimalNumber => SlowMath.CalculatePiDecimal(decimalNumber)) + .ForCases(0, 1, 2, new[]{300, 301, 302, 303}).ReturnConstantValue(decimalNumber => SlowMath.CalculatePiDecimal(decimalNumber)) .ForDefaultCase().UseBody(decimalNumber => () => SlowMath.CalculatePiDecimal(decimalNumber)); } diff --git a/MattSourceGenHelpers.Generators/GeneratesMethodExecutionRuntime.cs b/MattSourceGenHelpers.Generators/GeneratesMethodExecutionRuntime.cs index 9d25978..3059ac0 100644 --- a/MattSourceGenHelpers.Generators/GeneratesMethodExecutionRuntime.cs +++ b/MattSourceGenHelpers.Generators/GeneratesMethodExecutionRuntime.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Runtime.Loader; using System.Text; +using MattSourceGenHelpers.Abstractions; namespace MattSourceGenHelpers.Generators; @@ -141,7 +142,7 @@ reference.Display is not null } object? recordingFactory = Activator.CreateInstance(recordingFactoryType); - PropertyInfo? currentGeneratorProperty = generatorStaticType.GetProperty(Consts.CurrentGeneratorPropertyName, BindingFlags.Public | BindingFlags.Static); + PropertyInfo? currentGeneratorProperty = generatorStaticType.GetProperty(Consts.CurrentGeneratorPropertyName, BindingFlags.NonPublic | BindingFlags.Static); currentGeneratorProperty?.SetValue(null, recordingFactory); string typeName = generatorMethod.ContainingType.ToDisplayString(); @@ -284,9 +285,9 @@ internal static IReadOnlyList GetAllUnimplementedPartialMethods(C private static SwitchBodyData ExtractSwitchBodyData(object lastRecord, ITypeSymbol returnType) { Type recordType = lastRecord.GetType(); - PropertyInfo? caseKeysProperty = recordType.GetProperty("CaseKeys"); - PropertyInfo? caseValuesProperty = recordType.GetProperty("CaseValues"); - PropertyInfo? hasDefaultProperty = recordType.GetProperty("HasDefaultCase"); + PropertyInfo? caseKeysProperty = recordType.GetProperty(nameof(SwitchBodyRecord.CaseKeys)); + PropertyInfo? caseValuesProperty = recordType.GetProperty(nameof(SwitchBodyRecord.CaseValues)); + PropertyInfo? hasDefaultProperty = recordType.GetProperty(nameof(SwitchBodyRecord.HasDefaultCase)); IList caseKeys = (caseKeysProperty?.GetValue(lastRecord) as IList) ?? new List(); IList caseValues = (caseValuesProperty?.GetValue(lastRecord) as IList) ?? new List(); @@ -392,7 +393,8 @@ private static string BuildDummyImplementation(IEnumerable partia string parameters = string.Join(", ", partialMethod.Parameters.Select(parameter => $"{parameter.Type.ToDisplayString()} {parameter.Name}")); builder.AppendLine($"{accessibility} {staticModifier}partial {returnType} {partialMethod.Name}({parameters}) {{"); - string throwStatement = $"throw new global::MattSourceGenHelpers.Abstractions.PartialMethodCalledDuringGenerationException(\"{partialMethod.Name}\", \"{partialMethod.ContainingType.Name}\");"; + string exceptionName = $"{Consts.AbstractionsAssemblyName}.{nameof(PartialMethodCalledDuringGenerationException)}"; + string throwStatement = $"throw new global::{exceptionName}(\"{partialMethod.Name}\", \"{partialMethod.ContainingType.Name}\");"; builder.AppendLine(throwStatement); builder.AppendLine("}"); diff --git a/MattSourceGenHelpers.Tests/DefaultCaseConstValue.cs b/MattSourceGenHelpers.Tests/DefaultCaseConstValue.cs new file mode 100644 index 0000000..f22c22c --- /dev/null +++ b/MattSourceGenHelpers.Tests/DefaultCaseConstValue.cs @@ -0,0 +1,49 @@ +using MattSourceGenHelpers.Abstractions; +// ReSharper disable ConvertClosureToMethodGroup + +namespace MattSourceGenHelpers.Tests; + +[TestFixture] +public class DefaultCaseConstValue +{ + [TestCase(0, 777)] + [TestCase(777, 777)] + [TestCase(123456789, 777)] + public void PiExampleLikeGenerator_ProducesExpectedRuntimeOutput(int decimalNumber, int expectedDigit) + { + int result = DefaultCaseConstValueClass.Foo(decimalNumber); + + Assert.That(result, Is.EqualTo(expectedDigit)); + } + + [Test] + public void PiExampleLikeGenerator_ProducesExpectedGeneratedCode() + { + string generatedCode = GeneratedCodeTestHelper.ReadGeneratedCode("DefaultCaseConstValueClass_Foo.g.cs"); + string expectedCode = """ + namespace MattSourceGenHelpers.Tests; + + static partial class DefaultCaseConstValueClass + { + public static partial int Foo(int decimalNumber) + { + switch (decimalNumber) + { + default: return 777; + } + } + } + """.ReplaceLineEndings("\n").TrimEnd(); + + Assert.That(generatedCode, Is.EqualTo(expectedCode)); + } +} + +public static partial class DefaultCaseConstValueClass +{ + public static partial int Foo(int decimalNumber); + + [GeneratesMethod(nameof(Foo))] + [SwitchDefault] + static Func Foo_Generator_Default() => decimalNumber => 777; +} diff --git a/MattSourceGenHelpers.Tests/DefaultCaseConstValueFluent.cs b/MattSourceGenHelpers.Tests/DefaultCaseConstValueFluent.cs new file mode 100644 index 0000000..ec5511c --- /dev/null +++ b/MattSourceGenHelpers.Tests/DefaultCaseConstValueFluent.cs @@ -0,0 +1,52 @@ +using MattSourceGenHelpers.Abstractions; +// ReSharper disable ConvertClosureToMethodGroup + +namespace MattSourceGenHelpers.Tests; + +[TestFixture] +public class DefaultCaseConstValueFluent +{ + [TestCase(0, 888)] + [TestCase(888, 888)] + [TestCase(123456789, 888)] + public void PiExampleLikeGenerator_ProducesExpectedRuntimeOutput(int decimalNumber, int expectedDigit) + { + int result = DefaultCaseConstValueFluentClass.Foo(decimalNumber); + + Assert.That(result, Is.EqualTo(expectedDigit)); + } + + [Test] + public void PiExampleLikeGenerator_ProducesExpectedGeneratedCode() + { + string generatedCode = GeneratedCodeTestHelper.ReadGeneratedCode("DefaultCaseConstValueFluentClass_Foo.g.cs"); + string expectedCode = """ + namespace MattSourceGenHelpers.Tests; + + static partial class DefaultCaseConstValueFluentClass + { + public static partial int Foo(int decimalNumber) + { + switch (decimalNumber) + { + default: return 888; + } + } + } + """.ReplaceLineEndings("\n").TrimEnd(); + + Assert.That(generatedCode, Is.EqualTo(expectedCode)); + } +} + +public static partial class DefaultCaseConstValueFluentClass +{ + public static partial int Foo(int decimalNumber); + + [GeneratesMethod(nameof(Foo))] + static IMethodImplementationGenerator Foo_Generator_Default() => + Generate + .Method().WithParameter().WithReturnType() + .WithSwitchBody() + .ForDefaultCase().ReturnConstantValue(_ => 888); +} diff --git a/MattSourceGenHelpers.Tests/PiExampleFluentTests.cs b/MattSourceGenHelpers.Tests/PiExampleFluentTests.cs index e301536..da38b4a 100644 --- a/MattSourceGenHelpers.Tests/PiExampleFluentTests.cs +++ b/MattSourceGenHelpers.Tests/PiExampleFluentTests.cs @@ -154,7 +154,7 @@ static IMethodImplementationGenerator GetPiDecimal_Generator() => Generate .Method().WithParameter().WithReturnType() .WithSwitchBody() - .ForCases(0, 1, 2, Integer.Range(300, 303)).ReturnConstantValue(decimalNumber => TestSlowMath.CalculatePiDecimal(decimalNumber)) + .ForCases(0, 1, 2, new[]{300, 301, 302, 303}).ReturnConstantValue(decimalNumber => TestSlowMath.CalculatePiDecimal(decimalNumber)) .ForDefaultCase().UseBody(decimalNumber => () => TestSlowMath.CalculatePiDecimal(decimalNumber)); } diff --git a/MattSourceGenHelpers.sln.DotSettings.user b/MattSourceGenHelpers.sln.DotSettings.user index 0d7ad3c..c8d9d72 100644 --- a/MattSourceGenHelpers.sln.DotSettings.user +++ b/MattSourceGenHelpers.sln.DotSettings.user @@ -4,12 +4,19 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded True True True - <SessionState ContinuousTestingMode="0" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + + <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <Solution /> </SessionState> + + + + + \ No newline at end of file