CodeSampleX

Exemple

semver 1.0.28: Evaluate bare VersionReq caret defaulting, strict parser syntax, prerelease isolation, and build metadata total ordering in Cargo semver

Échantillon vérifié pour cargo semver 1.0.28: Evaluate bare VersionReq caret defaulting, strict parser syntax, prerelease isolation, and build metadata total…

sha256:aad15f75653e5762a15d7950d5230b7fdc092df0414827a20d188bfeaaeef9e2

Ce réseau offre une seule chose : un échantillon qui compile. Il l'a exécuté dans un bac à sable et conservé le reçu signé. Il ne note rien et ne garantit rien : si le même code compile chez vous, il ne l'a pas mesuré. Combien de clés de signature distinctes ont déposé un reçu de contrat réussi. Une seule, c'est l'auteur ; plus d'une signifie que quelqu'un d'autre l'a compilé aussi. Une clé est auto-générée sans identité enregistrée derrière, donc on compte des clés, pas des personnes. MIT-0

Preuves d'exécution

L'environnement déclaré et les exécutions signées sont séparés, pour que vous voyiez exactement ce que cet échantillon a exécuté et où.

Base de preuve
Contrat signé réussi
Reçus de vérification
3
Clés de signature qui l’ont compilé
3
Environnement déclaré rust linux x64 rust rust cargo

Environnements des exécutions de vérification

Environnement Contrat Étapes Exécution
rust 1 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · cargo@1
2026-08-16
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

Cas

HOW
Objectif
Evaluate bare VersionReq caret defaulting, strict parser syntax, prerelease isolation, and build metadata total ordering in Cargo semver
Paquets
Symboles
  • semver::Version
  • semver::Version::parse
  • semver::Version::cmp_precedence
  • semver::VersionReq
  • semver::VersionReq::parse
  • semver::VersionReq::matches
  • semver::Op
Environnement
rust
Créé
2026-08-16T08:18:26Z

Contrat

  1. assert VersionReq::parse("1.2.3") defaults to Op::Caret matching 1.2.4 and 1.9.0 rather than Op::Exact
  2. assert Version::parse and VersionReq::parse strictly reject 'v' prefix, incomplete tuples, and leading zeroes
  3. assert VersionReq without prerelease tag rejects all prereleases while tagged comparator matches only identical tuples
  4. assert Version Eq and Ord differentiate build metadata for total ordering while cmp_precedence and VersionReq ignore build metadata
  5. assert 0.x caret ranges enforce breaking changes at minor for ^0.x and patch for ^0.0.x while ~0.0.x permits patch bumps

Fichiers

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

Télécharger l’artefact source (tar.gz)

Code source

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

[[package]]
name = "cargo-semver-api"
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-api"
version = "0.1.0"
edition = "2021"
license = "MIT-0"

[dependencies]
semver = "1.0.28"
NOTES.md
# Implementation Notes: Cargo semver Behavioral Contracts and Parser Traps

## Search Known Solution Result
- `search_known_solution` for `pkg:cargo/semver` returned no existing cargo sample (only finding unrelated fallback samples and npm sample `sha256:c724f0f486baa77c970f9237e6c59914d606b71416407858dcdd9ea18b865877` for `pkg:npm/semver@7.8.5`).
- This sample proves the specific Rust `semver` crate mechanics: `VersionReq::parse("1.2.3")` defaulting to `Op::Caret` (^), parser strictness (rejection of `'v'`, incomplete versions, and leading zeroes), prerelease isolation rules in comparator matching, `PartialEq`/`Ord` total ordering behavior on build metadata vs `cmp_precedence`, and 0.x caret/tilde boundaries.

## Naive Model Assumption
A naive model assumes `VersionReq::parse("1.2.3")` pins an exact version (`=1.2.3`), `Version::parse("v1.2.3")` automatically strips the `'v'` prefix, wildcards (`*`) and ranges (`>=1.0.0`) match prerelease versions like `1.2.3-alpha.1`, and `Version::cmp` or `==` ignores build metadata per SemVer 2.0 precedence.

## Failure Mode
Loudly with runtime `semver::Error` when encountering `'v'` prefixes or two-part versions, and silently with a green build when dependency resolvers allow unpinned minor version upgrades under bare strings or fail to match prerelease versions in release gates.
csx.json
{"case":{"caseId":"case:sha256:aa590e3d99767061f50e39bfd3c06eba9b816fb45043c18c77afe38c9e2560de","contract":["assert VersionReq::parse(\"1.2.3\") defaults to Op::Caret matching 1.2.4 and 1.9.0 rather than Op::Exact","assert Version::parse and VersionReq::parse strictly reject 'v' prefix, incomplete tuples, and leading zeroes","assert VersionReq without prerelease tag rejects all prereleases while tagged comparator matches only identical tuples","assert Version Eq and Ord differentiate build metadata for total ordering while cmp_precedence and VersionReq ignore build metadata","assert 0.x caret ranges enforce breaking changes at minor for ^0.x and patch for ^0.0.x while ~0.0.x permits patch bumps"],"goal":"Evaluate bare VersionReq caret defaulting, strict parser syntax, prerelease isolation, and build metadata total ordering in Cargo semver","kind":"HOW","packages":["pkg:cargo/semver@1.0.28"],"schemaVersion":1,"symbols":["semver::Version","semver::Version::parse","semver::Version::cmp_precedence","semver::VersionReq","semver::VersionReq::parse","semver::VersionReq::matches","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::Version","semver::Version::parse","semver::Version::cmp_precedence","semver::VersionReq","semver::VersionReq::parse","semver::VersionReq::matches","semver::Op"],"verifierAdapter":"cargo@1"}
src/lib.rs
//! Proves the core behavioral contracts and subtle traps of Cargo's `semver` crate.
//!
//! Key traps covered:
//! 1. Default `VersionReq::parse` operator: A bare requirement string `"1.2.3"` parses as `^1.2.3`
//!    (Caret operator), NOT `=1.2.3` (Exact match). It matches `1.2.4` and `1.9.0`.
//! 2. Strict parser syntax: `Version::parse` and `VersionReq::parse` reject `'v'` prefixes,
//!    incomplete 2-part versions (`"1.2"`), and leading zeroes (`"01.2.3"`).
//! 3. Prerelease matching boundary: A requirement without a prerelease tag (e.g. `*` or `>=1.0.0`)
//!    never matches a prerelease version. A requirement with a prerelease tag (e.g. `>=1.2.3-alpha.1`)
//!    matches prereleases ONLY when the `[major, minor, patch]` tuple is identical.
//! 4. Build metadata vs equality vs precedence: `PartialEq` and `Ord` evaluate build metadata
//!    structurally to satisfy Rust's Total Order contract, while `cmp_precedence` and `VersionReq::matches`
//!    follow SemVer 2.0 precedence and ignore build metadata.
//! 5. 0.x Caret vs Tilde: `^0.2.3` breaks at minor, `^0.0.3` locks to exact patch, while `~0.0.3` permits patch updates.

use semver::{Version, VersionReq};
use std::cmp::Ordering;

/// Parses a version string strictly per SemVer 2.0 rules (no 'v' prefix, 3 numeric components).
pub fn parse_version(raw: &str) -> Result<Version, semver::Error> {
    Version::parse(raw)
}

/// Parses a version requirement string. Note: bare "1.2.3" produces `^1.2.3` (Caret).
pub fn parse_requirement(raw: &str) -> Result<VersionReq, semver::Error> {
    VersionReq::parse(raw)
}

/// Evaluates whether a version requirement matches a given version.
pub fn matches_req(req: &VersionReq, version: &Version) -> bool {
    req.matches(version)
}

/// Compares two versions using SemVer 2.0 precedence (ignoring build metadata).
pub fn compare_precedence(v1: &Version, v2: &Version) -> Ordering {
    v1.cmp_precedence(v2)
}

/// Compares two versions using Rust's total ordering (which includes build metadata).
pub fn compare_total_ord(v1: &Version, v2: &Version) -> Ordering {
    v1.cmp(v2)
}
tests/contract.rs
use cargo_semver_api::{
    compare_precedence, compare_total_ord, matches_req, parse_requirement, parse_version,
};
use semver::Op;
use std::cmp::Ordering;

#[test]
fn test_default_version_req_is_caret_not_exact() {
    // TRAP 1: In Cargo / Rust semver, `VersionReq::parse("1.2.3")` is `^1.2.3` (Op::Caret).
    // A naive model assumes bare version requirements mean exact matching (`=1.2.3`).
    let req_bare = parse_requirement("1.2.3").expect("valid requirement");
    assert_eq!(req_bare.comparators.len(), 1);
    assert_eq!(
        req_bare.comparators[0].op,
        Op::Caret,
        "Bare version '1.2.3' must produce Op::Caret (^), not Op::Exact (=)"
    );

    let v_exact = parse_version("1.2.3").unwrap();
    let v_patch_bump = parse_version("1.2.4").unwrap();
    let v_minor_bump = parse_version("1.9.0").unwrap();
    let v_major_bump = parse_version("2.0.0").unwrap();

    // Bare "1.2.3" accepts minor and patch updates:
    assert!(matches_req(&req_bare, &v_exact));
    assert!(matches_req(&req_bare, &v_patch_bump));
    assert!(matches_req(&req_bare, &v_minor_bump));
    assert!(!matches_req(&req_bare, &v_major_bump));

    // Caller must explicitly prefix with '=' to get exact pinning:
    let req_exact = parse_requirement("=1.2.3").expect("valid exact requirement");
    assert_eq!(req_exact.comparators[0].op, Op::Exact);
    assert!(matches_req(&req_exact, &v_exact));
    assert!(!matches_req(&req_exact, &v_patch_bump));
    assert!(!matches_req(&req_exact, &v_minor_bump));
}

#[test]
fn test_strict_parsing_syntax_rejections() {
    // TRAP 2: SemVer 2.0 does not allow 'v' prefixes, partial tuples, or leading zeroes.
    // Models frequently write Version::parse("v1.2.3") or Version::parse("1.2").
    assert!(
        parse_version("v1.2.3").is_err(),
        "Version::parse must reject leading 'v'"
    );
    assert!(
        parse_version("1.2").is_err(),
        "Version::parse must reject incomplete 2-part versions"
    );
    assert!(
        parse_version("01.2.3").is_err(),
        "Version::parse must reject numeric components with leading zeroes"
    );
    assert!(
        parse_requirement("v1.2.3").is_err(),
        "VersionReq::parse must also reject leading 'v'"
    );

    // Only strictly valid 3-part SemVer 2.0 strings pass:
    assert!(parse_version("1.2.3").is_ok());
    assert!(parse_version("0.0.0").is_ok());
}

#[test]
fn test_prerelease_boundary_matching_rules() {
    // TRAP 3: Prerelease isolation.
    // A requirement WITHOUT a prerelease tag NEVER matches a prerelease version.
    let req_wildcard = parse_requirement("*").unwrap();
    let req_gte = parse_requirement(">=1.0.0").unwrap();
    let req_caret = parse_requirement("^1.2.0").unwrap();
    let v_pre = parse_version("1.2.3-alpha.1").unwrap();

    assert!(
        !matches_req(&req_wildcard, &v_pre),
        "Wildcard '*' must reject prerelease version 1.2.3-alpha.1"
    );
    assert!(
        !matches_req(&req_gte, &v_pre),
        "'>=1.0.0' must reject prerelease version 1.2.3-alpha.1"
    );
    assert!(
        !matches_req(&req_caret, &v_pre),
        "'^1.2.0' must reject prerelease version 1.2.3-alpha.1"
    );

    // A requirement WITH a prerelease tag only matches prereleases with the SAME [major, minor, patch] tuple:
    let req_pre = parse_requirement(">=1.2.3-alpha.1").unwrap();
    let v_pre_same = parse_version("1.2.3-beta.2").unwrap();
    let v_pre_diff_patch = parse_version("1.2.4-alpha.1").unwrap();
    let v_normal_next = parse_version("1.2.4").unwrap();

    assert!(
        matches_req(&req_pre, &v_pre_same),
        "Same-tuple prerelease 1.2.3-beta.2 matches >=1.2.3-alpha.1"
    );
    assert!(
        !matches_req(&req_pre, &v_pre_diff_patch),
        "Different-patch prerelease 1.2.4-alpha.1 is REJECTED even though 1.2.4 > 1.2.3"
    );
    assert!(
        matches_req(&req_pre, &v_normal_next),
        "Normal release 1.2.4 matches >=1.2.3-alpha.1"
    );
}

#[test]
fn test_build_metadata_eq_ord_vs_precedence() {
    // TRAP 4: Build metadata in Rust `semver`.
    // SemVer 2.0 spec specifies build metadata is ignored for precedence.
    // However, Rust's `Eq` and `Ord` implement total ordering over all struct fields (including build metadata)
    // so that BTreeMap/BTreeSet behave deterministically.
    // For SemVer precedence, callers must use `cmp_precedence`.
    let v1 = parse_version("1.2.3+build.001").unwrap();
    let v2 = parse_version("1.2.3+build.002").unwrap();

    // Structural equality differentiates build metadata:
    assert_ne!(
        v1, v2,
        "Version PartialEq/Eq must distinguish build metadata strings"
    );

    // Ord total ordering differentiates build metadata lexicographically:
    assert_eq!(
        compare_total_ord(&v1, &v2),
        Ordering::Less,
        "Version Ord::cmp compares build metadata for total ordering"
    );

    // SemVer 2.0 precedence ignores build metadata:
    assert_eq!(
        compare_precedence(&v1, &v2),
        Ordering::Equal,
        "Version::cmp_precedence must treat differing build metadata as equal precedence"
    );

    // VersionReq::matches checks SemVer precedence:
    let req_exact = parse_requirement("=1.2.3").unwrap();
    assert!(
        matches_req(&req_exact, &v1),
        "VersionReq::matches(=1.2.3) accepts 1.2.3+build.001 per SemVer precedence"
    );
    assert!(
        matches_req(&req_exact, &v2),
        "VersionReq::matches(=1.2.3) accepts 1.2.3+build.002 per SemVer precedence"
    );
}

#[test]
fn test_zero_major_caret_and_tilde_boundaries() {
    // TRAP 5: 0.x (Zero-major) versions have distinct breaking boundaries.
    // ^0.2.3 allows patch updates but rejects minor bumps (<0.3.0).
    let req_0_2 = parse_requirement("^0.2.3").unwrap();
    assert!(matches_req(&req_0_2, &parse_version("0.2.3").unwrap()));
    assert!(matches_req(&req_0_2, &parse_version("0.2.9").unwrap()));
    assert!(
        !matches_req(&req_0_2, &parse_version("0.3.0").unwrap()),
        "^0.2.3 must reject 0.3.0"
    );

    // ^0.0.3 locks to exact patch (<0.0.4) because 0.0.x patch updates are breaking under Caret.
    let req_0_0_3 = parse_requirement("^0.0.3").unwrap();
    assert!(matches_req(&req_0_0_3, &parse_version("0.0.3").unwrap()));
    assert!(
        !matches_req(&req_0_0_3, &parse_version("0.0.4").unwrap()),
        "^0.0.3 must reject 0.0.4"
    );

    // ~0.0.3 allows patch updates (<0.1.0) even on 0.0.x versions!
    let req_tilde_0_0_3 = parse_requirement("~0.0.3").unwrap();
    assert!(matches_req(
        &req_tilde_0_0_3,
        &parse_version("0.0.4").unwrap()
    ));
    assert!(matches_req(
        &req_tilde_0_0_3,
        &parse_version("0.0.9").unwrap()
    ));
    assert!(
        !matches_req(&req_tilde_0_0_3, &parse_version("0.1.0").unwrap()),
        "~0.0.3 must reject 0.1.0"
    );
}

Seeder d'origine

csx-seed