
    liJ                        d Z ddlZddlmc mZ ddlZddlZddl	Z	ddl
mZ ej                  j                  d e ee      j                   j                                ddlmZmZmZmZ  e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 G d d      Z G d d      Zy)u2  
Tests for ast_dependency_map.py — AST 기반 Python 의존성 맵 생성기

테스트 커버리지:
- AST 파싱 (유효/무효 파일)
- 임포트 모듈 추출
- 의존성 그래프 구축
- 직접 임포터 조회
- analyze() 출력 구조
- 함수 레벨 호출자 분석
- 테스트 파일 감지
    N)Path)DependencyGraph_extract_imported_modules_parse_fileanalyzez/home/jay/workspace/dashboardc                   "    e Zd ZdZd Zd Zd Zy)TestParseFileValidu(   유효한 Python 파일 파싱 테스트c                    t        j                  ddd      5 }|j                  d       t        |j                        }ddd       	 t              }d}||u}|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}}t        j                  }t!        ||      }	|	sddt        j                         v st        j                  t               rt        j                  t               ndd	t        j                         v st        j                  |      rt        j                  |      nd	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}}	|j#                  d       y# 1 sw Y   xY w# j#                  d       w xY w)uK   유효한 Python 파일을 파싱하면 None이 아닌 AST를 반환한다.w.pyFmodesuffixdeletezx = 1
print(x)
Nis notz%(py0)s is not %(py3)sresultpy0py3assert %(py5)spy5Qassert %(py6)s
{%(py6)s = %(py0)s(%(py1)s, %(py4)s
{%(py4)s = %(py2)s.Module
})
}
isinstanceastr   py1py2py4py6T
missing_ok)tempfileNamedTemporaryFilewriter   namer   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationr   Moduler   unlink)selfftmp_pathr   @py_assert2@py_assert1@py_format4@py_format6@py_assert3@py_assert5@py_format7s              </home/jay/workspace/scripts/tests/test_ast_dependency_map.pytest_parse_valid_python_filez/TestParseFileValid.test_parse_valid_python_file*   sl   ((U5
 	$GG'(AFF|H		$	- *F!%%6%%%%6%%%%%%6%%%6%%%%%%%%%%&)jj1:fj11111111:111:111111f111f111111c111c111j1111111111OOtO,	$ 	$ OOtO,s   'I	G2I II/c                 ^   t        j                  ddd      5 }|j                  d       t        |j                        }ddd       	 t              }d}||u}|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}}|j                  d       y# 1 sw Y   xY w# j                  d       w xY w)uL   임포트가 포함된 유효한 파일을 파싱하면 AST를 반환한다.r   r   Fr   z:import os
from pathlib import Path

def hello():
    pass
Nr   r   r   r   r   r   Tr"   r$   r%   r&   r   r'   r   r(   r)   r*   r+   r,   r-   r.   r/   r1   r2   r3   r4   r   r5   r6   r7   r8   s           r<   "test_parse_valid_file_with_importsz5TestParseFileValid.test_parse_valid_file_with_imports9   s    ((U5
 	$GGQ AFF|H	$	- *F!%%6%%%%6%%%%%%6%%%6%%%%%%%%%%OOtO,	$ 	$ OOtO,   'D	B0D DD,c                    t         dz  }|j                  } |       }|st        j                  d      dz   dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}t        |      }|j                         j                  }|dkD  rd}||u }|st        j                  d|fd	||f      d
t	        j
                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}}yd}||u}|st        j                  d|fd||f      d
t	        j
                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}}t        j                  }t!        ||      }
|
sddt	        j
                         v st        j                  t               rt        j                  t               ndd
t	        j
                         v st        j                  |      rt        j                  |      nd
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}}
y)ul   실제 data_loader.py 파일을 파싱한다. 100KB 초과 시 대형 파일 보호로 None을 반환한다.data_loader.pyu%   data_loader.py 파일이 없습니다zC
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}data_loader_pathr   r   r    Ni isz%(py0)s is %(py3)sr   r   r   r   r   r   r   r   r   r   )DASHBOARD_ROOTexistsr(   _format_assertmsgr*   r+   r,   r-   r.   r/   r   statst_sizer)   r   r0   r   )r2   rE   r6   r9   @py_format5r   	file_sizer5   r7   r8   r:   r;   s               r<   test_parse_real_data_loaderz.TestParseFileValid.test_parse_real_data_loaderI   s   ),<<&&Q&(Q(QQ*QQQQQQQQQQQQQ&QQQ(QQQQQQ-.$))+33	w!!6T>!!!6T!!!!!!6!!!6!!!T!!!!!!!!%%6%%%%6%%%%%%6%%%6%%%%%%%%%%&)jj1:fj11111111:111:111111f111f111111c111c111j1111111111    N)__name__
__module____qualname____doc__r=   rA   rQ    rR   r<   r	   r	   '   s    2-- 2rR   r	   c                   "    e Zd ZdZd Zd Zd Zy)TestParseFileInvalidu/   구문 오류가 있는 파일 파싱 테스트c                 ^   t        j                  ddd      5 }|j                  d       t        |j                        }ddd       	 t              }d}||u }|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}}|j                  d       y# 1 sw Y   xY w# j                  d       w xY w)uD   구문 오류가 있는 파일을 파싱하면 None을 반환한다.r   r   Fr   u3   def broken(
    # 괄호가 닫히지 않음
x = 1
NrG   rI   r   r   r   r   Tr"   r?   r@   s           r<   $test_parse_syntax_error_returns_nonez9TestParseFileInvalid.test_parse_syntax_error_returns_none`   s    ((U5
 	$GGLMAFF|H		$	- *F!!6T>!!!6T!!!!!!6!!!6!!!T!!!!!!!OOtO,	$ 	$ OOtO,rB   c                 v   t        t        d            }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y)	u@   존재하지 않는 파일을 파싱하면 None을 반환한다.z#/nonexistent/path/does_not_exist.pyNrG   rI   r   r   r   r   )
r   r   r(   r)   r*   r+   r,   r-   r.   r/   )r2   r   r5   r6   r7   r8   s         r<   (test_parse_nonexistent_file_returns_nonez=TestParseFileInvalid.test_parse_nonexistent_file_returns_nonen   sj    T"GHIv~vvvrR   c                 ^   t        j                  ddd      5 }|j                  d       t        |j                        }ddd       	 t              }d}||u }|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}}|j                  d       y# 1 sw Y   xY w# j                  d       w xY w)uC   불완전한 표현식 파일을 파싱하면 None을 반환한다.r   r   Fr   zclass Foo:
  def bar(self
NrG   rI   r   r   r   r   Tr"   r?   r@   s           r<   -test_parse_incomplete_expression_returns_nonezBTestParseFileInvalid.test_parse_incomplete_expression_returns_nones   s    ((U5
 	$GG23AFF|H		$	- *F!!6T>!!!6T!!!!!!6!!!6!!!T!!!!!!!OOtO,	$ 	$ OOtO,rB   N)rS   rT   rU   rV   r[   r]   r_   rW   rR   r<   rY   rY   ]   s    9-
-rR   rY   c                   ^    e Zd ZdZdedej                  fdZd Zd Z	d Z
d Zd	 Zd
 Zd Zy)TestExtractImportedModulesu!   임포트 모듈 추출 테스트codereturnc                 ,    t        j                  |      S N)r   parse)r2   rb   s     r<   _parse_codez&TestExtractImportedModules._parse_code   s    yyrR   c                    | j                  d      }t        |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  }d	d
|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }d	d
|iz  }t        t        j                  |            dx}}y)u    import X 패턴을 처리한다.zimport os
import sys
	dashboardpkg_nameosinz%(py1)s in %(py3)smodulesr   r   r   r   Nsys
rg   r   r(   r)   r-   r*   r+   r,   r.   r/   r2   treerp   @py_assert0r5   r7   r8   s          r<   test_import_xz(TestExtractImportedModules.test_import_x   s     9:+D;GtwtwtwwuuurR   c                    | j                  d      }t        |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  }d	d
|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }d	d
|iz  }t        t        j                  |            dx}}y)u'   from X import Y 패턴을 처리한다.z1from pathlib import Path
from typing import List
ri   rj   pathlibrm   ro   rp   rq   r   r   Ntypingrs   rt   s          r<   test_from_x_import_yz/TestExtractImportedModules.test_from_x_import_y   s     UV+D;G#yG####yG###y######G###G#######"x7""""x7"""x""""""7"""7"""""""rR   c                    | j                  d      }t        |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  }d	d
|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }d	d
|iz  }t        t        j                  |            dx}}y)u9   from dashboard.X import Y 패턴에서 X를 추출한다.zWfrom dashboard.data_loader import DataLoader
from dashboard.server_utils import helper
ri   rj   data_loaderrm   ro   rp   rq   r   r   Nserver_utilsrs   rt   s          r<   test_from_dashboard_x_import_yz9TestExtractImportedModules.test_from_dashboard_x_import_y   s    :
 ,D;G'}''''}'''}''''''''''''''''(~((((~(((~((((((((((((((((rR   c                    | j                  d      }t        |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  }d	d
|iz  }t        t        j                  |            dx}}y)u0   from .X import Y 패턴에서 X를 추출한다.z$from .data_loader import DataLoader
ri   rj   r}   rm   ro   rp   rq   r   r   Nrs   rt   s          r<   test_relative_import_from_dot_xz:TestExtractImportedModules.test_relative_import_from_dot_x   sx     GH+D;G'}''''}'''}''''''''''''''''rR   c                    | j                  d      }t        |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  }d	d
|iz  }t        t        j                  |            dx}}y)u2   import dashboard.X 패턴에서 X를 추출한다.zimport dashboard.data_loader
ri   rj   r}   rm   ro   rp   rq   r   r   Nrs   rt   s          r<   test_import_dashboard_xz2TestExtractImportedModules.test_import_dashboard_x   sx     @A+D;G'}''''}'''}''''''''''''''''rR   c                 .   | j                  d      }t        |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                  t              rt        j                  t              ndt        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}}y)u9   임포트가 없는 파일은 빈 집합을 반환한다.zx = 1
y = 2
ri   rj   ==z)%(py0)s == %(py4)s
{%(py4)s = %(py2)s()
}rp   setrF   assert %(py6)sr!   N)rg   r   r   r(   r)   r*   r+   r,   r-   r.   r/   )r2   ru   rp   r9   r6   rO   r;   s          r<   !test_no_imports_returns_empty_setz<TestExtractImportedModules.test_no_imports_returns_empty_set   s     01+D;G%w%w%ww##%rR   c                    d}| j                  |      }t        |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  }d	d
|iz  }t        t        j                  |            dx}}y)u:   try/except 블록 내의 임포트 패턴을 처리한다.zqtry:
    from dashboard.data_loader import DataLoader
except ImportError:
    from data_loader import DataLoader
ri   rj   r}   rm   ro   rp   rq   r   r   Nrs   )r2   rb   ru   rp   rv   r5   r7   r8   s           r<   test_try_except_import_patternz9TestExtractImportedModules.test_try_except_import_pattern   s    7 	 %+D;G'}''''}'''}''''''''''''''''rR   N)rS   rT   rU   rV   strr   r0   rg   rw   r{   r   r   r   r   r   rW   rR   r<   ra   ra      s?    + 

  #)(( 
(rR   ra   c                   :    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
y	)
TestDependencyGraphBuildu$   의존성 그래프 구축 테스트c                    t        t              }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  }dd|iz  }t        t        j                  |            dx}x}}y)	uL   DependencyGraph 빌드 후 data_loader.py가 module_to_file에 포함된다.r}   rm   z6%(py1)s in %(py5)s
{%(py5)s = %(py3)s.module_to_file
}graphr   r   r   assert %(py7)spy7Nr   rJ   module_to_filer(   r)   r-   r*   r+   r,   r.   r/   r2   r   rv   @py_assert4r5   r8   @py_format8s          r<   "test_data_loader_in_module_to_filez;TestDependencyGraphBuild.test_data_loader_in_module_to_file   s~    /4 4 44} 44444} 4444}444444444444 44444444rR   c                    t        t              }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  }dd|iz  }t        t        j                  |            dx}x}}y)	uG   DependencyGraph 빌드 후 server.py가 module_to_file에 포함된다.serverrm   r   r   r   r   r   Nr   r   s          r<   test_server_in_module_to_filez6TestDependencyGraphBuild.test_server_in_module_to_file   s~    //5///x/////x////x//////5///5///////////rR   c                    t        t              }|j                  d   }t        |t              }|sddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}|j                  } |       }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d	z  }t        t        j                  |            dx}}y)
u?   module_to_file의 값이 실제 존재하는 Path 객체이다.r}   5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}r   rE   r   r   r   r   r    NAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}rF   )r   rJ   r   r   r   r*   r+   r(   r,   r-   r.   r/   rK   )r2   r   rE   r9   rO   r6   s         r<    test_module_to_file_maps_to_pathz9TestDependencyGraphBuild.test_module_to_file_maps_to_path   s   / //>*D11111111z111z111111*111*111111D111D1111111111&&(&((((((((((((((&((((((((((rR   c                    t        t              }|j                  }t        |      }d}||kD  }|s
t	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              nddt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d	x}x}x}}y	)
u2   file_imports 딕셔너리가 비어 있지 않다.r   >)zQ%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.file_imports
})
} > %(py8)slenr   )r   r   r   r   py8zassert %(py10)spy10N)r   rJ   file_importsr   r(   r)   r*   r+   r,   r-   r.   r/   )r2   r   r5   r   @py_assert7@py_assert6@py_format9@py_format11s           r<   test_graph_has_file_importsz4TestDependencyGraphBuild.test_graph_has_file_imports   s    /%%*s%&**&****&******s***s******5***5***%***&**********rR   c                    t        t              }|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  }dd|iz  }t        t        j                  |            dx}x}}y)	uD   그래프의 pkg_name이 루트 디렉토리 이름과 일치한다.ri   r   )z0%(py2)s
{%(py2)s = %(py0)s.pkg_name
} == %(py5)sr   )r   r   r   r   r   N)r   rJ   rk   r(   r)   r*   r+   r,   r-   r.   r/   )r2   r   r6   r   r9   r8   r   s          r<   test_graph_pkg_namez,TestDependencyGraphBuild.test_graph_pkg_name   sy    /~~,,~,,,,~,,,,,,u,,,u,,,~,,,,,,,,,,rR   c                    t        t              }|j                  d      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                  } |       }|sd	dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }t        t        j                  |            dx}}y)uE   get_file_path()가 .py 확장자가 있는 파일명도 처리한다.rD   Nr   r   pathr   r   r   r   rF   r   rJ   get_file_pathr(   r)   r*   r+   r,   r-   r.   r/   rK   	r2   r   r   r5   r6   r7   r8   r9   rO   s	            r<   !test_get_file_path_with_extensionz:TestDependencyGraphBuild.test_get_file_path_with_extension   s    /""#34t4t4tt4{{{}}tt{}rR   c                    t        t              }|j                  d      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                  } |       }|sd	dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }t        t        j                  |            dx}}y)u>   get_file_path()가 확장자 없는 모듈명도 처리한다.r}   Nr   r   r   r   r   r   r   rF   r   r   s	            r<   $test_get_file_path_without_extensionz=TestDependencyGraphBuild.test_get_file_path_without_extension   s    /""=1t4t4tt4{{{}}tt{}rR   N)rS   rT   rU   rV   r   r   r   r   r   r   r   rW   rR   r<   r   r      s(    .5
0
)+
-
rR   r   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestGetDirectImportersu!   직접 임포터 조회 테스트c                    t        t              }|j                  d      }|D ch c]  }|j                   }}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
c c}w )uK   data_loader를 직접 임포트하는 파일 중 server.py가 포함된다.r}   	server.pyrm   ro   importer_namesrq   uW   server.py가 data_loader의 직접 임포터 목록에 없습니다. 현재 임포터: 
>assert %(py5)sr   N)r   rJ   get_direct_importersr'   r(   r)   r-   r*   r+   r,   rL   r.   r/   )	r2   r   	importerspr   rv   r5   r7   r8   s	            r<   'test_data_loader_has_server_as_importerz>TestGetDirectImporters.test_data_loader_has_server_as_importer   s    /..}=	*34Q!&&44 	
{n, 	
 	
{n 	
 	
 
	  	
 	
 
6	
 	
  - 	
 	
 
	 - 	
 	
 !!/ 02	
 	
 	
 	
 	
 5s   C9c                    t        t              }|j                  d      }t        |t              }|sddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}|D ]#  }t        |t              }|sddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndd	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      dz  }t        t        j                  |            d}& y)
u@   get_direct_importers()가 Path 객체의 집합을 반환한다.r}   r   r   r   r   r   Nimpr   )r   rJ   r   r   r   r*   r+   r(   r,   r-   r.   r/   r   )r2   r   r   r9   rO   r   s         r<   $test_data_loader_importers_are_pathsz;TestGetDirectImporters.test_data_loader_importers_are_paths	  s;   /..}=	)S))))))))z)))z)))))))))))))))))S)))S)))))))))) 	)Cc4((((((((:(((:((((((c(((c((((((4(((4((((((((((	)rR   c                 2   t        t              }|j                  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                  t              rt	        j                  t              ndt	        j                  |      dz  }dd|iz  }t        t	        j                  |            d	x}}y	)
u@   존재하지 않는 모듈에 대해 빈 집합을 반환한다.nonexistent_module_xyzr   r   r   r   rF   r   r!   N)r   rJ   r   r   r(   r)   r*   r+   r,   r-   r.   r/   )r2   r   r   r9   r6   rO   r;   s          r<   )test_nonexistent_module_returns_empty_setz@TestGetDirectImporters.test_nonexistent_module_returns_empty_set  s    /../GH	E!yE!!!!yE!!!!!!y!!!y!!!!!!C!!!C!!!E!!!!!!!rR   c                    t        t              }|j                  dd      }t        |t              }|sddt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d	}y	)
u6   get_transitive_dependents()가 집합을 반환한다.r}      )hopsr   r   
dependentsr   r   N)r   rJ   get_transitive_dependentsr   r   r*   r+   r(   r,   r-   r.   r/   )r2   r   r   r9   rO   s        r<   *test_get_transitive_dependents_returns_setzATestGetDirectImporters.test_get_transitive_dependents_returns_set  s    /44]4K
*c********z***z*****************c***c**********rR   N)rS   rT   rU   rV   r   r   r   r   rW   rR   r<   r   r      s    +	
)"+rR   r   c                   L    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y)TestAnalyzeBasicu(   analyze() 기본 출력 구조 테스트c                 f   t        t        dg      }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}y)u'   analyze()는 리스트를 반환한다.rD   r   r   resultslistr   Nr   rJ   r   r   r*   r+   r(   r,   r-   r.   r/   )r2   r   r9   rO   s       r<   test_analyze_returns_listz*TestAnalyzeBasic.test_analyze_returns_list&  s    .+;*<='4((((((((z(((z(((((('((('((((((4(((4((((((((((rR   c                 F   t        t        dg      }t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}y
)u=   단일 파일 분석은 결과 항목 하나를 반환한다.rD      r   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   r   r   r   r   r!   assert %(py8)sr   Nr   rJ   r   r(   r)   r*   r+   r,   r-   r.   r/   )r2   r   r5   r:   r   r;   r   s          r<   +test_analyze_single_file_returns_one_resultz<TestAnalyzeBasic.test_analyze_single_file_returns_one_result+  s    .+;*<=7| q |q    |q      s   s      7   7   |   q       rR   c                 *   t        t        dg      }d}|d   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}|d   d   }d}||k(  }|slt        j                  d
|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}y	)u%   결과에 changed_file 키가 있다.rD   changed_filer   rm   z%(py1)s in %(py4)sr   r    r   r!   Nr   z%(py1)s == %(py4)sr   rJ   r(   r)   r-   r.   r/   r2   r   rv   r9   r5   rO   r;   s          r<   $test_analyze_result_has_changed_filez5TestAnalyzeBasic.test_analyze_result_has_changed_file0  s    .+;*<=++~++++~+++~++++++++++qz.)=-==)-=====)-====)===-========rR   c                 $   t        t        dg      }d}|d   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}y	)
u%   결과에 blast_radius 키가 있다.rD   blast_radiusr   rm   r   r   r   r!   Nr   r   s          r<   $test_analyze_result_has_blast_radiusz5TestAnalyzeBasic.test_analyze_result_has_blast_radius6  s`    .+;*<=++~++++~+++~++++++++++rR   c                    t        t        dg      }|d   d   }h d}|D ]  }||v }|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z   d|iz  }t        t        j                  |            d} y)u/   blast_radius에 필수 키들이 모두 있다.rD   r   r   >   callers
test_filestotal_affecteddirect_importerstransitive_dependentsrm   )z%(py0)s in %(py2)skeyblast)r   r   u   blast_radius에 'u   ' 키가 없습니다z
>assert %(py4)sr    N)r   rJ   r(   r)   r*   r+   r,   r-   rL   r.   r/   )r2   r   r   required_keysr   r6   @py_format3rO   s           r<   #test_blast_radius_has_required_keysz4TestAnalyzeBasic.test_blast_radius_has_required_keys;  s    .+;*<=
>*
 ! 	PC%<OOO3%OOOOOO3OOO3OOOOOO%OOO%OOOO#4SE9N!OOOOOOO	PrR   c                 $   t        t        dg      }|d   d   d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d	x}}y	)
u+   direct_importers가 리스트 타입이다.rD   r   r   r   5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}r   r   r   r   r   r   Nr   r2   r   r6   r   r8   s        r<   *test_blast_radius_direct_importers_is_listz;TestAnalyzeBasic.test_blast_radius_direct_importers_is_listI  s    .+;*<=!!*^45GHOzH$OOOOOOOOzOOOzOOOHOOOOOO$OOO$OOOOOOOOOOrR   c                 $   t        t        dg      }|d   d   d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d	x}}y	)
u&   total_affected가 정수 타입이다.rD   r   r   r   r   r   intr   N)r   rJ   r   r   r*   r+   r(   r,   r-   r.   r/   r   s        r<   'test_blast_radius_total_affected_is_intz8TestAnalyzeBasic.test_blast_radius_total_affected_is_intN  s    .+;*<=!!*^45EFLzFLLLLLLLLzLLLzLLLFLLLLLLLLLLLLLLLLLLLrR   c                    t        t        dg      }|d   d   d   }d |D        }t        |      }|st        j                  d|       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}}y
)u@   data_loader.py의 direct_importers에 server.py가 포함된다.rD   r   r   r   c              3   $   K   | ]  }d |v  
 yw)r   NrW   ).0r   s     r<   	<genexpr>zPTestAnalyzeBasic.test_blast_radius_server_in_direct_importers.<locals>.<genexpr>W  s     5s8s?5s   u;   server.py가 direct_importers에 없습니다. 현재 값: z.
>assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyrF   N)r   rJ   r   r(   rL   r*   r+   r,   r-   r.   r/   )r2   r   directr6   r9   rO   s         r<   ,test_blast_radius_server_in_direct_importersz=TestAnalyzeBasic.test_blast_radius_server_in_direct_importersS  s    .+;*<=N+,>?5f5 	
s55 	
5 	
  J&R	
 	
	6	
 	
   	
 	
 		  	
 	
 		 6 	
 	
 		 6 	
 	
 	
 	
 	
rR   c                    t        t        dg      }d}|d   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}|d   d   }t        t        f}t        ||      }|sd
dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            d	x}x}}y	)u)   결과에 analysis_time_ms 키가 있다.rD   analysis_time_msr   rm   r   r   r   r!   Nz5assert %(py6)s
{%(py6)s = %(py0)s(%(py2)s, %(py4)s)
}r   )r   r   r    r!   )r   rJ   r(   r)   r-   r.   r/   r   floatr   r*   r+   r,   )	r2   r   rv   r9   r5   rO   r;   r6   r:   s	            r<   (test_analyze_result_has_analysis_time_msz9TestAnalyzeBasic.test_analyze_result_has_analysis_time_ms[  s    .+;*<=!/WQZ/!Z////!Z///!///Z///////!!*%78G3,Gz8,GGGGGGGGzGGGzGGG8GGG,GGGGGGGGGGrR   c                 
   t        t        ddg      }t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|D cg c]  }|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  }
dd|
iz  }t        t        j                  |            dx}	}d}	|	|v }|st        j                  d|fd|	|f      t        j                  |	      dt        j                         v st        j                  |      rt        j                  |      nddz  }
dd|
iz  }t        t        j                  |            dx}	}yc c}w )uD   여러 파일 분석은 각 파일에 대한 결과를 반환한다.rD   r   r   r   r   r   r   r   r   r   Nr   rm   ro   changed_filesrq   r   r   r   )r2   r   r5   r:   r   r;   r   rr  rv   r7   r8   s               r<   test_analyze_multiple_filesz,TestAnalyzeBasic.test_analyze_multiple_filesa  sr   .+;[*IJ7| q |q    |q      s   s      7   7   |   q       4;<q>*<<0=0000=000000000=000=0000000+{m++++{m+++{++++++m+++m+++++++ =s   'J N)rS   rT   rU   rV   r   r   r   r   r   r   r   r  r  r
  rW   rR   r<   r   r   #  s;    2)
!
>,
PP
M

H,rR   r   c                   4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	TestAnalyzeWithFunctionu(   analyze() 함수 레벨 분석 테스트c                 .   t        t        dgd      }d}|d   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}y)u;   함수 지정 시 결과에 changed_function 키가 있다.rD   get_member_statusfunction_namechanged_functionr   rm   r   r   r   r!   Nr   r   r   r   s          r<   3test_analyze_with_function_has_changed_function_keyzKTestAnalyzeWithFunction.test_analyze_with_function_has_changed_function_keyr  s    -

 "/WQZ/!Z////!Z///!///Z///////qz,-D1DD-1DDDDD-1DDDD-DDD1DDDDDDDDrR   c                 $   t        t        dg      }d}|d   }||v}|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}y	)
u>   함수 미지정 시 결과에 changed_function 키가 없다.rD   r  r   )not in)z%(py1)s not in %(py4)sr   r   r!   Nr   r   s          r<   5test_analyze_without_function_no_changed_function_keyzMTestAnalyzeWithFunction.test_analyze_without_function_no_changed_function_key|  sc    .+;*<=!33!3333!333!3333333333rR   c                 (   t        t        dgd      }|d   d   d   }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}y)u4   함수 지정 시 callers가 리스트 타입이다.rD   r  r  r   r   r   r   r   r   r   Nr   r   s        r<   *test_analyze_with_function_callers_is_listzBTestAnalyzeWithFunction.test_analyze_with_function_callers_is_list  s    -

 "!*^4Y?Fz?FFFFFFFFzFFFzFFF?FFFFFFFFFFFFFFFFFFFrR   c                    t        t        dgd      }|d   d   d   }t        |      }d}||kD  }|st        j                  d|fd||f      d	t        j                         v st        j                  t              rt        j                  t              nd	dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }t        j                  d|d   d          dz   d|iz  }t        t        j                  |            dx}x}}y)uL   get_member_status 함수 분석 시 호출자가 하나 이상 발견된다.rD   r  r  r   r   r   r   )z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} > %(py6)sr   r   uO   get_member_status 함수의 호출자를 찾지 못했습니다. blast_radius: z
>assert %(py8)sr   N)r   rJ   r   r(   r)   r*   r+   r,   r-   rL   r.   r/   )r2   r   r   r5   r:   r   r;   r   s           r<   (test_analyze_with_function_callers_foundz@TestAnalyzeWithFunction.test_analyze_with_function_callers_found  sG   -

 !*^,Y77| 	
a 	
|a 	
 	
 	
|a 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	  	
 	
 
	   	
 	
 $QZ78:	
 	
 	
 	
 	
 	
rR   c                 J   t        t        dgd      }|d   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}}|j                  dd      }t        |      }d}	||	k(  }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}
}	|d   }|j                  } |       }
|
s|t        j                  d|d          dz   t        j                  |      t        j                  |      t        j                  |
      dz  }t        t        j                  |            dx}x}}
 y)u;   callers 목록의 각 항목이 'path:lineno' 형식이다.rD   r  r  r   r   r   :rm   ro   callerrq   u+   호출자 형식이 잘못되었습니다: r   r   Nr   r   r   r   r   partsr   r   r   u%   줄번호가 숫자가 아닙니다: zD
>assert %(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.isdigit
}()
}r   )r   rJ   r(   r)   r-   r*   r+   r,   rL   r.   r/   rsplitr   isdigit)r2   r   r   r  rv   r5   r7   r8   r  r:   r   r;   r   s                r<   )test_analyze_with_function_callers_formatzATestAnalyzeWithFunction.test_analyze_with_function_callers_format  s   -

 !*^,Y7 	ZFX3&=XXX3&XXX3XXXXXX&XXX&XXXX$OPVx"XXXXXXXMM#q)Eu:"":?""":""""""3"""3""""""u"""u""":""""""""""8Y8##Y#%Y%YY)NuUVxj'YYYY8YYY#YYY%YYYYYY		ZrR   c                    t        t        dgd      }|d   d   d   }g }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}}y)uE   존재하지 않는 함수 분석 시 callers가 빈 리스트이다.rD   $this_function_does_not_exist_xyz_abcr  r   r   r   r   )z%(py0)s == %(py3)sr   r   r   N)
r   rJ   r(   r)   r*   r+   r,   r-   r.   r/   )r2   r   r   r5   r6   r7   r8   s          r<   4test_analyze_with_nonexistent_function_callers_emptyzLTestAnalyzeWithFunction.test_analyze_with_nonexistent_function_callers_empty  s    @

 !*^,Y7w"}w"ww"rR   N)
rS   rT   rU   rV   r  r  r  r  r   r#  rW   rR   r<   r  r  o  s&    2E4
G
ZrR   r  c                   @    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestIsTestFileu!   테스트 파일 감지 테스트c                 ,    t        t              | _        y re   )r   rJ   r   )r2   s    r<   setup_methodzTestIsTestFile.setup_method  s    $^4
rR   c           	         t         dz  }| j                  }|j                  } ||      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}x}x}}y
)uE   test_로 시작하는 .py 파일은 테스트 파일로 감지된다.ztest_server.pyTrG   zn%(py7)s
{%(py7)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.graph
}.is_test_file
}(%(py5)s)
} is %(py10)sr2   	test_pathr   r   r    r   r   r   assert %(py12)spy12NrJ   r   is_test_filer(   r)   r*   r+   r,   r-   r.   r/   	r2   r*  r6   r9   r   @py_assert9@py_assert8r   @py_format13s	            r<   test_test_prefix_file_is_testz,TestIsTestFile.test_test_prefix_file_is_test  s    "%55	zz9z&&9&y19T91T99991T999999t999t999z999&999999y999y9991999T99999999rR   c           	         t         dz  }| j                  }|j                  } ||      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}x}x}}y
)u3   일반 .py 파일은 테스트 파일이 아니다.r   FrG   r)  r2   regular_pathr+  r,  r-  Nr.  )	r2   r6  r6   r9   r   r1  r2  r   r3  s	            r<   test_regular_file_is_not_testz,TestIsTestFile.test_regular_file_is_not_test  s    %3zz=z&&=&|4==4====4======t===t===z===&======|===|===4===========rR   c           	         t         dz  }| j                  }|j                  } ||      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}x}x}}y
)u0   data_loader.py는 테스트 파일이 아니다.rD   FrG   r)  r2   rE   r+  r,  r-  Nr.  )	r2   rE   r6   r9   r   r1  r2  r   r3  s	            r<   test_data_loader_is_not_testz+TestIsTestFile.test_data_loader_is_not_test  s    ),<<zzAz&&A&'78AEA8EAAAA8EAAAAAAtAAAtAAAzAAA&AAAAAA'7AAA'7AAA8AAAEAAAAAAAArR   c           	         t         dz  dz  }| j                  }|j                  } ||      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}y)uF   tests/ 디렉토리 내의 파일은 테스트 파일로 감지된다.testszsome_test.pyTrG   r)  r2   
tests_pathr+  r,  r-  Nr.  )	r2   r<  r6   r9   r   r1  r2  r   r3  s	            r<   test_file_in_tests_dir_is_testz-TestIsTestFile.test_file_in_tests_dir_is_test  s    #g->
zz:z&&:&z2:d:2d::::2d::::::t:::t:::z:::&::::::z:::z:::2:::d::::::::rR   c           	         t         dz  }| j                  }|j                  } ||      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}x}x}}y
)u@   test_blog_image_classify.py가 테스트 파일로 감지된다.ztest_blog_image_classify.pyTrG   r)  r2   r*  r+  r,  r-  Nr.  r0  s	            r<   %test_test_blog_image_classify_is_testz4TestIsTestFile.test_test_blog_image_classify_is_test  s    "%BB	zz9z&&9&y19T91T99991T999999t999t999z999&999999y999y9991999T99999999rR   c           	         t        d      }| j                  }|j                  } ||      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}x}x}}y
)uE   임의의 test_ 접두사 파일이 테스트 파일로 감지된다.z/some/dir/test_anything.pyTrG   r)  r2   arbitrary_testr+  r,  r-  N)r   r   r/  r(   r)   r*   r+   r,   r-   r.   r/   )	r2   rA  r6   r9   r   r1  r2  r   r3  s	            r<   test_arbitrary_test_prefix_filez.TestIsTestFile.test_arbitrary_test_prefix_file  s    :;zz>z&&>&~6>$>6$>>>>6$>>>>>>t>>>t>>>z>>>&>>>>>>~>>>~>>>6>>>$>>>>>>>>rR   c           	         t         dz  }| j                  }|j                  } ||      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}x}x}}y
)uO   test_로 시작하지만 .py가 아닌 파일은 테스트 파일이 아니다.ztest_session_watchdog.shFrG   r)  r2   non_pyr+  r,  r-  Nr.  )	r2   rD  r6   r9   r   r1  r2  r   r3  s	            r<   "test_non_py_test_file_not_detectedz1TestIsTestFile.test_non_py_test_file_not_detected  s    "<<zz7z&&7&v.7%7.%7777.%777777t777t777z777&777777v777v777.777%77777777rR   N)rS   rT   rU   rV   r'  r4  r7  r9  r=  r?  rB  rE  rW   rR   r<   r%  r%    s.    +5:
>
B
;
:
?8rR   r%  )rV   builtinsr*   _pytest.assertion.rewrite	assertionrewriter(   r   rr   r$   ry   r   r   insertr   __file__parentast_dependency_mapr   r   r   r   rJ   r	   rY   ra   r   r   r   r  r%  rW   rR   r<   <module>rN     s     
 
   3tH~,,334 5  56.2 .2l"- "-T:( :(D* *d +  +PD, D,X> >L)8 )8rR   