fork of https://github.com/rustwasm/wasm-pack for the needs of NextGraph.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
wasm-pack/tests/all/utils/fixture.rs

439 lines
13 KiB

use super::logger::null_logger;
use std::env;
use std::fs;
use std::mem::ManuallyDrop;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::sync::{MutexGuard, Once, ONCE_INIT};
use std::thread;
use tempfile::TempDir;
use wasm_pack;
use wasm_pack::binaries::Cache;
/// A test fixture in a temporary directory.
pub struct Fixture {
// NB: we wrap the fixture's tempdir in a `ManuallyDrop` so that if a test
// fails, its directory isn't deleted, and we have a chance to manually
// inspect its state and figure out what is going on.
pub dir: ManuallyDrop<TempDir>,
pub path: PathBuf,
}
impl Fixture {
/// Create a new test fixture in a temporary directory.
pub fn new() -> Fixture {
// Make sure that all fixtures end up sharing a target dir, and we don't
// recompile wasm-bindgen and friends many times over.
static SET_TARGET_DIR: Once = ONCE_INIT;
let target_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("target");
SET_TARGET_DIR.call_once(|| {
env::set_var("CARGO_TARGET_DIR", &target_dir);
});
let root = target_dir.join("t");
fs::create_dir_all(&root).unwrap();
let dir = TempDir::new_in(&root).unwrap();
let path = dir.path().join("wasm-pack");
eprintln!("Created fixture at {}", path.display());
Fixture {
dir: ManuallyDrop::new(dir),
path,
}
}
/// Create a file within this fixture.
///
/// `path` should be a relative path to the file (relative within this
/// fixture's path).
///
/// The `contents` are written to the file.
pub fn file<P: AsRef<Path>, C: AsRef<[u8]>>(&self, path: P, contents: C) -> &Self {
assert!(path.as_ref().is_relative());
let path = self.path.join(path);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).unwrap();
}
fs::write(path, contents).unwrap();
self
}
/// Add a generic `README.md` file to the fixture.
pub fn readme(&self) -> &Self {
self.file(
"README.md",
r#"
# Fixture!
> an example rust -> wasm project
"#,
)
}
/// Add a `Cargo.toml` with a correctly configured `wasm-bindgen`
/// dependency, `wasm-bindgen-test` dev-dependency, and `crate-type =
/// ["cdylib"]`.
///
/// `name` is the crate's name.
pub fn cargo_toml(&self, name: &str) -> &Self {
self.file(
"Cargo.toml",
&format!(
r#"
[package]
authors = ["The wasm-pack developers"]
description = "so awesome rust+wasm package"
license = "WTFPL"
name = "{}"
repository = "https://github.com/rustwasm/wasm-pack.git"
version = "0.1.0"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "=0.2.21"
[dev-dependencies]
wasm-bindgen-test = "=0.2.21"
"#,
name
),
)
}
/// Add a `src/lib.rs` file that contains a "hello world" program.
pub fn hello_world_src_lib(&self) -> &Self {
self.file(
"src/lib.rs",
r#"
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
// Import the `window.alert` function from the Web.
#[wasm_bindgen]
extern {
fn alert(s: &str);
}
// Export a `greet` function from Rust to JavaScript, that alerts a
// hello message.
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
"#,
)
}
/// Install a local wasm-bindgen for this fixture.
///
/// Takes care not to re-install for every fixture, but only the one time
/// for the whole test suite.
pub fn install_local_wasm_bindgen(&self) -> PathBuf {
static INSTALL_WASM_BINDGEN: Once = ONCE_INIT;
let cache = self.cache();
let version = "0.2.21";
let log = &null_logger();
let download = || {
if let Ok(download) =
wasm_pack::bindgen::download_prebuilt_wasm_bindgen(&cache, version, true)
{
return Ok(download);
}
wasm_pack::bindgen::cargo_install_wasm_bindgen(log, &cache, version, true)
};
// Only one thread can perform the actual download, and then afterwards
// everything will hit the cache so we can run the same path.
INSTALL_WASM_BINDGEN.call_once(|| {
download().unwrap();
});
download().unwrap().binary("wasm-bindgen")
}
/// Download `geckodriver` and return its path.
///
/// Takes care to ensure that only one `geckodriver` is downloaded for the whole
/// test suite.
pub fn install_local_geckodriver(&self) -> PathBuf {
static FETCH_GECKODRIVER: Once = ONCE_INIT;
let cache = self.cache();
// like above for synchronization
FETCH_GECKODRIVER.call_once(|| {
wasm_pack::test::webdriver::install_geckodriver(&cache, true).unwrap();
});
wasm_pack::test::webdriver::install_geckodriver(&cache, true).unwrap()
}
/// Download `chromedriver` and return its path.
///
/// Takes care to ensure that only one `chromedriver` is downloaded for the whole
/// test suite.
pub fn install_local_chromedriver(&self) -> PathBuf {
static FETCH_CHROMEDRIVER: Once = ONCE_INIT;
let cache = self.cache();
// like above for synchronization
FETCH_CHROMEDRIVER.call_once(|| {
wasm_pack::test::webdriver::install_chromedriver(&cache, true).unwrap();
});
wasm_pack::test::webdriver::install_chromedriver(&cache, true).unwrap()
}
pub fn cache(&self) -> Cache {
let target_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("target");
Cache::at(&target_dir.join("test_cache"))
}
/// The `step_install_wasm_bindgen` and `step_run_wasm_bindgen` steps only
/// occur after the `step_build_wasm` step. In order to read the lockfile
/// in the test fixture's temporary directory, we should first build the
/// crate, targeting `wasm32-unknown-unknown`.
pub fn cargo_check(&self) -> &Self {
Command::new("cargo")
.current_dir(&self.path)
.arg("check")
.arg("--target")
.arg("wasm32-unknown-unknown")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.unwrap();
self
}
pub fn run(&self, cmd: wasm_pack::command::Command) -> Result<(), failure::Error> {
let logger = wasm_pack::logger::new(&cmd, 3)?;
match cmd {
wasm_pack::command::Command::Test(cmd) => {
let _lock = self.lock();
let mut test = wasm_pack::command::test::Test::try_from_opts(cmd)?;
test.set_cache(self.cache());
test.run(&logger)
}
wasm_pack::command::Command::Build(cmd) => {
let mut build = wasm_pack::command::build::Build::try_from_opts(cmd)?;
build.set_cache(self.cache());
build.run(&logger)
}
_ => unreachable!(),
}
}
pub fn lock(&self) -> MutexGuard<'static, ()> {
use std::sync::Mutex;
lazy_static! {
static ref ONE_TEST_AT_A_TIME: Mutex<()> = Mutex::new(());
}
ONE_TEST_AT_A_TIME.lock().unwrap_or_else(|e| e.into_inner())
}
}
impl Drop for Fixture {
fn drop(&mut self) {
if !thread::panicking() {
unsafe { ManuallyDrop::drop(&mut self.dir) }
}
}
}
pub fn bad_cargo_toml() -> Fixture {
let fixture = Fixture::new();
fixture.readme().hello_world_src_lib().file(
"Cargo.toml",
r#"
[package]
name = "bad-cargo-toml"
version = "0.1.0"
authors = ["The wasm-pack developers"]
[lib]
crate-type = ["foo"]
[dependencies]
# Note: no wasm-bindgen dependency!
"#,
);
fixture
}
pub fn js_hello_world() -> Fixture {
let fixture = Fixture::new();
fixture
.readme()
.cargo_toml("js-hello-world")
.hello_world_src_lib();
fixture
}
pub fn no_cdylib() -> Fixture {
let fixture = Fixture::new();
fixture.readme().hello_world_src_lib().file(
"Cargo.toml",
r#"
[package]
authors = ["The wasm-pack developers"]
description = "so awesome rust+wasm package"
license = "WTFPL"
name = "foo"
repository = "https://github.com/rustwasm/wasm-pack.git"
version = "0.1.0"
# [lib]
# crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "=0.2.21"
[dev-dependencies]
wasm-bindgen-test = "=0.2.21"
"#,
);
fixture
}
pub fn not_a_crate() -> Fixture {
let fixture = Fixture::new();
fixture.file("README.md", "This is not a Rust crate!");
fixture
}
pub fn serde_feature() -> Fixture {
let fixture = Fixture::new();
fixture.readme().hello_world_src_lib().file(
"Cargo.toml",
r#"
[package]
name = "serde-serialize"
version = "0.1.0"
authors = ["The wasm-pack developers"]
[lib]
crate-type = ["cdylib"]
[dependencies.wasm-bindgen]
version = "^0.2"
features = ["serde-serialize"]
"#,
);
fixture
}
pub fn wbg_test_diff_versions() -> Fixture {
let fixture = Fixture::new();
fixture
.readme()
.file(
"Cargo.toml",
r#"
[package]
name = "wbg-test-diff-versions"
version = "0.1.0"
authors = ["The wasm-pack developers"]
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
# We depend on wasm-bindgen 0.2.21
wasm-bindgen = "=0.2.21"
[dev-dependencies]
# And we depend on wasm-bindgen-test 0.2.19. This should still
# work, and we should end up with `wasm-bindgen` at 0.2.21 and
# wasm-bindgen-test at 0.2.19, and everything should still work.
wasm-bindgen-test = "0.2.19"
"#,
)
.file(
"src/lib.rs",
r#"
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn one() -> u32 { 1 }
"#,
)
.file(
"tests/node.rs",
r#"
extern crate wbg_test_diff_versions;
extern crate wasm_bindgen_test;
use wasm_bindgen_test::*;
#[wasm_bindgen_test]
fn pass() {
assert_eq!(wbg_test_diff_versions::one(), 1);
}
"#,
);
fixture
}
pub fn wbg_test_browser() -> Fixture {
let fixture = Fixture::new();
fixture
.readme()
.cargo_toml("wbg-test-browser")
.hello_world_src_lib()
.file(
"tests/browser.rs",
r#"
extern crate wasm_bindgen_test;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn pass() {
assert_eq!(1, 1);
}
"#,
);
fixture
}
pub fn wbg_test_fail() -> Fixture {
let fixture = Fixture::new();
fixture
.readme()
.cargo_toml("wbg-test-fail")
.hello_world_src_lib()
.file(
"tests/node.rs",
r#"
extern crate wasm_bindgen_test;
use wasm_bindgen_test::*;
#[wasm_bindgen_test]
fn pass() {
assert_eq!(1, 2);
}
"#,
);
fixture
}
pub fn wbg_test_node() -> Fixture {
let fixture = Fixture::new();
fixture
.readme()
.cargo_toml("wbg-test-node")
.hello_world_src_lib()
.file(
"tests/node.rs",
r#"
extern crate wasm_bindgen_test;
use wasm_bindgen_test::*;
#[wasm_bindgen_test]
fn pass() {
assert_eq!(1, 1);
}
"#,
);
fixture
}