<#
.DESCRIPTION
Parses a semver version string into its components and supports operations around it that we use for versioning our packages.

See https://azure.github.io/azure-sdk/policies_releases.html#package-versioning

Example: 1.2.3-beta.4
Components: Major.Minor.Patch-PrereleaseLabel.PrereleaseNumber

Example: 1.2.3-alpha.20200828.4
Components: Major.Minor.Patch-PrereleaseLabel.PrereleaseNumber.BuildNumber

Note: A builtin Powershell version of SemVer exists in 'System.Management.Automation'. At this time, it does not parsing of PrereleaseNumber. It's name is also type accelerated to 'SemVer'.
#>

class AzureEngSemanticVersion : IComparable {
  [int] $Major
  [int] $Minor
  [int] $Patch
  [string] $PrereleaseLabelSeparator
  [string] $PrereleaseLabel
  [string] $PrereleaseNumberSeparator
  [string] $BuildNumberSeparator
  # BuildNumber is string to preserve zero-padding where applicable
  [string] $BuildNumber
  [int] $PrereleaseNumber
  [bool] $IsPrerelease
  [string] $VersionType
  [string] $RawVersion
  [bool] $IsSemVerFormat
  [string] $DefaultPrereleaseLabel
  [string] $DefaultAlphaReleaseLabel
  # For Python PEP440 post-release support only
  [bool] $IsPostRelease
  [int] $PostReleaseNumber
  [string] $PostReleaseSeparator

  # Regex inspired but simplified from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
  # Validation: https://regex101.com/r/vkijKf/426
  static [string] $SEMVER_REGEX = "(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:(?<presep>-?)(?<prelabel>[a-zA-Z]+)(?:(?<prenumsep>\.?)(?<prenumber>[0-9]{1,8})(?:(?<buildnumsep>\.?)(?<buildnumber>\d{1,3}))?)?)?"

  # Python PEP 440 post-release extension
  # Handles all PEP 440 alternate formats: .postN, -postN, _postN, postN, .post.N, .post (implicit 0) (case-insensitive)
  # Validation: https://regex101.com/r/rAdOg0/2
  static [string] $PYTHON_SEMVER_REGEX = [AzureEngSemanticVersion]::SEMVER_REGEX + "(?:(?<postsep>[.\-_]?)(?<postword>(?i:post))\.?(?<postnum>\d{1,8})?)?"

  static [AzureEngSemanticVersion] ParseVersionString([string] $versionString)
  {
    $version = [AzureEngSemanticVersion]::new($versionString)

    if (!$version.IsSemVerFormat) {
      return $null
    }
    return $version
  }

  static [AzureEngSemanticVersion] ParsePythonVersionString([string] $versionString)
  {
    $previousLanguage = (Get-Variable -Name "Language" -ValueOnly -ErrorAction "Ignore")
    $global:Language = "python"
    $version = $null
    try {
      $version = [AzureEngSemanticVersion]::new($versionString)
    }
    finally {
      $global:Language = $previousLanguage
    }

    if (!$version.IsSemVerFormat) {
      return $null
    }
    return $version
  }
  
  AzureEngSemanticVersion([string] $versionString)
  {
    $parseLanguage = (Get-Variable -Name "Language" -ValueOnly -ErrorAction "Ignore")

    if ($parseLanguage -eq "python") {
      $parseRegex = $this.SetupPythonConventions()
    }
    else {
      $parseRegex = $this.SetupDefaultConventions()
    }

    if ($versionString -match "^${parseRegex}$")
    {
      $this.IsSemVerFormat = $true
      $this.RawVersion = $versionString
      $this.Major = [int]$matches.Major
      $this.Minor = [int]$matches.Minor
      $this.Patch = [int]$matches.Patch

      $skipPrelabel = $false
      if ($parseLanguage -eq "python") {
        if ($matches['postword']) {
          $this.IsPostRelease = $true
          $this.PostReleaseNumber = if ($matches['postnum']) { [int]$matches['postnum'] } else { 0 }
          $this.PostReleaseSeparator = ".post"
        }
        elseif ($matches['prelabel'] -and $matches['prelabel'] -ieq 'post') {
          # Alternate PEP 440 forms like "1.0.0-post1" or "1.0.0post1" where the regex
          # matched "post" as a prerelease label — reinterpret as post-release.
          $this.IsPostRelease = $true
          $this.PostReleaseNumber = [int]$matches['prenumber']
          $this.PostReleaseSeparator = ".post"
          $skipPrelabel = $true
        }
      }

      if ($skipPrelabel -or $null -eq $matches['prelabel'])
      {
        $this.IsPrerelease = $false
        $this.VersionType = "GA"
        if ($this.Major -eq 0) {
          # Treat initial 0 versions as a prerelease beta's
          $this.VersionType = "Beta"
          $this.IsPrerelease = $true
        }
        elseif ($this.Patch -ne 0) {
          $this.VersionType = "Patch"
        }
      }
      else
      {
        $this.PrereleaseLabel = $matches["prelabel"]
        $this.PrereleaseLabelSeparator = $matches["presep"]
        $this.PrereleaseNumber = [int]$matches["prenumber"]
        $this.PrereleaseNumberSeparator = $matches["prenumsep"]
        $this.IsPrerelease = $true
        $this.VersionType = "Beta"

        $this.BuildNumberSeparator = $matches["buildnumsep"]
        $this.BuildNumber = $matches["buildnumber"]
      }
    }
    else
    {
      $this.RawVersion = $versionString
      $this.IsSemVerFormat = $false
    }
  }

  # If a prerelease label exists, it must be 'beta', and similar semantics used in our release guidelines
  # See https://azure.github.io/azure-sdk/policies_releases.html#package-versioning
  [bool] HasValidPrereleaseLabel()
  {
    if ($this.PrereleaseLabel) {
      if ($this.PrereleaseLabel -ne $this.DefaultPrereleaseLabel -and $this.PrereleaseLabel -ne $this.DefaultAlphaReleaseLabel) {
        Write-Host "Unexpected pre-release identifier '$($this.PrereleaseLabel)', "`
                   "should be '$($this.DefaultPrereleaseLabel)' or '$($this.DefaultAlphaReleaseLabel)'"
        return $false;
      }
      if ($this.PrereleaseNumber -lt 1)
      {
        Write-Host "Unexpected pre-release version '$($this.PrereleaseNumber)', should be >= '1'"
        return $false;
      }
    }

    return $true;
  }

  [string] ToString()
  {
    $versionString = "{0}.{1}.{2}" -F $this.Major, $this.Minor, $this.Patch

    if ($this.PrereleaseLabel)
    {
      $versionString += $this.PrereleaseLabelSeparator + $this.PrereleaseLabel + `
                        $this.PrereleaseNumberSeparator + $this.PrereleaseNumber
      if ($this.BuildNumber) {
          $versionString += $this.BuildNumberSeparator + $this.BuildNumber
      }
    }
    if ($this.IsPostRelease) {
      $versionString += $this.PostReleaseSeparator + $this.PostReleaseNumber
    }
    return $versionString;
  }

  [void] IncrementAndSetToPrerelease($Segment) {
    if ($this.BuildNumber)
    {
      throw "Cannot increment releases tagged with azure pipelines build numbers"
    }

    # Clear post-release state before incrementing
    if ($this.IsPostRelease) {
      $this.IsPostRelease = $false
      $this.PostReleaseNumber = 0
      $this.PostReleaseSeparator = ""
    }

    if ($this.PrereleaseLabel)
    {
      $this.PrereleaseNumber++
    }
    else
    {
      $this.$Segment++
      if($Segment -eq "Major") {
        $this.Minor = 0
        $this.Patch = 0
      }
      if($Segment -eq "Minor") {
        $this.Patch = 0
      }

      # If the major version is 0, we don't need a prerelease label
      if ($this.Major -ne 0)
      {
        $this.PrereleaseLabel = $this.DefaultPrereleaseLabel
        $this.PrereleaseNumber = 1
      }

      $this.IsPrerelease = $true
    }
  }

  [void] IncrementAndSetToPrerelease() {
    $this.IncrementAndSetToPrerelease("Minor")
  }

  [void] IncrementAndSetToPostRelease() {
    if ($this.BuildNumber)
    {
      throw "Cannot increment releases tagged with azure pipelines build numbers"
    }

    if ($this.IsPostRelease) {
      $this.PostReleaseNumber++
    }
    else {
      $this.IsPostRelease = $true
      $this.PostReleaseNumber = 1
      $this.PostReleaseSeparator = ".post"
    }
  }

  # Sets the version to a prerelease state with the specified label and number.
  # This clears any post-release state to ensure a clean prerelease version.
  [void] SetPrerelease([string] $Label, [int] $Number) {
    # Clear post-release state
    if ($this.IsPostRelease) {
      $this.IsPostRelease = $false
      $this.PostReleaseNumber = 0
      $this.PostReleaseSeparator = ""
    }

    $this.PrereleaseLabel = $Label
    $this.PrereleaseNumber = $Number
    $this.IsPrerelease = $true
  }

  [string] SetupPythonConventions()
  {
    # Python uses no separators and "b" for beta so this sets up the the object to work with those conventions
    $this.PrereleaseLabelSeparator = $this.PrereleaseNumberSeparator = $this.BuildNumberSeparator = ""
    $this.DefaultPrereleaseLabel = "b"
    $this.DefaultAlphaReleaseLabel = "a"
    return [AzureEngSemanticVersion]::PYTHON_SEMVER_REGEX
  }

  [string] SetupDefaultConventions()
  {
    # Use the default common conventions
    $this.PrereleaseLabelSeparator = "-"
    $this.PrereleaseNumberSeparator = "."
    $this.BuildNumberSeparator = "."
    $this.DefaultPrereleaseLabel = "beta"
    $this.DefaultAlphaReleaseLabel = "alpha"
    return [AzureEngSemanticVersion]::SEMVER_REGEX
  }

  [int] CompareTo($other)
  {
    if ($other -isnot [AzureEngSemanticVersion]) {
      throw "Cannot compare $other with $this"
    }

    $ret = $this.Major.CompareTo($other.Major)
    if ($ret) { return $ret }

    $ret = $this.Minor.CompareTo($other.Minor)
    if ($ret) { return $ret }

    $ret = $this.Patch.CompareTo($other.Patch)
    if ($ret) { return $ret }

    # provide artificial prerelease values for non-prereleases to sort them later than prereleases.
    if ($this.PrereleaseLabel) {
      $thisPrereleaseLabel = $this.PrereleaseLabel
      $thisPrereleaseNumber = $this.PrereleaseNumber
    }
    else {
      $thisPrereleaseLabel = "zzz"
      $thisPrereleaseNumber = 99999999
    }

    if ($other.PrereleaseLabel) {
      $otherPrereleaseLabel = $other.PrereleaseLabel
      $otherPrereleaseNumber = $other.PrereleaseNumber
    }
    else {
      $otherPrereleaseLabel = "zzz"
      $otherPrereleaseNumber = 99999999
    }

    # Mimic PowerShell that uses case-insensitive comparisons by default.
    $ret = [string]::Compare($thisPrereleaseLabel, $otherPrereleaseLabel, $true)
    if ($ret) { return $ret }

    $ret = $thisPrereleaseNumber.CompareTo($otherPrereleaseNumber)
    if ($ret) { return $ret }

    $thisBuildNumber = if ($this.BuildNumber) { [int] $this.BuildNumber } else { 0 }
    $otherBuildNumber = if ($other.BuildNumber) { [int] $other.BuildNumber } else { 0 }
    $ret = $thisBuildNumber.CompareTo($otherBuildNumber)
    if ($ret) { return $ret }

    # Post-release versions sort after their base version
    $thisPost = if ($this.IsPostRelease) { 1 } else { 0 }
    $otherPost = if ($other.IsPostRelease) { 1 } else { 0 }
    $ret = $thisPost.CompareTo($otherPost)
    if ($ret) { return $ret }

    return $this.PostReleaseNumber.CompareTo($other.PostReleaseNumber)
  }

  static [string[]] SortVersionStrings([string[]] $versionStrings)
  {
    $parseLanguage = (Get-Variable -Name "Language" -ValueOnly -ErrorAction "Ignore")
    if ($parseLanguage -eq "python") {
      $versions = $versionStrings | ForEach-Object { [AzureEngSemanticVersion]::ParsePythonVersionString($_) }
    }
    else {
      $versions = $versionStrings | ForEach-Object { [AzureEngSemanticVersion]::ParseVersionString($_) }
    }
    $sortedVersions = [AzureEngSemanticVersion]::SortVersions($versions)
    return ($sortedVersions | ForEach-Object { $_.RawVersion })
  }

  static [AzureEngSemanticVersion[]] SortVersions([AzureEngSemanticVersion[]] $versions)
  {
    return $versions | Sort-Object -Descending
  }

  static [void] QuickTests()
  {
    $global:Language = ""
    $versions = @(
      "1.0.1",
      "2.0.0",
      "2.0.0-alpha.20200920",
      "2.0.0-alpha.20200920.1",
      "2.0.0-beta.2",
      "1.0.10",
      "2.0.0-alpha.20201221.03",
      "2.0.0-alpha.20201221.1",
      "2.0.0-alpha.20201221.5",
      "2.0.0-alpha.20201221.2",
      "2.0.0-alpha.20201221.10",
      "2.0.0-beta.1",
      "2.0.0-beta.10",
      "1.0.0",
      "1.0.0b2",
      "1.0.2")

    $expectedSort = @(
      "2.0.0",
      "2.0.0-beta.10",
      "2.0.0-beta.2",
      "2.0.0-beta.1",
      "2.0.0-alpha.20201221.10",
      "2.0.0-alpha.20201221.5",
      "2.0.0-alpha.20201221.03",
      "2.0.0-alpha.20201221.2",
      "2.0.0-alpha.20201221.1",
      "2.0.0-alpha.20200920.1",
      "2.0.0-alpha.20200920",
      "1.0.10",
      "1.0.2",
      "1.0.1",
      "1.0.0",
      "1.0.0b2")

    $sort = [AzureEngSemanticVersion]::SortVersionStrings($versions)

    for ($i = 0; $i -lt $expectedSort.Count; $i++)
    {
      if ($sort[$i] -ne $expectedSort[$i]) {
        Write-Host "Error: Incorrect version sort:"
        Write-Host "Expected: "
        Write-Host $expectedSort
        Write-Host "Actual:"
        Write-Host $sort
        break
      }
    }

    $alphaVerString = "1.2.3-alpha.20200828.9"
    $alphaVer = [AzureEngSemanticVersion]::new($alphaVerString)
    if (!$alphaVer.IsPrerelease) {
      Write-Host "Expected alpha version to be marked as prerelease"
    }
    if ($alphaVer.Major -ne 1 -or $alphaVer.Minor -ne 2 -or $alphaVer.Patch -ne 3 -or `
        $alphaVer.PrereleaseLabel -ne "alpha" -or $alphaVer.PrereleaseNumber -ne 20200828 -or $alphaVer.BuildNumber -ne 9) {
      Write-Host "Error: Didn't correctly parse alpha version string $alphaVerString"
    }
    if ($alphaVerString -ne $alphaVer.ToString()) {
      Write-Host "Error: alpha string did not correctly round trip with ToString. Expected: $($alphaVerString), Actual: $($alphaVer)"
    }

    $global:Language = "python"
    $pythonAlphaVerString = "1.2.3a20200828009"
    $pythonAlphaVer = [AzureEngSemanticVersion]::new($pythonAlphaVerString)
    if (!$pythonAlphaVer.IsPrerelease) {
      Write-Host "Expected python alpha version to be marked as prerelease"
    }
    # Note: For python we lump build number into prerelease number, since it simplifies the code and regex, and is behaviorally the same
    if ($pythonAlphaVer.Major -ne 1 -or $pythonAlphaVer.Minor -ne 2 -or $pythonAlphaVer.Patch -ne 3 `
        -or $pythonAlphaVer.PrereleaseLabel -ne "a" -or $pythonAlphaVer.PrereleaseNumber -ne 20200828 `
        -or $pythonAlphaVer.BuildNumber -ne "009") {
      Write-Host "Error: Didn't correctly parse python alpha version string $pythonAlphaVerString"
    }
    if ($pythonAlphaVerString -ne $pythonAlphaVer.ToString()) {
      Write-Host "Error: python alpha string did not correctly round trip with ToString. Expected: $($pythonAlphaVerString), Actual: $($pythonAlphaVer)"
    }

    $versions = @("1.0.1", "2.0.0", "2.0.0a20201208001", "2.0.0a20201105020", "2.0.0a20201208012", `
                  "2.0.0b2", "1.0.10", "2.0.0b1", "2.0.0b10", "1.0.0", "1.0.0b2", "1.0.2")
    $expectedSort = @("2.0.0", "2.0.0b10", "2.0.0b2", "2.0.0b1", "2.0.0a20201208012", "2.0.0a20201208001", `
                      "2.0.0a20201105020", "1.0.10", "1.0.2", "1.0.1", "1.0.0", "1.0.0b2")
    $sort = [AzureEngSemanticVersion]::SortVersionStrings($versions)
    for ($i = 0; $i -lt $expectedSort.Count; $i++)
    {
      if ($sort[$i] -ne $expectedSort[$i]) { 
        Write-Host "Error: Incorrect python version sort:"
        Write-Host "Expected: "
        Write-Host $expectedSort
        Write-Host "Actual:"
        Write-Host $sort
        break
      }
    }

    $global:Language = ""

    $gaVerString = "1.2.3"
    $gaVer = [AzureEngSemanticVersion]::ParseVersionString($gaVerString)
    if ($gaVer.Major -ne 1 -or $gaVer.Minor -ne 2 -or $gaVer.Patch -ne 3) {
      Write-Host "Error: Didn't correctly parse ga version string $gaVerString"
    }
    if ($gaVerString -ne $gaVer.ToString()) {
      Write-Host "Error: Ga string did not correctly round trip with ToString. Expected: $($gaVerString), Actual: $($gaVer)"
    }
    $gaVer.IncrementAndSetToPrerelease()
    if ("1.3.0-beta.1" -ne $gaVer.ToString()) {
      Write-Host "Error: Ga string did not correctly increment"
    }

    $betaVerString = "1.2.3-beta.4"
    $betaVer = [AzureEngSemanticVersion]::ParseVersionString($betaVerString)
    if ($betaVer.Major -ne 1 -or $betaVer.Minor -ne 2 -or $betaVer.Patch -ne 3 -or $betaVer.PrereleaseLabel -ne "beta" -or $betaVer.PrereleaseNumber -ne 4) {
      Write-Host "Error: Didn't correctly parse beta version string $betaVerString"
    }
    if ($betaVerString -ne $betaVer.ToString()) {
      Write-Host "Error: beta string did not correctly round trip with ToString. Expected: $($betaVerString), Actual: $($betaVer)"
    }
    $betaVer.IncrementAndSetToPrerelease()
    if ("1.2.3-beta.5" -ne $betaVer.ToString()) {
      Write-Host "Error: Beta string did not correctly increment"
    }

    $pythonBetaVerString = "1.2.3b4"
    $pbetaVer = [AzureEngSemanticVersion]::ParsePythonVersionString($pythonBetaVerString)
    if ($pbetaVer.Major -ne 1 -or $pbetaVer.Minor -ne 2 -or $pbetaVer.Patch -ne 3 -or $pbetaVer.PrereleaseLabel -ne "b" -or $pbetaVer.PrereleaseNumber -ne 4) {
      Write-Host "Error: Didn't correctly parse python beta string $pythonBetaVerString"
    }
    if ($pythonBetaVerString -ne $pbetaVer.ToString()) {
      Write-Host "Error: python beta string did not correctly round trip with ToString"
    }
    $pbetaVer.IncrementAndSetToPrerelease()
    if ("1.2.3b5" -ne $pbetaVer.ToString()) {
      Write-Host "Error: Python beta string did not correctly increment"
    }

    $version = [AzureEngSemanticVersion]::ParseVersionString("0.1.2")
    $version.IncrementAndSetToPrerelease()
    $expected = "0.2.0"
    if ($expected -ne $version.ToString()) {
      Write-Host "Error: version string did not correctly increment. Expected: $expected, Actual: $version"
    }

    $version = [AzureEngSemanticVersion]::ParseVersionString("0.1.2")
    $version.IncrementAndSetToPrerelease("patch")
    $expected = "0.1.3"
    if ($expected -ne $version.ToString()) {
      Write-Host "Error: version string did not correctly increment. Expected: $expected, Actual: $version"
    }

    $version = [AzureEngSemanticVersion]::ParseVersionString("0.1.2")
    $version.IncrementAndSetToPrerelease("minor")
    $expected = "0.2.0"
    if ($expected -ne $version.ToString()) {
      Write-Host "Error: version string did not correctly increment. Expected: $expected, Actual: $version"
    }

    $version = [AzureEngSemanticVersion]::ParseVersionString("0.1.2")
    $version.IncrementAndSetToPrerelease("major")
    $expected = "1.0.0-beta.1"
    if ($expected -ne $version.ToString()) {
      Write-Host "Error: version string did not correctly increment. Expected: $expected, Actual: $version"
    }

    $version = [AzureEngSemanticVersion]::ParseVersionString("1.0.0-beta.1")
    $version.IncrementAndSetToPrerelease()
    $expected = "1.0.0-beta.2"
    if ($expected -ne $version.ToString()) {
      Write-Host "Error: version string did not correctly increment. Expected: $expected, Actual: $version"
    }

    # Python post-release parsing tests
    $postVerString = "1.0.0.post1"
    $postVer = [AzureEngSemanticVersion]::ParsePythonVersionString($postVerString)
    if ($postVer.Major -ne 1 -or $postVer.Minor -ne 0 -or $postVer.Patch -ne 0 -or `
        !$postVer.IsPostRelease -or $postVer.PostReleaseNumber -ne 1 -or $postVer.IsPrerelease) {
      Write-Host "Error: Didn't correctly parse python post-release string $postVerString"
    }
    if ($postVerString -ne $postVer.ToString()) {
      Write-Host "Error: post-release string did not correctly round trip with ToString. Expected: $($postVerString), Actual: $($postVer)"
    }

    # Implicit post-release number (PEP 440: 1.0.0.post == 1.0.0.post0)
    $implicitPostVerString = "1.0.0.post"
    $implicitPostVer = [AzureEngSemanticVersion]::ParsePythonVersionString($implicitPostVerString)
    if ($null -eq $implicitPostVer -or !$implicitPostVer.IsSemVerFormat) {
      Write-Host "Error: Failed to parse implicit post-release string $implicitPostVerString"
    }
    elseif ($implicitPostVer.Major -ne 1 -or $implicitPostVer.Minor -ne 0 -or $implicitPostVer.Patch -ne 0 -or `
            !$implicitPostVer.IsPostRelease -or $implicitPostVer.PostReleaseNumber -ne 0) {
      Write-Host "Error: Didn't correctly parse implicit post-release string $implicitPostVerString"
    }
    $expected = "1.0.0.post0"
    if ($expected -ne $implicitPostVer.ToString()) {
      Write-Host "Error: implicit post-release did not normalize. Expected: $expected, Actual: $($implicitPostVer)"
    }

    # Prerelease + post-release
    $preBetaPostString = "1.0.0b2.post1"
    $preBetaPost = [AzureEngSemanticVersion]::ParsePythonVersionString($preBetaPostString)
    if ($preBetaPost.Major -ne 1 -or $preBetaPost.Minor -ne 0 -or $preBetaPost.Patch -ne 0 -or `
        $preBetaPost.PrereleaseLabel -ne "b" -or $preBetaPost.PrereleaseNumber -ne 2 -or `
        !$preBetaPost.IsPostRelease -or $preBetaPost.PostReleaseNumber -ne 1) {
      Write-Host "Error: Didn't correctly parse python prerelease post-release string $preBetaPostString"
    }
    if ($preBetaPostString -ne $preBetaPost.ToString()) {
      Write-Host "Error: prerelease post-release string did not correctly round trip with ToString. Expected: $($preBetaPostString), Actual: $($preBetaPost)"
    }

    # Post-release alternate separators normalize to canonical form
    $expectedNormalized = "1.0.0.post1"
    foreach ($altVerString in @("1.0.0-post1", "1.0.0_post1", "1.0.0post1")) {
      $parsed = [AzureEngSemanticVersion]::ParsePythonVersionString($altVerString)
      if ($null -eq $parsed -or !$parsed.IsPostRelease -or $parsed.PostReleaseNumber -ne 1) {
        Write-Host "Error: Failed to parse alternate post-release format $altVerString"
      }
      if ($expectedNormalized -ne $parsed.ToString()) {
        Write-Host "Error: Alternate post-release '$altVerString' did not normalize. Expected: $expectedNormalized, Actual: $($parsed)"
      }
    }

    # Post-release increment clears post state
    $postIncVer = [AzureEngSemanticVersion]::ParsePythonVersionString("1.0.0.post1")
    $postIncVer.IncrementAndSetToPrerelease()
    $expected = "1.1.0b1"
    if ($expected -ne $postIncVer.ToString()) {
      Write-Host "Error: post-release increment did not produce expected result. Expected: $expected, Actual: $($postIncVer)"
    }

    # Post-release increment stays in post state
    $postBumpVer = [AzureEngSemanticVersion]::ParsePythonVersionString("1.0.0.post1")
    $postBumpVer.IncrementAndSetToPostRelease()
    $expected = "1.0.0.post2"
    if ($expected -ne $postBumpVer.ToString()) {
      Write-Host "Error: post-release bump did not produce expected result. Expected: $expected, Actual: $($postBumpVer)"
    }

    # Non-post version enters post state
    $gaToPost = [AzureEngSemanticVersion]::ParsePythonVersionString("1.0.0")
    $gaToPost.IncrementAndSetToPostRelease()
    $expected = "1.0.0.post1"
    if ($expected -ne $gaToPost.ToString()) {
      Write-Host "Error: GA to post-release did not produce expected result. Expected: $expected, Actual: $($gaToPost)"
    }

    Write-Host "QuickTests done"
  }
}