From 9d62041d675f35f3188052bcd26b4074aa12c761 Mon Sep 17 00:00:00 2001 From: Jan Krivanek Date: Mon, 30 Jan 2023 15:18:43 +0100 Subject: [PATCH 1/8] Add ability to create temp mapped drive for integration tests --- .../Definition/ProjectItem_Tests.cs | 23 +++++- ...Microsoft.Build.Engine.OM.UnitTests.csproj | 2 + src/UnitTests.Shared/DriveMapping.cs | 73 +++++++++++++++++ src/UnitTests.Shared/DummyMappedDrive.cs | 81 +++++++++++++++++++ 4 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 src/UnitTests.Shared/DriveMapping.cs create mode 100644 src/UnitTests.Shared/DummyMappedDrive.cs diff --git a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs index 0d44fcf3f06..ac91bd2de6c 100644 --- a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs +++ b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs @@ -13,6 +13,7 @@ using Microsoft.Build.Execution; using Microsoft.Build.Framework; using Microsoft.Build.Shared; +using Microsoft.Build.UnitTests.Shared; using Shouldly; using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException; using Xunit; @@ -54,7 +55,8 @@ public class ProjectItem_Tests : IDisposable "; - protected TestEnvironment _env; + protected readonly TestEnvironment _env; + private DummyMappedDrive _mappedDrive = null; public ProjectItem_Tests() { @@ -64,6 +66,7 @@ public ProjectItem_Tests() public void Dispose() { _env.Dispose(); + _mappedDrive?.Dispose(); } /// @@ -795,7 +798,6 @@ public void ProjectGetterResultsInDriveEnumerationException(string unevaluatedIn /// /// Project getter that renames an item to a drive enumerating wildcard that results in a logged warning. /// - [ActiveIssue("https://github.com/dotnet/msbuild/issues/7330")] [PlatformSpecific(TestPlatforms.Windows)] [Theory] [InlineData(@"z:\**\*.log")] @@ -806,6 +808,9 @@ public void ProjectGetterResultsInDriveEnumerationException(string unevaluatedIn [InlineData(@"z:\**\*.cs")] public void ProjectGetterResultsInWindowsDriveEnumerationWarning(string unevaluatedInclude) { + // let's create the mapped drive only once it's needed by any test, then let's reuse; + _mappedDrive ??= new DummyMappedDrive(); + unevaluatedInclude = UpdatePathToMappedDrive(unevaluatedInclude, _mappedDrive.MappedDriveLetter); ProjectGetterResultsInDriveEnumerationWarning(unevaluatedInclude); } @@ -880,7 +885,6 @@ public void ThrowExceptionUponProjectInstanceCreationFromDriveEnumeratingContent /// /// Project instance created from a file that contains a drive enumerating wildcard results in a logged warning on the Windows platform. /// - [ActiveIssue("https://github.com/dotnet/msbuild/issues/7330")] [PlatformSpecific(TestPlatforms.Windows)] [Theory] [InlineData( @@ -901,10 +905,23 @@ public void ThrowExceptionUponProjectInstanceCreationFromDriveEnumeratingContent @"z:\$(Microsoft_WindowsAzure_EngSys)**")] public void LogWindowsWarningUponProjectInstanceCreationFromDriveEnumeratingContent(string content, string placeHolder, string excludePlaceHolder = null) { + // let's create the mapped drive only once it's needed by any test, then let's reuse; + _mappedDrive ??= new DummyMappedDrive(); + placeHolder = UpdatePathToMappedDrive(placeHolder, _mappedDrive.MappedDriveLetter); + excludePlaceHolder = UpdatePathToMappedDrive(excludePlaceHolder, _mappedDrive.MappedDriveLetter); content = string.Format(content, placeHolder, excludePlaceHolder); CleanContentsAndCreateProjectInstanceFromFileWithDriveEnumeratingWildcard(content, false); } + private static string UpdatePathToMappedDrive(string path, char driveLetter) + { + if (!string.IsNullOrEmpty(path) && path.StartsWith(driveLetter + ":", StringComparison.OrdinalIgnoreCase)) + { + path = driveLetter + path.Substring(1); + } + return path; + } + [ActiveIssue("https://github.com/dotnet/msbuild/issues/7330")] [PlatformSpecific(TestPlatforms.AnyUnix)] [Theory] diff --git a/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj b/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj index 51d86b2f804..d3fa763cf2a 100644 --- a/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj +++ b/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj @@ -80,6 +80,8 @@ + + App.config Designer diff --git a/src/UnitTests.Shared/DriveMapping.cs b/src/UnitTests.Shared/DriveMapping.cs new file mode 100644 index 00000000000..9bdc36c031b --- /dev/null +++ b/src/UnitTests.Shared/DriveMapping.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable +using System.Runtime.InteropServices; +using System.Text; + +namespace Microsoft.Build.UnitTests.Shared; + +internal static class DriveMapping +{ + private const int ERROR_FILE_NOT_FOUND = 2; + private const int ERROR_INSUFFICIENT_BUFFER = 122; + private const int DDD_REMOVE_DEFINITION = 2; + private const int DDD_NO_FLAG = 0; + // extra space for '\??\'. Not counting for long paths support in tests. + private const int MAX_PATH = 259; + + /// + /// Windows specific. Maps path to a requested drive. + /// + /// Drive letter + /// Path to be mapped + public static void MapDrive(char letter, string path) + { + if (!DefineDosDevice(DDD_NO_FLAG, ToDeviceName(letter), path)) + { + NativeMethodsShared.ThrowExceptionForErrorCode(Marshal.GetLastWin32Error()); + } + } + + /// + /// Windows specific. Unmaps drive mapping. + /// + /// Drive letter. + public static void UnmapDrive(char letter) + { + if (!DefineDosDevice(DDD_REMOVE_DEFINITION, ToDeviceName(letter), null)) + { + NativeMethodsShared.ThrowExceptionForErrorCode(Marshal.GetLastWin32Error()); + } + } + + /// + /// Windows specific. Fetches path mapped under specific drive letter. + /// + /// Drive letter. + /// Path mapped under specified letter. Empty string if mapping not found. + public static string GetDriveMapping(char letter) + { + // since this is just for test purposes - let's not overcomplicate with long paths support + var sb = new StringBuilder(MAX_PATH); + if (QueryDosDevice(ToDeviceName(letter), sb, sb.Capacity) == 0) + { + // Return empty string if the drive is not mapped + int err = Marshal.GetLastWin32Error(); + if (err == ERROR_FILE_NOT_FOUND) return string.Empty; + NativeMethodsShared.ThrowExceptionForErrorCode(err); + } + // Translate from the native path semantic - starting with '\??\' + return sb.ToString(4, sb.Length - 4); + } + + private static string ToDeviceName(char letter) + { + return new string(char.ToUpper(letter), 1) + ":"; + } + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern bool DefineDosDevice(int flags, string deviceName, string? path); + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int QueryDosDevice(string deviceName, StringBuilder buffer, int bufSize); +} diff --git a/src/UnitTests.Shared/DummyMappedDrive.cs b/src/UnitTests.Shared/DummyMappedDrive.cs new file mode 100644 index 00000000000..8b3a99bb72c --- /dev/null +++ b/src/UnitTests.Shared/DummyMappedDrive.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable +using System; +using System.Diagnostics; +using System.IO; + +namespace Microsoft.Build.UnitTests.Shared; + +/// +/// Windows specific. Class managing system resource - temporary local path mapped to available drive letter. +/// +public class DummyMappedDrive : IDisposable +{ + public char MappedDriveLetter { get; init; } = 'z'; + private readonly string _mappedPath; + private readonly bool _mapped; + + public DummyMappedDrive() + { + _mappedPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + Directory.CreateDirectory(_mappedPath); + File.Create(Path.Combine(_mappedPath, "x")).Dispose(); + + for (char driveLetter = 'z'; driveLetter >= 'a'; driveLetter--) + { + if (DriveMapping.GetDriveMapping(driveLetter) == string.Empty) + { + DriveMapping.MapDrive(driveLetter, _mappedPath); + MappedDriveLetter = driveLetter; + _mapped = true; + return; + } + } + } + + private void ReleaseUnmanagedResources(bool disposing) + { + Exception? e = null; + if (Directory.Exists(_mappedPath)) + { + try + { + Directory.Delete(_mappedPath, true); + } + catch (Exception exc) + { + e = exc; + Debug.Fail("Exception in DummyMappedDrive finalizer: " + e.ToString()); + } + + } + + if (_mapped) + { + try + { + DriveMapping.UnmapDrive(MappedDriveLetter); + } + catch (Exception exc) + { + e = e == null ? exc : new AggregateException(e, exc); + Debug.Fail("Exception in DummyMappedDrive finalizer: " + e.ToString()); + } + } + + if (disposing && e != null) + { + throw e; + } + } + + public void Dispose() + { + ReleaseUnmanagedResources(true); + GC.SuppressFinalize(this); + } + + ~DummyMappedDrive() => ReleaseUnmanagedResources(false); +} From e498cc2a3ffa91a5318821171cd49da5c01ee7be Mon Sep 17 00:00:00 2001 From: Jan Krivanek Date: Mon, 30 Jan 2023 16:24:33 +0100 Subject: [PATCH 2/8] Fix analyzer findings --- src/UnitTests.Shared/DriveMapping.cs | 18 +++++++++++------- src/UnitTests.Shared/DummyMappedDrive.cs | 1 - 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/UnitTests.Shared/DriveMapping.cs b/src/UnitTests.Shared/DriveMapping.cs index 9bdc36c031b..689d31ab848 100644 --- a/src/UnitTests.Shared/DriveMapping.cs +++ b/src/UnitTests.Shared/DriveMapping.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #nullable enable +using System; using System.Runtime.InteropServices; using System.Text; @@ -10,7 +11,7 @@ namespace Microsoft.Build.UnitTests.Shared; internal static class DriveMapping { private const int ERROR_FILE_NOT_FOUND = 2; - private const int ERROR_INSUFFICIENT_BUFFER = 122; + // private const int ERROR_INSUFFICIENT_BUFFER = 122; private const int DDD_REMOVE_DEFINITION = 2; private const int DDD_NO_FLAG = 0; // extra space for '\??\'. Not counting for long paths support in tests. @@ -49,16 +50,19 @@ public static void UnmapDrive(char letter) public static string GetDriveMapping(char letter) { // since this is just for test purposes - let's not overcomplicate with long paths support - var sb = new StringBuilder(MAX_PATH); - if (QueryDosDevice(ToDeviceName(letter), sb, sb.Capacity) == 0) + char[] buffer = new char[MAX_PATH]; + if (QueryDosDevice(ToDeviceName(letter), buffer, buffer.Length) == 0) { // Return empty string if the drive is not mapped int err = Marshal.GetLastWin32Error(); - if (err == ERROR_FILE_NOT_FOUND) return string.Empty; + if (err == ERROR_FILE_NOT_FOUND) + { + return string.Empty; + } NativeMethodsShared.ThrowExceptionForErrorCode(err); } // Translate from the native path semantic - starting with '\??\' - return sb.ToString(4, sb.Length - 4); + return new string(buffer, 4, buffer.Length - 4); } private static string ToDeviceName(char letter) @@ -67,7 +71,7 @@ private static string ToDeviceName(char letter) } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - private static extern bool DefineDosDevice(int flags, string deviceName, string? path); + private static extern bool DefineDosDevice([In] int flags, [In] string deviceName, [In] string? path); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - private static extern int QueryDosDevice(string deviceName, StringBuilder buffer, int bufSize); + private static extern int QueryDosDevice([In] string deviceName, [Out] char[] buffer, [In] int bufSize); } diff --git a/src/UnitTests.Shared/DummyMappedDrive.cs b/src/UnitTests.Shared/DummyMappedDrive.cs index 8b3a99bb72c..acde6e569f1 100644 --- a/src/UnitTests.Shared/DummyMappedDrive.cs +++ b/src/UnitTests.Shared/DummyMappedDrive.cs @@ -49,7 +49,6 @@ private void ReleaseUnmanagedResources(bool disposing) e = exc; Debug.Fail("Exception in DummyMappedDrive finalizer: " + e.ToString()); } - } if (_mapped) From 908b6745140db8d78a7abba7917c359e52dd642a Mon Sep 17 00:00:00 2001 From: Jan Krivanek Date: Tue, 31 Jan 2023 10:08:22 +0100 Subject: [PATCH 3/8] Remove the unix warning --- src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs index ac91bd2de6c..e50d84dc0a4 100644 --- a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs +++ b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs @@ -814,7 +814,6 @@ public void ProjectGetterResultsInWindowsDriveEnumerationWarning(string unevalua ProjectGetterResultsInDriveEnumerationWarning(unevaluatedInclude); } - [ActiveIssue("https://github.com/dotnet/msbuild/issues/7330")] [PlatformSpecific(TestPlatforms.AnyUnix)] [Theory] [InlineData(@"/**/*.log")] @@ -922,7 +921,6 @@ private static string UpdatePathToMappedDrive(string path, char driveLetter) return path; } - [ActiveIssue("https://github.com/dotnet/msbuild/issues/7330")] [PlatformSpecific(TestPlatforms.AnyUnix)] [Theory] [InlineData( From f782273fea15ccc2d12b3b806542ac48da2c4b75 Mon Sep 17 00:00:00 2001 From: Jan Krivanek Date: Tue, 31 Jan 2023 10:34:41 +0100 Subject: [PATCH 4/8] Guard platform specific calls --- .../Definition/ProjectItem_Tests.cs | 26 +++++++++++++------ src/UnitTests.Shared/DriveMapping.cs | 7 +++++ src/UnitTests.Shared/DummyMappedDrive.cs | 9 ++++++- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs index e50d84dc0a4..6bc8b1623ac 100644 --- a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs +++ b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs @@ -808,9 +808,8 @@ public void ProjectGetterResultsInDriveEnumerationException(string unevaluatedIn [InlineData(@"z:\**\*.cs")] public void ProjectGetterResultsInWindowsDriveEnumerationWarning(string unevaluatedInclude) { - // let's create the mapped drive only once it's needed by any test, then let's reuse; - _mappedDrive ??= new DummyMappedDrive(); - unevaluatedInclude = UpdatePathToMappedDrive(unevaluatedInclude, _mappedDrive.MappedDriveLetter); + var mappedDrive = GetDummyMappedDrive(); + unevaluatedInclude = UpdatePathToMappedDrive(unevaluatedInclude, mappedDrive.MappedDriveLetter); ProjectGetterResultsInDriveEnumerationWarning(unevaluatedInclude); } @@ -904,17 +903,28 @@ public void ThrowExceptionUponProjectInstanceCreationFromDriveEnumeratingContent @"z:\$(Microsoft_WindowsAzure_EngSys)**")] public void LogWindowsWarningUponProjectInstanceCreationFromDriveEnumeratingContent(string content, string placeHolder, string excludePlaceHolder = null) { - // let's create the mapped drive only once it's needed by any test, then let's reuse; - _mappedDrive ??= new DummyMappedDrive(); - placeHolder = UpdatePathToMappedDrive(placeHolder, _mappedDrive.MappedDriveLetter); - excludePlaceHolder = UpdatePathToMappedDrive(excludePlaceHolder, _mappedDrive.MappedDriveLetter); + var mappedDrive = GetDummyMappedDrive(); + placeHolder = UpdatePathToMappedDrive(placeHolder, mappedDrive.MappedDriveLetter); + excludePlaceHolder = UpdatePathToMappedDrive(excludePlaceHolder, mappedDrive.MappedDriveLetter); content = string.Format(content, placeHolder, excludePlaceHolder); CleanContentsAndCreateProjectInstanceFromFileWithDriveEnumeratingWildcard(content, false); } + private DummyMappedDrive GetDummyMappedDrive() + { + if (NativeMethods.IsWindows) + { + // let's create the mapped drive only once it's needed by any test, then let's reuse; + _mappedDrive ??= new DummyMappedDrive(); + } + + return _mappedDrive; + } + private static string UpdatePathToMappedDrive(string path, char driveLetter) { - if (!string.IsNullOrEmpty(path) && path.StartsWith(driveLetter + ":", StringComparison.OrdinalIgnoreCase)) + // if this seems to be rooted path - replace with the dummy mount + if (!string.IsNullOrEmpty(path) && path.Length > 1 && path[1] == ':') { path = driveLetter + path.Substring(1); } diff --git a/src/UnitTests.Shared/DriveMapping.cs b/src/UnitTests.Shared/DriveMapping.cs index 689d31ab848..5f1dcd02bd2 100644 --- a/src/UnitTests.Shared/DriveMapping.cs +++ b/src/UnitTests.Shared/DriveMapping.cs @@ -4,6 +4,7 @@ #nullable enable using System; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Text; namespace Microsoft.Build.UnitTests.Shared; @@ -22,6 +23,7 @@ internal static class DriveMapping /// /// Drive letter /// Path to be mapped + [SupportedOSPlatform("windows")] public static void MapDrive(char letter, string path) { if (!DefineDosDevice(DDD_NO_FLAG, ToDeviceName(letter), path)) @@ -34,6 +36,7 @@ public static void MapDrive(char letter, string path) /// Windows specific. Unmaps drive mapping. /// /// Drive letter. + [SupportedOSPlatform("windows")] public static void UnmapDrive(char letter) { if (!DefineDosDevice(DDD_REMOVE_DEFINITION, ToDeviceName(letter), null)) @@ -47,6 +50,7 @@ public static void UnmapDrive(char letter) /// /// Drive letter. /// Path mapped under specified letter. Empty string if mapping not found. + [SupportedOSPlatform("windows")] public static string GetDriveMapping(char letter) { // since this is just for test purposes - let's not overcomplicate with long paths support @@ -71,7 +75,10 @@ private static string ToDeviceName(char letter) } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [SupportedOSPlatform("windows")] private static extern bool DefineDosDevice([In] int flags, [In] string deviceName, [In] string? path); + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [SupportedOSPlatform("windows")] private static extern int QueryDosDevice([In] string deviceName, [Out] char[] buffer, [In] int bufSize); } diff --git a/src/UnitTests.Shared/DummyMappedDrive.cs b/src/UnitTests.Shared/DummyMappedDrive.cs index acde6e569f1..ec7df37a00d 100644 --- a/src/UnitTests.Shared/DummyMappedDrive.cs +++ b/src/UnitTests.Shared/DummyMappedDrive.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Runtime.Versioning; namespace Microsoft.Build.UnitTests.Shared; @@ -20,6 +21,12 @@ public class DummyMappedDrive : IDisposable public DummyMappedDrive() { _mappedPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + + if (!NativeMethodsShared.IsWindows) + { + return; + } + Directory.CreateDirectory(_mappedPath); File.Create(Path.Combine(_mappedPath, "x")).Dispose(); @@ -51,7 +58,7 @@ private void ReleaseUnmanagedResources(bool disposing) } } - if (_mapped) + if (_mapped && NativeMethodsShared.IsWindows) { try { From f6f1998a432cfc420fd417ae33c60ac6fff6677e Mon Sep 17 00:00:00 2001 From: Jan Krivanek Date: Tue, 31 Jan 2023 10:50:43 +0100 Subject: [PATCH 5/8] Failing unix testcase --- src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs index 6bc8b1623ac..7e2a7bab39e 100644 --- a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs +++ b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs @@ -933,10 +933,11 @@ private static string UpdatePathToMappedDrive(string path, char driveLetter) [PlatformSpecific(TestPlatforms.AnyUnix)] [Theory] - [InlineData( - ImportProjectElement, - @"\**\*.targets", - null)] + //Failing: https://github.com/dotnet/msbuild/issues/8373 + //[InlineData( + // ImportProjectElement, + // @"\**\*.targets", + // null)] // LazyItem.IncludeOperation [InlineData( From 52f1ef38fb5844207694cfae5e137f3cf2899581 Mon Sep 17 00:00:00 2001 From: Jan Krivanek Date: Tue, 31 Jan 2023 11:00:24 +0100 Subject: [PATCH 6/8] Style checks --- src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs index 7e2a7bab39e..8829a0d2117 100644 --- a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs +++ b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs @@ -933,8 +933,8 @@ private static string UpdatePathToMappedDrive(string path, char driveLetter) [PlatformSpecific(TestPlatforms.AnyUnix)] [Theory] - //Failing: https://github.com/dotnet/msbuild/issues/8373 - //[InlineData( + // Failing: https://github.com/dotnet/msbuild/issues/8373 + // [InlineData( // ImportProjectElement, // @"\**\*.targets", // null)] From bc7179b7109d5ae92e7d4b94d95dd95fe29e7784 Mon Sep 17 00:00:00 2001 From: Jan Krivanek Date: Tue, 31 Jan 2023 15:01:37 +0100 Subject: [PATCH 7/8] Fix review comments --- .../Definition/ProjectItem_Tests.cs | 11 ++++++----- src/UnitTests.Shared/DriveMapping.cs | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs index c30b6e4a414..fed9bbf6f7b 100644 --- a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs +++ b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs @@ -810,6 +810,7 @@ public void ProjectGetterResultsInWindowsDriveEnumerationWarning(string unevalua } [UnixOnlyTheory] + [ActiveIssue("https://github.com/dotnet/msbuild/issues/8373")] [InlineData(@"/**/*.log")] [InlineData(@"$(empty)/**/*.log")] [InlineData(@"/$(empty)**/*.log")] @@ -926,11 +927,11 @@ private static string UpdatePathToMappedDrive(string path, char driveLetter) } [UnixOnlyTheory] - // Failing: https://github.com/dotnet/msbuild/issues/8373 - // [InlineData( - // ImportProjectElement, - // @"\**\*.targets", - // null)] + [ActiveIssue("https://github.com/dotnet/msbuild/issues/8373")] + [InlineData( + ImportProjectElement, + @"\**\*.targets", + null)] // LazyItem.IncludeOperation [InlineData( diff --git a/src/UnitTests.Shared/DriveMapping.cs b/src/UnitTests.Shared/DriveMapping.cs index 5f1dcd02bd2..81324086548 100644 --- a/src/UnitTests.Shared/DriveMapping.cs +++ b/src/UnitTests.Shared/DriveMapping.cs @@ -12,7 +12,7 @@ namespace Microsoft.Build.UnitTests.Shared; internal static class DriveMapping { private const int ERROR_FILE_NOT_FOUND = 2; - // private const int ERROR_INSUFFICIENT_BUFFER = 122; + private const int ERROR_INSUFFICIENT_BUFFER = 122; private const int DDD_REMOVE_DEFINITION = 2; private const int DDD_NO_FLAG = 0; // extra space for '\??\'. Not counting for long paths support in tests. @@ -55,7 +55,8 @@ public static string GetDriveMapping(char letter) { // since this is just for test purposes - let's not overcomplicate with long paths support char[] buffer = new char[MAX_PATH]; - if (QueryDosDevice(ToDeviceName(letter), buffer, buffer.Length) == 0) + + while (QueryDosDevice(ToDeviceName(letter), buffer, buffer.Length) == 0) { // Return empty string if the drive is not mapped int err = Marshal.GetLastWin32Error(); @@ -63,15 +64,22 @@ public static string GetDriveMapping(char letter) { return string.Empty; } - NativeMethodsShared.ThrowExceptionForErrorCode(err); + + if (err != ERROR_INSUFFICIENT_BUFFER) + { + NativeMethodsShared.ThrowExceptionForErrorCode(err); + } + + buffer = new char[buffer.Length * 4]; } + // Translate from the native path semantic - starting with '\??\' return new string(buffer, 4, buffer.Length - 4); } private static string ToDeviceName(char letter) { - return new string(char.ToUpper(letter), 1) + ":"; + return $"{char.ToUpper(letter)}:"; } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] From 0fbd8de18350720cdb3cd6983266a3baefe89f13 Mon Sep 17 00:00:00 2001 From: Jan Krivanek Date: Wed, 1 Feb 2023 14:20:13 +0100 Subject: [PATCH 8/8] Use drive placeholder --- .../Definition/ProjectItem_Tests.cs | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs index fed9bbf6f7b..7c94f520426 100644 --- a/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs +++ b/src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs @@ -796,12 +796,12 @@ public void ProjectGetterResultsInDriveEnumerationException(string unevaluatedIn /// Project getter that renames an item to a drive enumerating wildcard that results in a logged warning. /// [WindowsOnlyTheory] - [InlineData(@"z:\**\*.log")] - [InlineData(@"z:$(empty)\**\*.log")] - [InlineData(@"z:\**")] - [InlineData(@"z:\\**")] - [InlineData(@"z:\\\\\\\\**")] - [InlineData(@"z:\**\*.cs")] + [InlineData(@"%DRIVE%:\**\*.log")] + [InlineData(@"%DRIVE%:$(empty)\**\*.log")] + [InlineData(@"%DRIVE%:\**")] + [InlineData(@"%DRIVE%:\\**")] + [InlineData(@"%DRIVE%:\\\\\\\\**")] + [InlineData(@"%DRIVE%:\**\*.cs")] public void ProjectGetterResultsInWindowsDriveEnumerationWarning(string unevaluatedInclude) { var mappedDrive = GetDummyMappedDrive(); @@ -882,20 +882,20 @@ public void ThrowExceptionUponProjectInstanceCreationFromDriveEnumeratingContent [WindowsOnlyTheory] [InlineData( ImportProjectElement, - @"z:\**\*.targets", + @"%DRIVE%:\**\*.targets", null)] // LazyItem.IncludeOperation [InlineData( ItemWithIncludeAndExclude, - @"z:$(Microsoft_WindowsAzure_EngSys)\**\*", + @"%DRIVE%:$(Microsoft_WindowsAzure_EngSys)\**\*", @"$(Microsoft_WindowsAzure_EngSys)\*.pdb;$(Microsoft_WindowsAzure_EngSys)\Microsoft.WindowsAzure.Storage.dll;$(Microsoft_WindowsAzure_EngSys)\Certificates\**\*")] // LazyItem.IncludeOperation for Exclude [InlineData( ItemWithIncludeAndExclude, @"$(EmptyProperty)\*.cs", - @"z:\$(Microsoft_WindowsAzure_EngSys)**")] + @"%DRIVE%:\$(Microsoft_WindowsAzure_EngSys)**")] public void LogWindowsWarningUponProjectInstanceCreationFromDriveEnumeratingContent(string content, string placeHolder, string excludePlaceHolder = null) { var mappedDrive = GetDummyMappedDrive(); @@ -918,10 +918,11 @@ private DummyMappedDrive GetDummyMappedDrive() private static string UpdatePathToMappedDrive(string path, char driveLetter) { + const string drivePlaceholder = "%DRIVE%"; // if this seems to be rooted path - replace with the dummy mount - if (!string.IsNullOrEmpty(path) && path.Length > 1 && path[1] == ':') + if (!string.IsNullOrEmpty(path) && path.StartsWith(drivePlaceholder)) { - path = driveLetter + path.Substring(1); + path = driveLetter + path.Substring(drivePlaceholder.Length); } return path; }