tests/BykaCCSupervisor.Import.Tests.ps1

# Import smoke tests for the BykaCCSupervisor module.

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

AfterAll {
    Remove-Module BykaCCSupervisor -ErrorAction SilentlyContinue
}

Describe 'BykaCCSupervisor import' {

    It 'imports without errors' {
        Get-Module BykaCCSupervisor | Should -Not -BeNullOrEmpty
    }

    It 'exposes Start-BykaCCSupervisor as a function' {
        Get-Command Start-BykaCCSupervisor -Module BykaCCSupervisor -ErrorAction Stop | Should -Not -BeNullOrEmpty
    }

    It 'exposes New-BykaCCSupervisorLauncher as a function' {
        Get-Command New-BykaCCSupervisorLauncher -Module BykaCCSupervisor -ErrorAction Stop | Should -Not -BeNullOrEmpty
    }

    It 'does NOT export Private helpers (Resolve-ProjectDir, Write-LogLine, etc.)' {
        # The manifest's FunctionsToExport restricts visibility from outside the
        # module, even though the loader dot-sources Private/*.ps1. Validate the
        # boundary holds by querying with -Module scoping.
        Get-Command Resolve-ProjectDir -Module BykaCCSupervisor -ErrorAction SilentlyContinue | Should -BeNullOrEmpty
        Get-Command Write-LogLine -Module BykaCCSupervisor -ErrorAction SilentlyContinue | Should -BeNullOrEmpty
        Get-Command Get-ChannelsProcess -Module BykaCCSupervisor -ErrorAction SilentlyContinue | Should -BeNullOrEmpty
        Get-Command Stop-OurStaleBun -Module BykaCCSupervisor -ErrorAction SilentlyContinue | Should -BeNullOrEmpty
        Get-Command Start-ApplyWatcher -Module BykaCCSupervisor -ErrorAction SilentlyContinue | Should -BeNullOrEmpty
        Get-Command Test-WatcherAlive -Module BykaCCSupervisor -ErrorAction SilentlyContinue | Should -BeNullOrEmpty
        Get-Command Stop-ApplyWatcher -Module BykaCCSupervisor -ErrorAction SilentlyContinue | Should -BeNullOrEmpty
        Get-Command Write-FileAtomic -Module BykaCCSupervisor -ErrorAction SilentlyContinue | Should -BeNullOrEmpty
    }

    It 'exports EXACTLY 2 functions (FunctionsToExport pin)' {
        # [G4] qa F9: positive-bound assertion catches future authors adding a
        # Public/ function without updating FunctionsToExport. Negative assertions
        # above catch silent over-export of a known Private helper, but a brand-new
        # function name would slip through.
        (Get-Command -Module BykaCCSupervisor).Count | Should -Be 2
    }

    It 'derives BaseDir from Split-Path -Parent FallbackProjectDir when -BaseDir omitted' {
        # [G4] code-reviewer T2-9 / qa F6: param default value depends on
        # $FallbackProjectDir which is itself runtime-resolved. Inspect the AST.
        $cmd = Get-Command Start-BykaCCSupervisor
        $baseDirParam = $cmd.Parameters['BaseDir']
        $baseDirParam | Should -Not -BeNullOrEmpty
        # The default-value AST is stored on the function's ScriptBlock.
        $defaultAst = $cmd.ScriptBlock.Ast.Body.ParamBlock.Parameters |
            Where-Object { $_.Name.VariablePath.UserPath -eq 'BaseDir' } |
            Select-Object -ExpandProperty DefaultValue
        $defaultAst | Should -Not -BeNullOrEmpty
        # Default expression should reference Split-Path -Parent.
        $defaultAst.Extent.Text | Should -Match 'Split-Path\s+-Parent\s+\$FallbackProjectDir'
    }
}

Describe 'New-BykaCCSupervisorLauncher injection guard' {

    BeforeAll {
        # Re-import to ensure fresh state for this Describe.
        Import-Module (Join-Path $PSScriptRoot '..' 'BykaCCSupervisor.psd1') -Force
        $script:LauncherPath = Join-Path $TestDrive 'test-launcher.bat'
    }

    It 'rejects ProjectDir with single quote' {
        { New-BykaCCSupervisorLauncher -Path $script:LauncherPath -ProjectDir "C:\Dev\my'repo" } | Should -Throw '*disallowed character*'
    }

    It 'rejects ProjectDir with double quote' {
        { New-BykaCCSupervisorLauncher -Path $script:LauncherPath -ProjectDir 'C:\Dev\my"repo' } | Should -Throw '*disallowed character*'
    }

    It 'rejects ProjectDir with backtick' {
        { New-BykaCCSupervisorLauncher -Path $script:LauncherPath -ProjectDir 'C:\Dev\my`repo' } | Should -Throw '*disallowed character*'
    }

    It 'rejects ProjectDir with semicolon (cmd.exe metacharacter)' {
        { New-BykaCCSupervisorLauncher -Path $script:LauncherPath -ProjectDir 'C:\Dev\my;evil' } | Should -Throw '*disallowed character*'
    }

    It 'rejects ProjectDir with percent (cmd env-var expansion)' {
        { New-BykaCCSupervisorLauncher -Path $script:LauncherPath -ProjectDir 'C:\Dev\my%COMSPEC%' } | Should -Throw '*disallowed character*'
    }

    It 'accepts a clean absolute path and writes the .bat' {
        $cleanPath = 'C:\Dev\byka'
        { New-BykaCCSupervisorLauncher -Path $script:LauncherPath -ProjectDir $cleanPath } | Should -Not -Throw
        Test-Path $script:LauncherPath | Should -BeTrue
        $content = Get-Content $script:LauncherPath -Raw
        $content | Should -Match "Start-BykaCCSupervisor -FallbackProjectDir '$([regex]::Escape($cleanPath))'"
        $content | Should -Match 'Get-Module -ListAvailable BykaCCSupervisor'
    }

    It 'rejects null/empty ProjectDir' {
        { New-BykaCCSupervisorLauncher -Path $script:LauncherPath -ProjectDir '' } | Should -Throw
    }
}