mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Add CLI test for Hello World
This commit is contained in:
parent
16a783328e
commit
6f75ce6680
2 changed files with 126 additions and 5 deletions
|
@ -21,12 +21,13 @@ use roc_mono::expr::{Expr, Procs};
|
||||||
use roc_mono::layout::Layout;
|
use roc_mono::layout::Layout;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use clap::{App, AppSettings, Arg, ArgMatches};
|
use clap::{App, Arg, ArgMatches};
|
||||||
use inkwell::targets::{
|
use inkwell::targets::{
|
||||||
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetTriple,
|
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetTriple,
|
||||||
};
|
};
|
||||||
use std::io;
|
use std::io::{self, ErrorKind};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process;
|
||||||
use target_lexicon::{Architecture, OperatingSystem, Triple, Vendor};
|
use target_lexicon::{Architecture, OperatingSystem, Triple, Vendor};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::runtime::Builder;
|
use tokio::runtime::Builder;
|
||||||
|
@ -41,7 +42,6 @@ pub static FLAG_ROC_FILE: &str = "ROC_FILE";
|
||||||
pub fn build_app<'a>() -> App<'a> {
|
pub fn build_app<'a>() -> App<'a> {
|
||||||
App::new("roc")
|
App::new("roc")
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.setting(AppSettings::AllowNegativeNumbers)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(FLAG_ROC_FILE)
|
Arg::with_name(FLAG_ROC_FILE)
|
||||||
.help("The .roc file to compile and run")
|
.help("The .roc file to compile and run")
|
||||||
|
@ -58,7 +58,6 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
/// Run the CLI. This is separate from main() so that tests can call it directly.
|
/// Run the CLI. This is separate from main() so that tests can call it directly.
|
||||||
pub fn run(matches: ArgMatches) -> io::Result<()> {
|
pub fn run(matches: ArgMatches) -> io::Result<()> {
|
||||||
let filename = matches.value_of(FLAG_ROC_FILE).unwrap();
|
let filename = matches.value_of(FLAG_ROC_FILE).unwrap();
|
||||||
|
|
||||||
let opt_level = if matches.is_present(FLAG_OPTIMIZE) {
|
let opt_level = if matches.is_present(FLAG_OPTIMIZE) {
|
||||||
OptLevel::Optimize
|
OptLevel::Optimize
|
||||||
} else {
|
} else {
|
||||||
|
@ -76,7 +75,24 @@ pub fn run(matches: ArgMatches) -> io::Result<()> {
|
||||||
.expect("Error spawning initial compiler thread."); // TODO make this error nicer.
|
.expect("Error spawning initial compiler thread."); // TODO make this error nicer.
|
||||||
|
|
||||||
// Spawn the root task
|
// Spawn the root task
|
||||||
let loaded = rt.block_on(load_file(src_dir, path.canonicalize().unwrap(), opt_level));
|
let path = path.canonicalize().unwrap_or_else(|err| {
|
||||||
|
use ErrorKind::*;
|
||||||
|
|
||||||
|
match err.kind() {
|
||||||
|
NotFound => {
|
||||||
|
match path.to_str() {
|
||||||
|
Some(path_str) => println!("File not found: {}", path_str),
|
||||||
|
None => println!("Malformed file path : {:?}", path),
|
||||||
|
}
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
todo!("TODO Gracefully handle opening {:?} - {:?}", path, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let loaded = rt.block_on(load_file(src_dir, path, opt_level));
|
||||||
|
|
||||||
loaded.expect("TODO gracefully handle LoadingProblem");
|
loaded.expect("TODO gracefully handle LoadingProblem");
|
||||||
|
|
||||||
|
|
105
cli/tests/cli_run.rs
Normal file
105
cli/tests/cli_run.rs
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate pretty_assertions;
|
||||||
|
|
||||||
|
extern crate bumpalo;
|
||||||
|
extern crate inlinable_string;
|
||||||
|
extern crate roc_collections;
|
||||||
|
extern crate roc_load;
|
||||||
|
extern crate roc_module;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod cli_run {
|
||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::{Command, ExitStatus};
|
||||||
|
|
||||||
|
// HELPERS
|
||||||
|
|
||||||
|
pub struct Out {
|
||||||
|
pub stdout: String,
|
||||||
|
pub stderr: String,
|
||||||
|
pub status: ExitStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_to_roc_binary() -> PathBuf {
|
||||||
|
// Adapted from https://github.com/volta-cli/volta/blob/cefdf7436a15af3ce3a38b8fe53bb0cfdb37d3dd/tests/acceptance/support/sandbox.rs#L680 - BSD-2-Clause licensed
|
||||||
|
let mut path = env::var_os("CARGO_BIN_PATH")
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.or_else(|| {
|
||||||
|
env::current_exe().ok().map(|mut path| {
|
||||||
|
path.pop();
|
||||||
|
if path.ends_with("deps") { path.pop();
|
||||||
|
}
|
||||||
|
path
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| panic!("CARGO_BIN_PATH wasn't set, and couldn't be inferred from context. Can't run CLI tests."));
|
||||||
|
|
||||||
|
path.push("roc");
|
||||||
|
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_roc(args: &[&str]) -> Out {
|
||||||
|
let mut cmd = Command::new(path_to_roc_binary());
|
||||||
|
|
||||||
|
for arg in args {
|
||||||
|
cmd.arg(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = cmd
|
||||||
|
.output()
|
||||||
|
.expect("failed to execute compiled `roc` binary in CLI test");
|
||||||
|
|
||||||
|
Out {
|
||||||
|
stdout: String::from_utf8(output.stdout).unwrap(),
|
||||||
|
stderr: String::from_utf8(output.stderr).unwrap(),
|
||||||
|
status: output.status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn example_dir(dir_name: &str) -> PathBuf {
|
||||||
|
let mut path = env::current_exe().ok().unwrap();
|
||||||
|
|
||||||
|
// Get rid of the filename in target/debug/deps/cli_run-99c65e4e9a1fbd06
|
||||||
|
path.pop();
|
||||||
|
|
||||||
|
// If we're in deps/ get rid of deps/ in target/debug/deps/
|
||||||
|
if path.ends_with("deps") {
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get rid of target/debug/ so we're back at the project root
|
||||||
|
path.pop();
|
||||||
|
path.pop();
|
||||||
|
|
||||||
|
// Descend into examples/{dir_name}
|
||||||
|
path.push("examples");
|
||||||
|
path.push(dir_name);
|
||||||
|
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn example_file(dir_name: &str, file_name: &str) -> PathBuf {
|
||||||
|
let mut path = example_dir(dir_name);
|
||||||
|
|
||||||
|
path.push(file_name);
|
||||||
|
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTS
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run_hello_world() {
|
||||||
|
let out = run_roc(&[example_file("hello-world", "Hello.roc").to_str().unwrap()]);
|
||||||
|
|
||||||
|
assert_eq!(&out.stderr, "");
|
||||||
|
|
||||||
|
// TODO make separate `roc build` and `roc run` commands, and here do
|
||||||
|
// `roc build` followed by manually executing the compiled `app` binary
|
||||||
|
// and doing an `assert_eq!` on the entire stdout of that compiled `app` binary
|
||||||
|
assert!(&out.stdout.ends_with("Hello, World!\n"));
|
||||||
|
assert!(out.status.success());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue