aboutsummaryrefslogtreecommitdiffstats
path: root/tests/cli.rs
diff options
context:
space:
mode:
authorElvis Claros Castro <elvis@claros.ar>2026-09-26 18:47:40 -0300
committerElvis Claros Castro <elvis@claros.ar>2026-09-26 18:47:40 -0300
commitd9738b4be2add82ff955f061c79316b0dc91768f (patch)
treee0f31bb9f72dff315fc475f9e9f30322b69602ff /tests/cli.rs
downloadposta-main.tar.gz
posta-main.zip
posta: generic IMAP/SMTP mail CLI with JSON outputHEADmain
Diffstat (limited to 'tests/cli.rs')
-rw-r--r--tests/cli.rs144
1 files changed, 144 insertions, 0 deletions
diff --git a/tests/cli.rs b/tests/cli.rs
new file mode 100644
index 0000000..deca4ae
--- /dev/null
+++ b/tests/cli.rs
@@ -0,0 +1,144 @@
+//! End-to-end CLI tests that don't need a mail server.
+
+use assert_cmd::Command;
+use predicates::prelude::*;
+use std::io::Write;
+
+fn posta() -> Command {
+ let mut cmd = Command::cargo_bin("posta").unwrap();
+ // Isolate from the developer's real config and environment.
+ for (k, _) in std::env::vars() {
+ if k.starts_with("POSTA_") {
+ cmd.env_remove(k);
+ }
+ }
+ cmd
+}
+
+fn write_config(dir: &tempfile::TempDir, contents: &str) -> std::path::PathBuf {
+ let path = dir.path().join("config.toml");
+ let mut f = std::fs::File::create(&path).unwrap();
+ f.write_all(contents.as_bytes()).unwrap();
+ path
+}
+
+const SAMPLE: &str = r#"
+default_account = "personal"
+
+[accounts.personal]
+email = "alice@example.com"
+imap_url = "imap://alice@mail.example.com"
+smtp_url = "smtp://alice@mail.example.com"
+password = "x"
+
+[accounts.work]
+email = "alice@work.example"
+imap_url = "imaps://alice@imap.work.example"
+"#;
+
+#[test]
+fn help_mentions_the_basics() {
+ posta()
+ .arg("--help")
+ .assert()
+ .success()
+ .stdout(predicate::str::contains("IMAP/SMTP"))
+ .stdout(predicate::str::contains("send"))
+ .stdout(predicate::str::contains("list"));
+}
+
+#[test]
+fn version_prints_name_and_number() {
+ posta()
+ .arg("--version")
+ .assert()
+ .success()
+ .stdout(predicate::str::contains("posta"));
+}
+
+#[test]
+fn accounts_lists_names_without_secrets() {
+ let dir = tempfile::tempdir().unwrap();
+ let cfg = write_config(&dir, SAMPLE);
+ posta()
+ .arg("--config")
+ .arg(&cfg)
+ .arg("accounts")
+ .assert()
+ .success()
+ .stdout(predicate::str::contains("personal"))
+ .stdout(predicate::str::contains("work"))
+ .stdout(predicate::str::contains("\"x\"").not());
+}
+
+#[test]
+fn missing_config_file_is_a_clear_error() {
+ posta()
+ .env("POSTA_CONFIG", "/nonexistent/posta.toml")
+ .arg("status")
+ .assert()
+ .failure()
+ .stderr(predicate::str::contains("cannot read config file"));
+}
+
+#[test]
+fn unknown_account_error_lists_available_ones() {
+ let dir = tempfile::tempdir().unwrap();
+ let cfg = write_config(&dir, SAMPLE);
+ posta()
+ .arg("--config")
+ .arg(&cfg)
+ .args(["--account", "nope", "status"])
+ .assert()
+ .failure()
+ .stderr(predicate::str::contains("personal").and(predicate::str::contains("work")));
+}
+
+#[test]
+fn invalid_toml_reports_the_file() {
+ let dir = tempfile::tempdir().unwrap();
+ let cfg = write_config(&dir, "accounts = 42");
+ posta()
+ .arg("--config")
+ .arg(&cfg)
+ .arg("status")
+ .assert()
+ .failure()
+ .stderr(predicate::str::contains("invalid config file"));
+}
+
+#[test]
+fn env_only_mode_needs_no_config_file() {
+ // No config file at all: endpoints come from the environment. The URL is
+ // parsed before any connection is attempted, so a bad one fails fast.
+ posta()
+ .env("POSTA_CONFIG", "/nonexistent/posta.toml")
+ .env_remove("POSTA_CONFIG") // ensure truly unset
+ .env("HOME", "/nonexistent-home")
+ .env("POSTA_IMAP_URL", "ftp://wrong")
+ .arg("status")
+ .assert()
+ .failure()
+ .stderr(predicate::str::contains("imap://"));
+}
+
+#[test]
+fn send_rejects_invalid_recipient_before_connecting() {
+ let dir = tempfile::tempdir().unwrap();
+ let cfg = write_config(&dir, SAMPLE);
+ posta()
+ .arg("--config")
+ .arg(&cfg)
+ .args([
+ "send",
+ "--to",
+ "not-an-address",
+ "--subject",
+ "hi",
+ "--body",
+ "x",
+ ])
+ .assert()
+ .failure()
+ .stderr(predicate::str::contains("invalid recipient"));
+}