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
8 changes: 8 additions & 0 deletions JustDummies.Analyzers.UnitTests/AnalyzerTestHarness.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ public static async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync(Diagnos
references: References,
options: options);

// A snippet that does not compile binds no operations, so every rule stands down and an "expects nothing"
// assertion passes for the wrong reason. That is not hypothetical: a JD027 test omitted the type arguments a
// throw-only lambda cannot infer, went green, and hid a live false positive. Fail loudly instead.
ImmutableArray<Diagnostic> compilerErrors = [.. compilation.GetDiagnostics().Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)];
if (compilerErrors.Length > 0) {
throw new InvalidOperationException($"The test snippet does not compile, so no rule could have run:{Environment.NewLine}{string.Join(Environment.NewLine, compilerErrors)}");
}

CompilationWithAnalyzers withAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer));

return await withAnalyzers.GetAnalyzerDiagnosticsAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public static void M() {
[Fact]
public async Task Does_not_report_when_JustDummies_is_absent_from_the_compilation() {
const string source = """
public static class Other {
public sealed class Other {
public static Other NonEmpty() => new();
}

Expand Down
213 changes: 213 additions & 0 deletions JustDummies.Analyzers.UnitTests/Jd025Jd026PoolAndUriTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
using System.Collections.Immutable;

using Microsoft.CodeAnalysis;

using NFluent;

namespace JustDummies.Analyzers.UnitTests;

public class Jd025DuplicatePoolValueTests {

[Theory]
[InlineData("Any.OneOf(1, 2, 1)")]
[InlineData("Any.OneOf(\"EUR\", \"USD\", \"EUR\")")]
[InlineData("Any.Int32().OneOf(3, 3)")]
[InlineData("Any.OneOf(true, false, true)")]
public async Task Reports_a_value_listed_twice(string expression) {
string source = $$"""
using JustDummies;

public static class Sample {
public static void M() {
_ = {{expression}};
}
}
""";

ImmutableArray<Diagnostic> diagnostics = await AnalyzerTestHarness.GetDiagnosticsAsync(new DuplicatePoolValueAnalyzer(), source);

Check.That(diagnostics.Length).IsEqualTo(1);
Check.That(diagnostics[0].Id).IsEqualTo("JD025");
}

[Theory]
[InlineData("Any.OneOf(1, 2, 3)")]
[InlineData("Any.OneOf(\"a\", \"A\")")]
[InlineData("Any.Int32().OneOf(3, 4)")]
public async Task Does_not_report_a_pool_of_distinct_values(string expression) {
string source = $$"""
using JustDummies;

public static class Sample {
public static void M() {
_ = {{expression}};
}
}
""";

ImmutableArray<Diagnostic> diagnostics = await AnalyzerTestHarness.GetDiagnosticsAsync(new DuplicatePoolValueAnalyzer(), source);

Check.That(diagnostics.Length).IsEqualTo(0);
}

[Fact]
public async Task Reports_an_enum_member_listed_twice() {
const string source = """
using JustDummies;

public enum Status { Active, Pending, Closed }

public static class Sample {
public static void M() {
_ = Any.OneOf(Status.Active, Status.Pending, Status.Active);
}
}
""";

ImmutableArray<Diagnostic> diagnostics = await AnalyzerTestHarness.GetDiagnosticsAsync(new DuplicatePoolValueAnalyzer(), source);

Check.That(diagnostics.Length).IsEqualTo(1);
Check.That(diagnostics[0].Id).IsEqualTo("JD025");
}

[Fact]
public async Task Stands_down_when_one_element_does_not_fold() {
// The unfoldable element could itself be the duplicate of a later one, so a partial walk would claim a
// completeness it does not have.
const string source = """
using JustDummies;

public static class Sample {
public static void M(int supplied) {
_ = Any.OneOf(1, supplied, 1);
}
}
""";

ImmutableArray<Diagnostic> diagnostics = await AnalyzerTestHarness.GetDiagnosticsAsync(new DuplicatePoolValueAnalyzer(), source);

Check.That(diagnostics.Length).IsEqualTo(0);
}

[Fact]
public async Task Does_not_report_a_pool_held_in_a_variable() {
const string source = """
using System.Collections.Generic;
using JustDummies;

public static class Sample {
public static void M(IReadOnlyList<int> pool) {
_ = Any.ElementOf(pool);
}
}
""";

ImmutableArray<Diagnostic> diagnostics = await AnalyzerTestHarness.GetDiagnosticsAsync(new DuplicatePoolValueAnalyzer(), source);

Check.That(diagnostics.Length).IsEqualTo(0);
}

[Fact]
public async Task Does_not_report_a_negative_test() {
const string source = """
using System;
using JustDummies;

public static class Sample {
public static void M() {
Run(() => Any.OneOf(1, 1));
}

private static void Run(Func<object> body) { }
}
""";

ImmutableArray<Diagnostic> diagnostics = await AnalyzerTestHarness.GetDiagnosticsAsync(new DuplicatePoolValueAnalyzer(), source);

Check.That(diagnostics.Length).IsEqualTo(0);
}

}

public class Jd026EmptyRelativeUriTests {

[Fact]
public async Task Reports_a_relative_uri_that_can_only_be_empty() {
const string source = """
using JustDummies;

public static class Sample {
public static void M() {
_ = Any.Uri().Relative().WithPathSegments(0);
}
}
""";

ImmutableArray<Diagnostic> diagnostics = await AnalyzerTestHarness.GetDiagnosticsAsync(new EmptyRelativeUriAnalyzer(), source);

Check.That(diagnostics.Length).IsEqualTo(1);
Check.That(diagnostics[0].Id).IsEqualTo("JD026");
}

[Theory]
[InlineData("Any.Uri().Relative().WithPathSegments(0).WithQuery()")]
[InlineData("Any.Uri().Relative().WithPathSegments(0).WithFragment()")]
[InlineData("Any.Uri().Relative().Rooted().WithPathSegments(0)")]
[InlineData("Any.Uri().Relative().WithPathSegments(1)")]
[InlineData("Any.Uri().Relative()")]
[InlineData("Any.Uri().Web().WithPathSegments(0)")]
[InlineData("Any.Uri().Ftp().WithPathSegments(0)")]
public async Task Does_not_report_a_reference_that_can_render(string expression) {
string source = $$"""
using JustDummies;

public static class Sample {
public static void M() {
_ = {{expression}};
}
}
""";

ImmutableArray<Diagnostic> diagnostics = await AnalyzerTestHarness.GetDiagnosticsAsync(new EmptyRelativeUriAnalyzer(), source);

Check.That(diagnostics.Length).IsEqualTo(0);
}

[Fact]
public async Task Does_not_report_a_non_constant_segment_count() {
const string source = """
using JustDummies;

public static class Sample {
public static void M(int segments) {
_ = Any.Uri().Relative().WithPathSegments(segments);
}
}
""";

ImmutableArray<Diagnostic> diagnostics = await AnalyzerTestHarness.GetDiagnosticsAsync(new EmptyRelativeUriAnalyzer(), source);

Check.That(diagnostics.Length).IsEqualTo(0);
}

[Fact]
public async Task Does_not_report_a_negative_test() {
const string source = """
using System;
using JustDummies;

public static class Sample {
public static void M() {
Run(() => Any.Uri().Relative().WithPathSegments(0));
}

private static void Run(Func<object> body) { }
}
""";

ImmutableArray<Diagnostic> diagnostics = await AnalyzerTestHarness.GetDiagnosticsAsync(new EmptyRelativeUriAnalyzer(), source);

Check.That(diagnostics.Length).IsEqualTo(0);
}

}
Loading
Loading