mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
169 lines
5.8 KiB
Rust
169 lines
5.8 KiB
Rust
#[macro_use]
|
|
extern crate pretty_assertions;
|
|
|
|
#[macro_use]
|
|
extern crate indoc;
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
extern crate roc_collections;
|
|
|
|
mod helpers;
|
|
|
|
#[cfg(test)]
|
|
mod bindgen_cli_run {
|
|
use crate::helpers::fixtures_dir;
|
|
use cli_utils::helpers::{run_bindgen, run_roc, Out};
|
|
use std::fs;
|
|
use std::path::Path;
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
struct Example<'a> {
|
|
filename: &'a str,
|
|
executable_filename: &'a str,
|
|
stdin: &'a [&'a str],
|
|
input_file: Option<&'a str>,
|
|
expected_ending: &'a str,
|
|
use_valgrind: bool,
|
|
}
|
|
|
|
/// This macro does two things.
|
|
///
|
|
/// First, it generates and runs a separate test for each of the given
|
|
/// expected stdout endings. Each of these should test a particular .roc file
|
|
/// in the fixtures/ directory.
|
|
///
|
|
/// Second, it generates an extra test which (non-recursively) traverses the
|
|
/// fixtures/ directory and verifies that each of the .roc files in there
|
|
/// has had a corresponding test generated in the previous step. This test
|
|
/// will fail if we ever add a new .roc file to fixtures/ and forget to
|
|
/// add a test for it here!
|
|
macro_rules! fixtures {
|
|
($($test_name:ident:$fixture_dir:expr => $ends_with:expr,)+) => {
|
|
$(
|
|
#[test]
|
|
#[allow(non_snake_case)]
|
|
fn $test_name() {
|
|
let dir = fixtures_dir($fixture_dir);
|
|
|
|
generate_bindings_for(&dir.join("platform"), std::iter::empty());
|
|
let out = run_app(&dir.join("app.roc"), std::iter::empty());
|
|
|
|
assert!(out.status.success());
|
|
assert_eq!(out.stderr, "");
|
|
assert!(
|
|
out.stdout.ends_with($ends_with),
|
|
"Unexpected stdout ending - expected {:?} but stdout was: {:?}",
|
|
$ends_with,
|
|
out.stdout
|
|
);
|
|
}
|
|
)*
|
|
|
|
#[test]
|
|
#[cfg(not(debug_assertions))]
|
|
fn all_examples_have_tests() {
|
|
use roc_collections::all::VecSet;
|
|
|
|
let mut all_examples: VecSet<&str, &str> = VecSet::default();
|
|
|
|
$(
|
|
all_examples.insert($fixture_dir);
|
|
)*
|
|
|
|
check_for_tests(&mut all_examples);
|
|
}
|
|
}
|
|
}
|
|
|
|
fixtures! {
|
|
basic_record:"basic-record" => "Record was: MyRcd { b: 42, a: 1995 }\n",
|
|
}
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
fn check_for_tests(all_examples: &mut roc_collections::all::VecSet<&str>) {
|
|
use roc_collections::all::VecSet;
|
|
let fixtures_dir = fixtures_dir(".").with_file_name("");
|
|
let entries = std::fs::read_dir(fixtures_dir).unwrap_or_else(|err| {
|
|
panic!(
|
|
"Error trying to read {} as an examples directory: {}",
|
|
examples_dir, err
|
|
);
|
|
});
|
|
|
|
for entry in entries {
|
|
let entry = entry.unwrap();
|
|
|
|
if entry.file_type().unwrap().is_dir() {
|
|
let fixture_dir_name = entry.file_name().into_string().unwrap();
|
|
|
|
all_examples.remove(fixture_dir_name).unwrap_or_else(|| {
|
|
panic!("The bindgen fixture directory {} does not have any corresponding tests in cli_run. Please add one, so if it ever stops working, we'll know about it right away!", entry.path());
|
|
});
|
|
}
|
|
}
|
|
|
|
assert_eq!(all_examples, &mut VecSet::default());
|
|
}
|
|
|
|
fn generate_bindings_for<'a, I: IntoIterator<Item = &'a str>>(
|
|
platform_dir: &'a Path,
|
|
args: I,
|
|
) -> Out {
|
|
let package_config = platform_dir.join("Package-Config.roc");
|
|
let bindings_file = platform_dir.join("src").join("bindings.rs");
|
|
|
|
// Delete the bindings file to make sure we're actually regenerating it!
|
|
if bindings_file.exists() {
|
|
fs::remove_file(&bindings_file)
|
|
.expect("Unable to remove bindings.rs in order to regenerate it in the test");
|
|
}
|
|
|
|
// Generate a fresh bindings.rs for this platform
|
|
let bindgen_out = run_bindgen(
|
|
// converting these all to String avoids lifetime issues
|
|
args.into_iter().map(|arg| arg.to_string()).chain([
|
|
package_config.to_str().unwrap().to_string(),
|
|
bindings_file.to_str().unwrap().to_string(),
|
|
]),
|
|
);
|
|
|
|
// If there is any stderr, it should be reporting the runtime and that's it!
|
|
if !(bindgen_out.stderr.is_empty()
|
|
|| bindgen_out.stderr.starts_with("runtime: ") && bindgen_out.stderr.ends_with("ms\n"))
|
|
{
|
|
panic!(
|
|
"`roc-bindgen` command had unexpected stderr: {}",
|
|
bindgen_out.stderr
|
|
);
|
|
}
|
|
|
|
assert!(bindgen_out.status.success(), "bad status {:?}", bindgen_out);
|
|
|
|
bindgen_out
|
|
}
|
|
|
|
fn run_app<'a, I: IntoIterator<Item = &'a str>>(app_file: &'a Path, args: I) -> Out {
|
|
// Generate bindings.rs for this platform
|
|
let compile_out = run_roc(
|
|
// converting these all to String avoids lifetime issues
|
|
args.into_iter()
|
|
.map(|arg| arg.to_string())
|
|
.chain([app_file.to_str().unwrap().to_string()]),
|
|
&[],
|
|
);
|
|
|
|
// If there is any stderr, it should be reporting the runtime and that's it!
|
|
if !(compile_out.stderr.is_empty()
|
|
|| compile_out.stderr.starts_with("runtime: ") && compile_out.stderr.ends_with("ms\n"))
|
|
{
|
|
panic!(
|
|
"`roc` command had unexpected stderr: {}",
|
|
compile_out.stderr
|
|
);
|
|
}
|
|
|
|
assert!(compile_out.status.success(), "bad status {:?}", compile_out);
|
|
|
|
compile_out
|
|
}
|
|
}
|