diff --git a/src/BenchmarkDotNet/Toolchains/Results/ExecuteResult.cs b/src/BenchmarkDotNet/Toolchains/Results/ExecuteResult.cs index 76d9c41cd7..d37ad30f07 100644 --- a/src/BenchmarkDotNet/Toolchains/Results/ExecuteResult.cs +++ b/src/BenchmarkDotNet/Toolchains/Results/ExecuteResult.cs @@ -64,6 +64,18 @@ internal ExecuteResult(List measurements, GcStats gcStats, Threadin ExceptionFrequency = exceptionFrequency; } + internal ExecuteResult(List measurements) + { + FoundExecutable = true; + ExitCode = 0; + errors = new List(); + PrefixedLines = Array.Empty(); + this.measurements = measurements; + GcStats = GcStats.Empty; + ThreadingStats = ThreadingStats.Empty; + ExceptionFrequency = 0; + } + internal static ExecuteResult FromRunResults(RunResults runResults, int exitCode) => exitCode != 0 ? CreateFailed(exitCode) @@ -72,6 +84,13 @@ internal static ExecuteResult FromRunResults(RunResults runResults, int exitCode internal static ExecuteResult CreateFailed(int exitCode = -1) => new ExecuteResult(false, exitCode, default, Array.Empty(), Array.Empty(), Array.Empty(), 0); + internal static ExecuteResult CreateFailed(string error) + { + var result = new ExecuteResult(false, -1, default, Array.Empty(), Array.Empty(), Array.Empty(), 0); + result.errors.Add(error); + return result; + } + public override string ToString() => "ExecuteResult: " + (FoundExecutable ? "Found executable" : "Executable not found"); public void LogIssues(ILogger logger, BuildResult buildResult) diff --git a/tests/BenchmarkDotNet.Tests/Columns/RatioColumnTest.cs b/tests/BenchmarkDotNet.Tests/Columns/RatioColumnTest.cs new file mode 100644 index 0000000000..319d03741a --- /dev/null +++ b/tests/BenchmarkDotNet.Tests/Columns/RatioColumnTest.cs @@ -0,0 +1,50 @@ +using System; +using System.Linq; +using System.Xml.Linq; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Reports; +using BenchmarkDotNet.Tests.Mocks; +using BenchmarkDotNet.Tests.Mocks.Toolchain; +using Xunit; +using Xunit.Abstractions; + +namespace BenchmarkDotNet.Tests.Columns +{ + public class RatioColumnTest + { + private readonly ITestOutputHelper output; + + public RatioColumnTest(ITestOutputHelper output) + { + this.output = output; + } + + [Fact] + public void RatioColumnTest01() + { + var summary = MockRunner.Run(output, name => name switch + { + "Foo" => new double[] { 2, 2, 2 }, + "Bar" => new double[] { 4, 4, 4 }, + _ => throw new InvalidOperationException() + }); + + var ratioColumn = summary.GetColumns().FirstOrDefault(column => column.ColumnName == "Ratio"); + Assert.NotNull(ratioColumn); + + var fooCase = summary.BenchmarksCases.First(c => c.Descriptor.WorkloadMethod.Name == "Foo"); + var barCase = summary.BenchmarksCases.First(c => c.Descriptor.WorkloadMethod.Name == "Bar"); + Assert.Equal("1.00", ratioColumn.GetValue(summary, fooCase)); + Assert.Equal("2.00", ratioColumn.GetValue(summary, barCase)); + } + + public class BenchmarkClass + { + [Benchmark(Baseline = true)] + public void Foo() { } + + [Benchmark] + public void Bar() { } + } + } +} \ No newline at end of file diff --git a/tests/BenchmarkDotNet.Tests/Mocks/MockRunner.cs b/tests/BenchmarkDotNet.Tests/Mocks/MockRunner.cs new file mode 100644 index 0000000000..c8a2a8e42b --- /dev/null +++ b/tests/BenchmarkDotNet.Tests/Mocks/MockRunner.cs @@ -0,0 +1,48 @@ +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Engines; +using BenchmarkDotNet.Exporters; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Loggers; +using BenchmarkDotNet.Reports; +using BenchmarkDotNet.Running; +using BenchmarkDotNet.Tests.Mocks.Toolchain; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit.Abstractions; + +namespace BenchmarkDotNet.Tests.Mocks +{ + public static class MockRunner + { + public static Summary Run(ITestOutputHelper output, Func measurer) + => Run(output, benchmarkCase => measurer(benchmarkCase.Descriptor.WorkloadMethod.Name) + .Select((value, i) => new Measurement(1, IterationMode.Workload, IterationStage.Result, i, 1, value)) + .ToList()); + + public static Summary Run(ITestOutputHelper output, Func> measurer) + { + var job = new Job("MockJob") + { + Infrastructure = + { + Toolchain = new MockToolchain(measurer) + } + }.Freeze(); + + var logger = new AccumulationLogger(); + + var config = DefaultConfig.Instance + .WithOptions(ConfigOptions.DisableOptimizationsValidator) + .AddJob(job) + .AddLogger(logger); + var summary = BenchmarkRunner.Run(config); + + var exporter = MarkdownExporter.Mock; + exporter.ExportToLog(summary, logger); + output.WriteLine(logger.GetLog()); + + return summary; + } + } +} \ No newline at end of file diff --git a/tests/BenchmarkDotNet.Tests/Mocks/Toolchain/MockToolchain.cs b/tests/BenchmarkDotNet.Tests/Mocks/Toolchain/MockToolchain.cs new file mode 100644 index 0000000000..c25929854e --- /dev/null +++ b/tests/BenchmarkDotNet.Tests/Mocks/Toolchain/MockToolchain.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using BenchmarkDotNet.Characteristics; +using BenchmarkDotNet.Loggers; +using BenchmarkDotNet.Reports; +using BenchmarkDotNet.Running; +using BenchmarkDotNet.Toolchains; +using BenchmarkDotNet.Toolchains.Parameters; +using BenchmarkDotNet.Toolchains.Results; +using BenchmarkDotNet.Validators; + +namespace BenchmarkDotNet.Tests.Mocks.Toolchain +{ + public class MockToolchain : IToolchain + { + public MockToolchain(Func> measurer) + => Executor = new MockExecutor(measurer); + + public string Name => nameof(MockToolchain); + public IGenerator Generator => new MockGenerator(); + public IBuilder Builder => new MockBuilder(); + public IExecutor Executor { get; private set; } + public bool IsInProcess => false; + public IEnumerable Validate(BenchmarkCase benchmarkCase, IResolver resolver) => ImmutableArray.Empty; + + public override string ToString() => GetType().Name; + + private class MockGenerator : IGenerator + { + public GenerateResult GenerateProject(BuildPartition buildPartition, ILogger logger, string rootArtifactsFolderPath) + => GenerateResult.Success(ArtifactsPaths.Empty, ImmutableArray.Empty); + } + + private class MockBuilder : IBuilder + { + public BuildResult Build(GenerateResult generateResult, BuildPartition buildPartition, ILogger logger) => BuildResult.Success(generateResult); + } + + private class MockExecutor : IExecutor + { + private readonly Func> measurer; + + public MockExecutor(Func> measurer) => this.measurer = measurer; + + public ExecuteResult Execute(ExecuteParameters executeParameters) => new (measurer(executeParameters.BenchmarkCase)); + } + } +} \ No newline at end of file