Skip to content

Commit f1f12ec

Browse files
committed
Test reference counting in NSValue, NSArray and NSMutableArray
1 parent 6582c3a commit f1f12ec

File tree

6 files changed

+218
-145
lines changed

6 files changed

+218
-145
lines changed

objc2/src/__macro_helpers.rs

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,6 @@ mod tests {
255255
use crate::rc::{Allocated, Owned, RcTestObject, Shared, ThreadTestData};
256256
use crate::runtime::Object;
257257
use crate::{class, msg_send_id};
258-
use crate::{Encoding, RefEncode};
259258

260259
#[test]
261260
fn test_macro_alloc() {
@@ -273,30 +272,15 @@ mod tests {
273272
}
274273

275274
#[test]
276-
#[cfg_attr(
277-
all(feature = "gnustep-1-7", feature = "verify_message"),
278-
ignore = "NSZone's encoding is quite complex on GNUStep"
279-
)]
280275
fn test_alloc_with_zone() {
281-
#[repr(C)]
282-
struct _NSZone {
283-
_inner: [u8; 0],
284-
}
285-
286-
unsafe impl RefEncode for _NSZone {
287-
const ENCODING_REF: Encoding<'static> =
288-
Encoding::Pointer(&Encoding::Struct("_NSZone", &[]));
289-
}
290-
291-
let expected = ThreadTestData::current();
276+
use crate::foundation::NSZone;
277+
let mut expected = ThreadTestData::current();
292278
let cls = RcTestObject::class();
293279

294-
let zone: *const _NSZone = ptr::null();
280+
let zone: *const NSZone = ptr::null();
295281
let _obj: Id<Allocated<RcTestObject>, Owned> =
296282
unsafe { msg_send_id![cls, allocWithZone: zone].unwrap() };
297-
// `+[NSObject alloc]` delegates to `+[NSObject allocWithZone:]`, but
298-
// `RcTestObject` only catches `alloc`.
299-
// expected.alloc += 1;
283+
expected.alloc += 1;
300284
expected.assert_current();
301285
}
302286

@@ -339,9 +323,18 @@ mod tests {
339323
expected.init += 1;
340324
expected.assert_current();
341325

342-
// TODO:
343-
// let copy: Id<RcTestObject, Shared> = unsafe { msg_send_id![&obj, copy].unwrap() };
344-
// let mutable_copy: Id<RcTestObject, Shared> = unsafe { msg_send_id![&obj, mutableCopy].unwrap() };
326+
let _copy: Id<RcTestObject, Shared> = unsafe { msg_send_id![&obj, copy].unwrap() };
327+
expected.copy += 1;
328+
expected.alloc += 1;
329+
expected.init += 1;
330+
expected.assert_current();
331+
332+
let _mutable_copy: Id<RcTestObject, Shared> =
333+
unsafe { msg_send_id![&obj, mutableCopy].unwrap() };
334+
expected.mutable_copy += 1;
335+
expected.alloc += 1;
336+
expected.init += 1;
337+
expected.assert_current();
345338

346339
let _self: Id<RcTestObject, Shared> = unsafe { msg_send_id![&obj, self].unwrap() };
347340
expected.retain += 1;
@@ -351,8 +344,8 @@ mod tests {
351344
unsafe { msg_send_id![&obj, description] };
352345
expected.assert_current();
353346
});
354-
expected.release += 3;
355-
expected.dealloc += 2;
347+
expected.release += 5;
348+
expected.dealloc += 4;
356349
expected.assert_current();
357350
}
358351

objc2/src/foundation/array.rs

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ mod tests {
244244

245245
use super::*;
246246
use crate::foundation::{NSNumber, NSString};
247-
use crate::rc::autoreleasepool;
247+
use crate::rc::{RcTestObject, ThreadTestData};
248248

249249
fn sample_array(len: usize) -> Id<NSArray<NSObject, Owned>, Owned> {
250250
let mut vec = Vec::with_capacity(len);
@@ -262,10 +262,6 @@ mod tests {
262262
NSArray::from_vec(vec)
263263
}
264264

265-
fn retain_count(obj: &NSObject) -> usize {
266-
unsafe { msg_send![obj, retainCount] }
267-
}
268-
269265
#[test]
270266
fn test_two_empty() {
271267
let _empty_array1 = NSArray::<NSObject, _>::new();
@@ -317,25 +313,76 @@ mod tests {
317313
}
318314

319315
#[test]
320-
fn test_get_does_not_autorelease() {
321-
let obj: Id<_, Shared> = NSObject::new().into();
316+
fn test_retains_stored() {
317+
let obj = Id::from_owned(RcTestObject::new());
318+
let mut expected = ThreadTestData::current();
319+
320+
let input = [obj.clone(), obj.clone()];
321+
expected.retain += 2;
322+
expected.assert_current();
322323

323-
assert_eq!(retain_count(&obj), 1);
324+
let array = NSArray::from_slice(&input);
325+
expected.retain += 2;
326+
expected.assert_current();
324327

325-
let array = NSArray::from_slice(&[obj.clone()]);
328+
let _obj = array.first().unwrap();
329+
expected.assert_current();
326330

327-
assert_eq!(retain_count(&obj), 2);
331+
drop(array);
332+
expected.release += 2;
333+
expected.assert_current();
328334

329-
autoreleasepool(|_pool| {
330-
let obj2 = array.first().unwrap();
331-
assert_eq!(retain_count(obj2), 2);
332-
});
335+
let array = NSArray::from_vec(Vec::from(input));
336+
expected.retain += 2;
337+
expected.release += 2;
338+
expected.assert_current();
333339

334-
assert_eq!(retain_count(&obj), 2);
340+
let _obj = array.get(0).unwrap();
341+
let _obj = array.get(1).unwrap();
342+
assert!(array.get(2).is_none());
343+
expected.assert_current();
335344

336345
drop(array);
346+
expected.release += 2;
347+
expected.assert_current();
348+
349+
drop(obj);
350+
expected.release += 1;
351+
expected.dealloc += 1;
352+
expected.assert_current();
353+
}
337354

338-
assert_eq!(retain_count(&obj), 1);
355+
#[test]
356+
fn test_nscopying_uses_retain() {
357+
let obj = Id::from_owned(RcTestObject::new());
358+
let array = NSArray::from_slice(&[obj]);
359+
let mut expected = ThreadTestData::current();
360+
361+
let _copy = array.copy();
362+
expected.assert_current();
363+
364+
let _copy = array.mutable_copy();
365+
expected.retain += 1;
366+
expected.assert_current();
367+
}
368+
369+
#[test]
370+
fn test_iter_no_retain() {
371+
let obj = Id::from_owned(RcTestObject::new());
372+
let array = NSArray::from_slice(&[obj]);
373+
let mut expected = ThreadTestData::current();
374+
375+
let iter = array.iter();
376+
expected.retain += if cfg!(feature = "gnustep-1-7") { 0 } else { 1 };
377+
expected.assert_current();
378+
379+
assert_eq!(iter.count(), 1);
380+
expected.autorelease += if cfg!(feature = "gnustep-1-7") { 0 } else { 1 };
381+
expected.assert_current();
382+
383+
let iter = array.iter_fast();
384+
assert_eq!(iter.count(), 1);
385+
expected.assert_current();
339386
}
340387

341388
#[test]

objc2/src/foundation/mutable_array.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -226,47 +226,68 @@ mod tests {
226226

227227
use super::*;
228228
use crate::foundation::NSString;
229-
use crate::rc::autoreleasepool;
229+
use crate::rc::{autoreleasepool, RcTestObject, ThreadTestData};
230230

231231
#[test]
232232
fn test_adding() {
233233
let mut array = NSMutableArray::new();
234-
let obj = NSObject::new();
235-
array.push(obj);
236-
234+
let obj1 = RcTestObject::new();
235+
let obj2 = RcTestObject::new();
236+
let mut expected = ThreadTestData::current();
237+
238+
array.push(obj1);
239+
expected.retain += 1;
240+
expected.release += 1;
241+
expected.assert_current();
237242
assert_eq!(array.len(), 1);
238243
assert_eq!(array.get(0), array.get(0));
239244

240-
let obj = NSObject::new();
241-
array.insert(0, obj);
245+
array.insert(0, obj2);
246+
expected.retain += 1;
247+
expected.release += 1;
248+
expected.assert_current();
242249
assert_eq!(array.len(), 2);
243250
}
244251

245252
#[test]
246253
fn test_replace() {
247254
let mut array = NSMutableArray::new();
248-
let obj = NSObject::new();
249-
array.push(obj);
250-
251-
let obj = NSObject::new();
252-
let old_obj = array.replace(0, obj);
255+
let obj1 = RcTestObject::new();
256+
let obj2 = RcTestObject::new();
257+
array.push(obj1);
258+
let mut expected = ThreadTestData::current();
259+
260+
let old_obj = array.replace(0, obj2);
261+
expected.retain += 2;
262+
expected.release += 2;
263+
expected.assert_current();
253264
assert_ne!(&*old_obj, array.get(0).unwrap());
254265
}
255266

256267
#[test]
257268
fn test_remove() {
258269
let mut array = NSMutableArray::new();
259270
for _ in 0..4 {
260-
array.push(NSObject::new());
271+
array.push(RcTestObject::new());
261272
}
273+
let mut expected = ThreadTestData::current();
262274

263-
let _ = array.remove(1);
275+
let _obj = array.remove(1);
276+
expected.retain += 1;
277+
expected.release += 1;
278+
expected.assert_current();
264279
assert_eq!(array.len(), 3);
265280

266-
let _ = array.pop();
281+
let _obj = array.pop();
282+
expected.retain += 1;
283+
expected.release += 1;
284+
expected.assert_current();
267285
assert_eq!(array.len(), 2);
268286

269287
array.clear();
288+
expected.release += 2;
289+
expected.dealloc += 2;
290+
expected.assert_current();
270291
assert_eq!(array.len(), 0);
271292
}
272293

objc2/src/foundation/value.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,16 +227,38 @@ impl fmt::Debug for NSValue {
227227
#[cfg(test)]
228228
mod tests {
229229
use alloc::format;
230-
use core::slice;
230+
use core::{ptr, slice};
231231

232232
use super::*;
233+
use crate::rc::{RcTestObject, ThreadTestData};
233234

234235
#[test]
235236
fn basic() {
236237
let val = NSValue::new(13u32);
237238
assert_eq!(unsafe { val.get::<u32>() }, 13);
238239
}
239240

241+
#[test]
242+
fn does_not_retain() {
243+
let obj = RcTestObject::new();
244+
let expected = ThreadTestData::current();
245+
246+
let val = NSValue::new::<*const RcTestObject>(&*obj);
247+
expected.assert_current();
248+
249+
assert!(ptr::eq(unsafe { val.get::<*const RcTestObject>() }, &*obj));
250+
expected.assert_current();
251+
252+
let _clone = val.clone();
253+
expected.assert_current();
254+
255+
let _copy = val.copy();
256+
expected.assert_current();
257+
258+
drop(val);
259+
expected.assert_current();
260+
}
261+
240262
#[test]
241263
fn test_equality() {
242264
let val1 = NSValue::new(123u32);

objc2/src/macros/declare_class.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,6 @@ macro_rules! declare_class {
516516
$v fn class() -> &'static $crate::runtime::Class {
517517
use $crate::__macro_helpers::Once;
518518

519-
use $crate::declare::ClassBuilder;
520-
use $crate::runtime::{Class, Protocol};
521519
static REGISTER_CLASS: Once = Once::new();
522520

523521
REGISTER_CLASS.call_once(|| {
@@ -527,7 +525,7 @@ macro_rules! declare_class {
527525
stringify!($name),
528526
". Perhaps a class with that name already exists?",
529527
);
530-
let mut builder = ClassBuilder::new(stringify!($name), superclass).expect(err_str);
528+
let mut builder = $crate::declare::ClassBuilder::new(stringify!($name), superclass).expect(err_str);
531529

532530
$(
533531
builder.add_ivar::<<$ivar as $crate::declare::IvarType>::Type>(
@@ -539,7 +537,7 @@ macro_rules! declare_class {
539537
// Implement protocol if any specified
540538
$(
541539
let err_str = concat!("could not find protocol ", stringify!($protocol));
542-
builder.add_protocol(Protocol::get(stringify!($protocol)).expect(err_str));
540+
builder.add_protocol($crate::runtime::Protocol::get(stringify!($protocol)).expect(err_str));
543541
)?
544542

545543
// Implement methods
@@ -558,7 +556,7 @@ macro_rules! declare_class {
558556
});
559557

560558
// We just registered the class, so it should be available
561-
Class::get(stringify!($name)).unwrap()
559+
$crate::runtime::Class::get(stringify!($name)).unwrap()
562560
}
563561
}
564562

0 commit comments

Comments
 (0)