use super::*;
#[test]
fn test_eval_expression_variants() {
let output = sanitized_arf_command()
.args([
"-e",
"1 + 1\nx <- 5\nx * 2\nf <- function(x) { x + 1 }\nf(10)",
])
.output()
.expect("Failed to run arf -e");
assert!(
output.status.success(),
"arf -e should succeed. stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
for (case, expected) in [
("single expression", "[1] 2"),
("multiple expressions share state", "[1] 10"),
("function definition and call", "[1] 11"),
] {
assert!(
stdout.contains(expected),
"{case}: should output {expected:?}: {stdout}"
);
}
}
#[test]
#[cfg(unix)]
fn test_eval_with_mismatched_r_home() {
let output = sanitized_arf_command()
.env("R_HOME", r"/tmp/arf-test-nonexistent-r-4.0.5")
.args(["-e", r#"1 + 1"#])
.output()
.expect("Failed to run arf -e with mismatched R_HOME");
assert!(
output.status.success(),
"arf -e should succeed with a mismatched R_HOME: stdout={} stderr={}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("[1] 2"),
"R should evaluate an expression with a mismatched R_HOME: {}",
stdout
);
}
#[test]
fn test_eval_r_event_processing_api() {
let output = sanitized_arf_command()
.args([
"-e",
r#"
# Create a simple plot (opens graphics device)
# On non-interactive systems, this may use a null device
invisible(plot(1:3, main = "Event Processing Test"))
# Call dev.off() to close any graphics device
invisible(dev.off())
# Verify R is still responsive
42
"#,
])
.output()
.expect("Failed to run arf -e with plot");
assert!(
output.status.success(),
"arf should succeed with plot command. stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("[1] 42"),
"R should be responsive after plot: {}",
stdout
);
}
#[test]
fn test_eval_error_handling() {
let output = sanitized_arf_command()
.args(["-e", "stop('Test error')"])
.output()
.expect("Failed to run arf -e");
assert_eq!(
output.status.code(),
Some(1),
"arf -e should exit with status 1 on R errors"
);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("Test error") || stderr.contains("Error"),
"Should show error message: {}",
stderr
);
}
#[test]
fn test_eval_pipe_error() {
let output = sanitized_arf_command()
.args(["-e", "1 |> 1"])
.output()
.expect("Failed to run arf -e");
assert_eq!(
output.status.code(),
Some(1),
"arf -e should exit with status 1 on R errors"
);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("Error") || stderr.contains("error"),
"Should show pipe error: {}",
stderr
);
}
#[test]
fn test_eval_reprex_custom_comment() {
let mut config_file = NamedTempFile::new().expect("Failed to create temp config file");
writeln!(
config_file,
r###"[reprex]
comment = "## "
"###
)
.expect("Failed to write config file");
let output = sanitized_arf_command()
.args([
"--config",
config_file.path().to_str().unwrap(),
"--reprex",
"on",
"-e",
"1 + 1",
])
.output()
.expect("Failed to run arf --reprex with config file");
assert!(
output.status.success(),
"arf with custom reprex comment should succeed"
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("1 + 1"),
"Output should echo source code: {}",
stdout
);
assert!(
stdout.contains("## [1] 2"),
"Output should be prefixed with custom comment: {}",
stdout
);
}
#[test]
fn test_eval_reprex_mode() {
let output = sanitized_arf_command()
.args([
"--reprex",
"on",
"-e",
"1 + 1\ncat(\"hello\\n\")\ncat(\"tail\")",
])
.output()
.expect("Failed to run arf --reprex -e");
assert!(
output.status.success(),
"arf --reprex -e should succeed. stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
for (case, expected) in [
("source is echoed", "1 + 1"),
("cat() source is echoed", r#"cat("tail")"#),
("value is prefixed", "#> [1] 2"),
("cat() output with newline is prefixed", "#> hello"),
("cat() output without newline is captured", "#> tail"),
] {
assert!(
stdout.contains(expected),
"{case}: output should contain {expected:?}: {stdout}"
);
}
}
#[test]
fn test_eval_publishing_without_an_ipc_server_returns_false() {
let output = sanitized_arf_command()
.args([
"-e",
r#"
cat("version:", .Call("arf_api_version", PACKAGE = "(embedding)"), "\n")
cat("published:", .Call("arf_publish_event", "demo.topic", list(a = 1), PACKAGE = "(embedding)"), "\n")
"#,
])
.output()
.expect("Failed to run arf -e");
assert!(
output.status.success(),
"arf -e should succeed. stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("version: 1"), "{stdout}");
assert!(stdout.contains("published: FALSE"), "{stdout}");
}
#[test]
fn test_eval_publishing_a_reserved_topic_is_an_r_error() {
let output = sanitized_arf_command()
.args([
"-e",
r#".Call("arf_publish_event", "arf.reserved", NULL, PACKAGE = "(embedding)")"#,
])
.output()
.expect("Failed to run arf -e");
assert_eq!(output.status.code(), Some(1));
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("reserved"), "{stderr}");
}