ci(validation): add testing workflow

This commit is contained in:
Sam Chau
2025-08-27 05:49:26 +09:30
parent 14d364fd9b
commit 4c6ca5c13c
5 changed files with 185 additions and 78 deletions

View File

@@ -1,4 +1,4 @@
name: Validate Regex Patterns name: Regular Expressions
on: on:
push: push:
@@ -26,6 +26,4 @@ jobs:
run: pwsh scripts/validateAllPatterns.ps1 run: pwsh scripts/validateAllPatterns.ps1
- name: test - name: test
run: | run: pwsh scripts/testPatterns.ps1
echo "TODO: Implement unit tests for all patterns"
# TODO: Add test runner command here

183
scripts/testPatterns.ps1 Normal file
View File

@@ -0,0 +1,183 @@
param(
[string]$YamlFilePath
)
# Function to run tests for a single file
function Test-Pattern {
param([string]$FilePath)
$fileName = (Get-Item $FilePath).BaseName
try {
# Read YAML content
$yamlContent = Get-Content -Path $FilePath -Raw
# Extract pattern
$patternMatch = [regex]::Match($yamlContent, 'pattern:\s*(.+)')
$pattern = $patternMatch.Groups[1].Value.Trim()
# Create regex object with case-insensitive and multiline options
$regexOptions = [System.Text.RegularExpressions.RegexOptions]::IgnoreCase -bor [System.Text.RegularExpressions.RegexOptions]::Multiline
$regex = New-Object System.Text.RegularExpressions.Regex($pattern, $regexOptions)
# Extract tests
$testsSection = [regex]::Match($yamlContent, '(?s)tests:(.*?)(?:\n\w|\z)').Groups[1].Value
if ([string]::IsNullOrWhiteSpace($testsSection)) {
return @{
File = $fileName
Passed = 0
Failed = 0
Total = 0
}
}
# Parse each test
$tests = [regex]::Matches($testsSection, '(?s)- expected:\s*(true|false).*?input:\s*(.+?)(?=\n\s*\w|\n-|\z)')
$passed = 0
$failed = 0
$failureDetails = @()
foreach ($test in $tests) {
$expected = $test.Groups[1].Value -eq 'true'
$input = $test.Groups[2].Value.Trim()
# Run the test
$matches = $regex.IsMatch($input)
if ($matches -eq $expected) {
$passed++
}
else {
$failed++
$failureDetails += " Input: '$input' - Expected: $expected, Got: $matches"
}
}
return @{
File = $fileName
Passed = $passed
Failed = $failed
Total = $tests.Count
Failures = $failureDetails
}
}
catch {
return @{
File = $fileName
Error = $_.Exception.Message
}
}
}
# Main execution
if ($YamlFilePath) {
# Test single file
$result = Test-Pattern -FilePath $YamlFilePath
if ($result.Error) {
Write-Host "ERROR: $($result.File): $($result.Error)" -ForegroundColor Red
exit 1
}
if ($result.Failed -gt 0) {
Write-Host "$($result.File): $($result.Failed)/$($result.Total) tests failed" -ForegroundColor Red
foreach ($failure in $result.Failures) {
Write-Host $failure
}
exit 1
}
else {
Write-Host "$($result.File): All $($result.Total) tests passed"
exit 0
}
}
else {
# Test all files
$patternFiles = @()
$patternFiles += Get-ChildItem -Path "regex_patterns" -Filter "*.yml" -File
$patternFiles += Get-ChildItem -Path "regex_patterns" -Filter "*.yaml" -File
if ($patternFiles.Count -eq 0) {
Write-Host "No pattern files found"
exit 1
}
$results = @()
$totalFiles = $patternFiles.Count
$filesWithFailures = @()
foreach ($file in $patternFiles) {
$result = Test-Pattern -FilePath $file.FullName
$results += $result
if ($result.Error) {
$filesWithFailures += $result
}
elseif ($result.Failed -gt 0) {
$filesWithFailures += $result
}
}
# Report failures
if ($filesWithFailures.Count -gt 0) {
Write-Host "ERRORS:"
# Find global max input length across all failures
$globalMaxInputLength = 0
foreach ($failure in $filesWithFailures) {
if (-not $failure.Error) {
foreach ($detail in $failure.Failures) {
if ($detail -match "Input: '(.+?)' -") {
$inputLength = $matches[1].Length
if ($inputLength -gt $globalMaxInputLength) {
$globalMaxInputLength = $inputLength
}
}
}
}
}
# Limit padding to 150 characters
if ($globalMaxInputLength -gt 150) {
$globalMaxInputLength = 150
}
foreach ($failure in $filesWithFailures) {
Write-Host " $($failure.File):"
if ($failure.Error) {
# Extract cleaner error message
$errorMsg = $failure.Error
if ($errorMsg -match "at offset (\d+)\. (.+?)\.?`"") {
$errorMsg = "offset $($matches[1]): $($matches[2])"
}
Write-Host " $errorMsg"
}
else {
foreach ($detail in $failure.Failures) {
if ($detail -match "Input: '(.+?)' - Expected: (\w+), Got: (\w+)") {
$input = $matches[1]
$expected = $matches[2]
$got = $matches[3]
# Truncate only if longer than 150
if ($input.Length -gt 150) {
$input = $input.Substring(0, 147) + "..."
}
$paddedInput = $input.PadRight($globalMaxInputLength)
Write-Host " $paddedInput | Expected: $expected | Got: $got"
}
}
}
}
exit 1
}
else {
Write-Host "All tests passed"
exit 0
}
}

View File

@@ -1 +0,0 @@
# TODO: Run a single unit test given a regular expression and unit test. A unit test includes the input string and whether it should match or not.

View File

@@ -1,73 +0,0 @@
param(
[Parameter(Mandatory=$true)]
[string]$YamlFilePath
)
$moduleName = "regex"
function Write-Log {
param(
[Parameter(Mandatory=$true)]
[string]$Level,
[Parameter(Mandatory=$true)]
[string]$Message
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$levelPadded = $Level.ToUpper().PadRight(7)
$modulePadded = $moduleName.PadRight(0)
# Write colored level
Write-Host -NoNewline "["
if ($Level -eq "ERROR") {
Write-Host -NoNewline $levelPadded -ForegroundColor Red
}
elseif ($Level -eq "SUCCESS") {
Write-Host -NoNewline $levelPadded -ForegroundColor Green
}
elseif ($Level -eq "INFO") {
Write-Host -NoNewline $levelPadded -ForegroundColor Cyan
}
else {
Write-Host -NoNewline $levelPadded
}
Write-Host -NoNewline "] "
# Write grey timestamp
Write-Host -NoNewline "[$timestamp] " -ForegroundColor DarkGray
# Write module and message in normal color
Write-Host "[$modulePadded] $Message"
}
try {
# Check if file exists
if (-not (Test-Path $YamlFilePath)) {
Write-Log -Level "ERROR" -Message "YAML file not found: $YamlFilePath"
exit 1
}
# Read YAML content
$yamlContent = Get-Content -Path $YamlFilePath -Raw
# Extract pattern field from YAML
$patternMatch = [regex]::Match($yamlContent, 'pattern:\s*(.+)')
$pattern = $patternMatch.Groups[1].Value.Trim()
Write-Log -Level "INFO" -Message "Found pattern: $pattern"
# Validate the pattern against .NET regex engine
try {
$regex = New-Object System.Text.RegularExpressions.Regex($pattern)
Write-Log -Level "SUCCESS" -Message "Valid regex pattern"
exit 0
}
catch {
Write-Log -Level "ERROR" -Message "Pattern validation failed: $_"
exit 1
}
}
catch {
Write-Log -Level "ERROR" -Message "Script execution failed: $_"
exit 1
}