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 