Skip to content

Commit c19e54a

Browse files
authored
Implement configurations compatibility validation (#1263), Closes #1238
1 parent 3223c94 commit c19e54a

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

src/BenchmarkDotNet/Running/BenchmarkRunnerClean.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,17 @@ private static ImmutableArray<ValidationError> Validate(BenchmarkRunInfo[] bench
256256

257257
var validationErrors = new List<ValidationError>();
258258

259+
if (benchmarks.Any(b => b.Config.Options.IsSet(ConfigOptions.JoinSummary)))
260+
{
261+
var joinedCases = benchmarks.SelectMany(b => b.BenchmarksCases).ToArray();
262+
263+
validationErrors.AddRange(
264+
ConfigCompatibilityValidator
265+
.FailOnError
266+
.Validate(new ValidationParameters(joinedCases, null))
267+
);
268+
}
269+
259270
foreach (var benchmarkRunInfo in benchmarks)
260271
validationErrors.AddRange(benchmarkRunInfo.Config.GetCompositeValidator().Validate(new ValidationParameters(benchmarkRunInfo.BenchmarksCases, benchmarkRunInfo.Config)));
261272

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Linq;
2+
using System.Collections.Generic;
3+
using BenchmarkDotNet.Configs;
4+
5+
namespace BenchmarkDotNet.Validators
6+
{
7+
public class ConfigCompatibilityValidator : IValidator
8+
{
9+
public static readonly ConfigCompatibilityValidator FailOnError = new ConfigCompatibilityValidator();
10+
11+
public bool TreatsWarningsAsErrors => true;
12+
13+
public IEnumerable<ValidationError> Validate(ValidationParameters validationParameters)
14+
{
15+
var orderers =
16+
validationParameters
17+
.Benchmarks
18+
.Where(benchmark => benchmark.Config.Orderer != Order.DefaultOrderer.Instance)
19+
.Select(benchmark => benchmark.Config.Orderer)
20+
.Distinct();
21+
22+
if (orderers.Count() > 1)
23+
yield return new ValidationError(true, "You use JoinSummary options, but provided configurations cannot be joined. Only one Orderer per benchmark cases is allowed.");
24+
}
25+
}
26+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using BenchmarkDotNet.Attributes;
2+
using BenchmarkDotNet.Order;
3+
using BenchmarkDotNet.Running;
4+
using BenchmarkDotNet.Configs;
5+
using BenchmarkDotNet.Tests.Loggers;
6+
using BenchmarkDotNet.Validators;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using Xunit;
10+
using Xunit.Abstractions;
11+
12+
namespace BenchmarkDotNet.Tests.Validators
13+
{
14+
public class ConfigCompatibilityValidatorTests
15+
{
16+
private ITestOutputHelper Output { get; }
17+
18+
public ConfigCompatibilityValidatorTests(ITestOutputHelper output) => Output = output;
19+
20+
[Fact]
21+
public void RunningBenchmarksWithIncompatibleConfigsMustFailWithCriticalError()
22+
{
23+
var logger = new OutputLogger(Output);
24+
var config = ManualConfig.CreateEmpty().AddLogger(logger);
25+
var summary =
26+
BenchmarkSwitcher
27+
.FromTypes(new[] { typeof(BenchmarkClassWithExtraOrderer1), typeof(BenchmarkClassWithExtraOrderer2) })
28+
.RunAllJoined(config);
29+
Assert.True(summary.HasCriticalValidationErrors);
30+
Assert.Contains("You use JoinSummary options, but provided configurations cannot be joined", logger.GetLog());
31+
Assert.Contains("Orderer", logger.GetLog());
32+
}
33+
34+
[Fact]
35+
public void JoinedBenchmarksMustNotHaveDifferentExtraOrderers()
36+
{
37+
var benchmarks = new[]
38+
{
39+
BenchmarkConverter.TypeToBenchmarks(typeof(BenchmarkClassWithExtraOrderer1)),
40+
BenchmarkConverter.TypeToBenchmarks(typeof(BenchmarkClassWithExtraOrderer2))
41+
};
42+
43+
var cases = benchmarks.SelectMany(b => b.BenchmarksCases).ToArray();
44+
45+
var validationErrors =
46+
ConfigCompatibilityValidator
47+
.FailOnError
48+
.Validate(new ValidationParameters(cases, null))
49+
.ToArray();
50+
51+
Assert.NotEmpty(validationErrors);
52+
Assert.StartsWith("You use JoinSummary options, but provided configurations cannot be joined", validationErrors.Single().Message);
53+
Assert.Contains("Orderer", validationErrors.Single().Message);
54+
}
55+
56+
[Fact]
57+
public void JoinedBenchmarksMayHaveOneExtraOrderer()
58+
{
59+
var benchmarks = new[]
60+
{
61+
BenchmarkConverter.TypeToBenchmarks(typeof(BenchmarkClassWithExtraOrderer1)),
62+
BenchmarkConverter.TypeToBenchmarks(typeof(BenchmarkClassWithDefaultOrderer1))
63+
};
64+
65+
var cases = benchmarks.SelectMany(b => b.BenchmarksCases).ToArray();
66+
67+
var validationErrors =
68+
ConfigCompatibilityValidator
69+
.FailOnError
70+
.Validate(new ValidationParameters(cases, null))
71+
.ToArray();
72+
73+
Assert.Empty(validationErrors);
74+
}
75+
76+
[Fact]
77+
public void JoinedBenchmarksMayHaveDefaultOrderers()
78+
{
79+
var benchmarks = new[]
80+
{
81+
BenchmarkConverter.TypeToBenchmarks(typeof(BenchmarkClassWithDefaultOrderer1)),
82+
BenchmarkConverter.TypeToBenchmarks(typeof(BenchmarkClassWithDefaultOrderer2))
83+
};
84+
85+
var cases = benchmarks.SelectMany(b => b.BenchmarksCases).ToArray();
86+
87+
var validationErrors =
88+
ConfigCompatibilityValidator
89+
.FailOnError
90+
.Validate(new ValidationParameters(cases, null))
91+
.ToArray();
92+
93+
Assert.Empty(validationErrors);
94+
}
95+
96+
[Orderer(SummaryOrderPolicy.Method)]
97+
public class BenchmarkClassWithExtraOrderer1
98+
{
99+
[Benchmark]
100+
public void Foo() { }
101+
}
102+
103+
[Orderer(SummaryOrderPolicy.Method)]
104+
public class BenchmarkClassWithExtraOrderer2
105+
{
106+
[Benchmark]
107+
public void Bar() { }
108+
}
109+
110+
public class BenchmarkClassWithDefaultOrderer1
111+
{
112+
[Benchmark]
113+
public void Baz() { }
114+
}
115+
116+
public class BenchmarkClassWithDefaultOrderer2
117+
{
118+
[Benchmark]
119+
public void Buzz() { }
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)