diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ab8b35..82ab566 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- `Get-FileVersion` + - New public command to return the version information for a file. This command + returns the full `System.Diagnostics.FileVersionInfo` object. + +### Changed + +- Updated build scripts to Sampler 0.119.0-preview0005. +- `Get-FileProductVersion` + - Changed to use the new `Get-FileVersion` command internally instead of + directly accessing `Get-Item` and `VersionInfo`. + ### Fixed - New-*Exception @@ -16,10 +29,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 TurnOffTypeChecking is used [#184](https://github.com/dsccommunity/DscResource.Common/issues/184). - Fix typo in `Clear-ZeroedEnumPropertyValue` help text. Fixes [#181](https://github.com/dsccommunity/DscResource.Common/issues/181). -### Changed - -- Updated build scripts to Sampler 0.119.0-preview0005. - ## [0.24.2] - 2025-08-27 ### Changed diff --git a/source/Private/Assert-RequiredCommandParameter.ps1 b/source/Private/Assert-RequiredCommandParameter.ps1 index 2cca6ea..f841c48 100644 --- a/source/Private/Assert-RequiredCommandParameter.ps1 +++ b/source/Private/Assert-RequiredCommandParameter.ps1 @@ -92,12 +92,7 @@ function Assert-RequiredCommandParameter } $PSCmdlet.ThrowTerminatingError( - [System.Management.Automation.ErrorRecord]::new( - $errorMessage, - 'ARCP0001', # cspell: disable-line - [System.Management.Automation.ErrorCategory]::InvalidOperation, - 'Command parameters' - ) + (New-ErrorRecord -Exception $errorMessage -ErrorId 'ARCP0001' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidOperation) -TargetObject 'Command parameters') ) } } @@ -123,12 +118,7 @@ function Assert-RequiredCommandParameter } $PSCmdlet.ThrowTerminatingError( - [System.Management.Automation.ErrorRecord]::new( - $errorMessage, - 'ARCP0002', # cspell: disable-line - [System.Management.Automation.ErrorCategory]::InvalidOperation, - 'Command parameters' - ) + (New-ErrorRecord -Exception $errorMessage -ErrorId 'ARCP0002' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidOperation) -TargetObject 'Command parameters') ) } diff --git a/source/Public/Assert-ElevatedUser.ps1 b/source/Public/Assert-ElevatedUser.ps1 index 3825799..69f0c27 100644 --- a/source/Public/Assert-ElevatedUser.ps1 +++ b/source/Public/Assert-ElevatedUser.ps1 @@ -56,12 +56,7 @@ function Assert-ElevatedUser if (-not $isElevated) { $PSCmdlet.ThrowTerminatingError( - [System.Management.Automation.ErrorRecord]::new( - $ErrorMessage, - 'UserNotElevated', - [System.Management.Automation.ErrorCategory]::InvalidOperation, - 'Command parameters' - ) + (New-ErrorRecord -Exception $ErrorMessage -ErrorId 'UserNotElevated' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidOperation) -TargetObject 'Command parameters') ) } } diff --git a/source/Public/Get-FileProductVersion.ps1 b/source/Public/Get-FileProductVersion.ps1 index 68154e3..02f327d 100644 --- a/source/Public/Get-FileProductVersion.ps1 +++ b/source/Public/Get-FileProductVersion.ps1 @@ -13,6 +13,14 @@ Get-FileProductVersion -Path 'C:\Temp\setup.exe' Returns the product version of the file setup.exe as a System.Version object. + + .INPUTS + None. + + .OUTPUTS + `System.Version` + + Returns the product version as a System.Version object. #> function Get-FileProductVersion { @@ -27,14 +35,30 @@ function Get-FileProductVersion try { - $fileItem = Get-Item -Path $Path -ErrorAction 'Stop' - - return [System.Version] $fileItem.VersionInfo.ProductVersion + $fileVersionInfo = Get-FileVersion -Path $Path -ErrorAction 'Stop' } catch { $errorMessage = $script:localizedData.Get_FileProductVersion_GetFileProductVersionError -f $Path, $_.Exception.Message + $exception = New-Exception -Message $errorMessage -ErrorRecord $_ + + $PSCmdlet.ThrowTerminatingError( + (New-ErrorRecord -Exception $exception -ErrorId 'GFPV0001' -ErrorCategory ([System.Management.Automation.ErrorCategory]::ReadError) -TargetObject $Path) # cSpell: disable-line + ) + } + + $productVersionString = $fileVersionInfo.ProductVersion - Write-Error -Message $errorMessage + $parsedVersion = $null + if (-not [System.Version]::TryParse($productVersionString, [ref] $parsedVersion)) + { + $errorMessage = $script:localizedData.Get_FileProductVersion_InvalidVersionFormat -f $productVersionString, $Path + $exception = New-Exception -Message $errorMessage + + $PSCmdlet.ThrowTerminatingError( + (New-ErrorRecord -Exception $exception -ErrorId 'GFPV0002' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject $Path) # cSpell: disable-line + ) } + + return $parsedVersion } diff --git a/source/Public/Get-FileVersion.ps1 b/source/Public/Get-FileVersion.ps1 new file mode 100644 index 0000000..a71be10 --- /dev/null +++ b/source/Public/Get-FileVersion.ps1 @@ -0,0 +1,67 @@ +<# + .SYNOPSIS + Returns the version information for a file. + + .DESCRIPTION + Returns the version information for a file including the product version, + file version, and other version-related metadata. + + .PARAMETER Path + Specifies the file for which to return the version information. + + .EXAMPLE + Get-FileVersion -Path 'E:\setup.exe' + + Returns the version information for the file setup.exe. + + .EXAMPLE + Get-Item -Path 'E:\setup.exe' | Get-FileVersion + + Returns the version information for the file setup.exe using pipeline input. + + .EXAMPLE + 'E:\setup.exe' | Get-FileVersion + + Returns the version information for the file setup.exe using pipeline input. + + .INPUTS + System.IO.FileInfo + + Accepts a file path via the pipeline. + + .INPUTS + System.String + + Accepts a string path via the pipeline. + + .OUTPUTS + System.Diagnostics.FileVersionInfo + + Returns the file version information. +#> +function Get-FileVersion +{ + [OutputType([System.Diagnostics.FileVersionInfo])] + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [Alias('FullName')] + [System.IO.FileInfo] + $Path + ) + + process + { + $file = Get-Item -Path $Path -ErrorAction 'Stop' + + if ($file.PSIsContainer) + { + $PSCmdlet.ThrowTerminatingError( + (New-ErrorRecord -Exception ($script:localizedData.Get_FileVersion_PathIsNotFile -f $file.FullName) -ErrorId 'GFV0001' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidArgument) -TargetObject $file.FullName) # cSpell: disable-line + ) + } + + $file.VersionInfo + } +} diff --git a/source/Public/Get-PSModulePath.ps1 b/source/Public/Get-PSModulePath.ps1 index 2a5ba0a..30e7f82 100644 --- a/source/Public/Get-PSModulePath.ps1 +++ b/source/Public/Get-PSModulePath.ps1 @@ -135,12 +135,7 @@ function Get-PSModulePath if ([System.String]::IsNullOrEmpty($documentsFolder)) { $PSCmdlet.ThrowTerminatingError( - [System.Management.Automation.ErrorRecord]::new( - ($script:localizedData.PSModulePath_MissingMyDocumentsPath -f (Get-UserName)), - 'MissingMyDocumentsPath', - [System.Management.Automation.ErrorCategory]::ResourceUnavailable, - (Get-UserName) - ) + (New-ErrorRecord -Exception ($script:localizedData.PSModulePath_MissingMyDocumentsPath -f (Get-UserName)) -ErrorId 'MissingMyDocumentsPath' -ErrorCategory ([System.Management.Automation.ErrorCategory]::ResourceUnavailable) -TargetObject (Get-UserName)) ) } diff --git a/source/Public/New-ErrorRecord.ps1 b/source/Public/New-ErrorRecord.ps1 index 87875cf..163d37b 100644 --- a/source/Public/New-ErrorRecord.ps1 +++ b/source/Public/New-ErrorRecord.ps1 @@ -52,7 +52,7 @@ [System.Management.Automation.ErrorCategory]::InvalidOperation, $null ) - $newException = [System.Exception]::new('New error') + $newException = New-Exception -Message 'New error' $newErrorRecord = New-ErrorRecord -ErrorRecord $existingErrorRecord -Exception $newException $newErrorRecord.Exception.Message diff --git a/source/en-US/DscResource.Common.strings.psd1 b/source/en-US/DscResource.Common.strings.psd1 index 4b12139..5294def 100644 --- a/source/en-US/DscResource.Common.strings.psd1 +++ b/source/en-US/DscResource.Common.strings.psd1 @@ -55,7 +55,11 @@ ConvertFrom-StringData @' SearchingForCertificateUsingFilters = Looking for certificate in Store '{0}' using filter '{1}'. (DRC0047) ## Get-FileProductVersion - Get_FileProductVersion_GetFileProductVersionError = Failed to get product version for file '{0}'. Error: {1} + Get_FileProductVersion_GetFileProductVersionError = Failed to get product version for file '{0}'. Error: {1} (GFPV0001) + Get_FileProductVersion_InvalidVersionFormat = The product version '{0}' for file '{1}' is not a valid version string. (GFPV0002) + + ## Get-FileVersion + Get_FileVersion_PathIsNotFile = The specified path is not a file. (GFV0001) ## Get-PSModulePath PSModulePath_MissingMyDocumentsPath = The My Documents folder does not exist for user '{0}'. (DRC0048) diff --git a/tests/Integration/Commands/Get-FileVersion.Integration.Tests.ps1 b/tests/Integration/Commands/Get-FileVersion.Integration.Tests.ps1 new file mode 100644 index 0000000..2981bc9 --- /dev/null +++ b/tests/Integration/Commands/Get-FileVersion.Integration.Tests.ps1 @@ -0,0 +1,112 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies have not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks noop" first to set up the test environment.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.Common' + + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' +} + +Describe 'Get-FileVersion' -Tag 'Integration' { + Context 'When running on Windows' -Skip:(-not $IsWindows) { + Context 'When getting version information from notepad.exe' { + BeforeAll { + $script:notepadPath = Join-Path -Path $env:SystemRoot -ChildPath 'System32\notepad.exe' + } + + It 'Should return version information for notepad.exe' { + $result = Get-FileVersion -Path $script:notepadPath -ErrorAction Stop + + $result | Should -Not -BeNullOrEmpty + $result | Should -BeOfType [System.Diagnostics.FileVersionInfo] + $result.ProductVersion | Should -Not -BeNullOrEmpty + $result.FileVersion | Should -Not -BeNullOrEmpty + } + + It 'Should return version information using pipeline input' { + $result = $script:notepadPath | Get-FileVersion -ErrorAction Stop + + $result | Should -Not -BeNullOrEmpty + $result | Should -BeOfType [System.Diagnostics.FileVersionInfo] + $result.ProductVersion | Should -Not -BeNullOrEmpty + } + + It 'Should return version information using Get-Item pipeline input' { + $result = Get-Item -Path $script:notepadPath | Get-FileVersion -ErrorAction Stop + + $result | Should -Not -BeNullOrEmpty + $result | Should -BeOfType [System.Diagnostics.FileVersionInfo] + $result.ProductVersion | Should -Not -BeNullOrEmpty + } + } + + Context 'When getting version information from powershell.exe' { + BeforeAll { + $script:powershellPath = Join-Path -Path $env:SystemRoot -ChildPath 'System32\WindowsPowerShell\v1.0\powershell.exe' + } + + It 'Should return version information for powershell.exe' { + $result = Get-FileVersion -Path $script:powershellPath -ErrorAction Stop + + $result | Should -Not -BeNullOrEmpty + $result | Should -BeOfType [System.Diagnostics.FileVersionInfo] + $result.ProductVersion | Should -Not -BeNullOrEmpty + $result.FileVersion | Should -Not -BeNullOrEmpty + $result.ProductName | Should -Not -BeNullOrEmpty + } + } + + Context 'When passing an invalid path' { + It 'Should throw an error for non-existent file' { + { Get-FileVersion -Path 'C:\NonExistent\File.exe' -ErrorAction Stop } | + Should -Throw + } + } + + Context 'When passing a directory path' { + It 'Should throw the correct error' { + { Get-FileVersion -Path $env:SystemRoot -ErrorAction Stop } | + Should -Throw + } + } + } + + Context 'When running on non-Windows platforms' -Skip:($IsWindows -or $PSVersionTable.PSVersion.Major -lt 6) { + Context 'When getting version information from a shell executable' -Skip:(-not (Test-Path -Path '/bin/bash')) { + BeforeAll { + $script:bashPath = '/bin/bash' + } + + It 'Should handle Unix executables appropriately' { + # Unix executables typically don't have version info like Windows executables + # This test verifies the command can be called without error + $result = Get-FileVersion -Path $script:bashPath -ErrorAction 'Stop' + + # Result may be null or empty on Unix systems + $result | Should -BeOfType [System.Diagnostics.FileVersionInfo] + } + } + } +} diff --git a/tests/Unit/Public/Get-FileProductVersion.Tests.ps1 b/tests/Unit/Public/Get-FileProductVersion.Tests.ps1 index 1d01998..bdabc6a 100644 --- a/tests/Unit/Public/Get-FileProductVersion.Tests.ps1 +++ b/tests/Unit/Public/Get-FileProductVersion.Tests.ps1 @@ -46,20 +46,45 @@ AfterAll { } Describe 'Get-FileProductVersion' { - Context 'When the file exists and has a product version' { + BeforeDiscovery { + $parameterSetTestCases = @( + @{ + ExpectedParameterSetName = '__AllParameterSets' + ExpectedParameters = '[-Path] []' + } + ) + } + + It 'Should have the correct parameters in parameter set ' -ForEach $parameterSetTestCases { + $result = (Get-Command -Name 'Get-FileProductVersion').ParameterSets | + Where-Object -FilterScript { $_.Name -eq $ExpectedParameterSetName } | + Select-Object -Property @( + @{ Name = 'ParameterSetName'; Expression = { $_.Name } }, + @{ Name = 'ParameterListAsString'; Expression = { $_.ToString() } } + ) + + $result.ParameterSetName | Should -Be $ExpectedParameterSetName + $result.ParameterListAsString | Should -Be $ExpectedParameters + } + + It 'Should have Path as a mandatory parameter' { + $parameterInfo = (Get-Command -Name 'Get-FileProductVersion').Parameters['Path'] + + $parameterInfo.Attributes.Mandatory | Should -BeTrue + } + + Context 'When the file exists and has a product version as a string' { BeforeAll { - Mock -CommandName Get-Item -MockWith { + Mock -CommandName Get-FileVersion -MockWith { return [PSCustomObject] @{ - Exists = $true - VersionInfo = [PSCustomObject] @{ - ProductVersion = '15.0.2000.5' - } + ProductVersion = '15.0.2000.5' } } } It 'Should return the correct product version as a System.Version object' { $result = Get-FileProductVersion -Path (Join-Path -Path $TestDrive -ChildPath 'testfile.dll') + $result | Should -BeOfType [System.Version] $result.Major | Should -Be 15 $result.Minor | Should -Be 0 @@ -68,23 +93,75 @@ Describe 'Get-FileProductVersion' { } } - Context 'When Get-Item throws an exception' { + Context 'When the file has a product version as a System.Version object' { BeforeAll { - Mock -CommandName Get-Item -MockWith { - throw 'Mock exception message' + Mock -CommandName Get-FileVersion -MockWith { + return [PSCustomObject] @{ + ProductVersion = [System.Version] '10.5.3.2' + } + } + } + + It 'Should return the correct product version as a System.Version object' { + $result = Get-FileProductVersion -Path (Join-Path -Path $TestDrive -ChildPath 'testfile.dll') + + $result | Should -BeOfType [System.Version] + $result.Major | Should -Be 10 + $result.Minor | Should -Be 5 + $result.Build | Should -Be 3 + $result.Revision | Should -Be 2 + } + } + + Context 'When the file has a non-numeric product version' { + BeforeAll { + Mock -CommandName Get-FileVersion -MockWith { + return [PSCustomObject] @{ + ProductVersion = 'Not-A-Version-String' + } } } - It 'Should throw the correct error' { + It 'Should throw a terminating error with the correct error message' { $mockFilePath = Join-Path -Path $TestDrive -ChildPath 'testfile.dll' - $mockGetFileProductVersionErrorMessage = InModuleScope -ScriptBlock { - $script:localizedData.Get_FileProductVersion_GetFileProductVersionError + $mockInvalidVersionFormatMessage = InModuleScope -ScriptBlock { + $script:localizedData.Get_FileProductVersion_InvalidVersionFormat } { Get-FileProductVersion -Path $mockFilePath -ErrorAction 'Stop' - } | Should -Throw ($mockGetFileProductVersionErrorMessage -f $mockFilePath, 'Mock exception message') + } | Should -Throw ($mockInvalidVersionFormatMessage -f 'Not-A-Version-String', $mockFilePath) + } + + It 'Should throw an error with the correct error ID' { + $mockFilePath = Join-Path -Path $TestDrive -ChildPath 'testfile.dll' + + $result = { + Get-FileProductVersion -Path $mockFilePath -ErrorAction 'Stop' + } | Should -Throw -PassThru + + # Verify the error ID is GFPV0002 for invalid version format + $result.FullyQualifiedErrorId | Should -BeLike 'GFPV0002,*' + } + } + + Context 'When Get-FileVersion throws an exception' { + BeforeAll { + Mock -CommandName Get-FileVersion -MockWith { + throw 'Mock exception message' + } + } + + It 'Should throw an error with the correct error ID' { + $mockFilePath = Join-Path -Path $TestDrive -ChildPath 'testfile.dll' + + $result = { + Get-FileProductVersion -Path $mockFilePath -ErrorAction 'Stop' + } | Should -Throw -PassThru + + # Verify the error ID is correct + $result.FullyQualifiedErrorId | Should -BeLike 'GFPV0001,*' } } } diff --git a/tests/Unit/Public/Get-FileVersion.Tests.ps1 b/tests/Unit/Public/Get-FileVersion.Tests.ps1 new file mode 100644 index 0000000..5afc9c4 --- /dev/null +++ b/tests/Unit/Public/Get-FileVersion.Tests.ps1 @@ -0,0 +1,203 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies have not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.Common' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Remove-Module -Name $script:moduleName +} + +Describe 'Get-FileVersion' -Tag 'Public' { + Context 'When passing path as string' { + BeforeAll { + $script:mockFilePath = (New-Item -Path $TestDrive -Name 'setup.exe' -ItemType 'File' -Force).FullName + + Mock -CommandName Get-Item -MockWith { + return @{ + PSIsContainer = $false + FullName = $mockFilePath + VersionInfo = @{ + ProductVersion = '16.0.1000.6' + FileVersion = '2022.160.1000.6' + ProductName = 'Microsoft SQL Server' + } + } + } + } + + Context 'When passing as a named parameter' { + It 'Should return the correct result' { + $result = Get-FileVersion -Path $mockFilePath + + $result.ProductVersion | Should -Be '16.0.1000.6' + } + } + + Context 'When passing over the pipeline' { + It 'Should return the correct result' { + $result = $mockFilePath | Get-FileVersion + + $result.ProductVersion | Should -Be '16.0.1000.6' + } + } + } + + Context 'When passing path as the type FileInfo' { + BeforeAll { + $script:mockFilePath = (New-Item -Path $TestDrive -Name 'setup.exe' -ItemType 'File' -Force).FullName + $script:mockFileInfo = [System.IO.FileInfo]::new($script:mockFilePath) + + Mock -CommandName Get-Item -MockWith { + # Create a mock object that looks like a FileInfo with VersionInfo + $mockVersionInfo = [PSCustomObject]@{ + ProductVersion = '16.0.1000.6' + FileVersion = '2022.160.1000.6' + ProductName = 'Microsoft SQL Server' + } + + $mockItem = [PSCustomObject]@{ + PSIsContainer = $false + FullName = $mockFilePath + VersionInfo = $mockVersionInfo + } + + return $mockItem + } + } + + Context 'When passing as a named parameter' { + It 'Should return the correct result' { + $result = Get-FileVersion -Path $mockFileInfo + + $result.ProductVersion | Should -Be '16.0.1000.6' + } + } + + Context 'When passing over the pipeline' { + It 'Should return the correct result' { + $result = $mockFileInfo | Get-FileVersion + + $result.ProductVersion | Should -Be '16.0.1000.6' + } + } + } + + Context 'When passing in a FileInfo that represents a directory' { + BeforeAll { + Mock -CommandName Get-Item -MockWith { + return @{ + PSIsContainer = $true + FullName = $TestDrive + } + } + + $localizedString = InModuleScope -ScriptBlock { + $script:localizedData.Get_FileVersion_PathIsNotFile + } + + $script:expectedMessage = $localizedString -f $TestDrive + } + + It 'Should throw the correct error' { + { [System.IO.FileInfo] $TestDrive | Get-FileVersion } | + Should -Throw -ExpectedMessage $script:expectedMessage + } + } + + Context 'When passing in a directory that was accessed from Get-Item' { + BeforeAll { + $localizedString = InModuleScope -ScriptBlock { + $script:localizedData.Get_FileVersion_PathIsNotFile + } + + $script:expectedMessage = $localizedString -f $TestDrive + } + + It 'Should throw the correct error' { + { Get-Item -Path $TestDrive | Get-FileVersion -ErrorAction 'Stop' } | + Should -Throw -ExpectedMessage $script:expectedMessage + } + } + + Context 'When validating parameter sets' { + BeforeDiscovery { + $parameterSetTestCases = @( + @{ + ExpectedParameterSetName = '__AllParameterSets' + ExpectedParameters = '[-Path] []' + } + ) + } + + It 'Should have the correct parameters in parameter set ' -ForEach $parameterSetTestCases { + $result = (Get-Command -Name 'Get-FileVersion').ParameterSets | + Where-Object -FilterScript { $_.Name -eq $ExpectedParameterSetName } | + Select-Object -Property @( + @{ Name = 'ParameterSetName'; Expression = { $_.Name } }, + @{ Name = 'ParameterListAsString'; Expression = { $_.ToString() } } + ) + $result.ParameterSetName | Should -Be $ExpectedParameterSetName + $result.ParameterListAsString | Should -Be $ExpectedParameters + } + } + + Context 'When validating parameter properties' { + It 'Should have Path as a mandatory parameter' { + $parameterInfo = (Get-Command -Name 'Get-FileVersion').Parameters['Path'] + $parameterInfo.Attributes.Mandatory | Should -BeTrue + } + + It 'Should accept pipeline input for Path parameter' { + $parameterInfo = (Get-Command -Name 'Get-FileVersion').Parameters['Path'] + $parameterInfo.Attributes.ValueFromPipeline | Should -Not -Contain $false + } + + It 'Should accept pipeline input by property name for Path parameter' { + $parameterInfo = (Get-Command -Name 'Get-FileVersion').Parameters['Path'] + $parameterInfo.Attributes.ValueFromPipelineByPropertyName | Should -Not -Contain $false + } + + It 'Should have FullName as an alias for Path parameter' { + $parameterInfo = (Get-Command -Name 'Get-FileVersion').Parameters['Path'] + $parameterInfo.Aliases | Should -Contain 'FullName' + } + } +} diff --git a/tests/Unit/Public/New-ErrorRecord.Tests.ps1 b/tests/Unit/Public/New-ErrorRecord.Tests.ps1 index 04515ef..befbf77 100644 --- a/tests/Unit/Public/New-ErrorRecord.Tests.ps1 +++ b/tests/Unit/Public/New-ErrorRecord.Tests.ps1 @@ -48,13 +48,9 @@ AfterAll { Describe 'New-ErrorRecord' { Context 'ErrorRecord parameter set' { It 'creates a new ErrorRecord based on an existing one and an exception' { - $existingErrorRecord = [System.Management.Automation.ErrorRecord]::new( - [System.Management.Automation.ParentContainsErrorRecordException]::new('Existing error'), - 'ExistingErrorId', - [System.Management.Automation.ErrorCategory]::InvalidOperation, - $null - ) - $newException = [System.Exception]::new('New error') + $existingException = [System.Management.Automation.ParentContainsErrorRecordException]::new('Existing error') + $existingErrorRecord = New-ErrorRecord -Exception $existingException -ErrorId 'ExistingErrorId' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidOperation) -TargetObject $null + $newException = New-Exception -Message 'New error' $newErrorRecord = New-ErrorRecord -ErrorRecord $existingErrorRecord -Exception $newException $newErrorRecord.Exception.Message | Should -Be 'New error' @@ -65,7 +61,7 @@ Describe 'New-ErrorRecord' { Context 'Exception parameter set' { It 'creates a new ErrorRecord based on an exception, an error category, a target object, and an error ID' { - $exception = [System.Exception]::new('An error occurred.') + $exception = New-Exception -Message 'An error occurred.' $targetObject = New-Object -TypeName PSObject $errorRecord = New-ErrorRecord -Exception $exception -ErrorCategory 'InvalidOperation' -TargetObject $targetObject -ErrorId 'MyErrorId'