
    %i-                         U 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 ddlZej                  j                  dd       ddlmZmZ dZg dZee   ed<   g d	Zee   ed
<    ej0                  d      Z ej0                  d      Zd"dededefdZ ej:                  d      defd       Z ej:                  d      dede eef   f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   
test_comparison.py - opendataloader-pdf 파싱 품질 검증 테스트

목적: opendataloader-pdf를 통한 PDF 파싱 품질 데이터 수집.
     키워드 존재, 조항 번호 감지, 특수문자 처리 등을 확인한다.
    N)Anyz/home/jay/workspace/libs)ParseResult	parse_pdfuj   /home/jay/.cokacdir/workspace/autoset/금융소비자_보호에_관한_법률법률제21065호20260102.pdf)u   금융소비자u   금융상품u   금융상품판매업자u   손해배상u   청약철회REQUIRED_KEYWORDS)   「   」u   ㆍ   ·u   ①u   ②u   ③SPECIAL_CHARSu   제\s*\d+\s*조u*   [①②③④⑤⑥⑦⑧⑨⑩]|\b\d+\.\scharwidthreturnc                     | |z  S )N )r   r   s     1/home/jay/workspace/libs/tests/test_comparison.py
_separatorr   4   s    %<    module)scopec                  n    t        t        d      5 } | j                         cddd       S # 1 sw Y   yxY w)uP   테스트 PDF 파일을 바이트로 읽어 반환한다 (모듈 범위 캐싱).rbN)openPDF_PATHread)fs    r   	pdf_bytesr   =   s.     
h	 vvx  s   +4r   c                 x    t        j                         }t        |       }t        j                         |z
  }||dS )u   opendataloader-pdf(parse_pdf) 파싱 결과를 캐싱한다.

    Returns:
        {
            "parse_result": ParseResult,
            "elapsed": float,  # 초 단위
        }
    )parse_resultelapsed)timeperf_counterr   )r   t0resultr   s       r   
odl_resultr#   D   sA     
			B#I.F!B&G  r   c                   x    e Zd ZdZdeeef   ddfdZdeeef   ddfdZdeeef   ddfdZ	deeef   ddfdZ
y)	TestTextExtractionAccuracyu%   항목 1: 텍스트 추출 정확도.r#   r   Nc                 p   |d   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                  |      dz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}x}}y)u+   추출된 텍스트가 비어있지 않다.r   r   >z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} > %(py6)slendl_textpy0py1py3py6u*   opendataloader: 텍스트가 비어 있음
>assert %(py8)spy8N)textr*   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation)selfr#   r+   @py_assert2@py_assert5@py_assert4@py_format7@py_format9s           r   test_text_not_emptyz.TestTextExtractionAccuracy.test_text_not_empty`   s    !.1667|MaM|aMMM|aMMMMMMsMMMsMMMMMM7MMM7MMM|MMMaMMM!MMMMMMMMr   c                    |d   j                   }t                t        t        d             t        d       t        t                      t        D ]  }||v }|rdnd}t        d|dd|          t        t        d             y	)
u?   필수 키워드가 추출된 텍스트에 포함되어 있다.r   =u   [키워드 포함 여부]Ou
   X (누락)  z<20 N)r3   printr   r   )r=   r#   r+   kwdl_foundmarks         r   test_keyword_presencez0TestTextExtractionAccuracy.test_keyword_presencee   s|    !.166jo)*jl# 	(BW}H"3DBr#hav&'	(
 	jor   c                     |d   j                   }d}t                t        t        d             t        d       t        t                      t        d       t        |d|        t        t        d             y)uM   첫 500자 샘플을 출력하여 추출 품질을 육안으로 확인한다.r   i  rE   u   [텍스트 샘플 (첫 500자)]z-- opendataloader-pdf --N)r3   rI   r   )r=   r#   r+   
sample_lens       r   test_text_samplez+TestTextExtractionAccuracy.test_text_sampleu   s_    !.166
jo/0jl()gkz"#jor   c                 D   |d   j                   }t        |      }t                t        t        d             t        d       t        t                      t        d|dd       t        t        d             d}||kD  }|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+   추출된 텍스트 길이를 보고한다.r   rE   u   [텍스트 길이]u'     opendataloader-pdf 텍스트 길이: ,u    문자r   r'   z%(py0)s > %(py3)sdl_lenr-   r/   zassert %(py5)spy5N)r3   r*   rI   r   r4   r5   r6   r7   r8   r9   r;   r<   )r=   r#   r+   rT   r>   @py_assert1@py_format4@py_format6s           r   test_text_length_reportz2TestTextExtractionAccuracy.test_text_length_report   s    !.166Wjo"#jl7qzIJjovzvvvr   )__name__
__module____qualname____doc__dictstrr   rC   rM   rP   rZ   r   r   r   r%   r%   ]   st    /Nd38n N N
S#X 4  4S> d $sCx. T r   r%   c                   *    e Zd ZdZdeeef   ddfdZy)TestTableStructurePreservationu*   항목 2: 표(table) 구조 보존 여부.r#   r   Nc                    |d   j                   }t                t        t        d             t        d       t        t                      t        dt        |              |rt	        |      D ]r  \  }}|j                  dg       }|j                  dg       }t        d| dt        |       d	t        |       d
       t        d|        |sbt        d|d           t nt        d       t        t        d             y)u6   추출한 테이블의 행/열 구조를 출력한다.r   rE   u   [테이블 구조 상세]u     감지된 테이블 수: headersrowsz  Table[z]: u   행 x u   열u       헤더: u       첫 행: r   u     (감지된 테이블 없음)N)tablesrI   r   r*   	enumerateget)r=   r#   	dl_tablesidxtblrd   re   s          r   test_table_structure_detailz:TestTableStructurePreservation.test_table_structure_detail   s    *4^*D*K*K	jo)*jl+C	N+;<=%i0 5S%(WWY%;(+(;ST6#g,sKLWI./M$q'345 23jor   )r[   r\   r]   r^   r_   r`   r   rl   r   r   r   rb   rb      s     4d38n  r   rb   c                   D    e Zd ZdZdeeef   ddfdZdeeef   ddfdZy)TestArticleNumberAccuracyu3   항목 3: 조항 번호 정확성 (제N조 패턴).r#   r   Nc                 
   |d   j                   }t        j                  |      }t                t        t	        d             t        d       t        t	                      t        dt        |              t        t        |      d       }t        dt        |              t        d|d	d
  t        |      d
kD  rdnd        t        t	        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z   d|iz  }	t        t        j                   |	            d	x}x}}y	)uT   감지된 조항(제N조) 수를 출력하고 최소 1개 이상인지 확인한다.r   rE   u   [조항 번호(제N조) 감지]u(     opendataloader-pdf 감지 조항 수: c                 \    t        t        j                  d|       j                               S )Nz\d+)intresearchgroup)xs    r   <lambda>z>TestArticleNumberAccuracy.test_article_count.<locals>.<lambda>   s    #bii288:; r   )keyu     unique 조항 수: u     조항 목록: N   z... r   r'   r)   r*   dl_articlesr,   u>   opendataloader: 조항 번호가 하나도 감지되지 않음r1   r2   )r3   ARTICLE_PATTERNfindallrI   r   r*   sortedsetr4   r5   r6   r7   r8   r9   r:   r;   r<   )
r=   r#   r+   rz   	dl_uniquer>   r?   r@   rA   rB   s
             r   test_article_countz,TestArticleNumberAccuracy.test_article_count   s^   !.166%--g6jo/0jl8[9I8JKL;
	 	%c)n%567	#2/Y"9LRT/UV	
 	jo;e!e!#eee!eeeeeeseeeseeeeee;eee;eeeeee!eee%eeeeeeeer   c                    |d   j                   }t        j                  |      }t                t        t	        d             t        d       t        t	                      t        dt        |              t        t	        d             y)u7   항 번호(① ② ③ 등) 감지 수를 출력한다.r   rE   u   [항 번호(①②③) 감지]u,     opendataloader-pdf 감지 항 번호 수: N)r3   CLAUSE_PATTERNr|   rI   r   r*   )r=   r#   r+   
dl_clausess       r   test_clause_number_countz2TestArticleNumberAccuracy.test_clause_number_count   sg    !.166#++G4
jo./jl<S_<MNOjor   )	r[   r\   r]   r^   r_   r`   r   r   r   r   r   r   rn   rn      s>    =fT#s(^ f f04S> d r   rn   c                   D    e Zd ZdZdeeef   ddfdZdeeef   ddfdZy)TestSpecialCharacterHandlingu6   항목 4: 특수문자(「」, ㆍ 등) 처리 여부.r#   r   Nc                    |d   j                   t                t        t        d             t        d       t        t                      t        dddddd	       t        t        d
d             t        D ]2  }j	                  |      }|dkD  r| dnd}t        d|dd|d	       4 t        fdt        D              }t        t                      t        d| dt        t                      t        t        d             y)uC   각 특수문자의 존재 여부와 등장 횟수를 출력한다.r   rE   u   [특수문자 처리]rG   u   문자z<8rH   u   opendataloader-pdf 횟수z>24-$   r   u   회u	   미발견c              3   ,   K   | ]  }|v sd   yw   Nr   .0chr+   s     r   	<genexpr>zJTestSpecialCharacterHandling.test_special_char_presence.<locals>.<genexpr>        DrbGmD   	u     커버 특수문자: /N)r3   rI   r   r
   countsumr*   )r=   r#   r   dl_countdl_mark
dl_coveredr+   s         @r   test_special_char_presencez7TestSpecialCharacterHandling.test_special_char_presence   s    !.166jo%&jl8B-q!<S ABCjb!" 	0B}}R(H*2Q,
#&KGBrBiq./	0
 D]DD
jl'
|1S5G4HIJjor   c           	      4   |d   j                   }|j                  d      }|j                  d      }t                t        t        d             t        d       t        t                      t        d| d| d||k(          t        t        d             y	)
uO   한글 법령 괄호「」가 온전히 쌍으로 존재하는지 확인한다.r   r   r   rE   u&   [법령 괄호「」쌍 일치 여부]u     opendataloader-pdf - 「:u	   회, 」:u   회, 쌍 일치: N)r3   r   rI   r   )r=   r#   r+   dl_opendl_closes        r    test_unicode_normalization_checkz=TestSpecialCharacterHandling.test_unicode_normalization_check   s    !.166--&=='jo67jl)')H: F"h./1	
 	jor   )	r[   r\   r]   r^   r_   r`   r   r   r   r   r   r   r   r      s;    @T#s(^  *4S> d r   r   c                   *    e Zd ZdZdeeef   ddfdZy)TestProcessingSpeedu   항목 5: 처리 속도.r#   r   Nc                    |d   }|d   j                   j                  dd      }|dkD  r||z  nd}t                t        t        d             t        d       t        t                      t        d	|d
d       t        d| d|dd       t        t        d             d}||kD  }|st	        j
                  d|fd||f      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}}y)u8   파싱 시간을 출력하고 양수인지 확인한다.r   r   
page_countr   r   g        rE   u   [처리 속도]u$     opendataloader-pdf 처리 시간: z.3fu   초u     총 페이지: u   , 페이지당: z.4fr'   rS   
dl_elapsedrU   u,   opendataloader-pdf 처리 시간이 0 이하z
>assert %(py5)srV   N)metadatarh   rI   r   r4   r5   r6   r7   r8   r9   r:   r;   r<   )	r=   r#   r   dl_pagesdl_per_pager>   rW   rX   rY   s	            r   test_parsing_speedz&TestProcessingSpeed.test_parsing_speed  s    &y1
">2;;??aP/7!|j8+jo jl4Z4DCHI!(+;K;LCPQjoMzA~MMMzAMMMMMMzMMMzMMMAMMMMMMMMMMr   )r[   r\   r]   r^   r_   r`   r   r   r   r   r   r   r     s#    "NT#s(^ N Nr   r   c                   *    e Zd ZdZdeeef   ddfdZy)TestSummaryReportu   종합 요약 출력.r#   r   Nc           
      T   |d   j                   |d   j                  }|d   }t        j                        }t	        fdt
        D              }t	        fdt        D              }t                t        t        dd             t        d       t        t        dd             t        dd	d
ddd       t        t        dd             t        ddd
dt              d       dt        t               d}t        d|d
d|d       t        ddd
dt        |      d       t        ddd
dt        t        |            d       t        ddd
d|d       t        ddd
d|d       t        t        dd             t                t              }d}	||	kD  }
|
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 )!uD   모든 항목의 핵심 지표를 한 화면에 요약 출력한다.r   r   c              3   ,   K   | ]  }|v sd   ywr   r   r   s     r   r   z9TestSummaryReport.test_overall_summary.<locals>.<genexpr>8  r   r   c              3   ,   K   | ]  }|v sd   ywr   r   )r   rJ   r+   s     r   r   z9TestSummaryReport.test_overall_summary.<locals>.<genexpr>9  s     C"R7]ACr   rE   <   u2   [ opendataloader-pdf 파싱 품질 종합 요약 ]rG   u   항목z<30rH   zopendataloader-pdfz>20r   u   텍스트 길이 (문자)z>20,u   키워드 검출 (u   개 중)u   감지 테이블 수u   감지 조항 수(제N조)u   특수문자 커버 수u   처리 시간 (초)z>20.3fr   r'   r)   r*   r+   r,   zassert %(py8)sr2   N)r3   rf   r{   r|   r   r
   r   rI   r   r*   r~   r4   r5   r6   r7   r8   r9   r;   r<   )r=   r#   ri   r   rz   
dl_specialdl_kw	kw_headerr>   r?   r@   rA   rB   r+   s                @r   test_overall_summaryz&TestSummaryReport.test_overall_summary1  s    !.166*4^*D*K*K	&y1
%--g6D]DD
C 1CCjb!"BCjb!"8C."6s!;<=jb!".s31S\$4GHI(->)?(@I	9S/5+./)#.aIs/CDE/4Ac#k:J6KC5PQR,S1:c2BCD(-Qz&.ABCjb!"7|a|a|ass77|ar   )r[   r\   r]   r^   r_   r`   r   r   r   r   r   r   r   .  s      tCH~  $  r   r   )r   r   )(r^   builtinsr6   _pytest.assertion.rewrite	assertionrewriter4   rr   sysr   typingr   pytestpathinsert
doc_parserr   r   r   r   listr`   __annotations__r
   compiler{   r   rq   r   fixturebytesr   r_   r#   r%   rb   rn   r   r   r   r   r   r   <module>r      sA    	 
    - . -K 	  49  LtCy K "**/0 IJS s C  h5    h% DcN   02 2t @& &\' '^N N4   r   