Skip to content

Commit 423fd23

Browse files
committed
Add tests for error handling in env file operations and example creation for 100% cov
1 parent 206d0a3 commit 423fd23

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

tests/catch_dotenv_test.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,3 +442,109 @@ def boom(*_a: object, **_k: object) -> None:
442442
err = captured.err
443443
assert 'Example file generated' not in out
444444
assert 'ERROR: unable to write' in err
445+
446+
447+
def test_atomic_write_cleanup_failure(
448+
monkeypatch: pytest.MonkeyPatch,
449+
tmp_path: Path,
450+
env_file: Path,
451+
) -> None:
452+
"""Test rare case where os.remove fails during cleanup after os.replace
453+
failure.
454+
"""
455+
def failing_remove(_path: str) -> None:
456+
# Simulate os.remove failure during cleanup
457+
raise OSError('remove-fail')
458+
459+
def failing_replace(*_a: object, **_k: object) -> None:
460+
# First fail os.replace to trigger cleanup path
461+
raise OSError('replace-fail')
462+
463+
monkeypatch.setattr(
464+
'pre_commit_hooks.catch_dotenv.os.replace', failing_replace,
465+
)
466+
monkeypatch.setattr(
467+
'pre_commit_hooks.catch_dotenv.os.remove', failing_remove,
468+
)
469+
470+
# This should not raise an exception even if both replace and remove fail
471+
modified = ensure_env_in_gitignore(
472+
DEFAULT_ENV_FILE,
473+
str(tmp_path / DEFAULT_GITIGNORE_FILE),
474+
GITIGNORE_BANNER,
475+
)
476+
assert modified is False
477+
478+
479+
def test_create_example_read_error(
480+
monkeypatch: pytest.MonkeyPatch,
481+
tmp_path: Path,
482+
env_file: Path,
483+
capsys: pytest.CaptureFixture[str],
484+
) -> None:
485+
"""Test OSError when reading source env file for create_example."""
486+
def failing_open(*_args: object, **_kwargs: object) -> None:
487+
raise OSError('Permission denied')
488+
489+
# Mock open to fail when trying to read the env file
490+
monkeypatch.setattr('builtins.open', failing_open)
491+
492+
from pre_commit_hooks.catch_dotenv import create_example_env
493+
494+
result = create_example_env(str(env_file), str(tmp_path / 'test.example'))
495+
assert result is False
496+
497+
captured = capsys.readouterr()
498+
assert 'ERROR: unable to read' in captured.err
499+
500+
501+
def test_malformed_env_lines_ignored(tmp_path: Path, env_file: Path) -> None:
502+
"""Test that malformed env lines that don't match regex are ignored."""
503+
# Create env file with malformed lines
504+
malformed_env = tmp_path / 'malformed.env'
505+
malformed_content = [
506+
'VALID_KEY=value',
507+
'invalid-line-no-equals',
508+
'# comment line',
509+
'', # empty line
510+
'=INVALID_EQUALS_FIRST',
511+
'ANOTHER_VALID=value2',
512+
'spaces in key=invalid',
513+
'123_INVALID_START=value', # starts with number
514+
]
515+
malformed_env.write_text('\n'.join(malformed_content))
516+
517+
# Copy to .env location
518+
shutil.copyfile(malformed_env, tmp_path / DEFAULT_ENV_FILE)
519+
520+
# Run create-example - should only extract valid keys
521+
run_hook(tmp_path, [DEFAULT_ENV_FILE], create_example=True)
522+
523+
example_lines = (
524+
(tmp_path / DEFAULT_EXAMPLE_ENV_FILE).read_text().splitlines()
525+
)
526+
key_lines = [ln for ln in example_lines if ln and not ln.startswith('#')]
527+
528+
# Should only have the valid keys
529+
assert 'VALID_KEY=' in key_lines
530+
assert 'ANOTHER_VALID=' in key_lines
531+
assert len([k for k in key_lines if '=' in k]) == 2 # Only 2 valid keys
532+
533+
534+
def test_create_example_when_source_missing(
535+
tmp_path: Path, env_file: Path,
536+
) -> None:
537+
"""Test --create-example when source .env doesn't exist but .env is
538+
staged.
539+
"""
540+
# Remove the source .env file but keep it in the staged files list
541+
env_file.unlink() # Remove the .env file
542+
543+
# Stage .env even though it doesn't exist on disk
544+
ret = run_hook(tmp_path, [DEFAULT_ENV_FILE], create_example=True)
545+
546+
# Hook should still block commit
547+
assert ret == 1
548+
549+
# But no example file should be created since source doesn't exist
550+
assert not (tmp_path / DEFAULT_EXAMPLE_ENV_FILE).exists()

0 commit comments

Comments
 (0)