From 1c59cf3de9d6a0a692abf6245a039ae6f957f489 Mon Sep 17 00:00:00 2001 From: Dan Travison Date: Thu, 30 Nov 2017 08:17:16 -0800 Subject: [PATCH 1/6] Use explicit libpsl-native binary name for dllimport. (#5580) --- .../utils/tracing/SysLogProvider.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/utils/tracing/SysLogProvider.cs b/src/System.Management.Automation/utils/tracing/SysLogProvider.cs index d54392e607a..03d5d17e9eb 100755 --- a/src/System.Management.Automation/utils/tracing/SysLogProvider.cs +++ b/src/System.Management.Automation/utils/tracing/SysLogProvider.cs @@ -357,6 +357,7 @@ internal enum LogLevel : uint internal static class NativeMethods { + const string libpslnative = "libpsl-native"; /// /// Write a message to the system logger, which in turn writes the message to the system console, log files, etc. /// See man 3 syslog for more info. @@ -365,13 +366,13 @@ internal static class NativeMethods /// The OR of a priority and facility in the SysLogPriority enum indicating the the priority and facility of the log entry. /// /// The message to put in the log entry. - [DllImport("psl-native", CharSet = CharSet.Ansi, EntryPoint = "Native_SysLog")] + [DllImport(libpslnative, CharSet = CharSet.Ansi, EntryPoint = "Native_SysLog")] internal static extern void SysLog(SysLogPriority priority, string message); - [DllImport("psl-native", CharSet = CharSet.Ansi, EntryPoint = "Native_OpenLog")] + [DllImport(libpslnative, CharSet = CharSet.Ansi, EntryPoint = "Native_OpenLog")] internal static extern void OpenLog(IntPtr ident, SysLogPriority facility); - [DllImport("psl-native", EntryPoint = "Native_CloseLog")] + [DllImport(libpslnative, EntryPoint = "Native_CloseLog")] internal static extern void CloseLog(); [Flags] From 1ed5e7fb64b0e81bb703253c3166c03f3b4c12de Mon Sep 17 00:00:00 2001 From: Chunqing Chen Date: Thu, 30 Nov 2017 14:44:41 -0800 Subject: [PATCH 2/6] Fix xunnit test for PS (#4780) * Initial work to enable xunit * Moved AssemblyOriginatorKeyFile to csharp.tests.csproj * Native binary has dylib extension on macOS --- build.psm1 | 118 ++++++++++++++++----- test/csharp/csharp.tests.csproj | 21 ++-- test/csharp/fixture_AssemblyLoadContext.cs | 25 ----- test/csharp/test_Binders.cs | 7 +- test/csharp/test_CorePsPlatform.cs | 9 +- test/csharp/test_ExtensionMethods.cs | 6 +- test/csharp/test_FileSystemProvider.cs | 41 +++++-- test/csharp/test_MshSnapinInfo.cs | 7 +- test/csharp/test_PSVersionInfo.cs | 1 - test/csharp/test_Runspace.cs | 14 +-- test/csharp/test_SecuritySupport.cs | 11 +- test/csharp/test_SessionState.cs | 4 +- test/csharp/test_Utils.cs | 5 +- tools/appveyor.psm1 | 7 ++ tools/travis.ps1 | 5 +- 15 files changed, 178 insertions(+), 103 deletions(-) delete mode 100644 test/csharp/fixture_AssemblyLoadContext.cs diff --git a/build.psm1 b/build.psm1 index d770d53e530..9c97a4e65ef 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1188,6 +1188,53 @@ function Show-PSPesterError } +function Test-XUnitTestResults +{ + param( + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $TestResultsFile + ) + + if(-not (Test-Path $TestResultsFile)) + { + throw "File not found $TestResultsFile" + } + + try + { + $results = [xml] (Get-Content $TestResultsFile) + } + catch + { + throw "Cannot convert $TestResultsFile to xml : $($_.message)" + } + + $failedTests = $results.assemblies.assembly.collection | Where-Object failed -gt 0 + + if(-not $failedTests) + { + return $true + } + + foreach($failure in $failedTests) + { + $description = $failure.test.type + $name = $failure.test.method + $message = $failure.test.failure.message.'#cdata-section' + $stackTrace = $failure.test.failure.'stack-trace'.'#cdata-section' + + logerror ("Description: " + $description) + logerror ("Name: " + $name) + logerror "message:" + logerror $message + logerror "stack-trace:" + logerror $stackTrace + } + + throw "$($failedTests.failed) tests failed" +} + # # Read the test result file and # Throw if a test failed @@ -1251,46 +1298,67 @@ function Test-PSPesterResults function Start-PSxUnit { - [CmdletBinding()]param() - - log "xUnit tests are currently disabled pending fixes due to API and AssemblyLoadContext changes - @andschwa" - return - - if ($Environment.IsWindows) { - throw "xUnit tests are only currently supported on Linux / OS X" - } - - if ($Environment.IsMacOS) { - log "Not yet supported on OS X, pretending they passed..." - return - } + [CmdletBinding()]param( + [string] $TestResultsFile = "XUnitResults.xml" + ) # Add .NET CLI tools to PATH Find-Dotnet - $Arguments = "--configuration", "Linux", "-parallel", "none" - if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { - $Arguments += "-verbose" - } - $Content = Split-Path -Parent (Get-PSOutput) if (-not (Test-Path $Content)) { throw "PowerShell must be built before running tests!" } + if(Test-Path $TestResultsFile) + { + Remove-Item $TestResultsFile -Force -ErrorAction SilentlyContinue + } + try { Push-Location $PSScriptRoot/test/csharp + # Path manipulation to obtain test project output directory - $Output = Join-Path $pwd ((Split-Path -Parent (Get-PSOutput)) -replace (New-PSOptions).Top) - Write-Verbose "Output is $Output" + dotnet restore - Copy-Item -ErrorAction SilentlyContinue -Recurse -Path $Content/* -Include Modules,libpsl-native* -Destination $Output - Start-NativeExecution { dotnet test $Arguments } + # --fx-version workaround required due to https://github.com/dotnet/cli/issues/7901#issuecomment-343323674 + if($Environment.IsWindows) + { + dotnet xunit --fx-version 2.0.0 -xml $TestResultsFile + } + else + { + if($Environment.IsMacOS) + { + $nativeLib = "$Content/libpsl-native.dylib" + } + else + { + $nativeLib = "$Content/libpsl-native.so" + } + + $requiredDependencies = @( + $nativeLib, + "$Content/Microsoft.Management.Infrastructure.dll", + "$Content/System.Text.Encoding.CodePages.dll" + ) + + if((Test-Path $requiredDependencies) -notcontains $false) + { + $options = New-PSOptions + $Destination = "bin/$($options.configuration)/$($options.framework)" + New-Item $Destination -ItemType Directory -Force > $null + Copy-Item -Path $requiredDependencies -Destination $Destination -Force + } + else + { + throw "Dependencies $requiredDependencies not met." + } - if ($LASTEXITCODE -ne 0) { - throw "$LASTEXITCODE xUnit tests failed" + dotnet xunit --fx-version 2.0.0 -configuration $Options.configuration -xml $TestResultsFile } - } finally { + } + finally { Pop-Location } } diff --git a/test/csharp/csharp.tests.csproj b/test/csharp/csharp.tests.csproj index 03eb9cf93af..6ecf16d2a44 100644 --- a/test/csharp/csharp.tests.csproj +++ b/test/csharp/csharp.tests.csproj @@ -1,21 +1,30 @@  - + - PowerShell On Linux xUnit Tests + PowerShell xUnit Tests powershell-tests win7-x86;win7-x64;osx.10.12-x64;linux-x64 + + true + ../../src/signing/visualstudiopublic.snk + true + + - + + + - - - + + + + diff --git a/test/csharp/fixture_AssemblyLoadContext.cs b/test/csharp/fixture_AssemblyLoadContext.cs deleted file mode 100644 index b24f41fc269..00000000000 --- a/test/csharp/fixture_AssemblyLoadContext.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Xunit; -using System; -using System.Management.Automation; - -// This collection fixture initializes Core PowerShell's AssemblyLoadContext once and only -// once. Attempting to initialize in a class level fixture will cause multiple -// initializations, resulting in test failure due to "Binding model is already locked for -// the AppDomain and cannot be reset". -namespace PSTests -{ - public class AssemblyLoadContextFixture - { - public AssemblyLoadContextFixture() - { - // Initialize the Core PowerShell AssemblyLoadContext - PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext(AppContext.BaseDirectory); - } - } - - [CollectionDefinition("AssemblyLoadContext")] - public class AssemblyLoadContextCollection : ICollectionFixture - { - // nothing to do but satisfy the interface - } -} diff --git a/test/csharp/test_Binders.cs b/test/csharp/test_Binders.cs index 91dc76d25b5..e73d6b44ca4 100644 --- a/test/csharp/test_Binders.cs +++ b/test/csharp/test_Binders.cs @@ -4,14 +4,13 @@ namespace PSTests { - [Collection("AssemblyLoadContext")] public static class PSEnumerableBinderTests { [Fact] - public static void TestIsComObject() + public static void TestIsStaticTypePossiblyEnumerable() { - // It just needs an arbitrary object - Assert.False(PSEnumerableBinder.IsComObject(42)); + // It just needs an arbitrary type + Assert.False(PSEnumerableBinder.IsStaticTypePossiblyEnumerable(42.GetType())); } } } diff --git a/test/csharp/test_CorePsPlatform.cs b/test/csharp/test_CorePsPlatform.cs index 33579d9ed41..11a744b4046 100644 --- a/test/csharp/test_CorePsPlatform.cs +++ b/test/csharp/test_CorePsPlatform.cs @@ -6,7 +6,6 @@ namespace PSTests { - [Collection("AssemblyLoadContext")] public static class PlatformTests { [Fact] @@ -15,6 +14,7 @@ public static void TestIsCoreCLR() Assert.True(Platform.IsCoreCLR); } +#if Unix [Fact] public static void TestGetUserName() { @@ -38,7 +38,7 @@ public static void TestGetUserName() } } - [Fact(Skip="Bad arguments for macOS")] + [Fact] public static void TestGetMachineName() { var startInfo = new ProcessStartInfo @@ -61,7 +61,7 @@ public static void TestGetMachineName() } } - [Fact(Skip="Bad arguments for macOS")] + [Fact] public static void TestGetFQDN() { var startInfo = new ProcessStartInfo @@ -84,7 +84,7 @@ public static void TestGetFQDN() } } - [Fact(Skip="Bad arguments for macOS")] + [Fact] public static void TestGetDomainName() { var startInfo = new ProcessStartInfo @@ -255,5 +255,6 @@ public static void TestFileIsSymLink() File.Delete(path); File.Delete(link); } +#endif } } diff --git a/test/csharp/test_ExtensionMethods.cs b/test/csharp/test_ExtensionMethods.cs index 134f94b2811..0b2273fb3d2 100644 --- a/test/csharp/test_ExtensionMethods.cs +++ b/test/csharp/test_ExtensionMethods.cs @@ -4,14 +4,12 @@ namespace PSTests { - [Collection("AssemblyLoadContext")] public static class PSTypeExtensionsTests { [Fact] - public static void TestIsComObject() + public static void TestIsNumeric() { - // It just needs an arbitrary type - Assert.False(PSTypeExtensions.IsComObject(42.GetType())); + Assert.True(PSTypeExtensions.IsNumeric(42.GetType())); } } } diff --git a/test/csharp/test_FileSystemProvider.cs b/test/csharp/test_FileSystemProvider.cs index 78631251692..76d52137478 100644 --- a/test/csharp/test_FileSystemProvider.cs +++ b/test/csharp/test_FileSystemProvider.cs @@ -13,10 +13,10 @@ using System.Management.Automation.Runspaces; using Microsoft.PowerShell; using Microsoft.PowerShell.Commands; +using System.Reflection; namespace PSTests { - [Collection("AssemblyLoadContext")] public class FileSystemProviderTests: IDisposable { private string testPath; @@ -57,7 +57,14 @@ private ProviderInfo GetProvider() [Fact] public void TestCreateJunctionFails() { - Assert.False(InternalSymbolicLinkLinkCodeMethods.CreateJunction("","")); + if(!Platform.IsWindows) + { + Assert.False(InternalSymbolicLinkLinkCodeMethods.CreateJunction("","")); + } + else + { + Assert.Throws(delegate { InternalSymbolicLinkLinkCodeMethods.CreateJunction("",""); }); + } } [Fact] @@ -73,12 +80,26 @@ public void TestGetHelpMaml() public void TestMode() { Assert.Equal(FileSystemProvider.Mode(null),String.Empty); - FileSystemInfo directoryObject = new DirectoryInfo(@"/"); - FileSystemInfo fileObject = new FileInfo(@"/etc/hosts"); - FileSystemInfo executableObject = new FileInfo(@"/bin/echo"); - Assert.Equal(FileSystemProvider.Mode(PSObject.AsPSObject(directoryObject)).Replace("r","-"),"d-----"); - Assert.Equal(FileSystemProvider.Mode(PSObject.AsPSObject(fileObject)).Replace("r","-"),"------"); - Assert.Equal(FileSystemProvider.Mode(PSObject.AsPSObject(executableObject)).Replace("r","-"),"------"); + FileSystemInfo directoryObject = null; + FileSystemInfo fileObject = null; + FileSystemInfo executableObject = null; + + if(!Platform.IsWindows) + { + directoryObject = new DirectoryInfo(@"/"); + fileObject = new FileInfo(@"/etc/hosts"); + executableObject = new FileInfo(@"/bin/echo"); + } + else + { + directoryObject = new DirectoryInfo(System.Environment.CurrentDirectory); + fileObject = new FileInfo(System.Reflection.Assembly.GetEntryAssembly().Location); + executableObject = new FileInfo(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); + } + + Assert.Equal("d-----", FileSystemProvider.Mode(PSObject.AsPSObject(directoryObject)).Replace("r","-")); + Assert.Equal("------", FileSystemProvider.Mode(PSObject.AsPSObject(fileObject)).Replace("r","-").Replace("a","-")); + Assert.Equal("------", FileSystemProvider.Mode(PSObject.AsPSObject(executableObject)).Replace("r","-").Replace("a","-")); } [Fact] @@ -98,7 +119,7 @@ public void TestGetProperty() { if(property.Name == "IsReadOnly") { - Assert.Equal(property.Value,false); + Assert.False((bool)property.Value); } } } @@ -117,7 +138,7 @@ public void TestSetProperty() { if(property.Name == "Name") { - Assert.Equal(property.Value,"test"); + Assert.Equal("test", property.Value); } } } diff --git a/test/csharp/test_MshSnapinInfo.cs b/test/csharp/test_MshSnapinInfo.cs index ac755ec5afa..454a4ec0a60 100644 --- a/test/csharp/test_MshSnapinInfo.cs +++ b/test/csharp/test_MshSnapinInfo.cs @@ -5,22 +5,23 @@ namespace PSTests { // Not static because a test requires non-const variables - [Collection("AssemblyLoadContext")] public class MshSnapinInfoTests { // Test that it does not throw an exception - [Fact] + [SkippableFact] public void TestReadRegistryInfo() { + Skip.IfNot(Platform.IsWindows); Version someVersion = null; string someString = null; PSSnapInReader.ReadRegistryInfo(out someVersion, out someString, out someString, out someString, out someString, out someVersion); } // PublicKeyToken is null on Linux - [Fact] + [SkippableFact] public void TestReadCoreEngineSnapIn() { + Skip.IfNot(Platform.IsWindows); PSSnapInInfo pSSnapInInfo = PSSnapInReader.ReadCoreEngineSnapIn(); Assert.Contains("PublicKeyToken=31bf3856ad364e35", pSSnapInInfo.AssemblyName); } diff --git a/test/csharp/test_PSVersionInfo.cs b/test/csharp/test_PSVersionInfo.cs index 5bd7acb82e8..ef980475ebf 100644 --- a/test/csharp/test_PSVersionInfo.cs +++ b/test/csharp/test_PSVersionInfo.cs @@ -4,7 +4,6 @@ namespace PSTests { - [Collection("AssemblyLoadContext")] public static class PSVersionInfoTests { [Fact] diff --git a/test/csharp/test_Runspace.cs b/test/csharp/test_Runspace.cs index 9b42341962a..ee7877523ac 100644 --- a/test/csharp/test_Runspace.cs +++ b/test/csharp/test_Runspace.cs @@ -8,11 +8,10 @@ namespace PSTests // NOTE: do not call AddCommand("out-host") after invoking or MergeMyResults, // otherwise Invoke will not return any objects - [Collection("AssemblyLoadContext")] public class RunspaceTests { - private static int count = 3; - private static string script = String.Format($"get-command | select-object -first {count}"); + private static int count = 1; + private static string script = String.Format($"get-command get-command"); [Fact] public void TestRunspaceWithPipeline() @@ -63,7 +62,7 @@ public void TestRunspaceWithPowerShell() } - [Fact(Skip="Fails in Travis CI, need investigation")] + [Fact] public void TestRunspaceWithPowerShellAndInitialSessionState() { InitialSessionState iss = InitialSessionState.CreateDefault2(); @@ -76,11 +75,14 @@ public void TestRunspaceWithPowerShellAndInitialSessionState() using (PowerShell powerShell = PowerShell.Create()) { powerShell.Runspace = runspace; - + powerShell.AddScript("Import-Module Microsoft.PowerShell.Utility -Force"); powerShell.AddScript(script); int objCount = 0; - foreach (var result in powerShell.Invoke()) + + var results = powerShell.Invoke(); + + foreach (var result in results) { // this is how an object would be captured here and looked at, // each result is a PSObject with the data from the pipeline diff --git a/test/csharp/test_SecuritySupport.cs b/test/csharp/test_SecuritySupport.cs index 33c336308cc..aef3ac5ee8a 100644 --- a/test/csharp/test_SecuritySupport.cs +++ b/test/csharp/test_SecuritySupport.cs @@ -4,21 +4,12 @@ namespace PSTests { - [Collection("AssemblyLoadContext")] public static class SecuritySupportTests { [Fact] public static void TestScanContent() { - Assert.Equal(AmsiUtils.ScanContent("", ""), AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED); - } - - [Fact] - public static void TestCurrentDomain_ProcessExit() - { - Assert.Throws(delegate { - AmsiUtils.CurrentDomain_ProcessExit(null, EventArgs.Empty); - }); + Assert.Equal(AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED, AmsiUtils.ScanContent("", "")); } [Fact] diff --git a/test/csharp/test_SessionState.cs b/test/csharp/test_SessionState.cs index eec20153772..990242f69f1 100644 --- a/test/csharp/test_SessionState.cs +++ b/test/csharp/test_SessionState.cs @@ -12,12 +12,12 @@ namespace PSTests { - [Collection("AssemblyLoadContext")] public class SessionStateTests { - [Fact] + [SkippableFact] public void TestDrives() { + Skip.IfNot(Platform.IsWindows); CultureInfo currentCulture = CultureInfo.CurrentCulture; PSHost hostInterface = new DefaultHost(currentCulture,currentCulture); InitialSessionState iss = InitialSessionState.CreateDefault2(); diff --git a/test/csharp/test_Utils.cs b/test/csharp/test_Utils.cs index 65ded34f637..be1c5cfa492 100644 --- a/test/csharp/test_Utils.cs +++ b/test/csharp/test_Utils.cs @@ -1,15 +1,16 @@ using Xunit; using System; using System.Management.Automation; +using System.Reflection; namespace PSTests { - [Collection("AssemblyLoadContext")] public static class UtilsTests { - [Fact] + [SkippableFact] public static void TestIsWinPEHost() { + Skip.IfNot(Platform.IsWindows); Assert.False(Utils.IsWinPEHost()); } } diff --git a/tools/appveyor.psm1 b/tools/appveyor.psm1 index 359f7c85079..6237ee61517 100644 --- a/tools/appveyor.psm1 +++ b/tools/appveyor.psm1 @@ -323,6 +323,7 @@ function Invoke-AppVeyorTest Write-Host -Foreground Green 'Run CoreCLR tests' $testResultsNonAdminFile = "$pwd\TestsResultsNonAdmin.xml" $testResultsAdminFile = "$pwd\TestsResultsAdmin.xml" + $testResultsXUnitFile = "$pwd\TestResultsXUnit.xml" if(!(Test-Path "$env:CoreOutput\pwsh.exe")) { throw "CoreCLR pwsh.exe was not built" @@ -356,6 +357,10 @@ function Invoke-AppVeyorTest Write-Host -Foreground Green 'Upload CoreCLR Admin test results' Update-AppVeyorTestResults -resultsFile $testResultsAdminFile + Start-PSxUnit -TestResultsFile $testResultsXUnitFile + Write-Host -ForegroundColor Green 'Uploading PSxUnit test results' + Update-AppVeyorTestResults -resultsFile $testResultsXUnitFile + # # Fail the build, if tests failed @( @@ -365,6 +370,8 @@ function Invoke-AppVeyorTest Test-PSPesterResults -TestResultsFile $_ } + $testPassResult = Test-XUnitTestResults -TestResultsFile $testResultsXUnitFile + Set-BuildVariable -Name TestPassed -Value True } diff --git a/tools/travis.ps1 b/tools/travis.ps1 index 79cdb304919..3cb81520a26 100644 --- a/tools/travis.ps1 +++ b/tools/travis.ps1 @@ -224,7 +224,10 @@ elseif($Stage -eq 'Build') } try { - Start-PSxUnit + $testResultsXUnitFile = "$pwd/TestResultsXUnit.xml" + Start-PSxUnit -TestResultsFile $testResultsXUnitFile + # If there are failures, Test-XUnitTestResults throws + $testPassResult = Test-XUnitTestResults -TestResultsFile $testResultsXUnitFile } catch { $result = "FAIL" From e3f0ffd6ada3e40427e75574741a3e2eaaa6dc4d Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 30 Nov 2017 14:46:09 -0800 Subject: [PATCH 3/6] Skip null-element check for collections with a value-type element type (#5432) * Fix NotNullOrEmpty check logic * Fix a test issue on Unix --- .../engine/Attributes.cs | 127 ++++++++++-------- .../engine/CompiledCommandParameter.cs | 2 +- .../engine/ParameterBinderBase.cs | 26 ++-- .../engine/runtime/Binding/Binders.cs | 1 - .../engine/Basic/ValidateAttributes.Tests.ps1 | 120 +++++++++++++++++ 5 files changed, 206 insertions(+), 70 deletions(-) diff --git a/src/System.Management.Automation/engine/Attributes.cs b/src/System.Management.Automation/engine/Attributes.cs index 876f428bde8..d96a4284510 100644 --- a/src/System.Management.Automation/engine/Attributes.cs +++ b/src/System.Management.Automation/engine/Attributes.cs @@ -1865,11 +1865,40 @@ public ValidateUserDriveAttribute() #endregion #region NULL validation attributes + + /// + /// Base type of Null Validation attributes. + /// + public abstract class NullValidationAttributeBase : ValidateArgumentsAttribute + { + /// + /// Check if the argument type is a collection. + /// + protected bool IsArgumentCollection(Type argumentType, out bool isElementValueType) + { + isElementValueType = false; + var information = new ParameterCollectionTypeInformation(argumentType); + switch (information.ParameterCollectionType) + { + // If 'arguments' is an array, or implement 'IList', or implement 'ICollection<>' + // then we continue to check each element of the collection. + case ParameterCollectionType.Array: + case ParameterCollectionType.IList: + case ParameterCollectionType.ICollectionGeneric: + Type elementType = information.ElementType; + isElementValueType = elementType != null && elementType.IsValueType; + return true; + default: + return false; + } + } + } + /// /// Validates that the parameters's argument is not null /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public sealed class ValidateNotNullAttribute : ValidateArgumentsAttribute + public sealed class ValidateNotNullAttribute : NullValidationAttributeBase { /// /// Verifies the argument is not null and if it is a collection, that each @@ -1891,9 +1920,6 @@ public sealed class ValidateNotNullAttribute : ValidateArgumentsAttribute /// protected override void Validate(object arguments, EngineIntrinsics engineIntrinsics) { - IEnumerable ienum = null; - IEnumerator itor = null; - if (arguments == null || arguments == AutomationNull.Value) { throw new ValidationMetadataException( @@ -1901,10 +1927,16 @@ protected override void Validate(object arguments, EngineIntrinsics engineIntrin null, Metadata.ValidateNotNullFailure); } - else if ((ienum = arguments as IEnumerable) != null) + else if (IsArgumentCollection(arguments.GetType(), out bool isElementValueType)) { - foreach (object element in ienum) + // If the element of the collection is of value type, then no need to check for null + // because a value-type value cannot be null. + if (isElementValueType) { return; } + + IEnumerator ienum = LanguagePrimitives.GetEnumerator(arguments); + while (ienum.MoveNext()) { + object element = ienum.Current; if (element == null || element == AutomationNull.Value) { throw new ValidationMetadataException( @@ -1914,19 +1946,6 @@ protected override void Validate(object arguments, EngineIntrinsics engineIntrin } } } - else if ((itor = arguments as IEnumerator) != null) - { - for (; itor.MoveNext() == true;) - { - if (itor.Current == null || itor.Current == AutomationNull.Value) - { - throw new ValidationMetadataException( - "ArgumentIsNull", - null, - Metadata.ValidateNotNullCollectionFailure); - } - } - } } } @@ -1935,7 +1954,7 @@ protected override void Validate(object arguments, EngineIntrinsics engineIntrin /// an empty string, and is not an empty collection. /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public sealed class ValidateNotNullOrEmptyAttribute : ValidateArgumentsAttribute + public sealed class ValidateNotNullOrEmptyAttribute : NullValidationAttributeBase { /// /// Validates that the parameters's argument is not null, is not @@ -1954,10 +1973,6 @@ public sealed class ValidateNotNullOrEmptyAttribute : ValidateArgumentsAttribute /// protected override void Validate(object arguments, EngineIntrinsics engineIntrinsics) { - IEnumerable ienum = null; - IEnumerator itor = null; - string str = null; - if (arguments == null || arguments == AutomationNull.Value) { throw new ValidationMetadataException( @@ -1965,7 +1980,7 @@ protected override void Validate(object arguments, EngineIntrinsics engineIntrin null, Metadata.ValidateNotNullOrEmptyFailure); } - else if ((str = arguments as String) != null) + else if (arguments is string str) { if (String.IsNullOrEmpty(str)) { @@ -1975,34 +1990,40 @@ protected override void Validate(object arguments, EngineIntrinsics engineIntrin Metadata.ValidateNotNullOrEmptyFailure); } } - else if ((ienum = arguments as IEnumerable) != null) + else if (IsArgumentCollection(arguments.GetType(), out bool isElementValueType)) { - int validElements = 0; - foreach (object element in ienum) - { - validElements++; - if (element == null || element == AutomationNull.Value) - { - throw new ValidationMetadataException( - "ArgumentIsNull", - null, - Metadata.ValidateNotNullOrEmptyCollectionFailure); - } + bool isEmpty = true; + IEnumerator ienum = LanguagePrimitives.GetEnumerator(arguments); + if (ienum.MoveNext()) { isEmpty = false; } - string elementAsString = element as String; - if (elementAsString != null) - { - if (String.IsNullOrEmpty(elementAsString)) + // If the element of the collection is of value type, then no need to check for null + // because a value-type value cannot be null. + if (!isEmpty && !isElementValueType) + { + do { + object element = ienum.Current; + if (element == null || element == AutomationNull.Value) { throw new ValidationMetadataException( - "ArgumentCollectionContainsEmpty", + "ArgumentIsNull", null, - Metadata.ValidateNotNullOrEmptyFailure); + Metadata.ValidateNotNullOrEmptyCollectionFailure); } - } + + if (element is string elementAsString) + { + if (String.IsNullOrEmpty(elementAsString)) + { + throw new ValidationMetadataException( + "ArgumentCollectionContainsEmpty", + null, + Metadata.ValidateNotNullOrEmptyCollectionFailure); + } + } + } while (ienum.MoveNext()); } - if (validElements == 0) + if (isEmpty) { throw new ValidationMetadataException( "ArgumentIsEmpty", @@ -2010,21 +2031,9 @@ protected override void Validate(object arguments, EngineIntrinsics engineIntrin Metadata.ValidateNotNullOrEmptyCollectionFailure); } } - else if ((itor = arguments as IEnumerator) != null) + else if (arguments is IDictionary dict) { - int validElements = 0; - for (; itor.MoveNext() == true;) - { - validElements++; - if (itor.Current == null || itor.Current == AutomationNull.Value) - { - throw new ValidationMetadataException( - "ArgumentIsNull", - null, - Metadata.ValidateNotNullOrEmptyCollectionFailure); - } - } - if (validElements == 0) + if (dict.Count == 0) { throw new ValidationMetadataException( "ArgumentIsEmpty", diff --git a/src/System.Management.Automation/engine/CompiledCommandParameter.cs b/src/System.Management.Automation/engine/CompiledCommandParameter.cs index a8a4eb097d1..4a90b0849cf 100644 --- a/src/System.Management.Automation/engine/CompiledCommandParameter.cs +++ b/src/System.Management.Automation/engine/CompiledCommandParameter.cs @@ -698,7 +698,7 @@ internal ParameterCollectionTypeInformation(Type type) /// /// The type of the elements in the collection /// - internal Type ElementType { get; set; } + internal Type ElementType { get; private set; } } } diff --git a/src/System.Management.Automation/engine/ParameterBinderBase.cs b/src/System.Management.Automation/engine/ParameterBinderBase.cs index 4f3dc90e81e..94b15552f6c 100644 --- a/src/System.Management.Automation/engine/ParameterBinderBase.cs +++ b/src/System.Management.Automation/engine/ParameterBinderBase.cs @@ -787,18 +787,26 @@ private void ValidateNullOrEmptyArgument( // Ensure that each element abides by the metadata bool isEmpty = true; + Type elementType = parameterMetadata.CollectionTypeInformation.ElementType; + bool isElementValueType = elementType != null && elementType.IsValueType; + // Note - we explicitly don't pass the context here because we don't want // the overhead of the calls that check for stopping. - while (ParserOps.MoveNext(null, null, ienum)) + if (ParserOps.MoveNext(null, null, ienum)) { isEmpty = false; } + + // If the element of the collection is of value type, then no need to check for null + // because a value-type value cannot be null. + if (!isEmpty && !isElementValueType) { - object element = ParserOps.Current(null, ienum); - isEmpty = false; - ValidateNullOrEmptyArgument( - parameter, - parameterMetadata, - parameterMetadata.CollectionTypeInformation.ElementType, - element, - false); + do { + object element = ParserOps.Current(null, ienum); + ValidateNullOrEmptyArgument( + parameter, + parameterMetadata, + parameterMetadata.CollectionTypeInformation.ElementType, + element, + false); + } while (ParserOps.MoveNext(null, null, ienum)); } if (isEmpty && !parameterMetadata.AllowsEmptyCollectionArgument) diff --git a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs index 72934c33485..4f3c5ab80f8 100644 --- a/src/System.Management.Automation/engine/runtime/Binding/Binders.cs +++ b/src/System.Management.Automation/engine/runtime/Binding/Binders.cs @@ -594,7 +594,6 @@ public override DynamicMetaObject FallbackConvert(DynamicMetaObject target, Dyna return (errorSuggestion ?? NullResult(target)).WriteToDebugLog(this); } - // In CORECLR System.Data.DataTable does not have the DataRowCollection IEnumerable, so disabling code. if (targetValue is DataTable) { // Generate: diff --git a/test/powershell/engine/Basic/ValidateAttributes.Tests.ps1 b/test/powershell/engine/Basic/ValidateAttributes.Tests.ps1 index 92a04c1497d..d95af1cd2b7 100644 --- a/test/powershell/engine/Basic/ValidateAttributes.Tests.ps1 +++ b/test/powershell/engine/Basic/ValidateAttributes.Tests.ps1 @@ -260,4 +260,124 @@ Describe 'Validate Attributes Tests' -Tags 'CI' { $ScriptBlock | Should Not Throw } } + + Context "ValidateNotNull, ValidateNotNullOrEmpty and Not-Null-Or-Empty check for Mandatory parameter" { + + BeforeAll { + function MandatoryFunc { + param( + [Parameter(Mandatory, ParameterSetName = "ByteArray")] + [byte[]] $ByteArray, + + [Parameter(Mandatory, ParameterSetName = "ByteList")] + [System.Collections.Generic.List[byte]] $ByteList, + + [Parameter(Mandatory, ParameterSetName = "ByteCollection")] + [System.Collections.ObjectModel.Collection[byte]] $ByteCollection, + + [Parameter(ParameterSetName = "Default")] + $Value + ) + } + + function NotNullFunc { + param( + [ValidateNotNull()] + $Value, + [string] $TestType + ) + + switch ($TestType) { + "COM-Enumerable" { $Value | ForEach-Object Name } + "Enumerator" { + $items = foreach ($i in $Value) { $i } + $items -join "," + } + } + } + + function NotNullOrEmptyFunc { + param( + [ValidateNotNullOrEmpty()] + $Value, + [string] $TestType + ) + + switch ($TestType) { + "COM-Enumerable" { $Value | ForEach-Object Name } + "Enumerator" { + $items = foreach ($i in $Value) { $i } + $items -join "," + } + } + } + + $filePath = Join-Path -Path $PSHOME -ChildPath System.Management.Automation.dll + $byteArray = [System.IO.File]::ReadAllBytes($filePath) + $byteList = [System.Collections.Generic.List[byte]] $byteArray + $byteCollection = [System.Collections.ObjectModel.Collection[byte]] $byteArray + ## Use the running time of 'MandatoryFunc -Value $byteArray' as the baseline time + $baseline = (Measure-Command { MandatoryFunc -Value $byteArray }).Milliseconds + ## Running time should be less than 'expected' + $expected = $baseline + 20 + + if ($IsWindows) { + $null = New-Item -Path $TESTDRIVE/file1 + } + + $testCases = @( + @{ ScriptBlock = { MandatoryFunc -ByteArray $byteArray } } + @{ ScriptBlock = { MandatoryFunc -ByteList $byteList } } + @{ ScriptBlock = { MandatoryFunc -ByteCollection $byteCollection } } + @{ ScriptBlock = { NotNullFunc -Value $byteArray } } + @{ ScriptBlock = { NotNullFunc -Value $byteList } } + @{ ScriptBlock = { NotNullFunc -Value $byteCollection } } + @{ ScriptBlock = { NotNullOrEmptyFunc -Value $byteArray } } + @{ ScriptBlock = { NotNullOrEmptyFunc -Value $byteList } } + @{ ScriptBlock = { NotNullOrEmptyFunc -Value $byteCollection } } + ) + } + + It "Validate running time ''" -TestCases $testCases { + param ($ScriptBlock) + (Measure-Command $ScriptBlock).Milliseconds | Should BeLessThan $expected + } + + It "COM enumerable argument should work with 'ValidateNotNull' and 'ValidateNotNullOrEmpty'" -Skip:(!$IsWindows) { + $shell = New-Object -ComObject "Shell.Application" + $folder = $shell.Namespace("$TESTDRIVE") + $items = $folder.Items() + + NotNullFunc -Value $items -TestType "COM-Enumerable" | Should Be "file1" + NotNullOrEmptyFunc -Value $items -TestType "COM-Enumerable" | Should Be "file1" + } + + It "Enumerator argument should work with 'ValidateNotNull' and 'ValidateNotNullOrEmpty'" { + $data = @(1,2,3) + NotNullFunc -Value $data.GetEnumerator() -TestType "Enumerator" | Should Be "1,2,3" + NotNullOrEmptyFunc -Value $data.GetEnumerator() -TestType "Enumerator" | Should Be "1,2,3" + } + + It "'ValidateNotNull' should throw on null element of a collection argument" { + ## Should throw on null element + { NotNullFunc -Value @("string", $null, 2) } | Should Throw + ## Should not throw on empty string element + { NotNullFunc -Value @("string", "", 2) } | Should Not Throw + ## Should not throw on an empty collection + { NotNullFunc -Value @() } | Should Not Throw + } + + It "'ValidateNotNullOrEmpty' should throw on null element of a collection argument or empty collection/dictionary" { + { NotNullOrEmptyFunc -Value @("string", $null, 2) } | Should Throw + { NotNullOrEmptyFunc -Value @("string", "", 2) } | Should Throw + { NotNullOrEmptyFunc -Value @() } | Should Throw + { NotNullOrEmptyFunc -Value @{} } | Should Throw + } + + It "Mandatory parameter should throw on empty collection" { + { MandatoryFunc -ByteArray ([byte[]]@()) } | Should Throw + { MandatoryFunc -ByteList ([System.Collections.Generic.List[byte]]@()) } | Should Throw + { MandatoryFunc -ByteList ([System.Collections.ObjectModel.Collection[byte]]@()) } | Should Throw + } + } } From bafca58d3b487955df45ebd5a44066692f4b6633 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 30 Nov 2017 20:34:00 -0800 Subject: [PATCH 4/6] Update PowerShell executable name in using-vscode.md (#5593) --- docs/learning-powershell/using-vscode.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/learning-powershell/using-vscode.md b/docs/learning-powershell/using-vscode.md index 0441a53fbab..3623039153d 100644 --- a/docs/learning-powershell/using-vscode.md +++ b/docs/learning-powershell/using-vscode.md @@ -59,13 +59,13 @@ If you wish to use a specific installation of PowerShell with Visual Studio Code ```json // On Windows: - "powershell.powerShellExePath": "c:/Program Files/PowerShell//powershell.exe" + "powershell.powerShellExePath": "c:/Program Files/PowerShell//pwsh.exe" // On Linux: - "powershell.powerShellExePath": "/opt/microsoft/powershell//powershell" + "powershell.powerShellExePath": "/opt/microsoft/powershell//pwsh" // On macOS: - "powershell.powerShellExePath": "/usr/local/microsoft/powershell//powershell" + "powershell.powerShellExePath": "/usr/local/microsoft/powershell//pwsh" ``` 3. Replace the setting with the path to the desired PowerShell executable From f58fdeaedaeb4841ec33c6b1a37cf32b00059eee Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 1 Dec 2017 09:47:18 -0800 Subject: [PATCH 5/6] Remove exclusion for hang and add context exception for remaining instances (#5595) --- tools/terms/PowerShell-Terms-Rules.mdb | Bin 393216 -> 425984 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/terms/PowerShell-Terms-Rules.mdb b/tools/terms/PowerShell-Terms-Rules.mdb index 91251e061a9631228c0ea45eeab417a2a3ed398c..2a6abb2457aee90cd004ad0fde9870c669143ce0 100644 GIT binary patch delta 14879 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 WhqYY?{|SO8iX~zU?y~VY(tiVxs@qWj delta 4512 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 From 72bc90f4122e3c22567e3edc29b913a650221550 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Fri, 1 Dec 2017 10:57:00 -0800 Subject: [PATCH 6/6] Remove unncessary check for Paths.count > 0 as there is code later to use the current (#5596) Remove unnecessary check for Paths.count > 0 as there is code later to use the current working directory since -Path is not a mandatory parameter. Updated ShouldProcess to output the internal action on adding paths rather than the user action (which is the cmdlet name). Updated tests to not specify -Path Fix #5594 --- .../security/CatalogCommands.cs | 19 +++++++++---------- .../FileCatalog.Tests.ps1 | 7 +++++-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.PowerShell.Security/security/CatalogCommands.cs b/src/Microsoft.PowerShell.Security/security/CatalogCommands.cs index 07f2dc9015c..722a8b07072 100644 --- a/src/Microsoft.PowerShell.Security/security/CatalogCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/CatalogCommands.cs @@ -95,7 +95,7 @@ protected override void ProcessRecord() { foreach (PathInfo tempPath in SessionState.Path.GetResolvedPSPathFromPSPath(p)) { - if (ShouldProcess(tempPath.ProviderPath)) + if (ShouldProcess("Including path " + tempPath.ProviderPath, "", "")) { paths.Add(tempPath.ProviderPath); } @@ -103,17 +103,16 @@ protected override void ProcessRecord() } } - // We add 'paths.Count > 0' to support 'ShouldProcess()' - if (paths.Count > 0 ) - { - string drive = null; + string drive = null; - // resolve catalog destination Path - if (!SessionState.Path.IsPSAbsolute(catalogFilePath, out drive) && !System.IO.Path.IsPathRooted(catalogFilePath)) - { - catalogFilePath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(catalogFilePath); - } + // resolve catalog destination Path + if (!SessionState.Path.IsPSAbsolute(catalogFilePath, out drive) && !System.IO.Path.IsPathRooted(catalogFilePath)) + { + catalogFilePath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(catalogFilePath); + } + if (ShouldProcess(catalogFilePath)) + { PerformAction(paths, catalogFilePath); } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/FileCatalog.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/FileCatalog.Tests.ps1 index 85e4c9c8710..712310c8e52 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/FileCatalog.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/FileCatalog.Tests.ps1 @@ -233,11 +233,14 @@ Describe "Test suite for NewFileCatalogAndTestFileCatalogCmdlets" -Tags "CI" { try { copy-item "$testDataPath\UserConfigProv" $env:temp -Recurse -ErrorAction SilentlyContinue - $null = New-FileCatalog -Path $env:temp\UserConfigProv\ -CatalogFilePath $catalogPath -CatalogVersion 1.0 - $result = Test-FileCatalog -Path $env:temp\UserConfigProv\ -CatalogFilePath $catalogPath + Push-Location "$env:TEMP\UserConfigProv" + # When -Path is not specified, it should use current directory + $null = New-FileCatalog -CatalogFilePath $catalogPath -CatalogVersion 1.0 + $result = Test-FileCatalog -CatalogFilePath $catalogPath } finally { + Pop-Location Remove-Item "$catalogPath" -Force -ErrorAction SilentlyContinue Remove-Item "$env:temp\UserConfigProv\" -Force -ErrorAction SilentlyContinue -Recurse }