use core::{marker::PhantomPinned, pin::Pin, sync::atomic::Ordering::Relaxed};

use crate::{Atomic, AtomicOption};

#[test]
fn drop_empty() {
    let atomic = <AtomicOption<Box<&str>>>::none();
    drop(atomic);
}

#[test]
fn drop_emptied() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    atomic.take(Relaxed).unwrap();
    drop(atomic);
}

#[test]
fn drop_filled() {
    let atomic = <AtomicOption<Box<&str>>>::none();
    assert_eq!(
        atomic.insert(Box::new("hello world"), Relaxed, Relaxed),
        Ok(())
    );
    drop(atomic);
}

#[test]
fn drop_nonempty() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    drop(atomic);
}

#[test]
fn drop_nonoptional() {
    let atomic = <Atomic<Box<&str>>>::new(Box::new("hello world"));
    drop(atomic);
}

#[test]
fn drop_nonoptional_swapped() {
    let atomic = <Atomic<Box<&str>>>::new(Box::new("hello world"));
    atomic.swap(Box::new("hallo whirl"), Relaxed);
    drop(atomic);
}

#[test]
fn drop_swapped() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    atomic.swap(Box::new("hallo whirl"), Relaxed);
    drop(atomic);
}

#[test]
fn insert_failure() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    assert_eq!(
        atomic.insert(Box::new("hallo whirl"), Relaxed, Relaxed),
        Err(Box::new("hallo whirl"))
    );
    drop(atomic);
}

#[test]
fn load_empty() {
    let atomic = <AtomicOption<Box<&str>>>::none();
    assert_eq!(atomic.load(Relaxed), None);
    drop(atomic);
}

#[test]
fn load_nonempty() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    assert_eq!(atomic.load(Relaxed), Some(&"hello world"));
    drop(atomic);
}

#[test]
fn load_empty_mut() {
    let mut atomic = <AtomicOption<Box<&str>>>::none();
    assert_eq!(atomic.load_mut(), None);
    drop(atomic);
}

#[test]
fn load_nonempty_mut() {
    let mut atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    *atomic.load_mut().unwrap() = "good bye, world!";
    assert_eq!(atomic.load(Relaxed), Some(&"good bye, world!"));
    drop(atomic);
}

#[test]
fn load() {
    let atomic = <Atomic<Box<&str>>>::new(Box::new("hello world"));
    assert_eq!(atomic.load(Relaxed), &"hello world");
    drop(atomic);
}

#[test]
fn load_mut() {
    let mut atomic = <Atomic<Box<&str>>>::new(Box::new("hello world"));
    *atomic.load_mut() = "good bye, world!";
    assert_eq!(atomic.load(Relaxed), &"good bye, world!");
    drop(atomic);
}

#[test]
fn take_failure() {
    let atomic = <AtomicOption<Box<&str>>>::none();
    assert_eq!(atomic.take(Relaxed), None);
    drop(atomic);
}

#[test]
fn clone_empty() {
    let atomic = <AtomicOption<Box<&str>>>::none();
    assert_eq!(atomic.load_clone(Relaxed), None);
    drop(atomic);
}

#[test]
fn clone_nonempty() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    assert_eq!(atomic.load_clone(Relaxed), Some(Box::new("hello world")));
    drop(atomic);
}

#[test]
fn clone() {
    let atomic = <Atomic<Box<&str>>>::new(Box::new("hello world"));
    assert_eq!(atomic.load_clone(Relaxed), Box::new("hello world"));
    drop(atomic);
}

struct Pinned {
    marker: PhantomPinned,
    data: &'static str,
}
impl Pinned {
    fn new(data: &'static str) -> Pinned {
        Pinned {
            marker: PhantomPinned,
            data,
        }
    }
}

#[test]
fn pinned() {
    let mut atomic = <Atomic<Pin<Box<Pinned>>>>::new(Box::pin(Pinned::new("hello, world!")));
    assert_eq!(
        atomic.load_mut_pinned().into_ref().get_ref().data,
        "hello, world!"
    );
    drop(atomic);
}

#[test]
fn pinned_empty() {
    let mut atomic = <AtomicOption<Pin<Box<Pinned>>>>::none();
    assert!(atomic.load_mut_pinned().is_none());
    drop(atomic);
}

#[test]
fn pinned_nonempty() {
    let mut atomic = <AtomicOption<Pin<Box<Pinned>>>>::some(Box::pin(Pinned::new("hello, world!")));
    assert_eq!(
        atomic.load_mut_pinned().unwrap().into_ref().get_ref().data,
        "hello, world!"
    );
    drop(atomic);
}
