
    9[gc                       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c 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Z%d-dZ&i Z'dddgie'd<   dg die'd<   e'd   jQ                         e'd<    e&e'd   e'd          e'd   e'd<    G d d      Z)	 	 	 	 	 	 d.d Z*e#jV                  d/d!       Z,e#jV                  d/d"       Z-d0d#Z. e#jV                  d$%      d/d&       Z/d1d'Z0d2d(Z1d2d)Z2d3d*Z3 G d+ d      Z4y)4a  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LogXMLc                N    dd}d}t        j                  ||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.
    c                V    t        | j                               }|dk  rd|dS d|dS )N   z#x02X04X)ordgroup)matchobjis     K/var/www/html/bid-api/venv/lib/python3.12/site-packages/_pytest/junitxml.pyreplzbin_xml_escape.<locals>.repl3   s6     !9#w<#w<    u    [^	
 -~-퟿-�က0-ჿff])r   z
Match[str]returnstr)resubr!   )argr   illegal_xml_res      r   bin_xml_escaper&   (   s+      	W  66.$C11r   c                    i }| j                         D ]I  \  }}|j                         D ]1  \  }}t        |t              st        t	        |            ||z   ||<   3 K | j                  |       y N)items
isinstancelist	TypeErrortypeupdate)leftrightresultklvlkrvrs          r   merge_familyr6   C   sc    F**,BkkmFBb$'R))bF2J $ 
 	KKr   testcase	classnamename_base)filelineurl_base_legacyxunit1xunit2c                      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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y) _NodeReporterc                    || _         || _        | j                  j                  | _        | j                  j                  | _        d| _        g | _        g | _        i | _        y )N        )idxml	add_statsfamilyduration
propertiesr   attrs)selfnodeidrF   s      r   __init__z_NodeReporter.__init__Z   sL    ++hhoo13')
%'
r   c                    | j                   j                  |j                         | j                  j	                  |       y r(   )rF   rG   tagr   append)rL   nodes     r   rQ   z_NodeReporter.appendd   s*    488$

$r   c                b    | j                   j                  t        |      t        |      f       y r(   )rJ   rQ   r!   r&   rL   r9   values      r   add_propertyz_NodeReporter.add_propertyh   s"    D	>%+@ABr   c                F    t        |      | j                  t        |      <   y r(   )r&   rK   r!   rT   s      r   add_attributez_NodeReporter.add_attributek   s     .u 5

3t9r   c                    | j                   rRt        j                  d      }| j                   D ],  \  }}|j                  t        j                  d||             . |S yz9Return a Junit node containing custom properties, if any.rJ   propertyr9   rU   N)rJ   ETElementrQ   rL   rJ   r9   rU   s       r   make_properties_nodez"_NodeReporter.make_properties_noden   sM    ??L1J#e!!"**Zd%"PQ  /r   c                   t        |j                        }| j                  }|d d }| j                  j                  r&|j                  d| j                  j                         dj                  |      t        |d         |j                  d   d}|j                  d   t        |j                  d         |d<   t        |d      r|j                  |d<   || _        | j                  j                  |       | j                  dk(  ry i }| j                  D ]-  }|t        | j                     d	   v s| j                  |   ||<   / || _        y )
Nr   .)r8   r9   r;      r<   r=   r?   r7   )mangle_test_addressrM   rK   rF   prefixinsertjoinr&   locationr!   hasattrr=   r.   rH   families)rL   
testreportnamesexisting_attrs
classnamesrK   
temp_attrskeys           r   record_testreportz_NodeReporter.record_testreportw   s(   #J$5$563BZ
88??a1*-"59-''*!

 q!-
 3 3A 67E&M:u%%>>E%L


.) ;;(" 
::Cht{{+J77"&**S/
3   
r   c                    t        j                  d| j                  | j                  d      }| j	                         }||j                  |       |j                  | j                         |S )Nr7   .3f)time)r]   r^   rK   rI   r`   rQ   extendr   )rL   r7   rJ   s      r   to_xmlz_NodeReporter.to_xml   sV    ::j$**dmmC=PR..0
!OOJ'

#r   Nc                t    t        j                  ||      }t        |      |_        | j	                  |       y )N)messager]   r^   r&   textrQ   )rL   rP   ry   datarR   s        r   _add_simplez_NodeReporter._add_simple   s*    zz#w/"4(	Dr   c                R   | j                   j                  s|j                  ry |j                  }|j                  }|j
                  }| j                   j                  dk(  ry d}| j                   j                  dv r| j                  |d      }| j                   j                  dv r*|| j                  |d      z  }| j                  ||d       d}| j                   j                  dv r*|| j                  |d	      z  }| j                  ||d
       d}|r| j                  ||d       y y )Nno )logallz Captured Log )
system-outout-errr   z Captured Out r   )
system-errr   r   z Captured Err r   )	rF   log_passing_testspassed	capstdoutcaplog	capstderrlogging_prepare_content_write_content)rL   reportcontent_outcontent_logcontent_errcontent_alls         r   write_captured_outputz#_NodeReporter.write_captured_output   s   xx))fmm&&mm&&88t#88~-//=MNK88??400>NOOK\BK88??400>NOOK\BK\B r   c                J    dj                  |j                  dd      |dg      S )N
P   -r   )rh   center)rL   contentheaders      r   r   z_NodeReporter._prepare_content   s#    yy&--C0'2>??r   c                p    t        j                  |      }t        |      |_        | j	                  |       y r(   rz   )rL   r   r   jheaderrP   s        r   r   z_NodeReporter._write_content   s(    jj!!'*Cr   c                &    | j                  d       y )Nr   )rG   rL   r   s     r   append_passz_NodeReporter.append_pass   s    x r   c                6   t        |d      r| j                  dd       y |j                  J t        |j                  dd       }||j                  }nt        |j                        }t        |      }| j                  d|t        |j                               y )Nwasxfailskippedz%xfail-marked test passes unexpectedly	reprcrashfailure)rj   r}   longreprgetattrry   r!   r&   )rL   r   r   ry   s       r   append_failurez_NodeReporter.append_failure   s    6:&Y(OP??...18d2I $#++foo.$W-GYV__1EFr   c                l    |j                   J | j                  ddt        |j                                y )Nerrorzcollection failure)r   r}   r!   r   s     r   append_collect_errorz"_NodeReporter.append_collect_error   s.    ***"6FOO8LMr   c                P    | j                  ddt        |j                               y )Nr   zcollection skipped)r}   r!   r   r   s     r   append_collect_skippedz$_NodeReporter.append_collect_skipped   s    $8#foo:NOr   c                ,   |j                   J t        |j                   dd       }||j                  }nt        |j                         }|j                  dk(  rd| d}nd| d}| j                  dt        |      t        |j                                y )Nr   teardownzfailed on teardown with ""zfailed on setup with "r   )r   r   ry   r!   whenr}   r&   )rL   r   r   reasonmsgs        r   append_errorz_NodeReporter.append_error   s    ***-4V__kSW-X	 &&F)F;;*$-fXQ7C*6(!4C."5s6??7KLr   c                   t        |d      rW|j                  }|j                  d      r|dd  }t        |      }t	        j
                  dd|      }| j                  |       y t        |j                  t              sJ |j                  \  }}}|j                  d      r|dd  }| d	| d
| }t	        j
                  ddt        |            }t        |      |_
        | j                  |       | j                  |       y )Nr   zreason:    r   zpytest.xfail)r-   ry   z	Skipped: 	   :z: zpytest.skip)rj   r   
startswithr&   r]   r^   rQ   r*   r   tupler{   r   )rL   r   xfailreasonr   filenamelineno
skipreasondetailss           r   append_skippedz_NodeReporter.append_skipped   s    6:& //K%%j1)!"o(5KjjUGKK foou555+1??(Hfj$$[1'^
!
!F82j\:Gjj~j7QG *'2GLKK &&v.r   c                n    | j                         | j                  j                          fd| _         y )Nc                      S r(    )r|   s   r   <lambda>z(_NodeReporter.finalize.<locals>.<lambda>  s    dr   )rw   __dict__clear)rL   r|   s    @r   finalizez_NodeReporter.finalize   s'    {{} #r   )rM   zstr | TestReportrF   r   r    None)rR   
ET.Elementr    r   r9   r!   rU   objectr    r   r    zET.Element | None)rl   r   r    r   )r    r   r(   )rP   r!   ry   r!   r|   
str | Noner    r   r   r   r    r   )r   r!   r   r!   r    r!   )r   r   r   r!   r   r!   r    r   r    r   )__name__
__module____qualname__rN   rQ   rV   rX   r`   rr   rw   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   rB   rB   Y   sc    ( C6 <
C.@
!G N
PM/,#r   rB   c                    ddl m} | j                  j                  j	                  t
        d      }|A|j                  dvr2| j                  j                   || d|j                   d             yyy)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_keyrH   rR   warn)requestfixture_namer   rF   s       r   !_warn_incompatibility_with_xunit2r     sl     4
..


"
"7D
1C
3::-AA. DSZZLPlm	
 Br   c                ,     t         d       d f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_propertyc                T    j                   j                  j                  | |f       y r(   )rR   user_propertiesrQ   )r9   rU   r   s     r   append_propertyz(record_property.<locals>.append_property(  s    $$++T5M:r   r   )r   )r   r   s   ` r   r   r     s     &g/@A; r   c                2   ddl m} | j                  j                   |d             t	        | d       dd}|}| j
                  j                  j                  t        d      }|1|j                  | 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_attributec                     y r(   r   r\   s     r   add_attr_noopz+record_xml_attribute.<locals>.add_attr_noop>  s    r   Nr   )r   r   rR   r   r   r   r   r   r   node_reporterrM   rX   )r   r   r   	attr_funcrF   r   s         r   r   r   .  s     CLL$%VW &g/EF I
..


"
"7D
1C
))',,*=*=>!//	r   c                    d}t        |t              s1d}t        |j                  | t	        |      j
                              y)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)paramgN)r*   r!   r,   formatr-   r   )r   v__tracebackhide__r   s       r   _check_record_param_typer   K  s@     aE

$q'2B2B
CDD r   session)scopec                    d}dd}| j                   j                  j                  t        d      }||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.
    Tc                     d}t        d|        y)zFNo-op function in case --junit-xml was not passed in the command-line.Tr9   N)r   )r9   rU   r   s      r   record_funcz.record_testsuite_property.<locals>.record_funcp  s      .r   Nr   )r   r   r   r   add_global_property)r   r   r   rF   s       r   record_testsuite_propertyr   T  sC    4 /
 ..


"
"7D
1C
--r   c                   | j                  d      }|j                  dddddt        j                  t        d      d d	       |j                  d
dddd d       | j                  ddd       | j                  ddd       | j                  dddd       | j                  ddd       | j                  ddd        y )!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|allr   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)parserr   s     r   pytest_addoptionr  {  s    OO01E	OO|\B?  	 
OO?   MM>   MM	:	   MM!E	   MM4  
 MM:  r   c                   | j                   j                  }|rt        | d      s| j                  d      }t	        || j                   j
                  | j                  d      | j                  d      | j                  d      || j                  d            | j                  t        <   | j                  j                  | j                  t                  y y y )Nworkerinputr	  r  r  r  r  )
optionr   rj   getinir   junitprefixr   r   pluginmanagerregister)r   r   r	  s      r   pytest_configurer    s    mm##Gwv}5}}^4 &MM%%MM,-MM/*MM12MM34!
W 	%%fll7&;< 6wr   c                    | j                   j                  t        d       }|r-| j                   t        = | j                  j	                  |       y y r(   )r   r   r   r  
unregister)r   rF   s     r   pytest_unconfigurer    s@    
,,

7D
)C
LL!'', r   c                    | j                  d      \  }}}|j                  d      }|d   j                  t        j                  d      |d<   t        j                  dd|d         |d<   |dxx   ||z   z  cc<   |S )N[z::r   rc   z\.py$r   rb   )	partitionsplitreplacer   SEPr"   r#   )addressr   possible_open_bracketparamsrm   s        r   re   re     sy    *1*;*;C*@'D
JJtEQx		3/E!HvvhE!H-E!H	"I&//ILr   c                      e Zd Z	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 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dZy)r   c                    t         j                  j                  t         j                  j                  |            }t         j                  j	                  t         j                  j                  |            | _        || _        || _        || _	        || _
        || _        || _        t        j                  g dd      | _        i | _        g | _        g | _        g | _        d| _        | j                  dk(  rd| _        y y )N)r   r   r   r   r   r   r?   )osr   
expanduser
expandvarsnormpathabspathlogfilerf   
suite_namer   r   report_durationrH   dictfromkeysstatsnode_reportersnode_reporters_orderedglobal_propertiesopen_reportscnt_double_fail_tests)rL   r,  rf   r-  r   r.  rH   r   s           r   rN   zLogXML.__init__  s     ''$$RWW%7%7%@Aww''(@A$!2.%)]]5q&

 UW;=#8: /1%&" ;;(""DK #r   c                    t        |d|      }t        |dd       }| j                  j                  ||f      }|j                  D ]   \  }}|j	                  |t        |             " ||j                          y y NrM   rR   )r   r2  popr   rV   r!   r   )rL   r   rM   
workernodereporterpropname	propvalues          r   r   zLogXML.finalize  s{    62VVT2
&&**FJ+?@#)#9#9Hi!!(C	N; $:   r   c                    t        |d|      }t        |dd       }||f}|| j                  v r| j                  |   S t        ||       }|| j                  |<   | j                  j	                  |       |S r8  )r   r2  rB   r3  rQ   )rL   r   rM   r:  rq   r;  s         r   r   zLogXML.node_reporter  s|    #*68V#DVVT2
j $%%%&&s++ .#+C ##**84r   c                P    || j                   v r| j                   |xx   dz  cc<   y y )Nrd   )r1  )rL   rq   s     r   rG   zLogXML.add_stats  s%    $**JJsOq O r   c                J    | j                  |      }|j                  |       |S r(   )r   rr   rL   r   r;  s      r   _opentestcasezLogXML._opentestcase  s%    %%f-""6*r   c                8   d}j                   r4j                  dk(  rL| j                        }|j                         n(j                  rj                  dk(  rct        dd      t        dd      t        fd| j                  D        d      }|r&| j                  |       | xj                  dz  c_	        | j                        }j                  dk(  rJ|j                         | j                  j                         | j                  sR|j                         n@|j                         n.j                  r"| j                        }|j!                         | j#                         j                  dk(  r| j                        }|j                         | j                         t        dd      t        dd      t        fd| j                  D        d      }|r| j                  j%                  |       yyy)	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     K   | ]?  }|j                   j                   k(  r$t        |d d      k(  rt        |dd      k(  r| A ywrF  NrE  rM   r   .0repr   	report_ii
report_wids     r   	<genexpr>z2LogXML.pytest_runtest_logreport.<locals>.<genexpr>8  sK      #4CJJ&--7 '\4 @I M '[$ ?: M #4   AArd   c              3     K   | ]?  }|j                   j                   k(  r$t        |d d      k(  rt        |dd      k(  r| A ywrH  rI  rJ  s     r   rO  z2LogXML.pytest_runtest_logreport.<locals>.<genexpr>]  sK      0

fmm3#Ct<	I#Cd;zI 0rP  )r   r   rB  r   failedr   nextr5  r   r6  r   rQ   r   r   r   r   r   update_testcase_durationremove)rL   r   close_reportr;  rM  rN  s    `  @@r   pytest_runtest_logreportzLogXML.pytest_runtest_logreport  s   . =={{f$--f5$$V,]]{{j($V[$?
#FL$?	##'#4#4     MM,/..!3.))&1H{{f$''/!!((0--226:%%f-^^))&1H##F+%%f-;;*$))&1H**62MM&! d;Jd;I#00 L !!((6 ' %r   c                    | j                   d|j                  hv r2| j                  |      }|xj                  t	        |dd      z  c_        yy)zAccumulate total duration for nodeid from given report and update
        the Junit.testcase with the new total if already created.r  rI   rD   N)r.  r   r   rI   r   rA  s      r   rT  zLogXML.update_testcase_durationk  sJ     GV[[#99))&1HS!AA :r   c                    |j                   sA| j                  |      }|j                  r|j                  |       y |j	                  |       y y r(   )r   rB  rR  r   r   rA  s      r   pytest_collectreportzLogXML.pytest_collectreportr  sA    }}))&1H}}--f5//7 r   c                    | j                  d      }|j                  j                  dd       |j                  ddt	        |             y )Ninternalr  )r8   r9   r   zinternal error)r   rK   r.   r}   r!   )rL   excreprr;  s      r   pytest_internalerrorzLogXML.pytest_internalerrorz  s@    %%j1zBW&6GEr   c                6    t        j                         | _        y r(   )r	   ru   suite_start_time)rL   s    r   pytest_sessionstartzLogXML.pytest_sessionstart  s     &r   c                   t         j                  j                  t         j                  j                  | j                              }t        j
                  |d       t        | j                  dd      5 }t        j                         }|| j                  z
  }| j                  d   | j                  d   z   | j                  d   z   | j                  d	   z   | j                  z
  }|j                  d
       t        j                  d| j                  t!        | j                  d	         t!        | j                  d         t!        | j                  d         t!        |      |dt#        j$                  | j                  t&        j(                        j+                         j-                         t/        j0                         	      }| j3                         }||j5                  |       | j6                  D ]!  }|j5                  |j9                                # t        j                  d      }	|	j5                  |       |j                  t        j:                  |	d             d d d        y # 1 sw Y   y xY w)NT)exist_okwzutf-8)encodingr   r   r   r   z&<?xml version="1.0" encoding="utf-8"?>	testsuitert   )r9   errorsfailuresr   testsru   	timestamphostname
testsuitesunicode)r'  r   dirnamer+  r,  makedirsopenr	   ru   r`  r1  r6  writer]   r^   r-  r!   r   fromtimestampr   utc
astimezone	isoformatplatformrR   _get_global_properties_noderQ   r3  rw   tostring)
rL   rn  r,  suite_stop_timesuite_time_deltanumtests
suite_noder4  r   rl  s
             r   pytest_sessionfinishzLogXML.pytest_sessionfinish  s   ''//"''//$,,"?@
Gd+$,,g6'$kkmO.1F1FF 

8$**Y'(**Y'( **W%& ,,	-  MMBC__4::g./TZZ	23DJJy12(m(-"001F1FU!J !% @ @ B ,!!"34!%!<!<!!-"6"6"89 "=L1Jj)MM"++j9EFC 766s   6G/I..I7c                B    |j                  dd| j                          y )Nr   zgenerated xml file: )	write_sepr,  )rL   terminalreporters     r   pytest_terminal_summaryzLogXML.pytest_terminal_summary  s    ""3*>t||n(MNr   c                l    d}t        d|       | j                  j                  |t        |      f       y )NTr9   )r   r4  rQ   r&   )rL   r9   rU   r   s       r   r   zLogXML.add_global_property  s0      .%%t^E-B&CDr   c                    | j                   rRt        j                  d      }| j                   D ],  \  }}|j                  t        j                  d||             . |S yrZ   )r4  r]   r^   rQ   r_   s       r   rw  z"LogXML._get_global_properties_node  sQ    !!L1J#55e!!"**Zd%"PQ  6r   N)r  r   r  r?   T)rf   r   r-  r!   r   r!   r.  r!   r   r  r    r   r   )r   zTestReport | strr    rB   )rq   r!   r    r   )r   r   r    rB   )r]  r
   r    r   r   )r  r   r    r   r   r   )r   r   r   rN   r   r   rG   rB  rW  rT  rZ  r^  ra  r}  r  r   rw  r   r   r   r   r     s    
 #&"&# # 	#
 # #  # 
#B
 $!
S7jB8F
.&GPOE
r   )r$   r   r    r!   r   )r   r   r   r!   r    r   )r   r   r    zCallable[[str, object], None])r   r!   r   r!   r    r   )r  r   r    r   )r   r   r    r   )r"  r!   r    z	list[str])5__doc__
__future__r   r   r   r  r'  rv  r"   typingr   r   xml.etree.ElementTreeetreeElementTreer]   _pytestr   r	   _pytest._code.coder
   r   _pytest.configr   r   _pytest.config.argparsingr   _pytest.fixturesr   _pytest.reportsr   _pytest.stashr   _pytest.terminalr   r  r   r&   r6   rk   copyrB   r   fixturer   r   r   r   r  r  r  re   r   r   r   r   <module>r     sw   #    	  	   " "   , / ! ' , + & " -  (8

26 +v!67 &(?@  g&++-  Xh.!9 : g& l# l#^

+.
	
  ,  8E i # !#L,^="-l lr   