specification_compliance_complex.rs
1 use korni::{parse, Entry}; 2 3 // --- Security & Encoding Tests --- 4 5 6 7 #[test] 8 fn test_security_newline_injection_in_quotes() { 9 // Spec 6.2: Newlines in quotes are literal, NOT new definitions 10 let input = "SAFE=\"value\nKEY2=malicious\""; 11 let entries = parse(input); 12 assert_eq!(entries.len(), 1); 13 let kv = entries[0].as_pair().unwrap(); 14 assert_eq!(kv.key, "SAFE"); 15 assert_eq!(kv.value, "value\nKEY2=malicious"); 16 } 17 18 #[test] 19 fn test_security_newline_injection_attempt_unquoted() { 20 // Unquoted values end at newline. 21 let input = "SAFE=value\nKEY2=malicious"; 22 let entries = parse(input); 23 assert_eq!(entries.len(), 2); 24 let kv1 = entries[0].as_pair().unwrap(); 25 assert_eq!(kv1.key, "SAFE"); 26 assert_eq!(kv1.value, "value"); 27 28 let kv2 = entries[1].as_pair().unwrap(); 29 assert_eq!(kv2.key, "KEY2"); 30 assert_eq!(kv2.value, "malicious"); 31 } 32 33 // --- Complex Nesting & Escaping --- 34 35 #[test] 36 fn test_complex_nesting_deep() { 37 // Spec 4.2.4: Quote types nest literally 38 // Updated to use valid escaped quotes for inner quotes as parser tracks outermost only 39 let input = r#"KEY="a 'b \"c\" d' e""#; 40 let entries = parse(input); 41 let kv = entries[0].as_pair().unwrap(); 42 assert_eq!(kv.value, r#"a 'b "c" d' e"#); 43 } 44 45 #[test] 46 fn test_complex_escaping_madness() { 47 // Spec 4.2.4: All escape rules combined 48 // Input: KEY="tab:\t quote:\" slash:\\ dollar:\$ newline:\n" 49 let input = r#"KEY="tab:\t quote:\" slash:\\ dollar:\$ newline:\n""#; 50 let entries = parse(input); 51 let kv = entries[0].as_pair().unwrap(); 52 assert_eq!(kv.value, "tab:\t quote:\" slash:\\ dollar:$ newline:\n"); 53 } 54 55 #[test] 56 fn test_variable_interpolation_is_literal() { 57 // Spec 4.4: Interpolation is explicitly OUT OF SCOPE. Must return literal. 58 let input = "Usage=${VAR} $VAR"; 59 let entries = parse(input); 60 // Spec 4.2.2: Unquoted values end at first whitespace. 61 // So `Usage=${VAR} $VAR` -> value is `${VAR}`. The rest is ignored junk. 62 // This confirms interpolation is literal (no substitution) AND strict whitespace handling. 63 let kv = entries[0].as_pair().unwrap(); 64 assert_eq!(kv.value, "${VAR}"); 65 } 66 67 #[test] 68 fn test_variable_interpolation_escaped_dollar() { 69 // Spec 4.4: \$ becomes literal $ 70 let input = r#"KEY="\${VAR}""#; 71 let entries = parse(input); 72 let kv = entries[0].as_pair().unwrap(); 73 assert_eq!(kv.value, "${VAR}"); 74 } 75 76 // --- Multiline Quirks --- 77 78 #[test] 79 fn test_multiline_empty_lines_preserved_quoted() { 80 // Spec 5.1: Empty lines in quoted strings preserved 81 let input = "TEXT=\"Line1\n\nLine3\""; 82 let entries = parse(input); 83 let kv = entries[0].as_pair().unwrap(); 84 assert_eq!(kv.value, "Line1\n\nLine3"); 85 } 86 87 #[test] 88 fn test_continuation_empty_lines_consumed() { 89 // Spec 5.2 (Strict): Space terminates value. 90 // "KEY=value\ \n\nmore" -> "value\". 91 // The space comes AFTER the backslash, so backslash is part of value. 92 // Since we terminated at space (not newline), continuation is NOT triggered. 93 let input = "KEY=value\\ \n\nmore"; 94 let entries = parse(input); 95 let kv = entries[0].as_pair().unwrap(); 96 assert_eq!(kv.value, "value\\"); 97 } 98 99 #[test] 100 fn test_continuation_space_preservation() { 101 // Spec 5.2 (Strict): Unquoted value ends at space. 102 // "KEY=val \ ..." -> "val". 103 let input = "KEY=val \\\n ue"; 104 let entries = parse(input); 105 let kv = entries[0].as_pair().unwrap(); 106 assert_eq!(kv.value, "val"); 107 } 108 109 #[test] 110 fn test_continuation_with_inline_comment() { 111 // Spec 5.2 (Strict): Unquoted continuation CANNOT have inline comments 112 // because the space required for comment implies termination. 113 // "KEY=val \ # comment" -> "val" 114 let input = "KEY=val \\ # comment\n ue"; 115 let entries = parse(input); 116 let kv = entries[0].as_pair().unwrap(); 117 assert_eq!(kv.value, "val"); 118 } 119 120 // ... 121 122 #[test] 123 fn test_spec_5_2_continuation_before_comment() { 124 // Spec 5.2 (Strict): Backslash BEFORE comment requires space before #, 125 // which terminates value. So continuation is impossible here for unquoted. 126 // "KEY=val \ # comment" -> "val" 127 let input = "KEY=val \\ # comment\n continued"; 128 let entries = parse(input); 129 let kv = entries[0].as_pair().unwrap(); 130 assert_eq!(kv.value, "val"); 131 } 132 133 #[test] 134 fn test_error_message_no_value_leak() { 135 // Spec 6.3: Error messages MUST NOT leak values. 136 // We create a case that causes error during value parsing? 137 // Or invalid key with sensitive data? 138 // "KEY with invalid char" 139 let input = "KEY-SENSITIVE=secret_value"; // Invalid key (dash) 140 let entries = parse(input); 141 match &entries[0] { 142 Entry::Error(e) => { 143 let msg = e.to_string(); 144 // Error should define it's an invalid key, but NOT show full line content if possible? 145 // Actually spec says "Invalid character in key...". 146 // It shouldn't show "secret_value". 147 assert!(!msg.contains("secret_value")); 148 }, 149 _ => panic!("Should be error"), 150 } 151 } 152 153 #[test] 154 fn test_mixed_newline_normalization() { 155 // Spec 4.2.2: Parsers MAY normalize, but strictly preserving is fine. 156 // Check behavior consistency. 157 let input = "KEY=val\r\nNEXT=v\nLAST=x"; 158 let entries = parse(input); 159 assert_eq!(entries.len(), 3); 160 assert_eq!(entries[0].as_pair().unwrap().value, "val"); 161 assert_eq!(entries[1].as_pair().unwrap().value, "v"); 162 assert_eq!(entries[2].as_pair().unwrap().value, "x"); 163 }