1use crate::fields::{MultiArch, Priority};
36use crate::lossless::relations::Relations;
37use deb822_lossless::{Deb822, Paragraph};
38
39fn format_field(name: &str, value: &str) -> String {
40 match name {
41 "Uploaders" => value
42 .split(',')
43 .map(|s| s.trim().to_string())
44 .collect::<Vec<_>>()
45 .join(",\n"),
46 "Build-Depends"
47 | "Build-Depends-Indep"
48 | "Build-Depends-Arch"
49 | "Build-Conflicts"
50 | "Build-Conflicts-Indep"
51 | "Build-Conflics-Arch"
52 | "Depends"
53 | "Recommends"
54 | "Suggests"
55 | "Enhances"
56 | "Pre-Depends"
57 | "Breaks" => {
58 let relations: Relations = value.parse().unwrap();
59 let relations = relations.wrap_and_sort();
60 relations.to_string()
61 }
62 _ => value.to_string(),
63 }
64}
65
66pub struct Control(Deb822);
68
69impl Control {
70 pub fn new() -> Self {
72 Control(Deb822::new())
73 }
74
75 pub fn as_mut_deb822(&mut self) -> &mut Deb822 {
77 &mut self.0
78 }
79
80 pub fn as_deb822(&self) -> &Deb822 {
82 &self.0
83 }
84
85 pub fn source(&self) -> Option<Source> {
87 self.0
88 .paragraphs()
89 .find(|p| p.get("Source").is_some())
90 .map(Source)
91 }
92
93 pub fn binaries(&self) -> impl Iterator<Item = Binary> {
95 self.0
96 .paragraphs()
97 .filter(|p| p.get("Package").is_some())
98 .map(Binary)
99 }
100
101 pub fn add_source(&mut self, name: &str) -> Source {
117 let mut p = self.0.add_paragraph();
118 p.set("Source", name);
119 self.source().unwrap()
120 }
121
122 pub fn add_binary(&mut self, name: &str) -> Binary {
138 let mut p = self.0.add_paragraph();
139 p.set("Package", name);
140 Binary(p)
141 }
142
143 pub fn from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self, deb822_lossless::Error> {
145 Ok(Control(Deb822::from_file(path)?))
146 }
147
148 pub fn from_file_relaxed<P: AsRef<std::path::Path>>(
150 path: P,
151 ) -> Result<(Self, Vec<String>), std::io::Error> {
152 let (control, errors) = Deb822::from_file_relaxed(path)?;
153 Ok((Control(control), errors))
154 }
155
156 pub fn read<R: std::io::Read>(mut r: R) -> Result<Self, deb822_lossless::Error> {
158 Ok(Control(Deb822::read(&mut r)?))
159 }
160
161 pub fn read_relaxed<R: std::io::Read>(
163 mut r: R,
164 ) -> Result<(Self, Vec<String>), deb822_lossless::Error> {
165 let (control, errors) = Deb822::read_relaxed(&mut r)?;
166 Ok((Self(control), errors))
167 }
168
169 pub fn wrap_and_sort(
176 &mut self,
177 indentation: deb822_lossless::Indentation,
178 immediate_empty_line: bool,
179 max_line_length_one_liner: Option<usize>,
180 ) {
181 let sort_paragraphs = |a: &Paragraph, b: &Paragraph| -> std::cmp::Ordering {
182 let a_is_source = a.get("Source").is_some();
184 let b_is_source = b.get("Source").is_some();
185
186 if a_is_source && !b_is_source {
187 return std::cmp::Ordering::Less;
188 } else if !a_is_source && b_is_source {
189 return std::cmp::Ordering::Greater;
190 } else if a_is_source && b_is_source {
191 return a.get("Source").cmp(&b.get("Source"));
192 }
193
194 a.get("Package").cmp(&b.get("Package"))
195 };
196
197 let wrap_paragraph = |p: &Paragraph| -> Paragraph {
198 p.wrap_and_sort(
201 indentation,
202 immediate_empty_line,
203 max_line_length_one_liner,
204 None,
205 Some(&format_field),
206 )
207 };
208
209 self.0 = self
210 .0
211 .wrap_and_sort(Some(&sort_paragraphs), Some(&wrap_paragraph));
212 }
213}
214
215impl From<Control> for Deb822 {
216 fn from(c: Control) -> Self {
217 c.0
218 }
219}
220
221impl From<Deb822> for Control {
222 fn from(d: Deb822) -> Self {
223 Control(d)
224 }
225}
226
227impl Default for Control {
228 fn default() -> Self {
229 Self::new()
230 }
231}
232
233impl std::str::FromStr for Control {
234 type Err = deb822_lossless::ParseError;
235
236 fn from_str(s: &str) -> Result<Self, Self::Err> {
237 Ok(Control(s.parse()?))
238 }
239}
240
241pub struct Source(Paragraph);
243
244impl From<Source> for Paragraph {
245 fn from(s: Source) -> Self {
246 s.0
247 }
248}
249
250impl From<Paragraph> for Source {
251 fn from(p: Paragraph) -> Self {
252 Source(p)
253 }
254}
255
256impl std::fmt::Display for Source {
257 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
258 self.0.fmt(f)
259 }
260}
261
262impl Source {
263 pub fn name(&self) -> Option<String> {
265 self.0.get("Source")
266 }
267
268 pub fn wrap_and_sort(
270 &mut self,
271 indentation: deb822_lossless::Indentation,
272 immediate_empty_line: bool,
273 max_line_length_one_liner: Option<usize>,
274 ) {
275 self.0 = self.0.wrap_and_sort(
276 indentation,
277 immediate_empty_line,
278 max_line_length_one_liner,
279 None,
280 Some(&format_field),
281 );
282 }
283
284 pub fn as_mut_deb822(&mut self) -> &mut Paragraph {
286 &mut self.0
287 }
288
289 pub fn as_deb822(&self) -> &Paragraph {
291 &self.0
292 }
293
294 pub fn set_name(&mut self, name: &str) {
296 self.0.set("Source", name);
297 }
298
299 pub fn section(&self) -> Option<String> {
301 self.0.get("Section")
302 }
303
304 pub fn set_section(&mut self, section: Option<&str>) {
306 if let Some(section) = section {
307 self.0.set("Section", section);
308 } else {
309 self.0.remove("Section");
310 }
311 }
312
313 pub fn priority(&self) -> Option<Priority> {
315 self.0.get("Priority").and_then(|v| v.parse().ok())
316 }
317
318 pub fn set_priority(&mut self, priority: Option<Priority>) {
320 if let Some(priority) = priority {
321 self.0.set("Priority", priority.to_string().as_str());
322 } else {
323 self.0.remove("Priority");
324 }
325 }
326
327 pub fn maintainer(&self) -> Option<String> {
329 self.0.get("Maintainer")
330 }
331
332 pub fn set_maintainer(&mut self, maintainer: &str) {
334 self.0.set("Maintainer", maintainer);
335 }
336
337 pub fn build_depends(&self) -> Option<Relations> {
339 self.0.get("Build-Depends").map(|s| s.parse().unwrap())
340 }
341
342 pub fn set_build_depends(&mut self, relations: &Relations) {
344 self.0.set("Build-Depends", relations.to_string().as_str());
345 }
346
347 pub fn build_depends_indep(&self) -> Option<Relations> {
349 self.0
350 .get("Build-Depends-Indep")
351 .map(|s| s.parse().unwrap())
352 }
353
354 pub fn build_depends_arch(&self) -> Option<Relations> {
356 self.0.get("Build-Depends-Arch").map(|s| s.parse().unwrap())
357 }
358
359 pub fn build_conflicts(&self) -> Option<Relations> {
361 self.0.get("Build-Conflicts").map(|s| s.parse().unwrap())
362 }
363
364 pub fn build_conflicts_indep(&self) -> Option<Relations> {
366 self.0
367 .get("Build-Conflicts-Indep")
368 .map(|s| s.parse().unwrap())
369 }
370
371 pub fn build_conflicts_arch(&self) -> Option<Relations> {
373 self.0
374 .get("Build-Conflicts-Arch")
375 .map(|s| s.parse().unwrap())
376 }
377
378 pub fn standards_version(&self) -> Option<String> {
380 self.0.get("Standards-Version")
381 }
382
383 pub fn set_standards_version(&mut self, version: &str) {
385 self.0.set("Standards-Version", version);
386 }
387
388 pub fn homepage(&self) -> Option<url::Url> {
390 self.0.get("Homepage").and_then(|s| s.parse().ok())
391 }
392
393 pub fn set_homepage(&mut self, homepage: &url::Url) {
395 self.0.set("Homepage", homepage.to_string().as_str());
396 }
397
398 pub fn vcs_git(&self) -> Option<String> {
400 self.0.get("Vcs-Git")
401 }
402
403 pub fn set_vcs_git(&mut self, url: &str) {
405 self.0.set("Vcs-Git", url);
406 }
407
408 pub fn vcs_svn(&self) -> Option<String> {
410 self.0.get("Vcs-Svn").map(|s| s.to_string())
411 }
412
413 pub fn set_vcs_svn(&mut self, url: &str) {
415 self.0.set("Vcs-Svn", url);
416 }
417
418 pub fn vcs_bzr(&self) -> Option<String> {
420 self.0.get("Vcs-Bzr").map(|s| s.to_string())
421 }
422
423 pub fn set_vcs_bzr(&mut self, url: &str) {
425 self.0.set("Vcs-Bzr", url);
426 }
427
428 pub fn vcs_arch(&self) -> Option<String> {
430 self.0.get("Vcs-Arch").map(|s| s.to_string())
431 }
432
433 pub fn set_vcs_arch(&mut self, url: &str) {
435 self.0.set("Vcs-Arch", url);
436 }
437
438 pub fn vcs_svk(&self) -> Option<String> {
440 self.0.get("Vcs-Svk").map(|s| s.to_string())
441 }
442
443 pub fn set_vcs_svk(&mut self, url: &str) {
445 self.0.set("Vcs-Svk", url);
446 }
447
448 pub fn vcs_darcs(&self) -> Option<String> {
450 self.0.get("Vcs-Darcs").map(|s| s.to_string())
451 }
452
453 pub fn set_vcs_darcs(&mut self, url: &str) {
455 self.0.set("Vcs-Darcs", url);
456 }
457
458 pub fn vcs_mtn(&self) -> Option<String> {
460 self.0.get("Vcs-Mtn").map(|s| s.to_string())
461 }
462
463 pub fn set_vcs_mtn(&mut self, url: &str) {
465 self.0.set("Vcs-Mtn", url);
466 }
467
468 pub fn vcs_cvs(&self) -> Option<String> {
470 self.0.get("Vcs-Cvs").map(|s| s.to_string())
471 }
472
473 pub fn set_vcs_cvs(&mut self, url: &str) {
475 self.0.set("Vcs-Cvs", url);
476 }
477
478 pub fn vcs_hg(&self) -> Option<String> {
480 self.0.get("Vcs-Hg").map(|s| s.to_string())
481 }
482
483 pub fn set_vcs_hg(&mut self, url: &str) {
485 self.0.set("Vcs-Hg", url);
486 }
487
488 pub fn vcs_browser(&self) -> Option<String> {
490 self.0.get("Vcs-Browser")
491 }
492
493 pub fn vcs(&self) -> Option<crate::vcs::Vcs> {
495 for (name, value) in self.0.items() {
496 if name.starts_with("Vcs-") && name != "Vcs-Browser" {
497 return crate::vcs::Vcs::from_field(&name, &value).ok();
498 }
499 }
500 None
501 }
502
503 pub fn set_vcs_browser(&mut self, url: Option<&str>) {
505 if let Some(url) = url {
506 self.0.set("Vcs-Browser", url);
507 } else {
508 self.0.remove("Vcs-Browser");
509 }
510 }
511
512 pub fn uploaders(&self) -> Option<Vec<String>> {
514 self.0
515 .get("Uploaders")
516 .map(|s| s.split(',').map(|s| s.trim().to_owned()).collect())
517 }
518
519 pub fn set_uploaders(&mut self, uploaders: &[&str]) {
521 self.0.set(
522 "Uploaders",
523 uploaders
524 .iter()
525 .map(|s| s.to_string())
526 .collect::<Vec<_>>()
527 .join(", ")
528 .as_str(),
529 );
530 }
531
532 pub fn architecture(&self) -> Option<String> {
534 self.0.get("Architecture")
535 }
536
537 pub fn set_architecture(&mut self, arch: Option<&str>) {
539 if let Some(arch) = arch {
540 self.0.set("Architecture", arch);
541 } else {
542 self.0.remove("Architecture");
543 }
544 }
545
546 pub fn rules_requires_root(&self) -> Option<bool> {
548 self.0
549 .get("Rules-Requires-Root")
550 .map(|s| match s.to_lowercase().as_str() {
551 "yes" => true,
552 "no" => false,
553 _ => panic!("invalid Rules-Requires-Root value"),
554 })
555 }
556
557 pub fn set_rules_requires_root(&mut self, requires_root: bool) {
559 self.0.set(
560 "Rules-Requires-Root",
561 if requires_root { "yes" } else { "no" },
562 );
563 }
564
565 pub fn testsuite(&self) -> Option<String> {
567 self.0.get("Testsuite")
568 }
569
570 pub fn set_testsuite(&mut self, testsuite: &str) {
572 self.0.set("Testsuite", testsuite);
573 }
574}
575
576#[cfg(feature = "python-debian")]
577impl<'py> pyo3::IntoPyObject<'py> for Source {
578 type Target = pyo3::PyAny;
579 type Output = pyo3::Bound<'py, Self::Target>;
580 type Error = pyo3::PyErr;
581
582 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
583 self.0.into_pyobject(py)
584 }
585}
586
587#[cfg(feature = "python-debian")]
588impl<'a, 'py> pyo3::IntoPyObject<'py> for &'a Source {
589 type Target = pyo3::PyAny;
590 type Output = pyo3::Bound<'py, Self::Target>;
591 type Error = pyo3::PyErr;
592
593 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
594 (&self.0).into_pyobject(py)
595 }
596}
597
598#[cfg(feature = "python-debian")]
599impl pyo3::FromPyObject<'_> for Source {
600 fn extract_bound(ob: &pyo3::Bound<pyo3::PyAny>) -> pyo3::PyResult<Self> {
601 use pyo3::prelude::*;
602 Ok(Source(ob.extract()?))
603 }
604}
605
606impl std::fmt::Display for Control {
607 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
608 self.0.fmt(f)
609 }
610}
611
612pub struct Binary(Paragraph);
614
615impl From<Binary> for Paragraph {
616 fn from(b: Binary) -> Self {
617 b.0
618 }
619}
620
621impl From<Paragraph> for Binary {
622 fn from(p: Paragraph) -> Self {
623 Binary(p)
624 }
625}
626
627#[cfg(feature = "python-debian")]
628impl<'py> pyo3::IntoPyObject<'py> for Binary {
629 type Target = pyo3::PyAny;
630 type Output = pyo3::Bound<'py, Self::Target>;
631 type Error = pyo3::PyErr;
632
633 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
634 self.0.into_pyobject(py)
635 }
636}
637
638#[cfg(feature = "python-debian")]
639impl<'a, 'py> pyo3::IntoPyObject<'py> for &'a Binary {
640 type Target = pyo3::PyAny;
641 type Output = pyo3::Bound<'py, Self::Target>;
642 type Error = pyo3::PyErr;
643
644 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
645 (&self.0).into_pyobject(py)
646 }
647}
648
649#[cfg(feature = "python-debian")]
650impl pyo3::FromPyObject<'_> for Binary {
651 fn extract_bound(ob: &pyo3::Bound<pyo3::PyAny>) -> pyo3::PyResult<Self> {
652 use pyo3::prelude::*;
653 Ok(Binary(ob.extract()?))
654 }
655}
656
657impl Default for Binary {
658 fn default() -> Self {
659 Self::new()
660 }
661}
662
663impl Binary {
664 pub fn new() -> Self {
666 Binary(Paragraph::new())
667 }
668
669 pub fn as_mut_deb822(&mut self) -> &mut Paragraph {
671 &mut self.0
672 }
673
674 pub fn as_deb822(&self) -> &Paragraph {
676 &self.0
677 }
678
679 pub fn wrap_and_sort(
681 &mut self,
682 indentation: deb822_lossless::Indentation,
683 immediate_empty_line: bool,
684 max_line_length_one_liner: Option<usize>,
685 ) {
686 self.0 = self.0.wrap_and_sort(
687 indentation,
688 immediate_empty_line,
689 max_line_length_one_liner,
690 None,
691 Some(&format_field),
692 );
693 }
694
695 pub fn name(&self) -> Option<String> {
697 self.0.get("Package")
698 }
699
700 pub fn set_name(&mut self, name: &str) {
702 self.0.set("Package", name);
703 }
704
705 pub fn section(&self) -> Option<String> {
707 self.0.get("Section")
708 }
709
710 pub fn set_section(&mut self, section: Option<&str>) {
712 if let Some(section) = section {
713 self.0.set("Section", section);
714 } else {
715 self.0.remove("Section");
716 }
717 }
718
719 pub fn priority(&self) -> Option<Priority> {
721 self.0.get("Priority").and_then(|v| v.parse().ok())
722 }
723
724 pub fn set_priority(&mut self, priority: Option<Priority>) {
726 if let Some(priority) = priority {
727 self.0.set("Priority", priority.to_string().as_str());
728 } else {
729 self.0.remove("Priority");
730 }
731 }
732
733 pub fn architecture(&self) -> Option<String> {
735 self.0.get("Architecture")
736 }
737
738 pub fn set_architecture(&mut self, arch: Option<&str>) {
740 if let Some(arch) = arch {
741 self.0.set("Architecture", arch);
742 } else {
743 self.0.remove("Architecture");
744 }
745 }
746
747 pub fn depends(&self) -> Option<Relations> {
749 self.0.get("Depends").map(|s| s.parse().unwrap())
750 }
751
752 pub fn set_depends(&mut self, depends: Option<&Relations>) {
754 if let Some(depends) = depends {
755 self.0.set("Depends", depends.to_string().as_str());
756 } else {
757 self.0.remove("Depends");
758 }
759 }
760
761 pub fn recommends(&self) -> Option<Relations> {
763 self.0.get("Recommends").map(|s| s.parse().unwrap())
764 }
765
766 pub fn set_recommends(&mut self, recommends: Option<&Relations>) {
768 if let Some(recommends) = recommends {
769 self.0.set("Recommends", recommends.to_string().as_str());
770 } else {
771 self.0.remove("Recommends");
772 }
773 }
774
775 pub fn suggests(&self) -> Option<Relations> {
777 self.0.get("Suggests").map(|s| s.parse().unwrap())
778 }
779
780 pub fn set_suggests(&mut self, suggests: Option<&Relations>) {
782 if let Some(suggests) = suggests {
783 self.0.set("Suggests", suggests.to_string().as_str());
784 } else {
785 self.0.remove("Suggests");
786 }
787 }
788
789 pub fn enhances(&self) -> Option<Relations> {
791 self.0.get("Enhances").map(|s| s.parse().unwrap())
792 }
793
794 pub fn set_enhances(&mut self, enhances: Option<&Relations>) {
796 if let Some(enhances) = enhances {
797 self.0.set("Enhances", enhances.to_string().as_str());
798 } else {
799 self.0.remove("Enhances");
800 }
801 }
802
803 pub fn pre_depends(&self) -> Option<Relations> {
805 self.0.get("Pre-Depends").map(|s| s.parse().unwrap())
806 }
807
808 pub fn set_pre_depends(&mut self, pre_depends: Option<&Relations>) {
810 if let Some(pre_depends) = pre_depends {
811 self.0.set("Pre-Depends", pre_depends.to_string().as_str());
812 } else {
813 self.0.remove("Pre-Depends");
814 }
815 }
816
817 pub fn breaks(&self) -> Option<Relations> {
819 self.0.get("Breaks").map(|s| s.parse().unwrap())
820 }
821
822 pub fn set_breaks(&mut self, breaks: Option<&Relations>) {
824 if let Some(breaks) = breaks {
825 self.0.set("Breaks", breaks.to_string().as_str());
826 } else {
827 self.0.remove("Breaks");
828 }
829 }
830
831 pub fn conflicts(&self) -> Option<Relations> {
833 self.0.get("Conflicts").map(|s| s.parse().unwrap())
834 }
835
836 pub fn set_conflicts(&mut self, conflicts: Option<&Relations>) {
838 if let Some(conflicts) = conflicts {
839 self.0.set("Conflicts", conflicts.to_string().as_str());
840 } else {
841 self.0.remove("Conflicts");
842 }
843 }
844
845 pub fn replaces(&self) -> Option<Relations> {
847 self.0.get("Replaces").map(|s| s.parse().unwrap())
848 }
849
850 pub fn set_replaces(&mut self, replaces: Option<&Relations>) {
852 if let Some(replaces) = replaces {
853 self.0.set("Replaces", replaces.to_string().as_str());
854 } else {
855 self.0.remove("Replaces");
856 }
857 }
858
859 pub fn provides(&self) -> Option<Relations> {
861 self.0.get("Provides").map(|s| s.parse().unwrap())
862 }
863
864 pub fn set_provides(&mut self, provides: Option<&Relations>) {
866 if let Some(provides) = provides {
867 self.0.set("Provides", provides.to_string().as_str());
868 } else {
869 self.0.remove("Provides");
870 }
871 }
872
873 pub fn built_using(&self) -> Option<Relations> {
875 self.0.get("Built-Using").map(|s| s.parse().unwrap())
876 }
877
878 pub fn set_built_using(&mut self, built_using: Option<&Relations>) {
880 if let Some(built_using) = built_using {
881 self.0.set("Built-Using", built_using.to_string().as_str());
882 } else {
883 self.0.remove("Built-Using");
884 }
885 }
886
887 pub fn multi_arch(&self) -> Option<MultiArch> {
889 self.0.get("Multi-Arch").map(|s| s.parse().unwrap())
890 }
891
892 pub fn set_multi_arch(&mut self, multi_arch: Option<MultiArch>) {
894 if let Some(multi_arch) = multi_arch {
895 self.0.set("Multi-Arch", multi_arch.to_string().as_str());
896 } else {
897 self.0.remove("Multi-Arch");
898 }
899 }
900
901 pub fn essential(&self) -> bool {
903 self.0.get("Essential").map(|s| s == "yes").unwrap_or(false)
904 }
905
906 pub fn set_essential(&mut self, essential: bool) {
908 if essential {
909 self.0.set("Essential", "yes");
910 } else {
911 self.0.remove("Essential");
912 }
913 }
914
915 pub fn description(&self) -> Option<String> {
917 self.0.get("Description")
918 }
919
920 pub fn set_description(&mut self, description: Option<&str>) {
922 if let Some(description) = description {
923 self.0.set("Description", description);
924 } else {
925 self.0.remove("Description");
926 }
927 }
928
929 pub fn homepage(&self) -> Option<url::Url> {
931 self.0.get("Homepage").and_then(|s| s.parse().ok())
932 }
933
934 pub fn set_homepage(&mut self, url: &url::Url) {
936 self.0.set("Homepage", url.as_str());
937 }
938}
939
940#[cfg(test)]
941mod tests {
942 use super::*;
943 use crate::relations::VersionConstraint;
944 #[test]
945 fn test_parse() {
946 let control: Control = r#"Source: foo
947Section: libs
948Priority: optional
949Build-Depends: bar (>= 1.0.0), baz (>= 1.0.0)
950Homepage: https://example.com
951
952"#
953 .parse()
954 .unwrap();
955 let source = control.source().unwrap();
956
957 assert_eq!(source.name(), Some("foo".to_owned()));
958 assert_eq!(source.section(), Some("libs".to_owned()));
959 assert_eq!(source.priority(), Some(super::Priority::Optional));
960 assert_eq!(
961 source.homepage(),
962 Some("https://example.com".parse().unwrap())
963 );
964 let bd = source.build_depends().unwrap();
965 let entries = bd.entries().collect::<Vec<_>>();
966 assert_eq!(entries.len(), 2);
967 let rel = entries[0].relations().collect::<Vec<_>>().pop().unwrap();
968 assert_eq!(rel.name(), "bar");
969 assert_eq!(
970 rel.version(),
971 Some((
972 VersionConstraint::GreaterThanEqual,
973 "1.0.0".parse().unwrap()
974 ))
975 );
976 let rel = entries[1].relations().collect::<Vec<_>>().pop().unwrap();
977 assert_eq!(rel.name(), "baz");
978 assert_eq!(
979 rel.version(),
980 Some((
981 VersionConstraint::GreaterThanEqual,
982 "1.0.0".parse().unwrap()
983 ))
984 );
985 }
986
987 #[test]
988 fn test_description() {
989 let control: Control = r#"Source: foo
990
991Package: foo
992Description: this is the short description
993 And the longer one
994 .
995 is on the next lines
996"#
997 .parse()
998 .unwrap();
999 let binary = control.binaries().next().unwrap();
1000 assert_eq!(
1001 binary.description(),
1002 Some(
1003 "this is the short description\nAnd the longer one\n.\nis on the next lines"
1004 .to_owned()
1005 )
1006 );
1007 }
1008
1009 #[test]
1010 fn test_as_mut_deb822() {
1011 let mut control = Control::new();
1012 let deb822 = control.as_mut_deb822();
1013 let mut p = deb822.add_paragraph();
1014 p.set("Source", "foo");
1015 assert_eq!(control.source().unwrap().name(), Some("foo".to_owned()));
1016 }
1017
1018 #[test]
1019 fn test_as_deb822() {
1020 let control = Control::new();
1021 let _deb822: &Deb822 = control.as_deb822();
1022 }
1023
1024 #[test]
1025 fn test_set_depends() {
1026 let mut control = Control::new();
1027 let mut binary = control.add_binary("foo");
1028 let relations: Relations = "bar (>= 1.0.0)".parse().unwrap();
1029 binary.set_depends(Some(&relations));
1030 }
1031
1032 #[test]
1033 fn test_wrap_and_sort() {
1034 let mut control: Control = r#"Package: blah
1035Section: libs
1036
1037
1038
1039Package: foo
1040Description: this is a
1041 bar
1042 blah
1043"#
1044 .parse()
1045 .unwrap();
1046 control.wrap_and_sort(deb822_lossless::Indentation::Spaces(2), false, None);
1047 let expected = r#"Package: blah
1048Section: libs
1049
1050Package: foo
1051Description: this is a
1052 bar
1053 blah
1054"#
1055 .to_owned();
1056 assert_eq!(control.to_string(), expected);
1057 }
1058
1059 #[test]
1060 fn test_wrap_and_sort_source() {
1061 let mut control: Control = r#"Source: blah
1062Depends: foo, bar (<= 1.0.0)
1063
1064"#
1065 .parse()
1066 .unwrap();
1067 control.wrap_and_sort(deb822_lossless::Indentation::Spaces(2), true, None);
1068 let expected = r#"Source: blah
1069Depends: bar (<= 1.0.0), foo
1070"#
1071 .to_owned();
1072 assert_eq!(control.to_string(), expected);
1073 }
1074}