@@ -13,54 +13,67 @@ use bstr::ByteSlice;
13
13
14
14
// MAINTENANCE REGION START
15
15
16
- // When integrating with a new libtest version, update all emit_xxx functions.
16
+ // When integrating with a new libtest version, update all xxx_event functions.
17
17
18
- fn emit_suite_end ( failed : usize , filtered_out : usize , ignored : usize , passed : usize , status : & str ) {
18
+ fn suite_end_event (
19
+ failed : usize ,
20
+ filtered_out : usize ,
21
+ ignored : usize ,
22
+ passed : usize ,
23
+ status : & str ,
24
+ ) -> String {
19
25
// Adapted from test::formatters::json::write_run_finish().
20
- println ! (
26
+ format ! (
21
27
r#"{{ "type": "suite", "event": "{status}", "passed": {passed}, "failed": {failed}, "ignored": {ignored}, "measured": 0, "filtered_out": {filtered_out} }}"#
22
- ) ;
28
+ )
23
29
}
24
30
25
- fn emit_suite_start ( ) {
31
+ fn suite_start_event ( ) -> String {
26
32
// Adapted from test::formatters::json::write_run_start().
27
- println ! ( r#"{{ "type": "suite", "event": "started" }} "# ) ;
33
+ String :: from ( r#"{ "type": "suite", "event": "started" }"# )
28
34
}
29
35
30
- fn emit_test_end ( name : & String , revision : & String , path : & Path , status : & str , diags : & str ) {
31
- let displayed_path = path. display ( ) ;
32
- let stdout = if diags. is_empty ( ) {
33
- String :: new ( )
34
- } else {
35
- let triaged_diags = serde_json:: to_string ( diags) . unwrap ( ) ;
36
- format ! ( r#", "stdout": {triaged_diags}"# )
37
- } ;
36
+ fn test_end_event ( name : & str , revision : & str , path : & Path , status : & str , diags : & str ) -> String {
37
+ let name_attribute = make_name_attribute ( name, revision, path) ;
38
+ let stdout_attribute = make_stdout_attribute ( diags) ;
38
39
39
40
// Adapted from test::formatters::json::write_event().
40
- println ! (
41
- r#"{{ "type": "test", "event": "{status}", "name": "{name} ({revision}) - {displayed_path}"{stdout} }}"#
42
- ) ;
41
+ format ! ( r#"{{ "type": "test", "event": "{status}"{name_attribute}{stdout_attribute} }}"# )
43
42
}
44
43
45
- fn emit_test_start ( name : & String , revision : & String , path : & Path ) {
46
- let displayed_path = path . display ( ) ;
44
+ fn test_start_event ( name : & str , revision : & str , path : & Path ) -> String {
45
+ let name_attribute = make_name_attribute ( name , revision , path ) ;
47
46
48
47
// Adapted from test::formatters::json::write_test_start().
49
- println ! (
50
- r#"{{ "type": "test", "event": "started", "name": "{name} ({revision}) - {displayed_path}" }}"#
51
- ) ;
48
+ format ! ( r#"{{ "type": "test", "event": "started"{name_attribute} }}"# )
52
49
}
53
50
54
51
// MAINTENANCE REGION END
55
52
53
+ fn make_name_attribute ( name : & str , revision : & str , path : & Path ) -> String {
54
+ let path_display = path. display ( ) ;
55
+ let escaped_value =
56
+ serde_json:: to_string ( & format ! ( "{name} ({revision}) - {path_display}" ) ) . unwrap ( ) ;
57
+ format ! ( r#", "name": {escaped_value}"# )
58
+ }
59
+
60
+ fn make_stdout_attribute ( diags : & str ) -> String {
61
+ if diags. is_empty ( ) {
62
+ String :: new ( )
63
+ } else {
64
+ let escaped_diags = serde_json:: to_string ( diags) . unwrap ( ) ;
65
+ format ! ( r#", "stdout": {escaped_diags}"# )
66
+ }
67
+ }
68
+
56
69
/// A JSON output emitter.
57
70
#[ derive( Clone ) ]
58
71
pub struct JSON { }
59
72
60
73
impl JSON {
61
74
/// Create a new instance of a JSON output emitter.
62
75
pub fn new ( ) -> Self {
63
- emit_suite_start ( ) ;
76
+ println ! ( "{}" , suite_start_event ( ) ) ;
64
77
65
78
JSON { }
66
79
}
@@ -88,7 +101,10 @@ impl StatusEmitter for JSON {
88
101
"ok"
89
102
} ;
90
103
91
- emit_suite_end ( failed, filtered, ignored, succeeded, status) ;
104
+ println ! (
105
+ "{}" ,
106
+ suite_end_event( failed, filtered, ignored, succeeded, status)
107
+ ) ;
92
108
93
109
Box :: new ( ( ) )
94
110
}
@@ -99,7 +115,7 @@ impl StatusEmitter for JSON {
99
115
let name = path. to_str ( ) . unwrap ( ) . to_string ( ) ;
100
116
let revision = String :: new ( ) ;
101
117
102
- emit_test_start ( & name, & revision, & path) ;
118
+ println ! ( "{}" , test_start_event ( & name, & revision, & path) ) ;
103
119
104
120
Box :: new ( JSONStatus {
105
121
name,
@@ -140,7 +156,10 @@ impl TestStatus for JSONStatus {
140
156
String :: new ( )
141
157
} ;
142
158
143
- emit_test_end ( & self . name , & self . revision , self . path ( ) , status, & diags) ;
159
+ println ! (
160
+ "{}" ,
161
+ test_end_event( & self . name, & self . revision, self . path( ) , status, & diags)
162
+ ) ;
144
163
}
145
164
146
165
/// Invoked before each failed test prints its errors along with a drop guard that can
@@ -186,3 +205,79 @@ impl TestStatus for JSONStatus {
186
205
& self . revision
187
206
}
188
207
}
208
+
209
+ #[ test]
210
+ fn suite_end_event_constructs_event ( ) {
211
+ assert_eq ! (
212
+ suite_end_event(
213
+ 12 , // failed
214
+ 34 , // filtered_out
215
+ 56 , // ignored
216
+ 78 , // passed
217
+ "status"
218
+ ) ,
219
+ r#"{ "type": "suite", "event": "status", "passed": 78, "failed": 12, "ignored": 56, "measured": 0, "filtered_out": 34 }"#
220
+ ) ;
221
+ }
222
+
223
+ #[ test]
224
+ fn suite_start_event_constructs_event ( ) {
225
+ assert_eq ! (
226
+ suite_start_event( ) ,
227
+ r#"{ "type": "suite", "event": "started" }"#
228
+ ) ;
229
+ }
230
+
231
+ #[ test]
232
+ fn test_end_event_constructs_event ( ) {
233
+ assert_eq ! (
234
+ test_end_event( "name" , "revision" , Path :: new( "aaa/bbb" ) , "status" , "diags" ) ,
235
+ r#"{ "type": "test", "event": "status", "name": "name (revision) - aaa/bbb", "stdout": "diags" }"#
236
+ ) ;
237
+ }
238
+
239
+ #[ test]
240
+ fn test_end_event_constructs_event_with_escapes ( ) {
241
+ assert_eq ! (
242
+ test_end_event(
243
+ r#"aaa\bbb"# ,
244
+ r#"ccc ddd\eee"# ,
245
+ Path :: new( r#"fff\ggg"# ) ,
246
+ "status" ,
247
+ r#""rustc" "--error-format=json""#
248
+ ) ,
249
+ r#"{ "type": "test", "event": "status", "name": "aaa\\bbb (ccc ddd\\eee) - fff\\ggg", "stdout": "\"rustc\" \"--error-format=json\"" }"#
250
+ ) ;
251
+ }
252
+
253
+ #[ test]
254
+ fn test_end_event_constructs_event_without_revision ( ) {
255
+ assert_eq ! (
256
+ test_end_event( "name" , "" , Path :: new( "aaa/bbb" ) , "status" , "diags" ) ,
257
+ r#"{ "type": "test", "event": "status", "name": "name () - aaa/bbb", "stdout": "diags" }"#
258
+ ) ;
259
+ }
260
+
261
+ #[ test]
262
+ fn test_end_event_constructs_event_without_stdout ( ) {
263
+ assert_eq ! (
264
+ test_end_event( "name" , "revision" , Path :: new( "aaa/bbb" ) , "status" , "" ) ,
265
+ r#"{ "type": "test", "event": "status", "name": "name (revision) - aaa/bbb" }"#
266
+ ) ;
267
+ }
268
+
269
+ #[ test]
270
+ fn test_start_event_constructs_event ( ) {
271
+ assert_eq ! (
272
+ test_start_event( "name" , "revision" , Path :: new( "aaa/bbb" ) ) ,
273
+ r#"{ "type": "test", "event": "started", "name": "name (revision) - aaa/bbb" }"#
274
+ ) ;
275
+ }
276
+
277
+ #[ test]
278
+ fn test_start_event_constructs_event_with_escapes ( ) {
279
+ assert_eq ! (
280
+ test_start_event( r#"aaa\bbb"# , r#"ccc ddd\eee"# , Path :: new( r#"fff\ggg"# ) ) ,
281
+ r#"{ "type": "test", "event": "started", "name": "aaa\\bbb (ccc ddd\\eee) - fff\\ggg" }"#
282
+ ) ;
283
+ }
0 commit comments