Format-Hex: Improve mixed-collection piped input and piped streams of input (#8674)

This commit is contained in:
Joel Sallow (/u/ta11ow)
2019-10-15 11:04:45 -07:00
committed by Andrew
parent beb8b44420
commit 2e951793af
4 changed files with 614 additions and 362 deletions
@@ -17,12 +17,30 @@ namespace Microsoft.PowerShell.Commands
/// Displays the hexadecimal equivalent of the input data.
/// </summary>
[Cmdlet(VerbsCommon.Format, "Hex", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=526919")]
[OutputType(typeof(Microsoft.PowerShell.Commands.ByteCollection))]
[OutputType(typeof(ByteCollection))]
[Alias("fhx")]
public sealed class FormatHex : PSCmdlet
{
private const int BUFFERSIZE = 16;
/// <summary>
/// For cases where a homogenous collection of bytes or other items are directly piped in, we collect all the
/// bytes in a List&lt;byte&gt; and then output the formatted result all at once in EndProcessing().
/// </summary>
private readonly List<byte> _inputBuffer = new List<byte>();
/// <summary>
/// Expect to group <see cref="InputObject"/>s by default. When receiving input that should not be grouped,
/// e.g., arrays, strings, FileInfo objects, this flag will be disabled until the next groupable
/// <see cref="InputObject"/> is received over the pipeline.
/// </summary>
private bool _groupInput = true;
/// <summary>
/// Keep track of prior input types to determine if we're given a heterogenous collection.
/// </summary>
private Type _lastInputType;
#region Parameters
/// <summary>
@@ -85,19 +103,28 @@ namespace Microsoft.PowerShell.Commands
/// </summary>
protected override void ProcessRecord()
{
if (string.Equals(this.ParameterSetName, "ByInputObject", StringComparison.OrdinalIgnoreCase))
if (string.Equals(ParameterSetName, "ByInputObject", StringComparison.OrdinalIgnoreCase))
{
ProcessObjectContent(InputObject);
ProcessInputObjects(InputObject);
}
else
{
List<string> pathsToProcess = string.Equals(this.ParameterSetName, "LiteralPath", StringComparison.OrdinalIgnoreCase) ?
ResolvePaths(LiteralPath, true) : ResolvePaths(Path, false);
List<string> pathsToProcess = string.Equals(ParameterSetName, "LiteralPath", StringComparison.OrdinalIgnoreCase)
? ResolvePaths(LiteralPath, true)
: ResolvePaths(Path, false);
ProcessPath(pathsToProcess);
}
}
/// <summary>
/// Implements the EndProcessing method for the FormatHex command.
/// </summary>
protected override void EndProcessing()
{
FlushInputBuffer();
}
#endregion
#region Paths
@@ -114,7 +141,6 @@ namespace Microsoft.PowerShell.Commands
{
List<string> pathsToProcess = new List<string>();
ProviderInfo provider = null;
PSDriveInfo drive = null;
foreach (string currentPath in path)
{
@@ -122,7 +148,7 @@ namespace Microsoft.PowerShell.Commands
if (literalPath)
{
newPaths.Add(Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(currentPath, out provider, out drive));
newPaths.Add(Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(currentPath, out provider, out _));
}
else
{
@@ -183,34 +209,32 @@ namespace Microsoft.PowerShell.Commands
try
{
using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read)))
using var reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read));
long offset = Offset;
int bytesRead = 0;
long count = 0;
reader.BaseStream.Position = Offset;
while ((bytesRead = reader.Read(buffer)) > 0)
{
long offset = Offset;
int bytesRead = 0;
long count = 0;
reader.BaseStream.Position = Offset;
while ((bytesRead = reader.Read(buffer)) > 0)
count += bytesRead;
if (count > Count)
{
count += bytesRead;
if (count > Count)
{
bytesRead -= (int)(count - Count);
WriteHexadecimal(buffer.Slice(0, bytesRead), path, offset);
break;
}
bytesRead -= (int)(count - Count);
WriteHexadecimal(buffer.Slice(0, bytesRead), path, offset);
offset += bytesRead;
break;
}
WriteHexadecimal(buffer.Slice(0, bytesRead), path, offset);
offset += bytesRead;
}
}
catch (IOException ioException)
catch (IOException fileException)
{
// IOException takes care of FileNotFoundException, DirectoryNotFoundException, and PathTooLongException
WriteError(new ErrorRecord(ioException, "FormatHexIOError", ErrorCategory.WriteError, path));
WriteError(new ErrorRecord(fileException, "FormatHexIOError", ErrorCategory.WriteError, path));
}
catch (ArgumentException argException)
{
@@ -218,11 +242,19 @@ namespace Microsoft.PowerShell.Commands
}
catch (NotSupportedException notSupportedException)
{
WriteError(new ErrorRecord(notSupportedException, "FormatHexPathRefersToANonFileDevice", ErrorCategory.InvalidArgument, path));
WriteError(new ErrorRecord(
notSupportedException,
"FormatHexPathRefersToANonFileDevice",
ErrorCategory.InvalidArgument,
path));
}
catch (SecurityException securityException)
{
WriteError(new ErrorRecord(securityException, "FormatHexUnauthorizedAccessError", ErrorCategory.PermissionDenied, path));
WriteError(new ErrorRecord(
securityException,
"FormatHexUnauthorizedAccessError",
ErrorCategory.PermissionDenied,
path));
}
}
@@ -230,37 +262,95 @@ namespace Microsoft.PowerShell.Commands
#region InputObjects
private void ProcessString(string originalString)
{
Span<byte> bytes = Encoding.GetBytes(originalString);
int offset = Math.Min(bytes.Length, Offset < int.MaxValue ? (int)Offset : int.MaxValue);
int count = Math.Min(bytes.Length - offset, Count < int.MaxValue ? (int)Count : int.MaxValue);
if (offset != 0 || count != bytes.Length)
{
WriteHexadecimal(bytes.Slice(offset, count), offset: 0, label: GetGroupLabel(typeof(string)));
}
else
{
WriteHexadecimal(bytes, offset: 0, label: GetGroupLabel(typeof(string)));
}
}
private static readonly Random _idGenerator = new Random();
private static string GetGroupLabel(Type inputType)
=> string.Format("{0} ({1}) <{2:X8}>", inputType.Name, inputType.FullName, _idGenerator.Next());
private void FlushInputBuffer()
{
if (_inputBuffer.Count == 0)
{
return;
}
int offset = Math.Min(_inputBuffer.Count, Offset < int.MaxValue ? (int)Offset : int.MaxValue);
int count = Math.Min(_inputBuffer.Count - offset, Count < int.MaxValue ? (int)Count : int.MaxValue);
if (offset != 0 || count != _inputBuffer.Count)
{
WriteHexadecimal(
_inputBuffer.GetRange(offset, count).ToArray(),
offset: 0,
label: GetGroupLabel(_lastInputType));
}
else
{
WriteHexadecimal(
_inputBuffer.ToArray(),
offset: 0,
label: GetGroupLabel(_lastInputType));
}
// Reset flags so we can go back to filling up the buffer when needed.
_lastInputType = null;
_groupInput = true;
_inputBuffer.Clear();
}
/// <summary>
/// Creates a byte array from the object passed to the cmdlet (based on type) and passes
/// that array on to the WriteHexadecimal method to output.
/// </summary>
/// <param name="inputObject">The pipeline input object being processed.</param>
private void ProcessObjectContent(PSObject inputObject)
private void ProcessInputObjects(PSObject inputObject)
{
object obj = inputObject.BaseObject;
if (obj is System.IO.FileSystemInfo fsi)
if (obj is FileSystemInfo fsi)
{
// Output already processed objects first, then process the file input.
FlushInputBuffer();
string[] path = { fsi.FullName };
List<string> pathsToProcess = ResolvePaths(path, true);
ProcessPath(pathsToProcess);
return;
}
byte[] inputBytes = ConvertToByteArray(obj);
if (obj is string str)
{
// Output already processed objects first, then process the string input.
FlushInputBuffer();
ProcessString(str);
return;
}
byte[] inputBytes = ConvertToBytes(obj);
if (!_groupInput)
{
FlushInputBuffer();
}
if (inputBytes != null)
{
int offset = Math.Min(inputBytes.Length, Offset < (long)int.MaxValue ? (int)Offset : int.MaxValue);
int count = Math.Min(inputBytes.Length - offset, Count < (long)int.MaxValue ? (int)Count : int.MaxValue);
if (offset != 0 || count != inputBytes.Length)
{
WriteHexadecimal(inputBytes.AsSpan().Slice(offset, count), null, 0);
}
else
{
WriteHexadecimal(inputBytes, null, 0);
}
_inputBuffer.AddRange(inputBytes);
}
else
{
@@ -280,14 +370,9 @@ namespace Microsoft.PowerShell.Commands
/// </summary>
/// <param name="inputObject">The object to convert.</param>
/// <returns>Returns a byte array of the input values, or null if there is no available conversion path.</returns>
private byte[] ConvertToByteArray(object inputObject)
private byte[] ConvertToBytes(object inputObject)
{
if (inputObject is string str)
{
return Encoding.GetBytes(str);
}
var baseType = inputObject.GetType();
Type baseType = inputObject.GetType();
byte[] result = null;
int elements = 1;
bool isArray = false;
@@ -295,6 +380,10 @@ namespace Microsoft.PowerShell.Commands
bool isEnum = false;
if (baseType.IsArray)
{
FlushInputBuffer();
_lastInputType = baseType;
_groupInput = false;
baseType = baseType.GetElementType();
dynamic dynamicObject = inputObject;
elements = (int)dynamicObject.Length;
@@ -309,6 +398,16 @@ namespace Microsoft.PowerShell.Commands
if (baseType.IsPrimitive && elements > 0)
{
if (_groupInput)
{
if (_lastInputType != null && baseType != _lastInputType)
{
_groupInput = false;
}
_lastInputType = baseType;
}
if (baseType == typeof(bool))
{
isBool = true;
@@ -364,21 +463,44 @@ namespace Microsoft.PowerShell.Commands
#region Output
/// <summary>
/// Outputs the hexadecimial representation of the input data.
/// Outputs the hexadecimal representation of the input data.
/// </summary>
/// <param name="inputBytes">Bytes for the hexadecimial representation.</param>
/// <param name="inputBytes">Bytes for the hexadecimal representation.</param>
/// <param name="path">File path.</param>
/// <param name="offset">Offset in the file.</param>
private void WriteHexadecimal(Span<byte> inputBytes, string path, long offset)
{
ByteCollection byteCollectionObject = new ByteCollection((ulong)offset, inputBytes.ToArray(), path);
WriteObject(byteCollectionObject);
var bytesPerObject = 16;
for (int index = 0; index < inputBytes.Length; index += bytesPerObject)
{
var count = inputBytes.Length - index < bytesPerObject
? inputBytes.Length - index
: bytesPerObject;
var bytes = inputBytes.Slice(index, count);
WriteObject(new ByteCollection((ulong)index + (ulong)offset, bytes.ToArray(), path));
}
}
private void WriteHexadecimal(byte[] inputBytes, string path, long offset)
/// <summary>
/// Outputs the hexadecimal representation of the input data.
/// </summary>
/// <param name="inputBytes">Bytes for the hexadecimal representation.</param>
/// <param name="offset">Offset in the file.</param>
/// <param name="label">
/// The label for the byte group. This may be a file path, a string value, or a
/// formatted identifying string for the group.
/// </param>
private void WriteHexadecimal(Span<byte> inputBytes, long offset, string label)
{
ByteCollection byteCollectionObject = new ByteCollection((ulong)offset, inputBytes, path);
WriteObject(byteCollectionObject);
var bytesPerObject = 16;
for (int index = 0; index < inputBytes.Length; index += bytesPerObject)
{
var count = inputBytes.Length - index < bytesPerObject
? inputBytes.Length - index
: bytesPerObject;
var bytes = inputBytes.Slice(index, count);
WriteObject(new ByteCollection((ulong)index + (ulong)offset, label, bytes.ToArray()));
}
}
#endregion
@@ -95,26 +95,24 @@ namespace Microsoft.PowerShell.Commands
public class ByteCollection
{
/// <summary>
/// ByteCollection constructor.
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
/// </summary>
/// <param name="offset">The Offset address to be used while displaying the bytes in the collection.</param>
/// <param name="value">Underlying bytes stored in the collection.</param>
/// <param name="path">Indicates the path of the file whose contents are wrapped in the ByteCollection.</param>
[Obsolete("The constructor is deprecated.", true)]
public ByteCollection(UInt32 offset, byte[] value, string path)
public ByteCollection(uint offset, byte[] value, string path)
: this((ulong)offset, value, path)
{
Offset64 = offset;
Bytes = value;
Path = path;
}
/// <summary>
/// Initializes a new instance of ByteCollection.
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
/// </summary>
/// <param name="offset">The Offset address to be used while displaying the bytes in the collection.</param>
/// <param name="value">Underlying bytes stored in the collection.</param>
/// <param name="path">Indicates the path of the file whose contents are wrapped in the ByteCollection.</param>
public ByteCollection(UInt64 offset, byte[] value, string path)
public ByteCollection(ulong offset, byte[] value, string path)
{
if (value == null)
{
@@ -124,31 +122,26 @@ namespace Microsoft.PowerShell.Commands
Offset64 = offset;
Bytes = value;
Path = path;
Label = path;
}
/// <summary>
/// ByteCollection constructor.
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
/// </summary>
/// <param name="offset">The Offset address to be used while displaying the bytes in the collection.</param>
/// <param name="value">Underlying bytes stored in the collection.</param>
[Obsolete("The constructor is deprecated.", true)]
public ByteCollection(UInt32 offset, byte[] value)
public ByteCollection(uint offset, byte[] value)
: this((ulong)offset, value)
{
if (value == null)
{
throw PSTraceSource.NewArgumentNullException("value");
}
Offset64 = offset;
Bytes = value;
}
/// <summary>
/// ByteCollection constructor.
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
/// </summary>
/// <param name="offset">The Offset address to be used while displaying the bytes in the collection.</param>
/// <param name="value">Underlying bytes stored in the collection.</param>
public ByteCollection(UInt64 offset, byte[] value)
public ByteCollection(ulong offset, byte[] value)
{
if (value == null)
{
@@ -160,7 +153,21 @@ namespace Microsoft.PowerShell.Commands
}
/// <summary>
/// ByteCollection constructor.
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
/// </summary>
/// <param name="offset">The Offset address to be used while displaying the bytes in the collection.</param>
/// <param name="label">
/// The label for the byte group. This may be a file path or a formatted identifying string for the group.
/// </param>
/// <param name="value">Underlying bytes stored in the collection.</param>
public ByteCollection(ulong offset, string label, byte[] value)
: this(offset, value)
{
Label = label;
}
/// <summary>
/// Initializes a new instance of the <see cref="ByteCollection"/> class.
/// </summary>
/// <param name="value">Underlying bytes stored in the collection.</param>
public ByteCollection(byte[] value)
@@ -206,6 +213,82 @@ namespace Microsoft.PowerShell.Commands
/// </summary>
public string Path { get; private set; }
/// <summary>
/// Gets the hexadecimal representation of the <see cref="Offset64"/> value.
/// </summary>
public string HexOffset { get => string.Format(CultureInfo.CurrentCulture, "{0:X16}", Offset64); }
/// <summary>
/// Gets the type of the input objects used to create the <see cref="ByteCollection"/>.
/// </summary>
public string Label { get; private set; }
private const int BytesPerLine = 16;
private string _hexBytes = string.Empty;
/// <summary>
/// Gets a space-delimited string of the <see cref="Bytes"/> in this <see cref="ByteCollection"/>
/// in hexadecimal format.
/// </summary>
public string HexBytes
{
get
{
if (_hexBytes == string.Empty)
{
StringBuilder line = new StringBuilder(BytesPerLine * 3);
foreach (var currentByte in Bytes)
{
line.AppendFormat(CultureInfo.CurrentCulture, "{0:X2} ", currentByte);
}
_hexBytes = line.ToString().Trim();
}
return _hexBytes;
}
}
private string _ascii = string.Empty;
/// <summary>
/// Gets the ASCII string representation of the <see cref="Bytes"/> in this <see cref="ByteCollection"/>.
/// </summary>
/// <value></value>
public string Ascii
{
get
{
if (_ascii == string.Empty)
{
StringBuilder ascii = new StringBuilder(BytesPerLine);
foreach (var currentByte in Bytes)
{
var currentChar = (char)currentByte;
if (currentChar == 0x0)
{
ascii.Append(' ');
}
else if (char.IsControl(currentChar))
{
ascii.Append((char)0xFFFD);
}
else
{
ascii.Append(currentChar);
}
}
_ascii = ascii.ToString();
}
return _ascii;
}
}
/// <summary>
/// Displays the hexadecimal format of the bytes stored in the collection.
/// </summary>
@@ -213,11 +296,11 @@ namespace Microsoft.PowerShell.Commands
public override string ToString()
{
const int BytesPerLine = 16;
const string LineFormat = "{0:X20} ";
const string LineFormat = "{0:X16} ";
// '20 + 3' comes from format "{0:X20} ".
// '20' comes from '[Uint64]::MaxValue.ToString().Length'.
StringBuilder nextLine = new StringBuilder(20 + 3 + (BytesPerLine * 3));
// '16 + 3' comes from format "{0:X16} ".
// '16' comes from '[Uint64]::MaxValue.ToString("X").Length'.
StringBuilder nextLine = new StringBuilder(16 + 3 + (BytesPerLine * 3));
StringBuilder asciiEnd = new StringBuilder(BytesPerLine);
// '+1' comes from 'result.Append(nextLine.ToString() + " " + asciiEnd.ToString());' below.
@@ -225,10 +308,8 @@ namespace Microsoft.PowerShell.Commands
if (Bytes.Length > 0)
{
Int64 charCounter = 0;
long charCounter = 0;
// ToString() in invoked thrice by the F&O for the same content.
// Hence making sure that Offset is not getting incremented thrice for the same bytes being displayed.
var currentOffset = Offset64;
nextLine.AppendFormat(CultureInfo.InvariantCulture, LineFormat, currentOffset);
@@ -240,13 +321,18 @@ namespace Microsoft.PowerShell.Commands
// If the character is printable, add its ascii representation to
// the right-hand side. Otherwise, add a dot to the right hand side.
if ((currentByte >= 0x20) && (currentByte <= 0xFE))
var currentChar = (char)currentByte;
if (currentChar == 0x0)
{
asciiEnd.Append((char)currentByte);
asciiEnd.Append(' ');
}
else if (char.IsControl(currentChar))
{
asciiEnd.Append((char)0xFFFD);
}
else
{
asciiEnd.Append('.');
asciiEnd.Append(currentChar);
}
charCounter++;
@@ -262,7 +348,7 @@ namespace Microsoft.PowerShell.Commands
nextLine.AppendFormat(CultureInfo.InvariantCulture, LineFormat, currentOffset);
// Adding a newline to support long inputs strings flowing through InputObject parameterset.
if ((charCounter <= Bytes.Length) && string.IsNullOrEmpty(this.Path))
if ((charCounter <= Bytes.Length) && string.IsNullOrEmpty(Path))
{
result.AppendLine();
}
@@ -18,22 +18,8 @@ namespace System.Management.Automation.Runspaces
.EndEntry()
.EndControl();
var ByteCollection_GroupHeader = CustomControl.Create()
.StartEntry()
.StartFrame()
.AddScriptBlockExpressionBinding(@"
$header = "" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F""
if($_.Path) { $header = "" "" + [Microsoft.PowerShell.Commands.UtilityResources]::FormatHexPathPrefix + $_.Path + ""`r`n`r`n"" + $header }
$header
")
.EndFrame()
.EndEntry()
.EndControl();
var sharedControls = new CustomControl[] {
AvailableModules_GroupingFormat,
ByteCollection_GroupHeader
AvailableModules_GroupingFormat
};
yield return new ExtendedTypeDefinition(
@@ -167,10 +153,6 @@ namespace System.Management.Automation.Runspaces
"System.Management.Automation.InformationRecord",
ViewsOf_System_Management_Automation_InformationRecord());
yield return new ExtendedTypeDefinition(
"Microsoft.PowerShell.Commands.ByteCollection",
ViewsOf_Microsoft_PowerShell_Commands_ByteCollection(sharedControls));
yield return new ExtendedTypeDefinition(
"System.Exception",
ViewsOf_System_Exception());
@@ -254,6 +236,10 @@ namespace System.Management.Automation.Runspaces
yield return new ExtendedTypeDefinition(
"Microsoft.PowerShell.MarkdownRender.PSMarkdownOptionInfo",
ViewsOf_Microsoft_PowerShell_MarkdownRender_MarkdownOptionInfo());
yield return new ExtendedTypeDefinition(
"Microsoft.PowerShell.Commands.ByteCollection",
ViewsOf_Microsoft_PowerShell_Commands_ByteCollection());
}
private static IEnumerable<FormatViewDefinition> ViewsOf_System_RuntimeType()
@@ -1077,19 +1063,6 @@ namespace System.Management.Automation.Runspaces
.EndControl());
}
private static IEnumerable<FormatViewDefinition> ViewsOf_Microsoft_PowerShell_Commands_ByteCollection(CustomControl[] sharedControls)
{
yield return new FormatViewDefinition("ByteCollection",
CustomControl.Create()
.GroupByScriptBlock("if($_.Path) { $_.Path } else { $_.GetHashCode() }", customControl: sharedControls[1])
.StartEntry()
.StartFrame()
.AddScriptBlockExpressionBinding(@"$_.ToString()")
.EndFrame()
.EndEntry()
.EndControl());
}
private static IEnumerable<FormatViewDefinition> ViewsOf_System_Exception()
{
yield return new FormatViewDefinition("Exception",
@@ -1630,5 +1603,22 @@ namespace System.Management.Automation.Runspaces
.EndEntry()
.EndList());
}
private static IEnumerable<FormatViewDefinition> ViewsOf_Microsoft_PowerShell_Commands_ByteCollection()
{
yield return new FormatViewDefinition(
"Microsoft.PowerShell.Commands.ByteCollection",
TableControl.Create()
.AddHeader(Alignment.Right, label: "Offset", width: 16)
.AddHeader(Alignment.Left, label: "Bytes\n00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F", width: 47)
.AddHeader(Alignment.Left, label: "Ascii", width: 16)
.StartRowDefinition()
.AddPropertyColumn("HexOffset")
.AddPropertyColumn("HexBytes")
.AddPropertyColumn("Ascii")
.EndRowDefinition()
.GroupByProperty("Label")
.EndTable());
}
}
}
@@ -6,10 +6,8 @@
<#
Purpose:
Verify Format-Hex displays the Hexadecimal value for the input data.
Action:
Run Format-Hex.
Expected Result:
Hexadecimal equivalent of the input data is displayed.
#>
@@ -21,21 +19,27 @@ Describe "FormatHex" -tags "CI" {
$newline = [Environment]::Newline
Setup -d FormatHexDataDir
$inputFile1 = New-Item -Path "$TestDrive/SourceFile-1.txt"
$inputText1 = 'Hello World'
Set-Content -LiteralPath $inputFile1.FullName -Value $inputText1 -NoNewline
$inputFile2 = New-Item -Path "$TestDrive/SourceFile-2.txt"
$inputText2 = 'More text'
Set-Content -LiteralPath $inputFile2.FullName -Value $inputText2 -NoNewline
$inputFile3 = New-Item -Path "$TestDrive/SourceFile literal [3].txt"
$inputText3 = 'Literal path'
Set-Content -LiteralPath $inputFile3.FullName -Value $inputText3 -NoNewline
$inputFile4 = New-Item -Path "$TestDrive/SourceFile-4.txt"
$inputText4 = 'Now is the winter of our discontent'
$inputFile1 = setup -f "FormatHexDataDir/SourceFile-1.txt" -content $inputText1 -pass
$inputFile2 = setup -f "FormatHexDataDir/SourceFile-2.txt" -content $inputText2 -pass
$inputFile3 = setup -f "FormatHexDataDir/SourceFile literal [3].txt" -content $inputText3 -pass
$inputFile4 = setup -f "FormatHexDataDir/SourceFile-4.txt" -content $inputText4 -pass
Set-Content -LiteralPath $inputFile4.FullName -Value $inputText4 -NoNewline
$certificateProvider = Get-ChildItem Cert:\CurrentUser\My\ -ErrorAction SilentlyContinue
$thumbprint = $null
$certProviderAvailable = $false
if ($certificateProvider.Count -gt 0)
{
if ($certificateProvider.Count -gt 0) {
$thumbprint = $certificateProvider[0].Thumbprint
$certProviderAvailable = $true
}
@@ -44,100 +48,90 @@ Describe "FormatHex" -tags "CI" {
}
Context "InputObject Paramater" {
BeforeAll {
enum TestEnum {
TestOne = 1; TestTwo = 2; TestThree = 3; TestFour = 4
}
Add-Type -TypeDefinition @'
public enum TestSByteEnum : sbyte {
One = -1,
Two = -2,
Three = -3,
Four = -4
}
'@
}
$testCases = @(
@{
Name = "Can process byte type 'fhx -InputObject [byte]5'"
InputObject = [byte]5
Count = 1
Name = "Can process byte type 'fhx -InputObject [byte]5'"
InputObject = [byte]5
Count = 1
ExpectedResult = "00000000 05"
}
@{
Name = "Can process byte[] type 'fhx -InputObject [byte[]](1,2,3,4,5)'"
InputObject = [byte[]](1,2,3,4,5)
Count = 1
Name = "Can process byte[] type 'fhx -InputObject [byte[]](1,2,3,4,5)'"
InputObject = [byte[]](1, 2, 3, 4, 5)
Count = 1
ExpectedResult = "00000000 01 02 03 04 05 ....."
}
@{
Name = "Can process int type 'fhx -InputObject 7'"
InputObject = 7
Count = 1
Name = "Can process int type 'fhx -InputObject 7'"
InputObject = 7
Count = 1
ExpectedResult = "00000000 07 00 00 00 ...."
}
@{
Name = "Can process int[] type 'fhx -InputObject [int[]](5,6,7,8)'"
InputObject = [int[]](5,6,7,8)
Count = 1
Name = "Can process int[] type 'fhx -InputObject [int[]](5,6,7,8)'"
InputObject = [int[]](5, 6, 7, 8)
Count = 1
ExpectedResult = "00000000 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 ................"
}
@{
Name = "Can process int32 type 'fhx -InputObject [int32]2032'"
InputObject = [int32]2032
Count = 1
Name = "Can process int32 type 'fhx -InputObject [int32]2032'"
InputObject = [int32]2032
Count = 1
ExpectedResult = "00000000 F0 07 00 00 ð..."
}
@{
Name = "Can process int32[] type 'fhx -InputObject [int32[]](2032, 2033, 2034)'"
InputObject = [int32[]](2032, 2033, 2034)
Count = 1
ExpectedResult = "00000000000000000000 F0 07 00 00 F1 07 00 00 F2 07 00 00 ð...ñ...ò..."
Name = "Can process int32[] type 'fhx -InputObject [int32[]](2032, 2033, 2034)'"
InputObject = [int32[]](2032, 2033, 2034)
Count = 1
ExpectedResult = "0000000000000000 F0 07 00 00 F1 07 00 00 F2 07 00 00 ð...ñ...ò..."
}
@{
Name = "Can process Int64 type 'fhx -InputObject [Int64]9223372036854775807'"
InputObject = [Int64]9223372036854775807
Count = 1
ExpectedResult = "00000000000000000000 FF FF FF FF FF FF FF 7F ......."
Name = "Can process Int64 type 'fhx -InputObject [Int64]9223372036854775807'"
InputObject = [Int64]9223372036854775807
Count = 1
ExpectedResult = "0000000000000000 FF FF FF FF FF FF FF 7F ÿÿÿÿÿÿÿ�"
}
@{
Name = "Can process Int64[] type 'fhx -InputObject [Int64[]](9223372036852,9223372036853)'"
InputObject = [Int64[]](9223372036852,9223372036853)
Count = 1
ExpectedResult = "00000000000000000000 F4 5A D0 7B 63 08 00 00 F5 5A D0 7B 63 08 00 00 ôZÐ{c...õZÐ{c..."
Name = "Can process Int64[] type 'fhx -InputObject [Int64[]](9223372036852,9223372036853)'"
InputObject = [Int64[]](9223372036852, 9223372036853)
Count = 1
ExpectedResult = "0000000000000000 F4 5A D0 7B 63 08 00 00 F5 5A D0 7B 63 08 00 00 ôZÐ{c...õZÐ{c..."
}
@{
Name = "Can process string type 'fhx -InputObject hello world'"
InputObject = "hello world"
Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F 20 77 6F 72 6C 64 hello world"
Name = "Can process string type 'fhx -InputObject hello world'"
InputObject = "hello world"
Count = 1
ExpectedResult = "0000000000000000 68 65 6C 6C 6F 20 77 6F 72 6C 64 hello world"
}
@{
Name = "Can process enum type 'fhx -InputObject ([DisplayHintType]::DateTime)'"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType]::DateTime
Count = 1
ExpectedResult = "00000000000000000000 02 00 00 00 ...."
Name = "Can process PS-native enum array '[TestEnum[]]('TestOne', 'TestTwo', 'TestThree', 'TestFour') | fhx'"
InputObject = [TestEnum[]]('TestOne', 'TestTwo', 'TestThree', 'TestFour')
Count = 1
ExpectedResult = "0000000000000000 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ................"
}
@{
Name = "Can process DisplayHintType[] type 'fhx -InputObject ([DisplayHintType[]](DateTime, Time))'"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType[]]([Microsoft.PowerShell.Commands.DisplayHintType]::DateTime)
Count = 1
ExpectedResult = "00000000000000000000 02 00 00 00 ...."
}
@{
Name = "Can process DisplayHintType[] type 'fhx -InputObject ([DisplayHintType[]](DateTime, Time))'"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType[]]([Microsoft.PowerShell.Commands.DisplayHintType]::DateTime, [Microsoft.PowerShell.Commands.DisplayHintType]::Time)
Count = 1
ExpectedResult = "00000000000000000000 02 00 00 00 01 00 00 00 ........"
}
@{
Name = "Can process char type 'fhx -InputObject ([char]`'A`')'"
InputObject = [char]'A'
Count = 1
ExpectedResult = "00000000000000000000 41 A"
}
@{
Name = "Can process char[] type 'fhx -InputObject ([char[]](`'A`'))'"
InputObject = [char[]]('A')
Count = 1
ExpectedResult = "00000000000000000000 41 A"
}
@{
Name = "Can process char[] type 'fhx -InputObject ([char[]](`'A`', 'B'))'"
InputObject = [char[]]('A', 'B')
Count = 1
ExpectedResult = "00000000000000000000 41 42 AB"
Name = "Can process C#-native sbyte enum array '[TestSByteEnum[]]('One', 'Two', 'Three', 'Four') | fhx'"
InputObject = [TestSByteEnum[]]('One', 'Two', 'Three', 'Four')
Count = 1
ExpectedResult = "0000000000000000 FF FE FD FC .þýü"
}
)
It "<Name>" -TestCase $testCases{
It "<Name>" -TestCase $testCases {
param ($Name, $InputObject, $Count, $ExpectedResult)
@@ -150,120 +144,167 @@ Describe "FormatHex" -tags "CI" {
}
Context "InputObject From Pipeline" {
BeforeAll {
enum TestEnum {
TestOne = 1; TestTwo = 2; TestThree = 3; TestFour = 4
}
Add-Type -TypeDefinition @'
public enum TestSByteEnum : sbyte {
One = -1,
Two = -2,
Three = -3,
Four = -4
}
'@
}
$testCases = @(
@{
Name = "Can process byte type '[byte]5 | fhx'"
InputObject = [byte]5
Count = 1
ExpectedResult = "00000000000000000000 05"
Name = "Can process byte type '[byte]5 | fhx'"
InputObject = [byte]5
Count = 1
ExpectedResult = "0000000000000000 05"
}
@{
Name = "Can process byte[] type '[byte[]](1,2) | fhx'"
InputObject = [byte[]](1,2)
Count = 2
ExpectedResult = "00000000000000000000 01 ."
ExpectedSecondResult = "00000000000000000000 02 ."
Name = "Can process byte[] type '[byte[]](1,2) | fhx'"
InputObject = [byte[]](1, 2)
Count = 1
ExpectedResult = "0000000000000000 01 02 ��"
}
@{
Name = "Can process int type '7 | fhx'"
InputObject = 7
Count = 1
ExpectedResult = "00000000000000000000 07 00 00 00 ...."
Name = "Can process int type '7 | fhx'"
InputObject = 7
Count = 1
ExpectedResult = "0000000000000000 07 00 00 00 � "
}
@{
Name = "Can process int[] type '[int[]](5,6) | fhx'"
InputObject = [int[]](5,6)
Count = 2
ExpectedResult = "00000000000000000000 05 00 00 00 ...."
ExpectedSecondResult = "00000000000000000000 06 00 00 00 ...."
Name = "Can process int[] type '[int[]](5,6) | fhx'"
InputObject = [int[]](5, 6)
Count = 1
ExpectedResult = "0000000000000000 05 00 00 00 06 00 00 00 � � "
}
@{
Name = "Can process int32 type '[int32]2032 | fhx'"
InputObject = [int32]2032
Count = 1
ExpectedResult = "00000000000000000000 F0 07 00 00 ð..."
Name = "Can process int32 type '[int32]2032 | fhx'"
InputObject = [int32]2032
Count = 1
ExpectedResult = "0000000000000000 F0 07 00 00 ð� "
}
@{
Name = "Can process int32[] type '[int32[]](2032, 2033) | fhx'"
InputObject = [int32[]](2032, 2033)
Count = 2
ExpectedResult = "00000000000000000000 F0 07 00 00 ð..."
ExpectedSecondResult = "00000000000000000000 F1 07 00 00 ñ..."
Name = "Can process int32[] type '[int32[]](2032, 2033) | fhx'"
InputObject = [int32[]](2032, 2033)
Count = 1
ExpectedResult = "0000000000000000 F0 07 00 00 F1 07 00 00 ð� ñ� "
}
@{
Name = "Can process Int64 type '[Int64]9223372036854775807 | fhx'"
InputObject = [Int64]9223372036854775807
Count = 1
ExpectedResult = "00000000000000000000 FF FF FF FF FF FF FF 7F ......."
Name = "Can process Int64 type '[Int64]9223372036854775807 | fhx'"
InputObject = [Int64]9223372036854775807
Count = 1
ExpectedResult = "0000000000000000 FF FF FF FF FF FF FF 7F ÿÿÿÿÿÿÿ�"
}
@{
Name = "Can process Int64[] type '[Int64[]](9223372036852,9223372036853) | fhx'"
InputObject = [Int64[]](9223372036852,9223372036853)
Count = 2
ExpectedResult = "00000000000000000000 F4 5A D0 7B 63 08 00 00 ôZÐ{c..."
ExpectedSecondResult = "00000000000000000000 F5 5A D0 7B 63 08 00 00 õZÐ{c..."
Name = "Can process Int64[] type '[Int64[]](9223372036852,9223372036853) | fhx'"
InputObject = [Int64[]](9223372036852, 9223372036853)
Count = 1
ExpectedResult = "0000000000000000 F4 5A D0 7B 63 08 00 00 F5 5A D0 7B 63 08 00 00 ôZÐ{c� õZÐ{c� "
}
@{
Name = "Can process string type 'hello world | fhx'"
InputObject = "hello world"
Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F 20 77 6F 72 6C 64 hello world"
Name = "Can process string type 'hello world | fhx'"
InputObject = "hello world"
Count = 1
ExpectedResult = "0000000000000000 68 65 6C 6C 6F 20 77 6F 72 6C 64 hello world"
}
@{
Name = "Can process enum type '[DisplayHintType]::DateTime | fhx"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType]::DateTime
Count = 1
ExpectedResult = "00000000000000000000 02 00 00 00 ...."
Name = "Can process string type amidst other types { 1, 2, 3, 'hello world' | fhx }"
InputObject = 1, 2, 3, "hello world"
Count = 2
ExpectedResult = "0000000000000000 01 00 00 00 02 00 00 00 03 00 00 00 � � � "
ExpectedSecondResult = "0000000000000000 68 65 6C 6C 6F 20 77 6F 72 6C 64 hello world"
}
@{
Name = "Can process DisplayHintType[] type '[DisplayHintType[]](DateTime) | fhx'"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType[]]([Microsoft.PowerShell.Commands.DisplayHintType]::DateTime)
Count = 1
ExpectedResult = "00000000000000000000 02 00 00 00 ...."
Name = "Can process jagged array type '[sbyte[]](-15, 18, 21, -5), [byte[]](1, 2, 3, 4, 5, 6) | fhx'"
InputObject = [sbyte[]](-15, 18, 21, -5), [byte[]](1, 2, 3, 4, 5, 6)
Count = 2
ExpectedResult = "0000000000000000 F1 12 15 FB ñ��û"
ExpectedSecondResult = "0000000000000000 01 02 03 04 05 06 ������"
}
@{
Name = "Can process DisplayHintType[] type '[DisplayHintType[]](DateTime, Time) | fhx'"
InputObject = [Microsoft.PowerShell.Commands.DisplayHintType[]]([Microsoft.PowerShell.Commands.DisplayHintType]::DateTime, [Microsoft.PowerShell.Commands.DisplayHintType]::Time)
Count = 2
ExpectedResult = "00000000000000000000 02 00 00 00 ...."
ExpectedSecondResult = "00000000000000000000 01 00 00 00 ...."
Name = "Can process PS-native enum array '[TestEnum[]]('TestOne', 'TestTwo', 'TestThree', 'TestFour') | fhx'"
InputObject = [TestEnum[]]('TestOne', 'TestTwo', 'TestThree', 'TestFour')
Count = 1
ExpectedResult = "0000000000000000 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 � � � � "
}
@{
Name = "Can process char type '[char]`'A`' | fhx'"
InputObject = [char]'A'
Count = 1
ExpectedResult = "00000000000000000000 41 A"
}
@{
Name = "Can process char[] type '[char[]](`'A`') | fhx'"
InputObject = [char[]]('A')
Count = 1
ExpectedResult = "00000000000000000000 41 A"
}
@{
Name = "Can process char[] type '[char[]](`'A`', 'B') | fhx'"
InputObject = [char[]]('A', 'B')
Count = 2
ExpectedResult = "00000000000000000000 41 A"
ExpectedSecondResult = "00000000000000000000 42 B"
Name = "Can process C#-native sbyte enum array '[TestSByteEnum[]]('One', 'Two', 'Three', 'Four') | fhx'"
InputObject = [TestSByteEnum[]]('One', 'Two', 'Three', 'Four')
Count = 1
ExpectedResult = "0000000000000000 FF FE FD FC ÿþýü"
}
)
It "<Name>" -Testcase $testCases {
It "<Name>" -TestCases $testCases {
param ($Name, $InputObject, $Count, $ExpectedResult, $ExpectedSecondResult)
$result = $InputObject | Format-Hex
$result.count | Should -Be $Count
$result.Count | Should -Be $Count
$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$result[0].ToString() | Should -MatchExactly $ExpectedResult
if ($result.count -gt 1)
{
if ($result.count -gt 1) {
$result[1].ToString() | Should -MatchExactly $ExpectedSecondResult
}
}
$heterogenousInputCases = @(
@{
InputScript = { [sbyte[]](-15, 18, 21, -5), "hello", [byte[]](1..6), 1, 2, 3, 4 }
Count = 4
ExpectedResults = @(
"0000000000000000 F1 12 15 FB ñ��û"
"0000000000000000 68 65 6C 6C 6F hello"
"0000000000000000 01 02 03 04 05 06 ������"
"0000000000000000 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 � � � � "
)
ExpectedLabels = @(
"System.SByte[]"
"System.String"
"System.Byte"
"System.Int32"
).ForEach{ [regex]::Escape($_) } -join '|'
}
@{
InputScript = { $inputFile1, "Mountains are merely mountains", 1, 4, 5, 3, [ushort[]](1..10) }
Count = 6
ExpectedResults = @(
"0000000000000000 48 65 6C 6C 6F 20 57 6F 72 6C 64 Hello World"
"0000000000000000 4D 6F 75 6E 74 61 69 6E 73 20 61 72 65 20 6D 65 Mountains are me"
"0000000000000010 72 65 6C 79 20 6D 6F 75 6E 74 61 69 6E 73 rely mountains"
"0000000000000000 01 00 00 00 04 00 00 00 05 00 00 00 03 00 00 00 � � � � "
"0000000000000000 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 � � � � � � � � "
"0000000000000010 09 00 0A 00 � � "
)
ExpectedLabels = @(
$inputFile1.FullName
"System.String"
"System.Int32"
"System.UInt16[]"
).ForEach{ [regex]::Escape($_) } -join '|'
}
)
It 'can process jagged input: <InputScript>' -TestCases $heterogenousInputCases {
param($InputScript, $Count, $ExpectedResults, $ExpectedLabels)
$Results = & $InputScript | Format-Hex
$Results | Should -HaveCount $Count
$ExpectedResults | Should -HaveCount $Count
for ($Number = 0; $Number -lt $Results.Count; $Number++) {
$Results[$Number] | Should -MatchExactly $ExpectedResults[$Number]
$Results[$Number].Label | Should -MatchExactly $ExpectedLabels
}
}
}
Context "Path and LiteralPath Parameters" {
@@ -272,39 +313,39 @@ Describe "FormatHex" -tags "CI" {
$testCases = @(
@{
Name = "Can process file content from given file path 'fhx -Path `$inputFile1'"
PathCase = $true
Path = $inputFile1
Count = 1
Name = "Can process file content from given file path 'fhx -Path `$inputFile1'"
PathCase = $true
Path = $inputFile1
Count = 1
ExpectedResult = $inputText1
}
@{
Name = "Can process file content from all files in array of file paths 'fhx -Path `$inputFile1, `$inputFile2'"
PathCase = $true
Path = @($inputFile1, $inputFile2)
Count = 2
ExpectedResult = $inputText1
Name = "Can process file content from all files in array of file paths 'fhx -Path `$inputFile1, `$inputFile2'"
PathCase = $true
Path = @($inputFile1, $inputFile2)
Count = 2
ExpectedResult = $inputText1
ExpectedSecondResult = $inputText2
}
@{
Name = "Can process file content from all files when resolved to multiple paths 'fhx -Path '`$testDirectory\SourceFile-*''"
PathCase = $true
Path = "$testDirectory\SourceFile-*"
Count = 2
ExpectedResult = $inputText1
Name = "Can process file content from all files when resolved to multiple paths 'fhx -Path '`$testDirectory\SourceFile-*''"
PathCase = $true
Path = "$testDirectory\SourceFile-*"
Count = 2
ExpectedResult = $inputText1
ExpectedSecondResult = $inputText2
}
@{
Name = "Can process file content from given file path 'fhx -LiteralPath `$inputFile3'"
Path = $inputFile3
Count = 1
Name = "Can process file content from given file path 'fhx -LiteralPath `$inputFile3'"
Path = $inputFile3
Count = 1
ExpectedResult = $inputText3
}
@{
Name = "Can process file content from all files in array of file paths 'fhx -LiteralPath `$inputFile1, `$inputFile3'"
Path = @($inputFile1, $inputFile3)
Count = 2
ExpectedResult = $inputText1
Name = "Can process file content from all files in array of file paths 'fhx -LiteralPath `$inputFile1, `$inputFile3'"
Path = @($inputFile1, $inputFile3)
Count = 2
ExpectedResult = $inputText1
ExpectedSecondResult = $inputText3
}
)
@@ -313,62 +354,78 @@ Describe "FormatHex" -tags "CI" {
param ($Name, $PathCase, $Path, $ExpectedResult, $ExpectedSecondResult)
if ($PathCase)
{
$result = Format-Hex -Path $Path
if ($PathCase) {
$result = Format-Hex -Path $Path
}
else # LiteralPath
{
else {
# LiteralPath
$result = Format-Hex -LiteralPath $Path
}
$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$result[0].ToString() | Should -MatchExactly $ExpectedResult
if ($result.count -gt 1)
{
if ($result.count -gt 1) {
$result[1].ToString() | Should -MatchExactly $ExpectedSecondResult
}
}
It 'properly accepts -LiteralPath input from a FileInfo object' {
$FilePath = 'TestDrive:\FHX-LitPathTest.txt'
"Hello World!" | Set-Content -Path $FilePath
$FileObject = Get-Item -Path $FilePath
$result = $FileObject | Format-Hex
if ($IsWindows) {
$Result.Bytes[-1] | Should -Be 0x0A
$Result.Bytes[-2] | Should -Be 0x0D
$Result.Bytes.Length | Should -Be 14
}
else {
$Result.Bytes[-1] | Should -Be 0x0A
$Result.Bytes.Length | Should -Be 13
}
}
}
Context "Encoding Parameter" {
$testCases = @(
@{
Name = "Can process ASCII encoding 'fhx -InputObject 'hello' -Encoding ASCII'"
Encoding = "ASCII"
Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F hello"
Name = "Can process ASCII encoding 'fhx -InputObject 'hello' -Encoding ASCII'"
Encoding = "ASCII"
Count = 1
ExpectedResult = "0000000000000000 68 65 6C 6C 6F hello"
}
@{
Name = "Can process BigEndianUnicode encoding 'fhx -InputObject 'hello' -Encoding BigEndianUnicode'"
Encoding = "BigEndianUnicode"
Count = 1
ExpectedResult = "00000000000000000000 00 68 00 65 00 6C 00 6C 00 6F .h.e.l.l.o"
Name = "Can process BigEndianUnicode encoding 'fhx -InputObject 'hello' -Encoding BigEndianUnicode'"
Encoding = "BigEndianUnicode"
Count = 1
ExpectedResult = "0000000000000000 00 68 00 65 00 6C 00 6C 00 6F h e l l o"
}
@{
Name = "Can process Unicode encoding 'fhx -InputObject 'hello' -Encoding Unicode'"
Encoding = "Unicode"
Count = 1
ExpectedResult = "00000000000000000000 68 00 65 00 6C 00 6C 00 6F 00 h.e.l.l.o."
Name = "Can process Unicode encoding 'fhx -InputObject 'hello' -Encoding Unicode'"
Encoding = "Unicode"
Count = 1
ExpectedResult = "0000000000000000 68 00 65 00 6C 00 6C 00 6F 00 h e l l o "
}
@{
Name = "Can process UTF7 encoding 'fhx -InputObject 'hello' -Encoding UTF7'"
Encoding = "UTF7"
Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F hello"
Name = "Can process UTF7 encoding 'fhx -InputObject 'hello' -Encoding UTF7'"
Encoding = "UTF7"
Count = 1
ExpectedResult = "0000000000000000 68 65 6C 6C 6F hello"
}
@{
Name = "Can process UTF8 encoding 'fhx -InputObject 'hello' -Encoding UTF8'"
Encoding = "UTF8"
Count = 1
ExpectedResult = "00000000000000000000 68 65 6C 6C 6F hello"
@{
Name = "Can process UTF8 encoding 'fhx -InputObject 'hello' -Encoding UTF8'"
Encoding = "UTF8"
Count = 1
ExpectedResult = "0000000000000000 68 65 6C 6C 6F hello"
}
@{
Name = "Can process UTF32 encoding 'fhx -InputObject 'hello' -Encoding UTF32'"
Encoding = "UTF32"
Count = 1
ExpectedResult = "00000000000000000000 68 00 00 00 65 00 00 00 6C 00 00 00 6C 00 00 00 h...e...l...l...$($newline)00000000000000000010 6F 00 00 00 o..."
@{
Name = "Can process UTF32 encoding 'fhx -InputObject 'hello' -Encoding UTF32'"
Encoding = "UTF32"
Count = 2
ExpectedResult = "0000000000000000 68 00 00 00 65 00 00 00 6C 00 00 00 6C 00 00 00 h e l l "
ExpectedSecondResult = "0000000000000010 6F 00 00 00 o "
}
)
@@ -390,16 +447,16 @@ Describe "FormatHex" -tags "CI" {
$testCases = @(
@{
Name = "Does not support non-FileSystem Provider paths 'fhx -Path 'Cert:\CurrentUser\My\`$thumbprint' -ErrorAction Stop'"
PathParameterErrorCase = $true
Path = "Cert:\CurrentUser\My\$thumbprint"
Name = "Does not support non-FileSystem Provider paths 'fhx -Path 'Cert:\CurrentUser\My\`$thumbprint' -ErrorAction Stop'"
PathParameterErrorCase = $true
Path = "Cert:\CurrentUser\My\$thumbprint"
ExpectedFullyQualifiedErrorId = "FormatHexOnlySupportsFileSystemPaths,Microsoft.PowerShell.Commands.FormatHex"
}
@{
Name = "Type Not Supported 'fhx -InputObject @{'hash' = 'table'} -ErrorAction Stop'"
InputObjectErrorCase = $true
Path = $inputFile1
InputObject = @{ "hash" = "table" }
Name = "Type Not Supported 'fhx -InputObject @{'hash' = 'table'} -ErrorAction Stop'"
InputObjectErrorCase = $true
Path = $inputFile1
InputObject = @{ "hash" = "table" }
ExpectedFullyQualifiedErrorId = "FormatHexTypeNotSupported,Microsoft.PowerShell.Commands.FormatHex"
}
)
@@ -409,12 +466,10 @@ Describe "FormatHex" -tags "CI" {
param ($Name, $PathParameterErrorCase, $Path, $InputObject, $InputObjectErrorCase, $ExpectedFullyQualifiedErrorId)
{
if ($PathParameterErrorCase)
{
if ($PathParameterErrorCase) {
$result = Format-Hex -Path $Path -ErrorAction Stop
}
if ($InputObjectErrorCase)
{
if ($InputObjectErrorCase) {
$result = Format-Hex -InputObject $InputObject -ErrorAction Stop
}
} | Should -Throw -ErrorId $ExpectedFullyQualifiedErrorId
@@ -425,20 +480,20 @@ Describe "FormatHex" -tags "CI" {
$testCases = @(
@{
Name = "If given invalid path in array, continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
PathCase = $true
InvalidPath = "$($inputFile1.DirectoryName)\fakefile8888845345345348709.txt"
Name = "If given invalid path in array, continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
PathCase = $true
InvalidPath = "$($inputFile1.DirectoryName)\fakefile8888845345345348709.txt"
ExpectedFullyQualifiedErrorId = "FileNotFound,Microsoft.PowerShell.Commands.FormatHex"
}
@{
Name = "If given a non FileSystem path in array, continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
PathCase = $true
InvalidPath = "Cert:\CurrentUser\My\$thumbprint"
Name = "If given a non FileSystem path in array, continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
PathCase = $true
InvalidPath = "Cert:\CurrentUser\My\$thumbprint"
ExpectedFullyQualifiedErrorId = "FormatHexOnlySupportsFileSystemPaths,Microsoft.PowerShell.Commands.FormatHex"
}
@{
Name = "If given a non FileSystem path in array (with LiteralPath), continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
InvalidPath = "Cert:\CurrentUser\My\$thumbprint"
Name = "If given a non FileSystem path in array (with LiteralPath), continues to process valid paths 'fhx -Path `$invalidPath, `$inputFile1 -ErrorVariable e -ErrorAction SilentlyContinue'"
InvalidPath = "Cert:\CurrentUser\My\$thumbprint"
ExpectedFullyQualifiedErrorId = "FormatHexOnlySupportsFileSystemPaths,Microsoft.PowerShell.Commands.FormatHex"
}
)
@@ -450,12 +505,11 @@ Describe "FormatHex" -tags "CI" {
$output = $null
$errorThrown = $null
if ($PathCase)
{
if ($PathCase) {
$output = Format-Hex -Path $InvalidPath, $inputFile1 -ErrorVariable errorThrown -ErrorAction SilentlyContinue
}
else # LiteralPath
{
else {
# LiteralPath
$output = Format-Hex -LiteralPath $InvalidPath, $inputFile1 -ErrorVariable errorThrown -ErrorAction SilentlyContinue
}
@@ -470,10 +524,10 @@ Describe "FormatHex" -tags "CI" {
It "Path is default Parameter Set 'fhx `$inputFile1'" {
$result = Format-Hex $inputFile1
$result = Format-Hex $inputFile1
$result | Should -Not -BeNullOrEmpty
,$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
, $result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$actualResult = $result.ToString()
$actualResult | Should -MatchExactly $inputText1
}
@@ -483,7 +537,7 @@ Describe "FormatHex" -tags "CI" {
$result = Get-ChildItem $inputFile1 | Format-Hex
$result | Should -Not -BeNullOrEmpty
,$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
, $result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$actualResult = $result.ToString()
$actualResult | Should -MatchExactly $inputText1
}
@@ -493,8 +547,9 @@ Describe "FormatHex" -tags "CI" {
$result = "a" * 30 | Format-Hex
$result | Should -Not -BeNullOrEmpty
,$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$result.ToString() | Should -MatchExactly "00000000000000000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa$($newline)00000000000000000010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaa "
$result | Should -BeOfType 'Microsoft.PowerShell.Commands.ByteCollection'
$result[0].ToString() | Should -MatchExactly "0000000000000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa"
$result[1].ToString() | Should -MatchExactly "0000000000000010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaa "
}
It "Validate that files do not have buffer underrun problems 'Format-Hex -Path `$InputFile4'" {
@@ -503,9 +558,9 @@ Describe "FormatHex" -tags "CI" {
$result | Should -Not -BeNullOrEmpty
$result.Count | Should -Be 3
$result[0].ToString() | Should -MatchExactly "00000000000000000000 4E 6F 77 20 69 73 20 74 68 65 20 77 69 6E 74 65 Now is the winte"
$result[1].ToString() | Should -MatchExactly "00000000000000000010 72 20 6F 66 20 6F 75 72 20 64 69 73 63 6F 6E 74 r of our discont"
$result[2].ToString() | Should -MatchExactly "00000000000000000020 65 6E 74 ent "
$result[0].ToString() | Should -MatchExactly "0000000000000000 4E 6F 77 20 69 73 20 74 68 65 20 77 69 6E 74 65 Now is the winte"
$result[1].ToString() | Should -MatchExactly "0000000000000010 72 20 6F 66 20 6F 75 72 20 64 69 73 63 6F 6E 74 r of our discont"
$result[2].ToString() | Should -MatchExactly "0000000000000020 65 6E 74 ent "
}
}
@@ -516,23 +571,22 @@ Describe "FormatHex" -tags "CI" {
$result | Should -Not -BeNullOrEmpty
$result.Count | Should -Be 3
$result[0].ToString() | Should -MatchExactly "00000000000000000000 4E 6F 77 20 69 73 20 74 68 65 20 77 69 6E 74 65 Now is the winte"
$result[1].ToString() | Should -MatchExactly "00000000000000000010 72 20 6F 66 20 6F 75 72 20 64 69 73 63 6F 6E 74 r of our discont"
$result[2].ToString() | Should -MatchExactly "00000000000000000020 65 6E 74 ent "
$result[0].ToString() | Should -MatchExactly "0000000000000000 4E 6F 77 20 69 73 20 74 68 65 20 77 69 6E 74 65 Now is the winte"
$result[1].ToString() | Should -MatchExactly "0000000000000010 72 20 6F 66 20 6F 75 72 20 64 69 73 63 6F 6E 74 r of our discont"
$result[2].ToString() | Should -MatchExactly "0000000000000020 65 6E 74 ent "
}
It "Count = 1" {
$result = Format-Hex -Path $inputFile4 -Count 1
$result.ToString() | Should -MatchExactly "00000000000000000000 4E N "
$result.ToString() | Should -MatchExactly "0000000000000000 4E N "
}
It "Offset = length" {
$result = Format-Hex -Path $InputFile4 -Offset $inputText4.Length
$result | Should -BeNullOrEmpty
$result = Format-Hex -InputObject $inputText4 -Offset $inputText4.Length
$result.Bytes | Should -HaveCount 0
$result | Should -BeNullOrEmpty
}
It "Offset = 1" {
@@ -541,14 +595,14 @@ Describe "FormatHex" -tags "CI" {
$result | Should -Not -BeNullOrEmpty
$result.Count | Should -Be 3
$result[0].ToString() | Should -MatchExactly "00000000000000000001 6F 77 20 69 73 20 74 68 65 20 77 69 6E 74 65 72 ow is the winter"
$result[1].ToString() | Should -MatchExactly "00000000000000000011 20 6F 66 20 6F 75 72 20 64 69 73 63 6F 6E 74 65 of our disconte"
$result[2].ToString() | Should -MatchExactly "00000000000000000021 6E 74 nt "
$result[0].ToString() | Should -MatchExactly "0000000000000001 6F 77 20 69 73 20 74 68 65 20 77 69 6E 74 65 72 ow is the winter"
$result[1].ToString() | Should -MatchExactly "0000000000000011 20 6F 66 20 6F 75 72 20 64 69 73 63 6F 6E 74 65 of our disconte"
$result[2].ToString() | Should -MatchExactly "0000000000000021 6E 74 nt "
}
It "Count = 1 and Offset = 1" {
$result = Format-Hex -Path $inputFile4 -Count 1 -Offset 1
$result.ToString() | Should -MatchExactly "00000000000000000001 6F o "
$result.ToString() | Should -MatchExactly "0000000000000001 6F o "
}
It "Count should be > 0" {
@@ -565,9 +619,9 @@ Describe "FormatHex" -tags "CI" {
$result | Should -Not -BeNullOrEmpty
$result.Count | Should -Be 3
$result[0].ToString() | Should -MatchExactly "00000000000000000000 4E 6F 77 20 69 73 20 74 68 65 20 77 69 6E 74 65 Now is the winte"
$result[1].ToString() | Should -MatchExactly "00000000000000000010 72 20 6F 66 20 6F 75 72 20 64 69 73 63 6F 6E 74 r of our discont"
$result[2].ToString() | Should -MatchExactly "00000000000000000020 65 6E 74 ent "
$result[0].ToString() | Should -MatchExactly "0000000000000000 4E 6F 77 20 69 73 20 74 68 65 20 77 69 6E 74 65 Now is the winte"
$result[1].ToString() | Should -MatchExactly "0000000000000010 72 20 6F 66 20 6F 75 72 20 64 69 73 63 6F 6E 74 r of our discont"
$result[2].ToString() | Should -MatchExactly "0000000000000020 65 6E 74 ent "
}
}
}