1use crate::intern::{
2 InternKey, StringInterner, intern_option, intern_vec, resolve_option, resolve_vec,
3};
4use lasso::Key;
5use serde::{Deserialize, Serialize};
6use std::collections::BTreeSet;
7use std::collections::HashMap;
8use time::OffsetDateTime;
9
10#[derive(Serialize, Deserialize, Debug, Clone)]
16pub struct PackageManifest {
17 pub names: Vec<Option<String>>,
18 pub full_names: Vec<Option<String>>,
19 pub owners: Vec<Option<String>>,
20 pub package_urls: Vec<Option<String>>,
21 pub dates_created: Vec<OffsetDateTime>,
22 pub dates_updated: Vec<OffsetDateTime>,
23 pub uuid4s: Vec<Option<String>>,
24 pub rating_scores: Vec<Option<u32>>,
25 pub is_pinned: Vec<Option<bool>>,
26 pub is_deprecated: Vec<Option<bool>>,
27 pub has_nsfw_content: Vec<Option<bool>>,
28 pub categories: Vec<Vec<String>>,
29 pub version_ranges: Vec<(usize, usize)>,
30 pub versions: VersionManifest,
31}
32
33#[derive(Serialize, Deserialize, Debug, Clone)]
38pub struct VersionManifest {
39 pub package_indices: Vec<usize>,
40 pub version_numbers: Vec<Option<String>>,
41 pub download_urls: Vec<Option<String>>,
42 pub dependencies: Vec<Vec<String>>,
43 pub dates_created: Vec<OffsetDateTime>,
44 pub descriptions: Vec<Option<String>>,
45 pub icons: Vec<Option<String>>,
46 pub downloads: Vec<Option<u32>>,
47 pub website_urls: Vec<Option<String>>,
48 pub is_active: Vec<Option<bool>>,
49 pub uuid4s: Vec<Option<String>>,
50 pub file_sizes: Vec<Option<u64>>,
51}
52
53#[derive(Debug, Clone)]
63pub struct InternedPackageManifest {
64 pub interner: StringInterner,
65 pub names: Vec<Option<InternKey>>,
66 pub full_names: Vec<Option<InternKey>>,
67 pub owners: Vec<Option<InternKey>>,
68 pub package_urls: Vec<Option<InternKey>>,
69 pub dates_created: Vec<OffsetDateTime>,
70 pub dates_updated: Vec<OffsetDateTime>,
71 pub uuid4s: Vec<Option<InternKey>>,
72 pub rating_scores: Vec<Option<u32>>,
73 pub is_pinned: Vec<Option<bool>>,
74 pub is_deprecated: Vec<Option<bool>>,
75 pub has_nsfw_content: Vec<Option<bool>>,
76 pub categories: Vec<Vec<InternKey>>,
77 pub version_ranges: Vec<(usize, usize)>,
78 pub versions: InternedVersionManifest,
79}
80
81#[derive(Debug, Clone)]
87pub struct InternedVersionManifest {
88 pub package_indices: Vec<usize>,
89 pub version_numbers: Vec<Option<InternKey>>,
90 pub download_urls: Vec<Option<InternKey>>,
91 pub dependencies: Vec<Vec<InternKey>>,
92 pub dates_created: Vec<OffsetDateTime>,
93 pub descriptions: Vec<Option<InternKey>>,
94 pub icons: Vec<Option<InternKey>>,
95 pub downloads: Vec<Option<u32>>,
96 pub website_urls: Vec<Option<InternKey>>,
97 pub is_active: Vec<Option<bool>>,
98 pub uuid4s: Vec<Option<InternKey>>,
99 pub file_sizes: Vec<Option<u64>>,
100}
101
102#[derive(Serialize, Deserialize, Debug, Clone)]
112pub struct SerializableInternedManifest {
113 pub string_table: Vec<String>,
114 pub names: Vec<Option<u32>>,
115 pub full_names: Vec<Option<u32>>,
116 pub owners: Vec<Option<u32>>,
117 pub package_urls: Vec<Option<u32>>,
118 pub dates_created: Vec<OffsetDateTime>,
119 pub dates_updated: Vec<OffsetDateTime>,
120 pub uuid4s: Vec<Option<u32>>,
121 pub rating_scores: Vec<Option<u32>>,
122 pub is_pinned: Vec<Option<bool>>,
123 pub is_deprecated: Vec<Option<bool>>,
124 pub has_nsfw_content: Vec<Option<bool>>,
125 pub categories: Vec<Vec<u32>>,
126 pub version_ranges: Vec<(usize, usize)>,
127 pub versions: SerializableInternedVersionManifest,
128}
129
130#[derive(Serialize, Deserialize, Debug, Clone)]
136pub struct SerializableInternedVersionManifest {
137 pub package_indices: Vec<usize>,
138 pub version_numbers: Vec<Option<u32>>,
139 pub download_urls: Vec<Option<u32>>,
140 pub dependencies: Vec<Vec<u32>>,
141 pub dates_created: Vec<OffsetDateTime>,
142 pub descriptions: Vec<Option<u32>>,
143 pub icons: Vec<Option<u32>>,
144 pub downloads: Vec<Option<u32>>,
145 pub website_urls: Vec<Option<u32>>,
146 pub is_active: Vec<Option<bool>>,
147 pub uuid4s: Vec<Option<u32>>,
148 pub file_sizes: Vec<Option<u64>>,
149}
150
151#[allow(dead_code)]
152impl PackageManifest {
153 pub fn len(&self) -> usize {
159 self.names.len()
160 }
161
162 pub fn is_empty(&self) -> bool {
168 self.names.is_empty()
169 }
170
171 pub fn validate(&self) -> Result<(), String> {
180 let pkg_count = self.names.len();
181
182 if self.full_names.len() != pkg_count {
183 return Err(format!(
184 "full_names length {} != {}",
185 self.full_names.len(),
186 pkg_count
187 ));
188 }
189
190 if self.owners.len() != pkg_count {
191 return Err(format!(
192 "owners length {} != {}",
193 self.owners.len(),
194 pkg_count
195 ));
196 }
197
198 if self.package_urls.len() != pkg_count {
199 return Err(format!(
200 "package_urls length {} != {}",
201 self.package_urls.len(),
202 pkg_count
203 ));
204 }
205
206 if self.dates_created.len() != pkg_count {
207 return Err(format!(
208 "dates_created length {} != {}",
209 self.dates_created.len(),
210 pkg_count
211 ));
212 }
213
214 if self.dates_updated.len() != pkg_count {
215 return Err(format!(
216 "dates_updated length {} != {}",
217 self.dates_updated.len(),
218 pkg_count
219 ));
220 }
221
222 if self.uuid4s.len() != pkg_count {
223 return Err(format!(
224 "uuid4s length {} != {}",
225 self.uuid4s.len(),
226 pkg_count
227 ));
228 }
229
230 if self.rating_scores.len() != pkg_count {
231 return Err(format!(
232 "rating_scores length {} != {}",
233 self.rating_scores.len(),
234 pkg_count
235 ));
236 }
237
238 if self.is_pinned.len() != pkg_count {
239 return Err(format!(
240 "is_pinned length {} != {}",
241 self.is_pinned.len(),
242 pkg_count
243 ));
244 }
245
246 if self.is_deprecated.len() != pkg_count {
247 return Err(format!(
248 "is_deprecated length {} != {}",
249 self.is_deprecated.len(),
250 pkg_count
251 ));
252 }
253
254 if self.has_nsfw_content.len() != pkg_count {
255 return Err(format!(
256 "has_nsfw_content length {} != {}",
257 self.has_nsfw_content.len(),
258 pkg_count
259 ));
260 }
261
262 if self.categories.len() != pkg_count {
263 return Err(format!(
264 "categories length {} != {}",
265 self.categories.len(),
266 pkg_count
267 ));
268 }
269
270 if self.version_ranges.len() != pkg_count {
271 return Err(format!(
272 "version_ranges length {} != {}",
273 self.version_ranges.len(),
274 pkg_count
275 ));
276 }
277
278 let version_count = self.versions.version_numbers.len();
279
280 if self.versions.package_indices.len() != version_count {
281 return Err(format!(
282 "versions.package_indices length {} != {}",
283 self.versions.package_indices.len(),
284 version_count
285 ));
286 }
287
288 if self.versions.download_urls.len() != version_count {
289 return Err(format!(
290 "versions.download_urls length {} != {}",
291 self.versions.download_urls.len(),
292 version_count
293 ));
294 }
295
296 if self.versions.dependencies.len() != version_count {
297 return Err(format!(
298 "versions.dependencies length {} != {}",
299 self.versions.dependencies.len(),
300 version_count
301 ));
302 }
303
304 if self.versions.dates_created.len() != version_count {
305 return Err(format!(
306 "versions.dates_created length {} != {}",
307 self.versions.dates_created.len(),
308 version_count
309 ));
310 }
311
312 if self.versions.descriptions.len() != version_count {
313 return Err(format!(
314 "versions.descriptions length {} != {}",
315 self.versions.descriptions.len(),
316 version_count
317 ));
318 }
319
320 if self.versions.icons.len() != version_count {
321 return Err(format!(
322 "versions.icons length {} != {}",
323 self.versions.icons.len(),
324 version_count
325 ));
326 }
327
328 if self.versions.downloads.len() != version_count {
329 return Err(format!(
330 "versions.downloads length {} != {}",
331 self.versions.downloads.len(),
332 version_count
333 ));
334 }
335
336 if self.versions.website_urls.len() != version_count {
337 return Err(format!(
338 "versions.website_urls length {} != {}",
339 self.versions.website_urls.len(),
340 version_count
341 ));
342 }
343
344 if self.versions.is_active.len() != version_count {
345 return Err(format!(
346 "versions.is_active length {} != {}",
347 self.versions.is_active.len(),
348 version_count
349 ));
350 }
351
352 if self.versions.uuid4s.len() != version_count {
353 return Err(format!(
354 "versions.uuid4s length {} != {}",
355 self.versions.uuid4s.len(),
356 version_count
357 ));
358 }
359
360 if self.versions.file_sizes.len() != version_count {
361 return Err(format!(
362 "versions.file_sizes length {} != {}",
363 self.versions.file_sizes.len(),
364 version_count
365 ));
366 }
367
368 for (idx, (start, end)) in self.version_ranges.iter().enumerate() {
369 if start > end {
370 return Err(format!(
371 "Invalid version range at package {}: {} > {}",
372 idx, start, end
373 ));
374 }
375
376 if *end > version_count {
377 return Err(format!(
378 "Version range at package {} ends at {} but only {} versions exist",
379 idx, end, version_count
380 ));
381 }
382 }
383
384 Ok(())
385 }
386
387 #[allow(dead_code)]
397 pub fn get_package_by_full_name(&self, full_name: &str) -> Option<Package> {
398 let idx = self.find_index_by_full_name(full_name)?;
399 Some(self.get_package_at(idx))
400 }
401
402 #[allow(dead_code)]
412 pub fn find_index_by_full_name(&self, full_name: &str) -> Option<usize> {
413 self
414 .full_names
415 .iter()
416 .position(|name| name.as_ref().map(|n| n.as_str()) == Some(full_name))
417 }
418
419 #[allow(dead_code)]
432 pub fn get_package_at(&self, idx: usize) -> Package {
433 let (version_start, version_end) = self.version_ranges[idx];
434
435 let mut versions = Vec::with_capacity(version_end - version_start);
436
437 for ver_idx in version_start..version_end {
438 versions.push(Version {
439 name: self.names[idx].clone(),
440 full_name: self.full_names[idx].clone(),
441 description: self.versions.descriptions[ver_idx].clone(),
442 icon: self.versions.icons[ver_idx].clone(),
443 version_number: self.versions.version_numbers[ver_idx].clone(),
444 dependencies: self.versions.dependencies[ver_idx].clone(),
445 download_url: self.versions.download_urls[ver_idx].clone(),
446 downloads: self.versions.downloads[ver_idx],
447 date_created: self.versions.dates_created[ver_idx],
448 website_url: self.versions.website_urls[ver_idx].clone(),
449 is_active: self.versions.is_active[ver_idx],
450 uuid4: self.versions.uuid4s[ver_idx].clone(),
451 file_size: self.versions.file_sizes[ver_idx],
452 });
453 }
454
455 Package {
456 name: self.names[idx].clone(),
457 full_name: self.full_names[idx].clone(),
458 owner: self.owners[idx].clone(),
459 package_url: self.package_urls[idx].clone(),
460 date_created: self.dates_created[idx],
461 date_updated: self.dates_updated[idx],
462 uuid4: self.uuid4s[idx].clone(),
463 rating_score: self.rating_scores[idx],
464 is_pinned: self.is_pinned[idx],
465 is_deprecated: self.is_deprecated[idx],
466 has_nsfw_content: self.has_nsfw_content[idx],
467 categories: self.categories[idx].clone(),
468 versions,
469 }
470 }
471
472 pub fn get_latest_version_at(&self, idx: usize) -> Option<usize> {
484 let (ver_start, ver_end) = self.version_ranges[idx];
485
486 if ver_start >= ver_end {
487 return None;
488 }
489
490 (ver_start..ver_end).max_by_key(|&ver_idx| self.versions.dates_created[ver_idx])
491 }
492
493 pub fn build_name_index(&self) -> HashMap<String, usize> {
501 self
502 .full_names
503 .iter()
504 .enumerate()
505 .filter_map(|(idx, name)| Some((name.as_ref()?.clone(), idx)))
506 .collect()
507 }
508}
509
510impl VersionManifest {}
514
515impl InternedPackageManifest {
516 pub fn len(&self) -> usize {
518 self.names.len()
519 }
520
521 #[allow(dead_code)]
523 pub fn is_empty(&self) -> bool {
524 self.names.is_empty()
525 }
526
527 pub fn resolve_name_at(&self, idx: usize) -> Option<String> {
533 resolve_option(&self.interner, self.names[idx])
534 }
535
536 pub fn resolve_full_name_at(&self, idx: usize) -> Option<String> {
542 resolve_option(&self.interner, self.full_names[idx])
543 }
544
545 pub fn resolve_owner_at(&self, idx: usize) -> Option<String> {
551 resolve_option(&self.interner, self.owners[idx])
552 }
553
554 #[allow(dead_code)]
564 pub fn get_package_by_full_name(&self, full_name: &str) -> Option<Package> {
565 let idx = self.find_index_by_full_name(full_name)?;
566 Some(self.get_package_at(idx))
567 }
568
569 #[allow(dead_code)]
579 pub fn find_index_by_full_name(&self, full_name: &str) -> Option<usize> {
580 self.full_names.iter().position(|key| {
581 key
582 .map(|k| self.interner.resolve(&k) == full_name)
583 .unwrap_or(false)
584 })
585 }
586
587 #[allow(dead_code)]
600 pub fn get_package_at(&self, idx: usize) -> Package {
601 let (version_start, version_end) = self.version_ranges[idx];
602 let mut versions = Vec::with_capacity(version_end - version_start);
603
604 for ver_idx in version_start..version_end {
605 versions.push(Version {
606 name: resolve_option(&self.interner, self.names[idx]),
607 full_name: resolve_option(&self.interner, self.full_names[idx]),
608 description: resolve_option(&self.interner, self.versions.descriptions[ver_idx]),
609 icon: resolve_option(&self.interner, self.versions.icons[ver_idx]),
610 version_number: resolve_option(&self.interner, self.versions.version_numbers[ver_idx]),
611 dependencies: resolve_vec(&self.interner, &self.versions.dependencies[ver_idx]),
612 download_url: resolve_option(&self.interner, self.versions.download_urls[ver_idx]),
613 downloads: self.versions.downloads[ver_idx],
614 date_created: self.versions.dates_created[ver_idx],
615 website_url: resolve_option(&self.interner, self.versions.website_urls[ver_idx]),
616 is_active: self.versions.is_active[ver_idx],
617 uuid4: resolve_option(&self.interner, self.versions.uuid4s[ver_idx]),
618 file_size: self.versions.file_sizes[ver_idx],
619 });
620 }
621
622 Package {
623 name: resolve_option(&self.interner, self.names[idx]),
624 full_name: resolve_option(&self.interner, self.full_names[idx]),
625 owner: resolve_option(&self.interner, self.owners[idx]),
626 package_url: resolve_option(&self.interner, self.package_urls[idx]),
627 date_created: self.dates_created[idx],
628 date_updated: self.dates_updated[idx],
629 uuid4: resolve_option(&self.interner, self.uuid4s[idx]),
630 rating_score: self.rating_scores[idx],
631 is_pinned: self.is_pinned[idx],
632 is_deprecated: self.is_deprecated[idx],
633 has_nsfw_content: self.has_nsfw_content[idx],
634 categories: resolve_vec(&self.interner, &self.categories[idx]),
635 versions,
636 }
637 }
638
639 pub fn get_latest_version_at(&self, idx: usize) -> Option<usize> {
651 let (ver_start, ver_end) = self.version_ranges[idx];
652
653 if ver_start >= ver_end {
654 return None;
655 }
656
657 (ver_start..ver_end).max_by_key(|&ver_idx| self.versions.dates_created[ver_idx])
658 }
659
660 pub fn build_name_index(&self) -> HashMap<String, usize> {
668 self
669 .full_names
670 .iter()
671 .enumerate()
672 .filter_map(|(idx, key)| {
673 let name = resolve_option(&self.interner, *key)?;
674 Some((name, idx))
675 })
676 .collect()
677 }
678
679 pub fn validate(&self) -> Result<(), String> {
688 let pkg_count = self.names.len();
689
690 if self.full_names.len() != pkg_count {
691 return Err(format!(
692 "full_names length {} != {}",
693 self.full_names.len(),
694 pkg_count
695 ));
696 }
697
698 if self.owners.len() != pkg_count {
699 return Err(format!(
700 "owners length {} != {}",
701 self.owners.len(),
702 pkg_count
703 ));
704 }
705
706 if self.package_urls.len() != pkg_count {
707 return Err(format!(
708 "package_urls length {} != {}",
709 self.package_urls.len(),
710 pkg_count
711 ));
712 }
713
714 if self.dates_created.len() != pkg_count {
715 return Err(format!(
716 "dates_created length {} != {}",
717 self.dates_created.len(),
718 pkg_count
719 ));
720 }
721
722 if self.dates_updated.len() != pkg_count {
723 return Err(format!(
724 "dates_updated length {} != {}",
725 self.dates_updated.len(),
726 pkg_count
727 ));
728 }
729
730 if self.uuid4s.len() != pkg_count {
731 return Err(format!(
732 "uuid4s length {} != {}",
733 self.uuid4s.len(),
734 pkg_count
735 ));
736 }
737
738 if self.rating_scores.len() != pkg_count {
739 return Err(format!(
740 "rating_scores length {} != {}",
741 self.rating_scores.len(),
742 pkg_count
743 ));
744 }
745
746 if self.is_pinned.len() != pkg_count {
747 return Err(format!(
748 "is_pinned length {} != {}",
749 self.is_pinned.len(),
750 pkg_count
751 ));
752 }
753
754 if self.is_deprecated.len() != pkg_count {
755 return Err(format!(
756 "is_deprecated length {} != {}",
757 self.is_deprecated.len(),
758 pkg_count
759 ));
760 }
761
762 if self.has_nsfw_content.len() != pkg_count {
763 return Err(format!(
764 "has_nsfw_content length {} != {}",
765 self.has_nsfw_content.len(),
766 pkg_count
767 ));
768 }
769
770 if self.categories.len() != pkg_count {
771 return Err(format!(
772 "categories length {} != {}",
773 self.categories.len(),
774 pkg_count
775 ));
776 }
777
778 if self.version_ranges.len() != pkg_count {
779 return Err(format!(
780 "version_ranges length {} != {}",
781 self.version_ranges.len(),
782 pkg_count
783 ));
784 }
785
786 let version_count = self.versions.package_indices.len();
787
788 if self.versions.version_numbers.len() != version_count {
789 return Err(format!(
790 "versions.version_numbers length {} != {}",
791 self.versions.version_numbers.len(),
792 version_count
793 ));
794 }
795
796 if self.versions.download_urls.len() != version_count {
797 return Err(format!(
798 "versions.download_urls length {} != {}",
799 self.versions.download_urls.len(),
800 version_count
801 ));
802 }
803
804 if self.versions.dependencies.len() != version_count {
805 return Err(format!(
806 "versions.dependencies length {} != {}",
807 self.versions.dependencies.len(),
808 version_count
809 ));
810 }
811
812 if self.versions.dates_created.len() != version_count {
813 return Err(format!(
814 "versions.dates_created length {} != {}",
815 self.versions.dates_created.len(),
816 version_count
817 ));
818 }
819
820 if self.versions.descriptions.len() != version_count {
821 return Err(format!(
822 "versions.descriptions length {} != {}",
823 self.versions.descriptions.len(),
824 version_count
825 ));
826 }
827
828 if self.versions.icons.len() != version_count {
829 return Err(format!(
830 "versions.icons length {} != {}",
831 self.versions.icons.len(),
832 version_count
833 ));
834 }
835
836 if self.versions.downloads.len() != version_count {
837 return Err(format!(
838 "versions.downloads length {} != {}",
839 self.versions.downloads.len(),
840 version_count
841 ));
842 }
843
844 if self.versions.website_urls.len() != version_count {
845 return Err(format!(
846 "versions.website_urls length {} != {}",
847 self.versions.website_urls.len(),
848 version_count
849 ));
850 }
851
852 if self.versions.is_active.len() != version_count {
853 return Err(format!(
854 "versions.is_active length {} != {}",
855 self.versions.is_active.len(),
856 version_count
857 ));
858 }
859
860 if self.versions.uuid4s.len() != version_count {
861 return Err(format!(
862 "versions.uuid4s length {} != {}",
863 self.versions.uuid4s.len(),
864 version_count
865 ));
866 }
867
868 if self.versions.file_sizes.len() != version_count {
869 return Err(format!(
870 "versions.file_sizes length {} != {}",
871 self.versions.file_sizes.len(),
872 version_count
873 ));
874 }
875
876 for (idx, (start, end)) in self.version_ranges.iter().enumerate() {
877 if start > end {
878 return Err(format!(
879 "Invalid version range at package {}: {} > {}",
880 idx, start, end
881 ));
882 }
883
884 if *end > version_count {
885 return Err(format!(
886 "Version range at package {} ends at {} but only {} versions exist",
887 idx, end, version_count
888 ));
889 }
890 }
891
892 Ok(())
893 }
894}
895
896impl InternedVersionManifest {}
900
901#[derive(Serialize, Deserialize, Clone)]
906pub struct Package {
907 pub name: Option<String>,
909 pub full_name: Option<String>,
911 pub owner: Option<String>,
913 pub package_url: Option<String>,
915 #[serde(with = "time::serde::rfc3339")]
917 pub date_created: time::OffsetDateTime,
918 #[serde(with = "time::serde::rfc3339")]
920 pub date_updated: time::OffsetDateTime,
921 pub uuid4: Option<String>,
923 pub rating_score: Option<u32>,
925 pub is_pinned: Option<bool>,
927 pub is_deprecated: Option<bool>,
929 pub has_nsfw_content: Option<bool>,
931 pub categories: Vec<String>,
933 pub versions: Vec<Version>,
935}
936
937#[derive(Serialize, Deserialize, Debug, Clone)]
942pub struct Version {
943 pub name: Option<String>,
945 pub full_name: Option<String>,
947 pub description: Option<String>,
949 pub icon: Option<String>,
951 pub version_number: Option<String>,
953 pub dependencies: Vec<String>,
955 pub download_url: Option<String>,
957 pub downloads: Option<u32>,
959 #[serde(with = "time::serde::rfc3339")]
961 pub date_created: time::OffsetDateTime,
962 pub website_url: Option<String>,
964 pub is_active: Option<bool>,
966 pub uuid4: Option<String>,
968 pub file_size: Option<u64>,
970}
971
972impl Package {
973 pub fn latest_version(&self) -> Option<&Version> {
979 self
980 .versions
981 .iter()
982 .max_by(|a, b| a.date_created.partial_cmp(&b.date_created).unwrap())
983 }
984
985 #[cfg(test)]
995 pub fn zip_and_url(&self) -> Option<(String, String)> {
996 let pkg = self.latest_version()?;
997 let url: String = pkg.download_url.clone()?;
998 let version_number = pkg.version_number.as_ref()?;
999 let package_name = &self.full_name.as_ref()?;
1000 let zip_name = format!("{}-{}.zip", package_name, version_number);
1001
1002 Some((zip_name, url))
1003 }
1004}
1005
1006impl std::fmt::Debug for Package {
1008 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1018 f.debug_struct("Package")
1019 .field("full_name", &self.full_name)
1020 .field(
1021 "dependencies",
1022 &self.latest_version().map(|v| &v.dependencies),
1023 )
1024 .field(
1025 "download_url",
1026 &self.latest_version().map(|v| &v.download_url),
1027 )
1028 .finish()
1029 }
1030}
1031
1032#[derive(Debug, Deserialize, Serialize)]
1037pub struct DependencyGraph {
1038 install_packages: Vec<String>,
1040}
1041
1042impl DependencyGraph {
1043 pub fn new(install_packages: Vec<String>) -> Self {
1053 Self { install_packages }
1054 }
1055
1056 #[allow(dead_code)]
1071 pub fn resolve(&self, manifest: &PackageManifest) -> HashMap<String, String> {
1072 let name_index = manifest.build_name_index();
1073 let mut sorted_set: BTreeSet<&str> = self.install_packages.iter().map(String::as_str).collect();
1074 let mut install_indices = Vec::new();
1075
1076 tracing::debug!("Starting with mod list of: {:#?}", sorted_set);
1077
1078 while !sorted_set.is_empty() {
1079 let Some(item) = sorted_set.pop_first() else {
1080 continue;
1081 };
1082
1083 let item = item.split('-').take(2).collect::<Vec<&str>>().join("-");
1084 let Some(&pkg_idx) = name_index.get(&item) else {
1085 continue;
1086 };
1087
1088 if let Some(latest_ver_idx) = manifest.get_latest_version_at(pkg_idx) {
1089 manifest.versions.dependencies[latest_ver_idx]
1090 .iter()
1091 .for_each(|dep| {
1092 let dep_str = dep.as_str();
1093
1094 tracing::debug!(
1095 "Found dependency of {:#?} for {:#?} mod",
1096 dep_str,
1097 manifest.names[pkg_idx].as_ref().unwrap(),
1098 );
1099 sorted_set.insert(dep_str);
1100 });
1101 }
1102
1103 install_indices.push(pkg_idx);
1104 }
1105
1106 Self::package_indices_to_urls(manifest, &install_indices)
1107 }
1108
1109 #[allow(dead_code)]
1120 fn package_indices_to_urls(
1121 manifest: &PackageManifest,
1122 indices: &[usize],
1123 ) -> HashMap<String, String> {
1124 indices
1125 .iter()
1126 .filter_map(|&idx| {
1127 let latest_ver_idx = manifest.get_latest_version_at(idx)?;
1128 let url = manifest.versions.download_urls[latest_ver_idx].as_ref()?;
1129 let version_number = manifest.versions.version_numbers[latest_ver_idx].as_ref()?;
1130 let package_name = manifest.full_names[idx].as_ref()?;
1131 let zip_name = format!("{}-{}.zip", package_name, version_number);
1132
1133 Some((zip_name, url.clone()))
1134 })
1135 .collect()
1136 }
1137
1138 pub fn resolve_interned(&self, manifest: &InternedPackageManifest) -> HashMap<String, String> {
1153 let name_index = manifest.build_name_index();
1154 let mut sorted_set: BTreeSet<String> = self.install_packages.iter().cloned().collect();
1155 let mut install_indices = Vec::new();
1156
1157 tracing::debug!("Starting with mod list of: {:#?}", sorted_set);
1158
1159 while !sorted_set.is_empty() {
1160 let Some(item) = sorted_set.pop_first() else {
1161 continue;
1162 };
1163
1164 let item = item.split('-').take(2).collect::<Vec<&str>>().join("-");
1165 let Some(&pkg_idx) = name_index.get(&item) else {
1166 continue;
1167 };
1168
1169 if let Some(latest_ver_idx) = manifest.get_latest_version_at(pkg_idx) {
1170 let deps = resolve_vec(
1171 &manifest.interner,
1172 &manifest.versions.dependencies[latest_ver_idx],
1173 );
1174
1175 for dep in deps {
1176 tracing::debug!(
1177 "Found dependency of {:#?} for {:#?} mod",
1178 dep,
1179 manifest.resolve_name_at(pkg_idx).unwrap_or_default(),
1180 );
1181 sorted_set.insert(dep);
1182 }
1183 }
1184
1185 install_indices.push(pkg_idx);
1186 }
1187
1188 Self::package_indices_to_urls_interned(manifest, &install_indices)
1189 }
1190
1191 fn package_indices_to_urls_interned(
1202 manifest: &InternedPackageManifest,
1203 indices: &[usize],
1204 ) -> HashMap<String, String> {
1205 indices
1206 .iter()
1207 .filter_map(|&idx| {
1208 let latest_ver_idx = manifest.get_latest_version_at(idx)?;
1209 let url = resolve_option(
1210 &manifest.interner,
1211 manifest.versions.download_urls[latest_ver_idx],
1212 )?;
1213 let version_number = resolve_option(
1214 &manifest.interner,
1215 manifest.versions.version_numbers[latest_ver_idx],
1216 )?;
1217 let package_name = manifest.resolve_full_name_at(idx)?;
1218 let zip_name = format!("{}-{}.zip", package_name, version_number);
1219
1220 Some((zip_name, url))
1221 })
1222 .collect()
1223 }
1224}
1225
1226impl From<Vec<Package>> for PackageManifest {
1227 fn from(packages: Vec<Package>) -> Self {
1228 let num_packages = packages.len();
1229
1230 let total_versions: usize = packages.iter().map(|p| p.versions.len()).sum();
1231
1232 let mut names = Vec::with_capacity(num_packages);
1233 let mut full_names = Vec::with_capacity(num_packages);
1234 let mut owners = Vec::with_capacity(num_packages);
1235 let mut package_urls = Vec::with_capacity(num_packages);
1236 let mut dates_created = Vec::with_capacity(num_packages);
1237 let mut dates_updated = Vec::with_capacity(num_packages);
1238 let mut uuid4s = Vec::with_capacity(num_packages);
1239 let mut rating_scores = Vec::with_capacity(num_packages);
1240 let mut is_pinned = Vec::with_capacity(num_packages);
1241 let mut is_deprecated = Vec::with_capacity(num_packages);
1242 let mut has_nsfw_content = Vec::with_capacity(num_packages);
1243 let mut categories = Vec::with_capacity(num_packages);
1244 let mut version_ranges = Vec::with_capacity(num_packages);
1245
1246 let mut package_indices = Vec::with_capacity(total_versions);
1247 let mut version_numbers = Vec::with_capacity(total_versions);
1248 let mut download_urls = Vec::with_capacity(total_versions);
1249 let mut dependencies = Vec::with_capacity(total_versions);
1250 let mut version_dates_created = Vec::with_capacity(total_versions);
1251 let mut descriptions = Vec::with_capacity(total_versions);
1252 let mut icons = Vec::with_capacity(total_versions);
1253 let mut downloads = Vec::with_capacity(total_versions);
1254 let mut website_urls = Vec::with_capacity(total_versions);
1255 let mut is_active = Vec::with_capacity(total_versions);
1256 let mut version_uuid4s = Vec::with_capacity(total_versions);
1257 let mut file_sizes = Vec::with_capacity(total_versions);
1258
1259 let mut version_offset = 0;
1260
1261 for (pkg_idx, package) in packages.into_iter().enumerate() {
1262 names.push(package.name);
1263 full_names.push(package.full_name);
1264 owners.push(package.owner);
1265 package_urls.push(package.package_url);
1266 dates_created.push(package.date_created);
1267 dates_updated.push(package.date_updated);
1268 uuid4s.push(package.uuid4);
1269 rating_scores.push(package.rating_score);
1270 is_pinned.push(package.is_pinned);
1271 is_deprecated.push(package.is_deprecated);
1272 has_nsfw_content.push(package.has_nsfw_content);
1273 categories.push(package.categories);
1274
1275 let version_count = package.versions.len();
1276 version_ranges.push((version_offset, version_offset + version_count));
1277
1278 for version in package.versions {
1279 package_indices.push(pkg_idx);
1280 version_numbers.push(version.version_number);
1281 download_urls.push(version.download_url);
1282 dependencies.push(version.dependencies);
1283 version_dates_created.push(version.date_created);
1284 descriptions.push(version.description);
1285 icons.push(version.icon);
1286 downloads.push(version.downloads);
1287 website_urls.push(version.website_url);
1288 is_active.push(version.is_active);
1289 version_uuid4s.push(version.uuid4);
1290 file_sizes.push(version.file_size);
1291 }
1292
1293 version_offset += version_count;
1294 }
1295
1296 PackageManifest {
1297 names,
1298 full_names,
1299 owners,
1300 package_urls,
1301 dates_created,
1302 dates_updated,
1303 uuid4s,
1304 rating_scores,
1305 is_pinned,
1306 is_deprecated,
1307 has_nsfw_content,
1308 categories,
1309 version_ranges,
1310 versions: VersionManifest {
1311 package_indices,
1312 version_numbers,
1313 download_urls,
1314 dependencies,
1315 dates_created: version_dates_created,
1316 descriptions,
1317 icons,
1318 downloads,
1319 website_urls,
1320 is_active,
1321 uuid4s: version_uuid4s,
1322 file_sizes,
1323 },
1324 }
1325 }
1326}
1327
1328impl From<Vec<Package>> for InternedPackageManifest {
1329 fn from(packages: Vec<Package>) -> Self {
1330 let num_packages = packages.len();
1331 let total_versions: usize = packages.iter().map(|p| p.versions.len()).sum();
1332
1333 let mut interner = StringInterner::default();
1334
1335 let mut names = Vec::with_capacity(num_packages);
1336 let mut full_names = Vec::with_capacity(num_packages);
1337 let mut owners = Vec::with_capacity(num_packages);
1338 let mut package_urls = Vec::with_capacity(num_packages);
1339 let mut dates_created = Vec::with_capacity(num_packages);
1340 let mut dates_updated = Vec::with_capacity(num_packages);
1341 let mut uuid4s = Vec::with_capacity(num_packages);
1342 let mut rating_scores = Vec::with_capacity(num_packages);
1343 let mut is_pinned = Vec::with_capacity(num_packages);
1344 let mut is_deprecated = Vec::with_capacity(num_packages);
1345 let mut has_nsfw_content = Vec::with_capacity(num_packages);
1346 let mut categories = Vec::with_capacity(num_packages);
1347 let mut version_ranges = Vec::with_capacity(num_packages);
1348
1349 let mut package_indices = Vec::with_capacity(total_versions);
1350 let mut version_numbers = Vec::with_capacity(total_versions);
1351 let mut download_urls = Vec::with_capacity(total_versions);
1352 let mut dependencies = Vec::with_capacity(total_versions);
1353 let mut version_dates_created = Vec::with_capacity(total_versions);
1354 let mut descriptions = Vec::with_capacity(total_versions);
1355 let mut icons = Vec::with_capacity(total_versions);
1356 let mut downloads = Vec::with_capacity(total_versions);
1357 let mut website_urls = Vec::with_capacity(total_versions);
1358 let mut is_active = Vec::with_capacity(total_versions);
1359 let mut version_uuid4s = Vec::with_capacity(total_versions);
1360 let mut file_sizes = Vec::with_capacity(total_versions);
1361
1362 let mut version_offset = 0;
1363
1364 for (pkg_idx, package) in packages.into_iter().enumerate() {
1365 names.push(intern_option(&mut interner, package.name.as_deref()));
1366 full_names.push(intern_option(&mut interner, package.full_name.as_deref()));
1367 owners.push(intern_option(&mut interner, package.owner.as_deref()));
1368 package_urls.push(intern_option(&mut interner, package.package_url.as_deref()));
1369 dates_created.push(package.date_created);
1370 dates_updated.push(package.date_updated);
1371 uuid4s.push(intern_option(&mut interner, package.uuid4.as_deref()));
1372 rating_scores.push(package.rating_score);
1373 is_pinned.push(package.is_pinned);
1374 is_deprecated.push(package.is_deprecated);
1375 has_nsfw_content.push(package.has_nsfw_content);
1376 categories.push(intern_vec(&mut interner, &package.categories));
1377
1378 let version_count = package.versions.len();
1379 version_ranges.push((version_offset, version_offset + version_count));
1380
1381 for version in package.versions {
1382 package_indices.push(pkg_idx);
1383 version_numbers.push(intern_option(
1384 &mut interner,
1385 version.version_number.as_deref(),
1386 ));
1387 download_urls.push(intern_option(
1388 &mut interner,
1389 version.download_url.as_deref(),
1390 ));
1391 dependencies.push(intern_vec(&mut interner, &version.dependencies));
1392 version_dates_created.push(version.date_created);
1393 descriptions.push(intern_option(&mut interner, version.description.as_deref()));
1394 icons.push(intern_option(&mut interner, version.icon.as_deref()));
1395 downloads.push(version.downloads);
1396 website_urls.push(intern_option(&mut interner, version.website_url.as_deref()));
1397 is_active.push(version.is_active);
1398 version_uuid4s.push(intern_option(&mut interner, version.uuid4.as_deref()));
1399 file_sizes.push(version.file_size);
1400 }
1401
1402 version_offset += version_count;
1403 }
1404
1405 InternedPackageManifest {
1406 interner,
1407 names,
1408 full_names,
1409 owners,
1410 package_urls,
1411 dates_created,
1412 dates_updated,
1413 uuid4s,
1414 rating_scores,
1415 is_pinned,
1416 is_deprecated,
1417 has_nsfw_content,
1418 categories,
1419 version_ranges,
1420 versions: InternedVersionManifest {
1421 package_indices,
1422 version_numbers,
1423 download_urls,
1424 dependencies,
1425 dates_created: version_dates_created,
1426 descriptions,
1427 icons,
1428 downloads,
1429 website_urls,
1430 is_active,
1431 uuid4s: version_uuid4s,
1432 file_sizes,
1433 },
1434 }
1435 }
1436}
1437
1438impl From<PackageManifest> for InternedPackageManifest {
1439 fn from(manifest: PackageManifest) -> Self {
1440 let mut interner = StringInterner::default();
1441
1442 let names: Vec<Option<InternKey>> = manifest
1443 .names
1444 .iter()
1445 .map(|s| intern_option(&mut interner, s.as_deref()))
1446 .collect();
1447
1448 let full_names: Vec<Option<InternKey>> = manifest
1449 .full_names
1450 .iter()
1451 .map(|s| intern_option(&mut interner, s.as_deref()))
1452 .collect();
1453
1454 let owners: Vec<Option<InternKey>> = manifest
1455 .owners
1456 .iter()
1457 .map(|s| intern_option(&mut interner, s.as_deref()))
1458 .collect();
1459
1460 let package_urls: Vec<Option<InternKey>> = manifest
1461 .package_urls
1462 .iter()
1463 .map(|s| intern_option(&mut interner, s.as_deref()))
1464 .collect();
1465
1466 let uuid4s: Vec<Option<InternKey>> = manifest
1467 .uuid4s
1468 .iter()
1469 .map(|s| intern_option(&mut interner, s.as_deref()))
1470 .collect();
1471
1472 let categories: Vec<Vec<InternKey>> = manifest
1473 .categories
1474 .iter()
1475 .map(|c| intern_vec(&mut interner, c))
1476 .collect();
1477
1478 let version_numbers: Vec<Option<InternKey>> = manifest
1479 .versions
1480 .version_numbers
1481 .iter()
1482 .map(|s| intern_option(&mut interner, s.as_deref()))
1483 .collect();
1484
1485 let download_urls: Vec<Option<InternKey>> = manifest
1486 .versions
1487 .download_urls
1488 .iter()
1489 .map(|s| intern_option(&mut interner, s.as_deref()))
1490 .collect();
1491
1492 let dependencies: Vec<Vec<InternKey>> = manifest
1493 .versions
1494 .dependencies
1495 .iter()
1496 .map(|d| intern_vec(&mut interner, d))
1497 .collect();
1498
1499 let descriptions: Vec<Option<InternKey>> = manifest
1500 .versions
1501 .descriptions
1502 .iter()
1503 .map(|s| intern_option(&mut interner, s.as_deref()))
1504 .collect();
1505
1506 let icons: Vec<Option<InternKey>> = manifest
1507 .versions
1508 .icons
1509 .iter()
1510 .map(|s| intern_option(&mut interner, s.as_deref()))
1511 .collect();
1512
1513 let website_urls: Vec<Option<InternKey>> = manifest
1514 .versions
1515 .website_urls
1516 .iter()
1517 .map(|s| intern_option(&mut interner, s.as_deref()))
1518 .collect();
1519
1520 let version_uuid4s: Vec<Option<InternKey>> = manifest
1521 .versions
1522 .uuid4s
1523 .iter()
1524 .map(|s| intern_option(&mut interner, s.as_deref()))
1525 .collect();
1526
1527 InternedPackageManifest {
1528 interner,
1529 names,
1530 full_names,
1531 owners,
1532 package_urls,
1533 dates_created: manifest.dates_created,
1534 dates_updated: manifest.dates_updated,
1535 uuid4s,
1536 rating_scores: manifest.rating_scores,
1537 is_pinned: manifest.is_pinned,
1538 is_deprecated: manifest.is_deprecated,
1539 has_nsfw_content: manifest.has_nsfw_content,
1540 categories,
1541 version_ranges: manifest.version_ranges,
1542 versions: InternedVersionManifest {
1543 package_indices: manifest.versions.package_indices,
1544 version_numbers,
1545 download_urls,
1546 dependencies,
1547 dates_created: manifest.versions.dates_created,
1548 descriptions,
1549 icons,
1550 downloads: manifest.versions.downloads,
1551 website_urls,
1552 is_active: manifest.versions.is_active,
1553 uuid4s: version_uuid4s,
1554 file_sizes: manifest.versions.file_sizes,
1555 },
1556 }
1557 }
1558}
1559
1560fn key_to_index(_interner: &StringInterner, key: InternKey) -> u32 {
1571 key.into_usize() as u32
1572}
1573
1574fn index_to_key(index: u32) -> InternKey {
1588 InternKey::try_from_usize(index as usize).expect("Invalid intern key index")
1589}
1590
1591impl From<&InternedPackageManifest> for SerializableInternedManifest {
1592 fn from(manifest: &InternedPackageManifest) -> Self {
1593 let string_table: Vec<String> = manifest.interner.strings().map(|s| s.to_string()).collect();
1594
1595 let names: Vec<Option<u32>> = manifest
1596 .names
1597 .iter()
1598 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1599 .collect();
1600
1601 let full_names: Vec<Option<u32>> = manifest
1602 .full_names
1603 .iter()
1604 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1605 .collect();
1606
1607 let owners: Vec<Option<u32>> = manifest
1608 .owners
1609 .iter()
1610 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1611 .collect();
1612
1613 let package_urls: Vec<Option<u32>> = manifest
1614 .package_urls
1615 .iter()
1616 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1617 .collect();
1618
1619 let uuid4s: Vec<Option<u32>> = manifest
1620 .uuid4s
1621 .iter()
1622 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1623 .collect();
1624
1625 let categories: Vec<Vec<u32>> = manifest
1626 .categories
1627 .iter()
1628 .map(|keys| {
1629 keys
1630 .iter()
1631 .map(|k| key_to_index(&manifest.interner, *k))
1632 .collect()
1633 })
1634 .collect();
1635
1636 let version_numbers: Vec<Option<u32>> = manifest
1637 .versions
1638 .version_numbers
1639 .iter()
1640 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1641 .collect();
1642
1643 let download_urls: Vec<Option<u32>> = manifest
1644 .versions
1645 .download_urls
1646 .iter()
1647 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1648 .collect();
1649
1650 let dependencies: Vec<Vec<u32>> = manifest
1651 .versions
1652 .dependencies
1653 .iter()
1654 .map(|keys| {
1655 keys
1656 .iter()
1657 .map(|k| key_to_index(&manifest.interner, *k))
1658 .collect()
1659 })
1660 .collect();
1661
1662 let descriptions: Vec<Option<u32>> = manifest
1663 .versions
1664 .descriptions
1665 .iter()
1666 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1667 .collect();
1668
1669 let icons: Vec<Option<u32>> = manifest
1670 .versions
1671 .icons
1672 .iter()
1673 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1674 .collect();
1675
1676 let website_urls: Vec<Option<u32>> = manifest
1677 .versions
1678 .website_urls
1679 .iter()
1680 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1681 .collect();
1682
1683 let version_uuid4s: Vec<Option<u32>> = manifest
1684 .versions
1685 .uuid4s
1686 .iter()
1687 .map(|k| k.map(|key| key_to_index(&manifest.interner, key)))
1688 .collect();
1689
1690 SerializableInternedManifest {
1691 string_table,
1692 names,
1693 full_names,
1694 owners,
1695 package_urls,
1696 dates_created: manifest.dates_created.clone(),
1697 dates_updated: manifest.dates_updated.clone(),
1698 uuid4s,
1699 rating_scores: manifest.rating_scores.clone(),
1700 is_pinned: manifest.is_pinned.clone(),
1701 is_deprecated: manifest.is_deprecated.clone(),
1702 has_nsfw_content: manifest.has_nsfw_content.clone(),
1703 categories,
1704 version_ranges: manifest.version_ranges.clone(),
1705 versions: SerializableInternedVersionManifest {
1706 package_indices: manifest.versions.package_indices.clone(),
1707 version_numbers,
1708 download_urls,
1709 dependencies,
1710 dates_created: manifest.versions.dates_created.clone(),
1711 descriptions,
1712 icons,
1713 downloads: manifest.versions.downloads.clone(),
1714 website_urls,
1715 is_active: manifest.versions.is_active.clone(),
1716 uuid4s: version_uuid4s,
1717 file_sizes: manifest.versions.file_sizes.clone(),
1718 },
1719 }
1720 }
1721}
1722
1723impl From<SerializableInternedManifest> for InternedPackageManifest {
1724 fn from(manifest: SerializableInternedManifest) -> Self {
1725 let mut interner = StringInterner::default();
1726
1727 for s in &manifest.string_table {
1728 interner.get_or_intern(s);
1729 }
1730
1731 let names: Vec<Option<InternKey>> = manifest
1732 .names
1733 .iter()
1734 .map(|idx| idx.map(index_to_key))
1735 .collect();
1736
1737 let full_names: Vec<Option<InternKey>> = manifest
1738 .full_names
1739 .iter()
1740 .map(|idx| idx.map(index_to_key))
1741 .collect();
1742
1743 let owners: Vec<Option<InternKey>> = manifest
1744 .owners
1745 .iter()
1746 .map(|idx| idx.map(index_to_key))
1747 .collect();
1748
1749 let package_urls: Vec<Option<InternKey>> = manifest
1750 .package_urls
1751 .iter()
1752 .map(|idx| idx.map(index_to_key))
1753 .collect();
1754
1755 let uuid4s: Vec<Option<InternKey>> = manifest
1756 .uuid4s
1757 .iter()
1758 .map(|idx| idx.map(index_to_key))
1759 .collect();
1760
1761 let categories: Vec<Vec<InternKey>> = manifest
1762 .categories
1763 .iter()
1764 .map(|indices| indices.iter().map(|&i| index_to_key(i)).collect())
1765 .collect();
1766
1767 let version_numbers: Vec<Option<InternKey>> = manifest
1768 .versions
1769 .version_numbers
1770 .iter()
1771 .map(|idx| idx.map(index_to_key))
1772 .collect();
1773
1774 let download_urls: Vec<Option<InternKey>> = manifest
1775 .versions
1776 .download_urls
1777 .iter()
1778 .map(|idx| idx.map(index_to_key))
1779 .collect();
1780
1781 let dependencies: Vec<Vec<InternKey>> = manifest
1782 .versions
1783 .dependencies
1784 .iter()
1785 .map(|indices| indices.iter().map(|&i| index_to_key(i)).collect())
1786 .collect();
1787
1788 let descriptions: Vec<Option<InternKey>> = manifest
1789 .versions
1790 .descriptions
1791 .iter()
1792 .map(|idx| idx.map(index_to_key))
1793 .collect();
1794
1795 let icons: Vec<Option<InternKey>> = manifest
1796 .versions
1797 .icons
1798 .iter()
1799 .map(|idx| idx.map(index_to_key))
1800 .collect();
1801
1802 let website_urls: Vec<Option<InternKey>> = manifest
1803 .versions
1804 .website_urls
1805 .iter()
1806 .map(|idx| idx.map(index_to_key))
1807 .collect();
1808
1809 let version_uuid4s: Vec<Option<InternKey>> = manifest
1810 .versions
1811 .uuid4s
1812 .iter()
1813 .map(|idx| idx.map(index_to_key))
1814 .collect();
1815
1816 InternedPackageManifest {
1817 interner,
1818 names,
1819 full_names,
1820 owners,
1821 package_urls,
1822 dates_created: manifest.dates_created,
1823 dates_updated: manifest.dates_updated,
1824 uuid4s,
1825 rating_scores: manifest.rating_scores,
1826 is_pinned: manifest.is_pinned,
1827 is_deprecated: manifest.is_deprecated,
1828 has_nsfw_content: manifest.has_nsfw_content,
1829 categories,
1830 version_ranges: manifest.version_ranges,
1831 versions: InternedVersionManifest {
1832 package_indices: manifest.versions.package_indices,
1833 version_numbers,
1834 download_urls,
1835 dependencies,
1836 dates_created: manifest.versions.dates_created,
1837 descriptions,
1838 icons,
1839 downloads: manifest.versions.downloads,
1840 website_urls,
1841 is_active: manifest.versions.is_active,
1842 uuid4s: version_uuid4s,
1843 file_sizes: manifest.versions.file_sizes,
1844 },
1845 }
1846 }
1847}
1848
1849#[cfg(test)]
1850mod tests {
1851 use super::*;
1852 use time::OffsetDateTime;
1853
1854 fn create_test_package(name: &str, owner: &str, version: &str) -> Package {
1855 let full_name = format!("{}-{}", owner, name);
1856 Package {
1857 name: Some(name.to_string()),
1858 full_name: Some(full_name.clone()),
1859 owner: Some(owner.to_string()),
1860 package_url: Some(format!("https://example.com/{}", name)),
1861 date_created: OffsetDateTime::now_utc(),
1862 date_updated: OffsetDateTime::now_utc(),
1863 uuid4: Some("test-uuid".to_string()),
1864 rating_score: Some(5),
1865 is_pinned: Some(false),
1866 is_deprecated: Some(false),
1867 has_nsfw_content: Some(false),
1868 categories: vec!["category1".to_string()],
1869 versions: vec![Version {
1870 name: Some(name.to_string()),
1871 full_name: Some(full_name.clone()),
1872 description: Some("Test description".to_string()),
1873 icon: Some("icon.png".to_string()),
1874 version_number: Some(version.to_string()),
1875 dependencies: vec![],
1876 download_url: Some(format!("https://example.com/{}/download", name)),
1877 downloads: Some(100),
1878 date_created: OffsetDateTime::now_utc(),
1879 website_url: Some("https://example.com".to_string()),
1880 is_active: Some(true),
1881 uuid4: Some("test-version-uuid".to_string()),
1882 file_size: Some(1024),
1883 }],
1884 }
1885 }
1886
1887 fn create_test_package_with_dependencies(
1888 name: &str,
1889 owner: &str,
1890 version: &str,
1891 dependencies: Vec<String>,
1892 ) -> Package {
1893 let mut pkg = create_test_package(name, owner, version);
1894 if let Some(latest_version) = pkg.versions.first_mut() {
1895 latest_version.dependencies = dependencies;
1896 }
1897 pkg
1898 }
1899
1900 #[test]
1901 fn test_latest_version() {
1902 let mut pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
1903
1904 let older_version = Version {
1905 name: Some("TestMod".to_string()),
1906 full_name: Some("TestOwner-TestMod".to_string()),
1907 description: Some("Older version".to_string()),
1908 icon: Some("icon.png".to_string()),
1909 version_number: Some("0.9.0".to_string()),
1910 dependencies: vec![],
1911 download_url: Some("https://example.com/TestMod/download-old".to_string()),
1912 downloads: Some(50),
1913 date_created: OffsetDateTime::now_utc().saturating_sub(time::Duration::days(30)),
1914 website_url: Some("https://example.com".to_string()),
1915 is_active: Some(true),
1916 uuid4: Some("old-version-uuid".to_string()),
1917 file_size: Some(512),
1918 };
1919 pkg.versions.push(older_version);
1920
1921 let newer_version = Version {
1922 name: Some("TestMod".to_string()),
1923 full_name: Some("TestOwner-TestMod".to_string()),
1924 description: Some("Newer version".to_string()),
1925 icon: Some("icon.png".to_string()),
1926 version_number: Some("1.1.0".to_string()),
1927 dependencies: vec![],
1928 download_url: Some("https://example.com/TestMod/download-new".to_string()),
1929 downloads: Some(150),
1930 date_created: OffsetDateTime::now_utc().saturating_add(time::Duration::days(30)),
1931 website_url: Some("https://example.com".to_string()),
1932 is_active: Some(true),
1933 uuid4: Some("new-version-uuid".to_string()),
1934 file_size: Some(2048),
1935 };
1936 pkg.versions.push(newer_version);
1937
1938 let latest = pkg.latest_version().unwrap();
1939 assert_eq!(latest.version_number, Some("1.1.0".to_string()));
1940 assert_eq!(latest.description, Some("Newer version".to_string()));
1941 }
1942
1943 #[test]
1944 fn test_zip_and_url() {
1945 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
1946 let (filename, url) = pkg.zip_and_url().unwrap();
1947
1948 assert_eq!(filename, "TestOwner-TestMod-1.0.0.zip");
1949 assert_eq!(url, "https://example.com/TestMod/download");
1950 }
1951
1952 #[test]
1953 fn test_zip_and_url_missing_data() {
1954 let mut pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
1955
1956 if let Some(version) = pkg.versions.first_mut() {
1957 version.version_number = None;
1958 }
1959
1960 assert!(pkg.zip_and_url().is_none());
1961
1962 let mut pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
1963
1964 if let Some(version) = pkg.versions.first_mut() {
1965 version.download_url = None;
1966 }
1967
1968 assert!(pkg.zip_and_url().is_none());
1969
1970 let mut pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
1971 pkg.full_name = None;
1972
1973 assert!(pkg.zip_and_url().is_none());
1974 }
1975
1976 #[test]
1977 fn test_dependency_graph_resolve() {
1978 let pkg1 = create_test_package("ModA", "Owner1", "1.0.0");
1979 let pkg2 = create_test_package_with_dependencies(
1980 "ModB",
1981 "Owner2",
1982 "2.0.0",
1983 vec!["Owner3-ModC".to_string()],
1984 );
1985 let pkg3 = create_test_package_with_dependencies(
1986 "ModC",
1987 "Owner3",
1988 "1.5.0",
1989 vec!["Owner4-ModD".to_string()],
1990 );
1991 let pkg4 = create_test_package("ModD", "Owner4", "0.9.0");
1992
1993 let packages = vec![pkg1, pkg2, pkg3, pkg4];
1994 let manifest: PackageManifest = packages.into();
1995
1996 let dg1 = DependencyGraph::new(vec!["Owner1-ModA".to_string()]);
1997 let result1 = dg1.resolve(&manifest);
1998 assert_eq!(result1.len(), 1);
1999 assert!(result1.contains_key("Owner1-ModA-1.0.0.zip"));
2000
2001 let dg2 = DependencyGraph::new(vec!["Owner2-ModB".to_string()]);
2002 let result2 = dg2.resolve(&manifest);
2003 assert_eq!(result2.len(), 3);
2004 assert!(result2.contains_key("Owner2-ModB-2.0.0.zip"));
2005 assert!(result2.contains_key("Owner3-ModC-1.5.0.zip"));
2006 assert!(result2.contains_key("Owner4-ModD-0.9.0.zip"));
2007
2008 let dg3 = DependencyGraph::new(vec!["Owner1-ModA".to_string(), "Owner3-ModC".to_string()]);
2009 let result3 = dg3.resolve(&manifest);
2010 assert_eq!(result3.len(), 3);
2011 assert!(result3.contains_key("Owner1-ModA-1.0.0.zip"));
2012 assert!(result3.contains_key("Owner3-ModC-1.5.0.zip"));
2013 assert!(result3.contains_key("Owner4-ModD-0.9.0.zip"));
2014
2015 let dg4 = DependencyGraph::new(vec!["Owner5-ModE".to_string()]);
2016 let result4 = dg4.resolve(&manifest);
2017 assert_eq!(result4.len(), 0);
2018 }
2019
2020 #[test]
2021 fn test_package_debug() {
2022 let pkg = create_test_package("ModTest", "OwnerTest", "1.2.3");
2023 let debug_output = format!("{:?}", pkg);
2024
2025 assert!(debug_output.contains("Package"));
2026 assert!(debug_output.contains("full_name: Some(\"OwnerTest-ModTest\")"));
2027 assert!(debug_output.contains("dependencies: Some([])"));
2028 assert!(
2029 debug_output.contains("download_url: Some(Some(\"https://example.com/ModTest/download\"))")
2030 );
2031
2032 let mut pkg_with_deps = create_test_package_with_dependencies(
2033 "ModWithDeps",
2034 "OwnerTest",
2035 "2.0.0",
2036 vec!["Dep1-Mod1".to_string(), "Dep2-Mod2".to_string()],
2037 );
2038 let debug_with_deps = format!("{:?}", pkg_with_deps);
2039
2040 assert!(debug_with_deps.contains("dependencies: Some([\"Dep1-Mod1\", \"Dep2-Mod2\"])"));
2041
2042 pkg_with_deps.full_name = None;
2043 let debug_missing_name = format!("{:?}", pkg_with_deps);
2044 assert!(debug_missing_name.contains("full_name: None"));
2045
2046 let mut pkg_no_version = create_test_package("NoVersion", "TestOwner", "1.0.0");
2047 pkg_no_version.versions.clear();
2048 let debug_no_version = format!("{:?}", pkg_no_version);
2049
2050 assert!(debug_no_version.contains("dependencies: None"));
2051 assert!(debug_no_version.contains("download_url: None"));
2052 }
2053
2054 #[test]
2055 fn test_package_to_manifest_conversion() {
2056 let pkg1 = create_test_package("ModA", "Owner1", "1.0.0");
2057 let pkg2 = create_test_package_with_dependencies(
2058 "ModB",
2059 "Owner2",
2060 "2.0.0",
2061 vec!["Owner3-ModC".to_string()],
2062 );
2063
2064 let packages = vec![pkg1, pkg2];
2065 let manifest: PackageManifest = packages.clone().into();
2066
2067 assert_eq!(manifest.len(), 2);
2068 assert_eq!(manifest.names[0], Some("ModA".to_string()));
2069 assert_eq!(manifest.names[1], Some("ModB".to_string()));
2070 assert_eq!(manifest.full_names[0], Some("Owner1-ModA".to_string()));
2071 assert_eq!(manifest.full_names[1], Some("Owner2-ModB".to_string()));
2072
2073 assert_eq!(manifest.versions.version_numbers.len(), 2);
2074
2075 assert_eq!(manifest.version_ranges[0], (0, 1));
2076 assert_eq!(manifest.version_ranges[1], (1, 2));
2077
2078 assert_eq!(
2079 manifest.versions.version_numbers[0],
2080 Some("1.0.0".to_string())
2081 );
2082 assert_eq!(
2083 manifest.versions.version_numbers[1],
2084 Some("2.0.0".to_string())
2085 );
2086
2087 assert_eq!(manifest.versions.dependencies[0], Vec::<String>::new());
2088 assert_eq!(
2089 manifest.versions.dependencies[1],
2090 vec!["Owner3-ModC".to_string()]
2091 );
2092 }
2093
2094 #[test]
2095 fn test_manifest_get_package_methods() {
2096 let pkg1 = create_test_package("ModA", "Owner1", "1.0.0");
2097 let pkg2 = create_test_package_with_dependencies(
2098 "ModB",
2099 "Owner2",
2100 "2.0.0",
2101 vec!["Owner3-ModC".to_string()],
2102 );
2103
2104 let original_packages = vec![pkg1, pkg2];
2105 let manifest: PackageManifest = original_packages.clone().into();
2106
2107 assert_eq!(manifest.len(), 2);
2108
2109 let pkg_a = manifest.get_package_by_full_name("Owner1-ModA").unwrap();
2110 assert_eq!(pkg_a.name, Some("ModA".to_string()));
2111 assert_eq!(pkg_a.owner, Some("Owner1".to_string()));
2112 assert_eq!(pkg_a.versions.len(), 1);
2113 assert_eq!(pkg_a.versions[0].version_number, Some("1.0.0".to_string()));
2114
2115 let pkg_b = manifest.get_package_by_full_name("Owner2-ModB").unwrap();
2116 assert_eq!(pkg_b.name, Some("ModB".to_string()));
2117 assert_eq!(pkg_b.owner, Some("Owner2".to_string()));
2118 assert_eq!(pkg_b.versions.len(), 1);
2119 assert_eq!(pkg_b.versions[0].version_number, Some("2.0.0".to_string()));
2120 assert_eq!(
2121 pkg_b.versions[0].dependencies,
2122 vec!["Owner3-ModC".to_string()]
2123 );
2124
2125 let idx = manifest.find_index_by_full_name("Owner1-ModA").unwrap();
2126 assert_eq!(manifest.names[idx], Some("ModA".to_string()));
2127 }
2128
2129 #[test]
2130 fn test_round_trip_conversion() {
2131 let mut pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2132
2133 pkg.versions.push(Version {
2134 name: Some("TestMod".to_string()),
2135 full_name: Some("TestOwner-TestMod".to_string()),
2136 description: Some("Version 2".to_string()),
2137 icon: Some("icon2.png".to_string()),
2138 version_number: Some("2.0.0".to_string()),
2139 dependencies: vec!["Dep1-Mod1".to_string()],
2140 download_url: Some("https://example.com/TestMod/download-v2".to_string()),
2141 downloads: Some(200),
2142 date_created: OffsetDateTime::now_utc(),
2143 website_url: Some("https://example.com".to_string()),
2144 is_active: Some(true),
2145 uuid4: Some("test-version-uuid-2".to_string()),
2146 file_size: Some(2048),
2147 });
2148
2149 let original_full_name = pkg.full_name.clone().unwrap();
2150 let original_version_count = pkg.versions.len();
2151
2152 let packages = vec![pkg];
2153 let manifest: PackageManifest = packages.into();
2154
2155 let reconstructed = manifest
2156 .get_package_by_full_name(&original_full_name)
2157 .unwrap();
2158 assert_eq!(reconstructed.full_name, Some(original_full_name));
2159 assert_eq!(reconstructed.versions.len(), original_version_count);
2160 assert_eq!(
2161 reconstructed.versions[0].version_number,
2162 Some("1.0.0".to_string())
2163 );
2164 assert_eq!(
2165 reconstructed.versions[1].version_number,
2166 Some("2.0.0".to_string())
2167 );
2168 assert_eq!(
2169 reconstructed.versions[1].dependencies,
2170 vec!["Dep1-Mod1".to_string()]
2171 );
2172 }
2173
2174 #[test]
2175 fn test_validate_valid_manifest() {
2176 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2177 let packages = vec![pkg];
2178 let manifest: PackageManifest = packages.into();
2179
2180 assert!(manifest.validate().is_ok());
2181 }
2182
2183 #[test]
2184 fn test_validate_mismatched_full_names_length() {
2185 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2186 let packages = vec![pkg];
2187 let mut manifest: PackageManifest = packages.into();
2188
2189 manifest.full_names.pop();
2190
2191 let result = manifest.validate();
2192 assert!(result.is_err());
2193 assert!(result.unwrap_err().contains("full_names length"));
2194 }
2195
2196 #[test]
2197 fn test_validate_mismatched_owners_length() {
2198 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2199 let packages = vec![pkg];
2200 let mut manifest: PackageManifest = packages.into();
2201
2202 manifest.owners.push(Some("Extra".to_string()));
2203
2204 let result = manifest.validate();
2205 assert!(result.is_err());
2206 assert!(result.unwrap_err().contains("owners length"));
2207 }
2208
2209 #[test]
2210 fn test_validate_invalid_version_range() {
2211 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2212 let packages = vec![pkg];
2213 let mut manifest: PackageManifest = packages.into();
2214
2215 manifest.version_ranges[0] = (5, 3);
2216
2217 let result = manifest.validate();
2218 assert!(result.is_err());
2219 assert!(result.unwrap_err().contains("Invalid version range"));
2220 }
2221
2222 #[test]
2223 fn test_validate_version_range_out_of_bounds() {
2224 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2225 let packages = vec![pkg];
2226 let mut manifest: PackageManifest = packages.into();
2227
2228 manifest.version_ranges[0] = (0, 999);
2229
2230 let result = manifest.validate();
2231 assert!(result.is_err());
2232 let err_msg = result.unwrap_err();
2233 assert!(err_msg.contains("only"));
2234 assert!(err_msg.contains("versions exist"));
2235 }
2236
2237 #[test]
2238 fn test_validate_mismatched_version_arrays() {
2239 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2240 let packages = vec![pkg];
2241 let mut manifest: PackageManifest = packages.into();
2242
2243 manifest.versions.download_urls.pop();
2244
2245 let result = manifest.validate();
2246 assert!(result.is_err());
2247 assert!(
2248 result
2249 .unwrap_err()
2250 .contains("versions.download_urls length")
2251 );
2252 }
2253
2254 #[test]
2255 fn test_validate_empty_manifest() {
2256 let manifest = PackageManifest {
2257 names: vec![],
2258 full_names: vec![],
2259 owners: vec![],
2260 package_urls: vec![],
2261 dates_created: vec![],
2262 dates_updated: vec![],
2263 uuid4s: vec![],
2264 rating_scores: vec![],
2265 is_pinned: vec![],
2266 is_deprecated: vec![],
2267 has_nsfw_content: vec![],
2268 categories: vec![],
2269 version_ranges: vec![],
2270 versions: VersionManifest {
2271 package_indices: vec![],
2272 version_numbers: vec![],
2273 download_urls: vec![],
2274 dependencies: vec![],
2275 dates_created: vec![],
2276 descriptions: vec![],
2277 icons: vec![],
2278 downloads: vec![],
2279 website_urls: vec![],
2280 is_active: vec![],
2281 uuid4s: vec![],
2282 file_sizes: vec![],
2283 },
2284 };
2285
2286 assert!(manifest.validate().is_ok());
2287 assert!(manifest.is_empty());
2288 }
2289
2290 #[test]
2291 fn test_validate_mismatched_package_urls_length() {
2292 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2293 let packages = vec![pkg];
2294 let mut manifest: PackageManifest = packages.into();
2295
2296 manifest.package_urls.pop();
2297
2298 let result = manifest.validate();
2299 assert!(result.is_err());
2300 assert!(result.unwrap_err().contains("package_urls length"));
2301 }
2302
2303 #[test]
2304 fn test_validate_mismatched_dates_created_length() {
2305 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2306 let packages = vec![pkg];
2307 let mut manifest: PackageManifest = packages.into();
2308
2309 manifest.dates_created.pop();
2310
2311 let result = manifest.validate();
2312 assert!(result.is_err());
2313 assert!(result.unwrap_err().contains("dates_created length"));
2314 }
2315
2316 #[test]
2317 fn test_validate_mismatched_dates_updated_length() {
2318 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2319 let packages = vec![pkg];
2320 let mut manifest: PackageManifest = packages.into();
2321
2322 manifest.dates_updated.pop();
2323
2324 let result = manifest.validate();
2325 assert!(result.is_err());
2326 assert!(result.unwrap_err().contains("dates_updated length"));
2327 }
2328
2329 #[test]
2330 fn test_validate_mismatched_uuid4s_length() {
2331 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2332 let packages = vec![pkg];
2333 let mut manifest: PackageManifest = packages.into();
2334
2335 manifest.uuid4s.pop();
2336
2337 let result = manifest.validate();
2338 assert!(result.is_err());
2339 assert!(result.unwrap_err().contains("uuid4s length"));
2340 }
2341
2342 #[test]
2343 fn test_validate_mismatched_rating_scores_length() {
2344 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2345 let packages = vec![pkg];
2346 let mut manifest: PackageManifest = packages.into();
2347
2348 manifest.rating_scores.pop();
2349
2350 let result = manifest.validate();
2351 assert!(result.is_err());
2352 assert!(result.unwrap_err().contains("rating_scores length"));
2353 }
2354
2355 #[test]
2356 fn test_validate_mismatched_is_pinned_length() {
2357 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2358 let packages = vec![pkg];
2359 let mut manifest: PackageManifest = packages.into();
2360
2361 manifest.is_pinned.pop();
2362
2363 let result = manifest.validate();
2364 assert!(result.is_err());
2365 assert!(result.unwrap_err().contains("is_pinned length"));
2366 }
2367
2368 #[test]
2369 fn test_validate_mismatched_is_deprecated_length() {
2370 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2371 let packages = vec![pkg];
2372 let mut manifest: PackageManifest = packages.into();
2373
2374 manifest.is_deprecated.pop();
2375
2376 let result = manifest.validate();
2377 assert!(result.is_err());
2378 assert!(result.unwrap_err().contains("is_deprecated length"));
2379 }
2380
2381 #[test]
2382 fn test_validate_mismatched_has_nsfw_content_length() {
2383 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2384 let packages = vec![pkg];
2385 let mut manifest: PackageManifest = packages.into();
2386
2387 manifest.has_nsfw_content.pop();
2388
2389 let result = manifest.validate();
2390 assert!(result.is_err());
2391 assert!(result.unwrap_err().contains("has_nsfw_content length"));
2392 }
2393
2394 #[test]
2395 fn test_validate_mismatched_categories_length() {
2396 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2397 let packages = vec![pkg];
2398 let mut manifest: PackageManifest = packages.into();
2399
2400 manifest.categories.pop();
2401
2402 let result = manifest.validate();
2403 assert!(result.is_err());
2404 assert!(result.unwrap_err().contains("categories length"));
2405 }
2406
2407 #[test]
2408 fn test_validate_mismatched_version_ranges_length() {
2409 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2410 let packages = vec![pkg];
2411 let mut manifest: PackageManifest = packages.into();
2412
2413 manifest.version_ranges.pop();
2414
2415 let result = manifest.validate();
2416 assert!(result.is_err());
2417 assert!(result.unwrap_err().contains("version_ranges length"));
2418 }
2419
2420 #[test]
2421 fn test_validate_mismatched_version_package_indices_length() {
2422 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2423 let packages = vec![pkg];
2424 let mut manifest: PackageManifest = packages.into();
2425
2426 manifest.versions.package_indices.pop();
2427
2428 let result = manifest.validate();
2429 assert!(result.is_err());
2430 assert!(
2431 result
2432 .unwrap_err()
2433 .contains("versions.package_indices length")
2434 );
2435 }
2436
2437 #[test]
2438 fn test_validate_mismatched_version_dependencies_length() {
2439 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2440 let packages = vec![pkg];
2441 let mut manifest: PackageManifest = packages.into();
2442
2443 manifest.versions.dependencies.pop();
2444
2445 let result = manifest.validate();
2446 assert!(result.is_err());
2447 assert!(result.unwrap_err().contains("versions.dependencies length"));
2448 }
2449
2450 #[test]
2451 fn test_validate_mismatched_version_dates_created_length() {
2452 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2453 let packages = vec![pkg];
2454 let mut manifest: PackageManifest = packages.into();
2455
2456 manifest.versions.dates_created.pop();
2457
2458 let result = manifest.validate();
2459 assert!(result.is_err());
2460 assert!(
2461 result
2462 .unwrap_err()
2463 .contains("versions.dates_created length")
2464 );
2465 }
2466
2467 #[test]
2468 fn test_validate_mismatched_version_descriptions_length() {
2469 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2470 let packages = vec![pkg];
2471 let mut manifest: PackageManifest = packages.into();
2472
2473 manifest.versions.descriptions.pop();
2474
2475 let result = manifest.validate();
2476 assert!(result.is_err());
2477 assert!(result.unwrap_err().contains("versions.descriptions length"));
2478 }
2479
2480 #[test]
2481 fn test_validate_mismatched_version_icons_length() {
2482 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2483 let packages = vec![pkg];
2484 let mut manifest: PackageManifest = packages.into();
2485
2486 manifest.versions.icons.pop();
2487
2488 let result = manifest.validate();
2489 assert!(result.is_err());
2490 assert!(result.unwrap_err().contains("versions.icons length"));
2491 }
2492
2493 #[test]
2494 fn test_validate_mismatched_version_downloads_length() {
2495 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2496 let packages = vec![pkg];
2497 let mut manifest: PackageManifest = packages.into();
2498
2499 manifest.versions.downloads.pop();
2500
2501 let result = manifest.validate();
2502 assert!(result.is_err());
2503 assert!(result.unwrap_err().contains("versions.downloads length"));
2504 }
2505
2506 #[test]
2507 fn test_validate_mismatched_version_website_urls_length() {
2508 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2509 let packages = vec![pkg];
2510 let mut manifest: PackageManifest = packages.into();
2511
2512 manifest.versions.website_urls.pop();
2513
2514 let result = manifest.validate();
2515 assert!(result.is_err());
2516 assert!(result.unwrap_err().contains("versions.website_urls length"));
2517 }
2518
2519 #[test]
2520 fn test_validate_mismatched_version_is_active_length() {
2521 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2522 let packages = vec![pkg];
2523 let mut manifest: PackageManifest = packages.into();
2524
2525 manifest.versions.is_active.pop();
2526
2527 let result = manifest.validate();
2528 assert!(result.is_err());
2529 assert!(result.unwrap_err().contains("versions.is_active length"));
2530 }
2531
2532 #[test]
2533 fn test_validate_mismatched_version_uuid4s_length() {
2534 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2535 let packages = vec![pkg];
2536 let mut manifest: PackageManifest = packages.into();
2537
2538 manifest.versions.uuid4s.pop();
2539
2540 let result = manifest.validate();
2541 assert!(result.is_err());
2542 assert!(result.unwrap_err().contains("versions.uuid4s length"));
2543 }
2544
2545 #[test]
2546 fn test_validate_mismatched_version_file_sizes_length() {
2547 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2548 let packages = vec![pkg];
2549 let mut manifest: PackageManifest = packages.into();
2550
2551 manifest.versions.file_sizes.pop();
2552
2553 let result = manifest.validate();
2554 assert!(result.is_err());
2555 assert!(result.unwrap_err().contains("versions.file_sizes length"));
2556 }
2557
2558 #[test]
2559 fn test_get_latest_version_at_empty_range() {
2560 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2561 let packages = vec![pkg];
2562 let mut manifest: PackageManifest = packages.into();
2563
2564 manifest.version_ranges[0] = (0, 0);
2565
2566 let result = manifest.get_latest_version_at(0);
2567 assert!(result.is_none());
2568 }
2569
2570 #[test]
2571 fn test_dependency_graph_resolve_with_missing_dependency() {
2572 let pkg1 = create_test_package("ModA", "Owner1", "1.0.0");
2573 let pkg2 = create_test_package_with_dependencies(
2574 "ModB",
2575 "Owner2",
2576 "2.0.0",
2577 vec!["Owner3-NonExistent".to_string()],
2578 );
2579
2580 let packages = vec![pkg1, pkg2];
2581 let manifest: PackageManifest = packages.into();
2582
2583 let dg = DependencyGraph::new(vec!["Owner2-ModB".to_string()]);
2584 let result = dg.resolve(&manifest);
2585
2586 assert_eq!(result.len(), 1);
2587 assert!(result.contains_key("Owner2-ModB-2.0.0.zip"));
2588 }
2589
2590 #[test]
2591 fn test_dependency_graph_resolve_with_version_suffix() {
2592 let pkg1 = create_test_package("ModA", "Owner1", "1.0.0");
2593
2594 let packages = vec![pkg1];
2595 let manifest: PackageManifest = packages.into();
2596
2597 let dg = DependencyGraph::new(vec!["Owner1-ModA-1.0.0".to_string()]);
2598 let result = dg.resolve(&manifest);
2599
2600 assert_eq!(result.len(), 1);
2601 assert!(result.contains_key("Owner1-ModA-1.0.0.zip"));
2602 }
2603
2604 #[test]
2605 fn test_interned_manifest_basic_operations() {
2606 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2607 let packages = vec![pkg];
2608 let interned: InternedPackageManifest = packages.into();
2609
2610 assert_eq!(interned.len(), 1);
2611
2612 assert!(!interned.is_empty());
2613
2614 assert_eq!(interned.resolve_name_at(0), Some("TestMod".to_string()));
2615
2616 assert_eq!(
2617 interned.resolve_full_name_at(0),
2618 Some("TestOwner-TestMod".to_string())
2619 );
2620
2621 assert_eq!(interned.resolve_owner_at(0), Some("TestOwner".to_string()));
2622 }
2623
2624 #[test]
2625 fn test_interned_manifest_get_package_by_full_name() {
2626 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2627 let packages = vec![pkg];
2628 let interned: InternedPackageManifest = packages.into();
2629
2630 let found = interned.get_package_by_full_name("TestOwner-TestMod");
2631
2632 assert!(found.is_some());
2633
2634 let package = found.unwrap();
2635
2636 assert_eq!(package.name, Some("TestMod".to_string()));
2637
2638 assert_eq!(package.owner, Some("TestOwner".to_string()));
2639
2640 assert_eq!(package.versions.len(), 1);
2641 }
2642
2643 #[test]
2644 fn test_interned_manifest_find_index_by_full_name() {
2645 let pkg1 = create_test_package("ModA", "Owner1", "1.0.0");
2646 let pkg2 = create_test_package("ModB", "Owner2", "2.0.0");
2647 let packages = vec![pkg1, pkg2];
2648 let interned: InternedPackageManifest = packages.into();
2649
2650 assert_eq!(interned.find_index_by_full_name("Owner1-ModA"), Some(0));
2651
2652 assert_eq!(interned.find_index_by_full_name("Owner2-ModB"), Some(1));
2653
2654 assert_eq!(interned.find_index_by_full_name("NonExistent"), None);
2655 }
2656
2657 #[test]
2658 fn test_interned_manifest_get_package_at() {
2659 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2660 let packages = vec![pkg];
2661 let interned: InternedPackageManifest = packages.into();
2662
2663 let package = interned.get_package_at(0);
2664
2665 assert_eq!(package.name, Some("TestMod".to_string()));
2666
2667 assert_eq!(package.full_name, Some("TestOwner-TestMod".to_string()));
2668
2669 assert_eq!(package.owner, Some("TestOwner".to_string()));
2670
2671 assert_eq!(package.versions.len(), 1);
2672
2673 assert_eq!(
2674 package.versions[0].version_number,
2675 Some("1.0.0".to_string())
2676 );
2677 }
2678
2679 #[test]
2680 fn test_interned_manifest_get_latest_version_at() {
2681 let mut pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2682
2683 let older_version = Version {
2684 name: Some("TestMod".to_string()),
2685 full_name: Some("TestOwner-TestMod".to_string()),
2686 description: Some("Older version".to_string()),
2687 icon: Some("icon.png".to_string()),
2688 version_number: Some("0.9.0".to_string()),
2689 dependencies: vec![],
2690 download_url: Some("https://example.com/TestMod/download-old".to_string()),
2691 downloads: Some(50),
2692 date_created: OffsetDateTime::now_utc().saturating_sub(time::Duration::days(30)),
2693 website_url: Some("https://example.com".to_string()),
2694 is_active: Some(true),
2695 uuid4: Some("old-version-uuid".to_string()),
2696 file_size: Some(512),
2697 };
2698 pkg.versions.insert(0, older_version);
2699
2700 let packages = vec![pkg];
2701 let interned: InternedPackageManifest = packages.into();
2702
2703 let latest_idx = interned.get_latest_version_at(0);
2704
2705 assert!(latest_idx.is_some());
2706
2707 let version_idx = latest_idx.unwrap();
2708 let version_number = interned.versions.version_numbers[version_idx]
2709 .map(|key| interned.interner.resolve(&key).to_string());
2710
2711 assert_eq!(version_number, Some("1.0.0".to_string()));
2712 }
2713
2714 #[test]
2715 fn test_interned_manifest_get_latest_version_at_empty_range() {
2716 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2717 let packages = vec![pkg];
2718 let mut interned: InternedPackageManifest = packages.into();
2719
2720 interned.version_ranges[0] = (0, 0);
2721
2722 let latest = interned.get_latest_version_at(0);
2723
2724 assert!(latest.is_none());
2725 }
2726
2727 #[test]
2728 fn test_interned_manifest_build_name_index() {
2729 let pkg1 = create_test_package("ModA", "Owner1", "1.0.0");
2730 let pkg2 = create_test_package("ModB", "Owner2", "2.0.0");
2731 let packages = vec![pkg1, pkg2];
2732 let interned: InternedPackageManifest = packages.into();
2733
2734 let index = interned.build_name_index();
2735
2736 assert_eq!(index.len(), 2);
2737
2738 assert_eq!(index.get("Owner1-ModA"), Some(&0));
2739
2740 assert_eq!(index.get("Owner2-ModB"), Some(&1));
2741 }
2742
2743 #[test]
2744 fn test_interned_manifest_validate_valid() {
2745 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2746 let packages = vec![pkg];
2747 let interned: InternedPackageManifest = packages.into();
2748
2749 let result = interned.validate();
2750
2751 assert!(result.is_ok());
2752 }
2753
2754 #[test]
2755 fn test_interned_manifest_validate_mismatched_full_names_length() {
2756 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2757 let packages = vec![pkg];
2758 let mut interned: InternedPackageManifest = packages.into();
2759
2760 interned.full_names.pop();
2761
2762 let result = interned.validate();
2763
2764 assert!(result.is_err());
2765
2766 assert!(result.unwrap_err().contains("full_names length"));
2767 }
2768
2769 #[test]
2770 fn test_interned_manifest_validate_mismatched_owners_length() {
2771 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2772 let packages = vec![pkg];
2773 let mut interned: InternedPackageManifest = packages.into();
2774
2775 interned.owners.pop();
2776
2777 let result = interned.validate();
2778
2779 assert!(result.is_err());
2780
2781 assert!(result.unwrap_err().contains("owners length"));
2782 }
2783
2784 #[test]
2785 fn test_interned_manifest_validate_mismatched_package_urls_length() {
2786 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2787 let packages = vec![pkg];
2788 let mut interned: InternedPackageManifest = packages.into();
2789
2790 interned.package_urls.pop();
2791
2792 let result = interned.validate();
2793
2794 assert!(result.is_err());
2795
2796 assert!(result.unwrap_err().contains("package_urls length"));
2797 }
2798
2799 #[test]
2800 fn test_interned_manifest_validate_mismatched_dates_created_length() {
2801 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2802 let packages = vec![pkg];
2803 let mut interned: InternedPackageManifest = packages.into();
2804
2805 interned.dates_created.pop();
2806
2807 let result = interned.validate();
2808
2809 assert!(result.is_err());
2810
2811 assert!(result.unwrap_err().contains("dates_created length"));
2812 }
2813
2814 #[test]
2815 fn test_interned_manifest_validate_mismatched_dates_updated_length() {
2816 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2817 let packages = vec![pkg];
2818 let mut interned: InternedPackageManifest = packages.into();
2819
2820 interned.dates_updated.pop();
2821
2822 let result = interned.validate();
2823
2824 assert!(result.is_err());
2825
2826 assert!(result.unwrap_err().contains("dates_updated length"));
2827 }
2828
2829 #[test]
2830 fn test_interned_manifest_validate_mismatched_uuid4s_length() {
2831 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2832 let packages = vec![pkg];
2833 let mut interned: InternedPackageManifest = packages.into();
2834
2835 interned.uuid4s.pop();
2836
2837 let result = interned.validate();
2838
2839 assert!(result.is_err());
2840
2841 assert!(result.unwrap_err().contains("uuid4s length"));
2842 }
2843
2844 #[test]
2845 fn test_interned_manifest_validate_mismatched_rating_scores_length() {
2846 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2847 let packages = vec![pkg];
2848 let mut interned: InternedPackageManifest = packages.into();
2849
2850 interned.rating_scores.pop();
2851
2852 let result = interned.validate();
2853
2854 assert!(result.is_err());
2855
2856 assert!(result.unwrap_err().contains("rating_scores length"));
2857 }
2858
2859 #[test]
2860 fn test_interned_manifest_validate_mismatched_is_pinned_length() {
2861 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2862 let packages = vec![pkg];
2863 let mut interned: InternedPackageManifest = packages.into();
2864
2865 interned.is_pinned.pop();
2866
2867 let result = interned.validate();
2868
2869 assert!(result.is_err());
2870
2871 assert!(result.unwrap_err().contains("is_pinned length"));
2872 }
2873
2874 #[test]
2875 fn test_interned_manifest_validate_mismatched_is_deprecated_length() {
2876 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2877 let packages = vec![pkg];
2878 let mut interned: InternedPackageManifest = packages.into();
2879
2880 interned.is_deprecated.pop();
2881
2882 let result = interned.validate();
2883
2884 assert!(result.is_err());
2885
2886 assert!(result.unwrap_err().contains("is_deprecated length"));
2887 }
2888
2889 #[test]
2890 fn test_interned_manifest_validate_mismatched_has_nsfw_content_length() {
2891 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2892 let packages = vec![pkg];
2893 let mut interned: InternedPackageManifest = packages.into();
2894
2895 interned.has_nsfw_content.pop();
2896
2897 let result = interned.validate();
2898
2899 assert!(result.is_err());
2900
2901 assert!(result.unwrap_err().contains("has_nsfw_content length"));
2902 }
2903
2904 #[test]
2905 fn test_interned_manifest_validate_mismatched_categories_length() {
2906 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2907 let packages = vec![pkg];
2908 let mut interned: InternedPackageManifest = packages.into();
2909
2910 interned.categories.pop();
2911
2912 let result = interned.validate();
2913
2914 assert!(result.is_err());
2915
2916 assert!(result.unwrap_err().contains("categories length"));
2917 }
2918
2919 #[test]
2920 fn test_interned_manifest_validate_mismatched_version_ranges_length() {
2921 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2922 let packages = vec![pkg];
2923 let mut interned: InternedPackageManifest = packages.into();
2924
2925 interned.version_ranges.pop();
2926
2927 let result = interned.validate();
2928
2929 assert!(result.is_err());
2930
2931 assert!(result.unwrap_err().contains("version_ranges length"));
2932 }
2933
2934 #[test]
2935 fn test_interned_manifest_validate_mismatched_version_numbers_length() {
2936 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2937 let packages = vec![pkg];
2938 let mut interned: InternedPackageManifest = packages.into();
2939
2940 interned.versions.version_numbers.pop();
2941
2942 let result = interned.validate();
2943
2944 assert!(result.is_err());
2945
2946 assert!(result.unwrap_err().contains("version_numbers length"));
2947 }
2948
2949 #[test]
2950 fn test_interned_manifest_validate_mismatched_version_download_urls_length() {
2951 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2952 let packages = vec![pkg];
2953 let mut interned: InternedPackageManifest = packages.into();
2954
2955 interned.versions.download_urls.pop();
2956
2957 let result = interned.validate();
2958
2959 assert!(result.is_err());
2960
2961 assert!(result.unwrap_err().contains("download_urls length"));
2962 }
2963
2964 #[test]
2965 fn test_interned_manifest_validate_mismatched_version_dependencies_length() {
2966 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2967 let packages = vec![pkg];
2968 let mut interned: InternedPackageManifest = packages.into();
2969
2970 interned.versions.dependencies.pop();
2971
2972 let result = interned.validate();
2973
2974 assert!(result.is_err());
2975
2976 assert!(result.unwrap_err().contains("dependencies length"));
2977 }
2978
2979 #[test]
2980 fn test_interned_manifest_validate_mismatched_version_dates_created_length() {
2981 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2982 let packages = vec![pkg];
2983 let mut interned: InternedPackageManifest = packages.into();
2984
2985 interned.versions.dates_created.pop();
2986
2987 let result = interned.validate();
2988
2989 assert!(result.is_err());
2990
2991 assert!(result.unwrap_err().contains("dates_created length"));
2992 }
2993
2994 #[test]
2995 fn test_interned_manifest_validate_mismatched_version_descriptions_length() {
2996 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
2997 let packages = vec![pkg];
2998 let mut interned: InternedPackageManifest = packages.into();
2999
3000 interned.versions.descriptions.pop();
3001
3002 let result = interned.validate();
3003
3004 assert!(result.is_err());
3005
3006 assert!(result.unwrap_err().contains("descriptions length"));
3007 }
3008
3009 #[test]
3010 fn test_interned_manifest_validate_mismatched_version_icons_length() {
3011 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
3012 let packages = vec![pkg];
3013 let mut interned: InternedPackageManifest = packages.into();
3014
3015 interned.versions.icons.pop();
3016
3017 let result = interned.validate();
3018
3019 assert!(result.is_err());
3020
3021 assert!(result.unwrap_err().contains("icons length"));
3022 }
3023
3024 #[test]
3025 fn test_interned_manifest_validate_mismatched_version_downloads_length() {
3026 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
3027 let packages = vec![pkg];
3028 let mut interned: InternedPackageManifest = packages.into();
3029
3030 interned.versions.downloads.pop();
3031
3032 let result = interned.validate();
3033
3034 assert!(result.is_err());
3035
3036 assert!(result.unwrap_err().contains("downloads length"));
3037 }
3038
3039 #[test]
3040 fn test_interned_manifest_validate_mismatched_version_website_urls_length() {
3041 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
3042 let packages = vec![pkg];
3043 let mut interned: InternedPackageManifest = packages.into();
3044
3045 interned.versions.website_urls.pop();
3046
3047 let result = interned.validate();
3048
3049 assert!(result.is_err());
3050
3051 assert!(result.unwrap_err().contains("website_urls length"));
3052 }
3053
3054 #[test]
3055 fn test_interned_manifest_validate_mismatched_version_is_active_length() {
3056 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
3057 let packages = vec![pkg];
3058 let mut interned: InternedPackageManifest = packages.into();
3059
3060 interned.versions.is_active.pop();
3061
3062 let result = interned.validate();
3063
3064 assert!(result.is_err());
3065
3066 assert!(result.unwrap_err().contains("is_active length"));
3067 }
3068
3069 #[test]
3070 fn test_interned_manifest_validate_mismatched_version_uuid4s_length() {
3071 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
3072 let packages = vec![pkg];
3073 let mut interned: InternedPackageManifest = packages.into();
3074
3075 interned.versions.uuid4s.pop();
3076
3077 let result = interned.validate();
3078
3079 assert!(result.is_err());
3080
3081 assert!(result.unwrap_err().contains("uuid4s length"));
3082 }
3083
3084 #[test]
3085 fn test_interned_manifest_validate_mismatched_version_file_sizes_length() {
3086 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
3087 let packages = vec![pkg];
3088 let mut interned: InternedPackageManifest = packages.into();
3089
3090 interned.versions.file_sizes.pop();
3091
3092 let result = interned.validate();
3093
3094 assert!(result.is_err());
3095
3096 assert!(result.unwrap_err().contains("file_sizes length"));
3097 }
3098
3099 #[test]
3100 fn test_interned_manifest_validate_invalid_version_range() {
3101 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
3102 let packages = vec![pkg];
3103 let mut interned: InternedPackageManifest = packages.into();
3104
3105 interned.version_ranges[0] = (5, 3);
3106
3107 let result = interned.validate();
3108
3109 assert!(result.is_err());
3110
3111 assert!(result.unwrap_err().contains("Invalid version range"));
3112 }
3113
3114 #[test]
3115 fn test_interned_manifest_validate_version_range_out_of_bounds() {
3116 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
3117 let packages = vec![pkg];
3118 let mut interned: InternedPackageManifest = packages.into();
3119
3120 interned.version_ranges[0] = (0, 999);
3121
3122 let result = interned.validate();
3123
3124 assert!(result.is_err());
3125
3126 assert!(result.unwrap_err().contains("ends at"));
3127 }
3128
3129 #[test]
3130 fn test_interned_manifest_serialization_round_trip() {
3131 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
3132 let packages = vec![pkg.clone()];
3133 let interned: InternedPackageManifest = packages.into();
3134
3135 let serializable: SerializableInternedManifest = (&interned).into();
3136
3137 let binary = bincode::serialize(&serializable).unwrap();
3138
3139 let deserialized: SerializableInternedManifest = bincode::deserialize(&binary).unwrap();
3140
3141 let recovered: InternedPackageManifest = deserialized.into();
3142
3143 assert_eq!(recovered.len(), 1);
3144
3145 assert_eq!(recovered.resolve_name_at(0), Some("TestMod".to_string()));
3146
3147 assert_eq!(
3148 recovered.resolve_full_name_at(0),
3149 Some("TestOwner-TestMod".to_string())
3150 );
3151
3152 let recovered_pkg = recovered.get_package_at(0);
3153
3154 assert_eq!(recovered_pkg.name, pkg.name);
3155
3156 assert_eq!(recovered_pkg.full_name, pkg.full_name);
3157
3158 assert_eq!(recovered_pkg.versions.len(), pkg.versions.len());
3159 }
3160
3161 #[test]
3162 fn test_interned_manifest_conversion_from_package_manifest() {
3163 let pkg = create_test_package("TestMod", "TestOwner", "1.0.0");
3164 let packages = vec![pkg];
3165 let v2_manifest: PackageManifest = packages.into();
3166
3167 let interned: InternedPackageManifest = v2_manifest.clone().into();
3168
3169 assert_eq!(interned.len(), v2_manifest.len());
3170
3171 assert_eq!(interned.resolve_name_at(0), v2_manifest.names[0].clone());
3172
3173 assert_eq!(
3174 interned.resolve_full_name_at(0),
3175 v2_manifest.full_names[0].clone()
3176 );
3177 }
3178
3179 #[test]
3180 fn test_interned_manifest_dependency_graph_resolve() {
3181 let pkg1 = create_test_package("ModA", "Owner1", "1.0.0");
3182 let pkg2 = create_test_package_with_dependencies(
3183 "ModB",
3184 "Owner2",
3185 "2.0.0",
3186 vec!["Owner3-ModC".to_string()],
3187 );
3188 let pkg3 = create_test_package_with_dependencies(
3189 "ModC",
3190 "Owner3",
3191 "1.5.0",
3192 vec!["Owner4-ModD".to_string()],
3193 );
3194 let pkg4 = create_test_package("ModD", "Owner4", "0.9.0");
3195
3196 let packages = vec![pkg1, pkg2, pkg3, pkg4];
3197 let interned: InternedPackageManifest = packages.into();
3198
3199 let dg1 = DependencyGraph::new(vec!["Owner1-ModA".to_string()]);
3200 let result1 = dg1.resolve_interned(&interned);
3201
3202 assert_eq!(result1.len(), 1);
3203
3204 assert!(result1.contains_key("Owner1-ModA-1.0.0.zip"));
3205
3206 let dg2 = DependencyGraph::new(vec!["Owner2-ModB".to_string()]);
3207 let result2 = dg2.resolve_interned(&interned);
3208
3209 assert_eq!(result2.len(), 3);
3210
3211 assert!(result2.contains_key("Owner2-ModB-2.0.0.zip"));
3212
3213 assert!(result2.contains_key("Owner3-ModC-1.5.0.zip"));
3214
3215 assert!(result2.contains_key("Owner4-ModD-0.9.0.zip"));
3216 }
3217
3218 #[test]
3219 fn test_interned_manifest_dependency_graph_resolve_with_missing_dependency() {
3220 let pkg1 = create_test_package("ModA", "Owner1", "1.0.0");
3221 let pkg2 = create_test_package_with_dependencies(
3222 "ModB",
3223 "Owner2",
3224 "2.0.0",
3225 vec!["Owner3-NonExistent".to_string()],
3226 );
3227
3228 let packages = vec![pkg1, pkg2];
3229 let interned: InternedPackageManifest = packages.into();
3230
3231 let dg = DependencyGraph::new(vec!["Owner2-ModB".to_string()]);
3232 let result = dg.resolve_interned(&interned);
3233
3234 assert_eq!(result.len(), 1);
3235
3236 assert!(result.contains_key("Owner2-ModB-2.0.0.zip"));
3237 }
3238
3239 #[test]
3240 fn test_interned_manifest_dependency_graph_resolve_with_version_suffix() {
3241 let pkg1 = create_test_package("ModA", "Owner1", "1.0.0");
3242
3243 let packages = vec![pkg1];
3244 let interned: InternedPackageManifest = packages.into();
3245
3246 let dg = DependencyGraph::new(vec!["Owner1-ModA-1.0.0".to_string()]);
3247 let result = dg.resolve_interned(&interned);
3248
3249 assert_eq!(result.len(), 1);
3250
3251 assert!(result.contains_key("Owner1-ModA-1.0.0.zip"));
3252 }
3253}