@@ -10,9 +10,9 @@ export modify_for_testing;
10
10
11
11
type node_id_gen = @fn ( ) -> ast:: node_id ;
12
12
13
- type test_ctxt = rec ( node_id_gen next_node_id ,
14
- mutable ast:: ident[ ] path,
15
- mutable ast:: ident[ ] [ ] testfns) ;
13
+ type test_ctxt = @ rec ( node_id_gen next_node_id ,
14
+ mutable ast:: ident[ ] path,
15
+ mutable ast:: ident[ ] [ ] testfns) ;
16
16
17
17
// Traverse the crate, collecting all the test functions, eliding any
18
18
// existing main functions, and synthesizing a main test harness
@@ -30,9 +30,9 @@ fn modify_for_testing(@ast::crate crate) -> @ast::crate {
30
30
ret this_node_id;
31
31
} ( next_node_id) ;
32
32
33
- let test_ctxt cx = rec( next_node_id = next_node_id_fn,
34
- mutable path = ~[ ] ,
35
- mutable testfns = ~[ ] ) ;
33
+ let test_ctxt cx = @ rec( next_node_id = next_node_id_fn,
34
+ mutable path = ~[ ] ,
35
+ mutable testfns = ~[ ] ) ;
36
36
37
37
auto precursor = rec( fold_crate = bind fold_crate( cx, _, _) ,
38
38
fold_item = bind fold_item( cx, _, _)
@@ -55,14 +55,74 @@ fn fold_crate(&test_ctxt cx, &ast::crate_ c,
55
55
with folded) ;
56
56
}
57
57
58
+
59
+ fn fold_item( & test_ctxt cx, & @ast:: item i,
60
+ fold:: ast_fold fld) -> @ast:: item {
61
+
62
+ cx. path += ~[ i. ident] ;
63
+ log #fmt( "current path: %s" , ast:: path_name_i( cx. path) ) ;
64
+
65
+ if ( is_test_fn( i) ) {
66
+ log "this is a test function" ;
67
+ cx. testfns += ~[ cx . path] ;
68
+ log #fmt( "have %u test functions" , ivec:: len( cx. testfns) ) ;
69
+ }
70
+
71
+ auto res = fold:: noop_fold_item ( i , fld ) ;
72
+ ivec:: pop ( cx . path) ;
73
+ ret res;
74
+ }
75
+
76
+ fn is_test_fn ( & @ast:: item i) -> bool {
77
+ auto has_test_attr =
78
+ ivec:: len ( attr:: find_attrs_by_name ( i. attrs , "test" ) ) > 0 u;
79
+
80
+ fn has_test_signature ( & @ast:: item i) -> bool {
81
+ alt ( i. node) {
82
+ case ( ast:: item_fn ( ?f , ?tps ) ) {
83
+ auto input_cnt = ivec:: len ( f. decl. inputs ) ;
84
+ auto no_output = f. decl. output. node == ast:: ty_nil ;
85
+ auto tparm_cnt = ivec:: len ( tps) ;
86
+ input_cnt == 0 u && no_output && tparm_cnt == 0 u
87
+ }
88
+ case ( _) { false }
89
+ }
90
+ }
91
+
92
+ ret has_test_attr && has_test_signature ( i) ;
93
+ }
94
+
58
95
fn add_test_module ( & test_ctxt cx, & ast:: _mod m) -> ast:: _mod {
59
96
auto testmod = mk_test_module ( cx) ;
60
97
ret rec ( items=m. items + ~[ testmod] with m) ;
61
98
}
62
99
100
+ /*
101
+
102
+ We're going to be building a module that looks more or less like:
103
+
104
+ mod __test {
105
+
106
+ fn main(vec[str] args) -> int {
107
+ std::test::test_main(args, tests())
108
+ }
109
+
110
+ fn tests() -> std::test::test_desc[] {
111
+ ... the list of tests in the crate ...
112
+ }
113
+ }
114
+
115
+ */
116
+
63
117
fn mk_test_module ( & test_ctxt cx) -> @ast:: item {
118
+ // A function that generates a vector of test descriptors to feed to the
119
+ // test runner
120
+ auto testsfn = mk_tests ( cx) ;
121
+ // The synthesized main function which will call the console test runner
122
+ // with our list of tests
64
123
auto mainfn = mk_main ( cx) ;
65
- let ast:: _mod testmod = rec( view_items=~[ ] , items=~[ mainfn] ) ;
124
+ let ast:: _mod testmod = rec ( view_items=~[ ] ,
125
+ items=~[ mainfn, testsfn] ) ;
66
126
auto item_ = ast:: item_mod ( testmod) ;
67
127
let ast:: item item = rec ( ident = "__test" ,
68
128
attrs = ~[ ] ,
@@ -72,8 +132,123 @@ fn mk_test_module(&test_ctxt cx) -> @ast::item {
72
132
ret @item;
73
133
}
74
134
135
+ fn nospan[ T ] ( & T t) -> ast:: spanned[ T ] {
136
+ ret rec( node=t,
137
+ span=rec ( lo=0 u, hi=0 u) ) ;
138
+ }
139
+
140
+ fn mk_tests ( & test_ctxt cx) -> @ast:: item {
141
+ auto ret_ty = mk_test_desc_ivec_ty ( ) ;
142
+
143
+ let ast:: fn_decl decl = rec ( inputs = ~[ ] ,
144
+ output = ret_ty,
145
+ purity = ast:: impure_fn,
146
+ cf = ast:: return,
147
+ constraints = ~[ ] ) ;
148
+ auto proto = ast:: proto_fn;
149
+
150
+ // The vector of test_descs for this crate
151
+ auto test_descs = mk_test_desc_vec ( cx) ;
152
+
153
+ let ast:: block_ body_= rec ( stmts = ~[ ] ,
154
+ expr = option:: some ( test_descs) ,
155
+ id = cx. next_node_id ( ) ) ;
156
+ auto body = nospan ( body_) ;
157
+
158
+ auto fn_ = rec ( decl = decl,
159
+ proto = proto,
160
+ body = body) ;
161
+
162
+ auto item_ = ast:: item_fn ( fn_, ~[ ] ) ;
163
+ let ast:: item item = rec ( ident = "tests" ,
164
+ attrs = ~[ ] ,
165
+ id = cx. next_node_id ( ) ,
166
+ node = item_,
167
+ span = rec ( lo=0 u, hi=0 u) ) ;
168
+ ret @item;
169
+ }
170
+
171
+ fn empty_fn_ty ( ) -> ast:: ty {
172
+ auto proto = ast:: proto_fn;
173
+ auto input_ty = ~[ ] ;
174
+ auto ret_ty = @nospan ( ast:: ty_nil) ;
175
+ auto cf = ast:: return;
176
+ auto constrs = ~[ ] ;
177
+ ret nospan ( ast:: ty_fn ( proto, input_ty, ret_ty, cf, constrs) ) ;
178
+ }
179
+
180
+ // The ast::ty of std::test::test_desc
181
+ fn mk_test_desc_ivec_ty ( ) -> @ast:: ty {
182
+ // Oh this is brutal to build by hand
183
+ let ast:: mt name_mt = rec ( ty = @nospan ( ast:: ty_str) ,
184
+ mut = ast:: imm) ;
185
+ let ast:: mt fn_mt = rec ( ty = @empty_fn_ty ( ) ,
186
+ mut = ast:: imm) ;
187
+
188
+ let ast:: ty_field_ name_ty_field_ = rec ( ident = "name" ,
189
+ mt = name_mt) ;
190
+
191
+ let ast:: ty_field_ fn_ty_field_ = rec ( ident = "fn" ,
192
+ mt = fn_mt) ;
193
+
194
+ let ast:: ty_field[ ] test_desc_fields = ~[ nospan ( name_ty_field_) ,
195
+ nospan ( fn_ty_field_) ] ;
196
+ let ast:: ty test_desc_ty = nospan ( ast:: ty_rec ( test_desc_fields) ) ;
197
+
198
+ let ast:: mt ivec_mt = rec ( ty = @test_desc_ty,
199
+ mut = ast:: imm) ;
200
+
201
+ ret @nospan ( ast:: ty_ivec ( ivec_mt) ) ;
202
+ }
203
+
204
+ fn mk_test_desc_vec( & test_ctxt cx) -> @ast:: expr {
205
+ log #fmt( "building test vector from %u tests" ,
206
+ ivec:: len ( cx. testfns ) ) ;
207
+ auto descs = ~[ ] ;
208
+ for ( ast:: ident[ ] testpath in cx. testfns) {
209
+ log #fmt( "encoding %s" , ast:: path_name_i( testpath) ) ;
210
+ auto path = testpath;
211
+ descs += ~[ mk_test_desc_rec( cx, path) ] ;
212
+ }
213
+
214
+ ret @rec( id = cx. next_node_id( ) ,
215
+ node = ast:: expr_vec( descs, ast:: imm, ast:: sk_unique) ,
216
+ span = rec( lo=0 u, hi=0 u) ) ;
217
+ }
218
+
219
+ fn mk_test_desc_rec( & test_ctxt cx, ast:: ident[ ] path) -> @ast:: expr {
220
+
221
+ let ast:: lit name_lit = nospan( ast:: lit_str( ast:: path_name_i( path) ,
222
+ ast:: sk_rc) ) ;
223
+ let ast:: expr name_expr = rec( id = cx. next_node_id( ) ,
224
+ node = ast:: expr_lit( @name_lit) ,
225
+ span = rec( lo=0 u, hi=0 u) ) ;
226
+
227
+ let ast:: field name_field = nospan( rec( mut = ast:: imm,
228
+ ident = "name" ,
229
+ expr = @name_expr) ) ;
230
+
231
+ let ast:: path fn_path = nospan( rec( idents = path,
232
+ types = ~[ ] ) ) ;
233
+
234
+ let ast:: expr fn_expr = rec( id = cx. next_node_id( ) ,
235
+ node = ast:: expr_path( fn_path) ,
236
+ span = rec( lo=0 u, hi=0 u) ) ;
237
+
238
+ let ast:: field fn_field = nospan( rec( mut = ast:: imm,
239
+ ident = "fn" ,
240
+ expr = @fn_expr) ) ;
241
+
242
+ let ast:: expr_ desc_rec_ = ast:: expr_rec( ~[ name_field, fn_field] ,
243
+ option:: none) ;
244
+ let ast:: expr desc_rec = rec( id = cx. next_node_id( ) ,
245
+ node = desc_rec_,
246
+ span = rec( lo=0 u, hi=0 u) ) ;
247
+ ret @desc_rec;
248
+ }
249
+
75
250
fn mk_main( & test_ctxt cx) -> @ast:: item {
76
- auto ret_ty = @rec( node=ast:: ty_nil ,
251
+ auto ret_ty = @rec( node=ast:: ty_int ,
77
252
span=rec( lo=0 u, hi=0 u) ) ;
78
253
79
254
let ast:: fn_decl decl = rec( inputs = ~[ ] ,
@@ -83,9 +258,11 @@ fn mk_main(&test_ctxt cx) -> @ast::item {
83
258
constraints = ~[ ] ) ;
84
259
auto proto = ast:: proto_fn;
85
260
261
+ auto test_main_call_expr = mk_test_main_call( cx) ;
262
+
86
263
let ast:: block_ body_ = rec( stmts = ~[ ] ,
87
- expr = option:: none ,
88
- id = cx. next_node_id( ) ) ;
264
+ expr = option:: some ( test_main_call_expr ) ,
265
+ id = cx. next_node_id( ) ) ;
89
266
auto body = rec( node = body_, span = rec( lo=0 u, hi=0 u) ) ;
90
267
91
268
auto fn_ = rec( decl = decl,
@@ -101,39 +278,43 @@ fn mk_main(&test_ctxt cx) -> @ast::item {
101
278
ret @item;
102
279
}
103
280
104
- fn fold_item( & test_ctxt cx, & @ast:: item i,
105
- fold:: ast_fold fld) -> @ast:: item {
281
+ fn mk_test_main_call( & test_ctxt cx) -> @ast:: expr {
106
282
107
- cx . path += ~ [ i . ident ] ;
108
- log #fmt ( "current path: %s" , ast :: path_name_i ( cx . path ) ) ;
283
+ let ast :: path test_path = nospan ( rec ( idents = ~ [ "tests" ] ,
284
+ types = ~ [ ] ) ) ;
109
285
110
- if ( is_test_fn( i) ) {
111
- log "this is a test function" ;
112
- cx. testfns += ~[ cx . path] ;
113
- }
286
+ let ast:: expr_ test_path_expr_ = ast:: expr_path( test_path) ;
114
287
115
- auto res = fold:: noop_fold_item ( i , fld ) ;
116
- ivec:: pop ( cx . path) ;
117
- ret res;
118
- }
288
+ let ast:: expr test_path_expr = rec( id = cx. next_node_id( ) ,
289
+ node = test_path_expr_,
290
+ span = rec( lo=0 u, hi=0 u) ) ;
119
291
120
- fn is_test_fn ( & @ast:: item i) -> bool {
121
- auto has_test_attr =
122
- ivec:: len ( attr:: find_attrs_by_name ( i. attrs , "test" ) ) > 0 u;
292
+ let ast:: expr_ test_call_expr_ = ast:: expr_call( @test_path_expr, ~[ ] ) ;
123
293
124
- fn has_test_signature ( & @ast:: item i) -> bool {
125
- alt ( i. node) {
126
- case ( ast:: item_fn ( ?f , ?tps ) ) {
127
- auto input_cnt = ivec:: len ( f. decl. inputs ) ;
128
- auto no_output = f. decl. output. node == ast:: ty_nil ;
129
- auto tparm_cnt = ivec:: len ( tps) ;
130
- input_cnt == 0 u && no_output && tparm_cnt == 0 u
131
- }
132
- case ( _) { false }
133
- }
134
- }
294
+ let ast:: expr test_call_expr = rec( id = cx. next_node_id( ) ,
295
+ node = test_call_expr_,
296
+ span = rec( lo=0 u, hi=0 u) ) ;
135
297
136
- ret has_test_attr && has_test_signature ( i) ;
298
+ let ast:: path test_main_path = nospan( rec( idents = ~[ "std" ,
299
+ "test" ,
300
+ "test_main" ] ,
301
+ types = ~[ ] ) ) ;
302
+
303
+ let ast:: expr_ test_main_path_expr_
304
+ = ast:: expr_path( test_main_path) ;
305
+
306
+ let ast:: expr test_main_path_expr = rec( id = cx. next_node_id( ) ,
307
+ node = test_main_path_expr_,
308
+ span = rec( lo=0 u, hi=0 u) ) ;
309
+
310
+ let ast:: expr_ test_main_call_expr_
311
+ = ast:: expr_call( @test_main_path_expr, ~[ @test_call_expr] ) ;
312
+
313
+ let ast:: expr test_main_call_expr = rec( id = cx. next_node_id( ) ,
314
+ node = test_main_call_expr_,
315
+ span = rec( lo=0 u, hi=0 u) ) ;
316
+
317
+ ret @test_main_call_expr;
137
318
}
138
319
139
320
// Local Variables:
0 commit comments