@@ -11,7 +11,7 @@ use crate::{
1111
1212pub struct JunitFormatter < T > {
1313 out : OutputLocation < T > ,
14- results : Vec < ( TestDesc , TestResult , Duration ) > ,
14+ results : Vec < ( TestDesc , TestResult , Duration , Vec < u8 > ) > ,
1515}
1616
1717impl < T : Write > JunitFormatter < T > {
@@ -26,6 +26,18 @@ impl<T: Write> JunitFormatter<T> {
2626 }
2727}
2828
29+ fn str_to_cdata ( s : & str ) -> String {
30+ // Drop the stdout in a cdata. Unfortunately, you can't put either of `]]>` or
31+ // `<?'` in a CDATA block, so the escaping gets a little weird.
32+ let escaped_output = s. replace ( "]]>" , "]]]]><![CDATA[>" ) ;
33+ let escaped_output = escaped_output. replace ( "<?" , "<]]><![CDATA[?" ) ;
34+ // We also smuggle newlines as 
 so as to keep all the output on one line
35+ let escaped_output = escaped_output. replace ( "\n " , "]]>
<![CDATA[" ) ;
36+ // Prune empty CDATA blocks resulting from any escaping
37+ let escaped_output = escaped_output. replace ( "<![CDATA[]]>" , "" ) ;
38+ format ! ( "<![CDATA[{}]]>" , escaped_output)
39+ }
40+
2941impl < T : Write > OutputFormatter for JunitFormatter < T > {
3042 fn write_discovery_start ( & mut self ) -> io:: Result < ( ) > {
3143 Err ( io:: Error :: new ( io:: ErrorKind :: NotFound , "Not yet implemented!" ) )
@@ -63,14 +75,14 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
6375 desc : & TestDesc ,
6476 result : & TestResult ,
6577 exec_time : Option < & time:: TestExecTime > ,
66- _stdout : & [ u8 ] ,
78+ stdout : & [ u8 ] ,
6779 _state : & ConsoleTestState ,
6880 ) -> io:: Result < ( ) > {
6981 // Because the testsuite node holds some of the information as attributes, we can't write it
7082 // until all of the tests have finished. Instead of writing every result as they come in, we add
7183 // them to a Vec and write them all at once when run is complete.
7284 let duration = exec_time. map ( |t| t. 0 ) . unwrap_or_default ( ) ;
73- self . results . push ( ( desc. clone ( ) , result. clone ( ) , duration) ) ;
85+ self . results . push ( ( desc. clone ( ) , result. clone ( ) , duration, stdout . to_vec ( ) ) ) ;
7486 Ok ( ( ) )
7587 }
7688 fn write_run_finish ( & mut self , state : & ConsoleTestState ) -> io:: Result < bool > {
@@ -85,7 +97,7 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
8597 >",
8698 state. failed, state. total, state. ignored
8799 ) ) ?;
88- for ( desc, result, duration) in std:: mem:: take ( & mut self . results ) {
100+ for ( desc, result, duration, stdout ) in std:: mem:: take ( & mut self . results ) {
89101 let ( class_name, test_name) = parse_class_name ( & desc) ;
90102 match result {
91103 TestResult :: TrIgnored => { /* no-op */ }
@@ -98,6 +110,11 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
98110 duration. as_secs_f64( )
99111 ) ) ?;
100112 self . write_message ( "<failure type=\" assert\" />" ) ?;
113+ if !stdout. is_empty ( ) {
114+ self . write_message ( "<system-out>" ) ?;
115+ self . write_message ( & str_to_cdata ( & String :: from_utf8_lossy ( & stdout) ) ) ?;
116+ self . write_message ( "</system-out>" ) ?;
117+ }
101118 self . write_message ( "</testcase>" ) ?;
102119 }
103120
@@ -110,6 +127,11 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
110127 duration. as_secs_f64( )
111128 ) ) ?;
112129 self . write_message ( & format ! ( "<failure message=\" {m}\" type=\" assert\" />" ) ) ?;
130+ if !stdout. is_empty ( ) {
131+ self . write_message ( "<system-out>" ) ?;
132+ self . write_message ( & str_to_cdata ( & String :: from_utf8_lossy ( & stdout) ) ) ?;
133+ self . write_message ( "</system-out>" ) ?;
134+ }
113135 self . write_message ( "</testcase>" ) ?;
114136 }
115137
@@ -136,11 +158,19 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
136158 TestResult :: TrOk => {
137159 self . write_message ( & format ! (
138160 "<testcase classname=\" {}\" \
139- name=\" {}\" time=\" {}\" /> ",
161+ name=\" {}\" time=\" {}\" ",
140162 class_name,
141163 test_name,
142164 duration. as_secs_f64( )
143165 ) ) ?;
166+ if stdout. is_empty ( ) || !state. options . display_output {
167+ self . write_message ( "/>" ) ?;
168+ } else {
169+ self . write_message ( "><system-out>" ) ?;
170+ self . write_message ( & str_to_cdata ( & String :: from_utf8_lossy ( & stdout) ) ) ?;
171+ self . write_message ( "</system-out>" ) ?;
172+ self . write_message ( "</testcase>" ) ?;
173+ }
144174 }
145175 }
146176 }
0 commit comments