Make approved features non-experimental (#11303)

# Conflicts:
#	src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs
This commit is contained in:
Steve Lee
2019-12-10 16:05:15 -08:00
committed by Travis Plunk
parent 2dd264af03
commit fee57e1cdc
21 changed files with 107 additions and 457 deletions
@@ -11,7 +11,6 @@ namespace Microsoft.PowerShell.Commands
/// <summary>
/// Class for Get-Error implementation.
/// </summary>
[Experimental("Microsoft.PowerShell.Utility.PSGetError", ExperimentAction.Show)]
[Cmdlet(VerbsCommon.Get, "Error",
HelpUri = "https://docs.microsoft.com/powershell/module/microsoft.powershell.utility/get-error?view=powershell-7&WT.mc_id=ps-gethelp",
DefaultParameterSetName = NewestParameterSetName)]
@@ -57,7 +57,7 @@ namespace Microsoft.PowerShell
static UpdatesNotification()
{
s_notificationType = GetNotificationType();
CanNotifyUpdates = s_notificationType != NotificationType.Off && ExperimentalFeature.IsEnabled("PSUpdatesNotification");
CanNotifyUpdates = s_notificationType != NotificationType.Off;
if (CanNotifyUpdates)
{
@@ -109,24 +109,6 @@ namespace System.Management.Automation
new ExperimentalFeature(
name: "PSCommandNotFoundSuggestion",
description: "Recommend potential commands based on fuzzy search on a CommandNotFoundException"),
new ExperimentalFeature(
name: "PSForEachObjectParallel",
description: "New parameter set for ForEach-Object to run script blocks in parallel"),
new ExperimentalFeature(
name: "PSTernaryOperator",
description: "Support the ternary operator in PowerShell language"),
new ExperimentalFeature(
name: "PSErrorView",
description: "New formatting for ErrorRecord"),
new ExperimentalFeature(
name: "PSUpdatesNotification",
description: "Print notification message when new releases are available"),
new ExperimentalFeature(
name: "PSCoalescingOperators",
description: "Support the null coalescing operator and null coalescing assignment operator in PowerShell language"),
new ExperimentalFeature(
name: "PSPipelineChainOperators",
description: "Allow use of && and || as operators between pipeline invocations"),
#if UNIX
new ExperimentalFeature(
name: "PSUnixFileStat",
@@ -135,11 +117,6 @@ namespace System.Management.Automation
new ExperimentalFeature(
name: "PSNullConditionalOperators",
description: "Support the null conditional member access operators in PowerShell language"),
#if !UNIX
new ExperimentalFeature(
name: "PSWindowsPowerShellCompatibility",
description: "Load non-PSCore-compartible modules into Windows PowerShell over PS Remoting")
#endif
};
EngineExperimentalFeatures = new ReadOnlyCollection<ExperimentalFeature>(engineFeatures);
@@ -4426,7 +4426,7 @@ end {
internal const ActionPreference DefaultWarningPreference = ActionPreference.Continue;
internal const ActionPreference DefaultInformationPreference = ActionPreference.SilentlyContinue;
internal const ErrorView DefaultErrorView = ErrorView.NormalView;
internal const ErrorView DefaultErrorView = ErrorView.ConciseView;
internal const bool DefaultWhatIfPreference = false;
internal const ConfirmImpact DefaultConfirmPreference = ConfirmImpact.High;
@@ -4501,7 +4501,7 @@ end {
new ArgumentTypeConverterAttribute(typeof(ActionPreference))),
new SessionStateVariableEntry(
SpecialVariables.ErrorView,
ExperimentalFeature.IsEnabled("PSErrorView") ? ErrorView.ConciseView : DefaultErrorView,
DefaultErrorView,
RunspaceInit.ErrorViewDescription,
ScopedItemOptions.None,
new ArgumentTypeConverterAttribute(typeof(ErrorView))),
@@ -234,7 +234,6 @@ namespace Microsoft.PowerShell.Commands
/// <summary>
/// Gets or sets a script block to run in parallel for each pipeline object.
/// </summary>
[Experimental("PSForEachObjectParallel", ExperimentAction.Show)]
[Parameter(Mandatory = true, ParameterSetName = ForEachObjectCommand.ParallelParameterSet)]
public ScriptBlock Parallel { get; set; }
@@ -242,7 +241,6 @@ namespace Microsoft.PowerShell.Commands
/// Gets or sets the maximum number of concurrently running scriptblocks on separate threads.
/// The default number is 5.
/// </summary>
[Experimental("PSForEachObjectParallel", ExperimentAction.Show)]
[Parameter(ParameterSetName = ForEachObjectCommand.ParallelParameterSet)]
[ValidateRange(1, Int32.MaxValue)]
public int ThrottleLimit { get; set; } = 5;
@@ -251,7 +249,6 @@ namespace Microsoft.PowerShell.Commands
/// Gets or sets a timeout time in seconds, after which the parallel running scripts will be stopped
/// The default value is 0, indicating no timeout.
/// </summary>
[Experimental("PSForEachObjectParallel", ExperimentAction.Show)]
[Parameter(ParameterSetName = ForEachObjectCommand.ParallelParameterSet)]
[ValidateRange(0, (Int32.MaxValue / 1000))]
public int TimeoutSeconds { get; set; }
@@ -260,7 +257,6 @@ namespace Microsoft.PowerShell.Commands
/// Gets or sets a flag that returns a job object immediately for the parallel operation, instead of returning after
/// all foreach processing is completed.
/// </summary>
[Experimental("PSForEachObjectParallel", ExperimentAction.Show)]
[Parameter(ParameterSetName = ForEachObjectCommand.ParallelParameterSet)]
public SwitchParameter AsJob { get; set; }
@@ -103,12 +103,6 @@ namespace System.Management.Automation
var moduleManifestProperties = PsUtils.GetModuleManifestProperties(modulePath, PsUtils.FastModuleManifestAnalysisPropertyNames);
if (moduleManifestProperties != null)
{
if (!ExperimentalFeature.IsEnabled("PSWindowsPowerShellCompatibility") && ModuleIsEditionIncompatible(modulePath, moduleManifestProperties))
{
ModuleIntrinsics.Tracer.WriteLine($"Module lies on the Windows System32 legacy module path and is incompatible with current PowerShell edition, skipping module: {modulePath}");
return null;
}
Version version;
if (ModuleUtils.IsModuleInVersionSubdirectory(modulePath, out version))
{
@@ -491,14 +485,6 @@ namespace System.Management.Automation
{
ModuleIntrinsics.Tracer.WriteLine("Requested caching for {0}", module.Name);
// Don't cache incompatible modules on the system32 module path even if loaded with
// -SkipEditionCheck, since it will break subsequent sessions.
if (!ExperimentalFeature.IsEnabled("PSWindowsPowerShellCompatibility") && !module.IsConsideredEditionCompatible)
{
ModuleIntrinsics.Tracer.WriteLine($"Module '{module.Name}' not edition compatible and not cached.");
return;
}
DateTime lastWriteTime;
ModuleCacheEntry moduleCacheEntry;
GetModuleEntryFromCache(module.Path, out lastWriteTime, out moduleCacheEntry);
@@ -53,7 +53,6 @@ namespace Microsoft.PowerShell.Commands
private const string ParameterSet_FQName_ViaPsrpSession = "FullyQualifiedNameAndPSSession";
private const string ParameterSet_ViaWinCompat = "WinCompat";
private const string ParameterSet_FQName_ViaWinCompat = "FullyQualifiedNameAndWinCompat";
/// <summary>
/// This parameter specifies whether to import to the current session state
@@ -85,7 +84,7 @@ namespace Microsoft.PowerShell.Commands
[Parameter(ParameterSetName = ParameterSet_Name, Mandatory = true, ValueFromPipeline = true, Position = 0)]
[Parameter(ParameterSetName = ParameterSet_ViaPsrpSession, Mandatory = true, ValueFromPipeline = true, Position = 0)]
[Parameter(ParameterSetName = ParameterSet_ViaCimSession, Mandatory = true, ValueFromPipeline = true, Position = 0)]
[Parameter("PSWindowsPowerShellCompatibility", ExperimentAction.Show, ParameterSetName = ParameterSet_ViaWinCompat, Mandatory = true, ValueFromPipeline = true, Position = 0)]
[Parameter(ParameterSetName = ParameterSet_ViaWinCompat, Mandatory = true, ValueFromPipeline = true, Position = 0)]
[ValidateTrustedData]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Cmdlets use arrays for parameters.")]
public string[] Name { set; get; } = Array.Empty<string>();
@@ -95,7 +94,7 @@ namespace Microsoft.PowerShell.Commands
/// </summary>
[Parameter(ParameterSetName = ParameterSet_FQName, Mandatory = true, ValueFromPipeline = true, Position = 0)]
[Parameter(ParameterSetName = ParameterSet_FQName_ViaPsrpSession, Mandatory = true, ValueFromPipeline = true, Position = 0)]
[Parameter("PSWindowsPowerShellCompatibility", ExperimentAction.Show, ParameterSetName = ParameterSet_FQName_ViaWinCompat, Mandatory = true, ValueFromPipeline = true, Position = 0)]
[Parameter(ParameterSetName = ParameterSet_FQName_ViaWinCompat, Mandatory = true, ValueFromPipeline = true, Position = 0)]
[ValidateTrustedData]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Cmdlets use arrays for parameters.")]
public ModuleSpecification[] FullyQualifiedName { get; set; }
@@ -275,7 +274,7 @@ namespace Microsoft.PowerShell.Commands
[Parameter(ParameterSetName = ParameterSet_Name)]
[Parameter(ParameterSetName = ParameterSet_ViaPsrpSession)]
[Parameter(ParameterSetName = ParameterSet_ViaCimSession)]
[Parameter("PSWindowsPowerShellCompatibility", ExperimentAction.Show, ParameterSetName = ParameterSet_ViaWinCompat)]
[Parameter(ParameterSetName = ParameterSet_ViaWinCompat)]
[Alias("Version")]
public Version MinimumVersion
{
@@ -290,7 +289,7 @@ namespace Microsoft.PowerShell.Commands
[Parameter(ParameterSetName = ParameterSet_Name)]
[Parameter(ParameterSetName = ParameterSet_ViaPsrpSession)]
[Parameter(ParameterSetName = ParameterSet_ViaCimSession)]
[Parameter("PSWindowsPowerShellCompatibility", ExperimentAction.Show, ParameterSetName = ParameterSet_ViaWinCompat)]
[Parameter(ParameterSetName = ParameterSet_ViaWinCompat)]
public string MaximumVersion
{
get
@@ -320,7 +319,7 @@ namespace Microsoft.PowerShell.Commands
[Parameter(ParameterSetName = ParameterSet_Name)]
[Parameter(ParameterSetName = ParameterSet_ViaPsrpSession)]
[Parameter(ParameterSetName = ParameterSet_ViaCimSession)]
[Parameter("PSWindowsPowerShellCompatibility", ExperimentAction.Show, ParameterSetName = ParameterSet_ViaWinCompat)]
[Parameter(ParameterSetName = ParameterSet_ViaWinCompat)]
public Version RequiredVersion
{
get { return BaseRequiredVersion; }
@@ -425,8 +424,8 @@ namespace Microsoft.PowerShell.Commands
/// This parameter causes a module to be loaded into Windows PowerShell.
/// This is mutually exclusive with SkipEditionCheck parameter.
/// </summary>
[Parameter("PSWindowsPowerShellCompatibility", ExperimentAction.Show, ParameterSetName = ParameterSet_ViaWinCompat, Mandatory = true)]
[Parameter("PSWindowsPowerShellCompatibility", ExperimentAction.Show, ParameterSetName = ParameterSet_FQName_ViaWinCompat, Mandatory = true)]
[Parameter(ParameterSetName = ParameterSet_ViaWinCompat, Mandatory = true)]
[Parameter(ParameterSetName = ParameterSet_FQName_ViaWinCompat, Mandatory = true)]
[Alias("UseWinPS")]
public SwitchParameter UseWindowsPowerShell { get; set; }
@@ -293,7 +293,7 @@ namespace Microsoft.PowerShell.Commands
/// Session name for WindowsPS compat remoting session.
/// </summary>
internal const string WindowsPowerShellCompatRemotingSessionName = "WinPSCompatSession";
/// <summary>
/// Synchronization object for creation/cleanup of WindowsPS compat remoting session.
/// </summary>
@@ -2363,62 +2363,18 @@ namespace Microsoft.PowerShell.Commands
bool isConsideredCompatible = ModuleUtils.IsPSEditionCompatible(moduleManifestPath, inferredCompatiblePSEditions);
if (!BaseSkipEditionCheck && !isConsideredCompatible)
{
if (ExperimentalFeature.IsEnabled("PSWindowsPowerShellCompatibility"))
if (importingModule)
{
if (importingModule)
{
IList<PSModuleInfo> moduleProxies = ImportModulesUsingWinCompat(new string [] {moduleManifestPath}, null, new ImportModuleOptions());
IList<PSModuleInfo> moduleProxies = ImportModulesUsingWinCompat(new string [] {moduleManifestPath}, null, new ImportModuleOptions());
// we are loading by a single ManifestPath so expect max of 1
if(moduleProxies.Count > 0)
{
return moduleProxies[0];
}
else
{
return null;
}
// we are loading by a single ManifestPath so expect max of 1
if(moduleProxies.Count > 0)
{
return moduleProxies[0];
}
}
else
{
containedErrors = true;
if (writingErrors)
else
{
message = StringUtil.Format(
Modules.PSEditionNotSupported,
moduleManifestPath,
PSVersionInfo.PSEdition,
string.Join(',', inferredCompatiblePSEditions));
InvalidOperationException ioe = new InvalidOperationException(message);
ErrorRecord er = new ErrorRecord(
ioe,
nameof(Modules) + "_" + nameof(Modules.PSEditionNotSupported),
ErrorCategory.ResourceUnavailable,
moduleManifestPath);
WriteError(er);
}
if (bailOnFirstError)
{
// If we're trying to load the module, return null so that caches
// are not polluted
if (importingModule)
{
return null;
}
// If we return null with Get-Module, a fake module info will be created. Since
// we want to suppress output of the module, we need to do that here.
return new PSModuleInfo(moduleManifestPath, context: null, sessionState: null)
{
HadErrorsLoading = true,
IsConsideredEditionCompatible = false,
};
return null;
}
}
}
@@ -4954,7 +4910,7 @@ namespace Microsoft.PowerShell.Commands
}
}
if (ExperimentalFeature.IsEnabled("PSWindowsPowerShellCompatibility") && module.IsWindowsPowerShellCompatModule && (System.Threading.Interlocked.Decrement(ref s_WindowsPowerShellCompatUsageCounter) == 0))
if (module.IsWindowsPowerShellCompatModule && (System.Threading.Interlocked.Decrement(ref s_WindowsPowerShellCompatUsageCounter) == 0))
{
CleanupWindowsPowerShellCompatResources();
}
@@ -955,7 +955,7 @@ namespace System.Management.Automation.Language
case TokenKind.MultiplyEquals: et = ExpressionType.Multiply; break;
case TokenKind.DivideEquals: et = ExpressionType.Divide; break;
case TokenKind.RemainderEquals: et = ExpressionType.Modulo; break;
case TokenKind.QuestionQuestionEquals when ExperimentalFeature.IsEnabled("PSCoalescingOperators"): et = ExpressionType.Coalesce; break;
case TokenKind.QuestionQuestionEquals: et = ExpressionType.Coalesce; break;
}
var exprs = new List<Expression>();
@@ -5896,7 +5896,7 @@ namespace System.Management.Automation.Language
lhs.Cast(typeof(object)),
rhs.Cast(typeof(object)),
ExpressionCache.Constant(false));
case TokenKind.QuestionQuestion when ExperimentalFeature.IsEnabled("PSCoalescingOperators"):
case TokenKind.QuestionQuestion:
return Coalesce(lhs, rhs);
}
@@ -35,8 +35,6 @@ namespace System.Management.Automation.Language
/// </summary>
public sealed class Parser
{
private static readonly bool s_pipelineChainsEnabled = ExperimentalFeature.IsEnabled("PSPipelineChainOperators");
private readonly Tokenizer _tokenizer;
internal Token _ungotToken;
private bool _disableCommaOperator;
@@ -5715,11 +5713,6 @@ namespace System.Management.Automation.Language
// If this feature is not enabled,
// just look for pipelines as before.
if (!s_pipelineChainsEnabled)
{
return PipelineRule(allowBackground: true);
}
RuntimeHelpers.EnsureSufficientExecutionStack();
// First look for assignment, since PipelineRule once handled that and this supercedes that.
@@ -5950,7 +5943,6 @@ namespace System.Management.Automation.Language
while (scanning)
{
CommandBaseAst commandAst;
Token assignToken = null;
if (expr == null)
{
@@ -5960,21 +5952,6 @@ namespace System.Management.Automation.Language
{
SetTokenizerMode(TokenizerMode.Expression);
expr = ExpressionRule();
// When pipeline chains are not enabled, we must process assignment.
// We are looking for <expr> = <statement>, and have seen <expr>.
// Now looking for '='
if (!s_pipelineChainsEnabled && expr != null)
{
// We peek here because we are in expression mode,
// otherwise =0 will get scanned as a single token.
Token token = PeekToken();
if (token.Kind.HasTrait(TokenFlags.AssignmentOperator))
{
SkipToken();
assignToken = token;
}
}
}
finally
{
@@ -5993,35 +5970,6 @@ namespace System.Management.Automation.Language
ParserStrings.ExpressionsMustBeFirstInPipeline);
}
// To process assignment when pipeline chains are not enabled,
// we have seen '<expr> = ' and now expect a statement
if (!s_pipelineChainsEnabled && assignToken != null)
{
SkipNewlines();
StatementAst statement = StatementRule();
if (statement == null)
{
// ErrorRecovery:
// We are likely at EOF, since almost anything else should result in a pipeline,
// so just keep parsing
IScriptExtent errorExtent = After(assignToken);
ReportIncompleteInput(
errorExtent,
nameof(ParserStrings.ExpectedValueExpression),
ParserStrings.ExpectedValueExpression,
assignToken.Kind.Text());
statement = new ErrorStatementAst(errorExtent);
}
return new AssignmentStatementAst(
ExtentOf(expr, statement),
expr,
assignToken.Kind,
statement,
assignToken.Extent);
}
RedirectionAst[] redirections = null;
var redirectionToken = PeekToken() as RedirectionToken;
RedirectionAst lastRedirection = null;
@@ -6098,31 +6046,11 @@ namespace System.Management.Automation.Language
case TokenKind.AndAnd:
case TokenKind.OrOr:
if (s_pipelineChainsEnabled)
{
scanning = false;
continue;
}
// Report that &&/|| are unsupported
SkipToken();
SkipNewlines();
ReportError(
nextToken.Extent,
nameof(ParserStrings.InvalidEndOfLine),
ParserStrings.InvalidEndOfLine,
nextToken.Text);
if (PeekToken().Kind == TokenKind.EndOfInput)
{
scanning = false;
}
break;
scanning = false;
continue;
case TokenKind.Ampersand:
// When pipeline chains are not enabled, pipelines always handle backgrounding
if (s_pipelineChainsEnabled && !allowBackground)
if (!allowBackground)
{
// Handled by invoking rule
scanning = false;
@@ -6720,12 +6648,6 @@ namespace System.Management.Automation.Language
// G ternary-expression:
// G binary-expression '?' new-lines:opt ternary-expression new-lines:opt ':' new-lines:opt ternary-expression
// TODO: remove this if-block when making 'ternary operator' an official feature.
if (!ExperimentalFeature.IsEnabled("PSTernaryOperator"))
{
return BinaryExpressionRule();
}
RuntimeHelpers.EnsureSufficientExecutionStack();
var oldTokenizerMode = _tokenizer.Mode;
try
@@ -727,7 +727,7 @@ namespace System.Management.Automation.Language
internal bool ForceEndNumberOnTernaryOpChars
{
get { return _forceEndNumberOnTernaryOpChars; }
set { _forceEndNumberOnTernaryOpChars = value && ExperimentalFeature.IsEnabled("PSTernaryOperator"); }
set { _forceEndNumberOnTernaryOpChars = value; }
}
internal bool WantSimpleName { get; set; }
@@ -5015,23 +5015,20 @@ namespace System.Management.Automation.Language
return this.NewToken(TokenKind.Colon);
case '?' when InExpressionMode():
if (ExperimentalFeature.IsEnabled("PSCoalescingOperators"))
c1 = PeekChar();
if (c1 == '?')
{
SkipChar();
c1 = PeekChar();
if (c1 == '?')
if (c1 == '=')
{
SkipChar();
c1 = PeekChar();
if (c1 == '=')
{
SkipChar();
return this.NewToken(TokenKind.QuestionQuestionEquals);
}
return this.NewToken(TokenKind.QuestionQuestion);
return this.NewToken(TokenKind.QuestionQuestionEquals);
}
return this.NewToken(TokenKind.QuestionQuestion);
}
return this.NewToken(TokenKind.QuestionMark);
@@ -161,11 +161,10 @@ namespace Microsoft.PowerShell.Commands
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = NewPSSessionCommand.VMNameParameterSet)]
public string ConfigurationName { get; set; }
/// <summary>
/// Gets or sets parameter value that creates connection to a Windows PowerShell process.
/// </summary>
[Experimental("PSWindowsPowerShellCompatibility", ExperimentAction.Show)]
[Parameter(Mandatory = true, ParameterSetName = NewPSSessionCommand.UseWindowsPowerShellParameterSet)]
public SwitchParameter UseWindowsPowerShell { get; set; }
@@ -3,30 +3,15 @@
Describe 'NullCoalesceOperations' -Tags 'CI' {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSCoalescingOperators')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'PSCoalescingOperators' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
} else {
$someGuid = New-Guid
$typesTests = @(
@{ name = 'string'; valueToSet = 'hello' }
@{ name = 'dotnetType'; valueToSet = $someGuid }
@{ name = 'byte'; valueToSet = [byte]0x94 }
@{ name = 'intArray'; valueToSet = 1..2 }
@{ name = 'stringArray'; valueToSet = 'a'..'c' }
@{ name = 'emptyArray'; valueToSet = @(1, 2, 3) }
)
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
$someGuid = New-Guid
$typesTests = @(
@{ name = 'string'; valueToSet = 'hello' }
@{ name = 'dotnetType'; valueToSet = $someGuid }
@{ name = 'byte'; valueToSet = [byte]0x94 }
@{ name = 'intArray'; valueToSet = 1..2 }
@{ name = 'stringArray'; valueToSet = 'a'..'c' }
@{ name = 'emptyArray'; valueToSet = @(1, 2, 3) }
)
}
Context "Null conditional assignment operator ??=" {
@@ -3,15 +3,6 @@
Describe "Experimental Feature: && and || operators - Feature-Enabled" -Tag CI {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSPipelineChainOperators')
if ($skipTest)
{
Write-Verbose "Test Suite Skipped: These tests require the PSPipelineChainOperators experimental feature to be enabled" -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
return
}
function Test-SuccessfulCommand
{
Write-Output "SUCCESS"
@@ -135,12 +126,6 @@ Describe "Experimental Feature: && and || operators - Feature-Enabled" -Tag CI {
)
}
AfterAll {
if ($skipTest) {
$PSDefaultParameterValues = $originalDefaultParameterValues
}
}
It "Gets the correct output with statement '<Statement>'" -TestCases $simpleTestCases {
param($Statement, $Output)
@@ -3,54 +3,46 @@
Describe "Using of ternary operator" -Tags CI {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSTernaryOperator')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'PSTernaryOperator' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
}
else {
$testCases = @(
## Condition: variable and constant expressions
@{ Script = { $true ? 1 : 2 }; ExpectedValue = 1 }
@{ Script = { $true? ?1 :2 }; ExpectedValue = 2 }
@{ Script = { ${true}?1:2 }; ExpectedValue = 1 }
@{ Script = { 1 ? 1kb : 0xf }; ExpectedValue = 1kb }
@{ Script = { 0 ?1kb:0xf }; ExpectedValue = 15 }
@{ Script = { 's' ?1kb:0xf }; ExpectedValue = 1kb }
@{ Script = { $null ?1kb:0xf }; ExpectedValue = 15 }
@{ Script = { '' ?1kb:0xf }; ExpectedValue = 15 }
$testCases = @(
## Condition: variable and constant expressions
@{ Script = { $true ? 1 : 2 }; ExpectedValue = 1 }
@{ Script = { $true? ?1 :2 }; ExpectedValue = 2 }
@{ Script = { ${true}?1:2 }; ExpectedValue = 1 }
@{ Script = { 1 ? 1kb : 0xf }; ExpectedValue = 1kb }
@{ Script = { 0 ?1kb:0xf }; ExpectedValue = 15 }
@{ Script = { 's' ?1kb:0xf }; ExpectedValue = 1kb }
@{ Script = { $null ?1kb:0xf }; ExpectedValue = 15 }
@{ Script = { '' ?1kb:0xf }; ExpectedValue = 15 }
## Condition: other primary expressions
@{ Script = { 1,2,3,4 ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { @(1,2,3,4) ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { @{name = 'name'} ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { @{name = 'name'}.name ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { @{name = 'name'}.Contains('name') ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { (Test-Path Env:\NonExist) ? 'true' : 'false' }; ExpectedValue = 'false' }
@{ Script = { (Test-Path Env:\PSModulePath) ? 'true' : 'false' }; ExpectedValue = 'true' }
@{ Script = { $($p = Get-Process -Id $PID; $p.Name -eq 'pwsh') ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { ($a = 1) ? 2 : 3 }; ExpectedValue = 2 }
@{ Script = { $($a = 1) ? 2 : 3 }; ExpectedValue = 3 }
@{ Script = { (Write-Warning -Message warning -WarningAction SilentlyContinue) ? 1 : 2 }; ExpectedValue = 2 }
@{ Script = { (Write-Error -Message error -ErrorAction SilentlyContinue) ? 1 : 2 }; ExpectedValue = 2 }
## Condition: other primary expressions
@{ Script = { 1,2,3,4 ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { @(1,2,3,4) ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { @{name = 'name'} ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { @{name = 'name'}.name ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { @{name = 'name'}.Contains('name') ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { (Test-Path Env:\NonExist) ? 'true' : 'false' }; ExpectedValue = 'false' }
@{ Script = { (Test-Path Env:\PSModulePath) ? 'true' : 'false' }; ExpectedValue = 'true' }
@{ Script = { $($p = Get-Process -Id $PID; $p.Name -eq 'pwsh') ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { ($a = 1) ? 2 : 3 }; ExpectedValue = 2 }
@{ Script = { $($a = 1) ? 2 : 3 }; ExpectedValue = 3 }
@{ Script = { (Write-Warning -Message warning -WarningAction SilentlyContinue) ? 1 : 2 }; ExpectedValue = 2 }
@{ Script = { (Write-Error -Message error -ErrorAction SilentlyContinue) ? 1 : 2 }; ExpectedValue = 2 }
## Condition: unary and binary expression expressions
@{ Script = { -not $IsCoreCLR ? 'Desktop' : 'Core' }; ExpectedValue = 'Core' }
@{ Script = { $PSEdition -eq 'Core' ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { $IsCoreCLR -and (Get-Process -Id $PID).Name -eq 'pwsh' ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { $IsCoreCLR -and 'pwsh' -match 'p.*h' ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { 1,2,3 -contains 2 ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
## Condition: unary and binary expression expressions
@{ Script = { -not $IsCoreCLR ? 'Desktop' : 'Core' }; ExpectedValue = 'Core' }
@{ Script = { $PSEdition -eq 'Core' ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { $IsCoreCLR -and (Get-Process -Id $PID).Name -eq 'pwsh' ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { $IsCoreCLR -and 'pwsh' -match 'p.*h' ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
@{ Script = { 1,2,3 -contains 2 ? 'Core' : 'Desktop' }; ExpectedValue = 'Core' }
## Nested ternary expressions
@{ Script = { $IsCoreCLR ? $false ? 'nested-if-true' : 'nested-if-false' : 'if-false' }; ExpectedValue = 'nested-if-false' }
@{ Script = { $IsCoreCLR ? $false ? 'nested-if-true' : $true ? 'nested-nested-if-true' : 'nested-nested-if-false' : 'if-false' }; ExpectedValue = 'nested-nested-if-true' }
## Nested ternary expressions
@{ Script = { $IsCoreCLR ? $false ? 'nested-if-true' : 'nested-if-false' : 'if-false' }; ExpectedValue = 'nested-if-false' }
@{ Script = { $IsCoreCLR ? $false ? 'nested-if-true' : $true ? 'nested-nested-if-true' : 'nested-nested-if-false' : 'if-false' }; ExpectedValue = 'nested-nested-if-true' }
## Binary operator has higher precedence order than ternary
@{ Script = { !$IsCoreCLR ? 'Core' : 'Desktop' -eq 'Core' }; ExpectedValue = !$IsCoreCLR ? 'Core' : ('Desktop' -eq 'Core') }
@{ Script = { ($IsCoreCLR ? 'Core' : 'Desktop') -eq 'Core' }; ExpectedValue = $true }
)
}
## Binary operator has higher precedence order than ternary
@{ Script = { !$IsCoreCLR ? 'Core' : 'Desktop' -eq 'Core' }; ExpectedValue = !$IsCoreCLR ? 'Core' : ('Desktop' -eq 'Core') }
@{ Script = { ($IsCoreCLR ? 'Core' : 'Desktop') -eq 'Core' }; ExpectedValue = $true }
)
}
AfterAll {
@@ -263,21 +263,6 @@ Describe 'assignment statement parsing' -Tags "CI" {
}
Describe 'null coalescing assignment statement parsing' -Tag 'CI' {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSCoalescingOperators')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'PSCoalescingOperators' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
}
ShouldBeParseError '1 ??= 1' InvalidLeftHandSide 0
ShouldBeParseError '@() ??= 1' InvalidLeftHandSide 0
ShouldBeParseError '@{} ??= 1' InvalidLeftHandSide 0
@@ -287,21 +272,6 @@ Describe 'null coalescing assignment statement parsing' -Tag 'CI' {
}
Describe 'null coalescing statement parsing' -Tag "CI" {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSCoalescingOperators')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'PSCoalescingOperators' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
}
ShouldBeParseError '$x??=' ExpectedValueExpression 5
ShouldBeParseError '$x ??Get-Thing' ExpectedValueExpression,UnexpectedToken 5,5
ShouldBeParseError '$??=$false' ExpectedValueExpression,InvalidLeftHandSide 3,0
@@ -393,42 +363,28 @@ Describe 'Unicode escape sequence parsing' -Tag "CI" {
Describe "Ternary Operator parsing" -Tags CI {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSTernaryOperator')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'PSTernaryOperator' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
}
else {
$testCases_basic = @(
@{ Script = '$true?2:3'; TokenKind = [System.Management.Automation.Language.TokenKind]::Variable; }
@{ Script = '$false?'; TokenKind = [System.Management.Automation.Language.TokenKind]::Variable; }
@{ Script = '$:abc'; TokenKind = [System.Management.Automation.Language.TokenKind]::Variable; }
@{ Script = '$env:abc'; TokenKind = [System.Management.Automation.Language.TokenKind]::Variable; }
@{ Script = '$env:123'; TokenKind = [System.Management.Automation.Language.TokenKind]::Variable; }
@{ Script = 'a?2:2'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
@{ Script = '1?2:3'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
@{ Script = 'a?'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
@{ Script = 'a?b'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
@{ Script = '1?'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
@{ Script = '?2:3'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
)
$testCases_basic = @(
@{ Script = '$true?2:3'; TokenKind = [System.Management.Automation.Language.TokenKind]::Variable; }
@{ Script = '$false?'; TokenKind = [System.Management.Automation.Language.TokenKind]::Variable; }
@{ Script = '$:abc'; TokenKind = [System.Management.Automation.Language.TokenKind]::Variable; }
@{ Script = '$env:abc'; TokenKind = [System.Management.Automation.Language.TokenKind]::Variable; }
@{ Script = '$env:123'; TokenKind = [System.Management.Automation.Language.TokenKind]::Variable; }
@{ Script = 'a?2:2'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
@{ Script = '1?2:3'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
@{ Script = 'a?'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
@{ Script = 'a?b'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
@{ Script = '1?'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
@{ Script = '?2:3'; TokenKind = [System.Management.Automation.Language.TokenKind]::Generic; }
)
$testCases_incomplete = @(
@{ Script = '$true ?'; ErrorId = "ExpectedValueExpression"; AstType = [System.Management.Automation.Language.ErrorExpressionAst] }
@{ Script = '$true ? 3'; ErrorId = "MissingColonInTernaryExpression"; AstType = [System.Management.Automation.Language.ErrorExpressionAst] }
@{ Script = '$true ? 3 :'; ErrorId = "ExpectedValueExpression"; AstType = [System.Management.Automation.Language.TernaryExpressionAst] }
@{ Script = "`$true`t?"; ErrorId = "ExpectedValueExpression"; AstType = [System.Management.Automation.Language.ErrorExpressionAst] }
@{ Script = "`$true`t?`t3"; ErrorId = "MissingColonInTernaryExpression"; AstType = [System.Management.Automation.Language.ErrorExpressionAst] }
@{ Script = "`$true`t?`t3`t:"; ErrorId = "ExpectedValueExpression"; AstType = [System.Management.Automation.Language.TernaryExpressionAst] }
)
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
$testCases_incomplete = @(
@{ Script = '$true ?'; ErrorId = "ExpectedValueExpression"; AstType = [System.Management.Automation.Language.ErrorExpressionAst] }
@{ Script = '$true ? 3'; ErrorId = "MissingColonInTernaryExpression"; AstType = [System.Management.Automation.Language.ErrorExpressionAst] }
@{ Script = '$true ? 3 :'; ErrorId = "ExpectedValueExpression"; AstType = [System.Management.Automation.Language.TernaryExpressionAst] }
@{ Script = "`$true`t?"; ErrorId = "ExpectedValueExpression"; AstType = [System.Management.Automation.Language.ErrorExpressionAst] }
@{ Script = "`$true`t?`t3"; ErrorId = "MissingColonInTernaryExpression"; AstType = [System.Management.Automation.Language.ErrorExpressionAst] }
@{ Script = "`$true`t?`t3`t:"; ErrorId = "ExpectedValueExpression"; AstType = [System.Management.Automation.Language.TernaryExpressionAst] }
)
}
It "Question-mark and colon parsed correctly in <Script> when not in ternary expression context" -TestCases $testCases_basic {
@@ -885,23 +885,6 @@ try
Describe "ForEach-Object -Parallel Constrained Language Tests" -Tags 'Feature','RequireAdminOnWindows' {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSForEachObjectParallel')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'PSForEachObjectParallel' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
}
It 'Foreach-Object -Parallel must run in ConstrainedLanguage mode under system lock down' {
try
@@ -4,23 +4,7 @@
Describe 'ForEach-Object -Parallel Basic Tests' -Tags 'CI' {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSForEachObjectParallel')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'PSForEachObjectParallel' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
}
else {
$sb = { "Hello!" }
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
$sb = { "Hello!" }
}
It "Verifies dollar underbar variable" {
@@ -88,7 +72,7 @@ Describe 'ForEach-Object -Parallel Basic Tests' -Tags 'CI' {
}
It 'Verifies debug data streaming' {
$actualDebug = 1..1 | ForEach-Object -Parallel { Write-Debug "Debug!" -Debug } -Debug 5>&1
$actualDebug.Message | Should -BeExactly 'Debug!'
}
@@ -105,7 +89,7 @@ Describe 'ForEach-Object -Parallel Basic Tests' -Tags 'CI' {
}
It 'Verifies error for script block piped variable' {
$actualError = $sb | ForEach-Object -Parallel { "Hello" } 2>&1
$actualError.FullyQualifiedErrorId | Should -BeExactly 'ParallelPipedInputObjectCannotBeScriptBlock,Microsoft.PowerShell.Commands.ForEachObjectCommand'
}
@@ -126,13 +110,6 @@ Describe 'ForEach-Object -Parallel common parameters' -Tags 'CI' {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSForEachObjectParallel')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'PSForEachObjectParallel' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
}
# Test cases
$TestCasesNotSupportedCommonParameters = @(
@{
@@ -182,10 +159,6 @@ Describe 'ForEach-Object -Parallel common parameters' -Tags 'CI' {
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
$global:actualVariable = $null
}
@@ -207,23 +180,6 @@ Describe 'ForEach-Object -Parallel common parameters' -Tags 'CI' {
Describe 'ForEach-Object -Parallel -AsJob Basic Tests' -Tags 'CI' {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSForEachObjectParallel')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'PSForEachObjectParallel' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
}
It 'Verifies TimeoutSeconds parameter is excluded from AsJob' {
{ 1..1 | ForEach-Object -AsJob -Parallel { "Hello" } -TimeoutSeconds 60 } | Should -Throw -ErrorId 'ParallelCannotUseTimeoutWithJob,Microsoft.PowerShell.Commands.ForEachObjectCommand'
@@ -360,23 +316,6 @@ Describe 'ForEach-Object -Parallel -AsJob Basic Tests' -Tags 'CI' {
Describe 'ForEach-Object -Parallel Functional Tests' -Tags 'Feature' {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSForEachObjectParallel')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'PSForEachObjectParallel' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
}
It 'Verifies job queuing and throttle limit' {
# Run four job tasks, two in parallel at a time.
@@ -417,7 +356,7 @@ Describe 'ForEach-Object -Parallel Functional Tests' -Tags 'Feature' {
It 'Verifies timeout and throttle parameters' {
# With ThrottleLimit set to 1, the two 60 second long script blocks will run sequentially,
# With ThrottleLimit set to 1, the two 60 second long script blocks will run sequentially,
# until the timeout in 5 seconds.
$results = 1..2 | ForEach-Object -Parallel { "Output $_"; Start-Sleep -Seconds 60 } -TimeoutSeconds 5 -ThrottleLimit 1 2>&1
$results.Count | Should -BeExactly 2
@@ -2,21 +2,6 @@
# Licensed under the MIT License.
Describe 'Get-Error tests' -Tag CI {
BeforeAll {
$skipTest = -not $EnabledExperimentalFeatures.Contains('Microsoft.PowerShell.Utility.PSGetError')
if ($skipTest) {
Write-Verbose "Test Suite Skipped. The test suite requires the experimental feature 'Microsoft.PowerShell.Utility.PSGetError' to be enabled." -Verbose
$originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:skip"] = $true
}
}
AfterAll {
if ($skipTest) {
$global:PSDefaultParameterValues = $originalDefaultParameterValues
}
}
It 'Get-Error resolves $Error[0] and includes InnerException' {
try {
1/0
@@ -8,11 +8,7 @@ Describe 'Tests for $ErrorView' -Tag CI {
}
It '$ErrorView should have correct default value' {
$expectedDefault = 'NormalView'
if ((Get-ExperimentalFeature -Name PSErrorView).Enabled) {
$expectedDefault = 'ConciseView'
}
$expectedDefault = 'ConciseView'
$ErrorView | Should -BeExactly $expectedDefault
}
+1 -3
View File
@@ -1,7 +1,5 @@
{
"ExperimentalFeatures": {
"ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ],
"PSForEachObjectParallel": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/Foreach-Object-Parallel.Tests.ps1", "test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageRestriction.Tests.ps1" ],
"PSPipelineChainOperators": [ "test/powershell/Language/Operators/PipelineChainOperator.Tests.ps1" ]
"ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ]
}
}