1

I have an issue, where I try to mock the Windows built-in cmdlet Expand-Archive in a pester unit test. Somehow, during the execution the original cmdlet is executed rather than the mocked variant. I've tried putting the Expand-Archive mock outside of the Describe scope, but that didn't work.

Here is the module I'd like to test:

class Validator {
    
    [bool] Validate([string] $filePath) {
        return $False
    }

}

class DocxValidator : Validator {

    [bool] Validate([string] $filePath) {
        try { 
            $tempFile = [System.IO.Path]::GetTempFileName() + ".zip"
            Copy-Item $filePath -Destination $tempFile
            $tempDirectory = ([System.IO.Path]::GetTempPath()).ToString() + "validator"
            Expand-Archive -LiteralPath $tempFile -DestinationPath $tempDirectory -Force
            Remove-Item -Path $tempDirectory -Recurse -Force
            return $true   
        }
        catch {
            Write-Host "Failed to validate file $($filePath)" 
        }

        return $false
    }
} 

function Get-Validator {
    [OutputType([Validator])]
    param([string] $ValidatorType)
    switch ($ValidatorType) {
        "xml" {  
            return [XmlValidator]::new()
        }
        "json" {
            return [JsonValidator]::new()
        }
        "docx" {
            return [DocxValidator]::new()
        }
        Default {
            throw "invalid validator type"
        }
    }
}

Export-ModuleMember -Function Get-Validator

This is the unit test:

    Get-Module Validation-Helper | Remove-Module -Force
$modulePath = Resolve-Path -Path "$($PSScriptRoot)\..\Validation-Helper\Validation-Helper.psm1"
Import-Module $modulePath

InModuleScope Validation-Helper {

    Describe 'Validator for docx' {
        Context 'when the document is valid' {
            # arrange
            BeforeAll {
                Mock Write-Host { }
                Mock Copy-Item { }
                # this was another hint, to explicitly add the module scope here
                Mock -ModuleName Validation-Helper Expand-Archive { } -Verifiable -ParameterFilter {
                }
            }
            
            $tempFile = [System.IO.Path]::GetTempFileName()
            $docxValidator = Get-Validator -ValidatorType "docx"
            
            # act | assert 
            It 'returns true' {
                $docxValidator.Validate($tempFile) | Should Be $true
            }
        }
    }
}

The exception that I get in the catch branch of the Validate() method:

System.Management.Automation.MethodInvocationException: Exception calling ".ctor" with "3" argument(s): "Central Directory corrupt." ---> System.IO.InvalidDataException: Central Directory corrupt. ---> System.IO.IOException: An attempt was made to move the file pointer before the beginning of the file.

   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.SeekCore(Int64 offset, SeekOrigin origin)
   at System.IO.FileStream.Seek(Int64 offset, SeekOrigin origin)
   at System.IO.Compression.ZipArchive.ReadEndOfCentralDirectory()
   --- End of inner exception stack trace ---
   at System.IO.Compression.ZipArchive.ReadEndOfCentralDirectory()
   at System.IO.Compression.ZipArchive.Init(Stream stream, ZipArchiveMode mode, Boolean leaveOpen)
   at System.IO.Compression.ZipArchive..ctor(Stream stream, ZipArchiveMode mode, Boolean leaveOpen)
   --- End of inner exception stack trace ---
   at System.Management.Automation.DotNetAdapter.AuxiliaryConstructorInvoke(MethodInformation methodInformation, Object[] arguments, Object[] originalArguments)
   at System.Management.Automation.DotNetAdapter.ConstructorInvokeDotNet(Type type, ConstructorInfo[] constructors, Object[] arguments)
   at Microsoft.PowerShell.Commands.NewObjectCommand.CallConstructor(Type type, ConstructorInfo[] constructors, Object[] args)

Background: I'm currently working on a Powershell module, that shall verify if a Word document docx is corrupted. The idea is, that each docx document is basically a zip file. Therefore it should be possible to use any extract method to extract it - if no error during extraction occurs, the file is ok.

Mark Wragg
  • 22,105
  • 7
  • 39
  • 68
Michael
  • 153
  • 1
  • 14
  • Try removing the `-ParameterFilter { }` part from your `Mock` of `Expand-Archive`. I suspect its making it only invoke the Mock if the cmdlet was used without any parameters, and you use it with parameters. – Mark Wragg Nov 24 '20 at 10:24
  • No unfortunately, this does not solve the problem. I have still the same exception. – Michael Nov 24 '20 at 13:04

0 Answers0