U
    
W[                    @   sT  d Z ddlZddlZddlZddlmZmZ ddlmZ ddl	m
Z
 ddlmZmZ ddlmZ ddlmZ dd	lmZmZ G d
d deZG dd deZG dd deZG dd deZG dd deZdddeji dejejd dejejd gZ G dd deZ!G dd dej"Z#G dd  d eZ$G d!d" d"eZ%G d#d$ d$ejZ&G d%d& d&eZ'G d'd( d(e&e(Z)d)d* Z*G d+d, d,eZ+G d-d. d.eZ,G d/d0 d0ejZ-G d1d2 d2eZ.G d3d4 d4eZ/G d5d6 d6eZ0G d7d8 d8ejZ1G d9d: d:eZ2G d;d< d<eZ3G d=d> d>eZ4G d?d@ d@eZ5G dAdB dBeZ6G dCdD dDeZ7dS )Ez+
Tests for L{twisted.words.protocols.irc}.
    N)protocoltask)FilePath)unicode)StringTransportStringIOWithoutClosing)TestCase)irc)	IRCClient
attributesc                   @   s   e Zd Zdd ZdS )IRCTestCasec                 C   sN   |}t |tr|d}t |tr>t |d tr>dd |D }| || dS )a$  
        A buffer is always bytes, but sometimes
        we need to compare it to a utf-8 unicode string

        @param buf: the buffer
        @type buf: L{bytes} or L{unicode} or L{list}
        @param val: the value to compare
        @type val: L{bytes} or L{unicode} or L{list}
        utf-8r   c                 S   s   g | ]}| d qS )utf8)decode).0b r   =/usr/lib/python3/dist-packages/twisted/words/test/test_irc.py
<listcomp>&   s     z6IRCTestCase.assertEqualBufferValue.<locals>.<listcomp>N)
isinstancer   r   listassertEqual)selfZbufvalbufferValuer   r   r   assertEqualBufferValue   s    



z"IRCTestCase.assertEqualBufferValueN)__name__
__module____qualname__r   r   r   r   r   r      s   r   c                   @   sd   e Zd ZdZdZdd Zdd Zdd Zd	d
 Zdd Z	dd Z
dd Zdd Zdd Zdd ZdS )ModeParsingTestsz>
    Tests for L{twisted.words.protocols.irc.parseModes}.
    )Zklbr   c                 C   s   |  tjtjdg  dS )zI
        Parsing an empty mode string raises L{irc.IRCBadModes}.
         NassertRaisesr	   IRCBadModes
parseModesr   r   r   r   test_emptyModes2   s    z ModeParsingTests.test_emptyModesc                 C   sT   |  tjtjdg  |  tjtjdg  |  tjtjdg  |  tjtjdg  dS )z
        Parsing a mode string that contains an empty sequence (either a C{+} or
        C{-} followed directly by another C{+} or C{-}, or not followed by
        anything at all) raises L{irc.IRCBadModes}.
        z++kz-+k+-Nr!   r%   r   r   r   test_emptyModeSequence9   s    z'ModeParsingTests.test_emptyModeSequencec                 C   s,   |  tjtjdg  |  tjtjdg  dS )zp
        Parsing a mode string that does not start with C{+} or C{-} raises
        L{irc.IRCBadModes}.
        foo%Nr!   r%   r   r   r   test_malformedModesE   s    z$ModeParsingTests.test_malformedModesc                 C   s,   |  tjtjdg  |  tjtjdg  dS )zk
        Parsing a mode string that contains no mode characters raises
        L{irc.IRCBadModes}.
        r'   r(   Nr!   r%   r   r   r   test_nullModesN   s    zModeParsingTests.test_nullModesc                 C   sX   t dg \}}| |dg | |g  t dg \}}| |g  | |dg dS )z
        Parsing a single mode setting with no parameters results in that mode,
        with no parameters, in the "added" direction and no modes in the
        "removed" direction.
        +ssN-sNr	   r$   r   r   ZaddedZremovedr   r   r   test_singleModeW   s    z ModeParsingTests.test_singleModec                 C   s^   t dg \}}| |dddg | |g  t dg \}}| |g  | |ddg dS )z
        Parsing a single-direction mode setting with multiple modes and no
        parameters, results in all modes falling into the same direction group.
        z+stnr/   tNnNz-ntNr2   r3   r   r   r   test_singleDirectionf   s    z%ModeParsingTests.test_singleDirectionc                 C   s4   t dg \}}| |dddg | |dg dS )zL
        Parsing a multi-direction mode setting with no parameters.
        z+s-n+tir/   r5   iNr7   Nr2   r3   r   r   r   test_multiDirectionw   s    z$ModeParsingTests.test_multiDirectionc                 C   s4   t dg \}}| |ddddg | |g  dS )z
        Parsing a multi-direction mode setting containing two consecutive mode
        sequences with the same direction results in the same result as if
        there were only one mode sequence in the same direction.
        z+sn+tir/   r7   r5   r:   Nr2   r3   r   r   r   test_consecutiveDirection   s    z*ModeParsingTests.test_consecutiveDirectionc                 C   s:   |  tjtjdg | j |  tjtjddddg| j dS )z
        If the number of mode parameters does not match the number of modes
        expecting parameters, L{irc.IRCBadModes} is raised.
        z+kz+klr*   Z10Zlulz_extra_paramN)r"   r	   r#   r$   
paramModesr%   r   r   r   test_mismatchedParams   s      z&ModeParsingTests.test_mismatchedParamsc                 C   s   t dddddg| j\}}| |dddd	g | |g  t d
ddg| j\}}| |g  | |dddd	g t ddddg| j\}}| |dddd	g | |g  dS )z
        Modes which require parameters are parsed and paired with their relevant
        parameter, modes which do not require parameters do not consume any of
        the parameters.
        z+klbbsomekey42nick!user@host	other!*@*)kr@   )lrA   )r   rB   )r   rC   z-klbb)rD   N)rE   Nz+knbbr7   N)r	   r$   r>   r   r3   r   r   r   test_parameters   sB    
z ModeParsingTests.test_parametersN)r   r   r   __doc__r>   r&   r)   r,   r-   r4   r9   r<   r=   r?   rF   r   r   r   r   r   +   s   		r   c                   @   s   e Zd ZdZdd ZdS )	MiscTestsz,
    Tests for miscellaneous functions.
    c              
   C   sb   |  ttjdddddgd dd }|  t|g dgdgdgdggg dgdgdgdg d	S )
z
        Apply a function of two arguments cumulatively to the items of
        a sequence, from right to left, so as to reduce the sequence to
        a single value.
        r               c                 S   s   |  d| | S )Nr   )insert)rE   xr   r   r   	insertTop   s    z'MiscTests.test_foldr.<locals>.insertTopN)r   r	   Z_foldroperatorsub)r   rP   r   r   r   
test_foldr   s    zMiscTests.test_foldrN)r   r   r   rG   rS   r   r   r   r   rH      s   rH   c                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&S )'FormattedTextTestsz>
    Tests for parsing and assembling formatted IRC text.
    c                 C   s   t |}| || dS )a+  
        Assert that C{text} is parsed and assembled to the same value as what
        C{expectedFormatted} is assembled to. This provides a way to ignore
        meaningless differences in the formatting structure that would be
        difficult to detect without rendering the structures.
        N)r	   parseFormattedTextassertAssemblesTo)r   textexpectedFormatted	formattedr   r   r   assertAssembledEqually   s    
z)FormattedTextTests.assertAssembledEquallyc              	   C   s8   t |}t |}| t ||d||||f  dS )zg
        Assert that C{formatted} and C{expectedFormatted} assemble to the same
        value.
        z$%r (%r) is not equivalent to %r (%r)N)r	   assembleFormattedTextr   )r   rY   rX   rW   ZexpectedTextr   r   r   rV      s    

   z$FormattedTextTests.assertAssemblesToc                 C   s   |  dtj dS )zO
        An empty string parses to a I{normal} attribute with no text.
        r    N)rZ   Anormalr%   r   r   r   test_parseEmpty   s    z"FormattedTextTests.test_parseEmptyc                 C   s0   |  ttjd |  ttjd d dS )z
        An attribute with no text assembles to the empty string. An attribute
        whose text is the empty string assembles to two control codes: C{off}
        and that of the attribute.
        r    zN)r   r	   r[   r\   r]   boldr%   r   r   r   test_assembleEmpty  s    
z%FormattedTextTests.test_assembleEmptyc                 C   s   |  ttjd d dS )zi
        A I{normal} string assembles to a string prefixed with the I{off}
        control code.
        hellozhelloN)r   r	   r[   r\   r]   r%   r   r   r   test_assembleNormal  s    z&FormattedTextTests.test_assembleNormalc                 C   s   |  ttjd d dS )zt
        A I{bold} string assembles to a string prefixed with the I{off} and
        I{bold} control codes.
        ra   zhelloN)r   r	   r[   r\   r_   r%   r   r   r   test_assembleBold  s    z$FormattedTextTests.test_assembleBoldc                 C   s   |  ttjd d dS )z
        An I{underline} string assembles to a string prefixed with the I{off}
        and I{underline} control codes.
        ra   zhelloN)r   r	   r[   r\   	underliner%   r   r   r   test_assembleUnderline*  s    z)FormattedTextTests.test_assembleUnderlinec                 C   s   |  ttjd d dS )z
        A I{reverse video} string assembles to a string prefixed with the I{off}
        and I{reverse video} control codes.
        ra   zhelloN)r   r	   r[   r\   reverseVideor%   r   r   r   test_assembleReverseVideo5  s    z,FormattedTextTests.test_assembleReverseVideoc                 C   s   |  ttjjd d dS )z
        A I{foreground color} string assembles to a string prefixed with the
        I{off} and I{color} (followed by the relevant foreground color code)
        control codes.
        ra   z	02helloN)r   r	   r[   r\   fgbluer%   r   r   r   test_assembleForegroundColor@  s    
z/FormattedTextTests.test_assembleForegroundColorc                 C   s   |  ttjjd d dS )a  
        A I{background color} string assembles to a string prefixed with the
        I{off} and I{color} (followed by a I{,} to indicate the absence of a
        foreground color, followed by the relevant background color code)
        control codes.
        ra   z
,02helloN)r   r	   r[   r\   bgri   r%   r   r   r   test_assembleBackgroundColorL  s    
z/FormattedTextTests.test_assembleBackgroundColorc                 C   s&   |  ttjjtjjd  d dS )z
        A I{foreground} and I{background} color string assembles to a string
        prefixed with the I{off} and I{color} (followed by the relevant
        foreground color, I{,} and the relevant background color code) control
        codes.
        ra   z05,02helloN)r   r	   r[   r\   rh   redrk   ri   r%   r   r   r   test_assembleColorY  s    z%FormattedTextTests.test_assembleColorc                 C   s\   |  ttjdtjd f d |  ttjtjjtj	j
d df tjd f d dS )zK
        Nested attributes retain the attributes of their parents.
        ra    worldzhello worldz yayz05,03hello05 world yayN)r   r	   r[   r\   r_   rd   r]   rh   rm   rk   greenrf   r%   r   r   r   test_assembleNestedf  s     z&FormattedTextTests.test_assembleNestedc                 C   s   |  tdtjd  dS )zk
        Parsing unformatted text results in text with attributes that
        constitute a no-op.
        ra   N)r   r	   rU   r\   r]   r%   r   r   r   test_parseUnformattedTextw  s    z,FormattedTextTests.test_parseUnformattedTextc                 C   sf   |  tdtjjd  |  tdtjjtjjd   |  tdtjjdtjjd f  dS )z
        Correctly formatted text with colors uses 2 digits to specify
        foreground and (optionally) background.
        z01yayyayz
01,02yayz01yay02yipeeZyipeeN)r   r	   rU   r\   rh   blackrk   ri   r%   r   r   r   test_colorFormatting  s    
z'FormattedTextTests.test_colorFormattingc                 C   s   |  dtjjd  |  dtjjd  |  dtjjtjjd   |  dtjjtjjd   |  dtjjtjjd	   |  d
tjd  |  dtjd  |  dtjjd  |  dtj dS )a  
        Formatted text with colors can use 1 digit for both foreground and
        background, as long as the text part does not begin with a digit.
        Foreground and background colors are only processed to a maximum of 2
        digits per component, anything else is treated as text. Color sequences
        must begin with a digit, otherwise processing falls back to unformatted
        text.
        z1kinda validzkinda validz999,999kinda validz9,999kinda validz1,2kinda validz1,999kinda validz9kinda validz1,242 is a special numberz2 is a special numberz	,02oopsz,02oopszwrongwrongz1,hellora   zN)	rZ   r\   rh   rt   rp   rk   ri   Zyellowr]   r%   r   r   r   test_weirdColorFormatting  sH    	


z,FormattedTextTests.test_weirdColorFormattingc                 C   sH   |  dtjtjjd df  |  dtjtjjtjjd  df  dS )zb
        An empty color format specifier clears foreground and background
        colors.
        z01yayresetrs   resetz01,02yayresetN)rZ   r\   r]   rh   rt   rk   ri   r%   r   r   r   test_clearColorFormatting  s    z,FormattedTextTests.test_clearColorFormattingc                 C   sj   |  dtjtjtjd  df  |  dtjtjjd df  |  dtjtjjtjjd  df  dS )zL
        A reset format specifier clears all formatting attributes.
        zyayresetrs   rx   z01yayresetz01,02yayresetN)	rZ   r\   r]   r_   rd   rh   rt   rk   ri   r%   r   r   r   test_resetFormatting  s    z'FormattedTextTests.test_resetFormattingc                 C   sB   |  tttjtjtjtjj	tj
jd   df  d dS )zZ
        Strip formatting codes from formatted text, leaving only the text parts.
        ra   ro   zhello worldN)r   r	   ZstripFormattingr[   r\   r_   rd   rf   rh   rm   rk   rp   r%   r   r   r   test_stripFormatting  s    z'FormattedTextTests.test_stripFormattingN)r   r   r   rG   rZ   rV   r^   r`   rb   rc   re   rg   rj   rl   rn   rq   rr   ru   rw   ry   rz   r{   r   r   r   r   rT      s&   
&rT   c                   @   s   e Zd ZdZdd ZdS )FormattingStateAttributeTestszD
    Tests for L{twisted.words.protocols.irc._FormattingState}.
    c              
   C   s   |  t t  |  t tjdd |  tjddddtjd dtjddddtjd d | tjddtjdd dS )z
        L{irc._FormattingState}s must have matching character attribute
        values (bold, underline, etc) with the same values to be considered
        equal.
        F)offTri   )r_   rd   r}   rf   Z
foreground)r_   N)r   r	   Z_FormattingStateZ_IRC_COLORSassertNotEqualr%   r   r   r   test_equality  s8    
      

z+FormattingStateAttributeTests.test_equalityN)r   r   r   rG   r   r   r   r   r   r|     s   r|   z3Hello, this is a nice string with no complications.z'xargs%(NUL)smight%(NUL)slike%(NUL)sthisNULz*embedded%(CR)snewline%(CR)s%(NL)sFUN%(NL)s)CRNLz,escape!%(X)s escape!%(M)s %(X)s%(X)sa %(M)s0)XMc                   @   s   e Zd Zdd Zdd ZdS )QuotingTestsc              	   C   s&   t D ]}| |tt| qdS )z<
        Testing client-server level quote/dequote.
        N)stringSubjectsr   r	   Z
lowDequoteZlowQuoter   r0   r   r   r   test_lowquoteSanity  s    z QuotingTests.test_lowquoteSanityc              	   C   s&   t D ]}| |tt| qdS )z;
        Testing CTCP message level quote/dequote.
        N)r   r   r	   ZctcpDequoteZ	ctcpQuoter   r   r   r   test_ctcpquoteSanity  s    z!QuotingTests.test_ctcpquoteSanityN)r   r   r   r   r   r   r   r   r   r     s   r   c                   @   s$   e Zd ZdZdZdd Zdd ZdS )
DispatcherzS
    A dispatcher that exposes one known command and handles unknown commands.
    dispc                 C   s   ||fS )z9
        A known command that returns its input.
        r   )r   ar   r   r   r   disp_working$  s    zDispatcher.disp_workingc                 C   s
   |||fS )zM
        Handle unknown commands by returning their name and inputs.
        r   )r   namer   r   r   r   r   disp_unknown+  s    zDispatcher.disp_unknownN)r   r   r   rG   prefixr   r   r   r   r   r   r     s   r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	DispatcherTestsz3
    Tests for L{irc._CommandDispatcherMixin}.
    c                 C   s(   t  }d}|jd| }| || dS )zD
        Dispatching a command invokes the correct handler.
        rI   rJ   workingN)r   r   dispatchr   )r   r   argsresr   r   r   test_dispatch7  s    zDispatcherTests.test_dispatchc                 C   s4   t  }d}d}|j|f| }| ||f|  dS )zM
        Dispatching an unknown command invokes the default handler.
        Zmissingr   Nr   )r   r   r   r   r   r   r   r   test_dispatchUnknownA  s
    z$DispatcherTests.test_dispatchUnknownc                 C   s"   t  }d|_| tj|jd dS )z
        Dispatching an unknown command, when no default handler is present,
        results in an exception being raised.
        Nbar)r   r   r"   r	   ZUnhandledCommandr   )r   r   r   r   r   test_dispatchMissingUnknownL  s    z+DispatcherTests.test_dispatchMissingUnknownN)r   r   r   rG   r   r   r   r   r   r   r   r   3  s   
r   c                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zd9ddZd:ddZd;ddZdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 ZdS )<ServerSupportedFeatureTestszE
    Tests for L{ServerSupportedFeatures} and related functions.
    c                 C   sr   |  tdd |  tg d |  tdd |  tddd |  tdd |  tdd dS )zt
        L{_intOrDefault} converts values to C{int} if possible, otherwise
        returns a default value.
        Nr    ra      Z123{   )r   r	   _intOrDefaultr%   r   r   r   test_intOrDefault[  s    z-ServerSupportedFeatureTests.test_intOrDefaultc              
   C   s   dddgffdddgffdddgffdddddgffd	dd
gffdddgffdddgffdddgffg}t jj}|D ]\}}||}| || qt| t|d | t|d | t|d | t|d dS )a  
        L{ServerSupportedFeatures._splitParam} splits ISUPPORT parameters
        into key and values. Parameters without a separator are split into a
        key and a list containing only the empty string. Escaped parameters
        are unescaped.
        ZFOOr    zFOO=zFOO=11z	FOO=1,2,323z
FOO=A\x20BzA Bz	FOO=\x5Cxz\xzFOO=\\zFOO=\nz\nzFOO=\xzFOO=\xNNzFOO=\xNz
FOO=\x20\xN)r	   ServerSupportedFeatures_splitParamr   r"   
ValueError)r   Zparamsr   paramexpectedr   r   r   r   test_splitParamh  s"    	z+ServerSupportedFeatureTests.test_splitParamc                 C   s,   t jddddg}| |ddddg d	S )
z
        L{ServerSupportedFeatures._splitParamArgs} splits ISUPPORT parameter
        arguments into key and value.  Arguments without a separator are
        split into a key and an empty string.
        A:1B:2zC:D)r\   r   )Br   )Cr    )r   r    N)r	   r   _splitParamArgsr   r   r   r   r   r   test_splitParamArgs  s    z/ServerSupportedFeatureTests.test_splitParamArgsc                 C   s,   t jdddgt j}| |dddg dS )z
        L{ServerSupportedFeatures._splitParamArgs} uses the argument processor
        passed to convert ISUPPORT argument values to some more suitable
        form.
        r   r   r   )r\   rI   )r   rJ   )r   NN)r	   r   r   r   r   r   r   r   r   test_splitParamArgsProcessor  s    z8ServerSupportedFeatureTests.test_splitParamArgsProcessorc                 C   s@   t jj}| |dd | t|d | |dddd dS )a   
        L{ServerSupportedFeatures._parsePrefixParam} parses the ISUPPORT PREFIX
        parameter into a mapping from modes to prefix symbols, returns
        L{None} if there is no parseable prefix parameter or raises
        C{ValueError} if the prefix parameter is malformed.
        r    Nra   z(ov)@+@r   )r'   rI   )ov)r	   r   _parsePrefixParamr   r"   r   )r   r   r   r   r   test_parsePrefixParam  s    
z1ServerSupportedFeatureTests.test_parsePrefixParamc              	   C   s   t jj}| |ddddgddddd | |ddddgddddd | |ddddgddddd | t|dddd	d
g dS )aO  
        L{ServerSupportedFeatures._parseChanModesParam} parses the ISUPPORT
        CHANMODES parameter into a mapping from mode categories to mode
        characters. Passing fewer than 4 parameters results in the empty string
        for the relevant categories. Passing more than 4 parameters raises
        C{ValueError}.
        r    ZaddressModesr   ZsetParamZnoParamr   rD   rE   Zimnpstr   cdeN)r	   r   _parseChanModesParamr   r"   r   )r   r   r   r   r   test_parseChanModesParam  s<     z4ServerSupportedFeatureTests.test_parseChanModesParamc                 C   s   t  }|dddddg | |dd | |dd	d
g | |dd | |dd | |dd | |d |dg | |d |dg dS )a   
        L{ServerSupportedFeatures.parse} changes the internal state of the
        instance to reflect the features indicated by the parsed ISUPPORT
        parameters, including unknown parameters and unsetting previously set
        parameters.
        MODES=4zCHANLIMIT=#:20,&:10INVEXz	EXCEPTS=ZzUNKNOWN=A,B,CMODESrL   Z	CHANLIMIT)#   )&
   IEXCEPTSZZUNKNOWN)r\   r   r   z-INVEXN)r	   r   parser   
getFeature
assertTrue
hasFeatureZassertFalse)r   	supportedr   r   r   
test_parse  s(    z&ServerSupportedFeatureTests.test_parsec                 C   s$   t  }dd |D }|| |S )z
        Parse all specified features according to the ISUPPORT specifications.

        @type features: C{list} of C{(featureName, value)}
        @param features: Feature names and values to parse

        @rtype: L{irc.ServerSupportedFeatures}
        c                 S   s    g | ]\}}d ||pdf qS )z%s=%sr    r   )r   r   valuer   r   r   r     s   z6ServerSupportedFeatureTests._parse.<locals>.<listcomp>)r	   r   r   )r   featuresr   r   r   r   _parse  s    	
z"ServerSupportedFeatureTests._parseNc                 C   s   |  ||fg}||S )z
        Parse a feature, with the given name and value, according to the
        ISUPPORT specifications and return the parsed value.
        )r   r   )r   r   r   r   r   r   r   _parseFeature  s    z)ServerSupportedFeatureTests._parseFeaturec                 C   s@   |  | |d| |  | |d| |  | |dd dS )zW
        Perform some common tests on a feature known to use L{_intOrDefault}.
        NZnotanintrA   *   r   r   )r   r   defaultr   r   r   _testIntOrDefaultFeature  s    


z4ServerSupportedFeatureTests._testIntOrDefaultFeaturec                 C   sL   t  j| }|dkrdg}| |}| || | ||| dS )z
        Features known to have default values are reported as being present by
        L{irc.ServerSupportedFeatures.hasFeature}, and their value defaults
        correctly, when they don't appear in an ISUPPORT message.
        N)ZDEFINITELY_NOTZ	a_feature)r	   r   	_featuresr   r   r   r   r   )r   r   r   r   r   r   r   r   _testFeatureDefault  s    
z/ServerSupportedFeatureTests._testFeatureDefaultc                 C   s   |  d |  ddg |  ddg | | ddddddd | | ddddddd | | dd	dd
ddd dS )z
        The CHANMODES ISUPPORT parameter is parsed into a C{dict} giving the
        four mode categories, C{'addressModes'}, C{'param'}, C{'setParam'}, and
        C{'noParam'}.
        	CHANMODES)r   zb,,lk,)r   zb,,lk,ha,haz,,,r    r   z,A,,r\   zA,Bc,Def,GhijZBcZDefZGhijNr   r   r   r%   r   r   r   test_support_CHANMODES%  s6    



z2ServerSupportedFeatureTests.test_support_CHANMODESc                 C   s   |  | dddg dS )z
        The IDCHAN support parameter is parsed into a sequence of two-tuples
        giving channel prefix and ID length pairs.
        ZIDCHANz!:5)!5Nr   r%   r   r   r   test_support_IDCHANE  s    
z/ServerSupportedFeatureTests.test_support_IDCHANc                 C   sP   |  | ddddg |  | dddddg |  | dddddg dS )	z~
        The MAXLIST support parameter is parsed into a sequence of two-tuples
        giving modes and their limits.
        ZMAXLISTz
b:25,eI:50)r      )ZeI2   zb:25,eI:50,a:3.1415)r   Nzb:25,eI:50,a:notanintNr   r%   r   r   r   test_support_MAXLISTO  s    


z0ServerSupportedFeatureTests.test_support_MAXLISTc                 C   s   |  | ddd dS )zr
        The NETWORK support parameter is parsed as the network name, as
        specified by the server.
        ZNETWORKZIRCNetNr   r%   r   r   r   test_support_NETWORK`  s    
z0ServerSupportedFeatureTests.test_support_NETWORKc                 C   s   |  | dd dS )z
        The SAFELIST support parameter is parsed into a boolean indicating
        whether the safe "list" command is supported or not.
        ZSAFELISTTNr   r%   r   r   r   test_support_SAFELISTj  s    z1ServerSupportedFeatureTests.test_support_SAFELISTc                 C   s   |  | ddd dS )z
        The STATUSMSG support parameter is parsed into a string of channel
        status that support the exclusive channel notice method.
        Z	STATUSMSGz@+Nr   r%   r   r   r   test_support_STATUSMSGt  s    
z2ServerSupportedFeatureTests.test_support_STATUSMSGc                 C   sV   |  | ddddd |  | dddddd |  | dd	dddd dS )
z
        The TARGMAX support parameter is parsed into a dictionary, mapping
        strings to integers, of the maximum number of targets for a particular
        command.
        ZTARGMAXzPRIVMSG:4,NOTICE:3rL   rK   )PRIVMSGNOTICEzPRIVMSG:4,NOTICE:3,KICK:3.1415N)r   r   ZKICKz PRIVMSG:4,NOTICE:3,KICK:notanintr   r%   r   r   r   test_support_TARGMAX~  s(    


z0ServerSupportedFeatureTests.test_support_TARGMAXc                 C   s   t  jd }| d| dS )a  
        The NICKLEN support parameter is parsed into an integer value
        indicating the maximum length of a nickname the client may use,
        otherwise, if the parameter is missing or invalid, the default value
        (as specified by RFC 1459) is used.
        ZNICKLENNr	   r   r   r   r   r   r   r   r   test_support_NICKLEN  s    z0ServerSupportedFeatureTests.test_support_NICKLENc                 C   s   t  jd }| d| dS )z
        The CHANNELLEN support parameter is parsed into an integer value
        indicating the maximum channel name length, otherwise, if the
        parameter is missing or invalid, the default value (as specified by
        RFC 1459) is used.
        Z
CHANNELLENNr   r   r   r   r   test_support_CHANNELLEN  s    z3ServerSupportedFeatureTests.test_support_CHANNELLENc                 C   s"   |  d | | ddd dS )zt
        The CHANTYPES support parameter is parsed into a tuple of
        valid channel prefix characters.
        Z	CHANTYPESz#&%)r   r   r+   Nr   r%   r   r   r   test_support_CHANTYPES  s
    

z2ServerSupportedFeatureTests.test_support_CHANTYPESc                 C   s   |  d dS )z
        The KICKLEN support parameter is parsed into an integer value
        indicating the maximum length of a kick message a client may use.
        ZKICKLENNr   r%   r   r   r   test_support_KICKLEN  s    z0ServerSupportedFeatureTests.test_support_KICKLENc                 C   sh   |  d |  ddg | | ddd | | dddddd | | dd	dddd dS )
z
        The PREFIX support parameter is parsed into a dictionary mapping
        modes to two-tuples of status symbol and priority.
        PREFIX)r   ra   Nz(ohv)@%+r   )r+   rI   )r'   rJ   )r   hr   z(hov)@%+r   r%   r   r   r   test_support_PREFIX  s(    



z/ServerSupportedFeatureTests.test_support_PREFIXc                 C   s   |  d dS )z
        The TOPICLEN support parameter is parsed into an integer value
        indicating the maximum length of a topic a client may set.
        ZTOPICLENNr   r%   r   r   r   test_support_TOPICLEN  s    z1ServerSupportedFeatureTests.test_support_TOPICLENc                 C   s   |  d dS )a_  
        The MODES support parameter is parsed into an integer value
        indicating the maximum number of "variable" modes (defined as being
        modes from C{addressModes}, C{param} or C{setParam} categories for
        the C{CHANMODES} ISUPPORT parameter) which may by set on a channel
        by a single MODE command from a client.
        r   Nr   r%   r   r   r   test_support_MODES  s    z.ServerSupportedFeatureTests.test_support_MODESc                 C   s*   |  | ddd |  | dd dS )z
        The EXCEPTS support parameter is parsed into the mode character
        to be used for "ban exception" modes. If no parameter is specified
        then the character C{e} is assumed.
        r   r   r   Nr   r%   r   r   r   test_support_EXCEPTS  s    
z0ServerSupportedFeatureTests.test_support_EXCEPTSc                 C   s*   |  | ddd |  | dd dS )z
        The INVEX support parameter is parsed into the mode character to be
        used for "invite exception" modes. If no parameter is specified then
        the character C{I} is assumed.
        r   r   r   Nr   r%   r   r   r   test_support_INVEX  s    
z.ServerSupportedFeatureTests.test_support_INVEX)N)N)N)r   r   r   rG   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   W  s8   #
	

 



r   c                   @   s   e Zd ZdZdS )IRCClientWithoutLoginr   N)r   r   r   performLoginr   r   r   r   r     s   r   c                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )	CTCPTestszK
    Tests for L{twisted.words.protocols.irc.IRCClient} CTCP handling.
    c                 C   sN   t  | _t| j| _t | _| j| j | | jj	 | | jj
d  d S N)r   filer   FileWrapper	transportr   clientmakeConnection
addCleanuploseConnectionconnectionLostr%   r   r   r   setUp  s    zCTCPTests.setUpc                 C   sV   dt jt jt j d }dt jt jt j d }| j| | j }| || dS )zTesting CTCP query ERRMSG.

        Not because this is this is an especially important case in the
        field, but it does go through the entire dispatch/decode/encode
        process.
        z@:nick!guy@over.there PRIVMSG #theChan :%(X)cERRMSG t%(X)c%(EOL)sr   EOLz>NOTICE nick :%(X)cERRMSG t :No error has occurred.%(X)c%(EOL)sN)	r	   X_DELIMr   LFr   dataReceivedr   getvaluer   )r   ZerrQueryZerrReplyreplyr   r   r   test_ERRMSG  s    


zCTCPTests.test_ERRMSGc                 C   sP   d| j _| j ddd dtjtjtj | j jd }| j }| 	|| dS )z
        If attributes for version information on L{IRCClient} are set to
        L{None}, the parts of the CTCP VERSION response they correspond to
        are omitted.
        
FrobozzIRCnick!guy@over.there#theChanNz1NOTICE nick :%(X)cVERSION %(vname)s::%(X)c%(EOL)s)r   r  vname)
r   versionNamectcpQuery_VERSIONr	   r  r   r  r   r	  r   r   ZversionReplyr
  r   r   r   test_noNumbersVERSION1  s    

zCTCPTests.test_noNumbersVERSIONc                 C   sl   d| j _d| j _d| j _| j ddd dtjtjtj | j j| j j| j jd }| j	
 }| || dS )	z
        The response to a CTCP VERSION query includes the version number and
        environment information, as specified by L{IRCClient.versionNum} and
        L{IRCClient.versionEnv}.
        r  z1.2gZZorkOSr  r  NzANOTICE nick :%(X)cVERSION %(vname)s:%(vnum)s:%(venv)s%(X)c%(EOL)s)r   r  r  Zvnumvenv)r   r  Z
versionNumZ
versionEnvr  r	   r  r   r  r   r	  r   r  r   r   r   test_fullVERSIONB  s    

zCTCPTests.test_fullVERSIONc                    sZ    fdd}d _ | j_ jddddtji g   j d  	 j d	 d
S )zL
        Duplicated CTCP messages are ignored and no reply is made.
        c                    s     j d7  _ d S NrI   )calleduserchanneldatar%   r   r   testCTCP[  s    z8CTCPTests.test_noDuplicateCTCPDispatch.<locals>.testCTCPr   foo!bar@baz.quux#chanz'%(X)sTESTTHIS%(X)sfoo%(X)sTESTTHIS%(X)sr   r    rI   N)
r  r   ZctcpQuery_TESTTHISirc_PRIVMSGr	   r  r   r   r	  r   )r   r  r   r%   r   test_noDuplicateCTCPDispatchW  s    z&CTCPTests.test_noDuplicateCTCPDispatchc                    s    fdd}d _   jd|  jddddtji g   j d	  	 j
d
  	 j d  jddddtji g  	 j d dS )zQ
        The fallback handler is invoked for unrecognized CTCP messages.
        c                    s    | |||f _   jd7  _d S r  )
calledWithr  )r  r  tagr  r%   r   r   unknownQuerym  s    z6CTCPTests.test_noDefaultDispatch.<locals>.unknownQueryr   ZctcpUnknownQueryr  r  z%(X)sNOTREAL%(X)sr   r    )r  r  ZNOTREALNrI   z%%(X)sNOTREAL%(X)sfoo%(X)sNOTREAL%(X)srJ   N)r  patchr   r  r	   r  r   r   r	  r   r!  )r   r#  r   r%   r   test_noDefaultDispatchi  s,    z CTCPTests.test_noDefaultDispatchN)
r   r   r   rG   r  r  r  r  r   r%  r   r   r   r   r     s   
r   c                       sd   e Zd Zdddddddddddd	d	dd
dddddddddddZdd Z fddZdd Z  ZS )NoticingClientZwheninfo
servernameversionZumodesZcmodes)options)channels)ops)motdr  r  message)r  )r  r  setmodesr   )r  Zsecsr   )r  kickerr2  nick)r  r  )r  r  r5  r2  r  )r  r  ZnewTopic)ZoldnameZnewname)createdyourHostmyInfoluserClientbounceisupportluserChannelsluserOpluserMereceivedMOTDprivmsgjoinedleftnoticedmodeChangedZpongZsignedOn
kickedFromZnickChanged
userJoineduserLeft
userKickedactiontopicUpdatedZuserRenamedc                 O   s
   g | _ d S r   )calls)r   r   kwr   r   r   __init__  s    zNoticingClient.__init__c                    sr   | dr$|dr$tt| |S ztt| d| }W n$ tk
r`   tt| | Y S X | ||S d S )N__methods)
startswithendswithsuperr&  __getattribute__KeyError
makeMethod)r   r   r   	__class__r   r   rU    s    zNoticingClient.__getattribute__c                    s    fdd}|S )Nc                     s   t | t  kr*tdt  t | f t | D ]*\}}||krVtd|f q4|||< q4t |t  krtdt  t | f j|f d S )Nz-TypeError: %s() takes %d arguments (%d given)z=TypeError: %s() got multiple values for keyword argument '%s')len	TypeErrorziprM  append)r   rN  r   r   r   fnamer   r   r   method  s    
z)NoticingClient.makeMethod.<locals>.methodr   )r   r_  r   r`  r   r^  r   rW    s    zNoticingClient.makeMethod)r   r   r   rQ  rO  rU  rW  __classcell__r   r   rX  r   r&    s:   	r&  c                 C   s4   z| | }W n t k
r$   | Y S X | |= |S d S r   )rV  )dictkeyr   r   r   r   r   pop  s    
rd  c                   @   s  e Zd Zdd Zdd Zdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd?d'd(Zd@d)d*ZdAd+d,Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 Zd9d: Zd;d< Zd=d> Z d&S )BClientImplementationTestsc                 C   s@   t  | _t | _| j| j | | jj | | jjd  d S r   )r   r   r&  r   r   r   r  r  r%   r   r   r   r    s
    zClientImplementationTests.setUpc           	      K   sv   t |dd}t |dd}t |dd}d| d | d | d | d	 | d
 }| j| | | jj||fg d S )Nhostserver.hostr7  nicknamer   r    :  :
rd  r   r  r   rM  )	r   codemsgfuncrN  rf  r7  r   r2  r   r   r   _serverTestImpl  s:    z)ClientImplementationTests._serverTestImplc                 C   s   d}| j d|d|d d S )NzHYour host is some.host[blah.blah/6667], running version server-version-3Z002r9  r(  rq  r   ro  r   r   r   testYourHost  s    z&ClientImplementationTests.testYourHostc                 C   s   d}| j d|d|d d S )Nz=This server was cobbled together Fri Aug 13 18:00:25 UTC 2004Z003r8  r'  rr  rs  r   r   r   testCreated  s    z%ClientImplementationTests.testCreatedc              	   C   s    d}| j d|dddddd d S )	Nz(server.host server-version abcDEF bcdEHIZ004r:  rg  zserver-versionZabcDEFZbcdEHIr*  rr  rs  r   r   r   
testMyInfo  s    
z$ClientImplementationTests.testMyInfoc                 C   s   d}| j d|d|d d S )Nz4There are 9227 victims and 9542 hiding on 24 serversZ251r;  r(  rr  rs  r   r   r   testLuserClient  s    
z)ClientImplementationTests.testLuserClientc                 C   s<   d}d}| j d|d|ddddd	d
ddddddddgd d S )NzMODES=4 CHANLIMIT=#:20 NICKLEN=16 USERLEN=10 HOSTLEN=63 TOPICLEN=450 KICKLEN=450 CHANNELLEN=30 KEYLEN=23 CHANTYPES=# PREFIX=(ov)@+ CASEMAPPING=ascii CAPAB IRCD=dancerare available on this server005r=  r   zCHANLIMIT=#:20z
NICKLEN=16z
USERLEN=10z
HOSTLEN=63zTOPICLEN=450zKICKLEN=450zCHANNELLEN=30z	KEYLEN=23zCHANTYPES=#zPREFIX=(ov)@+zCASEMAPPING=asciiZCAPABzIRCD=dancerr   r-  rr  r   r   ro  r   r   r   _sendISUPPORT  s&    z'ClientImplementationTests._sendISUPPORTc                 C   s   |    dS )zq
        The client parses ISUPPORT messages sent by the server and calls
        L{IRCClient.isupport}.
        N)r|  r%   r   r   r   test_ISUPPORT"  s    z'ClientImplementationTests.test_ISUPPORTc                 C   s   d}| j d|d|d d S )NzTry server some.host, port 321Z010r<  r(  rr  rs  r   r   r   
testBounce*  s    
z$ClientImplementationTests.testBouncec                 C   s$   d}d}| j d|d|t|d d S )NZ7116zchannels formedZ254r>  )r   r.  rq  intr{  r   r   r   testLuserChannels0  s
    z+ClientImplementationTests.testLuserChannelsc                 C   s$   d}d}| j d|d|t|d d S )NZ34zflagged staff membersZ252r?  )r   r/  r  r{  r   r   r   testLuserOp7  s
    z%ClientImplementationTests.testLuserOpc                 C   s   d}| j d|d|d d S )Nz!I have 1937 clients and 0 serversZ255r@  r(  rr  rs  r   r   r   testLuserMe>  s    
z%ClientImplementationTests.testLuserMec                 C   sf   dddg}|D ]$}|  | jjg  | j|d  q|  | jjddddgifg | | jjd	 d	S )
z
        Lines received in I{RPL_MOTDSTART} and I{RPL_MOTD} are delivered to
        L{IRCClient.receivedMOTD} when I{RPL_ENDOFMOTD} is received.
        z9:host.name 375 nickname :- host.name Message of the Day -/:host.name 372 nickname :- Welcome to host.name.:host.name 376 nickname :End of /MOTD command.rl  rA  r0  zhost.name Message of the Day -Welcome to host.nameN)r   r   rM  r  assertIdenticalr0  r   linesLr   r   r   test_receivedMOTDD  s    z+ClientImplementationTests.test_receivedMOTDc                 C   sB   ddg}|D ]}| j |d  q| | j jdddgifg dS )z
        If L{IRCClient} receives I{RPL_MOTD} and I{RPL_ENDOFMOTD} without
        receiving I{RPL_MOTDSTART}, L{IRCClient.receivedMOTD} is still
        called with a list of MOTD lines.
        r  r  rl  rA  r0  r  N)r   r  r   rM  r  r   r   r   test_withoutMOTDSTARTZ  s    z/ClientImplementationTests.test_withoutMOTDSTARTc                 K   s~   t |dd}t |dd}|d | d | }	d|	 d | d | d | d }
| j|
 | | jj||fg g | j_d S )	Nidentrf  r   r   ri  rj  rk  rl  rm  )r   sendergrouptypero  rp  rN  r  rf  Z	wholeUserr2  r   r   r   _clientTestImpll  s4    z)ClientImplementationTests._clientTestImplc                 C   sD   d}| j ddd|ddddd|d	
 | j dd
d|ddddd
|d	
 d S )NzTooty toot toot.r  z#groupr   rB  r  rf  zsender!ident@host)r  rf  r  r  r2  Z	recipient)r  rs  r   r   r   testPrivmsg}  s      z%ClientImplementationTests.testPrivmsgc              	      s   t t j \}} |ddddddg  |ddddg  fdd}|d	 t t j \}} |dddg  |dddg |d
 t t j \}} |g   |g       jjd
d dS )z
        L{IRCClient.getChannelModeParams} uses ISUPPORT information, either
        given by the server or defaults, to determine which channel modes
        require arguments when being added or removed.
        r   r   rD   rE   r   r   c                    sD   d|  } d} j d|d| | gd   jj| d  g  j_d S )Nr(   rx  ry  r=  rz  )rq  r  r   r   r   rM  )r   ro  r%   r   r   removeFeature  s         zJClientImplementationTests.test_getChannelModeParams.<locals>.removeFeaturer   r   N)	mapsortedr   ZgetChannelModeParamsr   r|  assertNotIdenticalr   r   )r   addremover  r   r%   r   test_getChannelModeParams  s"     z3ClientImplementationTests.test_getChannelModeParamsc                 C   s0   t t| j \}}| |g  | |g  dS )z
        L{IRCClient.getUserModeParams} returns a list of user modes (modes that
        the user sets on themself, outside of channel modes) that require
        parameters when added and removed, respectively.
        N)r  r  r   getUserModeParamsr   )r   r  r  r   r   r   test_getUserModeParams  s    z0ClientImplementationTests.test_getUserModeParamsr    Nc                 C   s*   |dkrd}d|||f }| j | dS )z@
        Build a MODE string and send it to the client.
        Nr  z&:Wolf!~wolf@yok.utu.fi MODE %s %s %s
)r   r  )r   ro  r   targetr2  r   r   r   _sendModeChange  s      z)ClientImplementationTests._sendModeChangec                    sp   |dkrd}t |D ]V\}}|\} | |d |  d d |  d | t fddd	D ||< q|S )
zO
        Parse the results, do some test and return the data to check.
        Nr  rF  r  Wolf!~wolf@yok.utu.fir  c                    s   g | ]} | qS r   r   )r   rc  r  r   r   r     s     z>ClientImplementationTests._parseModeChange.<locals>.<listcomp>)r3  r4  r   )	enumerater   tuple)r   Zresultsr  r8   resultr`  r   r  r   _parseModeChange  s    z*ClientImplementationTests._parseModeChangec                 C   s(   |  | jj|}| || g | j_dS )zR
        Compare the expected result with the one returned by the client.
        N)r  r   rM  r   )r   r   r  r  r   r   r   _checkModeChange  s    z*ClientImplementationTests._checkModeChangec                 C   s   |  d | dg dS )z
        Mode strings that do not begin with a directional character, C{'+'} or
        C{'-'}, have C{'+'} automatically prepended.
        r0   )Tr0   r   Nr  r  r%   r   r   r   test_modeMissingDirection  s    
z3ClientImplementationTests.test_modeMissingDirectionc                 C   s0   |  d | dg |  d | dg dS )zx
        No parameters are passed to L{IRCClient.modeChanged} for modes that
        don't take any parameters.
        r1   )Fr0   r   z+n)Tr8   r   Nr  r%   r   r   r   test_noModeParameters  s    

z/ClientImplementationTests.test_noModeParametersc                 C   s4   |  dd | dg |  dd | dg dS )zk
        Parameters are passed to L{IRCClient.modeChanged} for modes that take
        parameters.
        +oa_user)Tr   r  z-o)Fr   r  Nr  r%   r   r   r   test_oneModeParameter  s    z/ClientImplementationTests.test_oneModeParameterc                 C   s6   |  dd | dg |  dd | ddg dS )z
        Mixing adding and removing modes that do and don't take parameters
        invokes L{IRCClient.modeChanged} with mode characters and parameters
        that match up.
        z+osvza_user another_user)TZosv)r  Nanother_userz+v-os)Tr   r  )Fos)r  NNr  r%   r   r   r   test_mixedModes  s    z)ClientImplementationTests.test_mixedModesc                 C   sJ   |  dd | g  | tj}| t|d | d|d   dS )z
        Passing an argument to modes that take no parameters results in
        L{IRCClient.modeChanged} not being called and an error being logged.
        r.   rv   rI   zToo many parametersr   N	r  r  ZflushLoggedErrorsr	   r#   r   rZ  ZassertSubstringZgetErrorMessager   errorsr   r   r   test_tooManyModeParameters  s    
 
z4ClientImplementationTests.test_tooManyModeParametersc                 C   sH   |  d | g  | tj}| t|d | d|d   dS )z
        Passing no arguments to modes that do take parameters results in
        L{IRCClient.modeChange} not being called and an error being logged.
        r  rI   zNot enough parametersr   Nr  r  r   r   r   test_tooFewModeParameters  s    

 
z3ClientImplementationTests.test_tooFewModeParametersc                 C   sb   | j j}| jd|d | jdg|d dd }| | j d| | jdd|d | jd	g|d d
S )z
        A C{MODE} message whose target is our user (the nickname of our user,
        to be precise), as opposed to a channel, will be parsed according to
        the modes specified by L{IRCClient.getUserModeParams}.
        r  )r  )Tr   r   c                   S   s   ddgS )Nr   r    r   r   r   r   r   r  5  s    zBClientImplementationTests.test_userMode.<locals>.getUserModeParamsr  z+Zan_arg)Tr   )r  N)r   rh  r  r  r$  )r   r  r  r   r   r   test_userMode)  s    z'ClientImplementationTests.test_userModec                    s    fdd}t   _ jj _  jd|   jjd  j	dg   
 jjd   jjd   j d  j jj   j d  j   jd  t j d   jjd dS )	a  
        When the I{RPL_WELCOME} message is received a heartbeat is started that
        will send a I{PING} message to the IRC server every
        L{irc.IRCClient.heartbeatInterval} seconds. When the transport is
        closed the heartbeat looping call is stopped too.
        c                     s      }  j| _| S r   )_originalCreateHeartbeatclock)Z	heartbeatr%   r   r   _createHeartbeatF  s    zBClientImplementationTests.test_heartbeat.<locals>._createHeartbeatr  Nr*   r    z
PING foo
r   )r   ZClockr  r   r  r  r$  r  
_heartbeatirc_RPL_WELCOMEr  r   hostnamer   r   r   ZadvanceheartbeatIntervalr  r  rZ  ZgetDelayedCalls)r   r  r   r%   r   test_heartbeat?  s$    


 z(ClientImplementationTests.test_heartbeatc                 C   s:   |  | jjd d| j_| jdg  |  | jjd dS )zo
        If L{irc.IRCClient.heartbeatInterval} is set to L{None} then no
        heartbeat is created.
        Nr*   )r  r   r  r  r  r%   r   r   r   test_heartbeatDisableda  s    z0ClientImplementationTests.test_heartbeatDisabled)r    N)N)N)!r   r   r   r  rq  rt  ru  rv  rw  r|  r}  r~  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r   r   r   re    s<   		&


		"re  c                   @   s   e Zd Zdd Zdd Zdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-S ).BasicServerFunctionalityTestsc                 C   s2   t  | _t| j| _t | _| j| j d S r   )	r   fr   r   r6   r	   ZIRCpr   r%   r   r   r   r  n  s    
z#BasicServerFunctionalityTests.setUpc                 C   s.   | j  }t|tr|d}| || dS )z
        Make sure that the internal buffer equals a specified value.

        @param s: the value to compare against buffer
        @type s: L{bytes} or L{unicode}
        r   N)r  r	  r   r   r   r   )r   r0   r   r   r   r   checku  s    


z#BasicServerFunctionalityTests.checkc                 C   s   | j ddd | d dS )z
        Passing a command and parameters to L{IRC.sendMessage} results in a
        query string that consists of the command and parameters, separated by
        a space, ending with '
'.
        CMDparam1param2CMD param1 param2
N)r  sendMessager  r%   r   r   r   test_sendMessage  s    z.BasicServerFunctionalityTests.test_sendMessagec                 C   s   | j dd | d dS )aF  
        Passing a command and parameters to L{IRC.sendCommand} results in a
        query string that consists of the command and parameters, separated by
        a space, ending with '
'.

        The format is described in more detail in
        U{RFC 1459 <https://tools.ietf.org/html/rfc1459.html#section-2.3>}.
        r  r  r  r  Nr  sendCommandr  r%   r   r   r   test_sendCommand  s    	z.BasicServerFunctionalityTests.test_sendCommandc                 C   s   | j dd | d dS )zk
        Passing unicode parameters to L{IRC.sendCommand} encodes the parameters
        in UTF-8.
        r  )u   param¹u   param²s   CMD param¹ param²
Nr  r%   r   r   r   test_sendUnicodeCommand  s    z5BasicServerFunctionalityTests.test_sendUnicodeCommandc                 C   s*   |  t| jjddd}| t|d dS )zf
        Passing L{None} as the command to L{IRC.sendMessage} raises a
        C{ValueError}.
        Nr  r  IRC message requires a command.r"   r   r  r  r   strr   errorr   r   r   test_sendMessageNoCommand  s
     z7BasicServerFunctionalityTests.test_sendMessageNoCommandc                 C   s*   |  t| jjdd}| |jd d dS )zf
        Passing L{None} as the command to L{IRC.sendCommand} raises a
        C{ValueError}.
        Nr  r   r  r"   r   r  r  r   r   r  r   r   r   test_sendCommandNoCommand  s    z7BasicServerFunctionalityTests.test_sendCommandNoCommandc                 C   s*   |  t| jjddd}| t|d dS )zi
        Passing an invalid string command to L{IRC.sendMessage} raises a
        C{ValueError}.
        rj  r  r  zCSomebody screwed up, 'cuz this doesn't look like a command to me:  Nr  r  r   r   r   test_sendMessageInvalidCommand  s     
z<BasicServerFunctionalityTests.test_sendMessageInvalidCommandc                 C   s*   |  t| jjdd}| |jd d dS )zi
        Passing an invalid string command to L{IRC.sendCommand} raises a
        C{ValueError}.
        rj  r  r   zInvalid command: " "Nr  r  r   r   r   test_sendCommandInvalidCommand  s    z<BasicServerFunctionalityTests.test_sendCommandInvalidCommandc                 C   s   | j ddd | d dS )z
        Passing a command and parameters with a specified prefix to
        L{IRC.sendCommand} results in a proper query string including the
        specified line prefix.
        r  r  irc.example.com$   :irc.example.com CMD param1 param2
Nr  r%   r   r   r   test_sendCommandWithPrefix  s    z8BasicServerFunctionalityTests.test_sendCommandWithPrefixc                 C   sr   dddd}d}| j ddd| | j }|d	d
\}}|d
d d}| |d | t|t| dS )aM  
        Passing a command and parameters with a specified prefix and tags
        to L{IRC.sendCommand} results in a proper query string including the
        specified line prefix and appropriate tags syntax.  The query string
        should be output as follows:
        @tags :prefix COMMAND param1 param2

        The tags are a string of IRCv3 tags, preceded by '@'.  The rest
        of the string is as described in test_sendMessage.  For more on
        the message tag format, see U{the IRCv3 specification
        <https://ircv3.net/specs/core/message-tags-3.2.html>}.
        bbbNZeee)aaaccczexample.com/ddd)   aaa=bbbs   cccs   example.com/ddd=eeer  r  r      rI      ;r  r  r  r  r	  splitr   r  r   sendTagsZexpectedTagsZoutMsgZ	outTagStrZoutLineZoutTagsr   r   r   test_sendCommandWithTags  s    
z6BasicServerFunctionalityTests.test_sendCommandWithTagsc                 C   s:   dddd}|  t| jjddd|}| |jd d	 dS )
zW
        Passing empty tag names to L{IRC.sendCommand} raises a C{ValueError}.
        r  Nr    )r  r  r    r  r  r  r   A tag name is required.r  r   r  r  r   r   r   !test_sendCommandValidateEmptyTags  s      z?BasicServerFunctionalityTests.test_sendCommandValidateEmptyTagsc                 C   s:   dddd}|  t| jjddd|}| |jd d	 dS )
zb
        Passing None as a tag name to L{IRC.sendCommand} raises a
        C{ValueError}.
        r  NZbeep)r  r  Nr  r  r  r   r  r  r  r   r   r    test_sendCommandValidateNoneTags  s      z>BasicServerFunctionalityTests.test_sendCommandValidateNoneTagsc                 C   s6   ddi}|  t| jjddd|}| |jd d dS )	zl
        Passing a tag name containing spaces to L{IRC.sendCommand} raises a
        C{ValueError}.
        zaaa bbbr  r  r  r  r    Tag contains invalid characters.Nr  r  r   r   r   &test_sendCommandValidateTagsWithSpaces  s       zDBasicServerFunctionalityTests.test_sendCommandValidateTagsWithSpacesc                 C   s6   ddi}|  t| jjddd|}| |jd d dS )	zx
        Passing a tag name containing invalid characters to L{IRC.sendCommand}
        raises a C{ValueError}.
        zaaa_b^@r  r  r  r  r   r  Nr  r  r   r   r   ,test_sendCommandValidateTagsWithInvalidChars  s       zJBasicServerFunctionalityTests.test_sendCommandValidateTagsWithInvalidCharsc                 C   sd   ddd}d}| j ddd| | j }|dd	\}}|d	d
 d}| t|t| d
S )zr
        Tags with values containing invalid characters passed to
        L{IRC.sendCommand} are escaped.
        r  z
test
 \;;)r  r  )r  s   ccc=test\r\n\s\\\:\:r  r  r  r  rI   Nr  r  r  r   r   r   (test_sendCommandValidateTagValueEscaping,  s    
zFBasicServerFunctionalityTests.test_sendCommandValidateTagValueEscapingc                 C   s   | j ddd | d d S )Nthis-is-senderthis-is-recipzthis is messagez8:this-is-sender PRIVMSG this-is-recip :this is message
)r  rB  r  r%   r   r   r   r  B  s    z)BasicServerFunctionalityTests.testPrivmsgc                 C   s   | j ddd | d d S )Nr  r  zthis is noticez6:this-is-sender NOTICE this-is-recip :this is notice
)r  Znoticer  r%   r   r   r   
testNoticeG  s    z(BasicServerFunctionalityTests.testNoticec                 C   s   | j ddd | d d S )Nr  r  zthis is actionz6:this-is-sender ACTION this-is-recip :this is action
)r  rK  r  r%   r   r   r   
testActionL  s    z(BasicServerFunctionalityTests.testActionc                 C   s   | j dd | d d S )Nthis-personz#this-channelz!:this-person JOIN #this-channel
)r  joinr  r%   r   r   r   testJoinQ  s    z&BasicServerFunctionalityTests.testJoinc                 C   s   | j dd | d d S )Nr  z#that-channelz!:this-person PART #that-channel
)r  partr  r%   r   r   r   testPartV  s    z&BasicServerFunctionalityTests.testPartc                 C   sx   t t d }| jj}d}d}| j||dddddd	d
|ddg dddddddgt||||d }| | dS )zp
        Verify that a whois by the client receives the right protocol actions
        from the server.
        d   zrequesting-nickztarget-nickr  zhost.comzTarget Userzirc.host.comzA fake serverF   z
#fakeusersz	#fakemiscrl  zA:%(hostname)s 311 %(req)s %(targ)s target host.com * :Target Userz>:%(hostname)s 312 %(req)s %(targ)s irc.host.com :A fake serverzN:%(hostname)s 317 %(req)s %(targ)s 12 %(timestamp)s :seconds idle, signon timez8:%(hostname)s 319 %(req)s %(targ)s :#fakeusers #fakemiscz6:%(hostname)s 318 %(req)s %(targ)s :End of WHOIS list.r    )r  	timestampreqtargN)r  timer  r  whoisr  rb  r  )r   r  r  r  r  r   r   r   r   	testWhois[  s0         z'BasicServerFunctionalityTests.testWhoisN)r   r   r   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r   r   r   r  m  s,   
	



r  c                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )DummyClientz{
    A L{twisted.words.protocols.irc.IRCClient} that stores sent lines in a
    C{list} rather than transmitting them.
    c                 C   s
   g | _ d S r   )r  r%   r   r   r   rO  w  s    zDummyClient.__init__c                 C   s   t j|  g | _d S r   )r	   r
   connectionMader  r%   r   r   r   r   {  s    zDummyClient.connectionMadec                 C   s   |dt jt| j  S )zE
        Truncate an IRC line to the maximum allowed length.
        N)r	   MAX_COMMAND_LENGTHrZ  Z	delimiterr   liner   r   r   _truncateLine  s    zDummyClient._truncateLinec                 C   s   |  |}tj| |S r   )r  r	   r
   lineReceivedr  r   r   r   r    s    
zDummyClient.lineReceivedc                 C   s   | j | | d S r   )r  r]  r  )r   mr   r   r   sendLine  s    zDummyClient.sendLineN)	r   r   r   rG   rO  r   r  r  r  r   r   r   r   r  r  s   r  c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	ClientInviteTestsz(
    Tests for L{IRCClient.invite}.
    c                 C   s   t  | _dS )zO
        Create a L{DummyClient} to call C{invite} on in test methods.
        N)r  r   r%   r   r   r   r    s    zClientInviteTests.setUpc                 C   s$   | j dd | | j jdg dS )z
        If the channel name passed to L{IRCClient.invite} does not begin with a
        channel prefix character, one is prepended to it.
        r*   r   INVITE foo #barNr   Zinviter   r  r%   r   r   r   test_channelCorrection  s    z(ClientInviteTests.test_channelCorrectionc                 C   s$   | j dd | | j jdg dS )zs
        L{IRCClient.invite} sends an I{INVITE} message with the specified
        username and a channel.
        r*   #barr	  Nr
  r%   r   r   r   test_invite  s    zClientInviteTests.test_inviteN)r   r   r   rG   r  r  r  r   r   r   r   r    s   	r  c                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zd'ddZdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& ZdS )(ClientMsgTestszP
    Tests for messages sent with L{twisted.words.protocols.irc.IRCClient}.
    c                 C   s   t  | _| j  d S r   )r  r   r   r%   r   r   r   r    s    zClientMsgTests.setUpc                 C   s$   | j dd | | j jdg dS )zO
        A message containing no newlines is sent in a single command.
        r*   r   PRIVMSG foo :barN)r   ro  r   r  r%   r   r   r   test_singleLine  s    zClientMsgTests.test_singleLinec                 C   s0   |  t| jjddd |  t| jjddd dS )z
        Specifying a C{length} value to L{IRCClient.msg} that is too short to
        contain the protocol command to send a message raises C{ValueError}.
        r*   r   r   rK   N)r"   r   r   ro  r%   r   r   r   test_invalidMaxLength  s    z$ClientMsgTests.test_invalidMaxLengthc                 C   s:   t dd d }| jdd| | | jjdddg d	S )
z
        Messages longer than the C{length} parameter to L{IRCClient.msg} will
        be split and sent in multiple commands.
        PRIVMSG foo :rK   rJ   r*   barbazbor  PRIVMSG foo :bazzPRIVMSG foo :boNrZ  r   ro  r   r  )r   maxLenr   r   r   test_multipleLine  s    z ClientMsgTests.test_multipleLinec                 C   s   d}t d|f d }| jd|| | | jjd|f g g | j_| jd||d  | dt | jj g | j_| jd||d  | dt | jj dS )z
        Messages exactly equal in length to the C{length} parameter to
        L{IRCClient.msg} are sent in a single command.
        r  zPRIVMSG foo :%srJ   r*   rI   Nr  )r   ro  r  r   r   r   test_sufficientWidth  s    z#ClientMsgTests.test_sufficientWidthc                 C   s,   g | j _| j dd | | j jdg dS )zC
        An LF at the beginning of the message is ignored.
        r*   z
barr  Nr   r  ro  r   r%   r   r   r   test_newlinesAtStart  s    z#ClientMsgTests.test_newlinesAtStartc                 C   s,   g | j _| j dd | | j jdg dS )z=
        An LF at the end of the message is ignored.
        r*   zbar
r  Nr  r%   r   r   r   test_newlinesAtEnd  s    z!ClientMsgTests.test_newlinesAtEndc                 C   s.   g | j _| j dd | | j jddg dS )z;
        An LF within a message causes a new line.
        r*   zbar
bazr  r  Nr  r%   r   r   r   test_newlinesWithinMessage  s    z)ClientMsgTests.test_newlinesWithinMessagec                 C   s.   g | j _| j dd | | j jddg dS )z<
        Consecutive LFs do not cause a blank line.
        r*   zbar

bazr  r  Nr  r%   r   r   r   test_consecutiveNewlines  s    z'ClientMsgTests.test_consecutiveNewlinesNc                    s   d| j j| j j| j jf }| j jd||d g  | | j d fdd | j jD ]}| j ||  qP| t	 | d
dd	  D }| || d
S )z
        Assert that messages sent by L{IRCClient.msg} are split into an
        expected number of commands and the original message is transmitted in
        its entirety over those commands.
        z
:%s!%s@%s r*   lengthrB  c                     s
     | S r   )r]  )r   rB  r   r   <lambda>"      z;ClientMsgTests.assertLongMessageSplitting.<locals>.<lambda>r    c                 s   s   | ]\}}}|V  qd S r   r   )r   r  r  r2  r   r   r   	<genexpr>(  s    z<ClientMsgTests.assertLongMessageSplitting.<locals>.<genexpr>N)r   rh  realnamer  ro  r$  r  r  r   rZ  r  )r   r2  ZexpectedNumCommandsr  ZresponsePrefixr  ZreceivedMessager   r   r   assertLongMessageSplitting  s    
z)ClientMsgTests.assertLongMessageSplittingc                 C   s   dt jd  }| |d dS )a]  
        If a maximum message length is not provided to L{IRCClient.msg} a
        best-guess effort is made to determine a safe maximum,  messages longer
        than this are split into multiple commands with the intent of
        delivering long messages without losing data due to message truncation
        when the server relays them.
        r   rJ   Nr	   r  r%  r   r2  r   r   r   !test_splitLongMessagesWithDefault/  s    z0ClientMsgTests.test_splitLongMessagesWithDefaultc                 C   s(   dt jd  }| j|dt jd d dS )a  
        The maximum message length can be specified to L{IRCClient.msg},
        messages longer than this are split into multiple commands with the
        intent of delivering long messages without losing data due to message
        truncation when the server relays them.
        r   rJ   rK   r  Nr&  r'  r   r   r   "test_splitLongMessagesWithOverride;  s      z1ClientMsgTests.test_splitLongMessagesWithOverridec                 C   sD   dt jd  }| jd|d |  | | jjd| d| g dS )zK
        IRCClient breaks on newlines before it breaks long lines.
        r   rJ   r*   
r  Nr	   r  r   ro  r   r  r   Zlongliner   r   r   test_newlinesBeforeLineBreakingG  s    z.ClientMsgTests.test_newlinesBeforeLineBreakingc                 C   sD   dt jd  }| jd|d |  | | jjd| d| g dS )zK
        IRCClient prefers to break long lines at word boundaries.
        r   rJ   r*   rj  r  Nr+  r,  r   r   r   test_lineBreakOnWordBoundariesV  s    z-ClientMsgTests.test_lineBreakOnWordBoundariesc                 C   sN   |  ttjdd |  ttjdd | g tdd | g td dS )z
        L{twisted.words.protocols.irc.split} raises C{ValueError} if given a
        length less than or equal to C{0} and returns C{[]} when splitting
        C{''}.
        r*   r   r    rI   N)r"   r   r	   r  r   r%   r   r   r   test_splitSanitye  s    zClientMsgTests.test_splitSanityc                 C   s@   t dd}| dddg| t dd}| dddg| dS )z
        L{twisted.words.protocols.irc.split} skips any delimiter (space or
        newline) that it finds at the very beginning of the string segment it
        is operating on.  Nothing should be added to the output list because of
        it.
        zxx yyzrJ   ZxxZyyzzxx
yyzN)r	   r  r   )r   rr   r   r   test_splitDelimitersr  s    z#ClientMsgTests.test_splitDelimitersc                 C   s(   |  ttjdd |  ttjdd dS )z
        L{twisted.words.protocols.irc.split} raises C{ValueError} if given a
        length less than or equal to C{0}.
        r*   r   r/  N)r"   r   r	   r  r%   r   r   r   test_splitValidatesLength  s    z(ClientMsgTests.test_splitValidatesLengthc                 C   s$   | j dd | | j jdg dS )z
        L{IRCClient.say} prepends the channel prefix C{"#"} if necessary and
        then sends the message to the server for delivery to that channel.
        Z
thechannelzthe messagez PRIVMSG #thechannel :the messageN)r   Zsayr   r  r%   r   r   r   test_say  s
     zClientMsgTests.test_say)N)r   r   r   rG   r  r  r  r  r  r  r  r  r  r%  r(  r)  r-  r.  r0  r3  r4  r5  r   r   r   r   r    s(   			 
	r  c                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd S )!ClientTestszs
    Tests for the protocol-level behavior of IRCClient methods intended to
    be called by application code.
    c                 C   sZ   t  | _t | _d| j_| j| j | | j d | | jj	 | | jj
d dS )zT
        Create and connect a new L{IRCClient} to a new L{StringTransport}.
        Fr    N)r   r   r
   r   r   r   r   r   r   r  r  r%   r   r   r   r    s    zClientTests.setUpc                 C   s2   |  }ttkr$t|tr$|d}|dd S )zF
        Return the last IRC message in the transport buffer.
        r   rl  rM   )r   bytesr  r   r   r  )r   r   r  r   r   r   getLastLine  s    
zClientTests.getLastLinec                 C   s:   d}| j | d|f dg}| | j d| dS )zU
        L{IRCClient.away} sends an AWAY command with the specified message.
        zSorry, I'm not here.zAWAY :%sr       
N)r   Zawayr   r   r   r  )r   r2  r   r   r   r   	test_away  s    zClientTests.test_awayc                 C   s.   | j   ddg}| | j d| dS )zP
        L{IRCClient.back} sends an AWAY command with an empty message.
        zAWAY :r    r9  N)r   Zbackr   r   r   r  )r   r   r   r   r   	test_back  s
    
zClientTests.test_backc                 C   s,   | j d | | j dddg dS )z;
        L{IRCClient.whois} sends a WHOIS message.
        alicer9  zWHOIS alicer    Nr   r  r   r   r   r  r%   r   r   r   
test_whois  s
    zClientTests.test_whoisc                 C   s.   | j dd | | j dddg dS )z
        L{IRCClient.whois} sends a WHOIS message with a server name if a
        value is passed for the C{server} parameter.
        r<  zexample.orgr9  zWHOIS example.org alicer    Nr=  r%   r   r   r   test_whoisWithServer  s
    z ClientTests.test_whoisWithServerc                 C   sh   d}d}d}d| j _d| j _| j ||| d|f d|||| j jf dg}| | j d	| dS )
z
        L{IRCClient.register} sends NICK and USER commands with the
        username, name, hostname, server name, and real name specified.
        testusertesthost
testservertestnameNNICK %sUSER %s %s %s :%sr    r9  r   r$  passwordregisterr   r   r   r  r   usernamer  r+  r   r   r   r   test_register  s        zClientTests.test_registerc                 C   st   d}d}d}d| j _d| j _| j ||| d| j jf d|f d|||| j jf d	g}| | j d
| dS )z
        If the C{password} attribute of L{IRCClient} is not L{None}, the
        C{register} method also sends a PASS command with it as the
        argument.
        r@  rA  rB  rC  testpasszPASS %srD  rE  r    r9  NrF  rI  r   r   r   test_registerWithPassword  s"       z%ClientTests.test_registerWithPasswordc                 C   s   d}d}d}d| j _d| j _| j ||| | j ddg | | j}| |d|f  | j ddg | | j}| |d|d	 f  d
S )z
        Verify that the client repeats the L{IRCClient.setNick} method with a
        new value when presented with an C{ERR_NICKNAMEINUSE} while trying to
        register.
        r@  rA  rB  rC  rL  r   r   rD  rP  N)	r   r$  rG  rH  irc_ERR_NICKNAMEINUSEr8  r   r~   r   )r   rJ  r  r+  lastLiner   r   r   test_registerWithTakenNick		  s    z&ClientTests.test_registerWithTakenNickc                 C   sR   d}dd | j _| j | | j ddg | | j}| |d|d f  dS )	z
        L{IRCClient.alterCollidedNick} determines how a nickname is altered upon
        collision while a user is trying to change to that nickname.
        r*   c                 S   s   | d S )N***r   r6  r   r   r   r!  %	  r"  z<ClientTests.test_overrideAlterCollidedNick.<locals>.<lambda>r   r   rD  rQ  N)r   ZalterCollidedNickrH  rN  r8  r   r   )r   r7  rO  r   r   r   test_overrideAlterCollidedNick	  s     z*ClientTests.test_overrideAlterCollidedNickc                 C   sj   d}d}| j | | j ddg | j | | | j j| | j d|f |g | | j j| dS )z
        When a NICK command is sent after signon, C{IRCClient.nickname} is set
        to the new nickname I{after} the server sends an acknowledgement.
        r*   r   r   r   z%s!quux@quxN)r   rH  r  setNickr   rh  Zirc_NICK)r   oldnickZnewnickr   r   r   test_nickChange-	  s    zClientTests.test_nickChangec                 C   s   d}|  | jjd | j| | jddg | | j}|  |d| jjf  | jddg |  | jjd | j	| jj |  | jj
| jj | jj
}| j	| | jddg | | j}|  |d|f  |  | jj
| dS )z
        Trying to register an illegal nickname results in the default legal
        nickname being set, and trying to change a nickname to an illegal
        nickname results in the old nickname being kept.
        r*   Fr   r   rD  TN)r   r   _registeredrH  Zirc_ERR_ERRONEUSNICKNAMEr8  r   ZerroneousNickFallbackr  rS  rh  )r   ZbadnickrO  rT  r   r   r   test_erroneousNick<	  s2       zClientTests.test_erroneousNickc                 C   s^   d}d}d}| j || | j || d||f d||f dg}| | j d| dS )zd
        L{IRCClient.desrcibe} sends a CTCP ACTION message to the target
        specified.
        r*   r  ZwaveszPRIVMSG %s :ACTION %sr    r9  N)r   Zdescriber   r   r   r  )r   r  r  rK  r   r   r   r   test_describe[	  s    

zClientTests.test_describec                    s*    fdd}| j _ j dddg dS )zh
        The default implementation of L{IRCClient.noticed} doesn't invoke
        C{privmsg()}
        c                    s     d d S )Nz%privmsg() should not have been called)Zfailr1  r%   r   r   rB  q	  s    z6ClientTests.test_noticedDoesntPrivmsg.<locals>.privmsgZspamz#greasyspooncafezI don't want any spam!N)r   rB  
irc_NOTICE)r   rB  r   r%   r   test_noticedDoesntPrivmsgl	  s     z%ClientTests.test_noticedDoesntPrivmsgc                 C   s   | j d | | j d | j  | j dd | | j d | j  i | j _t	| j j
d D ] }t | | j jdt|f< qn| t| j j| j j
d  | j dd | t| j j| j j
 | | j d dS )	z#
        L{IRCClient.ping}
        Z	otherusers   PRIVMSG otheruser :PINGzare you theres)   PRIVMSG otheruser :PING are you there
rK   zI sent a lot of pingss1   PRIVMSG otheruser :PING I sent a lot of pings
N)r   Zpingr   r   r   rR  clearr   Z_pingsrangeZ_MAX_PINGRINGr  r  rZ  )r   ZpingNumr   r   r   	test_pingx	  s(    


zClientTests.test_pingN)r   r   r   rG   r  r8  r:  r;  r>  r?  rK  rM  rP  rR  rU  rW  rX  rZ  r]  r   r   r   r   r6    s    

r6  c                   @   s   e Zd ZdZdd ZdS )CollectorClientzQ
    A client that saves in a list the names of the methods that got called.
    c                    s8   g  _ d _|D ]"}|f fdd	}t ||  qdS )zx
        @param methodsList: list of methods' names that should be replaced.
        @type methodsList: C{list}
        Wolfc                    s    fdd}|S )z6
                Collects C{method}s.
                c                     s   j  | f d S r   )rQ  r]  )r   )r`  r   r   r   inner	  s    z<CollectorClient.__init__.<locals>.fake_method.<locals>.innerr   )r`  r`  r%   )r`  r   fake_method	  s    z-CollectorClient.__init__.<locals>.fake_methodN)rQ  rh  setattr)r   ZmethodsListr`  ra  r   r%   r   rO  	  s
    zCollectorClient.__init__N)r   r   r   rG   rO  r   r   r   r   r^  	  s   r^  c                   @   sx   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd ZdS )DccTestsz%
    Tests for C{dcc_*} methods.
    c                 C   s&   ddddg}d| _ d| _t|| _d S )N	dccDoSenddccDoAcceptResumedccDoResume	dccDoChatr  #twistedr  r  r^  r   r   rQ  r   r   r   r  	  s    zDccTests.setUpc                 C   sB   | j | j| jd | | j jd| jdddddddgffg dS )	zO
        L{irc.IRCClient.dcc_SEND} invokes L{irc.IRCClient.dccDoSend}.
        foo.txt 127.0.0.1 1025rd  	127.0.0.1  foo.txtr/  1025N)r   dcc_SENDr  r  r   rQ  r%   r   r   r   test_dccSend	  s    
zDccTests.test_dccSendc                 C   s   t  }| t|jdd dS )zM
        L{irc.IRCClient.dccDoSend} is raises C{NotImplementedError}
        rJ  N)r	   r
   r"   NotImplementedErrorZdccSend)r   r   r   r   r   test_dccSendNotImplemented	  s      z#DccTests.test_dccSendNotImplementedc                 C   s0   |  tj| jj| j| jd}| t|d dS )z{
        L{irc.IRCClient.dcc_SEND} raises L{irc.IRCBadMessage} when it is passed
        a malformed query string.
        r*   z#malformed DCC SEND request: ['foo']N	r"   r	   IRCBadMessager   rp  r  r  r   r  r   r  r   r   r   test_dccSendMalformedRequest	  s      z%DccTests.test_dccSendMalformedRequestc                 C   s0   |  tj| jj| j| jd}| t|d dS )z
        L{irc.IRCClient.dcc_SEND} raises L{irc.IRCBadMessage} when it is passed
        a query string that doesn't contain a valid address.
        zfoo.txt #23 sd@dzIndecipherable address '#23'Nrt  rv  r   r   r   !test_dccSendIndecipherableAddress	  s      z*DccTests.test_dccSendIndecipherableAddressc                 C   s0   |  tj| jj| j| jd}| t|d dS )z
        L{irc.IRCClient.dcc_SEND} raises L{irc.IRCBadMessage} when it is passed
        a query string that doesn't contain a valid port number.
        foo.txt 127.0.0.1 sd@dIndecipherable port 'sd@d'Nrt  rv  r   r   r   test_dccSendIndecipherablePort	  s      z'DccTests.test_dccSendIndecipherablePortc                 C   s8   | j | j| jd | | j jd| jdddffg dS )zY
        L{irc.IRCClient.dcc_ACCEPT} invokes L{irc.IRCClient.dccDoAcceptResume}.
        foo.txt 1025 2re  rn  rm  rJ   N)r   
dcc_ACCEPTr  r  r   rQ  r%   r   r   r   test_dccAccept	  s    
zDccTests.test_dccAcceptc                 C   s0   |  tj| jj| j| jd}| t|d dS )z}
        L{irc.IRCClient.dcc_ACCEPT} raises L{irc.IRCBadMessage} when it is
        passed a malformed query string.
        r*   z*malformed DCC SEND ACCEPT request: ['foo']N)	r"   r	   ru  r   r}  r  r  r   r  rv  r   r   r   test_dccAcceptMalformedRequest	  s      
z'DccTests.test_dccAcceptMalformedRequestc                 C   s8   | j | j| jd | | j jd| jdddffg dS )zS
        L{irc.IRCClient.dcc_RESUME} invokes L{irc.IRCClient.dccDoResume}.
        r|  rf  rn  rm  rJ   N)r   
dcc_RESUMEr  r  r   rQ  r%   r   r   r   test_dccResume
  s    
zDccTests.test_dccResumec                 C   s0   |  tj| jj| j| jd}| t|d dS )z}
        L{irc.IRCClient.dcc_RESUME} raises L{irc.IRCBadMessage} when it is
        passed a malformed query string.
        r*   z*malformed DCC SEND RESUME request: ['foo']N)	r"   r	   ru  r   r  r  r  r   r  rv  r   r   r   test_dccResumeMalformedRequest

  s      
z'DccTests.test_dccResumeMalformedRequestc                 C   sB   | j | j| jd | | j jd| j| jdddddgffg dS )zO
        L{irc.IRCClient.dcc_CHAT} invokes L{irc.IRCClient.dccDoChat}.
        rk  rg  rl  rm  rn  ro  N)r   dcc_CHATr  r  r   rQ  r%   r   r   r   test_dccChat
  s    
zDccTests.test_dccChatc                 C   s0   |  tj| jj| j| jd}| t|d dS )z{
        L{irc.IRCClient.dcc_CHAT} raises L{irc.IRCBadMessage} when it is
        passed a malformed query string.
        r*   z#malformed DCC CHAT request: ['foo']N	r"   r	   ru  r   r  r  r  r   r  rv  r   r   r   test_dccChatMalformedRequest
  s      
z%DccTests.test_dccChatMalformedRequestc                 C   s0   |  tj| jj| j| jd}| t|d dS )z
        L{irc.IRCClient.dcc_CHAT} raises L{irc.IRCBadMessage} when it is passed
        a query string that doesn't contain a valid port number.
        ry  rz  Nr  rv  r   r   r   test_dccChatIndecipherablePort*
  s      z'DccTests.test_dccChatIndecipherablePortN)r   r   r   rG   r  rq  rs  rw  rx  r{  r~  r  r  r  r  r  r  r   r   r   r   rc  	  s   
	


		
rc  c                   @   sX   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd ZdS )ServerToClientTestszL
    Tests for the C{irc_*} methods sent from the server to the client.
    c              	   C   s0   d| _ d| _ddddddd	d
dg	}t|| _d S )Nr  rh  rC  rH  rD  rI  userQuitrE  rG  rJ  rL  ri  rj  r   r   r   r  9
  s    
   zServerToClientTests.setUpc                 C   sD   | j | j| jg | j ddg | | j jd| jffdg dS )z
        L{IRCClient.joined} is called when I join a channel;
        L{IRCClient.userJoined} is called when someone else joins.
        Svadilfari!~svadi@yok.utu.fi#pythonrC  )rH  
Svadilfarir  N)r   Zirc_JOINr  r  r   rQ  r%   r   r   r   test_irc_JOINA
  s    

z!ServerToClientTests.test_irc_JOINc                 C   sD   | j | j| jg | j ddg | | j jd| jffdg dS )z
        L{IRCClient.left} is called when I part the channel;
        L{IRCClient.userLeft} is called when someone else parts.
        r  r  rD  )rI  r  N)r   Zirc_PARTr  r  r   rQ  r%   r   r   r   test_irc_PARTM
  s    

z!ServerToClientTests.test_irc_PARTc                 C   s:   | j ddg | j | jdg | | j jddg dS )zo
        L{IRCClient.userQuit} is called whenever someone quits
        the channel (myself included).
        r  Adios.	Farewell.)r  )r  r  )r  )r_  r  N)r   Zirc_QUITr  r   rQ  r%   r   r   r   test_irc_QUITY
  s    
z!ServerToClientTests.test_irc_QUITc                 C   sP   dt jt jt j d }| j| j| j|g | | jj	d| jddffg dS )zK
        L{IRCClient.noticed} is called when a notice is received.
        z:%(X)cextended%(X)cdata1%(X)cextended%(X)cdata2%(X)c%(EOL)sr  rE  rh  zdata1 data2N)
r	   r  r   r  r   rY  r  r  r   rQ  rs  r   r   r   test_irc_NOTICEe
  s    
z#ServerToClientTests.test_irc_NOTICEc              	   C   sR   | j ddddg | j | j| jddg | | j jddd| jd	dffg d
S )z
        L{IRCClient.kickedFrom} is called when I get kicked from the channel;
        L{IRCClient.userKicked} is called when someone else gets kicked.
        r  r  ZWOLF
shoryuken!r  z	hadouken!)rG  )r  r  r  rJ  r_  N)r   Zirc_KICKr  r  r   rQ  r%   r   r   r   test_irc_KICKp
  s    


z!ServerToClientTests.test_irc_KICKc                 C   s8   | j | j| jdg | | j jdd| jdffg dS )zR
        L{IRCClient.topicUpdated} is called when someone sets the topic.
        new topic is newrL  r_  N)r   Z	irc_TOPICr  r  r   rQ  r%   r   r   r   test_irc_TOPIC
  s    


z"ServerToClientTests.test_irc_TOPICc                 C   s:   | j | jd| jdg | | j jdd| jdffg dS )zc
        L{IRCClient.topicUpdated} is called when the topic is initially
        reported.
        ?r  rL  r_  N)r   Zirc_RPL_TOPICr  r  r   rQ  r%   r   r   r   test_irc_RPL_TOPIC
  s    



z&ServerToClientTests.test_irc_RPL_TOPICc                 C   s8   | j | jd| jg | | j jdd| jdffg dS )zP
        L{IRCClient.topicUpdated} is called when the topic is removed.
        r  rL  r_  r    N)r   Zirc_RPL_NOTOPICr  r  r   rQ  r%   r   r   r   test_irc_RPL_NOTOPIC
  s    
z(ServerToClientTests.test_irc_RPL_NOTOPICN)r   r   r   rG   r  r  r  r  r  r  r  r  r  r   r   r   r   r  5
  s   r  c                   @   sP   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd ZdS )CTCPQueryTestsz/
    Tests for the C{ctcpQuery_*} methods.
    c                 C   s   d| _ d| _tdg| _d S )Nr  rh  ctcpMakeReplyri  r%   r   r   r   r  
  s    zCTCPQueryTests.setUpc                 C   s4   | j | j| jd | | j jdddgffg dS )zm
        L{IRCClient.ctcpQuery_PING} calls L{IRCClient.ctcpMakeReply} with the
        correct args.
        r  r  r_  )ZPINGr  N)r   ZctcpQuery_PINGr  r  r   rQ  r%   r   r   r   test_ctcpQuery_PING
  s    
z"CTCPQueryTests.test_ctcpQuery_PINGc                 C   s<   d| j _| j | j| jd | | j jdddgffg dS )zo
        L{IRCClient.ctcpQuery_FINGER} calls L{IRCClient.ctcpMakeReply} with the
        correct args.
        r
  r  r  r_  )ZFINGERr
  N)r   ZfingerReplyZctcpQuery_FINGERr  r  r   rQ  r%   r   r   r   test_ctcpQuery_FINGER
  s
    
z$CTCPQueryTests.test_ctcpQuery_FINGERc                 C   s>   d| j _| j | j| jd | | j jddddgffg dS )zo
        L{IRCClient.ctcpQuery_SOURCE} calls L{IRCClient.ctcpMakeReply} with the
        correct args.
        urlr  r  r_  )SOURCEr  )r  NN)r   Z	sourceURLZctcpQuery_SOURCEr  r  r   rQ  r%   r   r   r   test_ctcpQuery_SOURCE
  s    
z$CTCPQueryTests.test_ctcpQuery_SOURCEc                 C   s<   d| j _| j | j| jd | | j jdddgffg dS )zq
        L{IRCClient.ctcpQuery_USERINFO} calls L{IRCClient.ctcpMakeReply} with
        the correct args.
        r)  r  r  r_  )ZUSERINFOr)  N)r   ZuserinfoZctcpQuery_USERINFOr  r  r   rQ  r%   r   r   r   test_ctcpQuery_USERINFO
  s
    
z&CTCPQueryTests.test_ctcpQuery_USERINFOc                 C   s\   | j | j| jd | j | j| jd d}| | j jddd|fgffdddgffg dS )	zs
        L{IRCClient.ctcpQuery_CLIENTINFO} calls L{IRCClient.ctcpMakeReply} with
        the correct args.
        r    z	PING PONGzEACTION CLIENTINFO DCC ERRMSG FINGER PING SOURCE TIME USERINFO VERSIONr  r_  
CLIENTINFO)r  NN)r   ZctcpQuery_CLIENTINFOr  r  r   rQ  )r   r)  r   r   r   test_ctcpQuery_CLIENTINFO
  s    
z(CTCPQueryTests.test_ctcpQuery_CLIENTINFOc                 C   s4   | j | j| jd | | j jd d d d dS )zm
        L{IRCClient.ctcpQuery_TIME} calls L{IRCClient.ctcpMakeReply} with the
        correct args.
        r  r   rI   r_  N)r   ZctcpQuery_TIMEr  r  r   rQ  r%   r   r   r   test_ctcpQuery_TIME
  s    z"CTCPQueryTests.test_ctcpQuery_TIMEc                 C   s4   | j | j| jd | | j jdddgffg dS )zl
        L{IRCClient.ctcpQuery_DCC} calls L{IRCClient.ctcpMakeReply} with the
        correct args.
        r  r  r_  )ZERRMSGz!DCC data :Unknown DCC type 'DATA'N)r   ZctcpQuery_DCCr  r  r   rQ  r%   r   r   r   test_ctcpQuery_DCC
  s    
z!CTCPQueryTests.test_ctcpQuery_DCCN)r   r   r   rG   r  r  r  r  r  r  r  r  r   r   r   r   r  
  s   
	r  c                   @   s   e Zd ZdZdd ZdS )DccChatFactoryTestsz&
    Tests for L{DccChatFactory}.
    c                 C   s:   d}t d|}|d}| |t j | |j| dS )z
        An instance of the L{irc.DccChat} protocol is returned, which has the
        factory property set to the factory which created it.
        )ZfromUserNNNrl  )r	   ZDccChatFactoryZbuildProtocolZassertIsInstanceZDccChatr   factory)r   Z	queryDatar  r   r   r   r   test_buildProtocol   s
    
z&DccChatFactoryTests.test_buildProtocolN)r   r   r   rG   r  r   r   r   r   r  
  s   r  c                   @   s   e Zd ZdZdd ZdS )DccDescribeTestsz#
    Tests for L{dccDescribe}.
    c                 C   s   t d}| |d dS )z@
        L{irc.dccDescribe} supports long IP addresses.
        zCHAT arg 3232235522 6666z$CHAT for host 192.168.0.2, port 6666N)r	   ZdccDescriber   rv  r   r   r   test_address  s    
zDccDescribeTests.test_addressN)r   r   r   rG   r  r   r   r   r   r    s   r  c                   @   sZ   e Zd ZdZdddZdd Zdd	 Zd
d Zdd Zdd Z	dd Z
dd Zdd ZdS )DccFileReceiveTestsz&
    Tests for L{DccFileReceive}.
    r   Nc                 C   s0   t j||d}|r|d t }|| |S )a  
        Factory helper that returns a L{DccFileReceive} instance
        for a specific test case.

        @param filename: Path to the local file where received data is stored.
        @type filename: L{str}

        @param resumeOffset: An integer representing the amount of bytes from
            where the transfer of data should be resumed.
        @type resumeOffset: L{int}

        @param overwrite: A boolean specifying whether the file to write to
            should be overwritten by calling L{DccFileReceive.set_overwrite}
            or not.
        @type overwrite: L{bool}

        @return: An instance of L{DccFileReceive}.
        @rtype: L{DccFileReceive}
        resumeOffsetT)r	   ZDccFileReceiveZset_overwriter   r   )r   filenamer  	overwriter   r   r   r   r   makeConnectedDccFileReceive  s    

z/DccFileReceiveTests.makeConnectedDccFileReceivec                 C   s   | | |d dS )z
        Arrange the protocol so that it received all data.

        @param protocol: The protocol which will receive the data.
        @type: L{DccFileReceive}

        @param data: The received data.
        @type data: L{bytest}
        N)r  r  )r   r   r  r   r   r   allDataReceivedForProtocol;  s    

z.DccFileReceiveTests.allDataReceivedForProtocolc                 C   sF   t |  }|d | j|jdd}| |d | | d dS )z
        If given a resumeOffset argument, L{DccFileReceive} will attempt to
        resume from that number of bytes if the file exists.
        s   Twisted is awesome!   r  s   amazing!   Twisted is amazing!Nr   mktempZ
setContentr  pathr  r   
getContentr   fpr   r   r   r   test_resumeFromResumeOffsetI  s
    
z/DccFileReceiveTests.test_resumeFromResumeOffsetc                 C   sF   t |  }|d | j|jdd}| |d | | d dS )aG  
        When resuming from an offset somewhere in the middle of the file,
        for example, if there are 50 bytes in a file, and L{DccFileReceive}
        is given a resumeOffset of 25, and after that 15 more bytes are
        written to the file, then the resultant file should have just 40
        bytes of data.
        r  r  r  s   cool!s   Twisted is cool!Nr  r  r   r   r   :test_resumeFromResumeOffsetInTheMiddleOfAlreadyWrittenDataW  s
    
zNDccFileReceiveTests.test_resumeFromResumeOffsetInTheMiddleOfAlreadyWrittenDatac                 C   sF   t |  }|d | j|jdd}| |d | | d dS )z
        When local file already exists it can be overwritten using the
        L{DccFileReceive.set_overwrite} method.
        s   I love contributing to Twisted!T)r  s   Twisted rocks!Nr  r  r   r   r   test_setOverwriteh  s
    
z%DccFileReceiveTests.test_setOverwritec                 C   s8   t |  }| |j}| |d | | d dS )z~
        If the file does not already exist, then L{DccFileReceive} will
        create one and write the data to it.
        s   I <3 TwistedN)r   r  r  r  r  r   r  r  r   r   r   test_fileDoesNotExistv  s    z)DccFileReceiveTests.test_fileDoesNotExistc                 C   s6   t |  }| jt| j|jdd}| tj|j dS )z
        If given a resumeOffset to resume writing to a file that does not
        exist, L{DccFileReceive} will raise L{OSError}.
        rI   r  N)	r   r  r"   OSErrorr  r  r   errnoZENOENT)r   r  r  r   r   r   test_resumeWhenFileDoesNotExist  s      z3DccFileReceiveTests.test_resumeWhenFileDoesNotExistc                 C   s*   t |  }|  | t| j|j dS )zn
        If the file already exists and overwrite action was not asked,
        L{OSError} is raised.
        N)r   r  Ztouchr"   r  r  r  r   r  r   r   r   !test_fileAlreadyExistsNoOverwrite  s    z5DccFileReceiveTests.test_fileAlreadyExistsNoOverwritec                 C   s(   t |  d}| t| j|j dS )zO
        L{IOError} is raised when failing to open the requested path.
        zchild-with-no-existing-parentN)r   r  Zchildr"   IOErrorr  r  r  r   r   r   test_failToOpenLocalFile  s    z,DccFileReceiveTests.test_failToOpenLocalFile)r   N)r   r   r   rG   r  r  r  r  r  r  r  r  r  r   r   r   r   r    s     
r  )8rG   r  rQ   r  Ztwisted.internetr   r   Ztwisted.python.filepathr   Ztwisted.python.compatr   Ztwisted.test.proto_helpersr   r   Ztwisted.trial.unittestr   Ztwisted.words.protocolsr	   Ztwisted.words.protocols.ircr
   r   r\   r   r   rH   rT   r|   r   r   r   ZX_QUOTEZM_QUOTEr   r   Z_CommandDispatcherMixinr   r   r   r   r   objectr&  rd  re  r  r  r  r  r6  r^  rc  r  r  r  r  r  r   r   r   r   <module>   sx      !
$   2|E       d   mZ