Files
ModernAdminStudio/Tests/UserResolverService.Tests.ps1

199 lines
8.6 KiB
PowerShell

# Tests\UserResolverService.Tests.ps1
# Unit Tests for User Multi-Input Resolver & Ambiguity Detection Service
BeforeAll {
$scriptDir = Split-Path -Parent $PSScriptRoot
. (Join-Path $scriptDir "Modules\UserResolverService.ps1")
}
Describe "UserResolverService Unit Tests" -Tag "Mock", "Unit" {
Context "Parse-MultiUserInput Parsing & Tokenization" {
It "returns empty array for null, empty or whitespace strings" {
@((Parse-MultiUserInput -RawInput $null)).Count | Should -Be 0
@((Parse-MultiUserInput -RawInput "")).Count | Should -Be 0
@((Parse-MultiUserInput -RawInput " `t`r`n ")).Count | Should -Be 0
}
It "parses a single user token cleanly" {
$tokens = Parse-MultiUserInput -RawInput "gdhong"
$tokens.Count | Should -Be 1
$tokens[0] | Should -Be "gdhong"
}
It "splits tokens by commas, semicolons, tabs, and newlines" {
$raw = "gdhong, cskim; yylee`nmschoi`r`njhbak`tswjung"
$tokens = Parse-MultiUserInput -RawInput $raw
$tokens.Count | Should -Be 6
$tokens | Should -Contain "gdhong"
$tokens | Should -Contain "cskim"
$tokens | Should -Contain "yylee"
$tokens | Should -Contain "mschoi"
$tokens | Should -Contain "jhbak"
$tokens | Should -Contain "swjung"
}
It "strips surrounding whitespace from individual tokens" {
$raw = " gdhong , cskim ; yylee "
$tokens = Parse-MultiUserInput -RawInput $raw
$tokens.Count | Should -Be 3
$tokens[0] | Should -Be "gdhong"
$tokens[1] | Should -Be "cskim"
$tokens[2] | Should -Be "yylee"
}
It "deduplicates repeated tokens using Select-Unique" {
$raw = "gdhong, cskim, gdhong, yylee, cskim, gdhong"
$tokens = Parse-MultiUserInput -RawInput $raw
$tokens.Count | Should -Be 3
$tokens | Should -Contain "gdhong"
$tokens | Should -Contain "cskim"
$tokens | Should -Contain "yylee"
}
It "handles Korean names and Excel pasted tabular data" {
$raw = "홍길동`t김철수`r`n이영희,최민수;박지훈"
$tokens = Parse-MultiUserInput -RawInput $raw
$tokens.Count | Should -Be 5
$tokens | Should -Contain "홍길동"
$tokens | Should -Contain "김철수"
$tokens | Should -Contain "이영희"
}
}
Context "Resolve-UsersWithAmbiguityCheck - Exact SamAccountName Matching" {
It "resolves exact SamAccountName as Normal Match (정상 매칭)" {
$results = Resolve-UsersWithAmbiguityCheck -Tokens @("gdhong")
$results.Count | Should -Be 1
$r = $results[0]
$r.InputToken | Should -Be "gdhong"
$r.Status | Should -Be "정상 매칭"
$r.IsAmbiguous | Should -BeFalse
$r.IsResolved | Should -BeTrue
$r.IsSelected | Should -BeTrue
$r.SamAccountName | Should -Be "gdhong"
$r.DisplayName | Should -Be "홍길동"
$r.Department | Should -Be "클라우드인프라팀"
$r.CandidateCount | Should -Be 1
}
It "performs case-insensitive matching for SamAccountName" {
$results = Resolve-UsersWithAmbiguityCheck -Tokens @("CSKIM", "YyLee")
$results.Count | Should -Be 2
$results[0].SamAccountName | Should -Be "cskim"
$results[0].Status | Should -Be "정상 매칭"
$results[0].IsResolved | Should -BeTrue
$results[1].SamAccountName | Should -Be "yylee"
$results[1].Status | Should -Be "정상 매칭"
$results[1].IsResolved | Should -BeTrue
}
}
Context "Resolve-UsersWithAmbiguityCheck - DisplayName & Ambiguity (동명이인) Detection" {
It "resolves unique DisplayName as Single Match (단일 매칭)" {
$results = Resolve-UsersWithAmbiguityCheck -Tokens @("정수원")
$results.Count | Should -Be 1
$r = $results[0]
$r.Status | Should -Be "단일 매칭"
$r.IsAmbiguous | Should -BeFalse
$r.IsResolved | Should -BeTrue
$r.IsSelected | Should -BeTrue
$r.SamAccountName | Should -Be "swjung"
$r.DisplayName | Should -Be "정수원"
$r.Department | Should -Be "인사기획팀"
$r.CandidateCount | Should -Be 1
}
It "flags duplicate names as Ambiguous (동명이인 확인필요) and generates candidate rows" {
# '홍길동' exists twice in sample pool (gdhong: 클라우드인프라팀, gdhong_sales: 영업1팀)
$results = Resolve-UsersWithAmbiguityCheck -Tokens @("홍길동")
$results.Count | Should -Be 2
foreach ($cand in $results) {
$cand.InputToken | Should -Be "홍길동"
$cand.Status | Should -Be "동명이인 확인필요"
$cand.IsAmbiguous | Should -BeTrue
$cand.IsResolved | Should -BeFalse
$cand.IsSelected | Should -BeFalse # Operator must explicitly verify before selecting
$cand.CandidateCount | Should -Be 2
$cand.DisplayName | Should -Be "홍길동"
}
$sams = @($results | ForEach-Object { $_.SamAccountName })
$sams | Should -Contain "gdhong"
$sams | Should -Contain "gdhong_sales"
$depts = @($results | ForEach-Object { $_.Department })
$depts | Should -Contain "클라우드인프라팀"
$depts | Should -Contain "영업1팀"
}
It "flags second duplicate name '김철수' with 2 candidate rows" {
# '김철수' exists twice (cskim: 데이터플랫폼팀, cskim_dev: 프론트엔드개발팀)
$results = Resolve-UsersWithAmbiguityCheck -Tokens @("김철수")
$results.Count | Should -Be 2
$sams = @($results | ForEach-Object { $_.SamAccountName })
$sams | Should -Contain "cskim"
$sams | Should -Contain "cskim_dev"
}
}
Context "Resolve-UsersWithAmbiguityCheck - Unmatched / Non-existent Users" {
It "identifies nonexistent accounts as Not Found (미발견)" {
$results = Resolve-UsersWithAmbiguityCheck -Tokens @("nonexistent_user_999")
$results.Count | Should -Be 1
$r = $results[0]
$r.Status | Should -Be "미발견 (계정 없음)"
$r.IsAmbiguous | Should -BeFalse
$r.IsResolved | Should -BeFalse
$r.IsSelected | Should -BeFalse
$r.SamAccountName | Should -Be "-"
$r.CandidateCount | Should -Be 0
}
}
Context "Resolve-UsersWithAmbiguityCheck - Heterogeneous Mixed Batch" {
It "accurately classifies mixed tokens across all resolution states" {
$tokens = @("gdhong", "홍길동", "unknown_person_x", "jhbak")
$results = Resolve-UsersWithAmbiguityCheck -Tokens $tokens
# gdhong (1) + 홍길동 (2 candidates) + unknown (1) + jhbak (1) = 5 rows
$results.Count | Should -Be 5
$exactRows = @($results | Where-Object { $_.Status -eq "정상 매칭" })
$exactRows.Count | Should -Be 2
@($exactRows.SamAccountName) | Should -Contain "gdhong"
@($exactRows.SamAccountName) | Should -Contain "jhbak"
$ambRows = @($results | Where-Object { $_.IsAmbiguous })
$ambRows.Count | Should -Be 2
@($ambRows.InputToken) | Should -Contain "홍길동"
$missingRows = @($results | Where-Object { $_.Status -like "*미발견*" })
$missingRows.Count | Should -Be 1
$missingRows[0].InputToken | Should -Be "unknown_person_x"
}
}
Context "Resolve-UsersWithAmbiguityCheck - Edge Cases & Security" {
It "does not match all users when passed empty or whitespace tokens" {
# Regression test: $_.DisplayName -like '**' previously returned all 8 pool users
$resEmpty = Resolve-UsersWithAmbiguityCheck -Tokens @("", " `t`r`n ")
@($resEmpty).Count | Should -Be 0
}
It "safely handles wildcard tokens without pattern expansion" {
# An asterisk should NOT match all users via wildcard expansion
$resWildcard = Resolve-UsersWithAmbiguityCheck -Tokens @("*")
@($resWildcard).Count | Should -Be 1
$resWildcard[0].Status | Should -Be "미발견 (계정 없음)"
$resWildcard[0].CandidateCount | Should -Be 0
}
}
}