Add cmdlet 'Join-String' for creating text from pipeline input (#7660)
The cmdlet syntax is as follows: ``` Join-String [[-Property] <pspropertyexpression>] [[-Separator] <string>] [-OutputPrefix <string>] [-OutputSuffix <string>] [-UseCulture] [-InputObject <psobject>] [<CommonParameters>] Join-String [[-Property] <pspropertyexpression>] [[-Separator] <string>] [-OutputPrefix <string>] [-OutputSuffix <string>] [-SingleQuote] [-UseCulture] [-InputObject <psobject>] [<CommonParameters>] Join-String [[-Property] <pspropertyexpression>] [[-Separator] <string>] [-OutputPrefix <string>] [-OutputSuffix <string>] [-DoubleQuote] [-UseCulture] [-InputObject <psobject>] [<CommonParameters>] Join-String [[-Property] <pspropertyexpression>] [[-Separator] <string>] [-OutputPrefix <string>] [-OutputSuffix <string>] [-FormatString <string>] [-UseCulture] [-InputObject <psobject>] [<CommonParameters>] ```
This commit is contained in:
parent
a244c049e8
commit
877b9a9fbf
|
@ -0,0 +1,226 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Internal;
|
||||
using System.Management.Automation.Language;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.PowerShell.Commands.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// Join-Object implementation.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Join, "String", RemotingCapability = RemotingCapability.None, DefaultParameterSetName = "default")]
|
||||
[OutputType(typeof(string))]
|
||||
public sealed class JoinStringCommand : PSCmdlet
|
||||
{
|
||||
/// <summary>A bigger default to not get re-allocations in common use cases.</summary>
|
||||
private const int DefaultOutputStringCapacity = 256;
|
||||
private readonly StringBuilder _outputBuilder = new StringBuilder(DefaultOutputStringCapacity);
|
||||
private CultureInfo _cultureInfo = CultureInfo.InvariantCulture;
|
||||
private string _separator;
|
||||
private char _quoteChar;
|
||||
private bool _firstInputObject = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the property name or script block to use as the value to join.
|
||||
/// </summary>
|
||||
[Parameter(Position = 0)]
|
||||
[ArgumentCompleter(typeof(PropertyNameCompleter))]
|
||||
public PSPropertyExpression Property { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the delimiter to join the output with.
|
||||
/// </summary>
|
||||
[Parameter(Position = 1)]
|
||||
[ArgumentCompleter(typeof(JoinItemCompleter))]
|
||||
[AllowEmptyString]
|
||||
public string Separator
|
||||
{
|
||||
get => _separator ?? LanguagePrimitives.ConvertTo<string>(GetVariableValue("OFS"));
|
||||
set => _separator = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets text to include before the joined input text.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[Alias("op")]
|
||||
public string OutputPrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets text to include after the joined input text.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[Alias("os")]
|
||||
public string OutputSuffix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the output items should we wrapped in single quotes.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = "SingleQuote")]
|
||||
public SwitchParameter SingleQuote { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the output items should we wrapped in double quotes.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = "DoubleQuote")]
|
||||
public SwitchParameter DoubleQuote { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a format string that is applied to each input object.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = "Format")]
|
||||
[ArgumentCompleter(typeof(JoinItemCompleter))]
|
||||
public string FormatString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the current culture should be used with formatting instead of the invariant culture.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public SwitchParameter UseCulture { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the input object to join into text.
|
||||
/// </summary>
|
||||
[Parameter(ValueFromPipeline = true)]
|
||||
public PSObject InputObject { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void BeginProcessing()
|
||||
{
|
||||
_quoteChar = SingleQuote ? '\'' : DoubleQuote ? '"' : char.MinValue;
|
||||
_outputBuilder.Append(OutputPrefix);
|
||||
if (UseCulture)
|
||||
{
|
||||
_cultureInfo = CultureInfo.CurrentCulture;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
if (InputObject != null && InputObject != AutomationNull.Value)
|
||||
{
|
||||
var inputValue = Property == null
|
||||
? InputObject
|
||||
: Property.GetValues(InputObject, false, true).FirstOrDefault()?.Result;
|
||||
|
||||
// conversion to string always succeeds.
|
||||
if (!LanguagePrimitives.TryConvertTo<string>(inputValue, _cultureInfo, out var stringValue))
|
||||
{
|
||||
throw new PSInvalidCastException("InvalidCastFromAnyTypeToString", ExtendedTypeSystem.InvalidCastCannotRetrieveString, null);
|
||||
}
|
||||
|
||||
if (_firstInputObject)
|
||||
{
|
||||
_firstInputObject = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_outputBuilder.Append(Separator);
|
||||
}
|
||||
|
||||
if (_quoteChar != char.MinValue)
|
||||
{
|
||||
_outputBuilder.Append(_quoteChar);
|
||||
_outputBuilder.Append(stringValue);
|
||||
_outputBuilder.Append(_quoteChar);
|
||||
}
|
||||
else if (string.IsNullOrEmpty(FormatString))
|
||||
{
|
||||
_outputBuilder.Append(stringValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
_outputBuilder.AppendFormat(_cultureInfo, FormatString, stringValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void EndProcessing()
|
||||
{
|
||||
_outputBuilder.Append(OutputSuffix);
|
||||
WriteObject(_outputBuilder.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
internal class JoinItemCompleter : IArgumentCompleter
|
||||
{
|
||||
public IEnumerable<CompletionResult> CompleteArgument(
|
||||
string commandName,
|
||||
string parameterName,
|
||||
string wordToComplete,
|
||||
CommandAst commandAst,
|
||||
IDictionary fakeBoundParameters)
|
||||
{
|
||||
switch (parameterName)
|
||||
{
|
||||
case "Separator": return CompleteSeparator(wordToComplete);
|
||||
case "FormatString": return CompleteFormatString(wordToComplete);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IEnumerable<CompletionResult> CompleteFormatString(string wordToComplete)
|
||||
{
|
||||
var res = new List<CompletionResult>();
|
||||
void AddMatching(string completionText)
|
||||
{
|
||||
if (completionText.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
res.Add(new CompletionResult(completionText));
|
||||
}
|
||||
}
|
||||
|
||||
AddMatching("'[{0}]'");
|
||||
AddMatching("'{0:N2}'");
|
||||
AddMatching("\"`r`n `${0}\"");
|
||||
AddMatching("\"`r`n [string] `${0}\"");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private IEnumerable<CompletionResult> CompleteSeparator(string wordToComplete)
|
||||
{
|
||||
var res = new List<CompletionResult>(10);
|
||||
|
||||
void AddMatching(string completionText, string listText, string toolTip)
|
||||
{
|
||||
if (completionText.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
res.Add(new CompletionResult(completionText, listText, CompletionResultType.ParameterValue, toolTip));
|
||||
}
|
||||
}
|
||||
|
||||
AddMatching("', '", "Comma-Space", "', ' - Comma-Space");
|
||||
AddMatching("';'", "Semi-Colon", "';' - Semi-Colon ");
|
||||
AddMatching("'; '", "Semi-Colon-Space", "'; ' - Semi-Colon-Space");
|
||||
AddMatching($"\"{NewLineText}\"", "Newline", $"{NewLineText} - Newline");
|
||||
AddMatching("','", "Comma", "',' - Comma");
|
||||
AddMatching("'-'", "Dash", "'-' - Dash");
|
||||
AddMatching("' '", "Space", "' ' - Space");
|
||||
return res;
|
||||
}
|
||||
|
||||
public string NewLineText
|
||||
{
|
||||
get
|
||||
{
|
||||
#if UNIX
|
||||
return "`n";
|
||||
#else
|
||||
return "`r`n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide",
|
|||
"Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias", "Invoke-Expression",
|
||||
"Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random", "Get-UICulture",
|
||||
"Get-Unique", "Export-PSSession", "Import-PSSession", "Import-Alias", "Import-LocalizedData",
|
||||
"Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date",
|
||||
"Join-String", "Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date",
|
||||
"Start-Sleep", "Tee-Object", "Measure-Command", "Update-TypeData", "Update-FormatData",
|
||||
"Remove-TypeData", "Get-TypeData", "Write-Host", "Write-Progress", "New-Object", "Select-Object",
|
||||
"Group-Object", "Sort-Object", "Get-Variable", "New-Variable", "Set-Variable", "Remove-Variable",
|
||||
|
|
|
@ -14,7 +14,7 @@ CmdletsToExport= "Format-List", "Format-Custom", "Format-Table", "Format-Wide",
|
|||
"Export-Csv", "Import-Csv", "ConvertTo-Csv", "ConvertFrom-Csv", "Export-Alias", "Invoke-Expression",
|
||||
"Get-Alias", "Get-Culture", "Get-Date", "Get-Host", "Get-Member", "Get-Random", "Get-UICulture",
|
||||
"Get-Unique", "Export-PSSession", "Import-PSSession", "Import-Alias", "Import-LocalizedData",
|
||||
"Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date",
|
||||
"Join-String", "Select-String", "Measure-Object", "New-Alias", "New-TimeSpan", "Read-Host", "Set-Alias", "Set-Date",
|
||||
"Start-Sleep", "Tee-Object", "Measure-Command", "Update-TypeData", "Update-FormatData",
|
||||
"Remove-TypeData", "Get-TypeData", "Write-Host", "Write-Progress", "New-Object", "Select-Object",
|
||||
"Group-Object", "Sort-Object", "Get-Variable", "New-Variable", "Set-Variable", "Remove-Variable",
|
||||
|
|
|
@ -3746,7 +3746,7 @@ namespace System.Management.Automation
|
|||
prevType = AstTypeInference.InferTypeOf(pipelineAst.PipelineElements[i - 1], context.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval);
|
||||
}
|
||||
|
||||
CompleteMemberByInferredType(context, prevType, result, context.WordToComplete + "*", filter: IsPropertyMember, isStatic: false);
|
||||
CompleteMemberByInferredType(context.TypeInferenceContext, prevType, result, context.WordToComplete + "*", filter: IsPropertyMember, isStatic: false);
|
||||
result.Add(CompletionResult.Null);
|
||||
}
|
||||
|
||||
|
@ -5027,7 +5027,7 @@ namespace System.Management.Automation
|
|||
if (inferredTypes != null && inferredTypes.Length > 0)
|
||||
{
|
||||
// Use inferred types if we have any
|
||||
CompleteMemberByInferredType(context, inferredTypes, results, memberName, filter: null, isStatic: @static);
|
||||
CompleteMemberByInferredType(context.TypeInferenceContext, inferredTypes, results, memberName, filter: null, isStatic: @static);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5131,7 +5131,7 @@ namespace System.Management.Automation
|
|||
return Ast.GetAncestorAst<ConfigurationDefinitionAst>(expression) != null;
|
||||
}
|
||||
|
||||
private static void CompleteMemberByInferredType(CompletionContext context, IEnumerable<PSTypeName> inferredTypes, List<CompletionResult> results, string memberName, Func<object, bool> filter, bool isStatic)
|
||||
internal static void CompleteMemberByInferredType(TypeInferenceContext context, IEnumerable<PSTypeName> inferredTypes, List<CompletionResult> results, string memberName, Func<object, bool> filter, bool isStatic)
|
||||
{
|
||||
bool extensionMethodsAdded = false;
|
||||
HashSet<string> typeNameUsed = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
@ -5142,8 +5142,9 @@ namespace System.Management.Automation
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
typeNameUsed.Add(psTypeName.Name);
|
||||
var members = context.TypeInferenceContext.GetMembersByInferredType(psTypeName, isStatic, filter);
|
||||
var members = context.GetMembersByInferredType(psTypeName, isStatic, filter);
|
||||
foreach (var member in members)
|
||||
{
|
||||
AddInferredMember(member, memberNamePattern, results);
|
||||
|
@ -5276,7 +5277,7 @@ namespace System.Management.Automation
|
|||
return false;
|
||||
}
|
||||
|
||||
private static bool IsPropertyMember(object member)
|
||||
internal static bool IsPropertyMember(object member)
|
||||
{
|
||||
return member is PropertyInfo
|
||||
|| member is FieldInfo
|
||||
|
@ -6154,7 +6155,7 @@ namespace System.Management.Automation
|
|||
{
|
||||
var result = new List<CompletionResult>();
|
||||
CompleteMemberByInferredType(
|
||||
completionContext, AstTypeInference.InferTypeOf(typeAst, completionContext.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval),
|
||||
completionContext.TypeInferenceContext, AstTypeInference.InferTypeOf(typeAst, completionContext.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval),
|
||||
result, completionContext.WordToComplete + "*", IsWriteablePropertyMember, isStatic: false);
|
||||
return result;
|
||||
}
|
||||
|
@ -6265,7 +6266,7 @@ namespace System.Management.Automation
|
|||
var inferredType = AstTypeInference.InferTypeOf(commandAst, completionContext.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval);
|
||||
var result = new List<CompletionResult>();
|
||||
CompleteMemberByInferredType(
|
||||
completionContext, inferredType,
|
||||
completionContext.TypeInferenceContext, inferredType,
|
||||
result, completionContext.WordToComplete + "*", IsWriteablePropertyMember, isStatic: false);
|
||||
return result;
|
||||
case "Select-Object":
|
||||
|
@ -6910,4 +6911,79 @@ namespace System.Management.Automation
|
|||
return parenExpressionAst.Pipeline.Accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completes with the property names of the InputObject.
|
||||
/// </summary>
|
||||
internal class PropertyNameCompleter : IArgumentCompleter
|
||||
{
|
||||
private readonly string _parameterNameOfInput;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PropertyNameCompleter"/> class.
|
||||
/// </summary>
|
||||
public PropertyNameCompleter()
|
||||
{
|
||||
_parameterNameOfInput = "InputObject";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PropertyNameCompleter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="parameterNameOfInput">The name of the property of the input object for witch to complete with property names.</param>
|
||||
public PropertyNameCompleter(string parameterNameOfInput)
|
||||
{
|
||||
_parameterNameOfInput = parameterNameOfInput;
|
||||
}
|
||||
|
||||
IEnumerable<CompletionResult> IArgumentCompleter.CompleteArgument(
|
||||
string commandName,
|
||||
string parameterName,
|
||||
string wordToComplete,
|
||||
CommandAst commandAst,
|
||||
IDictionary fakeBoundParameters)
|
||||
{
|
||||
if (!(commandAst.Parent is PipelineAst pipelineAst))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < pipelineAst.PipelineElements.Count; i++)
|
||||
{
|
||||
if (pipelineAst.PipelineElements[i] == commandAst)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var typeInferenceContext = new TypeInferenceContext();
|
||||
IEnumerable<PSTypeName> prevType;
|
||||
if (i == 0)
|
||||
{
|
||||
var parameterAst = (CommandParameterAst)commandAst.Find(ast => ast is CommandParameterAst cpa && cpa.ParameterName == "PropertyName", false);
|
||||
var pseudoBinding = new PseudoParameterBinder().DoPseudoParameterBinding(commandAst, null, parameterAst, PseudoParameterBinder.BindingType.ParameterCompletion);
|
||||
if (!pseudoBinding.BoundArguments.TryGetValue(_parameterNameOfInput, out var pair) || !pair.ArgumentSpecified)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pair is AstPair astPair && astPair.Argument != null)
|
||||
{
|
||||
prevType = AstTypeInference.InferTypeOf(astPair.Argument, typeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevType = AstTypeInference.InferTypeOf(pipelineAst.PipelineElements[i - 1], typeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval);
|
||||
}
|
||||
|
||||
var result = new List<CompletionResult>();
|
||||
|
||||
CompletionCompleters.CompleteMemberByInferredType(typeInferenceContext, prevType, result, wordToComplete + "*", filter: CompletionCompleters.IsPropertyMember, isStatic: false);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3244,7 +3244,7 @@ namespace System.Management.Automation
|
|||
try
|
||||
{
|
||||
typeConversion.WriteLine("Converting object to string.");
|
||||
return PSObject.ToStringParser(ecFromTLS, valueToConvert);
|
||||
return PSObject.ToStringParser(ecFromTLS, valueToConvert, formatProvider);
|
||||
}
|
||||
catch (ExtendedTypeSystemException e)
|
||||
{
|
||||
|
|
|
@ -1149,10 +1149,31 @@ namespace System.Management.Automation
|
|||
/// When there is a brokered ToString but it failed, or when the ToString on obj throws an exception.
|
||||
/// </exception>
|
||||
internal static string ToStringParser(ExecutionContext context, object obj)
|
||||
{
|
||||
return ToStringParser(context, obj, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the string representation of obj.
|
||||
/// </summary>
|
||||
/// <param name="context">ExecutionContext used to fetch the separator. </param>
|
||||
/// <param name="obj">
|
||||
/// object we are trying to call ToString on. If this is not an PSObject we try
|
||||
/// enumerating and if that fails we call obj.ToString.
|
||||
/// If this is an PSObject, we look for a brokered ToString.
|
||||
/// If it is not present, and the BaseObject is null we try listing the properties.
|
||||
/// If the BaseObject is not null we try enumerating. If that fails we try the BaseObject's ToString.
|
||||
/// </param>
|
||||
/// <param name="formatProvider">The formatProvider to be passed to ToString.</param>
|
||||
/// <returns>A string representation of the object.</returns>
|
||||
/// <exception cref="ExtendedTypeSystemException">
|
||||
/// When there is a brokered ToString but it failed, or when the ToString on obj throws an exception.
|
||||
/// </exception>
|
||||
internal static string ToStringParser(ExecutionContext context, object obj, IFormatProvider formatProvider)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ToString(context, obj, null, null, CultureInfo.InvariantCulture, true, true);
|
||||
return ToString(context, obj, null, null, formatProvider, true, true);
|
||||
}
|
||||
catch (ExtendedTypeSystemException etse)
|
||||
{
|
||||
|
|
|
@ -368,7 +368,7 @@ namespace System.Management.Automation.Language
|
|||
internal static readonly FieldInfo PSObject_isDeserialized =
|
||||
typeof(PSObject).GetField(nameof(PSObject.isDeserialized), instanceFlags);
|
||||
internal static readonly MethodInfo PSObject_ToStringParser =
|
||||
typeof(PSObject).GetMethod(nameof(PSObject.ToStringParser), staticFlags);
|
||||
typeof(PSObject).GetMethod(nameof(PSObject.ToStringParser), staticFlags, null, new[]{typeof(ExecutionContext), typeof(object)}, null);
|
||||
|
||||
internal static readonly PropertyInfo PSReference_Value =
|
||||
typeof(PSReference).GetProperty(nameof(PSReference.Value));
|
||||
|
@ -1535,7 +1535,7 @@ namespace System.Management.Automation.Language
|
|||
|
||||
if (attribute is ExperimentalAttribute expAttribute)
|
||||
{
|
||||
// Only honor the first seen experimental attribute, ignore the others.
|
||||
// Only honor the first seen experimental attribute, ignore the others.
|
||||
if (!hasSeenExpAttribute && expAttribute.ToHide) { return null; }
|
||||
|
||||
// Do not add experimental attributes to the attribute list.
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
Describe "Join-String" -Tags "CI" {
|
||||
|
||||
BeforeAll {
|
||||
$testObject = Get-ChildItem
|
||||
}
|
||||
|
||||
It "Should be called using the InputObject without error with no other switches" {
|
||||
{ Join-String -InputObject $testObject } | Should -Not -Throw
|
||||
}
|
||||
|
||||
It "Should return a single string" {
|
||||
$actual = $testObject | Join-String
|
||||
|
||||
$actual.Count | Should -Be 1
|
||||
$actual | Should -BeOfType System.String
|
||||
}
|
||||
|
||||
It "Should join property values with default separator" {
|
||||
$expected = $testObject.Name -join $ofs
|
||||
$actual = $testObject | Join-String -Property Name
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should join property values positionally with default separator" {
|
||||
$expected = $testObject.Name -join $ofs
|
||||
$actual = $testObject | Join-String Name
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should join property values with custom Separator" {
|
||||
$expected = $testObject.Name -join "; "
|
||||
$actual = $testObject | Join-String -Property Name -Separator "; "
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should join property values SingleQuoted" {
|
||||
$expected = ($testObject.Name).Foreach{"'$_'"} -join "; "
|
||||
$actual = $testObject | Join-String -Property Name -Separator "; " -SingleQuote
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should join property values DoubleQuoted" {
|
||||
$expected = ($testObject.Name).Foreach{"""$_"""} -join "; "
|
||||
$actual = $testObject | Join-String -Property Name -Separator "; " -DoubleQuote
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should join property values Formatted" {
|
||||
$expected = ($testObject.Name).Foreach{"[$_]"} -join "; "
|
||||
$actual = $testObject | Join-String -Property Name -Separator "; " -Format "[{0}]"
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should join script block results with default separator" {
|
||||
$sb = {$_.Name + $_.Length}
|
||||
$expected = ($testObject | ForEach-Object $sb) -join $ofs
|
||||
$actual = $testObject | Join-String -Property $sb
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should join script block results with custom separator" {
|
||||
$sb = {$_.Name + $_.Length}
|
||||
$expected = ($testObject | ForEach-Object $sb) -join "; "
|
||||
$actual = $testObject | Join-String -Property $sb -Separator "; "
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should join script block results SingleQuoted" {
|
||||
$sb = {$_.Name + $_.Length}
|
||||
$expected = ($testObject | ForEach-Object $sb).Foreach{"'$_'"} -join $ofs
|
||||
$actual = $testObject | Join-String -Property $sb -SingleQuote
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
It "Should join script block results DoubleQuoted" {
|
||||
$sb = {$_.Name + $_.Length}
|
||||
$expected = ($testObject | ForEach-Object $sb).Foreach{"""$_"""} -join $ofs
|
||||
$actual = $testObject | Join-String -Property $sb -DoubleQuote
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should join script block results with Format and separator" {
|
||||
$sb = {$_.Name + $_.Length}
|
||||
$expected = ($testObject | ForEach-Object $sb).Foreach{"[{0}]" -f $_} -join "; "
|
||||
$actual = $testObject | Join-String -Property $sb -Separator "; " -Format "[{0}]"
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should Handle OutputPrefix and OutputSuffix" {
|
||||
$ofs = ','
|
||||
$expected = "A 1,2,3 B"
|
||||
$actual = 1..3 | Join-String -OutputPrefix "A " -OutputSuffix " B"
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should handle null separator" {
|
||||
$expected = -join 'hello'.tochararray()
|
||||
$actual = "hello" | Join-String -separator $null
|
||||
$actual | Should -BeExactly $expected
|
||||
}
|
||||
|
||||
It "Should tabcomplete InputObject properties" {
|
||||
$cmd = '[io.fileinfo]::new("c:\temp") | Join-String -Property '
|
||||
$res = tabexpansion2 $cmd $cmd.length
|
||||
$completionTexts = $res.CompletionMatches.CompletionText
|
||||
$Propertys = [io.fileinfo]::new($PSScriptRoot).psobject.properties.Name
|
||||
foreach ($n in $Propertys) {
|
||||
$n -in $completionTexts | Should -BeTrue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -320,6 +320,7 @@ Describe "Verify approved aliases list" -Tags "CI" {
|
|||
"Cmdlet", "Invoke-WmiMethod", , $($FullCLR )
|
||||
"Cmdlet", "Invoke-WSManAction", , $($FullCLR -or $CoreWindows )
|
||||
"Cmdlet", "Join-Path", , $($FullCLR -or $CoreWindows -or $CoreUnix)
|
||||
"Cmdlet", "Join-String", , $( $CoreWindows -or $CoreUnix)
|
||||
"Cmdlet", "Limit-EventLog", , $($FullCLR )
|
||||
"Cmdlet", "Measure-Command", , $($FullCLR -or $CoreWindows -or $CoreUnix)
|
||||
"Cmdlet", "Measure-Object", , $($FullCLR -or $CoreWindows -or $CoreUnix)
|
||||
|
|
Loading…
Reference in a new issue