1#[macro_export]
50macro_rules! impl_dependency {
51 ($type:ty {
52 name: $name:ident,
53 name_range: $name_range:ident,
54 version: $version:ident,
55 version_range: $version_range:ident $(,)?
56 }) => {
57 impl $crate::ecosystem::Dependency for $type {
58 fn name(&self) -> &$crate::PackageName {
59 &self.$name
60 }
61
62 fn name_range(&self) -> $crate::position::Range {
63 self.$name_range
64 }
65
66 fn version_requirement(&self) -> Option<&$crate::VersionReq> {
67 self.$version.as_ref()
68 }
69
70 fn version_range(&self) -> Option<$crate::position::Range> {
71 self.$version_range
72 }
73
74 fn source(&self) -> $crate::parser::DependencySource {
75 $crate::parser::DependencySource::Registry
76 }
77
78 fn as_any(&self) -> &dyn ::std::any::Any {
79 self
80 }
81 }
82 };
83 ($type:ty {
84 name: $name:ident,
85 name_range: $name_range:ident,
86 version: $version:ident,
87 version_range: $version_range:ident,
88 source: $source:ident $(,)?
89 }) => {
90 impl $crate::ecosystem::Dependency for $type {
91 fn name(&self) -> &$crate::PackageName {
92 &self.$name
93 }
94
95 fn name_range(&self) -> $crate::position::Range {
96 self.$name_range
97 }
98
99 fn version_requirement(&self) -> Option<&$crate::VersionReq> {
100 self.$version.as_ref()
101 }
102
103 fn version_range(&self) -> Option<$crate::position::Range> {
104 self.$version_range
105 }
106
107 fn source(&self) -> $crate::parser::DependencySource {
108 self.$source.clone()
109 }
110
111 fn as_any(&self) -> &dyn ::std::any::Any {
112 self
113 }
114 }
115 };
116 ($type:ty {
117 name: $name:ident,
118 name_range: $name_range:ident,
119 version: $version:ident,
120 version_range: $version_range:ident,
121 source: $source:ident,
122 version_literal: $version_literal:ident $(,)?
123 }) => {
124 impl $crate::ecosystem::Dependency for $type {
125 fn name(&self) -> &$crate::PackageName {
126 &self.$name
127 }
128
129 fn name_range(&self) -> $crate::position::Range {
130 self.$name_range
131 }
132
133 fn version_requirement(&self) -> Option<&$crate::VersionReq> {
134 self.$version.as_ref()
135 }
136
137 fn version_range(&self) -> Option<$crate::position::Range> {
138 self.$version_range
139 }
140
141 fn source(&self) -> $crate::parser::DependencySource {
142 self.$source.clone()
143 }
144
145 fn version_literal(&self) -> Option<&str> {
146 self.$version_literal.as_deref()
147 }
148
149 fn as_any(&self) -> &dyn ::std::any::Any {
150 self
151 }
152 }
153 };
154}
155
156#[macro_export]
234macro_rules! impl_version {
235 ($type:ty {
236 version: $version:ident,
237 status: $status:expr $(,)?
238 }) => {
239 impl $crate::registry::Version for $type {
240 fn version_string(&self) -> &$crate::ConcreteVersion {
241 &self.$version
242 }
243
244 fn removal_status(&self) -> $crate::registry::RemovalStatus {
245 ($status)(self)
246 }
247
248 fn as_any(&self) -> &dyn ::std::any::Any {
249 self
250 }
251 }
252 };
253 ($type:ty {
254 version: $version:ident,
255 status: $status:expr,
256 published_at: $published_at:ident $(,)?
257 }) => {
258 impl $crate::registry::Version for $type {
259 fn version_string(&self) -> &$crate::ConcreteVersion {
260 &self.$version
261 }
262
263 fn removal_status(&self) -> $crate::registry::RemovalStatus {
264 ($status)(self)
265 }
266
267 fn published_at(&self) -> Option<$crate::freshness::PublishTime> {
268 self.$published_at
269 }
270
271 fn as_any(&self) -> &dyn ::std::any::Any {
272 self
273 }
274 }
275 };
276 ($type:ty {
277 version: $version:ident,
278 status: $status:expr,
279 prerelease: $prerelease:expr $(,)?
280 }) => {
281 impl $crate::registry::Version for $type {
282 fn version_string(&self) -> &$crate::ConcreteVersion {
283 &self.$version
284 }
285
286 fn removal_status(&self) -> $crate::registry::RemovalStatus {
287 ($status)(self)
288 }
289
290 fn is_prerelease(&self) -> bool {
291 ($prerelease)(self)
292 }
293
294 fn as_any(&self) -> &dyn ::std::any::Any {
295 self
296 }
297 }
298 };
299 ($type:ty {
300 version: $version:ident,
301 status: $status:expr,
302 published_at: $published_at:ident,
303 prerelease: $prerelease:expr $(,)?
304 }) => {
305 impl $crate::registry::Version for $type {
306 fn version_string(&self) -> &$crate::ConcreteVersion {
307 &self.$version
308 }
309
310 fn removal_status(&self) -> $crate::registry::RemovalStatus {
311 ($status)(self)
312 }
313
314 fn published_at(&self) -> Option<$crate::freshness::PublishTime> {
315 self.$published_at
316 }
317
318 fn is_prerelease(&self) -> bool {
319 ($prerelease)(self)
320 }
321
322 fn as_any(&self) -> &dyn ::std::any::Any {
323 self
324 }
325 }
326 };
327 ($type:ty {
328 version: $version:ident,
329 status: $status:expr,
330 published_at: $published_at:ident,
331 prerelease: $prerelease:expr,
332 deprecation: $deprecation:expr $(,)?
333 }) => {
334 impl $crate::registry::Version for $type {
335 fn version_string(&self) -> &$crate::ConcreteVersion {
336 &self.$version
337 }
338
339 fn removal_status(&self) -> $crate::registry::RemovalStatus {
340 ($status)(self)
341 }
342
343 fn published_at(&self) -> Option<$crate::freshness::PublishTime> {
344 self.$published_at
345 }
346
347 fn is_prerelease(&self) -> bool {
348 ($prerelease)(self)
349 }
350
351 fn deprecation(&self) -> Option<&$crate::registry::Deprecation> {
352 let f: fn(&$type) -> Option<&$crate::registry::Deprecation> = $deprecation;
358 f(self)
359 }
360
361 fn as_any(&self) -> &dyn ::std::any::Any {
362 self
363 }
364 }
365 };
366 ($type:ty {
367 version: $version:ident,
368 status: $status:expr,
369 published_at: $published_at:ident,
370 prerelease: $prerelease:expr,
371 deprecation: $deprecation:expr,
372 license: $license:ident $(,)?
373 }) => {
374 impl $crate::registry::Version for $type {
375 fn version_string(&self) -> &$crate::ConcreteVersion {
376 &self.$version
377 }
378
379 fn removal_status(&self) -> $crate::registry::RemovalStatus {
380 ($status)(self)
381 }
382
383 fn published_at(&self) -> Option<$crate::freshness::PublishTime> {
384 self.$published_at
385 }
386
387 fn is_prerelease(&self) -> bool {
388 ($prerelease)(self)
389 }
390
391 fn deprecation(&self) -> Option<&$crate::registry::Deprecation> {
392 let f: fn(&$type) -> Option<&$crate::registry::Deprecation> = $deprecation;
393 f(self)
394 }
395
396 fn license(&self) -> &[String] {
397 &self.$license
398 }
399
400 fn as_any(&self) -> &dyn ::std::any::Any {
401 self
402 }
403 }
404 };
405}
406
407#[macro_export]
440macro_rules! impl_metadata {
441 ($type:ty {
442 name: $name:ident,
443 description: $description:ident,
444 repository: $repository:ident,
445 documentation: $documentation:ident,
446 latest_version: $latest_version:ident $(,)?
447 }) => {
448 impl $crate::registry::Metadata for $type {
449 fn name(&self) -> &$crate::PackageName {
450 &self.$name
451 }
452
453 fn description(&self) -> Option<&str> {
454 self.$description.as_deref()
455 }
456
457 fn repository(&self) -> Option<&str> {
458 self.$repository.as_deref()
459 }
460
461 fn documentation(&self) -> Option<&str> {
462 self.$documentation.as_deref()
463 }
464
465 fn latest_version(&self) -> &$crate::ConcreteVersion {
466 &self.$latest_version
467 }
468
469 fn as_any(&self) -> &dyn ::std::any::Any {
470 self
471 }
472 }
473 };
474}
475
476#[macro_export]
531macro_rules! impl_parse_result {
532 ($type:ty, $dep_type:ty {
533 dependencies: $dependencies:ident,
534 uri: $uri:ident $(,)?
535 }) => {
536 impl $crate::ecosystem::ParseResult for $type {
537 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
538 self.$dependencies
539 .iter()
540 .map(|d| d as &dyn $crate::ecosystem::Dependency)
541 .collect()
542 }
543
544 fn workspace_root(&self) -> Option<&::std::path::Path> {
545 None
546 }
547
548 fn uri(&self) -> &::url::Url {
549 &self.$uri
550 }
551
552 fn as_any(&self) -> &dyn ::std::any::Any {
553 self
554 }
555 }
556 };
557 ($type:ty, $dep_type:ty {
558 dependencies: $dependencies:ident,
559 uri: $uri:ident,
560 workspace_root: $workspace_root:ident $(,)?
561 }) => {
562 impl $crate::ecosystem::ParseResult for $type {
563 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
564 self.$dependencies
565 .iter()
566 .map(|d| d as &dyn $crate::ecosystem::Dependency)
567 .collect()
568 }
569
570 fn workspace_root(&self) -> Option<&::std::path::Path> {
571 self.$workspace_root.as_deref()
572 }
573
574 fn uri(&self) -> &::url::Url {
575 &self.$uri
576 }
577
578 fn as_any(&self) -> &dyn ::std::any::Any {
579 self
580 }
581 }
582 };
583 ($type:ty, $dep_type:ty {
584 dependencies: $dependencies:ident,
585 uri: $uri:ident,
586 dependency_truncation: $dependency_truncation:ident $(,)?
587 }) => {
588 impl $crate::ecosystem::ParseResult for $type {
589 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
590 self.$dependencies
591 .iter()
592 .map(|d| d as &dyn $crate::ecosystem::Dependency)
593 .collect()
594 }
595
596 fn workspace_root(&self) -> Option<&::std::path::Path> {
597 None
598 }
599
600 fn uri(&self) -> &::url::Url {
601 &self.$uri
602 }
603
604 fn as_any(&self) -> &dyn ::std::any::Any {
605 self
606 }
607
608 fn dependency_truncation(&self) -> Option<(usize, usize)> {
609 self.$dependency_truncation
610 }
611 }
612 };
613 ($type:ty, $dep_type:ty {
614 dependencies: $dependencies:ident,
615 uri: $uri:ident,
616 workspace_root: $workspace_root:ident,
617 dependency_truncation: $dependency_truncation:ident $(,)?
618 }) => {
619 impl $crate::ecosystem::ParseResult for $type {
620 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
621 self.$dependencies
622 .iter()
623 .map(|d| d as &dyn $crate::ecosystem::Dependency)
624 .collect()
625 }
626
627 fn workspace_root(&self) -> Option<&::std::path::Path> {
628 self.$workspace_root.as_deref()
629 }
630
631 fn uri(&self) -> &::url::Url {
632 &self.$uri
633 }
634
635 fn as_any(&self) -> &dyn ::std::any::Any {
636 self
637 }
638
639 fn dependency_truncation(&self) -> Option<(usize, usize)> {
640 self.$dependency_truncation
641 }
642 }
643 };
644 ($type:ty, $dep_type:ty {
645 dependencies: $dependencies:ident,
646 uri: $uri:ident,
647 blocked_registries: $blocked_registries:ident $(,)?
648 }) => {
649 impl $crate::ecosystem::ParseResult for $type {
650 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
651 self.$dependencies
652 .iter()
653 .map(|d| d as &dyn $crate::ecosystem::Dependency)
654 .collect()
655 }
656
657 fn workspace_root(&self) -> Option<&::std::path::Path> {
658 None
659 }
660
661 fn uri(&self) -> &::url::Url {
662 &self.$uri
663 }
664
665 fn blocked_registries(&self) -> Vec<$crate::ecosystem::BlockedRegistryOccurrence> {
666 self.$blocked_registries.clone()
667 }
668
669 fn as_any(&self) -> &dyn ::std::any::Any {
670 self
671 }
672 }
673 };
674 ($type:ty, $dep_type:ty {
675 dependencies: $dependencies:ident,
676 uri: $uri:ident,
677 workspace_root: $workspace_root:ident,
678 blocked_registries: $blocked_registries:ident $(,)?
679 }) => {
680 impl $crate::ecosystem::ParseResult for $type {
681 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
682 self.$dependencies
683 .iter()
684 .map(|d| d as &dyn $crate::ecosystem::Dependency)
685 .collect()
686 }
687
688 fn workspace_root(&self) -> Option<&::std::path::Path> {
689 self.$workspace_root.as_deref()
690 }
691
692 fn uri(&self) -> &::url::Url {
693 &self.$uri
694 }
695
696 fn blocked_registries(&self) -> Vec<$crate::ecosystem::BlockedRegistryOccurrence> {
697 self.$blocked_registries.clone()
698 }
699
700 fn as_any(&self) -> &dyn ::std::any::Any {
701 self
702 }
703 }
704 };
705 ($type:ty, $dep_type:ty {
706 dependencies: $dependencies:ident,
707 uri: $uri:ident,
708 dependency_truncation: $dependency_truncation:ident,
709 blocked_registries: $blocked_registries:ident $(,)?
710 }) => {
711 impl $crate::ecosystem::ParseResult for $type {
712 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
713 self.$dependencies
714 .iter()
715 .map(|d| d as &dyn $crate::ecosystem::Dependency)
716 .collect()
717 }
718
719 fn workspace_root(&self) -> Option<&::std::path::Path> {
720 None
721 }
722
723 fn uri(&self) -> &::url::Url {
724 &self.$uri
725 }
726
727 fn blocked_registries(&self) -> Vec<$crate::ecosystem::BlockedRegistryOccurrence> {
728 self.$blocked_registries.clone()
729 }
730
731 fn as_any(&self) -> &dyn ::std::any::Any {
732 self
733 }
734
735 fn dependency_truncation(&self) -> Option<(usize, usize)> {
736 self.$dependency_truncation
737 }
738 }
739 };
740 ($type:ty, $dep_type:ty {
741 dependencies: $dependencies:ident,
742 uri: $uri:ident,
743 workspace_root: $workspace_root:ident,
744 dependency_truncation: $dependency_truncation:ident,
745 blocked_registries: $blocked_registries:ident $(,)?
746 }) => {
747 impl $crate::ecosystem::ParseResult for $type {
748 fn dependencies(&self) -> Vec<&dyn $crate::ecosystem::Dependency> {
749 self.$dependencies
750 .iter()
751 .map(|d| d as &dyn $crate::ecosystem::Dependency)
752 .collect()
753 }
754
755 fn workspace_root(&self) -> Option<&::std::path::Path> {
756 self.$workspace_root.as_deref()
757 }
758
759 fn uri(&self) -> &::url::Url {
760 &self.$uri
761 }
762
763 fn blocked_registries(&self) -> Vec<$crate::ecosystem::BlockedRegistryOccurrence> {
764 self.$blocked_registries.clone()
765 }
766
767 fn as_any(&self) -> &dyn ::std::any::Any {
768 self
769 }
770
771 fn dependency_truncation(&self) -> Option<(usize, usize)> {
772 self.$dependency_truncation
773 }
774 }
775 };
776}
777
778#[macro_export]
804macro_rules! impl_registry_versions_method {
805 (get_versions) => {
806 fn get_versions<'a>(
807 &'a self,
808 name: &'a $crate::PackageName,
809 ) -> $crate::ecosystem::BoxFuture<
810 'a,
811 $crate::error::Result<::std::vec::Vec<::std::boxed::Box<dyn $crate::Version>>>,
812 > {
813 ::std::boxed::Box::pin(async move {
814 let versions = self.get_versions(name.as_str()).await?;
815 Ok(versions
816 .into_iter()
817 .map(|v| ::std::boxed::Box::new(v) as ::std::boxed::Box<dyn $crate::Version>)
818 .collect())
819 })
820 }
821 };
822 (get_versions_with) => {
823 fn get_versions_with<'a>(
824 &'a self,
825 name: &'a $crate::PackageName,
826 freshness: $crate::FreshnessSettings,
827 ) -> $crate::ecosystem::BoxFuture<
828 'a,
829 $crate::error::Result<::std::vec::Vec<::std::boxed::Box<dyn $crate::Version>>>,
830 > {
831 ::std::boxed::Box::pin(async move {
832 let versions = self.get_versions_with(name.as_str(), freshness).await?;
833 Ok(versions
834 .into_iter()
835 .map(|v| ::std::boxed::Box::new(v) as ::std::boxed::Box<dyn $crate::Version>)
836 .collect())
837 })
838 }
839 };
840}
841
842#[macro_export]
869macro_rules! impl_get_versions_with_passthrough {
870 ($type:ty, $version:ty $(,)?) => {
871 impl $type {
872 pub async fn get_versions_with(
881 &self,
882 name: &str,
883 _freshness: $crate::FreshnessSettings,
884 ) -> $crate::error::Result<::std::vec::Vec<$version>> {
885 self.get_versions(name).await
886 }
887 }
888 };
889}
890
891#[cfg(test)]
892mod tests {
893 use crate::ConcreteVersion;
894 use crate::position::{Position, Range};
895
896 #[derive(Debug, Clone)]
897 struct TestDependency {
898 name: crate::PackageName,
899 name_range: Range,
900 version_req: Option<crate::VersionReq>,
901 version_range: Option<Range>,
902 }
903
904 #[derive(Debug, Clone)]
905 struct TestDependencyWithSource {
906 name: crate::PackageName,
907 name_range: Range,
908 version_req: Option<crate::VersionReq>,
909 version_range: Option<Range>,
910 source: crate::parser::DependencySource,
911 version_literal: Option<String>,
912 }
913
914 #[derive(Debug, Clone)]
915 struct TestVersion {
916 version: ConcreteVersion,
917 yanked: bool,
918 }
919
920 #[derive(Debug, Clone)]
921 struct TestVersionWithPublishedAt {
922 version: ConcreteVersion,
923 yanked: bool,
924 published_at: Option<crate::freshness::PublishTime>,
925 }
926
927 #[derive(Debug, Clone)]
928 struct TestVersionWithPrerelease {
929 version: ConcreteVersion,
930 yanked: bool,
931 }
932
933 #[derive(Debug, Clone)]
934 struct TestVersionWithPublishedAtAndPrerelease {
935 version: ConcreteVersion,
936 yanked: bool,
937 published_at: Option<crate::freshness::PublishTime>,
938 }
939
940 #[derive(Debug, Clone)]
941 struct TestPackage {
942 name: crate::PackageName,
943 description: Option<String>,
944 repository: Option<String>,
945 homepage: Option<String>,
946 latest_version: ConcreteVersion,
947 }
948
949 #[derive(Debug)]
950 struct TestParseResult {
951 dependencies: Vec<TestDependency>,
952 uri: url::Url,
953 }
954
955 impl_dependency!(TestDependency {
956 name: name,
957 name_range: name_range,
958 version: version_req,
959 version_range: version_range,
960 });
961
962 impl_dependency!(TestDependencyWithSource {
963 name: name,
964 name_range: name_range,
965 version: version_req,
966 version_range: version_range,
967 source: source,
968 version_literal: version_literal,
969 });
970
971 impl_version!(TestVersion {
972 version: version,
973 status: |v: &TestVersion| crate::registry::RemovalStatus::from_yanked(v.yanked),
974 });
975
976 impl_version!(TestVersionWithPublishedAt {
977 version: version,
978 status: |v: &TestVersionWithPublishedAt| crate::registry::RemovalStatus::from_yanked(
979 v.yanked
980 ),
981 published_at: published_at,
982 });
983
984 impl_version!(TestVersionWithPrerelease {
985 version: version,
986 status: |v: &TestVersionWithPrerelease| crate::registry::RemovalStatus::from_yanked(
987 v.yanked
988 ),
989 prerelease: |v: &TestVersionWithPrerelease| v.version.as_str().contains(".pre"),
990 });
991
992 impl_version!(TestVersionWithPublishedAtAndPrerelease {
993 version: version,
994 status: |v: &TestVersionWithPublishedAtAndPrerelease| {
995 crate::registry::RemovalStatus::from_yanked(v.yanked)
996 },
997 published_at: published_at,
998 prerelease: |v: &TestVersionWithPublishedAtAndPrerelease| v
999 .version
1000 .as_str()
1001 .contains(".pre"),
1002 });
1003
1004 impl_metadata!(TestPackage {
1005 name: name,
1006 description: description,
1007 repository: repository,
1008 documentation: homepage,
1009 latest_version: latest_version,
1010 });
1011
1012 impl_parse_result!(
1013 TestParseResult,
1014 TestDependency {
1015 dependencies: dependencies,
1016 uri: uri,
1017 }
1018 );
1019
1020 #[test]
1021 fn test_impl_dependency_macro() {
1022 use crate::ecosystem::Dependency;
1023
1024 let dep = TestDependency {
1025 name: "test-pkg".into(),
1026 name_range: Range::new(Position::new(0, 0), Position::new(0, 8)),
1027 version_req: Some("1.0.0".into()),
1028 version_range: Some(Range::new(Position::new(0, 10), Position::new(0, 15))),
1029 };
1030
1031 assert_eq!(dep.name(), "test-pkg");
1032 assert_eq!(
1033 dep.version_requirement().map(crate::VersionReq::as_str),
1034 Some("1.0.0")
1035 );
1036 assert!(dep.as_any().is::<TestDependency>());
1037 assert!(matches!(
1038 dep.source(),
1039 crate::parser::DependencySource::Registry
1040 ));
1041 }
1042
1043 #[test]
1044 fn test_impl_dependency_macro_with_source_and_version_literal() {
1045 use crate::ecosystem::Dependency;
1046
1047 let dep = TestDependencyWithSource {
1048 name: "test-pkg".into(),
1049 name_range: Range::new(Position::new(0, 0), Position::new(0, 8)),
1050 version_req: Some("1.0.0".into()),
1051 version_range: Some(Range::new(Position::new(0, 10), Position::new(0, 15))),
1052 source: crate::parser::DependencySource::Git {
1053 url: "https://example.com/repo.git".into(),
1054 rev: None,
1055 },
1056 version_literal: Some("v1.0.0".into()),
1057 };
1058
1059 assert!(matches!(
1060 dep.source(),
1061 crate::parser::DependencySource::Git { .. }
1062 ));
1063 assert_eq!(dep.version_literal(), Some("v1.0.0"));
1064 }
1065
1066 #[test]
1067 fn test_impl_version_macro() {
1068 use crate::registry::Version;
1069
1070 let version = TestVersion {
1071 version: "2.0.0".into(),
1072 yanked: true,
1073 };
1074
1075 assert_eq!(version.version_string().as_str(), "2.0.0");
1076 assert!(version.removal_status().blocks_resolution());
1077 assert!(version.as_any().is::<TestVersion>());
1078 assert!(version.published_at().is_none());
1079 }
1080
1081 #[test]
1082 fn test_impl_version_macro_with_published_at() {
1083 use crate::freshness::PublishTime;
1084 use crate::registry::Version;
1085
1086 let version = TestVersionWithPublishedAt {
1087 version: "3.0.0".into(),
1088 yanked: false,
1089 published_at: Some(PublishTime::from_unix_secs(1_000)),
1090 };
1091
1092 assert_eq!(version.version_string().as_str(), "3.0.0");
1093 assert!(!version.removal_status().blocks_resolution());
1094 assert_eq!(
1095 version.published_at(),
1096 Some(PublishTime::from_unix_secs(1_000))
1097 );
1098 assert!(version.as_any().is::<TestVersionWithPublishedAt>());
1099 }
1100
1101 #[test]
1102 fn test_impl_version_macro_with_prerelease() {
1103 use crate::registry::Version;
1104
1105 let stable = TestVersionWithPrerelease {
1106 version: "1.0.0".into(),
1107 yanked: false,
1108 };
1109 let prerelease = TestVersionWithPrerelease {
1110 version: "1.0.0.pre1".into(),
1111 yanked: false,
1112 };
1113
1114 assert!(!stable.is_prerelease());
1115 assert!(prerelease.is_prerelease());
1116 assert!(stable.is_stable());
1117 assert!(!prerelease.is_stable());
1118 }
1119
1120 #[test]
1121 fn test_impl_version_macro_with_published_at_and_prerelease() {
1122 use crate::freshness::PublishTime;
1123 use crate::registry::Version;
1124
1125 let version = TestVersionWithPublishedAtAndPrerelease {
1126 version: "2.0.0.pre1".into(),
1127 yanked: false,
1128 published_at: Some(PublishTime::from_unix_secs(2_000)),
1129 };
1130
1131 assert!(version.is_prerelease());
1132 assert_eq!(
1133 version.published_at(),
1134 Some(PublishTime::from_unix_secs(2_000))
1135 );
1136 }
1137
1138 #[test]
1139 fn test_impl_metadata_macro() {
1140 use crate::registry::Metadata;
1141
1142 let pkg = TestPackage {
1143 name: crate::PackageName::new("my-pkg"),
1144 description: Some("A test package".into()),
1145 repository: Some("user/repo".into()),
1146 homepage: Some("https://example.com".into()),
1147 latest_version: "3.0.0".into(),
1148 };
1149
1150 assert_eq!(pkg.name(), "my-pkg");
1151 assert_eq!(pkg.description(), Some("A test package"));
1152 assert_eq!(pkg.documentation(), Some("https://example.com"));
1153 assert!(pkg.as_any().is::<TestPackage>());
1154 }
1155
1156 #[test]
1157 fn test_impl_parse_result_macro() {
1158 use crate::ecosystem::ParseResult;
1159
1160 let result = TestParseResult {
1161 dependencies: vec![TestDependency {
1162 name: "dep1".into(),
1163 name_range: Range::default(),
1164 version_req: None,
1165 version_range: None,
1166 }],
1167 uri: crate::test_util::test_uri("/test"),
1168 };
1169
1170 assert_eq!(result.dependencies().len(), 1);
1171 assert!(result.workspace_root().is_none());
1172 assert!(result.as_any().is::<TestParseResult>());
1173 }
1174}