Modules/businessdev.ALbuild.Apps/Private/Get-BcDeclaredTestCount.ps1

function Get-BcDeclaredTestCount {
    <#
    .SYNOPSIS
        Counts the [Test] procedures the test apps under a folder declare, narrowed to a test filter.
 
    .DESCRIPTION
        The number a run must reach: every [Test] procedure in a Subtype = Test codeunit of the source, with
        -TestCodeunit / -TestProcedure applied the way the test page applies them. Returned per codeunit as
        well, so a shortfall can be named.
 
    .OUTPUTS
        PSCustomObject: Total, Codeunits[] { Id, Name, Tests }.
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory)] [string] $WorkspaceRoot,
        [string] $TestCodeunit,
        [string] $TestProcedure
    )

    # Projects albuild.json excludes are not built or published, so their tests never run.
    $excluded = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
    try {
        $config = Get-ALbuildProjectConfig -AppFolder $WorkspaceRoot -WorkspaceRoot $WorkspaceRoot
        if ($config.Has('ExcludeProjects')) { foreach ($n in $config.ExcludeProjects) { if ("$n".Trim()) { [void]$excluded.Add("$n".Trim()) } } }
    }
    catch { Write-ALbuildLog -Level Verbose "No albuild.json at '$WorkspaceRoot': $($_.Exception.Message)" }

    $idCache = @{}
    $byCodeunit = [ordered]@{}
    foreach ($t in @(Get-BcAlTestProcedure -WorkspaceRoot $WorkspaceRoot)) {
        if ($excluded.Count -gt 0) {
            $owner = (Resolve-BcAlAppContext -Path $t.FilePath).AppFolder
            if ($owner -and $excluded.Contains((Split-Path -Path $owner -Leaf))) { continue }
        }
        if (-not $idCache.ContainsKey($t.FilePath)) {
            $m = [regex]::Match((Get-Content -LiteralPath $t.FilePath -Raw), '(?im)^\s*codeunit\s+(\d+)\s')
            $idCache[$t.FilePath] = if ($m.Success) { [int]$m.Groups[1].Value } else { 0 }
        }
        $id = $idCache[$t.FilePath]
        if ($TestCodeunit -and -not (Test-BcTestCodeunitFilter -Id $id -Filter $TestCodeunit)) { continue }
        if ($TestProcedure -and -not (Test-BcTestProcedureFilter -Name $t.TestName -Filter $TestProcedure)) { continue }
        $key = "$id"
        if (-not $byCodeunit.Contains($key)) { $byCodeunit[$key] = [PSCustomObject]@{ Id = $id; Name = $t.Codeunit; Tests = 0 } }
        $byCodeunit[$key].Tests++
    }
    $total = 0
    foreach ($c in $byCodeunit.Values) { $total += $c.Tests }
    return [PSCustomObject]@{ Total = $total; Codeunits = @($byCodeunit.Values) }
}