Skip to content

Commit 5906b53

Browse files
Merge pull request #735 from StealthyDeveloper/master
Fix failing Multifile tests on build server
2 parents 0bf0415 + 92ae6b8 commit 5906b53

File tree

8 files changed

+98
-69
lines changed

8 files changed

+98
-69
lines changed

CodeConverter/Shared/ProjectConversion.cs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@
1010
using ICSharpCode.CodeConverter.CSharp;
1111
using ICSharpCode.CodeConverter.Util;
1212
using Microsoft.CodeAnalysis;
13+
using Microsoft.CodeAnalysis.Text;
14+
1315
namespace ICSharpCode.CodeConverter.Shared
1416
{
15-
using System.IO.Abstractions;
16-
using Microsoft.CodeAnalysis.Text;
17-
1817
public class ProjectConversion
1918
{
2019
private readonly IProjectContentsConverter _projectContentsConverter;
@@ -82,7 +81,8 @@ private static ConversionResult GetSingleResultForDocument(ConversionResult[] co
8281
}
8382

8483
public static async IAsyncEnumerable<ConversionResult> ConvertProject(Project project,
85-
ILanguageConversion languageConversion, IProgress<ConversionProgress> progress,
84+
ILanguageConversion languageConversion, TextReplacementConverter textReplacementConverter,
85+
IProgress<ConversionProgress> progress,
8686
IEnumerable<IAssemblySymbol> assembliesBeingConverted,
8787
[EnumeratorCancellation] CancellationToken cancellationToken,
8888
params (string Find, string Replace, bool FirstOnly)[] replacements)
@@ -93,12 +93,14 @@ public static async IAsyncEnumerable<ConversionResult> ConvertProject(Project pr
9393
var sourceFilePaths = project.Documents.Concat(projectContentsConverter.SourceProject.AdditionalDocuments).Select(d => d.FilePath).ToImmutableHashSet();
9494
var convertProjectContents = ConvertProjectContents(projectContentsConverter, languageConversion, progress, cancellationToken);
9595

96-
var results = WithProjectFile(projectContentsConverter, languageConversion, sourceFilePaths, convertProjectContents, replacements);
96+
var results = WithProjectFile(projectContentsConverter, textReplacementConverter, languageConversion, sourceFilePaths, convertProjectContents, replacements);
9797
await foreach (var result in results.WithCancellation(cancellationToken)) yield return result;
9898
}
9999

100100
/// <remarks>Perf: Keep lazy so that we don't keep an extra copy of all files in memory at once</remarks>
101-
private static async IAsyncEnumerable<ConversionResult> WithProjectFile(IProjectContentsConverter projectContentsConverter, ILanguageConversion languageConversion, ImmutableHashSet<string> originalSourcePaths, IAsyncEnumerable<ConversionResult> convertProjectContents, (string Find, string Replace, bool FirstOnly)[] replacements)
101+
private static async IAsyncEnumerable<ConversionResult> WithProjectFile(IProjectContentsConverter projectContentsConverter, TextReplacementConverter textReplacementConverter,
102+
ILanguageConversion languageConversion, ImmutableHashSet<string> originalSourcePaths,
103+
IAsyncEnumerable<ConversionResult> convertProjectContents, (string Find, string Replace, bool FirstOnly)[] replacements)
102104
{
103105
var project = projectContentsConverter.SourceProject;
104106
var projectDir = project.GetDirectoryPath();
@@ -129,14 +131,17 @@ private static async IAsyncEnumerable<ConversionResult> WithProjectFile(IProject
129131
ChangeLanguageVersionRegex(projectContentsConverter.LanguageVersion)
130132
}).ToArray();
131133

132-
yield return ConvertProjectFile(project, languageConversion, replacementSpecs);
134+
yield return ConvertProjectFile(project, languageConversion, textReplacementConverter, replacementSpecs);
133135
}
134136

135137
public static ConversionResult ConvertProjectFile(Project project,
136138
ILanguageConversion languageConversion,
139+
TextReplacementConverter textReplacementConverter,
137140
params (string Find, string Replace, bool FirstOnly)[] textReplacements)
138141
{
139-
return new FileInfo(project.FilePath).ConversionResultFromReplacements(textReplacements,
142+
var fileInfo = new FileInfo(project.FilePath);
143+
144+
return textReplacementConverter.ConversionResultFromReplacements(fileInfo, textReplacements,
140145
languageConversion.PostTransformProjectFile);
141146
}
142147

CodeConverter/Shared/SolutionConverter.cs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,39 +20,34 @@ public class SolutionConverter
2020
private readonly ILanguageConversion _languageConversion;
2121
private readonly SolutionFileTextEditor _solutionFileTextEditor;
2222
private readonly CancellationToken _cancellationToken;
23-
24-
public static IFileSystem FileSystem { get; set; } = new FileSystem();
25-
26-
public static SolutionConverter CreateFor<TLanguageConversion>(IReadOnlyCollection<Project> projectsToConvert, string sourceSolutionContents)
27-
where TLanguageConversion : ILanguageConversion, new()
28-
{
29-
return CreateFor<TLanguageConversion>(projectsToConvert, solutionContents: sourceSolutionContents);
30-
}
23+
private readonly TextReplacementConverter _textReplacementConverter;
3124

3225
public static SolutionConverter CreateFor<TLanguageConversion>(IReadOnlyCollection<Project> projectsToConvert,
3326
ConversionOptions conversionOptions = default,
3427
IProgress<ConversionProgress> progress = null,
3528
CancellationToken cancellationToken = default,
29+
IFileSystem fileSystem = null,
3630
string solutionContents = "") where TLanguageConversion : ILanguageConversion, new()
3731
{
3832
var conversion = new TLanguageConversion { ConversionOptions = conversionOptions };
39-
return CreateFor(conversion, projectsToConvert, progress, cancellationToken, solutionContents);
33+
return CreateFor(conversion, projectsToConvert, progress, cancellationToken, fileSystem, solutionContents);
4034
}
4135

4236
public static SolutionConverter CreateFor(ILanguageConversion languageConversion, IReadOnlyCollection<Project> projectsToConvert,
43-
IProgress<ConversionProgress> progress,
44-
CancellationToken cancellationToken, string solutionContents = "")
37+
IProgress<ConversionProgress> progress, CancellationToken cancellationToken, IFileSystem fileSystem = null, string solutionContents = "")
4538
{
4639
languageConversion.ConversionOptions ??= new ConversionOptions();
40+
fileSystem ??= new FileSystem();
41+
4742
var solutionFilePath = projectsToConvert.First().Solution.FilePath;
48-
var sourceSolutionContents = File.Exists(solutionFilePath)
49-
? FileSystem.File.ReadAllText(solutionFilePath)
43+
var sourceSolutionContents = fileSystem.File.Exists(solutionFilePath)
44+
? fileSystem.File.ReadAllText(solutionFilePath)
5045
: solutionContents;
5146

5247
var projTuples = projectsToConvert.Select(proj =>
5348
{
5449
var relativeProjPath = PathConverter.GetRelativePath(solutionFilePath, proj.FilePath);
55-
var projContents = FileSystem.File.ReadAllText(proj.FilePath);
50+
var projContents = fileSystem.File.ReadAllText(proj.FilePath);
5651

5752
return (proj.Name, RelativeProjPath: relativeProjPath, ProjContents: projContents);
5853
});
@@ -61,15 +56,15 @@ public static SolutionConverter CreateFor(ILanguageConversion languageConversion
6156
var projectReferenceReplacements = solutionFileTextEditor.GetProjectFileProjectReferenceReplacements(projTuples, sourceSolutionContents);
6257

6358
return new SolutionConverter(solutionFilePath, sourceSolutionContents, projectsToConvert, projectReferenceReplacements,
64-
progress ?? new Progress<ConversionProgress>(), cancellationToken, languageConversion, solutionFileTextEditor);
59+
progress ?? new Progress<ConversionProgress>(), cancellationToken, languageConversion, solutionFileTextEditor, fileSystem);
6560
}
6661

6762
private SolutionConverter(string solutionFilePath,
6863
string sourceSolutionContents, IReadOnlyCollection<Project> projectsToConvert,
6964
List<(string Find, string Replace, bool FirstOnly)> projectReferenceReplacements,
7065
IProgress<ConversionProgress> showProgressMessage,
7166
CancellationToken cancellationToken, ILanguageConversion languageConversion,
72-
SolutionFileTextEditor solutionFileTextEditor)
67+
SolutionFileTextEditor solutionFileTextEditor, IFileSystem fileSystem)
7368
{
7469
_solutionFilePath = solutionFilePath;
7570
_sourceSolutionContents = sourceSolutionContents;
@@ -79,6 +74,7 @@ private SolutionConverter(string solutionFilePath,
7974
_languageConversion = languageConversion;
8075
_cancellationToken = cancellationToken;
8176
_solutionFileTextEditor = solutionFileTextEditor;
77+
_textReplacementConverter = new TextReplacementConverter(fileSystem);
8278
}
8379

8480
public async IAsyncEnumerable<ConversionResult> Convert()
@@ -103,17 +99,20 @@ private IAsyncEnumerable<ConversionResult> ConvertProject(Project project, IEnum
10399
{
104100
var replacements = _projectReferenceReplacements.ToArray();
105101
_progress.Report(new ConversionProgress($"Converting {project.Name}..."));
106-
return ProjectConversion.ConvertProject(project, _languageConversion, _progress, assembliesBeingConverted, _cancellationToken, replacements);
102+
return ProjectConversion.ConvertProject(project, _languageConversion, _textReplacementConverter, _progress, assembliesBeingConverted, _cancellationToken, replacements);
107103
}
108104

109105
private IEnumerable<ConversionResult> UpdateProjectReferences(IEnumerable<Project> projectsToUpdateReferencesOnly)
110106
{
111107
var conversionResults = projectsToUpdateReferencesOnly
112108
.Where(p => p.FilePath != null) //Some project types like Websites don't have a project file
113109
.Select(project => {
114-
var withReferencesReplaced =
115-
new FileInfo(project.FilePath).ConversionResultFromReplacements(_projectReferenceReplacements);
110+
var fileInfo = new FileInfo(project.FilePath);
111+
112+
var withReferencesReplaced =
113+
_textReplacementConverter.ConversionResultFromReplacements(fileInfo, _projectReferenceReplacements);
116114
withReferencesReplaced.TargetPathOrNull = withReferencesReplaced.SourcePathOrNull;
115+
117116
return withReferencesReplaced;
118117
});
119118

@@ -129,7 +128,7 @@ public ConversionResult ConvertSolutionFile()
129128
var slnProjectReferenceReplacements = _solutionFileTextEditor.GetSolutionFileProjectReferenceReplacements(relativeProjPaths,
130129
_sourceSolutionContents, projectTypeGuidMappings);
131130

132-
var convertedSolutionContents = _sourceSolutionContents.Replace(slnProjectReferenceReplacements);
131+
var convertedSolutionContents = _textReplacementConverter.Replace(_sourceSolutionContents, slnProjectReferenceReplacements);
133132
return new ConversionResult(convertedSolutionContents) {
134133
SourcePathOrNull = _solutionFilePath,
135134
TargetPathOrNull = _solutionFilePath

CodeConverter/Shared/SolutionFileTextEditor.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,15 @@ private static (string oldProjTypeReference, string newProjTypeReference) GetPro
8484
private static (string Find, string Replace, bool FirstOnly) GetProjectGuidReplacement(string projPath,
8585
string contents)
8686
{
87-
var projGuidRegex = new Regex(projPath + @""", ""({[0-9A-Fa-f\-]{32,36}})("")");
87+
var guidPattern = projPath + @""", ""({[0-9A-Fa-f\-]{32,36}})("")";
88+
var projGuidRegex = new Regex(guidPattern);
8889
var projGuidMatch = projGuidRegex.Match(contents);
90+
91+
if (!projGuidMatch.Success) {
92+
throw new OperationCanceledException($"{nameof(guidPattern)} {guidPattern} doesn't match with" +
93+
$" sourceSlnFileContents {contents}");
94+
}
95+
8996
var oldGuid = projGuidMatch.Groups[1].Value;
9097
var newGuid = GetDeterministicGuidFrom(new Guid(oldGuid));
9198
return (oldGuid, newGuid.ToString("B").ToUpperInvariant(), false);

CodeConverter/Shared/TextReplacementConverter.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,26 @@ namespace ICSharpCode.CodeConverter.Shared
66
using System.Text.RegularExpressions;
77
using System.IO.Abstractions;
88

9-
public static class TextReplacementConverter
9+
public class TextReplacementConverter
1010
{
11-
public static IFileSystem FileSystem { get; set; } = new FileSystem();
11+
private readonly IFileSystem _fileSystem;
1212

13-
public static ConversionResult ConversionResultFromReplacements(this FileInfo filePath, IEnumerable<(string Find, string Replace, bool FirstOnly)> replacements, Func<string, string> postReplacementTransform = null)
13+
public TextReplacementConverter(IFileSystem fileSystem)
14+
{
15+
_fileSystem = fileSystem;
16+
}
17+
18+
public ConversionResult ConversionResultFromReplacements(FileInfo filePath, IEnumerable<(string Find, string Replace, bool FirstOnly)> replacements,
19+
Func<string, string> postReplacementTransform = null)
1420
{
1521
postReplacementTransform ??= (s => s);
16-
var oldProjectText = FileSystem.File.ReadAllText(filePath.FullName);
17-
var newProjectText = oldProjectText.Replace(replacements);
22+
var oldProjectText = _fileSystem.File.ReadAllText(filePath.FullName);
23+
var newProjectText = Replace(oldProjectText, replacements);
1824
string withReplacements = postReplacementTransform(newProjectText);
1925
return new ConversionResult(withReplacements) { SourcePathOrNull = filePath.FullName, IsIdentity = oldProjectText == withReplacements};
2026
}
2127

22-
public static string Replace(this string originalText, IEnumerable<(string Find, string Replace, bool FirstOnly)> replacements)
28+
public string Replace(string originalText, IEnumerable<(string Find, string Replace, bool FirstOnly)> replacements)
2329
{
2430
foreach (var (oldValue, newValue, firstOnly) in replacements) {
2531
Regex regex = new Regex(oldValue, RegexOptions.IgnoreCase);

CodeConverter/Shared/ThreadSafeWorkspaceHelper.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,21 @@ namespace ICSharpCode.CodeConverter.Shared
1818
public static class ThreadSafeWorkspaceHelper
1919
{
2020
/// <summary>
21-
/// Empty solution in an adhoc workspace
21+
/// Create an empty adhoc workspace
2222
/// </summary>
23-
public static AsyncLazy<Solution> EmptyAdhocSolution { get; } = new AsyncLazy<Solution>(async () => {
23+
public static AsyncLazy<AdhocWorkspace> CreateAdhocWorkspace { get; } = new(async () =>
24+
{
2425
var hostServices = await CreateHostServicesAsync(MefHostServices.DefaultAssemblies);
25-
return new AdhocWorkspace(hostServices).CurrentSolution;
26+
return new AdhocWorkspace(hostServices);
27+
}, JoinableTaskFactorySingleton.Instance);
28+
29+
/// <summary>
30+
/// Empty solution in an adhoc workspace
31+
/// </summary>
32+
public static AsyncLazy<Solution> EmptyAdhocSolution { get; } = new(async () =>
33+
{
34+
var adhocWorkspace = await CreateAdhocWorkspace.GetValueAsync();
35+
return adhocWorkspace.CurrentSolution;
2636
}, JoinableTaskFactorySingleton.Instance);
2737

2838
/// <summary>

Tests/CSharp/MultiFileSolutionAndProjectTests.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,14 @@ public MultiFileSolutionAndProjectTests(MultiFileTestFixture multiFileTestFixtur
1717
_multiFileTestFixture = multiFileTestFixture;
1818
}
1919

20-
//[Fact] /* enable for executing locally */
21-
[Fact(Skip = "Doesn't work on Github actions agent")] /* disable for executing locally */
20+
[Fact] /* enable for executing locally */
2221
public async Task ConvertWholeSolutionAsync()
2322
{
2423

2524
await _multiFileTestFixture.ConvertProjectsWhereAsync(p => true, Language.CS);
2625
}
2726

28-
//[Fact] /* enable for executing locally */
29-
[Fact(Skip = "Doesn't work on Github actions agent")] /* disable for executing locally */
27+
[Fact] /* enable for executing locally */
3028
public async Task ConvertVbLibraryOnlyAsync()
3129
{
3230
await _multiFileTestFixture.ConvertProjectsWhereAsync(p => p.Name == "VbLibrary", Language.CS);

0 commit comments

Comments
 (0)