module_tests/nuspec_required.tests.ps1

[CmdletBinding()]
Param(
    [Parameter(Mandatory)]
    [hashtable]
    $Metadata
)

Describe 'Chocolatey Community Repository Nuspec Requirements' {

    Context 'Required Metadata' {
        
        It "<Property> is defined" -ForEach @(
            @{Property = 'id' }
            @{Property = 'version' }
            @{Property = 'summary' }
            @{Property = 'description' }
            @{Property = 'authors' }
        ) {
            $metadata.$($_.Property)  | Should -Not -BeNullOrEmpty -Because "$($_.Property) is required to run choco pack against this nuspec file."
        }

    }

    Context 'All required Urls are defined' {
        It "<Property> is defined" -ForEach @(
            @{Property = 'projectUrl' ; Rule = 'CPMR0009 - ProjectUrl Missing (nuspec)' }
            @{Property = 'packageSourceUrl' ; Rule = 'CPMR0040 - PackageSourceUrl Missing (nuspec)' }
            @{Property = 'iconUrl' ; Rule = 'CPMR0033 - IconUrl Missing (nuspec)' }
        ) {
            $metadata.$($_.Property)  | Should -Not -BeNullOrEmpty -Because $_.Rule
        }

        It 'projectSourceUrl matches ProjectUrl' {
            $metadata.projectSourceUrl -eq $metadata.projectUrl | Should -Be $true -Because 'CPMR0041 - ProjectSourceUrl Matches ProjectUrl (nuspec)'
        }
    }

    Context 'Templated values are not in use' {
        BeforeDiscovery {
            $data = @()
            $Metadata.GetEnumerator() | ForEach-Object {
                $data += @{Node = $_.Name; Value = $_.Value }
            }
        }
        It "<Node> does not have template values" -foreach $data {
            $matcher = '__.+__|SPACE_SEPARATED'
            $Value -match $matcher | Should -Be $false -Because "CPMR0019: The element $Node contained a templated value. Templated values should not be present in the Metadata file"
        }
        
    }

    Context 'All fields are valid lengths' {

        It 'Description > 30 characters' {
            ($metadata.description).length -gt 30 | Should -Be $true -Because 'CPMR0032 - Description Character count below 30 (nuspec)'
        }

        It 'Description less than 4000 characters' {
            ($metadata.description).Length -lt 4000 | Should -Be $true -Because 'CPMR0026 - Description Character Count Above 4000 (nuspec)'
        }

        It 'Copyright is >= 4 characters' {
            ($Metadata.copyright).length -ge 4 | Should -be $true -Because 'CPMR0001 - Copyright character count below 4 (nuspec)'
        }
    }

    Context 'Package id validation' {
        It 'Id does not use resevered name' {
            ($Metadata.id).EndsWith('.config') | Should -Be $false -Because 'CPMR0029 - Package Id Does Not End With .config (nuspec)'
        }

        It 'Does not contain prerelease information' {
            $matcher = '(alpha|beta)$'
            $Metadata.id -match $matcher | Should -Be $false -Because "CPMR0024 - Prerelease information shouldn't be included as part of Package Id (nuspec)"
        }
    }
    
    Context 'Tag validation' {

        It 'Tags are required for the package' {
            $Metadata.tags | should -Not -BeNullOrEmpty -Because 'CPMR0023 - Tags Missing (nuspec)'
        }

        It 'Tags should be space separated' {
            It 'Tags should be space separated' {
                $Metadata.tags | Should -Match '^(\S+ )+\S+$' -Because 'CPMR0014 - Tags Have Commas (nuspec)'
            }
        }
    }
    
    Context 'Description content' {
        BeforeDiscovery {
            $lines = $metadata.description -split '\n'
            $headings = $lines | Where-Object { $_ -match '^#' }
        }
        
        It 'Description is not null' {
            $metadata.description | Should -Not -BeNullOrEmpty -Because 'CPMR0002 - Description missing (nuspec)'
        }

        It "<_> is a valid heading" -foreach $headings {
            $_ | Should -Match '^#{1,6} .+' -Because 'CPMR0030 - Description Contains Invalid Markdown Heading (nuspec)'
        }
    }

    Context 'Version validation' {
        It 'Version is proper semver' {
            $semvermatch = '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
            $metadata.version -match $semvermatch | Should -Be $true
        }

        Context 'LicenseUrl is used correctly' {
            It 'Should have valid licenseUrl when requiring license acceptance' {
                if ($metadata.requireLicenseAcceptance) {
                    $metadata.licenseUrl | Should -not -BeNullOrEmpty -Because 'CPMR0007 - License Url Missing / License Acceptance is True (nuspec)'
                }
            }
        }

    }

    # TODO: https://docs.chocolatey.org/en-us/community-repository/moderation/package-validator/rules/cpmr0017
    # TODO: https://docs.chocolatey.org/en-us/community-repository/moderation/package-validator/rules/cpmr0020
}