Skip to content

Commit

Permalink
refactor(serde_yml): 🎨 add unit tests for util.rs and examples
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastienrousseau committed May 30, 2024
1 parent 303a741 commit 28dec03
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 7 deletions.
10 changes: 8 additions & 2 deletions examples/libyml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ pub(crate) mod tag;
/// This module contains the `emitter` example.
pub(crate) mod emitter;

/// This module contains the `util` example.
pub(crate) mod util;

/// The main function that runs all the example modules.
pub(crate) fn main() {
// Run the example module `emitter`.
emitter::main();

// Run the example module `tag`.
tag::main();

// Run the example module `emitter`.
emitter::main();
// Run the example module `util`.
util::main();
}
69 changes: 69 additions & 0 deletions examples/libyml/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//! Examples for the `Owned` and `InitPtr` structs and their methods in the `util` module.
//!
//! This file demonstrates the creation, usage, and safety considerations of `Owned` and `InitPtr` instances,
//! as well as the usage of their various methods.

use serde_yml::libyml::util::{InitPtr, Owned};
use std::mem::MaybeUninit;
use std::ops::Deref;

pub(crate) fn main() {
// Print a message to indicate the file being executed.
println!("\n❯ Executing examples/libyml/util.rs");

// Example: Creating a new uninitialized Owned instance
let uninit_owned: Owned<MaybeUninit<i32>, i32> =
Owned::new_uninit();
println!(
"\n✅ Created a new uninitialized Owned instance: {:?}",
uninit_owned
);

// Example: Converting an uninitialized Owned instance to an initialized one
let init_owned: Owned<i32> =
unsafe { Owned::assume_init(uninit_owned) };
println!(
"\n✅ Converted to an initialized Owned instance: {:?}",
init_owned
);

// Example: Dereferencing an Owned instance
let init_ptr = init_owned.deref().ptr;
println!(
"\n✅ Dereferenced the Owned instance to get the InitPtr: {:?}",
init_ptr
);

// Example: Creating an InitPtr instance
let mut value: i32 = 42;
let init_ptr = InitPtr { ptr: &mut value };
println!(
"\n✅ Created an InitPtr instance: {:?} with value: {}",
init_ptr,
unsafe { *init_ptr.ptr }
);

// Example: Using the Drop implementation
{
let drop_owned: Owned<MaybeUninit<i32>, i32> =
Owned::new_uninit();
println!(
"\n✅ Created a new Owned instance to be dropped: {:?}",
drop_owned
);
} // drop_owned goes out of scope here, and memory is deallocated.

// Example: Creating Owned instances with different types
let uninit_owned_f64: Owned<MaybeUninit<f64>, f64> =
Owned::new_uninit();
println!(
"\n✅ Created a new uninitialized Owned<f64> instance: {:?}",
uninit_owned_f64
);
let init_owned_f64: Owned<f64> =
unsafe { Owned::assume_init(uninit_owned_f64) };
println!(
"\n✅ Converted to an initialized Owned<f64> instance: {:?}",
init_owned_f64
);
}
12 changes: 7 additions & 5 deletions src/libyml/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{
/// A struct representing ownership of a pointer to a value of type `T`.
/// `Init` represents the initialization state of the value.
#[derive(Debug)]
pub(crate) struct Owned<T, Init = T> {
pub struct Owned<T, Init = T> {
ptr: NonNull<T>,
marker: PhantomData<NonNull<Init>>,
}
Expand All @@ -19,7 +19,7 @@ impl<T> Owned<T> {
/// # Safety
/// The created instance contains uninitialized memory, and should be properly
/// initialized before use.
pub(crate) fn new_uninit() -> Owned<MaybeUninit<T>, T> {
pub fn new_uninit() -> Owned<MaybeUninit<T>, T> {
// Allocate memory for `T` but leave it uninitialized.
let boxed = Box::new(MaybeUninit::<T>::uninit());
Owned {
Expand All @@ -35,7 +35,7 @@ impl<T> Owned<T> {
///
/// # Safety
/// The caller must ensure that `definitely_init` is properly initialized.
pub(crate) unsafe fn assume_init(
pub unsafe fn assume_init(
definitely_init: Owned<MaybeUninit<T>, T>,
) -> Owned<T> {
let ptr = definitely_init.ptr;
Expand All @@ -49,8 +49,10 @@ impl<T> Owned<T> {

/// A transparent wrapper around a mutable pointer of type `T`.
#[repr(transparent)]
pub(crate) struct InitPtr<T> {
pub(crate) ptr: *mut T,
#[derive(Debug)]
pub struct InitPtr<T> {
/// The mutable pointer.
pub ptr: *mut T,
}

impl<T, Init> Deref for Owned<T, Init> {
Expand Down
3 changes: 3 additions & 0 deletions tests/libyml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ pub mod test_emitter;

/// This module contains the tests for the `error` module.
pub mod test_error;

/// This module contains the tests for the `util` module.
pub mod test_util;
108 changes: 108 additions & 0 deletions tests/libyml/test_util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#[cfg(test)]
mod tests {
use serde_yml::libyml::util::{InitPtr, Owned};
use std::mem::MaybeUninit;
use std::ops::Deref;

/// Tests that a new uninitialized `Owned` instance can be created.
/// Verifies that the pointer in the `Owned` instance is not null.
#[test]
fn test_new_uninit() {
let uninit_owned: Owned<MaybeUninit<i32>, i32> =
Owned::new_uninit();
assert!(!uninit_owned.ptr.is_null());
}

/// Tests the `assume_init` function to ensure that it correctly converts
/// an uninitialized `Owned` instance to an initialized one.
/// Verifies that the pointer in the initialized `Owned` instance is not null.
#[test]
fn test_assume_init() {
let uninit_owned: Owned<MaybeUninit<i32>, i32> =
Owned::new_uninit();
let init_owned: Owned<i32> =
unsafe { Owned::assume_init(uninit_owned) };
assert!(!init_owned.ptr.is_null());
}

/// Tests the `deref` implementation for `Owned`.
/// Verifies that the dereferenced pointer matches the original pointer.
#[test]
fn test_deref() {
let uninit_owned: Owned<MaybeUninit<i32>, i32> =
Owned::new_uninit();
let init_ptr = uninit_owned.ptr;
assert_eq!(
uninit_owned.deref().ptr as *mut MaybeUninit<i32>,
init_ptr as *mut MaybeUninit<i32>
);
}

/// Tests the `drop` implementation for `Owned`.
/// Ensures that dropping an uninitialized `Owned` instance does not cause a panic.
#[test]
fn test_drop() {
let uninit_owned: Owned<MaybeUninit<i32>, i32> =
Owned::new_uninit();
drop(uninit_owned);
}

/// Tests that an `InitPtr` instance is correctly created and its pointer is not null.
#[test]
fn test_init_ptr() {
let mut value: i32 = 42;
let init_ptr = InitPtr { ptr: &mut value };
assert!(!init_ptr.ptr.is_null());
assert_eq!(unsafe { *init_ptr.ptr }, 42);
}

/// Tests the `deref` implementation for initialized `Owned`.
/// Verifies that the dereferenced pointer matches the original pointer after initialization.
#[test]
fn test_deref_after_init() {
let uninit_owned: Owned<MaybeUninit<i32>, i32> =
Owned::new_uninit();
let init_owned: Owned<i32> =
unsafe { Owned::assume_init(uninit_owned) };
let init_ptr = init_owned.ptr;
assert_eq!(init_owned.deref().ptr, init_ptr);
}

/// Tests creating and initializing an `Owned` instance with a different type (f64).
#[test]
fn test_new_uninit_f64() {
let uninit_owned: Owned<MaybeUninit<f64>, f64> =
Owned::new_uninit();
assert!(!uninit_owned.ptr.is_null());
}

/// Tests the `assume_init` function with a different type (f64).
#[test]
fn test_assume_init_f64() {
let uninit_owned: Owned<MaybeUninit<f64>, f64> =
Owned::new_uninit();
let init_owned: Owned<f64> =
unsafe { Owned::assume_init(uninit_owned) };
assert!(!init_owned.ptr.is_null());
}

/// Tests the `deref` implementation for `Owned` with a different type (f64).
#[test]
fn test_deref_f64() {
let uninit_owned: Owned<MaybeUninit<f64>, f64> =
Owned::new_uninit();
let init_ptr = uninit_owned.ptr;
assert_eq!(
uninit_owned.deref().ptr as *mut MaybeUninit<f64>,
init_ptr as *mut MaybeUninit<f64>
);
}

/// Tests the `drop` implementation for `Owned` with a different type (f64).
#[test]
fn test_drop_f64() {
let uninit_owned: Owned<MaybeUninit<f64>, f64> =
Owned::new_uninit();
drop(uninit_owned);
}
}

0 comments on commit 28dec03

Please sign in to comment.