Skip to content

Commit

Permalink
guarantee serde is in lockstep with serde_derive
Browse files Browse the repository at this point in the history
  • Loading branch information
soqb committed Aug 20, 2023
1 parent 3c7dd6f commit 2ea7e13
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Expand Up @@ -156,3 +156,12 @@ jobs:
- uses: actions/checkout@v3
- uses: dtolnay/install@cargo-outdated
- run: cargo outdated --workspace --exit-code 1

lockstep:
name: Lockstep
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- run: cd test_suite/assert_lockstep && cargo run -- dummy_dependant
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -4,6 +4,7 @@ members = [
"serde_derive",
"serde_derive_internals",
"test_suite",
"test_suite/assert_lockstep",
]

[patch.crates-io]
Expand Down
4 changes: 4 additions & 0 deletions serde/Cargo.toml
Expand Up @@ -31,6 +31,10 @@ features = ["derive"]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]

# Even though this `cfg` can never be enabled, it still forces cargo to keep `serde_derive` in lockstep with `serde`.
[target.'cfg(any())'.dependencies]
serde_derive = { version = "=1.0.185", path = "../serde_derive" }


### FEATURES #################################################################

Expand Down
12 changes: 12 additions & 0 deletions test_suite/assert_lockstep/Cargo.toml
@@ -0,0 +1,12 @@
[package]
name = "assert_lockstep"
version = "0.1.0"
edition = "2018"
rust-version = "1.70"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
cargo-lock = "8.0.0"
toml = "0.5"
thiserror = "1.0.39"
12 changes: 12 additions & 0 deletions test_suite/assert_lockstep/dummy_dependant/Cargo.toml
@@ -0,0 +1,12 @@
[package]
name = "dummy_dependant"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { path = "../../../serde" }

# `workspace.exclude` does not seem to work with doubly nested paths.
[workspace]
1 change: 1 addition & 0 deletions test_suite/assert_lockstep/dummy_dependant/src/lib.rs
@@ -0,0 +1 @@

110 changes: 110 additions & 0 deletions test_suite/assert_lockstep/src/main.rs
@@ -0,0 +1,110 @@
use cargo_lock::{Lockfile, Package, Version};
use std::convert::Infallible;
use std::fmt;
use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::str::FromStr;
use thiserror::Error;

#[derive(Debug, Error)]
enum TestError {
#[error("Package \"{name}\" not found in the lockfile")]
NoPackageFound { name: String },
#[error("Package \"{first}\" and \"{second}\" had different versions in the lockfile")]
VersionMismatch { first: PackageId, second: PackageId },
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Error parsing lockfile: {0}")]
Lock(#[from] cargo_lock::Error),
}

impl From<Infallible> for TestError {
fn from(value: Infallible) -> Self {
match value {}
}
}

#[derive(Debug)]
struct PackageId {
name: String,
version: Version,
}

impl PackageId {
fn new(package: &Package) -> Self {
Self {
name: package.name.to_string(),
version: package.version.clone(),
}
}
}

impl fmt::Display for PackageId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{name}@{version}",
name = self.name,
version = self.version,
)
}
}

fn find_package<'a>(lockfile: &'a Lockfile, package_name: &str) -> Result<&'a Package, TestError> {
lockfile
.packages
.iter()
.find(|package| package.name.as_str() == package_name)
.ok_or_else(|| TestError::NoPackageFound {
name: package_name.to_owned(),
})
}

fn main() {
if let Err(error) = main_inner() {
panic!("{}", error);
}
}

fn main_inner() -> Result<(), TestError> {
let path = PathBuf::from_str(&std::env::args().nth(1).unwrap())?;

Command::new("cargo")
.arg("clean")
.current_dir(&path)
.stdout(Stdio::inherit())
.output()?;

Command::new("cargo")
.arg("update")
.current_dir(&path)
.stdout(Stdio::inherit())
.output()?;

let lockfile = Lockfile::load(path.join("Cargo.lock"))?;

let serde = find_package(&lockfile, "serde")?;

println!("packages should match {id}", id = PackageId::new(&serde));

let package_names = &["serde_derive"];

let packages = package_names
.iter()
.map(|name| find_package(&lockfile, name));

for package in packages {
let package = package?;

println!("discovered package {id}", id = PackageId::new(&package));

if package.version != serde.version {
return Err(TestError::VersionMismatch {
first: PackageId::new(&serde),
second: PackageId::new(&package),
});
}
}

Ok(())
}

0 comments on commit 2ea7e13

Please sign in to comment.