//! Tests for semantic validation integration #[cfg(test)] mod tests { use crate::lsp::document::Document; #[test] fn test_reserved_keyword_caught_by_parser() { // Reserved keywords are caught by the parser, not the validator // This test verifies that parse errors catch reserved keywords let source = r#" character Alice { self: "Bad field name" } "#; let doc = Document::new(source.to_string()); // Should have parse error for reserved keyword assert!( !doc.parse_errors.is_empty(), "Parser should catch reserved keyword 'self' as field name" ); } #[test] fn test_valid_fields_no_validation_errors() { let source = r#" character Alice { age: 7 name: "Alice" } "#; let doc = Document::new(source.to_string()); // Should have no validation errors assert!( doc.resolve_errors.is_empty(), "Valid code should have no validation errors" ); } #[test] fn test_trait_range_validation() { let source = r#" character Alice { bond: 1.5 } "#; let doc = Document::new(source.to_string()); // Should have error for bond value out of range assert!( !doc.resolve_errors.is_empty(), "Should detect bond value out of range [0.0, 1.0]" ); let error_message = format!("{}", doc.resolve_errors[0]); assert!( error_message.contains("1.5") || error_message.contains("range"), "Error should mention the value or range: {}", error_message ); } #[test] fn test_valid_trait_ranges() { let source = r#" character Alice { bond: 0.75 trust: 0.0 love: 1.0 } "#; let doc = Document::new(source.to_string()); // Should have no validation errors for valid trait ranges assert!( doc.resolve_errors.is_empty(), "Valid trait values should produce no errors" ); } #[test] fn test_life_arc_transition_validation() { let source = r#" life_arc Growing { state child { on birthday -> adult } } "#; let doc = Document::new(source.to_string()); // Should have error for transition to unknown state 'adult' assert!( !doc.resolve_errors.is_empty(), "Should detect transition to undefined state" ); let error_message = format!("{}", doc.resolve_errors[0]); assert!( error_message.contains("adult") || error_message.contains("unknown"), "Error should mention unknown state" ); } #[test] fn test_valid_life_arc_transitions() { let source = r#" life_arc Growing { state child { on birthday -> teen } state teen { on birthday -> adult } state adult {} } "#; let doc = Document::new(source.to_string()); // Should have no validation errors assert!( doc.resolve_errors.is_empty(), "Valid life arc should produce no errors" ); } #[test] fn test_schedule_overlap_validation() { let source = r#" schedule Daily { 08:00 -> 10:00: morning {} 09:00 -> 11:00: overlap {} } "#; let doc = Document::new(source.to_string()); // Should have error for overlapping schedule blocks assert!( !doc.resolve_errors.is_empty(), "Should detect overlapping schedule blocks" ); let error_message = format!("{}", doc.resolve_errors[0]); assert!( error_message.contains("overlap"), "Error should mention overlap" ); } #[test] fn test_valid_schedule_no_overlaps() { let source = r#" schedule Daily { 08:00 -> 10:00: morning {} 10:00 -> 12:00: midday {} 12:00 -> 14:00: afternoon {} } "#; let doc = Document::new(source.to_string()); // Should have no validation errors assert!( doc.resolve_errors.is_empty(), "Non-overlapping schedule should produce no errors" ); } #[test] fn test_multiple_validation_errors() { // Test multiple validation errors at once let source = r#" character Alice { bond: 2.0 trust: -0.5 } "#; let doc = Document::new(source.to_string()); // Should have multiple errors for out-of-range values assert!( doc.resolve_errors.len() >= 2, "Should detect multiple range errors. Got {} errors", doc.resolve_errors.len() ); } #[test] fn test_parse_and_validation_errors_separate() { let source = r#" character Alice { character: "Reserved" invalid syntax here } "#; let doc = Document::new(source.to_string()); // Parse should fail, so we won't have validation errors // (validation only runs on successfully parsed AST) assert!( !doc.parse_errors.is_empty() || !doc.resolve_errors.is_empty(), "Should have either parse or validation errors" ); } }