use crate::support::*;
use anyhow::{Context, Result};
use assert_cmd::prelude::*;
use predicates::{prelude::PredicateBooleanExt, str::contains};
use std::{fs, rc::Rc};
use tempfile::TempDir;
use toml_edit::value;
mod support;
#[test]
fn help() {
for arg in ["help update", "update -h", "update --help"] {
cargo_component(arg)
.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 dir = Rc::new(TempDir::new()?);
let (_server, config) = spawn_server(dir.path()).await?;
config.write_to_file(&dir.path().join("warg-config.json"))?;
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;
}"#,
true,
)
.await?;
let project = Project::with_dir(dir.clone(), "component", "--target test:bar@1.0.0")?;
project
.cargo_component("build")
.assert()
.stderr(contains("Finished dev [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 dir = Rc::new(TempDir::new()?);
let (_server, config) = spawn_server(dir.path()).await?;
config.write_to_file(&dir.path().join("warg-config.json"))?;
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;
}"#,
true,
)
.await?;
let project = Project::with_dir(dir.clone(), "component", "--target test:bar@1.0.0")?;
project
.cargo_component("build")
.assert()
.stderr(contains("Finished dev [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;
}"#,
false,
)
.await?;
project
.cargo_component("update")
.assert()
.success()
.stderr(contains("test:bar").not());
project
.cargo_component("build")
.assert()
.stderr(contains("Finished dev [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 dir = Rc::new(TempDir::new()?);
let (_server, config) = spawn_server(dir.path()).await?;
config.write_to_file(&dir.path().join("warg-config.json"))?;
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;
}"#,
true,
)
.await?;
let project = Project::with_dir(dir.clone(), "component", "--target test:bar@1.0.0")?;
project
.cargo_component("build")
.assert()
.stderr(contains("Finished dev [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;
}"#,
false,
)
.await?;
project
.cargo_component("update")
.assert()
.success()
.stderr(contains("`test:bar` v1.0.0 -> v1.1.0"));
let source = r#"
mod bindings;
use bindings::{baz, Guest};
struct Component;
impl Guest for Component {
fn bar() -> String {
baz()
}
}
"#;
fs::write(project.root().join("src/lib.rs"), source)?;
project
.cargo_component("build")
.assert()
.stderr(contains("Finished dev [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 dir = Rc::new(TempDir::new()?);
let (_server, config) = spawn_server(dir.path()).await?;
config.write_to_file(&dir.path().join("warg-config.json"))?;
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;
}"#,
true,
)
.await?;
let project = Project::with_dir(dir.clone(), "component", "--target test:bar@1.0.0")?;
project
.cargo_component("build")
.assert()
.stderr(contains("Finished dev [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;
}"#,
false,
)
.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 [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 dir = Rc::new(TempDir::new()?);
let (_server, config) = spawn_server(dir.path()).await?;
config.write_to_file(&dir.path().join("warg-config.json"))?;
publish_component(&config, "test:bar", "1.0.0", "(component)", true).await?;
publish_component(&config, "test:baz", "1.0.0", "(component)", true).await?;
let project = Project::with_dir(dir.clone(), "foo", "")?;
project
.cargo_component("build")
.assert()
.stderr(contains("Finished dev [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 [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 [unoptimized + debuginfo] target(s)"))
.success();
Ok(())
}