Skip to content

Commit

Permalink
Update with tests from Jethro
Browse files Browse the repository at this point in the history
  • Loading branch information
Adrian Cruceru committed Dec 15, 2020
1 parent a20a198 commit 65ea801
Showing 1 changed file with 124 additions and 2 deletions.
126 changes: 124 additions & 2 deletions mbedtls/src/wrapper_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ macro_rules! callback {
}

#[cfg(feature="threading")]
pub trait $n {
pub trait $n : Sync {
unsafe extern "C" fn call_mut(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret where Self: Sized;

fn data_ptr_mut(&mut self) -> *mut ::mbedtls_sys::types::raw_types::c_void;
Expand Down Expand Up @@ -60,7 +60,7 @@ macro_rules! callback {
}

#[cfg(feature="threading")]
pub trait $m {
pub trait $m : Sync {
unsafe extern "C" fn call(user_data: *mut ::mbedtls_sys::types::raw_types::c_void, $($arg:$ty),*) -> $ret where Self: Sized;

fn data_ptr(&self) -> *mut ::mbedtls_sys::types::raw_types::c_void;
Expand Down Expand Up @@ -344,3 +344,125 @@ macro_rules! getter {
}
};
}



#[cfg(test)]
mod tests {
#[allow(dead_code)]
/// Utilities for testing whether types implement certain traits.
///
/// For each trait `Trait` that you want to be able to test, you should
/// implement:
/// ```ignore
/// impl<T: “Trait”> Testable<dyn “Trait”> for T {}
/// ```
///
/// Then, to test whether a type `Type` implements `Trait`, call:
/// ```ignore
/// TestTrait::<dyn “Trait”, “Type”>::new().impls_trait()
/// ```
/// This returns a `bool` indicating whether the trait is implemented.
// This relies on auto-deref to distinguish between types that do and don't
// implement the trait.
mod testtrait {
use core::marker::PhantomData;

pub struct NonImplTrait<T> {
inner: PhantomData<T>
}

pub struct TestTrait<TraitObj: ?Sized, Type> {
non_impl: NonImplTrait<Type>,
phantom: PhantomData<*const TraitObj>,
}

pub trait Testable<T: ?Sized> {}

impl<TraitObj: ?Sized, Type> TestTrait<TraitObj, Type> {
pub fn new() -> Self {
TestTrait { non_impl: NonImplTrait { inner: PhantomData }, phantom: PhantomData }
}
}

impl<TraitObj: ?Sized, Type: Testable<TraitObj>> TestTrait<TraitObj, Type> {
pub fn impls_trait(&self) -> bool {
true
}
}

impl<T> NonImplTrait<T> {
pub fn impls_trait(&self) -> bool {
false
}
}

impl<TraitObj: ?Sized, Type> core::ops::Deref for TestTrait<TraitObj, Type> {
type Target = NonImplTrait<Type>;

fn deref(&self) -> &NonImplTrait<Type> {
&self.non_impl
}
}
}

use testtrait::{TestTrait, Testable};

callback!(RustTest: Fn() -> ());
callback!(NativeTestMut,NativeTest() -> ());

impl<T: Sync> Testable<dyn Sync> for T {}
impl<T: RustTest> Testable<dyn RustTest> for T {}
impl<T: NativeTest> Testable<dyn NativeTest> for T {}
impl<T: NativeTestMut> Testable<dyn NativeTestMut> for T {}

#[test]
#[cfg(feature = "threading")]
fn callback_sync_with_threading() {
fn test_closure<T: RustTest>() {
assert!(TestTrait::<dyn Sync, T>::new().impls_trait(), "RustTest should be Sync");
}
fn test_native_closure<T: NativeTest>() {
assert!(TestTrait::<dyn Sync, T>::new().impls_trait(), "NativeTest should be Sync");
}
fn test_native_mut_closure<T: NativeTestMut>() {
assert!(TestTrait::<dyn Sync, T>::new().impls_trait(), "NativeTestMut should be Sync");
}

test_closure::<fn()->()>();
test_native_closure::<fn()->()>();
test_native_mut_closure::<fn()->()>();

assert!(!TestTrait::<dyn RustTest, &dyn Fn()->()>::new().impls_trait(), "non-Sync closure shouldn't be RustTest");
assert!(TestTrait::<dyn RustTest, &(dyn Fn()->() + Sync)>::new().impls_trait(), "Sync closure should be RustTest");
assert!(!TestTrait::<dyn NativeTest, &dyn Fn()->()>::new().impls_trait(), "non-Sync closure shouldn't be NativeTest");
assert!(TestTrait::<dyn NativeTest, &(dyn Fn()->() + Sync)>::new().impls_trait(), "Sync closure should be NativeTest");
assert!(!TestTrait::<dyn NativeTestMut, &dyn Fn()->()>::new().impls_trait(), "non-Sync closure shouldn't be NativeTestMut");
assert!(TestTrait::<dyn NativeTestMut, &(dyn Fn()->() + Sync)>::new().impls_trait(), "Sync closure should be NativeTestMut");
}

#[test]
#[cfg(not(feature = "threading"))]
fn callback_sync_without_threading() {
fn test_closure<T: RustTest>() {
assert!(!TestTrait::<dyn Sync, T>::new().impls_trait(), "RustTest shouldn't be Sync");
}
fn test_native_closure<T: NativeTest>() {
assert!(!TestTrait::<dyn Sync, T>::new().impls_trait(), "NativeTest shouldn't be Sync");
}
fn test_native_mut_closure<T: NativeTestMut>() {
assert!(!TestTrait::<dyn Sync, T>::new().impls_trait(), "NativeTestMut shouldn't be Sync");
}

test_closure::<fn()->()>();
test_native_closure::<fn()->()>();
test_native_mut_closure::<fn()->()>();

assert!(TestTrait::<dyn RustTest, &dyn Fn()->()>::new().impls_trait(), "non-Sync closure should be RustTest");
assert!(TestTrait::<dyn RustTest, &(dyn Fn()->() + Sync)>::new().impls_trait(), "Sync closure should be RustTest");
assert!(TestTrait::<dyn NativeTest, &dyn Fn()->()>::new().impls_trait(), "non-Sync closure should be NativeTest");
assert!(TestTrait::<dyn NativeTest, &(dyn Fn()->() + Sync)>::new().impls_trait(), "Sync closure should be NativeTest");
assert!(TestTrait::<dyn NativeTestMut, &dyn Fn()->()>::new().impls_trait(), "non-Sync closure should be NativeTestMut");
assert!(TestTrait::<dyn NativeTestMut, &(dyn Fn()->() + Sync)>::new().impls_trait(), "Sync closure should be NativeTestMut");
}
}

0 comments on commit 65ea801

Please sign in to comment.