Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 6 additions & 3 deletions SourceGenerationDebug.props
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<Project>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>SourceGeneratedViewer</CompilerGeneratedFilesOutputPath>
<EmitCompilerGeneratedFiles Condition="'$(EnableSourceGenerationDebug)' == 'true'">true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath Condition="'$(EmitCompilerGeneratedFiles)' == 'true' AND '$(CompilerGeneratedFilesOutputPath)' == ''">SourceGeneratedViewer</CompilerGeneratedFilesOutputPath>
</PropertyGroup>

<ItemGroup>
<Compile Remove="SourceGeneratedViewer\**" />
<None Include="SourceGeneratedViewer\**" />
</ItemGroup>

<ItemGroup Condition="'$(EmitCompilerGeneratedFiles)' == 'true'">
<None Include="SourceGeneratedViewer\**" Exclude="@(None)" />
</ItemGroup>
</Project>
21 changes: 21 additions & 0 deletions TUnit.Engine.Tests/Issue5753Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Shouldly;
using TUnit.Engine.Tests.Enums;

namespace TUnit.Engine.Tests;

public class Issue5753Tests(TestMode testMode) : InvokableTestBase(testMode)
{
[Test]
public async Task ReflectionPropertyInjection_DoesNotOverwriteExistingValue()
{
await RunTestsWithFilter(
"/*/*/Issue5753ReflectionPropertyInjectionTests/*",
[
result => result.ResultSummary.Outcome.ShouldBe("Completed"),
result => result.ResultSummary.Counters.Total.ShouldBe(1),
result => result.ResultSummary.Counters.Passed.ShouldBe(1),
result => result.ResultSummary.Counters.Failed.ShouldBe(0),
result => result.ResultSummary.Counters.NotExecuted.ShouldBe(0)
]);
}
}
5 changes: 5 additions & 0 deletions TUnit.Engine/Services/PropertyInjector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,11 @@ private async Task InjectReflectionPropertyAsync(
ConcurrentDictionary<object, byte> visitedObjects,
CancellationToken cancellationToken)
{
if (property.CanRead && property.GetValue(instance) != null)
{
return;
}

var testContext = TestContext.Current;
var propertySetter = PropertySetterFactory.CreateSetter(property);

Expand Down
41 changes: 41 additions & 0 deletions TUnit.TestProject/Bugs/5753/Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using TUnit.Core.Interfaces;
using TUnit.TestProject.Attributes;

namespace TUnit.TestProject.Bugs._5753;

[EngineTest(ExpectedResult.Pass)]
public class Issue5753ReflectionPropertyInjectionTests
{
[Test]
[ClassDataSource<Issue5753Container>]
public async Task InjectedProperty_IsNotResolvedAgain_WhenAlreadySet(Issue5753Container container)
{
await Assert.That(container.Service).IsNotNull();
await Assert.That(container.Service.InstanceNumber).IsEqualTo(1);
await Assert.That(Issue5753InjectedService.InstancesCreated).IsEqualTo(1);
await Assert.That(container.Service.IsInitialized).IsTrue();
}
}

public class Issue5753Container
{
[ClassDataSource<Issue5753InjectedService>]
public Issue5753InjectedService Service { get; set; } = null!;
}

public class Issue5753InjectedService : IAsyncInitializer
{
private static int _instancesCreated;

public static int InstancesCreated => Volatile.Read(ref _instancesCreated);

public int InstanceNumber { get; } = Interlocked.Increment(ref _instancesCreated);

public bool IsInitialized { get; private set; }

public Task InitializeAsync()
{
IsInitialized = true;
return Task.CompletedTask;
}
}
9 changes: 4 additions & 5 deletions TestProject.props
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,11 @@
<None Include="SourceGeneratedViewer\**" />
</ItemGroup>

<!-- Always clean SourceGeneratedViewer\ on local builds when the folder exists.
When EmitCompilerGeneratedFiles=true, this gives a fresh dump per build.
When EmitCompilerGeneratedFiles=false (the default), this clears stale files
left over from a prior opt-in build. CI runners are ephemeral, so skip. -->
<!-- Clean SourceGeneratedViewer\ only when generator output is being emitted.
Stale files are excluded from compilation unconditionally above, so normal
local builds should not fail because an ignored viewer tree is locked. -->
<Target Name="CleanSourceGeneratedViewer" BeforeTargets="BeforeBuild"
Condition="'$(ContinuousIntegrationBuild)' != 'true' AND Exists('$(ProjectDir)SourceGeneratedViewer')">
Condition="'$(ContinuousIntegrationBuild)' != 'true' AND '$(EmitCompilerGeneratedFiles)' == 'true' AND Exists('$(ProjectDir)SourceGeneratedViewer')">
<ItemGroup>
<FilesToDelete Include="$(ProjectDir)SourceGeneratedViewer\**\*" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"sdk": {
"version": "10.0.203",
"rollForward": "latestMajor",
"rollForward": "latestFeature",
"allowPrerelease": true
},
"test": {
Expand Down
Loading