o
    #if=d                     @   s  d 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	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  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e'de(fddZ)dCddZ*i Z+dddgie+d < dg d!ie+d"< e+d  , e+d#< e*e+d# e+d"  e+d  e+d$< G d%d& d&Z-d'ed(e(ddfd)d*Z.e%j/d'edee(e'gdf fd+d,Z0e%j/d'edee(e'gdf fd-d.Z1d/e(d0e(ddfd1d2Z2e%j/d3d4d'edee(e'gdf fd5d6Z3d7eddfd8d9Z4d:eddfd;d<Z5d:eddfd=d>Z6d?e(de	e( fd@dAZ7G dBd 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
    )datetimeN)Callable)Dict)List)Match)Optional)Tuple)Union)nodes)timing)ExceptionRepr)ReprFileLocation)Config)filename_arg)Parser)FixtureRequest)
TestReport)StashKey)TerminalReporterLogXMLargreturnc                 C   s,   dt t dtf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 )N   z#x%02Xz#x%04X)ordgroup)r   i r   I/var/www/html/corbot_env/lib/python3.10/site-packages/_pytest/junitxml.pyrepl5   s   zbin_xml_escape.<locals>.replu    [^	
 -~-퟿-�က0-ჿff])r   strresub)r   r   illegal_xml_rer   r   r   bin_xml_escape*   s   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klvlkrvrr   r   r   merge_familyE   s   
r3   testcase	classnamename_base)filelineurl_base_legacyxunit1xunit2c                	   @   sx  e Zd Zdeeef ddddfddZdejddfd	d
Z	dede
ddfddZdede
ddfddZdeej fddZdeddfddZdejfddZd5dededee ddfddZdeddfddZd ed!edefd"d#Zded ed$eddfd%d&Zdeddfd'd(Zdeddfd)d*Zdeddfd+d,Zdeddfd-d.Zdeddfd/d0Zdeddfd1d2Zd6d3d4ZdS )7_NodeReporternodeidxmlr   r   Nc                 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__\   s   


z_NodeReporter.__init__nodec                 C   s   | j |j | j| d S r%   )r@   rC   tagr
   append)rH   rJ   r   r   r   rL   f   s   z_NodeReporter.appendr6   valuec                 C   s   | j t|t|f d S r%   )rF   rL   r    r$   rH   r6   rM   r   r   r   add_propertyj   s   z_NodeReporter.add_propertyc                 C   s   t || jt|< d S r%   )r$   rG   r    rN   r   r   r   add_attributem      z_NodeReporter.add_attributec                 C   >   | j rtd}| j D ]\}}|tjd||d q|S dS z9Return a Junit node containing custom properties, if any.rF   propertyr6   rM   N)rF   ETElementrL   rH   rF   r6   rM   r   r   r   make_properties_nodep      
z"_NodeReporter.make_properties_node
testreportc                 C   s   t |j}| j}|d d }| jjr|d| jj d|t|d |jd d}|jd d ur:t	|jd |d< t
|drD|j|d< || _| j| | jdkrTd S i }| jD ]}|t| j d	 v rk| j| ||< qY|| _d S )
Nr   .)r5   r6   r8      r9   r:   r<   r4   )mangle_test_addressr?   rG   r@   prefixinsertjoinr$   locationr    hasattrr:   r+   rD   families)rH   r[   namesexisting_attrs
classnamesrG   
temp_attrskeyr   r   r   record_testreporty   s.   






z_NodeReporter.record_testreportc                 C   sB   t jd| jd| j d}|  }|d ur|| || j |S )Nr4   %.3f)time)rV   rW   rG   rE   rY   rL   extendr
   )rH   r4   rF   r   r   r   to_xml   s   
z_NodeReporter.to_xmlrK   messagedatac                 C   s&   t j||d}t||_| | d S )N)rp   rV   rW   r$   textrL   )rH   rK   rp   rq   rJ   r   r   r   _add_simple   s   
z_NodeReporter._add_simplereportc                 C   s   | j js	|jr	d S |j}|j}|j}| j jdkrd S d}| j jdv r(| |d}| j jdv r?|| |d7 }| ||d d}| j jdv rV|| |d	7 }| ||d
 d}|ra| ||d d S d S )Nno )logallz Captured Log )
system-outout-errry   z Captured Out rz   )
system-errr{   ry   z Captured Err r|   )	r@   log_passing_testspassed	capstdoutcaplog	capstderrlogging_prepare_content_write_content)rH   ru   content_outcontent_logcontent_errcontent_allr   r   r   write_captured_output   s*   z#_NodeReporter.write_captured_outputcontentheaderc                 C   s   d |dd|dgS )N
P   -rw   )rb   center)rH   r   r   r   r   r   r         z_NodeReporter._prepare_contentjheaderc                 C   s"   t |}t||_| | d S r%   rr   )rH   ru   r   r   rK   r   r   r   r      s   

z_NodeReporter._write_contentc                 C   s   |  d d S )Nr~   )rC   rH   ru   r   r   r   append_pass      z_NodeReporter.append_passc                 C   sp   t |dr| dd d S |jd usJ t|jdd }|d ur#|j}nt|j}t|}| d|t|j d S )Nwasxfailskippedz%xfail-marked test passes unexpectedly	reprcrashfailure)rd   rt   longreprgetattrrp   r    r$   )rH   ru   r   rp   r   r   r   append_failure   s   

z_NodeReporter.append_failurec                 C   s&   |j d usJ | ddt|j  d S )Nerrorzcollection failure)r   rt   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)rt   r    r   r   r   r   r   append_collect_skipped   r   z$_NodeReporter.append_collect_skippedc                 C   sv   |j d usJ t|j dd }|d ur|j}nt|j }|jdkr'd| d}nd| d}| dt|t|j  d S )Nr   teardownzfailed on teardown with ""zfailed on setup with "r   )r   r   rp   r    whenrt   r$   )rH   ru   r   reasonmsgr   r   r   append_error   s   

z_NodeReporter.append_errorc                 C   s   t |dr&|j}|dr|dd  }t|}tjdd|d}| | d S t|jt	s.J |j\}}}|dr?|dd  }| d	| d
| }tjddt|d}t||_
| | | | d S )Nr   zreason:    r   zpytest.xfail)r*   rp   z	Skipped: 	   :z: zpytest.skip)rd   r   
startswithr$   rV   rW   rL   r'   r   tuplers   r   )rH   ru   xfailreasonr   filenamelineno
skipreasondetailsr   r   r   append_skipped   s$   





z_NodeReporter.append_skippedc                    s$   |    | j   fdd| _ d S )Nc                      s    S r%   r   r   rq   r   r   <lambda>	  s    z(_NodeReporter.finalize.<locals>.<lambda>)ro   __dict__clearrH   r   r   r   finalize  s   
z_NodeReporter.finalizer%   r   N)__name__
__module____qualname__r	   r    r   rI   rV   rW   rL   objectrO   rP   r   rY   rk   ro   rt   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r>   [   s&    
	 r>   requestfixture_namec                 C   sX   ddl m} | jjtd}|dur(|jdvr*| j|| d|j d dS dS dS )z[Emit a PytestWarning about the given fixture being incompatible with newer xunit revisions.r   )PytestWarningN)r<   legacyz$ is incompatible with junit_family 'z' (use 'legacy' or 'xunit1'))	_pytest.warning_typesr   configstashgetxml_keyrD   rJ   warn)r   r   r   r@   r   r   r   !_warn_incompatibility_with_xunit2  s   r   c                    s(   t  d dtdtddf 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_propertyr6   rM   r   Nc                    s    j j| |f d S r%   )rJ   user_propertiesrL   rU   r   r   r   append_property,  rQ   z(record_property.<locals>.append_property)r   r    r   )r   r   r   r   r   r     s   
r   c                 C   sp   ddl m} | j|d t| d dtdtddfd	d
}|}| jj	t
d}|dur6|| 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_attributer6   rM   r   Nc                 S   s   d S r%   r   rU   r   r   r   add_attr_noopB  s   z+record_xml_attribute.<locals>.add_attr_noop)r   r   rJ   r   r   r    r   r   r   r   r   node_reporterr?   rP   )r   r   r   	attr_funcr@   r   r   r   r   r   2  s   
r   paramvc                 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_typeO  s
   
r   session)scopec                 C   s<   d}dt dtddfdd}| jjtd}|dur|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.
    Tr6   rM   r   Nc                 S   s   d}t d|  dS )zFNo-op function in case --junit-xml was not passed in the command-line.Tr6   N)r   )r6   rM   r   r   r   r   record_funct  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_propertyX  s   r   parserc              
   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|allrv   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|xunit2r=   )getgroup	addoption	functoolspartialr   addini)r   r   r   r   r   pytest_addoption  sV   


r   r   c              
   C   st   | j j}|r6t| ds8| d}t|| j j| d| d| d|| d| jt< | j	| jt  d S d S d S )Nworkerinputr   r   r   r   r   )
optionr   rd   getinir   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 d S r%   )r   r   r   r   
unregister)r   r@   r   r   r   pytest_unconfigure  s
   r   addressc                 C   s^   |  d\}}}|d}|d tjd|d< tdd|d |d< |d  || 7  < |S )N[z::r   r]   z\.py$rw   r\   )	partitionsplitreplacer
   SEPr!   r"   )r   r   possible_open_bracketparamsrf   r   r   r   r_     s   
r_   c                   @   s&  e Zd Z					d/dee deded	ed
eddfddZdeddfddZde	eef de
fddZdeddfddZdede
fddZdeddfddZdeddfddZdeddfddZdeddfd d!Zd0d"d#Zd0d$d%Zd&eddfd'd(Zd)ed*eddfd+d,Zdeej fd-d.ZdS )1r   r   rv   r   r<   Tr`   
suite_namer   report_durationr}   r   Nc                 C   s   t jt j|}t jt j|| _|| _|| _|| _	|| _
|| _|| _tg dd| _i | _g | _g | _g | _d| _| jdkrId| _d S d S )N)r   r~   r   r   r   r   r<   )osr   
expanduser
expandvarsnormpathabspathlogfiler`   r  r   r}   r  rD   dictfromkeysstatsnode_reportersnode_reporters_orderedglobal_propertiesopen_reportscnt_double_fail_tests)rH   r
  r`   r  r   r  rD   r}   r   r   r   rI     s(   


zLogXML.__init__ru   c                 C   s`   t |d|}t |dd }| j||f}|jD ]\}}||t| q|d ur.|  d S d S Nr?   rJ   )r   r  popr   rO   r    r   )rH   ru   r?   
workernodereporterpropname	propvaluer   r   r   r     s   zLogXML.finalizec                 C   sX   t |d|}t |dd }||f}|| jv r| j| S t|| }|| j|< | j| |S r  )r   r  r>   r  rL   )rH   ru   r?   r  rj   r  r   r   r   r     s   



zLogXML.node_reporterrj   c                 C   s$   || j v r| j |  d7  < d S d S )Nr^   )r  )rH   rj   r   r   r   rC     s   
zLogXML.add_statsc                 C   s   |  |}|| |S r%   )r   rk   rH   ru   r  r   r   r   _opentestcase  s   

zLogXML._opentestcasec                    sr  d} j r jdkr|  }|  nb jrj jdkrFt ddt ddt fdd| jD d}|rF| | |  j	d7  _	|  } jdkrd|
  | j  | jsc|  n|  n jrw|  }|  |    jdkr|  }|  |   t ddt ddt fd	d| jD d}|r| j| dS dS 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   @    | ]}|j  j krt|d dkrt|ddkr|V  qdS r  Nr  r?   r   .0repru   	report_ii
report_widr   r   	<genexpr>>      z2LogXML.pytest_runtest_logreport.<locals>.<genexpr>r^   c                 3   r  r  r   r!  r$  r   r   r'  c  r(  )r~   r   r  r   failedr   nextr  r   r  r   rL   r}   r   r   r   r   update_testcase_durationremove)rH   ru   close_reportr  r   r$  r   pytest_runtest_logreport  s^   



	











	zLogXML.pytest_runtest_logreportc                 C   s8   | j d|jhv r| |}| jt|dd7  _dS dS )zAccumulate total duration for nodeid from given report and update
        the Junit.testcase with the new total if already created.r   rE   rA   N)r  r   r   rE   r   r  r   r   r   r+  q  s   
zLogXML.update_testcase_durationc                 C   s6   |j s| |}|jr|| d S || d S d S r%   )r~   r  r)  r   r   r  r   r   r   pytest_collectreportx  s   
zLogXML.pytest_collectreportexcreprc                 C   s0   |  d}|jjddd |ddt| d S )Ninternalr   )r5   r6   r   zinternal error)r   rG   r+   rt   r    )rH   r0  r  r   r   r   pytest_internalerror  s   
zLogXML.pytest_internalerrorc                 C   s   t  | _d S r%   )r   rm   suite_start_timer   r   r   r   pytest_sessionstart  r   zLogXML.pytest_sessionstartc           
      C   sT  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 d	}|  }|d urw|| | jD ]	}||  qztd}	|	| |tj|	dd W d    d S 1 sw   Y  d S )NT)exist_okwzutf-8)encodingr~   r   r   r   z&<?xml version="1.0" encoding="utf-8"?>	testsuiterl   )r6   errorsfailuresr   testsrm   	timestamphostname
testsuitesunicode)r  r   dirnamer	  r
  makedirsopenr   rm   r3  r  r  writerV   rW   r  r    r   fromtimestamp	isoformatplatformrJ   _get_global_properties_noderL   r  ro   tostring)
rH   r@  r
  suite_stop_timesuite_time_deltanumtests
suite_noder  r   r>  r   r   r   pytest_sessionfinish  sH   





"zLogXML.pytest_sessionfinishterminalreporterc                 C   s   | dd| j  d S )Nr   zgenerated xml file: )	write_sepr
  )rH   rN  r   r   r   pytest_terminal_summary  r   zLogXML.pytest_terminal_summaryr6   rM   c                 C   s&   d}t d| | j|t|f d S )NTr6   )r   r  rL   r$   )rH   r6   rM   r   r   r   r   r     s   
zLogXML.add_global_propertyc                 C   rR   rS   )r  rV   rW   rL   rX   r   r   r   rG    rZ   z"LogXML._get_global_properties_node)r   rv   r   r<   Tr   )r   r   r   r   r    r   rI   r   r   r	   r>   r   rC   r  r.  r+  r/  r   r2  r4  rM  r   rP  r   r   rV   rW   rG  r   r   r   r   r     s@    	
#U

&r   )9__doc__r   r   r  rF  r!   typingr   r   r   r   r   r   r	   xml.etree.ElementTreeetreeElementTreerV   _pytestr
   r   _pytest._code.coder   r   _pytest.configr   r   _pytest.config.argparsingr   _pytest.fixturesr   _pytest.reportsr   _pytest.stashr   _pytest.terminalr   r   r   r   r    r$   r3   re   copyr>   r   fixturer   r   r   r   r   r   r   r_   r   r   r   r   r   <module>   sp   	


 2
  
	 &/