1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
|
//! Specific error type tests
//!
//! Tests verify:
//! - Specific error types and messages
//! - Error position accuracy (line/column)
//! - Multiple errors in single document
//! - Error context and recovery
use yaml_edit::YamlFile;
/// Test unterminated quote error with exact message
#[test]
fn test_unterminated_quote_error() {
let yaml = r#"name: "unclosed
age: 30"#;
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(errors[0], "1:7: Unterminated quoted string");
}
/// Test unterminated single quote
#[test]
fn test_unterminated_single_quote() {
let yaml = "name: 'unclosed\nage: 30";
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(errors[0], "1:7: Unterminated quoted string");
}
/// Test invalid YAML directive
#[test]
fn test_invalid_directive() {
let yaml = "%INVALID directive\nkey: value";
let parsed = YamlFile::parse(yaml);
// Parser should handle invalid directive
assert!(parsed.tree().document().is_some());
// Check if there are errors and their exact messages
let errors = parsed.errors();
if !errors.is_empty() {
// Document the actual error message for invalid directives
eprintln!("Invalid directive error: {}", errors[0]);
}
}
/// Test invalid anchor name (starting with number)
#[test]
fn test_invalid_anchor_name() {
let yaml = "&123invalid value";
let parsed = YamlFile::parse(yaml);
// Parser should handle this gracefully
assert!(parsed.tree().document().is_some());
let errors = parsed.errors();
if !errors.is_empty() {
eprintln!("Invalid anchor name error: {}", errors[0]);
}
}
/// Test undefined alias reference
#[test]
fn test_undefined_alias_error() {
let yaml = "ref: *undefined";
let parsed = YamlFile::parse(yaml);
// Parser accepts undefined alias (CST preserves it)
assert!(parsed.tree().document().is_some());
assert_eq!(
parsed.errors().len(),
0,
"Undefined alias should parse without error in CST"
);
}
/// Test duplicate anchor names
#[test]
fn test_duplicate_anchor_names() {
let yaml = r#"first: &x value1
second: &x value2
ref: *x"#;
let parsed = YamlFile::parse(yaml);
// Duplicate anchors are allowed in YAML (last one wins)
assert_eq!(
parsed.errors().len(),
0,
"Duplicate anchors should parse without error"
);
assert!(parsed.tree().document().is_some());
}
/// Test error position accuracy for unclosed bracket
#[test]
fn test_error_position_unclosed_bracket() {
let yaml = "line1: value\nline2: value\nbad: [";
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(
errors[0],
"3:7: Unclosed flow sequence. Expected: ']' to close sequence. Found: end of input. Context: in flow sequence. Suggestion: Add ']' to close the array, or check for missing commas between elements"
);
}
/// Test error position accuracy for unterminated string
#[test]
fn test_error_position_unterminated_string() {
let yaml = r#"valid: "good string"
also_valid: 42
broken: "unclosed
still_broken: value"#;
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(errors[0], "3:9: Unterminated quoted string");
}
/// Test that plain scalar with spaces is valid YAML
#[test]
fn test_plain_scalar_with_spaces_valid() {
let yaml = "key1 value\nkey2: value";
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
// Plain scalars can contain spaces, so "key1 value" is valid as a key
// with implicit null value. No errors expected.
assert_eq!(errors.len(), 0, "Plain scalar with space is valid YAML");
// Verify document exists
let tree = parsed.tree();
assert!(tree.document().is_some());
}
/// Test multiple errors in single document
#[test]
fn test_multiple_errors_single_document() {
let yaml = r#"bad1: [unclosed
bad2: {also_unclosed"#;
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
// Parser reports first error, then may stop or continue
assert!(
!errors.is_empty(),
"Should have at least one error for malformed document"
);
// Should still produce a tree despite errors
assert!(parsed.tree().document().is_some());
}
/// Test error recovery continues parsing after error
#[test]
fn test_error_recovery_continues_parsing() {
let yaml = r#"valid1: value1
broken: [unclosed
valid2: value2
valid3: value3"#;
let parsed = YamlFile::parse(yaml);
// Should have error for unclosed bracket
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have 1 error");
assert_eq!(
errors[0],
"4:15: Unclosed flow sequence. Expected: ']' to close sequence. Found: end of input. Context: in flow sequence. Suggestion: Add ']' to close the array, or check for missing commas between elements"
);
// Should still parse and produce a tree
let tree = parsed.tree();
assert!(tree.document().is_some());
// Verify we can access valid keys (error recovery worked)
let doc = tree.document().unwrap();
let mapping = doc.as_mapping().expect("Should have mapping");
assert!(
mapping.keys().count() >= 2,
"Should have parsed at least some keys"
);
}
/// Test error context shows where in structure error occurred
#[test]
fn test_error_context_nested_structure() {
let yaml = r#"valid:
nested:
deep:
error: [unclosed"#;
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(
errors[0],
"4:23: Unclosed flow sequence. Expected: ']' to close sequence. Found: end of input. Context: in flow sequence. Suggestion: Add ']' to close the array, or check for missing commas between elements"
);
}
/// Test unclosed flow mapping error message
#[test]
fn test_unclosed_flow_mapping_error() {
let yaml = "config: {host: localhost";
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(
errors[0],
"1:25: Unclosed flow mapping. Expected: '}' to close mapping. Found: end of input. Context: in flow mapping. Suggestion: Add '}' to close the object, or check for missing commas between key-value pairs"
);
}
/// Test unclosed flow sequence error message
#[test]
fn test_unclosed_flow_sequence_error() {
let yaml = "items: [a, b, c";
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(
errors[0],
"1:16: Unclosed flow sequence. Expected: ']' to close sequence. Found: end of input. Context: in flow sequence. Suggestion: Add ']' to close the array, or check for missing commas between elements"
);
}
/// Test error message format consistency
#[test]
fn test_error_message_format() {
let yaml = "items: [a, b";
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(
errors[0],
"1:13: Unclosed flow sequence. Expected: ']' to close sequence. Found: end of input. Context: in flow sequence. Suggestion: Add ']' to close the array, or check for missing commas between elements"
);
}
/// Test error in flow mapping with multiline content
#[test]
fn test_multiline_flow_mapping_error() {
let yaml = r#"config: {
host: localhost,
port: 8080
"#;
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(
errors[0],
"4:1: Unclosed flow mapping. Expected: '}' to close mapping. Found: end of input. Context: in flow mapping. Suggestion: Add '}' to close the object, or check for missing commas between key-value pairs"
);
// Should still produce a tree
assert!(parsed.tree().document().is_some());
}
/// Test error in flow sequence with multiline content
#[test]
fn test_multiline_flow_sequence_error() {
let yaml = r#"items: [
first,
second,
third
"#;
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(
errors[0],
"5:1: Unclosed flow sequence. Expected: ']' to close sequence. Found: end of input. Context: in flow sequence. Suggestion: Add ']' to close the array, or check for missing commas between elements"
);
// Should still produce a tree
assert!(parsed.tree().document().is_some());
}
/// Test that valid YAML after error is still processed
#[test]
fn test_valid_content_after_error_processed() {
let yaml = r#"start: value
broken: [
fixed: works
end: value"#;
let parsed = YamlFile::parse(yaml);
// Should have error for broken line
assert_eq!(parsed.errors().len(), 1);
// Should still produce a tree and process valid content
let tree = parsed.tree();
assert!(tree.document().is_some());
let doc = tree.document().unwrap();
let mapping = doc.as_mapping().expect("Should have mapping");
// Parser attempts to process all lines despite error
assert!(
mapping.keys().count() >= 2,
"Should have parsed multiple keys despite error"
);
}
/// Test exact error format for missing closing brace in nested structure
#[test]
fn test_nested_unclosed_brace_exact_error() {
let yaml = r#"outer:
inner: {key: value"#;
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(
errors[0],
"2:21: Unclosed flow mapping. Expected: '}' to close mapping. Found: end of input. Context: in flow mapping. Suggestion: Add '}' to close the object, or check for missing commas between key-value pairs"
);
}
/// Test exact error format for missing closing bracket in nested structure
#[test]
fn test_nested_unclosed_bracket_exact_error() {
let yaml = r#"outer:
inner: [a, b, c"#;
let parsed = YamlFile::parse(yaml);
let errors = parsed.errors();
assert_eq!(errors.len(), 1, "Should have exactly 1 error");
assert_eq!(
errors[0],
"2:18: Unclosed flow sequence. Expected: ']' to close sequence. Found: end of input. Context: in flow sequence. Suggestion: Add ']' to close the array, or check for missing commas between elements"
);
}
|