ó
    9°Mj\  ã                  ó   • S r SSKJr  SSKrSSKJs  Jr  SSK	r	SSK
Jr  SSKJr  SSKJrJr  SSKJr  SSKJrJr  SS	KJrJr  S
r/ SQrSS jrSS jrS r\" SSS9rS rSS jr SS jr!SS jr"SS jr#SS jr$SS jr%g)aC  Tests for the capture-drop repair loop.

Detection and acceptance are deterministic and hold all authority; the
advisor only proposes. These tests drive `repair_capture` with a mock
advisor and a monkeypatched Camelot retry, asserting the gate's verdicts:
a retry replaces the original only when it provably captures more.
é    )ÚannotationsN)ÚPath)ÚMonkeyPatch)ÚMockCaptureAdvisorÚRetryAdvice)Ú	recapture©ÚCamelotCandidateÚgrid_to_markdown)Údropped_numeric_keysÚrepair_captureç      Y@))g      $@ç      >@r   ç      A@ÚTotal)g      D@r   g      I@r   ú1,637)g      N@r   g     €Q@r   ú	2,207,229c                ó2   • [        SSSSSU [        U 5      S9$ )Nzrecovery-p1-o1Ústreamé   )g        g      4@r   g     €V@g     ÀW@)Úcandidate_idÚflavorÚpageÚbboxÚaccuracyÚcellsÚmarkdownr	   )r   s    Ú3/home/mande/repo/quber/tests/core/test_recapture.pyÚ	candidater      s)   € ÜØ%ØØØ%ØØÜ! %Ó(ñð ó    c                ó®   ^^• U R                  [        SS 5        U R                  [        SS 5        / mSUU4S jjnU R                  [        SU5        T$ )NÚ
page_wordsc                ó.   • S[         [        [        5      4$ )Nr   )ÚPAGE_HÚlistÚWORDS)Úsourcer   s     r   Ú<lambda>Úpatch_io.<locals>.<lambda>+   s   € ÀuÌfÔVZÔ[`ÓVaÑFbr    Úcrop_region_pngc                ó   • g)Ns   ‰PNG© )ÚimageÚregionÚdpis      r   r(   r)   ,   s   € ÐQ[r    c                ó0   >• TR                  XEUS.5        T$ )N©r   Úrow_tolÚ
column_tol)Úappend)	r'   r   ÚareaÚordinalr   r2   r3   ÚcallsÚretrys	          €€r   Úfake_targetedÚpatch_io.<locals>.fake_targeted/   s   ø€ Ø�‰ È*ÑUÔVØˆr    Úcamelot_targeted)r   NN)Úsetattrr   )Úmonkeypatchr8   r9   r7   s    ` @r   Úpatch_ior>   *   sS   ù€ Ø×Ñœ	 <Ñ1bÔcØ×Ñœ	Ð#4Ñ6[Ô\Ø€E÷ð ð ×Ñœ	Ð#5°}ÔEØ€Lr    c                ó^   • [         R                  " [        U SS[        S5      SSU5      5      $ )Nzdoc.pdfr   zpage.pngéÈ   )ÚasyncioÚrunr   r   )ÚcandÚadvisors     r   rB   rB   7   s)   € Ü�;Š;”~ d¨I°q¼$¸zÓ:JÈCÐQRÐT[Ó\Ó]Ð]r    ztotals row split into two bandsé   )Ú	diagnosisr2   c            	     óp  • SS//n [        U [        5      nS1o!U:H  o3(       Gd`  [        R                  " SU4SX45      S[        R
                  " 5       ;   d  [        R                  " [         5      (       a  [        R                  " [         5      OSS[        R
                  " 5       ;   d  [        R                  " U 5      (       a  [        R                  " U 5      OSS[        R
                  " 5       ;   d  [        R                  " [        5      (       a  [        R                  " [        5      OS[        R                  " U5      [        R                  " U5      S	.-  nS
SU0-  n[        [        R                  " U5      5      eS =n=p2/ SQ/n[        U[        5      n[        5       o‡U:H  o"(       Gd}  [        R                  " SU4SXx45      S[        R
                  " 5       ;   d  [        R                  " [         5      (       a  [        R                  " [         5      OS[        R                  " U5      S[        R
                  " 5       ;   d  [        R                  " [        5      (       a  [        R                  " [        5      OS[        R                  " U5      S[        R
                  " 5       ;   d  [        R                  " [        5      (       a  [        R                  " [        5      OS[        R                  " U5      S.-  nSSU0-  n	[        [        R                  " U	5      5      eS =n=n=p(g )Nr   r   Ú2207229©ú==)z9%(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
} == %(py7)sr   r   r&   )Úpy0Úpy1Úpy2Úpy4Úpy7úassert %(py9)sÚpy9©r   r   r   )zP%(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
} == %(py9)s
{%(py9)s = %(py7)s()
}Úset)rK   rM   Úpy3Úpy5rO   rQ   zassert %(py11)sÚpy11)r   r&   Ú
@pytest_arÚ_call_reprcompareÚ@py_builtinsÚlocalsÚ_should_repr_global_nameÚ	_safereprÚAssertionErrorÚ_format_explanationrS   )
r   Ú@py_assert3Ú@py_assert6Ú@py_assert5Ú@py_format8Ú@py_format10Ú@py_assert1Ú@py_assert4Ú@py_assert8Ú@py_format12s
             r   Ú0test_dropped_numeric_keys_detects_missing_valuesrh   >   s�  € Ø�wÐÐ €EÜ ¤uÓ-Ð<°)°Ð<°Ñ<×<×<×<Ó<Ð-×<×<×<×<×<Õ<Ô×<×<×<Ñ<Ô×<×<×<×<×<Ö< ×<×<×<Ñ< ×<×<×<×<×<Ö<¤u×<×<×<Ñ<¤u×<×<Õ<Ð-×<×<Ó<°×<×<×<×<×<×<Ó<Ú!@Ð AÐRÔÐ AÄ5ÓIÐRÌSËUÐRÈUÑR×R×R×RÓRÐI×R×R×R×R×RÕRÔ×R×R×RÑRÔ×R×RÕRÐ A×R×R×R×R×RÔRÄ5×R×R×RÑRÄ5×R×RÕRÐI×R×R×R×R×RÔRÌS×R×R×RÑRÌS×R×RÕRÈU×R×R×R×R×R×RÖRr    c                ó  • [        [        S9n[        U S S9n[        / SQ/5      n[	        X15      oDUL oU(       GdŽ  [
        R                  " SU4SXC45      S[        R                  " 5       ;   d  [
        R                  " [        5      (       a  [
        R                  " [        5      OSS[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OSS[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS[
        R                  " U5      S[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OSS	.-  nS
SU0-  n[        [
        R                  " U5      5      eS =pE/ o�R                  n/ o”U	:H  oUo¥(       a  / o²U:H  oÌn
U
(       GdŠ  [
        R                  " SU4SXI45      S[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS[
        R                  " U5      [
        R                  " U	5      S.-  nSSU0-  oèR                  U5        U(       a˜  [
        R                  " SW4SUW45      S[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS[
        R                  " U5      S.-  nSSU0-  nUR                  U5        [
        R                  " US5      0 -  nSSU0-  n[        [
        R                  " U5      5      eS =n
=n=n=n=n	=pËg )N©Úadvice©r8   rR   ©Úis©z9%(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
} is %(py6)srB   rC   rD   ©rK   rL   rM   rN   Úpy6úassert %(py8)sÚpy8rI   )z-%(py4)s
{%(py4)s = %(py2)s.calls
} == %(py7)s)rM   rN   rO   z%(py9)srQ   )z%(py11)s == %(py14)sr7   ©rV   Úpy14ú%(py16)sÚpy16r   úassert %(py19)sÚpy19)r   ÚADVICEr>   r   rB   rW   rX   rY   rZ   r[   r\   r]   r^   r7   r4   Ú_format_boolop)r=   rD   r7   rC   r_   ra   Ú@py_format7Ú@py_format9rd   r`   Ú@py_assert0Ú@py_assert13Ú@py_assert12rb   rc   Ú@py_format15Ú@py_format17Ú@py_format18Ú@py_format20s                      r   Ú7test_no_drop_short_circuits_without_calling_the_advisorr…   D   sÇ  € Ü ¬Ñ/€GÜ�[¨Ñ-€EÜÒ5Ð6Ó7€DÜˆtÓÐ% Ð%×%×%×%Ó%Ð×%×%×%×%×%Õ%Œ3×%×%×%Ñ%Œ3×%×%×%×%×%Ö%ˆt×%×%×%Ñ%ˆt×%×%×%×%×%Ö%�W×%×%×%Ñ%�W×%×%Õ%Ð×%×%×%×%×%Ô% ×%×%×%Ñ% ×%×%×%×%×%×%Ó%Ù.�=‰=Ð.˜BÐ.˜BÑ×.¨BÐ.¨B¡;×.×.×.Õ.ˆ=×.×.×.×.×.Õ.ˆ7×.×.×.Ñ.ˆ7×.×.Õ.ˆ=×.×.Ó.˜B×.×.×.×.×.×.×.Ò. 5¨B×.×.×.×.×.Õ. 5×.×.×.Ñ. 5×.×.Õ.¨B×.×.×.×.×.×.×.×.×.×.×.×.×.Ö.r    c                ó|  • [        [        S9n[        / SQ/5      n[        XS9n[	        [        SS//5      U5      nXBL oU(       dÛ  [
        R                  " SU4SXB45      S[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OSS	[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS	S
.-  nSSU0-  n[        [
        R                  " U5      5      eS nSSSS./oƒU:H  oU(       d¥  [
        R                  " SU4SX845      S[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS[
        R                  " U5      S.-  n	SSU	0-  n
[        [
        R                  " U
5      5      eS =pX/ nSo�R                  S   S   S   o¸U;   oÌoÜ(       a  SoáR                  S   S   S   oþU;   nUnU(       Gd
  [
        R                  " SU4SX‹45      [
        R                  " U5      [
        R                  " U5      S.-  nSSU0-  nUR                  U5        U(       ab  [
        R                  " SW4SWW45      [
        R                  " U5      [
        R                  " U5      S.-  nS S!U0-  nUR                  U5        [
        R                  " US5      0 -  nS"S#U0-  n[        [
        R                  " U5      5      eS =n=n=n=n=n=n=nng )$Nrj   rR   rl   r   r   rm   )z%(py0)s is %(py2)sÚoutr8   )rK   rM   zassert %(py4)srN   r   rE   r   r1   rI   )z%(py0)s == %(py3)sr7   )rK   rT   zassert %(py5)srU   rH   r   )Úin)z%(py3)s in %(py6)s)rT   rq   z%(py8)srs   )z%(py11)s in %(py14)srt   rv   rw   rx   ry   )r   rz   r   r>   rB   rW   rX   rY   rZ   r[   r\   r]   r^   r7   r4   r{   )r=   rD   r8   r7   r‡   rd   Ú@py_format3Ú@py_format5Ú@py_assert2Ú@py_format4Ú@py_format6ra   re   r~   Ú@py_assert10r   r€   r|   r}   r�   r‚   rƒ   r„   s                          r   Ú*test_accepted_retry_replaces_the_candidater�   L   sß  € Ü ¬Ñ/€GÜÒ6Ð7Ó8€EÜ�[Ñ.€EÜ
Œi˜' 7Ð+Ð,Ó-¨wÓ
7€CØˆ<×××Òˆ3×××××Õˆ3×××Ñˆ3×××××Ö�%×××Ñ�%××××××ÒØ (°QÀaÑHÐIÐIÐIÑI×I×I×IÒIˆ5×I×I×I×I×IÕIˆ5×I×I×IÑIˆ5×I×IÕIÐI×I×I×I×I×I×IÑIáTˆ9ÐTŸ™ aÑ(¨Ñ+¨AÑ.ÐTÐ.Ñ.×T°7ÐT¿m¹mÈAÑ>NÈqÑ>QÐRSÑ>TÐTÐ>TÑ3T×T×T×TÖTˆ9×T×TÔTˆ9×T×TÓTÐ.×T×T×T×T×T×T×TÓT°7Ð>T×T×TÔT°7×T×TÓTÐ>T×T×T×T×T×T×T×T×T×T×T×T×T×T×TÑTr    c                ó²  • [        [        S9n[        U [        SS//5      S9  [        SS//5      n[	        X!5      o3UL oD(       GdŽ  [
        R                  " SU4SX245      S[        R                  " 5       ;   d  [
        R                  " [        5      (       a  [
        R                  " [        5      OSS	[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS	S
[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS
[
        R                  " U5      S	[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS	S.-  nSSU0-  n[        [
        R                  " U5      5      eS =p4g )Nrj   r   r   rl   r   rm   ro   rB   rC   rD   rp   rr   rs   ©r   rz   r>   r   rB   rW   rX   rY   rZ   r[   r\   r]   r^   ©r=   rD   rC   r_   ra   r|   r}   s          r   Ú)test_retry_that_loses_a_value_is_rejectedr“   W   sý   € Ü ¬Ñ/€GÜˆ[¤	¨G°[Ð+AÐ*BÓ CÒDÜ�w Ð(Ð)Ó*€DÜˆtÓÐ% Ð%×%×%×%Ó%Ð×%×%×%×%×%Õ%Œ3×%×%×%Ñ%Œ3×%×%×%×%×%Ö%ˆt×%×%×%Ñ%ˆt×%×%×%×%×%Ö%�W×%×%×%Ñ%�W×%×%Õ%Ð×%×%×%×%×%Ô% ×%×%×%Ñ% ×%×%×%×%×%×%Ô%r    c                ó²  • [        [        S9n[        U [        SS//5      S9  [        SS//5      n[	        X!5      o3UL oD(       GdŽ  [
        R                  " SU4SX245      S[        R                  " 5       ;   d  [
        R                  " [        5      (       a  [
        R                  " [        5      OSS[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OSS	[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS	[
        R                  " U5      S[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OSS
.-  nSSU0-  n[        [
        R                  " U5      5      eS =p4g )Nrj   r   r   rl   rm   ro   rB   rC   rD   rp   rr   rs   r‘   r’   s          r   Ú,test_retry_that_recovers_nothing_is_rejectedr•   ^   sý   € Ü ¬Ñ/€GÜˆ[¤	¨G°WÐ+=Ð*>Ó ?Ò@Ü�w Ð(Ð)Ó*€DäˆtÓÐ% Ð%×%×%×%Ó%Ð×%×%×%×%×%Õ%Œ3×%×%×%Ñ%Œ3×%×%×%×%×%Ö%ˆt×%×%×%Ñ%ˆt×%×%×%×%×%Ö%�W×%×%×%Ñ%�W×%×%Õ%Ð×%×%×%×%×%Ô% ×%×%×%Ñ% ×%×%×%×%×%×%Ô%r    c                ó  • [        S S9n[        U [        / SQ/5      S9n[        SS//5      n[        X15      oDUL oU(       GdŽ  [        R
                  " SU4SXC45      S[        R                  " 5       ;   d  [        R                  " [        5      (       a  [        R                  " [        5      OSS	[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS	S
[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS
[        R                  " U5      S	[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS	S.-  nSSU0-  n[        [        R                  " U5      5      eS =pE/ o�R                  n	[        U	5      n
SoºU:H  oÌoÜ(       a  / oâU:H  oÿnU(       Gdó  [        R
                  " SU4SX«45      S[        R                  " 5       ;   d  [        R                  " [        5      (       a  [        R                  " [        5      OSS
[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS
[        R                  " U	5      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  nUR                  U5        U(       a˜  [        R
                  " SW4SUW45      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S.-  nSSU0-  nUR                  U5        [        R                  " US5      0 -  nSSU0-  n[        [        R                  " U5      5      eS =n=n=n	=n
=n=n=pþg )Nrj   rR   rl   r   r   rm   ro   rB   rC   rD   rp   rr   rs   r   rI   )zL%(py7)s
{%(py7)s = %(py2)s(%(py5)s
{%(py5)s = %(py3)s.calls
})
} == %(py10)sÚlen)rM   rT   rU   rO   Úpy10z%(py12)sÚpy12)z%(py14)s == %(py17)sr7   )ru   Úpy17z%(py19)sry   r   zassert %(py22)sÚpy22)r   r>   r   rB   rW   rX   rY   rZ   r[   r\   r]   r^   r7   r—   r4   r{   )r=   rD   r7   rC   r_   ra   r|   r}   rd   re   r`   Ú@py_assert9rf   r~   Ú@py_assert16Ú@py_assert15Ú@py_format11Ú@py_format13rƒ   r„   Ú@py_format21Ú@py_format23s                         r   Ú.test_advisor_returning_none_keeps_the_originalr£   f   s  € Ü ¨Ñ-€GÜ�[¬	Ò3RÐ2SÓ(TÑU€EÜ�w Ð(Ð)Ó*€DÜˆtÓÐ% Ð%×%×%×%Ó%Ð×%×%×%×%×%Õ%Œ3×%×%×%Ñ%Œ3×%×%×%×%×%Ö%ˆt×%×%×%Ñ%ˆt×%×%×%×%×%Ö%�W×%×%×%Ñ%�W×%×%Õ%Ð×%×%×%×%×%Ô% ×%×%×%Ñ% ×%×%×%×%×%×%Ó%Ù2�}‰}Ð2Œ3ˆ}ÓÐ2 Ð2 Ñ"×2°Ð2°¡{×2×2×2Õ2Ð×2×2×2×2×2Õ2Œ3×2×2×2Ñ2Œ3×2×2×2×2×2Ö2ˆw×2×2×2Ñ2ˆw×2×2Õ2ˆ}×2×2Ó2Ð×2×2Ó2 ×2×2×2×2×2×2×2Ó2 u°×2×2×2×2×2Õ2 u×2×2×2Ñ2 u×2×2Õ2°×2×2×2×2×2×2×2×2×2×2×2×2×2×2Ð2r    c                ó<  • S nU R                  [        SU5        [        SS//5      nS n[        X#5      oDUL oU(       GdX  [        R
                  " SU4SXB45      S[        R                  " 5       ;   d  [        R                  " [        5      (       a  [        R                  " [        5      OSS[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OSS	.-  nS
SU0-  n[        [        R                  " U5      5      eS =n=pEg )Nc                 ó   • [        S5      e)Nzmust not be called)r]   )ÚaÚks     r   ÚboomÚ2test_disabled_advisor_is_a_pure_noop.<locals>.boomo   s   € ÜÐ1Ó2Ð2r    r"   r   r   rm   )z9%(py5)s
{%(py5)s = %(py0)s(%(py1)s, %(py3)s)
} is %(py7)srB   rC   )rK   rL   rT   rU   rO   rP   rQ   )r<   r   r   rB   rW   rX   rY   rZ   r[   r\   r]   r^   )r=   r¨   rC   r‹   re   r`   rb   rc   s           r   Ú$test_disabled_advisor_is_a_pure_nooprª   n   sà   € ò3ð ×Ñœ	 <°Ô6Ü�w Ð(Ð)Ó*€DØÐ"Œ3ˆt‹?Ð"˜dÐ"×"×"×"Ó"ˆ?×"×"×"×"×"Õ"Œ3×"×"×"Ñ"Œ3×"×"×"×"×"Ö"ˆt×"×"×"Ñ"ˆt×"×"Õ"�T×"×"Ó"ˆ?×"×"×"×"×"Ô"˜d×"×"×"Ñ"˜d×"×"×"×"×"×"Ö"r    )Úreturnr
   )r=   r   r8   zCamelotCandidate | None)r=   r   )&Ú__doc__Ú
__future__r   ÚbuiltinsrY   Ú_pytest.assertion.rewriteÚ	assertionÚrewriterW   rA   Úpathlibr   Úpytestr   Úquber.agents.capture_advisorr   r   Úquber.core.extractors.camelotr   Ú%quber.core.extractors.camelot.acquirer
   r   Ú'quber.core.extractors.camelot.recapturer   r   r$   r&   r   r>   rB   rz   rh   r…   r�   r“   r•   r£   rª   r,   r    r   Ú<module>r¸      sx   ðñõ #ç  „ ƒÝ å ç HÝ 3ß Tß Xà	€ò	€ô	ô
ò^ñ 
Ð@È!Ñ	L€òSô/ôUô&ô&ô3õ#r    