summaryrefslogtreecommitdiff
path: root/tests/helper_test.py
diff options
context:
space:
mode:
authorLucas Hoffmann <lucc@posteo.de>2018-12-21 00:33:19 +0100
committerLucas Hoffmann <lucc@posteo.de>2019-01-29 00:31:03 +0100
commit7f0a1b8cdd492917f84f90cade28cefa0a37c3e0 (patch)
tree84fc17675a16fba219d56c0c17b5c0183086e64a /tests/helper_test.py
parentfd1348329b8697d9bb014e7d61560f3421d29e46 (diff)
Rename test files
The two main reasons are - to run `python3 -m unittest discover` without specifying a custom `--pattern *_test.py` - to include the test files automatically when generating the MANIFEST file.
Diffstat (limited to 'tests/helper_test.py')
-rw-r--r--tests/helper_test.py473
1 files changed, 0 insertions, 473 deletions
diff --git a/tests/helper_test.py b/tests/helper_test.py
deleted file mode 100644
index 2aff842d..00000000
--- a/tests/helper_test.py
+++ /dev/null
@@ -1,473 +0,0 @@
-# encoding=utf-8
-# Copyright © 2016-2018 Dylan Baker
-# Copyright © 2017 Lucas Hoffman
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-"""Test suite for alot.helper module."""
-
-import datetime
-import email
-import errno
-import os
-import random
-import unittest
-
-import mock
-
-from alot import helper
-
-from . import utilities
-
-# Descriptive names for tests often violate PEP8. That's not an issue, users
-# aren't meant to call these functions.
-# pylint: disable=invalid-name
-
-# They're tests, only add docstrings when it makes sense
-# pylint: disable=missing-docstring
-
-
-class TestHelperShortenAuthorString(unittest.TestCase):
-
- authors = u'King Kong, Mucho Muchacho, Jaime Huerta, Flash Gordon'
-
- def test_high_maxlength_keeps_string_intact(self):
- short = helper.shorten_author_string(self.authors, 60)
- self.assertEqual(short, self.authors)
-
- def test_shows_only_first_names_if_they_fit(self):
- short = helper.shorten_author_string(self.authors, 40)
- self.assertEqual(short, u"King, Mucho, Jaime, Flash")
-
- def test_adds_ellipses_to_long_first_names(self):
- short = helper.shorten_author_string(self.authors, 20)
- self.assertEqual(short, u"King, …, Jai…, Flash")
-
- def test_replace_all_but_first_name_with_ellipses(self):
- short = helper.shorten_author_string(self.authors, 10)
- self.assertEqual(short, u"King, …")
-
- def test_shorten_first_name_with_ellipses(self):
- short = helper.shorten_author_string(self.authors, 2)
- self.assertEqual(short, u"K…")
-
- def test_only_display_initial_letter_for_maxlength_1(self):
- short = helper.shorten_author_string(self.authors, 1)
- self.assertEqual(short, u"K")
-
-
-class TestShellQuote(unittest.TestCase):
-
- def test_all_strings_are_sourrounded_by_single_quotes(self):
- quoted = helper.shell_quote("hello")
- self.assertEqual(quoted, "'hello'")
-
- def test_single_quotes_are_escaped_using_double_quotes(self):
- quoted = helper.shell_quote("hello'there")
- self.assertEqual(quoted, """'hello'"'"'there'""")
-
-
-class TestHumanizeSize(unittest.TestCase):
-
- def test_small_numbers_are_converted_to_strings_directly(self):
- readable = helper.humanize_size(1)
- self.assertEqual(readable, "1")
- readable = helper.humanize_size(123)
- self.assertEqual(readable, "123")
-
- def test_numbers_above_1024_are_converted_to_kilobyte(self):
- readable = helper.humanize_size(1023)
- self.assertEqual(readable, "1023")
- readable = helper.humanize_size(1024)
- self.assertEqual(readable, "1KiB")
- readable = helper.humanize_size(1234)
- self.assertEqual(readable, "1KiB")
-
- def test_numbers_above_1048576_are_converted_to_megabyte(self):
- readable = helper.humanize_size(1024*1024-1)
- self.assertEqual(readable, "1023KiB")
- readable = helper.humanize_size(1024*1024)
- self.assertEqual(readable, "1.0MiB")
-
- def test_megabyte_numbers_are_converted_with_precision_1(self):
- readable = helper.humanize_size(1234*1024)
- self.assertEqual(readable, "1.2MiB")
-
- def test_numbers_are_not_converted_to_gigabyte(self):
- readable = helper.humanize_size(1234*1024*1024)
- self.assertEqual(readable, "1234.0MiB")
-
-
-class TestSplitCommandline(unittest.TestCase):
-
- def _test(self, base, expected):
- """Shared helper to reduce some boilerplate."""
- actual = helper.split_commandline(base)
- self.assertListEqual(actual, expected)
-
- def test_simple(self):
- base = 'echo "foo";sleep 1'
- expected = ['echo "foo"', 'sleep 1']
- self._test(base, expected)
-
- def test_single(self):
- base = 'echo "foo bar"'
- expected = [base]
- self._test(base, expected)
-
- def test_unicode(self):
- base = u'echo "foo";sleep 1'
- expected = ['echo "foo"', 'sleep 1']
- self._test(base, expected)
-
-
-class TestSplitCommandstring(unittest.TestCase):
-
- def _test(self, base, expected):
- """Shared helper to reduce some boilerplate."""
- actual = helper.split_commandstring(base)
- self.assertListEqual(actual, expected)
-
- def test_bytes(self):
- base = 'echo "foo bar"'
- expected = ['echo', 'foo bar']
- self._test(base, expected)
-
- def test_unicode(self):
- base = 'echo "foo €"'
- expected = ['echo', 'foo €']
- self._test(base, expected)
-
-
-class TestStringSanitize(unittest.TestCase):
-
- def test_tabs(self):
- base = 'foo\tbar\noink\n'
- expected = 'foo' + ' ' * 5 + 'bar\noink\n'
- actual = helper.string_sanitize(base)
- self.assertEqual(actual, expected)
-
-
-class TestStringDecode(unittest.TestCase):
-
- def _test(self, base, expected, encoding='ascii'):
- actual = helper.string_decode(base, encoding)
- self.assertEqual(actual, expected)
-
- def test_ascii_bytes(self):
- base = u'test'.encode('ascii')
- expected = u'test'
- self._test(base, expected)
-
- def test_utf8_bytes(self):
- base = u'test'.encode('utf-8')
- expected = u'test'
- self._test(base, expected, 'utf-8')
-
- def test_unicode(self):
- base = u'test'
- expected = u'test'
- self._test(base, expected)
-
-
-class TestPrettyDatetime(unittest.TestCase):
-
- # TODO: Currently these tests use the ampm format based on whether or not
- # the testing machine's locale sets them. To be really good mock should be
- # used to change the locale between an am/pm locale and a 24 hour locale
- # and test both scenarios.
-
- __patchers = []
-
- @classmethod
- def setUpClass(cls):
- # Create a random number generator, but seed it so that it will produce
- # deterministic output. This is used to select a subset of possible
- # values for each of the tests in this class, since otherwise they
- # would get really expensive (time wise).
- cls.random = random.Random()
- cls.random.seed(42)
-
- # Pick an exact date to ensure that the tests run the same no matter
- # what time of day they're run.
- cls.now = datetime.datetime(2000, 1, 5, 12, 0, 0, 0)
-
- # Mock datetime.now, which ensures that the time is always the same
- # removing race conditions from the tests.
- dt = mock.Mock()
- dt.now = mock.Mock(return_value=cls.now)
- cls.__patchers.append(mock.patch('alot.helper.datetime', dt))
-
- for p in cls.__patchers:
- p.start()
-
- @classmethod
- def tearDownClass(cls):
- for p in cls.__patchers:
- p.stop()
-
- def test_just_now(self):
- for i in (self.random.randint(0, 60) for _ in range(5)):
- test = self.now - datetime.timedelta(seconds=i)
- actual = helper.pretty_datetime(test)
- self.assertEqual(actual, u'just now')
-
- def test_x_minutes_ago(self):
- for i in (self.random.randint(60, 3600) for _ in range(10)):
- test = self.now - datetime.timedelta(seconds=i)
- actual = helper.pretty_datetime(test)
- self.assertEqual(
- actual, u'{}min ago'.format((self.now - test).seconds // 60))
-
- def test_x_hours_ago(self):
- for i in (self.random.randint(3600, 3600 * 6) for _ in range(10)):
- test = self.now - datetime.timedelta(seconds=i)
- actual = helper.pretty_datetime(test)
- self.assertEqual(
- actual, u'{}h ago'.format((self.now - test).seconds // 3600))
-
- # TODO: yesterday
- # TODO: yesterday > now > a year
- # TODO: last year
- # XXX: when can the last else be hit?
-
- @staticmethod
- def _future_expected(test):
- if test.strftime('%p'):
- expected = test.strftime('%I:%M%p').lower()
- else:
- expected = test.strftime('%H:%M')
- expected = expected
- return expected
-
- def test_future_seconds(self):
- test = self.now + datetime.timedelta(seconds=30)
- actual = helper.pretty_datetime(test)
- expected = self._future_expected(test)
- self.assertEqual(actual, expected)
-
- # Returns 'just now', instead of 'from future' or something similar
- @unittest.expectedFailure
- def test_future_minutes(self):
- test = self.now + datetime.timedelta(minutes=5)
- actual = helper.pretty_datetime(test)
- expected = test.strftime('%a ') + self._future_expected(test)
- self.assertEqual(actual, expected)
-
- # Returns 'just now', instead of 'from future' or something similar
- @unittest.expectedFailure
- def test_future_hours(self):
- test = self.now + datetime.timedelta(hours=1)
- actual = helper.pretty_datetime(test)
- expected = test.strftime('%a ') + self._future_expected(test)
- self.assertEqual(actual, expected)
-
- # Returns 'just now', instead of 'from future' or something similar
- @unittest.expectedFailure
- def test_future_days(self):
- def make_expected():
- # Uses the hourfmt instead of the hourminfmt from pretty_datetime
- if test.strftime('%p'):
- expected = test.strftime('%I%p')
- else:
- expected = test.strftime('%Hh')
- expected = expected.decode('utf-8')
- return expected
-
- test = self.now + datetime.timedelta(days=1)
- actual = helper.pretty_datetime(test)
- expected = test.strftime('%a ') + make_expected()
- self.assertEqual(actual, expected)
-
- # Returns 'just now', instead of 'from future' or something similar
- @unittest.expectedFailure
- def test_future_week(self):
- test = self.now + datetime.timedelta(days=7)
- actual = helper.pretty_datetime(test)
- expected = test.strftime('%b %d')
- self.assertEqual(actual, expected)
-
- # Returns 'just now', instead of 'from future' or something similar
- @unittest.expectedFailure
- def test_future_month(self):
- test = self.now + datetime.timedelta(days=31)
- actual = helper.pretty_datetime(test)
- expected = test.strftime('%b %d')
- self.assertEqual(actual, expected)
-
- # Returns 'just now', instead of 'from future' or something similar
- @unittest.expectedFailure
- def test_future_year(self):
- test = self.now + datetime.timedelta(days=365)
- actual = helper.pretty_datetime(test)
- expected = test.strftime('%b %Y')
- self.assertEqual(actual, expected)
-
-
-class TestCallCmd(unittest.TestCase):
- """Tests for the call_cmd function."""
-
- def test_no_stdin(self):
- out, err, code = helper.call_cmd(['echo', '-n', 'foo'])
- self.assertEqual(out, u'foo')
- self.assertEqual(err, u'')
- self.assertEqual(code, 0)
-
- def test_no_stdin_unicode(self):
- out, err, code = helper.call_cmd(['echo', '-n', '�'])
- self.assertEqual(out, u'�')
- self.assertEqual(err, u'')
- self.assertEqual(code, 0)
-
- def test_stdin(self):
- out, err, code = helper.call_cmd(['cat'], stdin='�')
- self.assertEqual(out, u'�')
- self.assertEqual(err, u'')
- self.assertEqual(code, 0)
-
- def test_no_such_command(self):
- out, err, code = helper.call_cmd(['thiscommandabsolutelydoesntexist'])
- self.assertEqual(out, u'')
-
- # We don't control the output of err, the shell does. Therefore simply
- # assert that the shell said *something*
- self.assertNotEqual(err, u'')
- self.assertEqual(code, errno.ENOENT)
-
- def test_no_such_command_stdin(self):
- out, err, code = helper.call_cmd(['thiscommandabsolutelydoesntexist'],
- stdin='foo')
- self.assertEqual(out, u'')
-
- # We don't control the output of err, the shell does. Therefore simply
- # assert that the shell said *something*
- self.assertNotEqual(err, u'')
- self.assertEqual(code, errno.ENOENT)
-
- def test_bad_argument_stdin(self):
- out, err, code = helper.call_cmd(['cat', '-Y'], stdin='�')
- self.assertEqual(out, u'')
- self.assertNotEqual(err, u'')
-
- # We don't control this, although 1 might be a fairly safe guess, we
- # know for certain it should *not* return 0
- self.assertNotEqual(code, 0)
-
- def test_bad_argument(self):
- out, err, code = helper.call_cmd(['cat', '-Y'])
- self.assertEqual(out, u'')
- self.assertNotEqual(err, u'')
-
- # We don't control this, although 1 might be a fairly safe guess, we
- # know for certain it should *not* return 0
- self.assertNotEqual(code, 0)
-
- def test_os_errors_from_popen_are_caught(self):
- with mock.patch('subprocess.Popen',
- mock.Mock(side_effect=OSError(42, u'foobar'))):
- out, err, code = helper.call_cmd(
- ['does_not_matter_as_subprocess_popen_is_mocked'])
- self.assertEqual(out, u'')
- self.assertEqual(err, u'foobar')
- self.assertEqual(code, 42)
-
-
-class TestShorten(unittest.TestCase):
-
- def test_lt_maxlen(self):
- expected = u'a string'
- actual = helper.shorten(expected, 25)
- self.assertEqual(expected, actual)
-
- def test_eq_maxlen(self):
- expected = 'a string'
- actual = helper.shorten(expected, len(expected))
- self.assertEqual(expected, actual)
-
- def test_gt_maxlen(self):
- expected = u'a long string…'
- actual = helper.shorten('a long string that is full of text', 14)
- self.assertEqual(expected, actual)
-
-
-class TestCallCmdAsync(unittest.TestCase):
-
- @utilities.async_test
- async def test_no_stdin(self):
- ret = await helper.call_cmd_async(['echo', '-n', 'foo'])
- self.assertEqual(ret[0], 'foo')
-
- @utilities.async_test
- async def test_stdin(self):
- ret = await helper.call_cmd_async(['cat', '-'], stdin='foo')
- self.assertEqual(ret[0], 'foo')
-
- @utilities.async_test
- async def test_env_set(self):
- with mock.patch.dict(os.environ, {}, clear=True):
- ret = await helper.call_cmd_async(
- ['python3', '-c', 'import os; '
- 'print(os.environ.get("foo", "fail"), end="")'
- ],
- env={'foo': 'bar'})
- self.assertEqual(ret[0], 'bar')
-
- @utilities.async_test
- async def test_env_doesnt_pollute(self):
- with mock.patch.dict(os.environ, {}, clear=True):
- await helper.call_cmd_async(['echo', '-n', 'foo'],
- env={'foo': 'bar'})
- self.assertEqual(os.environ, {})
-
- @utilities.async_test
- async def test_command_fails(self):
- _, err, ret = await helper.call_cmd_async(['_____better_not_exist'])
- self.assertEqual(ret, 1)
- self.assertTrue(err)
-
-
-class TestGetEnv(unittest.TestCase):
- env_name = 'XDG_CONFIG_HOME'
- default = '~/.config'
-
- def test_env_not_set(self):
- with mock.patch.dict('os.environ'):
- if self.env_name in os.environ:
- del os.environ[self.env_name]
- self.assertEqual(helper.get_xdg_env(self.env_name, self.default),
- self.default)
-
- def test_env_empty(self):
- with mock.patch.dict('os.environ', {self.env_name: ''}):
- self.assertEqual(helper.get_xdg_env(self.env_name, self.default),
- self.default)
-
- def test_env_not_empty(self):
- custom_path = '/my/personal/config/home'
-
- with mock.patch.dict('os.environ', {self.env_name: custom_path}):
- self.assertEqual(helper.get_xdg_env(self.env_name, self.default),
- custom_path)
-
-
-class TestParseMailto(unittest.TestCase):
-
- def test_parsing_working(self):
- uri = 'mailto:test%40example.org?Subject=Re%3A%20Hello\
-&In-Reply-To=%3CC8CE9EFD-CB23-4BC0-B70D-9B7FEAD59F8C%40example.org%3E'
- actual = helper.parse_mailto(uri)
- expected = ({'To': ['test@example.org'],
- 'Subject': ['Re: Hello'],
- 'In-reply-to': ['<C8CE9EFD-CB23-4BC0-B70D-9B7FEAD59F8C@example.org>']}, '')
- self.assertEqual(actual, expected)