
    i!                       d Z ddlmZ ddlZddlZddlZddlmZ ddlZej                  j                  d e ee      j                  j                  j                               ddlmZmZmZmZmZmZ ddlmZ ej.                  d        Z G d d	      Z G d
 d      Z G d d      Z G d d      Z G d d      Z G d d      Zy)u]   utils/delegate_controller.py + delegate_runner.py 테스트 스위트 (TDD — RED → GREEN)    )annotationsN)Path)BLOCKED_TOOLSMAX_CONCURRENT	MAX_DEPTHDelegateControllerSubAgentResultSubAgentTask)run_subagentc                     t        d      S )u$   기본 깊이(0) DelegateController.r   parent_depth)r        U/home/jay/workspace/.worktrees/task-2116-dev1/utils/tests/test_delegate_controller.pyctrlr      s     1--r   c                  .    e Zd ZdZd Zd Zd Zd Zd Zy)TestCanDelegateDepthu   깊이 제한 검증c                D    |j                         \  }}|du sJ |dk(  sJ y)u   깊이 0은 위임 가능.TOKN)can_delegateselfr   okreasons       r   test_depth_zero_allowedz,TestCanDelegateDepth.test_depth_zero_allowed,   s,    &&(
FTzz~~r   c                N    t        d      }|j                         \  }}|du sJ y)u(   깊이 1도 위임 가능 (MAX_DEPTH=2).   r   TN)r   r   r   cr   _s       r   test_depth_one_allowedz+TestCanDelegateDepth.test_depth_one_allowed2   s(    A. ATzzr   c                |    t        t              }|j                         \  }}|du sJ t        t              |v sJ y)u(   깊이가 MAX_DEPTH 이상이면 거부.r   FN)r   r   r   str)r   r    r   r   s       r   test_depth_at_max_deniedz-TestCanDelegateDepth.test_depth_at_max_denied8   s:    I6^^%
FU{{9~'''r   c                \    t        t        dz         }|j                         \  }}|du sJ y)u   MAX_DEPTH+1 깊이는 거부.r   r   FN)r   r   r   r   s       r   test_depth_exceeds_max_deniedz2TestCanDelegateDepth.test_depth_exceeds_max_denied?   s,    IM: AU{{r   c                r    t         dz   }t        |      }|j                         \  }}t        |      |v sJ y)u/   거부 이유에 현재 깊이가 포함된다.r   r   N)r   r   r   r$   )r   depthr    r!   r   s        r   "test_reason_contains_current_depthz7TestCanDelegateDepth.test_reason_contains_current_depthE   s7    AE2NN$	65zV###r   N)	__name__
__module____qualname____doc__r   r"   r%   r'   r*   r   r   r   r   r   )   s    ($r   r   c                      e Zd ZdZd Zd Zy)TestCanDelegateConcurrencyu   동시 자식 수 제한 검증c                    |j                   5  |j                  j                  dgt        z         ddd       |j	                         \  }}|du sJ t        t              |v sJ y# 1 sw Y   6xY w)u0   _active_children이 MAX_CONCURRENT이면 거부.dummyNF)_children_lock_active_childrenextendr   r   r$   r   s       r   test_concurrent_limit_respectedz:TestCanDelegateConcurrency.test_concurrent_limit_respectedU   sp       	E!!(('^)CD	E&&(
FU{{>"f,,,		E 	Es   $A&&A/c                    |j                   5  |j                  j                  dgt        dz
  z         ddd       |j	                         \  }}|du sJ y# 1 sw Y   #xY w)u7   _active_children이 MAX_CONCURRENT 미만이면 허용.r2   r   NT)r3   r4   r5   r   r   )r   r   r   r!   s       r   #test_concurrent_below_limit_allowedz>TestCanDelegateConcurrency.test_concurrent_below_limit_allowed]   sb       	K!!(('nq6H)IJ	K!!#ATzz	K 	Ks   'AAN)r+   r,   r-   r.   r6   r8   r   r   r   r0   r0   R   s    )-r   r0   c                  .    e Zd ZdZd Zd Zd Zd Zd Zy)TestFilterToolsu   BLOCKED_TOOLS 필터링c                p    t        t              ddgz   }|j                  |      }t        D ]  }||vrJ  y)u%   BLOCKED_TOOLS 항목이 제거된다.	read_filebashN)listr   filter_tools)r   r   toolsresultblockeds        r   test_blocked_tools_removedz*TestFilterTools.test_blocked_tools_removedm   sC    ]#{F&;;""5)$ 	)G&(((	)r   c                <    g d}|j                  |      }||k(  sJ y)u   허용 도구는 보존된다.)r<   r=   
write_fileNr?   )r   r   r@   rA   s       r   test_allowed_tools_keptz'TestFilterTools.test_allowed_tools_keptt   s#    3""5)r   c                0    |j                  d      g k(  sJ y)u)   toolsets=None이면 빈 리스트 반환.NrF   r   r   s     r    test_none_toolsets_returns_emptyz0TestFilterTools.test_none_toolsets_returns_emptyz   s      &",,,r   c                0    |j                  g       g k(  sJ y)u.   빈 리스트 입력 시 빈 리스트 반환.NrF   rI   s     r   !test_empty_toolsets_returns_emptyz1TestFilterTools.test_empty_toolsets_returns_empty~   s      $***r   c                N    |j                  t        t                    }|g k(  sJ y)u&   모두 차단 도구면 빈 리스트.N)r?   r>   r   )r   r   rA   s      r   test_only_blocked_returns_emptyz/TestFilterTools.test_only_blocked_returns_empty   s#    ""4#67||r   N)	r+   r,   r-   r.   rC   rG   rJ   rL   rN   r   r   r   r:   r:   j   s    !)-+r   r:   c                  :    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
y	)
TestRunBatchu    배치 서브에이전트 실행c                4    |j                  g       }|g k(  sJ y)u*   빈 태스크 목록은 빈 결과 반환.N)run)r   r   resultss      r   test_empty_tasks_returns_emptyz+TestRunBatch.test_empty_tasks_returns_empty   s    ((2,"}}r   c                `    t        d      g}|j                  |      }t        |      dk(  sJ y)u'   단일 태스크는 결과 1개 반환.z	test goalgoalr   N)r
   rR   lenr   r   tasksrS   s       r   #test_single_task_returns_one_resultz0TestRunBatch.test_single_task_returns_one_result   s.    ;/0((5/7|q   r   c                    t        d      D cg c]  }t        d|        }}|j                  |      }t        |      dk(  sJ yc c}w )u,   결과 수가 태스크 수와 일치한다.   task rV   N)ranger
   rR   rX   )r   r   irZ   rS   s        r    test_results_count_matches_tasksz-TestRunBatch.test_results_count_matches_tasks   sI    9>qBAU1#;/BB((5/7|q    Cs   Ac                    t        d      D cg c]  }t        d|        }}|j                  |      }t        d |D              }|g dk(  sJ yc c}w )u6   각 결과의 task_index가 올바르게 할당된다.r]   r^   rV   c              3  4   K   | ]  }|j                     y w)N)
task_index).0rs     r   	<genexpr>zBTestRunBatch.test_task_index_assigned_correctly.<locals>.<genexpr>   s     7!7s   )r   r      N)r_   r
   rR   sorted)r   r   r`   rZ   rS   indicess         r   "test_task_index_assigned_correctlyz/TestRunBatch.test_task_index_assigned_correctly   sU    9>qBAU1#;/BB((5/7w77)### Cs   Ac                v    h d}t        d      g}|j                  |      }|D ]  }|j                  |v rJ  y)u(   결과의 status가 유효한 값이다.>   errorfailed	completedinterruptedhellorV   N)r
   rR   status)r   r   valid_statusesrZ   rS   rf   s         r   test_result_status_is_validz(TestRunBatch.test_result_status_is_valid   sB    H7+,((5/ 	.A88~---	.r   c                j    t        d      g}|j                  |      }t        |d   t              sJ y)u&   반환 타입이 SubAgentResult이다.testrV   r   N)r
   rR   
isinstancer	   rY   s       r   #test_result_is_subagent_result_typez0TestRunBatch.test_result_is_subagent_result_type   s0    6*+((5/'!*n555r   c                h    t        d      g}|j                  |      }|d   j                  dk\  sJ y)u#   duration_seconds가 0 이상이다.rv   rV   r           N)r
   rR   duration_secondsrY   s       r   test_duration_is_non_negativez*TestRunBatch.test_duration_is_non_negative   s4    6*+((5/qz**c111r   N)r+   r,   r-   r.   rT   r[   ra   rk   rt   rx   r|   r   r   r   rP   rP      s(    *
!!$.62r   rP   c                      e Zd ZdZd Zd Zy)TestInterruptChildrenu   인터럽트 전파c                \    |j                          |j                  j                         sJ y)u;   interrupt_children() 호출 후 _interrupted가 set 된다.N)interrupt_children_interruptedis_setrI   s     r   test_interrupt_sets_eventz/TestInterruptChildren.test_interrupt_sets_event   s&    !  '')))r   c                    |j                          t        d      g}|j                  |      }|d   j                  dv sJ y)uG   인터럽트 후 run()이 'interrupted' 상태를 포함할 수 있다.rv   rV   r   >   rm   rn   ro   rp   N)r   r
   rR   rr   rY   s       r   test_interrupted_run_statusz1TestInterruptChildren.test_interrupted_run_status   sA    !6*+((5/qz  $SSSSr   N)r+   r,   r-   r.   r   r   r   r   r   r~   r~      s    *
Tr   r~   c                  (    e Zd ZdZd Zd Zd Zd Zy)TestRunSubagentu   run_subagent 래퍼 동작c                    t        d      }t        j                         }t        |d|d      }t	        |t
              sJ y)u&   SubAgentResult 타입을 반환한다.zsimple taskrV   r   r)   rp   rd   N)r
   	threadingEventr   rw   r	   r   taskeventrA   s       r   test_returns_subagent_resultz,TestRunSubagent.test_returns_subagent_result   s8    /!d!1M&.111r   c                    t        d      }t        j                         }t        |d|d      }|j                  dk(  sJ y)u%   task_index가 결과에 보존된다.r   rV   r      r   N)r
   r   r   r   rd   r   s       r   test_task_index_preservedz)TestRunSubagent.test_task_index_preserved   s<    (!d!1M  A%%%r   c                    t        d      }t        j                         }|j                          t	        |d|d      }|j
                  dk(  sJ y)u=   인터럽트 이벤트가 set된 경우 status='interrupted'.r   rV   r   r   rp   N)r
   r   r   setr   rr   r   s       r   *test_interrupted_event_returns_interruptedz:TestRunSubagent.test_interrupted_event_returns_interrupted   sC    (!		d!1M}}---r   c                    t        d      }t        j                         }t        |d|d      }|j                  dk\  sJ y)u(   정상 실행 시 duration_seconds >= 0.r   rV   r   r   rz   N)r
   r   r   r   r{   r   s       r   $test_duration_positive_on_normal_runz4TestRunSubagent.test_duration_positive_on_normal_run   s<    (!d!1M&&#---r   N)r+   r,   r-   r.   r   r   r   r   r   r   r   r   r      s    $2&..r   r   )r.   
__future__r   sysr   timepathlibr   pytestpathinsertr$   __file__parentutils.delegate_controllerr   r   r   r   r	   r
   utils.delegate_runnerr   fixturer   r   r0   r:   rP   r~   r   r   r   r   <module>r      s    c " 
     3tH~,,33::; <  / . .!$ !$R 0 F-2 -2jT T,. .r   