Skip to content

Commit 5cc4434

Browse files
perkopsPer Kops
authored andcommitted
test(member-data): add failing negative promotion test across different interfaces
1 parent 2a44894 commit 5cc4434

File tree

5 files changed

+65
-0
lines changed

5 files changed

+65
-0
lines changed

test/Atc.Test.Tests/MemberAutoNSubstituteDataAttributeTests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,35 @@ public void MemberData_SuppliesValueEarlier_ReusedByLaterFrozenParameter(
8080
{
8181
yield return [Substitute.For<ISampleInterface>()];
8282
}
83+
84+
// Negative promotion scenario
85+
// We provide an earlier argument typed as IFirstInterface whose concrete instance also
86+
// implements ISecondInterface. The later parameter is [Frozen] ISecondInterface. Desired
87+
// invariant: the framework should NOT promote the earlier IFirstInterface value to satisfy
88+
// the frozen ISecondInterface; a distinct instance should be generated/injected instead.
89+
// Current promotion logic (Type.IsInstanceOfType) is broad and WILL incorrectly reuse it.
90+
// This test therefore initially fails (red) and will pass after tightening promotion logic
91+
// in the upcoming refactor (shared frozen helper with exact-type matching / index mapping).
92+
[Theory]
93+
[MemberAutoNSubstituteData(nameof(DualInterfaceProvidedData))]
94+
public void MemberData_DifferentInterface_NotPromoted(
95+
IFirstInterface first,
96+
[Frozen] ISecondInterface second,
97+
SecondInterfaceDependant dependant)
98+
{
99+
first.Should().NotBeNull();
100+
second.Should().NotBeNull();
101+
dependant.Should().NotBeNull();
102+
103+
// Guard: dependant wired to the frozen instance.
104+
dependant.Dependency.Should().BeSameAs(second);
105+
106+
// Specification: these should NOT be the same instance
107+
second.Should().NotBeSameAs(first);
108+
}
109+
110+
public static IEnumerable<object?[]> DualInterfaceProvidedData()
111+
{
112+
yield return [new DualInterfaceImpl { Name = "n", Description = "d" }];
113+
}
83114
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Atc.Test.Tests.SampleTypes;
2+
3+
// Implements both interfaces so underlying instance satisfies each, allowing us to
4+
// detect overly-broad promotion logic that reuses an earlier IFirstInterface value
5+
// for a later [Frozen] ISecondInterface parameter.
6+
public class DualInterfaceImpl : IFirstInterface, ISecondInterface
7+
{
8+
public string? Name { get; set; }
9+
10+
public string? Description { get; set; }
11+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace Atc.Test.Tests.SampleTypes;
2+
3+
public interface IFirstInterface
4+
{
5+
string? Name { get; set; }
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace Atc.Test.Tests.SampleTypes;
2+
3+
public interface ISecondInterface
4+
{
5+
string? Description { get; set; }
6+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Atc.Test.Tests.SampleTypes;
2+
3+
public class SecondInterfaceDependant
4+
{
5+
public SecondInterfaceDependant(ISecondInterface dependency)
6+
{
7+
Dependency = dependency;
8+
}
9+
10+
public ISecondInterface Dependency { get; }
11+
}

0 commit comments

Comments
 (0)