1use crate::fields::{MultiArch, Priority};
36use crate::lossless::relations::Relations;
37use deb822_lossless::{Deb822, Paragraph};
38use rowan::ast::AstNode;
39
40fn format_field(name: &str, value: &str) -> String {
41 match name {
42 "Uploaders" => value
43 .split(',')
44 .map(|s| s.trim().to_string())
45 .collect::<Vec<_>>()
46 .join(",\n"),
47 "Build-Depends"
48 | "Build-Depends-Indep"
49 | "Build-Depends-Arch"
50 | "Build-Conflicts"
51 | "Build-Conflicts-Indep"
52 | "Build-Conflics-Arch"
53 | "Depends"
54 | "Recommends"
55 | "Suggests"
56 | "Enhances"
57 | "Pre-Depends"
58 | "Breaks" => {
59 let relations: Relations = value.parse().unwrap();
60 let relations = relations.wrap_and_sort();
61 relations.to_string()
62 }
63 _ => value.to_string(),
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
69pub struct Control(Deb822);
70
71impl Control {
72 pub fn new() -> Self {
74 Control(Deb822::new())
75 }
76
77 pub fn as_mut_deb822(&mut self) -> &mut Deb822 {
79 &mut self.0
80 }
81
82 pub fn as_deb822(&self) -> &Deb822 {
84 &self.0
85 }
86
87 pub fn parse(text: &str) -> deb822_lossless::Parse<Control> {
89 let deb822_parse = Deb822::parse(text);
90 let green = deb822_parse.green().clone();
92 let errors = deb822_parse.errors().to_vec();
93 deb822_lossless::Parse::new(green, errors)
94 }
95
96 pub fn source(&self) -> Option<Source> {
98 self.0
99 .paragraphs()
100 .find(|p| p.get("Source").is_some())
101 .map(Source)
102 }
103
104 pub fn binaries(&self) -> impl Iterator<Item = Binary> {
106 self.0
107 .paragraphs()
108 .filter(|p| p.get("Package").is_some())
109 .map(Binary)
110 }
111
112 pub fn add_source(&mut self, name: &str) -> Source {
128 let mut p = self.0.add_paragraph();
129 p.set("Source", name);
130 self.source().unwrap()
131 }
132
133 pub fn add_binary(&mut self, name: &str) -> Binary {
149 let mut p = self.0.add_paragraph();
150 p.set("Package", name);
151 Binary(p)
152 }
153
154 pub fn from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self, deb822_lossless::Error> {
156 Ok(Control(Deb822::from_file(path)?))
157 }
158
159 pub fn from_file_relaxed<P: AsRef<std::path::Path>>(
161 path: P,
162 ) -> Result<(Self, Vec<String>), std::io::Error> {
163 let (control, errors) = Deb822::from_file_relaxed(path)?;
164 Ok((Control(control), errors))
165 }
166
167 pub fn read<R: std::io::Read>(mut r: R) -> Result<Self, deb822_lossless::Error> {
169 Ok(Control(Deb822::read(&mut r)?))
170 }
171
172 pub fn read_relaxed<R: std::io::Read>(
174 mut r: R,
175 ) -> Result<(Self, Vec<String>), deb822_lossless::Error> {
176 let (control, errors) = Deb822::read_relaxed(&mut r)?;
177 Ok((Self(control), errors))
178 }
179
180 pub fn wrap_and_sort(
187 &mut self,
188 indentation: deb822_lossless::Indentation,
189 immediate_empty_line: bool,
190 max_line_length_one_liner: Option<usize>,
191 ) {
192 let sort_paragraphs = |a: &Paragraph, b: &Paragraph| -> std::cmp::Ordering {
193 let a_is_source = a.get("Source").is_some();
195 let b_is_source = b.get("Source").is_some();
196
197 if a_is_source && !b_is_source {
198 return std::cmp::Ordering::Less;
199 } else if !a_is_source && b_is_source {
200 return std::cmp::Ordering::Greater;
201 } else if a_is_source && b_is_source {
202 return a.get("Source").cmp(&b.get("Source"));
203 }
204
205 a.get("Package").cmp(&b.get("Package"))
206 };
207
208 let wrap_paragraph = |p: &Paragraph| -> Paragraph {
209 p.wrap_and_sort(
212 indentation,
213 immediate_empty_line,
214 max_line_length_one_liner,
215 None,
216 Some(&format_field),
217 )
218 };
219
220 self.0 = self
221 .0
222 .wrap_and_sort(Some(&sort_paragraphs), Some(&wrap_paragraph));
223 }
224}
225
226impl From<Control> for Deb822 {
227 fn from(c: Control) -> Self {
228 c.0
229 }
230}
231
232impl From<Deb822> for Control {
233 fn from(d: Deb822) -> Self {
234 Control(d)
235 }
236}
237
238impl Default for Control {
239 fn default() -> Self {
240 Self::new()
241 }
242}
243
244impl std::str::FromStr for Control {
245 type Err = deb822_lossless::ParseError;
246
247 fn from_str(s: &str) -> Result<Self, Self::Err> {
248 Control::parse(s).to_result()
249 }
250}
251
252#[derive(Debug, Clone, PartialEq, Eq)]
254pub struct Source(Paragraph);
255
256impl From<Source> for Paragraph {
257 fn from(s: Source) -> Self {
258 s.0
259 }
260}
261
262impl From<Paragraph> for Source {
263 fn from(p: Paragraph) -> Self {
264 Source(p)
265 }
266}
267
268impl std::fmt::Display for Source {
269 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
270 self.0.fmt(f)
271 }
272}
273
274impl Source {
275 pub fn name(&self) -> Option<String> {
277 self.0.get("Source")
278 }
279
280 pub fn wrap_and_sort(
282 &mut self,
283 indentation: deb822_lossless::Indentation,
284 immediate_empty_line: bool,
285 max_line_length_one_liner: Option<usize>,
286 ) {
287 self.0 = self.0.wrap_and_sort(
288 indentation,
289 immediate_empty_line,
290 max_line_length_one_liner,
291 None,
292 Some(&format_field),
293 );
294 }
295
296 pub fn as_mut_deb822(&mut self) -> &mut Paragraph {
298 &mut self.0
299 }
300
301 pub fn as_deb822(&self) -> &Paragraph {
303 &self.0
304 }
305
306 pub fn set_name(&mut self, name: &str) {
308 self.0.set("Source", name);
309 }
310
311 pub fn section(&self) -> Option<String> {
313 self.0.get("Section")
314 }
315
316 pub fn set_section(&mut self, section: Option<&str>) {
318 if let Some(section) = section {
319 self.0.set("Section", section);
320 } else {
321 self.0.remove("Section");
322 }
323 }
324
325 pub fn priority(&self) -> Option<Priority> {
327 self.0.get("Priority").and_then(|v| v.parse().ok())
328 }
329
330 pub fn set_priority(&mut self, priority: Option<Priority>) {
332 if let Some(priority) = priority {
333 self.0.set("Priority", priority.to_string().as_str());
334 } else {
335 self.0.remove("Priority");
336 }
337 }
338
339 pub fn maintainer(&self) -> Option<String> {
341 self.0.get("Maintainer")
342 }
343
344 pub fn set_maintainer(&mut self, maintainer: &str) {
346 self.0.set("Maintainer", maintainer);
347 }
348
349 pub fn build_depends(&self) -> Option<Relations> {
351 self.0.get("Build-Depends").map(|s| s.parse().unwrap())
352 }
353
354 pub fn set_build_depends(&mut self, relations: &Relations) {
356 self.0.set("Build-Depends", relations.to_string().as_str());
357 }
358
359 pub fn build_depends_indep(&self) -> Option<Relations> {
361 self.0
362 .get("Build-Depends-Indep")
363 .map(|s| s.parse().unwrap())
364 }
365
366 pub fn build_depends_arch(&self) -> Option<Relations> {
368 self.0.get("Build-Depends-Arch").map(|s| s.parse().unwrap())
369 }
370
371 pub fn build_conflicts(&self) -> Option<Relations> {
373 self.0.get("Build-Conflicts").map(|s| s.parse().unwrap())
374 }
375
376 pub fn build_conflicts_indep(&self) -> Option<Relations> {
378 self.0
379 .get("Build-Conflicts-Indep")
380 .map(|s| s.parse().unwrap())
381 }
382
383 pub fn build_conflicts_arch(&self) -> Option<Relations> {
385 self.0
386 .get("Build-Conflicts-Arch")
387 .map(|s| s.parse().unwrap())
388 }
389
390 pub fn standards_version(&self) -> Option<String> {
392 self.0.get("Standards-Version")
393 }
394
395 pub fn set_standards_version(&mut self, version: &str) {
397 self.0.set("Standards-Version", version);
398 }
399
400 pub fn homepage(&self) -> Option<url::Url> {
402 self.0.get("Homepage").and_then(|s| s.parse().ok())
403 }
404
405 pub fn set_homepage(&mut self, homepage: &url::Url) {
407 self.0.set("Homepage", homepage.to_string().as_str());
408 }
409
410 pub fn vcs_git(&self) -> Option<String> {
412 self.0.get("Vcs-Git")
413 }
414
415 pub fn set_vcs_git(&mut self, url: &str) {
417 self.0.set("Vcs-Git", url);
418 }
419
420 pub fn vcs_svn(&self) -> Option<String> {
422 self.0.get("Vcs-Svn").map(|s| s.to_string())
423 }
424
425 pub fn set_vcs_svn(&mut self, url: &str) {
427 self.0.set("Vcs-Svn", url);
428 }
429
430 pub fn vcs_bzr(&self) -> Option<String> {
432 self.0.get("Vcs-Bzr").map(|s| s.to_string())
433 }
434
435 pub fn set_vcs_bzr(&mut self, url: &str) {
437 self.0.set("Vcs-Bzr", url);
438 }
439
440 pub fn vcs_arch(&self) -> Option<String> {
442 self.0.get("Vcs-Arch").map(|s| s.to_string())
443 }
444
445 pub fn set_vcs_arch(&mut self, url: &str) {
447 self.0.set("Vcs-Arch", url);
448 }
449
450 pub fn vcs_svk(&self) -> Option<String> {
452 self.0.get("Vcs-Svk").map(|s| s.to_string())
453 }
454
455 pub fn set_vcs_svk(&mut self, url: &str) {
457 self.0.set("Vcs-Svk", url);
458 }
459
460 pub fn vcs_darcs(&self) -> Option<String> {
462 self.0.get("Vcs-Darcs").map(|s| s.to_string())
463 }
464
465 pub fn set_vcs_darcs(&mut self, url: &str) {
467 self.0.set("Vcs-Darcs", url);
468 }
469
470 pub fn vcs_mtn(&self) -> Option<String> {
472 self.0.get("Vcs-Mtn").map(|s| s.to_string())
473 }
474
475 pub fn set_vcs_mtn(&mut self, url: &str) {
477 self.0.set("Vcs-Mtn", url);
478 }
479
480 pub fn vcs_cvs(&self) -> Option<String> {
482 self.0.get("Vcs-Cvs").map(|s| s.to_string())
483 }
484
485 pub fn set_vcs_cvs(&mut self, url: &str) {
487 self.0.set("Vcs-Cvs", url);
488 }
489
490 pub fn vcs_hg(&self) -> Option<String> {
492 self.0.get("Vcs-Hg").map(|s| s.to_string())
493 }
494
495 pub fn set_vcs_hg(&mut self, url: &str) {
497 self.0.set("Vcs-Hg", url);
498 }
499
500 pub fn vcs_browser(&self) -> Option<String> {
502 self.0.get("Vcs-Browser")
503 }
504
505 pub fn vcs(&self) -> Option<crate::vcs::Vcs> {
507 for (name, value) in self.0.items() {
508 if name.starts_with("Vcs-") && name != "Vcs-Browser" {
509 return crate::vcs::Vcs::from_field(&name, &value).ok();
510 }
511 }
512 None
513 }
514
515 pub fn set_vcs_browser(&mut self, url: Option<&str>) {
517 if let Some(url) = url {
518 self.0.set("Vcs-Browser", url);
519 } else {
520 self.0.remove("Vcs-Browser");
521 }
522 }
523
524 pub fn uploaders(&self) -> Option<Vec<String>> {
526 self.0
527 .get("Uploaders")
528 .map(|s| s.split(',').map(|s| s.trim().to_owned()).collect())
529 }
530
531 pub fn set_uploaders(&mut self, uploaders: &[&str]) {
533 self.0.set(
534 "Uploaders",
535 uploaders
536 .iter()
537 .map(|s| s.to_string())
538 .collect::<Vec<_>>()
539 .join(", ")
540 .as_str(),
541 );
542 }
543
544 pub fn architecture(&self) -> Option<String> {
546 self.0.get("Architecture")
547 }
548
549 pub fn set_architecture(&mut self, arch: Option<&str>) {
551 if let Some(arch) = arch {
552 self.0.set("Architecture", arch);
553 } else {
554 self.0.remove("Architecture");
555 }
556 }
557
558 pub fn rules_requires_root(&self) -> Option<bool> {
560 self.0
561 .get("Rules-Requires-Root")
562 .map(|s| match s.to_lowercase().as_str() {
563 "yes" => true,
564 "no" => false,
565 _ => panic!("invalid Rules-Requires-Root value"),
566 })
567 }
568
569 pub fn set_rules_requires_root(&mut self, requires_root: bool) {
571 self.0.set(
572 "Rules-Requires-Root",
573 if requires_root { "yes" } else { "no" },
574 );
575 }
576
577 pub fn testsuite(&self) -> Option<String> {
579 self.0.get("Testsuite")
580 }
581
582 pub fn set_testsuite(&mut self, testsuite: &str) {
584 self.0.set("Testsuite", testsuite);
585 }
586}
587
588#[cfg(feature = "python-debian")]
589impl<'py> pyo3::IntoPyObject<'py> for Source {
590 type Target = pyo3::PyAny;
591 type Output = pyo3::Bound<'py, Self::Target>;
592 type Error = pyo3::PyErr;
593
594 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
595 self.0.into_pyobject(py)
596 }
597}
598
599#[cfg(feature = "python-debian")]
600impl<'a, 'py> pyo3::IntoPyObject<'py> for &'a Source {
601 type Target = pyo3::PyAny;
602 type Output = pyo3::Bound<'py, Self::Target>;
603 type Error = pyo3::PyErr;
604
605 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
606 (&self.0).into_pyobject(py)
607 }
608}
609
610#[cfg(feature = "python-debian")]
611impl pyo3::FromPyObject<'_> for Source {
612 fn extract_bound(ob: &pyo3::Bound<pyo3::PyAny>) -> pyo3::PyResult<Self> {
613 use pyo3::prelude::*;
614 Ok(Source(ob.extract()?))
615 }
616}
617
618impl std::fmt::Display for Control {
619 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
620 self.0.fmt(f)
621 }
622}
623
624impl AstNode for Control {
625 type Language = deb822_lossless::Lang;
626
627 fn can_cast(kind: <Self::Language as rowan::Language>::Kind) -> bool {
628 Deb822::can_cast(kind)
629 }
630
631 fn cast(syntax: rowan::SyntaxNode<Self::Language>) -> Option<Self> {
632 Deb822::cast(syntax).map(Control)
633 }
634
635 fn syntax(&self) -> &rowan::SyntaxNode<Self::Language> {
636 self.0.syntax()
637 }
638}
639
640#[derive(Debug, Clone, PartialEq, Eq)]
642pub struct Binary(Paragraph);
643
644impl From<Binary> for Paragraph {
645 fn from(b: Binary) -> Self {
646 b.0
647 }
648}
649
650impl From<Paragraph> for Binary {
651 fn from(p: Paragraph) -> Self {
652 Binary(p)
653 }
654}
655
656#[cfg(feature = "python-debian")]
657impl<'py> pyo3::IntoPyObject<'py> for Binary {
658 type Target = pyo3::PyAny;
659 type Output = pyo3::Bound<'py, Self::Target>;
660 type Error = pyo3::PyErr;
661
662 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
663 self.0.into_pyobject(py)
664 }
665}
666
667#[cfg(feature = "python-debian")]
668impl<'a, 'py> pyo3::IntoPyObject<'py> for &'a Binary {
669 type Target = pyo3::PyAny;
670 type Output = pyo3::Bound<'py, Self::Target>;
671 type Error = pyo3::PyErr;
672
673 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
674 (&self.0).into_pyobject(py)
675 }
676}
677
678#[cfg(feature = "python-debian")]
679impl pyo3::FromPyObject<'_> for Binary {
680 fn extract_bound(ob: &pyo3::Bound<pyo3::PyAny>) -> pyo3::PyResult<Self> {
681 use pyo3::prelude::*;
682 Ok(Binary(ob.extract()?))
683 }
684}
685
686impl Default for Binary {
687 fn default() -> Self {
688 Self::new()
689 }
690}
691
692impl Binary {
693 pub fn new() -> Self {
695 Binary(Paragraph::new())
696 }
697
698 pub fn as_mut_deb822(&mut self) -> &mut Paragraph {
700 &mut self.0
701 }
702
703 pub fn as_deb822(&self) -> &Paragraph {
705 &self.0
706 }
707
708 pub fn wrap_and_sort(
710 &mut self,
711 indentation: deb822_lossless::Indentation,
712 immediate_empty_line: bool,
713 max_line_length_one_liner: Option<usize>,
714 ) {
715 self.0 = self.0.wrap_and_sort(
716 indentation,
717 immediate_empty_line,
718 max_line_length_one_liner,
719 None,
720 Some(&format_field),
721 );
722 }
723
724 pub fn name(&self) -> Option<String> {
726 self.0.get("Package")
727 }
728
729 pub fn set_name(&mut self, name: &str) {
731 self.0.set("Package", name);
732 }
733
734 pub fn section(&self) -> Option<String> {
736 self.0.get("Section")
737 }
738
739 pub fn set_section(&mut self, section: Option<&str>) {
741 if let Some(section) = section {
742 self.0.set("Section", section);
743 } else {
744 self.0.remove("Section");
745 }
746 }
747
748 pub fn priority(&self) -> Option<Priority> {
750 self.0.get("Priority").and_then(|v| v.parse().ok())
751 }
752
753 pub fn set_priority(&mut self, priority: Option<Priority>) {
755 if let Some(priority) = priority {
756 self.0.set("Priority", priority.to_string().as_str());
757 } else {
758 self.0.remove("Priority");
759 }
760 }
761
762 pub fn architecture(&self) -> Option<String> {
764 self.0.get("Architecture")
765 }
766
767 pub fn set_architecture(&mut self, arch: Option<&str>) {
769 if let Some(arch) = arch {
770 self.0.set("Architecture", arch);
771 } else {
772 self.0.remove("Architecture");
773 }
774 }
775
776 pub fn depends(&self) -> Option<Relations> {
778 self.0.get("Depends").map(|s| s.parse().unwrap())
779 }
780
781 pub fn set_depends(&mut self, depends: Option<&Relations>) {
783 if let Some(depends) = depends {
784 self.0.set("Depends", depends.to_string().as_str());
785 } else {
786 self.0.remove("Depends");
787 }
788 }
789
790 pub fn recommends(&self) -> Option<Relations> {
792 self.0.get("Recommends").map(|s| s.parse().unwrap())
793 }
794
795 pub fn set_recommends(&mut self, recommends: Option<&Relations>) {
797 if let Some(recommends) = recommends {
798 self.0.set("Recommends", recommends.to_string().as_str());
799 } else {
800 self.0.remove("Recommends");
801 }
802 }
803
804 pub fn suggests(&self) -> Option<Relations> {
806 self.0.get("Suggests").map(|s| s.parse().unwrap())
807 }
808
809 pub fn set_suggests(&mut self, suggests: Option<&Relations>) {
811 if let Some(suggests) = suggests {
812 self.0.set("Suggests", suggests.to_string().as_str());
813 } else {
814 self.0.remove("Suggests");
815 }
816 }
817
818 pub fn enhances(&self) -> Option<Relations> {
820 self.0.get("Enhances").map(|s| s.parse().unwrap())
821 }
822
823 pub fn set_enhances(&mut self, enhances: Option<&Relations>) {
825 if let Some(enhances) = enhances {
826 self.0.set("Enhances", enhances.to_string().as_str());
827 } else {
828 self.0.remove("Enhances");
829 }
830 }
831
832 pub fn pre_depends(&self) -> Option<Relations> {
834 self.0.get("Pre-Depends").map(|s| s.parse().unwrap())
835 }
836
837 pub fn set_pre_depends(&mut self, pre_depends: Option<&Relations>) {
839 if let Some(pre_depends) = pre_depends {
840 self.0.set("Pre-Depends", pre_depends.to_string().as_str());
841 } else {
842 self.0.remove("Pre-Depends");
843 }
844 }
845
846 pub fn breaks(&self) -> Option<Relations> {
848 self.0.get("Breaks").map(|s| s.parse().unwrap())
849 }
850
851 pub fn set_breaks(&mut self, breaks: Option<&Relations>) {
853 if let Some(breaks) = breaks {
854 self.0.set("Breaks", breaks.to_string().as_str());
855 } else {
856 self.0.remove("Breaks");
857 }
858 }
859
860 pub fn conflicts(&self) -> Option<Relations> {
862 self.0.get("Conflicts").map(|s| s.parse().unwrap())
863 }
864
865 pub fn set_conflicts(&mut self, conflicts: Option<&Relations>) {
867 if let Some(conflicts) = conflicts {
868 self.0.set("Conflicts", conflicts.to_string().as_str());
869 } else {
870 self.0.remove("Conflicts");
871 }
872 }
873
874 pub fn replaces(&self) -> Option<Relations> {
876 self.0.get("Replaces").map(|s| s.parse().unwrap())
877 }
878
879 pub fn set_replaces(&mut self, replaces: Option<&Relations>) {
881 if let Some(replaces) = replaces {
882 self.0.set("Replaces", replaces.to_string().as_str());
883 } else {
884 self.0.remove("Replaces");
885 }
886 }
887
888 pub fn provides(&self) -> Option<Relations> {
890 self.0.get("Provides").map(|s| s.parse().unwrap())
891 }
892
893 pub fn set_provides(&mut self, provides: Option<&Relations>) {
895 if let Some(provides) = provides {
896 self.0.set("Provides", provides.to_string().as_str());
897 } else {
898 self.0.remove("Provides");
899 }
900 }
901
902 pub fn built_using(&self) -> Option<Relations> {
904 self.0.get("Built-Using").map(|s| s.parse().unwrap())
905 }
906
907 pub fn set_built_using(&mut self, built_using: Option<&Relations>) {
909 if let Some(built_using) = built_using {
910 self.0.set("Built-Using", built_using.to_string().as_str());
911 } else {
912 self.0.remove("Built-Using");
913 }
914 }
915
916 pub fn multi_arch(&self) -> Option<MultiArch> {
918 self.0.get("Multi-Arch").map(|s| s.parse().unwrap())
919 }
920
921 pub fn set_multi_arch(&mut self, multi_arch: Option<MultiArch>) {
923 if let Some(multi_arch) = multi_arch {
924 self.0.set("Multi-Arch", multi_arch.to_string().as_str());
925 } else {
926 self.0.remove("Multi-Arch");
927 }
928 }
929
930 pub fn essential(&self) -> bool {
932 self.0.get("Essential").map(|s| s == "yes").unwrap_or(false)
933 }
934
935 pub fn set_essential(&mut self, essential: bool) {
937 if essential {
938 self.0.set("Essential", "yes");
939 } else {
940 self.0.remove("Essential");
941 }
942 }
943
944 pub fn description(&self) -> Option<String> {
946 self.0.get("Description")
947 }
948
949 pub fn set_description(&mut self, description: Option<&str>) {
951 if let Some(description) = description {
952 self.0.set("Description", description);
953 } else {
954 self.0.remove("Description");
955 }
956 }
957
958 pub fn homepage(&self) -> Option<url::Url> {
960 self.0.get("Homepage").and_then(|s| s.parse().ok())
961 }
962
963 pub fn set_homepage(&mut self, url: &url::Url) {
965 self.0.set("Homepage", url.as_str());
966 }
967}
968
969#[cfg(test)]
970mod tests {
971 use super::*;
972 use crate::relations::VersionConstraint;
973 #[test]
974 fn test_parse() {
975 let control: Control = r#"Source: foo
976Section: libs
977Priority: optional
978Build-Depends: bar (>= 1.0.0), baz (>= 1.0.0)
979Homepage: https://example.com
980
981"#
982 .parse()
983 .unwrap();
984 let source = control.source().unwrap();
985
986 assert_eq!(source.name(), Some("foo".to_owned()));
987 assert_eq!(source.section(), Some("libs".to_owned()));
988 assert_eq!(source.priority(), Some(super::Priority::Optional));
989 assert_eq!(
990 source.homepage(),
991 Some("https://example.com".parse().unwrap())
992 );
993 let bd = source.build_depends().unwrap();
994 let entries = bd.entries().collect::<Vec<_>>();
995 assert_eq!(entries.len(), 2);
996 let rel = entries[0].relations().collect::<Vec<_>>().pop().unwrap();
997 assert_eq!(rel.name(), "bar");
998 assert_eq!(
999 rel.version(),
1000 Some((
1001 VersionConstraint::GreaterThanEqual,
1002 "1.0.0".parse().unwrap()
1003 ))
1004 );
1005 let rel = entries[1].relations().collect::<Vec<_>>().pop().unwrap();
1006 assert_eq!(rel.name(), "baz");
1007 assert_eq!(
1008 rel.version(),
1009 Some((
1010 VersionConstraint::GreaterThanEqual,
1011 "1.0.0".parse().unwrap()
1012 ))
1013 );
1014 }
1015
1016 #[test]
1017 fn test_description() {
1018 let control: Control = r#"Source: foo
1019
1020Package: foo
1021Description: this is the short description
1022 And the longer one
1023 .
1024 is on the next lines
1025"#
1026 .parse()
1027 .unwrap();
1028 let binary = control.binaries().next().unwrap();
1029 assert_eq!(
1030 binary.description(),
1031 Some(
1032 "this is the short description\nAnd the longer one\n.\nis on the next lines"
1033 .to_owned()
1034 )
1035 );
1036 }
1037
1038 #[test]
1039 fn test_as_mut_deb822() {
1040 let mut control = Control::new();
1041 let deb822 = control.as_mut_deb822();
1042 let mut p = deb822.add_paragraph();
1043 p.set("Source", "foo");
1044 assert_eq!(control.source().unwrap().name(), Some("foo".to_owned()));
1045 }
1046
1047 #[test]
1048 fn test_as_deb822() {
1049 let control = Control::new();
1050 let _deb822: &Deb822 = control.as_deb822();
1051 }
1052
1053 #[test]
1054 fn test_set_depends() {
1055 let mut control = Control::new();
1056 let mut binary = control.add_binary("foo");
1057 let relations: Relations = "bar (>= 1.0.0)".parse().unwrap();
1058 binary.set_depends(Some(&relations));
1059 }
1060
1061 #[test]
1062 fn test_wrap_and_sort() {
1063 let mut control: Control = r#"Package: blah
1064Section: libs
1065
1066
1067
1068Package: foo
1069Description: this is a
1070 bar
1071 blah
1072"#
1073 .parse()
1074 .unwrap();
1075 control.wrap_and_sort(deb822_lossless::Indentation::Spaces(2), false, None);
1076 let expected = r#"Package: blah
1077Section: libs
1078
1079Package: foo
1080Description: this is a
1081 bar
1082 blah
1083"#
1084 .to_owned();
1085 assert_eq!(control.to_string(), expected);
1086 }
1087
1088 #[test]
1089 fn test_wrap_and_sort_source() {
1090 let mut control: Control = r#"Source: blah
1091Depends: foo, bar (<= 1.0.0)
1092
1093"#
1094 .parse()
1095 .unwrap();
1096 control.wrap_and_sort(deb822_lossless::Indentation::Spaces(2), true, None);
1097 let expected = r#"Source: blah
1098Depends: bar (<= 1.0.0), foo
1099"#
1100 .to_owned();
1101 assert_eq!(control.to_string(), expected);
1102 }
1103
1104 #[test]
1105 fn test_source_wrap_and_sort() {
1106 let control: Control = r#"Source: blah
1107Build-Depends: foo, bar (>= 1.0.0)
1108
1109"#
1110 .parse()
1111 .unwrap();
1112 let mut source = control.source().unwrap();
1113 source.wrap_and_sort(deb822_lossless::Indentation::Spaces(2), true, None);
1114 assert!(source.build_depends().is_some());
1118 }
1119
1120 #[test]
1121 fn test_binary_set_breaks() {
1122 let mut control = Control::new();
1123 let mut binary = control.add_binary("foo");
1124 let relations: Relations = "bar (>= 1.0.0)".parse().unwrap();
1125 binary.set_breaks(Some(&relations));
1126 assert!(binary.breaks().is_some());
1127 }
1128
1129 #[test]
1130 fn test_binary_set_pre_depends() {
1131 let mut control = Control::new();
1132 let mut binary = control.add_binary("foo");
1133 let relations: Relations = "bar (>= 1.0.0)".parse().unwrap();
1134 binary.set_pre_depends(Some(&relations));
1135 assert!(binary.pre_depends().is_some());
1136 }
1137
1138 #[test]
1139 fn test_binary_set_provides() {
1140 let mut control = Control::new();
1141 let mut binary = control.add_binary("foo");
1142 let relations: Relations = "bar (>= 1.0.0)".parse().unwrap();
1143 binary.set_provides(Some(&relations));
1144 assert!(binary.provides().is_some());
1145 }
1146
1147 #[test]
1148 fn test_source_build_conflicts() {
1149 let control: Control = r#"Source: blah
1150Build-Conflicts: foo, bar (>= 1.0.0)
1151
1152"#
1153 .parse()
1154 .unwrap();
1155 let source = control.source().unwrap();
1156 let conflicts = source.build_conflicts();
1157 assert!(conflicts.is_some());
1158 }
1159
1160 #[test]
1161 fn test_source_vcs_svn() {
1162 let control: Control = r#"Source: blah
1163Vcs-Svn: https://example.com/svn/repo
1164
1165"#
1166 .parse()
1167 .unwrap();
1168 let source = control.source().unwrap();
1169 assert_eq!(
1170 source.vcs_svn(),
1171 Some("https://example.com/svn/repo".to_string())
1172 );
1173 }
1174
1175 #[test]
1176 fn test_control_from_conversion() {
1177 let deb822_data = r#"Source: test
1178Section: libs
1179
1180"#;
1181 let deb822: Deb822 = deb822_data.parse().unwrap();
1182 let control = Control::from(deb822);
1183 assert!(control.source().is_some());
1184 }
1185}