Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle large numbers and PSCustomObjects #135

Merged
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
11 changes: 9 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
name: Pester tests on powershell.exe
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-2019, windows-2022]

Expand All @@ -27,7 +28,7 @@ jobs:
run: |
Set-PSRepository PSGallery -InstallationPolicy Trusted
Install-Module Assert -ErrorAction Stop -MaximumVersion 0.9.6 -Force
Install-Module Pester -ErrorAction Stop -Force
Install-Module Pester -ErrorAction Stop -MaximumVersion 5.6.1 -Force
- name: Run tests
shell: powershell
run: |
Expand All @@ -37,6 +38,7 @@ jobs:
name: Pester tests
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, ubuntu-20.04, macos-12, windows-2019, windows-2022]

Expand All @@ -47,8 +49,13 @@ jobs:
run: |
Set-PSRepository PSGallery -InstallationPolicy Trusted
Install-Module Assert -ErrorAction Stop -MaximumVersion 0.9.6 -Force
Install-Module Pester -ErrorAction Stop -Force
Install-Module Pester -ErrorAction Stop -MaximumVersion 5.6.1 -Force
- name: Run tests
shell: pwsh
run: |
Remove-Module Pester -ErrorAction SilentlyContinue
Import-Module pester -Version 5.6.1
$PSVersionTable
Invoke-Pester
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
src/obj
src/bin
78 changes: 78 additions & 0 deletions Tests/powershell-yaml.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,84 @@ bools:
}
}

Describe 'Numbers are parsed as the smallest type possible' {
BeforeAll {
$global:value = @'
bigInt: 99999999999999999999999999999999999
int32: 2147483647
int64: 9223372036854775807
'@
}

It 'Should be a BigInt' {
$result = ConvertFrom-Yaml -Yaml $value
$result.bigInt | Should -BeOfType System.Numerics.BigInteger
}

It 'Should be of proper type and value' {
$result = ConvertFrom-Yaml -Yaml $value
$result.bigInt | Should -Be ([System.Numerics.BigInteger]::Parse("99999999999999999999999999999999999"))
$result.int32 | Should -Be ([int32]2147483647)
$result.int64 | Should -Be ([int64]9223372036854775807)
}
}

Describe 'PSCustomObjects' {
Context 'Classes with PSCustomObjects' {
It 'Should serialise as a hash' {
$nestedPsO = [PSCustomObject]@{
Nested = 'NestedValue'
}
$PsO = [PSCustomObject]@{
Name = 'Value'
Nested = $nestedPsO
}

class TestClass {
[PSCustomObject]$PsO
[string]$Ok
}
$Class = [TestClass]@{
PsO = $PsO
Ok = 'aye'
}
$asYaml = ConvertTo-Yaml $Class
$result = ConvertFrom-Yaml -Yaml $asYaml -Ordered
[System.Collections.Specialized.OrderedDictionary]$ret = [System.Collections.Specialized.OrderedDictionary]::new()
$ret["PsO"] = [System.Collections.Specialized.OrderedDictionary]::new()
$ret["PsO"]["Name"] = "Value"
$ret["PsO"]["Nested"] = [System.Collections.Specialized.OrderedDictionary]::new()
$ret["PsO"]["Nested"]["Nested"] = "NestedValue"
$ret["Ok"] = "aye"
Assert-Equivalent -Options $compareStrictly -Expected $ret -Actual $result
}
}

Context 'PSCustomObject with a single property' {
BeforeAll {
$global:value = [PSCustomObject]@{key="value"}
}
It 'Should serialise as a hash' {
$result = ConvertTo-Yaml $value
$result | Should -Be "key: value$([Environment]::NewLine)"
}
}
Context 'PSCustomObject with multiple properties' {
BeforeAll {
$global:value = [PSCustomObject]@{key1="value1"; key2="value2"}
}
It 'Should serialise as a hash' {
$result = ConvertTo-Yaml $value
$result | Should -Be "key1: value1$([Environment]::NewLine)key2: value2$([Environment]::NewLine)"
}
It 'Should deserialise as a hash' {
$asYaml = ConvertTo-Yaml $value
$result = ConvertFrom-Yaml -Yaml $asYaml -Ordered
Assert-Equivalent -Options $compareStrictly -Expected @{key1="value1"; key2="value2"} -Actual ([hashtable]$result)
}
}
}

Describe 'StringQuotingEmitter' {
BeforeAll {
$oldYamlPkgUrl = 'https://www.nuget.org/api/v2/package/YamlDotNet/11.2.1'
Expand Down
117 changes: 6 additions & 111 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,119 +14,14 @@
#

$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$source = @"
using System;
using System.Text.RegularExpressions;
using YamlDotNet;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.EventEmitters;
public class StringQuotingEmitter: ChainedEventEmitter {
// Patterns from https://yaml.org/spec/1.2/spec.html#id2804356
private static Regex quotedRegex = new Regex(@`"^(\~|null|true|false|on|off|yes|no|y|n|[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?|[-+]?(\.inf))?$`", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public StringQuotingEmitter(IEventEmitter next): base(next) {}

public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) {
var typeCode = eventInfo.Source.Value != null
? Type.GetTypeCode(eventInfo.Source.Type)
: TypeCode.Empty;
dotnet build --configuration Release $here/src/

switch (typeCode) {
case TypeCode.Char:
if (Char.IsDigit((char)eventInfo.Source.Value)) {
eventInfo.Style = ScalarStyle.DoubleQuoted;
}
break;
case TypeCode.String:
var val = eventInfo.Source.Value.ToString();
if (quotedRegex.IsMatch(val))
{
eventInfo.Style = ScalarStyle.DoubleQuoted;
} else if (val.IndexOf('\n') > -1) {
eventInfo.Style = ScalarStyle.Literal;
}
break;
}
$destinations = @("netstandard2.1", "net47")

base.Emit(eventInfo, emitter);
}
foreach ($item in $destinations) {
$src = Join-Path $here "src" "bin" "Release" $item "serializer.dll"
$dst = Join-Path $here "lib" $item "StringQuotingEmitter.dll"

public static SerializerBuilder Add(SerializerBuilder builder) {
return builder.WithEventEmitter(next => new StringQuotingEmitter(next));
}
Copy-Item -Force $src $dst
}
"@


function Invoke-LoadInContext {
param(
[string]$assemblyPath,
[string]$loadContextName
)

$loadContext = [System.Runtime.Loader.AssemblyLoadContext]::New($loadContextName, $true)
$assemblies = $loadContext.LoadFromAssemblyPath($assemblyPath)

return @{ "yaml"= $assemblies }
}

function Invoke-LoadInGlobalContext {
param(
[string]$assemblyPath
)
$assemblies = [Reflection.Assembly]::LoadFrom($assemblyPath)
return @{ "yaml"= $assemblies }
}


function Invoke-LoadAssembly {
$libDir = Join-Path $here "lib"
$assemblies = @{
"core" = Join-Path $libDir "netstandard2.1\YamlDotNet.dll";
"net45" = Join-Path $libDir "net45\YamlDotNet.dll";
"net35" = Join-Path $libDir "net35\YamlDotNet.dll";
}

if ($PSVersionTable.Keys -contains "PSEdition") {
if ($PSVersionTable.PSEdition -eq "Core") {
return (Invoke-LoadInContext -assemblyPath $assemblies["core"] -loadContextName "powershellyaml")
} elseif ($PSVersionTable.PSVersion.Major -gt 5.1) {
return (Invoke-LoadInContext -assemblyPath $assemblies["net45"] -loadContextName "powershellyaml")
} elseif ($PSVersionTable.PSVersion.Major -ge 4) {
return (Invoke-LoadInGlobalContext $assemblies["net45"])
} else {
return (Invoke-LoadInGlobalContext $assemblies["net35"])
}
} else { # Powershell 4.0 and lower do not know "PSEdition" yet
return (Invoke-LoadInGlobalContext $assemblies["net35"])
}
}

$assemblies = Invoke-LoadAssembly
$yamlDotNetAssembly = $assemblies["yaml"]


if (!([System.Management.Automation.PSTypeName]'StringQuotingEmitter').Type) {
$referenceList = @($yamlDotNetAssembly.Location,[Text.RegularExpressions.Regex].Assembly.Location)
if ($PSVersionTable.PSEdition -eq "Core") {
$referenceList += [IO.Directory]::GetFiles([IO.Path]::Combine($PSHOME, 'ref'), 'netstandard.dll', [IO.SearchOption]::TopDirectoryOnly)
$destinations = @("lib/netstandard2.1")
} else {
$referenceList += 'System.Runtime.dll'
$destinations = @("lib/net45", "lib/net35")
}
}

$destinations = @("lib/netstandard2.1", "lib/net45", "lib/net35")

foreach ($target in $destinations) {
$targetPath = Join-Path $here $target
$file = Join-Path $targetPath "StringQuotingEmitter.dll"
if (!(Test-Path $file)) {
if ($PSVersionTable.PSEdition -eq "Core") {
Add-Type -TypeDefinition $source -ReferencedAssemblies $referenceList -Language CSharp -CompilerOptions "-nowarn:1701" -OutputAssembly $file
} else {
Add-Type -TypeDefinition $source -ReferencedAssemblies $referenceList -Language CSharp -OutputAssembly $file
}
}
}
19 changes: 0 additions & 19 deletions lib/net35/LICENSE-libyaml

This file was deleted.

Binary file removed lib/net35/StringQuotingEmitter.dll
Binary file not shown.
Binary file removed lib/net35/YamlDotNet.dll
Binary file not shown.
Loading
Loading