Skip to content

Commit aa3e377

Browse files
authored
Add support for method NormalizeProperties (#28)
1 parent 1790004 commit aa3e377

File tree

3 files changed

+147
-9
lines changed

3 files changed

+147
-9
lines changed

CHANGELOG.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
55

66
## [Unreleased]
77

8+
### Added
9+
10+
- `ResourceBase`
11+
- Added a new method `NormalizeProperties` that can be overridden in a
12+
derived class to provide custom normalization logic. This method can
13+
be used to normalize the properties of a desired state prior to the
14+
methods `AssertProperties`, `GetCurrentState`, and `Modify` being called.
15+
Default there is no normalization of properties. Fixes [issue #27](https://github.com/dsccommunity/DscResource.Base/issues/27).
16+
817
## [1.2.1] - 2025-02-03
918

1019
### Changed
@@ -16,7 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1625

1726
### Added
1827

19-
- `Resource.Base`
28+
- `ResourceBase`
2029
- Add optional feature flag to handle using Enums as optional properties.
2130
This requires setting the starting value of the Enum to 1 so it is
2231
initialized as 0. Fixes [Issue #22](https://github.com/dsccommunity/DscResource.Base/issues/22).

source/Classes/010.ResourceBase.ps1

+30-8
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class ResourceBase
5858

5959
[ResourceBase] Get()
6060
{
61+
$this.Normalize()
62+
6163
$this.Assert()
6264

6365
# Get all key properties.
@@ -135,6 +137,8 @@ class ResourceBase
135137

136138
[void] Set()
137139
{
140+
$this.Normalize()
141+
138142
# Get all key properties.
139143
$keyProperty = $this | Get-DscProperty -Attribute 'Key'
140144

@@ -171,6 +175,8 @@ class ResourceBase
171175

172176
[System.Boolean] Test()
173177
{
178+
$this.Normalize()
179+
174180
# Get all key properties.
175181
$keyProperty = $this | Get-DscProperty -Attribute 'Key'
176182

@@ -227,13 +233,7 @@ class ResourceBase
227233
#>
228234
hidden [System.Collections.Hashtable[]] Compare([System.Collections.Hashtable] $currentState, [System.String[]] $excludeProperties)
229235
{
230-
# Get the desired state, all assigned properties that has an non-null value.
231-
$desiredState = $this | Get-DscProperty -Attribute @('Key', 'Mandatory', 'Optional') -HasValue
232-
233-
if ($this.FeatureOptionalEnums)
234-
{
235-
$desiredState = $desiredState | Clear-ZeroedEnumPropertyValue
236-
}
236+
$desiredState = $this.GetDesiredState()
237237

238238
$CompareDscParameterState = @{
239239
CurrentValues = $currentState
@@ -254,6 +254,18 @@ class ResourceBase
254254

255255
# This method should normally not be overridden.
256256
hidden [void] Assert()
257+
{
258+
$this.AssertProperties($this.GetDesiredState())
259+
}
260+
261+
# This method should normally not be overridden.
262+
hidden [void] Normalize()
263+
{
264+
$this.NormalizeProperties($this.GetDesiredState())
265+
}
266+
267+
# This is a private method and should normally not be overridden.
268+
hidden [System.Collections.Hashtable] GetDesiredState()
257269
{
258270
# Get the properties that has a non-null value and is not of type Read.
259271
$desiredState = $this | Get-DscProperty -Attribute @('Key', 'Mandatory', 'Optional') -HasValue
@@ -263,7 +275,7 @@ class ResourceBase
263275
$desiredState = $desiredState | Clear-ZeroedEnumPropertyValue
264276
}
265277

266-
$this.AssertProperties($desiredState)
278+
return $desiredState
267279
}
268280

269281
<#
@@ -276,6 +288,16 @@ class ResourceBase
276288
{
277289
}
278290

291+
<#
292+
This method can be overridden if resource specific property normalization
293+
is needed. The parameter properties will contain the properties that was
294+
assigned a value.
295+
#>
296+
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('AvoidEmptyNamedBlocks', '')]
297+
hidden [void] NormalizeProperties([System.Collections.Hashtable] $properties)
298+
{
299+
}
300+
279301
<#
280302
This method must be overridden by a resource. The parameter properties will
281303
contain the properties that should be enforced and that are not in desired

tests/Unit/Classes/ResourceBase.Tests.ps1

+107
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,22 @@ Describe 'ResourceBase\AssertProperties()' -Tag 'AssertProperties' {
122122
}
123123
}
124124

125+
Describe 'ResourceBase\NormalizeProperties()' -Tag 'NormalizeProperties' {
126+
BeforeAll {
127+
$mockResourceBaseInstance = InModuleScope -ScriptBlock {
128+
[ResourceBase]::new()
129+
}
130+
}
131+
132+
It 'Should not throw' {
133+
$mockDesiredState = @{
134+
MyProperty1 = 'MyValue1'
135+
}
136+
137+
{ $mockResourceBaseInstance.NormalizeProperties($mockDesiredState) } | Should -Not -Throw
138+
}
139+
}
140+
125141
Describe 'ResourceBase\Assert()' -Tag 'Assert' {
126142
Context 'When the system is in the desired state' {
127143
BeforeAll {
@@ -213,6 +229,97 @@ $script:mockResourceBaseInstance = [MyMockResource]::new()
213229
}
214230
}
215231

232+
Describe 'ResourceBase\Normalize()' -Tag 'Normalize' {
233+
Context 'When the system is in the desired state' {
234+
BeforeAll {
235+
Mock -CommandName Get-ClassName -MockWith {
236+
# Only return localized strings for this class name.
237+
@('ResourceBase')
238+
}
239+
240+
Mock -CommandName Get-DscProperty -MockWith {
241+
return @{
242+
MyResourceKeyProperty1 = 'SomeString'
243+
}
244+
}
245+
246+
Mock -CommandName Clear-ZeroedEnumPropertyValue
247+
248+
$inModuleScopeScriptBlock = @'
249+
using module DscResource.Base
250+
251+
enum MyMockEnum {
252+
Value1 = 1
253+
Value2
254+
Value3
255+
Value4
256+
}
257+
258+
class MyMockResource : ResourceBase
259+
{
260+
[DscProperty(Key)]
261+
[System.String]
262+
$MyResourceKeyProperty1
263+
264+
[DscProperty()]
265+
[System.String]
266+
$MyResourceProperty2
267+
268+
[DscProperty()]
269+
[MyMockEnum]
270+
$MyResourceProperty3
271+
272+
[DscProperty()]
273+
[MyMockEnum]
274+
$MyResourceProperty4 = [MyMockEnum]::Value4
275+
276+
[DscProperty(NotConfigurable)]
277+
[System.String]
278+
$MyResourceReadProperty
279+
280+
MyMockResource () {
281+
$this.FeatureOptionalEnums = $true
282+
}
283+
284+
[ResourceBase] Get()
285+
{
286+
# Creates a new instance of the mock instance MyMockResource.
287+
$currentStateInstance = [System.Activator]::CreateInstance($this.GetType())
288+
289+
$currentStateInstance.MyResourceProperty2 = 'MyValue1'
290+
$currentStateInstance.MyResourceProperty4 = [MyMockEnum]::Value4
291+
$currentStateInstance.MyResourceReadProperty = 'MyReadValue1'
292+
293+
return $currentStateInstance
294+
}
295+
}
296+
297+
$script:mockResourceBaseInstance = [MyMockResource]::new()
298+
'@
299+
300+
InModuleScope -ScriptBlock ([Scriptblock]::Create($inModuleScopeScriptBlock))
301+
}
302+
303+
It 'Should have correctly instantiated the resource class' {
304+
InModuleScope -ScriptBlock {
305+
$mockResourceBaseInstance | Should -Not -BeNullOrEmpty
306+
$mockResourceBaseInstance.GetType().BaseType.Name | Should -Be 'ResourceBase'
307+
}
308+
}
309+
310+
Context 'When no properties are enforced' {
311+
It 'Should not return any property to enforce' {
312+
InModuleScope -ScriptBlock {
313+
$mockResourceBaseInstance.Normalize()
314+
}
315+
316+
Should -Invoke -CommandName Get-DscProperty -Exactly -Times 1 -Scope It
317+
Should -Invoke -CommandName Clear-ZeroedEnumPropertyValue -Exactly -Times 1 -Scope It
318+
}
319+
}
320+
}
321+
}
322+
216323
Describe 'ResourceBase\Get()' -Tag 'Get' {
217324
Context 'When the system is in the desired state' {
218325
BeforeAll {

0 commit comments

Comments
 (0)