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 )NÚ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   Útwisted.python.filepathr   ÚsetÚsysÚmodulesÚkeysÚoriginalSysModulesÚpathÚsavedSysPathÚtempfileÚ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   ÚsixÚviewkeysr   r   ÚshutilÚrmtreer   )r   Ú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   Ú
moduleNameÚ	directoryr'   Úfr   r   r   ÚwriteSourceInto7   s   

ÿz$_WritesPythonModules.writeSourceIntoc                 C   s"   t j |¡\}}|  |||¡| S r    )Úosr   Úsplitextr3   )r   r/   r   r0   Ú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>)ÚiterAttributes)r   ÚhasIterAttributesr   r   r   ÚattributesAsDictF   s   z%_WritesPythonModules.attributesAsDictc                 C   s   |  ¡  |  |¡S r    )Úloadr?   )r   r'   r   r   r   ÚloadModuleAsDictI   s   
z%_WritesPythonModules.loadModuleAsDictc                 C   s   |   |  |||¡¡S r    )rA   r8   )r   r/   r   r9   r   r   r   ÚmakeModuleAsDictM   s   z%_WritesPythonModules.makeModuleAsDict)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r!   r   r3   r8   r?   rA   rB   Ú__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   rH   r   Ú	_discoverrK   )r   rK   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)rB   r   ÚassertFalserK   )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)r8   r   rB   rN   rK   r?   )r   ÚoriginalSourceÚimportingSourceÚ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.   rB   r   Ú
assertTruerK   r?   )r   ÚmSourceÚmDictrV   rW   rX   r   r   r   Útest_succeedsWithSameModule›   s   
ÿ
z1OriginalLocationTests.test_succeedsWithSameModule)	rC   rD   rE   rF   r   rP   rY   r]   rG   r   r   r   r   rH   Q   s    %rH   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                    rI   )NrJ   )ÚfindMachinesViaWrapper)r   r^   r   rL   r_   )r   r_   r   r   r   r   Ï   rM   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)rB   r   ÚassertInr@   Úlistr_   )r   r/   rO   Ú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)rB   r   rc   r@   Ú_classMachinerd   r_   ©r   r/   rO   Ú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)rB   r   rc   r@   ÚNestedClassrk   rd   r_   rl   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.
        r`   ra   rb   N)r8   r   rA   r@   rc   rd   r_   )r   r/   r'   re   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.
        rg   rh   ri   rj   N)r8   r   rA   r@   rc   rk   rd   r_   ©r   r/   r'   rm   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.
        ro   rp   rq   rr   N)	r8   r   rA   r@   rc   rs   rk   rd   r_   rv   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
        rQ   rR   N©r8   r   rN   rd   r_   )r   rS   rT   Ú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Útouchr8   r   Úsortedr_   ÚoperatorÚ
itemgetterrA   r@   rk   ÚassertEqual)
r   Ú
pythonPathÚpackager/   r|   ÚmachinesrO   re   rm   Ú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.pyNry   )r   r/   r'   r   r   r   Útest_infiniteLoopŠ  s   z-FindMachinesViaWrapperTests.test_infiniteLoop)rC   rD   rE   rF   ÚTEST_MODULE_SOURCEr   rf   rn   rt   ru   rw   rx   r{   r‹   rŒ   rG   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 )Ú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ÚPythonAttributerJ   )ÚwrapFQPNÚInvalidFQPNÚNoModuleÚNoObject)r   r�   r�   rL   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�   r†   r9   rC   ÚassertIsr@   )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�   r†   r9   r–   r@   )r   Ú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   Ú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   Nr4   )r4   r‘   r•   r�   r–   r@   )r   r4   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)Ú	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)r4   rœ   r‘   r   )r   r4   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°   Ú
fromstringÚMethodicalMachinerF   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)rC   rD   rE   rF   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 )NrJ   )ÚfindMachinesr|   r}   Ú
subpackager~   r'   )r   r¹   r   rL   rº   r   r   r*   r�   r   r‡   r3   ÚSOURCEr   r‚   r8   rA   ÚpackageDictrO   )r   rº   Ú
packageDirÚ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.
        r|   r   r   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)	rƒ   rº   r„   r…   r½   r@   rO   Ú_machiner†   )	r   r‰   ÚtpRootLevelÚtpPythonClassÚmRLAttrÚ
mRootLevelÚmPCAttrÚmPythonClassrŠ   r   r   r   Útest_discoverAllI  s(   
ÿ

ÿýúz-FindMachinesIntegrationTests.test_discoverAll)rC   rD   rE   rF   r¼   r   rÇ   rG   r   r   r   r   r¹      s
    r¹   )r„   r4   r$   r   r-   r   Úunittestr   r   r"   r	   r
   rH   r^   rŽ   r¹   r   r   r   r   Ú<module>   s(    	<a g 