Private/Generator/Tests/ConvertTo-OpenApiGenFunction.Tests.ps1
|
BeforeAll { $env:TCS_CONFIG_ROOT = Join-Path -Path $TestDrive -ChildPath 'config' $env:TCS_SKIP_UPDATE_CHECK = '1' $env:TCS_TELEMETRY_OPTOUT = '1' $ModuleRoot = Split-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -Parent Import-Module -Name (Join-Path -Path $ModuleRoot -ChildPath 'tcs.openapi.psd1') -Force $RepoRoot = Split-Path -Path (Split-Path -Path $ModuleRoot -Parent) -Parent . (Join-Path -Path $RepoRoot -ChildPath 'tests/Helpers/New-TestOpenApiModel.ps1') } Describe 'ConvertTo-OpenApiGenFunction' { BeforeAll { function ConvertTo-TestFunction { param($Operation, [string]$Prefix = 'Shop', [string]$ResponseTypeName) InModuleScope tcs.openapi -Parameters @{ Operation = $Operation; Prefix = $Prefix; ResponseTypeName = $ResponseTypeName } { param($Operation, $Prefix, $ResponseTypeName) $name = Get-OpenApiGenCommandName -Operation $Operation -NounPrefix $Prefix $model = Get-OpenApiGenParameterModel -Operation $Operation -BaseNoun $name.BaseNoun $template = (Get-OpenApiGenTemplate -Path (Join-Path -Path $script:TcsOpenApiModuleRoot -ChildPath 'Templates'))['Function.ps1'] $text = ConvertTo-OpenApiGenFunction -CommandName $name -Operation $Operation -ParameterModel $model -ResponseTypeName $ResponseTypeName -Template $template [pscustomobject]@{ Name = $name.Name; Text = $text; Check = (Test-OpenApiGenFunction -Text $text -FunctionName $name.Name) } } } $orderSchema = New-TestSchema -Type object -Required @('item') -Properties ([ordered]@{ item = New-TestSchema -Type string count = New-TestSchema -Type integer -Format int32 }) } It 'renders a function that parses and binds' { $operation = New-TestOperation -OperationId 'getOrder' -Method GET -Path '/orders/{orderId}' -Parameters @((New-TestParameter -Name 'orderId' -In path)) $result = ConvertTo-TestFunction -Operation $operation $result.Check.IsValid | Should -BeTrue $result.Check.ParameterNames | Should -Contain 'OrderId' $result.Text | Should -Match '(?m)^function Get-ShopOrder \{$' $result.Text | Should -Match "Invoke-OpenApiRequest @tcsRequest" $result.Text | Should -Match "\`$script:TcsOpenApiOperations\['getOrder'\]" $result.Text | Should -Match "'OrderId' = @\('path', 'orderId'\)" $result.Text | Should -Match "\[Alias\('Id'\)\]" } It 'uses ShouldProcess for <Method> with ConfirmImpact <Impact>' -TestCases @( @{ Method = 'POST'; Impact = 'Medium' }, @{ Method = 'PUT'; Impact = 'Medium' }, @{ Method = 'PATCH'; Impact = 'Medium' }, @{ Method = 'DELETE'; Impact = 'High' } ) { param($Method, $Impact) $result = ConvertTo-TestFunction -Operation (New-TestOperation -OperationId 'doThing' -Method $Method -Path '/things/{id}' -Parameters @((New-TestParameter -Name 'id' -In path))) $result.Text | Should -Match "SupportsShouldProcess = \`$true, ConfirmImpact = '$Impact'" $result.Text | Should -Match "ShouldProcess\(\`$tcsTarget, '$Method'\)" $result.Check.ParameterNames | Should -Contain 'WhatIf' } It 'does not use ShouldProcess for <Method>' -TestCases @(@{ Method = 'GET' }, @{ Method = 'HEAD' }, @{ Method = 'OPTIONS' }) { param($Method) $result = ConvertTo-TestFunction -Operation (New-TestOperation -OperationId 'readThing' -Method $Method -Path '/things') $result.Text | Should -Not -Match 'ShouldProcess' $result.Check.ParameterNames | Should -Not -Contain 'WhatIf' } It 'uses ShouldProcess for a state-changing verb on GET' { (ConvertTo-TestFunction -Operation (New-TestOperation -OperationId 'resetCache' -Method GET -Path '/cache')).Text | Should -Match 'SupportsShouldProcess' } It 'does not use ShouldProcess for <Verb> from <OperationId> on <Method>' -TestCases @( @{ OperationId = 'queryMetrics'; Method = 'POST'; Verb = 'Get' } @{ OperationId = 'searchOrders'; Method = 'POST'; Verb = 'Get' } @{ OperationId = 'getReport'; Method = 'PUT'; Verb = 'Get' } @{ OperationId = 'validateOrder'; Method = 'POST'; Verb = 'Test' } @{ OperationId = 'checkAddress'; Method = 'PATCH'; Verb = 'Test' } ) { param($OperationId, $Method, $Verb) $result = ConvertTo-TestFunction -Operation (New-TestOperation -OperationId $OperationId -Method $Method -Path '/things') $result.Name | Should -BeLike "$Verb-*" $result.Text | Should -Not -Match 'ShouldProcess' $result.Check.ParameterNames | Should -Not -Contain 'WhatIf' $result.Check.ParameterNames | Should -Not -Contain 'Confirm' } It 'uses ShouldProcess for <Verb> from <OperationId> on <Method>' -TestCases @( @{ OperationId = 'runReport'; Method = 'POST'; Verb = 'Invoke' } @{ OperationId = 'sendMessage'; Method = 'POST'; Verb = 'Send' } @{ OperationId = 'exportOrders'; Method = 'POST'; Verb = 'Export' } @{ OperationId = 'getRidOfOrder'; Method = 'DELETE'; Verb = 'Get' } ) { param($OperationId, $Method, $Verb) $result = ConvertTo-TestFunction -Operation (New-TestOperation -OperationId $OperationId -Method $Method -Path '/things') $result.Name | Should -BeLike "$Verb-*" $result.Text | Should -Match 'SupportsShouldProcess' $result.Check.ParameterNames | Should -Contain 'WhatIf' } It 'renders a flattened body with two parameter sets' { $operation = New-TestOperation -OperationId 'createOrder' -Method POST -Path '/orders' -RequestBody (New-TestRequestBody -Required -Content @((New-TestMediaType -ContentType 'application/json' -Schema $orderSchema))) $result = ConvertTo-TestFunction -Operation $operation $result.Check.IsValid | Should -BeTrue $result.Check.ParameterSets | Should -Be @('Parameters', 'Body') $result.Text | Should -Match "DefaultParameterSetName = 'Parameters'" $result.Text | Should -Match "if \(\`$PSCmdlet.ParameterSetName -eq 'Body'\)" $result.Text | Should -Match "\`$tcsRequest\['ContentType'\] = 'application/json'" $result.Text | Should -Match '(?m)^ else \{$' } It 'sends a flattened optional body only when a body parameter is bound' { $operation = New-TestOperation -OperationId 'createOrder' -Method POST -Path '/orders' -RequestBody (New-TestRequestBody -Content @((New-TestMediaType -ContentType 'application/json' -Schema $orderSchema))) (ConvertTo-TestFunction -Operation $operation).Text | Should -Match "elseif \(\`$tcsValues\['body'\].Count -gt 0\)" } It 'adds OutputType when the response type is known' { (ConvertTo-TestFunction -Operation (New-TestOperation -OperationId 'getOrder' -Method GET -Path '/o') -ResponseTypeName 'Shop.Order').Text | Should -Match "\[OutputType\('Shop.Order'\)\]" (ConvertTo-TestFunction -Operation (New-TestOperation -OperationId 'getOrder' -Method GET -Path '/o')).Text | Should -Not -Match 'OutputType' } It 'writes help: synopsis, description, parameters, a runnable example, link and deprecation' { $operation = New-TestOperation -OperationId 'getOrder' -Method GET -Path '/orders/{orderId}' -Summary 'Gets an order.' -Description 'Returns one order.' -ExternalDocsUrl 'https://docs.example.com/orders' -Deprecated -Parameters @( (New-TestParameter -Name 'orderId' -In path -Description 'The order id.' -Example 'o-1'), (New-TestParameter -Name 'expand' -In query -Required -Schema (New-TestSchema -Type array -Items (New-TestSchema -Type string))) ) $result = ConvertTo-TestFunction -Operation $operation $result.Text | Should -Match '\.SYNOPSIS\s+Gets an order\.' $result.Text | Should -Match '\.DESCRIPTION\s+Returns one order\.' $result.Text | Should -Match 'This operation is deprecated\.' $result.Text | Should -Match '\.PARAMETER OrderId\s+The order id\.' $result.Text | Should -Match "\.PARAMETER Expand\s+The 'expand' query parameter\." $result.Text | Should -Match '\.PARAMETER Raw' $result.Text | Should -Match "\.EXAMPLE\s+Get-ShopOrder -OrderId 'o-1' -Expand @\('example'\)" $result.Text | Should -Match '\.LINK\s+https://docs.example.com/orders' $example = [regex]::Match($result.Text, '\.EXAMPLE\s+(.+)').Groups[1].Value $tokens = $null $errors = $null [void][System.Management.Automation.Language.Parser]::ParseInput($example, [ref]$tokens, [ref]$errors) $errors.Count | Should -Be 0 } It 'uses the method and path when there is no summary or description' { (ConvertTo-TestFunction -Operation (New-TestOperation -OperationId 'getOrder' -Method GET -Path '/o')).Text | Should -Match '\.SYNOPSIS\s+Calls GET /o\.' } It 'passes only the locations the operation has' { $operation = New-TestOperation -OperationId 'getOrder' -Method GET -Path '/o' -Parameters @((New-TestParameter -Name 'q' -In query), (New-TestParameter -Name 'c' -In cookie)) $text = (ConvertTo-TestFunction -Operation $operation).Text $text | Should -Match "QueryParameters" $text | Should -Match "CookieParameters" $text | Should -Not -Match "PathParameters" $text | Should -Not -Match "HeaderParameters" } It 'adds a suppression for password parameters and plural-looking nouns' { $schema = New-TestSchema -Type object -Properties ([ordered]@{ password = New-TestSchema -Type string }) $text = (ConvertTo-TestFunction -Operation (New-TestOperation -OperationId 'setPassword' -Method PUT -Path '/p' -RequestBody (New-TestRequestBody -Content @((New-TestMediaType -ContentType 'application/json' -Schema $schema))))).Text $text | Should -Match "SuppressMessageAttribute\('PSAvoidUsingPlainTextForPassword'" (ConvertTo-TestFunction -Operation (New-TestOperation -OperationId 'getMetadata' -Method GET -Path '/m')).Text | Should -Match "SuppressMessageAttribute\('PSUseSingularNouns'" } It 'escapes quotes from the document in code and help' { $operation = New-TestOperation -OperationId "get'Odd" -Method GET -Path "/it's" -Summary 'Has #> in it' -Parameters @((New-TestParameter -Name "o'k" -In query)) $result = ConvertTo-TestFunction -Operation $operation $result.Check.IsValid | Should -BeTrue $result.Text | Should -Match "\['get''Odd'\]" } } |