Skip to content

Commit 41b066f

Browse files
committed
feat: add validator for job that contains null runtime
1 parent c84de9a commit 41b066f

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed

src/BenchmarkDotNet/Configs/DefaultConfig.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public IEnumerable<IValidator> GetValidators()
7272
yield return DeferredExecutionValidator.FailOnError;
7373
yield return ParamsAllValuesValidator.FailOnError;
7474
yield return ParamsValidator.FailOnError;
75+
yield return RuntimeValidator.DontFailOnError;
7576
}
7677

7778
public IOrderer Orderer => null;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Collections.Generic;
2+
using System.Collections.Immutable;
3+
using System.Linq;
4+
using BenchmarkDotNet.Jobs;
5+
6+
namespace BenchmarkDotNet.Validators;
7+
8+
/// <summary>
9+
/// Validator for runtime characteristic.
10+
/// <see href="https://github.com/dotnet/BenchmarkDotNet/issues/2609" />
11+
/// </summary>
12+
public class RuntimeValidator : IValidator
13+
{
14+
public static readonly IValidator DontFailOnError = new RuntimeValidator();
15+
16+
private RuntimeValidator() { }
17+
18+
public bool TreatsWarningsAsErrors => false;
19+
20+
public IEnumerable<ValidationError> Validate(ValidationParameters input)
21+
{
22+
var allBenchmarks = input.Benchmarks.ToArray();
23+
24+
var runtimes = allBenchmarks.Select(x => x.Job.Environment.Runtime)
25+
.Distinct()
26+
.ToArray();
27+
28+
if (runtimes.Length > 1 && runtimes.Contains(null))
29+
{
30+
// GetRuntime() method returns current environment's runtime if RuntimeCharacteristic is not set.
31+
var message = "There are benchmarks that job don't have a Runtime characteristic. It's recommended explicitly specify runtime by `WithRuntime`.";
32+
yield return new ValidationError(false, message);
33+
}
34+
}
35+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
using BenchmarkDotNet.Attributes;
2+
using BenchmarkDotNet.Configs;
3+
using BenchmarkDotNet.Environments;
4+
using BenchmarkDotNet.Jobs;
5+
using BenchmarkDotNet.Running;
6+
using BenchmarkDotNet.Toolchains.CsProj;
7+
using BenchmarkDotNet.Validators;
8+
using System.Linq;
9+
using Xunit;
10+
11+
namespace BenchmarkDotNet.Tests.Validators;
12+
13+
public class RuntimeValidatorTests
14+
{
15+
[Fact]
16+
public void SameRuntime_Should_Success()
17+
{
18+
// Arrange
19+
var config = new TestConfig1().CreateImmutableConfig();
20+
var runInfo = BenchmarkConverter.TypeToBenchmarks(typeof(DummyBenchmark), config);
21+
var parameters = new ValidationParameters(runInfo.BenchmarksCases, config);
22+
23+
// Act
24+
var errors = RuntimeValidator.DontFailOnError.Validate(parameters).Select(e => e.Message).ToArray();
25+
26+
// Assert
27+
Assert.Empty(errors);
28+
}
29+
30+
[Fact]
31+
public void NullRuntimeMixed_Should_Failed()
32+
{
33+
// Arrange
34+
var config = new TestConfig2().CreateImmutableConfig();
35+
var runInfo = BenchmarkConverter.TypeToBenchmarks(typeof(DummyBenchmark), config);
36+
var parameters = new ValidationParameters(runInfo.BenchmarksCases, config);
37+
38+
// Act
39+
var errors = RuntimeValidator.DontFailOnError.Validate(parameters).Select(e => e.Message).ToArray();
40+
41+
// Assert
42+
var expectedMessage = "There are benchmarks that job don't have a Runtime characteristic. It's recommended explicitly specify runtime by `WithRuntime`.";
43+
Assert.Contains(errors, s => s.Equals(expectedMessage));
44+
}
45+
46+
[Fact]
47+
public void NotNullRuntimeOnly_Should_Success()
48+
{
49+
// Arrange
50+
var config = new TestConfig3().CreateImmutableConfig();
51+
var runInfo = BenchmarkConverter.TypeToBenchmarks(typeof(DummyBenchmark), config);
52+
var parameters = new ValidationParameters(runInfo.BenchmarksCases, config);
53+
54+
// Act
55+
var errors = RuntimeValidator.DontFailOnError.Validate(parameters).Select(e => e.Message).ToArray();
56+
57+
// Assert
58+
Assert.Empty(errors);
59+
}
60+
61+
public class DummyBenchmark
62+
{
63+
[Benchmark]
64+
public void Benchmark()
65+
{
66+
}
67+
}
68+
69+
// TestConfig that expicitly specify runtime.
70+
private class TestConfig1 : ManualConfig
71+
{
72+
public TestConfig1()
73+
{
74+
var baseJob = Job.Dry;
75+
76+
WithOption(ConfigOptions.DisableOptimizationsValidator, true);
77+
AddColumnProvider(DefaultConfig.Instance.GetColumnProviders().ToArray());
78+
79+
AddJob(baseJob.WithToolchain(CsProjCoreToolchain.NetCoreApp80));
80+
AddJob(baseJob.WithToolchain(CsProjCoreToolchain.NetCoreApp90));
81+
}
82+
}
83+
84+
// TestConfig that contains job that don't specify runtime.
85+
private class TestConfig2 : ManualConfig
86+
{
87+
public TestConfig2()
88+
{
89+
var baseJob = Job.Dry;
90+
91+
WithOption(ConfigOptions.DisableOptimizationsValidator, true);
92+
AddColumnProvider(DefaultConfig.Instance.GetColumnProviders().ToArray());
93+
94+
AddJob(baseJob.WithToolchain(CsProjCoreToolchain.NetCoreApp80));
95+
AddJob(baseJob.WithToolchain(CsProjCoreToolchain.NetCoreApp90)
96+
.WithRuntime(CoreRuntime.Core90));
97+
}
98+
}
99+
100+
// TestConfig that expicitly specify runtime.
101+
private class TestConfig3 : ManualConfig
102+
{
103+
public TestConfig3()
104+
{
105+
var baseJob = Job.Dry;
106+
107+
WithOption(ConfigOptions.DisableOptimizationsValidator, true);
108+
AddColumnProvider(DefaultConfig.Instance.GetColumnProviders().ToArray());
109+
110+
AddJob(baseJob.WithToolchain(CsProjCoreToolchain.NetCoreApp80)
111+
.WithRuntime(CoreRuntime.Core80)); ;
112+
AddJob(baseJob.WithToolchain(CsProjCoreToolchain.NetCoreApp90)
113+
.WithRuntime(CoreRuntime.Core90));
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)