Skip to content
Merged
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
28 changes: 0 additions & 28 deletions benchmarks/Compono.Benchmarks/ArchitectureBenchmarks.cs

This file was deleted.

17 changes: 0 additions & 17 deletions benchmarks/Compono.Benchmarks/AutoFixtureComposer.cs

This file was deleted.

18 changes: 18 additions & 0 deletions benchmarks/Compono.Benchmarks/Baselines/AutoFixtureComposer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using AutoFixture;

namespace Compono.Benchmarks.Baselines;

/// <summary>
/// External-comparison reference point, per ADR-0034: AutoFixture is one comparison point
/// answering "what should a developer expect when migrating," not the suite's center. Stock
/// <c>Fixture</c>, no customization - an honest out-of-the-box comparison, not tuned to
/// artificially favor either library.
/// </summary>
public sealed class AutoFixtureComposer
{
private readonly Fixture _fixture = new();

/// <summary>Constructs an instance of <typeparamref name="T"/> via AutoFixture.</summary>
/// <typeparam name="T">The type to construct.</typeparam>
public T Compose<T>() => _fixture.Create<T>();
}
19 changes: 0 additions & 19 deletions benchmarks/Compono.Benchmarks/BenchmarkTypes.cs

This file was deleted.

26 changes: 22 additions & 4 deletions benchmarks/Compono.Benchmarks/Compono.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,32 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
</ItemGroup>

<!-- ADR-0034's SourceGeneration category drives ComponoIncrementalGenerator directly via
CSharpGeneratorDriver (not through an analyzer build reference), the same way
test/Compono.Generators.Tests does - needs a real compilation reference set to build
against, matching that project's own pattern exactly. -->
<ItemGroup Condition="'$(TargetFramework)' == 'net10.0'">
<PackageReference Include="Basic.Reference.Assemblies.Net100" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net11.0'">
<PackageReference Include="Basic.Reference.Assemblies.Net110" />
</ItemGroup>

<ItemGroup>
<!-- Referenced normally so benchmark code compiles against Composer/ICompositionPlan<T>. -->
<ProjectReference Include="..\..\src\Compono\Compono.csproj" />
<!-- Analyzer-only, so the generator actually runs against the types declared in this
project - matching how test/Compono.Generators.Tests and Compono.csproj itself
both reference Compono.Generators. -->
<!-- Both an analyzer (so the generator runs against this project's own composable types,
matching Compono.csproj's pattern) and a normal compile reference (so
SourceGeneration/GeneratorDriverBenchmarks.cs can drive ComponoIncrementalGenerator
directly in-process, matching Compono.Generators.Tests' pattern) - ADR-0034 needs
both from the same project, not two separate references to it. -->
<ProjectReference Include="..\..\src\Compono.Generators\Compono.Generators.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
OutputItemType="Analyzer" />
<!-- ConsumerScenarios/ProviderEnabledBenchmarks and FeatureOverhead/ProviderOverheadBenchmarks
exercise UseNSubstitute()/UseBogus() (ADR-0034) - no prior benchmark referenced either
package. -->
<ProjectReference Include="..\..\src\Compono.NSubstitute\Compono.NSubstitute.csproj" />
<ProjectReference Include="..\..\src\Compono.Bogus\Compono.Bogus.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using BenchmarkDotNet.Attributes;
using Compono.Benchmarks.Models;

namespace Compono.Benchmarks.ConsumerScenarios;

/// <summary>
/// What performance should a user expect from a profile with a package provider active - a
/// <c>Compono.Bogus</c>-enabled profile composing <see cref="MediumAggregate"/> (whose
/// <c>FirstName</c>/<c>LastName</c> members match Bogus's built-in convention allowlist), and a
/// <c>Compono.NSubstitute</c>-enabled profile composing <see cref="ProviderBackedModel"/> (whose
/// <see cref="IClock"/> member NSubstitute's stage-6 provider satisfies) - realistic usage, not
/// the isolated marginal cost <c>FeatureOverhead/ProviderOverheadBenchmarks</c> measures.
/// </summary>
[MemoryDiagnoser]
public class ProviderEnabledBenchmarks
{
private readonly Composer _bogusComposer = Composer.Create(builder => builder.UseBogus());
private readonly Composer _nsubstituteComposer = Composer.Create(builder => builder.UseNSubstitute());

/// <summary>Composes <see cref="MediumAggregate"/> with <c>UseBogus()</c> active.</summary>
[Benchmark]
public MediumAggregate BogusEnabledScenario() => _bogusComposer.Create<MediumAggregate>();

/// <summary>Composes <see cref="ProviderBackedModel"/> with <c>UseNSubstitute()</c> active.</summary>
[Benchmark]
public ProviderBackedModel NSubstituteEnabledScenario() => _nsubstituteComposer.Create<ProviderBackedModel>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using BenchmarkDotNet.Attributes;
using Compono.Benchmarks.Models;

namespace Compono.Benchmarks.ConsumerScenarios;

/// <summary>
/// What performance should a user expect composing each of ADR-0034's representative models in a
/// realistic application - no comparison baseline, just the absolute cost a consumer actually
/// pays for <c>Create&lt;T&gt;()</c> against each shape. This is the category most likely to
/// surface in public documentation, per ADR-0034.
/// </summary>
[MemoryDiagnoser]
public class RepresentativeModelBenchmarks
{
private readonly Composer _composer = Composer.Create();
private readonly Composer _largeCollectionComposer = Composer.Create(builder => builder.WithCollectionSize(100));

/// <summary>Composes the flat <see cref="SimplePoco"/> model.</summary>
[Benchmark]
public SimplePoco SimplePocoScenario() => _composer.Create<SimplePoco>();

/// <summary>Composes the moderately-nested <see cref="MediumAggregate"/> model.</summary>
[Benchmark]
public MediumAggregate MediumAggregateScenario() => _composer.Create<MediumAggregate>();

/// <summary>Composes the 8-level-deep <see cref="DeepGraph"/> model.</summary>
[Benchmark]
public DeepGraph DeepGraphScenario() => _composer.Create<DeepGraph>();

/// <summary>Composes <see cref="LargeCollection"/> with a 100-element collection size.</summary>
[Benchmark]
public LargeCollection LargeCollectionScenario() => _largeCollectionComposer.Create<LargeCollection>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using BenchmarkDotNet.Attributes;
using Compono.Benchmarks.Models;

namespace Compono.Benchmarks.ConsumerScenarios;

/// <summary>
/// What performance should a user expect from a shared value reused across sibling row
/// parameters - the mechanism <c>Compono.XunitV3</c>'s <c>[Shared]</c> attribute builds on, per
/// ADR-0021. Composed via <c>Composer.CreateRow</c>/<c>ResolveShared</c> directly (the same public
/// core API a test-framework integration uses) rather than depending on
/// <c>Compono.XunitV3</c> itself.
/// </summary>
[MemoryDiagnoser]
public class SharedValueBenchmarks
{
private readonly Composer _composer = Composer.Create();

/// <summary>
/// Composes one <see cref="SharedContext"/> row value plus two sibling consumers, both of
/// which nest it as an ordinary constructor parameter - the row's shared instance is
/// transparently reused by both, never composed independently.
/// </summary>
[Benchmark]
public (ConsumerOne One, ConsumerTwo Two) SharedContextAcrossRow()
{
var row = _composer.CreateRow(typeof(SharedValueBenchmarks));

row.ResolveShared<SharedContext>(new CompositionRequestDescriptor(
CompositionRequestKind.TestParameter, 0, "context", typeof(SharedValueBenchmarks), Nullability.NotNullable));

var one = row.Resolve<ConsumerOne>(new CompositionRequestDescriptor(
CompositionRequestKind.TestParameter, 1, "one", typeof(SharedValueBenchmarks), Nullability.NotNullable));
var two = row.Resolve<ConsumerTwo>(new CompositionRequestDescriptor(
CompositionRequestKind.TestParameter, 2, "two", typeof(SharedValueBenchmarks), Nullability.NotNullable));

return (one, two);
}
}
46 changes: 0 additions & 46 deletions benchmarks/Compono.Benchmarks/DeepGraphBenchmarks.cs

This file was deleted.

26 changes: 0 additions & 26 deletions benchmarks/Compono.Benchmarks/EcosystemBenchmarks.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using BenchmarkDotNet.Attributes;
using Compono.Benchmarks.Baselines;
using Compono.Benchmarks.Models;

namespace Compono.Benchmarks.ExternalComparison;

/// <summary>
/// What should a developer expect when migrating from AutoFixture, for the moderately-nested
/// <see cref="MediumAggregate"/> model - the nested-graph counterpart to
/// <see cref="SimplePocoComparisonBenchmarks"/>, giving AutoFixture real randomized-value-
/// generation work to do (unlike the flat <see cref="Models.SimplePoco"/> model).
/// </summary>
[MemoryDiagnoser]
public class MediumAggregateComparisonBenchmarks
{
private readonly Composer _composer = Composer.Create();
private readonly AutoFixtureComposer _autoFixture = new();

/// <summary>Composes <see cref="MediumAggregate"/> through the real resolution pipeline.</summary>
[Benchmark(Baseline = true)]
public MediumAggregate Generated() => _composer.Create<MediumAggregate>();

/// <summary>Constructs <see cref="MediumAggregate"/> via AutoFixture.</summary>
[Benchmark]
public MediumAggregate AutoFixture() => _autoFixture.Compose<MediumAggregate>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using BenchmarkDotNet.Attributes;
using Compono.Benchmarks.Baselines;
using Compono.Benchmarks.Models;

namespace Compono.Benchmarks.ExternalComparison;

/// <summary>
/// What should a developer expect when migrating from AutoFixture, for the flat
/// <see cref="SimplePoco"/> model - per ADR-0034, AutoFixture is one comparison point, not the
/// suite's center. Equivalent object graph, equivalent work - published honestly either way.
/// </summary>
[MemoryDiagnoser]
public class SimplePocoComparisonBenchmarks
{
private readonly Composer _composer = Composer.Create();
private readonly AutoFixtureComposer _autoFixture = new();

/// <summary>Composes <see cref="SimplePoco"/> through the real resolution pipeline.</summary>
[Benchmark(Baseline = true)]
public SimplePoco Generated() => _composer.Create<SimplePoco>();

/// <summary>Constructs <see cref="SimplePoco"/> via AutoFixture.</summary>
[Benchmark]
public SimplePoco AutoFixture() => _autoFixture.Compose<SimplePoco>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using BenchmarkDotNet.Attributes;
using Compono.Benchmarks.Models;

namespace Compono.Benchmarks.FeatureOverhead;

/// <summary>
/// How expensive is <c>UseBogus()</c>, on its own? Both arms pin <see cref="ProviderBackedModel.Clock"/>
/// identically (a plain registration - unrelated to what's being measured) and vary only how
/// <see cref="ProviderBackedModel.Email"/> is resolved: a stage-4 member rule (the baseline) vs.
/// <c>Compono.Bogus</c>'s stage-5 convention provider.
/// </summary>
[MemoryDiagnoser]
public class BogusOverheadBenchmarks
{
private readonly Composer _memberRule = Composer.Create(builder => builder
.Register<IClock>(_ => new FixedClock())
.For<ProviderBackedModel>().Member(x => x.Email).Use("fixed@example.com"));

private readonly Composer _bogus = Composer.Create(builder => builder
.Register<IClock>(_ => new FixedClock())
.UseBogus());

/// <summary>Resolves <c>Email</c> via a stage-4 member rule - the baseline <see cref="EmailViaBogus"/> is measured against.</summary>
[Benchmark(Baseline = true)]
public ProviderBackedModel EmailViaMemberRule() => _memberRule.Create<ProviderBackedModel>();

/// <summary>Resolves <c>Email</c> via <c>Compono.Bogus</c>'s stage-5 convention provider.</summary>
[Benchmark]
public ProviderBackedModel EmailViaBogus() => _bogus.Create<ProviderBackedModel>();
}
Loading