diff --git a/test/powershell/engine/SemanticVersion.Tests.ps1 b/test/powershell/engine/SemanticVersion.Tests.ps1 new file mode 100644 index 0000000000..c350dcfc7c --- /dev/null +++ b/test/powershell/engine/SemanticVersion.Tests.ps1 @@ -0,0 +1,187 @@ +using namespace System.Management.Automation +using namespace System.Management.Automation.Language + +Describe "SemanticVersion api tests" { + Context "constructing valid versions" { + It "string argument constructor" { + $v = [SemanticVersion]::new("1.2.3-alpha") + $v.Major | Should Be 1 + $v.Minor | Should Be 2 + $v.Patch | Should Be 3 + $v.Label | Should Be "alpha" + $v.ToString() | Should Be "1.2.3-alpha" + + $v = [SemanticVersion]::new("1.0.0") + $v.Major | Should Be 1 + $v.Minor | Should Be 0 + $v.Patch | Should Be 0 + $v.Label | Should BeNullOrEmpty + $v.ToString() | Should Be "1.0.0" + } + + # After the above test, we trust the properties and rely on ToString for validation + + It "int args constructor" { + $v = [SemanticVersion]::new(1, 0, 0) + $v.ToString() | Should Be "1.0.0" + + $v = [SemanticVersion]::new(3, 2, 0, "beta.1") + $v.ToString() | Should Be "3.2.0-beta.1" + } + + It "version arg constructor" { + $v = [SemanticVersion]::new([Version]::new(1, 2, 3)) + $v.ToString() | Should Be '1.2.3' + } + + It "semantic version can round trip through version" { + $v1 = [SemanticVersion]::new(3, 2, 1, "prerelease") + $v2 = [SemanticVersion]::new([Version]$v1) + $v2.ToString() | Should Be "3.2.1-prerelease" + } + } + + Context "Comparisons" { + $v1_0_0 = [SemanticVersion]::new(1, 0, 0) + $v1_1_0 = [SemanticVersion]::new(1, 1, 0) + $v1_1_1 = [SemanticVersion]::new(1, 1, 1) + $v2_1_0 = [SemanticVersion]::new(2, 1, 0) + $v1_0_0_alpha = [SemanticVersion]::new(1, 0, 0, "alpha") + $v1_0_0_beta = [SemanticVersion]::new(1, 0, 0, "beta") + + $testCases = @( + @{ lhs = $v1_0_0; rhs = $v1_1_0 } + @{ lhs = $v1_0_0; rhs = $v1_1_1 } + @{ lhs = $v1_1_0; rhs = $v1_1_1 } + @{ lhs = $v1_0_0; rhs = $v2_1_0 } + @{ lhs = $v1_0_0_alpha; rhs = $v1_0_0_beta } + @{ lhs = $v1_0_0_alpha; rhs = $v1_0_0 } + @{ lhs = $v1_0_0_beta; rhs = $v1_0_0 } + ) + It "less than" -TestCases $testCases { + param($lhs, $rhs) + $lhs -lt $rhs | Should Be $true + $rhs -lt $lhs | Should Be $false + } + It "less than or equal" -TestCases $testCases { + param($lhs, $rhs) + $lhs -le $rhs | Should Be $true + $rhs -le $lhs | Should Be $false + $lhs -le $lhs | Should Be $true + $rhs -le $rhs | Should Be $true + } + It "greater than" -TestCases $testCases { + param($lhs, $rhs) + $lhs -gt $rhs | Should Be $false + $rhs -gt $lhs | Should Be $true + } + It "greater than or equal" -TestCases $testCases { + param($lhs, $rhs) + $lhs -ge $rhs | Should Be $false + $rhs -ge $lhs | Should Be $true + $lhs -ge $lhs | Should Be $true + $rhs -ge $rhs | Should Be $true + } + + $testCases = @( + @{ operand = $v1_0_0 } + @{ operand = $v1_0_0_alpha } + ) + It "Equality" -TestCases $testCases { + param($operand) + $operand -eq $operand | Should Be $true + $operand -ne $operand | Should Be $false + $null -eq $operand | Should Be $false + $operand -eq $null | Should Be $false + $null -ne $operand | Should Be $true + $operand -ne $null | Should Be $true + } + + It "comparisons with null" { + $v1_0_0 -lt $null | Should Be $false + $null -lt $v1_0_0 | Should Be $true + $v1_0_0 -le $null | Should Be $false + $null -le $v1_0_0 | Should Be $true + $v1_0_0 -gt $null | Should Be $true + $null -gt $v1_0_0 | Should Be $false + $v1_0_0 -ge $null | Should Be $true + $null -ge $v1_0_0 | Should Be $false + } + } + + Context "error handling" { + + # The specific errors aren't too useful here, but noted in comments + # so when we pick up a version of Pester that will let us check FullyQualifiedErrorId, + # it's easier to tweak the tests + + $testCases = @( + @{ expectedResult = $false; version = $null } + @{ expectedResult = $false; version = [NullString]::Value } + @{ expectedResult = $false; version = "" } + @{ expectedResult = $false; version = "1.0.0-" } + @{ expectedResult = $false; version = "-" } + @{ expectedResult = $false; version = "-alpha" } + @{ expectedResult = $false; version = "1.0" } # REVIEW - should this be allowed + @{ expectedResult = $false; version = "1..0" } + @{ expectedResult = $false; version = "1.0.-alpha" } + @{ expectedResult = $false; version = "1.0." } + @{ expectedResult = $false; version = ".0.0" } + ) + + It "parts of version missing" -TestCases $testCases { + param($version, $expectedResult) + { [SemanticVersion]::new($version) } | Should Throw # PSArgumentException + { [SemanticVersion]::Parse($version) } | Should Throw # PSArgumentException + $semVer = $null + [SemanticVersion]::TryParse($_, [ref]$semVer) | Should Be $expectedResult + $semVer | Should Be $null + } + + $testCases = @( + @{ expectedResult = $false; version = "-1.0.0" } + @{ expectedResult = $false; version = "1.-1.0" } + @{ expectedResult = $false; version = "1.0.-1" } + ) + + It "range check of versions" -TestCases $testCases { + param($version, $expectedResult) + { [SemanticVersion]::new($version) } | Should Throw # PSArgumentException + { [SemanticVersion]::Parse($version) } | Should Throw # PSArgumentException + $semVer = $null + [SemanticVersion]::TryParse($_, [ref]$semVer) | Should Be $expectedResult + $semVer | Should Be $null + } + + $testCases = @( + @{ expectedResult = $false; version = "aa.0.0" } + @{ expectedResult = $false; version = "1.bb.0" } + @{ expectedResult = $false; version = "1.0.cc" } + ) + + It "format errors" -TestCases $testCases { + param($version, $expectedResult) + { [SemanticVersion]::new($version) } | Should Throw # PSArgumentException + { [SemanticVersion]::Parse($version) } | Should Throw # PSArgumentException + $semVer = $null + [SemanticVersion]::TryParse($_, [ref]$semVer) | Should Be $expectedResult + $semVer | Should Be $null + } + + It "Negative version arguments" { + { [SemanticVersion]::new(-1, 0) } | Should Throw # PSArgumentException + { [SemanticVersion]::new(1, -1) } | Should Throw # PSArgumentException + { [SemanticVersion]::new(1, 1, -1) } | Should Throw # PSArgumentException + } + + It "Incompatible version throws" { + # Revision isn't supported + { [SemanticVersion]::new([Version]::new(0, 0, 0, 4)) } | Should Throw # PSArgumentException + { [SemanticVersion]::new([Version]::new("1.2.3.4")) } | Should Throw # PSArgumentException + + # Build is required + { [SemanticVersion]::new([Version]::new(1, 2)) } | Should Throw # PSArgumentException + { [SemanticVersion]::new([Version]::new("1.2")) } | Should Throw # PSArgumentException + } + } +} \ No newline at end of file