tests/productivity.Tests.ps1

[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', 'Global:foo')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', 'Global:bar')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', 'Global:baz')]
Param()

& (Join-Path $PSScriptRoot '_setup.ps1') 'productivity'

Describe 'Find-Duplicates' {
  It 'can identify duplicate files' {
    $Same = 'these files have identical content'
    $Same | Out-File 'TestDrive:\foo'
    'unique' | Out-File 'TestDrive:\bar'
    $Same | Out-File 'TestDrive:\baz'
    mkdir 'TestDrive:\sub'
    $Same | Out-File 'TestDrive:\sub\bam'
    'also unique' | Out-File 'TestDrive:\sub\bat'
    Find-Duplicate 'TestDrive:\' | ForEach-Object { Get-Item $_.Path } | Select-Object -ExpandProperty Name | Sort-Object | Should -Be 'bam','baz','foo'
  }
}
Describe 'Find-FirstTrueVariable' {
  It 'should support default value' {
    $Global:foo = $false
    $Global:bar = $true
    $Global:baz = $false
    $Names = 'foo','bar','baz'
    Find-FirstTrueVariable $Names | Should -Be 'bar'
    Find-FirstTrueVariable $Names -DefaultIndex 2 | Should -Be 'bar'
    Find-FirstTrueVariable $Names -DefaultValue 'boo' | Should -Be 'bar'
  }
  It 'should support default value' {
    $Global:foo = $false
    $Global:bar = $false
    $Global:baz = $false
    $Names = 'foo','bar','baz'
    Find-FirstTrueVariable $Names | Should -Be 'foo'
  }
  It 'should support default value passed as index' {
    $Global:foo = $false
    $Global:bar = $false
    $Global:baz = $false
    $Names = 'foo','bar','baz'
    Find-FirstTrueVariable $Names -DefaultIndex 2 | Should -Be 'baz'
  }
  It 'should support default value passed as value' {
    $Global:foo = $false
    $Global:bar = $false
    $Global:baz = $false
    $Names = 'foo','bar','baz'
    Find-FirstTrueVariable $Names -DefaultValue 'boo' | Should -Be 'boo'
  }
}
Describe 'Get-HostsContent / Update-HostsFile' {
  It 'can get content of hosts file from path' {
    $Content = Get-HostsContent (Join-Path $PSScriptRoot "fixtures\hosts")
    $Content.Count | Should -Be 3
    $Content | ForEach-Object Hostname | Should -Be 'foo','bar','foo.bar.baz'
    $Content | ForEach-Object IPAddress | Should -Be '192.168.0.111','127.0.0.1','192.168.0.2'
    $Content | ForEach-Object Comment | Should -Be '','some random comment',''
    $Content = (Join-Path $PSScriptRoot "fixtures\hosts") | Get-HostsContent
    $Content.Count | Should -Be 3
    $Content | ForEach-Object Hostname | Should -Be 'foo','bar','foo.bar.baz'
    $Content | ForEach-Object IPAddress | Should -Be '192.168.0.111','127.0.0.1','192.168.0.2'
    $Content | ForEach-Object Comment | Should -Be '','some random comment',''
  }
  It 'can add an entry to a hosts file' {
    $Path = Join-Path $TestDrive 'hosts'
    New-Item $Path
    $A = @{
      Hostname = 'home'
      IPAddress = '127.0.0.1'
    }
    $B = @{
      Hostname = 'foo'
      IPAddress = '127.0.0.2'
      Comment = 'bar'
    }
    $NewIpAddress = '127.0.0.42'
    $NewComment = 'this is an updated comment'
    $Updated = $A.Clone(),@{ IPAddress = $NewIpAddress; Comment = $NewComment } | Invoke-ObjectMerge
    Update-HostsFile @A -Path $Path
    Get-HostsContent $Path | ConvertTo-Json | Should -Be @"
{
    "LineNumber": 1,
    "IPAddress": "$($A.IPAddress)",
    "IsValidIP": true,
    "Hostname": "$($A.Hostname)",
    "Comment": "$($A.Comment)"
}
"@

    Update-HostsFile @B -Path $Path
    Get-HostsContent $Path | ConvertTo-Json | Should -Be @"
[
    {
        "LineNumber": 1,
        "IPAddress": "$($A.IPAddress)",
        "IsValidIP": true,
        "Hostname": "$($A.Hostname)",
        "Comment": "$($A.Comment)"
    },
    {
        "LineNumber": 3,
        "IPAddress": "$($B.IPAddress)",
        "IsValidIP": true,
        "Hostname": "$($B.Hostname)",
        "Comment": "$($B.Comment)"
    }
]
"@

    Update-HostsFile @Updated -Path $Path
    Get-HostsContent $Path | ConvertTo-Json | Should -Be @"
[
    {
        "LineNumber": 1,
        "IPAddress": "$NewIpAddress",
        "IsValidIP": true,
        "Hostname": "$($A.Hostname)",
        "Comment": "$NewComment"
    },
    {
        "LineNumber": 3,
        "IPAddress": "$($B.IPAddress)",
        "IsValidIP": true,
        "Hostname": "$($B.Hostname)",
        "Comment": "$($B.Comment)"
    }
]
"@

    Update-HostsFile @B -Path $Path -PassThru | ConvertTo-Json | Should -Be @"
[
    {
        "LineNumber": 1,
        "IPAddress": "$NewIpAddress",
        "IsValidIP": true,
        "Hostname": "$($A.Hostname)",
        "Comment": "$NewComment"
    },
    {
        "LineNumber": 3,
        "IPAddress": "$($B.IPAddress)",
        "IsValidIP": true,
        "Hostname": "$($B.Hostname)",
        "Comment": "$($B.Comment)"
    }
]
"@

    }
}
Describe 'Invoke-Speak (say)' {
  It 'can passthru text without speaking' {
    $Text = 'this should not be heard'
    Invoke-Speak $Text -Silent | Should -BeNullOrEmpty
    Invoke-Speak $Text -Silent -Output text | Should -Be $Text
  }
  It 'can output SSML' {
    $Text = 'this should not be heard either'
    Invoke-Speak $Text -Silent -Output ssml | Should -match "<p>$Text</p>"
  }
  It 'can output SSML with custom rate' {
    $Text = 'this should not be heard either'
    $Rate = 10
    Invoke-Speak $Text -Silent -Output ssml -Rate $Rate | Should -match "<p>$Text</p>"
    Invoke-Speak $Text -Silent -Output ssml -Rate $Rate | Should -match "<prosody rate=`"$Rate`">"
  }
}
Describe 'New-File (touch)' {
  AfterAll {
    Remove-Item -Path .\SomeFile
  }
  It 'can create a file' {
    $Content = 'testing'
    '.\SomeFile' | Should -not -Exist
    New-File SomeFile
    Write-Output $Content >> .\SomeFile
    '.\SomeFile' | Should -FileContentMatch $Content
  }
}
Describe 'Remove-DirectoryForce (rf)' {
  It 'can create a file' {
    New-File SomeFile
    '.\SomeFile' | Should -Exist
    Remove-DirectoryForce .\SomeFile
    '.\SomeFile' | Should -Not -Exist
  }
}
Describe 'Rename-FileExtension' {
  It 'can rename file extensions using -TXT switch' {
    $Path = Join-Path $TestDrive 'foo.bar'
    New-Item $Path
    Get-ChildItem -Path $TestDrive -Name '*.bar' -File | Should -Be 'foo.bar'
    Rename-FileExtension -Path (Join-Path $TestDrive 'foo.bar') -txt
    Get-ChildItem -Path $TestDrive -Name '*.txt' -File | Should -Be 'foo.txt'
    Remove-Item (Join-Path $TestDrive 'foo.txt')
  }
  It 'can rename file extensions using -PNG switch' {
    $Path = Join-Path $TestDrive 'foo.bar'
    New-Item $Path
    Get-ChildItem -Path $TestDrive -Name '*.bar' -File | Should -Be 'foo.bar'
    Rename-FileExtension -Path (Join-Path $TestDrive 'foo.bar') -png
    Get-ChildItem -Path $TestDrive -Name '*.png' -File | Should -Be 'foo.png'
    Remove-Item (Join-Path $TestDrive 'foo.png')
  }
  It 'can rename file extensions using -GIF switch' {
    $Path = Join-Path $TestDrive 'foo.bar'
    New-Item $Path
    Get-ChildItem -Path $TestDrive -Name '*.bar' -File | Should -Be 'foo.bar'
    Rename-FileExtension -Path (Join-Path $TestDrive 'foo.bar') -gif
    Get-ChildItem -Path $TestDrive -Name '*.gif' -File | Should -Be 'foo.gif'
    Remove-Item (Join-Path $TestDrive 'foo.gif')
  }
  It 'can rename file extensions with custom value using -To parameter' {
    $Path = Join-Path $TestDrive 'foo.bar'
    New-Item $Path
    Get-ChildItem -Path $TestDrive -Name '*.bar' -File | Should -Be 'foo.bar'
    Rename-FileExtension -Path (Join-Path $TestDrive 'foo.bar') -To baz
    Get-ChildItem -Path $TestDrive -Name '*.baz' -File | Should -Be 'foo.baz'
    Remove-Item (Join-Path $TestDrive 'foo.baz')
  }
  It 'can rename file extensions with custom value using -To parameter (pipeline syntax)' {
    $Path = Join-Path $TestDrive 'foo.bar'
    New-Item $Path
    Get-ChildItem -Path $TestDrive -Name '*.bar' -File | Should -Be 'foo.bar'
    (Join-Path $TestDrive 'foo.bar') | Rename-FileExtension -To baz
    Get-ChildItem -Path $TestDrive -Name '*.baz' -File | Should -Be 'foo.baz'
    Remove-Item (Join-Path $TestDrive 'foo.baz')
  }
  It 'can rename files extension of multiple files using pipeline' {
    $ExtBefore = 'pre'
    $ExtAfter = 'post'
    $Files = @(
      (Join-Path $TestDrive "bar.$ExtBefore")
      (Join-Path $TestDrive "baz.$ExtBefore")
      (Join-Path $TestDrive "foo.$ExtBefore")
    )
    $Expected = @(
      "bar.$ExtAfter"
      "baz.$ExtAfter"
      "foo.$ExtAfter"
    )
    $Files | ForEach-Object { New-Item $_ }
    $Files | Rename-FileExtension -To 'post'
    Get-ChildItem -Path $TestDrive -Name "*.$ExtAfter" -File | Should -Be $Expected
    $Expected | ForEach-Object { Remove-Item (Join-Path $TestDrive $_) }
  }
}
Describe -Skip 'Test-Admin' {
  It 'should return false if not Administrator' {
    Test-Admin | Should -Be $false
  }
}
Describe 'Test-Empty' {
  It 'should return true for directories with no contents' {
    'TestDrive:\Foo' | Should -not -Exist
    mkdir 'TestDrive:\Foo'
    'TestDrive:\Foo' | Should -Exist
    Test-Empty 'TestDrive:\Foo' | Should -BeTrue
    mkdir 'TestDrive:\Foo\Bar'
    mkdir 'TestDrive:\Foo\Bar\Baz'
    Test-Empty 'TestDrive:\Foo' | Should -BeFalse
  }
}
Describe 'Test-Installed' {
  It 'should return true if passed module is installed' {
    Test-Installed Pester | Should -BeTrue
    Test-Installed NotInstalledModule | Should -BeFalse
  }
}