Files
flalingo/examples/test_repository_functions.rs
2025-11-06 21:22:28 +01:00

487 lines
16 KiB
Rust

use std::path::Path;
// This is a test/example file demonstrating how to use the new repository functions
// Note: This requires the database to be set up and proper imports
#[cfg(test)]
mod tests {
use chrono::Utc;
use sqlx::SqlitePool;
use crate::models::{
exercise::Exercise,
node::Node,
path::{Metadata, Path},
};
use crate::repositories::{
path_json_utils::PathJsonUtils,
repository_manager::RepositoryManager,
};
async fn setup_test_database() -> SqlitePool {
// This would normally connect to a test database
// For demonstration purposes only
todo!("Setup test database connection")
}
#[tokio::test]
async fn test_save_and_retrieve_path() {
let pool = setup_test_database().await;
let repo_manager = RepositoryManager::new(&pool);
// Create a test path
let test_path = create_sample_path();
// Save the path
let saved_path_id = repo_manager
.paths()
.save_path(test_path.clone())
.await
.expect("Failed to save path");
println!("Saved path with ID: {}", saved_path_id);
// Retrieve the path
let path_id_int = saved_path_id.parse::<i32>().expect("Invalid path ID");
let retrieved_path = repo_manager
.paths()
.get_path_by_id(path_id_int)
.await
.expect("Failed to retrieve path");
// Verify the data
assert_eq!(retrieved_path.id, test_path.id);
assert_eq!(retrieved_path.title, test_path.title);
assert_eq!(retrieved_path.nodes.len(), test_path.nodes.len());
println!("✅ Successfully saved and retrieved path!");
}
#[tokio::test]
async fn test_update_path() {
let pool = setup_test_database().await;
let repo_manager = RepositoryManager::new(&pool);
// Create and save initial path
let mut test_path = create_sample_path();
let path_id = repo_manager
.paths()
.save_path(test_path.clone())
.await
.expect("Failed to save path");
// Modify the path
test_path.title = "Updated Path Title".to_string();
test_path.description = "Updated description with new content".to_string();
// Add a new node
let new_node = Node {
id: 999, // This will be auto-assigned
title: "New Node".to_string(),
description: "A newly added node".to_string(),
path_id: test_path.id.clone(),
exercises: vec![Exercise {
id: 999,
ex_type: "vocabulary".to_string(),
content: r#"{"word": "neu", "translation": "new", "example": "Das ist neu."}"#
.to_string(),
node_id: 999,
}],
};
test_path.nodes.push(new_node);
// Update the path
repo_manager
.paths()
.update_path(test_path.clone())
.await
.expect("Failed to update path");
// Retrieve and verify
let path_id_int = path_id.parse::<i32>().expect("Invalid path ID");
let updated_path = repo_manager
.paths()
.get_path_by_id(path_id_int)
.await
.expect("Failed to retrieve updated path");
assert_eq!(updated_path.title, "Updated Path Title");
assert_eq!(updated_path.nodes.len(), 3); // Original 2 + 1 new
println!("✅ Successfully updated path!");
}
#[tokio::test]
async fn test_clone_path() {
let pool = setup_test_database().await;
let repo_manager = RepositoryManager::new(&pool);
// Create and save original path
let original_path = create_sample_path();
let original_path_id = repo_manager
.paths()
.save_path(original_path.clone())
.await
.expect("Failed to save original path");
// Clone the path
let original_id_int = original_path_id.parse::<i32>().expect("Invalid path ID");
let cloned_path_id = repo_manager
.clone_path_complete(
original_id_int,
"cloned_path_001",
"Cloned German Basics",
)
.await
.expect("Failed to clone path");
// Retrieve the cloned path
let cloned_id_int = cloned_path_id.parse::<i32>().unwrap_or(0);
let cloned_path = repo_manager
.paths()
.get_path_by_id(cloned_id_int)
.await
.expect("Failed to retrieve cloned path");
// Verify clone
assert_eq!(cloned_path.id, "cloned_path_001");
assert_eq!(cloned_path.title, "Cloned German Basics");
assert_eq!(cloned_path.nodes.len(), original_path.nodes.len());
println!("✅ Successfully cloned path!");
}
#[tokio::test]
async fn test_json_import_export() {
let pool = setup_test_database().await;
let repo_manager = RepositoryManager::new(&pool);
// Create sample JSON
let json_content = r#"
{
"id": "test_json_path",
"title": "JSON Test Path",
"description": "Testing JSON import/export functionality",
"metadata": [
{
"path_id": "test_json_path",
"version": "1.0.0",
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
],
"nodes": [
{
"id": 1,
"title": "JSON Test Node",
"description": "Testing node from JSON",
"path_id": "test_json_path",
"exercises": [
{
"id": 1,
"ex_type": "vocabulary",
"content": "{\"word\": \"Test\", \"translation\": \"Test\", \"example\": \"This is a test.\"}",
"node_id": 1
}
]
}
]
}
"#;
// Import from JSON
let imported_path_id = repo_manager
.import_path_from_json(json_content)
.await
.expect("Failed to import path from JSON");
println!("Imported path ID: {}", imported_path_id);
// Export back to JSON
let path_id_int = imported_path_id.parse::<i32>().expect("Invalid path ID");
let exported_json = repo_manager
.export_path_to_json(path_id_int)
.await
.expect("Failed to export path to JSON");
println!("Exported JSON length: {} characters", exported_json.len());
// Verify the exported JSON contains expected content
assert!(exported_json.contains("JSON Test Path"));
assert!(exported_json.contains("test_json_path"));
println!("✅ Successfully imported and exported JSON!");
}
#[tokio::test]
async fn test_path_statistics() {
let pool = setup_test_database().await;
let repo_manager = RepositoryManager::new(&pool);
// Create and save path
let test_path = create_sample_path();
let path_id = repo_manager
.paths()
.save_path(test_path)
.await
.expect("Failed to save path");
// Get statistics
let path_id_int = path_id.parse::<i32>().expect("Invalid path ID");
let stats = repo_manager
.get_path_statistics(path_id_int)
.await
.expect("Failed to get path statistics");
// Print statistics
stats.print_detailed_summary();
// Verify statistics
assert_eq!(stats.node_count, 2);
assert_eq!(stats.total_exercises, 3);
assert!(stats.exercise_types.contains_key("vocabulary"));
assert!(stats.exercise_types.contains_key("multiple_choice"));
println!("✅ Successfully generated path statistics!");
}
#[tokio::test]
async fn test_path_validation() {
let pool = setup_test_database().await;
let repo_manager = RepositoryManager::new(&pool);
// Create and save path
let test_path = create_sample_path();
let path_id = repo_manager
.paths()
.save_path(test_path)
.await
.expect("Failed to save path");
// Validate path integrity
let path_id_int = path_id.parse::<i32>().expect("Invalid path ID");
let issues = repo_manager
.validate_path_integrity(path_id_int)
.await
.expect("Failed to validate path");
if issues.is_empty() {
println!("✅ Path validation passed - no issues found!");
} else {
println!("⚠️ Path validation found issues:");
for issue in &issues {
println!(" - {}", issue);
}
}
}
#[tokio::test]
async fn test_search_functionality() {
let pool = setup_test_database().await;
let repo_manager = RepositoryManager::new(&pool);
// Create and save multiple paths for searching
let path1 = create_sample_path();
let mut path2 = create_sample_path();
path2.id = "search_test_002".to_string();
path2.title = "Advanced German Grammar".to_string();
path2.description = "Complex grammatical structures and advanced vocabulary".to_string();
repo_manager
.paths()
.save_path(path1)
.await
.expect("Failed to save path1");
repo_manager
.paths()
.save_path(path2)
.await
.expect("Failed to save path2");
// Search for paths
let search_results = repo_manager
.search_paths("German")
.await
.expect("Failed to search paths");
println!("Search results for 'German':");
for result in &search_results {
result.print_summary();
println!();
}
assert!(!search_results.is_empty());
println!("✅ Search functionality working correctly!");
}
#[tokio::test]
async fn test_delete_operations() {
let pool = setup_test_database().await;
let repo_manager = RepositoryManager::new(&pool);
// Create and save path
let test_path = create_sample_path();
let path_id = repo_manager
.paths()
.save_path(test_path)
.await
.expect("Failed to save path");
// Verify path exists
let path_id_int = path_id.parse::<i32>().expect("Invalid path ID");
let path_exists = repo_manager
.paths()
.path_exists(path_id_int)
.await
.expect("Failed to check path existence");
assert!(path_exists);
// Delete the path
repo_manager
.paths()
.delete_path(path_id_int)
.await
.expect("Failed to delete path");
// Verify path no longer exists
let path_still_exists = repo_manager
.paths()
.path_exists(path_id_int)
.await
.expect("Failed to check path existence after deletion");
assert!(!path_still_exists);
println!("✅ Successfully deleted path and verified removal!");
}
#[tokio::test]
async fn test_database_statistics() {
let pool = setup_test_database().await;
let repo_manager = RepositoryManager::new(&pool);
// Get database statistics
let stats = repo_manager
.get_stats()
.await
.expect("Failed to get database statistics");
println!("=== Database Statistics ===");
println!("Total paths: {}", stats.path_count);
println!("Total nodes: {}", stats.node_count);
println!("Total exercises: {}", stats.exercise_count);
println!("Total metadata records: {}", stats.metadata_count);
println!("Total records: {}", stats.total_records());
println!("Database empty: {}", stats.is_empty());
println!("✅ Successfully retrieved database statistics!");
}
// Helper function to create a sample path for testing
fn create_sample_path() -> Path {
let now = Utc::now();
let metadata = vec![Metadata {
path_id: "test_path_001".to_string(),
version: "1.0.0".to_string(),
created_at: now,
updated_at: now,
}];
let exercises1 = vec![
Exercise {
id: 1,
ex_type: "vocabulary".to_string(),
content: r#"{"word": "Hallo", "translation": "Hello", "audio": "/audio/hallo.mp3", "example": "Hallo, wie geht's?"}"#.to_string(),
node_id: 1,
},
Exercise {
id: 2,
ex_type: "multiple_choice".to_string(),
content: r#"{"question": "How do you say 'goodbye' in German?", "options": ["Tschüss", "Hallo", "Bitte", "Danke"], "correct": 0, "explanation": "Tschüss is the informal way to say goodbye."}"#.to_string(),
node_id: 1,
}
];
let exercises2 = vec![Exercise {
id: 3,
ex_type: "vocabulary".to_string(),
content: r#"{"word": "Danke", "translation": "Thank you", "audio": "/audio/danke.mp3", "example": "Danke schön!"}"#.to_string(),
node_id: 2,
}];
let nodes = vec![
Node {
id: 1,
title: "Basic Greetings".to_string(),
description: "Learn essential German greetings".to_string(),
path_id: "test_path_001".to_string(),
exercises: exercises1,
},
Node {
id: 2,
title: "Politeness".to_string(),
description: "Learn polite expressions".to_string(),
path_id: "test_path_001".to_string(),
exercises: exercises2,
},
];
Path {
id: "test_path_001".to_string(),
title: "German Basics Test".to_string(),
description: "A test path for demonstrating repository functionality".to_string(),
metadata,
nodes,
}
}
}
// Example usage functions (not tests)
pub mod examples {
use super::*;
/// Example: How to use the repository manager in your application
pub async fn example_basic_usage() {
println!("=== Basic Repository Usage Example ===");
// This would normally use your actual database connection
// let pool = get_database_pool().await;
// let repo_manager = RepositoryManager::new(&pool);
// Example operations:
println!("1. Create repository manager");
println!("2. Save a new path");
println!("3. Retrieve and display path");
println!("4. Update path content");
println!("5. Search for paths");
println!("6. Generate statistics");
println!("7. Export to JSON");
println!("8. Cleanup/delete if needed");
}
/// Example: How to work with JSON imports
pub async fn example_json_workflow() {
println!("=== JSON Import/Export Workflow ===");
// Steps for JSON workflow:
println!("1. Validate JSON file structure");
println!("2. Import path from JSON");
println!("3. Verify import success");
println!("4. Make modifications if needed");
println!("5. Export updated version");
println!("6. Backup all paths to JSON files");
}
/// Example: How to perform bulk operations
pub async fn example_bulk_operations() {
println!("=== Bulk Operations Example ===");
// Bulk operation examples:
println!("1. Import multiple paths from directory");
println!("2. Validate all paths in database");
println!("3. Generate statistics for all paths");
println!("4. Search across all content");
println!("5. Export all paths to backup directory");
}
}