From 481ff2df702f0e99efdbe70b70089b858c101a49 Mon Sep 17 00:00:00 2001 From: Guillermo Date: Mon, 24 Aug 2026 10:57:49 +0200 Subject: [PATCH] test: pin the contents kept when a symlinked .env is replaced The six existing symlink tests all pass against an implementation that keeps the contents the path resolved to and against one that discards them, so neither behaviour is currently pinned. test_set_key_symlink_to_existing_file uses a target holding the same key that is then set, and asserts with a substring, so any prior contents are overwritten by the set and invisible either way. test_unset_key_symlink_to_existing_file has a target holding only the key that is then unset, so the result is "" whether the previous contents were read or not. Adds two tests whose targets hold a key the operation does not touch, so the kept contents are asserted exactly. No existing test is modified and no behaviour changes. --- tests/test_main.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/test_main.py b/tests/test_main.py index 6f9d4c5c..90926985 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -172,6 +172,24 @@ def test_set_key_follow_symlinks(tmp_path): assert symlink.is_symlink() +@pytest.mark.skipif( + sys.platform == "win32", reason="symlinks require elevated privileges on Windows" +) +def test_set_key_symlink_keeps_target_contents(tmp_path): + # The target holds a key the set does not touch, so losing the contents the + # path resolved to would show up here. + target = tmp_path / "target.env" + target.write_text("b=x\n") + symlink = tmp_path / ".env" + symlink.symlink_to(target) + + dotenv.set_key(symlink, "a", "y") + + assert target.read_text() == "b=x\n" + assert not symlink.is_symlink() + assert symlink.read_text() == "b=x\na='y'\n" + + @pytest.mark.skipif( sys.platform != "win32" and os.geteuid() == 0, reason="Root user can access files even with 000 permissions.", @@ -365,6 +383,24 @@ def test_unset_key_follow_symlinks(tmp_path): assert symlink.is_symlink() +@pytest.mark.skipif( + sys.platform == "win32", reason="symlinks require elevated privileges on Windows" +) +def test_unset_key_symlink_keeps_target_contents(tmp_path): + # The target holds a second key the unset does not touch, so losing the + # contents the path resolved to would show up here. + target = tmp_path / "target.env" + target.write_text("a=x\nb=y\n") + symlink = tmp_path / ".env" + symlink.symlink_to(target) + + dotenv.unset_key(symlink, "a") + + assert target.read_text() == "a=x\nb=y\n" + assert not symlink.is_symlink() + assert symlink.read_text() == "b=y\n" + + def prepare_file_hierarchy(path): """ Create a temporary folder structure like the following: