
    >Ji                          d Z ddlZddlmZ ddlZdZeej                  vrej                  j                  de       dZej                  de
fd       Z G d d	      Z G d
 d      Z G d d      Z G d d      Zy)u  
테스트: ai_parser.py — Docling fallback 및 유틸리티 함수 검증

테스트 항목
-----------
1. extract_text_from_pdf()가 정상 PDF bytes에서 텍스트를 추출한다 (Docling 경로)
2. Docling 실패 시 pdfplumber로 fallback하여 텍스트를 추출한다
3. _table_to_markdown()이 테이블 딕셔너리를 올바른 마크다운으로 변환한다
4. 빈 bytes 입력 시 적절한 예외 발생
    N)patchz /home/jay/projects/InsuRo/serveruj   /home/jay/.cokacdir/workspace/autoset/금융소비자_보호에_관한_법률법률제21065호20260102.pdfreturnc                  n    t        t        d      5 } | j                         cddd       S # 1 sw Y   yxY w)u6   실제 PDF 파일을 바이트로 읽어 반환한다.rbN)openTEST_PDF_PATHread)fs    9/home/jay/workspace/libs/tests/test_ai_parser_fallback.py	pdf_bytesr      s.     
mT	" avvx  s   +4c                   ,    e Zd ZdeddfdZdeddfdZy)TestExtractTextFromPdfDoclingr   r   Nc                 d    ddl m}  ||      }t        |t              sJ t	        |      dkD  sJ y)u`   extract_text_from_pdf()가 정상 PDF bytes에서 비어있지 않은 텍스트를 반환한다.r   extract_text_from_pdfN)	ai_parserr   
isinstancestrlenselfr   r   results       r   test_returns_nonempty_stringz:TestExtractTextFromPdfDocling.test_returns_nonempty_string(   s/    3&y1&#&&&6{Q    c                 R    ddl m}  ||      }t        d |D              sJ d       y)uO   추출된 텍스트가 한국어 문자를 포함한다 (금소법 PDF 특성).r   r   c              3   <   K   | ]  }d |cxk  xr dk  nc   yw)u   가u   힣N ).0chs     r   	<genexpr>zQTestExtractTextFromPdfDocling.test_result_contains_korean_text.<locals>.<genexpr>6   s"      
+-H&h&&
s   u8   추출된 텍스트에 한국어 문자가 없습니다.N)r   r   anyr   s       r    test_result_contains_korean_textz>TestExtractTextFromPdfDocling.test_result_contains_korean_text0   s8    3&y1 
17
 
 	FE	F 
r   )__name__
__module____qualname__bytesr   r"   r   r   r   r   r   '   s+    e  F% FD Fr   r   c                   <    e Zd ZdeddfdZdeddfdZdeddfdZy)TestExtractTextFromPdfFallbackr   r   Nc                     ddl m} t        dt        d            5   ||      }ddd       t	        t
              sJ t        |      dkD  sJ y# 1 sw Y   ,xY w)uc   doc_parser.parse_pdf가 예외를 던지면 pdfplumber로 fallback하여 텍스트를 반환한다.r   r   ai_parser.parse_pdfu   Docling 모의 실패side_effectN)r   r   r   RuntimeErrorr   r   r   r   s       r   0test_fallback_to_pdfplumber_on_docling_exceptionzOTestExtractTextFromPdfFallback.test_fallback_to_pdfplumber_on_docling_exception?   s]     	4!|<S/T
 	6 +95F	6
 &#&&&6{Q	6 	6s   	AAc                     ddl m} t        dt        d            5   ||      }ddd       t	        j                               dkD  sJ y# 1 sw Y   (xY w)uF   pdfplumber fallback 결과도 의미 있는 텍스트를 포함한다.r   r   r*   u   Docling 임의 오류r+   N)r   r   r   	Exceptionr   stripr   s       r   "test_fallback_result_contains_textzATestExtractTextFromPdfFallback.test_fallback_result_contains_textM   sP    3(i@W6XY 	6*95F	6 6<<>"Q&&&	6 	6s   	AAc                     ddl m} t        dt        d            5   ||      }ddd       t	        t
              sJ y# 1 sw Y   xY w)uI   parse_pdf가 ValueError를 던져도 pdfplumber fallback이 동작한다.r   r   r*   u   잘못된 입력 (모의)r+   N)r   r   r   
ValueErrorr   r   r   s       r   test_fallback_on_value_errorz;TestExtractTextFromPdfFallback.test_fallback_on_value_errorV   sG    3(jA\6]^ 	6*95F	6 &#&&&	6 	6s   	AA
)r#   r$   r%   r&   r.   r2   r5   r   r   r   r(   r(   >   s=    	'E 'd ''e ' 'r   r(   c                   <    e Zd ZddZddZddZddZddZddZy)	TestTableToMarkdownNc                 x    ddl m} g dg dg dgd} ||d      }d|v sJ d	|v sJ d
|v sJ d|v sJ d|v sJ y)uO   헤더와 행이 있는 테이블을 올바른 마크다운으로 변환한다.r   _table_to_markdown)u   이름u   나이u   직업)u	   홍길동30u	   개발자)u	   김철수25u   디자이너headersrows   u	   ### 표 1u   | 이름 | 나이 | 직업 |z|---|---|---|u   | 홍길동 | 30 | 개발자 |u!   | 김철수 | 25 | 디자이너 |Nr   r:   r   r:   tabler   s       r   test_basic_table_structurez.TestTableToMarkdown.test_basic_table_structured   sp    0 603
 $E1-f$$$-777&(((/69992f<<<r   c                    ddl m} ddgddggd} ||d      }|j                         j                         }t	        d	 |D        d
      }|j                  d      sJ |j                  d      sJ |j                  d      dk(  sJ y)u7   구분선의 열 수가 헤더 열 수와 일치한다.r   r9   AB12r=      c              3   N   K   | ]  }|j                  d       sd|v s|  yw)|---N)
startswith)r   lines     r   r    zGTestTableToMarkdown.test_separator_line_column_count.<locals>.<genexpr>   s!     Ndts';TNs   %%% rL   rM   N)r   r:   r1   
splitlinesnextrN   endswithcount)r   r:   rC   r   lines	separators         r    test_separator_line_column_countz4TestTableToMarkdown.test_separator_line_column_countw   s    0 Sz3ZL
 $E1-))+NeNPR
	 ##C(((!!#&&&u%***r   c                 @    ddl m} g ddggd} ||d      }|dk(  sJ y)	u2   헤더가 없으면 빈 문자열을 반환한다.r   r9   rH   rI   r=   r@   rP   NrA   rB   s       r   'test_empty_headers_returns_empty_stringz;TestTableToMarkdown.test_empty_headers_returns_empty_string   s-    0"$Szl;#E1-||r   c                     ddl m} g ddggd} ||d      }|j                         D cg c]  }|j                  d      s| }}t	        |      dk(  sJ |d   j                  d	      d
k(  sJ yc c}w )uH   행의 열 수가 헤더보다 적을 때 빈 문자열로 패딩된다.r   r9   )rF   rG   CrH   r=      z| 1r@   rL      N)r   r:   rQ   rN   r   rT   )r   r:   rC   r   rO   	data_lines         r   *test_row_padding_when_shorter_than_headersz>TestTableToMarkdown.test_row_padding_when_shorter_than_headers   s    0 'UG
 $E1- '-&7&7&9TdT__U=STT	T9~"""|!!#&!+++ Us   A2A2c                 X    ddl m} dgg d} ||d      } ||d      }d|v sJ d|v sJ y	)
uE   테이블 번호가 마크다운 헤더에 올바르게 표시된다.r   r9   Xr=      
   u	   ### 표 5u
   ### 표 10NrA   )r   r:   rC   result_5	result_10s        r   test_table_index_in_headerz.TestTableToMarkdown.test_table_index_in_header   sE    0 E2.%eQ/&ub1	h&&&y(((r   c                 H    ddl m} ddgg d} ||d      }d|v sJ d|v sJ y	)
u5   행이 없어도 헤더와 구분선은 출력된다.r   r9   u   컬럼1u   컬럼2r=   r@   u   | 컬럼1 | 컬럼2 |z	|---|---|NrA   rB   s       r   test_no_rows_only_headerz,TestTableToMarkdown.test_no_rows_only_header   s<    0&	2B?#E1-&&000f$$$r   r   N)	r#   r$   r%   rD   rW   rY   r_   rf   rh   r   r   r   r7   r7   c   s     =&+&,	)%r   r7   c                       e Zd ZddZddZy)TestEmptyBytesRaisesExceptionNc                 |    ddl m} t        j                  t              5   |d       ddd       y# 1 sw Y   yxY w)uF   빈 bytes를 입력하면 적절한 예외(Exception)가 발생한다.r   r   r   N)r   r   pytestraisesr0   )r   r   s     r   test_empty_bytes_raisesz5TestEmptyBytesRaisesException.test_empty_bytes_raises   s.    3]]9% 	'!#&	' 	' 	's   	2;c                 Z    ddl m} d}	  |d       |sJ d       y# t        $ r d}Y w xY w)uZ   빈 bytes 입력 시 문자열이 반환되지 않고 예외가 발생함을 확인한다.r   r   Fr   Tu6   빈 bytes 입력 시 예외가 발생해야 합니다.N)r   r   r0   )r   r   raiseds      r   #test_empty_bytes_not_returns_stringzATestEmptyBytesRaisesException.test_empty_bytes_not_returns_string   s=    3	!#& OOOv  	F	s    **ri   )r#   r$   r%   ro   rr   r   r   r   rk   rk      s    '
Pr   rk   )__doc__sysunittest.mockr   rm   _SERVER_PATHpathinsertr   fixturer&   r   r   r(   r7   rk   r   r   r   <module>rz      s   	    2sxxHHOOA|$K  5  F F.' 'JR% R%pP Pr   