
    Ái<                        d Z ddlZddlmc mZ ddlZddlZddl	m
Z
 ddlZ e
d      Z e
d      Z e
d      Z e
d      Zded	efd
Zd	ee   fdZdee   fdZ G d d      Z G d d      Zedk(  r ej0                  edg       yy)u  
하누만(Hanuman), dev4팀 테스터
동적 멤버 매핑 검증 테스트 스위트

이 테스트 스위트는 parse-member-id.sh가 organization-structure.json에서
동적으로 매핑을 로드하고 정확하게 에이전트 ID를 추출하는지 검증합니다.
    N)Pathz6/home/jay/workspace/memory/organization-structure.jsonz./home/jay/.claude/hooks/lib/parse-member-id.shz2/home/jay/.claude/hooks/lib/generate-member-map.pyz0/home/jay/.claude/hooks/lib/.member-map-cache.shtextreturnc                     t         j                         st        j                  dt                 t	        j
                  dddt          dd| gddd	      }|j                  j                         S )
u   
    bash에서 parse_member_id 함수를 호출하고 결과 반환.

    Args:
        text: 에이전트 이름을 포함한 텍스트

    Returns:
        추출된 에이전트 ID (없으면 빈 문자열)
    zparse-member-id.sh not found: bash-csource "z" && parse_member_id "$1"_T
   capture_outputr   timeout)PARSE_MEMBER_ID_PATHexistspytestskip
subprocessrunstdoutstrip)r   results     C/home/jay/workspace/teams/dev4/tests/test_dynamic_member_mapping.py_call_parse_member_idr      st      &&(45I4JKL^^+,,EF	
 F ==      c                  .   t         j                         st        j                  dt                 t         j	                         5 } t        j                  |       }ddd       t               }t        j                  di       |       |S # 1 sw Y   1xY w)u   
    organization-structure.json에서 유효한 에이전트 ID 추출.

    consulting-lead와 venus-delegate는 제외합니다.

    Returns:
        추출된 ID들의 집합
    z"Organization structure not found: N	structure)
ORG_STRUCTURE_PATHr   r   r   openjsonloadset_collect_idsget)forgidss      r   _extract_ids_from_orgr'   :   sy     $$&89K8LMN		 	 	" aiil %Cb)3/J s   BB	collectedc                     t        | t              rZ| j                  d      }|r%t        |t              r|dvr|j	                  |       | j                         D ]  }t        ||        yt        | t              r| D ]  }t        ||        yy)u   
    재귀적으로 JSON 구조에서 id 필드를 수집합니다.

    consulting-lead와 venus-delegate는 필터링됩니다.

    Args:
        node: JSON 노드 (dict, list, 또는 기타)
        collected: ID를 수집할 set
    id)zconsulting-leadzvenus-delegateN)
isinstancedictr#   straddvaluesr"   list)noder(   raw_idvitems        r   r"   r"   N   s     $$j-BBf% 	'AI&	'	D$	 	*Dy)	* 
 r   c                   R    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zy)TestDynamicMemberMappingu(   동적 멤버 매핑 테스트 클래스c                 X   t         j                         st        j                  dt                 t        j                         r1t        j
                  } |       }|j                  }d}||kD  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }t        j                  dt               dz   d	|iz  }t        t        j                  |            d
x}x}x}x}}y
t!        j"                  dt%        t               gddd      }t        j                  } |       }|st        j                  dt         d|j&                         dz   dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            d
x}}t        j
                  } |       }|j                  }d}||kD  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }t        j                  dt               dz   d	|iz  }t        t        j                  |            d
x}x}x}x}}y
)u   
        generate-member-map.py 실행 시 캐시 파일이 생성되는지 검증.

        캐시 파일이 존재하고 크기가 0보다 커야 합니다.
        z"generate-member-map.py not found: r   >z_%(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.stat
}()
}.st_size
} > %(py9)s
CACHE_PATHpy0py2py4py6py9z Cache file exists but is empty: 
>assert %(py11)spy11Npython3T   r   zCache file was not created: 
zC
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
})r=   r>   r?   zCache file is empty: )GENERATOR_PATHr   r   r   r;   statst_size
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationr   r   r-   stderr)
self@py_assert1@py_assert3@py_assert5@py_assert8@py_assert7@py_format10@py_format12r   @py_format5s
             r   test_cache_generationz.TestDynamicMemberMapping.test_cache_generationm   s    $$&KK<^<LMN ?!?!))?,-?)A-?->->?)A? ?8>? ?&>&> ? ?5>Y ? ?5>Y  ? ?5>Y "? ?5>Y *? ?5>Y -.? ?->->1*>? ? ?+>+>? ? ?
  ^^C/0#	F !!L!#L#L:K:K-j\FMM?KL LEKVL L3K3K L LBK) L LBK) "L LBK) $L L L8K8KL L ??V?$V$,,VqV,q0VVV,qVVVVVV:VVV:VVV?VVV$VVV,VVVqVVV4I*2VVVVVVVVr   c                     t               }|st        j                  d       g d}g }|D ]-  \  }}t        |      }||k7  s|j	                  | d| d       / |rt        j
                  d|        yy)ut  
        organization-structure.json의 모든 에이전트가 parse-member-id에서 매핑 가능한지 검증.

        - org-structure.json에서 재귀적으로 모든 id 추출 (consulting-lead, venus-delegate 제외)
        - parse-member-id.sh가 major names를 포함하고 있는지 확인 (spot check)
        - 누락된 주요 멤버가 없어야 함
        z-No member IDs found in organization structure))	kartikeya	Kartikeya)vishnuVishnu)hanumanHanuman)hermesHermes)odinOdin)lokiLoki)	aphrodite	Aphroditez (from 'z')z0Following major agents are not properly mapped: N)r'   r   r   r   appendfail)rT   org_idsmajor_agentsunmapped	member_idnamer   s          r   'test_all_org_members_mapped_dynamicallyz@TestDynamicMemberMapping.test_all_org_members_mapped_dynamically   s     ()KKGH
 + 	@OIt*40F"9+XdV2 >?	@
 KKJ8*UV r   c           
         g d}|D ]   \  }}t        |      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      nddt        j                         v st        j
                  |      rt        j                  |      nddz  }t        j                  d| d| d	| d
      dz   d|iz  }t        t        j                  |            d} y)u  
        bash에서 parse_member_id 함수 호출하여 기본 매핑 동작 검증.

        테스트 케이스:
        - 한국어: "카르티케야가 작업합니다" → "kartikeya"
        - 영어: "Vishnu is reviewing" → "vishnu"
        - 마케팅: "아프로디테 팀장님" → "aphrodite"
        - dev8: "아누비스 코드 리뷰" → "anubis" (dev8 팀장 ra)
        ))u"   카르티케야가 작업합니다r_   )zVishnu is reviewingra   )u   아프로디테 팀장님rk   )u   아누비스 코드 리뷰anubis==z%(py0)s == %(py2)sr   expected_idr=   r>   Failed for '': expected '', got ''
>assert %(py4)sr?   N
r   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   rT   
test_casesr   rz   r   rU   @py_format3r\   s           r   test_parse_basic_namesz/TestDynamicMemberMapping.test_parse_basic_names      

 ", 	PD+*40F+%P>O>OP+P PIOP P7O7O P PFOi P PIOP P7O7O &P PFOi &P P>O>OdV=XfXQOP P P<O<OP P	Pr   c           
         g d}|D ]   \  }}t        |      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      nddt        j                         v st        j
                  |      rt        j                  |      nddz  }t        j                  d| d| d	| d
      dz   d|iz  }t        t        j                  |            d} y)u  
        substring 충돌 방지 검증.

        테스트 케이스:
        - "아누비스가 코드 리뷰" → "anubis" (not "anu")
        - "아누 실장님" → "anu"
        - "라타토스크 보고" → "ratatoskr" (not "라" 매칭 아님)
        ))u   아누비스가 코드 리뷰rv   )u   아누 실장님anu)u   라타토스크 보고	ratatoskrrw   ry   r   rz   r{   r|   r}   r~   r   r   r?   Nr   r   s           r   #test_substring_collision_preventionz<TestDynamicMemberMapping.test_substring_collision_prevention      

 ", 	PD+*40F+%P>O>OP+P PIOP P7O7O P PFOi P PIOP P7O7O &P PFOi &P P>O>OdV=XfXQOP P P<O<OP P	Pr   c           
         g d}|D ]   \  }}t        |      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      nddt        j                         v st        j
                  |      rt        j                  |      nddz  }t        j                  d| d| d	| d
      dz   d|iz  }t        t        j                  |            d} y)ug  
        짧은 이름의 PCRE 경계 검증.

        테스트 케이스:
        - "루 백엔드 작업" → "lugh" (독립 단어로 매칭)
        - "루비처럼" → "" (빈 문자열 — 다른 단어의 일부이므로 false positive 아님)
        - "에코 데이터 수집" → "echo"
        - "에코시스템" → "" (빈 문자열)
        ))u   루 백엔드 작업lugh)u   루비처럼 )u   에코 데이터 수집echo)u   에코시스템r   rw   ry   r   rz   r{   r|   r}   r~   r   r   r?   Nr   r   s           r   test_short_name_pcre_boundariesz8TestDynamicMemberMapping.test_short_name_pcre_boundaries   r   r   c           
         g d}|D ]   \  }}t        |      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      nddt        j                         v st        j
                  |      rt        j                  |      nddz  }t        j                  d| d| d	| d
      dz   d|iz  }t        t        j                  |            d} y)u   
        특수 영어 이름 매핑 검증.

        테스트 케이스:
        - "Ah Kin designed" → "ah_kin"
        - "Ma'at 검증" → "maat"
        - "Da Vinci 아이디어" → "davinci"
        ))zAh Kin designedah_kin)u   Ma'at 검증maat)u   Da Vinci 아이디어davincirw   ry   r   rz   r{   r|   r}   r~   r   r   r?   Nr   r   s           r   test_special_english_namesz3TestDynamicMemberMapping.test_special_english_names   r   r   c                    g d}|D ]  \  }}t        |      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      nddt        j                         v st        j
                  |      rt        j                  |      nddz  }t        j                  d| d| d	      d
z   d|iz  }t        t        j                  |            d} y)u   
        무관 텍스트에서 false positive 없음을 검증.

        테스트 케이스:
        - "오늘 날씨가 맑습니다" → ""
        - "서버 배포 완료" → ""
        - "random English text" → ""
        ))u   오늘 날씨가 맑습니다r   )u   서버 배포 완료r   )zrandom English textr   rw   ry   r   rz   r{   r|   z': expected empty string, got 'r   r   r?   Nr   r   s           r   test_no_false_positivez/TestDynamicMemberMapping.test_no_false_positive  s   

 ", 	MD+*40F+%M;L;LM+M MFLfM M4L4L M MCL9 M MFLfM M4L4L &M MCL9 &M M;L;LdV#B6(!LM M M9L9LM M	Mr   c                 f   t         j                         st        j                  d       t         j                  } |       }|j
                  }d}||kD  }|st        j                  d|fd||f      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }t        j                  d      dz   d	|iz  }t        t        j                  |            d
x}x}x}x}}t        j                   dddt"         dgddd      }|j$                  }d}	||	k(  }|st        j                  d|fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |	      dz  }
t        j                  d      dz   d|
iz  }t        t        j                  |            d
x}x}}	d}|j&                  }	||	v }|st        j                  d|fd||	f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      dz  }
t        j                  d      dz   d|
iz  }t        t        j                  |            d
x}x}}	y
)u   
        캐시 갱신 체크.

        캐시 파일의 mtime을 과거로 설정하고 parse-member-id.sh 소싱 시
        캐시가 적절히 관리되는지 확인합니다.
        z-Cache file not found, skipping staleness testr   r8   r:   r;   r<   zCache file is emptyrB   rC   Nr   r   r	   z" && echo "loaded"Tr   r   rw   )z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sr   )r=   r>   py5z"parse-member-id.sh sourcing failedz
>assert %(py7)spy7loadedin)z.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.stdout
})py1py3r   z'parse-member-id.sh not sourced properly)r;   r   r   r   rH   rI   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   r   r   r   
returncoder   )rT   rU   rV   rW   rX   rY   rZ   r[   r   @py_assert4@py_format6@py_format8@py_assert0@py_assert2s                 r   test_cache_staleness_detectionz7TestDynamicMemberMapping.test_cache_staleness_detection  s      "KKGH C C ((C1C(1,CCC(1CCCCCCzCCCzCCCCCC CCC(CCC1CCC.CCCCCCCC TX&:%;;MNO	
   KAK A%KKK AKKKKKKvKKKvKKK KKKAKKK'KKKKKKKKS6==Sx=(SSSx=SSSxSSSSSS6SSS6SSS=SSS*SSSSSSSSr   c           
         g d}|D ]   \  }}t        |      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      nddt        j                         v st        j
                  |      rt        j                  |      nddz  }t        j                  d| d| d	| d
      dz   d|iz  }t        t        j                  |            d} y)u   
        한국어 이름 파싱 검증.

        모든 한국어 이름이 정상적으로 매핑되는지 확인합니다.
        )
)u   헤르메스 검토re   )u   불칸이 작업vulcan)u   이리스가 디자인iris)u   아테나를 호출athena)u   아르고스 확인argos)u   오딘 팀장rg   )u   토르가 개발thor)u   프레이야입니다freya)u   미미르 의견mimir)u   헤임달 점검heimdallrw   ry   r   rz   r{   r|   r}   r~   r   r   r?   Nr   )rT   korean_test_casesr   rz   r   rU   r   r\   s           r   test_korean_name_parsingz1TestDynamicMemberMapping.test_korean_name_parsing1  s   
 "3 	PD+*40F+%P>O>OP+P PIOP P7O7O P PFOi P PIOP P7O7O &P PFOi &P P>O>OdV=XfXQOP P P<O<OP P	Pr   c           
         g d}|D ]   \  }}t        |      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      nddt        j                         v st        j
                  |      rt        j                  |      nddz  }t        j                  d| d| d	| d
      dz   d|iz  }t        t        j                  |            d} y)u   
        영어 이름 파싱 검증.

        모든 영어 이름이 정상적으로 매핑되는지 확인합니다.
        )
)zHermes is herere   )zVulcan worksr   )zIris designedr   )zAthena talksr   )zArgos checkingr   )z
Odin leadsrg   )zThor developsr   )zFreya is presentr   )zMimir suggestsr   )zHeimdall guardsr   rw   ry   r   rz   r{   r|   r}   r~   r   r   r?   Nr   )rT   english_test_casesr   rz   r   rU   r   r\   s           r   test_english_name_parsingz2TestDynamicMemberMapping.test_english_name_parsingJ  s   
 "4 	PD+*40F+%P>O>OP+P PIOP P7O7O P PFOi P PIOP P7O7O &P PFOi &P P>O>OdV=XfXQOP P P<O<OP P	Pr   c           
         g d}|D ]   \  }}t        |      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      nddt        j                         v st        j
                  |      rt        j                  |      nddz  }t        j                  d| d| d	| d
      dz   d|iz  }t        t        j                  |            d} y)u   
        한국어 + 영어 혼합 텍스트 파싱 검증.

        한국어와 영어가 혼합된 텍스트에서도 정상적으로 매핑되는지 확인합니다.
        ))u   헤르메스(Hermes) 리뷰re   )u   Vulcan 불칸이 작업r   )u   아테나 Athena 의견r   )u$   프로메테우스 Prometheus 전략
prometheus)u   마아트 Ma'at 검증r   rw   ry   r   rz   r{   r|   r}   r~   r   r   r?   Nr   )rT   mixed_test_casesr   rz   r   rU   r   r\   s           r   test_mixed_language_parsingz4TestDynamicMemberMapping.test_mixed_language_parsingc  s   
 "2 	PD+*40F+%P>O>OP+P PIOP P7O7O P PFOi P PIOP P7O7O &P PFOi &P P>O>OdV=XfXQOP P P<O<OP P	Pr   N)__name__
__module____qualname____doc__r]   rt   r   r   r   r   r   r   r   r   r    r   r   r6   r6   j   sH    2W:WBP.P*P.P*M*T2P2P2Pr   r6   c                       e Zd ZdZd Zy)TestCacheIntegrationu    캐시 통합 테스트 (선택)c                 >   t         j                         st        j                  d       t         j	                         5 }|j                         }ddd       d}|v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y# 1 sw Y   xY w)u   
        캐시 파일이 bash 함수를 포함하는지 검증.

        캐시 파일에 `echo "xxx"` 패턴의 매핑이 포함되어 있는지 확인합니다.
        zCache file not foundNr   r   )z%(py1)s in %(py3)scache_content)r   r   z+Cache file does not contain echo statementsz
>assert %(py5)sr   )r;   r   r   r   r   readrJ   rK   rO   rL   rM   rN   rP   rQ   rR   )rT   r$   r   r   r   @py_format4r   s          r   "test_cache_contains_bash_functionsz7TestCacheIntegration.test_cache_contains_bash_functions  s       "KK./__ 	%!FFHM	% Uv&UUUvUUUvUUUUUUUUUUUUU(UUUUUUU		% 	%s   DDN)r   r   r   r   r   r   r   r   r   r   }  s    *Vr   r   __main__z-v)r   builtinsrL   _pytest.assertion.rewrite	assertionrewriterJ   r   r   pathlibr   r   r   r   rG   r;   r-   r   r!   r'   r"   r6   r   r   main__file__r   r   r   <module>r      s         RS LM JKDE
! ! !8s3x (*#c( *8KP KPfV V. zFKK4 ! r   