1use crate::lossy::{Relations, SourceRelation};
3use deb822_fast::{FromDeb822, FromDeb822Paragraph, ToDeb822, ToDeb822Paragraph};
4
5fn deserialize_yesno(s: &str) -> Result<bool, String> {
6 match s {
7 "yes" => Ok(true),
8 "no" => Ok(false),
9 _ => Err(format!("invalid value for yesno: {}", s)),
10 }
11}
12
13fn serialize_yesno(b: &bool) -> String {
14 if *b {
15 "yes".to_string()
16 } else {
17 "no".to_string()
18 }
19}
20
21fn deserialize_components(value: &str) -> Result<Vec<String>, String> {
22 Ok(value.split_whitespace().map(|s| s.to_string()).collect())
23}
24
25fn join_whitespace(components: &[String]) -> String {
26 components.join(" ")
27}
28
29fn deserialize_architectures(value: &str) -> Result<Vec<String>, String> {
30 Ok(value.split_whitespace().map(|s| s.to_string()).collect())
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, ToDeb822, FromDeb822)]
34pub struct Release {
36 #[deb822(field = "Codename")]
37 pub codename: Option<String>,
39
40 #[deb822(
41 field = "Components",
42 deserialize_with = deserialize_components,
43 serialize_with = join_whitespace
44 )]
45 pub components: Vec<String>,
47
48 #[deb822(
49 field = "Architectures",
50 deserialize_with = deserialize_architectures,
51 serialize_with = join_whitespace
52 )]
53 pub architectures: Vec<String>,
55
56 #[deb822(field = "Description")]
57 pub description: Option<String>,
59
60 #[deb822(field = "Origin")]
61 pub origin: Option<String>,
63
64 #[deb822(field = "Label")]
65 pub label: Option<String>,
67
68 #[deb822(field = "Suite")]
69 pub suite: Option<String>,
71
72 #[deb822(field = "Version")]
73 pub version: Option<String>,
75
76 #[deb822(field = "Date")]
77 pub date: Option<String>,
79
80 #[deb822(field = "NotAutomatic", deserialize_with = deserialize_yesno, serialize_with = serialize_yesno)]
81 pub not_automatic: Option<bool>,
83
84 #[deb822(field = "ButAutomaticUpgrades", deserialize_with = deserialize_yesno, serialize_with = serialize_yesno)]
85 pub but_automatic_upgrades: Option<bool>,
87
88 #[deb822(field = "Acquire-By-Hash", deserialize_with = deserialize_yesno, serialize_with = serialize_yesno)]
89 pub acquire_by_hash: Option<bool>,
91
92 #[deb822(field = "MD5Sum", deserialize_with = deserialize_checksums::<crate::fields::Md5Checksum>, serialize_with = serialize_checksums::<crate::fields::Md5Checksum>)]
93 pub checksums_md5: Option<Vec<crate::fields::Md5Checksum>>,
95
96 #[deb822(field = "SHA1", deserialize_with = deserialize_checksums::<crate::fields::Sha1Checksum>, serialize_with = serialize_checksums::<crate::fields::Sha1Checksum>)]
97 pub checksums_sha1: Option<Vec<crate::fields::Sha1Checksum>>,
99
100 #[deb822(field = "SHA256", deserialize_with = deserialize_checksums::<crate::fields::Sha256Checksum>, serialize_with = serialize_checksums::<crate::fields::Sha256Checksum>)]
101 pub checksums_sha256: Option<Vec<crate::fields::Sha256Checksum>>,
103
104 #[deb822(field = "SHA512", deserialize_with = deserialize_checksums::<crate::fields::Sha512Checksum>, serialize_with = serialize_checksums::<crate::fields::Sha512Checksum>)]
105 pub checksums_sha512: Option<Vec<crate::fields::Sha512Checksum>>,
107}
108
109impl std::str::FromStr for Release {
110 type Err = String;
111
112 fn from_str(s: &str) -> Result<Self, Self::Err> {
113 let para = s
114 .parse::<deb822_fast::Paragraph>()
115 .map_err(|e| e.to_string())?;
116 FromDeb822Paragraph::from_paragraph(¶)
117 }
118}
119
120impl std::fmt::Display for Release {
121 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
122 let para: deb822_fast::Paragraph = self.to_paragraph();
123 write!(f, "{}", para)
124 }
125}
126
127fn deserialize_binaries(value: &str) -> Result<Vec<String>, String> {
128 Ok(value.split(",").map(|s| s.trim().to_string()).collect())
129}
130
131fn deserialize_testsuite_triggers(value: &str) -> Result<Vec<String>, String> {
132 Ok(value.split(",").map(|s| s.trim().to_string()).collect())
133}
134
135fn join_lines(components: &[String]) -> String {
136 components.join("\n")
137}
138
139fn deserialize_package_list(value: &str) -> Result<Vec<String>, String> {
140 Ok(value
141 .split('\n')
142 .map(|s| s.trim().to_string())
143 .filter(|s| !s.is_empty())
144 .collect())
145}
146
147fn deserialize_checksums<T>(value: &str) -> Result<Vec<T>, String>
148where
149 T: std::str::FromStr,
150 T::Err: std::fmt::Display,
151{
152 value
153 .lines()
154 .map(|s| s.trim())
155 .filter(|s| !s.is_empty())
156 .map(|s| s.parse::<T>().map_err(|e| e.to_string()))
157 .collect()
158}
159
160fn serialize_checksums<T: std::fmt::Display>(checksums: &[T]) -> String {
161 checksums
162 .iter()
163 .map(|c| format!(" {}", c))
164 .collect::<Vec<_>>()
165 .join("\n")
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, ToDeb822, FromDeb822)]
169pub struct Source {
171 #[deb822(field = "Directory")]
172 pub directory: String,
174
175 #[deb822(field = "Description")]
176 pub description: Option<String>,
178
179 #[deb822(field = "Version")]
180 pub version: debversion::Version,
182
183 #[deb822(field = "Package")]
184 pub package: String,
186
187 #[deb822(field = "Binary", deserialize_with = deserialize_binaries, serialize_with = join_whitespace)]
188 pub binaries: Option<Vec<String>>,
190
191 #[deb822(field = "Maintainer")]
192 pub maintainer: Option<String>,
194
195 #[deb822(field = "Uploaders")]
196 pub uploaders: Option<String>,
198
199 #[deb822(field = "Build-Depends")]
200 pub build_depends: Option<Relations>,
202
203 #[deb822(field = "Build-Depends-Indep")]
204 pub build_depends_indep: Option<Relations>,
206
207 #[deb822(field = "Build-Depends-Arch")]
208 pub build_depends_arch: Option<Relations>,
210
211 #[deb822(field = "Build-Conflicts")]
212 pub build_conflicts: Option<Relations>,
214
215 #[deb822(field = "Build-Conflicts-Indep")]
216 pub build_conflicts_indep: Option<Relations>,
218
219 #[deb822(field = "Build-Conflicts-Arch")]
220 pub build_conflicts_arch: Option<Relations>,
222
223 #[deb822(field = "Standards-Version")]
224 pub standards_version: Option<String>,
226
227 #[deb822(field = "Homepage")]
228 pub homepage: Option<String>,
230
231 #[deb822(field = "Autobuild")]
232 pub autobuild: Option<bool>,
234
235 #[deb822(field = "Extra-Source-Only", deserialize_with = deserialize_yesno, serialize_with = serialize_yesno)]
236 pub extra_source_only: Option<bool>,
238
239 #[deb822(field = "Testsuite")]
240 pub testsuite: Option<String>,
242
243 #[deb822(field = "Testsuite-Triggers", deserialize_with = deserialize_testsuite_triggers, serialize_with = join_whitespace)]
244 pub testsuite_triggers: Option<Vec<String>>,
246
247 #[deb822(field = "Vcs-Browser")]
248 pub vcs_browser: Option<String>,
250
251 #[deb822(field = "Vcs-Git")]
252 pub vcs_git: Option<String>,
254
255 #[deb822(field = "Vcs-Bzr")]
256 pub vcs_bzr: Option<String>,
258
259 #[deb822(field = "Vcs-Hg")]
260 pub vcs_hg: Option<String>,
262
263 #[deb822(field = "Vcs-Svn")]
264 pub vcs_svn: Option<String>,
266
267 #[deb822(field = "Vcs-Darcs")]
268 pub vcs_darcs: Option<String>,
270
271 #[deb822(field = "Vcs-Cvs")]
272 pub vcs_cvs: Option<String>,
274
275 #[deb822(field = "Vcs-Arch")]
276 pub vcs_arch: Option<String>,
278
279 #[deb822(field = "Vcs-Mtn")]
280 pub vcs_mtn: Option<String>,
282
283 #[deb822(field = "Dgit")]
284 pub dgit: Option<crate::fields::DgitInfo>,
286
287 #[deb822(field = "Priority")]
288 pub priority: Option<crate::fields::Priority>,
290
291 #[deb822(field = "Section")]
292 pub section: Option<String>,
294
295 #[deb822(field = "Format")]
296 pub format: Option<String>,
298
299 #[deb822(field = "Architecture")]
300 pub architecture: Option<String>,
302
303 #[deb822(field = "Package-List", deserialize_with = deserialize_package_list, serialize_with = join_lines)]
304 pub package_list: Option<Vec<String>>,
306
307 #[deb822(field = "Files", deserialize_with = deserialize_checksums::<crate::fields::Md5Checksum>, serialize_with = serialize_checksums::<crate::fields::Md5Checksum>)]
308 pub files: Option<Vec<crate::fields::Md5Checksum>>,
310
311 #[deb822(field = "Checksums-Sha1", deserialize_with = deserialize_checksums::<crate::fields::Sha1Checksum>, serialize_with = serialize_checksums::<crate::fields::Sha1Checksum>)]
312 pub checksums_sha1: Option<Vec<crate::fields::Sha1Checksum>>,
314
315 #[deb822(field = "Checksums-Sha256", deserialize_with = deserialize_checksums::<crate::fields::Sha256Checksum>, serialize_with = serialize_checksums::<crate::fields::Sha256Checksum>)]
316 pub checksums_sha256: Option<Vec<crate::fields::Sha256Checksum>>,
318
319 #[deb822(field = "Checksums-Sha512", deserialize_with = deserialize_checksums::<crate::fields::Sha512Checksum>, serialize_with = serialize_checksums::<crate::fields::Sha512Checksum>)]
320 pub checksums_sha512: Option<Vec<crate::fields::Sha512Checksum>>,
322}
323
324impl std::str::FromStr for Source {
325 type Err = String;
326
327 fn from_str(s: &str) -> Result<Self, Self::Err> {
328 let para = s
329 .parse::<deb822_fast::Paragraph>()
330 .map_err(|e| e.to_string())?;
331
332 FromDeb822Paragraph::from_paragraph(¶)
333 }
334}
335
336impl std::fmt::Display for Source {
337 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
338 let para: deb822_fast::Paragraph = self.to_paragraph();
339 write!(f, "{}", para)
340 }
341}
342
343#[derive(Debug, Clone, PartialEq, Eq, ToDeb822, FromDeb822)]
345pub struct Package {
346 #[deb822(field = "Package")]
348 pub name: String,
349
350 #[deb822(field = "Version")]
352 pub version: debversion::Version,
353
354 #[deb822(field = "Source")]
356 pub source: Option<SourceRelation>,
357
358 #[deb822(field = "Architecture")]
360 pub architecture: String,
361
362 #[deb822(field = "Maintainer")]
364 pub maintainer: Option<String>,
365
366 #[deb822(field = "Installed-Size")]
368 pub installed_size: Option<usize>,
369
370 #[deb822(field = "Depends")]
372 pub depends: Option<Relations>,
373
374 #[deb822(field = "Pre-Depends")]
376 pub pre_depends: Option<Relations>,
377
378 #[deb822(field = "Recommends")]
380 pub recommends: Option<Relations>,
381
382 #[deb822(field = "Suggests")]
384 pub suggests: Option<Relations>,
385
386 #[deb822(field = "Enhances")]
388 pub enhances: Option<Relations>,
389
390 #[deb822(field = "Breaks")]
392 pub breaks: Option<Relations>,
393
394 #[deb822(field = "Conflicts")]
396 pub conflicts: Option<Relations>,
397
398 #[deb822(field = "Provides")]
400 pub provides: Option<Relations>,
401
402 #[deb822(field = "Replaces")]
404 pub replaces: Option<Relations>,
405
406 #[deb822(field = "Built-Using")]
408 pub built_using: Option<Relations>,
409
410 #[deb822(field = "Static-Built-Using")]
412 pub static_built_using: Option<Relations>,
413
414 #[deb822(field = "Description")]
416 pub description: Option<String>,
417
418 #[deb822(field = "Homepage")]
420 pub homepage: Option<String>,
421
422 #[deb822(field = "Origin")]
424 pub origin: Option<String>,
425
426 #[deb822(field = "Priority")]
428 pub priority: Option<crate::fields::Priority>,
429
430 #[deb822(field = "Section")]
432 pub section: Option<String>,
433
434 #[deb822(field = "Essential", deserialize_with = deserialize_yesno, serialize_with = serialize_yesno)]
436 pub essential: Option<bool>,
437
438 #[deb822(field = "Multi-Arch")]
440 pub multi_arch: Option<crate::fields::MultiArch>,
441
442 #[deb822(field = "Tag")]
444 pub tag: Option<String>,
445
446 #[deb822(field = "Task")]
448 pub task: Option<String>,
449
450 #[deb822(field = "Size")]
452 pub size: Option<usize>,
453
454 #[deb822(field = "Filename")]
456 pub filename: Option<String>,
457
458 #[deb822(field = "MD5sum")]
460 pub md5sum: Option<String>,
461
462 #[deb822(field = "SHA1")]
464 pub sha1: Option<String>,
465
466 #[deb822(field = "SHA256")]
468 pub sha256: Option<String>,
469
470 #[deb822(field = "SHA512")]
472 pub sha512: Option<String>,
473
474 #[deb822(field = "Description-MD5")]
476 pub description_md5: Option<String>,
477}
478
479impl std::str::FromStr for Package {
480 type Err = String;
481
482 fn from_str(s: &str) -> Result<Self, Self::Err> {
483 let para = s
484 .parse::<deb822_fast::Paragraph>()
485 .map_err(|e| e.to_string())?;
486
487 FromDeb822Paragraph::from_paragraph(¶)
488 }
489}
490
491impl std::fmt::Display for Package {
492 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
493 let para: deb822_fast::Paragraph = self.to_paragraph();
494 write!(f, "{}", para)
495 }
496}
497
498#[cfg(test)]
499mod tests {
500 use super::*;
501 use deb822_fast::Paragraph;
502 use deb822_fast::ToDeb822Paragraph;
503
504 #[test]
505 fn test_release() {
506 let release = Release {
507 codename: Some("focal".to_string()),
508 components: vec!["main".to_string(), "restricted".to_string()],
509 architectures: vec!["amd64".to_string(), "arm64".to_string()],
510 description: Some("Ubuntu 20.04 LTS".to_string()),
511 origin: Some("Ubuntu".to_string()),
512 label: Some("Ubuntu".to_string()),
513 suite: Some("focal".to_string()),
514 version: Some("20.04".to_string()),
515 date: Some("Thu, 23 Apr 2020 17:19:19 UTC".to_string()),
516 not_automatic: Some(false),
517 but_automatic_upgrades: Some(true),
518 acquire_by_hash: Some(true),
519 checksums_md5: None,
520 checksums_sha1: None,
521 checksums_sha256: None,
522 checksums_sha512: None,
523 };
524
525 let deb822 = r#"Codename: focal
526Components: main restricted
527Architectures: amd64 arm64
528Description: Ubuntu 20.04 LTS
529Origin: Ubuntu
530Label: Ubuntu
531Suite: focal
532Version: 20.04
533Date: Thu, 23 Apr 2020 17:19:19 UTC
534NotAutomatic: no
535ButAutomaticUpgrades: yes
536Acquire-By-Hash: yes
537"#;
538
539 let para = deb822.parse::<Paragraph>().unwrap();
540
541 let release: deb822_fast::Paragraph = release.to_paragraph();
542
543 assert_eq!(release, para);
544 }
545
546 #[test]
547 fn test_package() {
548 let package = r#"Package: apt
549Version: 2.1.10
550Architecture: amd64
551Maintainer: APT Development Team <apt@lists.debian.org>
552Installed-Size: 3524
553Depends: libc6 (>= 2.14), libgcc1
554Pre-Depends: dpkg (>= 1.15.6)
555Recommends: gnupg
556Suggests: apt-doc, aptitude | synaptic | wajig
557"#;
558
559 let package: Package = package.parse().unwrap();
560
561 assert_eq!(package.name, "apt");
562 assert_eq!(package.version, "2.1.10".parse().unwrap());
563 assert_eq!(package.architecture, "amd64");
564 }
565
566 #[test]
567 fn test_package_essential() {
568 let package = r#"Package: base-files
569Version: 11.1
570Architecture: amd64
571Essential: yes
572"#;
573
574 let package: Package = package.parse().unwrap();
575
576 assert_eq!(package.name, "base-files");
577 assert_eq!(package.essential, Some(true));
578 }
579
580 #[test]
581 fn test_package_essential_no() {
582 let package = r#"Package: apt
583Version: 2.1.10
584Architecture: amd64
585Essential: no
586"#;
587
588 let package: Package = package.parse().unwrap();
589
590 assert_eq!(package.name, "apt");
591 assert_eq!(package.essential, Some(false));
592 }
593
594 #[test]
595 fn test_package_with_different_source() {
596 let package = r#"Package: apt
597Source: not-apt (1.1.5)
598Version: 2.1.10
599Architecture: amd64
600Maintainer: APT Development Team <apt@lists.debian.org>
601Installed-Size: 3524
602Depends: libc6 (>= 2.14), libgcc1
603Pre-Depends: dpkg (>= 1.15.6)
604Recommends: gnupg
605Suggests: apt-doc, aptitude | synaptic | wajig
606"#;
607
608 let package: Package = package.parse().unwrap();
609
610 assert_eq!(package.name, "apt");
611 assert_eq!(package.version, "2.1.10".parse().unwrap());
612 assert_eq!(package.architecture, "amd64");
613 assert_eq!(
614 package.source,
615 Some(SourceRelation {
616 name: "not-apt".to_string(),
617 version: Some("1.1.5".parse().unwrap())
618 })
619 );
620 }
621
622 #[test]
623 fn test_source() {
624 let source = r#"Package: abinit
625Binary: abinit, abinit-doc, abinit-data
626Version: 9.10.4-3
627Maintainer: Debichem Team <debichem-devel@lists.alioth.debian.org>
628Uploaders: Andreas Tille <tille@debian.org>, Michael Banck <mbanck@debian.org>
629Build-Depends: debhelper (>= 11), gfortran, liblapack-dev, python3, graphviz, markdown, ghostscript, help2man, libfftw3-dev, libhdf5-dev, libnetcdff-dev, libssl-dev, libxc-dev, mpi-default-dev, python3-dev, python3-numpy, python3-pandas, python3-yaml, texlive-latex-extra, texlive-fonts-recommended, texlive-extra-utils, texlive-pstricks, texlive-publishers, texlive-luatex
630Architecture: any all
631Standards-Version: 3.9.8
632Format: 3.0 (quilt)
633Files:
634 843550cbd14395c0b9408158a91a239c 2464 abinit_9.10.4-3.dsc
635 a323f11fbd4a7d0f461d99c931903b5c 130747285 abinit_9.10.4.orig.tar.gz
636 27c12d3dac5cd105cebaa2af4247e807 15068 abinit_9.10.4-3.debian.tar.xz
637Vcs-Browser: https://salsa.debian.org/debichem-team/abinit
638Vcs-Git: https://salsa.debian.org/debichem-team/abinit.git
639Checksums-Sha256:
640 c3c217b14bc5705a1d8930a2e7fcef58e64beaa22abc213e2eacc7d5537ef840 2464 abinit_9.10.4-3.dsc
641 6bf3c276c333956f722761f189f2b4324e150c8a50470ecb72ee07cc1c457d48 130747285 abinit_9.10.4.orig.tar.gz
642 80c4fb7575d67f3167d7c34fd59477baf839810d0b863e19f1dd9fea1bc0b3b5 15068 abinit_9.10.4-3.debian.tar.xz
643Homepage: http://www.abinit.org/
644Package-List:
645 abinit deb science optional arch=any
646 abinit-data deb science optional arch=all
647 abinit-doc deb doc optional arch=all
648Testsuite: autopkgtest
649Testsuite-Triggers: python3, python3-numpy, python3-pandas, python3-yaml
650Directory: pool/main/a/abinit
651Priority: optional
652Section: science
653"#;
654
655 let source: Source = source.parse().unwrap();
656
657 assert_eq!(source.package, "abinit");
658 assert_eq!(source.version, "9.10.4-3".parse().unwrap());
659 assert_eq!(
660 source.binaries,
661 Some(vec![
662 "abinit".to_string(),
663 "abinit-doc".to_string(),
664 "abinit-data".to_string()
665 ])
666 );
667
668 let build_depends = source.build_depends.as_ref();
669 let build_depends: Vec<_> = build_depends.iter().collect();
670 let build_depends = build_depends[0];
671
672 let expected_build_depends = &[
673 "debhelper",
674 "gfortran",
675 "liblapack-dev",
676 "python3",
677 "graphviz",
678 "markdown",
679 "ghostscript",
680 "help2man",
681 "libfftw3-dev",
682 "libhdf5-dev",
683 "libnetcdff-dev",
684 "libssl-dev",
685 "libxc-dev",
686 "mpi-default-dev",
687 "python3-dev",
688 "python3-numpy",
689 "python3-pandas",
690 "python3-yaml",
691 "texlive-latex-extra",
692 "texlive-fonts-recommended",
693 "texlive-extra-utils",
694 "texlive-pstricks",
695 "texlive-publishers",
696 "texlive-luatex",
697 ];
698
699 assert_eq!(build_depends.len(), expected_build_depends.len());
700 assert_eq!(build_depends[0][0].name, expected_build_depends[0]);
701 assert_eq!(
702 build_depends[build_depends.len() - 1][0].name,
703 expected_build_depends[build_depends.len() - 1]
704 );
705
706 assert_eq!(
707 source.testsuite_triggers,
708 Some(
709 ["python3", "python3-numpy", "python3-pandas", "python3-yaml"]
710 .into_iter()
711 .map(String::from)
712 .collect()
713 )
714 );
715
716 assert_eq!(
718 source.uploaders,
719 Some("Andreas Tille <tille@debian.org>, Michael Banck <mbanck@debian.org>".to_string())
720 );
721
722 let files = source.files.as_ref().unwrap();
724 assert_eq!(files.len(), 3);
725 assert_eq!(files[0].md5sum, "843550cbd14395c0b9408158a91a239c");
726 assert_eq!(files[0].size, 2464);
727 assert_eq!(files[0].filename, "abinit_9.10.4-3.dsc");
728
729 let checksums_sha256 = source.checksums_sha256.as_ref().unwrap();
731 assert_eq!(checksums_sha256.len(), 3);
732 assert_eq!(
733 checksums_sha256[0].sha256,
734 "c3c217b14bc5705a1d8930a2e7fcef58e64beaa22abc213e2eacc7d5537ef840"
735 );
736 assert_eq!(checksums_sha256[0].size, 2464);
737 assert_eq!(checksums_sha256[0].filename, "abinit_9.10.4-3.dsc");
738
739 let package_list = source.package_list.as_ref().unwrap();
741 assert_eq!(package_list.len(), 3);
742 assert!(package_list[0].starts_with("abinit "));
743 }
744
745 #[test]
746 fn test_source_with_extra_source_only() {
747 let source = r#"Package: test-pkg
748Version: 1.0-1
749Maintainer: Test Maintainer <test@example.com>
750Extra-Source-Only: yes
751Directory: pool/main/t/test-pkg
752"#;
753
754 let source: Source = source.parse().unwrap();
755 assert_eq!(source.package, "test-pkg");
756 assert_eq!(source.extra_source_only, Some(true));
757 }
758
759 #[test]
760 fn test_source_with_checksums_sha1() {
761 let source = r#"Package: test-pkg
762Version: 1.0-1
763Maintainer: Test Maintainer <test@example.com>
764Checksums-Sha1:
765 da39a3ee5e6b4b0d3255bfef95601890afd80709 0 test_1.0-1.dsc
766Directory: pool/main/t/test-pkg
767"#;
768
769 let source: Source = source.parse().unwrap();
770 let checksums = source.checksums_sha1.as_ref().unwrap();
771 assert_eq!(checksums.len(), 1);
772 assert_eq!(
773 checksums[0].sha1,
774 "da39a3ee5e6b4b0d3255bfef95601890afd80709"
775 );
776 assert_eq!(checksums[0].size, 0);
777 assert_eq!(checksums[0].filename, "test_1.0-1.dsc");
778 }
779
780 #[test]
781 fn test_source_with_checksums_sha512() {
782 let source = r#"Package: test-pkg
783Version: 1.0-1
784Maintainer: Test Maintainer <test@example.com>
785Checksums-Sha512:
786 cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e 0 test_1.0-1.dsc
787Directory: pool/main/t/test-pkg
788"#;
789
790 let source: Source = source.parse().unwrap();
791 let checksums = source.checksums_sha512.as_ref().unwrap();
792 assert_eq!(checksums.len(), 1);
793 assert_eq!(checksums[0].sha512, "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
794 assert_eq!(checksums[0].size, 0);
795 assert_eq!(checksums[0].filename, "test_1.0-1.dsc");
796 }
797
798 #[test]
799 fn test_package_with_multi_arch() {
800 let package = r#"Package: test-pkg
801Version: 1.0-1
802Architecture: amd64
803Multi-Arch: same
804"#;
805
806 let package: Package = package.parse().unwrap();
807 assert_eq!(package.name, "test-pkg");
808 assert_eq!(package.multi_arch, Some(crate::fields::MultiArch::Same));
809 }
810
811 #[test]
812 fn test_package_with_all_checksums() {
813 let package = r#"Package: test-pkg
814Version: 1.0-1
815Architecture: amd64
816MD5sum: d41d8cd98f00b204e9800998ecf8427e
817SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709
818SHA256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
819SHA512: cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
820"#;
821
822 let package: Package = package.parse().unwrap();
823 assert_eq!(
824 package.md5sum,
825 Some("d41d8cd98f00b204e9800998ecf8427e".to_string())
826 );
827 assert_eq!(
828 package.sha1,
829 Some("da39a3ee5e6b4b0d3255bfef95601890afd80709".to_string())
830 );
831 assert_eq!(
832 package.sha256,
833 Some("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855".to_string())
834 );
835 assert_eq!(package.sha512, Some("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e".to_string()));
836 }
837
838 #[test]
839 fn test_package_with_filename() {
840 let package = r#"Package: test-pkg
841Version: 1.0-1
842Architecture: amd64
843Filename: pool/main/t/test-pkg/test-pkg_1.0-1_amd64.deb
844"#;
845
846 let package: Package = package.parse().unwrap();
847 assert_eq!(
848 package.filename,
849 Some("pool/main/t/test-pkg/test-pkg_1.0-1_amd64.deb".to_string())
850 );
851 }
852
853 #[test]
854 fn test_package_with_task() {
855 let package = r#"Package: ubuntu-desktop
856Version: 1.0
857Architecture: amd64
858Task: ubuntu-desktop
859"#;
860
861 let package: Package = package.parse().unwrap();
862 assert_eq!(package.task, Some("ubuntu-desktop".to_string()));
863 }
864
865 #[test]
866 fn test_package_with_origin() {
867 let package = r#"Package: test-pkg
868Version: 1.0-1
869Architecture: amd64
870Origin: Debian
871"#;
872
873 let package: Package = package.parse().unwrap();
874 assert_eq!(package.origin, Some("Debian".to_string()));
875 }
876
877 #[test]
878 fn test_package_full_with_all_new_fields() {
879 let package = r#"Package: test-pkg
880Version: 1.0-1
881Architecture: amd64
882Multi-Arch: foreign
883Origin: Ubuntu
884Task: minimal
885Filename: pool/main/t/test-pkg/test-pkg_1.0-1_amd64.deb
886Size: 1234
887MD5sum: d41d8cd98f00b204e9800998ecf8427e
888SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709
889SHA256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
890SHA512: cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
891"#;
892
893 let package: Package = package.parse().unwrap();
894 assert_eq!(package.name, "test-pkg");
895 assert_eq!(package.version, "1.0-1".parse().unwrap());
896 assert_eq!(package.architecture, "amd64");
897 assert_eq!(package.multi_arch, Some(crate::fields::MultiArch::Foreign));
898 assert_eq!(package.origin, Some("Ubuntu".to_string()));
899 assert_eq!(package.task, Some("minimal".to_string()));
900 assert_eq!(
901 package.filename,
902 Some("pool/main/t/test-pkg/test-pkg_1.0-1_amd64.deb".to_string())
903 );
904 assert_eq!(package.size, Some(1234));
905 assert!(package.md5sum.is_some());
906 assert!(package.sha1.is_some());
907 assert!(package.sha256.is_some());
908 assert!(package.sha512.is_some());
909 }
910
911 #[test]
912 fn test_source_with_dgit() {
913 let source = r#"Package: test-pkg
914Version: 1.0-1
915Maintainer: Test Maintainer <test@example.com>
916Dgit: c1370424e2404d3c22bd09c828d4b28d81d897ad debian archive/debian/1.1.0 https://git.dgit.debian.org/test-pkg
917Directory: pool/main/t/test-pkg
918Package-List:
919 abinit deb science optional arch=any
920 abinit-data deb science optional arch=all
921 abinit-doc deb doc optional arch=all
922"#;
923
924 let source: Source = source.parse().unwrap();
925 assert_eq!(source.package, "test-pkg");
926 let dgit = source.dgit.as_ref().unwrap();
927 assert_eq!(dgit.commit, "c1370424e2404d3c22bd09c828d4b28d81d897ad");
928 assert_eq!(dgit.suite, "debian");
929 assert_eq!(dgit.git_ref, "archive/debian/1.1.0");
930 assert_eq!(dgit.url, "https://git.dgit.debian.org/test-pkg");
931 }
932
933 #[test]
934 fn test_source_checksums() {
935 let source = r#"Package: hello
936Version: 1.0-1
937Directory: pool/main/h/hello
938Package-List:
939 hello deb misc optional arch=any
940Files:
941 acbd18db4cc2f85cedef654fccc4a4d8 1234 hello_1.0.orig.tar.gz
942Checksums-Sha256:
943 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 1234 hello_1.0.orig.tar.gz
944"#;
945
946 let source: Source = source.parse().unwrap();
947 assert_eq!(source.package, "hello");
948 let files = source.files.as_ref().unwrap();
949 assert_eq!(files.len(), 1);
950 assert_eq!(files[0].md5sum, "acbd18db4cc2f85cedef654fccc4a4d8");
951 assert_eq!(files[0].size, 1234);
952 assert_eq!(files[0].filename, "hello_1.0.orig.tar.gz");
953 let sha256 = source.checksums_sha256.as_ref().unwrap();
954 assert_eq!(sha256.len(), 1);
955 assert_eq!(
956 sha256[0].sha256,
957 "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
958 );
959 }
960
961 #[test]
962 fn test_release_checksums() {
963 let release_str = r#"Suite: stable
964Codename: stable
965Architectures: amd64
966Components: main
967MD5Sum:
968 acbd18db4cc2f85cedef654fccc4a4d8 1234 main/binary-amd64/Packages
969SHA256:
970 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 1234 main/binary-amd64/Packages
971"#;
972
973 let release: Release = release_str.parse().unwrap();
974 assert_eq!(release.suite, Some("stable".to_string()));
975 let md5 = release.checksums_md5.as_ref().unwrap();
976 assert_eq!(md5.len(), 1);
977 assert_eq!(md5[0].filename, "main/binary-amd64/Packages");
978 assert_eq!(md5[0].size, 1234);
979 let sha256 = release.checksums_sha256.as_ref().unwrap();
980 assert_eq!(sha256.len(), 1);
981 assert_eq!(sha256[0].filename, "main/binary-amd64/Packages");
982 }
983}