Tests/GitHubCore.Tests.ps1

# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

<#
.Synopsis
   Tests for GitHubCore.ps1 module
#>


[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '',
    Justification='Suppress false positives in Pester code blocks')]
param()

# This is common test code setup logic for all Pester test files
$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent
. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1')

try
{
    Describe 'Testing ConvertTo-SmarterObject behavior' {
        InModuleScope PowerShellForGitHub {
            $jsonConversionDepth = 20

            Context 'When a property is a simple type' {
                $original = [PSCustomObject]@{
                    'prop1' = 'value1'
                    'prop2' = 3
                    'prop3' = $null
                }

                $converted = ConvertTo-SmarterObject -InputObject $original

                It 'Should return the same values' {
                    $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth)
                    $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth)
                    $originalJson -eq $convertedJson | Should -Be $true
                }
            }

            Context 'When a property is a PSCustomObject' {
                $original = [PSCustomObject]@{
                    'prop1' = [PSCustomObject]@{
                        'prop1' = 'value1'
                        'prop2' = 3
                        'prop3' = $null
                    }
                'prop2' = 3
                'prop3' = $null
            }

                $converted = ConvertTo-SmarterObject -InputObject $original

                It 'Should return the correct values' {
                    $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth)
                    $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth)
                    $originalJson -eq $convertedJson | Should -Be $true
                }
            }

            Context 'When a known date property has a date string' {
                $date = Get-Date
                $dateString = $date.ToUniversalTime().ToString('o')
                $original = [PSCustomObject]@{
                    'prop1' = $dateString
                    'closed_at' = $dateString
                    'committed_at' = $dateString
                    'completed_at' = $dateString
                    'created_at' = $dateString
                    'date' = $dateString
                    'due_on' = $dateString
                    'last_edited_at' = $dateString
                    'last_read_at' = $dateString
                    'merged_at' = $dateString
                    'published_at' = $dateString
                    'pushed_at' = $dateString
                    'starred_at' = $dateString
                    'started_at' = $dateString
                    'submitted_at' = $dateString
                    'timestamp' = $dateString
                    'updated_at' = $dateString
                }

                $converted = ConvertTo-SmarterObject -InputObject $original

                It 'Should convert the value to a [DateTime]' {
                    $converted.closed_at -is [DateTime] | Should -Be $true
                    $converted.committed_at -is [DateTime] | Should -Be $true
                    $converted.completed_at -is [DateTime] | Should -Be $true
                    $converted.created_at -is [DateTime] | Should -Be $true
                    $converted.date -is [DateTime] | Should -Be $true
                    $converted.due_on -is [DateTime] | Should -Be $true
                    $converted.last_edited_at -is [DateTime] | Should -Be $true
                    $converted.last_read_at -is [DateTime] | Should -Be $true
                    $converted.merged_at -is [DateTime] | Should -Be $true
                    $converted.published_at -is [DateTime] | Should -Be $true
                    $converted.pushed_at -is [DateTime] | Should -Be $true
                    $converted.starred_at -is [DateTime] | Should -Be $true
                    $converted.started_at -is [DateTime] | Should -Be $true
                    $converted.submitted_at -is [DateTime] | Should -Be $true
                    $converted.timestamp -is [DateTime] | Should -Be $true
                    $converted.updated_at -is [DateTime] | Should -Be $true
                }

                It 'Should NOT convert the value to a [DateTime] if it''s not a known property' {
                    $converted.prop1 -is [DateTime] | Should -Be $false
                }
            }

            Context 'When a known date property has a null, empty or invalid date string' {
                $original = [PSCustomObject]@{
                    'closed_at' = $null
                    'committed_at' = '123'
                    'completed_at' = ''
                    'created_at' = 123
                    'date' = $null
                    'due_on' = '123'
                    'last_edited_at' = ''
                    'last_read_at' = 123
                    'merged_at' = $null
                    'published_at' = '123'
                    'pushed_at' = ''
                    'starred_at' = 123
                    'started_at' = $null
                    'submitted_at' = '123'
                    'timestamp' = ''
                    'updated_at' = 123
                }

                $converted = ConvertTo-SmarterObject -InputObject $original

                It 'Should keep the existing value' {
                    $original.closed_at -eq $converted.closed_at | Should -Be $true
                    $original.committed_at -eq $converted.committed_at | Should -Be $true
                    $original.completed_at -eq $converted.completed_at | Should -Be $true
                    $original.created_at -eq $converted.created_at | Should -Be $true
                    $original.date -eq $converted.date | Should -Be $true
                    $original.due_on -eq $converted.due_on | Should -Be $true
                    $original.last_edited_at -eq $converted.last_edited_at | Should -Be $true
                    $original.last_read_at -eq $converted.last_read_at | Should -Be $true
                    $original.merged_at -eq $converted.merged_at | Should -Be $true
                    $original.published_at -eq $converted.published_at | Should -Be $true
                    $original.pushed_at -eq $converted.pushed_at | Should -Be $true
                    $original.starred_at -eq $converted.starred_at | Should -Be $true
                    $original.started_at -eq $converted.started_at | Should -Be $true
                    $original.submitted_at -eq $converted.submitted_at | Should -Be $true
                    $original.timestamp -eq $converted.timestamp | Should -Be $true
                    $original.updated_at -eq $converted.updated_at | Should -Be $true
                }
            }

            Context 'When an object has an empty array' {
                $original = [PSCustomObject]@{
                    'prop1' = 'value1'
                    'prop2' = 3
                    'prop3' = @()
                    'prop4' = $null
                }

                $converted = ConvertTo-SmarterObject -InputObject $original

                It 'Should still be an empty array after conversion' {
                    $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth)
                    $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth)
                    $originalJson -eq $convertedJson | Should -Be $true
                }
            }

            Context 'When an object has a single item array' {
                $original = [PSCustomObject]@{
                    'prop1' = 'value1'
                    'prop2' = 3
                    'prop3' = @(1)
                    'prop4' = $null
                }

                $converted = ConvertTo-SmarterObject -InputObject $original

                It 'Should still be a single item array after conversion' {
                    $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth)
                    $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth)
                    $originalJson -eq $convertedJson | Should -Be $true
                }
            }

            Context 'When an object has a multi-item array' {
                $original = [PSCustomObject]@{
                    'prop1' = 'value1'
                    'prop2' = 3
                    'prop3' = @(1, 2)
                    'prop4' = $null
                }

                $converted = ConvertTo-SmarterObject -InputObject $original

                It 'Should still be a multi item array after conversion' {
                    $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth)
                    $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth)
                    $originalJson -eq $convertedJson | Should -Be $true
                }
            }
        }
    }

    Describe 'Testing Split-GitHubUri' {
        BeforeAll {
            $repositoryName = [guid]::NewGuid().Guid
            $url = "https://github.com/$script:ownerName/$repositoryName"
        }

        Context 'For getting the OwnerName' {
            It 'Should return expected repository name' {
                $name = Split-GitHubUri -Uri $url -RepositoryName
                $name | Should -Be $repositoryName
            }

            It 'Should return expected repository name with the pipeline' {
                $name = $url | Split-GitHubUri -RepositoryName
                $name | Should -Be $repositoryName
            }
        }

        Context 'For getting the RepositoryName' {
            It 'Should return expected owner name' {
                $name = Split-GitHubUri -Uri $url -OwnerName
                $name | Should -Be $script:ownerName
            }

            It 'Should return expected owner name with the pipeline' {
                $owner = $url | Split-GitHubUri -OwnerName
                $owner | Should -Be $script:ownerName
            }
        }

        Context 'For getting both the OwnerName and the RepositoryName' {
            It 'Should return both OwnerName and RepositoryName' {
                $elements = Split-GitHubUri -Uri $url
                $elements.ownerName | Should -Be $script:ownerName
                $elements.repositoryName | Should -Be $repositoryName
            }

            It 'Should return both OwnerName and RepositoryName with the pipeline' {
                $elements = $url | Split-GitHubUri
                $elements.ownerName | Should -Be $script:ownerName
                $elements.repositoryName | Should -Be $repositoryName
            }
        }
    }
}
finally
{
    if (Test-Path -Path $script:originalConfigFile -PathType Leaf)
    {
        # Restore the user's configuration to its pre-test state
        Restore-GitHubConfiguration -Path $script:originalConfigFile
        $script:originalConfigFile = $null
    }
}