Skip to content

Commit 254d5bf

Browse files
bbc2theskumar
authored andcommitted
Isolate test files (#160)
The test suite had the following issues: * A failing test would leave files in the `tests` directory, causing other tests to fail unexpectedly. * Even successful tests would require clean up code like `sh.rm(...)` to avoid leaving test files. This was easy to forget as shown by #153. * The same test file would be used for several tests, making them unsafe to run in parallel. This commit fixes that by using the `dotenv_file` and `tmp_path` fixtures whenever the filesystem is required. The advantage of those fixtures is that they use unique test directories, which are eventually cleaned up. The `tmp_path` fixture is preferred to the `tmpdir` fixture because `tmpdir` relies on `py.path`, a library in "maintenance mode".
1 parent cf9bd1f commit 254d5bf

File tree

5 files changed

+192
-217
lines changed

5 files changed

+192
-217
lines changed

requirements.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
flake8>=2.2.3
2-
pytest>=3.0.5
3-
sh>=1.09
41
bumpversion
5-
wheel
6-
pytest-cov
72
click
3+
flake8>=2.2.3
84
ipython
95
pypandoc
6+
pytest-cov
7+
pytest>=3.9
8+
sh>=1.09
9+
wheel

tests/conftest.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import pytest
2+
from click.testing import CliRunner
23

3-
from .fixtures import * # noqa
4+
5+
@pytest.fixture
6+
def cli():
7+
yield CliRunner()
48

59

610
@pytest.fixture
7-
def dotenv_file(tmpdir):
8-
file_ = tmpdir.mkdir('dotenv_file').join('.env')
9-
file_.write('')
10-
return str(file_)
11+
def dotenv_file(tmp_path):
12+
file_ = tmp_path / '.env'
13+
file_.write_bytes(b'')
14+
yield str(file_)

tests/fixtures.py

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/test_cli.py

Lines changed: 116 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# -*- coding: utf-8 -*-
22
import os
3-
from os.path import dirname, join
43

54
import pytest
65
import sh
@@ -9,18 +8,14 @@
98
from dotenv.cli import cli as dotenv_cli
109
from dotenv.version import __version__
1110

12-
here = dirname(__file__)
13-
dotenv_path = join(here, '.env')
1411

15-
16-
def test_get_key():
17-
sh.touch(dotenv_path)
18-
success, key_to_set, value_to_set = dotenv.set_key(dotenv_path, 'HELLO', 'WORLD')
19-
stored_value = dotenv.get_key(dotenv_path, 'HELLO')
12+
def test_get_key(dotenv_file):
13+
success, key_to_set, value_to_set = dotenv.set_key(dotenv_file, 'HELLO', 'WORLD')
14+
stored_value = dotenv.get_key(dotenv_file, 'HELLO')
2015
assert stored_value == 'WORLD'
21-
sh.rm(dotenv_path)
22-
assert dotenv.get_key(dotenv_path, 'HELLO') is None
23-
success, key_to_set, value_to_set = dotenv.set_key(dotenv_path, 'HELLO', 'WORLD')
16+
sh.rm(dotenv_file)
17+
assert dotenv.get_key(dotenv_file, 'HELLO') is None
18+
success, key_to_set, value_to_set = dotenv.set_key(dotenv_file, 'HELLO', 'WORLD')
2419
assert success is None
2520

2621

@@ -76,66 +71,52 @@ def test_list_wo_file(cli):
7671
assert 'Invalid value for "-f"' in result.output
7772

7873

79-
def test_empty_value():
80-
with open(dotenv_path, "w") as f:
74+
def test_empty_value(dotenv_file):
75+
with open(dotenv_file, "w") as f:
8176
f.write("TEST=")
82-
assert dotenv.get_key(dotenv_path, "TEST") == ""
83-
sh.rm(dotenv_path)
77+
assert dotenv.get_key(dotenv_file, "TEST") == ""
8478

8579

86-
def test_key_value_without_quotes():
87-
with open(dotenv_path, 'w') as f:
80+
def test_key_value_without_quotes(dotenv_file):
81+
with open(dotenv_file, 'w') as f:
8882
f.write("TEST = value \n")
89-
assert dotenv.get_key(dotenv_path, 'TEST') == "value"
90-
sh.rm(dotenv_path)
83+
assert dotenv.get_key(dotenv_file, 'TEST') == "value"
84+
9185

92-
with open(dotenv_path, 'w') as f:
86+
def test_key_value_without_quotes_with_spaces(dotenv_file):
87+
with open(dotenv_file, 'w') as f:
9388
f.write('TEST = " with spaces " \n')
94-
assert dotenv.get_key(dotenv_path, 'TEST') == " with spaces "
95-
sh.rm(dotenv_path)
89+
assert dotenv.get_key(dotenv_file, 'TEST') == " with spaces "
9690

9791

98-
def test_value_with_quotes():
99-
with open(dotenv_path, 'w') as f:
92+
def test_value_with_double_quotes(dotenv_file):
93+
with open(dotenv_file, 'w') as f:
10094
f.write('TEST="two words"\n')
101-
assert dotenv.get_key(dotenv_path, 'TEST') == 'two words'
102-
sh.rm(dotenv_path)
95+
assert dotenv.get_key(dotenv_file, 'TEST') == 'two words'
96+
10397

104-
with open(dotenv_path, 'w') as f:
98+
def test_value_with_simple_quotes(dotenv_file):
99+
with open(dotenv_file, 'w') as f:
105100
f.write("TEST='two words'\n")
106-
assert dotenv.get_key(dotenv_path, 'TEST') == 'two words'
107-
sh.rm(dotenv_path)
101+
assert dotenv.get_key(dotenv_file, 'TEST') == 'two words'
108102

109103

110-
def test_value_with_special_characters():
111-
with open(dotenv_path, 'w') as f:
104+
def test_value_with_special_characters(dotenv_file):
105+
with open(dotenv_file, 'w') as f:
112106
f.write(r'TEST="}=&~{,(\5%{&;"')
113-
assert dotenv.get_key(dotenv_path, 'TEST') == r'}=&~{,(\5%{&;'
114-
sh.rm(dotenv_path)
107+
assert dotenv.get_key(dotenv_file, 'TEST') == r'}=&~{,(\5%{&;'
115108

116-
with open(dotenv_path, 'w') as f:
117-
f.write(r"TEST='}=&~{,(\5%{&;'")
118-
assert dotenv.get_key(dotenv_path, 'TEST') == r'}=&~{,(\5%{&;'
119-
sh.rm(dotenv_path)
120109

121-
122-
def test_value_with_new_lines():
123-
with open(dotenv_path, 'w') as f:
110+
def test_value_with_new_lines(dotenv_file):
111+
with open(dotenv_file, 'w') as f:
124112
f.write('TEST="a\nb"')
125-
assert dotenv.get_key(dotenv_path, 'TEST') == "a\nb"
126-
sh.rm(dotenv_path)
127-
128-
with open(dotenv_path, 'w') as f:
129-
f.write("TEST='a\nb'")
130-
assert dotenv.get_key(dotenv_path, 'TEST') == "a\nb"
131-
sh.rm(dotenv_path)
113+
assert dotenv.get_key(dotenv_file, 'TEST') == "a\nb"
132114

133115

134-
def test_value_after_comment():
135-
with open(dotenv_path, "w") as f:
116+
def test_value_after_comment(dotenv_file):
117+
with open(dotenv_file, "w") as f:
136118
f.write("# comment\nTEST=a")
137-
assert dotenv.get_key(dotenv_path, "TEST") == "a"
138-
sh.rm(dotenv_path)
119+
assert dotenv.get_key(dotenv_file, "TEST") == "a"
139120

140121

141122
def test_unset_ok(dotenv_file):
@@ -148,7 +129,6 @@ def test_unset_ok(dotenv_file):
148129
assert key_to_unset == "a"
149130
with open(dotenv_file, "r") as f:
150131
assert f.read() == "c=d"
151-
sh.rm(dotenv_file)
152132

153133

154134
def test_unset_non_existing_file():
@@ -168,105 +148,104 @@ def test_unset_cli(cli, dotenv_file):
168148
assert result.exit_code == 1, result.output
169149

170150

171-
def test_console_script(cli):
172-
TEST_COMBINATIONS = (
173-
# quote_mode, var_name, var_value, expected_result
151+
@pytest.mark.parametrize(
152+
"quote_mode,variable,value,expected",
153+
(
174154
("always", "HELLO", "WORLD", 'HELLO="WORLD"\n'),
175155
("never", "HELLO", "WORLD", 'HELLO=WORLD\n'),
176156
("auto", "HELLO", "WORLD", 'HELLO=WORLD\n'),
177157
("auto", "HELLO", "HELLO WORLD", 'HELLO="HELLO WORLD"\n'),
178158
)
179-
with cli.isolated_filesystem():
180-
for quote_mode, variable, value, expected_result in TEST_COMBINATIONS:
181-
sh.touch(dotenv_path)
182-
sh.dotenv('-f', dotenv_path, '-q', quote_mode, 'set', variable, value)
183-
output = sh.cat(dotenv_path)
184-
assert output == expected_result
185-
sh.rm(dotenv_path)
186-
187-
# should fail for not existing file
159+
)
160+
def test_console_script(quote_mode, variable, value, expected, dotenv_file):
161+
sh.dotenv('-f', dotenv_file, '-q', quote_mode, 'set', variable, value)
162+
163+
result = sh.cat(dotenv_file)
164+
165+
assert result == expected
166+
167+
168+
def test_set_non_existing_file(cli):
188169
result = cli.invoke(dotenv.cli.set, ['my_key', 'my_value'])
170+
189171
assert result.exit_code != 0
190172

191-
# should fail for not existing file
173+
174+
def test_get_non_existing_file(cli):
192175
result = cli.invoke(dotenv.cli.get, ['my_key'])
176+
193177
assert result.exit_code != 0
194178

195-
# should fail for not existing file
196-
result = cli.invoke(dotenv.cli.list, [])
179+
180+
def test_list_non_existing_file(cli):
181+
result = cli.invoke(dotenv.cli.set, [])
182+
197183
assert result.exit_code != 0
198184

199185

200-
def test_default_path(cli):
201-
with cli.isolated_filesystem():
202-
sh.touch(dotenv_path)
203-
sh.cd(here)
204-
sh.dotenv('set', 'HELLO', 'WORLD')
205-
output = sh.dotenv('get', 'HELLO')
206-
assert output == 'HELLO=WORLD\n'
207-
sh.rm(dotenv_path)
208-
209-
210-
def test_get_key_with_interpolation(cli):
211-
with cli.isolated_filesystem():
212-
sh.touch(dotenv_path)
213-
dotenv.set_key(dotenv_path, 'HELLO', 'WORLD')
214-
dotenv.set_key(dotenv_path, 'FOO', '${HELLO}')
215-
dotenv.set_key(dotenv_path, 'BAR', 'CONCATENATED_${HELLO}_POSIX_VAR')
216-
217-
lines = list(open(dotenv_path, "r").readlines())
218-
assert lines == [
219-
'HELLO="WORLD"\n',
220-
'FOO="${HELLO}"\n',
221-
'BAR="CONCATENATED_${HELLO}_POSIX_VAR"\n',
222-
]
223-
224-
# test replace from variable in file
225-
stored_value = dotenv.get_key(dotenv_path, 'FOO')
226-
assert stored_value == 'WORLD'
227-
stored_value = dotenv.get_key(dotenv_path, 'BAR')
228-
assert stored_value == 'CONCATENATED_WORLD_POSIX_VAR'
229-
# test replace from environ taking precedence over file
230-
os.environ["HELLO"] = "TAKES_PRECEDENCE"
231-
stored_value = dotenv.get_key(dotenv_path, 'FOO')
232-
assert stored_value == "TAKES_PRECEDENCE"
233-
sh.rm(dotenv_path)
234-
235-
236-
def test_get_key_with_interpolation_of_unset_variable(cli):
237-
with cli.isolated_filesystem():
238-
sh.touch(dotenv_path)
239-
dotenv.set_key(dotenv_path, 'FOO', '${NOT_SET}')
240-
# test unavailable replacement returns empty string
241-
stored_value = dotenv.get_key(dotenv_path, 'FOO')
242-
assert stored_value == ''
243-
# unless present in environment
244-
os.environ['NOT_SET'] = 'BAR'
245-
stored_value = dotenv.get_key(dotenv_path, 'FOO')
246-
assert stored_value == 'BAR'
247-
del(os.environ['NOT_SET'])
248-
sh.rm(dotenv_path)
249-
250-
251-
def test_run(cli):
252-
with cli.isolated_filesystem():
253-
sh.touch(dotenv_path)
254-
sh.cd(here)
255-
dotenv.set_key(dotenv_path, 'FOO', 'BAR')
256-
result = sh.dotenv('run', 'printenv', 'FOO').strip()
257-
assert result == 'BAR'
258-
sh.rm(dotenv_path)
259-
260-
261-
def test_run_with_other_env(cli):
262-
DOTENV_FILE = 'dotenv'
263-
with cli.isolated_filesystem():
264-
sh.cd(here)
265-
sh.touch(DOTENV_FILE)
266-
sh.dotenv('--file', DOTENV_FILE, 'set', 'FOO', 'BAR')
267-
result = sh.dotenv('--file', DOTENV_FILE, 'run', 'printenv', 'FOO').strip()
268-
assert result == 'BAR'
269-
sh.rm(DOTENV_FILE)
186+
def test_default_path(tmp_path):
187+
sh.cd(str(tmp_path))
188+
sh.touch(tmp_path / '.env')
189+
sh.dotenv('set', 'HELLO', 'WORLD')
190+
191+
result = sh.dotenv('get', 'HELLO')
192+
193+
assert result == 'HELLO=WORLD\n'
194+
195+
196+
def test_get_key_with_interpolation(dotenv_file):
197+
sh.touch(dotenv_file)
198+
dotenv.set_key(dotenv_file, 'HELLO', 'WORLD')
199+
dotenv.set_key(dotenv_file, 'FOO', '${HELLO}')
200+
dotenv.set_key(dotenv_file, 'BAR', 'CONCATENATED_${HELLO}_POSIX_VAR')
201+
202+
lines = list(open(dotenv_file, "r").readlines())
203+
assert lines == [
204+
'HELLO="WORLD"\n',
205+
'FOO="${HELLO}"\n',
206+
'BAR="CONCATENATED_${HELLO}_POSIX_VAR"\n',
207+
]
208+
209+
# test replace from variable in file
210+
stored_value = dotenv.get_key(dotenv_file, 'FOO')
211+
assert stored_value == 'WORLD'
212+
stored_value = dotenv.get_key(dotenv_file, 'BAR')
213+
assert stored_value == 'CONCATENATED_WORLD_POSIX_VAR'
214+
# test replace from environ taking precedence over file
215+
os.environ["HELLO"] = "TAKES_PRECEDENCE"
216+
stored_value = dotenv.get_key(dotenv_file, 'FOO')
217+
assert stored_value == "TAKES_PRECEDENCE"
218+
219+
220+
def test_get_key_with_interpolation_of_unset_variable(dotenv_file):
221+
dotenv.set_key(dotenv_file, 'FOO', '${NOT_SET}')
222+
# test unavailable replacement returns empty string
223+
stored_value = dotenv.get_key(dotenv_file, 'FOO')
224+
assert stored_value == ''
225+
# unless present in environment
226+
os.environ['NOT_SET'] = 'BAR'
227+
stored_value = dotenv.get_key(dotenv_file, 'FOO')
228+
assert stored_value == 'BAR'
229+
del(os.environ['NOT_SET'])
230+
231+
232+
def test_run(tmp_path):
233+
dotenv_file = tmp_path / '.env'
234+
dotenv_file.touch()
235+
sh.cd(str(tmp_path))
236+
dotenv.set_key(str(dotenv_file), 'FOO', 'BAR')
237+
result = sh.dotenv('run', 'printenv', 'FOO').strip()
238+
assert result == 'BAR'
239+
240+
241+
def test_run_with_other_env(tmp_path):
242+
dotenv_name = 'dotenv'
243+
dotenv_file = tmp_path / dotenv_name
244+
dotenv_file.touch()
245+
sh.cd(str(tmp_path))
246+
sh.dotenv('--file', dotenv_name, 'set', 'FOO', 'BAR')
247+
result = sh.dotenv('--file', dotenv_name, 'run', 'printenv', 'FOO').strip()
248+
assert result == 'BAR'
270249

271250

272251
def test_run_without_cmd(cli):

0 commit comments

Comments
 (0)