Public/TestCaseManagement/Get-TcmTestCase.ps1

function Get-TcmTestCase {
    <#
        .SYNOPSIS
            Retrieves test case data from YAML files.

        .DESCRIPTION
            Retrieves test case information from local YAML files. Can return a single test case by ID or path,
            or return all test cases in the repository.

            The function searches for YAML files in the test cases root directory and parses them
            into structured PowerShell objects for further processing or display.

        .PARAMETER Id
            The local identifier of a specific test case to retrieve (e.g., "TC001").
            When specified, returns only the matching test case.

        .PARAMETER Path
            The relative or absolute path to a specific test case YAML file.
            When specified, loads and returns data from that specific file.

        .PARAMETER TestCasesRoot
            The root directory containing test case YAML files.
            If not specified, uses the current directory or searches parent directories for .tcm-config.yaml.

        .EXAMPLE
            PS C:\> Get-TcmTestCase -Id "TC001"

            Retrieves the test case with ID "TC001" and returns its data.

        .EXAMPLE
            PS C:\> Get-TcmTestCase -Path "authentication/TC001-login.yaml"

            Loads the test case from the specified file path.

        .EXAMPLE
            PS C:\> Get-TcmTestCase | Where-Object { $_.LocalData.state -eq "Design" }

            Retrieves all test cases and filters for those in "Design" state.

        .PARAMETER InputObject
            Test case input from pipeline. Accepts:
            - Test case ID (string) - e.g., "TC001"
            - File path (string) - relative or absolute path to YAML file
            - Test case object (hashtable) - from previous operations
            Accepts pipeline input by value or property name.

        .EXAMPLE
            PS C:\> "TC001", "TC002" | Get-TcmTestCase

            Retrieves multiple test cases by ID from pipeline.

        .INPUTS
            System.String
            System.Collections.Hashtable
            Accepts test case IDs, file paths, or test case objects from the pipeline.

        .OUTPUTS
            PSTypeNames.AzureDevOpsApi.TcmTestCaseExtended
            Returns objects that extend TcmTestCaseInput with test case data in the LocalData property.
            LocalData contains the parsed test case properties (id, title, state, etc.).

        .NOTES
            - Searches recursively through the test cases root directory for .yaml files.
            - Test case IDs are extracted from filenames (e.g., "TC001-test-name.yaml" has ID "TC001").
            - Invalid YAML files are skipped with warnings.

        .LINK
            New-TcmTestCase

        .LINK
            Sync-TcmTestCase

        .LINK
            New-TcmConfig
    #>


    [CmdletBinding()]
    [OutputType('PSTypeNames.AzureDevOpsApi.TcmTestCaseExtended')]
    param(
        [Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [Alias('Id', 'Path')]
        $InputObject,

        [string] $TestCasesRoot = (Get-Location -PSProvider FileSystem).Path
    )

    begin {
        # Get configuration
        $config = Get-TcmTestCaseConfig -TestCasesRoot $TestCasesRoot
        $inputItems = @()
        $seenEmptyInput = $false
    }

    process {
        # Collect all input items (or null for 'all' mode)
        if ($null -eq $InputObject) {
            $seenEmptyInput = $true
        } else {
            $inputItems += $InputObject
        }
    }

    end {
        $results = @()

        # If no specific input was provided, add null to indicate 'all' mode
        if ($seenEmptyInput) {
            $inputItems = $null
        }

        # Use ConvertTo-TcmTestCaseInput to normalize all inputs
        $resolvedInputs = $inputItems `
        | ConvertTo-TcmTestCaseInput -TestCasesRoot $config.TestCasesRoot

        foreach ($resolved in $resolvedInputs) {
            try {
                $localData = $null
                $remoteData = $null
                $remoteDataHash = $null

                # If LocalData is already populated (from pipeline objects), use it
                if ($null -ne $resolved.LocalData) {
                    $localData = $resolved.LocalData
                }

                # If we have a FilePath, check exclude patterns and load local data
                if ($null -ne $resolved.FilePath) {
                    Write-Debug "Loading local data from file $($resolved.FilePath)..."
                    $localData = Get-TcmTestCaseFromFile -FilePath $resolved.FilePath
                    $resolved.Id = $localData.testCase.id
                }

                # If we have a numeric ID, load from remote
                if (($null -ne $resolved.Id) -and ($resolved.Id -match '^\d+$')) {
                    Write-Debug "Loading remote data for Work Item ID $($resolved.Id)..."

                    # Get Azure DevOps configuration
                    $collectionUri = $config.azureDevOps.collectionUri
                    $project = $config.azureDevOps.project

                    if (-not $collectionUri -or -not $project) {
                        throw "Azure DevOps collectionUri and project must be configured in config.yaml"
                    }

                    $workItemId = [int]$resolved.Id
                    Write-Verbose "Loading work item $workItemId from Azure DevOps..."

                    $workItem = Get-WorkItem -WorkItem $workItemId -CollectionUri $collectionUri -Project $project

                    if ($null -eq $workItem) {
                        throw "Work item $workItemId not found in Azure DevOps"
                    }
                    if ($workItem.fields.'System.WorkItemType' -ne 'Test Case') {
                        throw "Work item $workItemId is not a Test Case (type: $($workItem.fields.'System.WorkItemType'))"
                    }

                    # Convert work item to test case format
                    $remoteData = ConvertFrom-TcmWorkItemToTestCase -WorkItem $workItem

                    # Calculate hash for remote data
                    $remoteDataHash = Get-TcmStringHash -InputObject $remoteData
                }

                # If we have a non-numeric ID without a local file, throw error
                elseif ($null -ne $resolved.Id) {
                    throw "Invalid test case ID '$($resolved.Id)': Not a numeric Work Item ID and no local file found"
                }

                # Create unified output object that extends TcmTestCaseInput
                if ($localData -or $remoteData) {
                    $resultObject = [PSCustomObject] @{
                        # Inherit from TcmTestCaseInput
                        FilePath   = $resolved.FilePath
                        Id         = $resolved.Id
                        SyncStatus = $null

                        # Additional metadata properties
                        FileName       = if ($localData) { $localData.FileName } else { $null }
                        LocalData      = if ($localData.testCase) { $localData.testCase } else { $null }
                        LocalDataHash  = if ($localData) { $localData.LocalDataHash } else { $null }
                        RemoteDataHash = if ($remoteData) { $remoteDataHash } else { $null }
                        RemoteData     = if ($remoteData) { $remoteData } else { $null }
                        RemoteWorkItem = if ($workItem) { $workItem } else { $null }
                    }

                    # Set proper PSTypeNames for inheritance
                    $resultObject.PSTypeNames.Insert(0, $global:PSTypeNames.AzureDevOpsApi.TcmTestCaseExtended)
                    $resultObject.PSTypeNames.Insert(0, $global:PSTypeNames.AzureDevOpsApi.TcmTestCaseInput)

                    # Ensure Id is set from LocalData if not already available
                    if (-not $resultObject.Id -and $localData.testCase.id) {
                        $resultObject.Id = $localData.testCase.id
                    }

                    # Determine sync status
                    $resultObject = Resolve-TcmTestCaseSyncStatus -InputObject $resultObject -Config $config

                    $results += $resultObject
                }
            } catch {
                Write-Error "Failed to load test case: $($_.Exception.Message)"
            }
        }

        return $results
    }
}