o
    q+WZVU  ć                   @   sÜ   d dl Z d dlZd dlZd dlZd dlZd dlZd dlmZmZ d dl	Z	dd Z
G dd deZee
  dG dd	 d	eZee
  dG d
d deZee
  dG dd deZee
  dG dd deZdS )é    N)ŚskipIfŚTestCasec                   C   s$   zt d W dS  ty   Y dS w )NZtwistedFT)Ś
__import__ŚImportError© r   r   ś=/usr/lib/python3/dist-packages/automat/_test/test_discover.pyŚisTwistedInstalled   s   
ż’r   c                       s\   e Zd ZdZ fddZ fddZdd Zdd	 Zd
d Zdd Z	dd Z
dd Z  ZS )Ś_WritesPythonModuleszG
    A helper that enables generating Python module test fixtures.
    c                    sv   t t|  ”  ddlm}m} ddlm} || _|| _|| _tt	j
 ” | _t	jd d  | _t ” | _|  | j” d S )Nr   )Ś	getModuleŚ
PythonPath)ŚFilePath)Śsuperr	   ŚsetUpŚtwisted.python.modulesr
   r   Ztwisted.python.filepathr   ŚsetŚsysŚmodulesŚkeysŚoriginalSysModulesŚpathŚsavedSysPathŚtempfileZmkdtempŚpathDirŚmakeImportable)Śselfr
   r   r   ©Ś	__class__r   r   r      s   
z_WritesPythonModules.setUpc                    sR   t t|  ”  | jtjd d < t tj”| j	 }|D ]}tj|= qt
 | j” d S ©N)r   r	   ŚtearDownr   r   r   ŚsixZviewkeysr   r   ŚshutilŚrmtreer   )r   ZmodulesToDeleteŚmoduler   r   r   r   *   s   
z_WritesPythonModules.tearDownc                 C   s   t j |” d S r   )r   r   Śappend)r   r   r   r   r   r   4   s   z#_WritesPythonModules.makeImportablec                 C   s^   |   |”}| |”}t|jd}| t |”” W d    n1 s#w   Y  |  |jg”S )NŚw)r   ŚchildŚopenr   ŚwriteŚtextwrapŚdedentr   )r   Śsourcer   Ś
moduleNameZ	directoryr"   Śfr   r   r   ŚwriteSourceInto7   s   

’z$_WritesPythonModules.writeSourceIntoc                 C   s"   t j |”\}}|  |||”| S r   )Śosr   Śsplitextr-   )r   r*   r   r+   ZpythonModuleNameŚ_r   r   r   Ś
makeModuleB   s   z_WritesPythonModules.makeModulec                 C   s   dd |  ” D S )Nc                 S   s   i | ]}|j |qS r   )Śname)Ś.0Śattrr   r   r   Ś
<dictcomp>G   s    z9_WritesPythonModules.attributesAsDict.<locals>.<dictcomp>)ZiterAttributes)r   ZhasIterAttributesr   r   r   ŚattributesAsDictF   s   z%_WritesPythonModules.attributesAsDictc                 C   s   |  ”  |  |”S r   )Śloadr6   )r   r"   r   r   r   ŚloadModuleAsDictI   s   
z%_WritesPythonModules.loadModuleAsDictc                 C   s   |   |  |||””S r   )r8   r1   )r   r*   r   r2   r   r   r   ŚmakeModuleAsDictM   s   z%_WritesPythonModules.makeModuleAsDict)Ś__name__Ś
__module__Ś__qualname__Ś__doc__r   r   r   r-   r1   r6   r8   r9   Ś__classcell__r   r   r   r   r	      s    
r	   zTwisted is not installed.c                       s8   e Zd ZdZ fddZdd Zdd Zdd	 Z  ZS )
ŚOriginalLocationTestsa  
    Tests that L{isOriginalLocation} detects when a
    L{PythonAttribute}'s FQPN refers to an object inside the module
    where it was defined.

    For example: A L{twisted.python.modules.PythonAttribute} with a
    name of 'foo.bar' that refers to a 'bar' object defined in module
    'baz' does *not* refer to bar's original location, while a
    L{PythonAttribute} with a name of 'baz.bar' does.

    c                    ó$   t t|  ”  ddlm} || _d S )Né   )ŚisOriginalLocation)r   r?   r   Ś	_discoverrB   )r   rB   r   r   r   r   ^   ó   
zOriginalLocationTests.setUpc                 C   s,   d}|   || jd”}|  |  |d ”” dS )z
        L{isOriginalLocation} returns False when the attribute refers to an
        object whose source module cannot be determined.
        z~        class Fake(object):
            pass
        hasEmptyModule = Fake()
        hasEmptyModule.__module__ = None
        zempty_module_attr.pyz empty_module_attr.hasEmptyModuleN)r9   r   ŚassertFalserB   )r   r*   Ś
moduleDictr   r   r   Śtest_failsWithNoModulec   s   ž
’z,OriginalLocationTests.test_failsWithNoModulec                 C   s~   d}d}|   || jd” |  || jd”}|  |  |d ”” |  |  |d ”” |d }|  |”}|d }|  |  |”” d	S )
z
        L{isOriginalLocation} returns False when the attribute refers to
        an object outside of the module where that object was defined.
        zā        class ImportThisClass(object):
            pass
        importThisObject = ImportThisClass()
        importThisNestingObject = ImportThisClass()
        importThisNestingObject.nestedObject = ImportThisClass()
        z        from original import (ImportThisClass,
                              importThisObject,
                              importThisNestingObject)
        śoriginal.pyśimporting.pyzimporting.ImportThisClasszimporting.importThisObjectz!importing.importThisNestingObjectz.importing.importThisNestingObject.nestedObjectN)r1   r   r9   rE   rB   r6   )r   ŚoriginalSourceŚimportingSourceZimportingDictŚnestingObjectŚnestingObjectDictŚnestedObjectr   r   r   Śtest_failsWithDifferentModulev   s.   ž’’’’
’z3OriginalLocationTests.test_failsWithDifferentModulec                 C   sp   t  d”}|  || jd”}|  |  |d ”” |  |  |d ”” |d }|  |”}|d }|  |  |”” dS )z
        L{isOriginalLocation} returns True when the attribute refers to an
        object inside the module where that object was defined.
        zé
        class ThisClassWasDefinedHere(object):
            pass
        anObject = ThisClassWasDefinedHere()
        aNestingObject = ThisClassWasDefinedHere()
        aNestingObject.nestedObject = ThisClassWasDefinedHere()
        zm.pyzm.ThisClassWasDefinedHerezm.aNestingObjectzm.aNestingObject.nestedObjectN)r(   r)   r9   r   Z
assertTruerB   r6   )r   ZmSourceZmDictrL   rM   rN   r   r   r   Śtest_succeedsWithSameModule   s   
’
z1OriginalLocationTests.test_succeedsWithSameModule)	r:   r;   r<   r=   r   rG   rO   rP   r>   r   r   r   r   r?   Q   s    %r?   c                       sl   e Zd ZdZdZ f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  ZS )ŚFindMachinesViaWrapperTestszĶ
    L{findMachinesViaWrapper} recursively yields FQPN,
    L{MethodicalMachine} pairs in and under a given
    L{twisted.python.modules.PythonModule} or
    L{twisted.python.modules.PythonAttribute}.
    aŹ  
    from automat import MethodicalMachine


    class PythonClass(object):
        _classMachine = MethodicalMachine()

        class NestedClass(object):
            _nestedClassMachine = MethodicalMachine()

        ignoredAttribute = "I am ignored."

        def ignoredMethod(self):
            "I am also ignored."

    rootLevelMachine = MethodicalMachine()
    ignoredPythonObject = PythonClass()
    anotherIgnoredPythonObject = "I am ignored."
    c                    r@   )NrA   )ŚfindMachinesViaWrapper)r   rQ   r   rC   rR   )r   rR   r   r   r   r   Ļ   rD   z!FindMachinesViaWrapperTests.setUpc                 C   s>   d}|   || jd”}|d }|  d| ” ft|  |”” dS )zÄ
        When given a L{twisted.python.modules.PythonAttribute} that refers
        directly to a L{MethodicalMachine}, L{findMachinesViaWrapper}
        yields that machine and its FQPN.
        śa        from automat import MethodicalMachine

        rootMachine = MethodicalMachine()
        śroot.pyśroot.rootMachineN)r9   r   ŚassertInr7   ŚlistrR   )r   r*   rF   ŚrootMachiner   r   r   Śtest_yieldsMachineŌ   s   ’z.FindMachinesViaWrapperTests.test_yieldsMachinec                 C   s@   d}|   || jd”}|d }|  d| ” jft|  |”” dS )zķ
        When given a L{twisted.python.modules.PythonAttribute} that refers
        to a class that contains a L{MethodicalMachine} as a class
        variable, L{findMachinesViaWrapper} yields that machine and
        its FQPN.
        ś        from automat import MethodicalMachine

        class PythonClass(object):
            _classMachine = MethodicalMachine()
        ś	clsmod.pyśclsmod.PythonClassś clsmod.PythonClass._classMachineN)r9   r   rV   r7   Ś_classMachinerW   rR   ©r   r*   rF   ŚPythonClassr   r   r   Śtest_yieldsMachineInClasså   s   ’žz5FindMachinesViaWrapperTests.test_yieldsMachineInClassc                 C   sB   d}|   || jd”}|d }|  d| ” jjft|  |”” dS )zō
        When given a L{twisted.python.modules.PythonAttribute} that refers
        to a nested class that contains a L{MethodicalMachine} as a
        class variable, L{findMachinesViaWrapper} yields that machine
        and its FQPN.
        śµ        from automat import MethodicalMachine

        class PythonClass(object):
            class NestedClass(object):
                _classMachine = MethodicalMachine()
        śnestedcls.pyśnestedcls.PythonClassś/nestedcls.PythonClass.NestedClass._classMachineN)r9   r   rV   r7   ŚNestedClassr^   rW   rR   r_   r   r   r   Śtest_yieldsMachineInNestedClassų   s   ž
’žz;FindMachinesViaWrapperTests.test_yieldsMachineInNestedClassc                 C   sD   d}|   || jd”}|  |”d  ” }|  d|ft|  |”” dS )zĻ
        When given a L{twisted.python.modules.PythonModule} that refers to
        a module that contains a L{MethodicalMachine},
        L{findMachinesViaWrapper} yields that machine and its FQPN.
        rS   rT   rU   N)r1   r   r8   r7   rV   rW   rR   )r   r*   r"   rX   r   r   r   Śtest_yieldsMachineInModule  s   
’z6FindMachinesViaWrapperTests.test_yieldsMachineInModulec                 C   sF   d}|   || jd”}|  |”d  ” }|  d|jft|  |”” dS )zź
        When given a L{twisted.python.modules.PythonModule} that refers to
        the original module of a class containing a
        L{MethodicalMachine}, L{findMachinesViaWrapper} yields that
        machine and its FQPN.
        rZ   r[   r\   r]   N)r1   r   r8   r7   rV   r^   rW   rR   ©r   r*   r"   r`   r   r   r   Ś!test_yieldsMachineInClassInModule  s   ’’’’žz=FindMachinesViaWrapperTests.test_yieldsMachineInClassInModulec                 C   sH   d}|   || jd”}|  |”d  ” }|  d|jjft|  |”” dS )zń
        When given a L{twisted.python.modules.PythonModule} that refers to
        the original module of a nested class containing a
        L{MethodicalMachine}, L{findMachinesViaWrapper} yields that
        machine and its FQPN.
        rb   rc   rd   re   N)	r1   r   r8   r7   rV   rf   r^   rW   rR   ri   r   r   r   Ś'test_yieldsMachineInNestedClassInModule3  s   ’’’’žzCFindMachinesViaWrapperTests.test_yieldsMachineInNestedClassInModulec                 C   s@   d}d}|   || jd” |   || jd”}|  t|  |”” dS )aM  
        When given a L{twisted.python.modules.PythonAttribute} that refers
        to a class imported from another module, any
        L{MethodicalMachine}s on that class are ignored.

        This behavior ensures that a machine is only discovered on a
        class when visiting the module where that class was defined.
        z
        from automat import MethodicalMachine

        class PythonClass(object):
            _classMachine = MethodicalMachine()
        z2
        from original import PythonClass
        rH   rI   N©r1   r   rE   rW   rR   )r   rJ   rK   ZimportingModuler   r   r   Śtest_ignoresImportedClassI  s   	žz5FindMachinesViaWrapperTests.test_ignoresImportedClassc           
      C   sĄ   |   | jg”}|  | j” d”}| ”  | d” ”  d}|  ||jd” |d }t|  	|”t
 d”d}|  |d ”}|d  ” }|d	  ” }td|fd
|jfgt
 d”d}	|  |	|” dS )z`
        L{findMachinesViaWrapper} descends into packages to discover
        machines.
        Śtest_packageś__init__.pyzø
        from automat import MethodicalMachine


        class PythonClass(object):
            _classMachine = MethodicalMachine()


        rootMachine = MethodicalMachine()
        ś	module.pyr   ©Śkeyr"   ztest_package.module.rootMachineztest_package.module.PythonClassz-test_package.module.PythonClass._classMachineN)r   r   r   r%   ŚmakedirsŚtouchr1   r   ŚsortedrR   ŚoperatorŚ
itemgetterr8   r7   r^   ŚassertEqual)
r   Ś
pythonPathŚpackager*   rn   ŚmachinesrF   rX   r`   ŚexpectedMachinesr   r   r   Śtest_descendsIntoPackagesd  s0   

’’’žüz5FindMachinesViaWrapperTests.test_descendsIntoPackagesc                 C   s,   d}|   || jd”}|  t|  |”” dS )z
        L{findMachinesViaWrapper} ignores infinite loops.

        Note this test can't fail - it can only run forever!
        zh
        class InfiniteLoop(object):
            pass

        InfiniteLoop.loop = InfiniteLoop
        zloop.pyNrl   )r   r*   r"   r   r   r   Śtest_infiniteLoop  s   z-FindMachinesViaWrapperTests.test_infiniteLoop)r:   r;   r<   r=   ZTEST_MODULE_SOURCEr   rY   ra   rg   rh   rj   rk   rm   r}   r~   r>   r   r   r   r   rQ   ³   s    &rQ   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 )ŚWrapFQPNTestsz
    Tests that ensure L{wrapFQPN} loads the
    L{twisted.python.modules.PythonModule} or
    L{twisted.python.modules.PythonAttribute} for a given FQPN.
    c                 C   sP   ddl m}m} ddlm}m}m}m} || _|| _|| _|| _|| _|| _d S )Nr   )ŚPythonModuleŚPythonAttributerA   )ŚwrapFQPNŚInvalidFQPNŚNoModuleŚNoObject)r   r   r   rC   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   r   ¢  s   
zWrapFQPNTests.setUpc                 C   s2   |   || j” |  |j|j” |  | ” |” dS )zt
        Assert that a L{twisted.python.modules.PythonModule} refers to a
        particular Python module.
        N)ŚassertIsInstancer   rx   r2   r:   ŚassertIsr7   )r   ŚmoduleWrapperr"   r   r   r   ŚassertModuleWrapperRefersTo­  s   z)WrapFQPNTests.assertModuleWrapperRefersToc                 C   s0   |   || j” |  |j|” |  | ” |” dS )zw
        Assert that a L{twisted.python.modules.PythonAttribute} refers to a
        particular Python object.
        N)r   r   rx   r2   r   r7   )r   ZattributeWrapperŚfqpnŚobjr   r   r   ŚassertAttributeWrapperRefersTo¶  s   z,WrapFQPNTests.assertAttributeWrapperRefersToc                 C   ó<   |   | j” |  d” W d   dS 1 sw   Y  dS )zO
        L{wrapFQPN} raises L{InvalidFQPN} when given an empty string.
        Ś N©ŚassertRaisesr   r   ©r   r   r   r   Śtest_failsWithEmptyFQPNæ  s   "’z%WrapFQPNTests.test_failsWithEmptyFQPNc              	   C   óD   dD ]}|   | j” |  |” W d   n1 sw   Y  qdS )zk"
        L{wrapFQPN} raises L{InvalidFQPN} when given a badly-dotted
        FQPN.  (e.g., x..y).
        )z.failszfails.zthis..failsNr   ©r   Zbadr   r   r   Śtest_failsWithBadDottingĘ  s   ’’z&WrapFQPNTests.test_failsWithBadDottingc                 C   s4   ddl }|  d”}|  || j” |  | ” |” dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
        referring to the single module a dotless FQPN describes.
        r   Nr.   )r.   r   r   r   r   r7   )r   r.   r   r   r   r   Śtest_singleModuleĻ  s   
zWrapFQPNTests.test_singleModulec                 C   r   )z~
        L{wrapFQPN} raises L{NoModule} when given a dotless FQPN that does
        not refer to a module or package.
        zthis is not an acceptable name!N)r   r   r   r   r   r   r   Ś*test_failsWithMissingSingleModuleOrPackageŪ  s   "’z8WrapFQPNTests.test_failsWithMissingSingleModuleOrPackagec                 C   s   ddl }|  |  d”|” dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
        referring to the single package a dotless FQPN describes.
        r   NŚxml)r   r   r   ©r   r   r   r   r   Śtest_singlePackageć  s   z WrapFQPNTests.test_singlePackagec                 C   s    ddl }|  |  d”|j” dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
        referring to the deepest package described by dotted FQPN.
        r   Nz	xml.etree)Z	xml.etreer   r   Śetreer   r   r   r   Śtest_multiplePackagesė  s   z#WrapFQPNTests.test_multiplePackagesc                 C   s"   ddl }|  |  d”|jj” dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
        referring to the deepest module described by dotted FQPN.
        r   Nzxml.etree.ElementTree)Śxml.etree.ElementTreer   r   r   ŚElementTreer   r   r   r   Ś test_multiplePackagesFinalModuleó  ó   ’z.WrapFQPNTests.test_multiplePackagesFinalModulec                 C   s"   ddl }|  |  d”d|j” dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonAttribute}
        referring to the deepest object an FQPN names, traversing one module.
        r   Nzos.path)r.   r   r   r   )r   r.   r   r   r   Śtest_singleModuleObjectü  r    z%WrapFQPNTests.test_singleModuleObjectc                 C   sL   ddl }ddl}d|jjjfd|jjffD ]\}}|  |  |”||” qdS )z¼
        L{wrapFQPN} returns a L{twisted.python.modules.PythonAttribute}
        referring to the deepest object described by an FQPN,
        descending through several packages.
        r   Nz xml.etree.ElementTree.fromstringz!automat.MethodicalMachine.__doc__)	r   Śautomatr   r   Z
fromstringZMethodicalMachiner=   r   r   )r   r   r¢   r   r   r   r   r   Śtest_multiplePackagesObject  s   ’’ž’üz)WrapFQPNTests.test_multiplePackagesObjectc              	   C   r   )z
        L{wrapFQPN} raises L{NoObject} when given an FQPN that contains a
        missing attribute, module, or package.
        )zxml.etree.nope!z*xml.etree.nope!.but.the.rest.is.believableN)r   r   r   r   r   r   r   Ś4test_failsWithMultiplePackagesMissingModuleOrPackage  s   ’žzBWrapFQPNTests.test_failsWithMultiplePackagesMissingModuleOrPackageN)r:   r;   r<   r=   r   r   r   r   r   r   r   r   r   r   r”   r£   r¤   r   r   r   r   r     s    					r   c                       s,   e Zd ZdZdZ fddZdd Z  ZS )ŚFindMachinesIntegrationTestszs
    Integration tests to check that L{findMachines} yields all
    machines discoverable at or below an FQPN.
    zŚ
    from automat import MethodicalMachine

    class PythonClass(object):
        _machine = MethodicalMachine()
        ignored = "i am ignored"

    rootLevel = MethodicalMachine()

    ignored = "i am ignored"
    c                    s¾   t t|  ”  ddlm} || _|  | j” d”}| ”  |  	| jg”| _
|  | j|jd” | d”}| ”  | d” ”  |  | j|jd” |  | j
d ”| _|  | j
d d d ”| _d S )NrA   )ŚfindMachinesrn   ro   Z
subpackagerp   r"   )r   r„   r   rC   r¦   r   r   r%   rs   r   ry   r-   ŚSOURCEr   rt   r1   r8   ŚpackageDictrF   )r   r¦   Z
packageDirZsubPackageDirr   r   r   r   3  s"   
’
’z"FindMachinesIntegrationTests.setUpc           	      C   s   t |  d”t d”d}| jd  ” }| jd  ” }| jd }| ” }| jd }| ” }t d|fd|jfd|fd	|jfgt d”d}|  ||” d
S )z
        Given a top-level package FQPN, L{findMachines} discovers all
        L{MethodicalMachine} instances in and below it.
        rn   r   rq   ztest_package.rootLevelztest_package.PythonClassz(test_package.subpackage.module.rootLevelz*test_package.subpackage.module.PythonClassz!test_package.PythonClass._machinez3test_package.subpackage.module.PythonClass._machineN)	ru   r¦   rv   rw   rØ   r7   rF   Z_machinerx   )	r   r{   ZtpRootLevelZtpPythonClassZmRLAttrZ
mRootLevelZmPCAttrZmPythonClassr|   r   r   r   Śtest_discoverAllI  s(   
’

’żśz-FindMachinesIntegrationTests.test_discoverAll)r:   r;   r<   r=   r§   r   r©   r>   r   r   r   r   r„      s
    r„   )rv   r.   r    r   r(   r   Zunittestr   r   r   r   r	   r?   rQ   r   r„   r   r   r   r   Ś<module>   s(    	<a g 