diff options
-rw-r--r-- | alot/helper.py | 4 | ||||
-rw-r--r-- | tests/helper_test.py | 78 | ||||
-rw-r--r-- | tests/utilities.py | 10 |
3 files changed, 82 insertions, 10 deletions
diff --git a/alot/helper.py b/alot/helper.py index 1c569a23..26787fa8 100644 --- a/alot/helper.py +++ b/alot/helper.py @@ -129,7 +129,7 @@ def string_decode(string, enc='ascii'): def shorten(string, maxlen): """shortens string if longer than maxlen, appending ellipsis""" if 1 < maxlen < len(string): - string = string[:maxlen - 1] + u'\u2026' + string = string[:maxlen - 1] + u'…' return string[:maxlen] @@ -333,7 +333,7 @@ def call_cmd_async(cmdlist, stdin=None, env=None): self.deferred.errback(terminated_obj) d = Deferred() - environment = os.environ + environment = os.environ.copy() if env is not None: environment.update(env) logging.debug('ENV = %s', environment) diff --git a/tests/helper_test.py b/tests/helper_test.py index 62e37ed8..c2927725 100644 --- a/tests/helper_test.py +++ b/tests/helper_test.py @@ -18,17 +18,21 @@ """Test suite for alot.helper module.""" from __future__ import absolute_import - import datetime import email import errno +import os import random -import unittest import mock +from twisted.trial import unittest +from twisted.internet.defer import inlineCallbacks +from twisted.internet.error import ProcessTerminated 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 @@ -257,7 +261,7 @@ class TestPrettyDatetime(unittest.TestCase): self.assertEqual(actual, expected) # Returns 'just now', instead of 'from future' or something similar - @unittest.expectedFailure + @utilities.expected_failure def test_future_minutes(self): test = self.now + datetime.timedelta(minutes=5) actual = helper.pretty_datetime(test) @@ -265,7 +269,7 @@ class TestPrettyDatetime(unittest.TestCase): self.assertEqual(actual, expected) # Returns 'just now', instead of 'from future' or something similar - @unittest.expectedFailure + @utilities.expected_failure def test_future_hours(self): test = self.now + datetime.timedelta(hours=1) actual = helper.pretty_datetime(test) @@ -273,7 +277,7 @@ class TestPrettyDatetime(unittest.TestCase): self.assertEqual(actual, expected) # Returns 'just now', instead of 'from future' or something similar - @unittest.expectedFailure + @utilities.expected_failure def test_future_days(self): def make_expected(): # Uses the hourfmt instead of the hourminfmt from pretty_datetime @@ -290,7 +294,7 @@ class TestPrettyDatetime(unittest.TestCase): self.assertEqual(actual, expected) # Returns 'just now', instead of 'from future' or something similar - @unittest.expectedFailure + @utilities.expected_failure def test_future_week(self): test = self.now + datetime.timedelta(days=7) actual = helper.pretty_datetime(test) @@ -298,7 +302,7 @@ class TestPrettyDatetime(unittest.TestCase): self.assertEqual(actual, expected) # Returns 'just now', instead of 'from future' or something similar - @unittest.expectedFailure + @utilities.expected_failure def test_future_month(self): test = self.now + datetime.timedelta(days=31) actual = helper.pretty_datetime(test) @@ -306,7 +310,7 @@ class TestPrettyDatetime(unittest.TestCase): self.assertEqual(actual, expected) # Returns 'just now', instead of 'from future' or something similar - @unittest.expectedFailure + @utilities.expected_failure def test_future_year(self): test = self.now + datetime.timedelta(days=365) actual = helper.pretty_datetime(test) @@ -402,3 +406,61 @@ class TestEmailAsString(unittest.TestCase): actual = helper.email_as_string(message) expected = 'X-Unicode-Header: dummy value\r\n\r\n' self.assertEqual(actual, expected) + + +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): + + @inlineCallbacks + def test_no_stdin(self): + ret = yield helper.call_cmd_async(['echo', '-n', 'foo']) + self.assertEqual(ret, 'foo') + + @inlineCallbacks + def test_stdin(self): + ret = yield helper.call_cmd_async(['cat', '-'], stdin='foo') + self.assertEqual(ret, 'foo') + + @inlineCallbacks + def test_env_set(self): + with mock.patch.dict(os.environ, {}, clear=True): + ret = yield helper.call_cmd_async( + # Thanks to the future import it doesn't matter if python is + # python2 or python3 + ['python', '-c', 'from __future__ import print_function; ' + 'import os; ' + 'print(os.environ.get("foo", "fail"), end="")' + ], + env={'foo': 'bar'}) + self.assertEqual(ret, 'bar') + + @inlineCallbacks + def test_env_doesnt_pollute(self): + with mock.patch.dict(os.environ, {}, clear=True): + yield helper.call_cmd_async(['echo', '-n', 'foo'], + env={'foo': 'bar'}) + self.assertEqual(os.environ, {}) + + @inlineCallbacks + def test_command_fails(self): + with self.assertRaises(ProcessTerminated) as cm: + yield helper.call_cmd_async(['_____better_not_exist']) + self.assertEqual(cm.exception.exitCode, 1) + self.assertTrue(cm.exception.stderr) diff --git a/tests/utilities.py b/tests/utilities.py index 402feb38..8123afd8 100644 --- a/tests/utilities.py +++ b/tests/utilities.py @@ -171,3 +171,13 @@ def make_key(revoked=False, expired=False, invalid=False, can_encrypt=True, mock_key.can_sign = can_sign return mock_key + + +def expected_failure(func): + """For marking expected failures for twisted.trial based unit tests. + + The builtin unittest.expectedFailure does not work with twisted.trail, + there is an outstanding bug for this, but no one has ever fixed it. + """ + func.todo = 'expected failure' + return func |