
    践id                        U d Z ddlZddlmc mZ ddlZddlm	Z	 ddl
mZ ddlmZ ddlmZmZ ddlZej$                  j'                  d e e	e      j,                  j,                               dZee   ed<   	 ddlZedu Zej8                  j;                  ed	      Zd
ZdZ dZ!dZ"dZ#dZ$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# e$ r Y w xY w)!u  
TDD RED 단계: test_insurance_crawler.py

보험사 공개 데이터 크롤러 InsuranceCrawler 클래스에 대한 테스트 스위트.
(insurance_crawler.py는 아직 구현되지 않음 - TDD RED 단계)

주의:
- 모든 테스트는 로컬 HTML 문자열로 수행. 외부 네트워크 호출 없음.
- 실제 보험사 사이트 크롤링은 robots.txt를 반드시 확인하고 준수해야 합니다.
- 합법적 공개 데이터만 대상으로 합니다.
    N)Path)
ModuleType)Optional)	MagicMockpatch_insurance_crawleruI   insurance_crawler.py 미구현 (TDD RED 단계 - 토르가 구현 예정))reasonuv  
<html>
<body>
  <div class="product">
    <span class="name">화재보험</span>
    <span class="price">50000</span>
  </div>
  <div class="product">
    <span class="name">자동차보험</span>
    <span class="price">100000</span>
  </div>
  <div class="product">
    <span class="name">생명보험</span>
    <span class="price">30000</span>
  </div>
</body>
</html>
u   
<html>
<body>
  <table>
    <tr><th>보험명</th><th>보험료</th><th>가입기간</th></tr>
    <tr><td>화재보험</td><td>50000</td><td>1년</td></tr>
    <tr><td>자동차보험</td><td>100000</td><td>1년</td></tr>
  </table>
</body>
</html>
u   
<html>
<body>
  <table>
    <tr><td>화재보험</td><td>50000</td></tr>
    <tr><td>자동차보험</td><td>100000</td></tr>
  </table>
</body>
</html>
z1
<html>
<body>
  <table></table>
</body>
</html>
u   
<html>
<body>
  <script>alert('xss');</script>
  <p>보험 공시 정보</p>
  <div class="product"><span class="name">화재보험</span></div>
</body>
</html>
u.   <html><body><p>보험 정보</p></body></html> c                   X    e Zd ZdZedd       Zedd       Zedd       Zedd       Zy)TestInsuranceCrawlerInitu%   InsuranceCrawler 초기화 테스트.Nc                 $   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                         }|j                  }d}||u }|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)u=   기본 생성 시 adaptive=True로 초기화되어야 한다.Nis notz%(py0)s is not %(py3)sr   py0py3assert %(py5)spy5Tisz0%(py2)s
{%(py2)s = %(py0)s.adaptive
} is %(py5)scrawlerr   py2r   assert %(py7)spy7r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationInsuranceCrawleradaptive	self@py_assert2@py_assert1@py_format4@py_format6r   @py_assert4@py_assert3@py_format8s	            ;/home/jay/workspace/scripts/tests/test_insurance_crawler.pytest_default_init_adaptive_truez8TestInsuranceCrawlerInit.test_default_init_adaptive_truer   s     *.-!----!------!---!----------$557'4'4''''4''''''w'''w''''''4'''''''    c                    d}t         |u}|st        j                  d|fdt         |f      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}}dd	l	m
} d
dg}t        j                  |      }|j                  }d}||u}	|	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}	}|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t        j                  |      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            dx}}y)uS   프록시 리스트 전달 시 ProxyRotator 인스턴스가 생성되어야 한다.Nr   r   r   r   r   r   r   )ProxyRotatorzhttp://proxy1:8080zhttp://proxy2:8080)
proxy_list)z9%(py2)s
{%(py2)s = %(py0)s.proxy_rotator
} is not %(py5)sr   r   r   r   zXassert %(py6)s
{%(py6)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.proxy_rotator
}, %(py4)s)
}
isinstancer6   )r   py1r   py4py6)r   r   r    r!   r"   r#   r$   r%   r&   crawl_utilsr6   r'   proxy_rotatorr8   )r*   r+   r,   r-   r.   r6   r7   r   r/   r0   r1   @py_assert5@py_format7s                r2   test_init_with_proxy_listz2TestInsuranceCrawlerInit.test_init_with_proxy_listy   s    *.-!----!------!---!----------,*,@A
$55L$$0D0$D0000$D000000w000w000$000D0000000!//>z/>>>>>>>>z>>>z>>>>>>'>>>'>>>/>>>>>>>>>>>>>>>>>>>r4   c                 $   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                         }|j                  }d}||u }|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)u:   프록시 없으면 proxy_rotator는 None이어야 한다.Nr   r   r   r   r   r   r   )z5%(py2)s
{%(py2)s = %(py0)s.proxy_rotator
} is %(py5)sr   r   r   r   )r   r   r    r!   r"   r#   r$   r%   r&   r'   r=   r)   s	            r2   test_init_without_proxyz0TestInsuranceCrawlerInit.test_init_without_proxy   s     *.-!----!------!---!----------$557$$,,$,,,,$,,,,,,w,,,w,,,$,,,,,,,,,,r4   c                 (   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  }d}||u }|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)u@   adaptive=False 전달 시 adaptive 속성이 False여야 한다.Nr   r   r   r   r   r   Fr(   r   r   r   r   r   r   r   r)   s	            r2   test_init_adaptive_falsez1TestInsuranceCrawlerInit.test_init_adaptive_false   s     *.-!----!------!---!----------$55uE(5(5((((5((((((w(((w((((((5(((((((r4   returnN)	__name__
__module____qualname____doc___skip_if_missingr3   r@   rB   rE    r4   r2   r   r   o   sS    /( ( ? ? - - ) )r4   r   c                   X    e Zd ZdZedd       Zedd       Zedd       Zedd       Zy)TestInsuranceCrawlerParseu-   InsuranceCrawler.parse() 메서드 테스트.Nc                    d}t         |u}|st        j                  d|fdt         |f      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}}dd	l	m
} t        j                         }|j                  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
                  |      rt        j                  |      ndt        j                  |      dz  }	t        t        j                  |	            d}y)u8   parse()가 Selector 인스턴스를 반환해야 한다.Nr   r   r   r   r   r   r   Selector5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}r8   resultrR   r   r9   r   r:   )r   r   r    r!   r"   r#   r$   r%   r&   scrapling.parserrR   r'   parseHTML_SIMPLEr8   )
r*   r+   r,   r-   r.   rR   r   rT   r0   @py_format5s
             r2   test_parse_returns_selectorz5TestInsuranceCrawlerParse.test_parse_returns_selector   s    *.-!----!------!---!-----------$557{+&(++++++++z+++z++++++&+++&++++++(+++(++++++++++r4   c                    d}t         |u}|st        j                  d|fdt         |f      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}}dd	l	m
} t        j                         }d
}|j                  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
                  |      rt        j                  |      ndt        j                  |	      dz  }
t        t        j                  |
            d}	|j                  }||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j
                  |      rt        j                  |      nd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)u1   url 인자가 Selector에 전달되어야 한다.Nr   r   r   r   r   r   r   rQ   zhttps://example-insurance.co.krurlrS   r8   rT   rR   rU   ==)z+%(py2)s
{%(py2)s = %(py0)s.url
} == %(py4)sr]   )r   r   r:   assert %(py6)sr;   )r   r   r    r!   r"   r#   r$   r%   r&   rV   rR   r'   rW   rX   r8   r]   )r*   r+   r,   r-   r.   rR   r   r]   rT   r0   rY   r?   s               r2   test_parse_with_urlz-TestInsuranceCrawlerParse.test_parse_with_url   s    *.-!----!------!---!-----------$557/{4&(++++++++z+++z++++++&+++&++++++(+++(++++++++++zz zS    zS      v   v   z      S   S       r4   c                    d}t         |u}|st        j                  d|fdt         |f      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}}dd	l	m
} t        j                  d
      }|j                  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
                  |      rt        j                  |      ndt        j                  |      dz  }	t        t        j                  |	            d}|j                  }d
}
||
u }|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)uc   adaptive=True인 crawler로 parse()하면 Selector가 adaptive 설정으로 생성되어야 한다.Nr   r   r   r   r   r   r   rQ   TrD   rS   r8   rT   rR   rU   r   zC%(py2)s
{%(py2)s = %(py0)s._Selector__adaptive_enabled
} is %(py5)sr   r   r   r   r   r    r!   r"   r#   r$   r%   r&   rV   rR   r'   rW   rX   r8   _Selector__adaptive_enabledr*   r+   r,   r-   r.   rR   r   rT   r0   rY   r/   r1   s               r2   test_parse_adaptive_modez2TestInsuranceCrawlerParse.test_parse_adaptive_mode   s|    *.-!----!------!---!-----------$55tD{+&(++++++++z+++z++++++&+++&++++++(+++(++++++++++119T91T99991T999999v999v9991999T9999999r4   c                    d}t         |u}|st        j                  d|fdt         |f      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}}dd	l	m
} t        j                  d
      }|j                  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
                  |      rt        j                  |      ndt        j                  |      dz  }	t        t        j                  |	            d}|j                  }d
}
||
u }|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)uV   adaptive=False인 crawler로 parse()하면 Selector의 adaptive가 False여야 한다.Nr   r   r   r   r   r   r   rQ   FrD   rS   r8   rT   rR   rU   r   rc   r   r   r   rd   rf   s               r2   test_parse_non_adaptive_modez6TestInsuranceCrawlerParse.test_parse_non_adaptive_mode   s|    *.-!----!------!---!-----------$55uE{+&(++++++++z+++z++++++&+++&++++++(+++(++++++++++11:U:1U::::1U::::::v:::v:::1:::U:::::::r4   rF   )	rH   rI   rJ   rK   rL   rZ   ra   rg   ri   rM   r4   r2   rO   rO      sS    7, , 
! 
! 	: 	: ; ;r4   rO   c                   |    e Zd ZdZed	d       Zed	d       Zed	d       Zed	d       Zed	d       Z	ed	d       Z
y)
TestExtractWithSelectoru=   InsuranceCrawler.extract_with_selector() 메서드 테스트.Nc                 j
   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |d
d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}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   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}}|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}}|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}}|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)(uH   CSS 셀렉터로 name, price 필드를 올바르게 추출해야 한다.Nr   r   r   r   r   r   FrD   .product.name.pricenamepricecss_selectorfieldsrS   r8   rT   listrU      r^   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenr   r9   r   r;   assert %(py8)spy8r   rq      화재보험z%(py1)s == %(py4)sr9   r:   r`   r;   rr   50000      자동차보험      생명보험r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   HTML_PRODUCTSextract_with_selectorr8   rv   ry   r*   r+   r,   r-   r.   r   pagerT   r0   rY   r>   r/   r?   @py_format9@py_assert0s                  r2   test_extract_basic_fieldsz1TestExtractWithSelector.test_extract_basic_fields   s    *.-!----!------!---!----------$55uE}}]+..##h7 / 

 &$''''''''z'''z''''''&'''&''''''$'''$''''''''''6{a{a{ass66{aay 2N2 N2222 N222 222N2222222ay!,W,!W,,,,!W,,,!,,,W,,,,,,,ay 5$55 $55555 $5555 555$55555555ay 2N2 N2222 N222 222N2222222r4   c                 <   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |d
ddi      }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)uG   매칭 없는 CSS 셀렉터이면 빈 리스트를 반환해야 한다.Nr   r   r   r   r   r   FrD   .nonexistentrq   rn   rs   r^   z%(py0)s == %(py3)srT   )r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   r   r   r*   r+   r,   r-   r.   r   r   rT   s           r2   test_extract_empty_selectorz3TestExtractWithSelector.test_extract_empty_selector   s     *.-!----!------!---!----------$55uE}}]+..'G$ / 

 v|vvvr4   c                    d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  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}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 ]  }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)uQ   fields=None이면 컨테이너의 텍스트를 'text' 키로 추출해야 한다.Nr   r   r   r   r   r   FrD   rm   rs   rS   r8   rT   rv   rU   rw   r^   rx   ry   rz   r{   r|   textinz%(py1)s in %(py3)sitemr9   r   r   )r*   r+   r,   r-   r.   r   r   rT   r0   rY   r>   r/   r?   r   r   r   s                   r2   test_extract_no_fieldsz.TestExtractWithSelector.test_extract_no_fields   s    *.-!----!------!---!----------$55uE}}]+..# / 

 &$''''''''z'''z''''''&'''&''''''$'''$''''''''''6{a{a{ass66{a 	"D!6T>!!!6T!!!6!!!!!!T!!!T!!!!!!!	"r4   c                 R   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |d
dddi      }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}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)ub   identifier 전달 시 예외 없이 실행되고 결과를 반환해야 한다 (auto_save 동작).Nr   r   r   r   r   r   FrD   rm   test_product_listrq   rn   rt   
identifierru   rS   r8   rT   rv   rU   rw   r^   rx   ry   rz   r{   r|   r   r*   r+   r,   r-   r.   r   r   rT   r0   rY   r>   r/   r?   r   s                 r2   test_extract_with_identifierz4TestExtractWithSelector.test_extract_with_identifier  s    *.-!----!------!---!----------$55uE}}]+..#*G$	 / 
 &$''''''''z'''z''''''&'''&''''''$'''$''''''''''6{a{a{ass66{ar4   c                    d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |d
d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   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}}|d   d   }d}||u }|slt        j                  d|fd ||f      t        j                  |      t        j                  |      dz  }dd|iz  }
t        t        j                  |
            dx}x}}y)!uU   일부 필드 서브셀렉터가 없으면 해당 값은 None으로 채워야 한다.Nr   r   r   r   r   r   FrD   rm   rn   z.nonexistent-category)rq   categoryrs   rw   r^   rx   ry   rT   rz   r{   r|   r   rq   r}   r~   r   r`   r;   r   r   z%(py1)s is %(py4)s)r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   r   r   ry   )r*   r+   r,   r-   r.   r   r   rT   r>   r/   r?   r   r   r0   rY   s                  r2   test_extract_partial_fieldsz3TestExtractWithSelector.test_extract_partial_fields  s    *.-!----!------!---!----------$55uE}}]+..##1HI / 

 6{a{a{ass66{aay 2N2 N2222 N222 222N2222222ay$,,$,,,,$,,,$,,,,,,,,,,r4   c                    d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |d
ddi      }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/   반환값은 list[dict] 타입이어야 한다.Nr   r   r   r   r   r   FrD   rm   rq   rn   rs   rS   r8   rT   rv   rU   r   dict)r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   r   r   r8   rv   r   )r*   r+   r,   r-   r.   r   r   rT   r0   rY   r   s              r2   "test_extract_returns_list_of_dictsz:TestExtractWithSelector.test_extract_returns_list_of_dicts!  s    *.-!----!------!---!----------$55uE}}]+..#G$ / 

 &$''''''''z'''z''''''&'''&''''''$'''$'''''''''' 	*DdD)))))))):))):))))))d)))d))))))D)))D))))))))))	*r4   rF   )rH   rI   rJ   rK   rL   r   r   r   r   r   r   rM   r4   r2   rk   rk      s{    G3 3" 
 
 " "      - - * *r4   rk   c                   X    e Zd ZdZedd       Zedd       Zedd       Zedd       Zy)TestExtractSimilaru7   InsuranceCrawler.extract_similar() 메서드 테스트.Nc                 J   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  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}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)uJ   유사 구조 요소들을 모두 찾아 리스트를 반환해야 한다.Nr   r   r   r   r   r   FrD   rm   reference_selectorrS   r8   rT   rv   rU   r   )>=)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)sry   rz   r{   r|   )r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   r   extract_similarr8   rv   ry   r   s                 r2   test_find_similar_basicz*TestExtractSimilar.test_find_similar_basic9  s    *.-!----!------!---!----------$55uE}}]+(() ) 
 &$''''''''z'''z''''''&'''&''''''$'''$''''''''''6{a{a{ass66{ar4   c                    d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |d
d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}|D ]M  }
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}}P y)uI   필드 매핑 적용 시 각 항목에 필드 키가 존재해야 한다.Nr   r   r   r   r   r   FrD   rm   rn   ro   rp   )r   ru   rS   r8   rT   rv   rU   rq   r   r   r   r   rr   r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   r   r   r8   rv   )r*   r+   r,   r-   r.   r   r   rT   r0   rY   r   r   s               r2   test_find_similar_with_fieldsz0TestExtractSimilar.test_find_similar_with_fieldsG  s    *.-!----!------!---!----------$55uE}}]+(()#h7 ) 

 &$''''''''z'''z''''''&'''&''''''$'''$'''''''''' 	#D!6T>!!!6T!!!6!!!!!!T!!!T!!!!!!!"7d?"""7d"""7""""""d"""d"""""""	#r4   c                 6   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |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)uP   기준 셀렉터가 매칭되지 않으면 빈 리스트를 반환해야 한다.Nr   r   r   r   r   r   FrD   z.nonexistent-elementr   r^   r   rT   )r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   r   r   r   s           r2   test_find_similar_no_matchz-TestExtractSimilar.test_find_similar_no_matchW  s     *.-!----!------!---!----------$55uE}}]+((5 ) 
 v|vvvr4   c                    d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  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}|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)uH   임계값 인자가 정상적으로 전달되어 실행되어야 한다.Nr   r   r   r   r   r   FrD   rm   g        )r   	thresholdrS   r8   result_looserv   rU   g?result_strictr   )r*   r+   r,   r-   r.   r   r   r   r0   rY   r   s              r2   test_find_similar_thresholdz.TestExtractSimilar.test_find_similar_thresholdc  s    *.-!----!------!---!----------$55uE}}]+..) / 

 ,--------z---z------,---,-------------------//) 0 

 -........z...z......-...-...................r4   rF   )	rH   rI   rJ   rK   rL   r   r   r   r   rM   r4   r2   r   r   6  sS    A    # # 	 	 / /r4   r   c                   j    e Zd ZdZedd       Zedd       Zedd       Zedd       Zedd       Z	y)	TestExtractTableu5   InsuranceCrawler.extract_table() 메서드 테스트.Nc                 ^
   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |      }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}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   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}}|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}}|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}}|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\   기본 테이블 추출: th 헤더 + td 데이터가 딕셔너리로 변환되어야 한다.Nr   r   r   r   r   r   FrD   rS   r8   rT   rv   rU   r   r^   rx   ry   rz   r{   r|   r   u	   보험명r}   r~   r   r`   r;   u	   보험료r   u   가입기간u   1년r   r   )r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   
HTML_TABLEextract_tabler8   rv   ry   r   s                  r2   test_extract_table_basicz)TestExtractTable.test_extract_table_basic  s    *.-!----!------!---!----------$55uE}}Z(&&t,&$''''''''z'''z''''''&'''&''''''$'''$''''''''''6{a{a{ass66{aay%77%7777%777%7777777777ay%00%0000%000%0000000000ay(2F2(F2222(F222(222F2222222ay%:)::%):::::%)::::%:::)::::::::r4   c                 N
   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |      }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}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}|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   }||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}}|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)!uJ   헤더(th) 없으면 col_0, col_1... 형태로 자동 명명해야 한다.Nr   r   r   r   r   r   FrD   rS   r8   rT   rv   rU   r   r^   rx   ry   rz   r{   r|   col_0r   r   )z%(py1)s in %(py4)sr   r`   r;   col_1r}   r~   r   )r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   HTML_TABLE_NO_HEADERr   r8   rv   ry   r   s                  r2   test_extract_table_no_headerz-TestExtractTable.test_extract_table_no_header  s    *.-!----!------!---!----------$55uE}}12&&t,&$''''''''z'''z''''''&'''&''''''$'''$''''''''''6{a{a{ass66{a#&)#w)####w)###w###)########&)#w)####w)###w###)#######ay!3^3!^3333!^333!333^3333333ay!,W,!W,,,,!W,,,!,,,W,,,,,,,r4   c                 2   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |      }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)u9   빈 테이블이면 빈 리스트를 반환해야 한다.Nr   r   r   r   r   r   FrD   r^   r   rT   )r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   HTML_EMPTY_TABLEr   r   s           r2   test_extract_table_emptyz)TestExtractTable.test_extract_table_empty  s     *.-!----!------!---!----------$55uE}}-.&&t,v|vvvr4   c                 R   d}t         |u}|st        j                  d|fdt         |f      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}}d}t        j                  d	
      }|j                  |      }|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}	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   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}}	|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\   커스텀 table_selector를 사용하여 특정 테이블을 선택할 수 있어야 한다.Nr   r   r   r   r   r   u   <html><body>
        <table id="insurance-table">
          <tr><th>상품명</th><th>월납입료</th></tr>
          <tr><td>종신보험</td><td>200000</td></tr>
        </table>
        </body></html>FrD   z#insurance-table)table_selectorrS   r8   rT   rv   rU   r   r^   rx   ry   rz   r{   r|   r   u	   상품명u   종신보험r~   r   r`   r;   u   월납입료200000)r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   r   r8   rv   ry   )r*   r+   r,   r-   r.   htmlr   r   rT   r0   rY   r>   r/   r?   r   r   s                   r2   #test_extract_table_custom_selectorsz4TestExtractTable.test_extract_table_custom_selectors  s^    *.-!----!------!---!---------- %55uE}}T"&&t<N&O&$''''''''z'''z''''''&'''&''''''$'''$''''''''''6{a{a{ass66{aay%77%7777%777%7777777777ay(4H4(H4444(H444(444H4444444r4   c                 2   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t              }|j                  |      }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)u\   테이블이 없는 HTML에서 extract_table() 호출 시 빈 리스트 반환해야 한다.Nr   r   r   r   r   r   FrD   r^   r   rT   )r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   rX   r   r   s           r2   )test_extract_table_no_table_returns_emptyz:TestExtractTable.test_extract_table_no_table_returns_empty  s     *.-!----!------!---!----------$55uE}}[)&&t,v|vvvr4   rF   )
rH   rI   rJ   rK   rL   r   r   r   r   r   rM   r4   r2   r   r   ~  sg    ?; ; - -   5 5"  r4   r   c                   j    e Zd ZdZedd       Zedd       Zedd       Zedd       Zedd       Z	y)	TestToLlmInputu4   InsuranceCrawler.to_llm_input() 메서드 테스트.Nc                 B   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                         }|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}	|	|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)uI   HTML을 마크다운으로 변환하고 문자열을 반환해야 한다.Nr   r   r   r   r   r   u   <p>보험 공시 정보</p>rS   r8   rT   strrU      보험 공시 정보r   r   r   )r   r   r    r!   r"   r#   r$   r%   r&   r'   to_llm_inputr8   r   )
r*   r+   r,   r-   r.   r   rT   r0   rY   r   s
             r2   test_to_llm_input_basicz&TestToLlmInput.test_to_llm_input_basic  sd    *.-!----!------!---!----------$557%%&CD&#&&&&&&&&z&&&z&&&&&&&&&&&&&&&&&#&&&#&&&&&&&&&&%/%////%///%////////////////r4   c                 T   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                         }|j                  t              }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)uE   script 태그가 제거되어야 한다 (clean_html 파이프라인).Nr   r   r   r   r   r   alert)not in)z%(py1)s not in %(py3)srT   r   xssr   r   r    r!   r"   r#   r$   r%   r&   r'   r   HTML_WITH_SCRIPTr*   r+   r,   r-   r.   r   rT   r   s           r2    test_to_llm_input_removes_scriptz/TestToLlmInput.test_to_llm_input_removes_script  s2    *.-!----!------!---!----------$557%%&67$wf$$$$wf$$$w$$$$$$f$$$f$$$$$$$"uF""""uF"""u""""""F"""F"""""""r4   c                 
   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                         }|j                  t              }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)u5   텍스트 내용은 결과에 보존되어야 한다.Nr   r   r   r   r   r   r   r   r   rT   r   r   r   s           r2    test_to_llm_input_preserves_textz/TestToLlmInput.test_to_llm_input_preserves_text  s     *.-!----!------!---!----------$557%%&67%/%////%///%////////////////r4   c                    d}t         |u}|st        j                  d|fdt         |f      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}}t        j                         }|j                  t              }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                  } |       }d}	||	k(  }
|
st        j                  d|
fd||	f      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)uN   빈 HTML 입력 시 빈 문자열 또는 최소한 str을 반환해야 한다.Nr   r   r   r   r   r   rS   r8   rT   r   rU   r
   r^   )zD%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.strip
}()
} == %(py7)s)r   r   r:   r   zassert %(py9)spy9)r   r   r    r!   r"   r#   r$   r%   r&   r'   r   
HTML_EMPTYr8   r   strip)r*   r+   r,   r-   r.   r   rT   r0   rY   @py_assert6r>   r1   @py_format10s                r2   test_to_llm_input_emptyz&TestToLlmInput.test_to_llm_input_empty  s    *.-!----!------!---!----------$557%%j1&#&&&&&&&&z&&&z&&&&&&&&&&&&&&&&&#&&&#&&&&&&&&&&||#|~##~####~######v###v###|###~##########r4   c                     d}t         |u}|st        j                  d|fdt         |f      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}}t        j                         }|j                  t              }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)u2   반환값은 반드시 str 타입이어야 한다.Nr   r   r   r   r   r   rS   r8   rT   r   rU   )r   r   r    r!   r"   r#   r$   r%   r&   r'   r   rX   r8   r   )	r*   r+   r,   r-   r.   r   rT   r0   rY   s	            r2    test_to_llm_input_returns_stringz/TestToLlmInput.test_to_llm_input_returns_string  s    *.-!----!------!---!----------$557%%k2&#&&&&&&&&z&&&z&&&&&&&&&&&&&&&&&#&&&#&&&&&&&&&&r4   rF   )
rH   rI   rJ   rK   rL   r   r   r   r   r   rM   r4   r2   r   r     sg    >0 0 # # 0 0 $ $ ' 'r4   r   c                   F    e Zd ZdZedd       Zedd       Zedd       Zy)TestExtractFieldsuE   InsuranceCrawler._extract_fields() 내부 헬퍼 메서드 테스트.Nc                 z   d}t         |u}|st        j                  d|fdt         |f      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}}dd	l	m
} t        j                  d
      } |t        d
      }|j                  d      }|j                  |d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}
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   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}}
|	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^   기본 필드 추출: elements에서 fields 매핑에 따라 데이터를 추출해야 한다.Nr   r   r   r   r   r   r   rQ   FrD   rm   rn   ro   rp   rS   r8   rT   rv   rU   rw   r^   rx   ry   rz   r{   r|   rq   r}   r~   r   r`   r;   rr   r   )r   r   r    r!   r"   r#   r$   r%   r&   rV   rR   r'   r   css_extract_fieldsr8   rv   ry   )r*   r+   r,   r-   r.   rR   r   r   elementsrT   r0   rY   r>   r/   r?   r   r   s                    r2   test_extract_fields_basicz+TestExtractFields.test_extract_fields_basic  se    *.-!----!------!---!-----------$55uE688J'((Gh3WX&$''''''''z'''z''''''&'''&''''''$'''$''''''''''6{a{a{ass66{aay 2N2 N2222 N222 222N2222222ay!,W,!W,,,,!W,,,!,,,W,,,,,,,r4   c                 8   d}t         |u}|st        j                  d|fdt         |f      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}}dd	l	m
} t        j                  d
      } |t        d
      }|j                  d      }|j                  |d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   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}}|	d   d   }d}||u }|slt        j                  d|fd ||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)!uT   서브셀렉터가 존재하지 않으면 해당 필드 값은 None이어야 한다.Nr   r   r   r   r   r   r   rQ   FrD   rm   rn   r   )rq   discountrw   r^   rx   ry   rT   rz   r{   r|   rq   r}   r~   r   r`   r;   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   rV   rR   r'   r   r   r   ry   )r*   r+   r,   r-   r.   rR   r   r   r   rT   r>   r/   r?   r   r   r0   rY   s                    r2   (test_extract_fields_missing_sub_selectorz:TestExtractFields.test_extract_fields_missing_sub_selector  s    *.-!----!------!---!-----------$55uE688J'((GQ_3`a6{a{a{ass66{aay 2N2 N2222 N222 222N2222222ay$,,$,,,,$,,,$,,,,,,,,,,r4   c                 8   d}t         |u}|st        j                  d|fdt         |f      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}}dd	l	m
} t        j                  d
      } |t        d
      }|j                  d      }|j                  |ddi      }	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}}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 )uN   복수 요소에서 일괄 추출 시 모든 요소가 처리되어야 한다.Nr   r   r   r   r   r   r   rQ   FrD   rm   rq   rn   rw   r^   rx   ry   rT   rz   r{   r|   r}   r   r   namesr   r   r   r   )r*   r+   r,   r-   r.   rR   r   r   r   rT   r>   r/   r?   r   r   r   r   s                    r2   %test_extract_fields_multiple_elementsz7TestExtractFields.test_extract_fields_multiple_elements  s[    *.-!----!------!---!-----------$55uE688J'((FG3DE6{a{a{ass66{a*01$f11&~&&&&~&&&~&&&&&&&&&&&&&&&& ) E)))) E))) ))))))E)))E)))))))&~&&&&~&&&~&&&&&&&&&&&&&&&& 2s   PrF   )rH   rI   rJ   rK   rL   r   r   r   rM   r4   r2   r   r     s?    O- - - - ' 'r4   r   c                   4    e Zd ZdZedd       Zedd       Zy)TestSmartMatchingIntegrationuA   Smart Matching 통합 테스트 (auto_save + adaptive 재탐색).Nc                    d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t        d
      }|j                  |ddd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                  |d
      }|j                  |ddd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  auto_save로 저장 후 구조 변경된 HTML에서 adaptive로 재탐색해야 한다.

        시나리오:
        1. 원본 HTML로 extract_with_selector() (auto_save=True, identifier 포함)
        2. 구조 변경된 HTML로 adaptive 모드 재탐색
        3. 결과가 리스트 형태로 반환되는지 확인 (adaptive 재탐색 성공 여부는 환경 의존)
        Nr   r   r   r   r   r   TrD   z(https://example-insurance.co.kr/productsr\   rm   insurance_product_adaptive_testrn   ro   rp   r   rw   r^   rx   ry   result1rz   r{   r|   u   
        <html>
        <body>
          <article class="insurance-item">
            <h3 class="name">화재보험</h3>
            <span class="price">50000</span>
          </article>
        </body>
        </html>
        rS   r8   result2rv   rU   )r   r   r    r!   r"   r#   r$   r%   r&   r'   rW   r   r   ry   r8   rv   )r*   r+   r,   r-   r.   r   page_originalr   r>   r/   r?   r   html_changedpage_changedr   r0   rY   s                    r2   test_auto_save_and_adaptivez8TestSmartMatchingIntegration.test_auto_save_and_adaptive6  s    *.-!----!------!---!----------$55tD  m9cd//#8#h7	 0 
 7| q |q    |q      s   s      7   7   |   q       	 }}\7a}b//#8#h7	 0 
 '4((((((((z(((z(((((('((('((((((4(((4((((((((((r4   c                 V   d}t         |u}|st        j                  d|fdt         |f      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}}t        j                  d	      }|j                  t        d
      }|j                  |ddddi      }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}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)uc   adaptive=True 크롤러는 extract_with_selector()에서 adaptive 옵션을 활성화해야 한다.Nr   r   r   r   r   r   TrD   zhttps://example.comr\   rm   adaptive_testrq   rn   r   rS   r8   rT   rv   rU   rw   r^   rx   ry   rz   r{   r|   r   r   s                 r2   +test_extract_with_selector_adaptive_enabledzHTestSmartMatchingIntegration.test_extract_with_selector_adaptive_enabledb  s    *.-!----!------!---!----------$55tD}}]0E}F..#&G$	 / 
 &$''''''''z'''z''''''&'''&''''''$'''$''''''''''6{a{a{ass66{ar4   rF   )rH   rI   rJ   rK   rL   r   r  rM   r4   r2   r   r   3  s,    K)) ))V    r4   r   ).rK   builtinsr!   _pytest.assertion.rewrite	assertionrewriter   syspathlibr   typesr   typingr   unittest.mockr   r   pytestpathinsertr   __file__parentr   __annotations__insurance_crawlerModuleNotFoundError_MISSINGmarkskipifrL   r   r   r   r   r   rX   r   r   rO   rk   r   r   r   r   r   rM   r4   r2   <module>r     s5  
  
    *  3tH~,,334 5 ,0 HZ( /	2 %;;%%V &  &

	    ?
!) !)R/; /;n_* _*N@/ @/PA AR-' -'j/' /'n=  = o  		s   :C> >DD