diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..f20a0fb --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,51 @@ +name: PowerShell Archive Module Tests + +on: + push: + branches: [ master, servicing ] + pull_request: + branches: [ master, servicing ] + workflow_dispatch: + +jobs: + test: + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + + runs-on: ${{ matrix.os }} + + name: Test on ${{ matrix.os }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Install Pester + shell: pwsh + run: | + if (!(Get-Module -ListAvailable -Name Pester | Where-Object {$_.Version -le "4.99" -and $_.Version -ge "4.0"})) { + Install-Module -Name Pester -Force -SkipPublisherCheck -MaximumVersion 4.99 + } + + Import-Module "Pester" -MaximumVersion "4.99" + + - name: Run Tests + shell: pwsh + run: | + Get-Module "Pester" + $testResultsFile = "./ArchiveTestResults.xml" + Import-Module "./Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1" -Force + $testResults = Invoke-Pester -Script "./Tests" -OutputFormat NUnitXml -OutputFile $testResultsFile -PassThru + if ($testResults.FailedCount -gt 0) { + throw "$($testResults.FailedCount) tests failed." + } + + - name: Upload test results + uses: actions/upload-artifact@v4 + if: always() + with: + name: test-results-${{ matrix.os }} + path: ArchiveTestResults.xml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7c69a18..0000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: csharp - -git: - depth: 1000 - -os: - - linux -sudo: required -dist: trusty - -matrix: - fast_finish: true - -install: - - git clone https://github.com/PowerShell/PowerShell.git - - pushd PowerShell/tools - - ./install-powershell.sh - - popd - -script: - - ulimit -n 4096 - - pwsh -File ./TravisCI.ps1 diff --git a/Tests/Pester.Commands.Cmdlets.Archive.Tests.ps1 b/Tests/Pester.Commands.Cmdlets.Archive.Tests.ps1 index 7c3c619..d7c9921 100644 --- a/Tests/Pester.Commands.Cmdlets.Archive.Tests.ps1 +++ b/Tests/Pester.Commands.Cmdlets.Archive.Tests.ps1 @@ -1,21 +1,24 @@ -<############################################################################################ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<############################################################################################ # File: Pester.Commands.Cmdlets.ArchiveTests.ps1 # Commands.Cmdlets.ArchiveTests suite contains Tests that are # used for validating Microsoft.PowerShell.Archive module. ############################################################################################> -$script:TestSourceRoot = $PSScriptRoot +$modPath = "$psscriptroot/Pester.Commands.Cmdlets.Archive.Tests.psm1" +Import-Module $modPath -Force -Verbose + $DS = [System.IO.Path]::DirectorySeparatorChar -if ($IsWindows -eq $null) { - $IsWindows = $PSVersionTable.PSEdition -eq "Desktop" -} Describe "Test suite for Microsoft.PowerShell.Archive module" -Tags "BVT" { BeforeAll { $originalProgressPref = $ProgressPreference $ProgressPreference = "SilentlyContinue" $originalPSModulePath = $env:PSModulePath + $testSourceRoot = $PSScriptRoot # make sure we use the one in this repo - $env:PSModulePath = "$($script:TestSourceRoot)\..;$($env:PSModulePath)" + $env:PSModulePath = "$($testSourceRoot)\..;$($env:PSModulePath)" New-Item $TestDrive$($DS)SourceDir -Type Directory | Out-Null New-Item $TestDrive$($DS)SourceDir$($DS)ChildDir-1 -Type Directory | Out-Null @@ -33,10 +36,10 @@ Describe "Test suite for Microsoft.PowerShell.Archive module" -Tags "BVT" { "Some Text" > $TestDrive$($DS)Sample.unzip "Some Text" > $TestDrive$($DS)Sample.cab - $preCreatedArchivePath = Join-Path $script:TestSourceRoot "SamplePreCreatedArchive.archive" + $preCreatedArchivePath = Join-Path $testSourceRoot "SamplePreCreatedArchive.archive" Copy-Item $preCreatedArchivePath $TestDrive$($DS)SamplePreCreatedArchive.zip -Force - $preCreatedArchivePath = Join-Path $script:TestSourceRoot "TrailingSpacer.archive" + $preCreatedArchivePath = Join-Path $testSourceRoot "TrailingSpacer.archive" Copy-Item $preCreatedArchivePath $TestDrive$($DS)TrailingSpacer.zip -Force } @@ -45,232 +48,6 @@ Describe "Test suite for Microsoft.PowerShell.Archive module" -Tags "BVT" { $env:PSModulePath = $originalPSModulePath } - function Add-CompressionAssemblies { - Add-Type -AssemblyName System.IO.Compression - if ($psedition -eq "Core") - { - Add-Type -AssemblyName System.IO.Compression.ZipFile - } - else - { - Add-Type -AssemblyName System.IO.Compression.FileSystem - } - } - - function CompressArchivePathParameterSetValidator { - param - ( - [string[]] $path, - [string] $destinationPath, - [string] $compressionLevel = "Optimal" - ) - - try - { - Compress-Archive -Path $path -DestinationPath $destinationPath -CompressionLevel $compressionLevel - throw "ValidateNotNullOrEmpty attribute is missing on one of parameters belonging to Path parameterset." - } - catch - { - $_.FullyQualifiedErrorId | Should Be "ParameterArgumentValidationError,Compress-Archive" - } - } - - function CompressArchiveLiteralPathParameterSetValidator { - param - ( - [string[]] $literalPath, - [string] $destinationPath, - [string] $compressionLevel = "Optimal" - ) - - try - { - Compress-Archive -LiteralPath $literalPath -DestinationPath $destinationPath -CompressionLevel $compressionLevel - throw "ValidateNotNullOrEmpty attribute is missing on one of parameters belonging to LiteralPath parameterset." - } - catch - { - $_.FullyQualifiedErrorId | Should Be "ParameterArgumentValidationError,Compress-Archive" - } - } - - - function CompressArchiveInValidPathValidator { - param - ( - [string[]] $path, - [string] $destinationPath, - [string] $invalidPath, - [string] $expectedFullyQualifiedErrorId - ) - - try - { - Compress-Archive -Path $path -DestinationPath $destinationPath - throw "Failed to validate that an invalid Path $invalidPath was supplied as input to Compress-Archive cmdlet." - } - catch - { - $_.FullyQualifiedErrorId | Should Be $expectedFullyQualifiedErrorId - } - } - - function CompressArchiveInValidArchiveFileExtensionValidator { - param - ( - [string[]] $path, - [string] $destinationPath, - [string] $invalidArchiveFileExtension - ) - - try - { - Compress-Archive -Path $path -DestinationPath $destinationPath - throw "Failed to validate that an invalid archive file format $invalidArchiveFileExtension was supplied as input to Compress-Archive cmdlet." - } - catch - { - $_.FullyQualifiedErrorId | Should Be "NotSupportedArchiveFileExtension,Compress-Archive" - } - } - - function Validate-ArchiveEntryCount { - param - ( - [string] $path, - [int] $expectedEntryCount - ) - - Add-CompressionAssemblies - try - { - $archiveFileStreamArgs = @($path, [System.IO.FileMode]::Open) - $archiveFileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $archiveFileStreamArgs - - $zipArchiveArgs = @($archiveFileStream, [System.IO.Compression.ZipArchiveMode]::Read, $false) - $zipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -ArgumentList $zipArchiveArgs - - $actualEntryCount = $zipArchive.Entries.Count - $actualEntryCount | Should Be $expectedEntryCount - } - finally - { - if ($null -ne $zipArchive) { $zipArchive.Dispose()} - if ($null -ne $archiveFileStream) { $archiveFileStream.Dispose() } - } - } - - function ArchiveFileEntryContentValidator { - param - ( - [string] $path, - [string] $entryFileName, - [string] $expectedEntryFileContent - ) - - Add-CompressionAssemblies - try - { - $destFile = "$TestDrive$($DS)ExpandedFile"+([System.Guid]::NewGuid().ToString())+".txt" - - $archiveFileStreamArgs = @($path, [System.IO.FileMode]::Open) - $archiveFileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $archiveFileStreamArgs - - $zipArchiveArgs = @($archiveFileStream, [System.IO.Compression.ZipArchiveMode]::Read, $false) - $zipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -ArgumentList $zipArchiveArgs - - $entryToBeUpdated = $zipArchive.Entries | ? {$_.FullName -eq $entryFileName.replace([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar)} - - if($entryToBeUpdated -ne $null) - { - $srcStream = $entryToBeUpdated.Open() - $destStream = New-Object "System.IO.FileStream" -ArgumentList( $destFile, [System.IO.FileMode]::Create ) - $srcStream.CopyTo( $destStream ) - $destStream.Dispose() - $srcStream.Dispose() - Get-Content $destFile | Should Be $expectedEntryFileContent - } - else - { - throw "Failed to find the file $entryFileName in the archive file $path" - } - } - finally - { - if ($zipArchive) - { - $zipArchive.Dispose() - } - if ($archiveFileStream) - { - $archiveFileStream.Dispose() - } - } - } - - function ArchiveFileEntrySeparatorValidator { - param - ( - [string] $path - ) - - Add-CompressionAssemblies - try - { - $destFile = "$TestDrive$($DS)ExpandedFile"+([System.Guid]::NewGuid().ToString())+".txt" - - $archiveFileStreamArgs = @($path, [System.IO.FileMode]::Open) - $archiveFileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $archiveFileStreamArgs - - $zipArchiveArgs = @($archiveFileStream, [System.IO.Compression.ZipArchiveMode]::Read, $false) - $zipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -ArgumentList $zipArchiveArgs - - $badEntries = $zipArchive.Entries | Where-Object {$_.FullName.Contains('\')} - - $badEntries.Count | Should Be 0 - } - finally - { - if ($zipArchive) - { - $zipArchive.Dispose() - } - if ($archiveFileStream) - { - $archiveFileStream.Dispose() - } - } - } - - function ExpandArchiveInvalidParameterValidator { - param - ( - [boolean] $isLiteralPathParameterSet, - [string[]] $path, - [string] $destinationPath, - [string] $expectedFullyQualifiedErrorId - ) - - try - { - if($isLiteralPathParameterSet) - { - Expand-Archive -LiteralPath $literalPath -DestinationPath $destinationPath - } - else - { - Expand-Archive -Path $path -DestinationPath $destinationPath - } - - throw "Expand-Archive did NOT throw expected error" - } - catch - { - $_.FullyQualifiedErrorId | Should Be $expectedFullyQualifiedErrorId - } - } - Context "Compress-Archive - Parameter validation test cases" { It "Validate errors from Compress-Archive with NULL & EMPTY values for Path, LiteralPath, DestinationPath, CompressionLevel parameters" { diff --git a/Tests/Pester.Commands.Cmdlets.Archive.Tests.psm1 b/Tests/Pester.Commands.Cmdlets.Archive.Tests.psm1 new file mode 100644 index 0000000..e4024e6 --- /dev/null +++ b/Tests/Pester.Commands.Cmdlets.Archive.Tests.psm1 @@ -0,0 +1,229 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +$DS = [System.IO.Path]::DirectorySeparatorChar +function Add-CompressionAssemblies { + Add-Type -AssemblyName System.IO.Compression + if ($psedition -eq "Core") + { + Add-Type -AssemblyName System.IO.Compression.ZipFile + } + else + { + Add-Type -AssemblyName System.IO.Compression.FileSystem + } +} + +function CompressArchivePathParameterSetValidator { + param + ( + [string[]] $path, + [string] $destinationPath, + [string] $compressionLevel = "Optimal" + ) + + try + { + Compress-Archive -Path $path -DestinationPath $destinationPath -CompressionLevel $compressionLevel + throw "ValidateNotNullOrEmpty attribute is missing on one of parameters belonging to Path parameterset." + } + catch + { + $_.FullyQualifiedErrorId | Should Be "ParameterArgumentValidationError,Compress-Archive" + } +} + +function CompressArchiveLiteralPathParameterSetValidator { + param + ( + [string[]] $literalPath, + [string] $destinationPath, + [string] $compressionLevel = "Optimal" + ) + + try + { + Compress-Archive -LiteralPath $literalPath -DestinationPath $destinationPath -CompressionLevel $compressionLevel + throw "ValidateNotNullOrEmpty attribute is missing on one of parameters belonging to LiteralPath parameterset." + } + catch + { + $_.FullyQualifiedErrorId | Should Be "ParameterArgumentValidationError,Compress-Archive" + } +} + + +function CompressArchiveInValidPathValidator { + param + ( + [string[]] $path, + [string] $destinationPath, + [string] $invalidPath, + [string] $expectedFullyQualifiedErrorId + ) + + try + { + Compress-Archive -Path $path -DestinationPath $destinationPath + throw "Failed to validate that an invalid Path $invalidPath was supplied as input to Compress-Archive cmdlet." + } + catch + { + $_.FullyQualifiedErrorId | Should Be $expectedFullyQualifiedErrorId + } +} + +function CompressArchiveInValidArchiveFileExtensionValidator { + param + ( + [string[]] $path, + [string] $destinationPath, + [string] $invalidArchiveFileExtension + ) + + try + { + Compress-Archive -Path $path -DestinationPath $destinationPath + throw "Failed to validate that an invalid archive file format $invalidArchiveFileExtension was supplied as input to Compress-Archive cmdlet." + } + catch + { + $_.FullyQualifiedErrorId | Should Be "NotSupportedArchiveFileExtension,Compress-Archive" + } +} + +function Validate-ArchiveEntryCount { + param + ( + [string] $path, + [int] $expectedEntryCount + ) + + Add-CompressionAssemblies + try + { + $archiveFileStreamArgs = @($path, [System.IO.FileMode]::Open) + $archiveFileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $archiveFileStreamArgs + + $zipArchiveArgs = @($archiveFileStream, [System.IO.Compression.ZipArchiveMode]::Read, $false) + $zipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -ArgumentList $zipArchiveArgs + + $actualEntryCount = $zipArchive.Entries.Count + $actualEntryCount | Should Be $expectedEntryCount + } + finally + { + if ($null -ne $zipArchive) { $zipArchive.Dispose()} + if ($null -ne $archiveFileStream) { $archiveFileStream.Dispose() } + } +} + +function ArchiveFileEntryContentValidator { + param + ( + [string] $path, + [string] $entryFileName, + [string] $expectedEntryFileContent + ) + + Add-CompressionAssemblies + try + { + $destFile = "$TestDrive$($DS)ExpandedFile"+([System.Guid]::NewGuid().ToString())+".txt" + + $archiveFileStreamArgs = @($path, [System.IO.FileMode]::Open) + $archiveFileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $archiveFileStreamArgs + + $zipArchiveArgs = @($archiveFileStream, [System.IO.Compression.ZipArchiveMode]::Read, $false) + $zipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -ArgumentList $zipArchiveArgs + + $entryToBeUpdated = $zipArchive.Entries | ? {$_.FullName -eq $entryFileName.replace([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar)} + + if($entryToBeUpdated -ne $null) + { + $srcStream = $entryToBeUpdated.Open() + $destStream = New-Object "System.IO.FileStream" -ArgumentList( $destFile, [System.IO.FileMode]::Create ) + $srcStream.CopyTo( $destStream ) + $destStream.Dispose() + $srcStream.Dispose() + Get-Content $destFile | Should Be $expectedEntryFileContent + } + else + { + throw "Failed to find the file $entryFileName in the archive file $path" + } + } + finally + { + if ($zipArchive) + { + $zipArchive.Dispose() + } + if ($archiveFileStream) + { + $archiveFileStream.Dispose() + } + } +} + +function ArchiveFileEntrySeparatorValidator { + param + ( + [string] $path + ) + + Add-CompressionAssemblies + try + { + $destFile = "$TestDrive$($DS)ExpandedFile"+([System.Guid]::NewGuid().ToString())+".txt" + + $archiveFileStreamArgs = @($path, [System.IO.FileMode]::Open) + $archiveFileStream = New-Object -TypeName System.IO.FileStream -ArgumentList $archiveFileStreamArgs + + $zipArchiveArgs = @($archiveFileStream, [System.IO.Compression.ZipArchiveMode]::Read, $false) + $zipArchive = New-Object -TypeName System.IO.Compression.ZipArchive -ArgumentList $zipArchiveArgs + + $badEntries = $zipArchive.Entries | Where-Object {$_.FullName.Contains('\')} + + $badEntries.Count | Should Be 0 + } + finally + { + if ($zipArchive) + { + $zipArchive.Dispose() + } + if ($archiveFileStream) + { + $archiveFileStream.Dispose() + } + } +} + +function ExpandArchiveInvalidParameterValidator { + param + ( + [boolean] $isLiteralPathParameterSet, + [string[]] $path, + [string] $destinationPath, + [string] $expectedFullyQualifiedErrorId + ) + + try + { + if($isLiteralPathParameterSet) + { + Expand-Archive -LiteralPath $literalPath -DestinationPath $destinationPath + } + else + { + Expand-Archive -Path $path -DestinationPath $destinationPath + } + + throw "Expand-Archive did NOT throw expected error" + } + catch + { + $_.FullyQualifiedErrorId | Should Be $expectedFullyQualifiedErrorId + } +} diff --git a/TravisCI.ps1 b/TravisCI.ps1 deleted file mode 100644 index a605497..0000000 --- a/TravisCI.ps1 +++ /dev/null @@ -1,6 +0,0 @@ -$testResultsFile = "./ArchiveTestResults.xml" -Import-Module "./Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1" -Force -$testResults = Invoke-Pester -Script "./Tests" -OutputFormat NUnitXml -OutputFile $testResultsFile -PassThru -if ($testResults.FailedCount -gt 0) { - throw "$($testResults.FailedCount) tests failed." -} diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index ac70956..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,22 +0,0 @@ -# Image with WMF5.0 RTM -os: "WMF 5" - -# clone directory -clone_folder: c:\projects\Archive-Module - -# Install Pester -install: - - cinst -y pester - -build: false - -# Run Pester tests and store the results -test_script: - - ps: | - $testResultsFile = ".\ArchiveTestResults.xml" - Import-Module "C:\projects\Archive-Module\Microsoft.PowerShell.Archive" -Force - $testResults = Invoke-Pester -Script "C:\projects\Archive-Module\Tests" -OutputFormat NUnitXml -OutputFile $testResultsFile -PassThru - (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFile)) - if ($testResults.FailedCount -gt 0) { - throw "$($testResults.FailedCount) tests failed." - }