Skip to content

Commit 41da36d

Browse files
authored
Support custom path of a test file (#1609)
1 parent 4376224 commit 41da36d

11 files changed

+452
-29
lines changed

ChangeLog.md

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Support custom path of a test file ([PR](https://github.com/dotnet/roslynator/pull/1609))
13+
- It's possible to specify a directory path and/or a file name.
14+
1015
## [4.13.0] - 2025-02-09
1116

1217
### Fixed

src/Tests/Testing.Common/Testing/AdditionalFile.cs

+17-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@ public readonly struct AdditionalFile
1717
/// <summary>
1818
/// Initializes a new instance of <see cref="AdditionalFile"/>
1919
/// </summary>
20-
public AdditionalFile(string source, string? expectedSource = null)
20+
public AdditionalFile(string source, string? expectedSource = null, string? directoryPath = null, string? name = null)
2121
{
2222
Source = source ?? throw new ArgumentNullException(nameof(source));
2323
ExpectedSource = expectedSource;
24+
25+
FileSystemVerifier.VerifyDirectoryPath(directoryPath);
26+
DirectoryPath = directoryPath;
27+
28+
FileSystemVerifier.VerifyFileName(name);
29+
Name = name;
2430
}
2531

2632
/// <summary>
@@ -33,6 +39,16 @@ public AdditionalFile(string source, string? expectedSource = null)
3339
/// </summary>
3440
public string? ExpectedSource { get; }
3541

42+
/// <summary>
43+
/// Gets the relative directory path.
44+
/// </summary>
45+
public string? DirectoryPath { get; }
46+
47+
/// <summary>
48+
/// Gets the file name.
49+
/// </summary>
50+
public string? Name { get; }
51+
3652
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
3753
private string DebuggerDisplay => Source;
3854

src/Tests/Testing.Common/Testing/CodeVerifier.cs

+10-8
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ private void VerifyAnnotations(
295295
}
296296

297297
internal static (Document document, ImmutableArray<ExpectedDocument> expectedDocuments)
298-
CreateDocument(Solution solution, string source, ImmutableArray<AdditionalFile> additionalFiles, TestOptions options, DiagnosticDescriptor? descriptor = null)
298+
CreateDocument(Solution solution, string source, string? directoryPath, string? fileName, ImmutableArray<AdditionalFile> additionalFiles, TestOptions options, DiagnosticDescriptor? descriptor = null)
299299
{
300300
const string DefaultProjectName = "TestProject";
301301

@@ -315,7 +315,7 @@ internal static (Document document, ImmutableArray<ExpectedDocument> expectedDoc
315315
.AddProject(projectInfo)
316316
.GetProject(projectId)!;
317317

318-
string directoryPath = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
318+
string baseDirectoryPath = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
319319
? "z:"
320320
: "/";
321321

@@ -336,7 +336,7 @@ internal static (Document document, ImmutableArray<ExpectedDocument> expectedDoc
336336
TextDocument configFile = project.AddAnalyzerConfigDocument(
337337
".editorconfig",
338338
SourceText.From(StringBuilderCache.GetStringAndFree(sb)),
339-
filePath: Path.Combine(directoryPath, ".editorconfig"));
339+
filePath: Path.Combine(baseDirectoryPath, ".editorconfig"));
340340

341341
project = configFile.Project;
342342
}
@@ -348,10 +348,12 @@ internal static (Document document, ImmutableArray<ExpectedDocument> expectedDoc
348348
project = project.WithCompilationOptions(newCompilationOptions);
349349
}
350350

351+
string documentName = fileName ?? options.DocumentName;
352+
351353
Document document = project.AddDocument(
352-
options.DocumentName,
354+
documentName,
353355
SourceText.From(source),
354-
filePath: Path.Combine(directoryPath, options.DocumentName));
356+
filePath: Path.Combine(baseDirectoryPath, (directoryPath is not null) ? Path.Combine(directoryPath, documentName) : documentName));
355357

356358
ImmutableArray<ExpectedDocument>.Builder? expectedDocuments = null;
357359

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

363365
for (int i = 0; i < additionalFiles.Length; i++)
364366
{
365-
string documentName = AppendNumberToFileName(options.DocumentName, i + 2);
367+
string additionalDocumentName = additionalFiles[i].Name ?? AppendNumberToFileName(options.DocumentName, i + 2);
366368

367369
Document additionalDocument = project.AddDocument(
368-
documentName,
370+
additionalDocumentName,
369371
SourceText.From(additionalFiles[i].Source),
370-
filePath: Path.Combine(directoryPath, documentName));
372+
filePath: Path.Combine(baseDirectoryPath, (directoryPath is not null) ? Path.Combine(directoryPath, additionalDocumentName) : additionalDocumentName));
371373

372374
string? expectedSource = additionalFiles[i].ExpectedSource;
373375

src/Tests/Testing.Common/Testing/CompilerDiagnosticFixTestData.cs

+38-5
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,20 @@ public CompilerDiagnosticFixTestData(
2121
string diagnosticId,
2222
string source,
2323
IEnumerable<AdditionalFile>? additionalFiles = null,
24-
string? equivalenceKey = null)
24+
string? equivalenceKey = null,
25+
string? directoryPath = null,
26+
string? fileName = null)
2527
{
2628
DiagnosticId = diagnosticId ?? throw new ArgumentNullException(nameof(diagnosticId));
2729
Source = source ?? throw new ArgumentNullException(nameof(source));
2830
AdditionalFiles = additionalFiles?.ToImmutableArray() ?? ImmutableArray<AdditionalFile>.Empty;
2931
EquivalenceKey = equivalenceKey;
32+
33+
FileSystemVerifier.VerifyDirectoryPath(directoryPath);
34+
DirectoryPath = directoryPath;
35+
36+
FileSystemVerifier.VerifyFileName(fileName);
37+
FileName = fileName;
3038
}
3139

3240
#pragma warning disable CS0618 // Type or member is obsolete
@@ -36,11 +44,20 @@ public CompilerDiagnosticFixTestData(
3644
public CompilerDiagnosticFixTestData(
3745
string source,
3846
IEnumerable<AdditionalFile>? additionalFiles = null,
39-
string? equivalenceKey = null)
47+
string? equivalenceKey = null,
48+
string? directoryPath = null,
49+
string? fileName = null)
4050
{
4151
Source = source ?? throw new ArgumentNullException(nameof(source));
4252
AdditionalFiles = additionalFiles?.ToImmutableArray() ?? ImmutableArray<AdditionalFile>.Empty;
4353
EquivalenceKey = equivalenceKey;
54+
55+
FileSystemVerifier.VerifyDirectoryPath(directoryPath);
56+
DirectoryPath = directoryPath;
57+
58+
FileSystemVerifier.VerifyFileName(fileName);
59+
FileName = fileName;
60+
4461
DiagnosticId = null!;
4562
}
4663

@@ -49,7 +66,9 @@ internal CompilerDiagnosticFixTestData(CompilerDiagnosticFixTestData other)
4966
diagnosticId: other.DiagnosticId,
5067
source: other.Source,
5168
additionalFiles: other.AdditionalFiles,
52-
equivalenceKey: other.EquivalenceKey)
69+
equivalenceKey: other.EquivalenceKey,
70+
directoryPath: other.DirectoryPath,
71+
fileName: other.FileName)
5372
{
5473
}
5574
#pragma warning restore CS0618 // Type or member is obsolete
@@ -75,6 +94,16 @@ internal CompilerDiagnosticFixTestData(CompilerDiagnosticFixTestData other)
7594
/// </summary>
7695
public string? EquivalenceKey { get; }
7796

97+
/// <summary>
98+
/// Gets the relative directory path.
99+
/// </summary>
100+
public string? DirectoryPath { get; }
101+
102+
/// <summary>
103+
/// Gets the file name.
104+
/// </summary>
105+
public string? FileName { get; }
106+
78107
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
79108
private string DebuggerDisplay => $"{Source}";
80109

@@ -86,12 +115,16 @@ public CompilerDiagnosticFixTestData Update(
86115
string diagnosticId,
87116
string source,
88117
IEnumerable<AdditionalFile> additionalFiles,
89-
string equivalenceKey)
118+
string equivalenceKey,
119+
string directoryPath,
120+
string fileName)
90121
{
91122
return new(
92123
diagnosticId: diagnosticId,
93124
source: source,
94125
additionalFiles: additionalFiles,
95-
equivalenceKey: equivalenceKey);
126+
equivalenceKey: equivalenceKey,
127+
directoryPath: directoryPath,
128+
fileName: fileName);
96129
}
97130
}

src/Tests/Testing.Common/Testing/CompilerDiagnosticFixVerifier.cs

+61-2
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,39 @@ await VerifyFixAsync(
7878
cancellationToken);
7979
}
8080

81+
/// <summary>
82+
/// Verifies that specified source will produce compiler diagnostic.
83+
/// </summary>
84+
/// <param name="file">Source file where diagnostic's location is marked with <c>[|</c> and <c>|]</c> tokens.</param>
85+
public async Task VerifyFixAsync(
86+
TestFile file,
87+
IEnumerable<AdditionalFile>? additionalFiles = null,
88+
string? equivalenceKey = null,
89+
TestOptions? options = null,
90+
CancellationToken cancellationToken = default)
91+
{
92+
if (file is null)
93+
throw new ArgumentNullException(nameof(file));
94+
95+
if (file.ExpectedSource is null)
96+
throw new ArgumentException("Expected source is required.", nameof(file));
97+
98+
var expected = ExpectedTestState.Parse(file.ExpectedSource);
99+
100+
var data = new CompilerDiagnosticFixTestData(
101+
file.Source,
102+
additionalFiles,
103+
equivalenceKey: equivalenceKey,
104+
directoryPath: file.DirectoryPath,
105+
fileName: file.Name);
106+
107+
await VerifyFixAsync(
108+
data,
109+
expected,
110+
options,
111+
cancellationToken);
112+
}
113+
81114
/// <summary>
82115
/// Verifies that specified source will produce compiler diagnostic.
83116
/// </summary>
@@ -103,7 +136,7 @@ public async Task VerifyFixAsync(
103136

104137
using (Workspace workspace = new AdhocWorkspace())
105138
{
106-
(Document document, ImmutableArray<ExpectedDocument> expectedDocuments) = CreateDocument(workspace.CurrentSolution, data.Source, data.AdditionalFiles, options);
139+
(Document document, ImmutableArray<ExpectedDocument> expectedDocuments) = CreateDocument(workspace.CurrentSolution, data.Source, directoryPath: data.DirectoryPath, fileName: data.FileName, data.AdditionalFiles, options);
107140

108141
Project project = document.Project;
109142

@@ -251,6 +284,32 @@ await VerifyNoFixAsync(
251284
cancellationToken);
252285
}
253286

287+
/// <summary>
288+
/// Verifies that specified source will not produce compiler diagnostic.
289+
/// </summary>
290+
public async Task VerifyNoFixAsync(
291+
TestFile file,
292+
IEnumerable<AdditionalFile>? additionalFiles = null,
293+
string? equivalenceKey = null,
294+
TestOptions? options = null,
295+
CancellationToken cancellationToken = default)
296+
{
297+
if (file is null)
298+
throw new ArgumentNullException(nameof(file));
299+
300+
var data = new CompilerDiagnosticFixTestData(
301+
file.Source,
302+
additionalFiles: additionalFiles,
303+
equivalenceKey: equivalenceKey,
304+
directoryPath: file.DirectoryPath,
305+
fileName: file.Name);
306+
307+
await VerifyNoFixAsync(
308+
data,
309+
options,
310+
cancellationToken);
311+
}
312+
254313
/// <summary>
255314
/// Verifies that specified source will not produce compiler diagnostic.
256315
/// </summary>
@@ -271,7 +330,7 @@ public async Task VerifyNoFixAsync(
271330

272331
using (Workspace workspace = new AdhocWorkspace())
273332
{
274-
(Document document, ImmutableArray<ExpectedDocument> _) = CreateDocument(workspace.CurrentSolution, data.Source, data.AdditionalFiles, options);
333+
(Document document, ImmutableArray<ExpectedDocument> _) = CreateDocument(workspace.CurrentSolution, data.Source, directoryPath: data.DirectoryPath, fileName: data.FileName, data.AdditionalFiles, options);
275334

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

src/Tests/Testing.Common/Testing/DiagnosticTestData.cs

+32-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ public DiagnosticTestData(
2929
string? diagnosticMessage = null,
3030
IFormatProvider? formatProvider = null,
3131
string? equivalenceKey = null,
32-
bool alwaysVerifyAdditionalLocations = false)
32+
bool alwaysVerifyAdditionalLocations = false,
33+
string? directoryPath = null,
34+
string? fileName = null)
3335
{
3436
Descriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor));
3537
Source = source ?? throw new ArgumentNullException(nameof(source));
@@ -41,6 +43,12 @@ public DiagnosticTestData(
4143
EquivalenceKey = equivalenceKey;
4244
AlwaysVerifyAdditionalLocations = alwaysVerifyAdditionalLocations;
4345

46+
FileSystemVerifier.VerifyDirectoryPath(directoryPath);
47+
DirectoryPath = directoryPath;
48+
49+
FileSystemVerifier.VerifyFileName(fileName);
50+
FileName = fileName;
51+
4452
if (Spans.Length > 1
4553
&& !AdditionalSpans.IsEmpty)
4654
{
@@ -60,7 +68,9 @@ public DiagnosticTestData(
6068
string? diagnosticMessage = null,
6169
IFormatProvider? formatProvider = null,
6270
string? equivalenceKey = null,
63-
bool alwaysVerifyAdditionalLocations = false)
71+
bool alwaysVerifyAdditionalLocations = false,
72+
string? directoryPath = null,
73+
string? fileName = null)
6474
{
6575
Source = source ?? throw new ArgumentNullException(nameof(source));
6676
Spans = spans?.ToImmutableArray() ?? ImmutableArray<TextSpan>.Empty;
@@ -70,6 +80,13 @@ public DiagnosticTestData(
7080
FormatProvider = formatProvider;
7181
EquivalenceKey = equivalenceKey;
7282
AlwaysVerifyAdditionalLocations = alwaysVerifyAdditionalLocations;
83+
84+
FileSystemVerifier.VerifyDirectoryPath(directoryPath);
85+
DirectoryPath = directoryPath;
86+
87+
FileSystemVerifier.VerifyFileName(fileName);
88+
FileName = fileName;
89+
7390
Descriptor = null!;
7491

7592
if (Spans.Length > 1
@@ -89,7 +106,9 @@ internal DiagnosticTestData(DiagnosticTestData other)
89106
diagnosticMessage: other.DiagnosticMessage,
90107
formatProvider: other.FormatProvider,
91108
equivalenceKey: other.EquivalenceKey,
92-
alwaysVerifyAdditionalLocations: other.AlwaysVerifyAdditionalLocations)
109+
alwaysVerifyAdditionalLocations: other.AlwaysVerifyAdditionalLocations,
110+
directoryPath: other.DirectoryPath,
111+
fileName: other.FileName)
93112
{
94113
}
95114
#pragma warning restore CS0618 // Type or member is obsolete
@@ -143,6 +162,16 @@ internal DiagnosticTestData(DiagnosticTestData other)
143162
/// </summary>
144163
public bool AlwaysVerifyAdditionalLocations { get; }
145164

165+
/// <summary>
166+
/// Gets the relative directory path.
167+
/// </summary>
168+
public string? DirectoryPath { get; }
169+
170+
/// <summary>
171+
/// Gets the file name.
172+
/// </summary>
173+
public string? FileName { get; }
174+
146175
internal ImmutableArray<Diagnostic> GetDiagnostics(DiagnosticDescriptor descriptor, SyntaxTree tree)
147176
{
148177
if (Spans.IsEmpty)

0 commit comments

Comments
 (0)