1
\$\begingroup\$

I am learning PowerShell, and created the following script cmdlet.

It reads one or more specified script files, to discover special functions (UnitTests, or functions with the Verb 'UnitTest' or 'DataTest'.

I designed the parameters to work like Get-Content, as it reads content from files.

I would like general feedback on this cmdlet (design, workings), but i am also intrested in correctness.

<#
.SYNOPSIS
 Gets UnitTests from a UnitTestFile.
.DESCRIPTION
 UnitTests are PowerShell script functions, which are identified with the verb 'UnitTest' or 'DataTest'.
#>
function Get-UnitTest {
 [CmdletBinding(DefaultParameterSetName = "Path")]
 [OutputType([System.Management.Automation.FunctionInfo])]
 Param(
 <# Specifies a path to one or more UnitTestFiles. Wildcards are permitted. #>
 [Parameter(Position = 0, ParameterSetName = "Path", Mandatory = $true)]
 [string[]] $Path,
 <# Specifies a LiteralPath to one or more UnitTestFiles. Wildcards are permitted. #>
 [Parameter(ParameterSetName = "LiteralPath", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
 [Alias("FullName")]
 [string[]] $LiteralPath,
 <# Specifies the Verb to use to identify UnitTests. The default verbs are 'UnitTest' and 'DataTest'. This means that functions with a name like 'UnitTest-Get-ChildItem' or 'DataTest-Invoke-WebRequest' are found. #>
 [String[]] $Verb = @( "UnitTest", "DataTest" )
 )
 Process {
 foreach($curPath in ($LiteralPath + $Path | Where {$_} | Resolve-Path)) {
 if(Test-Path $curPath -PathType Leaf) {
 Write-Trace "Getting UnitTests from '$curPath'."
 . $curPath
 # find and return all unit tests (from the requested file)
 Get-Command -Verb $Verb `
 | Where { $_.CommandType -eq "Function" } `
 | Where { ( $_.ScriptBlock.File ) -eq $curPath }
 }
 }
 }
}

This cmdlet can be called as follows:

Get-UnitTest -Path .\somefile.ps1
Get-UnitTest -Path .\somefile.ps1 -Verb 'OtherTest'
Get-ChildItem -Recurse *.ps1 | Get-UnitTest
Caridorc
28k7 gold badges54 silver badges137 bronze badges
asked Jul 28, 2013 at 20:10
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Looks good. Personally, I would take:

foreach($curPath in ($LiteralPath + $Path | Where {$_} | Resolve-Path)) {

and break out the collection generation code. Specifically into something like:

$PathList = Join-Path $literalPath $Path | Resolve-Path 

You shouldn't need to worry about a Where-Object to validate that it isn't $null. If there is no result it won't go up the pipeline.

If you Dot Include all of your Scripts you can wait until all are included then check your commands. This will run anything else you have in the script though.

It may be safer to use the parser like this sample below. In this code I looked for catch blocks to insert a breakpoint , but you could have it filter for your test prefixes too.

$ParseError = $null
$Tokens = $null
$AST = [System.Management.Automation.Language.Parser]::ParseInput($psISE.CurrentFile.Editor.Text, [ref]$Tokens, [ref]$ParseError)
if($ParseError) { 
 foreach($er in $ParseError) { Write-Error $er }
 throw "There was an error parsing script (See above). We cannot expand aliases until the script parses without errors."
}
$a = $ast.FindAll({($args[0] -is [System.Management.Automation.Language.CatchClauseAst])},$true)
  • Josh
answered Jul 31, 2013 at 17:58
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.