Skip to content

Commit 362777f

Browse files
committed
Start implementing a test suite for the CLI
We have very few tests today so this starts to add the basics of a test suite which compiles Cargo projects on-the-fly which will hopefully help us bolster the amount of assertions we can make about the output.
1 parent 6edb40a commit 362777f

File tree

7 files changed

+319
-9
lines changed

7 files changed

+319
-9
lines changed

azure-pipelines.yml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,17 @@ jobs:
6262
- template: ci/azure-install-sccache.yml
6363
- script: cargo test --target wasm32-unknown-unknown --features nightly --test wasm
6464

65-
- job: test_cli_support
66-
displayName: "Run wasm-bindgen-cli-support crate tests"
65+
- job: test_cli
66+
displayName: "Run wasm-bindgen-cli crate tests"
6767
steps:
6868
- template: ci/azure-install-rust.yml
6969
- template: ci/azure-install-sccache.yml
70+
- script: rustup target add wasm32-unknown-unknown
71+
displayName: "install wasm target"
7072
- script: cargo test -p wasm-bindgen-cli-support
73+
displayName: "wasm-bindgen-cli-support tests"
74+
- script: cargo test -p wasm-bindgen-cli
75+
displayName: "wasm-bindgen-cli tests"
7176

7277
- job: test_web_sys
7378
displayName: "Run web-sys crate tests"
@@ -139,16 +144,22 @@ jobs:
139144
steps:
140145
- template: ci/azure-install-rust.yml
141146
- template: ci/azure-install-sccache.yml
142-
- script: npm install
147+
- script: mv _package.json package.json && npm install && rm package.json
148+
displayName: "run npm install"
143149
- script: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
144-
- script: cargo build -p wasm-bindgen-cli
145-
- script: ln -snf `pwd`/target/debug/wasm-bindgen $HOME/.cargo/bin/wasm-bindgen
150+
displayName: "install wasm-pack"
151+
- script: |
152+
set -ex
153+
cargo build -p wasm-bindgen-cli
154+
ln -snf `pwd`/target/debug/wasm-bindgen $HOME/.cargo/bin/wasm-bindgen
155+
displayName: "install wasm-bindgen for `wasm-pack` to use"
146156
- script: |
147157
for dir in `ls examples | grep -v README | grep -v asm.js | grep -v raytrace | grep -v without-a-bundler`; do
148158
(cd examples/$dir &&
149159
ln -fs ../../node_modules . &&
150160
npm run build -- --output-path $BUILD_ARTIFACTSTAGINGDIRECTORY/exbuild/$dir) || exit 1;
151161
done
162+
displayName: "build examples"
152163
- task: PublishPipelineArtifact@0
153164
inputs:
154165
artifactName: examples1

crates/cli-support/src/js/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ pub struct Context<'a> {
6767

6868
/// All package.json dependencies we've learned about so far
6969
pub package_json_read: HashSet<&'a str>,
70+
71+
/// A map of the name of npm dependencies we've loaded so far to the path
72+
/// they're defined in as well as their version specification.
7073
pub npm_dependencies: HashMap<String, (&'a str, String)>,
7174

7275
pub anyref: wasm_bindgen_anyref_xform::Context,
@@ -2967,8 +2970,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
29672970
}
29682971
if !self.cx.config.mode.nodejs() && !self.cx.config.mode.bundler() {
29692972
bail!("NPM dependencies have been specified in `{}` but \
2970-
this is only compatible with the default output of \
2971-
`wasm-bindgen` or the `--nodejs` flag");
2973+
this is only compatible with the `bundler` and `nodejs` targets");
29722974
}
29732975
let contents = fs::read_to_string(path).context(format!("failed to read `{}`", path))?;
29742976
let json: serde_json::Value = serde_json::from_str(&contents)?;

crates/cli-support/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ impl OutputMode {
716716

717717
fn bundler(&self) -> bool {
718718
match self {
719-
OutputMode::Bundler => true,
719+
OutputMode::Bundler { .. } => true,
720720
_ => false,
721721
}
722722
}

crates/cli/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,9 @@ walrus = "0.5"
2828
wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.40" }
2929
wasm-bindgen-shared = { path = "../shared", version = "=0.2.40" }
3030

31+
[dev-dependencies]
32+
assert_cmd = "0.11"
33+
predicates = "1.0.0"
34+
3135
[features]
3236
vendored-openssl = ['openssl/vendored']

crates/cli/src/bin/wasm-bindgen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ fn main() {
7979
};
8080
eprintln!("error: {}", err);
8181
for cause in err.iter_causes() {
82-
eprintln!("\tcaused by: {}", cause);
82+
eprintln!(" caused by: {}", cause);
8383
}
8484
process::exit(1);
8585
}

crates/cli/tests/wasm-bindgen/main.rs

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
//! A small test suite for the `wasm-bindgen` CLI command itself
2+
//!
3+
//! This test suite is intended to exercise functionality of the CLI in terms of
4+
//! errors and such. It is not intended for comprehensive behavior testing, as
5+
//! that should all be placed in the top-level `tests` directory for the
6+
//! `wasm-bindgen` crate itself.
7+
//!
8+
//! Assertions about errors in `wasm-bindgen` or assertions about the output of
9+
//! `wasm-bindgen` should all be placed in this test suite, however. Currently
10+
//! it is largely based off actually running `cargo build` at test time which is
11+
//! quite expensive, so it's recommended that this test suite doesn't become too
12+
//! large!
13+
14+
use assert_cmd::prelude::*;
15+
use predicates::str;
16+
use std::env;
17+
use std::fs;
18+
use std::path::PathBuf;
19+
use std::process::Command;
20+
21+
fn target_dir() -> PathBuf {
22+
let mut dir = PathBuf::from(env::current_exe().unwrap());
23+
dir.pop(); // current exe
24+
if dir.ends_with("deps") {
25+
dir.pop();
26+
}
27+
dir.pop(); // debug and/or release
28+
return dir;
29+
}
30+
31+
fn repo_root() -> PathBuf {
32+
let mut repo_root = env::current_dir().unwrap();
33+
repo_root.pop(); // remove 'cli'
34+
repo_root.pop(); // remove 'crates'
35+
repo_root
36+
}
37+
38+
struct Project {
39+
root: PathBuf,
40+
name: &'static str,
41+
}
42+
43+
impl Project {
44+
fn new(name: &'static str) -> Project {
45+
let root = target_dir().join("cli-tests").join(name);
46+
drop(fs::remove_dir_all(&root));
47+
fs::create_dir_all(&root).unwrap();
48+
Project { root, name }
49+
}
50+
51+
fn file(&mut self, name: &str, contents: &str) -> &mut Project {
52+
let dst = self.root.join(name);
53+
fs::create_dir_all(dst.parent().unwrap()).unwrap();
54+
fs::write(&dst, contents).unwrap();
55+
self
56+
}
57+
58+
fn wasm_bindgen(&mut self, args: &str) -> (Command, PathBuf) {
59+
let wasm = self.build();
60+
let output = self.root.join("pkg");
61+
fs::create_dir_all(&output).unwrap();
62+
let mut cmd = Command::cargo_bin("wasm-bindgen").unwrap();
63+
cmd.arg("--out-dir").arg(&output);
64+
cmd.arg(&wasm);
65+
for arg in args.split_whitespace() {
66+
cmd.arg(arg);
67+
}
68+
(cmd, output)
69+
}
70+
71+
fn build(&mut self) -> PathBuf {
72+
if !self.root.join("Cargo.toml").is_file() {
73+
self.file(
74+
"Cargo.toml",
75+
&format!(
76+
"
77+
[package]
78+
name = \"{}\"
79+
authors = []
80+
version = \"1.0.0\"
81+
edition = '2018'
82+
83+
[dependencies]
84+
wasm-bindgen = {{ path = '{}' }}
85+
86+
[lib]
87+
crate-type = ['cdylib']
88+
89+
[workspace]
90+
",
91+
self.name,
92+
repo_root().display(),
93+
),
94+
);
95+
}
96+
97+
let target_dir = target_dir();
98+
Command::new("cargo")
99+
.current_dir(&self.root)
100+
.arg("build")
101+
.arg("--target")
102+
.arg("wasm32-unknown-unknown")
103+
.env("CARGO_TARGET_DIR", &target_dir)
104+
.assert()
105+
.success();
106+
107+
target_dir
108+
.join("wasm32-unknown-unknown")
109+
.join("debug")
110+
.join(self.name)
111+
.with_extension("wasm")
112+
}
113+
}
114+
115+
#[test]
116+
fn version_useful() {
117+
Command::cargo_bin("wasm-bindgen")
118+
.unwrap()
119+
.arg("-V")
120+
.assert()
121+
.stdout(str::ends_with("\n"))
122+
.stdout(str::starts_with("wasm-bindgen "))
123+
.success();
124+
}
125+
126+
#[test]
127+
fn works_on_empty_project() {
128+
let (mut cmd, _out_dir) = Project::new("works_on_empty_project")
129+
.file(
130+
"src/lib.rs",
131+
r#"
132+
"#,
133+
)
134+
.wasm_bindgen("");
135+
cmd.assert().success();
136+
}
137+
138+
mod npm;

crates/cli/tests/wasm-bindgen/npm.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
use crate::*;
2+
3+
#[test]
4+
fn no_modules_rejects_npm() {
5+
let (mut cmd, _out_dir) = Project::new("no_modules_rejects_npm")
6+
.file(
7+
"src/lib.rs",
8+
r#"
9+
use wasm_bindgen::prelude::*;
10+
11+
#[wasm_bindgen(module = "foo")]
12+
extern {
13+
fn foo();
14+
}
15+
16+
#[wasm_bindgen(start)]
17+
pub fn main() {
18+
foo();
19+
}
20+
"#,
21+
)
22+
.file("package.json", "")
23+
.wasm_bindgen("--no-modules");
24+
cmd.assert()
25+
.stderr("\
26+
error: failed to generate bindings for JS import `foo`
27+
caused by: import from `foo` module not allowed with `--target no-modules`; use `nodejs`, `web`, or `bundler` target instead
28+
")
29+
.failure();
30+
}
31+
32+
#[test]
33+
fn more_package_json_fields_rejected() {
34+
let (mut cmd, _out_dir) = Project::new("more_package_json_fields_rejected")
35+
.file(
36+
"src/lib.rs",
37+
r#"
38+
use wasm_bindgen::prelude::*;
39+
40+
#[wasm_bindgen(module = "foo")]
41+
extern {
42+
fn foo();
43+
}
44+
45+
#[wasm_bindgen(start)]
46+
pub fn main() {
47+
foo();
48+
}
49+
"#,
50+
)
51+
.file(
52+
"package.json",
53+
r#"
54+
{
55+
"name": "foo",
56+
"dependencies": {}
57+
}
58+
"#,
59+
)
60+
.wasm_bindgen("");
61+
cmd.assert()
62+
.stderr(str::is_match("\
63+
error: NPM manifest found at `.*` can currently only have one key, .*
64+
").unwrap())
65+
.failure();
66+
}
67+
68+
#[test]
69+
fn npm_conflict_rejected() {
70+
let (mut cmd, _out_dir) = Project::new("npm_conflict_rejected")
71+
.file(
72+
"Cargo.toml",
73+
&format!(r#"
74+
[package]
75+
name = "npm_conflict_rejected"
76+
authors = []
77+
version = "1.0.0"
78+
edition = '2018'
79+
80+
[dependencies]
81+
wasm-bindgen = {{ path = '{}' }}
82+
bar = {{ path = 'bar' }}
83+
84+
[lib]
85+
crate-type = ['cdylib']
86+
87+
[workspace]
88+
"#,
89+
repo_root().display()
90+
)
91+
)
92+
.file(
93+
"src/lib.rs",
94+
r#"
95+
use wasm_bindgen::prelude::*;
96+
97+
#[wasm_bindgen(module = "bar")]
98+
extern {
99+
fn foo();
100+
}
101+
102+
#[wasm_bindgen(start)]
103+
pub fn main() {
104+
foo();
105+
bar::foo();
106+
}
107+
"#,
108+
)
109+
.file(
110+
"package.json",
111+
r#"
112+
{
113+
"dependencies": {"bar": "0.0.0"}
114+
}
115+
"#,
116+
)
117+
.file(
118+
"bar/Cargo.toml",
119+
&format!(r#"
120+
[package]
121+
name = "bar"
122+
authors = []
123+
version = "1.0.0"
124+
edition = '2018'
125+
126+
[dependencies]
127+
wasm-bindgen = {{ path = '{}' }}
128+
"#,
129+
repo_root().display()
130+
)
131+
)
132+
.file(
133+
"bar/src/lib.rs",
134+
r#"
135+
use wasm_bindgen::prelude::*;
136+
137+
#[wasm_bindgen(module = "bar")]
138+
extern {
139+
pub fn foo();
140+
}
141+
"#,
142+
)
143+
.file(
144+
"bar/package.json",
145+
r#"
146+
{
147+
"dependencies": {"bar": "1.0.0"}
148+
}
149+
"#,
150+
)
151+
.wasm_bindgen("");
152+
cmd.assert()
153+
.stderr(str::is_match("dependency on NPM package `bar` specified in two").unwrap())
154+
.failure();
155+
}

0 commit comments

Comments
 (0)