+
    BiJW                        R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHtHt ^ RI	H
t
 ]! R4        ^ RIt^ RIHt ]P                   t]P"                  t ! R R]P$                  4      tR#   ] d     ^ RIt LC  ] d    Rt  LOi ; ii ; i)z[Tests comparing PyREPL's pure Python curses implementation with the standard curses module.N)requireshas_subprocess_support)dedentcurses)terminfoc                      a  ] tR t^t o Rt]R 4       tR tR t]V 3R lR l4       t	R t
R tR	 tR
 tR tR tR tR tR tR tRtV tR# )TestCursesCompatibilityzTest that PyREPL's curses implementation matches the standard curses behavior.

Python's `curses` doesn't allow calling `setupterm()` again with a different
$TERM in the same process, so we subprocess all `curses` tests to get correctly
set up terminfo.c                    \         f   \        P                  ! R4      h\        '       g   \        P                  ! R4      hV P	                  R4       R # )NzE`curses` capability provided to regrtest but `_curses` not importableztest module requires subprocessdumb)_cursesunittestSkipTestr   infocmp)clss   &5/usr/lib/python3.14/test/test_pyrepl/test_terminfo.py
setUpClass"TestCursesCompatibility.setUpClass$   sE    ?##W  &%##$EFF 	F    c                P    \         P                  P                  R R4      V n        R# )TERMN)osenvirongetoriginal_termselfs   &r   setUpTestCursesCompatibility.setUp2   s    ZZ^^FD9r   c                    V P                   e    V P                   \        P                  R&   R # R\        P                  9   d   \        P                  R R # R # )Nr   )r   r   r   r   s   &r   tearDown TestCursesCompatibility.tearDown5   s?    )!%!3!3BJJvrzz!

6" "r   c                0   < V ^8  d   QhRS[ S[,          /# )   return)liststr)format__classdict__s   "r   __annotate__$TestCursesCompatibility.__annotate__<   s      d3i r   c                   . p \         P                  ! R RV.RRRR7      pTP
                  P                  4        F  pTP                  4       pTP                  R4      '       d)   RT9  d    RT9   d   \        P                  ! R4      hKP  KR  R	T9   g   K[  TP                  R	4      ^ ,          pTP                  T4       K  	  T#   \         d    \        P                  ! R4      hi ; i)
r   z-l1T)capture_outputtextcheckz&calling `infocmp` failed on the system#r   termcapz;curses using termcap.db: no terminfo database on the system=)
subprocessrun	Exceptionr   r   stdout
splitlinesstrip
startswithsplitappend)r   termall_capsresultlinecap_names   &&    r   r   TestCursesCompatibility.infocmp;   s    	N^^E4(#	F MM,,.D::<Ds##T)i4.?"++&  /@) ::c?1-) / !  	N##$LMM	Ns   C "C'c           	        . ROpV F  pV P                  VR7      ;_uu_ 4        \        R\        V4       R24      p\        P                  ! \
        P                  RV.RRR7      p\        P                  ! VP                  4      pVR,          p \        P                  ! VRR	7       RpV'       d   V P                  VRV 24       M R
R
R
4       K  	  R
#   \         d   pRpTp	 R
p?LAR
p?ii ; i  + '       g   i     K  ; i)z#Test basic setupterm functionality.r:   z
                    import _curses
                    import json
                    try:
                        _curses.setupterm(z, 1)
                        print(json.dumps({"success": True}))
                    except Exception as e:
                        print(json.dumps({"success": False, "error": str(e)}))
                    -cTr+   r,   successFfallbackNz0Standard curses succeeded but PyREPL failed for )xtermzxterm-256colorvt100ansi)subTestr   reprr1   r2   sys
executablejsonloadsr4   r   TermInfor3   
assertTrue)
r   
test_termsr:   ncurses_coder<   ncurses_datastd_successpyrepl_successepyrepl_errors
   &         r   test_setupterm_basic,TestCursesCompatibility.test_setupterm_basicW   s     B
D4((%+ ,0:, 7	
  $^^T<8#'
  $zz&--8*95%%%dU;%)N OO&J4&Q M )( 4 ! %%*N#$L%3 )((s<   A,C4C+C43C4C1	#C,	'C4,C1	1C44Dc                V   \        R4      p\        P                  ! \        P                  RV.RRR7      p\
        P                  ! VP                  4      pVR,          p \        P                  ! RRR7       RpV'       d   V P                  VR	4       R# R#   \         d    Rp L-i ; i)
z6Test setupterm with None (uses TERM from environment).a  
            import _curses
            import json
            try:
                _curses.setupterm(None, 1)
                print(json.dumps({"success": True}))
            except Exception as e:
                print(json.dumps({"success": False, "error": str(e)}))
            rB   TrC   rD   NFrE   z4Standard curses succeeded but PyREPL failed for None)r   r1   r2   rL   rM   rN   rO   r4   r   rP   r3   rQ   )r   rS   r<   rT   rU   rV   s   &     r   test_setupterm_none+TestCursesCompatibility.test_setupterm_none   s     

 ^^T<0

 zz&--0"9-	#dU3!N
 OOF 	  	#"N	#s    B B('B(c                   RpV P                  V4      p\        R\        V4       R\        V4       R24      p\        P                  ! \
        P                  RV.RRR7      pV P                  VP                  ^ RVP                   24       \        P                  ! VP                  4      p\        P                  ! VR	R
7      pV F  pWu9  g   WW,          R8X  d   K  V P                  VR7      ;_uu_ 4        WW,          p\!        V\"        4      '       d   \%        V4      pVP'                  V4      p	V P                  V	VRV R\        V4       R\        V	4       24       RRR4       K  	  R#   + '       g   i     K  ; i)z/Test tigetstr for common terminal capabilities.rG   R
            import _curses
            import json
            _curses.setupterm(z5, 1)
            results = {}
            for cap in a  :
                try:
                    val = _curses.tigetstr(cap)
                    if val is None:
                        results[cap] = None
                    elif val == -1:
                        results[cap] = -1
                    else:
                        results[cap] = list(val)
                except BaseException:
                    results[cap] = "error"
            print(json.dumps(results))
            rB   TrC   Failed to run ncurses: FrE   error
capabilityCapability 
: ncurses=	, pyrepl=N)r   r   rK   r1   r2   rL   rM   assertEqual
returncodestderrrN   rO   r4   r   rP   rJ   
isinstancer$   bytesr   )
r   r:   r;   rS   r<   rT   ticapncurses_val
pyrepl_vals
   &         r   !test_tigetstr_common_capabilities9TestCursesCompatibility.test_tigetstr_common_capabilities   sl     <<%  $Dzl +X' (
* ^^T<0

 	q$;FMM?"K	
 zz&--0te4 C&,*;w*F--*/k400"'"4KVVC[
  !#jk1B0C D":./1 .-	  .--s   8A)E//F c                r   RpRp\        R\        V4       R\        V4       R24      p\        P                  ! \        P
                  RV.RRR7      p\        P                  ! VP                  4      p\        P                  ! VR	R
7      p VP                  V4      pRpV P                  \        4      ;_uu_ 4        VP                  VP                  R4      4       RRR4       V P                  VVR,          R4       V P!                  VR4       R#   \         d    R	p Li ; i  + '       g   i     LQ; i)z)Test tigetstr with different input types.rG   cupr_   zn, 1)

            # Test with string input
            try:
                std_str_result = _curses.tigetstr(a  )
                std_accepts_str = True
                if std_str_result is None:
                    std_str_val = None
                elif std_str_result == -1:
                    std_str_val = -1
                else:
                    std_str_val = list(std_str_result)
            except TypeError:
                std_accepts_str = False
                std_str_val = None

            print(json.dumps({
                "accepts_str": std_accepts_str,
                "str_result": std_str_val
            }))
            rB   TrC   FrE   asciiNaccepts_strz;PyREPL and standard curses should have same string handlingz!PyREPL should accept string input)r   rK   r1   r2   rL   rM   rN   rO   r4   r   rP   r   	TypeErrorassertRaisesencoderg   rQ   )	r   r:   rm   rS   r<   rT   rl   pyrepl_str_resultpyrepl_accepts_strs	   &        r   test_tigetstr_input_types1TestCursesCompatibility.test_tigetstr_input_types   s&      $Dzl +3 489+ >
6 ^^T<0

 zz&--0 te4	' "s!%
 y))FF3::g&' * 	'I	

 	 C	
  	'!&	' *)s   D <!D&D#"D#&D6	c                   Rp\         P                  ! VRR7      pVP                  R4      pV'       Ed   V\        \        09  Edw   . ROp\        R\        V4       R\        V4       R24      p\        P                  ! \        P                  RV.R	R	R
7      pV P                  VP                  ^ RVP                   24       \        P                  ! VP                   4      pV F  w  rV P#                  WR7      ;_uu_ 4        V RV	 2p
\%        Wz,          \&        4      '       d/   RWz,          9   d"   V P)                  RWz,          R,           24       \+        Wz,          4      p\         P,                  ! W8V	4      pV P                  VVRV RV	 R\        V4       R\        V4       24       RRR4       K  	  R# \.        P0                  ! R4      h  + '       g   i     K  ; i)zTest basic tparm functionality.rG   FrE   rs   z^
                import _curses
                import json
                _curses.setupterm(z, 1)

                # Get cup capability
                cup = _curses.tigetstr('cup')
                results = {}

                for row, col in aC  :
                    try:
                        result = _curses.tparm(cup, row, col)
                        results[f"{row},{col}"] = list(result)
                    except Exception as e:
                        results[f"{row},{col}"] = {"error": str(e)}

                print(json.dumps(results))
                rB   TrC   r`   )rowcol,ra   ncurses tparm failed: ztparm(cup, , ): std=rf   Nz0test_tparm_basic() requires the `cup` capability))    r   )   
   )   O   )  r   )r   rP   r   ABSENT_STRINGCANCELLED_STRINGr   rK   r1   r2   rL   rM   rg   rh   ri   rN   rO   r4   rJ   rj   dictfailrk   tparmr   r   )r   r:   rl   rs   
test_casesrS   r<   rT   r~   r   key
std_resultpyrepl_results   &            r   test_tparm_basic(TestCursesCompatibility.test_tparm_basic&  s   te4 ffUm33}.>??J "# $(:, /! "&j!1 2 3L*  ^^|4#F
 !!1(?&O  ::fmm4L&\\c\33 E3%.C"<#4d;;#|'88		4\5Fw5O4PQ "'|'8!9J %-NN3S$AM $$%"%cU"SE 2#J/0	$}:M9NP! 43 '0 ##B / 433s   B+GG$c                F   Rp\         P                  ! VRR7      pR^R^R^R^R^R	^/p/ pV F5  pVP                  V4      pV'       g   K  V\        \        09  g   K1  WdV&   K7  	  V'       g   V P                  R
4       \        R\        V4       R\        V4       R24      p\        P                  ! \        P                  RV.RRR7      pV P                  VP                  ^ RVP                   24       \        P                   ! VP"                  4      p	VP%                  4        F  w  rVV P'                  VR7      ;_uu_ 4        R F  p
V RV
 2pW9   g   K  \)        W,          \*        4      '       d/   RW,          9   d"   V P-                  RW,          R,           24       \/        W,          4      p\         P0                  ! Wj4      pV P                  VVRV RV
 R\        V4       R\        V4       24       K  	  RRR4       K  	  R#   + '       g   i     K  ; i)z7Test tparm with capabilities using multiple parameters.rG   FrE   cubcufcuucuddchichz"No parametrized capabilities foundr_   z, 1)

            param_caps = aM  
            test_values = [1, 5, 10, 99]
            results = {}

            for cap in param_caps:
                cap_value = _curses.tigetstr(cap)
                if cap_value and cap_value != -1:
                    for value in test_values:
                        try:
                            result = _curses.tparm(cap_value, value)
                            results[f"{cap},{value}"] = list(result)
                        except Exception as e:
                            results[f"{cap},{value}"] = {"error": str(e)}

            print(json.dumps(results))
            rB   TrC   r`   rb   r   ra   r   ztparm(r   r   rf   N)   r   r   c   )r   rP   r   r   r   skipTestr   rK   r1   r2   rL   rM   rg   rh   ri   rN   rO   r4   itemsrJ   rj   r   r   rk   r   )r   r:   rl   
param_capspyrepl_capsrm   	cap_valuerS   r<   rT   valuer   r   r   s   &             r   test_tparm_multiple_params2TestCursesCompatibility.test_tparm_multiple_paramsr  s   te4 111111

 CsIyY /  $-C   MM>?   $Dzl +z*+ ,
0 ^^T<0

 	q$;FMM?"K	
 zz&--0)//1NC--+E E5'*C*&|'8$?? '<+< < II"89J79S8T U &+<+<%=
(0y(H(()&$SEE7 3##'
#3"4Id=>Q=RT , .- 2---s   HB&HH c                4   Rp\        R\        V4       R24      p\        P                  ! \        P
                  RV.RRR7      p\        P                  ! VP                  4      p\        P                  ! VRR7      pVR	,          '       d?   V P                  \        4      ;_uu_ 4        \        P                  ! R
4       R
R
R
4       R
#  \        P                  ! R
4       R
#   + '       g   i     R
# ; i  \         d    T P                  R4        R
# i ; i)z Test tparm with None/null input.rG   r_   a  , 1)

            # Test with None
            try:
                _curses.tparm(None)
                raises_typeerror = False
            except TypeError:
                raises_typeerror = True
            except Exception as e:
                raises_typeerror = False
                error_type = type(e).__name__

            print(json.dumps({"raises_typeerror": raises_typeerror}))
            rB   TrC   FrE   raises_typeerrorNz+PyREPL raised TypeError but ncurses did not)r   rK   r1   r2   rL   rM   rN   rO   r4   r   rP   rw   rv   r   r   )r   r:   rS   r<   rT   rl   s   &     r   test_tparm_null_handling0TestCursesCompatibility.test_tparm_null_handling  s      $Dzl +
( ^^T<0

 zz&--0 te4 *++""9--t$ .-It$ .--  I		GHIs   )C#C7 #C4	7DDc                ~   . ROpV EF  pV P                  VR7      ;_uu_ 4        V P                  V4      p\        R\        V4       R\        V4       R24      p\        P
                  ! \        P                  RV.RRR7      pVP                  ^ 8w  d"   V P                  RV R	VP                   24        \        P                  ! VP                  4      pRX9   d5   \        V4      ^8X  d%   \         P"                  ! VRR7      p RRR4       EK  \         P"                  ! VRR7      pV F  pW9  d   K  V P                  W(R7      ;_uu_ 4        Wh,          p	\%        V	\&        4      '       d   \)        V	4      p	VP+                  V4      p
V P-                  V
V	RV RV R\        V	4       R\        V
4       24       RRR4       K  	  RRR4       EK  	  R#   \        P                   d&    T P                  R
T R	TP                   24        EL:i ; i  + '       g   i     K  ; i  + '       g   i     EK5  ; i)z!Test with special terminal types.rA   z
                    import _curses
                    import json
                    import sys

                    try:
                        _curses.setupterm(zM, 1)
                        results = {}
                        for cap in a  :
                            try:
                                val = _curses.tigetstr(cap)
                                if val is None:
                                    results[cap] = None
                                elif val == -1:
                                    results[cap] = -1
                                else:
                                    # Convert bytes to list of ints for JSON
                                    results[cap] = list(val)
                            except BaseException:
                                results[cap] = "error"
                        print(json.dumps(results))
                    except Exception as e:
                        print(json.dumps({"error": str(e)}))
                    rB   TrC   zFailed to get ncurses data for z: z#Failed to parse ncurses output for ra   rE   NF)r:   rc   rd   z for re   rf   )r
   unknownlinuxscreentmux)rJ   r   r   rK   r1   r2   rL   rM   rh   r   ri   rN   rO   r4   JSONDecodeErrorlenr   rP   rj   r$   rk   r   rg   )r   special_termsr:   r;   rS   r<   rT   rl   rm   rn   ro   s   &          r   test_special_terminals.TestCursesCompatibility.test_special_terminals  s   
 "D4((<<-%+ ,0:, 7$$(N#3 4 8 $^^T<8#'
 $$)II9$r&--Q#'::fmm#<L l*s</@A/E "**4$?Bg )(j &&te< $C. 4@@&2&7%k488*/*<K%'VVC[
 ((&')#eD6 :''+K'8&9 :&&*:&6%79 A@	 $q )( "V ++ II=dV2fmm_U$ A@@y )((sO   BH*8 G0H*?H*A,H>H*6H	H*H	H*H'!	H**H<c                   Rp\        R\        V4       R24      p\        P                  ! \        P
                  RV.RRR7      p\        P                  ! VP                  4      pVR,          '       d   V P                  RV R	24        \        P                  ! VRR
7      pRpV P                  VR4       XP                  R4      pV P                  VR4       R#   \         d    Rp LFi ; i)zBTest that PyREPL falls back gracefully when terminfo is not found.znonexistent-terminal-type-12345zg
            import _curses
            import json
            try:
                _curses.setupterm(a!  , 1)
                print(json.dumps({"success": True}))
            except _curses.error:
                print(json.dumps({"success": False, "error": "curses.error"}))
            except Exception as e:
                print(json.dumps({"success": False, "error": str(e)}))
            rB   TrC   rD   z&System unexpectedly has terminfo for ''rE   Fz-PyREPL should fall back for unknown terminalsbelz7PyREPL should provide basic capabilities after fallbackN)r   rK   r1   r2   rL   rM   rN   rO   r4   r   r   rP   r3   rQ   r   assertIsNotNone)r   	fake_termrS   r<   rT   rl   	pyrepl_okr   s   &       r   test_terminfo_fallback.TestCursesCompatibility.test_terminfo_fallbackN  s     6	 # $(	?"3 4	

 ^^T<0

 zz&--0	""MM81E
	""9t<BI 	F	

 ffUmJ	
  	I	s   
C C+*C+c           
        ^*\         3R\        3R\        3R\        P                   R2\        3.pV F`  w  r#V P	                  VR7      ;_uu_ 4        V P                  V4      ;_uu_ 4        \        P                  ! V4       RRR4       RRR4       Kb  	  R#   + '       g   i     L; i  + '       g   i     K  ; i)*    zw tz..namerA   N)rv   
ValueErrorr   seprJ   rw   r    _validate_terminal_name_or_raise)r   casesr:   excs   &   r   test_invalid_terminal_names3TestCursesCompatibility.test_invalid_terminal_names  s    Oz""&&
+	
 ID4((&&s++==dC , )( ++ )((s$   B,,BB,B)$B,,B=)r   N)__name__
__module____qualname____firstlineno____doc__classmethodr   r   r   r   rY   r\   rp   r{   r   r   r   r   r   r   __static_attributes____classdictcell__)r'   s   @r   r   r      s       :#  6,\"H;z>
@JXTl+IZWr0
dD Dr   r   )r   rN   r   r1   rL   r   test.supportr   r   textwrapr   r   ImportErrorr   _pyreplr   r   r   TestCaser    r   r   <module>r      s    a  	  
  9  	   &&,, n	Dh// n	D    s)   A' 'B/A55	B>BBB