B
    `d                 @   s  d Z ddlZddlZddlZddlZddlm  mZ ddl	m	Z	 ddl
mZ ddl
mZ ddl
mZ ddl
mZ ddl
mZ dd	l
mZ dd
l
m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 ddlmZ ddlmZ ddlmZ ddlmZ ddl m!Z! ddl"m#Z# ddl$m%Z% e#d  Z&e'e(dddZ)ddddZ*i Z+dddgie+d < dd!d"d#gie+d$< e+d  , e+d%< e*e+d% e+d$  e+d  e+d&< G d'd( d(Z-ee(dd)d*d+Z.ej/eee(e'gdf d,d-d.Z0ej/eee(e'gdf d,d/d0Z1e(e(dd1d2d3Z2ej/d4d5eee(e'gdf d,d6d7Z3edd8d9d:Z4edd;d<d=Z5edd;d>d?Z6e(ee( d@dAdBZ7G dCd dZ8dS )Da  Report test results in JUnit-XML format, for use with Jenkins and build
integration servers.

Based on initial code from Ross Lawley.

Output conforms to
https://github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd
    N)datetime)Callable)Dict)List)Match)Optional)Tuple)Union)nodes)timing)ExceptionRepr)ReprFileLocation)Config)filename_arg)Parser)FixtureRequest)
TestReport)StoreKey)TerminalReporterLogXML)argreturnc             C   s*   t t tddd}d}t||t| S )a!  Visually escape invalid XML characters.

    For example, transforms
        'hello\aworld\b'
    into
        'hello#x07world#x08'
    Note that the #xABs are *not* XML escapes - missing the ampersand &#xAB.
    The idea is to escape visually for the user rather than for XML itself.
    )matchobjr   c             S   s(   t |  }|dkrd| S d| S d S )N   z#x%02Xz#x%04X)ordgroup)r   i r   X/home/kop/projects/devel/pgwui/test_venv/lib/python3.7/site-packages/_pytest/junitxml.pyrepl3   s    zbin_xml_escape.<locals>.replu    [^	
 -~-퟿-�က0-ჿFF])r   strresub)r   r   Zillegal_xml_rer   r   r   bin_xml_escape(   s    r#   )r   c             C   s`   i }xL|   D ]@\}}x6|  D ]*\}}t|ts>tt||| ||< q W qW | | d S )N)items
isinstancelist	TypeErrortypeupdate)leftrightresultklZvlZkrZvrr   r   r   merge_familyC   s    
r.   testcase	classnamename_basefilelineurlZ_base_legacyxunit1xunit2c               @   sN  e Zd Zeeef dddddZejddddZ	ee
dd	d
dZee
dd	ddZeej dddZeddddZejdddZd0eeee ddddZeddddZeeedddZeeeddd d!Zeddd"d#Zeddd$d%Zeddd&d'Zeddd(d)Zeddd*d+Zeddd,d-Zddd.d/ZdS )1_NodeReporterr   N)nodeidxmlr   c             C   s<   || _ || _| jj| _| jj| _d| _g | _g | _i | _d S )Nr   )idr:   	add_statsfamilyduration
propertiesr
   attrs)selfr9   r:   r   r   r   __init__Z   s    

z_NodeReporter.__init__)noder   c             C   s   | j |j | j| d S )N)r:   r<   tagr
   append)rA   rC   r   r   r   rE   d   s    z_NodeReporter.append)r1   valuer   c             C   s   | j t|t|f d S )N)r?   rE   r    r#   )rA   r1   rF   r   r   r   add_propertyh   s    z_NodeReporter.add_propertyc             C   s   t || jt|< d S )N)r#   r@   r    )rA   r1   rF   r   r   r   add_attributek   s    z_NodeReporter.add_attribute)r   c             C   sB   | j r>td}x(| j D ]\}}|tjd||d qW |S dS )z9Return a Junit node containing custom properties, if any.r?   property)r1   rF   N)r?   ETElementrE   )rA   r?   r1   rF   r   r   r   make_properties_noden   s    
z"_NodeReporter.make_properties_node)
testreportr   c             C   s   t |j}| j}|d d }| jjr4|d| jj d|t|d |jd d}|jd d k	rtt	|jd |d< t
|dr|j|d< || _| j| | jdkrd S i }x2| j D ]$}|t| j d	 kr| j| ||< qW || _d S )
Nr   .)r0   r1   r3      r4   r5   r6   r/   )mangle_test_addressr9   r@   r:   prefixinsertjoinr#   locationr    hasattrr5   r)   r=   keysfamilies)rA   rM   namesZexisting_attrsZ
classnamesr@   Z
temp_attrskeyr   r   r   record_testreportw   s*    




z_NodeReporter.record_testreportc             C   sB   t jd| jd| j d}|  }|d k	r2|| || j |S )Nr/   z%.3f)time)rJ   rK   r@   r>   rL   rE   extendr
   )rA   r/   r?   r   r   r   to_xml   s    
z_NodeReporter.to_xml)rD   messagedatar   c             C   s&   t j||d}t||_| | d S )N)r_   )rJ   rK   r#   textrE   )rA   rD   r_   r`   rC   r   r   r   _add_simple   s    
z_NodeReporter._add_simple)reportr   c             C   s   | j js|jrd S |j}|j}|j}| j jdkr4d S d}| j jdkrP| |d}| j jdkr~|| |d7 }| ||d d}| j jdkr|| |d	7 }| ||d
 d}|r| ||d d S )Nno )logallz Captured Log )z
system-outzout-errrg   z Captured Out z
system-out)z
system-errzout-errrg   z Captured Err z
system-err)	r:   log_passing_testspassedZ	capstdoutZcaplogZ	capstderrlogging_prepare_content_write_content)rA   rc   Zcontent_outZcontent_logZcontent_errZcontent_allr   r   r   write_captured_output   s(    z#_NodeReporter.write_captured_output)contentheaderr   c             C   s   d |dd|dgS )N
P   -re   )rT   center)rA   rn   ro   r   r   r   rk      s    z_NodeReporter._prepare_content)rc   rn   jheaderr   c             C   s"   t |}t||_| | d S )N)rJ   rK   r#   ra   rE   )rA   rc   rn   rt   rD   r   r   r   rl      s    

z_NodeReporter._write_contentc             C   s   |  d d S )Nri   )r<   )rA   rc   r   r   r   append_pass   s    z_NodeReporter.append_passc             C   sn   t |dr| dd nR|jd k	s&tt|jdd }|d k	rD|j}n
t|j}t|}| d|t|j d S )Nwasxfailskippedz%xfail-marked test passes unexpectedly	reprcrashfailure)rV   rb   longreprAssertionErrorgetattrr_   r    r#   )rA   rc   rx   r_   r   r   r   append_failure   s    

z_NodeReporter.append_failurec             C   s&   |j d k	st| ddt|j  d S )Nerrorzcollection failure)rz   r{   rb   r    )rA   rc   r   r   r   append_collect_error   s    z"_NodeReporter.append_collect_errorc             C   s   |  ddt|j d S )Nrw   zcollection skipped)rb   r    rz   )rA   rc   r   r   r   append_collect_skipped   s    z$_NodeReporter.append_collect_skippedc             C   sr   |j d k	stt|j dd }|d k	r,|j}n
t|j }|jdkrNd| d}nd| d}| d|t|j  d S )Nrx   teardownzfailed on teardown with ""zfailed on setup with "r~   )rz   r{   r|   r_   r    whenrb   )rA   rc   rx   reasonmsgr   r   r   append_error   s    

z_NodeReporter.append_errorc             C   s   t |drJ|j}|dr&|dd  }t|}tjdd|d}| | ntt|jt	sZt
|j\}}}|dr||dd  }| d	| d
| }tjdd|d}t||_| | | | d S )Nrv   zreason:    rw   zpytest.xfail)r(   r_   z	Skipped: 	   :z: zpytest.skip)rV   rv   
startswithr#   rJ   rK   rE   r%   rz   tupler{   ra   rm   )rA   rc   Zxfailreasonrw   filenamelinenoZ
skipreasondetailsr   r   r   append_skipped   s     




z_NodeReporter.append_skippedc                s$   |    | j   fdd| _ d S )Nc                  s    S )Nr   r   )r`   r   r   <lambda>      z(_NodeReporter.finalize.<locals>.<lambda>)r^   __dict__clear)rA   r   )r`   r   finalize   s    
z_NodeReporter.finalize)N)__name__
__module____qualname__r	   r    r   rB   rJ   rK   rE   objectrG   rH   r   rL   r[   r^   rb   rm   rk   rl   ru   r}   r   r   r   r   r   r   r   r   r   r8   Y   s$   
	r8   )requestfixture_namer   c             C   sN   ddl m} | jjtd}|dk	rJ|jdkrJ| j|dj	||jd dS )z[Emit a PytestWarning about the given fixture being incompatible with newer xunit revisions.r   )PytestWarningN)r6   legacyzV{fixture_name} is incompatible with junit_family '{family}' (use 'legacy' or 'xunit1'))r   r=   )
_pytest.warning_typesr   config_storegetxml_keyr=   rC   warnformat)r   r   r   r:   r   r   r   !_warn_incompatibility_with_xunit2  s    r   )r   r   c                s$   t  d ttdd fdd}|S )an  Add extra properties to the calling test.

    User properties become part of the test report and are available to the
    configured reporters, like JUnit XML.

    The fixture is callable with ``name, value``. The value is automatically
    XML-encoded.

    Example::

        def test_function(record_property):
            record_property("example_key", 1)
    record_propertyN)r1   rF   r   c                s    j j| |f d S )N)rC   user_propertiesrE   )r1   rF   )r   r   r   append_property*  s    z(record_property.<locals>.append_property)r   r    r   )r   r   r   )r   r   r     s    
r   c             C   sl   ddl m} | j|d t| d ttdddd}|}| jj	t
d}|dk	rh|| jj}|j}|S )	zAdd extra xml attributes to the tag for the calling test.

    The fixture is callable with ``name, value``. The value is
    automatically XML-encoded.
    r   )PytestExperimentalApiWarningz/record_xml_attribute is an experimental featurerecord_xml_attributeN)r1   rF   r   c             S   s   d S )Nr   )r1   rF   r   r   r   add_attr_noop@  s    z+record_xml_attribute.<locals>.add_attr_noop)r   r   rC   r   r   r    r   r   r   r   r   node_reporterr9   rH   )r   r   r   Z	attr_funcr:   r   r   r   r   r   0  s    

r   )paramvr   c             C   s.   d}t |ts*d}t|j| t|jddS )zcUsed by record_testsuite_property to check that the given parameter name is of the proper
    type.Tz5{param} parameter needs to be a string, but {g} given)r   gN)r%   r    r'   r   r(   r   )r   r   __tracebackhide__r   r   r   r   _check_record_param_typeM  s    
r   session)Zscopec             C   s8   d}t tdddd}| jjtd}|dk	r4|j}|S )aH  Record a new ``<property>`` tag as child of the root ``<testsuite>``.

    This is suitable to writing global information regarding the entire test
    suite, and is compatible with ``xunit2`` JUnit family.

    This is a ``session``-scoped fixture which is called with ``(name, value)``. Example:

    .. code-block:: python

        def test_foo(record_testsuite_property):
            record_testsuite_property("ARCH", "PPC")
            record_testsuite_property("STORAGE_TYPE", "CEPH")

    ``name`` must be a string, ``value`` will be converted to a string and properly xml-escaped.

    .. warning::

        Currently this fixture **does not work** with the
        `pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See issue
        `#7767 <https://github.com/pytest-dev/pytest/issues/7767>`__ for details.
    TN)r1   rF   r   c             S   s   d}t d|  dS )zENo-op function in case --junitxml was not passed in the command-line.Tr1   N)r   )r1   rF   r   r   r   r   record_funcp  s    z.record_testsuite_property.<locals>.record_func)r    r   r   r   r   r   add_global_property)r   r   r   r:   r   r   r   record_testsuite_propertyV  s    r   )parserr   c          
   C   s   |  d}|jdddddtjtddd dd	 |jd
dddd dd | jdddd | jdddd | jddddd | jdddd | jddd d d S )!Nzterminal reportingz
--junitxmlz--junit-xmlstorexmlpathpath)optnamez1create junit-xml style report file at given path.)actiondestmetavarr(   defaulthelpz--junitprefixz--junit-prefixr    z0prepend prefix to classnames in junit-xml output)r   r   r   r   junit_suite_namez Test suite name for JUnit reportpytest)r   junit_loggingz\Write captured log messages to JUnit report: one of no|log|system-out|system-err|out-err|allrd   junit_log_passing_testsz;Capture log information for passing tests to JUnit report: boolT)r(   r   junit_duration_reportz*Duration time to report: one of total|calltotaljunit_familyz0Emit XML for schema: one of legacy|xunit1|xunit2r7   )ZgetgroupZ	addoption	functoolspartialr   Zaddini)r   r   r   r   r   pytest_addoption{  sH    
r   )r   r   c          
   C   sl   | j j}|rht| dsh| d}t|| j j| d| d| d|| d| jt< | j	| jt  d S )NZworkerinputr   r   r   r   r   )
optionr   rV   Zgetinir   Zjunitprefixr   r   pluginmanagerregister)r   r   r   r   r   r   pytest_configure  s    
r   c             C   s*   | j td }|r&| j t= | j| d S )N)r   r   r   r   
unregister)r   r:   r   r   r   pytest_unconfigure  s    r   )addressr   c             C   s   |  d\}}}|d}y|d W n tk
r<   Y nX |d tjd|d< tdd|d |d< |d  || 7  < |S )	N[z::z()r   rO   z\.py$re   rN   )		partitionsplitremove
ValueErrorreplacer
   ZSEPr!   r"   )r   r   Zpossible_open_bracketparamsrY   r   r   r   rQ     s    
rQ   c               @   s  e Zd Zd*ee eeeedddd	Zedd
ddZe	eef e
d
ddZeddddZee
d
ddZedd
ddZedd
ddZedd
ddZeddddZddddZddd d!Zedd"d#d$Zeedd%d&d'Zeej dd(d)ZdS )+r   r   rd   r   r6   TN)rR   
suite_namerj   report_durationrh   r   c             C   s   t jt j|}t jt j|| _|| _|| _|| _	|| _
|| _|| _tddddgd| _i | _g | _g | _g | _d| _| jdkrd| _d S )Nr~   ri   ry   rw   r   r   r6   )osr   
expanduser
expandvarsnormpathabspathlogfilerR   r   rj   rh   r   r=   dictfromkeysstatsnode_reportersnode_reporters_orderedglobal_propertiesopen_reportscnt_double_fail_tests)rA   r   rR   r   rj   r   r=   rh   r   r   r   rB     s"    

zLogXML.__init__)rc   r   c             C   s<   t |d|}t |dd }| j||f}|d k	r8|  d S )Nr9   rC   )r|   r   popr   )rA   rc   r9   
workernodereporterr   r   r   r     s
    zLogXML.finalizec             C   sX   t |d|}t |dd }||f}|| jkr4| j| S t|| }|| j|< | j| |S )Nr9   rC   )r|   r   r8   r   rE   )rA   rc   r9   r   rZ   r   r   r   r   r     s    



zLogXML.node_reporter)rZ   r   c             C   s    || j kr| j |  d7  < d S )NrP   )r   )rA   rZ   r   r   r   r<     s    
zLogXML.add_statsc             C   s   |  |}|| |S )N)r   r[   )rA   rc   r   r   r   r   _opentestcase  s    

zLogXML._opentestcasec                s  d} j r* jdkr|  }|  nĈ jrԈ jdkrt ddt ddt fdd| jD d}|r| | |  j	d7  _	|  } jdkr|
  | j  | js|  q|  n jr|  }|  |    jdkr|  }|  x$ jD ]\}}||t| q W |   t ddt ddt fd	d| jD d}|r| j| dS )
a  Handle a setup/call/teardown report, generating the appropriate
        XML tags as necessary.

        Note: due to plugins like xdist, this hook may be called in interlaced
        order with reports from other nodes. For example:

        Usual call order:
            -> setup node1
            -> call node1
            -> teardown node1
            -> setup node2
            -> call node2
            -> teardown node2

        Possible call order in xdist:
            -> setup node1
            -> call node1
            -> setup node2
            -> call node2
            -> teardown node2
            -> teardown node1
        Ncallr   	worker_id
item_indexc             3   s>   | ]6}|j  j krt|d dkrt|ddkr|V  qdS )r   Nr   )r9   r|   ).0rep)rc   	report_ii
report_widr   r   	<genexpr>;  s   z2LogXML.pytest_runtest_logreport.<locals>.<genexpr>rP   c             3   s>   | ]6}|j  j krt|d dkrt|ddkr|V  qdS )r   Nr   )r9   r|   )r   r   )rc   r   r   r   r   r   c  s   )ri   r   r   ru   failedr|   nextr   r   r   r}   rE   rh   rm   r   rw   r   update_testcase_durationr   rG   r    r   )rA   rc   Zclose_reportr   ZpropnameZ	propvaluer   )rc   r   r   r   pytest_runtest_logreport  sR    












zLogXML.pytest_runtest_logreportc             C   s:   | j dks|j| j kr6| |}| jt|dd7  _dS )zAccumulate total duration for nodeid from given report and update
        the Junit.testcase with the new total if already created.r   r>   g        N)r   r   r   r>   r|   )rA   rc   r   r   r   r   r   p  s    
zLogXML.update_testcase_durationc             C   s0   |j s,| |}|jr"|| n
|| d S )N)ri   r   r   r   r   )rA   rc   r   r   r   r   pytest_collectreportw  s
    
zLogXML.pytest_collectreport)excreprr   c             C   s0   |  d}|jjddd |ddt| d S )NZinternalr   )r0   r1   r~   zinternal error)r   r@   r)   rb   r    )rA   r   r   r   r   r   pytest_internalerror  s    
zLogXML.pytest_internalerror)r   c             C   s   t  | _d S )N)r   r\   suite_start_time)rA   r   r   r   pytest_sessionstart  s    zLogXML.pytest_sessionstartc       
      C   sF  t jt j| j}t j|s,t | t| jddd}t	 }|| j
 }| jd | jd  | jd  | jd  | j }|d tjd	| jt| jd t| jd t| jd t|d
| t| j
 t d	}|  }|d k	r|| x| jD ]}||  qW td}	|	| |tj|	dd |  d S )Nwzutf-8)encodingri   ry   rw   r~   z&<?xml version="1.0" encoding="utf-8"?>Z	testsuitez%.3f)r1   errorsZfailuresrw   testsr\   	timestamphostname
testsuitesunicode)r   r   dirnamer   r   isdirmakedirsopenr   r\   r   r   r   writerJ   rK   r   r    r   fromtimestamp	isoformatplatformrC   _get_global_properties_noderE   r   r^   tostringclose)
rA   r  r   Zsuite_stop_timeZsuite_time_deltaZnumtestsZ
suite_noder   r   r  r   r   r   pytest_sessionfinish  s6    

.



zLogXML.pytest_sessionfinish)terminalreporterr   c             C   s   | dd| j  d S )Nrr   zgenerated xml file: )Z	write_sepr   )rA   r  r   r   r   pytest_terminal_summary  s    zLogXML.pytest_terminal_summary)r1   rF   r   c             C   s&   d}t d| | j|t|f d S )NTr1   )r   r   rE   r#   )rA   r1   rF   r   r   r   r   r     s    
zLogXML.add_global_propertyc             C   sB   | j r>td}x(| j D ]\}}|tjd||d qW |S dS )z9Return a Junit node containing custom properties, if any.r?   rI   )r1   rF   N)r   rJ   rK   rE   )rA   r?   r1   rF   r   r   r   r    s    
z"LogXML._get_global_properties_node)r   rd   r   r6   T)r   r   r   r   r    r   rB   r   r   r	   r8   r   r<   r   r   r   r   r   r   r   r  r   r  r   r   rJ   rK   r  r   r   r   r   r     s&       X&)9__doc__r   r   r  r!   xml.etree.ElementTreeetreeElementTreerJ   r   typingr   r   r   r   r   r   r	   r   Z_pytestr
   r   Z_pytest._code.coder   r   Z_pytest.configr   r   Z_pytest.config.argparsingr   Z_pytest.fixturesr   Z_pytest.reportsr   Z_pytest.storer   Z_pytest.terminalr   r   r   r    r#   r.   rX   copyr8   r   Zfixturer   r   r   r   r   r   r   rQ   r   r   r   r   r   <module>   sd   

 1	
$/