#![cfg(feature = "std")]

use std::sync::{Arc, atomic::AtomicU32};

use osom_lib_arc::std::StdCArc;

#[test]
fn test_carc() {
    let arc = StdCArc::new(42).unwrap();
    assert_eq!(StdCArc::strong_count(&arc), 1);
    assert_eq!(StdCArc::weak_count(&arc), 1);
    let weak = StdCArc::downgrade(&arc).unwrap();
    assert_eq!(StdCArc::strong_count(&arc), 1);
    assert_eq!(StdCArc::weak_count(&arc), 2);
    let up = weak.upgrade().unwrap();
    assert_eq!(StdCArc::strong_count(&arc), 2);
    assert_eq!(StdCArc::weak_count(&arc), 2);
    drop(weak);
    assert_eq!(StdCArc::strong_count(&arc), 2);
    assert_eq!(StdCArc::weak_count(&arc), 1);
    drop(up);
    assert_eq!(StdCArc::strong_count(&arc), 1);
    assert_eq!(StdCArc::weak_count(&arc), 1);

    let arc_clone = arc.clone();
    assert_eq!(StdCArc::strong_count(&arc), 2);
    assert_eq!(StdCArc::weak_count(&arc), 1);
    assert_eq!(StdCArc::strong_count(&arc_clone), 2);
    assert_eq!(StdCArc::weak_count(&arc_clone), 1);
    assert_eq!(StdCArc::data(&arc), &42);
    assert_eq!(StdCArc::data(&arc_clone), &42);
}

#[test]
fn test_drop() {
    struct Data {
        pub counter: Arc<AtomicU32>,
    }

    impl Drop for Data {
        fn drop(&mut self) {
            self.counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
        }
    }

    let counter = Arc::new(AtomicU32::new(0));
    let get = || counter.load(std::sync::atomic::Ordering::SeqCst);

    let data = StdCArc::new(Data {
        counter: counter.clone(),
    })
    .unwrap();
    assert_eq!(get(), 0);
    let data2 = data.clone();
    assert_eq!(get(), 0);
    drop(data2);
    assert_eq!(get(), 0);
    drop(data);
    assert_eq!(get(), 1);
}
