diff --git a/src/Framework.UnitTests/AbsolutePath_Tests.cs b/src/Framework.UnitTests/AbsolutePath_Tests.cs index b890d9938bc..40a93551385 100644 --- a/src/Framework.UnitTests/AbsolutePath_Tests.cs +++ b/src/Framework.UnitTests/AbsolutePath_Tests.cs @@ -7,6 +7,7 @@ using Microsoft.Build.Shared; using Shouldly; using Xunit; +using Xunit.NetCore.Extensions; namespace Microsoft.Build.UnitTests { @@ -47,18 +48,22 @@ public void AbsolutePath_FromAbsolutePath_ShouldPreservePath() [Theory] [InlineData(null)] [InlineData("")] + [UseInvariantCulture] public void AbsolutePath_NullOrEmpty_ShouldThrow(string? path) { - Should.Throw(() => new AbsolutePath(path!)); + var exception = Should.Throw(() => new AbsolutePath(path!)); + exception.Message.ShouldContain("Path must not be null or empty"); } [Theory] [InlineData(null)] [InlineData("")] + [UseInvariantCulture] public void AbsolutePath_NullOrEmptyWithBasePath_ShouldThrow(string? path) { var basePath = GetTestBasePath(); - Should.Throw(() => new AbsolutePath(path!, basePath)); + var exception = Should.Throw(() => new AbsolutePath(path!, basePath)); + exception.Message.ShouldContain("Path must not be null or empty"); } [Theory] @@ -213,5 +218,13 @@ public void AbsolutePath_UnixPathValidation_ShouldAcceptOnlyTrueAbsolutePaths(st { ValidatePathAcceptance(path, shouldBeAccepted); } + + [WindowsOnlyFact] + [UseInvariantCulture] + public void AbsolutePath_NotRooted_ShouldThrowWithLocalizedMessage() + { + var exception = Should.Throw(() => new AbsolutePath("relative/path")); + exception.Message.ShouldContain("Path must be rooted"); + } } } diff --git a/src/Framework/Microsoft.Build.Framework.csproj b/src/Framework/Microsoft.Build.Framework.csproj index b87b9db871e..b644c5ca208 100644 --- a/src/Framework/Microsoft.Build.Framework.csproj +++ b/src/Framework/Microsoft.Build.Framework.csproj @@ -73,4 +73,11 @@ + + + + $(AssemblyName).Strings.resources + Designer + + diff --git a/src/Framework/PathHelpers/AbsolutePath.cs b/src/Framework/PathHelpers/AbsolutePath.cs index 8a625ad6a4f..a3433c46b46 100644 --- a/src/Framework/PathHelpers/AbsolutePath.cs +++ b/src/Framework/PathHelpers/AbsolutePath.cs @@ -87,7 +87,7 @@ private static void ValidatePath(string path) { if (string.IsNullOrEmpty(path)) { - throw new ArgumentException("Path must not be null or empty.", nameof(path)); + throw new ArgumentException(FrameworkResources.GetString("PathMustNotBeNullOrEmpty"), nameof(path)); } // Path.IsPathFullyQualified is not available in .NET Standard 2.0 @@ -95,7 +95,7 @@ private static void ValidatePath(string path) #if NETFRAMEWORK || NET if (!Path.IsPathFullyQualified(path)) { - throw new ArgumentException("Path must be rooted.", nameof(path)); + throw new ArgumentException(FrameworkResources.GetString("PathMustBeRooted"), nameof(path)); } #endif } @@ -110,7 +110,7 @@ public AbsolutePath(string path, AbsolutePath basePath) { if (string.IsNullOrEmpty(path)) { - throw new ArgumentException("Path must not be null or empty.", nameof(path)); + throw new ArgumentException(FrameworkResources.GetString("PathMustNotBeNullOrEmpty"), nameof(path)); } // This function should not throw when path has illegal characters. @@ -118,7 +118,7 @@ public AbsolutePath(string path, AbsolutePath basePath) // For .NET Core, System.IO.Path.Combine already does not throw in this case. Value = Path.Combine(basePath.Value, path); OriginalValue = path; - } + } /// /// Implicitly converts an AbsolutePath to a string. diff --git a/src/Framework/Resources/AssemblyResources.cs b/src/Framework/Resources/AssemblyResources.cs new file mode 100644 index 00000000000..f30e00fce30 --- /dev/null +++ b/src/Framework/Resources/AssemblyResources.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; +using System.Reflection; +using System.Resources; + +namespace Microsoft.Build.Framework +{ + /// + /// This class provides access to the Framework assembly's resources. + /// + /// + /// Named FrameworkResources (not AssemblyResources) to avoid conflicts with + /// Microsoft.Build.Shared.AssemblyResources which is visible via InternalsVisibleTo. + /// + internal static class FrameworkResources + { + /// + /// The assembly's primary resources. + /// + private static readonly ResourceManager s_resources = new ResourceManager("Microsoft.Build.Framework.Strings", typeof(FrameworkResources).GetTypeInfo().Assembly); + + /// + /// Loads the specified resource string. + /// + /// This method is thread-safe. + /// The name of the string resource to load. + /// The resource string. + internal static string GetString(string name) + { + // NOTE: the ResourceManager.GetString() method is thread-safe + string? resource = s_resources.GetString(name, CultureInfo.CurrentUICulture); + + FrameworkErrorUtilities.VerifyThrow(resource != null, $"Missing resource '{name}'"); + + return resource!; + } + } +} diff --git a/src/Framework/Resources/Strings.resx b/src/Framework/Resources/Strings.resx new file mode 100644 index 00000000000..deba17d06bc --- /dev/null +++ b/src/Framework/Resources/Strings.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Path must not be null or empty. + + + Path must be rooted. + + diff --git a/src/Framework/Resources/xlf/Strings.cs.xlf b/src/Framework/Resources/xlf/Strings.cs.xlf new file mode 100644 index 00000000000..a747a3298fb --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.cs.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.de.xlf b/src/Framework/Resources/xlf/Strings.de.xlf new file mode 100644 index 00000000000..d8f53700f59 --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.de.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.en.xlf b/src/Framework/Resources/xlf/Strings.en.xlf new file mode 100644 index 00000000000..1ca805d7ff0 --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.en.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + Error thrown when a relative (non-absolute) path is passed to AbsolutePath constructor. + + + Path must not be null or empty. + Path must not be null or empty. + Error thrown when a null or empty path is passed to AbsolutePath constructor. + + + + diff --git a/src/Framework/Resources/xlf/Strings.es.xlf b/src/Framework/Resources/xlf/Strings.es.xlf new file mode 100644 index 00000000000..1c8415ec1ea --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.es.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.fr.xlf b/src/Framework/Resources/xlf/Strings.fr.xlf new file mode 100644 index 00000000000..cb3e3856555 --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.fr.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.it.xlf b/src/Framework/Resources/xlf/Strings.it.xlf new file mode 100644 index 00000000000..e11594b43d2 --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.it.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.ja.xlf b/src/Framework/Resources/xlf/Strings.ja.xlf new file mode 100644 index 00000000000..56994062df2 --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.ja.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.ko.xlf b/src/Framework/Resources/xlf/Strings.ko.xlf new file mode 100644 index 00000000000..87e8331cd1d --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.ko.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.pl.xlf b/src/Framework/Resources/xlf/Strings.pl.xlf new file mode 100644 index 00000000000..781293c265e --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.pl.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.pt-BR.xlf b/src/Framework/Resources/xlf/Strings.pt-BR.xlf new file mode 100644 index 00000000000..903a8395c4e --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.pt-BR.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.ru.xlf b/src/Framework/Resources/xlf/Strings.ru.xlf new file mode 100644 index 00000000000..0e2525be58d --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.ru.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.tr.xlf b/src/Framework/Resources/xlf/Strings.tr.xlf new file mode 100644 index 00000000000..f42747284ea --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.tr.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.xlf b/src/Framework/Resources/xlf/Strings.xlf new file mode 100644 index 00000000000..2b84b4f9f6b --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.xlf @@ -0,0 +1,16 @@ + + + + + + + Path must be rooted. + Error thrown when a relative (non-absolute) path is passed to AbsolutePath constructor. + + + Path must not be null or empty. + Error thrown when a null or empty path is passed to AbsolutePath constructor. + + + + diff --git a/src/Framework/Resources/xlf/Strings.zh-Hans.xlf b/src/Framework/Resources/xlf/Strings.zh-Hans.xlf new file mode 100644 index 00000000000..f07294d17ee --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.zh-Hans.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file diff --git a/src/Framework/Resources/xlf/Strings.zh-Hant.xlf b/src/Framework/Resources/xlf/Strings.zh-Hant.xlf new file mode 100644 index 00000000000..2c4af9f202f --- /dev/null +++ b/src/Framework/Resources/xlf/Strings.zh-Hant.xlf @@ -0,0 +1,17 @@ + + + + + + Path must be rooted. + Path must be rooted. + + + + Path must not be null or empty. + Path must not be null or empty. + + + + + \ No newline at end of file