From 2ab48ffce9de57d6e9199b3ea27c3a647dbfdf20 Mon Sep 17 00:00:00 2001 From: rami3l Date: Wed, 28 Jan 2026 22:48:57 +0100 Subject: [PATCH 1/2] refactor(test)!: pass status code directly to `SanitizedOutput` --- src/test/clitools.rs | 29 +++++++++++++++++++---------- tests/suite/cli_inst_interactive.rs | 2 +- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/test/clitools.rs b/src/test/clitools.rs index 17bcf923b8..80fcd3b4cf 100644 --- a/src/test/clitools.rs +++ b/src/test/clitools.rs @@ -183,13 +183,18 @@ impl Assert { /// Asserts that the command exited with an ok status. pub fn is_ok(&self) -> &Self { - assert!(self.output.ok); - self + self.has_code(0) } /// Asserts that the command exited with an error. pub fn is_err(&self) -> &Self { - assert!(!self.output.ok); + assert_ne!(self.output.status, Some(0)); + self + } + + /// Asserts that the command exited with the specific code. + pub fn has_code(&self, code: i32) -> &Self { + assert_eq!(self.output.status, Some(code)); self } @@ -350,7 +355,7 @@ impl Config { pub async fn expect_ok_contains(&self, args: &[&str], stdout: &str, stderr: &str) { let out = self.run(args[0], &args[1..], &[]).await; - if !out.ok || !out.stdout.contains(stdout) || !out.stderr.contains(stderr) { + if out.status != Some(0) || !out.stdout.contains(stdout) || !out.stderr.contains(stderr) { print_command(args, &out); println!("expected.ok: true"); print_indented("expected.stdout.contains", stdout); @@ -362,7 +367,11 @@ impl Config { pub async fn expect_ok_eq(&self, args1: &[&str], args2: &[&str]) { let out1 = self.run(args1[0], &args1[1..], &[]).await; let out2 = self.run(args2[0], &args2[1..], &[]).await; - if !out1.ok || !out2.ok || out1.stdout != out2.stdout || out1.stderr != out2.stderr { + if out1.status != Some(0) + || out2.status != Some(0) + || out1.stdout != out2.stdout + || out1.stderr != out2.stderr + { print_command(args1, &out1); println!("expected.ok: true"); print_command(args2, &out2); @@ -373,7 +382,7 @@ impl Config { pub async fn expect_component_executable(&self, cmd: &str) { let out1 = self.run(cmd, ["--version"], &[]).await; - if !out1.ok { + if out1.status != Some(0) { print_command(&[cmd, "--version"], &out1); println!("expected.ok: true"); panic!() @@ -382,7 +391,7 @@ impl Config { pub async fn expect_component_not_executable(&self, cmd: &str) { let out1 = self.run(cmd, ["--version"], &[]).await; - if out1.ok { + if out1.status == Some(0) { print_command(&[cmd, "--version"], &out1); println!("expected.ok: false"); panic!() @@ -1092,7 +1101,7 @@ pub fn print_command(args: &[&str], out: &SanitizedOutput) { } } println!(); - println!("out.ok: {}", out.ok); + println!("out.status: {:?}", out.status); print_indented("out.stdout", &out.stdout); print_indented("out.stderr", &out.stderr); } @@ -1120,7 +1129,7 @@ pub struct Output { #[derive(Debug, Clone)] pub struct SanitizedOutput { - pub ok: bool, + pub status: Option, pub stdout: String, pub stderr: String, } @@ -1130,7 +1139,7 @@ impl TryFrom for SanitizedOutput { fn try_from(out: Output) -> Result { Ok(Self { - ok: matches!(out.status, Some(0)), + status: out.status, stdout: String::from_utf8(out.stdout)?, stderr: String::from_utf8(out.stderr)?, }) diff --git a/tests/suite/cli_inst_interactive.rs b/tests/suite/cli_inst_interactive.rs index 6b1e31bfd2..044cccaddd 100644 --- a/tests/suite/cli_inst_interactive.rs +++ b/tests/suite/cli_inst_interactive.rs @@ -35,7 +35,7 @@ fn run_input_with_env(config: &Config, args: &[&str], input: &str, env: &[(&str, let out = child.wait_with_output().unwrap(); Assert::new(SanitizedOutput { - ok: out.status.success(), + status: out.status.code(), stdout: String::from_utf8(out.stdout).unwrap(), stderr: String::from_utf8(out.stderr).unwrap(), }) From 9becf3bd66377ed1faa0d19cc947b828eb424e81 Mon Sep 17 00:00:00 2001 From: rami3l Date: Wed, 28 Jan 2026 22:13:51 +0100 Subject: [PATCH 2/2] fix(cli/rustup-mode): improve exit code of `rustup check` This change follows the convention of DNF where `0` is returned when no updates and `100` when updates are available. --- src/cli/rustup_mode.rs | 3 +-- tests/suite/cli_exact.rs | 14 +++++++------- tests/suite/cli_inst_interactive.rs | 4 ++-- tests/suite/cli_rustup_ui.rs | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 077381f266..b81d26f23c 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -927,8 +927,7 @@ async fn check_updates(cfg: &Cfg<'_>, opts: CheckOpts) -> Result { update_available = true; } - let exit_status = if update_available { 0 } else { 1 }; - Ok(ExitCode(exit_status)) + Ok(ExitCode(if update_available { 100 } else { 0 })) } async fn update( diff --git a/tests/suite/cli_exact.rs b/tests/suite/cli_exact.rs index 06165a5deb..3a4031f7c5 100644 --- a/tests/suite/cli_exact.rs +++ b/tests/suite/cli_exact.rs @@ -180,7 +180,7 @@ async fn check_updates_none() { cx.config .expect(["rustup", "check"]) .await - .is_err() + .is_ok() .with_stdout(snapbox::str![[r#" stable-[HOST_TRIPLE] - up to date: 1.1.0 (hash-stable-1.1.0) beta-[HOST_TRIPLE] - up to date: 1.2.0 (hash-beta-1.2.0) @@ -205,7 +205,7 @@ async fn check_updates_some() { cx.config .expect(["rustup", "check"]) .await - .is_ok() + .has_code(100) .with_stdout(snapbox::str![[r#" stable-[HOST_TRIPLE] - update available: 1.0.0 (hash-stable-1.0.0) -> 1.1.0 (hash-stable-1.1.0) beta-[HOST_TRIPLE] - update available: 1.1.0 (hash-beta-1.1.0) -> 1.2.0 (hash-beta-1.2.0) @@ -230,7 +230,7 @@ async fn check_updates_self() { .expect(["rustup", "check"]) .await .extend_redactions([("[TEST_VERSION]", test_version)]) - .is_ok() + .has_code(100) .with_stdout(snapbox::str![[r#" rustup - Update available : [CURRENT_VERSION] -> [TEST_VERSION] @@ -252,7 +252,7 @@ async fn check_updates_self_no_change() { cx.config .expect(["rustup", "check"]) .await - .is_err() + .is_ok() .with_stdout(snapbox::str![[r#" rustup - Up to date : [CURRENT_VERSION] @@ -272,7 +272,7 @@ async fn check_updates_with_update() { cx.config .expect(["rustup", "check"]) .await - .is_err() + .is_ok() .with_stdout(snapbox::str![[r#" stable-[HOST_TRIPLE] - up to date: 1.0.0 (hash-stable-1.0.0) beta-[HOST_TRIPLE] - up to date: 1.1.0 (hash-beta-1.1.0) @@ -285,7 +285,7 @@ nightly-[HOST_TRIPLE] - up to date: 1.2.0 (hash-nightly-1) cx.config .expect(["rustup", "check"]) .await - .is_ok() + .has_code(100) .with_stdout(snapbox::str![[r#" stable-[HOST_TRIPLE] - update available: 1.0.0 (hash-stable-1.0.0) -> 1.1.0 (hash-stable-1.1.0) beta-[HOST_TRIPLE] - update available: 1.1.0 (hash-beta-1.1.0) -> 1.2.0 (hash-beta-1.2.0) @@ -296,7 +296,7 @@ nightly-[HOST_TRIPLE] - update available: 1.2.0 (hash-nightly-1) -> 1.3.0 (hash- cx.config .expect(["rustup", "check"]) .await - .is_ok() + .has_code(100) .with_stdout(snapbox::str![[r#" stable-[HOST_TRIPLE] - update available: 1.0.0 (hash-stable-1.0.0) -> 1.1.0 (hash-stable-1.1.0) beta-[HOST_TRIPLE] - up to date: 1.2.0 (hash-beta-1.2.0) diff --git a/tests/suite/cli_inst_interactive.rs b/tests/suite/cli_inst_interactive.rs index 044cccaddd..10075fe49b 100644 --- a/tests/suite/cli_inst_interactive.rs +++ b/tests/suite/cli_inst_interactive.rs @@ -276,7 +276,7 @@ async fn with_no_toolchain_doesnt_hang() { ) .is_ok(); - cx.config.expect(["rustup", "check"]).await.is_err(); + cx.config.expect(["rustup", "check"]).await.is_ok(); } #[tokio::test] @@ -296,7 +296,7 @@ async fn with_no_toolchain_doesnt_hang_with_concurrent_downloads_override() { cx.config .expect_with_env(["rustup", "check"], [("RUSTUP_CONCURRENT_DOWNLOADS", "2")]) .await - .is_err(); + .is_ok(); } #[tokio::test] diff --git a/tests/suite/cli_rustup_ui.rs b/tests/suite/cli_rustup_ui.rs index b94e46ab62..289b8c8713 100644 --- a/tests/suite/cli_rustup_ui.rs +++ b/tests/suite/cli_rustup_ui.rs @@ -83,7 +83,7 @@ async fn rustup_check_updates_none() { None, )) .with_stderr("") - .is_err(); + .is_ok(); } #[tokio::test] @@ -108,7 +108,7 @@ async fn rustup_check_updates_some() { None, )) .with_stderr("") - .is_ok(); + .has_code(100); } #[test]