|
| 1 | +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( |
| 2 | + 'PSReviewUnusedParameter', '', |
| 3 | + Justification = 'Required for Pester tests' |
| 4 | +)] |
| 5 | +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( |
| 6 | + 'PSUseDeclaredVarsMoreThanAssignments', '', |
| 7 | + Justification = 'Required for Pester tests' |
| 8 | +)] |
| 9 | +[CmdletBinding()] |
| 10 | +param() |
| 11 | + |
| 12 | +Describe 'ConvertFrom-Yaml' { |
| 13 | + |
| 14 | + Context 'Scalars' { |
| 15 | + It 'Parses a simple string value' { |
| 16 | + $result = 'name: World' | ConvertFrom-Yaml |
| 17 | + $result.name | Should -Be 'World' |
| 18 | + } |
| 19 | + |
| 20 | + It 'Parses an integer value' { |
| 21 | + $result = 'count: 42' | ConvertFrom-Yaml |
| 22 | + $result.count | Should -Be 42 |
| 23 | + $result.count | Should -BeOfType [int] |
| 24 | + } |
| 25 | + |
| 26 | + It 'Parses a floating-point value' { |
| 27 | + $result = 'ratio: 1.5' | ConvertFrom-Yaml |
| 28 | + $result.ratio | Should -Be 1.5 |
| 29 | + $result.ratio | Should -BeOfType [double] |
| 30 | + } |
| 31 | + |
| 32 | + It 'Parses boolean true variants' { |
| 33 | + $result = "a: true`nb: True`nc: yes" | ConvertFrom-Yaml |
| 34 | + $result.a | Should -BeTrue |
| 35 | + $result.b | Should -BeTrue |
| 36 | + $result.c | Should -BeTrue |
| 37 | + } |
| 38 | + |
| 39 | + It 'Parses boolean false variants' { |
| 40 | + $result = "a: false`nb: False`nc: no" | ConvertFrom-Yaml |
| 41 | + $result.a | Should -BeFalse |
| 42 | + $result.b | Should -BeFalse |
| 43 | + $result.c | Should -BeFalse |
| 44 | + } |
| 45 | + |
| 46 | + It 'Parses null values' { |
| 47 | + $result = "a: null`nb: ~`nc:" | ConvertFrom-Yaml |
| 48 | + $result.a | Should -BeNullOrEmpty |
| 49 | + $result.b | Should -BeNullOrEmpty |
| 50 | + $result.c | Should -BeNullOrEmpty |
| 51 | + } |
| 52 | + |
| 53 | + It 'Parses single-quoted strings preserving content' { |
| 54 | + $result = "value: 'true'" | ConvertFrom-Yaml |
| 55 | + $result.value | Should -Be 'true' |
| 56 | + $result.value | Should -BeOfType [string] |
| 57 | + } |
| 58 | + |
| 59 | + It 'Parses double-quoted strings preserving content' { |
| 60 | + $result = 'value: "42"' | ConvertFrom-Yaml |
| 61 | + $result.value | Should -Be '42' |
| 62 | + $result.value | Should -BeOfType [string] |
| 63 | + } |
| 64 | + |
| 65 | + It 'Handles double-quoted escape sequences' { |
| 66 | + $result = 'value: "line1\nline2\ttab"' | ConvertFrom-Yaml |
| 67 | + $result.value | Should -Be "line1`nline2`ttab" |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + Context 'Mappings' { |
| 72 | + It 'Parses a flat mapping into a PSCustomObject by default' { |
| 73 | + $yaml = @" |
| 74 | +name: Alice |
| 75 | +age: 30 |
| 76 | +"@ |
| 77 | + $result = $yaml | ConvertFrom-Yaml |
| 78 | + $result | Should -BeOfType [PSCustomObject] |
| 79 | + $result.name | Should -Be 'Alice' |
| 80 | + $result.age | Should -Be 30 |
| 81 | + } |
| 82 | + |
| 83 | + It 'Parses nested mappings' { |
| 84 | + $yaml = @" |
| 85 | +person: |
| 86 | + name: Alice |
| 87 | + address: |
| 88 | + city: Oslo |
| 89 | + country: Norway |
| 90 | +"@ |
| 91 | + $result = $yaml | ConvertFrom-Yaml |
| 92 | + $result.person.name | Should -Be 'Alice' |
| 93 | + $result.person.address.city | Should -Be 'Oslo' |
| 94 | + $result.person.address.country | Should -Be 'Norway' |
| 95 | + } |
| 96 | + |
| 97 | + It 'Preserves key insertion order' { |
| 98 | + $yaml = @" |
| 99 | +zebra: 1 |
| 100 | +apple: 2 |
| 101 | +mango: 3 |
| 102 | +"@ |
| 103 | + $result = $yaml | ConvertFrom-Yaml |
| 104 | + $names = $result.PSObject.Properties.Name |
| 105 | + $names[0] | Should -Be 'zebra' |
| 106 | + $names[1] | Should -Be 'apple' |
| 107 | + $names[2] | Should -Be 'mango' |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + Context 'Sequences' { |
| 112 | + It 'Parses a sequence of scalars' { |
| 113 | + $yaml = @" |
| 114 | +- one |
| 115 | +- two |
| 116 | +- three |
| 117 | +"@ |
| 118 | + $result = $yaml | ConvertFrom-Yaml -NoEnumerate |
| 119 | + $result.Count | Should -Be 3 |
| 120 | + $result[0] | Should -Be 'one' |
| 121 | + $result[2] | Should -Be 'three' |
| 122 | + } |
| 123 | + |
| 124 | + It 'Parses a sequence under a key' { |
| 125 | + $yaml = @" |
| 126 | +items: |
| 127 | + - apple |
| 128 | + - banana |
| 129 | + - cherry |
| 130 | +"@ |
| 131 | + $result = $yaml | ConvertFrom-Yaml |
| 132 | + $result.items.Count | Should -Be 3 |
| 133 | + $result.items[1] | Should -Be 'banana' |
| 134 | + } |
| 135 | + |
| 136 | + It 'Parses a sequence of mappings' { |
| 137 | + $yaml = @" |
| 138 | +people: |
| 139 | + - name: Alice |
| 140 | + age: 30 |
| 141 | + - name: Bob |
| 142 | + age: 25 |
| 143 | +"@ |
| 144 | + $result = $yaml | ConvertFrom-Yaml |
| 145 | + $result.people.Count | Should -Be 2 |
| 146 | + $result.people[0].name | Should -Be 'Alice' |
| 147 | + $result.people[1].age | Should -Be 25 |
| 148 | + } |
| 149 | + } |
| 150 | + |
| 151 | + Context '-AsHashtable' { |
| 152 | + It 'Returns an ordered dictionary instead of PSCustomObject' { |
| 153 | + $result = "a: 1`nb: 2" | ConvertFrom-Yaml -AsHashtable |
| 154 | + $result | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] |
| 155 | + $result['a'] | Should -Be 1 |
| 156 | + $result['b'] | Should -Be 2 |
| 157 | + } |
| 158 | + |
| 159 | + It 'Returns nested structures as ordered dictionaries' { |
| 160 | + $yaml = @" |
| 161 | +outer: |
| 162 | + inner: |
| 163 | + leaf: value |
| 164 | +"@ |
| 165 | + $result = $yaml | ConvertFrom-Yaml -AsHashtable |
| 166 | + $result['outer'] | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] |
| 167 | + $result['outer']['inner']['leaf'] | Should -Be 'value' |
| 168 | + } |
| 169 | + |
| 170 | + It 'Preserves key insertion order' { |
| 171 | + $result = "zebra: 1`napple: 2" | ConvertFrom-Yaml -AsHashtable |
| 172 | + @($result.Keys)[0] | Should -Be 'zebra' |
| 173 | + @($result.Keys)[1] | Should -Be 'apple' |
| 174 | + } |
| 175 | + } |
| 176 | + |
| 177 | + Context '-NoEnumerate' { |
| 178 | + It 'Returns a single-element top-level sequence as an array when -NoEnumerate is set' { |
| 179 | + $yaml = "- only" |
| 180 | + $result = $yaml | ConvertFrom-Yaml -NoEnumerate |
| 181 | + ,$result | Should -BeOfType [System.Object[]] |
| 182 | + $result.Count | Should -Be 1 |
| 183 | + } |
| 184 | + } |
| 185 | + |
| 186 | + Context 'Frontmatter' { |
| 187 | + It 'Parses YAML between --- delimiters' { |
| 188 | + $content = @" |
| 189 | +--- |
| 190 | +title: Hello |
| 191 | +draft: false |
| 192 | +--- |
| 193 | +# Markdown body here |
| 194 | +
|
| 195 | +Some content. |
| 196 | +"@ |
| 197 | + $result = $content | ConvertFrom-Yaml |
| 198 | + $result.title | Should -Be 'Hello' |
| 199 | + $result.draft | Should -BeFalse |
| 200 | + } |
| 201 | + |
| 202 | + It 'Parses content that is only frontmatter' { |
| 203 | + $content = @" |
| 204 | +--- |
| 205 | +key: value |
| 206 | +--- |
| 207 | +"@ |
| 208 | + $result = $content | ConvertFrom-Yaml |
| 209 | + $result.key | Should -Be 'value' |
| 210 | + } |
| 211 | + } |
| 212 | + |
| 213 | + Context 'Comments and blank lines' { |
| 214 | + It 'Ignores full-line comments' { |
| 215 | + $yaml = @" |
| 216 | +# this is a comment |
| 217 | +name: Alice |
| 218 | +# another comment |
| 219 | +age: 30 |
| 220 | +"@ |
| 221 | + $result = $yaml | ConvertFrom-Yaml |
| 222 | + $result.name | Should -Be 'Alice' |
| 223 | + $result.age | Should -Be 30 |
| 224 | + } |
| 225 | + |
| 226 | + It 'Ignores inline comments after values' { |
| 227 | + $result = 'name: Alice # the user' | ConvertFrom-Yaml |
| 228 | + $result.name | Should -Be 'Alice' |
| 229 | + } |
| 230 | + |
| 231 | + It 'Ignores blank lines' { |
| 232 | + $yaml = @" |
| 233 | +name: Alice |
| 234 | +
|
| 235 | +age: 30 |
| 236 | +
|
| 237 | +"@ |
| 238 | + $result = $yaml | ConvertFrom-Yaml |
| 239 | + $result.name | Should -Be 'Alice' |
| 240 | + $result.age | Should -Be 30 |
| 241 | + } |
| 242 | + } |
| 243 | + |
| 244 | + Context '-Depth' { |
| 245 | + It 'Throws when nesting exceeds -Depth' { |
| 246 | + $yaml = @" |
| 247 | +a: |
| 248 | + b: |
| 249 | + c: |
| 250 | + d: value |
| 251 | +"@ |
| 252 | + { $yaml | ConvertFrom-Yaml -Depth 2 } | Should -Throw |
| 253 | + } |
| 254 | + |
| 255 | + It 'Allows nesting within -Depth' { |
| 256 | + $yaml = @" |
| 257 | +a: |
| 258 | + b: |
| 259 | + c: value |
| 260 | +"@ |
| 261 | + $result = $yaml | ConvertFrom-Yaml -Depth 5 |
| 262 | + $result.a.b.c | Should -Be 'value' |
| 263 | + } |
| 264 | + } |
| 265 | + |
| 266 | + Context 'Aliases' { |
| 267 | + It 'Has ConvertFrom-Yml as an alias' { |
| 268 | + (Get-Alias -Name ConvertFrom-Yml -ErrorAction SilentlyContinue).ResolvedCommand.Name | |
| 269 | + Should -Be 'ConvertFrom-Yaml' |
| 270 | + } |
| 271 | + } |
| 272 | +} |
0 commit comments