//! Tests for the `min-publish-age` feature (RFC 3923).

use cargo_test_support::compare::assert_e2e;
use cargo_test_support::install::assert_has_installed_exe;
use cargo_test_support::paths;
use cargo_test_support::project;
use cargo_test_support::registry;
use cargo_test_support::registry::Package;
use cargo_test_support::str;

use crate::prelude::*;
use crate::utils::cargo_process;

/// Mocked "now" for deterministic publish-age comparisons.
const NOW: &str = "2006-08-08T00:00:00Z";

fn publish_packages() {
    // 14 days before `NOW`
    Package::new("bar", "1.0.0")
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    // 2 days before `NOW`
    Package::new("bar", "1.1.0")
        .pubtime("2006-08-06T00:00:00Z")
        .publish();
}

#[cargo_test]
fn feature_gated() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1.0"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[WARNING] ignoring `registry.global-min-publish-age` without `-Zmin-publish-age`
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn feature_gated_env() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1.0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile")
        .env("CARGO_REGISTRY_GLOBAL_MIN_PUBLISH_AGE", "7 days")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[WARNING] ignoring `registry.global-min-publish-age` without `-Zmin-publish-age`
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn warns_on_resolver_config_without_flag() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1.0"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [resolver]
                incompatible-publish-age = "deny"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile")
        .with_stderr_data(str![[r#"
[WARNING] ignoring `resolver.incompatible-publish-age` without `-Zmin-publish-age`
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version

"#]])
        .run();
}

#[cargo_test]
fn filters_too_new_versions() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (available: v1.1.0, published 2 days ago)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn incompatible_publish_age_allow() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [resolver]
                incompatible-publish-age = "allow"

                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.1.0 (published 2 days ago, minimum age 7 days)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn incompatible_publish_age_deny() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [resolver]
                incompatible-publish-age = "deny"

                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (available: v1.1.0, published 2 days ago)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn no_candidates_error() {
    Package::new("bar", "0.2.0")
        .pubtime("2006-07-06T00:00:00Z") // ver-req not match, old enough
        .publish();
    Package::new("bar", "0.3.0")
        .pubtime("2006-08-05T00:00:00Z") // ver-req not match, too-new
        .publish();
    Package::new("bar", "1.1.0")
        .pubtime("2006-08-06T00:00:00Z")
        .publish();
    Package::new("bar", "1.2.0")
        .pubtime("2006-08-07T00:00:00Z")
        .publish();
    Package::new("bar", "1.3.0")
        .pubtime("2006-08-08T00:00:20Z") // a future version (clock drift)
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_status(101)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[ERROR] failed to select a version for the requirement `bar = "^1"`
  version 1.1.0 is too new (published 2 days ago, minimum age 7 days)
  version 1.2.0 is too new (published 24 hours ago, minimum age 7 days)
  version 1.3.0 is too new (published moments ago, minimum age 7 days)
location searched: `dummy-registry` index (which is replacing registry `crates-io`)
required by package `foo v0.0.0 ([ROOT]/foo)`
[HELP] to preserve the min-publish-age, downgrade the requirement to "0.2.0"
[HELP] to use too-new packages anyways, re-resolve with `CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow`

"#]])
        .run();
}

#[cargo_test]
fn report_unchanged_too_new_version() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [resolver]
                incompatible-publish-age = "allow"

                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .run();

    p.cargo("update --verbose -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 0 packages to latest compatible versions
[UNCHANGED] bar v1.1.0 (published 2 days ago, minimum age 7 days)
[NOTE] to see how you depend on a package, run `cargo tree --invert <dep>@<ver>`

"#]])
        .run();
}

#[cargo_test]
fn report_rust_version_note_over_too_new_note() {
    Package::new("bar", "1.0.0")
        .rust_version("1.60.0")
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    // 2 days before `NOW`, and needs a newer Rust than the workspace.
    Package::new("bar", "1.1.0")
        .rust_version("1.65535.0")
        .pubtime("2006-08-06T00:00:00Z")
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"
                rust-version = "1.60.0"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [resolver]
                incompatible-publish-age = "allow"
                incompatible-rust-versions = "allow"

                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.1.0 (requires Rust 1.65535.0)

"#]])
        .run();
}

#[cargo_test]
fn locked_versions_preserved() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file(
            "Cargo.lock",
            r#"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]
"#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("check -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[DOWNLOADING] crates ...
[DOWNLOADED] bar v1.1.0 (registry `dummy-registry`)
[CHECKING] bar v1.1.0
[CHECKING] foo v0.0.0 ([ROOT]/foo)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn patched_versions_preserved() {
    registry::alt_init();
    // Old on crates.io, but patched away.
    Package::new("bar", "1.0.0")
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    // Too new on the alternative registry
    Package::new("bar", "1.1.0")
        .alternative(true)
        .pubtime("2006-08-06T00:00:00Z")
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"

                [patch.crates-io]
                bar = { version = "1.1.0", registry = "alternative" }
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `alternative` index
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.1.0 (registry `alternative`) (published 2 days ago, minimum age 7 days)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+[ROOTURL]/alternative-registry"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn versions_without_pubtime_unaffected() {
    Package::new("bar", "1.0.0").publish();
    Package::new("bar", "1.1.0").publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn cargo_install_ignores_min_publish_age() {
    Package::new("foo", "1.0.0")
        .file("src/main.rs", "fn main() {}")
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    Package::new("foo", "1.1.0")
        .file("src/main.rs", "fn main() {}")
        .pubtime("2006-08-06T00:00:00Z")
        .publish();

    cargo_process("install foo -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .env("CARGO_REGISTRY_GLOBAL_MIN_PUBLISH_AGE", "7 days")
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[DOWNLOADING] crates ...
[DOWNLOADED] foo v1.1.0 (registry `dummy-registry`)
[INSTALLING] foo v1.1.0
[COMPILING] foo v1.1.0
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
[INSTALLED] package `foo v1.1.0` (executable `foo[EXE]`)
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries

"#]])
        .run();

    assert_has_installed_exe(paths::cargo_home(), "foo");
}

#[cargo_test]
fn cargo_install_allows_too_new_deps() {
    Package::new("bar", "1.0.0")
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    Package::new("bar", "1.1.0")
        .pubtime("2006-08-06T00:00:00Z")
        .publish();
    Package::new("foo", "1.0.0")
        .dep("bar", "1")
        .file("src/lib.rs", "")
        .file("src/main.rs", "extern crate bar; fn main() {}")
        .pubtime("2006-07-25T00:00:00Z")
        .publish();

    cargo_process("install foo -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .env("CARGO_REGISTRY_GLOBAL_MIN_PUBLISH_AGE", "7 days")
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[DOWNLOADING] crates ...
[DOWNLOADED] foo v1.0.0 (registry `dummy-registry`)
[INSTALLING] foo v1.0.0
[LOCKING] 1 package to latest compatible version
[DOWNLOADING] crates ...
[DOWNLOADED] bar v1.1.0 (registry `dummy-registry`)
[COMPILING] bar v1.1.0
[COMPILING] foo v1.0.0
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
[INSTALLED] package `foo v1.0.0` (executable `foo[EXE]`)
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries

"#]])
         .run();

    assert_has_installed_exe(paths::cargo_home(), "foo");
}

#[cargo_test]
fn cargo_install_path_allows_too_new_deps() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/main.rs", "extern crate bar; fn main() {}")
        .build();

    p.cargo("install --path . -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[INSTALLING] foo v0.0.0 ([ROOT]/foo)
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (available: v1.1.0, published 2 days ago)
[DOWNLOADING] crates ...
[DOWNLOADED] bar v1.0.0 (registry `dummy-registry`)
[COMPILING] bar v1.0.0
[COMPILING] foo v0.0.0 ([ROOT]/foo)
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
[INSTALLED] package `foo v0.0.0 ([ROOT]/foo)` (executable `foo[EXE]`)
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries

"#]])
        .run();

    assert_has_installed_exe(paths::cargo_home(), "foo");
}

#[cargo_test]
fn cargo_install_locked_allows_too_new_dep() {
    publish_packages();
    Package::new("foo", "1.0.0")
        .dep("bar", "1")
        .file("src/lib.rs", "")
        .file("src/main.rs", "extern crate bar; fn main() {}")
        .file(
            "Cargo.lock",
            r#"
[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "foo"
version = "1.0.0"
dependencies = [
 "bar 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
"#,
        )
        .pubtime("2006-07-25T00:00:00Z")
        .publish();

    cargo_process("install --locked foo -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .env("CARGO_REGISTRY_GLOBAL_MIN_PUBLISH_AGE", "7 days")
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[DOWNLOADING] crates ...
[DOWNLOADED] foo v1.0.0 (registry `dummy-registry`)
[INSTALLING] foo v1.0.0
[DOWNLOADING] crates ...
[DOWNLOADED] bar v1.1.0 (registry `dummy-registry`)
[COMPILING] bar v1.1.0
[COMPILING] foo v1.0.0
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
[INSTALLED] package `foo v1.0.0` (executable `foo[EXE]`)
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries

"#]])
        .run();

    assert_has_installed_exe(paths::cargo_home(), "foo");
}

#[cargo_test]
fn update_precise_to_too_new() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (available: v1.1.0, published 2 days ago)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );

    p.cargo("update bar --precise 1.1.0 -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_status(101)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[ERROR] failed to select a version for the requirement `bar = "^1"`
  version 1.1.0 is too new (published 2 days ago, minimum age 7 days)
location searched: `dummy-registry` index (which is replacing registry `crates-io`)
required by package `foo v0.0.0 ([ROOT]/foo)`
[HELP] to use too-new packages anyways, re-resolve with `CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow`

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn update_precise_with_allow() {
    publish_packages();
    // 1 day before `NOW`, also too new.
    Package::new("bar", "1.2.0")
        .pubtime("2006-08-07T00:00:00Z")
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (available: v1.2.0, published 24 hours ago)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );

    p.cargo("update bar --precise 1.1.0 -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .env("CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE", "allow")
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[UPDATING] bar v1.0.0 -> v1.1.0 (published 2 days ago, minimum age 7 days)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn publish_age_zero() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn publish_age_invalid() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "garbage"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_status(101)
        .with_stderr_data(str![[r#"
[ERROR] invalid value for `registry.global-min-publish-age`: expected a value of the form "N seconds/minutes/hours/days/weeks/months", got: "garbage"

"#]])
        .run();
}

#[cargo_test]
fn registry_default() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (available: v1.1.0, published 2 days ago)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn registry_default_overrides_global() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "0"
                min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (available: v1.1.0, published 2 days ago)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn registry_default_zero_overrides_global() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
                min-publish-age = "0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn registries_crates_io() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registries.crates-io]
                min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (available: v1.1.0, published 2 days ago)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn registries_crates_io_overrides_registry_default() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                min-publish-age = "7 days"

                [registries.crates-io]
                min-publish-age = "0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 1 package to latest compatible version

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn registries_alt() {
    registry::alt_init();
    Package::new("bar", "1.0.0")
        .alternative(true)
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    Package::new("bar", "1.1.0")
        .alternative(true)
        .pubtime("2006-08-06T00:00:00Z")
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = { version = "1", registry = "alternative" }
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registries.alternative]
                min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `alternative` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (registry `alternative`) (available: v1.1.0, published 2 days ago)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+[ROOTURL]/alternative-registry"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn registries_alt_overrides_global() {
    registry::alt_init();
    Package::new("bar", "1.0.0")
        .alternative(true)
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    Package::new("bar", "1.1.0")
        .alternative(true)
        .pubtime("2006-08-06T00:00:00Z")
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = { version = "1", registry = "alternative" }
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"

                [registries.alternative]
                min-publish-age = "0"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `alternative` index
[LOCKING] 1 package to latest compatible version

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+[ROOTURL]/alternative-registry"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn registries_alt_respects_global() {
    registry::alt_init();
    Package::new("bar", "1.0.0")
        .alternative(true)
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    Package::new("bar", "1.1.0")
        .alternative(true)
        .pubtime("2006-08-06T00:00:00Z")
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = { version = "1", registry = "alternative" }
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `alternative` index
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (registry `alternative`) (available: v1.1.0, published 2 days ago)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+[ROOTURL]/alternative-registry"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn registries_alt_ignores_registry_default() {
    registry::alt_init();
    Package::new("bar", "1.0.0")
        .alternative(true)
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    Package::new("bar", "1.1.0")
        .alternative(true)
        .pubtime("2006-08-06T00:00:00Z")
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = { version = "1", registry = "alternative" }
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `alternative` index
[LOCKING] 1 package to latest compatible version

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+[ROOTURL]/alternative-registry"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

#[cargo_test]
fn registry_alt_ignores_min_publish_age() {
    // `registry.min-publish-age` stays crates.io-only
    // and must not apply to the alt registry,
    // just like `registry.token`.
    // This may change before stabilization
    registry::alt_init();
    Package::new("bar", "1.0.0")
        .alternative(true)
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    Package::new("bar", "1.1.0")
        .alternative(true)
        .pubtime("2006-08-06T00:00:00Z")
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                bar = { version = "1", registry = "alternative" }
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                default = "alternative"
                min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `alternative` index
[LOCKING] 1 package to latest compatible version

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.1.0"
source = "registry+[ROOTURL]/alternative-registry"
checksum = "2216902cacb5611f65e00da63d917a6b9f4dbb10ddc39ee24c853322ab44b041"

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "bar",
]

"##]],
    );
}

/// Mimic `rust_version::resolve_with_backtracking`.
///
/// This is unlikely to happen unless a registry did something weird
/// that a old published crate can depend on future published crate.
#[cargo_test]
fn resolve_with_backtracking() {
    // foo@1.1.0 (old) depends on bar@2.0 (too new) -> backtrack to foo@1.0.0
    Package::new("bar", "1.0.0")
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    Package::new("bar", "2.0.0")
        .pubtime("2006-08-06T00:00:00Z")
        .publish();
    Package::new("dep", "1.0.0")
        .dep("bar", "1")
        .pubtime("2006-07-25T00:00:00Z")
        .publish();
    Package::new("dep", "1.1.0")
        .dep("bar", "2")
        .pubtime("2006-07-25T00:00:00Z")
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"

                [dependencies]
                dep = "1"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("generate-lockfile -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[LOCKING] 2 packages to latest compatible versions
[ADDING] dep v1.0.0 (available: v1.1.0)

"#]])
        .run();

    assert_e2e().eq(
        p.read_lockfile(),
        str![[r##"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "bar"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75120345f1869de1197d82823818e8151ad3325d58f084044181fc4457c087c4"

[[package]]
name = "dep"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f7ae4b3f8c82164502d95cdee595a98e7855c7134987510b31e2d9004bcdbc8"
dependencies = [
 "bar",
]

[[package]]
name = "foo"
version = "0.0.0"
dependencies = [
 "dep",
]

"##]],
    );
}

#[cargo_test]
fn cargo_add_skips_too_new() {
    publish_packages();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("add bar -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[ADDING] bar v1.0.0 to dependencies
[LOCKING] 1 package to latest compatible version
[ADDING] bar v1.0.0 (available: v1.1.0, published 2 days ago)

"#]])
        .run();

    assert_e2e().eq(
        p.read_file("Cargo.toml"),
        str![[r#"

                [package]
                name = "foo"
                edition = "2021"

[dependencies]
bar = "1.0.0"
            
"#]],
    );
}

#[cargo_test]
fn cargo_add_all_versions_too_new() {
    Package::new("bar", "1.1.0")
        .pubtime("2006-08-06T00:00:00Z")
        .publish();
    Package::new("bar", "1.2.0")
        .pubtime("2006-08-07T00:00:00Z")
        .publish();
    Package::new("bar", "1.3.0")
        .pubtime("2006-08-08T00:00:20Z") // a future version (clock drift)
        .publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = "foo"
                edition = "2021"
            "#,
        )
        .file(
            ".cargo/config.toml",
            r#"
                [registry]
                global-min-publish-age = "7 days"
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("add bar -Zmin-publish-age")
        .masquerade_as_nightly_cargo(&["min-publish-age"])
        .env("__CARGO_TEST_INVOCATION_TIME", NOW)
        .with_status(101)
        .with_stderr_data(str![[r#"
[UPDATING] `dummy-registry` index
[ERROR] all versions of crate `bar` are too new per `min-publish-age`
  version 1.1.0 is too new (published 2 days ago, minimum age 7 days)
  version 1.2.0 is too new (published 24 hours ago, minimum age 7 days)
  version 1.3.0 is too new (published moments ago, minimum age 7 days)
[HELP] to add the latest version anyways, re-run with `CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow`

"#]])
        .run();
}
