tests/Invoke-BykaDrBackup.Integration.Tests.ps1

# End-to-end integration tests for Invoke-BykaDrBackup against $TestDrive.
#
# These tests run the full backup function (writing into TestDrive, NOT a real
# desktop location) and assert observable side effects: backup folder created,
# RESTORE-INSTRUCTIONS.md written, cleanup loop honors -KeepDays, -ProjectRoot
# explicit pass short-circuits auto-detect.
#
# Added 2026-05-27 in M-13 Phase 3 Wave E [G4] panel-followup. Per operator
# instruction, no Tier-3 deferrals -- the panel's code-reviewer F15 + qa F2
# specifically called out the missing happy-path integration coverage.

BeforeAll {
    $script:ManifestPath = Join-Path $PSScriptRoot '..' 'BykaDrBackup.psd1'
    Import-Module $script:ManifestPath -Force
}

AfterAll {
    Remove-Module BykaDrBackup -ErrorAction SilentlyContinue
}

Describe 'Invoke-BykaDrBackup happy path' {

    It 'creates a backup-<timestamp> directory containing RESTORE-INSTRUCTIONS.md' {
        $dest = Join-Path $TestDrive 'happy-dest'
        # Suppress noisy console output during test.
        Invoke-BykaDrBackup -Destination $dest -KeepDays 365 6>$null

        $backupFolders = @(Get-ChildItem -LiteralPath $dest -Directory -Filter 'backup-*' -ErrorAction SilentlyContinue)
        $backupFolders.Count | Should -Be 1
        $restoreFile = Join-Path $backupFolders[0].FullName 'RESTORE-INSTRUCTIONS.md'
        Test-Path $restoreFile | Should -BeTrue
        $content = Get-Content -LiteralPath $restoreFile -Raw
        $content | Should -Match '# BYKA Emergency Restore Instructions'
        $content | Should -Match 'Install-PSResource -Name BykaDrBackup'
    }
}

Describe 'Invoke-BykaDrBackup cleanup loop' {

    It 'deletes folders older than -KeepDays and preserves the current run' {
        $dest = Join-Path $TestDrive 'cleanup-dest'
        New-Item -ItemType Directory -Path $dest -Force | Out-Null
        # Seed: one old (10 days ago) + one ineligible-by-name folder.
        $oldFolder = Join-Path $dest 'backup-2026-05-15_120000'
        New-Item -ItemType Directory -Path $oldFolder -Force | Out-Null
        $unparseable = Join-Path $dest 'backup-not-a-date'
        New-Item -ItemType Directory -Path $unparseable -Force | Out-Null

        Invoke-BykaDrBackup -Destination $dest -KeepDays 7 6>$null

        # Old folder should be DELETED; unparseable should be PRESERVED (date-parse
        # guard skips it); current-run folder should EXIST.
        Test-Path $oldFolder    | Should -BeFalse
        Test-Path $unparseable  | Should -BeTrue
        @(Get-ChildItem -LiteralPath $dest -Directory -Filter 'backup-*' -ErrorAction SilentlyContinue).Count | Should -BeGreaterOrEqual 1
    }

    It 'preserves a fresh-named folder under -KeepDays' {
        $dest = Join-Path $TestDrive 'keep-fresh-dest'
        New-Item -ItemType Directory -Path $dest -Force | Out-Null
        $todayStamp = Get-Date -Format 'yyyy-MM-dd_HHmmss'
        $freshOld = Join-Path $dest "backup-$todayStamp"
        New-Item -ItemType Directory -Path $freshOld -Force | Out-Null

        Invoke-BykaDrBackup -Destination $dest -KeepDays 1 6>$null

        Test-Path $freshOld | Should -BeTrue
    }
}

Describe 'Invoke-BykaDrBackup -ProjectRoot handling' {

    It 'accepts an explicit -ProjectRoot that exists' {
        $dest = Join-Path $TestDrive 'pr-dest'
        $pr   = Join-Path $TestDrive 'fake-project'
        New-Item -ItemType Directory -Path $pr -Force | Out-Null

        # Should not throw despite no CLAUDE.md (-ProjectRoot bypasses auto-detect).
        { Invoke-BykaDrBackup -Destination $dest -KeepDays 365 -ProjectRoot $pr 6>$null } | Should -Not -Throw
    }

    It 'warns but does not throw when -ProjectRoot does not exist' {
        $dest = Join-Path $TestDrive 'pr-missing-dest'
        $missingPr = Join-Path $TestDrive 'no-such-dir'

        { Invoke-BykaDrBackup -Destination $dest -KeepDays 365 -ProjectRoot $missingPr 6>$null } | Should -Not -Throw
    }
}

Describe 'Invoke-BykaDrBackup -Destination deny-list' {

    It 'rejects -Destination inside the Windows system root' {
        # ValidateScript should throw with the deny-list message.
        { Invoke-BykaDrBackup -Destination "$env:WINDIR\BYKA-EVIL" } | Should -Throw '*protected system path*'
    }
}