Skip to content

Commit 61cadf9

Browse files
committed
Refactor test registry state to be more type safe
1 parent 14eeb70 commit 61cadf9

File tree

3 files changed

+55
-39
lines changed

3 files changed

+55
-39
lines changed

src/cli/self_update/test.rs

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ use std::{io, sync::Mutex};
66
#[cfg(windows)]
77
use winreg::{
88
enums::{HKEY_CURRENT_USER, KEY_READ, KEY_WRITE},
9+
types::{FromRegValue, ToRegValue},
910
RegKey, RegValue,
1011
};
1112

1213
#[cfg(windows)]
1314
pub fn with_saved_path(f: &mut dyn FnMut()) {
14-
with_saved_reg_value(&RegKey::predef(HKEY_CURRENT_USER), "Environment", "PATH", f)
15+
with_saved_reg_value(&USER_PATH, f)
1516
}
1617

1718
#[cfg(unix)]
@@ -21,41 +22,62 @@ pub fn with_saved_path(f: &mut dyn FnMut()) {
2122

2223
#[cfg(windows)]
2324
pub fn get_path() -> io::Result<Option<RegValue>> {
24-
get_reg_value(&RegKey::predef(HKEY_CURRENT_USER), "Environment", "PATH")
25+
USER_PATH.get()
2526
}
2627

2728
#[cfg(windows)]
28-
pub fn with_saved_reg_value(root: &RegKey, subkey: &str, name: &str, f: &mut dyn FnMut()) {
29+
pub fn with_saved_reg_value(id: &RegistryValueId, f: &mut dyn FnMut()) {
2930
// Lock protects concurrent mutation of registry
3031
static LOCK: Mutex<()> = Mutex::new(());
3132
let _g = LOCK.lock();
3233

3334
// Save and restore the global state here to keep from trashing things.
34-
let saved_state = get_reg_value(root, subkey, name)
35+
let saved_state = id
36+
.get()
3537
.expect("Error getting global state: Better abort to avoid trashing it");
36-
let _g = scopeguard::guard(saved_state, |p| restore_reg_value(root, subkey, name, p));
38+
let _g = scopeguard::guard(saved_state, |p| id.set(p.as_ref()).unwrap());
3739

3840
f();
3941
}
4042

4143
#[cfg(windows)]
42-
fn get_reg_value(root: &RegKey, subkey: &str, name: &str) -> io::Result<Option<RegValue>> {
43-
let subkey = root.open_subkey_with_flags(subkey, KEY_READ | KEY_WRITE)?;
44-
match subkey.get_raw_value(name) {
45-
Ok(val) => Ok(Some(val)),
46-
Err(ref e) if e.kind() == io::ErrorKind::NotFound => Ok(None),
47-
Err(e) => Err(e),
48-
}
44+
const USER_PATH: RegistryValueId = RegistryValueId {
45+
sub_key: "Environment",
46+
value_name: "PATH",
47+
};
48+
49+
#[cfg(windows)]
50+
pub struct RegistryValueId {
51+
pub sub_key: &'static str,
52+
pub value_name: &'static str,
4953
}
5054

5155
#[cfg(windows)]
52-
fn restore_reg_value(root: &RegKey, subkey: &str, name: &str, p: Option<RegValue>) {
53-
let subkey = root
54-
.open_subkey_with_flags(subkey, KEY_READ | KEY_WRITE)
55-
.unwrap();
56-
if let Some(p) = p.as_ref() {
57-
subkey.set_raw_value(name, p).unwrap();
58-
} else {
59-
let _ = subkey.delete_value(name);
56+
impl RegistryValueId {
57+
pub fn get_value<T: FromRegValue>(&self) -> io::Result<Option<T>> {
58+
self.get()?.map(|v| T::from_reg_value(&v)).transpose()
59+
}
60+
61+
pub fn get(&self) -> io::Result<Option<RegValue>> {
62+
let sub_key = RegKey::predef(HKEY_CURRENT_USER)
63+
.open_subkey_with_flags(self.sub_key, KEY_READ | KEY_WRITE)?;
64+
match sub_key.get_raw_value(self.value_name) {
65+
Ok(val) => Ok(Some(val)),
66+
Err(ref e) if e.kind() == io::ErrorKind::NotFound => Ok(None),
67+
Err(e) => Err(e),
68+
}
69+
}
70+
71+
pub fn set_value(&self, new: Option<impl ToRegValue>) -> io::Result<()> {
72+
self.set(new.map(|s| s.to_reg_value()).as_ref())
73+
}
74+
75+
pub fn set(&self, new: Option<&RegValue>) -> io::Result<()> {
76+
let sub_key = RegKey::predef(HKEY_CURRENT_USER)
77+
.open_subkey_with_flags(self.sub_key, KEY_READ | KEY_WRITE)?;
78+
match new {
79+
Some(new) => sub_key.set_raw_value(self.value_name, new),
80+
None => sub_key.delete_value(self.value_name),
81+
}
6082
}
6183
}

src/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::currentprocess::TestProcess;
2020
use crate::dist::TargetTriple;
2121

2222
#[cfg(windows)]
23-
pub use crate::cli::self_update::test::{get_path, with_saved_reg_value};
23+
pub use crate::cli::self_update::test::{get_path, with_saved_reg_value, RegistryValueId};
2424

2525
// Things that can have environment variables applied to them.
2626
pub trait Env {

tests/suite/cli_self_upd.rs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,11 @@ use rustup::test::{
1919
},
2020
this_host_triple, with_saved_path,
2121
};
22+
#[cfg(windows)]
23+
use rustup::test::{with_saved_reg_value, RegistryValueId};
2224
use rustup::utils::{raw, utils};
2325
use rustup::{for_host, DUP_TOOLS, TOOLS};
2426

25-
#[cfg(windows)]
26-
use rustup::test::with_saved_reg_value;
27-
2827
const TEST_VERSION: &str = "1.1.1";
2928

3029
/// Empty dist server, rustup installed with no toolchain
@@ -315,36 +314,31 @@ info: downloading self-update
315314
#[test]
316315
#[cfg(windows)]
317316
fn update_overwrites_programs_display_version() {
318-
let root = &winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER);
319-
let key = r"Software\Microsoft\Windows\CurrentVersion\Uninstall\Rustup";
320-
let name = "DisplayVersion";
321-
322317
const PLACEHOLDER_VERSION: &str = "9.999.99";
323318
let version = env!("CARGO_PKG_VERSION");
324319

325320
let mut cx = SelfUpdateTestContext::new(TEST_VERSION);
326-
with_saved_reg_value(root, key, name, &mut || {
321+
with_saved_reg_value(&USER_RUSTUP_VERSION, &mut || {
327322
cx.config
328323
.expect_ok(&["rustup-init", "-y", "--no-modify-path"]);
329324

330-
root.create_subkey(key)
331-
.unwrap()
332-
.0
333-
.set_value(name, &PLACEHOLDER_VERSION)
325+
USER_RUSTUP_VERSION
326+
.set_value(Some(PLACEHOLDER_VERSION))
334327
.unwrap();
335-
336328
cx.config.expect_ok(&["rustup", "self", "update"]);
337-
338329
assert_eq!(
339-
root.open_subkey(key)
340-
.unwrap()
341-
.get_value::<String, _>(name)
342-
.unwrap(),
330+
USER_RUSTUP_VERSION.get_value::<String>().unwrap().unwrap(),
343331
version,
344332
);
345333
});
346334
}
347335

336+
#[cfg(windows)]
337+
const USER_RUSTUP_VERSION: RegistryValueId = RegistryValueId {
338+
sub_key: r"Software\Microsoft\Windows\CurrentVersion\Uninstall\Rustup",
339+
value_name: "DisplayVersion",
340+
};
341+
348342
#[test]
349343
fn update_but_not_installed() {
350344
let cx = SelfUpdateTestContext::new(TEST_VERSION);

0 commit comments

Comments
 (0)