Fix -NoEnumerate behaviour in Write-Output (#9069)

Fix is to preserve input collection type in output.
The regression was caused by #2038
This commit is contained in:
Joel Sallow (/u/ta11ow) 2019-03-13 04:54:12 -04:00 committed by Ilya
parent e75bd1482f
commit 18d5037ad2
2 changed files with 49 additions and 56 deletions

View file

@ -12,49 +12,32 @@ namespace Microsoft.PowerShell.Commands
[Cmdlet(VerbsCommunications.Write, "Output", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113427", RemotingCapability = RemotingCapability.None)] [Cmdlet(VerbsCommunications.Write, "Output", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113427", RemotingCapability = RemotingCapability.None)]
public sealed class WriteOutputCommand : PSCmdlet public sealed class WriteOutputCommand : PSCmdlet
{ {
private PSObject[] _inputObjects = null;
/// <summary> /// <summary>
/// Holds the list of objects to be written. /// Holds the list of objects to be written.
/// </summary> /// </summary>
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromRemainingArguments = true)] [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromRemainingArguments = true)]
[AllowNull] [AllowNull]
[AllowEmptyCollection] [AllowEmptyCollection]
public PSObject[] InputObject public PSObject InputObject { get; set; }
{
get { return _inputObjects; }
set { _inputObjects = value; }
}
/// <summary> /// <summary>
/// Prevents Write-Output from unravelling collections passed to the InputObject parameter. /// Prevents Write-Output from unravelling collections passed to the InputObject parameter.
/// </summary> /// </summary>
[Parameter()] [Parameter]
public SwitchParameter NoEnumerate public SwitchParameter NoEnumerate { get; set; }
{
get;
set;
}
/// <summary> /// <summary>
/// This method implements the ProcessRecord method for Write-output command. /// This method implements the ProcessRecord method for Write-output command.
/// </summary> /// </summary>
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
if (_inputObjects == null) if (InputObject == null)
{ {
WriteObject(_inputObjects); WriteObject(InputObject);
return; return;
} }
bool enumerate = true; WriteObject(InputObject, !NoEnumerate.IsPresent);
if (NoEnumerate.IsPresent)
{
enumerate = false;
}
WriteObject(_inputObjects, enumerate);
} }
} }
#endregion #endregion

View file

@ -18,60 +18,70 @@ Describe "Write-Output DRT Unit Tests" -Tags "CI" {
It "Works with NoEnumerate switch" { It "Works with NoEnumerate switch" {
$objectWritten = 1, 2.2, @("John", "Smith", 10), "abc" $objectWritten = 1, 2.2, @("John", "Smith", 10), "abc"
[string]$s = Write-Output $objectWritten -NoEnumerate 6>&1 [string]$s = Write-Output $objectWritten -NoEnumerate 6>&1
$s | Should -Be '1 2.2 System.Object[] abc' $s | Should -Be '1 2.2 System.Object[] abc'
} }
It "Preserves the input collection type and contents with -NoEnumerate" {
$List = [System.Collections.Generic.List[string]]::new( [string[]]@("test", "one", "two") )
$ObjectWritten = Write-Output $List -NoEnumerate
$ObjectWritten.GetType() | Should -Be ([System.Collections.Generic.List[string]])
$ObjectWritten[0] | Should -BeExactly "test"
$ObjectWritten[1] | Should -BeExactly "one"
$ObjectWritten[2] | Should -BeExactly "two"
}
} }
Describe "Write-Output" -Tags "CI" { Describe "Write-Output" -Tags "CI" {
$testString = $testString $testString = $testString
Context "Input Tests" { Context "Input Tests" {
It "Should allow piped input" { It "Should allow piped input" {
{ $testString | Write-Output } | Should -Not -Throw { $testString | Write-Output } | Should -Not -Throw
} }
It "Should write output to the output stream when using piped input" { It "Should write output to the output stream when using piped input" {
$testString | Write-Output | Should -Be $testString $testString | Write-Output | Should -Be $testString
} }
It "Should use inputobject switch" { It "Should use inputobject switch" {
{ Write-Output -InputObject $testString } | Should -Not -Throw { Write-Output -InputObject $testString } | Should -Not -Throw
} }
It "Should write output to the output stream when using inputobject switch" { It "Should write output to the output stream when using inputobject switch" {
Write-Output -InputObject $testString | Should -Be $testString Write-Output -InputObject $testString | Should -Be $testString
} }
It "Should be able to write to a variable" { It "Should be able to write to a variable" {
Write-Output -InputObject $testString -OutVariable var Write-Output -InputObject $testString -OutVariable var
$var | Should -Be $testString $var | Should -Be $testString
} }
} }
Context "Pipeline Command Tests" { Context "Pipeline Command Tests" {
It "Should send object to the next command in the pipeline" { It "Should send object to the next command in the pipeline" {
Write-Output -InputObject (1+1) | Should -Be 2 Write-Output -InputObject (1 + 1) | Should -Be 2
} }
It "Should have the same result between inputobject switch and piped input" { It "Should have the same result between inputobject switch and piped input" {
Write-Output -InputObject (1+1) | Should -Be 2 Write-Output -InputObject (1 + 1) | Should -Be 2
1+1 | Write-Output | Should -Be 2 1 + 1 | Write-Output | Should -Be 2
} }
} }
Context "Enumerate Objects" { Context "Enumerate Objects" {
$enumerationObject = @(1,2,3) $enumerationObject = @(1, 2, 3)
It "Should see individual objects when not using the NoEnumerate switch" { It "Should see individual objects when not using the NoEnumerate switch" {
$singleCollection = $(Write-Output $enumerationObject| Measure-Object).Count $singleCollection = $(Write-Output $enumerationObject| Measure-Object).Count
$singleCollection | Should -Be $enumerationObject.length $singleCollection | Should -Be $enumerationObject.length
} }
It "Should be able to treat a collection as a single object using the NoEnumerate switch" { It "Should be able to treat a collection as a single object using the NoEnumerate switch" {
$singleCollection = $(Write-Output $enumerationObject -NoEnumerate | Measure-Object).Count $singleCollection = $(Write-Output $enumerationObject -NoEnumerate | Measure-Object).Count
$singleCollection | Should -Be 1 $singleCollection | Should -Be 1
} }
} }
} }