Skip to content

Commit 19efc80

Browse files
max-charlambCopilot
andcommitted
Refactor test Builder to use version-based contract resolution
TestPlaceholderTarget.Builder now defaults to CoreCLRContracts.Register and supports AddContract<T>(version) for version-based resolution and AddMockContract<T>(mock) for injecting test doubles. TestContractRegistry supports Register, SetVersion, and SetMock with proper version lookup. Migrated 5 Builder-pattern test files from factory lambdas to version-based contract resolution. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 715c53c commit 19efc80

6 files changed

Lines changed: 67 additions & 24 deletions

File tree

src/native/managed/cdac/tests/AuxiliarySymbolsTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ private static Target CreateTarget(
9191
.AddGlobals(
9292
(Constants.Globals.AuxiliarySymbols, arrayAddress),
9393
(Constants.Globals.AuxiliarySymbolCount, countFragment.Address))
94-
.AddContract<IPlatformMetadata>(_ => Mock.Of<IPlatformMetadata>(p => p.GetCodePointerFlags() == default(CodePointerFlags)))
95-
.AddContract<IAuxiliarySymbols>(static target => (IAuxiliarySymbols)new AuxiliarySymbols_1(target))
94+
.AddMockContract<IPlatformMetadata>(Mock.Of<IPlatformMetadata>(p => p.GetCodePointerFlags() == default(CodePointerFlags)))
95+
.AddContract<IAuxiliarySymbols>(version: 1)
9696
.Build();
9797
}
9898

src/native/managed/cdac/tests/DebuggerTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ private static TestPlaceholderTarget BuildTarget(
6565
builder.AddGlobals((Constants.Globals.MetadataUpdatesApplied, metadataFrag.Address));
6666
}
6767

68-
builder.AddContract<IDebugger>(target => (IDebugger)new Debugger_1(target));
68+
builder.AddContract<IDebugger>(version: 1);
6969

7070
return builder.Build();
7171
}
@@ -82,7 +82,7 @@ private static TestPlaceholderTarget BuildNullDebuggerTarget(MockTarget.Architec
8282
helpers.WritePointer(debuggerPtrFrag.Data, 0);
8383
memBuilder.AddHeapFragment(debuggerPtrFrag);
8484
builder.AddGlobals((Constants.Globals.Debugger, debuggerPtrFrag.Address));
85-
builder.AddContract<IDebugger>(target => (IDebugger)new Debugger_1(target));
85+
builder.AddContract<IDebugger>(version: 1);
8686

8787
return builder.Build();
8888
}

src/native/managed/cdac/tests/GCTests.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,7 @@ public static TestPlaceholderTarget.Builder AddGCHeapWks(
142142
GCHeapBuilder config = new();
143143
configure(config);
144144
BuildWksHeap(targetBuilder, config);
145-
targetBuilder.AddContract<IGC>(static target =>
146-
(IGC)new GC_1(target));
145+
targetBuilder.AddContract<IGC>(version: 1);
147146
return targetBuilder;
148147
}
149148

@@ -155,8 +154,7 @@ public static TestPlaceholderTarget.Builder AddGCHeapSvr(
155154
GCHeapBuilder config = new();
156155
configure(config);
157156
heapAddress = BuildSvrHeap(targetBuilder, config);
158-
targetBuilder.AddContract<IGC>(static target =>
159-
(IGC)new GC_1(target));
157+
targetBuilder.AddContract<IGC>(version: 1);
160158
return targetBuilder;
161159
}
162160

src/native/managed/cdac/tests/ReJITTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ private static ReJITContractContext CreateReJITContract(
4040
TestPlaceholderTarget target = targetBuilder
4141
.AddTypes(CreateContractTypes(rejitBuilder))
4242
.AddGlobals((nameof(Constants.Globals.ProfilerControlBlock), rejitBuilder.ProfilerControlBlockGlobalAddress))
43-
.AddContract<IReJIT>(static target => (IReJIT)new ReJIT_1(target))
44-
.AddContract<ICodeVersions>(_ => mockCodeVersions.Object)
43+
.AddContract<IReJIT>(version: 1)
44+
.AddMockContract<ICodeVersions>(mockCodeVersions.Object)
4545
.Build();
4646
return new ReJITContractContext(target.Contracts.ReJIT, target);
4747
}

src/native/managed/cdac/tests/TestPlaceholderTarget.cs

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ internal class Builder
5757
private readonly Dictionary<DataType, Target.TypeInfo> _types = new();
5858
private readonly List<(string Name, ulong Value)> _globals = new();
5959
private readonly List<(string Name, string Value)> _globalStrings = new();
60-
private readonly List<(Type Type, Func<Target, IContract> Factory)> _contractFactories = new();
60+
private readonly List<Action<TestContractRegistry>> _contractSetups = new();
61+
private Action<ContractRegistry> _registrations = CoreCLRContracts.Register;
6162

6263
public Builder(MockTarget.Architecture arch)
6364
{
@@ -86,9 +87,21 @@ public Builder AddGlobalStrings(params (string Name, string Value)[] globalStrin
8687
return this;
8788
}
8889

89-
public Builder AddContract<TContract>(Func<Target, TContract> factory) where TContract : IContract
90+
public Builder UseRegistrations(Action<ContractRegistry> registrations)
9091
{
91-
_contractFactories.Add((typeof(TContract), target => factory(target)));
92+
_registrations = registrations;
93+
return this;
94+
}
95+
96+
public Builder AddContract<TContract>(int version) where TContract : IContract
97+
{
98+
_contractSetups.Add(registry => registry.SetVersion<TContract>(version));
99+
return this;
100+
}
101+
102+
public Builder AddMockContract<TContract>(TContract mock) where TContract : IContract
103+
{
104+
_contractSetups.Add(registry => registry.SetMock(mock));
92105
return this;
93106
}
94107

@@ -102,8 +115,12 @@ public TestPlaceholderTarget Build()
102115
_globalStrings.ToArray());
103116

104117
var registry = new TestContractRegistry();
105-
foreach (var (type, factory) in _contractFactories)
106-
registry.Add(type, new Lazy<IContract>(() => factory(target)));
118+
registry.SetTarget(target);
119+
_registrations(registry);
120+
121+
foreach (var setup in _contractSetups)
122+
setup(registry);
123+
107124
target.SetContracts(registry);
108125

109126
return target;
@@ -457,20 +474,48 @@ public void Clear()
457474

458475
private sealed class TestContractRegistry : ContractRegistry
459476
{
460-
private readonly Dictionary<Type, Lazy<IContract>> _contracts = new();
477+
private readonly Dictionary<(Type, int), Func<Target, IContract>> _creators = new();
478+
private readonly Dictionary<Type, int> _versions = new();
479+
private readonly Dictionary<Type, IContract> _mocks = new();
480+
private readonly Dictionary<Type, IContract> _resolved = new();
481+
private Target _target;
482+
483+
public void SetTarget(Target target) => _target = target;
484+
485+
public void SetVersion<TContract>(int version) where TContract : IContract
486+
=> _versions[typeof(TContract)] = version;
461487

462-
public void Add(Type type, Lazy<IContract> contract) => _contracts[type] = contract;
488+
public void SetMock<TContract>(TContract mock) where TContract : IContract
489+
=> _mocks[typeof(TContract)] = mock;
490+
491+
public override void Register<TContract>(int version, Func<Target, TContract> creator)
492+
=> _creators[(typeof(TContract), version)] = t => creator(t);
463493

464494
public override TContract GetContract<TContract>()
465495
{
466-
if (_contracts.TryGetValue(typeof(TContract), out var lazy))
467-
return (TContract)lazy.Value;
496+
if (_resolved.TryGetValue(typeof(TContract), out var cached))
497+
return (TContract)cached;
468498

469-
throw new NotImplementedException($"Contract {typeof(TContract).Name} is not registered.");
470-
}
499+
IContract contract;
500+
if (_mocks.TryGetValue(typeof(TContract), out var mock))
501+
{
502+
contract = mock;
503+
}
504+
else if (_versions.TryGetValue(typeof(TContract), out int version))
505+
{
506+
if (!_creators.TryGetValue((typeof(TContract), version), out var creator))
507+
throw new NotImplementedException($"No implementation registered for contract '{typeof(TContract).Name}' version {version}.");
471508

472-
public override void Register<TContract>(int version, Func<Target, TContract> creator)
473-
=> throw new NotSupportedException("TestContractRegistry does not support dynamic registration. Use SetContracts to configure contracts for testing.");
509+
contract = creator(_target);
510+
}
511+
else
512+
{
513+
throw new NotImplementedException($"Contract {typeof(TContract).Name} is not registered. Use AddContract<T>(version) or AddMockContract<T>(mock) on the Builder.");
514+
}
515+
516+
_resolved[typeof(TContract)] = contract;
517+
return (TContract)contract;
518+
}
474519

475520
public override void Flush() { }
476521
}

src/native/managed/cdac/tests/ThreadTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ private static TestPlaceholderTarget CreateTarget(
2525
(nameof(Constants.Globals.ThreadStore), threadBuilder.ThreadStoreGlobalAddress),
2626
(nameof(Constants.Globals.FinalizerThread), threadBuilder.FinalizerThreadGlobalAddress),
2727
(nameof(Constants.Globals.GCThread), threadBuilder.GCThreadGlobalAddress))
28-
.AddContract<IThread>(static target => (IThread)new Thread_1(target))
28+
.AddContract<IThread>(version: 1)
2929
.Build();
3030

3131

0 commit comments

Comments
 (0)