
Features implemented: - Clean trait-based plugin architecture (no global registries) - SQLite database with centralized SQL operations - Songs plugin: CCLI support, lyrics search and display - Bible plugin: Multi-translation verse lookup and rendering - Media plugin: Auto-detection for images/video/audio files - Presentations plugin: LibreOffice integration with HTML/XHTML combo parsing - Service management: Add items, navigation, current slide tracking - Comprehensive integration tests with real database operations Architecture follows KISS/DRY principles: - All SQL operations centralized in core/database.rs - Plugins focus on business logic only - No complex state management or global registries - Clean separation of concerns throughout Ready for church presentation use with PowerPoint theme preservation.
176 lines
6.1 KiB
Rust
176 lines
6.1 KiB
Rust
use lumina_core::App;
|
|
use lumina_songs::{Song, SongsPlugin};
|
|
use lumina_bible::{BibleVerse, BiblePlugin};
|
|
use lumina_media::MediaPlugin;
|
|
use lumina_presentations::PresentationsPlugin;
|
|
use tokio;
|
|
|
|
#[tokio::test]
|
|
async fn test_songs_plugin_full_workflow() {
|
|
// Use in-memory database for tests
|
|
let mut app = App::new(":memory:").await.unwrap();
|
|
let songs_plugin = SongsPlugin::new(app.db.clone());
|
|
|
|
// Add a real song
|
|
let song = Song {
|
|
id: 0, // Will be set by DB
|
|
title: "Amazing Grace".to_string(),
|
|
lyrics: "Amazing grace how sweet the sound\nThat saved a wretch like me\n\nI once was lost but now am found\nWas blind but now I see".to_string(),
|
|
author: Some("John Newton".to_string()),
|
|
ccli: Some("12345".to_string()),
|
|
};
|
|
|
|
let song_id = songs_plugin.add_song(song).await.unwrap();
|
|
assert!(song_id > 0);
|
|
|
|
app.register_plugin(Box::new(songs_plugin));
|
|
|
|
// Search for the song
|
|
let results = app.search("songs", "Amazing").await.unwrap();
|
|
assert_eq!(results.len(), 1);
|
|
assert_eq!(results[0].title, "Amazing Grace");
|
|
assert_eq!(results[0].plugin, "songs");
|
|
|
|
// Test rendering
|
|
let rendered = app.plugins.get("songs").unwrap().render(&results[0]).await.unwrap();
|
|
assert!(rendered.html.contains("Amazing Grace"));
|
|
assert!(rendered.html.contains("Amazing grace how sweet the sound"));
|
|
assert!(rendered.html.contains("John Newton"));
|
|
assert!(rendered.html.contains("CCLI: 12345"));
|
|
assert!(rendered.css.is_some());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_bible_plugin_full_workflow() {
|
|
let mut app = App::new(":memory:").await.unwrap();
|
|
let bible_plugin = BiblePlugin::new(app.db.clone());
|
|
|
|
// Add a real verse
|
|
let verse = BibleVerse {
|
|
id: 0,
|
|
book: "John".to_string(),
|
|
chapter: 3,
|
|
verse: 16,
|
|
text: "For God so loved the world, that he gave his only begotten Son, that whosoever believeth in him should not perish, but have everlasting life.".to_string(),
|
|
translation: "KJV".to_string(),
|
|
};
|
|
|
|
let verse_id = bible_plugin.add_verse(verse).await.unwrap();
|
|
assert!(verse_id > 0);
|
|
|
|
app.register_plugin(Box::new(bible_plugin));
|
|
|
|
// Search for the verse
|
|
let results = app.search("bible", "God so loved").await.unwrap();
|
|
assert_eq!(results.len(), 1);
|
|
assert_eq!(results[0].title, "John 3:16 (KJV)");
|
|
assert_eq!(results[0].plugin, "bible");
|
|
|
|
// Test rendering
|
|
let rendered = app.plugins.get("bible").unwrap().render(&results[0]).await.unwrap();
|
|
assert!(rendered.html.contains("For God so loved the world"));
|
|
assert!(rendered.html.contains("John 3:16 (KJV)"));
|
|
assert!(rendered.css.is_some());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_media_plugin_full_workflow() {
|
|
let mut app = App::new(":memory:").await.unwrap();
|
|
let media_plugin = MediaPlugin::new(app.db.clone());
|
|
|
|
// Add a media item
|
|
let media_id = media_plugin.add_media(
|
|
"Church Logo".to_string(),
|
|
"/path/to/church_logo.jpg".to_string()
|
|
).await.unwrap();
|
|
assert!(media_id > 0);
|
|
|
|
app.register_plugin(Box::new(media_plugin));
|
|
|
|
// Search for media
|
|
let results = app.search("media", "Church").await.unwrap();
|
|
assert_eq!(results.len(), 1);
|
|
assert_eq!(results[0].title, "Church Logo");
|
|
assert_eq!(results[0].plugin, "media");
|
|
|
|
// Test rendering
|
|
let rendered = app.plugins.get("media").unwrap().render(&results[0]).await.unwrap();
|
|
assert!(rendered.html.contains("church_logo.jpg"));
|
|
assert!(rendered.html.contains("img src"));
|
|
assert!(rendered.css.is_some());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_service_management() {
|
|
let mut app = App::new(":memory:").await.unwrap();
|
|
let songs_plugin = SongsPlugin::new(app.db.clone());
|
|
|
|
// Add some songs
|
|
let song1 = Song {
|
|
id: 0,
|
|
title: "Song 1".to_string(),
|
|
lyrics: "Verse 1 content".to_string(),
|
|
author: None,
|
|
ccli: None,
|
|
};
|
|
let song2 = Song {
|
|
id: 0,
|
|
title: "Song 2".to_string(),
|
|
lyrics: "Verse 2 content".to_string(),
|
|
author: None,
|
|
ccli: None,
|
|
};
|
|
|
|
songs_plugin.add_song(song1).await.unwrap();
|
|
songs_plugin.add_song(song2).await.unwrap();
|
|
app.register_plugin(Box::new(songs_plugin));
|
|
|
|
// Search and add to service
|
|
let song1_results = app.search("songs", "Song 1").await.unwrap();
|
|
let song2_results = app.search("songs", "Song 2").await.unwrap();
|
|
|
|
app.service.add_item(song1_results[0].clone());
|
|
app.service.add_item(song2_results[0].clone());
|
|
|
|
// Test service navigation
|
|
assert_eq!(app.service.items.len(), 2);
|
|
assert_eq!(app.service.current_index, 0);
|
|
|
|
let current = app.service.current().unwrap();
|
|
assert_eq!(current.title, "Song 1");
|
|
|
|
let next = app.service.next().unwrap();
|
|
assert_eq!(next.title, "Song 2");
|
|
assert_eq!(app.service.current_index, 1);
|
|
|
|
let prev = app.service.previous().unwrap();
|
|
assert_eq!(prev.title, "Song 1");
|
|
assert_eq!(app.service.current_index, 0);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_multiple_plugins_together() {
|
|
let mut app = App::new(":memory:").await.unwrap();
|
|
|
|
// Register all plugins
|
|
let songs_plugin = SongsPlugin::new(app.db.clone());
|
|
let bible_plugin = BiblePlugin::new(app.db.clone());
|
|
let media_plugin = MediaPlugin::new(app.db.clone());
|
|
let presentations_plugin = PresentationsPlugin::new(app.db.clone());
|
|
|
|
app.register_plugin(Box::new(songs_plugin));
|
|
app.register_plugin(Box::new(bible_plugin));
|
|
app.register_plugin(Box::new(media_plugin));
|
|
app.register_plugin(Box::new(presentations_plugin));
|
|
|
|
// Verify all plugins are registered
|
|
assert_eq!(app.plugins.len(), 4);
|
|
assert!(app.plugins.contains_key("songs"));
|
|
assert!(app.plugins.contains_key("bible"));
|
|
assert!(app.plugins.contains_key("media"));
|
|
assert!(app.plugins.contains_key("presentations"));
|
|
|
|
// Test that each plugin returns empty results for unknown queries
|
|
let empty_results = app.search("songs", "nonexistent").await.unwrap();
|
|
assert_eq!(empty_results.len(), 0);
|
|
} |