Skip to content

Commit 9e71d55

Browse files
committed
Update alternative locations integration tests for user program files
This updates the integration-style tests for Windows-specific `git` executable alternative locations to include locations under the per-user program files directory. The user program files directory, when present, is a subdirectory of the user's local application data directory. (The sense in which these are "integration-style" tests is noted in e9770a7 in #2115, where they were last updated.) These tests will now fail until `ALTERNATIVE_LOCATIONS` is enhanced to check in the user program files directory (as well as the global program files directories that are currently checked).
1 parent e365244 commit 9e71d55

File tree

1 file changed

+95
-34
lines changed

1 file changed

+95
-34
lines changed

gix-path/src/env/git/tests.rs

Lines changed: 95 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,10 @@ mod locations {
205205
Some(folded_text.ends_with(&folded_pattern))
206206
}
207207

208-
/// The most common global program files paths on this system, by process and system architecture.
208+
/// The most common program files paths, as they are available in this environment.
209209
///
210-
/// This omits the 32-bit ARM program files directory, as Git for Windows is never installed there.
210+
/// This omits the global 32-bit ARM program files directory, because Git for Windows is never
211+
/// installed there.
211212
#[derive(Clone, Debug)]
212213
struct ProgramFilesPaths {
213214
/// The program files directory used for whatever architecture this program was built for.
@@ -224,20 +225,24 @@ mod locations {
224225
/// AMD64 programs use the same program files directory while 32-bit x86 and 32-bit ARM
225226
/// programs use two others. Only a 32-bit system has no 64-bit program files directory.
226227
maybe_64bit: Option<PathBuf>,
228+
229+
/// The per-user `Programs` subdirectory of the user's local application data directory.
230+
user: PathBuf,
227231
}
228232

229233
impl ProgramFilesPaths {
230-
/// Get the three most common kinds of global program files paths without environment variables.
234+
/// Get the four most common kinds of program files paths without environment variables.
231235
///
232236
/// The idea here is to obtain this information, which the `alternative_locations()` unit
233237
/// test uses to learn the expected alternative locations, without duplicating *any* of the
234238
/// approach used for `ALTERNATIVE_LOCATIONS`, so it can be used to test that. The approach
235239
/// here is also more reliable than using environment variables, but it is a bit more
236240
/// complex, and it requires either additional dependencies or the use of unsafe code.
237241
///
238-
/// This gets `pf_current` and `pf_x86` by the [known folders][known-folders] system. But
239-
/// it gets `maybe_pf_64bit` from the registry, as the corresponding known folder is not
240-
/// available to 32-bit processes. See the [`KNOWNFOLDDERID`][knownfolderid] documentation.
242+
/// This gets `pf_user`, `pf_current`, and `pf_x86` by the [known folders][known-folders]
243+
/// system. But it gets `maybe_pf_64bit` from the registry, as the corresponding known
244+
/// folder is not available to 32-bit processes. See the [`KNOWNFOLDDERID`][knownfolderid]
245+
/// documentation.
241246
///
242247
/// If in the future the implementation of `ALTERNATIVE_LOCATIONS` uses these techniques,
243248
/// then this function can be changed to use environment variables and renamed accordingly.
@@ -262,10 +267,15 @@ mod locations {
262267
})
263268
.ok();
264269

270+
// FIXME: This lacks KF_FLAG_DONT_VERIFY, so it errors out if the folder hasn't been created.
271+
let pf_user = get_known_folder_path(KnownFolder::UserProgramFiles)
272+
.expect("The path where the user's local Programs folder is, or would be created, is known");
273+
265274
Self {
266275
current: pf_current,
267276
x86: pf_x86,
268277
maybe_64bit: maybe_pf_64bit,
278+
user: pf_user,
269279
}
270280
}
271281

@@ -274,6 +284,12 @@ mod locations {
274284
/// This checks that `obtain_envlessly()` returned paths that are likely to be correct and
275285
/// that satisfy the most important properties based on the current system and process.
276286
fn validated(self) -> Self {
287+
self.validate_global_folders();
288+
self.validate_user_folder();
289+
self
290+
}
291+
292+
fn validate_global_folders(&self) {
277293
match PlatformBitness::current().expect("Process and system 'bitness' should be available") {
278294
PlatformBitness::Is32on32 => {
279295
assert_eq!(
@@ -325,66 +341,111 @@ mod locations {
325341
);
326342
}
327343
}
344+
}
328345

329-
self
346+
fn validate_user_folder(&self) {
347+
let expected = get_known_folder_path(KnownFolder::LocalAppData)
348+
.expect("The user's local application data directory is available")
349+
.join("Programs");
350+
assert_eq!(
351+
self.user, expected,
352+
"The user program files directory is Programs in the local application data directory.",
353+
);
330354
}
331355
}
332356

333-
/// Paths relative to process architecture specific program files directories.
357+
/// Architecture-specific Git for Windows paths relative to particular program files directories.
334358
#[derive(Clone, Debug)]
335359
struct RelativeGitBinPaths<'a> {
336-
x86: &'a Path,
337-
maybe_x64: Option<&'a Path>,
338-
maybe_arm64: Option<&'a Path>,
360+
global_x86: &'a Path,
361+
maybe_global_x64: Option<&'a Path>,
362+
maybe_global_arm64: Option<&'a Path>,
363+
user_x86: &'a Path,
364+
maybe_user_x64: Option<&'a Path>,
365+
maybe_user_arm64: Option<&'a Path>,
339366
}
340367

341368
impl<'a> RelativeGitBinPaths<'a> {
342369
/// Assert that `locations` has the given path prefixes, and extract the suffixes.
343370
fn assert_from(pf: &'a ProgramFilesPaths, locations: &'static [PathBuf]) -> Self {
344371
match locations {
345-
[primary, secondary, tertiary] => {
372+
[path1, path2, path3, path4, path5, path6] => {
346373
let prefix_64bit = pf
347374
.maybe_64bit
348375
.as_ref()
349-
.expect("It gives three paths only if some can be 64-bit");
350-
let suffix_arm64 = primary
376+
.expect("It gives six paths only if some can be 64-bit");
377+
let suffix_user_arm64 = path1
378+
.strip_prefix(pf.user.as_path())
379+
.expect("It gives the per-user 64-bit ARM64 path and lists it first");
380+
let suffix_user_x64 = path2
381+
.strip_prefix(pf.user.as_path())
382+
.expect("It gives the per-user 64-bit x86 path and lists it second");
383+
let suffix_user_x86 = path3
384+
.strip_prefix(pf.user.as_path())
385+
.expect("It gives the per-user 32-bit x86 path and lists it third");
386+
let suffix_global_arm64 = path4
351387
.strip_prefix(prefix_64bit)
352-
.expect("It gives the 64-bit ARM64 path and lists it first");
353-
let suffix_x64 = secondary
388+
.expect("It gives the global 64-bit ARM64 path and lists it fourth");
389+
let suffix_global_x64 = path5
354390
.strip_prefix(prefix_64bit)
355-
.expect("It gives the 64-bit x86 path and lists it second");
356-
let suffix_x86 = tertiary
391+
.expect("It gives the global 64-bit x86 path and lists it fifth");
392+
let suffix_global_x86 = path6
357393
.strip_prefix(pf.x86.as_path())
358-
.expect("It gives the 32-bit path and lists it third");
394+
.expect("It gives the global 32-bit path and lists it sixth");
359395
Self {
360-
x86: suffix_x86,
361-
maybe_x64: Some(suffix_x64),
362-
maybe_arm64: Some(suffix_arm64),
396+
global_x86: suffix_global_x86,
397+
maybe_global_x64: Some(suffix_global_x64),
398+
maybe_global_arm64: Some(suffix_global_arm64),
399+
user_x86: suffix_user_x86,
400+
maybe_user_x64: Some(suffix_user_x64),
401+
maybe_user_arm64: Some(suffix_user_arm64),
363402
}
364403
}
365-
[only] => {
366-
assert_eq!(pf.maybe_64bit, None, "It gives one path only if none can be 64-bit.");
367-
let suffix_x86 = only
404+
[path1, path2] => {
405+
assert_eq!(pf.maybe_64bit, None, "It gives two paths only if none can be 64-bit.");
406+
let suffix_user_x86 = path1
407+
.strip_prefix(pf.user.as_path())
408+
.expect("It gives the per-user 32-bit path and lists it first");
409+
let suffix_global_x86 = path2
368410
.strip_prefix(pf.x86.as_path())
369-
.expect("The one path it gives is the 32-bit path");
411+
.expect("It gives the global 32-bit path and lists it second");
370412
Self {
371-
x86: suffix_x86,
372-
maybe_x64: None,
373-
maybe_arm64: None,
413+
global_x86: suffix_global_x86,
414+
maybe_global_x64: None,
415+
maybe_global_arm64: None,
416+
user_x86: suffix_user_x86,
417+
maybe_user_x64: None,
418+
maybe_user_arm64: None,
374419
}
375420
}
376-
other => panic!("{:?} has length {}, expected 1 or 3.", other, other.len()),
421+
other => panic!("{:?} has length {}, expected 2 or 6.", other, other.len()),
377422
}
378423
}
379424

380-
/// Assert that the suffixes (relative subdirectories) are the common per-architecture Git install locations.
425+
/// Assert that the suffixes (relative subdirectories) are the common Git install locations.
381426
fn assert_architectures(&self) {
382-
assert_eq!(self.x86, Path::new("Git/mingw32/bin"));
427+
self.assert_architectures_global();
428+
self.assert_architectures_user();
429+
}
430+
431+
fn assert_architectures_global(&self) {
432+
assert_eq!(self.global_x86, Path::new("Git/mingw32/bin"));
433+
434+
if let Some(suffix_x64) = self.maybe_global_x64 {
435+
assert_eq!(suffix_x64, Path::new("Git/mingw64/bin"));
436+
}
437+
if let Some(suffix_arm64) = self.maybe_global_arm64 {
438+
assert_eq!(suffix_arm64, Path::new("Git/clangarm64/bin"));
439+
}
440+
}
441+
442+
fn assert_architectures_user(&self) {
443+
assert_eq!(self.user_x86, Path::new("Git/mingw32/bin"));
383444

384-
if let Some(suffix_x64) = self.maybe_x64 {
445+
if let Some(suffix_x64) = self.maybe_user_x64 {
385446
assert_eq!(suffix_x64, Path::new("Git/mingw64/bin"));
386447
}
387-
if let Some(suffix_arm64) = self.maybe_arm64 {
448+
if let Some(suffix_arm64) = self.maybe_user_arm64 {
388449
assert_eq!(suffix_arm64, Path::new("Git/clangarm64/bin"));
389450
}
390451
}

0 commit comments

Comments
 (0)