diff --git a/build.ps1 b/build.ps1 index a3adf7890..2ee850d14 100755 --- a/build.ps1 +++ b/build.ps1 @@ -44,6 +44,10 @@ using module ./helpers.build.psm1 .PARAMETER Test Determines whether to run Rust and Pester tests for the project. + .PARAMETER Project + Specifies the projects to build. When used with `-Test`, only tests for the selected projects + are run. + .PARAMETER CodeCoverage Enables code coverage instrumentation using cargo-llvm-cov. When specified, the build and tests run with coverage instrumentation enabled and an LCOV report is generated at the path @@ -178,6 +182,9 @@ begin { $BuildData.Projects = $BuildData.Projects | Where-Object -FilterScript { $_.Name -in $Project } + if ($BuildData.Projects.Count -eq 0) { + throw "No projects matched the specified project names: $($Project -join ', ')" + } } $VerboseParam = @{} if ($VerbosePreference -eq 'Continue' -and -not $Quiet) { @@ -366,6 +373,9 @@ process { $pesterParams = @{ UsingADO = $usingADO } + if ($Project.Count -ge 1) { + $pesterParams.Project = $BuildData.Projects + } if ($null -ne $PesterTestGroup) { $pesterParams.Group = $PesterTestGroup } diff --git a/helpers.build.psm1 b/helpers.build.psm1 index 4c2d64a98..b1f8bdc55 100644 --- a/helpers.build.psm1 +++ b/helpers.build.psm1 @@ -2882,15 +2882,36 @@ function Test-ProjectWithPester { Write-Verbose "Updated Pester module location:`n`t$((Get-Module -Name Pester -ListAvailable).Path)" } $pesterParams = @{ - Output = 'Detailed' + Output = 'Detailed' ErrorAction = 'Stop' } if ($Project) { - $pesterParams.ExcludePath = $Project.RelativePath | Where-Object -FilterScript { - $_.Name -notin $Project.Name + $projectPath = @($Project.RelativePath) + if ($Group) { + $projectPath = @( + foreach ($path in $projectPath) { + $normalizedPath = $path -replace '\\', '/' + foreach ($testGroup in $Group) { + if ($normalizedPath -eq '.') { + $testGroup + } elseif ( + $normalizedPath -eq $testGroup -or + $normalizedPath.StartsWith("$testGroup/") + ) { + $normalizedPath + } elseif ($testGroup.StartsWith("$normalizedPath/")) { + $testGroup + } + } + } + ) | Select-Object -Unique + $projectPath = @($projectPath) } - } - if ($Group) { + if ($projectPath.Count -eq 0) { + throw 'None of the selected projects are in the specified Pester test groups.' + } + $pesterParams.Path = $projectPath + } elseif ($Group) { $pesterParams.Path = $Group } } diff --git a/tests/helpers.build.pester.tests.ps1 b/tests/helpers.build.pester.tests.ps1 new file mode 100644 index 000000000..42a7f5728 --- /dev/null +++ b/tests/helpers.build.pester.tests.ps1 @@ -0,0 +1,67 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe 'Test-ProjectWithPester' { + BeforeAll { + Import-Module (Join-Path $PSScriptRoot '..' 'helpers.build.psm1') -Force + $buildData = Import-DscBuildData -RefreshProjects + $dscProject = $buildData.Projects | Where-Object -Property Name -EQ 'dsc' + $fileContentProject = $buildData.Projects | Where-Object -Property Name -EQ 'filecontent' + } + + BeforeEach { + $originalPSModulePath = $env:PSModulePath + Mock Invoke-Pester -ModuleName helpers.build + } + + AfterEach { + $env:PSModulePath = $originalPSModulePath + } + + It 'Runs tests only from the selected project paths' { + Test-ProjectWithPester -Project @($dscProject, $fileContentProject) + + Should -Invoke Invoke-Pester -ModuleName helpers.build -Exactly 1 -ParameterFilter { + $Path.Count -eq 2 -and + $Path -contains 'dsc' -and + $Path -contains 'resources/filecontent' + } + } + + Describe 'build.ps1 project selection' { + It 'Fails when no projects match the requested names' { + $pwsh = (Get-Process -Id $PID).Path + $output = & $pwsh -NoProfile -File (Join-Path $PSScriptRoot '..' 'build.ps1') ` + -SkipBuild -Test -ExcludeRustTests -ExcludePesterTests -Project 'does-not-exist' 2>&1 + + $LASTEXITCODE | Should -Not -Be 0 + $output -join "`n" | Should -Match 'No projects matched the specified project names: does-not-exist' + } + } + + It 'Intersects selected projects with Pester test groups' { + Test-ProjectWithPester -Project @($dscProject, $fileContentProject) -Group 'resources' + + Should -Invoke Invoke-Pester -ModuleName helpers.build -Exactly 1 -ParameterFilter { + $Path.Count -eq 1 -and $Path -contains 'resources/filecontent' + } + } + + It 'Uses the narrower test group when the root project is selected' { + $rootProject = $buildData.Projects | Where-Object -Property Name -EQ 'root' + + Test-ProjectWithPester -Project $rootProject -Group 'resources' + + Should -Invoke Invoke-Pester -ModuleName helpers.build -Exactly 1 -ParameterFilter { + $Path.Count -eq 1 -and $Path -contains 'resources' + } + } + + It 'Fails when selected projects do not belong to a Pester test group' { + { + Test-ProjectWithPester -Project $dscProject -Group 'resources' + } | Should -Throw 'None of the selected projects are in the specified Pester test groups.' + + Should -Invoke Invoke-Pester -ModuleName helpers.build -Exactly 0 + } +}