Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions PSGraph/Public/Export-PSGraph.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ function Export-PSGraph
It checks the piped data for file paths. If it cannot find a file, it assumes it is graph data.
This may give unexpected errors when the file does not exist.
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingInvokeExpression", "")]
[cmdletbinding()]
param(
# The GraphViz file to process or contents of the graph in Dot notation
Expand Down Expand Up @@ -89,18 +88,34 @@ function Export-PSGraph
{
try
{
# Use Resolve-Path to test all passed paths
# Select only items with 'dot' BaseName and use first one
$graphViz = Resolve-Path -path $GraphVizPath -ErrorAction SilentlyContinue | Get-Item | Where-Object BaseName -eq 'dot' | Select-Object -First 1
$graphViz = $null

# Unless the caller explicitly pinned a path, prefer a cross-platform
# PATH lookup (works regardless of install location/OS).
if ( -Not $PSBoundParameters.ContainsKey('GraphVizPath') )
{
$graphViz = Get-Command -Name 'dot' -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1
}

if ( $null -eq $graphViz )
{
# Use Resolve-Path to test all passed/default paths
# Select only items with 'dot' BaseName and use first one
$graphViz = Resolve-Path -path $GraphVizPath -ErrorAction SilentlyContinue | Get-Item | Where-Object BaseName -eq 'dot' | Select-Object -First 1
}

if ( $null -eq $graphViz )
{
$GraphvizPathString = $GraphVizPath -Join " or "
throw "Could not find GraphViz installed on this system. Please run 'Install-GraphViz' to install the needed binaries and libraries. This module just a wrapper around GraphViz and is looking for it in the following paths: $($GraphvizPathString). Optionally pass a path to your dot.exe file with the GraphVizPath parameter"
throw "Could not find GraphViz installed on this system. Please run 'Install-GraphViz' to install the needed binaries and libraries. This module looked for a 'dot' executable on PATH and in the following paths: $($GraphvizPathString). Optionally pass a path to your dot.exe file with the GraphVizPath parameter"
}

$useStandardInput = $false
$standardInput = New-Object System.Text.StringBuilder

# Pipe DOT source to graphviz as UTF-8 without a BOM, regardless of the
# caller's ambient $OutputEncoding (a BOM here breaks dot's parser).
$OutputEncoding = [System.Text.UTF8Encoding]::new($false)
}
catch
{
Expand Down Expand Up @@ -195,7 +210,7 @@ function Export-PSGraph
{
# Launches image with default viewer as decided by explorer
Write-Verbose "Launching $($PSBoundParameters["DestinationPath"])"
Invoke-Expression $PSBoundParameters["DestinationPath"]
Invoke-Item -Path $PSBoundParameters["DestinationPath"]
}

Get-ChildItem $PSBoundParameters["DestinationPath"]
Expand Down
5 changes: 4 additions & 1 deletion PSGraph/Public/Graph.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ function Graph
if ($Type -eq 'digraph')
{
$script:indent = 0
$Attributes.compound = 'true'
if (-not $Attributes.ContainsKey('compound'))
{
$Attributes.compound = 'true'
}
$script:SubGraphList = @{}
}

Expand Down
64 changes: 64 additions & 0 deletions Tests/Export-PSGraph.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,68 @@ Describe "$ModuleName Export-PSGraph" -Tag graphviz {
"$path.png" | Should Exist
}
}

Context "#110 ShowGraph and destination path with spaces" {

It "Exports to a destination path containing spaces without throwing" {
$dir = Join-Path $testdrive "spaced dir"
New-Item -ItemType Directory -Path $dir -Force | Out-Null
$path = Join-Path $dir "spaced graph.png"

{ Export-PSGraph -Source $dot -DestinationPath $path -ErrorAction Stop } | Should Not Throw

$path | Should Exist
}

It "-ShowGraph launches a destination path containing spaces without throwing" {
$dir = Join-Path $testdrive "spaced dir 2"
New-Item -ItemType Directory -Path $dir -Force | Out-Null
$path = Join-Path $dir "spaced graph.png"

{ Export-PSGraph -Source $dot -DestinationPath $path -ShowGraph -ErrorAction Stop } | Should Not Throw

$path | Should Exist
}
}

Context "#97 BOM in generated DOT breaks dot's parser" {

AfterEach {
$OutputEncoding = [System.Text.UTF8Encoding]::new($false)
}

It "Exports successfully even when the caller's `$OutputEncoding would inject a BOM" {
$OutputEncoding = [System.Text.UTF8Encoding]::new($true)
$path = "$testdrive\bom.dot"

{ Export-PSGraph -Source $dot -DestinationPath $path -OutputFormat dot -ErrorAction Stop } | Should Not Throw

$bytes = [System.IO.File]::ReadAllBytes($path)
($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) | Should Be $false
}
}

Context "#104 Non-ASCII characters in labels" {

It "Round-trips accented/non-ASCII labels through dot without garbling" {
$accented = graph g { node cafe @{label = 'héllo wörld'} }
$path = "$testdrive\accented.dot"

Export-PSGraph -Source $accented -DestinationPath $path -OutputFormat dot

$text = [System.IO.File]::ReadAllText($path, [System.Text.Encoding]::UTF8)
$text | Should Match 'héllo wörld'
}
}

Context "#75 #88 #85 Graphviz path detection" {

It "Finds dot via PATH when -GraphVizPath is not specified" {
{ Export-PSGraph -Source $dot -DestinationPath "$testdrive\pathlookup.png" -ErrorAction Stop } | Should Not Throw
}

It "Honors an explicitly-supplied -GraphVizPath instead of silently falling back to PATH" {
{ Export-PSGraph -Source $dot -DestinationPath "$testdrive\badpath.png" -GraphVizPath 'C:\does\not\exist\dot.exe' -ErrorAction Stop } | Should Throw
}
}
}
40 changes: 38 additions & 2 deletions Tests/Regression.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,46 @@ Describe "Regression tests for Github issues" -Tag Build {
Context "Sequential edges require parameter name for attributes #40" {

It "#40 correctly handles the positional attributes" {
$graph = Graph g {
Edge a, b, c, d, a @{label = 'to'}
$graph = Graph g {
Edge a, b, c, d, a @{label = 'to'}
}
$graph | Out-String | Should Not Match 'System.Collections.Hashtable'
}
}

Context "#98 Setting compound=false fails" {

It "#98 an explicit compound=`$false attribute is not overridden" {
$graph = Graph g -Attributes @{compound = $false} {} | Out-String
$graph | Should Match 'compound="False"'
$graph | Should Not Match 'compound="true"'
}

It "#98 compound still defaults to true when not specified" {
$graph = Graph g {} | Out-String
$graph | Should Match 'compound="true"'
}
}

Context "#66 SubGraph example from help/docs" {

It "#66 unnamed subgraph binds with -Attributes and -ScriptBlock passed by name" {
{
graph {
subgraph -Attributes @{label = 'DMZ'} -ScriptBlock {
node web1, web2
}
}
} | Should Not Throw
}

It "#66 unnamed subgraph with named parameters applies the attributes" {
$graph = graph {
subgraph -Attributes @{label = 'DMZ'} -ScriptBlock {
node web1
}
} | Out-String
$graph | Should Match 'label="DMZ"'
}
}
}
2 changes: 1 addition & 1 deletion docs/Command-SubGraph.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This allows you to define a graph within the graph. This will group those objects together in some engines.

graph {
subgraph -Attributes @{label='DMZ'} {
subgraph -Attributes @{label='DMZ'} -ScriptBlock {
node web1,web2,reports
edge report -To web1,web2
}
Expand Down