1use crate::lex::SyntaxKind;
6
7#[cfg(feature = "derive")]
8pub use deb822_derive::{FromDeb822, ToDeb822};
9
10pub mod convert;
11pub use convert::{FromDeb822Paragraph, ToDeb822Paragraph};
12mod lex;
13
14#[derive(Debug)]
16pub enum Error {
17 UnexpectedToken(SyntaxKind, String),
19
20 UnexpectedEof,
22
23 ExpectedEof,
25
26 Io(std::io::Error),
28}
29
30impl From<std::io::Error> for Error {
31 fn from(e: std::io::Error) -> Self {
32 Self::Io(e)
33 }
34}
35
36impl std::fmt::Display for Error {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
38 match self {
39 Self::UnexpectedToken(_k, t) => write!(f, "Unexpected token: {}", t),
40 Self::UnexpectedEof => f.write_str("Unexpected end-of-file"),
41 Self::Io(e) => write!(f, "IO error: {}", e),
42 Self::ExpectedEof => f.write_str("Expected end-of-file"),
43 }
44 }
45}
46
47#[derive(Debug, PartialEq, Eq, Clone)]
49pub struct Field {
50 pub name: String,
52
53 pub value: String,
55}
56
57#[derive(Debug, PartialEq, Eq, Clone)]
59pub struct Paragraph {
60 pub fields: Vec<Field>,
62}
63
64impl Paragraph {
65 pub fn get(&self, name: &str) -> Option<&str> {
69 for field in &self.fields {
70 if field.name == name {
71 return Some(&field.value);
72 }
73 }
74 None
75 }
76
77 pub fn is_empty(&self) -> bool {
79 self.fields.is_empty()
80 }
81
82 pub fn len(&self) -> usize {
84 self.fields.len()
85 }
86
87 pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
89 self.fields
90 .iter()
91 .map(|field| (field.name.as_str(), field.value.as_str()))
92 }
93
94 pub fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut String)> {
96 self.fields
97 .iter_mut()
98 .map(|field| (field.name.as_str(), &mut field.value))
99 }
100
101 pub fn insert(&mut self, name: &str, value: &str) {
106 self.fields.push(Field {
107 name: name.to_string(),
108 value: value.to_string(),
109 });
110 }
111
112 pub fn set(&mut self, name: &str, value: &str) {
117 for field in &mut self.fields {
118 if field.name == name {
119 field.value = value.to_string();
120 return;
121 }
122 }
123 self.insert(name, value);
124 }
125
126 pub fn remove(&mut self, name: &str) {
128 self.fields.retain(|field| field.name != name);
129 }
130}
131
132impl std::fmt::Display for Field {
133 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
134 let lines = self.value.lines().collect::<Vec<_>>();
135 if lines.len() > 1 {
136 write!(f, "{}:", self.name)?;
137 for line in lines {
138 writeln!(f, " {}", line)?;
139 }
140 Ok(())
141 } else {
142 writeln!(f, "{}: {}", self.name, self.value)
143 }
144 }
145}
146
147impl std::fmt::Display for Paragraph {
148 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
149 for field in &self.fields {
150 field.fmt(f)?;
151 }
152 Ok(())
153 }
154}
155
156impl std::fmt::Display for Deb822 {
157 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
158 for (i, paragraph) in self.0.iter().enumerate() {
159 if i > 0 {
160 writeln!(f)?;
161 }
162 write!(f, "{}", paragraph)?;
163 }
164 Ok(())
165 }
166}
167
168impl std::str::FromStr for Paragraph {
169 type Err = Error;
170
171 fn from_str(s: &str) -> Result<Self, Self::Err> {
172 let doc: Deb822 = s.parse().map_err(|_| Error::ExpectedEof)?;
173 if doc.is_empty() {
174 Err(Error::UnexpectedEof)
175 } else if doc.len() > 1 {
176 Err(Error::ExpectedEof)
177 } else {
178 Ok(doc.0.into_iter().next().unwrap())
179 }
180 }
181}
182
183impl From<Vec<(String, String)>> for Paragraph {
184 fn from(fields: Vec<(String, String)>) -> Self {
185 fields.into_iter().collect()
186 }
187}
188
189impl FromIterator<(String, String)> for Paragraph {
190 fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
191 let fields = iter
192 .into_iter()
193 .map(|(name, value)| Field { name, value })
194 .collect();
195 Paragraph { fields }
196 }
197}
198
199impl IntoIterator for Paragraph {
200 type Item = (String, String);
201 type IntoIter = std::iter::Map<std::vec::IntoIter<Field>, fn(Field) -> (String, String)>;
202
203 fn into_iter(self) -> Self::IntoIter {
204 self.fields
205 .into_iter()
206 .map(|field| (field.name, field.value))
207 }
208}
209
210#[derive(Debug, PartialEq, Eq, Clone)]
212pub struct Deb822(Vec<Paragraph>);
213
214impl From<Deb822> for Vec<Paragraph> {
215 fn from(doc: Deb822) -> Self {
216 doc.0
217 }
218}
219
220impl IntoIterator for Deb822 {
221 type Item = Paragraph;
222 type IntoIter = std::vec::IntoIter<Paragraph>;
223
224 fn into_iter(self) -> Self::IntoIter {
225 self.0.into_iter()
226 }
227}
228
229impl Deb822 {
230 pub fn len(&self) -> usize {
232 self.0.len()
233 }
234
235 pub fn is_empty(&self) -> bool {
237 self.0.is_empty()
238 }
239
240 pub fn iter(&self) -> impl Iterator<Item = &Paragraph> {
242 self.0.iter()
243 }
244
245 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Paragraph> {
247 self.0.iter_mut()
248 }
249
250 pub fn from_reader<R: std::io::Read>(mut r: R) -> Result<Self, Error> {
252 let mut buf = String::new();
253 r.read_to_string(&mut buf)?;
254 buf.parse()
255 }
256}
257
258impl std::str::FromStr for Deb822 {
259 type Err = Error;
260
261 fn from_str(s: &str) -> Result<Self, Self::Err> {
262 let mut tokens = crate::lex::lex(s).peekable();
263
264 let mut paragraphs = Vec::new();
265 let mut current_paragraph = Vec::new();
266
267 while let Some((k, t)) = tokens.next() {
268 match k {
269 SyntaxKind::INDENT | SyntaxKind::COLON | SyntaxKind::ERROR => {
270 return Err(Error::UnexpectedToken(k, t.to_string()));
271 }
272 SyntaxKind::WHITESPACE => {
273 }
275 SyntaxKind::KEY => {
276 current_paragraph.push(Field {
277 name: t.to_string(),
278 value: String::new(),
279 });
280
281 match tokens.next() {
282 Some((SyntaxKind::COLON, _)) => {}
283 Some((k, t)) => {
284 return Err(Error::UnexpectedToken(k, t.to_string()));
285 }
286 None => {
287 return Err(Error::UnexpectedEof);
288 }
289 }
290
291 while tokens.peek().map(|(k, _)| k) == Some(&SyntaxKind::WHITESPACE) {
292 tokens.next();
293 }
294
295 for (k, t) in tokens.by_ref() {
296 match k {
297 SyntaxKind::VALUE => {
298 current_paragraph.last_mut().unwrap().value = t.to_string();
299 }
300 SyntaxKind::NEWLINE => {
301 break;
302 }
303 _ => return Err(Error::UnexpectedToken(k, t.to_string())),
304 }
305 }
306
307 current_paragraph.last_mut().unwrap().value.push('\n');
308
309 while tokens.peek().map(|(k, _)| k) == Some(&SyntaxKind::INDENT) {
311 tokens.next();
312 loop {
313 match tokens.peek() {
314 Some((SyntaxKind::VALUE, t)) => {
315 current_paragraph.last_mut().unwrap().value.push_str(t);
316 tokens.next();
317 }
318 Some((SyntaxKind::COMMENT, _)) => {
319 tokens.next();
321 }
322 Some((SyntaxKind::NEWLINE, n)) => {
323 current_paragraph.last_mut().unwrap().value.push_str(n);
324 tokens.next();
325 break;
326 }
327 Some((SyntaxKind::KEY, _)) => {
328 break;
329 }
330 Some((k, _)) => {
331 return Err(Error::UnexpectedToken(*k, t.to_string()));
332 }
333 None => {
334 break;
335 }
336 }
337 }
338 }
339
340 {
342 let par = current_paragraph.last_mut().unwrap();
343 if par.value.ends_with('\n') {
344 par.value.pop();
345 }
346 }
347 }
348 SyntaxKind::VALUE => {
349 return Err(Error::UnexpectedToken(k, t.to_string()));
350 }
351 SyntaxKind::COMMENT => {
352 for (k, _) in tokens.by_ref() {
353 if k == SyntaxKind::NEWLINE {
354 break;
355 }
356 }
357 }
358 SyntaxKind::NEWLINE => {
359 if !current_paragraph.is_empty() {
360 paragraphs.push(Paragraph {
361 fields: current_paragraph,
362 });
363 current_paragraph = Vec::new();
364 }
365 }
366 }
367 }
368 if !current_paragraph.is_empty() {
369 paragraphs.push(Paragraph {
370 fields: current_paragraph,
371 });
372 }
373 Ok(Deb822(paragraphs))
374 }
375}
376
377#[cfg(test)]
378mod tests {
379 use super::*;
380 use crate::lex::lex;
381
382 #[test]
383 fn test_error_display() {
384 let err = Error::UnexpectedToken(SyntaxKind::ERROR, "invalid".to_string());
385 assert_eq!(err.to_string(), "Unexpected token: invalid");
386
387 let err = Error::UnexpectedEof;
388 assert_eq!(err.to_string(), "Unexpected end-of-file");
389
390 let err = Error::ExpectedEof;
391 assert_eq!(err.to_string(), "Expected end-of-file");
392
393 let io_err = std::io::Error::new(std::io::ErrorKind::Other, "test error");
394 let err = Error::Io(io_err);
395 assert!(err.to_string().contains("IO error: test error"));
396 }
397
398 #[test]
399 fn test_parse() {
400 let input = r#"Package: hello
401Version: 2.10
402Description: A program that says hello
403 Some more text
404
405Package: world
406Version: 1.0
407Description: A program that says world
408 And some more text
409Another-Field: value
410
411# A comment
412
413"#;
414
415 let mut deb822: Deb822 = input.parse().unwrap();
416 assert_eq!(
417 deb822,
418 Deb822(vec![
419 Paragraph {
420 fields: vec![
421 Field {
422 name: "Package".to_string(),
423 value: "hello".to_string(),
424 },
425 Field {
426 name: "Version".to_string(),
427 value: "2.10".to_string(),
428 },
429 Field {
430 name: "Description".to_string(),
431 value: "A program that says hello\nSome more text".to_string(),
432 },
433 ],
434 },
435 Paragraph {
436 fields: vec![
437 Field {
438 name: "Package".to_string(),
439 value: "world".to_string(),
440 },
441 Field {
442 name: "Version".to_string(),
443 value: "1.0".to_string(),
444 },
445 Field {
446 name: "Description".to_string(),
447 value: "A program that says world\nAnd some more text".to_string(),
448 },
449 Field {
450 name: "Another-Field".to_string(),
451 value: "value".to_string(),
452 },
453 ],
454 },
455 ])
456 );
457 assert_eq!(deb822.len(), 2);
458 assert!(!deb822.is_empty());
459 assert_eq!(deb822.iter().count(), 2);
460
461 let para = deb822.iter().next().unwrap();
462 assert_eq!(para.get("Package"), Some("hello"));
463 assert_eq!(para.get("Version"), Some("2.10"));
464 assert_eq!(
465 para.get("Description"),
466 Some("A program that says hello\nSome more text")
467 );
468 assert_eq!(para.get("Another-Field"), None);
469 assert!(!para.is_empty());
470 assert_eq!(para.len(), 3);
471 assert_eq!(
472 para.iter().collect::<Vec<_>>(),
473 vec![
474 ("Package", "hello"),
475 ("Version", "2.10"),
476 ("Description", "A program that says hello\nSome more text"),
477 ]
478 );
479 let para = deb822.iter_mut().next().unwrap();
480 para.insert("Another-Field", "value");
481 assert_eq!(para.get("Another-Field"), Some("value"));
482
483 let mut newpara = Paragraph { fields: vec![] };
484 newpara.insert("Package", "new");
485 assert_eq!(newpara.to_string(), "Package: new\n");
486 }
487
488 #[test]
489 fn test_lex() {
490 let input = r#"Package: hello
491Version: 2.10
492
493Package: world
494# Comment
495Version: 1.0
496Description: A program that says world
497 And some more text
498"#;
499 assert_eq!(
500 lex(input).collect::<Vec<_>>(),
501 vec![
502 (SyntaxKind::KEY, "Package"),
503 (SyntaxKind::COLON, ":"),
504 (SyntaxKind::WHITESPACE, " "),
505 (SyntaxKind::VALUE, "hello"),
506 (SyntaxKind::NEWLINE, "\n"),
507 (SyntaxKind::KEY, "Version"),
508 (SyntaxKind::COLON, ":"),
509 (SyntaxKind::WHITESPACE, " "),
510 (SyntaxKind::VALUE, "2.10"),
511 (SyntaxKind::NEWLINE, "\n"),
512 (SyntaxKind::NEWLINE, "\n"),
513 (SyntaxKind::KEY, "Package"),
514 (SyntaxKind::COLON, ":"),
515 (SyntaxKind::WHITESPACE, " "),
516 (SyntaxKind::VALUE, "world"),
517 (SyntaxKind::NEWLINE, "\n"),
518 (SyntaxKind::COMMENT, "# Comment"),
519 (SyntaxKind::NEWLINE, "\n"),
520 (SyntaxKind::KEY, "Version"),
521 (SyntaxKind::COLON, ":"),
522 (SyntaxKind::WHITESPACE, " "),
523 (SyntaxKind::VALUE, "1.0"),
524 (SyntaxKind::NEWLINE, "\n"),
525 (SyntaxKind::KEY, "Description"),
526 (SyntaxKind::COLON, ":"),
527 (SyntaxKind::WHITESPACE, " "),
528 (SyntaxKind::VALUE, "A program that says world"),
529 (SyntaxKind::NEWLINE, "\n"),
530 (SyntaxKind::INDENT, " "),
531 (SyntaxKind::VALUE, "And some more text"),
532 (SyntaxKind::NEWLINE, "\n"),
533 ]
534 );
535 }
536
537 #[test]
538 fn test_paragraph_iter() {
539 let input = r#"Package: hello
540Version: 2.10
541"#;
542 let para: Paragraph = input.parse().unwrap();
543 let mut iter = para.into_iter();
544 assert_eq!(
545 iter.next(),
546 Some(("Package".to_string(), "hello".to_string()))
547 );
548 assert_eq!(
549 iter.next(),
550 Some(("Version".to_string(), "2.10".to_string()))
551 );
552 assert_eq!(iter.next(), None);
553 }
554
555 #[test]
556 fn test_format_multiline() {
557 let para = Paragraph {
558 fields: vec![Field {
559 name: "Description".to_string(),
560 value: "A program that says hello\nSome more text".to_string(),
561 }],
562 };
563
564 assert_eq!(
565 para.to_string(),
566 "Description: A program that says hello\n Some more text\n"
567 );
568 }
569
570 #[test]
571 fn test_paragraph_from_str_errors() {
572 let result = "Package: foo\n\nPackage: bar\n".parse::<Paragraph>();
574 assert!(matches!(result, Err(Error::ExpectedEof)));
575
576 let result = "".parse::<Paragraph>();
578 assert!(matches!(result, Err(Error::UnexpectedEof)));
579 }
580
581 #[test]
582 fn test_from_vec() {
583 let fields = vec![
584 ("Package".to_string(), "hello".to_string()),
585 ("Version".to_string(), "1.0".to_string()),
586 ];
587
588 let para: Paragraph = fields.into();
589 assert_eq!(para.get("Package"), Some("hello"));
590 assert_eq!(para.get("Version"), Some("1.0"));
591 }
592
593 #[test]
594 fn test_unexpected_tokens() {
595 let input = "Value before key\nPackage: hello\n";
597 let result = input.parse::<Deb822>();
598 assert!(matches!(result, Err(Error::UnexpectedToken(_, _))));
599
600 let input = "Package hello\n";
602 let result = input.parse::<Deb822>();
603 assert!(matches!(result, Err(Error::UnexpectedToken(_, _))));
604
605 let input = " Indented: value\n";
607 let result = input.parse::<Deb822>();
608 assert!(matches!(result, Err(Error::UnexpectedToken(_, _))));
609
610 let input = "Key: value\nvalue without key\n";
612 let result = input.parse::<Deb822>();
613 assert!(matches!(result, Err(Error::UnexpectedToken(_, _))));
614
615 let input = "Key: value\n:\n";
617 let result = input.parse::<Deb822>();
618 assert!(matches!(result, Err(Error::UnexpectedToken(_, _))));
619 }
620
621 #[test]
622 fn test_from_reader() {
623 let input = "Package: hello\nVersion: 1.0\n";
625 let result = Deb822::from_reader(input.as_bytes()).unwrap();
626 assert_eq!(result.len(), 1);
627 let para = result.iter().next().unwrap();
628 assert_eq!(para.get("Package"), Some("hello"));
629
630 use std::io::{Error as IoError, ErrorKind};
632 struct FailingReader;
633 impl std::io::Read for FailingReader {
634 fn read(&mut self, _: &mut [u8]) -> std::io::Result<usize> {
635 Err(IoError::new(ErrorKind::Other, "test error"))
636 }
637 }
638
639 let result = Deb822::from_reader(FailingReader);
640 assert!(matches!(result, Err(Error::Io(_))));
641 }
642
643 #[test]
644 fn test_deb822_vec_conversion() {
645 let paragraphs = vec![
646 Paragraph {
647 fields: vec![Field {
648 name: "Package".to_string(),
649 value: "hello".to_string(),
650 }],
651 },
652 Paragraph {
653 fields: vec![Field {
654 name: "Package".to_string(),
655 value: "world".to_string(),
656 }],
657 },
658 ];
659
660 let deb822 = Deb822(paragraphs.clone());
661 let vec: Vec<Paragraph> = deb822.into();
662 assert_eq!(vec, paragraphs);
663 }
664
665 #[test]
666 fn test_deb822_iteration() {
667 let paragraphs = vec![
668 Paragraph {
669 fields: vec![Field {
670 name: "Package".to_string(),
671 value: "hello".to_string(),
672 }],
673 },
674 Paragraph {
675 fields: vec![Field {
676 name: "Package".to_string(),
677 value: "world".to_string(),
678 }],
679 },
680 ];
681
682 let deb822 = Deb822(paragraphs.clone());
683
684 let collected: Vec<_> = deb822.into_iter().collect();
686 assert_eq!(collected, paragraphs);
687
688 let deb822 = Deb822(paragraphs.clone());
690 let iter_refs: Vec<&Paragraph> = deb822.iter().collect();
691 assert_eq!(iter_refs.len(), 2);
692 assert_eq!(iter_refs[0].get("Package"), Some("hello"));
693
694 let mut deb822 = Deb822(paragraphs.clone());
695 for para in deb822.iter_mut() {
696 if para.get("Package") == Some("hello") {
697 para.set("Version", "1.0");
698 }
699 }
700 assert_eq!(deb822.iter().next().unwrap().get("Version"), Some("1.0"));
701 }
702
703 #[test]
704 fn test_empty_collections() {
705 let deb822 = Deb822(vec![]);
707 assert!(deb822.is_empty());
708 assert_eq!(deb822.len(), 0);
709 assert_eq!(deb822.iter().count(), 0);
710
711 let para = Paragraph { fields: vec![] };
713 assert!(para.is_empty());
714 assert_eq!(para.len(), 0);
715 assert_eq!(para.iter().count(), 0);
716 assert_eq!(para.get("Any"), None);
717
718 assert_eq!(para.to_string(), "");
720
721 assert_eq!(deb822.to_string(), "");
723 }
724
725 #[test]
726 fn test_paragraph_mutable_iteration() {
727 let mut para = Paragraph {
728 fields: vec![
729 Field {
730 name: "First".to_string(),
731 value: "1".to_string(),
732 },
733 Field {
734 name: "Second".to_string(),
735 value: "2".to_string(),
736 },
737 ],
738 };
739
740 for (_, value) in para.iter_mut() {
742 *value = format!("{}0", value);
743 }
744
745 assert_eq!(para.get("First"), Some("10"));
746 assert_eq!(para.get("Second"), Some("20"));
747 }
748
749 #[test]
750 fn test_insert_duplicate_key() {
751 let mut para = Paragraph {
752 fields: vec![Field {
753 name: "Key".to_string(),
754 value: "Value1".to_string(),
755 }],
756 };
757
758 para.insert("Key", "Value2");
760
761 assert_eq!(para.fields.len(), 2);
762 assert_eq!(para.fields[0].value, "Value1");
763 assert_eq!(para.fields[1].value, "Value2");
764
765 assert_eq!(para.get("Key"), Some("Value1"));
767 }
768
769 #[test]
770 fn test_multiline_field_format() {
771 let field = Field {
773 name: "MultiField".to_string(),
774 value: "line1\nline2\nline3".to_string(),
775 };
776
777 let formatted = format!("{}", field);
778 assert_eq!(formatted, "MultiField: line1\n line2\n line3\n");
779
780 let para = Paragraph {
782 fields: vec![field],
783 };
784
785 let formatted = format!("{}", para);
786 assert_eq!(formatted, "MultiField: line1\n line2\n line3\n");
787 }
788
789 #[test]
790 fn test_paragraph_parsing_edge_cases() {
791 let input = "Key:\n";
793 let para: Paragraph = input.parse().unwrap();
794 assert_eq!(para.get("Key"), Some(""));
795
796 let input = "Key: \n";
799 let para: Paragraph = input.parse().unwrap();
800 assert_eq!(para.get("Key"), Some(""));
801
802 let input = "Key1: value1\n\n\n\nKey2: value2\n";
804 let deb822: Deb822 = input.parse().unwrap();
805 assert_eq!(deb822.len(), 2);
806
807 let input = "Key: value\n with\n indentation\n levels\n";
810 let para: Paragraph = input.parse().unwrap();
811 assert_eq!(para.get("Key"), Some("value\nwith\nindentation\nlevels"));
812 }
813
814 #[test]
815 fn test_parse_complex() {
816 let input = "# Comment at start\nKey1: val1\nKey2: \n indented\nKey3: val3\n\n# Comment between paragraphs\n\nKey4: val4\n";
818 let deb822: Deb822 = input.parse().unwrap();
819
820 assert_eq!(deb822.len(), 2);
821 let paragraphs: Vec<Paragraph> = deb822.into();
822
823 assert_eq!(paragraphs[0].get("Key2"), Some("\nindented"));
824 assert_eq!(paragraphs[1].get("Key4"), Some("val4"));
825
826 let input = "Key:\n indented value\n";
828 let para: Paragraph = input.parse().unwrap();
829 assert_eq!(para.get("Key"), Some("\nindented value"));
830 }
831
832 #[test]
833 fn test_deb822_display() {
834 let para1 = Paragraph {
836 fields: vec![Field {
837 name: "Key1".to_string(),
838 value: "Value1".to_string(),
839 }],
840 };
841
842 let para2 = Paragraph {
843 fields: vec![Field {
844 name: "Key2".to_string(),
845 value: "Value2".to_string(),
846 }],
847 };
848
849 let deb822 = Deb822(vec![para1, para2]);
850 let formatted = format!("{}", deb822);
851
852 assert_eq!(formatted, "Key1: Value1\n\nKey2: Value2\n");
853 }
854
855 #[test]
856 fn test_parser_edge_cases() {
857 let input = "# Comment\nKey: value";
861 let deb822: Deb822 = input.parse().unwrap();
862 assert_eq!(deb822.len(), 1);
863
864 let input = "Key: value\n .indented";
866 let deb822: Deb822 = input.parse().unwrap();
867 assert_eq!(
868 deb822.iter().next().unwrap().get("Key"),
869 Some("value\n.indented")
870 );
871
872 let input = "Key: value\n line1\n line2\n\nNextKey: value";
874 let deb822: Deb822 = input.parse().unwrap();
875 assert_eq!(deb822.len(), 2);
876 assert_eq!(
877 deb822.iter().next().unwrap().get("Key"),
878 Some("value\nline1\nline2")
879 );
880 }
881}