use predicates::prelude::*;
#[allow(deprecated)] fn run_binary() -> assert_cmd::Command {
assert_cmd::Command::cargo_bin("run").expect("binary built")
}
fn run_repl() -> assert_cmd::Command {
let mut cmd = run_binary();
cmd.arg("-i");
cmd
}
fn norm(s: &str) -> String {
s.replace("\r\n", "\n")
}
fn norm_contains(needle: &str) -> impl predicates::Predicate<str> {
let needle = needle.to_string();
predicates::function::function(move |s: &str| norm(s).contains(needle.as_str()))
}
#[test]
fn repl_shell_capture_echo() {
run_repl()
.write_stdin(":!! echo hello-from-capture\n:exit\n")
.assert()
.success()
.stdout(norm_contains("hello-from-capture"));
}
#[test]
fn repl_shell_inherit_echo() {
run_repl()
.write_stdin(":! echo hello-from-inherit\n:exit\n")
.assert()
.success()
.stdout(norm_contains("hello-from-inherit"));
}
#[test]
fn repl_help_lists_shell_commands() {
run_repl()
.write_stdin(":help\n:exit\n")
.assert()
.success()
.stdout(
norm_contains(":!")
.and(norm_contains(":!!"))
.and(norm_contains("shell")),
);
}
#[test]
fn repl_exit_quits() {
run_repl().write_stdin(":exit\n").assert().success();
}
#[test]
fn repl_quit_quits() {
run_repl().write_stdin(":quit\n").assert().success();
}
#[test]
fn repl_cd_and_dhist() {
run_repl()
.write_stdin(":cd .\n:dhist 1\n:exit\n")
.assert()
.success();
}
#[test]
fn repl_env_lists_or_gets() {
run_repl()
.write_stdin(":env\n:exit\n")
.assert()
.success()
.stdout(predicate::str::contains("="));
}
#[test]
fn repl_bookmark_list_empty_or_contains() {
let out = run_repl()
.write_stdin(":bookmark -l\n:exit\n")
.assert()
.success()
.get_output()
.stdout
.clone();
let out = String::from_utf8_lossy(&out);
assert!(
out.contains("(no bookmarks)") || out.contains("\t"),
"expected (no bookmarks) or a list; got: {}",
out
);
}
#[test]
fn repl_history_no_args_or_range() {
run_repl()
.write_stdin(":history\n:history 1\n:exit\n")
.assert()
.success();
}
#[test]
fn repl_history_grep() {
run_repl()
.write_stdin("1+1\n:history -g 1\n:exit\n")
.assert()
.success();
}
#[test]
fn repl_logstart_logstop_logstate() {
use std::io::Read;
let dir = std::env::temp_dir();
let logfile = dir.join("run_log_test.txt");
let _ = std::fs::remove_file(&logfile);
run_repl()
.write_stdin(format!(
":logstart {}\n:logstate\n1+1\n:logstop\n:logstate\n:exit\n",
logfile.display()
))
.assert()
.success();
let mut buf = String::new();
if std::fs::File::open(&logfile)
.and_then(|mut f| f.read_to_string(&mut buf))
.is_ok()
{
assert!(
buf.contains(":logstart"),
"log should contain :logstart line"
);
assert!(buf.contains("1+1"), "log should contain code");
}
let _ = std::fs::remove_file(&logfile);
}
#[test]
fn repl_edit_then_execute() {
let dir = std::env::temp_dir();
let path = dir.join("run_edit_test.py");
std::fs::write(&path, "print(42)\n").expect("write test file");
let result = run_repl()
.env("EDITOR", "cat")
.write_stdin(format!(":edit {}\n:exit\n", path.display()))
.assert()
.success();
let stdout = result.get_output().stdout.clone();
let out = String::from_utf8_lossy(&stdout);
assert!(out.contains("42"), "expected 42 in output, got: {}", out);
let _ = std::fs::remove_file(&path);
}
#[test]
fn repl_load_http_url() {
let url = "https://raw.githubusercontent.com/Esubaalew/run/master/examples/python/counter.py";
run_repl()
.write_stdin(format!(":load {url}\n:exit\n"))
.assert()
.success();
}
#[test]
fn repl_history_f_file() {
use std::io::Read;
let dir = std::env::temp_dir();
let file = dir.join("run_hist_f_test");
let _ = std::fs::remove_file(&file);
let input = format!(":history -f {}\n:exit\n", file.display());
run_repl().write_stdin(input).assert().success();
let mut buf = String::new();
if std::fs::File::open(&file)
.and_then(|mut f| f.read_to_string(&mut buf))
.is_ok()
{
assert!(buf.is_empty() || buf.contains('\n'));
}
let _ = std::fs::remove_file(&file);
}
#[test]
fn repl_time_prints_elapsed() {
run_repl()
.write_stdin(":lang python\n:time 1+1\n:exit\n")
.assert()
.success()
.stdout(norm_contains("elapsed").and(norm_contains("2")));
}
#[test]
fn repl_macro_save_and_run() {
run_repl()
.write_stdin(":lang python\n1+1\n2+2\n:macro m -2\n:run m\n:exit\n")
.assert()
.success()
.stdout(
norm_contains("macro")
.and(norm_contains("saved"))
.and(norm_contains("2"))
.and(norm_contains("4")),
);
}
#[test]
fn repl_who_and_whos() {
run_repl()
.write_stdin(":lang python\nx = 1\n:who\n:whos x\n:whos z\n:exit\n")
.assert()
.success()
.stdout(norm_contains("x"));
}
#[test]
fn repl_commands_machine_friendly() {
run_repl()
.write_stdin(":commands\n:exit\n")
.assert()
.success()
.stdout(
norm_contains(":help")
.and(norm_contains("Show this help"))
.and(norm_contains(":exit")),
);
}
#[test]
fn repl_help_single_cmd() {
run_repl()
.write_stdin(":help load\n:exit\n")
.assert()
.success()
.stdout(norm_contains("load").and(norm_contains("Load")));
}
#[test]
fn repl_quickref() {
run_repl()
.write_stdin(":quickref\n:exit\n")
.assert()
.success()
.stdout(norm_contains("Quick reference").and(norm_contains(":exit")));
}
#[test]
fn repl_xmode() {
run_repl()
.write_stdin(":xmode\n:xmode plain\n:xmode\n:exit\n")
.assert()
.success()
.stdout(
norm_contains("exception display")
.and(norm_contains("verbose"))
.and(norm_contains("plain")),
);
}
#[test]
fn repl_config() {
run_repl()
.write_stdin(":config\n:config detect\n:config xmode\n:exit\n")
.assert()
.success()
.stdout(norm_contains("detect").and(norm_contains("xmode")));
}
#[test]
fn repl_paste_mode() {
run_repl()
.write_stdin(":lang python\n:paste\n>>> 1+1\n>>> 2+2\n:end\n:exit\n")
.assert()
.success()
.stdout(norm_contains("paste mode").and(norm_contains("paste done")));
}
#[test]
fn repl_precision() {
run_repl()
.write_stdin(":precision\n:precision 4\n:precision\n:exit\n")
.assert()
.success()
.stdout(norm_contains("precision").and(norm_contains("4")));
}
#[test]
fn repl_last() {
run_repl()
.write_stdin(":last\n:lang python\n1+1\n:last\n:exit\n")
.assert()
.success()
.stdout(norm_contains("no last output").and(norm_contains("2")));
}
#[test]
fn repl_numbered_prompts() {
run_repl()
.write_stdin(":config numbered_prompts on\n:config\n:exit\n")
.assert()
.success()
.stdout(norm_contains("numbered_prompts").and(norm_contains("on")));
}
#[test]
fn repl_introspect() {
run_repl()
.write_stdin(":?\n:lang python\n:? print\n:exit\n")
.assert()
.success()
.stdout(
norm_contains(":? <name>")
.and(norm_contains("print"))
.and(norm_contains("Help")),
);
}
#[test]
fn repl_debug() {
run_repl()
.write_stdin(":debug\n:lang javascript\n:debug 1+1\n:exit\n")
.assert()
.success()
.stdout(
norm_contains(":debug [CODE]")
.and(norm_contains("Debug not available"))
.and(norm_contains("javascript")),
);
}