1use std::borrow::Cow;
2use std::cmp::Ordering;
3use std::fmt::Formatter;
4use std::ops::Bound;
5use std::str::FromStr;
6
7use crate::{
8 Operator, OperatorParseError, Version, VersionPattern, VersionPatternParseError, version,
9};
10use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
11#[cfg(feature = "tracing")]
12use tracing::warn;
13
14#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
30#[cfg_attr(
31 feature = "rkyv",
32 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
33)]
34#[cfg_attr(feature = "rkyv", rkyv(derive(Debug)))]
35pub struct VersionSpecifiers(Box<[VersionSpecifier]>);
36
37impl std::ops::Deref for VersionSpecifiers {
38 type Target = [VersionSpecifier];
39
40 fn deref(&self) -> &Self::Target {
41 &self.0
42 }
43}
44
45impl VersionSpecifiers {
46 pub fn empty() -> Self {
48 Self(Box::new([]))
49 }
50
51 pub fn len(&self) -> usize {
53 self.0.len()
54 }
55
56 pub fn contains(&self, version: &Version) -> bool {
58 self.iter().all(|specifier| specifier.contains(version))
59 }
60
61 pub fn is_empty(&self) -> bool {
63 self.0.is_empty()
64 }
65
66 fn from_unsorted(mut specifiers: Vec<VersionSpecifier>) -> Self {
68 specifiers.sort_by(|a, b| a.version().cmp(b.version()));
71 Self(specifiers.into_boxed_slice())
72 }
73
74 pub fn from_release_only_bounds<'a>(
78 mut bounds: impl Iterator<Item = (&'a Bound<Version>, &'a Bound<Version>)>,
79 ) -> Self {
80 let mut specifiers = Vec::new();
81
82 let Some((start, mut next)) = bounds.next() else {
83 return Self::empty();
84 };
85
86 for (lower, upper) in bounds {
88 let specifier = match (next, lower) {
89 (Bound::Excluded(prev), Bound::Excluded(lower)) if prev == lower => {
91 Some(VersionSpecifier::not_equals_version(prev.clone()))
92 }
93 (Bound::Excluded(prev), Bound::Included(lower)) => {
95 match *prev.only_release_trimmed().release() {
96 [major] if *lower.only_release_trimmed().release() == [major, 1] => {
97 Some(VersionSpecifier::not_equals_star_version(Version::new([
98 major, 0,
99 ])))
100 }
101 [major, minor]
102 if *lower.only_release_trimmed().release() == [major, minor + 1] =>
103 {
104 Some(VersionSpecifier::not_equals_star_version(Version::new([
105 major, minor,
106 ])))
107 }
108 _ => None,
109 }
110 }
111 _ => None,
112 };
113 if let Some(specifier) = specifier {
114 specifiers.push(specifier);
115 } else {
116 #[cfg(feature = "tracing")]
117 warn!(
118 "Ignoring unsupported gap in `requires-python` version: {next:?} -> {lower:?}"
119 );
120 }
121 next = upper;
122 }
123 let end = next;
124
125 specifiers.extend(VersionSpecifier::from_release_only_bounds((start, end)));
127
128 Self::from_unsorted(specifiers)
129 }
130}
131
132impl FromIterator<VersionSpecifier> for VersionSpecifiers {
133 fn from_iter<T: IntoIterator<Item = VersionSpecifier>>(iter: T) -> Self {
134 Self::from_unsorted(iter.into_iter().collect())
135 }
136}
137
138impl IntoIterator for VersionSpecifiers {
139 type Item = VersionSpecifier;
140 type IntoIter = std::vec::IntoIter<VersionSpecifier>;
141
142 fn into_iter(self) -> Self::IntoIter {
143 self.0.into_vec().into_iter()
144 }
145}
146
147impl FromStr for VersionSpecifiers {
148 type Err = VersionSpecifiersParseError;
149
150 fn from_str(s: &str) -> Result<Self, Self::Err> {
151 parse_version_specifiers(s).map(Self::from_unsorted)
152 }
153}
154
155impl From<VersionSpecifier> for VersionSpecifiers {
156 fn from(specifier: VersionSpecifier) -> Self {
157 Self(Box::new([specifier]))
158 }
159}
160
161impl std::fmt::Display for VersionSpecifiers {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 for (idx, version_specifier) in self.0.iter().enumerate() {
164 if idx == 0 {
167 write!(f, "{version_specifier}")?;
168 } else {
169 write!(f, ", {version_specifier}")?;
170 }
171 }
172 Ok(())
173 }
174}
175
176impl Default for VersionSpecifiers {
177 fn default() -> Self {
178 Self::empty()
179 }
180}
181
182impl<'de> Deserialize<'de> for VersionSpecifiers {
183 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
184 where
185 D: Deserializer<'de>,
186 {
187 struct Visitor;
188
189 impl de::Visitor<'_> for Visitor {
190 type Value = VersionSpecifiers;
191
192 fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
193 f.write_str("a string")
194 }
195
196 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
197 VersionSpecifiers::from_str(v).map_err(de::Error::custom)
198 }
199 }
200
201 deserializer.deserialize_str(Visitor)
202 }
203}
204
205impl Serialize for VersionSpecifiers {
206 #[allow(unstable_name_collisions)]
207 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
208 where
209 S: Serializer,
210 {
211 serializer.serialize_str(
212 &self
213 .iter()
214 .map(ToString::to_string)
215 .collect::<Vec<String>>()
216 .join(","),
217 )
218 }
219}
220
221#[derive(Debug, Eq, PartialEq, Clone)]
223pub struct VersionSpecifiersParseError {
224 inner: Box<VersionSpecifiersParseErrorInner>,
227}
228
229#[derive(Debug, Eq, PartialEq, Clone)]
230struct VersionSpecifiersParseErrorInner {
231 err: VersionSpecifierParseError,
233 line: String,
235 start: usize,
238 end: usize,
241}
242
243impl std::fmt::Display for VersionSpecifiersParseError {
244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245 use unicode_width::UnicodeWidthStr;
246
247 let VersionSpecifiersParseErrorInner {
248 ref err,
249 ref line,
250 start,
251 end,
252 } = *self.inner;
253 writeln!(f, "Failed to parse version: {err}:")?;
254 writeln!(f, "{line}")?;
255 let indent = line[..start].width();
256 let point = line[start..end].width();
257 writeln!(f, "{}{}", " ".repeat(indent), "^".repeat(point))?;
258 Ok(())
259 }
260}
261
262impl VersionSpecifiersParseError {
263 pub fn line(&self) -> &String {
265 &self.inner.line
266 }
267}
268
269impl std::error::Error for VersionSpecifiersParseError {}
270
271#[derive(Eq, Ord, PartialEq, PartialOrd, Debug, Clone, Hash)]
283#[cfg_attr(
284 feature = "rkyv",
285 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
286)]
287#[cfg_attr(feature = "rkyv", rkyv(derive(Debug)))]
288pub struct VersionSpecifier {
289 pub(crate) operator: Operator,
291 pub(crate) version: Version,
293}
294
295impl<'de> Deserialize<'de> for VersionSpecifier {
296 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
297 where
298 D: Deserializer<'de>,
299 {
300 struct Visitor;
301
302 impl de::Visitor<'_> for Visitor {
303 type Value = VersionSpecifier;
304
305 fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
306 f.write_str("a string")
307 }
308
309 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
310 VersionSpecifier::from_str(v).map_err(de::Error::custom)
311 }
312 }
313
314 deserializer.deserialize_str(Visitor)
315 }
316}
317
318impl Serialize for VersionSpecifier {
320 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
321 where
322 S: Serializer,
323 {
324 serializer.collect_str(self)
325 }
326}
327
328impl VersionSpecifier {
329 pub fn from_pattern(
332 operator: Operator,
333 version_pattern: VersionPattern,
334 ) -> Result<Self, VersionSpecifierBuildError> {
335 let star = version_pattern.is_wildcard();
336 let version = version_pattern.into_version();
337
338 let operator = if star {
340 match operator.to_star() {
341 Some(starop) => starop,
342 None => {
343 return Err(BuildErrorKind::OperatorWithStar { operator }.into());
344 }
345 }
346 } else {
347 operator
348 };
349
350 Self::from_version(operator, version)
351 }
352
353 pub fn from_version(
355 operator: Operator,
356 version: Version,
357 ) -> Result<Self, VersionSpecifierBuildError> {
358 if version.is_local() && !operator.is_local_compatible() {
360 return Err(BuildErrorKind::OperatorLocalCombo { operator, version }.into());
361 }
362
363 if operator == Operator::TildeEqual && version.release().len() < 2 {
364 return Err(BuildErrorKind::CompatibleRelease.into());
365 }
366
367 Ok(Self { operator, version })
368 }
369
370 #[must_use]
390 pub fn only_release(self) -> Self {
391 Self {
392 operator: self.operator,
393 version: self.version.only_release(),
394 }
395 }
396
397 #[must_use]
399 pub fn only_minor_release(&self) -> Self {
400 Self {
401 operator: self.operator,
402 version: self.version.only_minor_release(),
403 }
404 }
405
406 pub fn equals_version(version: Version) -> Self {
408 Self {
409 operator: Operator::Equal,
410 version,
411 }
412 }
413
414 pub fn equals_star_version(version: Version) -> Self {
416 Self {
417 operator: Operator::EqualStar,
418 version,
419 }
420 }
421
422 pub fn not_equals_star_version(version: Version) -> Self {
424 Self {
425 operator: Operator::NotEqualStar,
426 version,
427 }
428 }
429
430 pub fn not_equals_version(version: Version) -> Self {
432 Self {
433 operator: Operator::NotEqual,
434 version,
435 }
436 }
437
438 pub fn greater_than_equal_version(version: Version) -> Self {
440 Self {
441 operator: Operator::GreaterThanEqual,
442 version,
443 }
444 }
445 pub fn greater_than_version(version: Version) -> Self {
447 Self {
448 operator: Operator::GreaterThan,
449 version,
450 }
451 }
452
453 pub fn less_than_equal_version(version: Version) -> Self {
455 Self {
456 operator: Operator::LessThanEqual,
457 version,
458 }
459 }
460
461 pub fn less_than_version(version: Version) -> Self {
463 Self {
464 operator: Operator::LessThan,
465 version,
466 }
467 }
468
469 pub fn operator(&self) -> &Operator {
471 &self.operator
472 }
473
474 pub fn version(&self) -> &Version {
476 &self.version
477 }
478
479 pub fn into_parts(self) -> (Operator, Version) {
481 (self.operator, self.version)
482 }
483
484 pub fn any_prerelease(&self) -> bool {
486 self.version.any_prerelease()
487 }
488
489 pub fn from_release_only_bounds(
493 bounds: (&Bound<Version>, &Bound<Version>),
494 ) -> impl Iterator<Item = Self> {
495 let (b1, b2) = match bounds {
496 (Bound::Included(v1), Bound::Included(v2)) if v1 == v2 => {
497 (Some(Self::equals_version(v1.clone())), None)
498 }
499 (Bound::Included(v1), Bound::Excluded(v2)) => {
501 match *v1.only_release_trimmed().release() {
502 [major] if *v2.only_release_trimmed().release() == [major, 1] => {
503 let version = Version::new([major, 0]);
504 (Some(Self::equals_star_version(version)), None)
505 }
506 [major, minor]
507 if *v2.only_release_trimmed().release() == [major, minor + 1] =>
508 {
509 let version = Version::new([major, minor]);
510 (Some(Self::equals_star_version(version)), None)
511 }
512 _ => (
513 Self::from_lower_bound(&Bound::Included(v1.clone())),
514 Self::from_upper_bound(&Bound::Excluded(v2.clone())),
515 ),
516 }
517 }
518 (lower, upper) => (Self::from_lower_bound(lower), Self::from_upper_bound(upper)),
519 };
520
521 b1.into_iter().chain(b2)
522 }
523
524 pub fn from_lower_bound(bound: &Bound<Version>) -> Option<Self> {
526 match bound {
527 Bound::Included(version) => {
528 Some(Self::from_version(Operator::GreaterThanEqual, version.clone()).unwrap())
529 }
530 Bound::Excluded(version) => {
531 Some(Self::from_version(Operator::GreaterThan, version.clone()).unwrap())
532 }
533 Bound::Unbounded => None,
534 }
535 }
536
537 pub fn from_upper_bound(bound: &Bound<Version>) -> Option<Self> {
539 match bound {
540 Bound::Included(version) => {
541 Some(Self::from_version(Operator::LessThanEqual, version.clone()).unwrap())
542 }
543 Bound::Excluded(version) => {
544 Some(Self::from_version(Operator::LessThan, version.clone()).unwrap())
545 }
546 Bound::Unbounded => None,
547 }
548 }
549
550 pub fn contains(&self, version: &Version) -> bool {
558 let this = self.version();
562 let other = if this.local().is_empty() && !version.local().is_empty() {
563 Cow::Owned(version.clone().without_local())
564 } else {
565 Cow::Borrowed(version)
566 };
567
568 match self.operator {
569 Operator::Equal => other.as_ref() == this,
570 Operator::EqualStar => {
571 this.epoch() == other.epoch()
572 && self
573 .version
574 .release()
575 .iter()
576 .zip(&*other.release())
577 .all(|(this, other)| this == other)
578 }
579 #[allow(deprecated)]
580 Operator::ExactEqual => {
581 #[cfg(feature = "tracing")]
582 {
583 warn!("Using arbitrary equality (`===`) is discouraged");
584 }
585 self.version.to_string() == version.to_string()
586 }
587 Operator::NotEqual => this != other.as_ref(),
588 Operator::NotEqualStar => {
589 this.epoch() != other.epoch()
590 || !this
591 .release()
592 .iter()
593 .zip(&*version.release())
594 .all(|(this, other)| this == other)
595 }
596 Operator::TildeEqual => {
597 assert!(this.release().len() > 1);
602 if this.epoch() != other.epoch() {
603 return false;
604 }
605
606 if !this.release()[..this.release().len() - 1]
607 .iter()
608 .zip(&*other.release())
609 .all(|(this, other)| this == other)
610 {
611 return false;
612 }
613
614 other.as_ref() >= this
617 }
618 Operator::GreaterThan => {
619 if other.epoch() > this.epoch() {
620 return true;
621 }
622
623 if version::compare_release(&this.release(), &other.release()) == Ordering::Equal {
624 if !this.is_post() && other.is_post() {
629 return false;
630 }
631
632 if other.is_local() {
634 return false;
635 }
636 }
637
638 other.as_ref() > this
639 }
640 Operator::GreaterThanEqual => other.as_ref() >= this,
641 Operator::LessThan => {
642 if other.epoch() < this.epoch() {
643 return true;
644 }
645
646 if version::compare_release(&this.release(), &other.release()) == Ordering::Equal
651 && !this.any_prerelease()
652 && other.any_prerelease()
653 {
654 return false;
655 }
656
657 other.as_ref() < this
658 }
659 Operator::LessThanEqual => other.as_ref() <= this,
660 }
661 }
662
663 pub fn has_lower_bound(&self) -> bool {
665 match self.operator() {
666 Operator::Equal
667 | Operator::EqualStar
668 | Operator::ExactEqual
669 | Operator::TildeEqual
670 | Operator::GreaterThan
671 | Operator::GreaterThanEqual => true,
672 Operator::LessThanEqual
673 | Operator::LessThan
674 | Operator::NotEqualStar
675 | Operator::NotEqual => false,
676 }
677 }
678}
679
680impl FromStr for VersionSpecifier {
681 type Err = VersionSpecifierParseError;
682
683 fn from_str(spec: &str) -> Result<Self, Self::Err> {
685 let mut s = unscanny::Scanner::new(spec);
686 s.eat_while(|c: char| c.is_whitespace());
687 let operator = s.eat_while(['=', '!', '~', '<', '>']);
689 if operator.is_empty() {
690 s.eat_while(|c: char| c.is_whitespace());
693 let version = s.eat_while(|c: char| !c.is_whitespace());
694 s.eat_while(|c: char| c.is_whitespace());
695 return Err(ParseErrorKind::MissingOperator(VersionOperatorBuildError {
696 version_pattern: VersionPattern::from_str(version).ok(),
697 })
698 .into());
699 }
700 let operator = Operator::from_str(operator).map_err(ParseErrorKind::InvalidOperator)?;
701 s.eat_while(|c: char| c.is_whitespace());
702 let version = s.eat_while(|c: char| !c.is_whitespace());
703 if version.is_empty() {
704 return Err(ParseErrorKind::MissingVersion.into());
705 }
706 let vpat = version.parse().map_err(ParseErrorKind::InvalidVersion)?;
707 let version_specifier =
708 Self::from_pattern(operator, vpat).map_err(ParseErrorKind::InvalidSpecifier)?;
709 s.eat_while(|c: char| c.is_whitespace());
710 if !s.done() {
711 return Err(ParseErrorKind::InvalidTrailing(s.after().to_string()).into());
712 }
713 Ok(version_specifier)
714 }
715}
716
717impl std::fmt::Display for VersionSpecifier {
718 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
719 if self.operator == Operator::EqualStar || self.operator == Operator::NotEqualStar {
720 return write!(f, "{}{}.*", self.operator, self.version);
721 }
722 write!(f, "{}{}", self.operator, self.version)
723 }
724}
725
726#[derive(Clone, Debug, Eq, PartialEq)]
728pub struct VersionSpecifierBuildError {
729 kind: Box<BuildErrorKind>,
732}
733
734impl std::error::Error for VersionSpecifierBuildError {}
735
736impl std::fmt::Display for VersionSpecifierBuildError {
737 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
738 match *self.kind {
739 BuildErrorKind::OperatorLocalCombo {
740 operator: ref op,
741 ref version,
742 } => {
743 let local = version.local();
744 write!(
745 f,
746 "Operator {op} is incompatible with versions \
747 containing non-empty local segments (`+{local}`)",
748 )
749 }
750 BuildErrorKind::OperatorWithStar { operator: ref op } => {
751 write!(
752 f,
753 "Operator {op} cannot be used with a wildcard version specifier",
754 )
755 }
756 BuildErrorKind::CompatibleRelease => {
757 write!(
758 f,
759 "The ~= operator requires at least two segments in the release version"
760 )
761 }
762 }
763 }
764}
765
766#[derive(Clone, Debug, Eq, PartialEq)]
767struct VersionOperatorBuildError {
768 version_pattern: Option<VersionPattern>,
769}
770
771impl std::error::Error for VersionOperatorBuildError {}
772
773impl std::fmt::Display for VersionOperatorBuildError {
774 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
775 write!(f, "Unexpected end of version specifier, expected operator")?;
776 if let Some(version_pattern) = &self.version_pattern {
777 let version_specifier =
778 VersionSpecifier::from_pattern(Operator::Equal, version_pattern.clone()).unwrap();
779 write!(f, ". Did you mean `{version_specifier}`?")?;
780 }
781 Ok(())
782 }
783}
784
785#[derive(Clone, Debug, Eq, PartialEq)]
788enum BuildErrorKind {
789 OperatorLocalCombo {
793 operator: Operator,
795 version: Version,
797 },
798 OperatorWithStar {
801 operator: Operator,
803 },
804 CompatibleRelease,
807}
808
809impl From<BuildErrorKind> for VersionSpecifierBuildError {
810 fn from(kind: BuildErrorKind) -> Self {
811 Self {
812 kind: Box::new(kind),
813 }
814 }
815}
816
817#[derive(Clone, Debug, Eq, PartialEq)]
819pub struct VersionSpecifierParseError {
820 kind: Box<ParseErrorKind>,
823}
824
825impl std::error::Error for VersionSpecifierParseError {}
826
827impl std::fmt::Display for VersionSpecifierParseError {
828 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
829 match *self.kind {
835 ParseErrorKind::InvalidOperator(ref err) => err.fmt(f),
836 ParseErrorKind::InvalidVersion(ref err) => err.fmt(f),
837 ParseErrorKind::InvalidSpecifier(ref err) => err.fmt(f),
838 ParseErrorKind::MissingOperator(ref err) => err.fmt(f),
839 ParseErrorKind::MissingVersion => {
840 write!(f, "Unexpected end of version specifier, expected version")
841 }
842 ParseErrorKind::InvalidTrailing(ref trail) => {
843 write!(f, "Trailing `{trail}` is not allowed")
844 }
845 }
846 }
847}
848
849#[derive(Clone, Debug, Eq, PartialEq)]
852enum ParseErrorKind {
853 InvalidOperator(OperatorParseError),
854 InvalidVersion(VersionPatternParseError),
855 InvalidSpecifier(VersionSpecifierBuildError),
856 MissingOperator(VersionOperatorBuildError),
857 MissingVersion,
858 InvalidTrailing(String),
859}
860
861impl From<ParseErrorKind> for VersionSpecifierParseError {
862 fn from(kind: ParseErrorKind) -> Self {
863 Self {
864 kind: Box::new(kind),
865 }
866 }
867}
868
869pub(crate) fn parse_version_specifiers(
871 spec: &str,
872) -> Result<Vec<VersionSpecifier>, VersionSpecifiersParseError> {
873 let mut version_ranges = Vec::new();
874 if spec.is_empty() {
875 return Ok(version_ranges);
876 }
877 let mut start: usize = 0;
878 let separator = ",";
879 for version_range_spec in spec.split(separator) {
880 match VersionSpecifier::from_str(version_range_spec) {
881 Err(err) => {
882 return Err(VersionSpecifiersParseError {
883 inner: Box::new(VersionSpecifiersParseErrorInner {
884 err,
885 line: spec.to_string(),
886 start,
887 end: start + version_range_spec.len(),
888 }),
889 });
890 }
891 Ok(version_range) => {
892 version_ranges.push(version_range);
893 }
894 }
895 start += version_range_spec.len();
896 start += separator.len();
897 }
898 Ok(version_ranges)
899}
900
901#[derive(Clone, Debug)]
904pub struct TildeVersionSpecifier<'a> {
905 inner: Cow<'a, VersionSpecifier>,
906}
907
908impl<'a> TildeVersionSpecifier<'a> {
909 pub fn from_specifier(specifier: VersionSpecifier) -> Option<Self> {
914 TildeVersionSpecifier::new(Cow::Owned(specifier))
915 }
916
917 pub fn from_specifier_ref(specifier: &'a VersionSpecifier) -> Option<Self> {
921 TildeVersionSpecifier::new(Cow::Borrowed(specifier))
922 }
923
924 fn new(specifier: Cow<'a, VersionSpecifier>) -> Option<Self> {
925 if specifier.operator != Operator::TildeEqual {
926 return None;
927 }
928 if specifier.version().release().len() < 2 || specifier.version().release().len() > 3 {
929 return None;
930 }
931 if specifier.version().any_prerelease()
932 || specifier.version().is_local()
933 || specifier.version().is_post()
934 {
935 return None;
936 }
937 Some(Self { inner: specifier })
938 }
939
940 pub fn has_patch(&self) -> bool {
942 self.inner.version.release().len() == 3
943 }
944
945 pub fn bounding_specifiers(&self) -> (VersionSpecifier, VersionSpecifier) {
949 let release = self.inner.version().release();
950 let lower = self.inner.version.clone();
951 let upper = if self.has_patch() {
952 Version::new([release[0], release[1] + 1])
953 } else {
954 Version::new([release[0] + 1])
955 };
956 (
957 VersionSpecifier::greater_than_equal_version(lower),
958 VersionSpecifier::less_than_version(upper),
959 )
960 }
961
962 pub fn with_patch_version(&self, patch: u64) -> TildeVersionSpecifier<'_> {
964 let mut release = self.inner.version.release().to_vec();
965 if self.has_patch() {
966 release.pop();
967 }
968 release.push(patch);
969 TildeVersionSpecifier::from_specifier(
970 VersionSpecifier::from_version(Operator::TildeEqual, Version::new(release))
971 .expect("We should always derive a valid new version specifier"),
972 )
973 .expect("We should always derive a new tilde version specifier")
974 }
975}
976
977impl std::fmt::Display for TildeVersionSpecifier<'_> {
978 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
979 write!(f, "{}", self.inner)
980 }
981}
982
983#[cfg(test)]
984mod tests {
985 use std::{cmp::Ordering, str::FromStr};
986
987 use indoc::indoc;
988
989 use crate::LocalSegment;
990
991 use super::*;
992
993 #[test]
995 fn test_equal() {
996 let version = Version::from_str("1.1.post1").unwrap();
997
998 assert!(
999 !VersionSpecifier::from_str("== 1.1")
1000 .unwrap()
1001 .contains(&version)
1002 );
1003 assert!(
1004 VersionSpecifier::from_str("== 1.1.post1")
1005 .unwrap()
1006 .contains(&version)
1007 );
1008 assert!(
1009 VersionSpecifier::from_str("== 1.1.*")
1010 .unwrap()
1011 .contains(&version)
1012 );
1013 }
1014
1015 const VERSIONS_ALL: &[&str] = &[
1016 "1.0.dev456",
1018 "1.0a1",
1019 "1.0a2.dev456",
1020 "1.0a12.dev456",
1021 "1.0a12",
1022 "1.0b1.dev456",
1023 "1.0b2",
1024 "1.0b2.post345.dev456",
1025 "1.0b2.post345",
1026 "1.0b2-346",
1027 "1.0c1.dev456",
1028 "1.0c1",
1029 "1.0rc2",
1030 "1.0c3",
1031 "1.0",
1032 "1.0.post456.dev34",
1033 "1.0.post456",
1034 "1.1.dev1",
1035 "1.2+123abc",
1036 "1.2+123abc456",
1037 "1.2+abc",
1038 "1.2+abc123",
1039 "1.2+abc123def",
1040 "1.2+1234.abc",
1041 "1.2+123456",
1042 "1.2.r32+123456",
1043 "1.2.rev33+123456",
1044 "1!1.0.dev456",
1046 "1!1.0a1",
1047 "1!1.0a2.dev456",
1048 "1!1.0a12.dev456",
1049 "1!1.0a12",
1050 "1!1.0b1.dev456",
1051 "1!1.0b2",
1052 "1!1.0b2.post345.dev456",
1053 "1!1.0b2.post345",
1054 "1!1.0b2-346",
1055 "1!1.0c1.dev456",
1056 "1!1.0c1",
1057 "1!1.0rc2",
1058 "1!1.0c3",
1059 "1!1.0",
1060 "1!1.0.post456.dev34",
1061 "1!1.0.post456",
1062 "1!1.1.dev1",
1063 "1!1.2+123abc",
1064 "1!1.2+123abc456",
1065 "1!1.2+abc",
1066 "1!1.2+abc123",
1067 "1!1.2+abc123def",
1068 "1!1.2+1234.abc",
1069 "1!1.2+123456",
1070 "1!1.2.r32+123456",
1071 "1!1.2.rev33+123456",
1072 ];
1073
1074 #[test]
1080 fn test_operators_true() {
1081 let versions: Vec<Version> = VERSIONS_ALL
1082 .iter()
1083 .map(|version| Version::from_str(version).unwrap())
1084 .collect();
1085
1086 let operations = [
1089 versions
1091 .iter()
1092 .enumerate()
1093 .flat_map(|(i, x)| {
1094 versions[i + 1..]
1095 .iter()
1096 .map(move |y| (x, y, Ordering::Less))
1097 })
1098 .collect::<Vec<_>>(),
1099 versions
1101 .iter()
1102 .map(move |x| (x, x, Ordering::Equal))
1103 .collect::<Vec<_>>(),
1104 versions
1106 .iter()
1107 .enumerate()
1108 .flat_map(|(i, x)| versions[..i].iter().map(move |y| (x, y, Ordering::Greater)))
1109 .collect::<Vec<_>>(),
1110 ]
1111 .into_iter()
1112 .flatten();
1113
1114 for (a, b, ordering) in operations {
1115 assert_eq!(a.cmp(b), ordering, "{a} {ordering:?} {b}");
1116 }
1117 }
1118
1119 const VERSIONS_0: &[&str] = &[
1120 "1.0.dev456",
1121 "1.0a1",
1122 "1.0a2.dev456",
1123 "1.0a12.dev456",
1124 "1.0a12",
1125 "1.0b1.dev456",
1126 "1.0b2",
1127 "1.0b2.post345.dev456",
1128 "1.0b2.post345",
1129 "1.0b2-346",
1130 "1.0c1.dev456",
1131 "1.0c1",
1132 "1.0rc2",
1133 "1.0c3",
1134 "1.0",
1135 "1.0.post456.dev34",
1136 "1.0.post456",
1137 "1.1.dev1",
1138 "1.2+123abc",
1139 "1.2+123abc456",
1140 "1.2+abc",
1141 "1.2+abc123",
1142 "1.2+abc123def",
1143 "1.2+1234.abc",
1144 "1.2+123456",
1145 "1.2.r32+123456",
1146 "1.2.rev33+123456",
1147 ];
1148
1149 const SPECIFIERS_OTHER: &[&str] = &[
1150 "== 1.*", "== 1.0.*", "== 1.1.*", "== 1.2.*", "== 2.*", "~= 1.0", "~= 1.0b1", "~= 1.1",
1151 "~= 1.2", "~= 2.0",
1152 ];
1153
1154 const EXPECTED_OTHER: &[[bool; 10]] = &[
1155 [
1156 true, true, false, false, false, false, false, false, false, false,
1157 ],
1158 [
1159 true, true, false, false, false, false, false, false, false, false,
1160 ],
1161 [
1162 true, true, false, false, false, false, false, false, false, false,
1163 ],
1164 [
1165 true, true, false, false, false, false, false, false, false, false,
1166 ],
1167 [
1168 true, true, false, false, false, false, false, false, false, false,
1169 ],
1170 [
1171 true, true, false, false, false, false, false, false, false, false,
1172 ],
1173 [
1174 true, true, false, false, false, false, true, false, false, false,
1175 ],
1176 [
1177 true, true, false, false, false, false, true, false, false, false,
1178 ],
1179 [
1180 true, true, false, false, false, false, true, false, false, false,
1181 ],
1182 [
1183 true, true, false, false, false, false, true, false, false, false,
1184 ],
1185 [
1186 true, true, false, false, false, false, true, false, false, false,
1187 ],
1188 [
1189 true, true, false, false, false, false, true, false, false, false,
1190 ],
1191 [
1192 true, true, false, false, false, false, true, false, false, false,
1193 ],
1194 [
1195 true, true, false, false, false, false, true, false, false, false,
1196 ],
1197 [
1198 true, true, false, false, false, true, true, false, false, false,
1199 ],
1200 [
1201 true, true, false, false, false, true, true, false, false, false,
1202 ],
1203 [
1204 true, true, false, false, false, true, true, false, false, false,
1205 ],
1206 [
1207 true, false, true, false, false, true, true, false, false, false,
1208 ],
1209 [
1210 true, false, false, true, false, true, true, true, true, false,
1211 ],
1212 [
1213 true, false, false, true, false, true, true, true, true, false,
1214 ],
1215 [
1216 true, false, false, true, false, true, true, true, true, false,
1217 ],
1218 [
1219 true, false, false, true, false, true, true, true, true, false,
1220 ],
1221 [
1222 true, false, false, true, false, true, true, true, true, false,
1223 ],
1224 [
1225 true, false, false, true, false, true, true, true, true, false,
1226 ],
1227 [
1228 true, false, false, true, false, true, true, true, true, false,
1229 ],
1230 [
1231 true, false, false, true, false, true, true, true, true, false,
1232 ],
1233 [
1234 true, false, false, true, false, true, true, true, true, false,
1235 ],
1236 ];
1237
1238 #[test]
1242 fn test_operators_other() {
1243 let versions = VERSIONS_0
1244 .iter()
1245 .map(|version| Version::from_str(version).unwrap());
1246 let specifiers: Vec<_> = SPECIFIERS_OTHER
1247 .iter()
1248 .map(|specifier| VersionSpecifier::from_str(specifier).unwrap())
1249 .collect();
1250
1251 for (version, expected) in versions.zip(EXPECTED_OTHER) {
1252 let actual = specifiers
1253 .iter()
1254 .map(|specifier| specifier.contains(&version));
1255 for ((actual, expected), _specifier) in actual.zip(expected).zip(SPECIFIERS_OTHER) {
1256 assert_eq!(actual, *expected);
1257 }
1258 }
1259 }
1260
1261 #[test]
1262 fn test_arbitrary_equality() {
1263 assert!(
1264 VersionSpecifier::from_str("=== 1.2a1")
1265 .unwrap()
1266 .contains(&Version::from_str("1.2a1").unwrap())
1267 );
1268 assert!(
1269 !VersionSpecifier::from_str("=== 1.2a1")
1270 .unwrap()
1271 .contains(&Version::from_str("1.2a1+local").unwrap())
1272 );
1273 }
1274
1275 #[test]
1276 fn test_specifiers_true() {
1277 let pairs = [
1278 ("2.0", "==2"),
1280 ("2.0", "==2.0"),
1281 ("2.0", "==2.0.0"),
1282 ("2.0+deadbeef", "==2"),
1283 ("2.0+deadbeef", "==2.0"),
1284 ("2.0+deadbeef", "==2.0.0"),
1285 ("2.0+deadbeef", "==2+deadbeef"),
1286 ("2.0+deadbeef", "==2.0+deadbeef"),
1287 ("2.0+deadbeef", "==2.0.0+deadbeef"),
1288 ("2.0+deadbeef.0", "==2.0.0+deadbeef.00"),
1289 ("2.dev1", "==2.*"),
1291 ("2a1", "==2.*"),
1292 ("2a1.post1", "==2.*"),
1293 ("2b1", "==2.*"),
1294 ("2b1.dev1", "==2.*"),
1295 ("2c1", "==2.*"),
1296 ("2c1.post1.dev1", "==2.*"),
1297 ("2c1.post1.dev1", "==2.0.*"),
1298 ("2rc1", "==2.*"),
1299 ("2rc1", "==2.0.*"),
1300 ("2", "==2.*"),
1301 ("2", "==2.0.*"),
1302 ("2", "==0!2.*"),
1303 ("0!2", "==2.*"),
1304 ("2.0", "==2.*"),
1305 ("2.0.0", "==2.*"),
1306 ("2.1+local.version", "==2.1.*"),
1307 ("2.1", "!=2"),
1309 ("2.1", "!=2.0"),
1310 ("2.0.1", "!=2"),
1311 ("2.0.1", "!=2.0"),
1312 ("2.0.1", "!=2.0.0"),
1313 ("2.0", "!=2.0+deadbeef"),
1314 ("2.0", "!=3.*"),
1316 ("2.1", "!=2.0.*"),
1317 ("2.0", ">=2"),
1319 ("2.0", ">=2.0"),
1320 ("2.0", ">=2.0.0"),
1321 ("2.0.post1", ">=2"),
1322 ("2.0.post1.dev1", ">=2"),
1323 ("3", ">=2"),
1324 ("2.0", "<=2"),
1326 ("2.0", "<=2.0"),
1327 ("2.0", "<=2.0.0"),
1328 ("2.0.dev1", "<=2"),
1329 ("2.0a1", "<=2"),
1330 ("2.0a1.dev1", "<=2"),
1331 ("2.0b1", "<=2"),
1332 ("2.0b1.post1", "<=2"),
1333 ("2.0c1", "<=2"),
1334 ("2.0c1.post1.dev1", "<=2"),
1335 ("2.0rc1", "<=2"),
1336 ("1", "<=2"),
1337 ("3", ">2"),
1339 ("2.1", ">2.0"),
1340 ("2.0.1", ">2"),
1341 ("2.1.post1", ">2"),
1342 ("2.1+local.version", ">2"),
1343 ("2.post2", ">2.post1"),
1344 ("1", "<2"),
1346 ("2.0", "<2.1"),
1347 ("2.0.dev0", "<2.1"),
1348 ("0.1a1", "<0.1a2"),
1350 ("0.1dev1", "<0.1dev2"),
1351 ("0.1dev1", "<0.1a1"),
1352 ("1", "~=1.0"),
1354 ("1.0.1", "~=1.0"),
1355 ("1.1", "~=1.0"),
1356 ("1.9999999", "~=1.0"),
1357 ("1.1", "~=1.0a1"),
1358 ("2022.01.01", "~=2022.01.01"),
1359 ("2!1.0", "~=2!1.0"),
1361 ("2!1.0", "==2!1.*"),
1362 ("2!1.0", "==2!1.0"),
1363 ("2!1.0", "!=1.0"),
1364 ("1.0", "!=2!1.0"),
1365 ("1.0", "<=2!0.1"),
1366 ("2!1.0", ">=2.0"),
1367 ("1.0", "<2!0.1"),
1368 ("2!1.0", ">2.0"),
1369 ("2.0.5", ">2.0dev"),
1371 ];
1372
1373 for (s_version, s_spec) in pairs {
1374 let version = s_version.parse::<Version>().unwrap();
1375 let spec = s_spec.parse::<VersionSpecifier>().unwrap();
1376 assert!(
1377 spec.contains(&version),
1378 "{s_version} {s_spec}\nversion repr: {:?}\nspec version repr: {:?}",
1379 version.as_bloated_debug(),
1380 spec.version.as_bloated_debug(),
1381 );
1382 }
1383 }
1384
1385 #[test]
1386 fn test_specifier_false() {
1387 let pairs = [
1388 ("2.1", "==2"),
1390 ("2.1", "==2.0"),
1391 ("2.1", "==2.0.0"),
1392 ("2.0", "==2.0+deadbeef"),
1393 ("2.0", "==3.*"),
1395 ("2.1", "==2.0.*"),
1396 ("2.0", "!=2"),
1398 ("2.0", "!=2.0"),
1399 ("2.0", "!=2.0.0"),
1400 ("2.0+deadbeef", "!=2"),
1401 ("2.0+deadbeef", "!=2.0"),
1402 ("2.0+deadbeef", "!=2.0.0"),
1403 ("2.0+deadbeef", "!=2+deadbeef"),
1404 ("2.0+deadbeef", "!=2.0+deadbeef"),
1405 ("2.0+deadbeef", "!=2.0.0+deadbeef"),
1406 ("2.0+deadbeef.0", "!=2.0.0+deadbeef.00"),
1407 ("2.dev1", "!=2.*"),
1409 ("2a1", "!=2.*"),
1410 ("2a1.post1", "!=2.*"),
1411 ("2b1", "!=2.*"),
1412 ("2b1.dev1", "!=2.*"),
1413 ("2c1", "!=2.*"),
1414 ("2c1.post1.dev1", "!=2.*"),
1415 ("2c1.post1.dev1", "!=2.0.*"),
1416 ("2rc1", "!=2.*"),
1417 ("2rc1", "!=2.0.*"),
1418 ("2", "!=2.*"),
1419 ("2", "!=2.0.*"),
1420 ("2.0", "!=2.*"),
1421 ("2.0.0", "!=2.*"),
1422 ("2.0.dev1", ">=2"),
1424 ("2.0a1", ">=2"),
1425 ("2.0a1.dev1", ">=2"),
1426 ("2.0b1", ">=2"),
1427 ("2.0b1.post1", ">=2"),
1428 ("2.0c1", ">=2"),
1429 ("2.0c1.post1.dev1", ">=2"),
1430 ("2.0rc1", ">=2"),
1431 ("1", ">=2"),
1432 ("2.0.post1", "<=2"),
1434 ("2.0.post1.dev1", "<=2"),
1435 ("3", "<=2"),
1436 ("1", ">2"),
1438 ("2.0.dev1", ">2"),
1439 ("2.0a1", ">2"),
1440 ("2.0a1.post1", ">2"),
1441 ("2.0b1", ">2"),
1442 ("2.0b1.dev1", ">2"),
1443 ("2.0c1", ">2"),
1444 ("2.0c1.post1.dev1", ">2"),
1445 ("2.0rc1", ">2"),
1446 ("2.0", ">2"),
1447 ("2.post2", ">2"),
1448 ("2.0.post1", ">2"),
1449 ("2.0.post1.dev1", ">2"),
1450 ("2.0+local.version", ">2"),
1451 ("2.0.dev1", "<2"),
1453 ("2.0a1", "<2"),
1454 ("2.0a1.post1", "<2"),
1455 ("2.0b1", "<2"),
1456 ("2.0b2.dev1", "<2"),
1457 ("2.0c1", "<2"),
1458 ("2.0c1.post1.dev1", "<2"),
1459 ("2.0rc1", "<2"),
1460 ("2.0", "<2"),
1461 ("2.post1", "<2"),
1462 ("2.post1.dev1", "<2"),
1463 ("3", "<2"),
1464 ("2.0", "~=1.0"),
1466 ("1.1.0", "~=1.0.0"),
1467 ("1.1.post1", "~=1.0.0"),
1468 ("1.0", "~=2!1.0"),
1470 ("2!1.0", "~=1.0"),
1471 ("2!1.0", "==1.0"),
1472 ("1.0", "==2!1.0"),
1473 ("2!1.0", "==1.*"),
1474 ("1.0", "==2!1.*"),
1475 ("2!1.0", "!=2!1.0"),
1476 ];
1477 for (version, specifier) in pairs {
1478 assert!(
1479 !VersionSpecifier::from_str(specifier)
1480 .unwrap()
1481 .contains(&Version::from_str(version).unwrap()),
1482 "{version} {specifier}"
1483 );
1484 }
1485 }
1486
1487 #[test]
1488 fn test_parse_version_specifiers() {
1489 let result = VersionSpecifiers::from_str("~= 0.9, >= 1.0, != 1.3.4.*, < 2.0").unwrap();
1490 assert_eq!(
1491 result.0.as_ref(),
1492 [
1493 VersionSpecifier {
1494 operator: Operator::TildeEqual,
1495 version: Version::new([0, 9]),
1496 },
1497 VersionSpecifier {
1498 operator: Operator::GreaterThanEqual,
1499 version: Version::new([1, 0]),
1500 },
1501 VersionSpecifier {
1502 operator: Operator::NotEqualStar,
1503 version: Version::new([1, 3, 4]),
1504 },
1505 VersionSpecifier {
1506 operator: Operator::LessThan,
1507 version: Version::new([2, 0]),
1508 }
1509 ]
1510 );
1511 }
1512
1513 #[test]
1514 fn test_parse_error() {
1515 let result = VersionSpecifiers::from_str("~= 0.9, %= 1.0, != 1.3.4.*");
1516 assert_eq!(
1517 result.unwrap_err().to_string(),
1518 indoc! {r"
1519 Failed to parse version: Unexpected end of version specifier, expected operator:
1520 ~= 0.9, %= 1.0, != 1.3.4.*
1521 ^^^^^^^
1522 "}
1523 );
1524 }
1525
1526 #[test]
1527 fn test_parse_specifier_missing_operator_error() {
1528 let result = VersionSpecifiers::from_str("3.12");
1529 assert_eq!(
1530 result.unwrap_err().to_string(),
1531 indoc! {"
1532 Failed to parse version: Unexpected end of version specifier, expected operator. Did you mean `==3.12`?:
1533 3.12
1534 ^^^^
1535 "}
1536 );
1537 }
1538
1539 #[test]
1540 fn test_parse_specifier_missing_operator_invalid_version_error() {
1541 let result = VersionSpecifiers::from_str("blergh");
1542 assert_eq!(
1543 result.unwrap_err().to_string(),
1544 indoc! {r"
1545 Failed to parse version: Unexpected end of version specifier, expected operator:
1546 blergh
1547 ^^^^^^
1548 "}
1549 );
1550 }
1551
1552 #[test]
1553 fn test_non_star_after_star() {
1554 let result = VersionSpecifiers::from_str("== 0.9.*.1");
1555 assert_eq!(
1556 result.unwrap_err().inner.err,
1557 ParseErrorKind::InvalidVersion(version::PatternErrorKind::WildcardNotTrailing.into())
1558 .into(),
1559 );
1560 }
1561
1562 #[test]
1563 fn test_star_wrong_operator() {
1564 let result = VersionSpecifiers::from_str(">= 0.9.1.*");
1565 assert_eq!(
1566 result.unwrap_err().inner.err,
1567 ParseErrorKind::InvalidSpecifier(
1568 BuildErrorKind::OperatorWithStar {
1569 operator: Operator::GreaterThanEqual,
1570 }
1571 .into()
1572 )
1573 .into(),
1574 );
1575 }
1576
1577 #[test]
1578 fn test_invalid_word() {
1579 let result = VersionSpecifiers::from_str("blergh");
1580 assert_eq!(
1581 result.unwrap_err().inner.err,
1582 ParseErrorKind::MissingOperator(VersionOperatorBuildError {
1583 version_pattern: None
1584 })
1585 .into(),
1586 );
1587 }
1588
1589 #[test]
1591 fn test_invalid_specifier() {
1592 let specifiers = [
1593 (
1595 "2.0",
1596 ParseErrorKind::MissingOperator(VersionOperatorBuildError {
1597 version_pattern: VersionPattern::from_str("2.0").ok(),
1598 })
1599 .into(),
1600 ),
1601 (
1603 "=>2.0",
1604 ParseErrorKind::InvalidOperator(OperatorParseError {
1605 got: "=>".to_string(),
1606 })
1607 .into(),
1608 ),
1609 ("==", ParseErrorKind::MissingVersion.into()),
1611 (
1613 "~=1.0+5",
1614 ParseErrorKind::InvalidSpecifier(
1615 BuildErrorKind::OperatorLocalCombo {
1616 operator: Operator::TildeEqual,
1617 version: Version::new([1, 0])
1618 .with_local_segments(vec![LocalSegment::Number(5)]),
1619 }
1620 .into(),
1621 )
1622 .into(),
1623 ),
1624 (
1625 ">=1.0+deadbeef",
1626 ParseErrorKind::InvalidSpecifier(
1627 BuildErrorKind::OperatorLocalCombo {
1628 operator: Operator::GreaterThanEqual,
1629 version: Version::new([1, 0]).with_local_segments(vec![
1630 LocalSegment::String("deadbeef".to_string()),
1631 ]),
1632 }
1633 .into(),
1634 )
1635 .into(),
1636 ),
1637 (
1638 "<=1.0+abc123",
1639 ParseErrorKind::InvalidSpecifier(
1640 BuildErrorKind::OperatorLocalCombo {
1641 operator: Operator::LessThanEqual,
1642 version: Version::new([1, 0])
1643 .with_local_segments(vec![LocalSegment::String("abc123".to_string())]),
1644 }
1645 .into(),
1646 )
1647 .into(),
1648 ),
1649 (
1650 ">1.0+watwat",
1651 ParseErrorKind::InvalidSpecifier(
1652 BuildErrorKind::OperatorLocalCombo {
1653 operator: Operator::GreaterThan,
1654 version: Version::new([1, 0])
1655 .with_local_segments(vec![LocalSegment::String("watwat".to_string())]),
1656 }
1657 .into(),
1658 )
1659 .into(),
1660 ),
1661 (
1662 "<1.0+1.0",
1663 ParseErrorKind::InvalidSpecifier(
1664 BuildErrorKind::OperatorLocalCombo {
1665 operator: Operator::LessThan,
1666 version: Version::new([1, 0]).with_local_segments(vec![
1667 LocalSegment::Number(1),
1668 LocalSegment::Number(0),
1669 ]),
1670 }
1671 .into(),
1672 )
1673 .into(),
1674 ),
1675 (
1677 "~=1.0.*",
1678 ParseErrorKind::InvalidSpecifier(
1679 BuildErrorKind::OperatorWithStar {
1680 operator: Operator::TildeEqual,
1681 }
1682 .into(),
1683 )
1684 .into(),
1685 ),
1686 (
1687 ">=1.0.*",
1688 ParseErrorKind::InvalidSpecifier(
1689 BuildErrorKind::OperatorWithStar {
1690 operator: Operator::GreaterThanEqual,
1691 }
1692 .into(),
1693 )
1694 .into(),
1695 ),
1696 (
1697 "<=1.0.*",
1698 ParseErrorKind::InvalidSpecifier(
1699 BuildErrorKind::OperatorWithStar {
1700 operator: Operator::LessThanEqual,
1701 }
1702 .into(),
1703 )
1704 .into(),
1705 ),
1706 (
1707 ">1.0.*",
1708 ParseErrorKind::InvalidSpecifier(
1709 BuildErrorKind::OperatorWithStar {
1710 operator: Operator::GreaterThan,
1711 }
1712 .into(),
1713 )
1714 .into(),
1715 ),
1716 (
1717 "<1.0.*",
1718 ParseErrorKind::InvalidSpecifier(
1719 BuildErrorKind::OperatorWithStar {
1720 operator: Operator::LessThan,
1721 }
1722 .into(),
1723 )
1724 .into(),
1725 ),
1726 (
1729 "==1.0.*+5",
1730 ParseErrorKind::InvalidVersion(
1731 version::PatternErrorKind::WildcardNotTrailing.into(),
1732 )
1733 .into(),
1734 ),
1735 (
1736 "!=1.0.*+deadbeef",
1737 ParseErrorKind::InvalidVersion(
1738 version::PatternErrorKind::WildcardNotTrailing.into(),
1739 )
1740 .into(),
1741 ),
1742 (
1745 "==2.0a1.*",
1746 ParseErrorKind::InvalidVersion(
1747 version::ErrorKind::UnexpectedEnd {
1748 version: "2.0a1".to_string(),
1749 remaining: ".*".to_string(),
1750 }
1751 .into(),
1752 )
1753 .into(),
1754 ),
1755 (
1756 "!=2.0a1.*",
1757 ParseErrorKind::InvalidVersion(
1758 version::ErrorKind::UnexpectedEnd {
1759 version: "2.0a1".to_string(),
1760 remaining: ".*".to_string(),
1761 }
1762 .into(),
1763 )
1764 .into(),
1765 ),
1766 (
1767 "==2.0.post1.*",
1768 ParseErrorKind::InvalidVersion(
1769 version::ErrorKind::UnexpectedEnd {
1770 version: "2.0.post1".to_string(),
1771 remaining: ".*".to_string(),
1772 }
1773 .into(),
1774 )
1775 .into(),
1776 ),
1777 (
1778 "!=2.0.post1.*",
1779 ParseErrorKind::InvalidVersion(
1780 version::ErrorKind::UnexpectedEnd {
1781 version: "2.0.post1".to_string(),
1782 remaining: ".*".to_string(),
1783 }
1784 .into(),
1785 )
1786 .into(),
1787 ),
1788 (
1789 "==2.0.dev1.*",
1790 ParseErrorKind::InvalidVersion(
1791 version::ErrorKind::UnexpectedEnd {
1792 version: "2.0.dev1".to_string(),
1793 remaining: ".*".to_string(),
1794 }
1795 .into(),
1796 )
1797 .into(),
1798 ),
1799 (
1800 "!=2.0.dev1.*",
1801 ParseErrorKind::InvalidVersion(
1802 version::ErrorKind::UnexpectedEnd {
1803 version: "2.0.dev1".to_string(),
1804 remaining: ".*".to_string(),
1805 }
1806 .into(),
1807 )
1808 .into(),
1809 ),
1810 (
1811 "==1.0+5.*",
1812 ParseErrorKind::InvalidVersion(
1813 version::ErrorKind::LocalEmpty { precursor: '.' }.into(),
1814 )
1815 .into(),
1816 ),
1817 (
1818 "!=1.0+deadbeef.*",
1819 ParseErrorKind::InvalidVersion(
1820 version::ErrorKind::LocalEmpty { precursor: '.' }.into(),
1821 )
1822 .into(),
1823 ),
1824 (
1826 "==1.0.*.5",
1827 ParseErrorKind::InvalidVersion(
1828 version::PatternErrorKind::WildcardNotTrailing.into(),
1829 )
1830 .into(),
1831 ),
1832 (
1834 "~=1",
1835 ParseErrorKind::InvalidSpecifier(BuildErrorKind::CompatibleRelease.into()).into(),
1836 ),
1837 (
1839 "==1.0.dev1.*",
1840 ParseErrorKind::InvalidVersion(
1841 version::ErrorKind::UnexpectedEnd {
1842 version: "1.0.dev1".to_string(),
1843 remaining: ".*".to_string(),
1844 }
1845 .into(),
1846 )
1847 .into(),
1848 ),
1849 (
1850 "!=1.0.dev1.*",
1851 ParseErrorKind::InvalidVersion(
1852 version::ErrorKind::UnexpectedEnd {
1853 version: "1.0.dev1".to_string(),
1854 remaining: ".*".to_string(),
1855 }
1856 .into(),
1857 )
1858 .into(),
1859 ),
1860 ];
1861 for (specifier, error) in specifiers {
1862 assert_eq!(VersionSpecifier::from_str(specifier).unwrap_err(), error);
1863 }
1864 }
1865
1866 #[test]
1867 fn test_display_start() {
1868 assert_eq!(
1869 VersionSpecifier::from_str("== 1.1.*")
1870 .unwrap()
1871 .to_string(),
1872 "==1.1.*"
1873 );
1874 assert_eq!(
1875 VersionSpecifier::from_str("!= 1.1.*")
1876 .unwrap()
1877 .to_string(),
1878 "!=1.1.*"
1879 );
1880 }
1881
1882 #[test]
1883 fn test_version_specifiers_str() {
1884 assert_eq!(
1885 VersionSpecifiers::from_str(">= 3.7").unwrap().to_string(),
1886 ">=3.7"
1887 );
1888 assert_eq!(
1889 VersionSpecifiers::from_str(">=3.7, < 4.0, != 3.9.0")
1890 .unwrap()
1891 .to_string(),
1892 ">=3.7, !=3.9.0, <4.0"
1893 );
1894 }
1895
1896 #[test]
1899 fn test_version_specifiers_empty() {
1900 assert_eq!(VersionSpecifiers::from_str("").unwrap().to_string(), "");
1901 }
1902
1903 #[test]
1907 fn non_ascii_version_specifier() {
1908 let s = "💩";
1909 let err = s.parse::<VersionSpecifiers>().unwrap_err();
1910 assert_eq!(err.inner.start, 0);
1911 assert_eq!(err.inner.end, 4);
1912
1913 let s = ">=3.7, <4.0,>5.%";
1917 let err = s.parse::<VersionSpecifiers>().unwrap_err();
1918 assert_eq!(err.inner.start, 12);
1919 assert_eq!(err.inner.end, 16);
1920 let s = ">=3.7,\u{3000}<4.0,>5.%";
1929 let err = s.parse::<VersionSpecifiers>().unwrap_err();
1930 assert_eq!(err.inner.start, 14);
1931 assert_eq!(err.inner.end, 18);
1932 }
1933
1934 #[test]
1937 fn error_message_version_specifiers_parse_error() {
1938 let specs = ">=1.2.3, 5.4.3, >=3.4.5";
1939 let err = VersionSpecifierParseError {
1940 kind: Box::new(ParseErrorKind::MissingOperator(VersionOperatorBuildError {
1941 version_pattern: VersionPattern::from_str("5.4.3").ok(),
1942 })),
1943 };
1944 let inner = Box::new(VersionSpecifiersParseErrorInner {
1945 err,
1946 line: specs.to_string(),
1947 start: 8,
1948 end: 14,
1949 });
1950 let err = VersionSpecifiersParseError { inner };
1951 assert_eq!(err, VersionSpecifiers::from_str(specs).unwrap_err());
1952 assert_eq!(
1953 err.to_string(),
1954 "\
1955Failed to parse version: Unexpected end of version specifier, expected operator. Did you mean `==5.4.3`?:
1956>=1.2.3, 5.4.3, >=3.4.5
1957 ^^^^^^
1958"
1959 );
1960 }
1961
1962 #[test]
1965 fn error_message_version_specifier_build_error() {
1966 let err = VersionSpecifierBuildError {
1967 kind: Box::new(BuildErrorKind::CompatibleRelease),
1968 };
1969 let op = Operator::TildeEqual;
1970 let v = Version::new([5]);
1971 let vpat = VersionPattern::verbatim(v);
1972 assert_eq!(err, VersionSpecifier::from_pattern(op, vpat).unwrap_err());
1973 assert_eq!(
1974 err.to_string(),
1975 "The ~= operator requires at least two segments in the release version"
1976 );
1977 }
1978
1979 #[test]
1982 fn error_message_version_specifier_parse_error() {
1983 let err = VersionSpecifierParseError {
1984 kind: Box::new(ParseErrorKind::InvalidSpecifier(
1985 VersionSpecifierBuildError {
1986 kind: Box::new(BuildErrorKind::CompatibleRelease),
1987 },
1988 )),
1989 };
1990 assert_eq!(err, VersionSpecifier::from_str("~=5").unwrap_err());
1991 assert_eq!(
1992 err.to_string(),
1993 "The ~= operator requires at least two segments in the release version"
1994 );
1995 }
1996}