@@ -46,9 +46,24 @@ def _patch_out_env(name):
46
46
47
47
@contextlib .contextmanager
48
48
def _rollback_refresh ():
49
+ old_git_executable = Git .GIT_PYTHON_GIT_EXECUTABLE
50
+
51
+ if old_git_executable is None :
52
+ raise RuntimeError ("no executable string (need initial refresh before test)" )
53
+
49
54
try :
50
- yield Git . GIT_PYTHON_GIT_EXECUTABLE # Provide the old value for convenience.
55
+ yield old_git_executable # Provide the old value for convenience.
51
56
finally :
57
+ # The cleanup refresh should always raise an exception if it fails, since if it
58
+ # fails then previously discovered test results could be misleading and, more
59
+ # importantly, subsequent tests may be unable to run or give misleading results.
60
+ # So pre-set a non-None value, so that the cleanup will be a "second" refresh.
61
+ # This covers cases where a test has set it to None to test a "first" refresh.
62
+ Git .GIT_PYTHON_GIT_EXECUTABLE = Git .git_exec_name
63
+
64
+ # Do the cleanup refresh. This sets Git.GIT_PYTHON_GIT_EXECUTABLE to old_value
65
+ # in most cases. The reason to call it is to achieve other associated state
66
+ # changes as well, which include updating attributes of the FetchInfo class.
52
67
refresh ()
53
68
54
69
@@ -314,7 +329,127 @@ def test_cmd_override(self):
314
329
):
315
330
self .assertRaises (GitCommandNotFound , self .git .version )
316
331
317
- def test_refresh_bad_absolute_git_path (self ):
332
+ def test_git_exc_name_is_git (self ):
333
+ self .assertEqual (self .git .git_exec_name , "git" )
334
+
335
+ @ddt .data (("0" ,), ("q" ,), ("quiet" ,), ("s" ,), ("silence" ,), ("silent" ,), ("n" ,), ("none" ,))
336
+ def test_initial_refresh_from_bad_git_path_env_quiet (self , case ):
337
+ """In "q" mode, bad initial path sets "git" and is quiet."""
338
+ (mode ,) = case
339
+ set_vars = {
340
+ "GIT_PYTHON_GIT_EXECUTABLE" : str (Path ("yada" ).absolute ()), # Any bad path.
341
+ "GIT_PYTHON_REFRESH" : mode ,
342
+ }
343
+ with _rollback_refresh ():
344
+ type(self .git ).GIT_PYTHON_GIT_EXECUTABLE = None # Simulate startup.
345
+
346
+ with mock .patch .dict (os .environ , set_vars ):
347
+ refresh ()
348
+ self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , "git" )
349
+
350
+ @ddt .data (("1" ,), ("w" ,), ("warn" ,), ("warning" ,), ("l" ,), ("log" ,))
351
+ def test_initial_refresh_from_bad_git_path_env_warn (self , case ):
352
+ """In "w" mode, bad initial path sets "git" and warns, by logging."""
353
+ (mode ,) = case
354
+ env_vars = {
355
+ "GIT_PYTHON_GIT_EXECUTABLE" : str (Path ("yada" ).absolute ()), # Any bad path.
356
+ "GIT_PYTHON_REFRESH" : mode ,
357
+ }
358
+ with _rollback_refresh ():
359
+ type(self .git ).GIT_PYTHON_GIT_EXECUTABLE = None # Simulate startup.
360
+
361
+ with mock .patch .dict (os .environ , env_vars ):
362
+ with self .assertLogs (cmd .__name__ , logging .CRITICAL ) as ctx :
363
+ refresh ()
364
+ self .assertEqual (len (ctx .records ), 1 )
365
+ message = ctx .records [0 ].getMessage ()
366
+ self .assertRegex (message , r"\AWARNING: Bad git executable.\n" )
367
+ self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , "git" )
368
+
369
+ @ddt .data (("2" ,), ("r" ,), ("raise" ,), ("e" ,), ("error" ,))
370
+ def test_initial_refresh_from_bad_git_path_env_error (self , case ):
371
+ """In "e" mode, bad initial path raises an exception."""
372
+ (mode ,) = case
373
+ env_vars = {
374
+ "GIT_PYTHON_GIT_EXECUTABLE" : str (Path ("yada" ).absolute ()), # Any bad path.
375
+ "GIT_PYTHON_REFRESH" : mode ,
376
+ }
377
+ with _rollback_refresh ():
378
+ type(self .git ).GIT_PYTHON_GIT_EXECUTABLE = None # Simulate startup.
379
+
380
+ with mock .patch .dict (os .environ , env_vars ):
381
+ with self .assertRaisesRegex (ImportError , r"\ABad git executable.\n" ):
382
+ refresh ()
383
+
384
+ def test_initial_refresh_from_good_absolute_git_path_env (self ):
385
+ """Good initial absolute path from environment is set."""
386
+ absolute_path = shutil .which ("git" )
387
+
388
+ with _rollback_refresh ():
389
+ type(self .git ).GIT_PYTHON_GIT_EXECUTABLE = None # Simulate startup.
390
+
391
+ with mock .patch .dict (os .environ , {"GIT_PYTHON_GIT_EXECUTABLE" : absolute_path }):
392
+ refresh ()
393
+ self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , absolute_path )
394
+
395
+ def test_initial_refresh_from_good_relative_git_path_env (self ):
396
+ """Good initial relative path from environment is kept relative and set."""
397
+ with _rollback_refresh ():
398
+ # Set the fallback to a string that wouldn't work and isn't "git", so we are
399
+ # more likely to detect if "git" is not set from the environment variable.
400
+ with mock .patch .object (type (self .git ), "git_exec_name" , "" ):
401
+ type(self .git ).GIT_PYTHON_GIT_EXECUTABLE = None # Simulate startup.
402
+
403
+ # Now observe if setting the environment variable to "git" takes effect.
404
+ with mock .patch .dict (os .environ , {"GIT_PYTHON_GIT_EXECUTABLE" : "git" }):
405
+ refresh ()
406
+ self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , "git" )
407
+
408
+ def test_refresh_from_bad_absolute_git_path_env (self ):
409
+ """Bad absolute path from environment is reported and not set."""
410
+ absolute_path = str (Path ("yada" ).absolute ())
411
+ expected_pattern = rf"\n[ \t]*cmdline: { re .escape (absolute_path )} \Z"
412
+
413
+ with _rollback_refresh () as old_git_executable :
414
+ with mock .patch .dict (os .environ , {"GIT_PYTHON_GIT_EXECUTABLE" : absolute_path }):
415
+ with self .assertRaisesRegex (GitCommandNotFound , expected_pattern ):
416
+ refresh ()
417
+ self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , old_git_executable )
418
+
419
+ def test_refresh_from_bad_relative_git_path_env (self ):
420
+ """Bad relative path from environment is kept relative and reported, not set."""
421
+ # Relative paths are not resolved when refresh() is called with no arguments, so
422
+ # use a string that's very unlikely to be a command name found in a path lookup.
423
+ relative_path = "yada-e47e70c6-acbf-40f8-ad65-13af93c2195b"
424
+ expected_pattern = rf"\n[ \t]*cmdline: { re .escape (relative_path )} \Z"
425
+
426
+ with _rollback_refresh () as old_git_executable :
427
+ with mock .patch .dict (os .environ , {"GIT_PYTHON_GIT_EXECUTABLE" : relative_path }):
428
+ with self .assertRaisesRegex (GitCommandNotFound , expected_pattern ):
429
+ refresh ()
430
+ self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , old_git_executable )
431
+
432
+ def test_refresh_from_good_absolute_git_path_env (self ):
433
+ """Good absolute path from environment is set."""
434
+ absolute_path = shutil .which ("git" )
435
+
436
+ with _rollback_refresh ():
437
+ with mock .patch .dict (os .environ , {"GIT_PYTHON_GIT_EXECUTABLE" : absolute_path }):
438
+ refresh ()
439
+ self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , absolute_path )
440
+
441
+ def test_refresh_from_good_relative_git_path_env (self ):
442
+ """Good relative path from environment is kept relative and set."""
443
+ with _rollback_refresh ():
444
+ # Set as the executable name a string that wouldn't work and isn't "git".
445
+ type(self .git ).GIT_PYTHON_GIT_EXECUTABLE = ""
446
+
447
+ # Now observe if setting the environment variable to "git" takes effect.
448
+ with mock .patch .dict (os .environ , {"GIT_PYTHON_GIT_EXECUTABLE" : "git" }):
449
+ refresh ()
450
+ self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , "git" )
451
+
452
+ def test_refresh_with_bad_absolute_git_path_arg (self ):
318
453
"""Bad absolute path arg is reported and not set."""
319
454
absolute_path = str (Path ("yada" ).absolute ())
320
455
expected_pattern = rf"\n[ \t]*cmdline: { re .escape (absolute_path )} \Z"
@@ -324,7 +459,7 @@ def test_refresh_bad_absolute_git_path(self):
324
459
refresh (absolute_path )
325
460
self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , old_git_executable )
326
461
327
- def test_refresh_bad_relative_git_path (self ):
462
+ def test_refresh_with_bad_relative_git_path_arg (self ):
328
463
"""Bad relative path arg is resolved to absolute path and reported, not set."""
329
464
absolute_path = str (Path ("yada" ).absolute ())
330
465
expected_pattern = rf"\n[ \t]*cmdline: { re .escape (absolute_path )} \Z"
@@ -334,15 +469,15 @@ def test_refresh_bad_relative_git_path(self):
334
469
refresh ("yada" )
335
470
self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , old_git_executable )
336
471
337
- def test_refresh_good_absolute_git_path (self ):
472
+ def test_refresh_with_good_absolute_git_path_arg (self ):
338
473
"""Good absolute path arg is set."""
339
474
absolute_path = shutil .which ("git" )
340
475
341
476
with _rollback_refresh ():
342
477
refresh (absolute_path )
343
478
self .assertEqual (self .git .GIT_PYTHON_GIT_EXECUTABLE , absolute_path )
344
479
345
- def test_refresh_good_relative_git_path (self ):
480
+ def test_refresh_with_good_relative_git_path_arg (self ):
346
481
"""Good relative path arg is resolved to absolute path and set."""
347
482
absolute_path = shutil .which ("git" )
348
483
dirname , basename = osp .split (absolute_path )
0 commit comments