199 lines
8.6 KiB
PowerShell
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
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|