Skip to content

Commit 0b6f82a

Browse files
Merge pull request #83 from microsoft/users/richsta/duplicatefolderid
Solution folders with duplicate ids should not error when reading sln…
2 parents 87ee8ea + 4a9985b commit 0b6f82a

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

src/Microsoft.VisualStudio.SolutionPersistence/Serializer/SlnV12/SlnFileV12Serializer.Reader.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,14 @@ private SolutionItemModel ReadProjectInfo(SolutionModel solution, ref StringToke
532532
#pragma warning disable CS0618 // Type or member is obsolete (Temporaily create a potentially invalid solution folder until nested projects is interpreted.)
533533
SolutionFolderModel folder = solution.CreateSlnFolder(name: displayName.ToString());
534534
#pragma warning restore CS0618 // Type or member is obsolete
535+
536+
// Solution folders with duplicate ids should not error when reading sln files to preserve legacy behavior.
537+
if (solution.FindItemById(projectId) is not null)
538+
{
539+
projectId = Guid.NewGuid();
540+
this.tarnished = true;
541+
}
542+
535543
folder.Id = projectId;
536544
return folder;
537545
}

test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/InvalidSolutions.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,35 @@ public async Task InvalidSlnxVersionAsync()
208208
Assert.Equal(1, ex.Line);
209209
Assert.Equal(2, ex.Column);
210210
}
211+
212+
/// <summary>
213+
/// The legacy sln solution parser would ignore duplicate folder guids.
214+
/// Ensure this behavior is maintained.
215+
/// </summary>
216+
[Fact]
217+
public async Task DuplicateFolderIdSlnAsync()
218+
{
219+
ResourceStream duplicateId = SlnAssets.LoadResource("Invalid/DuplicateFolderId.sln");
220+
SolutionModel solution = await SolutionSerializers.SlnFileV12.OpenAsync(duplicateId.Stream, CancellationToken.None);
221+
222+
Assert.Equal(4, solution.SolutionFolders.Count);
223+
224+
Assert.NotNull(solution.SerializerExtension);
225+
Assert.True(solution.SerializerExtension.Tarnished);
226+
}
227+
228+
/// <summary>
229+
/// Ensure the slnx parser does fail on duplicate folder guids.
230+
/// </summary>
231+
[Fact]
232+
public async Task DuplicateFolderIdSlnxAsync()
233+
{
234+
ResourceStream duplicateId = SlnAssets.LoadResource("Invalid/DuplicateFolderId.slnx");
235+
SolutionException ex = await Assert.ThrowsAsync<SolutionException>(
236+
async () => _ = await SolutionSerializers.SlnXml.OpenAsync(duplicateId.Stream, CancellationToken.None));
237+
238+
Assert.StartsWith(string.Format(Errors.DuplicateItemRef_Args2, "11111111-1111-1111-1111-111111111111", nameof(SolutionFolderModel)), ex.Message);
239+
Assert.Equal(3, ex.Line);
240+
Assert.Equal(4, ex.Column);
241+
}
211242
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+

2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apple", "Apple", "{11111111-1111-1111-1111-111111111111}"
4+
EndProject
5+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mango", "Mango", "{11111111-1111-1111-1111-111111111111}"
6+
EndProject
7+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Pear", "Pear", "{11111111-1111-1111-1111-111111111111}"
8+
EndProject
9+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Orange", "Orange", "{11111111-1111-1111-1111-111111111111}"
10+
EndProject
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<Solution>
2+
<Folder Name="/Apple/" Id="11111111-1111-1111-1111-111111111111" />
3+
<Folder Name="/Mango/" Id="11111111-1111-1111-1111-111111111111" />
4+
<Folder Name="/Pear/" Id="11111111-1111-1111-1111-111111111111" />
5+
<Folder Name="/Orange/" Id="11111111-1111-1111-1111-111111111111" />
6+
</Solution>

0 commit comments

Comments
 (0)