U
    42ic                     @  sF  d Z ddlmZ ddlmZ ddlm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  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  ddl!m"Z" ddl#Z#e d  Z$dd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)d)ddd*d+d,Z*e#j+d)d-d.d/d0Z,e#j+d)d-d.d1d2Z-dddd3d4d5Z.e#j+d6d7d)d-d.d8d9Z/d:dd;d<d=Z0d>dd?d@dAZ1d>dd?dBdCZ2ddDdEdFdGZ3G dHd dZ4dS )Ia  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
    )annotations)datetime)timezoneN)Callable)Match)nodes)timing)ExceptionRepr)ReprFileLocation)Config)filename_arg)Parser)FixtureRequest)
TestReport)StashKey)TerminalReporterLogXMLobjectstr)argreturnc                 C  s&   dd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.
    z
Match[str]r   )matchobjr   c                 S  s0   t |  }|dkr d|dS d|dS d S )N   z#xZ02XZ04X)ordgroup)r   i r   4/tmp/pip-unpacked-wheel-7n2p7kht/_pytest/junitxml.pyrepl3   s    zbin_xml_escape.<locals>.replu    [^	
 -~-퟿-�က0-ჿff])resubr   )r   r   Zillegal_xml_rer   r   r   bin_xml_escape(   s    r!   Noner   c                 C  sX   i }|   D ]<\}}|  D ]*\}}t|ts:tt||| ||< qq| | 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                   @  s8  e Zd ZddddddZdddd	d
ZddddddZddddddZddddZdddddZddddZ	d8ddddddd Z
ddd!d"d#Zdddd$d%d&Zddddd'd(d)Zddd!d*d+Zddd!d,d-Zddd!d.d/Zddd!d0d1Zddd!d2d3Zddd!d4d5Zddd6d7ZdS )9_NodeReporterzstr | TestReportr   r"   )nodeidxmlr   c                 C  s<   || _ || _| jj| _| jj| _d| _g | _g | _i | _d S )N        )idr;   	add_statsfamilyduration
propertiesr   attrs)selfr:   r;   r   r   r   __init__Z   s    

z_NodeReporter.__init__z
ET.Element)noder   c                 C  s   | j |j | j| d S r$   )r;   r>   tagr   append)rC   rE   r   r   r   rG   d   s    z_NodeReporter.appendr   r   r2   valuer   c                 C  s   | j t|t|f d S r$   )rA   rG   r   r!   rC   r2   rI   r   r   r   add_propertyh   s    z_NodeReporter.add_propertyc                 C  s   t || jt|< d S r$   )r!   rB   r   rJ   r   r   r   add_attributek   s    z_NodeReporter.add_attributeET.Element | Noner#   c                 C  s>   | j r:td}| j D ]\}}|tjd||d q|S dS z9Return a Junit node containing custom properties, if any.rA   propertyr2   rI   N)rA   ETElementrG   rC   rA   r2   rI   r   r   r   make_properties_noden   s    
z"_NodeReporter.make_properties_noder   )
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 }| jD ]$}|t| j d	 kr| j| ||< q|| _d S )
Nr   .)r1   r2   r4      r5   r6   r7   r0   )mangle_test_addressr:   rB   r;   prefixinsertjoinr!   locationr   hasattrr6   r*   r?   families)rC   rU   namesZexisting_attrsZ
classnamesrB   Z
temp_attrskeyr   r   r   record_testreportw   s,    





z_NodeReporter.record_testreportc                 C  sB   t jd| j| jdd}|  }|d k	r2|| || j |S )Nr0   .3f)time)rQ   rR   rB   r@   rT   rG   extendr   )rC   r0   rA   r   r   r   to_xml   s    
z_NodeReporter.to_xmlN
str | None)rF   messagedatar   c                 C  s&   t j||d}t||_| | d S )N)rh   rQ   rR   r!   textrG   )rC   rF   rh   ri   rE   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 )
system-outout-errrr   z Captured Out rs   )
system-errrt   rr   z Captured Err ru   )	r;   log_passing_testspassedZ	capstdoutZcaplogZ	capstderrlogging_prepare_content_write_content)rC   rn   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   -rp   )r\   center)rC   r|   r}   r   r   r   ry      s    z_NodeReporter._prepare_content)rn   r|   jheaderr   c                 C  s"   t |}t||_| | d S r$   rj   )rC   rn   r|   r   rF   r   r   r   rz      s    

z_NodeReporter._write_contentc                 C  s   |  d d S )Nrw   )r>   rC   rn   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)r^   rl   longreprAssertionErrorgetattrrh   r   r!   )rC   rn   r   rh   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)r   r   rl   r   r   r   r   r   append_collect_error   s    z"_NodeReporter.append_collect_errorc                 C  s   |  ddt|j d S )Nr   zcollection skipped)rl   r   r   r   r   r   r   append_collect_skipped   s    z$_NodeReporter.append_collect_skippedc                 C  sv   |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|t|j  d S )Nr   teardownzfailed on teardown with ""zfailed on setup with "r   )r   r   r   rh   r   whenrl   r!   )rC   rn   r   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}| | nxt|jt	sZt
|j\}}}|dr||dd  }| d	| d
| }tjddt|d}t||_| | | | d S )Nr   zreason:    r   zpytest.xfail)r)   rh   z	Skipped: 	   :z: zpytest.skip)r^   r   
startswithr!   rQ   rR   rG   r&   r   tupler   rk   r{   )rC   rn   Zxfailreasonr   filenamelinenoZ
skipreasondetailsr   r   r   append_skipped   s(    


  

z_NodeReporter.append_skippedc                   s$   |    | j   fdd| _ d S )Nc                     s    S r$   r   r   ri   r   r   <lambda>      z(_NodeReporter.finalize.<locals>.<lambda>)rf   __dict__clearrC   r   r   r   finalize   s    
z_NodeReporter.finalize)N)__name__
__module____qualname__rD   rG   rK   rL   rT   rb   rf   rl   r{   ry   rz   r   r   r   r   r   r   r   r   r   r   r   r9   Y   s$   
	r9   r   )requestfixture_namer   c                 C  sP   ddl m} | jjtd}|dk	rL|jdkrL| j|| d|j d dS )z[Emit a PytestWarning about the given fixture being incompatible with newer xunit revisions.r   )PytestWarningN)r7   legacyz$ is incompatible with junit_family 'z' (use 'legacy' or 'xunit1'))	_pytest.warning_typesr   configstashgetxml_keyr?   rE   warn)r   r   r   r;   r   r   r   !_warn_incompatibility_with_xunit2  s    r   zCallable[[str, object], None])r   r   c                   s$   t  d dd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_propertyr   r   r"   rH   c                   s    j j| |f d S r$   )rE   user_propertiesrG   rP   r   r   r   append_property(  s    z(record_property.<locals>.append_property)r   )r   r   r   r   r   r     s    
r   c                 C  sl   ddl m} | j|d t| d dd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_attributer   r   r"   rH   c                 S  s   d S r$   r   rP   r   r   r   add_attr_noop>  s    z+record_xml_attribute.<locals>.add_attr_noopN)r   r   rE   r   r   r   r   r   r   node_reporterr:   rL   )r   r   r   Z	attr_funcr;   r   r   r   r   r   .  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(   formatr)   r   )r   r   __tracebackhide__r   r   r   r   _check_record_param_typeK  s    
r   session)Zscopec                 C  s8   d}dddddd}| j jtd}|dk	r4|j}|S )	a+  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")

    :param name:
        The property name.
    :param value:
        The property value. Will be converted to a string.

    .. warning::

        Currently this fixture **does not work** with the
        `pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See
        :issue:`7767` for details.
    Tr   r   r"   rH   c                 S  s   d}t d|  dS )zFNo-op function in case --junit-xml was not passed in the command-line.Tr2   N)r   )r2   rI   r   r   r   r   record_funcp  s    z.record_testsuite_property.<locals>.record_funcN)r   r   r   r   add_global_property)r   r   r   r;   r   r   r   record_testsuite_propertyT  s    r   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)optnamez0Create 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|allro   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|xunit2r8   )ZgetgroupZ	addoption	functoolspartialr   Zaddini)r   r   r   r   r   pytest_addoption{  sZ    

  r   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   r^   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 r$   )r   r   r   r   
unregister)r   r;   r   r   r   pytest_unconfigure  s    r   z	list[str])addressr   c                 C  s^   |  d\}}}|d}|d tjd|d< tdd|d |d< |d  || 7  < |S )N[z::r   rW   z\.py$rp   rV   )	partitionsplitreplacer   ZSEPr   r    )r   r   Zpossible_open_bracketparamsr`   r   r   r   rY     s    
rY   c                   @  s   e Zd Zd5dddddd	d
ddZdd	dddZdddddZdd	dddZdddddZdd	dddZdd	dddZ	dd	dddZ
d d	d!d"d#Zd	d$d%d&Zd	d$d'd(Zd)d	d*d+d,Zdd-d	d.d/d0Zd1d$d2d3Zd4S )6r   r   ro   r   r7   Trg   r   r   r"   )rZ   
suite_namerx   report_durationrv   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   rw   r   r   r   r   r7   )osr   
expanduser
expandvarsnormpathabspathlogfilerZ   r   rx   rv   r   r?   dictfromkeysstatsnode_reportersnode_reporters_orderedglobal_propertiesopen_reportscnt_double_fail_tests)rC   r   rZ   r   rx   r   r?   rv   r   r   r   rD     s&    

 
zLogXML.__init__r   rm   c                 C  s\   t |d|}t |dd }| j||f}|jD ]\}}||t| q.|d k	rX|  d S Nr:   rE   )r   r   popr   rK   r   r   )rC   rn   r:   
workernodereporterZpropnameZ	propvaluer   r   r   r     s    zLogXML.finalizezTestReport | strr9   c                 C  sX   t |d|}t |dd }||f}|| jkr4| j| S t|| }|| j|< | j| |S r   )r   r   r9   r   rG   )rC   rn   r:   r   ra   r   r   r   r   r     s    



zLogXML.node_reporter)ra   r   c                 C  s    || j kr| j |  d7  < d S )NrX   )r   )rC   ra   r   r   r   r>     s    
zLogXML.add_statsc                 C  s   |  |}|| |S r$   )r   rb   rC   rn   r   r   r   r   _opentestcase  s    

zLogXML._opentestcasec                   sn  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rj|  }|  |   t ddt ddt fd	d| jD d}|rj| 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   r:   r   .0reprn   Z	report_iiZ
report_widr   r   	<genexpr>8  s
   z2LogXML.pytest_runtest_logreport.<locals>.<genexpr>rX   c                 3  s>   | ]6}|j  j krt|d dkrt|ddkr|V  qdS r   r  r  r  r   r   r  ]  s
   )rw   r   r   r   failedr   nextr   r   r   r   rG   rv   r{   r   r   r   update_testcase_durationremove)rC   rn   Zclose_reportr   r   r  r   pytest_runtest_logreport  sV    


	









	zLogXML.pytest_runtest_logreportc                 C  s4   | j d|jhkr0| |}| 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@   r<   N)r   r   r   r@   r   r   r   r   r   r	  k  s    
zLogXML.update_testcase_durationc                 C  s0   |j s,| |}|jr"|| n
|| d S r$   )rw   r   r  r   r   r   r   r   r   pytest_collectreportr  s
    
zLogXML.pytest_collectreportr	   )excreprr   c                 C  s0   |  d}|jjddd |ddt| d S )NZinternalr   )r1   r2   r   zinternal error)r   rB   r*   rl   r   )rC   r  r   r   r   r   pytest_internalerrorz  s    
zLogXML.pytest_internalerrorr#   c                 C  s   t  | _d S r$   )r   rd   suite_start_timer   r   r   r   pytest_sessionstart  s    zLogXML.pytest_sessionstartc           
      C  sH  t jt j| j}t j|dd 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j  t d	}|  }|d k	r|| | jD ]}||  qtd}	|	| |tj|	dd W 5 Q R X d S )NT)exist_okwzutf-8)encodingrw   r   r   r   z&<?xml version="1.0" encoding="utf-8"?>Z	testsuiterc   )r2   errorsZfailuresr   testsrd   	timestamphostname
testsuitesunicode)r   r   dirnamer   r   makedirsopenr   rd   r  r   r   writerQ   rR   r   r   r   fromtimestampr   utc
astimezone	isoformatplatformrE   _get_global_properties_noderG   r   rf   tostring)
rC   r  r   Zsuite_stop_timeZsuite_time_deltaZnumtestsZ
suite_noder   r   r  r   r   r   pytest_sessionfinish  sF    





zLogXML.pytest_sessionfinishr   )terminalreporterr   c                 C  s   | dd| j  d S )Nr   zgenerated xml file: )Z	write_sepr   )rC   r&  r   r   r   pytest_terminal_summary  s    zLogXML.pytest_terminal_summaryr   rH   c                 C  s&   d}t d| | j|t|f d S )NTr2   )r   r   rG   r!   )rC   r2   rI   r   r   r   r   r     s    
zLogXML.add_global_propertyrM   c                 C  s>   | j r:td}| j D ]\}}|tjd||d q|S dS rN   )r   rQ   rR   rG   rS   r   r   r   r#    s    
z"LogXML._get_global_properties_nodeN)r   ro   r   r7   T)r   r   r   rD   r   r   r>   r   r  r	  r  r  r  r%  r'  r   r#  r   r   r   r   r     s&        !U()5__doc__
__future__r   r   r   r   r   r"  r   typingr   r   xml.etree.ElementTreeetreeElementTreerQ   Z_pytestr   r   Z_pytest._code.coder	   r
   Z_pytest.configr   r   Z_pytest.config.argparsingr   Z_pytest.fixturesr   Z_pytest.reportsr   Z_pytest.stashr   Z_pytest.terminalr   r   r   r!   r/   r_   copyr9   r   Zfixturer   r   r   r   r   r   r   rY   r   r   r   r   r   <module>   s\   	

 0	
&/