#![allow(deprecated)]
use rstest::*;
use uuid::Uuid;
pub use reinhardt_auth::mfa::MFAAuthentication as MfaManager;
pub use reinhardt_auth::{
Argon2Hasher, InMemoryTokenStorage, JwtAuth, PasswordHasher, StoredToken, TokenStorage,
};
#[deprecated(
since = "0.1.0-rc.16",
note = "define your own user type with `#[user]` macro and use `ForceLoginUser` trait"
)]
#[derive(Clone, Debug)]
pub struct TestUser {
pub id: Uuid,
pub username: String,
pub email: String,
pub is_active: bool,
pub is_admin: bool,
pub is_staff: bool,
pub is_superuser: bool,
}
#[fixture]
pub fn test_user() -> TestUser {
TestUser {
id: Uuid::now_v7(),
username: "testuser".to_string(),
email: "test@example.com".to_string(),
is_active: true,
is_admin: false,
is_staff: false,
is_superuser: false,
}
}
#[fixture]
pub fn admin_user() -> TestUser {
TestUser {
id: Uuid::now_v7(),
username: "admin".to_string(),
email: "admin@example.com".to_string(),
is_active: true,
is_admin: true,
is_staff: true,
is_superuser: true,
}
}
#[fixture]
pub fn test_users() -> Vec<TestUser> {
vec![
TestUser {
id: Uuid::now_v7(),
username: "user1".to_string(),
email: "user1@example.com".to_string(),
is_active: true,
is_admin: false,
is_staff: false,
is_superuser: false,
},
TestUser {
id: Uuid::now_v7(),
username: "user2".to_string(),
email: "user2@example.com".to_string(),
is_active: true,
is_admin: false,
is_staff: false,
is_superuser: false,
},
TestUser {
id: Uuid::now_v7(),
username: "user3".to_string(),
email: "user3@example.com".to_string(),
is_active: false, is_admin: false,
is_staff: false,
is_superuser: false,
},
TestUser {
id: Uuid::now_v7(),
username: "staff".to_string(),
email: "staff@example.com".to_string(),
is_active: true,
is_admin: false,
is_staff: true,
is_superuser: false,
},
TestUser {
id: Uuid::now_v7(),
username: "superuser".to_string(),
email: "superuser@example.com".to_string(),
is_active: true,
is_admin: true,
is_staff: true,
is_superuser: true,
},
]
}
#[fixture]
pub fn mfa_authentication() -> MfaManager {
MfaManager::new("ReinhardtTest").time_window(30)
}
#[fixture]
pub fn mfa_with_registered_user(test_user: TestUser) -> (MfaManager, String) {
let mfa = MfaManager::new("ReinhardtTest").time_window(30);
let secret = "JBSWY3DPEHPK3PXP".to_string();
tokio::runtime::Handle::current().block_on(mfa.register_user(&test_user.username, &secret));
(mfa, secret)
}
#[fixture]
pub fn jwt_auth() -> JwtAuth {
JwtAuth::new(b"reinhardt-test-secret-key-32bytes")
}
#[fixture]
pub fn jwt_auth_with_secret(
#[default(b"custom-secret-key-for-testing-32")] secret: &[u8],
) -> JwtAuth {
JwtAuth::new(secret)
}
#[fixture]
pub fn argon2_hasher() -> Argon2Hasher {
Argon2Hasher
}
#[fixture]
pub fn in_memory_token_storage() -> InMemoryTokenStorage {
InMemoryTokenStorage::new()
}
#[fixture]
pub fn token_storage_with_data() -> InMemoryTokenStorage {
InMemoryTokenStorage::new()
}
#[fixture]
pub fn inactive_user() -> TestUser {
TestUser {
id: Uuid::now_v7(),
username: "inactive".to_string(),
email: "inactive@example.com".to_string(),
is_active: false,
is_admin: false,
is_staff: false,
is_superuser: false,
}
}
#[fixture]
pub fn staff_user() -> TestUser {
TestUser {
id: Uuid::now_v7(),
username: "staffuser".to_string(),
email: "staff@example.com".to_string(),
is_active: true,
is_admin: false,
is_staff: true,
is_superuser: false,
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
use std::collections::HashSet;
#[rstest]
fn test_test_user_default_fields(test_user: TestUser) {
let user = test_user;
assert_eq!(user.username, "testuser");
assert_eq!(user.email, "test@example.com");
assert!(user.is_active);
assert!(!user.is_admin);
assert!(!user.is_staff);
assert!(!user.is_superuser);
}
#[rstest]
fn test_test_user_has_valid_uuid(test_user: TestUser) {
let user = test_user;
let id = user.id;
assert!(!id.is_nil(), "test_user id should be a non-nil UUID");
}
#[rstest]
fn test_admin_user_all_privileges(admin_user: TestUser) {
let user = admin_user;
assert!(user.is_admin);
assert!(user.is_staff);
assert!(user.is_superuser);
assert!(user.is_active);
}
#[rstest]
fn test_admin_user_credentials(admin_user: TestUser) {
let user = admin_user;
assert_eq!(user.username, "admin");
assert_eq!(user.email, "admin@example.com");
}
#[rstest]
fn test_inactive_user_is_not_active(inactive_user: TestUser) {
let user = inactive_user;
assert!(!user.is_active);
assert!(!user.is_admin);
assert!(!user.is_staff);
assert!(!user.is_superuser);
}
#[rstest]
fn test_inactive_user_credentials(inactive_user: TestUser) {
let user = inactive_user;
assert_eq!(user.username, "inactive");
}
#[rstest]
fn test_staff_user_is_staff_not_admin(staff_user: TestUser) {
let user = staff_user;
assert!(user.is_staff);
assert!(!user.is_admin);
assert!(!user.is_superuser);
}
#[rstest]
fn test_staff_user_is_active(staff_user: TestUser) {
let user = staff_user;
assert!(user.is_active);
}
#[rstest]
fn test_test_users_count(test_users: Vec<TestUser>) {
let users = test_users;
let count = users.len();
assert_eq!(count, 5);
}
#[rstest]
fn test_test_users_contains_inactive(test_users: Vec<TestUser>) {
let users = test_users;
let inactive_count = users.iter().filter(|u| !u.is_active).count();
assert_eq!(inactive_count, 1, "exactly one user should be inactive");
}
#[rstest]
fn test_test_users_contains_staff(test_users: Vec<TestUser>) {
let users = test_users;
let staff_non_admin_count = users.iter().filter(|u| u.is_staff && !u.is_admin).count();
assert_eq!(
staff_non_admin_count, 1,
"exactly one user should be staff but not admin"
);
}
#[rstest]
fn test_test_users_contains_superuser(test_users: Vec<TestUser>) {
let users = test_users;
let superuser_count = users.iter().filter(|u| u.is_superuser).count();
assert_eq!(superuser_count, 1, "exactly one user should be a superuser");
}
#[rstest]
fn test_jwt_auth_construction(jwt_auth: JwtAuth) {
let _auth = jwt_auth;
}
#[rstest]
fn test_argon2_hasher_construction(argon2_hasher: Argon2Hasher) {
let _hasher = argon2_hasher;
}
#[rstest]
#[tokio::test]
async fn test_in_memory_token_storage_empty(in_memory_token_storage: InMemoryTokenStorage) {
let storage = in_memory_token_storage;
assert!(storage.is_empty().await);
}
#[rstest]
fn test_mfa_authentication_construction(mfa_authentication: MfaManager) {
let _mfa = mfa_authentication;
}
#[rstest]
fn test_test_users_unique_ids(test_users: Vec<TestUser>) {
let users = test_users;
let id_set: HashSet<Uuid> = users.iter().map(|u| u.id).collect();
assert_eq!(id_set.len(), 5, "all 5 users should have distinct UUIDs");
}
#[rstest]
fn test_test_users_unique_usernames(test_users: Vec<TestUser>) {
let users = test_users;
let name_set: HashSet<&str> = users.iter().map(|u| u.username.as_str()).collect();
assert_eq!(
name_set.len(),
5,
"all 5 users should have distinct usernames"
);
}
#[rstest]
fn test_test_user_clone(test_user: TestUser) {
let original = test_user;
let cloned = original.clone();
assert_eq!(cloned.id, original.id);
assert_eq!(cloned.username, original.username);
assert_eq!(cloned.email, original.email);
assert_eq!(cloned.is_active, original.is_active);
assert_eq!(cloned.is_admin, original.is_admin);
assert_eq!(cloned.is_staff, original.is_staff);
assert_eq!(cloned.is_superuser, original.is_superuser);
}
#[rstest]
fn test_test_user_debug(test_user: TestUser) {
let user = test_user;
let debug_str = format!("{:?}", user);
assert!(!debug_str.is_empty(), "Debug output should be non-empty");
assert!(
debug_str.contains("TestUser"),
"Debug output should contain the struct name"
);
}
}