-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(dotenv): add tests for core IO functionality
- Loading branch information
1 parent
8398fdd
commit d15114e
Showing
1 changed file
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
"""Tests for the module that contains core dotenv functionality.""" | ||
|
||
import io | ||
import os | ||
import sys | ||
import textwrap | ||
|
||
from pathlib import Path | ||
from typing import Dict | ||
from unittest import mock | ||
|
||
import sh | ||
import pytest | ||
|
||
from poetry_dotenv.dotenv import core as dotenv | ||
|
||
|
||
def prepare_file_hierarchy(path: Path): | ||
"""Create a temporary folder structure like the following. | ||
test_find_dotenv0/ | ||
└── child1 | ||
├──── child2 | ||
│ └── child3 | ||
│ └── child4 | ||
└── .env | ||
Then try to automatically ``find_dotenv`` starting in ``child4``. | ||
""" | ||
|
||
curr_dir = path | ||
dirs = [] | ||
for file in ("child1", "child2", "child3", "child4"): | ||
curr_dir /= file | ||
dirs.append(curr_dir) | ||
curr_dir.mkdir() | ||
|
||
return dirs[0], dirs[-1] | ||
|
||
|
||
def test_find_dotenv_no_file_raise(tmp_path: Path) -> None: | ||
"""Test ``find_dotenv`` function.""" | ||
|
||
*_, leaf = prepare_file_hierarchy(tmp_path) | ||
os.chdir(str(leaf)) | ||
|
||
# PT011 - IOError is the actual exception that will be raised | ||
with pytest.raises(IOError): # noqa: PT011 | ||
dotenv.find_dotenv(raise_error_if_not_found=True, usecwd=True) | ||
|
||
|
||
def test_find_dotenv_no_file_no_raise(tmp_path: Path) -> None: | ||
"""Test ``find_dotenv`` function.""" | ||
|
||
*_, leaf = prepare_file_hierarchy(tmp_path) | ||
os.chdir(str(leaf)) | ||
|
||
result = dotenv.find_dotenv(usecwd=True) | ||
|
||
assert result == "" | ||
|
||
|
||
def test_find_dotenv_found(tmp_path: Path) -> None: | ||
"""Test ``find_dotenv`` function.""" | ||
|
||
(root, leaf) = prepare_file_hierarchy(tmp_path) | ||
os.chdir(str(leaf)) | ||
dotenv_file = root / ".env" | ||
dotenv_file.write_bytes(b"TEST=test\n") | ||
|
||
result = dotenv.find_dotenv(usecwd=True) | ||
|
||
assert result == str(dotenv_file) | ||
|
||
|
||
@mock.patch.dict(os.environ, {}, clear=True) | ||
def test_load_dotenv_existing_file(dotenv_file: str) -> None: | ||
"""Test ``load_dotenv`` function.""" | ||
|
||
with open(dotenv_file, "w") as env_file: | ||
env_file.write("a=b") | ||
|
||
result = dotenv.load_dotenv(dotenv_file) | ||
|
||
assert result is True | ||
assert os.environ == {"a": "b"} | ||
|
||
|
||
@mock.patch.dict(os.environ, {"a": "c"}, clear=True) | ||
def test_load_dotenv_existing_variable_no_override(dotenv_file: str) -> None: | ||
"""Test ``load_dotenv`` function.""" | ||
|
||
with open(dotenv_file, "w") as env_file: | ||
env_file.write("a=b") | ||
|
||
result = dotenv.load_dotenv(dotenv_file) | ||
|
||
assert result is True | ||
assert os.environ == {"a": "c"} | ||
|
||
|
||
@mock.patch.dict(os.environ, {"a": "c"}, clear=True) | ||
def test_load_dotenv_existing_variable_override(dotenv_file: str) -> None: | ||
"""Test ``load_dotenv`` function.""" | ||
|
||
with open(dotenv_file, "w") as env_file: | ||
env_file.write("a=b") | ||
|
||
result = dotenv.load_dotenv(dotenv_file, override=True) | ||
|
||
assert result is True | ||
assert os.environ == {"a": "b"} | ||
|
||
|
||
@mock.patch.dict(os.environ, {"a": "c"}, clear=True) | ||
def test_load_dotenv_redefine_var_used_in_file_no_override(dotenv_file: str) -> None: | ||
"""Test ``load_dotenv`` function.""" | ||
|
||
with open(dotenv_file, "w") as env_file: | ||
env_file.write('a=b\nd="${a}"') | ||
|
||
result = dotenv.load_dotenv(dotenv_file) | ||
|
||
assert result is True | ||
assert os.environ == {"a": "c", "d": "c"} | ||
|
||
|
||
@mock.patch.dict(os.environ, {"a": "c"}, clear=True) | ||
def test_load_dotenv_redefine_var_used_in_file_with_override(dotenv_file: str) -> None: | ||
"""Test ``load_dotenv`` function.""" | ||
|
||
with open(dotenv_file, "w") as env_file: | ||
env_file.write('a=b\nd="${a}"') | ||
|
||
result = dotenv.load_dotenv(dotenv_file, override=True) | ||
|
||
assert result is True | ||
assert os.environ == {"a": "b", "d": "b"} | ||
|
||
|
||
@mock.patch.dict(os.environ, {}, clear=True) | ||
def test_load_dotenv_string_io(): | ||
"""Test ``load_dotenv`` function.""" | ||
|
||
stream = io.StringIO("a=à") | ||
|
||
result = dotenv.load_dotenv(stream=stream) | ||
|
||
assert result is True | ||
assert os.environ == {"a": "à"} | ||
|
||
|
||
@mock.patch.dict(os.environ, {}, clear=True) | ||
def test_load_dotenv_file_stream(dotenv_file: str) -> None: | ||
"""Test ``load_dotenv`` function.""" | ||
|
||
with open(dotenv_file, "w") as env_file: | ||
env_file.write("a=b") | ||
|
||
with open(dotenv_file, "r") as env_file: | ||
result = dotenv.load_dotenv(stream=env_file) | ||
|
||
assert result is True | ||
assert os.environ == {"a": "b"} | ||
|
||
|
||
def test_load_dotenv_in_current_dir(tmp_path: Path) -> None: | ||
"""Test ``load_dotenv`` function.""" | ||
|
||
dotenv_path = tmp_path / ".env" | ||
dotenv_path.write_bytes(b"a=b") | ||
code_path = tmp_path / "code.py" | ||
code_path.write_text( | ||
textwrap.dedent( # noqa: WPS462 | ||
""" | ||
from poetry_dotenv.dotenv import core as dotenv | ||
import os | ||
dotenv.load_dotenv() | ||
print(os.environ['a']) | ||
""", | ||
), | ||
) | ||
os.chdir(str(tmp_path)) | ||
|
||
result = sh.Command(sys.executable)(code_path) | ||
|
||
assert result == "b\n" | ||
|
||
code_path.unlink() | ||
|
||
|
||
def test_dotenv_values_file(dotenv_file: str) -> None: | ||
"""Test ``dotenv_values`` function.""" | ||
|
||
with open(dotenv_file, "w") as env_file: | ||
env_file.write("a=b") | ||
|
||
result = dotenv.dotenv_values(dotenv_file) | ||
|
||
assert result == {"a": "b"} | ||
|
||
|
||
def test_dotenv_values_file_stream(dotenv_file: str) -> None: | ||
"""Test ``dotenv_values`` function.""" | ||
|
||
with open(dotenv_file, "w") as env_file: | ||
env_file.write("a=b") | ||
|
||
with open(dotenv_file, "r") as env_file: | ||
result = dotenv.dotenv_values(stream=env_file) | ||
|
||
assert result == {"a": "b"} | ||
|
||
|
||
@pytest.mark.parametrize( | ||
argnames=("env", "string", "interpolate", "expected"), | ||
argvalues=[ | ||
({"b": "c"}, "a=$b", False, {"a": "$b"}), | ||
({"b": "c"}, "a=$b", True, {"a": "$b"}), | ||
({"b": "c"}, "a=${b}", False, {"a": "${b}"}), | ||
({"b": "c"}, "a=${b}", True, {"a": "c"}), | ||
({"b": "c"}, "a=${b:-d}", False, {"a": "${b:-d}"}), | ||
({"b": "c"}, "a=${b:-d}", True, {"a": "c"}), | ||
({}, "b=c\na=${b}", True, {"a": "c", "b": "c"}), | ||
({}, "a=${b}", True, {"a": ""}), | ||
({}, "a=${b:-d}", True, {"a": "d"}), | ||
({"b": "c"}, 'a="${b}"', True, {"a": "c"}), | ||
({"b": "c"}, "a='${b}'", True, {"a": "c"}), | ||
({"b": "c"}, "a=x${b}y", True, {"a": "xcy"}), | ||
({"a": "b"}, "a=${a}", True, {"a": "b"}), | ||
({}, "a=${a}", True, {"a": ""}), | ||
({"a": "b"}, "a=${a:-c}", True, {"a": "b"}), | ||
({}, "a=${a:-c}", True, {"a": "c"}), | ||
({"b": "c"}, "a=${b}${b}", True, {"a": "cc"}), | ||
({"b": "c"}, "b=d\na=${b}", True, {"a": "d", "b": "d"}), | ||
({}, "a=b\na=c\nd=${a}", True, {"a": "c", "d": "c"}), | ||
({}, "a=b\nc=${a}\nd=e\nc=${d}", True, {"a": "b", "c": "e", "d": "e"}), | ||
], | ||
) | ||
def test_dotenv_values_string_io( | ||
env: Dict[str, str], | ||
string: str, | ||
interpolate: bool, | ||
expected: Dict[str, str], | ||
) -> None: | ||
"""Test ``dotenv_values`` function.""" | ||
|
||
with mock.patch.dict(os.environ, env, clear=True): | ||
stream = io.StringIO(string) | ||
stream.seek(0) | ||
|
||
result = dotenv.dotenv_values(stream=stream, interpolate=interpolate) | ||
|
||
assert result == expected |