summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2025-10-22 22:12:50 +0200
committerMarkus Pettersson <markus.pettersson@mullvad.net>2025-10-29 10:25:55 +0100
commit6b45195a63ddd79b3e694c2766076a597c375e8f (patch)
treed35c3afe62c44727d842303850ecb924c2ec83f1
parent53921838460b68083c81ac42a63348a65e7f401d (diff)
downloadmullvadvpn-proptest-update-logic.tar.xz
mullvadvpn-proptest-update-logic.zip
Test all possible version numbers!proptest-update-logic
-rw-r--r--Cargo.lock13
-rw-r--r--Cargo.toml1
-rw-r--r--mullvad-version/Cargo.toml4
-rw-r--r--mullvad-version/src/lib.rs41
4 files changed, 53 insertions, 6 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 24fbf638dd..9148bcd376 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3406,6 +3406,8 @@ dependencies = [
name = "mullvad-version"
version = "0.0.0"
dependencies = [
+ "proptest",
+ "proptest-derive",
"regex-lite",
"serde",
]
@@ -4414,6 +4416,17 @@ dependencies = [
]
[[package]]
+name = "proptest-derive"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "095a99f75c69734802359b682be8daaf8980296731f6470434ea2c652af1dd30"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
name = "prost"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 3f2d2db23e..4032591dc3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -149,6 +149,7 @@ itertools = "0.14"
# Test dependencies
proptest = "1.8"
+proptest-derive = "0.6"
insta = { version = "1.42", features = ["yaml"] }
[profile.release]
diff --git a/mullvad-version/Cargo.toml b/mullvad-version/Cargo.toml
index e7a75f93bc..cf1237b617 100644
--- a/mullvad-version/Cargo.toml
+++ b/mullvad-version/Cargo.toml
@@ -19,3 +19,7 @@ workspace = true
[dependencies]
regex-lite = "0.1"
serde = { workspace = true, optional = true }
+
+[dev-dependencies]
+proptest = { workspace = true }
+proptest-derive = { workspace = true }
diff --git a/mullvad-version/src/lib.rs b/mullvad-version/src/lib.rs
index 6efa48d6a9..89cc4f43ff 100644
--- a/mullvad-version/src/lib.rs
+++ b/mullvad-version/src/lib.rs
@@ -5,24 +5,43 @@ use std::sync::LazyLock;
use regex_lite::Regex;
+#[cfg(test)]
+use proptest::prelude::proptest;
+#[cfg(test)]
+use proptest_derive::Arbitrary;
+
/// The Mullvad VPN app product version
#[cfg(has_version)]
pub const VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/product-version.txt"));
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(test, derive(Arbitrary))]
pub struct Version {
+ #[cfg_attr(test, proptest(strategy = "1000u32..=9999"))]
pub year: u32,
+ #[cfg_attr(test, proptest(strategy = "1u32..=99"))]
pub incremental: u32,
/// A version can have an optional pre-stable type, e.g. alpha or beta.
pub pre_stable: Option<PreStableType>,
/// All versions may have an optional -dev-[commit hash] suffix.
- pub dev: Option<String>,
+ pub dev: Option<Hash>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(test, derive(Arbitrary))]
+pub struct Hash(#[cfg_attr(test, proptest(regex = "([0-9a-f]+)"))] String);
+
+impl Display for Hash {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.0.fmt(f)
+ }
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[cfg_attr(test, derive(Arbitrary))]
pub enum PreStableType {
- Alpha(u32),
- Beta(u32),
+ Alpha(#[cfg_attr(test, proptest(strategy = "1u32..=999"))] u32),
+ Beta(#[cfg_attr(test, proptest(strategy = "1u32..=999"))] u32),
}
impl Ord for PreStableType {
@@ -190,7 +209,10 @@ impl FromStr for Version {
let alpha = captures.name("alpha").map(|m| m.as_str().parse().unwrap());
let beta = captures.name("beta").map(|m| m.as_str().parse().unwrap());
- let dev = captures.name("dev").map(|m| m.as_str().to_owned());
+ let dev = captures
+ .name("dev")
+ .map(|m| m.as_str().to_owned())
+ .map(Hash);
let pre_stable = match (alpha, beta) {
(None, None) => None,
@@ -373,7 +395,7 @@ mod tests {
year: 2021,
incremental: 34,
pre_stable: None,
- dev: Some("0b60e4d87".to_string()),
+ dev: Some(Hash("0b60e4d87".to_string())),
}
);
}
@@ -386,7 +408,7 @@ mod tests {
year: 2024,
incremental: 8,
pre_stable: Some(PreStableType::Beta(1)),
- dev: Some("e5483d".to_string()),
+ dev: Some(Hash("e5483d".to_string())),
}
);
}
@@ -443,4 +465,11 @@ mod tests {
let expected = Version::from_str("2025.11").unwrap();
assert_eq!(parsed.bump(Type::Stable).unwrap(), expected)
}
+
+ proptest! {
+ #[test]
+ fn parse_all_version_numbers(version: Version) {
+ parse(&version.to_string());
+ }
+ }
}