Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom path of a test file #1609

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- [CLI] Add support for .NET 9 ([PR](https://github.com/dotnet/roslynator/pull/1605))
- Support custom path of a test file ([PR](https://github.com/dotnet/roslynator/pull/1609))

### Fixed

Expand Down
8 changes: 7 additions & 1 deletion src/Tests/Testing.Common/Testing/AdditionalFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ public readonly struct AdditionalFile
/// <summary>
/// Initializes a new instance of <see cref="AdditionalFile"/>
/// </summary>
public AdditionalFile(string source, string? expectedSource = null)
public AdditionalFile(string source, string? expectedSource = null, string? path = null)
{
Source = source ?? throw new ArgumentNullException(nameof(source));
ExpectedSource = expectedSource;
Path = path;
}

/// <summary>
Expand All @@ -33,6 +34,11 @@ public AdditionalFile(string source, string? expectedSource = null)
/// </summary>
public string? ExpectedSource { get; }

/// <summary>
/// Gets the relative path a source file.
/// </summary>
public string? Path { get; }

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay => Source;

Expand Down
10 changes: 5 additions & 5 deletions src/Tests/Testing.Common/Testing/CodeVerifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ private void VerifyAnnotations(
}

internal static (Document document, ImmutableArray<ExpectedDocument> expectedDocuments)
CreateDocument(Solution solution, string source, ImmutableArray<AdditionalFile> additionalFiles, TestOptions options, DiagnosticDescriptor? descriptor = null)
CreateDocument(Solution solution, string source, string? path, ImmutableArray<AdditionalFile> additionalFiles, TestOptions options, DiagnosticDescriptor? descriptor = null)
{
const string DefaultProjectName = "TestProject";

Expand Down Expand Up @@ -349,9 +349,9 @@ internal static (Document document, ImmutableArray<ExpectedDocument> expectedDoc
}

Document document = project.AddDocument(
options.DocumentName,
Path.GetFileName(path) ?? options.DocumentName,
SourceText.From(source),
filePath: Path.Combine(directoryPath, options.DocumentName));
filePath: Path.Combine(directoryPath, path ?? options.DocumentName));

ImmutableArray<ExpectedDocument>.Builder? expectedDocuments = null;

Expand All @@ -362,12 +362,12 @@ internal static (Document document, ImmutableArray<ExpectedDocument> expectedDoc

for (int i = 0; i < additionalFiles.Length; i++)
{
string documentName = AppendNumberToFileName(options.DocumentName, i + 2);
string documentName = Path.GetFileName(additionalFiles[i].Path) ?? AppendNumberToFileName(options.DocumentName, i + 2);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in case I am providing only a path, it could work erroneously. I do not know how it would behave for cases Foo/Bar and Foo/Bar/

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added validation of file path


Document additionalDocument = project.AddDocument(
documentName,
SourceText.From(additionalFiles[i].Source),
filePath: Path.Combine(directoryPath, documentName));
filePath: Path.Combine(directoryPath, additionalFiles[i].Path ?? documentName));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest

Suggested change
filePath: Path.Combine(directoryPath, additionalFiles[i].Path ?? documentName));
filePath: Path.Combine(directoryPath, Path.GetDirectoryName(additionalFiles[i].Path ?? documentName), documentName));

that should properly process passed paths without file name, like Foo/Bar/ or something like this

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added validation of file path


string? expectedSource = additionalFiles[i].ExpectedSource;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public async Task VerifyFixAsync(

using (Workspace workspace = new AdhocWorkspace())
{
(Document document, ImmutableArray<ExpectedDocument> expectedDocuments) = CreateDocument(workspace.CurrentSolution, data.Source, data.AdditionalFiles, options);
(Document document, ImmutableArray<ExpectedDocument> expectedDocuments) = CreateDocument(workspace.CurrentSolution, data.Source, path: null, data.AdditionalFiles, options);

Project project = document.Project;

Expand Down Expand Up @@ -271,7 +271,7 @@ public async Task VerifyNoFixAsync(

using (Workspace workspace = new AdhocWorkspace())
{
(Document document, ImmutableArray<ExpectedDocument> _) = CreateDocument(workspace.CurrentSolution, data.Source, data.AdditionalFiles, options);
(Document document, ImmutableArray<ExpectedDocument> _) = CreateDocument(workspace.CurrentSolution, data.Source, path: null, data.AdditionalFiles, options);

Compilation compilation = (await document.Project.GetCompilationAsync(cancellationToken))!;

Expand Down
16 changes: 13 additions & 3 deletions src/Tests/Testing.Common/Testing/DiagnosticTestData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public DiagnosticTestData(
string? diagnosticMessage = null,
IFormatProvider? formatProvider = null,
string? equivalenceKey = null,
bool alwaysVerifyAdditionalLocations = false)
bool alwaysVerifyAdditionalLocations = false,
string? path = null)
{
Descriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor));
Source = source ?? throw new ArgumentNullException(nameof(source));
Expand All @@ -40,6 +41,7 @@ public DiagnosticTestData(
FormatProvider = formatProvider;
EquivalenceKey = equivalenceKey;
AlwaysVerifyAdditionalLocations = alwaysVerifyAdditionalLocations;
Path = path;

if (Spans.Length > 1
&& !AdditionalSpans.IsEmpty)
Expand All @@ -60,7 +62,8 @@ public DiagnosticTestData(
string? diagnosticMessage = null,
IFormatProvider? formatProvider = null,
string? equivalenceKey = null,
bool alwaysVerifyAdditionalLocations = false)
bool alwaysVerifyAdditionalLocations = false,
string? path = null)
{
Source = source ?? throw new ArgumentNullException(nameof(source));
Spans = spans?.ToImmutableArray() ?? ImmutableArray<TextSpan>.Empty;
Expand All @@ -70,6 +73,7 @@ public DiagnosticTestData(
FormatProvider = formatProvider;
EquivalenceKey = equivalenceKey;
AlwaysVerifyAdditionalLocations = alwaysVerifyAdditionalLocations;
Path = path;
Descriptor = null!;

if (Spans.Length > 1
Expand All @@ -89,7 +93,8 @@ internal DiagnosticTestData(DiagnosticTestData other)
diagnosticMessage: other.DiagnosticMessage,
formatProvider: other.FormatProvider,
equivalenceKey: other.EquivalenceKey,
alwaysVerifyAdditionalLocations: other.AlwaysVerifyAdditionalLocations)
alwaysVerifyAdditionalLocations: other.AlwaysVerifyAdditionalLocations,
path: other.Path)
{
}
#pragma warning restore CS0618 // Type or member is obsolete
Expand Down Expand Up @@ -143,6 +148,11 @@ internal DiagnosticTestData(DiagnosticTestData other)
/// </summary>
public bool AlwaysVerifyAdditionalLocations { get; }

/// <summary>
/// Gets source file path.
/// </summary>
public string? Path { get; }

internal ImmutableArray<Diagnostic> GetDiagnostics(DiagnosticDescriptor descriptor, SyntaxTree tree)
{
if (Spans.IsEmpty)
Expand Down
119 changes: 115 additions & 4 deletions src/Tests/Testing.Common/Testing/DiagnosticVerifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,34 @@ await VerifyDiagnosticAsync(
cancellationToken: cancellationToken);
}

/// <summary>
/// Verifies that specified source will produce specified diagnostic(s).
/// </summary>
/// <param name="file">Source code where diagnostic's location is marked with <c>[|</c> and <c>|]</c> tokens.</param>
public async Task VerifyDiagnosticAsync(
TestFile file,
IEnumerable<AdditionalFile>? additionalFiles = null,
TestOptions? options = null,
CancellationToken cancellationToken = default)
{
if (file is null)
throw new ArgumentNullException(nameof(file));

var code = TestCode.Parse(file.Source);

var data = new DiagnosticTestData(
code.Value,
code.Spans,
code.AdditionalSpans,
additionalFiles: additionalFiles,
path: file.Path);

await VerifyDiagnosticAsync(
data,
options: options,
cancellationToken: cancellationToken);
}

internal async Task VerifyDiagnosticAsync(
string source,
string sourceData,
Expand Down Expand Up @@ -92,7 +120,7 @@ public async Task VerifyDiagnosticAsync(

using (Workspace workspace = new AdhocWorkspace())
{
(Document document, ImmutableArray<ExpectedDocument> expectedDocuments) = CreateDocument(workspace.CurrentSolution, data.Source, data.AdditionalFiles, options, Descriptor);
(Document document, ImmutableArray<ExpectedDocument> expectedDocuments) = CreateDocument(workspace.CurrentSolution, data.Source, data.Path, data.AdditionalFiles, options, Descriptor);

SyntaxTree tree = (await document.GetSyntaxTreeAsync(cancellationToken))!;

Expand Down Expand Up @@ -185,6 +213,33 @@ await VerifyNoDiagnosticAsync(
cancellationToken);
}

/// <summary>
/// Verifies that specified source will not produce specified diagnostic.
/// </summary>
public async Task VerifyNoDiagnosticAsync(
TestFile file,
IEnumerable<AdditionalFile>? additionalFiles = null,
TestOptions? options = null,
CancellationToken cancellationToken = default)
{
if (file is null)
throw new ArgumentNullException(nameof(file));

var code = TestCode.Parse(file.Source);

var data = new DiagnosticTestData(
code.Value,
code.Spans,
code.AdditionalSpans,
additionalFiles: additionalFiles,
path: file.Path);

await VerifyNoDiagnosticAsync(
data,
options: options,
cancellationToken);
}

/// <summary>
/// Verifies that specified source will not produce specified diagnostic.
/// </summary>
Expand All @@ -204,7 +259,7 @@ public async Task VerifyNoDiagnosticAsync(

using (Workspace workspace = new AdhocWorkspace())
{
(Document document, ImmutableArray<ExpectedDocument> _) = CreateDocument(workspace.CurrentSolution, data.Source, data.AdditionalFiles, options, Descriptor);
(Document document, ImmutableArray<ExpectedDocument> _) = CreateDocument(workspace.CurrentSolution, data.Source, data.Path, data.AdditionalFiles, options, Descriptor);

SyntaxTree tree = (await document.GetSyntaxTreeAsync(cancellationToken))!;

Expand Down Expand Up @@ -255,6 +310,36 @@ public async Task VerifyDiagnosticAndFixAsync(
await VerifyDiagnosticAndFixAsync(data, expected, options, cancellationToken);
}

/// <summary>
/// Verifies that specified source will produce specified diagnostic and that the diagnostic will be fixed.
/// </summary>
/// <param name="file">Source code where diagnostic's location is marked with <c>[|</c> and <c>|]</c> tokens.</param>
public async Task VerifyDiagnosticAndFixAsync(
TestFile file,
IEnumerable<AdditionalFile>? additionalFiles = null,
string? equivalenceKey = null,
TestOptions? options = null,
CancellationToken cancellationToken = default)
{
if (file is null)
throw new ArgumentNullException(nameof(file));

if (file.ExpectedSource is null)
throw new ArgumentException("Expected source is required.", nameof(file));

var code = TestCode.Parse(file.Source);
var expected = ExpectedTestState.Parse(file.ExpectedSource);

var data = new DiagnosticTestData(
code.Value,
code.Spans,
additionalSpans: code.AdditionalSpans,
additionalFiles: additionalFiles,
equivalenceKey: equivalenceKey);

await VerifyDiagnosticAndFixAsync(data, expected, options, cancellationToken);
}

internal async Task VerifyDiagnosticAndFixAsync(
string source,
string sourceData,
Expand Down Expand Up @@ -314,6 +399,32 @@ public async Task VerifyDiagnosticAndNoFixAsync(
await VerifyDiagnosticAndNoFixAsync(data, options, cancellationToken);
}

/// <summary>
/// Verifies that specified source will produce specified diagnostic and that the diagnostic will not be fixed.
/// </summary>
/// <param name="file">Source code where diagnostic's location is marked with <c>[|</c> and <c>|]</c> tokens.</param>
public async Task VerifyDiagnosticAndNoFixAsync(
TestFile file,
IEnumerable<AdditionalFile>? additionalFiles = null,
string? equivalenceKey = null,
TestOptions? options = null,
CancellationToken cancellationToken = default)
{
if (file is null)
throw new ArgumentNullException(nameof(file));

var code = TestCode.Parse(file.Source);

var data = new DiagnosticTestData(
code.Value,
code.Spans,
additionalSpans: code.AdditionalSpans,
additionalFiles: additionalFiles,
equivalenceKey: equivalenceKey);

await VerifyDiagnosticAndNoFixAsync(data, options, cancellationToken);
}

/// <summary>
/// Verifies that specified source will produce specified diagnostic and that the diagnostic will not be fixed.
/// </summary>
Expand Down Expand Up @@ -349,7 +460,7 @@ private async Task VerifyFixAsync(

using (Workspace workspace = new AdhocWorkspace())
{
(Document document, ImmutableArray<ExpectedDocument> expectedDocuments) = CreateDocument(workspace.CurrentSolution, data.Source, data.AdditionalFiles, options, Descriptor);
(Document document, ImmutableArray<ExpectedDocument> expectedDocuments) = CreateDocument(workspace.CurrentSolution, data.Source, data.Path, data.AdditionalFiles, options, Descriptor);

Project project = document.Project;

Expand Down Expand Up @@ -513,7 +624,7 @@ private async Task VerifyNoFixAsync(

using (Workspace workspace = new AdhocWorkspace())
{
(Document document, ImmutableArray<ExpectedDocument> _) = CreateDocument(workspace.CurrentSolution, data.Source, data.AdditionalFiles, options, Descriptor);
(Document document, ImmutableArray<ExpectedDocument> _) = CreateDocument(workspace.CurrentSolution, data.Source, data.Path, data.AdditionalFiles, options, Descriptor);

Compilation compilation = (await document.Project.GetCompilationAsync(cancellationToken))!;

Expand Down
4 changes: 2 additions & 2 deletions src/Tests/Testing.Common/Testing/RefactoringVerifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public async Task VerifyRefactoringAsync(

using (Workspace workspace = new AdhocWorkspace())
{
(Document document, ImmutableArray<ExpectedDocument> expectedDocuments) = CreateDocument(workspace.CurrentSolution, data.Source, data.AdditionalFiles, options);
(Document document, ImmutableArray<ExpectedDocument> expectedDocuments) = CreateDocument(workspace.CurrentSolution, data.Source, path: null, data.AdditionalFiles, options);

SemanticModel semanticModel = (await document.GetSemanticModelAsync(cancellationToken))!;

Expand Down Expand Up @@ -223,7 +223,7 @@ public async Task VerifyNoRefactoringAsync(

using (Workspace workspace = new AdhocWorkspace())
{
(Document document, ImmutableArray<ExpectedDocument> _) = CreateDocument(workspace.CurrentSolution, data.Source, data.AdditionalFiles, options);
(Document document, ImmutableArray<ExpectedDocument> _) = CreateDocument(workspace.CurrentSolution, data.Source, path: null, data.AdditionalFiles, options);

SemanticModel semanticModel = (await document.GetSemanticModelAsync(cancellationToken))!;

Expand Down
23 changes: 23 additions & 0 deletions src/Tests/Testing.Common/Testing/TestFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Diagnostics;

namespace Roslynator.Testing;

[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class TestFile
{
public TestFile(string source, string? expectedSource = null, string? path = null)
{
Source = source;
ExpectedSource = expectedSource;
Path = path;
}

public string Source { get; }

public string? ExpectedSource { get; }

public string? Path { get; }

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay => Source;
}
Loading