use std::fs;
use anyhow::{Context, Result};
use assert_cmd::prelude::*;
use predicates::{prelude::PredicateBooleanExt, str::contains};
use toml_edit::value;
use crate::support::*;
mod support;
#[test]
fn help() {
for arg in ["help update", "update -h", "update --help"] {
cargo_component(arg.split_whitespace())
.assert()
.stdout(contains(
"Update dependencies as recorded in the component lock file",
))
.success();
}
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn update_without_changes_is_a_noop() -> Result<()> {
let (server, config, _) = spawn_server(Vec::<String>::new()).await?;
publish_wit(
config,
"test:bar",
"1.0.0",
r#"package test:bar@1.0.0;
world foo {
import foo: func() -> string;
export bar: func() -> string;
}"#,
)
.await?;
let project = server.project("component", true, ["--target", "test:bar@1.0.0"])?;
project
.cargo_component(["build"])
.assert()
.stderr(contains(
"Finished `dev` profile [unoptimized + debuginfo] target(s)",
))
.success();
validate_component(&project.debug_wasm("component"))?;
project
.cargo_component(["update"])
.assert()
.success()
.stderr(contains("test:bar").not());
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn update_without_compatible_changes_is_a_noop() -> Result<()> {
let (server, config, _) = spawn_server(Vec::<String>::new()).await?;
publish_wit(
config.clone(),
"test:bar",
"1.0.0",
r#"package test:bar@1.0.0;
world foo {
import foo: func() -> string;
export bar: func() -> string;
}"#,
)
.await?;
let project = server.project("component", true, ["--target", "test:bar@1.0.0"])?;
project
.cargo_component(["build"])
.assert()
.stderr(contains(
"Finished `dev` profile [unoptimized + debuginfo] target(s)",
))
.success();
validate_component(&project.debug_wasm("component"))?;
publish_wit(
config,
"test:bar",
"2.0.0",
r#"package test:bar@2.0.0;
world foo {
export bar: func() -> string;
}"#,
)
.await?;
project
.cargo_component(["update"])
.assert()
.success()
.stderr(contains("test:bar").not());
project
.cargo_component(["build"])
.assert()
.stderr(contains(
"Finished `dev` profile [unoptimized + debuginfo] target(s)",
))
.success();
validate_component(&project.debug_wasm("component"))?;
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn update_with_compatible_changes() -> Result<()> {
let (server, config, _) = spawn_server(Vec::<String>::new()).await?;
publish_wit(
config.clone(),
"test:bar",
"1.0.0",
r#"package test:bar@1.0.0;
world foo {
import foo: func() -> string;
export bar: func() -> string;
}"#,
)
.await?;
let project = server.project("component", true, ["--target", "test:bar@1.0.0"])?;
project
.cargo_component(["build"])
.assert()
.stderr(contains(
"Finished `dev` profile [unoptimized + debuginfo] target(s)",
))
.success();
validate_component(&project.debug_wasm("component"))?;
publish_wit(
config,
"test:bar",
"1.1.0",
r#"package test:bar@1.1.0;
world foo {
import foo: func() -> string;
import baz: func() -> string;
export bar: func() -> string;
}"#,
)
.await?;
project
.cargo_component(["update"])
.assert()
.success()
.stderr(contains("`test:bar` v1.0.0 -> v1.1.0"));
let source = r#"
#[allow(warnings)]
mod bindings;
use bindings::{baz, Guest};
struct Component;
impl Guest for Component {
fn bar() -> String {
baz()
}
}
bindings::export!(Component with_types_in bindings);
"#;
fs::write(project.root().join("src/lib.rs"), source)?;
project
.cargo_component(["build"])
.assert()
.stderr(contains(
"Finished `dev` profile [unoptimized + debuginfo] target(s)",
))
.success();
validate_component(&project.debug_wasm("component"))?;
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn update_with_compatible_changes_is_noop_for_dryrun() -> Result<()> {
let (server, config, _) = spawn_server(Vec::<String>::new()).await?;
publish_wit(
config.clone(),
"test:bar",
"1.0.0",
r#"package test:bar@1.0.0;
world foo {
import foo: func() -> string;
export bar: func() -> string;
}"#,
)
.await?;
let project = server.project("component", true, ["--target", "test:bar@1.0.0"])?;
project
.cargo_component(["build"])
.assert()
.stderr(contains(
"Finished `dev` profile [unoptimized + debuginfo] target(s)",
))
.success();
validate_component(&project.debug_wasm("component"))?;
publish_wit(
config.clone(),
"test:bar",
"1.1.0",
r#"package test:bar@1.1.0;
world foo {
import foo: func() -> string;
import baz: func() -> string;
export bar: func() -> string;
}"#,
)
.await?;
project
.cargo_component(["update", "--dry-run"])
.assert()
.success()
.stderr(contains(
"Would update dependency `test:bar` v1.0.0 -> v1.1.0",
));
project
.cargo_component(["build"])
.assert()
.stderr(contains(
"Finished `dev` profile [unoptimized + debuginfo] target(s)",
))
.success();
validate_component(&project.debug_wasm("component"))?;
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn update_with_changed_dependencies() -> Result<()> {
let (server, config, _) = spawn_server(Vec::<String>::new()).await?;
publish_component(config.clone(), "test:bar", "1.0.0", "(component)").await?;
publish_component(config, "test:baz", "1.0.0", "(component)").await?;
let project = server.project("foo", true, Vec::<String>::new())?;
project
.cargo_component(["build"])
.assert()
.stderr(contains(
"Finished `dev` profile [unoptimized + debuginfo] target(s)",
))
.success();
validate_component(&project.debug_wasm("foo"))?;
project
.cargo_component(["add", "test:bar"])
.assert()
.stderr(contains("Added dependency `test:bar` with version `1.0.0`"))
.success();
project
.cargo_component(["build"])
.assert()
.stderr(contains(
"Finished `dev` profile [unoptimized + debuginfo] target(s)",
))
.success();
project.update_manifest(|mut doc| {
let deps = doc["package"]["metadata"]["component"]["dependencies"]
.as_table_mut()
.context("missing deps table")?;
deps.remove("test:bar").context("missing dependency")?;
deps.insert("test:baz", value("1.0.0"));
Ok(doc)
})?;
project
.cargo_component(["update"])
.assert()
.stderr(
contains("Removing dependency `test:bar` v1.0.0")
.and(contains("Adding dependency `test:baz` v1.0.0")),
)
.success();
project
.cargo_component(["build"])
.assert()
.stderr(contains(
"Finished `dev` profile [unoptimized + debuginfo] target(s)",
))
.success();
Ok(())
}