@@ -1167,3 +1167,131 @@ impl Default for MainThreadValidator {
1167
1167
}
1168
1168
}
1169
1169
}
1170
+
1171
+ #[ cfg( test) ]
1172
+ mod tests {
1173
+ use super :: World ;
1174
+ use std:: {
1175
+ panic,
1176
+ sync:: {
1177
+ atomic:: { AtomicBool , Ordering } ,
1178
+ Arc , Mutex ,
1179
+ } ,
1180
+ } ;
1181
+
1182
+ type ID = u8 ;
1183
+
1184
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
1185
+ enum DropLogItem {
1186
+ Create ( ID ) ,
1187
+ Drop ( ID ) ,
1188
+ }
1189
+
1190
+ struct MayPanicInDrop {
1191
+ drop_log : Arc < Mutex < Vec < DropLogItem > > > ,
1192
+ expected_panic_flag : Arc < AtomicBool > ,
1193
+ should_panic : bool ,
1194
+ id : u8 ,
1195
+ }
1196
+
1197
+ impl MayPanicInDrop {
1198
+ fn new (
1199
+ drop_log : & Arc < Mutex < Vec < DropLogItem > > > ,
1200
+ expected_panic_flag : & Arc < AtomicBool > ,
1201
+ should_panic : bool ,
1202
+ id : u8 ,
1203
+ ) -> Self {
1204
+ println ! ( "creating component with id {}" , id) ;
1205
+ drop_log. lock ( ) . unwrap ( ) . push ( DropLogItem :: Create ( id) ) ;
1206
+
1207
+ Self {
1208
+ drop_log : Arc :: clone ( & drop_log) ,
1209
+ expected_panic_flag : Arc :: clone ( & expected_panic_flag) ,
1210
+ should_panic,
1211
+ id,
1212
+ }
1213
+ }
1214
+ }
1215
+
1216
+ impl Drop for MayPanicInDrop {
1217
+ fn drop ( & mut self ) {
1218
+ println ! ( "dropping component with id {}" , self . id) ;
1219
+
1220
+ {
1221
+ let mut drop_log = self . drop_log . lock ( ) . unwrap ( ) ;
1222
+ drop_log. push ( DropLogItem :: Drop ( self . id ) ) ;
1223
+ // Don't keep the mutex while panicking, or we'll poison it.
1224
+ drop ( drop_log) ;
1225
+ }
1226
+
1227
+ if self . should_panic {
1228
+ self . expected_panic_flag . store ( true , Ordering :: SeqCst ) ;
1229
+ panic ! ( "testing what happens on panic inside drop" ) ;
1230
+ }
1231
+ }
1232
+ }
1233
+
1234
+ struct DropTestHelper {
1235
+ drop_log : Arc < Mutex < Vec < DropLogItem > > > ,
1236
+ /// Set to `true` right before we intentionally panic, so that if we get
1237
+ /// a panic, we know if it was intended or not.
1238
+ expected_panic_flag : Arc < AtomicBool > ,
1239
+ }
1240
+
1241
+ impl DropTestHelper {
1242
+ pub fn new ( ) -> Self {
1243
+ Self {
1244
+ drop_log : Arc :: new ( Mutex :: new ( Vec :: < DropLogItem > :: new ( ) ) ) ,
1245
+ expected_panic_flag : Arc :: new ( AtomicBool :: new ( false ) ) ,
1246
+ }
1247
+ }
1248
+
1249
+ pub fn make_component ( & self , should_panic : bool , id : ID ) -> MayPanicInDrop {
1250
+ MayPanicInDrop :: new ( & self . drop_log , & self . expected_panic_flag , should_panic, id)
1251
+ }
1252
+
1253
+ pub fn finish ( self , panic_res : std:: thread:: Result < ( ) > ) -> Vec < DropLogItem > {
1254
+ let drop_log = Arc :: try_unwrap ( self . drop_log )
1255
+ . unwrap ( )
1256
+ . into_inner ( )
1257
+ . unwrap ( ) ;
1258
+ let expected_panic_flag = self . expected_panic_flag . load ( Ordering :: SeqCst ) ;
1259
+
1260
+ if !expected_panic_flag {
1261
+ match panic_res {
1262
+ Ok ( ( ) ) => panic ! ( "Expected a panic but it didn't happen" ) ,
1263
+ Err ( e) => panic:: resume_unwind ( e) ,
1264
+ }
1265
+ }
1266
+
1267
+ drop_log
1268
+ }
1269
+ }
1270
+
1271
+ #[ test]
1272
+ fn panic_while_overwriting_component ( ) {
1273
+ let helper = DropTestHelper :: new ( ) ;
1274
+
1275
+ let res = panic:: catch_unwind ( || {
1276
+ let mut world = World :: new ( ) ;
1277
+ world
1278
+ . spawn ( )
1279
+ . insert ( helper. make_component ( true , 0 ) )
1280
+ . insert ( helper. make_component ( false , 1 ) ) ;
1281
+
1282
+ println ! ( "Done inserting! Dropping world..." ) ;
1283
+ } ) ;
1284
+
1285
+ let drop_log = helper. finish ( res) ;
1286
+
1287
+ assert_eq ! (
1288
+ & * drop_log,
1289
+ [
1290
+ DropLogItem :: Create ( 0 ) ,
1291
+ DropLogItem :: Create ( 1 ) ,
1292
+ DropLogItem :: Drop ( 0 ) ,
1293
+ DropLogItem :: Drop ( 1 )
1294
+ ]
1295
+ ) ;
1296
+ }
1297
+ }
0 commit comments