mod preloader;
pub use preloader::*;
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use std::time::Duration;
use tokio::time::sleep;
#[tokio::test]
async fn test_new_preloader() {
let preloader = Preloader::<String>::new();
assert!(matches!(
preloader.try_get(),
Err(PreloaderError::NotLoaded)
));
}
#[tokio::test]
async fn test_load_and_get() {
let preloader = Preloader::new();
preloader
.load(async {
sleep(Duration::from_millis(10)).await;
"test data".to_string()
})
.await;
let result = preloader.get().await;
assert!(result.is_ok());
assert_eq!(*result.unwrap(), "test data");
}
#[tokio::test]
async fn test_try_get_before_load() {
let preloader = Preloader::<String>::new();
let result = preloader.try_get();
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), PreloaderError::NotLoaded));
}
#[tokio::test]
async fn test_try_get_while_loading() {
let preloader = Preloader::new();
preloader
.load(async {
sleep(Duration::from_millis(100)).await;
"slow data".to_string()
})
.await;
let result = preloader.try_get();
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), PreloaderError::Loading));
}
#[tokio::test]
async fn test_try_get_after_load() {
let preloader = Preloader::new();
preloader
.load(async {
sleep(Duration::from_millis(10)).await;
42
})
.await;
preloader.get().await.unwrap();
let result = preloader.try_get();
assert!(result.is_ok());
assert_eq!(*result.unwrap(), 42);
}
#[tokio::test]
async fn test_multiple_load_calls() {
let preloader = Preloader::new();
preloader
.load(async {
sleep(Duration::from_millis(10)).await;
"first".to_string()
})
.await;
preloader
.load(async {
sleep(Duration::from_millis(10)).await;
"second".to_string()
})
.await;
let result = preloader.get().await;
assert!(result.is_ok());
assert_eq!(*result.unwrap(), "first");
}
#[tokio::test]
async fn test_concurrent_access() {
let preloader = Arc::new(Preloader::new());
preloader
.load(async {
sleep(Duration::from_millis(50)).await;
"concurrent access test".to_string()
})
.await;
let mut handles = vec![];
for i in 0..5 {
let preloader = Arc::clone(&preloader);
handles.push(tokio::spawn(async move {
let result = preloader.get().await;
(i, result.map(|s| s.to_string()))
}));
}
let results = futures::future::join_all(handles).await;
for result in results {
let (i, data_result) = result.unwrap();
assert!(data_result.is_ok(), "Task {} failed", i);
assert_eq!(data_result.unwrap(), "concurrent access test");
}
}
#[tokio::test]
async fn test_error_handling() {
let preloader = Preloader::new();
preloader
.load(async {
sleep(Duration::from_millis(10)).await;
panic!("intentional panic");
})
.await;
let result = preloader.get().await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_different_data_types() {
let string_preloader = Preloader::new();
string_preloader.load(async { "string".to_string() }).await;
let result = string_preloader.get().await;
assert!(result.is_ok());
assert_eq!(*result.unwrap(), "string");
let int_preloader = Preloader::new();
int_preloader.load(async { 123 }).await;
let result = int_preloader.get().await;
assert!(result.is_ok());
assert_eq!(*result.unwrap(), 123);
let vec_preloader = Preloader::new();
vec_preloader.load(async { vec![1, 2, 3] }).await;
let result = vec_preloader.get().await;
assert!(result.is_ok());
assert_eq!(*result.unwrap(), vec![1, 2, 3]);
}
#[tokio::test]
async fn test_state_transitions() {
let preloader = Preloader::new();
assert!(matches!(
preloader.try_get(),
Err(PreloaderError::NotLoaded)
));
preloader
.load(async {
sleep(Duration::from_millis(50)).await;
"state test".to_string()
})
.await;
assert!(matches!(preloader.try_get(), Err(PreloaderError::Loading)));
preloader.get().await.unwrap();
let result = preloader.try_get();
assert!(result.is_ok());
assert_eq!(*result.unwrap(), "state test");
}
#[tokio::test]
async fn test_reuse_after_load() {
let preloader = Preloader::new();
preloader.load(async { "reuse test".to_string() }).await;
let result1 = preloader.get().await;
assert!(result1.is_ok());
assert_eq!(*result1.unwrap(), "reuse test");
let result2 = preloader.get().await;
assert!(result2.is_ok());
assert_eq!(*result2.unwrap(), "reuse test");
let result3 = preloader.try_get();
assert!(result3.is_ok());
assert_eq!(*result3.unwrap(), "reuse test");
}
#[tokio::test]
async fn test_immediate_load() {
let preloader = Preloader::new();
preloader.load(async { "immediate data".to_string() }).await;
let _ = preloader.get().await;
let result = preloader.try_get();
assert!(result.is_ok());
assert_eq!(*result.unwrap(), "immediate data");
}
#[tokio::test]
async fn test_multiple_concurrent_loads() {
let preloader = Arc::new(Preloader::new());
let mut handles = vec![];
for i in 0..3 {
let preloader = Arc::clone(&preloader);
let i = i; handles.push(tokio::spawn(async move {
preloader
.load(async move {
sleep(Duration::from_millis(50)).await;
format!("data {}", i)
})
.await;
i
}));
}
for handle in handles {
handle.await.unwrap();
}
let result = preloader.get().await;
assert!(result.is_ok());
let data = result.unwrap();
assert!(data.starts_with("data "));
}
#[tokio::test]
async fn test_take_after_load() {
let preloader = Preloader::new();
preloader
.load(async {
sleep(Duration::from_millis(10)).await;
"take test data".to_string()
})
.await;
let result = preloader.take().await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), "take test data");
}
#[tokio::test]
async fn test_take_before_load() {
let preloader = Preloader::<String>::new();
let result = preloader.take().await;
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), PreloaderError::NotLoaded));
}
#[tokio::test]
async fn test_take_while_loading() {
let preloader = Preloader::new();
preloader
.load(async {
sleep(Duration::from_millis(100)).await;
"slow data for take".to_string()
})
.await;
let result = preloader.take().await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), "slow data for take");
}
#[tokio::test]
async fn test_is_loaded() {
let preloader = Preloader::new();
assert!(!preloader.is_loaded());
preloader
.load(async {
sleep(Duration::from_millis(10)).await;
"loaded data".to_string()
})
.await;
assert!(!preloader.is_loaded());
preloader.get().await.unwrap();
assert!(preloader.is_loaded());
}
}