Private/Utils/New-ValueFromPattern.ps1

Function New-ValueFromPattern {
    <#
    .SYNOPSIS
    Generates new values based on pattern descriptions.
 
    .DESCRIPTION
    This function creates new values that match the characteristics described in a pattern
    hashtable. It supports various data types including null, strings with specific patterns
    (ISO8601 dates, GUIDs, numeric, kebab-case, dotted notation, text), numeric types
    with ranges, booleans, and provides fallback generation for unknown types.
 
    The function uses a provided random generator for consistent and reproducible results
    across test runs, and supports anonymization mode for generating test-appropriate values.
 
    .PARAMETER Pattern
    A hashtable describing the pattern to generate, typically created by Get-ValuePattern.
    Must contain 'Type' key and may include 'Pattern', 'Length', 'Range' depending on type.
 
    .PARAMETER RandomGenerator
    A System.Random instance for generating random values. Using the same seed ensures
    reproducible results. Default creates a new random generator.
 
    .PARAMETER Anonymize
    Indicates whether to generate anonymized values. Currently used for context but
    doesn't change generation behavior in this implementation.
 
    .OUTPUTS
    [object]
    Returns a newly generated value matching the pattern specification:
    - null for null patterns
    - ISO8601 datetime strings for datetime patterns
    - GUID strings for guid patterns
    - Various string formats based on pattern type
    - Numeric values within specified ranges
    - Boolean values
    - Fallback string for unknown patterns
 
    .EXAMPLE
    $pattern = @{Type = 'string'; Pattern = 'kebab-case'}
    New-ValueFromPattern -Pattern $pattern
    Returns: "test-data" (or similar kebab-case string)
 
    .EXAMPLE
    $pattern = @{Type = 'int'; Range = @(1, 100)}
    New-ValueFromPattern -Pattern $pattern
    Returns: Random integer between 1 and 99
 
    .EXAMPLE
    $pattern = @{Type = 'datetime'; Pattern = 'iso8601'}
    New-ValueFromPattern -Pattern $pattern
    Returns: "2023-08-15T14:30:22Z" (or similar ISO8601 string)
 
    .NOTES
    This is an internal utility function used by the PSTestableData module for generating
    individual values during test data creation. It provides consistent, reproducible
    value generation when used with seeded random generators.
    #>

    [CmdletBinding()]
    [OutputType([object])]
    Param(
        [hashtable]$Pattern,
        [System.Random]$RandomGenerator = [System.Random]::new(),
        [bool]$Anonymize = $false
    )

    # If field should be preserved and we have the original value, return it
    if ($Pattern.PreserveField -and $Pattern.ContainsKey('OriginalValue')) {
        return $Pattern.OriginalValue
    }

    switch ($Pattern.Type) {
        'null' { return $null }
        'datetime' {
            if ($Pattern.Pattern -eq 'iso8601') {
                return (Get-Date).AddDays(($RandomGenerator.Next(-365, 366))).ToString('yyyy-MM-ddTHH:mm:ssZ')
            }
        }
        'guid' { return [guid]::NewGuid().ToString() }
        'string' {
            switch ($Pattern.Pattern) {
                'numeric' { return ($RandomGenerator.Next(1000000, 99999999)).ToString() }
                'kebab-case' {
                    $words = @('active', 'ready', 'pending', 'complete', 'failed', 'running', 'stopped')
                    $word1 = $words[($RandomGenerator.Next(0, $words.Count))]
                    $word2 = $words[($RandomGenerator.Next(0, $words.Count))]
                    return "$word1-$word2"
                }
                'dotted' {
                    $prefixes = @('kubernetes.io', 'app.kubernetes', 'service.mesh', 'metadata.k8s', 'config.example', 'system.core', 'runtime.api', 'network.fabric')
                    $suffixes = @('metadata.name', 'metadata.labels', 'config.data', 'service.port', 'resource.type', 'status.phase', 'spec.selector', 'policy.rules')
                    $prefix = $prefixes[($RandomGenerator.Next(0, $prefixes.Count))]
                    $suffix = $suffixes[($RandomGenerator.Next(0, $suffixes.Count))]
                    return "$prefix/$suffix"
                }
                'text' {
                    # Don't anonymize if this field should be preserved
                    if ($Anonymize -and -not $Pattern.PreserveField -and (Get-Command Out-AnonymizedString -ErrorAction SilentlyContinue)) {
                        $sampleString = ("sample" * [math]::Ceiling($Pattern.Length / 6)).Substring(0, $Pattern.Length)
                        return Out-AnonymizedString -InputString $sampleString
                    }
                    else {
                        $words = @('sample', 'test', 'demo', 'example', 'data', 'value', 'item', 'content')
                        $selectedWord = $words[($RandomGenerator.Next(0, $words.Count))]
                        return $selectedWord
                    }
                }
                default {
                    # Fallback for any unhandled string patterns
                    $words = @('sample', 'test', 'demo', 'example', 'data', 'value', 'item', 'content')
                    $selectedWord = $words[($RandomGenerator.Next(0, $words.Count))]
                    return $selectedWord
                }
            }
        }
        'int' {
            if ($Pattern.Range) {
                return $RandomGenerator.Next($Pattern.Range[0], $Pattern.Range[1])
            }
            else {
                return $RandomGenerator.Next(1, 1000)
            }
        }
        'long' {
            if ($Pattern.Range) {
                return [long]($RandomGenerator.Next($Pattern.Range[0], $Pattern.Range[1]))
            }
            else {
                return [long]($RandomGenerator.Next(1000, 999999))
            }
        }
        'double' { return [double]($RandomGenerator.NextDouble() * 99.9 + 0.1) }
        'bool' { return ($RandomGenerator.Next(0, 2)) -eq 1 }
        default { return "generated-value" }
    }
}