tests/Harvest.Parsers.Tests.ps1
|
BeforeAll { $script:RepoRoot = Split-Path -Parent $PSScriptRoot Get-ChildItem (Join-Path $script:RepoRoot 'Private') -Filter *.ps1 | ForEach-Object { . $_.FullName } $script:Fixtures = Join-Path $PSScriptRoot 'Fixtures\RegressionTests' } Describe 'Split-QAFrameworkAttributeArgument' { It 'splits on top level commas only' { $result = Split-QAFrameworkAttributeArgument -ArgumentText '"a", 1, true' $result.Count | Should -Be 3 } It 'keeps commas inside string literals together' { $result = Split-QAFrameworkAttributeArgument -ArgumentText '"Customer, With Comma", "Second"' $result.Count | Should -Be 2 $result[0].Trim() | Should -Be '"Customer, With Comma"' } It 'keeps nested collection initialisers together' { $result = Split-QAFrameworkAttributeArgument -ArgumentText 'new[] { 1, 2, 3 }, "x"' $result.Count | Should -Be 2 } It 'returns nothing for empty input' { @(Split-QAFrameworkAttributeArgument -ArgumentText '').Count | Should -Be 0 } } Describe 'ConvertFrom-QAFrameworkAttributeValue' { It 'unescapes regular string literals' { ConvertFrom-QAFrameworkAttributeValue -Expression '"a\tb"' | Should -Be "a`tb" } It 'handles verbatim string literals' { ConvertFrom-QAFrameworkAttributeValue -Expression '@"C:\Temp"' | Should -Be 'C:\Temp' } It 'strips the enum type prefix' { ConvertFrom-QAFrameworkAttributeValue -Expression 'RunOn.All' | Should -Be 'All' ConvertFrom-QAFrameworkAttributeValue -Expression 'DiagnosticRunType.Before' | Should -Be 'Before' } It 'converts booleans and integers' { ConvertFrom-QAFrameworkAttributeValue -Expression 'true' | Should -BeOfType [bool] ConvertFrom-QAFrameworkAttributeValue -Expression '42' | Should -Be 42 } } Describe 'ConvertTo-QAFrameworkAttributeArgumentMap' { It 'separates positional from named arguments' { $map = ConvertTo-QAFrameworkAttributeArgumentMap -ArgumentText '"Name", true, RunOnNonFailoverSystems = true' $map.Positional.Count | Should -Be 2 $map.Named['RunOnNonFailoverSystems'] | Should -BeTrue } It 'supports C# named argument syntax' { $map = ConvertTo-QAFrameworkAttributeArgumentMap -ArgumentText '"Name", runDirectAfterSwitch: true' $map.Positional.Count | Should -Be 1 $map.Named['runDirectAfterSwitch'] | Should -BeTrue } } Describe 'Get-QAFrameworkAttribute' { It 'expands grouped attributes' { $attributes = @(Get-QAFrameworkAttribute -Text '[BaselineTest, CentralizedTest]') $attributes.Name | Should -Be @('BaselineTest', 'CentralizedTest') } It 'ignores an attribute target prefix' { $attributes = @(Get-QAFrameworkAttribute -Text '[method: Order(1)]') $attributes[0].Name | Should -Be 'Order' } It 'strips the Attribute suffix and namespace qualifier' { $attributes = @(Get-QAFrameworkAttribute -Text '[QAManagement.TestFramework.Attributes.DisabledAttribute("x")]') $attributes[0].Name | Should -Be 'Disabled' } } Describe 'Get-QAFrameworkClassAttributeBlock' { It 'captures a multi-line attribute' { $block = Get-QAFrameworkClassAttributeBlock -Path (Join-Path $script:Fixtures 'TeamA\RT_Failover\RT_Failover.cs') $block | Should -Match 'FailoverTestFixture' $block | Should -Match 'RunOnNonFailoverSystems' $block | Should -Match 'Weight\(5\)' } It 'returns an empty string when the class does not exist' { Get-QAFrameworkClassAttributeBlock -Content 'namespace X { }' -ClassName 'Nope' | Should -Be '' } } Describe 'ConvertFrom-QAFrameworkAttributeBlock' { It 'ignores Disabled when the reason is blank' { $result = ConvertFrom-QAFrameworkAttributeBlock -Block '[TestFixture("T")][Disabled("")]' $result.ContainsKey('disabled') | Should -BeFalse } It 'honours Disabled when a reason is supplied' { $result = ConvertFrom-QAFrameworkAttributeBlock -Block '[TestFixture("T")][Disabled("broken")]' $result['disabled'].reason | Should -Be 'broken' } It 'clamps the weight to the 1..3 agent capacity range' { (ConvertFrom-QAFrameworkAttributeBlock -Block '[Weight(5)]')['weight'] | Should -Be 3 (ConvertFrom-QAFrameworkAttributeBlock -Block '[Weight(0)]')['weight'] | Should -Be 1 } It 'reads the test name from the first positional argument of every fixture' { (ConvertFrom-QAFrameworkAttributeBlock -Block '[PreRunFixture("A")]')['name'] | Should -Be 'A' (ConvertFrom-QAFrameworkAttributeBlock -Block '[DiagnosticTestFixture("B")]')['name'] | Should -Be 'B' (ConvertFrom-QAFrameworkAttributeBlock -Block '[FailoverTestFixture("C")]')['name'] | Should -Be 'C' } It 'defaults the diagnostic run type to BeforeAndAfter' { (ConvertFrom-QAFrameworkAttributeBlock -Block '[DiagnosticTestFixture("B")]')['diagnosticRunType'] | Should -Be 'BeforeAndAfter' } It 'reads failover switch booleans from positions one and two' { $failover = (ConvertFrom-QAFrameworkAttributeBlock -Block '[FailoverTestFixture("C", false, true)]')['failover'] $failover['runDirectBeforeSwitch'] | Should -BeFalse $failover['runDirectAfterSwitch'] | Should -BeTrue } It 'treats an argument-less LocalDB as supporting every database' { (ConvertFrom-QAFrameworkAttributeBlock -Block '[LocalDB]')['localDbs'].Count | Should -Be 0 } } Describe 'Get-QAFrameworkMethodAttributeFlag' { It 'detects failover switch methods' { $flags = Get-QAFrameworkMethodAttributeFlag -Path (Join-Path $script:Fixtures 'TeamA\RT_Failover\RT_Failover.cs') $flags['hasBeforeSwitch'] | Should -BeTrue $flags['hasAfterSwitch'] | Should -BeTrue $flags['hasAfterSwitchBack'] | Should -BeFalse } It 'does not confuse AfterSwitchReInit with AfterSwitch' { $flags = Get-QAFrameworkMethodAttributeFlag -Content " [AfterSwitchReInit]`r`n public void X() { }" $flags['hasAfterSwitch'] | Should -BeFalse } } Describe 'ConvertFrom-QAFrameworkMetaFile' { BeforeAll { $script:Meta = ConvertFrom-QAFrameworkMetaFile -Path (Join-Path $script:Fixtures 'TeamB\RT_LegacyMeta\RT_LegacyMeta.meta') } It 'reads the DLL references' { $script:Meta['dllReferences'].Count | Should -Be 2 } It 'reads squads, customers, DCP IDs and RN IDs' { $script:Meta['squads'] | Should -Contain 'LegacySquad' $script:Meta['customers'] | Should -Contain 'LegacyCustomer' $script:Meta['dcpIds'] | Should -Contain 'DCP9999' $script:Meta['rnIds'] | Should -Contain 'RN4242' } It 'reads the baseline flag' { $script:Meta['isBaseline'] | Should -BeTrue } It 'returns an empty result for a missing file' { (ConvertFrom-QAFrameworkMetaFile -Path 'X:\does\not\exist.meta').Count | Should -Be 0 } } Describe 'New-QAFrameworkTestMetadata' { Context 'test with the full attribute set' { BeforeAll { $script:Full = New-QAFrameworkTestMetadata ` -CsPath (Join-Path $script:Fixtures 'TeamA\RT_Full\RT_Full.cs') ` -MetaPath (Join-Path $script:Fixtures 'TeamA\RT_Full\RT_Full.meta') ` -RegressionTestsRoot $script:Fixtures } It 'uses the fixture name' { $script:Full.name | Should -Be 'RT_Full' } It 'keeps the clamped weight' { $script:Full.weight | Should -Be 2 } It 'reads CanRunConcurrently' { $script:Full.canRunConcurrently | Should -BeFalse } It 'reads TargetDMA' { $script:Full.targetDma | Should -Be 'All' } It 'keeps commas inside a customer name' { $script:Full.customers | Should -Contain 'Customer, With Comma' } It 'reads the min version triplet' { $script:Full.minVersion.featureRelease | Should -Be '10.1.0.0-CU5' $script:Full.minVersion.nextMainRelease | Should -Be '10.2.0.0' $script:Full.minVersion.mainRelease | Should -Be '10.3.0.0' } It 'reads the solution info' { $script:Full.solution.name | Should -Be 'SRM' $script:Full.solution.minVersion | Should -Be '1.2.3' } It 'reads the marker attributes' { $script:Full.isRedGreen | Should -BeTrue $script:Full.isBaseline | Should -BeTrue $script:Full.isCentralizedOnly | Should -BeTrue } It 'ignores a Disabled attribute without a reason' { $script:Full.disabled | Should -BeNullOrEmpty } It 'lets attribute values win over meta values' { $script:Full.maintainers | Should -Be @('jdoe') } It 'falls back to meta values for gaps' { $script:Full.dllReferences.Count | Should -Be 1 } It 'stores relative source paths' { $script:Full.source.cs | Should -Be 'TeamA\RT_Full\RT_Full.cs' } } Context 'failover test' { BeforeAll { $script:Failover = New-QAFrameworkTestMetadata -CsPath (Join-Path $script:Fixtures 'TeamA\RT_Failover\RT_Failover.cs') } It 'is recognised as a failover fixture' { $script:Failover.fixture | Should -Be 'Failover' } It 'reads the positional switch booleans' { $script:Failover.failover.runDirectBeforeSwitch | Should -BeTrue $script:Failover.failover.runDirectAfterSwitch | Should -BeFalse } It 'reads the named RunOnNonFailoverSystems field' { $script:Failover.failover.runOnNonFailoverSystems | Should -BeTrue } It 'merges the method level switch flags' { $script:Failover.failover.hasBeforeSwitch | Should -BeTrue $script:Failover.failover.hasAfterSwitch | Should -BeTrue $script:Failover.failover.hasAfterSwitchBack | Should -BeFalse } } Context 'diagnostic test' { BeforeAll { $script:Diagnostic = New-QAFrameworkTestMetadata -CsPath (Join-Path $script:Fixtures 'TeamB\RT_Diagnostic\RT_Diagnostic.cs') } It 'is recognised as a diagnostic fixture' { $script:Diagnostic.fixture | Should -Be 'Diagnostic' } It 'reads the run type' { $script:Diagnostic.diagnosticRunType | Should -Be 'Before' } It 'reads NonCentralizedTest' { $script:Diagnostic.isNonCentralizedOnly | Should -BeTrue } It 'treats an empty LocalDB as all databases' { $script:Diagnostic.localDbs.Count | Should -Be 0 } } Context 'prerun test that is disabled' { BeforeAll { $script:PreRun = New-QAFrameworkTestMetadata -CsPath (Join-Path $script:Fixtures 'TeamB\RT_DisabledNoReason\RT_DisabledNoReason.cs') } It 'is recognised as a prerun fixture' { $script:PreRun.fixture | Should -Be 'PreRun' } It 'carries the disable reason' { $script:PreRun.disabled.reason | Should -Match 'DCP1234' } } Context 'legacy meta only test' { BeforeAll { $script:Legacy = New-QAFrameworkTestMetadata -MetaPath (Join-Path $script:Fixtures 'TeamB\RT_LegacyMeta\RT_LegacyMeta.meta') } It 'derives the name from the file' { $script:Legacy.name | Should -Be 'RT_LegacyMeta' } It 'defaults to a standard fixture' { $script:Legacy.fixture | Should -Be 'Standard' } It 'reads the weight from the meta file' { $script:Legacy.weight | Should -Be 3 } It 'reads concurrency from the meta file' { $script:Legacy.canRunConcurrently | Should -BeFalse } It 'defaults TargetDMA to One' { $script:Legacy.targetDma | Should -Be 'One' } } } |