#![allow(non_local_definitions)]
use super::*;
use crate::data_types::NoatunVec;
use crate::data_types::{NoatunCellArrayExt, NoatunString};
use crate::disk_access::FileAccessor;
use crate::sequence_nr::SequenceNr;
use byteorder::{LittleEndian, WriteBytesExt};
use tracing::info;
use crate::database::{DatabaseSettings, OpenMode};
use data_types::NoatunBox;
use data_types::NoatunCell;
use database::Database;
use datetime_literal::datetime;
use savefile::{
Deserialize, Packed, SavefileError, Schema, Serialize, Serializer, WithSchema,
WithSchemaContext,
};
use savefile_derive::Savefile;
use std::io::{Read, SeekFrom};
use tracing_subscriber::Layer;
mod all_up_sync_test;
mod distributor_tests;
mod fuzz_test_insert;
mod recovery_tests;
mod test_rotation;
mod test_subsumption_hashmap;
mod test_subsumption_vec;
mod test_subsumption_nonlocal;
mod test_subsumption_nonlocal_opaque;
mod tests_using_noatun_object_macro;
mod test_issue_tracker;
mod test_subsumption_map_advanced;
mod test_types_rewind;
pub(crate) mod test_driver;
#[repr(transparent)]
#[derive(Debug)]
pub struct DummyTestApp<Root>(pub Root);
unsafe impl<Root: NoatunStorable> NoatunStorable for DummyTestApp<Root> {
fn hash_schema(hasher: &mut SchemaHasher) {
hasher.write_str("DummyTestApp");
Root::hash_schema(hasher);
}
}
impl<Root> DummyTestApp<Root> {
pub fn inner_mut(self: Pin<&mut Self>) -> Pin<&mut Root> {
unsafe { self.map_unchecked_mut(|x| &mut x.0) }
}
pub fn inner(&self) -> &Root {
&self.0
}
pub fn inner_pin(self: Pin<&mut Self>) -> Pin<&mut Root> {
unsafe { self.map_unchecked_mut(|x| &mut x.0) }
}
}
impl<Root: FixedSizeObject> Object for DummyTestApp<Root> {
type Ptr = ThinPtr;
type NativeType = ();
type NativeOwnedType = ();
fn export(&self) -> Self::NativeOwnedType {}
fn destroy(self: Pin<&mut Self>) {
unimplemented!()
}
fn init_from(self: Pin<&mut Self>, _detached: &Self::NativeType) {}
unsafe fn allocate_from<'a>(_detached: &Self::NativeType) -> Pin<&'a mut Self> {
unimplemented!()
}
fn hash_object_schema(hasher: &mut SchemaHasher) {
hasher.write_str("DummyTestApp");
Root::hash_schema(hasher);
}
}
pub struct DummyTestMessage<Root>(std::marker::PhantomData<Root>);
impl<Root> Default for DummyTestMessage<Root> {
fn default() -> Self {
DummyTestMessage(std::marker::PhantomData)
}
}
impl<Root> Debug for DummyTestMessage<Root> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "DummyTestMessage")
}
}
impl<T> WithSchema for DummyTestMessage<T> {
fn schema(_version: u32, _context: &mut WithSchemaContext) -> Schema {
Schema::Custom("DummyTestMessage".to_string())
}
}
impl<T> Packed for DummyTestMessage<T> {}
impl<T> Serialize for DummyTestMessage<T> {
fn serialize(
&self,
_serializer: &mut Serializer<impl Write>,
) -> std::result::Result<(), SavefileError> {
Ok(())
}
}
impl<T> Deserialize for DummyTestMessage<T> {
fn deserialize(
_deserializer: &mut Deserializer<impl Read>,
) -> std::result::Result<Self, SavefileError> {
Ok(DummyTestMessage(std::marker::PhantomData))
}
}
pub(crate) trait DummyTestMessageApply {
fn test_message_apply(time: NoatunTime, root: Pin<&mut Self>);
}
impl<Root: FixedSizeObject + DummyTestMessageApply> Message for DummyTestMessage<Root> {
type Root = DummyTestApp<Root>;
type Serializer = SavefileMessageSerializer<Self>;
fn apply(&self, time: MessageId, root: Pin<&mut Self::Root>) {
Root::test_message_apply(time.timestamp(), root.inner_mut())
}
}
pub fn setup_tracing() {
set_test_epoch(Instant::now());
pub struct TracingTimer(Instant);
impl tracing_subscriber::fmt::time::FormatTime for TracingTimer {
fn format_time(
&self,
w: &mut tracing_subscriber::fmt::format::Writer<'_>,
) -> core::fmt::Result {
let t = Instant::now();
write!(w, "{:>10?}", (t - self.0))
}
}
use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt;
if std::env::var("RUST_LOG_JSON").is_ok() {
let stdout_log = tracing_subscriber::fmt::layer()
.with_timer(TracingTimer(Instant::now()))
.with_ansi(false)
.json()
.with_filter(tracing_subscriber::EnvFilter::from_default_env());
let subscriber = tracing_subscriber::registry().with(stdout_log);
_ = tracing::subscriber::set_global_default(subscriber);
} else {
let stdout_log = tracing_subscriber::fmt::layer()
.with_timer(TracingTimer(Instant::now()))
.with_ansi(false)
.with_filter(tracing_subscriber::EnvFilter::from_default_env());
let subscriber = tracing_subscriber::registry().with(stdout_log);
_ = tracing::subscriber::set_global_default(subscriber);
}
info!("Tracing enabled");
}
#[test]
fn test_mmap_big() {
let _mmap = FileAccessor::new(
&Target::CreateNewOrOverwrite("test/mmap_test_big".into()),
"mmap",
0,
1024 * 1024 * 1024,
"test_mmap_big",
"test-description",
);
}
#[test]
fn test_mmap_helper() {
let mut mmap = FileAccessor::new(
&Target::CreateNewOrOverwrite("test/mmap_test1".into()),
"mmap",
0,
16 * 1024 * 1024,
"test_mmap1",
"test-description",
)
.unwrap()
.0;
mmap.write_u32::<LittleEndian>(0x2b).unwrap();
use byteorder::ReadBytesExt;
use std::io::Read;
use std::io::Seek;
mmap.seek(SeekFrom::Start(12)).unwrap();
mmap.write_u64::<LittleEndian>(0x2c).unwrap();
mmap.seek(SeekFrom::Start(12)).unwrap();
let initial_ptr = mmap.map_mut_ptr();
assert_eq!(mmap.read_u64::<LittleEndian>().unwrap(), 0x2c);
mmap.seek(SeekFrom::Start(3_000_000)).unwrap();
mmap.write_u8(1).unwrap();
assert_eq!(initial_ptr, mmap.map_mut_ptr());
mmap.seek(SeekFrom::Start(3_000_000)).unwrap();
assert_eq!(mmap.read_u8().unwrap(), 1);
mmap.sync_all().unwrap();
mmap.truncate(0).unwrap();
mmap.seek(SeekFrom::Start(0)).unwrap();
let mut buf = [0];
let got = mmap.read(&mut buf).unwrap();
assert_eq!(got, 0);
mmap.write_u8(42).unwrap();
mmap.write_u8(42).unwrap();
mmap.seek(SeekFrom::Start(0)).unwrap();
assert_eq!(mmap.read_u8().unwrap(), 42);
}
#[repr(C)]
struct CounterObject {
counter: NoatunCell<u32>,
counter2: NoatunCell<u32>,
}
unsafe impl NoatunStorable for CounterObject {
fn hash_schema(hasher: &mut SchemaHasher) {
hasher.write_str("noatun::CounterObject/1");
hasher.write_usize(2);
<NoatunCell<u32> as NoatunStorable>::hash_schema(hasher);
<NoatunCell<u32> as NoatunStorable>::hash_schema(hasher);
}
}
impl Object for CounterObject {
type Ptr = ThinPtr;
type NativeType = ();
type NativeOwnedType = ();
fn export(&self) -> Self::NativeOwnedType {
unimplemented!()
}
fn destroy(self: Pin<&mut Self>) {
unsafe {
let tself = self.get_unchecked_mut();
Pin::new_unchecked(&mut tself.counter).destroy();
Pin::new_unchecked(&mut tself.counter2).destroy();
}
}
fn init_from(self: Pin<&mut Self>, _detached: &Self::NativeType) {
unimplemented!()
}
unsafe fn allocate_from<'a>(_detached: &Self::NativeType) -> Pin<&'a mut Self> {
unimplemented!()
}
fn hash_object_schema(hasher: &mut SchemaHasher) {
hasher.write_str("noatun::CounterObject/1");
}
}
#[test]
fn test1() {
let mut db: Database<CounterMessage> = Database::create_new(
"test/test1.bin",
OpenMode::Overwrite,
DatabaseSettings::default(),
)
.unwrap();
let mut db = db.begin_session_mut().unwrap();
db.with_root_mut(|counter| unsafe {
let counter = counter.get_unchecked_mut();
assert_eq!(counter.counter.get(), 0);
Pin::new_unchecked(&mut counter.counter).set(42);
Pin::new_unchecked(&mut counter.counter2).set(43);
Pin::new_unchecked(&mut counter.counter).set(44);
assert_eq!(counter.counter.get(), 44);
assert_eq!(counter.counter.get(), 44);
assert_eq!(counter.counter2.get(), 43);
})
.unwrap();
}
#[derive(Debug, Clone, Savefile)]
struct CounterMessage {
id: MessageId,
parent: Vec<MessageId>,
inc1: i32,
set1: u32,
}
impl CounterMessage {
fn wrap(&self, cutoff: NoatunTime) -> MessageFrame<CounterMessage> {
MessageFrame::new(
self.id,
if self.id.timestamp() >= cutoff {
self.parent.clone()
} else {
vec![]
},
self.clone(),
)
}
}
impl Message for CounterMessage {
type Root = CounterObject;
type Serializer = SavefileMessageSerializer<Self>;
fn apply(&self, _time: MessageId, root: Pin<&mut CounterObject>) {
unsafe {
if self.inc1 != 0 {
let val = root.counter.get().saturating_add_signed(self.inc1);
root.map_unchecked_mut(|x| &mut x.counter).set(val);
} else {
root.map_unchecked_mut(|x| &mut x.counter).set(self.set1);
}
}
}
}
#[test]
fn test_projection_time_limit() {
let mut db: Database<CounterMessage> = Database::create_new(
"test/msg_store_time_limit.bin",
OpenMode::Overwrite,
DatabaseSettings {
projection_time_limit: Some(datetime!(2024-01-02 00:00:00 Z).into()),
..Default::default()
},
)
.unwrap();
let mut db = db.begin_session_mut().unwrap();
db.append_single(
&CounterMessage {
parent: vec![],
id: MessageId::from_parts(datetime!(2024-01-01 00:00:00 Z).into(), [0; 10]).unwrap(),
inc1: 1,
set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.mark_transmitted(MessageId::new_debug(0x100)).unwrap();
db.append_single(
&CounterMessage {
parent: vec![],
id: MessageId::from_parts(datetime!(2024-01-02 00:00:00 Z).into(), [0; 10]).unwrap(),
inc1: 1,
set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.append_single(
&CounterMessage {
parent: vec![],
id: MessageId::from_parts(datetime!(2024-01-03 00:00:00 Z).into(), [0; 10]).unwrap(),
inc1: 1, set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.with_root_mut(|root| {
assert_eq!(root.counter.get(), 2);
})
.unwrap();
db.with_root_preview(
datetime!(2024-01-03 00:00:00 Z),
[CounterMessage {
parent: vec![],
id: MessageId::from_parts(datetime!(2024-01-03 00:00:00 Z).into(), [0; 10]).unwrap(),
inc1: 2,
set1: 0,
}]
.into_iter(),
|root| {
assert_eq!(root.counter.get(), 4);
},
)
.unwrap();
db.with_root_mut(|root| {
assert_eq!(root.counter.get(), 2);
})
.unwrap();
}
#[test]
fn test_msg_store_real() {
let mut db: Database<CounterMessage> = Database::create_new(
"test/msg_store.bin",
OpenMode::Overwrite,
DatabaseSettings::default(),
)
.unwrap();
let mut db = db.begin_session_mut().unwrap();
db.append_single(
&CounterMessage {
parent: vec![],
id: MessageId::new_debug(0x100),
inc1: 2,
set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.mark_transmitted(MessageId::new_debug(0x100)).unwrap();
db.append_single(
&CounterMessage {
parent: vec![MessageId::new_debug(0x100)],
id: MessageId::new_debug(0x101),
inc1: 0,
set1: 42,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.append_single(
&CounterMessage {
parent: vec![MessageId::new_debug(0x101)],
id: MessageId::new_debug(0x102),
inc1: 1,
set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
println!("Update heads: {:?}", db.get_update_heads());
db.with_root_mut(|root| {
assert_eq!(root.counter.get(), 43);
})
.unwrap();
}
#[test]
fn test_msg_store_inmem_miri() {
let mut db: Database<CounterMessage> = Database::create_in_memory(
10000,
DatabaseSettings {
mock_time: Some(datetime!(2021-01-01 Z).into()),
..Default::default()
},
)
.unwrap();
let mut db = db.begin_session_mut().unwrap();
db.append_single(
&CounterMessage {
parent: vec![],
id: MessageId::new_debug(0x100),
inc1: 2,
set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.append_single(
&CounterMessage {
parent: vec![MessageId::new_debug(0x100)],
id: MessageId::new_debug(0x101),
inc1: 0,
set1: 42,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.append_single(
&CounterMessage {
parent: vec![MessageId::new_debug(0x101)],
id: MessageId::new_debug(0x102),
inc1: 1,
set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
assert!(!db.contains_message(MessageId::new_debug(0x100)).unwrap());
assert!(db.contains_message(MessageId::new_debug(0x101)).unwrap());
assert!(db.contains_message(MessageId::new_debug(0x102)).unwrap());
db.with_root_mut(|root| {
assert_eq!(root.counter.get(), 43);
})
.unwrap();
}
#[test]
fn test_msg_store_after_cutoff_inmem_miri() {
setup_tracing();
let mut db: Database<CounterMessage> = Database::create_in_memory(
10000,
DatabaseSettings {
mock_time: Some(datetime!(2024-01-01 Z).into()),
..Default::default()
},
)
.unwrap();
let m1 = MessageId::from_parts(datetime!(2024-01-01 Z).into(), [0u8; 10]).unwrap();
let mut db = db.begin_session_mut().unwrap();
db.append_single(
&CounterMessage {
parent: vec![],
id: m1,
inc1: 2,
set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.mark_transmitted(m1).unwrap();
let m2 = MessageId::from_parts(datetime!(2024-01-01 Z).into(), [1u8; 10]).unwrap();
db.append_single(
&CounterMessage {
parent: vec![MessageId::new_debug(0x100)],
id: m2,
inc1: 0,
set1: 42,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.set_mock_time(datetime!(2024-01-10 Z).into()).unwrap();
db.reproject().unwrap();
println!("Appending 2nd");
let m3 = MessageId::from_parts(datetime!(2024-01-10 Z).into(), [2u8; 10]).unwrap();
db.append_single(
&CounterMessage {
parent: vec![MessageId::new_debug(0x101)],
id: m3,
inc1: 1,
set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
assert!(!db.contains_message(m1).unwrap());
assert!(db.contains_message(m2).unwrap());
assert!(db.contains_message(m3).unwrap());
db.with_root_mut(|root| {
assert_eq!(root.counter.get(), 43);
})
.unwrap();
}
#[test]
fn test_cutoff_handling() {
let mut db: Database<CounterMessage> =
Database::create_in_memory(10000, DatabaseSettings::default()).unwrap();
let mut db = db.begin_session_mut().unwrap();
db.append_single(
&CounterMessage {
id: MessageId::new_debug(0x100),
parent: vec![],
inc1: 2,
set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.append_single(
&CounterMessage {
id: MessageId::new_debug(0x101),
parent: vec![MessageId::new_debug(0x100)],
inc1: 0,
set1: 42,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.append_single(
&CounterMessage {
id: MessageId::new_debug(0x102),
parent: vec![MessageId::new_debug(0x101)],
inc1: 1,
set1: 0,
}
.wrap(db.current_cutoff_time().unwrap()),
true,
)
.unwrap();
db.with_root_mut(|root| {
assert_eq!(root.counter.get(), 43);
})
.unwrap();
}
#[test]
fn test_handle() {
impl DummyTestMessageApply for NoatunBox<NoatunCell<u32>> {
fn test_message_apply(_time: NoatunTime, root: Pin<&mut Self>) {
root.assign(&43);
}
}
let mut db: Database<DummyTestMessage<NoatunBox<NoatunCell<u32>>>> = Database::create_new(
"test/test_handle.bin",
OpenMode::Overwrite,
DatabaseSettings::default(),
)
.unwrap();
db.begin_session_mut()
.unwrap()
.append_local(DummyTestMessage::default())
.unwrap();
db.with_root(|handle| {
assert_eq!(handle.0.get_inner().get(), 43);
});
}
#[test]
fn test_handle_to_unsized_miri() {
impl DummyTestMessageApply for NoatunBox<[NoatunCell<u8>]> {
fn test_message_apply(_time: NoatunTime, root: Pin<&mut Self>) {
root.assign(&[1, 2, 3]);
}
}
let mut db: Database<DummyTestMessage<NoatunBox<[NoatunCell<u8>]>>> =
Database::create_in_memory(
1000,
DatabaseSettings {
mock_time: Some(datetime!(2021-01-01 Z).into()),
..Default::default()
},
)
.unwrap();
db.begin_session_mut()
.unwrap()
.append_local(DummyTestMessage::default())
.unwrap();
db.with_root(|handle| {
assert_eq!(handle.inner().get_inner().observe(), &[1, 2, 3]);
});
}
#[test]
fn test_noatun_box_miri() {
let mut db: Database<DummyTestMessage<NoatunBox<NoatunCell<u32>>>> =
Database::create_in_memory(
1000,
DatabaseSettings {
mock_time: Some(datetime!(2021-01-01 Z).into()),
..Default::default()
},
)
.unwrap();
db.begin_session_mut()
.unwrap()
.append_local(DummyTestMessage::default())
.unwrap();
db.with_root(|handle| {
assert_eq!(handle.inner().get_inner().get(), 43);
});
let mut db = db.begin_session_mut().unwrap();
db.with_root_mut(|root| {
let a1 = root.inner_mut().get_inner_mut();
assert_eq!(a1.get(), 43);
})
.unwrap();
}
#[test]
fn test_string0() {
let mut db: Database<DummyTestMessage<NoatunString>> = Database::create_new(
"test/test_string0",
OpenMode::Overwrite,
DatabaseSettings::default(),
)
.unwrap();
let mut db = db.begin_session_mut().unwrap();
db.with_root_mut(|test_str| {
let mut test_str = test_str.inner_pin();
test_str.as_mut().assign("hello");
assert_eq!(test_str.len(), 5);
assert_eq!(test_str.get(), "hello");
let ptr = test_str.get().as_ptr();
test_str.as_mut().assign("hell");
assert_eq!(ptr, test_str.get().as_ptr());
assert_eq!(test_str.get(), "hell");
test_str.as_mut().assign("hello world!");
assert_eq!(test_str.get(), "hello world!");
})
.unwrap();
}
#[test]
fn test_vec0() {
impl DummyTestMessageApply for NoatunVec<CounterObject> {
fn test_message_apply(_time: NoatunTime, _root: Pin<&mut Self>) {}
}
let mut db: Database<DummyTestMessage<NoatunVec<CounterObject>>> = Database::create_new(
"test/test_vec0",
OpenMode::Overwrite,
DatabaseSettings::default(),
)
.unwrap();
let mut db = db.begin_session_mut().unwrap();
db.with_root_mut(|counter_vec| {
let mut counter_vec = counter_vec.inner_pin();
unsafe {
assert_eq!(counter_vec.len(), 0);
let _new_element = counter_vec.as_mut().push_zeroed();
let new_element = counter_vec.as_mut().get_index_mut(0);
new_element.map_unchecked_mut(|x| &mut x.counter).set(47);
let new_element = counter_vec.as_mut().push_zeroed();
new_element.map_unchecked_mut(|x| &mut x.counter).set(48);
assert_eq!(counter_vec.len(), 2);
let item = counter_vec.as_mut().get_index_mut(1);
assert_eq!(item.counter.get(), 48);
for _ in 0..10 {
let _new_element = counter_vec.as_mut().push_zeroed();
}
let item = counter_vec.as_mut().get_index_mut(1);
assert_eq!(item.counter.get(), 48);
}
})
.unwrap();
}
#[test]
fn test_vec_miri0() {
let mut db: Database<DummyTestMessage<NoatunVec<CounterObject>>> = Database::create_in_memory(
10000,
DatabaseSettings {
mock_time: Some(datetime!(2021-01-01 Z).into()),
..Default::default()
},
)
.unwrap();
let mut db = db.begin_session_mut().unwrap();
db.with_root_mut(|counter_vec| {
let mut counter_vec = counter_vec.inner_pin();
assert_eq!(counter_vec.len(), 0);
let _new_element = counter_vec.as_mut().push_zeroed();
let new_element = counter_vec.as_mut().get_index_mut(0);
unsafe {
new_element.map_unchecked_mut(|x| &mut x.counter).set(47);
}
let new_element = counter_vec.as_mut().push_zeroed();
unsafe {
new_element.map_unchecked_mut(|x| &mut x.counter).set(48);
}
assert_eq!(counter_vec.len(), 2);
let item = counter_vec.as_mut().get_index_mut(1);
assert_eq!(item.counter.get(), 48);
for _i in 0..10 {
let _new_element = counter_vec.as_mut().push_zeroed();
}
let item = counter_vec.as_mut().get_index_mut(1);
assert_eq!(item.counter.get(), 48);
assert_eq!(counter_vec.len(), 12);
counter_vec.as_mut().swap_remove(1);
assert_eq!(counter_vec.len(), 11);
assert_eq!(counter_vec.as_mut()[0].counter.get(), 47);
counter_vec.as_mut().retain(|x| x.counter.get() == 0);
assert_eq!(counter_vec.len(), 10);
for i in 0..10 {
assert_eq!(counter_vec[i].counter.get() as usize, 0);
}
})
.unwrap();
}
#[test]
fn test_vec_retain_miri0() {
let mut db: Database<DummyTestMessage<NoatunVec<CounterObject>>> = Database::create_in_memory(
10000,
DatabaseSettings {
mock_time: Some(datetime!(2021-01-01 Z).into()),
..Default::default()
},
)
.unwrap();
let mut db = db.begin_session_mut().unwrap();
db.with_root_mut(|counter_vec| {
let mut counter_vec = counter_vec.inner_pin();
let obj0 = counter_vec.as_mut().push_zeroed();
unsafe {
obj0.map_unchecked_mut(|x| &mut x.counter).set(0);
}
let obj1 = counter_vec.as_mut().push_zeroed();
unsafe {
obj1.map_unchecked_mut(|x| &mut x.counter).set(1);
}
let obj2 = counter_vec.as_mut().push_zeroed();
unsafe {
obj2.map_unchecked_mut(|x| &mut x.counter).set(2);
}
catch_unwind(AssertUnwindSafe(|| {
counter_vec.as_mut().retain(|x| {
if x.counter.get() == 0 {
false
} else {
panic!("check panics")
}
});
}))
.unwrap_err();
assert_eq!(counter_vec.as_mut().len(), 2);
assert_eq!(counter_vec.get_index(0).counter.get(), 1);
assert_eq!(counter_vec.get_index(1).counter.get(), 2);
})
.unwrap();
}
#[test]
fn test_vec_undo() {
let mut db: Database<DummyTestMessage<NoatunVec<CounterObject>>> = Database::create_new(
"test/vec_undo",
OpenMode::Overwrite,
DatabaseSettings::default(),
)
.unwrap();
{
let mut db = db.begin_session_mut().unwrap();
db.with_root_mut(|counter_vec| {
let mut counter_vec = counter_vec.inner_pin();
NoatunContext.set_next_seqnr(SequenceNr::from_index(1));
assert_eq!(counter_vec.len(), 0);
let mut new_element = counter_vec.as_mut().push_zeroed();
unsafe {
new_element
.as_mut()
.map_unchecked_mut(|x| &mut x.counter)
.set(47);
new_element
.as_mut()
.map_unchecked_mut(|x| &mut x.counter2)
.set(48);
}
NoatunContext.set_next_seqnr(SequenceNr::from_index(2));
assert_eq!(counter_vec.len(), 1);
NoatunContext.set_next_seqnr(SequenceNr::from_index(3));
})
.unwrap();
}
let mut db = db.begin_session_mut().unwrap();
{
db.with_root_mut(|counter_vec| {
let counter_vec = counter_vec.inner_pin();
let mut counter = counter_vec.get_index_mut(0);
unsafe {
counter
.as_mut()
.map_unchecked_mut(|x| &mut x.counter)
.set(50);
NoatunContext.rewind(SequenceNr::from_index(2));
}
assert_eq!(counter.counter.get(), 47);
})
.unwrap();
}
db.force_rewind(SequenceNr::from_index(1));
{
db.with_root_mut(|counter_vec| {
let counter_vec = counter_vec.inner_pin();
assert_eq!(counter_vec.len(), 0);
})
.unwrap();
}
}
#[test]
fn test_object_macro() {
#[allow(unused)]
{
noatun_object!(
struct Kalle {
pod hej:u32,
pod tva:u32,
object da: NoatunVec<NoatunCell<u32>>
}
);
noatun_object!(
struct Nalle {
pod hej:u32,
pod tva:u32,
object da: NoatunVec<NoatunCell<u32>>
}
);
}
}
#[allow(clippy::assertions_on_constants)]
#[test]
#[ignore]
fn test_id_generation_must_be_random() {
assert!(!FOR_TEST_NON_RANDOM_ID);
}
#[test]
fn test_noatuntime_comparison() {
let id1 = MessageId::generate_for_time(datetime!(2024-01-01 T 00:00:00 Z).into()).unwrap();
let id2 = MessageId::generate_for_time(datetime!(2024-01-01 T 00:00:01 Z).into()).unwrap();
assert!(id1 < id2);
}
#[test]
fn test_time_comparison() {
let t = NoatunTime::now();
let prev_id = MessageId::generate_for_time(t).unwrap();
for step in [1, 937, 23423, 3745863] {
for i in 1..1000 {
let id = MessageId::generate_for_time(t + Duration::from_millis(step * i)).unwrap();
assert!(prev_id < id);
let mut temp = id;
for _ in 0..100 {
temp = temp.unique_successor().unwrap();
assert!(id < temp);
}
}
}
}
#[test]
fn test_successor() {
for _ in 0..100 {
let id = MessageId::generate_for_time(NoatunTime::now()).unwrap();
let mut temp = id;
for _ in 0..100 {
let prev = temp;
temp = temp.unique_successor().unwrap();
assert!(prev < temp);
}
}
}
#[test]
fn test_successor_exhaustion() {
let mut id = MessageId::generate_for_time(NoatunTime::now()).unwrap();
let mut increments = 0;
while let Ok(new_id) = id.unique_successor() {
assert!(new_id > id);
id = new_id;
increments += 1;
}
println!("Increments : {increments}");
assert!(increments >= 16383);
assert!(increments <= 32768 + 16383);
}
#[test]
fn test_predecessor_exhaustion() {
let mut id = MessageId::generate_for_time(NoatunTime::now()).unwrap();
let mut increments = 0;
while let Ok(new_id) = id.unique_predecessor() {
assert!(new_id < id);
id = new_id;
increments += 1;
}
println!("Increments : {increments}");
assert!(increments >= 16383);
assert!(increments <= 32768 + 16383);
}
#[test]
fn test_predecessor() {
for _ in 0..100 {
let id = MessageId::generate_for_time(NoatunTime::now()).unwrap();
let mut temp = id;
for _ in 0..100 {
let prev = temp;
temp = temp.unique_predecessor().unwrap();
assert!(prev > temp);
}
}
}
#[test]
fn max_time() {
println!("Time: {}", NoatunTime((1 << 48) - 1));
println!("Time: {}", NoatunTime((1 << 49) - 1));
}
#[test]
fn test_noatun_time_max() {
println!("MAX: {:?}", NoatunTime::MAX);
}