Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using EasySourceGenerators.Generators.DataBuilding;
using EasySourceGenerators.Generators.IncrementalGenerators;

namespace EasySourceGenerators.GeneratorTests;

[TestFixture]
public class BodyGenerationDataExtractorTests
{
[Test]
public void Extract_WithCompileTimeConstants_BodyReturningConstant_InvokesWithConstants()
{
DataMethodBodyGenerator generator = new DataMethodBodyGenerator(
new BodyGenerationData(
ReturnType: typeof(string),
ParametersTypes: [],
CompileTimeConstants: 42,
ReturnConstantValueFactory: (Func<int, string>)(constants => $"value_{constants}")));

FluentBodyResult result = BodyGenerationDataExtractor.Extract(generator, false);

Assert.That(result.ReturnValue, Is.EqualTo("value_42"));
Assert.That(result.IsVoid, Is.False);
}

[Test]
public void Extract_WithCompileTimeConstants_RuntimeBodyNoArgs_InvokesWithConstants()
{
DataMethodBodyGenerator generator = new DataMethodBodyGenerator(
new BodyGenerationData(
ReturnType: typeof(string),
ParametersTypes: [],
CompileTimeConstants: 10,
RuntimeDelegateBody: (Func<int, string>)(constants => $"body_{constants}")));

FluentBodyResult result = BodyGenerationDataExtractor.Extract(generator, false);

Assert.That(result.ReturnValue, Is.EqualTo("body_10"));
Assert.That(result.IsVoid, Is.False);
}

[Test]
public void Extract_WithCompileTimeConstants_RuntimeBodyWithAdditionalParams_ReturnsNullValue()
{
DataMethodBodyGenerator generator = new DataMethodBodyGenerator(
new BodyGenerationData(
ReturnType: typeof(string),
ParametersTypes: [typeof(int)],
CompileTimeConstants: 10,
RuntimeDelegateBody: (Func<int, int, string>)((constants, param) => $"{constants}_{param}")));

FluentBodyResult result = BodyGenerationDataExtractor.Extract(generator, false);

Assert.That(result.ReturnValue, Is.Null);
Assert.That(result.IsVoid, Is.False);
}

[Test]
public void Extract_WithoutConstants_BodyReturningConstant_InvokesWithoutArgs()
{
DataMethodBodyGenerator generator = new DataMethodBodyGenerator(
new BodyGenerationData(
ReturnType: typeof(int),
ParametersTypes: [],
ReturnConstantValueFactory: (Func<int>)(() => 99)));

FluentBodyResult result = BodyGenerationDataExtractor.Extract(generator, false);

Assert.That(result.ReturnValue, Is.EqualTo("99"));
}

[Test]
public void Extract_WithoutConstants_RuntimeBodyNoParams_InvokesDirectly()
{
DataMethodBodyGenerator generator = new DataMethodBodyGenerator(
new BodyGenerationData(
ReturnType: typeof(string),
ParametersTypes: [],
RuntimeDelegateBody: (Func<string>)(() => "hello")));

FluentBodyResult result = BodyGenerationDataExtractor.Extract(generator, false);

Assert.That(result.ReturnValue, Is.EqualTo("hello"));
}

[Test]
public void Extract_VoidReturnType_WithConstants_RuntimeBody_InvokesWithConstants()
{
string captured = "";
DataMethodBodyGenerator generator = new DataMethodBodyGenerator(
new BodyGenerationData(
ReturnType: typeof(void),
ParametersTypes: [],
CompileTimeConstants: "test",
RuntimeDelegateBody: (Action<string>)(constants => { captured = constants; })));

FluentBodyResult result = BodyGenerationDataExtractor.Extract(generator, true);

Assert.That(result.IsVoid, Is.True);
Assert.That(captured, Is.EqualTo("test"));
}

[Test]
public void Extract_NullBodyGenerationData_ReturnsNullReturnValue()
{
DataMethodBodyGenerator generator = new DataMethodBodyGenerator(
new BodyGenerationData(ReturnType: typeof(string)));

FluentBodyResult result = BodyGenerationDataExtractor.Extract(generator, false);

Assert.That(result.ReturnValue, Is.Null);
}

[Test]
public void Extract_WithCompileTimeConstants_ConstantFactoryTakesPriority()
{
DataMethodBodyGenerator generator = new DataMethodBodyGenerator(
new BodyGenerationData(
ReturnType: typeof(string),
ParametersTypes: [],
CompileTimeConstants: 5,
ReturnConstantValueFactory: (Func<int, string>)(constants => $"factory_{constants}"),
RuntimeDelegateBody: (Func<int, string>)(constants => $"body_{constants}")));

FluentBodyResult result = BodyGenerationDataExtractor.Extract(generator, false);

Assert.That(result.ReturnValue, Is.EqualTo("factory_5"));
}
}
194 changes: 194 additions & 0 deletions EasySourceGenerators.GeneratorTests/MethodBodyBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,198 @@ public void FullFluentChain_UseProvidedBody_ProducesCorrectData()
object? bodyValue = generator.Data.RuntimeDelegateBody!.DynamicInvoke();
Assert.That(bodyValue, Is.EqualTo(42));
}

[Test]
public void WithCompileTimeConstants_WithParam_ReturnsStage5WithConstants()
{
DataMethodBodyBuilderStage4<int, string> stage4 = new DataMethodBodyBuilderStage4<int, string>(
new BodyGenerationData(ReturnType: typeof(string), ParametersTypes: [typeof(int)]));

IMethodBodyBuilderStage5WithConstants<int, string, int> result = stage4.WithCompileTimeConstants(() => 42);

Assert.That(result, Is.TypeOf<DataMethodBodyBuilderStage5WithConstants<int, string, int>>());
DataMethodBodyBuilderStage5WithConstants<int, string, int> stage5 = (DataMethodBodyBuilderStage5WithConstants<int, string, int>)result;
Assert.That(stage5.Data.CompileTimeConstants, Is.EqualTo(42));
}

[Test]
public void WithCompileTimeConstants_NoArg_ReturnsStage5NoArgWithConstants()
{
DataMethodBodyBuilderStage4NoArg<string> stage4 = new DataMethodBodyBuilderStage4NoArg<string>(
new BodyGenerationData(ReturnType: typeof(string), ParametersTypes: []));

IMethodBodyBuilderStage5NoArgWithConstants<string, int> result = stage4.WithCompileTimeConstants(() => 99);

Assert.That(result, Is.TypeOf<DataMethodBodyBuilderStage5NoArgWithConstants<string, int>>());
DataMethodBodyBuilderStage5NoArgWithConstants<string, int> stage5 = (DataMethodBodyBuilderStage5NoArgWithConstants<string, int>)result;
Assert.That(stage5.Data.CompileTimeConstants, Is.EqualTo(99));
}

[Test]
public void WithCompileTimeConstants_ReturnVoid_ReturnsStage5ReturnVoidWithConstants()
{
DataMethodBodyBuilderStage4ReturnVoid<int> stage4 = new DataMethodBodyBuilderStage4ReturnVoid<int>(
new BodyGenerationData(ReturnType: typeof(void), ParametersTypes: [typeof(int)]));

IMethodBodyBuilderStage5ReturnVoidWithConstants<int, string> result = stage4.WithCompileTimeConstants(() => "test");

Assert.That(result, Is.TypeOf<DataMethodBodyBuilderStage5ReturnVoidWithConstants<int, string>>());
DataMethodBodyBuilderStage5ReturnVoidWithConstants<int, string> stage5 = (DataMethodBodyBuilderStage5ReturnVoidWithConstants<int, string>)result;
Assert.That(stage5.Data.CompileTimeConstants, Is.EqualTo("test"));
}

[Test]
public void WithCompileTimeConstants_ReturnVoidNoArg_ReturnsStage5ReturnVoidNoArgWithConstants()
{
DataMethodBodyBuilderStage4ReturnVoidNoArg stage4 = new DataMethodBodyBuilderStage4ReturnVoidNoArg(
new BodyGenerationData(ReturnType: typeof(void), ParametersTypes: []));

IMethodBodyBuilderStage5ReturnVoidNoArgWithConstants<int> result = stage4.WithCompileTimeConstants(() => 7);

Assert.That(result, Is.TypeOf<DataMethodBodyBuilderStage5ReturnVoidNoArgWithConstants<int>>());
DataMethodBodyBuilderStage5ReturnVoidNoArgWithConstants<int> stage5 = (DataMethodBodyBuilderStage5ReturnVoidNoArgWithConstants<int>)result;
Assert.That(stage5.Data.CompileTimeConstants, Is.EqualTo(7));
}

[Test]
public void Stage5WithConstants_UseProvidedBody_SetsRuntimeDelegateBody()
{
DataMethodBodyBuilderStage5WithConstants<int, string, int> stage5 = new DataMethodBodyBuilderStage5WithConstants<int, string, int>(
new BodyGenerationData(ReturnType: typeof(string), ParametersTypes: [typeof(int)], CompileTimeConstants: 42));

IMethodBodyGenerator result = stage5.UseProvidedBody((constants, param) => $"{constants}_{param}");

Assert.That(result, Is.TypeOf<DataMethodBodyGenerator>());
DataMethodBodyGenerator generator = (DataMethodBodyGenerator)result;
Assert.That(generator.Data.RuntimeDelegateBody, Is.Not.Null);
Assert.That(generator.Data.CompileTimeConstants, Is.EqualTo(42));
}

[Test]
public void Stage5WithConstants_BodyReturningConstant_SetsReturnConstantValueFactory()
{
DataMethodBodyBuilderStage5WithConstants<int, string, int> stage5 = new DataMethodBodyBuilderStage5WithConstants<int, string, int>(
new BodyGenerationData(ReturnType: typeof(string), ParametersTypes: [typeof(int)], CompileTimeConstants: 42));

IMethodBodyGenerator result = stage5.BodyReturningConstant(constants => $"value_{constants}");

Assert.That(result, Is.TypeOf<DataMethodBodyGenerator>());
DataMethodBodyGenerator generator = (DataMethodBodyGenerator)result;
Assert.That(generator.Data.ReturnConstantValueFactory, Is.Not.Null);
Assert.That(generator.Data.CompileTimeConstants, Is.EqualTo(42));
}

[Test]
public void Stage5NoArgWithConstants_UseProvidedBody_SetsRuntimeDelegateBody()
{
DataMethodBodyBuilderStage5NoArgWithConstants<string, int> stage5 = new DataMethodBodyBuilderStage5NoArgWithConstants<string, int>(
new BodyGenerationData(ReturnType: typeof(string), ParametersTypes: [], CompileTimeConstants: 10));

IMethodBodyGenerator result = stage5.UseProvidedBody(constants => $"value_{constants}");

Assert.That(result, Is.TypeOf<DataMethodBodyGenerator>());
DataMethodBodyGenerator generator = (DataMethodBodyGenerator)result;
Assert.That(generator.Data.RuntimeDelegateBody, Is.Not.Null);
Assert.That(generator.Data.CompileTimeConstants, Is.EqualTo(10));
}

[Test]
public void Stage5NoArgWithConstants_BodyReturningConstant_SetsReturnConstantValueFactory()
{
DataMethodBodyBuilderStage5NoArgWithConstants<string, int> stage5 = new DataMethodBodyBuilderStage5NoArgWithConstants<string, int>(
new BodyGenerationData(ReturnType: typeof(string), ParametersTypes: [], CompileTimeConstants: 10));

IMethodBodyGenerator result = stage5.BodyReturningConstant(constants => $"const_{constants}");

Assert.That(result, Is.TypeOf<DataMethodBodyGenerator>());
DataMethodBodyGenerator generator = (DataMethodBodyGenerator)result;
Assert.That(generator.Data.ReturnConstantValueFactory, Is.Not.Null);
Assert.That(generator.Data.CompileTimeConstants, Is.EqualTo(10));
}

[Test]
public void Stage5ReturnVoidWithConstants_UseProvidedBody_SetsRuntimeDelegateBody()
{
DataMethodBodyBuilderStage5ReturnVoidWithConstants<int, string> stage5 = new DataMethodBodyBuilderStage5ReturnVoidWithConstants<int, string>(
new BodyGenerationData(ReturnType: typeof(void), ParametersTypes: [typeof(int)], CompileTimeConstants: "ctx"));

IMethodBodyGenerator result = stage5.UseProvidedBody((constants, param) => { });

Assert.That(result, Is.TypeOf<DataMethodBodyGenerator>());
DataMethodBodyGenerator generator = (DataMethodBodyGenerator)result;
Assert.That(generator.Data.RuntimeDelegateBody, Is.Not.Null);
Assert.That(generator.Data.CompileTimeConstants, Is.EqualTo("ctx"));
}

[Test]
public void Stage5ReturnVoidNoArgWithConstants_UseProvidedBody_SetsRuntimeDelegateBody()
{
DataMethodBodyBuilderStage5ReturnVoidNoArgWithConstants<string> stage5 = new DataMethodBodyBuilderStage5ReturnVoidNoArgWithConstants<string>(
new BodyGenerationData(ReturnType: typeof(void), ParametersTypes: [], CompileTimeConstants: "ctx"));

IMethodBodyGenerator result = stage5.UseProvidedBody(constants => { });

Assert.That(result, Is.TypeOf<DataMethodBodyGenerator>());
DataMethodBodyGenerator generator = (DataMethodBodyGenerator)result;
Assert.That(generator.Data.RuntimeDelegateBody, Is.Not.Null);
Assert.That(generator.Data.CompileTimeConstants, Is.EqualTo("ctx"));
}

[Test]
public void FullFluentChain_WithConstants_NoArg_BodyReturningConstant_ProducesCorrectData()
{
DataGeneratorsFactory factory = new DataGeneratorsFactory();

IMethodBodyGenerator result = factory.StartFluentApiBuilderForBody()
.ForMethod()
.WithReturnType<string>()
.WithNoParameters()
.WithCompileTimeConstants(() => 42)
.BodyReturningConstant(constants => $"value_{constants}");

Assert.That(result, Is.TypeOf<DataMethodBodyGenerator>());
DataMethodBodyGenerator generator = (DataMethodBodyGenerator)result;
Assert.That(generator.Data.ReturnType, Is.EqualTo(typeof(string)));
Assert.That(generator.Data.ParametersTypes, Is.Empty);
Assert.That(generator.Data.CompileTimeConstants, Is.EqualTo(42));
Assert.That(generator.Data.ReturnConstantValueFactory, Is.Not.Null);
object? constantValue = generator.Data.ReturnConstantValueFactory!.DynamicInvoke(42);
Assert.That(constantValue, Is.EqualTo("value_42"));
}

[Test]
public void FullFluentChain_WithConstants_WithParam_UseProvidedBody_ProducesCorrectData()
{
DataGeneratorsFactory factory = new DataGeneratorsFactory();

IMethodBodyGenerator result = factory.StartFluentApiBuilderForBody()
.ForMethod()
.WithReturnType<int>()
.WithParameter<int>()
.WithCompileTimeConstants(() => new { Offset = 100 })
.UseProvidedBody((constants, param) => constants.Offset + param);

Assert.That(result, Is.TypeOf<DataMethodBodyGenerator>());
DataMethodBodyGenerator generator = (DataMethodBodyGenerator)result;
Assert.That(generator.Data.ReturnType, Is.EqualTo(typeof(int)));
Assert.That(generator.Data.ParametersTypes, Is.EqualTo(new[] { typeof(int) }));
Assert.That(generator.Data.CompileTimeConstants, Is.Not.Null);
Assert.That(generator.Data.RuntimeDelegateBody, Is.Not.Null);
}

[Test]
public void WithCompileTimeConstants_FactoryIsInvokedImmediately()
{
int invocationCount = 0;
DataMethodBodyBuilderStage4NoArg<string> stage4 = new DataMethodBodyBuilderStage4NoArg<string>(
new BodyGenerationData(ReturnType: typeof(string), ParametersTypes: []));

stage4.WithCompileTimeConstants(() =>
{
invocationCount++;
return 42;
});

Assert.That(invocationCount, Is.EqualTo(1));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public IMethodBodyBuilderStage4<TParam1, T> WithParameter<TParam1>() =>

public record DataMethodBodyBuilderStage4<TParam1, TReturnType>(BodyGenerationData Data) : IMethodBodyBuilderStage4<TParam1, TReturnType>
{
public IMethodBodyBuilderStage5WithConstants<TParam1, TReturnType, TConstants> WithCompileTimeConstants<TConstants>(Func<TConstants> compileTimeConstantsFactory) =>
new DataMethodBodyBuilderStage5WithConstants<TParam1, TReturnType, TConstants>(Data with { CompileTimeConstants = compileTimeConstantsFactory() });

public IMethodBodyGenerator UseProvidedBody(Func<TParam1, TReturnType> body) => new DataMethodBodyGenerator(Data with { RuntimeDelegateBody = body });

public IMethodBodyGenerator BodyReturningConstant(Func<TReturnType> constantValueFactory) =>
Expand All @@ -46,6 +49,9 @@ public IMethodBodyGenerator BodyReturningConstant(Func<TReturnType> constantValu

public record DataMethodBodyBuilderStage4NoArg<TReturnType>(BodyGenerationData Data) : IMethodBodyBuilderStage4NoArg<TReturnType>
{
public IMethodBodyBuilderStage5NoArgWithConstants<TReturnType, TConstants> WithCompileTimeConstants<TConstants>(Func<TConstants> compileTimeConstantsFactory) =>
new DataMethodBodyBuilderStage5NoArgWithConstants<TReturnType, TConstants>(Data with { CompileTimeConstants = compileTimeConstantsFactory() });

public IMethodBodyGenerator UseProvidedBody(Func<TReturnType> body) => new DataMethodBodyGenerator(Data with { RuntimeDelegateBody = body });

public IMethodBodyGenerator BodyReturningConstant(Func<TReturnType> constantValueFactory) =>
Expand All @@ -54,10 +60,42 @@ public IMethodBodyGenerator BodyReturningConstant(Func<TReturnType> constantValu

public record DataMethodBodyBuilderStage4ReturnVoid<TParam1>(BodyGenerationData BodyGenerationData) : IMethodBodyBuilderStage4ReturnVoid<TParam1>
{
public IMethodBodyBuilderStage5ReturnVoidWithConstants<TParam1, TConstants> WithCompileTimeConstants<TConstants>(Func<TConstants> compileTimeConstantsFactory) =>
new DataMethodBodyBuilderStage5ReturnVoidWithConstants<TParam1, TConstants>(BodyGenerationData with { CompileTimeConstants = compileTimeConstantsFactory() });

public IMethodBodyGenerator UseProvidedBody(Action<TParam1> body) => new DataMethodBodyGenerator(BodyGenerationData with { RuntimeDelegateBody = body });
}

public record DataMethodBodyBuilderStage4ReturnVoidNoArg(BodyGenerationData BodyGenerationData) : IMethodBodyBuilderStage4ReturnVoidNoArg
{
public IMethodBodyBuilderStage5ReturnVoidNoArgWithConstants<TConstants> WithCompileTimeConstants<TConstants>(Func<TConstants> compileTimeConstantsFactory) =>
new DataMethodBodyBuilderStage5ReturnVoidNoArgWithConstants<TConstants>(BodyGenerationData with { CompileTimeConstants = compileTimeConstantsFactory() });

public IMethodBodyGenerator UseProvidedBody(Action body) => new DataMethodBodyGenerator(BodyGenerationData with { RuntimeDelegateBody = body });
}

public record DataMethodBodyBuilderStage5WithConstants<TParam1, TReturnType, TConstants>(BodyGenerationData Data) : IMethodBodyBuilderStage5WithConstants<TParam1, TReturnType, TConstants>
{
public IMethodBodyGenerator UseProvidedBody(Func<TConstants, TParam1, TReturnType> body) => new DataMethodBodyGenerator(Data with { RuntimeDelegateBody = body });

public IMethodBodyGenerator BodyReturningConstant(Func<TConstants, TReturnType> constantValueFactory) =>
new DataMethodBodyGenerator(Data with { ReturnConstantValueFactory = constantValueFactory });
}

public record DataMethodBodyBuilderStage5NoArgWithConstants<TReturnType, TConstants>(BodyGenerationData Data) : IMethodBodyBuilderStage5NoArgWithConstants<TReturnType, TConstants>
{
public IMethodBodyGenerator UseProvidedBody(Func<TConstants, TReturnType> body) => new DataMethodBodyGenerator(Data with { RuntimeDelegateBody = body });

public IMethodBodyGenerator BodyReturningConstant(Func<TConstants, TReturnType> constantValueFactory) =>
new DataMethodBodyGenerator(Data with { ReturnConstantValueFactory = constantValueFactory });
}

public record DataMethodBodyBuilderStage5ReturnVoidWithConstants<TParam1, TConstants>(BodyGenerationData Data) : IMethodBodyBuilderStage5ReturnVoidWithConstants<TParam1, TConstants>
{
public IMethodBodyGenerator UseProvidedBody(Action<TConstants, TParam1> body) => new DataMethodBodyGenerator(Data with { RuntimeDelegateBody = body });
}

public record DataMethodBodyBuilderStage5ReturnVoidNoArgWithConstants<TConstants>(BodyGenerationData Data) : IMethodBodyBuilderStage5ReturnVoidNoArgWithConstants<TConstants>
{
public IMethodBodyGenerator UseProvidedBody(Action<TConstants> body) => new DataMethodBodyGenerator(Data with { RuntimeDelegateBody = body });
}
Loading