CodeSampleX

Пример

semver 1.0.28: Evaluate Cargo semver bare requirement caret defaulting, prerelease tuple isolation, zero-version breaking bounds, and build metadata equality

Проверенный пример — cargo semver 1.0.28: Evaluate Cargo semver bare requirement caret defaulting, prerelease tuple isolation, zero-version breaking bounds…

sha256:b979dab7a5d51fa64903ed732962f3498ca88091a70e52792d77687af65070fd

Эта сеть предлагает одно: образец, который собирается. Она запустила его в песочнице и сохранила подписанную квитанцию. Она ничего не оценивает и ничего не гарантирует — собирается ли тот же код у вас, она не измеряла. Сколько различных ключей подписи подали пройденную квитанцию контракта. Один — только автор; больше одного — значит, кто-то ещё тоже собрал. Ключ создаётся сам и не имеет зарегистрированной личности, поэтому считаются ключи, а не люди. MIT-0

Свидетельства выполнения

Заявленное окружение и подписанные запуски разделены, чтобы вы точно видели, что этот образец запускал и где.

Основа свидетельства
Подписанный контракт пройден
Квитанции проверки
3
Ключи подписи, собравшие его
3
Заявленная среда rust linux x64 rust rust cargo

Среды запусков проверки

Окружение Контракт Этапы Запуск
rust 1 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · cargo@1
2026-08-17
rust 1 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · cargo@1
2026-08-18
rust 1 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · cargo@1rust:1-alpine@sha256:a10e64dd139b…
2026-09-08

Кейс

HOW
Цель
Evaluate Cargo semver bare requirement caret defaulting, prerelease tuple isolation, zero-version breaking bounds, and build metadata equality
Пакеты
Символы
  • semver::VersionReq
  • semver::Version
  • semver::Comparator
  • semver::Op
Окружение
rust
Создан
2026-08-17T02:34:02Z

Контракт

  1. assert bare requirement 1.2.3 defaults to caret ^1.2.3 accepting 1.2.4 and 1.3.0 while rejecting 2.0.0
  2. assert ^0.2.3 rejects 0.3.0 and ^0.0.3 rejects 0.0.4 because zero-major releases treat minor/patch as breaking
  3. assert ~0.0.3 accepts 0.0.4 making tilde looser than caret for zero-major zero-minor ranges
  4. assert wildcard * matches all stable versions but rejects prereleases like 1.0.0-alpha.1
  5. assert >=1.2.3-alpha.1 accepts 1.2.3-alpha.2 and 1.2.4 but rejects 1.2.4-alpha.1 due to Cargo tuple isolation
  6. assert Rust Version struct Eq and Ord differentiate build metadata whereas VersionReq matches ignores it
  7. assert leading zeros are forbidden in numeric prerelease identifiers but allowed in build metadata

Файлы

  • .gitignore
  • Cargo.lock
  • Cargo.toml
  • NOTES.md
  • csx.json
  • src/lib.rs

Скачать артефакт с исходным кодом (tar.gz)

Исходный код

.gitignore
/target
Cargo.lock
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "cargo-semver-matching"
version = "0.1.0"
dependencies = [
 "semver",
]

[[package]]
name = "semver"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
Cargo.toml
[package]
name = "cargo-semver-matching"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
semver = "1.0.28"
NOTES.md
# Implementation Notes: Cargo semver Evaluation & Matching Traps

## Search Known Solution Result
- `search_known_solution` returned a **HIT** for Node/npm sample `sha256:c724f0f486baa77c970f9237e6c59914d606b71416407858dcdd9ea18b865877` (*"Evaluate 0.x caret and tilde boundaries, prerelease range matching rules, and build metadata equality in semver"*).
- **Why this sample is distinct**: This sample targets the Rust/Cargo implementation (`pkg:cargo/semver@1.0.28`). In Rust's `semver` crate, bare requirements without operators (`"1.2.3"`) default to Caret (`^1.2.3`) rather than exact equality (`=1.2.3`), Cargo enforces strict major-minor-patch tuple isolation on prerelease comparators (`>=1.2.3-alpha.1` rejects `1.2.4-alpha.1`), wildcard `*` rejects all prereleases, `~0.0.3` is strictly looser than `^0.0.3`, and `Version`'s derived `Eq` and `Ord` compare `BuildMetadata` despite `VersionReq::matches` ignoring it.

## Naive Model Assumption
A model would assume bare `"1.2.3"` requires an exact version, `>=1.2.3-alpha.1` matches any higher prerelease such as `1.2.4-alpha.1`, wildcard `*` matches all versions including prereleases, and `Version` structural equality (`==`) ignores build metadata per SemVer 2.0 section 10.

## Failure Mode
Silently with a green build: dependency resolvers and version gates permit unexpected minor/patch bumps on bare requirements, fail to match valid newer prereleases across differing tuples, and treat identical version releases with distinct build metadata as unequal in hash sets and btree maps.
csx.json
{"case":{"caseId":"case:sha256:b796f8a97763352cba26f3a6b7d6f6d1d5426771211b4556b9072e65e7a69df0","contract":["assert bare requirement 1.2.3 defaults to caret ^1.2.3 accepting 1.2.4 and 1.3.0 while rejecting 2.0.0","assert ^0.2.3 rejects 0.3.0 and ^0.0.3 rejects 0.0.4 because zero-major releases treat minor/patch as breaking","assert ~0.0.3 accepts 0.0.4 making tilde looser than caret for zero-major zero-minor ranges","assert wildcard * matches all stable versions but rejects prereleases like 1.0.0-alpha.1","assert \u003e=1.2.3-alpha.1 accepts 1.2.3-alpha.2 and 1.2.4 but rejects 1.2.4-alpha.1 due to Cargo tuple isolation","assert Rust Version struct Eq and Ord differentiate build metadata whereas VersionReq matches ignores it","assert leading zeros are forbidden in numeric prerelease identifiers but allowed in build metadata"],"goal":"Evaluate Cargo semver bare requirement caret defaulting, prerelease tuple isolation, zero-version breaking bounds, and build metadata equality","kind":"HOW","packages":["pkg:cargo/semver@1.0.28"],"schemaVersion":1,"symbols":["semver::VersionReq","semver::Version","semver::Comparator","semver::Op"]},"contractCommand":["cargo","test","--offline"],"environment":{"arch":"x64","ecosystem":"cargo","executionContext":"rust","language":"rust","os":"linux","packageManager":"cargo","runtime":"rust","schemaVersion":1},"license":"MIT-0","packages":["pkg:cargo/semver@1.0.28"],"schemaVersion":1,"symbols":["semver::VersionReq","semver::Version","semver::Comparator","semver::Op"],"verifierAdapter":"cargo@1"}
src/lib.rs
use std::cmp::Ordering;
use semver::{Error, Op, Version, VersionReq};

/// Evaluates whether a version string matches a requirement string under Cargo's SemVer flavor.
pub fn matches_requirement(req_str: &str, ver_str: &str) -> Result<bool, Error> {
    let req = VersionReq::parse(req_str)?;
    let ver = Version::parse(ver_str)?;
    Ok(req.matches(&ver))
}

/// Compares two version strings using Rust's `Version::cmp` implementation.
///
/// Note: In Rust's `semver` crate, `Version::cmp` performs a full structural comparison
/// including `build` metadata, differing from SemVer 2.0 section 10 precedence rules.
pub fn compare_versions(v1_str: &str, v2_str: &str) -> Result<Ordering, Error> {
    let v1 = Version::parse(v1_str)?;
    let v2 = Version::parse(v2_str)?;
    Ok(v1.cmp(&v2))
}

/// Checks equality of two version strings using Rust's `Version::eq` (`PartialEq`).
pub fn are_versions_equal(v1_str: &str, v2_str: &str) -> Result<bool, Error> {
    let v1 = Version::parse(v1_str)?;
    let v2 = Version::parse(v2_str)?;
    Ok(v1 == v2)
}

/// Returns the primary comparator operator for a requirement string, if present.
pub fn primary_comparator_op(req_str: &str) -> Result<Option<Op>, Error> {
    let req = VersionReq::parse(req_str)?;
    Ok(req.comparators.first().map(|c| c.op))
}

/// Parses a Version string, returning Version struct.
pub fn parse_version(ver_str: &str) -> Result<Version, Error> {
    Version::parse(ver_str)
}

/// Parses a VersionReq string, returning VersionReq struct.
pub fn parse_requirement(req_str: &str) -> Result<VersionReq, Error> {
    VersionReq::parse(req_str)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_bare_requirement_defaults_to_caret() {
        // In Cargo semver, a bare requirement without operator (e.g. "1.2.3") defaults to Caret (^1.2.3),
        // NOT exact equality (=1.2.3) as in npm or strict spec interpretation.
        let op = primary_comparator_op("1.2.3").expect("should parse");
        assert_eq!(op, Some(Op::Caret));

        // Caret ^1.2.3 accepts minor and patch bumps within major version 1
        assert!(matches_requirement("1.2.3", "1.2.3").unwrap());
        assert!(matches_requirement("1.2.3", "1.2.4").unwrap());
        assert!(matches_requirement("1.2.3", "1.3.0").unwrap());
        assert!(matches_requirement("1.2.3", "1.99.0").unwrap());

        // But rejects next major version
        assert!(!matches_requirement("1.2.3", "2.0.0").unwrap());

        // Exact match requires explicit '=' operator
        let exact_op = primary_comparator_op("=1.2.3").expect("should parse");
        assert_eq!(exact_op, Some(Op::Exact));
        assert!(matches_requirement("=1.2.3", "1.2.3").unwrap());
        assert!(!matches_requirement("=1.2.3", "1.2.4").unwrap());
        assert!(!matches_requirement("=1.2.3", "1.3.0").unwrap());
    }

    #[test]
    fn test_zero_version_breaking_boundaries() {
        // In 0.x versions, minor bumps are breaking changes (e.g. ^0.2.3 := >=0.2.3, <0.3.0)
        assert!(matches_requirement("^0.2.3", "0.2.3").unwrap());
        assert!(matches_requirement("^0.2.3", "0.2.4").unwrap());
        assert!(!matches_requirement("^0.2.3", "0.3.0").unwrap());

        // In 0.0.x versions, patch bumps are breaking changes (e.g. ^0.0.3 := >=0.0.3, <0.0.4)
        assert!(matches_requirement("^0.0.3", "0.0.3").unwrap());
        assert!(!matches_requirement("^0.0.3", "0.0.4").unwrap());

        // 0.0.0 matches only 0.0.0
        assert!(matches_requirement("0.0.0", "0.0.0").unwrap());
        assert!(!matches_requirement("0.0.0", "0.0.1").unwrap());
    }

    #[test]
    fn test_zero_patch_tilde_vs_caret_asymmetry() {
        // For 1.x versions, ^ is looser than ~ (^1.2.3 allows <2.0.0, ~1.2.3 allows <1.3.0).
        // BUT for 0.0.x versions, ~ is LOOSER than ^:
        // ^0.0.3 locks to exact patch (<0.0.4), whereas ~0.0.3 allows patch bumps (<0.1.0)!
        assert!(!matches_requirement("^0.0.3", "0.0.4").unwrap());
        assert!(matches_requirement("~0.0.3", "0.0.4").unwrap());
        assert!(matches_requirement("~0.0.3", "0.0.99").unwrap());
        assert!(!matches_requirement("~0.0.3", "0.1.0").unwrap());
    }

    #[test]
    fn test_wildcard_star_rejects_prereleases() {
        // Wildcard '*' (VersionReq::STAR) matches all stable versions
        assert!(matches_requirement("*", "1.0.0").unwrap());
        assert!(matches_requirement("*", "0.1.0").unwrap());
        assert!(matches_requirement("*", "99.0.0").unwrap());

        // But rejects any prerelease version
        assert!(!matches_requirement("*", "1.0.0-alpha.1").unwrap());
        assert!(!matches_requirement("*", "0.1.0-beta").unwrap());
    }

    #[test]
    fn test_prerelease_tuple_isolation_rule() {
        // Cargo SemVer rule: a prerelease version X.Y.Z-pre matches a comparator ONLY if
        // the comparator explicitly includes a prerelease AND shares the exact (major, minor, patch) tuple.
        // Thus, >=1.2.3-alpha.1 matches 1.2.3-alpha.2 and stable 1.2.4, but REJECTS 1.2.4-alpha.1!
        assert!(matches_requirement(">=1.2.3-alpha.1", "1.2.3-alpha.1").unwrap());
        assert!(matches_requirement(">=1.2.3-alpha.1", "1.2.3-alpha.2").unwrap());
        assert!(matches_requirement(">=1.2.3-alpha.1", "1.2.4").unwrap());
        assert!(!matches_requirement(">=1.2.3-alpha.1", "1.2.4-alpha.1").unwrap());

        // Same for Caret requirement ^1.2.3-alpha.1
        assert!(matches_requirement("^1.2.3-alpha.1", "1.2.3-alpha.2").unwrap());
        assert!(matches_requirement("^1.2.3-alpha.1", "1.2.4").unwrap());
        assert!(!matches_requirement("^1.2.3-alpha.1", "1.2.4-alpha.1").unwrap());

        // Range without prerelease comparator rejects prereleases entirely
        assert!(!matches_requirement(">=1.2.0", "1.2.3-alpha.1").unwrap());
    }

    #[test]
    fn test_version_struct_equality_and_ordering_includes_build_metadata() {
        // In Rust's semver crate, Version's PartialEq / Eq / Ord compare build metadata field-by-field.
        // This causes two versions differing only in build metadata to be NOT equal and have a strict ordering.
        let v1 = Version::parse("1.2.3+build.1").unwrap();
        let v2 = Version::parse("1.2.3+build.2").unwrap();

        assert_ne!(v1, v2);
        assert_eq!(v1.cmp(&v2), Ordering::Less);
        assert!(!are_versions_equal("1.2.3+build.1", "1.2.3+build.2").unwrap());
        assert_eq!(compare_versions("1.2.3+build.1", "1.2.3+build.2").unwrap(), Ordering::Less);

        // However, VersionReq::matches ignores build metadata
        assert!(matches_requirement("1.2.3+build.1", "1.2.3").unwrap());
        assert!(matches_requirement("1.2.3+build.1", "1.2.3+build.1").unwrap());
        assert!(matches_requirement("1.2.3+build.1", "1.2.3+build.2").unwrap());
    }

    #[test]
    fn test_leading_zeroes_rejection_in_prerelease_vs_build_metadata() {
        // SemVer 2.0 forbids leading zeros in numerical prerelease identifiers
        assert!(parse_version("1.0.0-0").is_ok());
        assert!(parse_version("1.0.0-01").is_err());

        // But leading zeros ARE permitted in build metadata identifiers
        assert!(parse_version("1.0.0+01").is_ok());
        assert!(parse_version("1.0.0+build.01").is_ok());
    }
}

Исходный сидер

csx-seed