Skip to content

Commit

Permalink
Test reference-counting properties of msg_send_id!
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Jun 15, 2022
1 parent aed5cdd commit f1ca00a
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 33 deletions.
108 changes: 78 additions & 30 deletions objc2/src/__macro_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,59 +151,107 @@ mod tests {

use core::ptr;

use crate::rc::{Owned, Shared};
use crate::rc::{Owned, RcTestObject, Shared, ThreadTestData};
use crate::runtime::Object;
use crate::{Encoding, RefEncode};

#[repr(C)]
struct _NSZone {
_inner: [u8; 0],
}
#[test]
fn test_macro_alloc() {
let mut expected = ThreadTestData::current();
let cls = RcTestObject::class();

let obj: Id<RcTestObject, Shared> = unsafe { msg_send_id![cls, alloc].unwrap() };
expected.alloc += 1;
expected.assert_current();

unsafe impl RefEncode for _NSZone {
const ENCODING_REF: Encoding<'static> =
Encoding::Pointer(&Encoding::Struct("_NSZone", &[]));
drop(obj);
expected.release += 1;
expected.dealloc += 1;
expected.assert_current();
}

#[test]
fn test_macro_alloc() {
let cls = class!(NSObject);
#[cfg_attr(
all(feature = "gnustep-1-7", feature = "verify_message"),
ignore = "NSZone's encoding is quite complex on GNUStep"
)]
fn test_alloc_with_zone() {
#[repr(C)]
struct _NSZone {
_inner: [u8; 0],
}

let _obj: Option<Id<Object, Shared>> = unsafe { msg_send_id![cls, alloc] };
unsafe impl RefEncode for _NSZone {
const ENCODING_REF: Encoding<'static> =
Encoding::Pointer(&Encoding::Struct("_NSZone", &[]));
}

let expected = ThreadTestData::current();
let cls = RcTestObject::class();

let zone: *const _NSZone = ptr::null();
let _obj: Option<Id<Object, Owned>> = unsafe { msg_send_id![cls, allocWithZone: zone] };
let _obj: Id<RcTestObject, Owned> =
unsafe { msg_send_id![cls, allocWithZone: zone].unwrap() };
// `+[NSObject alloc]` delegates to `+[NSObject allocWithZone:]`, but
// `RcTestObject` only catches `alloc`.
// expected.alloc += 1;
expected.assert_current();
}

#[test]
fn test_macro_init() {
let cls = class!(NSObject);
let mut expected = ThreadTestData::current();
let cls = RcTestObject::class();

let obj: Option<Id<Object, Shared>> = unsafe { msg_send_id![cls, alloc] };
let obj: Option<Id<RcTestObject, Shared>> = unsafe { msg_send_id![cls, alloc] };
expected.alloc += 1;
// Don't check allocation error
let _obj: Id<Object, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
let _obj: Id<RcTestObject, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
expected.init += 1;
expected.assert_current();

let obj: Option<Id<Object, Shared>> = unsafe { msg_send_id![cls, alloc] };
let obj: Option<Id<RcTestObject, Shared>> = unsafe { msg_send_id![cls, alloc] };
expected.alloc += 1;
// Check allocation error before init
let obj = obj.unwrap();
let _obj: Id<Object, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
let _obj: Id<RcTestObject, Shared> = unsafe { msg_send_id![obj, init].unwrap() };
expected.init += 1;
expected.assert_current();
}

#[test]
fn test_macro() {
let cls = class!(NSObject);

let _obj: Id<Object, Owned> = unsafe { msg_send_id![cls, new].unwrap() };

let obj = unsafe { msg_send_id![cls, alloc] };

let obj: Id<Object, Owned> = unsafe { msg_send_id![obj, init].unwrap() };

// TODO:
// let copy: Id<Object, Shared> = unsafe { msg_send_id![&obj, copy].unwrap() };
// let mutable_copy: Id<Object, Shared> = unsafe { msg_send_id![&obj, mutableCopy].unwrap() };

let _desc: Option<Id<Object, Shared>> = unsafe { msg_send_id![&obj, description] };
let mut expected = ThreadTestData::current();
let cls = RcTestObject::class();
crate::rc::autoreleasepool(|_| {
let _obj: Id<RcTestObject, Owned> = unsafe { msg_send_id![cls, new].unwrap() };
expected.alloc += 1;
expected.init += 1;
expected.assert_current();

let obj = unsafe { msg_send_id![cls, alloc] };
expected.alloc += 1;
expected.assert_current();

let obj: Id<RcTestObject, Owned> = unsafe { msg_send_id![obj, init].unwrap() };
expected.init += 1;
expected.assert_current();

// TODO:
// let copy: Id<RcTestObject, Shared> = unsafe { msg_send_id![&obj, copy].unwrap() };
// let mutable_copy: Id<RcTestObject, Shared> = unsafe { msg_send_id![&obj, mutableCopy].unwrap() };

let _self: Id<RcTestObject, Shared> = unsafe { msg_send_id![&obj, self].unwrap() };
expected.retain += 1;
expected.assert_current();

let _desc: Option<Id<RcTestObject, Shared>> =
unsafe { msg_send_id![&obj, description] };
expected.assert_current();
});
expected.release += 3;
expected.dealloc += 2;
expected.assert_current();
}

#[test]
Expand Down
7 changes: 4 additions & 3 deletions objc2/src/rc/test_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::sync::Once;
use super::{Id, Owned};
use crate::declare::ClassBuilder;
use crate::runtime::{Bool, Class, Object, Sel};
use crate::{msg_send, msg_send_bool, msg_send_id};
use crate::{msg_send, msg_send_bool};
use crate::{Encoding, Message, RefEncode};

#[derive(Debug, Clone, Default, PartialEq)]
Expand Down Expand Up @@ -77,7 +77,7 @@ impl DerefMut for RcTestObject {
}

impl RcTestObject {
fn class() -> &'static Class {
pub(crate) fn class() -> &'static Class {
static REGISTER_CLASS: Once = Once::new();

REGISTER_CLASS.call_once(|| {
Expand Down Expand Up @@ -152,6 +152,7 @@ impl RcTestObject {
}

pub(crate) fn new() -> Id<Self, Owned> {
unsafe { msg_send_id![Self::class(), new] }.unwrap()
// Use msg_send! to test that; msg_send_id! is tested elsewhere!
unsafe { Id::new(msg_send![Self::class(), new]) }.unwrap()
}
}

0 comments on commit f1ca00a

Please sign in to comment.