import importlib.util import io import os from pathlib import Path import tempfile import unittest from unittest.mock import patch MODULE_PATH = Path(__file__).resolve().parents[1] / "scripts" / "env_config.py" SPEC = importlib.util.spec_from_file_location("env_config", MODULE_PATH) env_config = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(env_config) class EnvironmentConfigTests(unittest.TestCase): def setUp(self): self.directory = tempfile.TemporaryDirectory() self.addCleanup(self.directory.cleanup) self.path = Path(self.directory.name) / ".env" def load(self, contents, current=None): self.path.write_text(contents, encoding="utf-8") return env_config.load_environment(self.path, current or {}) def test_current_environment_wins_including_empty_values(self): current = {"VALUE": "from-environment", "EMPTY": "", "EXTRA": "kept"} result = self.load("VALUE=from-file\nEMPTY=from-file\nFILE_ONLY=yes", current) self.assertEqual( result, {"VALUE": "from-environment", "EMPTY": "", "EXTRA": "kept", "FILE_ONLY": "yes"}, ) self.assertEqual(current, {"VALUE": "from-environment", "EMPTY": "", "EXTRA": "kept"}) self.assertIsNot(result, current) def test_missing_file_returns_a_copy_of_current_environment(self): current = {"VALUE": "present", "EMPTY": ""} result = env_config.load_environment(self.path, current) self.assertEqual(result, current) self.assertIsNot(result, current) def test_blank_lines_comments_export_and_quotes(self): result = self.load( "\n \t\n # comment\n FIRST=one\n\texport SECOND='two words'\n" 'THIRD="three words" \nEMPTY=\nEMPTY_QUOTED=\'\'\n' ) self.assertEqual( result, {"FIRST": "one", "SECOND": "two words", "THIRD": "three words", "EMPTY": "", "EMPTY_QUOTED": ""}, ) def test_special_characters_remain_literal(self): value = r"$NAME:${NAME}:#part=a=b:C:\folder\file\n" self.assertEqual(self.load(f"VALUE={value}\n"), {"VALUE": value}) self.assertEqual(self.load(f"VALUE='{value}'\n"), {"VALUE": value}) self.assertEqual(self.load(f'VALUE="{value}"\n'), {"VALUE": value}) def test_unquoted_whitespace_and_inline_hash_are_preserved(self): value = " value # still part of the value \t " self.assertEqual(self.load(f"VALUE={value}\n"), {"VALUE": value}) def test_commands_are_not_executed(self): marker = Path(self.directory.name) / "should-not-exist" value = f"$(touch {marker}) `touch {marker}` $HOME ${{HOME}}" self.assertEqual(self.load(f"VALUE={value}\n"), {"VALUE": value}) self.assertFalse(marker.exists()) def test_last_file_assignment_wins(self): self.assertEqual(self.load("VALUE=first\nVALUE=last\n"), {"VALUE": "last"}) def test_crlf_line_endings(self): self.path.write_bytes(b"FIRST=one\r\nSECOND=two\r\n") self.assertEqual(env_config.load_environment(self.path, {}), {"FIRST": "one", "SECOND": "two"}) def test_invalid_syntax_only_reports_line_number(self): for invalid in ( "secret-without-an-assignment", "1INVALID=private-value", "INVALID-KEY=private-value", "INVALID KEY=private-value", "=private-value", "export VALUE", "VALUE='private-value", 'VALUE="private-value', "VALUE='", 'VALUE="', "VALUE='private-value' trailing-text", "VALUE=private\x00value", "# private\x00value", "VALUE=private\rvalue", ): with self.subTest(invalid=invalid): with self.assertRaises(ValueError) as caught: self.load(f"VALID=ok\n{invalid}\n") self.assertEqual(str(caught.exception), "Invalid .env syntax at line 2") def test_invalid_encoding_only_reports_line_number(self): self.path.write_bytes(b"VALID=ok\nVALUE=private\xffvalue\n") with self.assertRaises(ValueError) as caught: env_config.load_environment(self.path, {}) self.assertEqual(str(caught.exception), "Invalid .env syntax at line 2") self.assertTrue(caught.exception.__suppress_context__) def test_invalid_file_is_validated_even_when_current_has_the_key(self): with self.assertRaisesRegex(ValueError, r"^Invalid \.env syntax at line 1$"): self.load("VALUE='unterminated", {"VALUE": "current"}) class EnvironmentCommandTests(unittest.TestCase): def test_command_executes_with_environment_and_literal_arguments(self): current = {"EXISTING": "present", "EMPTY": ""} environment = {**current, "FROM_FILE": "loaded"} command = ["./mvnw", "test", "literal $HOME ; $(command) `command`"] original_directory = Path.cwd() with ( patch.dict(os.environ, current, clear=True), patch.object(env_config, "load_environment", return_value=environment) as load, patch.object(env_config.os, "execvpe") as execute, ): self.assertEqual(env_config.main(command), 0) load.assert_called_once_with(MODULE_PATH.parents[1] / ".env", current) execute.assert_called_once_with(command[0], command, environment) self.assertEqual(Path.cwd(), original_directory) def test_help_and_missing_command_do_not_load_or_execute(self): for arguments, status, stream in (([], 2, "stderr"), (["--help"], 0, "stdout"), (["-h"], 0, "stdout")): with ( self.subTest(arguments=arguments), patch.object(env_config, "load_environment") as load, patch.object(env_config.os, "execvpe") as execute, patch.object(env_config.sys, stream, new_callable=io.StringIO) as output, ): self.assertEqual(env_config.main(arguments), status) self.assertIn("COMMAND [ARGS...]", output.getvalue()) load.assert_not_called() execute.assert_not_called() def test_invalid_file_reports_only_safe_line_number(self): with ( patch.object(env_config, "load_environment", side_effect=ValueError("Invalid .env syntax at line 7")), patch.object(env_config.os, "execvpe") as execute, patch.object(env_config.sys, "stderr", new_callable=io.StringIO) as output, ): self.assertEqual(env_config.main(["command"]), 1) self.assertEqual(output.getvalue(), "Invalid .env syntax at line 7\n") execute.assert_not_called() def test_unexpected_value_error_is_sanitized(self): with ( patch.object(env_config, "load_environment", side_effect=ValueError("private-value")), patch.object(env_config.sys, "stderr", new_callable=io.StringIO) as output, ): self.assertEqual(env_config.main(["command"]), 1) self.assertEqual(output.getvalue(), "Invalid .env syntax.\n") def test_read_error_is_sanitized(self): with ( patch.object(env_config, "load_environment", side_effect=OSError("private-value")), patch.object(env_config.os, "execvpe") as execute, patch.object(env_config.sys, "stderr", new_callable=io.StringIO) as output, ): self.assertEqual(env_config.main(["command"]), 1) self.assertEqual(output.getvalue(), "Unable to read .env.\n") execute.assert_not_called() def test_execution_error_is_sanitized(self): with ( patch.object(env_config, "load_environment", return_value={}), patch.object(env_config.os, "execvpe", side_effect=OSError("private-value")), patch.object(env_config.sys, "stderr", new_callable=io.StringIO) as output, ): self.assertEqual(env_config.main(["private-command", "private-value"]), 1) self.assertEqual(output.getvalue(), "Unable to start command.\n") if __name__ == "__main__": unittest.main()