//! Tests for LSP document formatting functionality //! //! This module tests auto-formatting for: //! - Spacing normalization around colons //! - Indentation preservation //! - Prose block preservation //! - Edge cases (empty documents, already formatted) use tower_lsp::lsp_types::FormattingOptions; use super::{ document::Document, formatting::{ format_document, format_text, }, }; #[test] fn test_format_adds_space_after_colon() { let input = "character Alice{age:7}"; let formatted = format_text(input); // Main formatting: adds space after colon assert!(formatted.contains("age: 7")); } #[test] fn test_format_normalizes_colon_spacing() { let input = "character Alice{age : 7}"; let formatted = format_text(input); // Should normalize to single space after colon assert!(formatted.contains("age: 7")); assert!(!formatted.contains("age :")); } #[test] fn test_format_multiple_fields() { let input = "character Alice{age:7\nname:\"Alice\"}"; let formatted = format_text(input); assert!(formatted.contains("age: 7")); assert!(formatted.contains("name: \"Alice\"")); } #[test] fn test_format_preserves_module_paths() { let input = "use characters::Alice;"; let formatted = format_text(input); // Should NOT add space in :: paths assert!(formatted.contains("characters::Alice")); assert!(!formatted.contains("characters: :Alice")); } #[test] fn test_format_preserves_prose_blocks() { let input = r#"character Alice{ ---backstory Some irregular spacing here --- age:7}"#; let formatted = format_text(input); // Prose content preserved exactly assert!(formatted.contains("Some irregular spacing here")); // But other fields still formatted assert!(formatted.contains("age: 7")); } #[test] fn test_format_indentation_with_braces() { let input = "character Alice{\nage:7\n}"; let formatted = format_text(input); // Check indentation (4 spaces) assert!(formatted.contains("character Alice{")); assert!(formatted.contains(" age: 7")); assert!(formatted.contains("}")); } #[test] fn test_format_nested_indentation() { let input = "template Person{\nnested:{\nvalue:123\n}\n}"; let formatted = format_text(input); assert!(formatted.contains(" nested: {")); assert!(formatted.contains(" value: 123")); assert!(formatted.contains(" }")); } #[test] fn test_format_empty_document() { let input = ""; let formatted = format_text(input); assert_eq!(formatted, ""); } #[test] fn test_format_whitespace_only() { let input = " \n \n "; let formatted = format_text(input); // Should collapse to single newline or empty assert!(formatted.len() <= 2); } #[test] fn test_format_already_formatted() { let input = "character Alice{\n age: 7\n}"; let formatted = format_text(input); // Should remain essentially the same assert!(formatted.contains("age: 7")); } #[test] fn test_format_removes_multiple_blank_lines() { let input = "character Alice{age:7}\n\n\n\ncharacter Bob{age:10}"; let formatted = format_text(input); // Should consolidate multiple blank lines let double_newlines = formatted.matches("\n\n\n").count(); assert_eq!(double_newlines, 0, "Should not have triple newlines"); } #[test] fn test_format_comments_unchanged() { let input = "// Comment\ncharacter Alice{age:7}"; let formatted = format_text(input); assert!(formatted.contains("// Comment")); } #[test] fn test_format_document_returns_text_edit() { let input = "character Alice{age:7}"; let doc = Document::new(input.to_string()); let result = format_document(&doc, &FormattingOptions::default()); if doc.ast.is_some() { assert!( result.is_some(), "Should return TextEdit for valid document" ); } } #[test] fn test_format_document_no_changes_returns_none() { let input = "character Alice{\n age: 7\n}\n"; let doc = Document::new(input.to_string()); let result = format_document(&doc, &FormattingOptions::default()); // If document is already formatted, may return None // (depends on exact formatting match) if result.is_none() { assert!( doc.ast.is_some(), "Should only return None if formatting matches" ); } }