Make Out-String and Out-File keep string input unchanged (#17455)

This commit is contained in:
Dongbo Wang
2022-06-08 18:13:40 -07:00
committed by GitHub
parent 57dbecb612
commit 17e4db9b1b
5 changed files with 95 additions and 6 deletions
@@ -552,7 +552,8 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
}
else
{
_lo.WriteLine(rte.text);
// Write out raw text without any changes to it.
_lo.WriteRawText(rte.text);
}
return;
@@ -250,6 +250,13 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
/// </param>
internal abstract void WriteLine(string s);
/// <summary>
/// Write a line of string as raw text to the output device, with no change to the string.
/// For example, keeping VT escape sequences intact in it.
/// </summary>
/// <param name="s">The raw text to be written to the device.</param>
internal virtual void WriteRawText(string s) => WriteLine(s);
internal WriteStreamType WriteStream
{
get;
@@ -431,7 +438,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
/// Implementation of the ILineOutput interface accepting an instance of a
/// TextWriter abstract class.
/// </summary>
internal class TextWriterLineOutput : LineOutput
internal sealed class TextWriterLineOutput : LineOutput
{
#region ILineOutput methods
@@ -467,9 +474,17 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
/// <param name="s"></param>
internal override void WriteLine(string s)
{
CheckStopProcessing();
WriteRawText(PSHostUserInterface.GetOutputString(s, isHost: false));
}
s = PSHostUserInterface.GetOutputString(s, isHost: false);
/// <summary>
/// Write a raw text by delegating to the writer underneath, with no change to the text.
/// For example, keeping VT escape sequences intact in it.
/// </summary>
/// <param name="s">The raw text to be written to the device.</param>
internal override void WriteRawText(string s)
{
CheckStopProcessing();
if (_suppressNewline)
{
@@ -480,6 +495,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
_writer.WriteLine(s);
}
}
#endregion
/// <summary>
@@ -115,7 +115,8 @@ Describe 'Tests for $ErrorView' -Tag CI {
It "Error shows for advanced function" {
# need to have it virtually interactive so that InvocationInfo.MyCommand is empty
$e = '[cmdletbinding()]param()$pscmdlet.writeerror([System.Management.Automation.ErrorRecord]::new(([System.NotImplementedException]::new("myTest")),"stub","notimplemented","command"))' | pwsh -noprofile -file - 2>&1 | Out-String
$e = '[cmdletbinding()]param()$pscmdlet.writeerror([System.Management.Automation.ErrorRecord]::new(([System.NotImplementedException]::new("myTest")),"stub","notimplemented","command"))' | pwsh -noprofile -file - 2>&1
$e = $e | Where-Object { $_ -is [System.Management.Automation.ErrorRecord] } | Out-String
$e | Should -Not -BeNullOrEmpty
# need to see if ANSI escape sequences are in the output as ANSI is disabled for CI
@@ -39,7 +39,7 @@ Describe 'OutputRendering tests' {
param($outputRendering, $ansi)
$PSStyle.OutputRendering = $outputRendering
$out = "$($PSStyle.Foreground.Green)hello" | Out-String
$out = [pscustomobject] @{ key = "$($PSStyle.Foreground.Green)hello" } | Out-String
if ($ansi) {
$out | Should -BeLike "*`e*" -Because ($out | Format-Hex | Out-String)
@@ -286,6 +286,77 @@ Describe 'Tests for $PSStyle automatic variable' {
$strDec.ContentLength | Should -Be $word.Length
$strDec.ToString("PlainText") | Should -Be $word
}
It "String intput to Out-String should be intact with OutputRendering='<OutputRendering>'" -TestCases @(
@{ OutputRendering = 'Ansi'; ContainsAnsi = $true }
@{ OutputRendering = 'Host'; ContainsAnsi = $false }
@{ OutputRendering = 'PlainText'; ContainsAnsi = $false }
) {
param($OutputRendering, $ContainsAnsi)
$oldRender = $PSStyle.OutputRendering
$testStr = "`e[31mABC`e[0m"
try {
$PSStyle.OutputRendering = $OutputRendering
## For input that actually goes through formatting, Out-String should remove VT sequences
## from the formatting output based on the output rendering option that is in effect.
(Get-Verb -Verb Get | Out-String).Contains("`e[") | Should -Be $ContainsAnsi
## For string input, since no formatting is applied, Out-String should keep the string intact.
($testStr | Out-String).Trim() | Should -BeExactly $testStr
}
finally {
$PSStyle.OutputRendering = $oldRender
}
}
It "String input to Out-File should be intact with OutputRendering='<OutputRendering>'" -TestCases @(
@{ OutputRendering = 'Ansi'; }
@{ OutputRendering = 'Host'; }
@{ OutputRendering = 'PlainText'; }
) {
param($OutputRendering)
$oldRender = $PSStyle.OutputRendering
$content = "Read-Host -Prompt '`e[33mEnter your device code`e[0m'"
Set-Content -Path $TestDrive\test.ps1 -Value $content -Encoding utf8NoBOM
try {
$PSStyle.OutputRendering = $OutputRendering
Get-Content $TestDrive\test.ps1 > $TestDrive\copy.ps1
(Get-Content $TestDrive\copy.ps1 -Raw).Trim() | Should -BeExactly $content
}
finally {
$PSStyle.OutputRendering = $oldRender
Remove-Item $TestDrive\test.ps1 -Force
Remove-Item $TestDrive\copy.ps1 -Force
}
}
It "Comment based help works with `$PSStyle when OutputRendering='<OutputRendering>'" -TestCases @(
@{ OutputRendering = 'Ansi'; ContainsAnsi = $true }
@{ OutputRendering = 'Host'; ContainsAnsi = $false }
@{ OutputRendering = 'PlainText'; ContainsAnsi = $false }
) {
param($OutputRendering, $ContainsAnsi)
$oldRender = $PSStyle.OutputRendering
function Test-PSStyle {
<#
.Description
Get-Function displays the name and syntax of all functions in the session.
#>
}
try {
$PSStyle.OutputRendering = $OutputRendering
(Get-Help Test-PSStyle | Out-String).Contains("`e[31mdisplays`e[0m") | Should -Be $ContainsAnsi
}
finally {
$PSStyle.OutputRendering = $oldRender
}
}
}
Describe 'Handle strings with escape sequences in formatting' {