Code

2a0c2f83fa0daf9fda7b73631e0562556103b98e
[roundup.git] / test / test_actions.py
1 from __future__ import nested_scopes\r
2 \r
3 import unittest\r
4 from cgi import FieldStorage, MiniFieldStorage\r
5 \r
6 from roundup import hyperdb\r
7 from roundup.date import Date, Interval\r
8 from roundup.cgi.actions import *\r
9 from roundup.cgi.exceptions import Redirect, Unauthorised, SeriousError\r
10 \r
11 class MockNull:\r
12     def __init__(self, **kwargs):\r
13         for key, value in kwargs.items():\r
14             setattr(self, key, value)\r
15 \r
16     def __call__(self, *args, **kwargs): return MockNull()\r
17     def __getattr__(self, name):\r
18         # This allows assignments which assume all intermediate steps are Null\r
19         # objects if they don't exist yet.\r
20         #\r
21         # For example (with just 'client' defined):\r
22         #\r
23         # client.db.config.TRACKER_WEB = 'BASE/'\r
24         setattr(self, name, MockNull())\r
25         return getattr(self, name)\r
26 \r
27     def __getitem__(self, key): return self\r
28     def __nonzero__(self): return 0\r
29     def __str__(self): return ''\r
30 \r
31 def true(*args, **kwargs):\r
32     return 1\r
33 \r
34 class ActionTestCase(unittest.TestCase):\r
35     def setUp(self):\r
36         self.form = FieldStorage()\r
37         self.client = MockNull()\r
38         self.client.form = self.form\r
39 \r
40 class ShowActionTestCase(ActionTestCase):\r
41     def assertRaisesMessage(self, exception, callable, message, *args,\r
42                             **kwargs):\r
43         """An extension of assertRaises, which also checks the exception\r
44         message. We need this because we rely on exception messages when\r
45         redirecting.\r
46         """\r
47         try:\r
48             callable(*args, **kwargs)\r
49         except exception, msg:\r
50             self.assertEqual(str(msg), message)\r
51         else:\r
52             if hasattr(excClass,'__name__'):\r
53                 excName = excClass.__name__\r
54             else:\r
55                 excName = str(excClass)\r
56             raise self.failureException, excName\r
57 \r
58     def testShowAction(self):\r
59         self.client.db.config.TRACKER_WEB = 'BASE/'\r
60 \r
61         action = ShowAction(self.client)\r
62         self.assertRaises(ValueError, action.handle)\r
63 \r
64         self.form.value.append(MiniFieldStorage('@type', 'issue'))\r
65         self.assertRaises(SeriousError, action.handle)\r
66 \r
67         self.form.value.append(MiniFieldStorage('@number', '1'))\r
68         self.assertRaisesMessage(Redirect, action.handle, 'BASE/issue1')\r
69 \r
70     def testShowActionNoType(self):\r
71         action = ShowAction(self.client)\r
72         self.assertRaises(ValueError, action.handle)\r
73         self.form.value.append(MiniFieldStorage('@number', '1'))\r
74         self.assertRaisesMessage(ValueError, action.handle,\r
75             'No type specified')\r
76 \r
77 class RetireActionTestCase(ActionTestCase):\r
78     def testRetireAction(self):\r
79         self.client.db.security.hasPermission = true\r
80         self.client.ok_message = []\r
81         RetireAction(self.client).handle()\r
82         self.assert_(len(self.client.ok_message) == 1)\r
83 \r
84     def testNoPermission(self):\r
85         self.assertRaises(Unauthorised, RetireAction(self.client).execute)\r
86 \r
87     def testDontRetireAdminOrAnonymous(self):\r
88         self.client.db.security.hasPermission=true\r
89         # look up the user class\r
90         self.client.classname = 'user'\r
91         # but always look up admin, regardless of nodeid\r
92         self.client.db.user.get = lambda a,b: 'admin'\r
93         self.assertRaises(ValueError, RetireAction(self.client).handle)\r
94         # .. or anonymous\r
95         self.client.db.user.get = lambda a,b: 'anonymous'\r
96         self.assertRaises(ValueError, RetireAction(self.client).handle)\r
97 \r
98 class SearchActionTestCase(ActionTestCase):\r
99     def setUp(self):\r
100         ActionTestCase.setUp(self)\r
101         self.action = SearchAction(self.client)\r
102 \r
103 class StandardSearchActionTestCase(SearchActionTestCase):\r
104     def testNoPermission(self):\r
105         self.assertRaises(Unauthorised, self.action.execute)\r
106 \r
107     def testQueryName(self):\r
108         self.assertEqual(self.action.getQueryName(), '')\r
109 \r
110         self.form.value.append(MiniFieldStorage('@queryname', 'foo'))\r
111         self.assertEqual(self.action.getQueryName(), 'foo')\r
112 \r
113 class FakeFilterVarsTestCase(SearchActionTestCase):\r
114     def setUp(self):\r
115         SearchActionTestCase.setUp(self)\r
116         self.client.db.classes.getprops = lambda: {'foo': hyperdb.Multilink('foo')}\r
117 \r
118     def assertFilterEquals(self, expected):\r
119         self.action.fakeFilterVars()\r
120         self.assertEqual(self.form.getvalue('@filter'), expected)\r
121 \r
122     def testEmptyMultilink(self):\r
123         self.form.value.append(MiniFieldStorage('foo', ''))\r
124         self.form.value.append(MiniFieldStorage('foo', ''))\r
125 \r
126         self.assertFilterEquals(None)\r
127 \r
128     def testNonEmptyMultilink(self):\r
129         self.form.value.append(MiniFieldStorage('foo', ''))\r
130         self.form.value.append(MiniFieldStorage('foo', '1'))\r
131 \r
132         self.assertFilterEquals('foo')\r
133 \r
134     def testEmptyKey(self):\r
135         self.form.value.append(MiniFieldStorage('foo', ''))\r
136         self.assertFilterEquals(None)\r
137 \r
138     def testStandardKey(self):\r
139         self.form.value.append(MiniFieldStorage('foo', '1'))\r
140         self.assertFilterEquals('foo')\r
141 \r
142     def testStringKey(self):\r
143         self.client.db.classes.getprops = lambda: {'foo': hyperdb.String()}\r
144         self.form.value.append(MiniFieldStorage('foo', 'hello'))\r
145         self.assertFilterEquals('foo')\r
146 \r
147     def testTokenizedStringKey(self):\r
148         self.client.db.classes.getprops = lambda: {'foo': hyperdb.String()}\r
149         self.form.value.append(MiniFieldStorage('foo', 'hello world'))\r
150 \r
151         self.assertFilterEquals('foo')\r
152 \r
153         # The single value gets replaced with the tokenized list.\r
154         self.assertEqual([x.value for x in self.form['foo']], ['hello', 'world'])\r
155 \r
156 class CollisionDetectionTestCase(ActionTestCase):\r
157     def setUp(self):\r
158         ActionTestCase.setUp(self)\r
159         self.action = EditItemAction(self.client)\r
160         self.now = Date('.')\r
161         # round off for testing\r
162         self.now.seconds = int(self.now.seconds)\r
163 \r
164     def testLastUserActivity(self):\r
165         self.assertEqual(self.action.lastUserActivity(), None)\r
166 \r
167         self.client.form.value.append(MiniFieldStorage('@lastactivity', str(self.now)))\r
168         self.assertEqual(self.action.lastUserActivity(), self.now)\r
169 \r
170     def testLastNodeActivity(self):\r
171         self.action.classname = 'issue'\r
172         self.action.nodeid = '1'\r
173 \r
174         def get(nodeid, propname):\r
175             self.assertEqual(nodeid, '1')\r
176             self.assertEqual(propname, 'activity')\r
177             return self.now\r
178         self.client.db.issue.get = get\r
179 \r
180         self.assertEqual(self.action.lastNodeActivity(), self.now)\r
181 \r
182     def testCollision(self):\r
183         self.failUnless(self.action.detectCollision(self.now, self.now + Interval("1d")))\r
184         self.failIf(self.action.detectCollision(self.now, self.now - Interval("1d")))\r
185         self.failIf(self.action.detectCollision(None, self.now))\r
186 \r
187 def test_suite():\r
188     suite = unittest.TestSuite()\r
189     suite.addTest(unittest.makeSuite(RetireActionTestCase))\r
190     suite.addTest(unittest.makeSuite(StandardSearchActionTestCase))\r
191     suite.addTest(unittest.makeSuite(FakeFilterVarsTestCase))\r
192     suite.addTest(unittest.makeSuite(ShowActionTestCase))\r
193     suite.addTest(unittest.makeSuite(CollisionDetectionTestCase))\r
194     return suite\r
195 \r
196 if __name__ == '__main__':\r
197     runner = unittest.TextTestRunner()\r
198     unittest.main(testRunner=runner)\r