Skip to content
This repository has been archived by the owner on Oct 21, 2023. It is now read-only.

Fixes bugs in TransformTag attribute #70

Merged
merged 1 commit into from
Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions Tests/TransformTagAttribute.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
Describe 'TransformTagAttribute' {
BeforeAll {
function Test-TagBinding {
[CmdletBinding()]
param (
[VaporShell.Core.TransformTag()]
[object[]] $Tags
)

$Tags
}
}

It 'Should return one or more tags when given <TestName>' -TestCases @(
@{
TestName = 'multiple hashtables'
InputData = @{ one = 1 }, @{ two = 2 }
ExpectedResult = [PSCustomObject]@{ Key = 'one'; Value = '1' }, [PSCustomObject]@{ Key = 'two'; Value = '2' }
}
@{
TestName = 'multiple PSObjects'
InputData = [PSCustomObject]@{ one = 1 }, [PSCustomObject]@{ two = 2 }
ExpectedResult = [PSCustomObject]@{ Key = 'one'; Value = '1' }, [PSCustomObject]@{ Key = 'two'; Value = '2' }
}
@{
TestName = 'a single hashtable with multiple keys'
InputData = [PSCustomobject]@{ one = 1; two = 2 }
ExpectedResult = [PSCustomObject]@{ Key = 'one'; Value = '1' }, [PSCustomObject]@{ Key = 'two'; Value = '2' }
}
@{
TestName = 'an existing VSTag object'
InputData = Add-VSTag -Key one -Value '1'
ExpectedResult = [PSCustomObject]@{ Key = 'one'; Value = '1' }
}
@{
TestName = 'a hashtable with Key and Value keys'
InputData = @{Key = 'Name'; Value = 'Harold'}
ExpectedResult = [PSCustomObject]@{ Key = 'Name'; Value = 'Harold' }
}
@{
TestName = 'a hashtable with lowercase key and value keys'
InputData = @{ key = 'Name'; value = 'Harold'}
ExpectedResult = [PSCustomObject]@{ Key = 'Name'; Value = 'Harold' }
}
@{
TestName = 'a hashtable with mixed case key and value keys'
InputData = @{ kEy = 'Name'; ValUE = 'Harold'}
ExpectedResult = [PSCustomObject]@{ Key = 'Name'; Value = 'Harold' }
}
@{
TestName = 'a PSCustomObject key and value properties'
InputData = [PSCustomObject]@{ Key = 'Name'; Value = 'Harold' }
ExpectedResult = [PSCustomObject]@{ Key = 'Name'; Value = 'Harold' }
}
@{
TestName = 'a PSCustomObject lowercase key and value properties'
InputData = [PSCustomObject]@{ key = 'Name'; value = 'Harold' }
ExpectedResult = [PSCustomObject]@{ Key = 'Name'; Value = 'Harold' }
}
) {
param (
$InputData,
$ExpectedResult
)

Assert-Equivalent -Actual (Test-TagBinding -Tags $InputData) -Expected $ExpectedResult
}
}
94 changes: 49 additions & 45 deletions VaporShell.Core/VaporShell.Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,43 @@ public class TransformTagAttribute : ArgumentTransformationAttribute
{
private EngineIntrinsics engineIntrinsics;

private IEnumerable<PSObject> ConvertToTag(object key, object value)
private PSObject ConvertToTag(object key, object value)
{
PSObject tag = new PSObject();
tag.Members.Add(new PSNoteProperty("Key", key));
tag.Members.Add(new PSNoteProperty("Value", value));
tag.TypeNames.Insert(0,"Vaporshell.Resource.Tag");
tag.Members.Add(new PSNoteProperty("Key", key.ToString()));
tag.Members.Add(new PSNoteProperty("Value", value.ToString()));
tag.TypeNames.Insert(0, "Vaporshell.Resource.Tag");

yield return tag;
return tag;
}

private IEnumerable<PSObject> TransformHashtable(IDictionary inputData)
private bool TryGetKey(IDictionary dictionary, string keyName, ref string KeyValue)
{
if (inputData.Contains("Key") && inputData.Contains("Value"))
foreach (object key in dictionary.Keys)
{
foreach (PSObject tag in this.ConvertToTag(inputData["Key"],inputData["Value"]))
if (key.ToString().ToLower() == keyName.ToLower())
{
yield return tag;
KeyValue = dictionary[key].ToString();
return true;
}
}

return false;
}

private IEnumerable<PSObject> TransformHashtable(IDictionary inputData)
{
string keyName = "";
string value = "";
if (this.TryGetKey(inputData, "key", ref keyName) && this.TryGetKey(inputData, "value", ref value))
{
yield return this.ConvertToTag(keyName, value);
}
else
{
foreach (string key in inputData.Keys)
{
foreach (PSObject tag in this.ConvertToTag(key,inputData[key]))
{
yield return tag;
}
yield return this.ConvertToTag(key, inputData[key]);
}
}
}
Expand All @@ -45,80 +55,74 @@ private IEnumerable<PSObject> TransformPSObject(PSObject inputData)
var props = new List<string>();
foreach (var property in inputData.Properties)
{
props.Add(property.Name);
props.Add(property.Name.ToLower());
}
if (props.Contains("Key") && props.Contains("Value"))
{
object key = null;
object value = null;

foreach (var property in inputData.Properties)
{
if (property.Name == "Key")
{
key = property.Value;
}
else if (property.Name == "Value")
{
value = property.Value;
}
}
foreach (PSObject tag in this.ConvertToTag(key,value))
{
yield return tag;
}
if (props.Contains("key") && props.Contains("value"))
{
yield return this.ConvertToTag(inputData.Properties["Key"].Value, inputData.Properties["Value"].Value);
}
else
{
foreach (var property in inputData.Properties)
{
foreach (PSObject tag in this.ConvertToTag(property.Name,property.Value))
{
yield return tag;
}
yield return this.ConvertToTag(property.Name, property.Value);
}
}
}

private object TransformSingle(object inputData)
private IEnumerable<PSObject> TransformSingle(object inputData)
{
if (inputData is IDictionary)
{
return this.TransformHashtable(inputData as IDictionary);
foreach (PSObject tag in this.TransformHashtable(inputData as IDictionary))
{
yield return tag;
}
}
else if (inputData is PSObject)
{
PSObject psObject = inputData as PSObject;
if (psObject.TypeNames.Contains("Vaporshell.Resource.Tag"))
{
return inputData;
yield return psObject;
}
else if (psObject.TypeNames.Contains("System.Management.Automation.PSCustomObject"))
{
return this.TransformPSObject(psObject);
foreach (PSObject tag in this.TransformPSObject(psObject))
{
yield return tag;
}
}
}
return null;
}

private IEnumerable<object> TransformData(object inputData)
private IEnumerable<PSObject> TransformData(object inputData)
{
if (inputData is Array)
{
foreach (object item in inputData as Array)
{
yield return this.TransformSingle(item);
// This is returning an unenumerated array
foreach (PSObject tag in this.TransformSingle(item))
{
yield return tag;
}
}
}
else
{
yield return this.TransformSingle(inputData);
foreach (PSObject tag in this.TransformSingle(inputData))
{
yield return tag;
}
}
}

public override object Transform(EngineIntrinsics engineIntrinsics, object inputData)
{
this.engineIntrinsics = engineIntrinsics;

return this.TransformData(inputData);
}
}
Expand Down
5 changes: 3 additions & 2 deletions VaporShell.Core/VaporShell.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Management.Automation" Version="6.0.4" />

<ItemGroup>
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions VaporShell.Core/VaporShell.Core.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29806.167
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VaporShell.Core", "VaporShell.Core.csproj", "{8FF3CC38-B1B4-4F93-8F90-7FDF82AFD193}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8FF3CC38-B1B4-4F93-8F90-7FDF82AFD193}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8FF3CC38-B1B4-4F93-8F90-7FDF82AFD193}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FF3CC38-B1B4-4F93-8F90-7FDF82AFD193}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FF3CC38-B1B4-4F93-8F90-7FDF82AFD193}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {115A389F-865B-4A5F-9761-0E606AB74BF5}
EndGlobalSection
EndGlobal