//! Edge case tests for document functionality #[cfg(test)] mod tests { use crate::lsp::document::Document; #[test] fn test_word_at_offset_unicode() { let doc = Document::new("character Café { age: 7 }".to_string()); // Test finding "Café" let word = doc.word_at_offset(10); assert_eq!(word, Some("Café".to_string())); } #[test] fn test_word_at_offset_underscore() { let doc = Document::new("character snake_case { }".to_string()); let word = doc.word_at_offset(12); assert_eq!(word, Some("snake_case".to_string())); } #[test] fn test_word_at_offset_at_start() { let doc = Document::new("character Alice { }".to_string()); let word = doc.word_at_offset(0); assert_eq!(word, Some("character".to_string())); } #[test] fn test_word_at_offset_at_end() { let doc = Document::new("character Alice".to_string()); let word = doc.word_at_offset(14); assert_eq!(word, Some("Alice".to_string())); } #[test] fn test_word_at_offset_out_of_bounds() { let doc = Document::new("test".to_string()); let word = doc.word_at_offset(1000); assert_eq!(word, None); } #[test] fn test_word_at_offset_on_whitespace() { let doc = Document::new("character Alice".to_string()); let word = doc.word_at_offset(9); // Space between character and Alice assert_eq!(word, None); } #[test] fn test_word_at_offset_on_punctuation() { let doc = Document::new("character Alice { }".to_string()); let word = doc.word_at_offset(16); // On '{' assert_eq!(word, None); } #[test] fn test_update_clears_old_symbols() { let mut doc = Document::new("character Alice {}".to_string()); assert!(doc.name_table.resolve_name("Alice").is_some()); doc.update("character Bob {}".to_string()); assert!(doc.name_table.resolve_name("Alice").is_none()); assert!(doc.name_table.resolve_name("Bob").is_some()); } #[test] fn test_update_with_invalid_syntax() { let mut doc = Document::new("character Alice {}".to_string()); assert!(doc.ast.is_some()); assert!(doc.parse_errors.is_empty()); doc.update("invalid { }".to_string()); assert!(doc.ast.is_none()); assert!(!doc.parse_errors.is_empty()); } #[test] fn test_empty_document_has_no_symbols() { let doc = Document::new("".to_string()); assert_eq!(doc.name_table.all_entries().count(), 0); } #[test] fn test_symbol_table_with_duplicates() { let source = r#" character Alice { age: 7 } character Alice { age: 8 } "#; let doc = Document::new(source.to_string()); // Duplicate declarations should be caught during resolution // NameTable from_file will fail, so we'll have an empty table and // resolve_errors assert!( !doc.resolve_errors.is_empty(), "Should have validation error for duplicate" ); } #[test] fn test_mixed_declaration_types() { let source = r#" species Human {} character Alice: Human {} template Child {} location Home {} relationship Friends { Alice as friend {} Bob as friend {} } "#; let doc = Document::new(source.to_string()); assert!(doc.name_table.resolve_name("Human").is_some()); assert!(doc.name_table.resolve_name("Alice").is_some()); assert!(doc.name_table.resolve_name("Child").is_some()); assert!(doc.name_table.resolve_name("Home").is_some()); assert!(doc.name_table.resolve_name("Friends").is_some()); } #[test] fn test_life_arc_symbol_extraction() { let source = r#" life_arc Growing { state child {} state teen {} state adult {} } "#; let doc = Document::new(source.to_string()); assert!(doc.name_table.resolve_name("Growing").is_some()); let growing = doc.name_table.resolve_name("Growing").unwrap(); assert_eq!(growing.kind, crate::resolve::names::DeclKind::LifeArc); } #[test] fn test_schedule_symbol_extraction() { let source = r#" schedule Daily { 08:00 -> 09:00: breakfast {} 09:00 -> 12:00: work {} } "#; let doc = Document::new(source.to_string()); assert!(doc.name_table.resolve_name("Daily").is_some()); let daily = doc.name_table.resolve_name("Daily").unwrap(); assert_eq!(daily.kind, crate::resolve::names::DeclKind::Schedule); } #[test] fn test_institution_symbol_extraction() { let source = "institution School { type: education }"; let doc = Document::new(source.to_string()); assert!(doc.name_table.resolve_name("School").is_some()); let school = doc.name_table.resolve_name("School").unwrap(); assert_eq!(school.kind, crate::resolve::names::DeclKind::Institution); } #[test] fn test_very_long_identifier() { let long_name = "a".repeat(1000); let source = format!("character {} {{}}", long_name); let doc = Document::new(source); assert!(doc.name_table.resolve_name(&long_name).is_some()); } #[test] fn test_multiline_document() { let source = "\n\n\n\ncharacter Alice {\n\n\n age: 7\n\n\n}"; let doc = Document::new(source.to_string()); assert!(doc.ast.is_some()); assert!(doc.name_table.resolve_name("Alice").is_some()); } }