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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ output/
bin/
obj/
libs/

# Pester test output
testResults.xml
119 changes: 119 additions & 0 deletions src/functions/public/Test-Toml.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
function Test-Toml {
<#
.SYNOPSIS
Tests whether a string or file contains valid TOML.

.DESCRIPTION
Validates TOML content without throwing. Returns $true when the input
parses successfully and $false when it does not. On failure, a
non-terminating error is written via Write-Error so the caller can
inspect $Error or use -ErrorVariable while the pipeline continues.

Three parameter sets are supported:
- Default : -InputObject β€” validates a TOML string directly.
- Path : -Path β€” reads a file (relative paths resolved).
- LiteralPath: -LiteralPath β€” reads a file (no wildcard expansion).

.EXAMPLE
Test-Toml -InputObject 'title = "Hello"'

Returns $true because the string is valid TOML.

.EXAMPLE
Test-Toml -InputObject 'bad = = "syntax"'

Returns $false and writes a non-terminating error describing the parse
failure.

.EXAMPLE
Test-Toml -Path '.\config.toml'

Reads the file and returns $true if its content is valid TOML.

.EXAMPLE
Test-Toml -LiteralPath 'C:\Configs\app.toml'

Reads the file using a literal path (no glob expansion) and returns
$true if the content parses successfully.

.INPUTS
[string] β€” pipeline input supported for the InputObject parameter.

.OUTPUTS
[bool]

.NOTES
Mirrors the pattern of the built-in Test-Json cmdlet.
All exceptions from the parser are caught and surfaced as
non-terminating errors so the function never throws.

.LINK
https://psmodule.io/Toml/Functions/Test-Toml
#>
[OutputType([bool])]
[CmdletBinding(DefaultParameterSetName = 'Default')]
param(
# The TOML string to validate. Accepts pipeline input.
[Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'Default')]
[AllowEmptyString()]
[string] $InputObject,

# Path to a TOML file to validate. Relative paths are resolved against
# the current working directory.
[Parameter(Mandatory, ParameterSetName = 'Path')]
[string] $Path,

# Literal path to a TOML file to validate. No wildcard expansion is
# performed.
[Parameter(Mandatory, ParameterSetName = 'LiteralPath')]
[string] $LiteralPath
)

process {
$content = $null

if ($PSCmdlet.ParameterSetName -eq 'Path') {
Write-Verbose "Resolving path: $Path"
try {
$resolved = Resolve-Path -Path $Path -ErrorAction Stop
} catch {
Write-Error -Message "Cannot find path '$Path': $($_.Exception.Message)" -ErrorAction Continue
return $false
}
try {
$content = [System.IO.File]::ReadAllText($resolved.ProviderPath)
} catch {
Write-Error -Message "Cannot read file '$($resolved.ProviderPath)': $($_.Exception.Message)" -ErrorAction Continue
return $false
}
} elseif ($PSCmdlet.ParameterSetName -eq 'LiteralPath') {
Write-Verbose "Using literal path: $LiteralPath"
try {
$resolved = Resolve-Path -LiteralPath $LiteralPath -ErrorAction Stop
} catch {
Write-Error -Message "Cannot find path '$LiteralPath': $($_.Exception.Message)" -ErrorAction Continue
return $false
}
try {
$content = [System.IO.File]::ReadAllText($resolved.ProviderPath)
} catch {
Write-Error -Message "Cannot read file '$($resolved.ProviderPath)': $($_.Exception.Message)" -ErrorAction Continue
return $false
}
} else {
$content = $InputObject
}

Write-Verbose "Validating TOML content ($($content.Length) character(s))."
try {
if ([string]::IsNullOrEmpty($content)) {
throw [System.ArgumentException]::new('Input is empty.')
}
$null = ConvertFrom-Toml -InputObject $content
return $true
} catch {
Write-Error -Message "TOML validation failed: $($_.Exception.Message)" -ErrorAction Continue
return $false
}
}
}
104 changes: 104 additions & 0 deletions tests/Toml.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Describe 'Toml' {
$commands | Should -Contain 'ConvertTo-Toml'
$commands | Should -Contain 'Import-Toml'
$commands | Should -Contain 'Export-Toml'
$commands | Should -Contain 'Test-Toml'
}
}

Expand Down Expand Up @@ -801,4 +802,107 @@ Describe 'Toml' {
}
}
}

Describe 'Test-Toml' {

Context 'Module registration' {
It 'is exported from the module' {
Get-Command -Module Toml | Select-Object -ExpandProperty Name | Should -Contain 'Test-Toml'
}

It 'declares [OutputType([bool])]' {
$cmd = Get-Command -Name Test-Toml
$cmd.OutputType.Type | Should -Contain ([bool])
}
}

Context 'InputObject β€” valid TOML' {
It 'returns $true for a minimal key=value string' {
$result = Test-Toml -InputObject 'key = "value"'
$result | Should -BeTrue
}

It 'returns a [bool]' {
$result = Test-Toml -InputObject 'key = 1'
$result | Should -BeOfType [bool]
}

It 'accepts pipeline input and returns $true' {
$result = 'enabled = true' | Test-Toml
$result | Should -BeTrue
}

It 'returns $true for a multi-section TOML string' {
$toml = @'
[server]
host = "localhost"
port = 8080
'@
Test-Toml -InputObject $toml | Should -BeTrue
}
}

Context 'InputObject β€” invalid TOML' {
It 'returns $false for invalid syntax' {
$result = Test-Toml -InputObject 'bad = = "syntax"' 2>$null
$result | Should -BeFalse
}

It 'writes a non-terminating error for invalid TOML' {
$errors = @()
$result = Test-Toml -InputObject 'bad = = "syntax"' -ErrorVariable errors 2>$null
$result | Should -BeFalse
$errors | Should -Not -BeNullOrEmpty
}

It 'returns $false for an empty string' {
$result = Test-Toml -InputObject '' 2>$null
$result | Should -BeFalse
}

It 'returns $false for a duplicate-key document' {
$result = Test-Toml -InputObject "key = 1`nkey = 2" 2>$null
$result | Should -BeFalse
}
}

Context 'Path β€” valid file' {
It 'returns $true for a valid TOML file via -Path' {
$path = Join-Path $TestDrive 'valid.toml'
Set-Content -Path $path -Value 'name = "test"' -Encoding UTF8
Test-Toml -Path $path | Should -BeTrue
}
}

Context 'Path β€” invalid file' {
It 'returns $false for an invalid TOML file via -Path' {
$path = Join-Path $TestDrive 'invalid.toml'
Set-Content -Path $path -Value 'bad = = "syntax"' -Encoding UTF8
$result = Test-Toml -Path $path 2>$null
$result | Should -BeFalse
}

It 'returns $false and writes an error for a non-existent file via -Path' {
$errors = @()
$result = Test-Toml -Path (Join-Path $TestDrive 'does-not-exist.toml') -ErrorVariable errors 2>$null
$result | Should -BeFalse
$errors | Should -Not -BeNullOrEmpty
}
}

Context 'LiteralPath β€” valid file' {
It 'returns $true for a valid TOML file via -LiteralPath' {
$path = Join-Path $TestDrive 'literal-valid.toml'
Set-Content -Path $path -Value 'answer = 42' -Encoding UTF8
Test-Toml -LiteralPath $path | Should -BeTrue
}

It 'returns a [bool] via -LiteralPath' {
$path = Join-Path $TestDrive 'literal-bool.toml'
Set-Content -Path $path -Value 'flag = true' -Encoding UTF8
$result = Test-Toml -LiteralPath $path
$result | Should -BeOfType [bool]
}
}
}
}