Modules/businessdev.ALbuild.Apps/Private/Test-BcIsTestApp.ps1

function Test-BcIsTestApp {
    <#
    .SYNOPSIS
        Determines whether an AL app is a test app.
 
    .DESCRIPTION
        Internal, pure-ish helper (reads AL source only when the manifest is inconclusive). An app
        is a test app when its manifest declares the "test" framework reference, depends on a
        Microsoft test/assert library, or its AL source defines an object with "Subtype = Test".
 
        The two kinds of evidence do not mean the same thing, which is what -ManifestOnly is for. The
        manifest signals are a DECLARATION: an app that references Library Assert or Tests-TestLibraries
        is a test project. A "Subtype = Test" object anywhere in the source is much weaker evidence - a
        product app is free to ship a test codeunit of its own (365 business ERiC does, and its tests are
        discovered and run from the product extension). Callers that must decide "does this app host
        tests?" - test discovery - want the source scan; callers that must decide "is this app test code
        rather than product code?" - code coverage - must not treat one embedded test codeunit as a
        verdict on the whole app, and pass -ManifestOnly.
 
    .PARAMETER Manifest
        The parsed app.json manifest object.
 
    .PARAMETER AppFolder
        The app folder, used to scan AL source as a fallback.
 
    .PARAMETER ManifestOnly
        Decide from the manifest alone and skip the AL source scan, so an app that merely CONTAINS a test
        object is not classified as a test app. See the description.
 
    .OUTPUTS
        System.Boolean.
    #>

    [CmdletBinding()]
    [OutputType([bool])]
    param(
        [Parameter(Mandatory)] [PSCustomObject] $Manifest,
        [Parameter(Mandatory)] [string] $AppFolder,
        [switch] $ManifestOnly
    )

    if (($Manifest.PSObject.Properties.Name -contains 'test') -and $Manifest.test) {
        return $true
    }

    if ($Manifest.PSObject.Properties.Name -contains 'dependencies') {
        foreach ($dependency in @($Manifest.dependencies)) {
            if ("$($dependency.publisher)" -eq 'Microsoft' -and
                ("$($dependency.name)" -like '*assert*' -or "$($dependency.name)" -like '*test*')) {
                return $true
            }
        }
    }

    if ($ManifestOnly) { return $false }

    foreach ($alFile in (Get-ChildItem -LiteralPath $AppFolder -Filter '*.al' -Recurse -File -ErrorAction SilentlyContinue)) {
        $content = Get-Content -LiteralPath $alFile.FullName -Raw -ErrorAction SilentlyContinue
        if ($content -match '(?im)^\s*Subtype\s*=\s*Test\s*;') {
            return $true
        }
    }

    return $false
}