Skip to content

Commit 1488d42

Browse files
authored
Merge pull request #2 from hija/tests
added basic tests
2 parents 8ce5f1d + 587079a commit 1488d42

File tree

7 files changed

+134
-9
lines changed

7 files changed

+134
-9
lines changed

.github/workflows/main.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: main
2+
3+
on:
4+
push:
5+
branches: [main, test-me-*]
6+
tags: '*'
7+
pull_request:
8+
9+
jobs:
10+
main-windows:
11+
uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0
12+
with:
13+
env: '["py38"]'
14+
os: windows-latest
15+
main-linux:
16+
uses: asottile/workflows/.github/workflows/tox.yml@v1.6.0
17+
with:
18+
env: '["py38", "py39", "py310", "py311", "py312", "py313"]'
19+
os: ubuntu-latest

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
[![build status](https://github.com/hija/clean-dotenv/actions/workflows/main.yml/badge.svg)](https://github.com/hija/clean-dotenv/actions/workflows/main.yml)
12
[![PyPI version](https://badge.fury.io/py/clean-dotenv.svg)](https://badge.fury.io/py/clean-dotenv)
23

34
clean-dotenv
@@ -38,7 +39,7 @@ Consult `clean-dotenv --help` for the full set of options.
3839

3940
Common options:
4041

41-
- `--root path`: Defines the root path in which to look for .env files
42+
- `--root path`: Defines the root path in which to look for .env files. This is **not recursive**
4243

4344
## As a pre-commit hook
4445

clean_dotenv.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import os
22
import argparse
3+
from typing import Iterator
34
import dotenv.main
45

56

6-
def clean_env(path_to_env: str):
7+
def _clean_env(path_to_env: str):
78
# Open the .env file and remove the sensitive data
89
# We rely on python-dotenv to parse the file, since we do not want to write our own parser
910

@@ -18,13 +19,19 @@ def clean_env(path_to_env: str):
1819
print(f"{key}=", file=example_env_f)
1920

2021

21-
def clean_dotenv_files(path_to_root: str):
22+
def _find_dotenv_files(path_to_root: str) -> Iterator[str]:
23+
# Finds and yields .env files in the path_to_root
24+
for entry in os.scandir(path_to_root):
25+
if entry.name.endswith(".env") and entry.is_file():
26+
# Create a cleaned .env.example file for the found .env file
27+
yield entry.path
28+
29+
30+
def _main(path_to_root: str):
2231
# Find possible .env files
23-
with os.scandir(path_to_root) as it:
24-
for entry in it:
25-
if entry.name.endswith(".env") and entry.is_file():
26-
# Create a cleaned .env.example file for the found .env file
27-
clean_env(entry.path)
32+
for dotenv_file in _find_dotenv_files(path_to_root):
33+
# Clean dotenv file
34+
_clean_env(dotenv_file)
2835

2936

3037
def main():
@@ -38,7 +45,7 @@ def main():
3845
default=os.getcwd(),
3946
)
4047
args = parser.parse_args()
41-
clean_dotenv_files(args.root_path)
48+
_main(args.root_path)
4249

4350

4451
if __name__ == "__main__":

requirements-dev.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-r requirements.txt
2+
pytest
3+
coverage
4+
covdefaults

tests/__init__.py

Whitespace-only changes.

tests/main_test.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from os import DirEntry
2+
from unittest.mock import MagicMock, call, mock_open, patch
3+
import pytest
4+
import clean_dotenv
5+
6+
7+
class DirEntry:
8+
def __init__(self, path, is_file=True):
9+
self.path = path
10+
self.name = path
11+
self._is_file = is_file
12+
13+
def path(self): # pragma: no cover
14+
return self.path
15+
16+
def is_file(self):
17+
return self._is_file
18+
19+
20+
@patch("os.scandir")
21+
def test_find_dotenv_files(mock_scandir):
22+
# Mock os.scandir() for files
23+
mock_scandir.return_value = [
24+
DirEntry(filename)
25+
for filename in ["test.py", "abba", "env", "test.env", ".env"]
26+
]
27+
assert list(clean_dotenv._find_dotenv_files(None)) == ["test.env", ".env"]
28+
29+
# Mock os.scandir() for directories
30+
mock_scandir.return_value = [
31+
DirEntry(filename, is_file=False)
32+
for filename in ["test.py", "abba", "env", "test.env", ".env", "env"]
33+
]
34+
assert list(clean_dotenv._find_dotenv_files(None)) == []
35+
36+
37+
@patch("dotenv.main.DotEnv")
38+
def test_clean_env_function(mock_dotenv):
39+
dotenv_dict = {"KEY1": "secret_value1", "KEY2": "secret_value2"}
40+
mock_dotenv.return_value.dict.return_value.items.return_value = dotenv_dict.items()
41+
42+
with patch("builtins.open", mock_open()) as mock_file:
43+
clean_dotenv._clean_env("test.env")
44+
mock_file.assert_called_with("test.env.example", "w")
45+
expected_calls = [call("KEY1="), call("\n"), call("KEY2="), call("\n")]
46+
mock_file.return_value.write.assert_has_calls(expected_calls)
47+
48+
49+
def test_find_dotenv_files_function():
50+
with patch("os.scandir") as mock_scandir:
51+
mock_scandir.return_value = [DirEntry("test.env")]
52+
53+
result = list(clean_dotenv._find_dotenv_files("path_to_root"))
54+
55+
assert result == ["test.env"]
56+
57+
58+
@patch("argparse.ArgumentParser.parse_args")
59+
@patch("clean_dotenv._main")
60+
def test_main(mock_main, mock_parse_args):
61+
mock_parse_args.return_value = MagicMock(root_path="test_rpath")
62+
63+
clean_dotenv.main()
64+
65+
mock_main.assert_called_once_with("test_rpath")
66+
67+
68+
def test__main():
69+
# Mock _find_dotenv_files
70+
mm_find_dotenv = MagicMock(return_value=[".env", "test.env"])
71+
clean_dotenv._find_dotenv_files = mm_find_dotenv
72+
73+
# Mock _clean_env
74+
mm_clean_env = MagicMock()
75+
clean_dotenv._clean_env = mm_clean_env
76+
77+
# Call main method
78+
clean_dotenv._main("test_directory")
79+
80+
# Detection should be called once
81+
mm_find_dotenv.assert_called_once_with("test_directory")
82+
83+
# The creation of new .env file should be called twice, last with "test.env"
84+
assert mm_clean_env.call_count == 2
85+
mm_clean_env.assert_called_with("test.env")

tox.ini

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[tox]
2+
envlist = py,pre-commit
3+
4+
[testenv]
5+
deps = -rrequirements-dev.txt
6+
commands =
7+
coverage erase
8+
coverage run -m pytest {posargs:tests}
9+
coverage report

0 commit comments

Comments
 (0)