use crate::parsers::modular;
use crate::{BaseVersion, FullVersionParser, ParserError};
use std::fmt;
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FullVersion {
pub major: u64,
pub minor: u64,
pub patch: u64,
}
impl FullVersion {
pub fn new(major: u64, minor: u64, patch: u64) -> Self {
Self {
major,
minor,
patch,
}
}
pub fn parse(input: &str) -> Result<Self, ParserError> {
modular::ModularParser.parse_full(input)
}
pub fn to_base_version_lossy(self) -> BaseVersion {
BaseVersion {
major: self.major,
minor: self.minor,
}
}
pub fn map<U, F>(self, fun: F) -> U
where
F: FnOnce(Self) -> U,
{
fun(self)
}
}
#[cfg(feature = "semver")]
impl From<FullVersion> for semver::Version {
fn from(version: FullVersion) -> Self {
semver::Version::new(version.major, version.minor, version.patch)
}
}
impl From<(u64, u64, u64)> for FullVersion {
fn from(tuple: (u64, u64, u64)) -> Self {
FullVersion {
major: tuple.0,
minor: tuple.1,
patch: tuple.2,
}
}
}
impl fmt::Display for FullVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("{}.{}.{}", self.major, self.minor, self.patch))
}
}
#[cfg(test)]
mod tests {
use crate::{BaseVersion, FullVersion};
#[test]
fn from_tuple() {
let major = 0;
let minor = 1;
let patch = 2;
assert_eq!(
FullVersion {
major,
minor,
patch
},
FullVersion::from((major, minor, patch))
);
}
#[yare::parameterized(
zeros = { FullVersion { major: 0, minor: 0, patch: 0 }, "0.0.0" },
non_zero = { FullVersion { major: 1, minor: 2, patch: 3 }, "1.2.3" },
)]
fn display(base_version: FullVersion, expected: &str) {
let displayed = format!("{}", base_version);
assert_eq!(&displayed, expected);
}
#[test]
fn to_base_version_lossy() {
let full = FullVersion {
major: 1,
minor: 2,
patch: 3,
};
let converted = full.to_base_version_lossy();
assert_eq!(BaseVersion { major: 1, minor: 2 }, converted)
}
#[test]
fn map() {
let version = BaseVersion::new(1, 2);
let mapped = version.map(|v| ("Everything is awesome", v.major, v.minor));
assert_eq!(mapped.1, 1);
assert_eq!(mapped.2, 2);
}
}
#[cfg(test)]
mod ord_tests {
use crate::FullVersion;
use std::cmp::Ordering;
#[yare::parameterized(
zero = { FullVersion { major: 0, minor: 0, patch: 0 }, FullVersion { major: 0, minor: 0, patch: 0 } },
ones = { FullVersion { major: 1, minor: 1, patch: 1 }, FullVersion { major: 1, minor: 1, patch: 1 } },
)]
fn equals(lhs: FullVersion, rhs: FullVersion) {
assert_eq!(lhs.cmp(&rhs), Ordering::Equal);
}
#[yare::parameterized(
major_by_1 = { FullVersion { major: 0, minor: 0, patch: 0 }, FullVersion { major: 1, minor: 0, patch: 0 } },
minor_by_1 = { FullVersion { major: 0, minor: 0, patch: 0 }, FullVersion { major: 0, minor: 1, patch: 0 } },
patch_by_1 = { FullVersion { major: 0, minor: 0, patch: 0 }, FullVersion { major: 0, minor: 0, patch: 1 } },
)]
fn less(lhs: FullVersion, rhs: FullVersion) {
assert_eq!(lhs.cmp(&rhs), Ordering::Less);
}
#[yare::parameterized(
major_by_1 = { FullVersion { major: 1, minor: 0, patch: 0 }, FullVersion { major: 0, minor: 0, patch: 0 } },
minor_by_1 = { FullVersion { major: 0, minor: 1, patch: 0 }, FullVersion { major: 0, minor: 0, patch: 0 } },
patch_by_1 = { FullVersion { major: 0, minor: 0, patch: 1 }, FullVersion { major: 0, minor: 0, patch: 0 } },
)]
fn greater(lhs: FullVersion, rhs: FullVersion) {
assert_eq!(lhs.cmp(&rhs), Ordering::Greater);
}
}
#[cfg(test)]
mod partial_ord_tests {
use crate::FullVersion;
use std::cmp::Ordering;
#[yare::parameterized(
zero = { FullVersion { major: 0, minor: 0, patch: 0 }, FullVersion { major: 0, minor: 0, patch: 0 } },
ones = { FullVersion { major: 1, minor: 1, patch: 1 }, FullVersion { major: 1, minor: 1, patch: 1 } },
)]
fn equals(lhs: FullVersion, rhs: FullVersion) {
assert_eq!(lhs.partial_cmp(&rhs), Some(Ordering::Equal));
}
#[yare::parameterized(
major_by_1 = { FullVersion { major: 0, minor: 0, patch: 0 }, FullVersion { major: 1, minor: 0, patch: 0 } },
minor_by_1 = { FullVersion { major: 0, minor: 0, patch: 0 }, FullVersion { major: 0, minor: 1, patch: 0 } },
patch_by_1 = { FullVersion { major: 0, minor: 0, patch: 0 }, FullVersion { major: 0, minor: 0, patch: 1 } },
)]
fn less(lhs: FullVersion, rhs: FullVersion) {
assert_eq!(lhs.partial_cmp(&rhs), Some(Ordering::Less));
}
#[yare::parameterized(
major_by_1 = { FullVersion { major: 1, minor: 0, patch: 0 }, FullVersion { major: 0, minor: 0, patch: 0 } },
minor_by_1 = { FullVersion { major: 0, minor: 1, patch: 0 }, FullVersion { major: 0, minor: 0, patch: 0 } },
patch_by_1 = { FullVersion { major: 0, minor: 0, patch: 1 }, FullVersion { major: 0, minor: 0, patch: 0 } },
)]
fn greater(lhs: FullVersion, rhs: FullVersion) {
assert_eq!(lhs.partial_cmp(&rhs), Some(Ordering::Greater));
}
}
#[cfg(test)]
mod parse_full {
use crate::parsers::error::ExpectedError;
use crate::parsers::NumericError;
use crate::{FullVersion, ParserError};
#[test]
fn ok() {
let version = FullVersion::parse("1.2.3").unwrap();
assert_eq!(version, FullVersion::new(1, 2, 3));
}
#[test]
fn err_on_base_only() {
let result = FullVersion::parse("1.2");
assert!(matches!(
result.unwrap_err(),
ParserError::Expected(ExpectedError::Separator { .. })
));
}
#[test]
fn err_on_not_finished() {
let result = FullVersion::parse("1.2.3.");
assert!(matches!(
result.unwrap_err(),
ParserError::Expected(ExpectedError::EndOfInput { .. })
));
}
#[test]
fn err_on_starts_with_0() {
let result = FullVersion::parse("1.2.03");
assert!(matches!(
result.unwrap_err(),
ParserError::Numeric(NumericError::LeadingZero)
));
}
}