##// END OF EJS Templates
Fixed tests for new i18n changes...
marcink -
r2317:c4d8ed62 beta
parent child Browse files
Show More
@@ -1,21 +1,22 b''
1 List of contributors to RhodeCode project:
1 List of contributors to RhodeCode project:
2 Marcin Kuźmiński <marcin@python-works.com>
2 Marcin Kuźmiński <marcin@python-works.com>
3 Lukasz Balcerzak <lukaszbalcerzak@gmail.com>
3 Lukasz Balcerzak <lukaszbalcerzak@gmail.com>
4 Jason Harris <jason@jasonfharris.com>
4 Jason Harris <jason@jasonfharris.com>
5 Thayne Harbaugh <thayne@fusionio.com>
5 Thayne Harbaugh <thayne@fusionio.com>
6 cejones <>
6 cejones <>
7 Thomas Waldmann <tw-public@gmx.de>
7 Thomas Waldmann <tw-public@gmx.de>
8 Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it>
8 Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it>
9 Dmitri Kuznetsov <>
9 Dmitri Kuznetsov <>
10 Jared Bunting <jared.bunting@peachjean.com>
10 Jared Bunting <jared.bunting@peachjean.com>
11 Steve Romanow <slestak989@gmail.com>
11 Steve Romanow <slestak989@gmail.com>
12 Augosto Hermann <augusto.herrmann@planejamento.gov.br>
12 Augosto Hermann <augusto.herrmann@planejamento.gov.br>
13 Ankit Solanki <ankit.solanki@gmail.com>
13 Ankit Solanki <ankit.solanki@gmail.com>
14 Liad Shani <liadff@gmail.com>
14 Liad Shani <liadff@gmail.com>
15 Les Peabody <lpeabody@gmail.com>
15 Les Peabody <lpeabody@gmail.com>
16 Jonas Oberschweiber <jonas.oberschweiber@d-velop.de>
16 Jonas Oberschweiber <jonas.oberschweiber@d-velop.de>
17 Matt Zuba <matt.zuba@goodwillaz.org>
17 Matt Zuba <matt.zuba@goodwillaz.org>
18 Aras Pranckevicius <aras@unity3d.com>
18 Aras Pranckevicius <aras@unity3d.com>
19 Tony Bussieres <t.bussieres@gmail.com>
19 Tony Bussieres <t.bussieres@gmail.com>
20 Erwin Kroon <e.kroon@smartmetersolutions.nl>
20 Erwin Kroon <e.kroon@smartmetersolutions.nl>
21 nansenat16 <nansenat16@null.tw> No newline at end of file
21 nansenat16 <nansenat16@null.tw>
22 Vincent Duvert <vincent@duvert.net> No newline at end of file
@@ -1,152 +1,152 b''
1 from rhodecode.tests import *
1 from rhodecode.tests import *
2 from rhodecode.model.db import ChangesetComment, Notification, User, \
2 from rhodecode.model.db import ChangesetComment, Notification, User, \
3 UserNotification
3 UserNotification
4
4
5
5
6 class TestChangeSetCommentsController(TestController):
6 class TestChangeSetCommentsController(TestController):
7
7
8 def setUp(self):
8 def setUp(self):
9 for x in ChangesetComment.query().all():
9 for x in ChangesetComment.query().all():
10 self.Session.delete(x)
10 self.Session.delete(x)
11 self.Session.commit()
11 self.Session.commit()
12
12
13 for x in Notification.query().all():
13 for x in Notification.query().all():
14 self.Session.delete(x)
14 self.Session.delete(x)
15 self.Session.commit()
15 self.Session.commit()
16
16
17 def tearDown(self):
17 def tearDown(self):
18 for x in ChangesetComment.query().all():
18 for x in ChangesetComment.query().all():
19 self.Session.delete(x)
19 self.Session.delete(x)
20 self.Session.commit()
20 self.Session.commit()
21
21
22 for x in Notification.query().all():
22 for x in Notification.query().all():
23 self.Session.delete(x)
23 self.Session.delete(x)
24 self.Session.commit()
24 self.Session.commit()
25
25
26 def test_create(self):
26 def test_create(self):
27 self.log_user()
27 self.log_user()
28 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
28 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
29 text = u'CommentOnRevision'
29 text = u'CommentOnRevision'
30
30
31 params = {'text': text}
31 params = {'text': text}
32 response = self.app.post(url(controller='changeset', action='comment',
32 response = self.app.post(url(controller='changeset', action='comment',
33 repo_name=HG_REPO, revision=rev),
33 repo_name=HG_REPO, revision=rev),
34 params=params)
34 params=params)
35 # Test response...
35 # Test response...
36 self.assertEqual(response.status, '302 Found')
36 self.assertEqual(response.status, '302 Found')
37 response.follow()
37 response.follow()
38
38
39 response = self.app.get(url(controller='changeset', action='index',
39 response = self.app.get(url(controller='changeset', action='index',
40 repo_name=HG_REPO, revision=rev))
40 repo_name=HG_REPO, revision=rev))
41 # test DB
41 # test DB
42 self.assertEqual(ChangesetComment.query().count(), 1)
42 self.assertEqual(ChangesetComment.query().count(), 1)
43 self.assertTrue('''<div class="comments-number">%s '''
43 response.mustcontain('''<div class="comments-number">%s comment '''
44 '''comment(s) (0 inline)</div>''' % 1 in response.body)
44 '''(0 inline)</div>''' % 1)
45
45
46 self.assertEqual(Notification.query().count(), 1)
46 self.assertEqual(Notification.query().count(), 1)
47 self.assertEqual(ChangesetComment.query().count(), 1)
47 self.assertEqual(ChangesetComment.query().count(), 1)
48
48
49 notification = Notification.query().all()[0]
49 notification = Notification.query().all()[0]
50
50
51 ID = ChangesetComment.query().first().comment_id
51 ID = ChangesetComment.query().first().comment_id
52 self.assertEqual(notification.type_,
52 self.assertEqual(notification.type_,
53 Notification.TYPE_CHANGESET_COMMENT)
53 Notification.TYPE_CHANGESET_COMMENT)
54 sbj = (u'/vcs_test_hg/changeset/'
54 sbj = (u'/vcs_test_hg/changeset/'
55 '27cd5cce30c96924232dffcd24178a07ffeb5dfc#comment-%s' % ID)
55 '27cd5cce30c96924232dffcd24178a07ffeb5dfc#comment-%s' % ID)
56 print "%s vs %s" % (sbj, notification.subject)
56 print "%s vs %s" % (sbj, notification.subject)
57 self.assertTrue(sbj in notification.subject)
57 self.assertTrue(sbj in notification.subject)
58
58
59 def test_create_inline(self):
59 def test_create_inline(self):
60 self.log_user()
60 self.log_user()
61 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
61 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
62 text = u'CommentOnRevision'
62 text = u'CommentOnRevision'
63 f_path = 'vcs/web/simplevcs/views/repository.py'
63 f_path = 'vcs/web/simplevcs/views/repository.py'
64 line = 'n1'
64 line = 'n1'
65
65
66 params = {'text': text, 'f_path': f_path, 'line': line}
66 params = {'text': text, 'f_path': f_path, 'line': line}
67 response = self.app.post(url(controller='changeset', action='comment',
67 response = self.app.post(url(controller='changeset', action='comment',
68 repo_name=HG_REPO, revision=rev),
68 repo_name=HG_REPO, revision=rev),
69 params=params)
69 params=params)
70 # Test response...
70 # Test response...
71 self.assertEqual(response.status, '302 Found')
71 self.assertEqual(response.status, '302 Found')
72 response.follow()
72 response.follow()
73
73
74 response = self.app.get(url(controller='changeset', action='index',
74 response = self.app.get(url(controller='changeset', action='index',
75 repo_name=HG_REPO, revision=rev))
75 repo_name=HG_REPO, revision=rev))
76 #test DB
76 #test DB
77 self.assertEqual(ChangesetComment.query().count(), 1)
77 self.assertEqual(ChangesetComment.query().count(), 1)
78 response.mustcontain(
78 response.mustcontain(
79 '''<div class="comments-number">0 comment(s)'''
79 '''<div class="comments-number">0 comments'''
80 ''' (%s inline)</div>''' % 1
80 ''' (%s inline)</div>''' % 1
81 )
81 )
82 response.mustcontain(
82 response.mustcontain(
83 '''<div style="display:none" class="inline-comment-placeholder" '''
83 '''<div style="display:none" class="inline-comment-placeholder" '''
84 '''path="vcs/web/simplevcs/views/repository.py" '''
84 '''path="vcs/web/simplevcs/views/repository.py" '''
85 '''target_id="vcswebsimplevcsviewsrepositorypy">'''
85 '''target_id="vcswebsimplevcsviewsrepositorypy">'''
86 )
86 )
87
87
88 self.assertEqual(Notification.query().count(), 1)
88 self.assertEqual(Notification.query().count(), 1)
89 self.assertEqual(ChangesetComment.query().count(), 1)
89 self.assertEqual(ChangesetComment.query().count(), 1)
90
90
91 notification = Notification.query().all()[0]
91 notification = Notification.query().all()[0]
92 ID = ChangesetComment.query().first().comment_id
92 ID = ChangesetComment.query().first().comment_id
93 self.assertEqual(notification.type_,
93 self.assertEqual(notification.type_,
94 Notification.TYPE_CHANGESET_COMMENT)
94 Notification.TYPE_CHANGESET_COMMENT)
95 sbj = (u'/vcs_test_hg/changeset/'
95 sbj = (u'/vcs_test_hg/changeset/'
96 '27cd5cce30c96924232dffcd24178a07ffeb5dfc#comment-%s' % ID)
96 '27cd5cce30c96924232dffcd24178a07ffeb5dfc#comment-%s' % ID)
97 print "%s vs %s" % (sbj, notification.subject)
97 print "%s vs %s" % (sbj, notification.subject)
98 self.assertTrue(sbj in notification.subject)
98 self.assertTrue(sbj in notification.subject)
99
99
100 def test_create_with_mention(self):
100 def test_create_with_mention(self):
101 self.log_user()
101 self.log_user()
102
102
103 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
103 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
104 text = u'@test_regular check CommentOnRevision'
104 text = u'@test_regular check CommentOnRevision'
105
105
106 params = {'text':text}
106 params = {'text':text}
107 response = self.app.post(url(controller='changeset', action='comment',
107 response = self.app.post(url(controller='changeset', action='comment',
108 repo_name=HG_REPO, revision=rev),
108 repo_name=HG_REPO, revision=rev),
109 params=params)
109 params=params)
110 # Test response...
110 # Test response...
111 self.assertEqual(response.status, '302 Found')
111 self.assertEqual(response.status, '302 Found')
112 response.follow()
112 response.follow()
113
113
114 response = self.app.get(url(controller='changeset', action='index',
114 response = self.app.get(url(controller='changeset', action='index',
115 repo_name=HG_REPO, revision=rev))
115 repo_name=HG_REPO, revision=rev))
116 # test DB
116 # test DB
117 self.assertEqual(ChangesetComment.query().count(), 1)
117 self.assertEqual(ChangesetComment.query().count(), 1)
118 self.assertTrue('''<div class="comments-number">%s '''
118 response.mustcontain('''<div class="comments-number">%s '''
119 '''comment(s) (0 inline)</div>''' % 1 in response.body)
119 '''comment (0 inline)</div>''' % 1)
120
120
121 self.assertEqual(Notification.query().count(), 2)
121 self.assertEqual(Notification.query().count(), 2)
122 users = [x.user.username for x in UserNotification.query().all()]
122 users = [x.user.username for x in UserNotification.query().all()]
123
123
124 # test_regular get's notification by @mention
124 # test_regular get's notification by @mention
125 self.assertEqual(sorted(users), [u'test_admin', u'test_regular'])
125 self.assertEqual(sorted(users), [u'test_admin', u'test_regular'])
126
126
127 def test_delete(self):
127 def test_delete(self):
128 self.log_user()
128 self.log_user()
129 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
129 rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
130 text = u'CommentOnRevision'
130 text = u'CommentOnRevision'
131
131
132 params = {'text': text}
132 params = {'text': text}
133 response = self.app.post(url(controller='changeset', action='comment',
133 response = self.app.post(url(controller='changeset', action='comment',
134 repo_name=HG_REPO, revision=rev),
134 repo_name=HG_REPO, revision=rev),
135 params=params)
135 params=params)
136
136
137 comments = ChangesetComment.query().all()
137 comments = ChangesetComment.query().all()
138 self.assertEqual(len(comments), 1)
138 self.assertEqual(len(comments), 1)
139 comment_id = comments[0].comment_id
139 comment_id = comments[0].comment_id
140
140
141 self.app.delete(url(controller='changeset',
141 self.app.delete(url(controller='changeset',
142 action='delete_comment',
142 action='delete_comment',
143 repo_name=HG_REPO,
143 repo_name=HG_REPO,
144 comment_id=comment_id))
144 comment_id=comment_id))
145
145
146 comments = ChangesetComment.query().all()
146 comments = ChangesetComment.query().all()
147 self.assertEqual(len(comments), 0)
147 self.assertEqual(len(comments), 0)
148
148
149 response = self.app.get(url(controller='changeset', action='index',
149 response = self.app.get(url(controller='changeset', action='index',
150 repo_name=HG_REPO, revision=rev))
150 repo_name=HG_REPO, revision=rev))
151 self.assertTrue('''<div class="comments-number">0 comment(s)'''
151 response.mustcontain('''<div class="comments-number">0 comments'''
152 ''' (0 inline)</div>''' in response.body)
152 ''' (0 inline)</div>''')
@@ -1,118 +1,131 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.tests.test_libs
3 rhodecode.tests.test_libs
4 ~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6
6
7 Package for testing various lib/helper functions in rhodecode
7 Package for testing various lib/helper functions in rhodecode
8
8
9 :created_on: Jun 9, 2011
9 :created_on: Jun 9, 2011
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26
26 import unittest
27 import datetime
28 from rhodecode.tests import *
27
29
28 import unittest
29 from rhodecode.tests import *
30
30
31 proto = 'http'
31 proto = 'http'
32 TEST_URLS = [
32 TEST_URLS = [
33 ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
33 ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
34 '%s://127.0.0.1' % proto),
34 '%s://127.0.0.1' % proto),
35 ('%s://marcink@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
35 ('%s://marcink@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
36 '%s://127.0.0.1' % proto),
36 '%s://127.0.0.1' % proto),
37 ('%s://marcink:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
37 ('%s://marcink:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
38 '%s://127.0.0.1' % proto),
38 '%s://127.0.0.1' % proto),
39 ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
39 ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
40 '%s://127.0.0.1:8080' % proto),
40 '%s://127.0.0.1:8080' % proto),
41 ('%s://domain.org' % proto, ['%s://' % proto, 'domain.org'],
41 ('%s://domain.org' % proto, ['%s://' % proto, 'domain.org'],
42 '%s://domain.org' % proto),
42 '%s://domain.org' % proto),
43 ('%s://user:pass@domain.org:8080' % proto, ['%s://' % proto, 'domain.org',
43 ('%s://user:pass@domain.org:8080' % proto, ['%s://' % proto, 'domain.org',
44 '8080'],
44 '8080'],
45 '%s://domain.org:8080' % proto),
45 '%s://domain.org:8080' % proto),
46 ]
46 ]
47
47
48 proto = 'https'
48 proto = 'https'
49 TEST_URLS += [
49 TEST_URLS += [
50 ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
50 ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
51 '%s://127.0.0.1' % proto),
51 '%s://127.0.0.1' % proto),
52 ('%s://marcink@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
52 ('%s://marcink@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
53 '%s://127.0.0.1' % proto),
53 '%s://127.0.0.1' % proto),
54 ('%s://marcink:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
54 ('%s://marcink:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
55 '%s://127.0.0.1' % proto),
55 '%s://127.0.0.1' % proto),
56 ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
56 ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
57 '%s://127.0.0.1:8080' % proto),
57 '%s://127.0.0.1:8080' % proto),
58 ('%s://domain.org' % proto, ['%s://' % proto, 'domain.org'],
58 ('%s://domain.org' % proto, ['%s://' % proto, 'domain.org'],
59 '%s://domain.org' % proto),
59 '%s://domain.org' % proto),
60 ('%s://user:pass@domain.org:8080' % proto, ['%s://' % proto, 'domain.org',
60 ('%s://user:pass@domain.org:8080' % proto, ['%s://' % proto, 'domain.org',
61 '8080'],
61 '8080'],
62 '%s://domain.org:8080' % proto),
62 '%s://domain.org:8080' % proto),
63 ]
63 ]
64
64
65
65
66 class TestLibs(unittest.TestCase):
66 class TestLibs(unittest.TestCase):
67
67
68 def test_uri_filter(self):
68 def test_uri_filter(self):
69 from rhodecode.lib.utils2 import uri_filter
69 from rhodecode.lib.utils2 import uri_filter
70
70
71 for url in TEST_URLS:
71 for url in TEST_URLS:
72 self.assertEqual(uri_filter(url[0]), url[1])
72 self.assertEqual(uri_filter(url[0]), url[1])
73
73
74 def test_credentials_filter(self):
74 def test_credentials_filter(self):
75 from rhodecode.lib.utils2 import credentials_filter
75 from rhodecode.lib.utils2 import credentials_filter
76
76
77 for url in TEST_URLS:
77 for url in TEST_URLS:
78 self.assertEqual(credentials_filter(url[0]), url[2])
78 self.assertEqual(credentials_filter(url[0]), url[2])
79
79
80 def test_str2bool(self):
80 def test_str2bool(self):
81 from rhodecode.lib.utils2 import str2bool
81 from rhodecode.lib.utils2 import str2bool
82 test_cases = [
82 test_cases = [
83 ('t', True),
83 ('t', True),
84 ('true', True),
84 ('true', True),
85 ('y', True),
85 ('y', True),
86 ('yes', True),
86 ('yes', True),
87 ('on', True),
87 ('on', True),
88 ('1', True),
88 ('1', True),
89 ('Y', True),
89 ('Y', True),
90 ('yeS', True),
90 ('yeS', True),
91 ('Y', True),
91 ('Y', True),
92 ('TRUE', True),
92 ('TRUE', True),
93 ('T', True),
93 ('T', True),
94 ('False', False),
94 ('False', False),
95 ('F', False),
95 ('F', False),
96 ('FALSE', False),
96 ('FALSE', False),
97 ('0', False),
97 ('0', False),
98 ('-1', False),
98 ('-1', False),
99 ('', False), ]
99 ('', False), ]
100
100
101 for case in test_cases:
101 for case in test_cases:
102 self.assertEqual(str2bool(case[0]), case[1])
102 self.assertEqual(str2bool(case[0]), case[1])
103
103
104 def test_mention_extractor(self):
104 def test_mention_extractor(self):
105 from rhodecode.lib.utils2 import extract_mentioned_users
105 from rhodecode.lib.utils2 import extract_mentioned_users
106 sample = (
106 sample = (
107 "@first hi there @marcink here's my email marcin@email.com "
107 "@first hi there @marcink here's my email marcin@email.com "
108 "@lukaszb check @one_more22 it pls @ ttwelve @D[] @one@two@three "
108 "@lukaszb check @one_more22 it pls @ ttwelve @D[] @one@two@three "
109 "@MARCIN @maRCiN @2one_more22 @john please see this http://org.pl "
109 "@MARCIN @maRCiN @2one_more22 @john please see this http://org.pl "
110 "@marian.user just do it @marco-polo and next extract @marco_polo "
110 "@marian.user just do it @marco-polo and next extract @marco_polo "
111 "user.dot hej ! not-needed maril@domain.org"
111 "user.dot hej ! not-needed maril@domain.org"
112 )
112 )
113
113
114 s = sorted([
114 s = sorted([
115 'first', 'marcink', 'lukaszb', 'one_more22', 'MARCIN', 'maRCiN', 'john',
115 'first', 'marcink', 'lukaszb', 'one_more22', 'MARCIN', 'maRCiN', 'john',
116 'marian.user', 'marco-polo', 'marco_polo'
116 'marian.user', 'marco-polo', 'marco_polo'
117 ], key=lambda k: k.lower())
117 ], key=lambda k: k.lower())
118 self.assertEqual(s, extract_mentioned_users(sample))
118 self.assertEqual(s, extract_mentioned_users(sample))
119
120 def test_age(self):
121 from rhodecode.lib.utils2 import age
122 n = datetime.datetime.now()
123 delt = lambda *args, **kwargs: datetime.timedelta(*args, **kwargs)
124 self.assertEqual(age(n), u'just now')
125 self.assertEqual(age(n - delt(seconds=1)), u'1 second ago')
126 self.assertEqual(age(n - delt(seconds=60 * 2)), u'2 minutes ago')
127 self.assertEqual(age(n - delt(hours=1)), u'1 hour ago')
128 self.assertEqual(age(n - delt(hours=24)), u'1 day ago')
129 self.assertEqual(age(n - delt(hours=24 * 5)), u'5 days ago')
130 self.assertEqual(age(n - delt(hours=24 * 32)), u'1 month and 2 days ago')
131 self.assertEqual(age(n - delt(hours=24 * 400)), u'1 year and 1 month ago')
General Comments 0
You need to be logged in to leave comments. Login now