U
    {h:                     @   sJ  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Zd dlmZ ddl	m
Z
 ddlmZ ddlmZmZmZ ddlmZmZ ddl	mZ dd	lmZ G d
d deZdd ZG dd dejZG dd deZeeedddjdZeeedddjdZdd ZG dd deZ dd Z!d$ddZ"d%d d!Z#d"d# Z$dS )&    N)partial   )Errors)
CodeWriter)TreeFragmentstrip_common_indentStringParseContext)TreeVisitorVisitorTransform)TreePath)	PostParsec                       s$   e Zd Z fddZdd Z  ZS )NodeTypeWriterc                    s   t    d| _g | _d S )Nr   )super__init___indentsresultself	__class__ 4/tmp/pip-unpacked-wheel-fhl22ezh/Cython/TestUtils.pyr      s    
zNodeTypeWriter.__init__c                 C   s   | j sd}n0| j d }|d d k	r4d|dd  }n|d }| jd| j d||jjf   |  jd7  _| | |  jd8  _d S )	Nz(root)   z%s[%d]r      z  z%s: %s)Zaccess_pathr   appendr   r   __name__visitchildren)r   nodenameZtipr   r   r   
visit_Node   s    

zNodeTypeWriter.visit_Node)r   
__module____qualname__r   r    __classcell__r   r   r   r   r      s   r   c                 C   s(   t  }||  ddg|j dg S )zReturns a string representing the tree by class names.
    There's a leading and trailing whitespace so that it can be
    compared by simple string comparison while still making test
    cases look ok.
 )r   visitjoinr   )rootwr   r   r   	treetypes)   s    
r*   c                   @   sj   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dZ
dd ZefddZdd ZdS )
CythonTestc                 C   s   t   d S Nr   Zinit_threadr   r   r   r   setUp5   s    zCythonTest.setUpc                 C   s   t   d S r,   r-   r   r   r   r   tearDown8   s    zCythonTest.tearDownc              	   C   s   t |ts|d}t |ts(|d}tt||D ]$\}\}}| ||d|||f  q6| t|t|dd|d|f  dS )zHChecks that the given strings or lists of strings are equal line by liner$   zLine %d:
Exp: %s
Got: %s%Unmatched lines. Got:
%s
Expected:
%sN)
isinstancelistsplit	enumeratezipassertEquallenr'   )r   expectedr   idxexpected_lineZresult_liner   r   r   assertLines;   s    



zCythonTest.assertLinesc                 C   s   t  }|| |jjS r,   )r   writer   lines)r   treewriterr   r   r   codeToLinesG   s    
zCythonTest.codeToLinesc                 C   s   d | |S )Nr$   )r'   r@   )r   r>   r   r   r   codeToStringL   s    zCythonTest.codeToStringc              	   C   st   |  |}t|d}tt||D ]$\}\}}| ||d|||f  q&| t|t|dd||f  d S )Nr$   zLine %d:
Got: %s
Exp: %sr0   )r@   r   r3   r4   r5   r6   r7   r'   )r   r8   result_treeZresult_linesZexpected_linesr9   liner:   r   r   r   
assertCodeO   s    
zCythonTest.assertCodec                 C   s   |  t||d d|  d S )Nz"Path '%s' not found in result tree)ZassertNotEqualr   
find_first)r   pathrB   r   r   r   assertNodeExistsZ   s    zCythonTest.assertNodeExistsNc                 C   sV   |dkri }|dkrg }|   }|dr:|tdd }|dd}t||||dS )zNSimply create a tree fragment using the name of the test-case in parse errors.Nz	__main__.._pipeline)id
startswithr7   replacer   )r   codepxdsrK   r   r   r   r   fragment^   s    
zCythonTest.fragmentc                 C   s   t |S r,   )r*   )r   r(   r   r   r   r*   j   s    zCythonTest.treetypesc              
   C   sX   z|  |  d|  W n: |k
rR } z| t|| | W Y S d}~X Y nX dS )zCalls "func" and fails if it doesn't raise the right exception
        (any exception by default). Also returns the exception in question.
        z Expected an exception of type %rN)fail
assertTruer1   )r   funcexc_typeer   r   r   should_failm   s    zCythonTest.should_failc              
   C   s>   z| W S  t k
r8 } z| t| W 5 d}~X Y nX dS )zCalls func and succeeds if and only if no exception is raised
        (i.e. converts exception raising into a failed testcase). Returns
        the return value of func.N)	ExceptionrR   str)r   rT   excr   r   r   should_not_failx   s    zCythonTest.should_not_fail)NN)r   r!   r"   r.   r/   r;   r@   rA   rD   rG   rQ   r*   rX   rW   r[   r   r   r   r   r+   3   s   
r+   c                   @   s   e Zd ZdZdddZdS )TransformTesta.  
    Utility base class for transform unit tests. It is based around constructing
    test trees (either explicitly or by parsing a Cython code string); running
    the transform, serialize it using a customized Cython serializer (with
    special markup for nodes that cannot be represented in Cython),
    and do a string-comparison line-by-line of the result.

    To create a test case:
     - Call run_pipeline. The pipeline should at least contain the transform you
       are testing; pyx should be either a string (passed to the parser to
       create a post-parse tree) or a node representing input to pipeline.
       The result will be a transformed result.

     - Check that the tree is correct. If wanted, assertCode can be used, which
       takes a code string as expected, and a ModuleNode in result_tree
       (it serializes the ModuleNode to a string and compares line-by-line).

    All code strings are first stripped for whitespace lines and then common
    indentation.

    Plans: One could have a pxd dictionary parameter to run_pipeline.
    Nc                 C   s0   |d kri }|  ||j}|D ]}||}q|S r,   )rQ   r(   )r   rK   ZpyxrP   r>   Tr   r   r   run_pipeline   s    
zTransformTest.run_pipeline)N)r   r!   r"   __doc__r^   r   r   r   r   r\      s   r\   z\s+r%   zz
        /[*] (
            (?: [^*\n] | [*][^/] )*
            [\n]
            (?: [^*] | [*][^/] )*
        ) [*]/
    z\s\s+z
    (?:
        <pre class=["'][^"']*cython\s+line[^"']*["']\s*>
        (?:[^<]|<(?!/pre))+
        </pre>
    )|(?:
        <style[^>]*>
        (?:[^<]|<(?!/style))+
        </style>
    )
    c                 C   s   d  }}|  dr6tjd| dd  dd\}} |  } |  dr~| dd   } |  dr~tjd| dd  dd\}} |  } ||| fS )N/z(?<!\\)/r   )maxsplit:)rM   rer3   strip)patternstartendr   r   r   _parse_pattern   s    


rh   c                       sB   e Zd Z fddZdd Zdd Zdd Zd	d
 Zej	Z
  ZS )TreeAssertVisitorc                    s    t    d | _g | _g | _d S r,   )r   r   _module_pos_c_patterns_c_antipatternsr   r   r   r   r      s    
zTreeAssertVisitor.__init__c                    sL   j j  dd fdd fdd fdd}|S )	Nc                 S   s"   t | d||rdnd|f  d S )NzPattern '%s' %s found in %swaszwas not)r   error)posre   found	file_pathr   r   r   rR      s
    
z7TreeAssertVisitor.create_c_file_validator.<locals>.failc                    st   |r8t ||}|r&|| d  }n j|d| d |rpt ||}|r^|d |  }n j|d| d |S )NFrp   rq   )rc   searchrg   rj   rf   )rq   contentrf   rg   r3   )rR   r   r   r   extract_section   s    zBTreeAssertVisitor.create_c_file_validator.<locals>.extract_sectionc                    s   D ]>}t |\}}}| |||}t||sj|d| d q D ]>}t |\}}}| |||}t||rHj|d| d qHd S )NFrr   T)rh   rc   rs   rj   )rq   rt   re   rf   rg   sectionZantipattern)antipatternsru   rR   patternsr   r   r   validate_file_content   s    zHTreeAssertVisitor.create_c_file_validator.<locals>.validate_file_contentc              	      sH   | j }s s| S t|dd}| }W 5 Q R X t|}|| d S )Nutf8)encoding)c_fileopenread_strip_c_comments)r   r|   frt   )rw   rx   ry   r   r   validate_c_file   s    zBTreeAssertVisitor.create_c_file_validator.<locals>.validate_c_file)rk   rl   )r   r   r   )rw   ru   rR   rx   r   ry   r   create_c_file_validator   s    z)TreeAssertVisitor.create_c_file_validatorc                 C   s   |j }d|kr>|d D ]&}t||d krt|jd|  qd|krz|d D ]*}t||}|d k	rNt|jd|  qNd|kr| j|d  d|kr| j|d  d S )NZtest_assert_path_existsz+Expected path '%s' not found in result treeZtest_fail_if_path_existsz)Unexpected path '%s' found in result treeZtest_assert_c_code_hasZtest_fail_if_c_code_has)	
directivesr   rE   r   rn   ro   rk   extendrl   )r   r   r   rF   Z
first_noder   r   r   _check_directives  s(    z#TreeAssertVisitor._check_directivesc                 C   s    |j | _| | | | |S r,   )ro   rj   r   r   r   r   r   r   r   visit_ModuleNode!  s    

z"TreeAssertVisitor.visit_ModuleNodec                 C   s   |  | | | |S r,   )r   r   r   r   r   r   visit_CompilerDirectivesNode'  s    

z.TreeAssertVisitor.visit_CompilerDirectivesNode)r   r!   r"   r   r   r   r   r   r
   Zrecurse_to_childrenr    r#   r   r   r   r   ri      s   5ri   c              
   C   s  t jgt jtj|dgt jtj|dgd}|d kr@t }g d  }}t| dZ}z<|D ]0}|d d dkr|	 	d	 
dd	tjj}tj||}	tjtj|	sttj|	 |d k	r|d  }
}|
  t|	d
}q`|d k	r
|| q`|	 r`| ds`|	 dkr`t|
d}|sDq`|d |dd   }}z||| |  W q` tk
r   || Y q`X q`W 5 |d k	r|  X W 5 Q R X ||fS )Nz	cython.pyzcythonize.py)PYTHONZCYTHONZ	CYTHONIZErb   s   #####   #rz   r`   wb)s   """s   '''r   r   )sys
executableosrF   r'   tempfilemkdtempr}   closerd   decoderN   sepexistsdirnamemakedirsr<   lstriprM   shlexr3   r   KeyError)Z	tree_fileZworkdirZcython_rootZprogramsheaderZcur_filer   rC   filenamerF   to_closecommandprogargsr   r   r   unpack_source_tree/  sD    

$

 
r   Fc              	   C   sh   t |trd}d}d}nd}d}d}|dkr0|}|r>t|}t| |||d}|| W 5 Q R X dS )zWrite some content (text or bytes) to the file
    at `file_path` without translating `'\n'` into `os.linesep`.

    The default encoding is `'utf-8'`.
    r   Nr)   r$   zutf-8)moder{   newline)r1   bytestextwrapdedentr}   r<   )rq   rt   r   r{   r   r   default_encodingr   r   r   r   
write_fileW  s    

r   c                 C   sh   t | |||d ztj|}W n tk
r8   d}Y nX |dksR|tj| krdt | |||d q:dS )z
    Write `content` to the file `file_path` without translating `'\n'`
    into `os.linesep` and make sure it is newer than the file `newer_than`.

    The default encoding is `'utf-8'` (same as for `write_file`).
    )r   r{   N)r   r   rF   getmtimeOSError)rq   Z
newer_thanrt   r   r{   Z
other_timer   r   r   write_newer_fileu  s    
r   c              
   C   s   t d}zFt  }t| t|gd}| }W 5 Q R X |rF|d n|W S W n. tjk
r| } zt|jW 5 d}~X Y nX dS )z
    Compiles code far enough to get errors from the parser and post-parse stage.

    Is useful for checking for syntax errors, however it doesn't generate runable
    code.
    testrJ   r   N)	r   r   Zlocal_errorsr   r   
substituteCompileErrorSyntaxErrorZmessage_only)rO   contexterrorsr   rV   r   r   r   py_parse_code  s    


r   )FN)FN)%r   rc   Zunittestr   r   r   r   	functoolsr   ZCompilerr   r   ZCompiler.TreeFragmentr   r   r   ZCompiler.Visitorr	   r
   r   ZCompiler.ParseTreeTransformsr   r   r*   ZTestCaser+   r\   compilesubr   Z_strip_cython_code_from_htmlrh   ri   r   r   r   r   r   r   r   r   <module>   sB   
O&
a(

