|
| 1 | +import os |
| 2 | +import unittest |
| 3 | +import warnings |
| 4 | + |
| 5 | +from dotenv import parse_dotenv, read_dotenv |
| 6 | + |
| 7 | + |
| 8 | +class ParseDotenvTestCase(unittest.TestCase): |
| 9 | + def test_parses_unquoted_values(self): |
| 10 | + self.assertEqual(parse_dotenv('FOO=bar'), {'FOO': 'bar'}) |
| 11 | + |
| 12 | + def test_parses_values_with_spaces_around_equal_sign(self): |
| 13 | + self.assertEqual(parse_dotenv('FOO =bar'), {'FOO': 'bar'}) |
| 14 | + self.assertEqual(parse_dotenv('FOO= bar'), {'FOO': 'bar'}) |
| 15 | + |
| 16 | + def test_parses_double_quoted_values(self): |
| 17 | + self.assertEqual(parse_dotenv('FOO="bar"'), {'FOO': 'bar'}) |
| 18 | + |
| 19 | + def test_parses_single_quoted_values(self): |
| 20 | + self.assertEqual(parse_dotenv("FOO='bar'"), {'FOO': 'bar'}) |
| 21 | + |
| 22 | + def test_parses_escaped_double_quotes(self): |
| 23 | + self.assertEqual(parse_dotenv('FOO="escaped\"bar"'), {'FOO': 'escaped"bar'}) |
| 24 | + |
| 25 | + def test_parses_empty_values(self): |
| 26 | + self.assertEqual(parse_dotenv('FOO='), {'FOO': ''}) |
| 27 | + |
| 28 | + def test_expands_variables_found_in_values(self): |
| 29 | + self.assertEqual(parse_dotenv("FOO=test\nBAR=$FOO"), {'FOO': 'test', 'BAR': 'test'}) |
| 30 | + |
| 31 | + def test_expands_variables_wrapped_in_brackets(self): |
| 32 | + self.assertEqual(parse_dotenv("FOO=test\nBAR=${FOO}bar"), {'FOO': 'test', 'BAR': 'testbar'}) |
| 33 | + |
| 34 | + def test_expands_variables_from_environ_if_not_found_in_local_env(self): |
| 35 | + os.environ.setdefault('FOO', 'test') |
| 36 | + self.assertEqual(parse_dotenv('BAR=$FOO'), {'BAR': 'test'}) |
| 37 | + |
| 38 | + def test_expands_undefined_variables_to_an_empty_string(self): |
| 39 | + self.assertEqual(parse_dotenv('BAR=$FOO'), {'BAR': ''}) |
| 40 | + |
| 41 | + def test_expands_variables_in_double_quoted_values(self): |
| 42 | + self.assertEqual(parse_dotenv("FOO=test\nBAR=\"quote $FOO\""), {'FOO': 'test', 'BAR': 'quote test'}) |
| 43 | + |
| 44 | + def test_does_not_expand_variables_in_single_quoted_values(self): |
| 45 | + self.assertEqual(parse_dotenv("BAR='quote $FOO'"), {'BAR': 'quote $FOO'}) |
| 46 | + |
| 47 | + def test_does_not_expand_escaped_variables(self): |
| 48 | + self.assertEqual(parse_dotenv('FOO="foo\\$BAR"'), {'FOO': 'foo$BAR'}) |
| 49 | + self.assertEqual(parse_dotenv('FOO="foo\${BAR}"'), {'FOO': 'foo${BAR}'}) |
| 50 | + |
| 51 | + def test_parses_export_keyword(self): |
| 52 | + self.assertEqual(parse_dotenv('export FOO=bar'), {'FOO': 'bar'}) |
| 53 | + |
| 54 | + def test_parses_key_with_dot_in_the_name(self): |
| 55 | + self.assertEqual(parse_dotenv('FOO.BAR=foobar'), {'FOO.BAR': 'foobar'}) |
| 56 | + |
| 57 | + def test_strips_unquoted_values(self): |
| 58 | + self.assertEqual(parse_dotenv('foo=bar '), {'foo': 'bar'}) # not 'bar ' |
| 59 | + |
| 60 | + def test_warns_if_line_format_is_incorrect(self): |
| 61 | + with warnings.catch_warnings(record=True) as w: |
| 62 | + parse_dotenv('lol$wut') |
| 63 | + |
| 64 | + self.assertEqual(len(w), 1) |
| 65 | + self.assertIs(w[0].category, SyntaxWarning) |
| 66 | + self.assertEqual(str(w[0].message), "Line 'lol$wut' doesn't match format") |
| 67 | + |
| 68 | + def test_ignores_empty_lines(self): |
| 69 | + self.assertEqual(parse_dotenv("\n \t \nfoo=bar\n \nfizz=buzz"), {'foo': 'bar', 'fizz': 'buzz'}) |
| 70 | + |
| 71 | + def test_ignores_inline_comments(self): |
| 72 | + self.assertEqual(parse_dotenv('foo=bar # this is foo'), {'foo': 'bar'}) |
| 73 | + |
| 74 | + def test_allows_hash_in_quoted_values(self): |
| 75 | + self.assertEqual(parse_dotenv('foo="bar#baz" # comment '), {'foo': 'bar#baz'}) |
| 76 | + |
| 77 | + def test_ignores_comment_lines(self): |
| 78 | + self.assertEqual(parse_dotenv("\n\n\n # HERE GOES FOO \nfoo=bar"), {'foo': 'bar'}) |
| 79 | + |
| 80 | + def test_parses_hash_in_quoted_values(self): |
| 81 | + self.assertEqual(parse_dotenv('foo="ba#r"'), {'foo': 'ba#r'}) |
| 82 | + self.assertEqual(parse_dotenv("foo='ba#r'"), {'foo': 'ba#r'}) |
| 83 | + |
| 84 | + |
| 85 | +class ReadDotenvTestCase(unittest.TestCase): |
| 86 | + def test_defaults_to_dotenv(self): |
| 87 | + read_dotenv() |
| 88 | + self.assertEqual(os.environ.get('DOTENV'), 'true') |
| 89 | + |
| 90 | + def test_reads_the_file(self): |
| 91 | + read_dotenv('.env') |
| 92 | + self.assertEqual(os.environ.get('DOTENV'), 'true') |
| 93 | + |
| 94 | + def test_warns_if_file_does_not_exist(self): |
| 95 | + with warnings.catch_warnings(record=True) as w: |
| 96 | + read_dotenv('.does_not_exist') |
| 97 | + |
| 98 | + self.assertEqual(len(w), 1) |
| 99 | + self.assertIs(w[0].category, UserWarning) |
| 100 | + self.assertEqual(str(w[0].message), "not reading .does_not_exist - it doesn't exist.") |
0 commit comments