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\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, **kwargs):\r
42 try:\r
43 callable(*args, **kwargs)\r
44 except exception, msg:\r
45 self.assertEqual(str(msg), message)\r
46 else:\r
47 if hasattr(excClass,'__name__'): excName = excClass.__name__\r
48 else: excName = str(excClass)\r
49 raise self.failureException, excName\r
50 \r
51 def testShowAction(self):\r
52 self.client.db.config.TRACKER_WEB = 'BASE/'\r
53 \r
54 action = ShowAction(self.client)\r
55 self.assertRaises(ValueError, action.handle)\r
56 \r
57 self.form.value.append(MiniFieldStorage('@type', 'issue'))\r
58 self.assertRaisesMessage(Redirect, action.handle, 'BASE/issue')\r
59 \r
60 self.form.value.append(MiniFieldStorage('@number', '1'))\r
61 self.assertRaisesMessage(Redirect, action.handle, 'BASE/issue1')\r
62 \r
63 class RetireActionTestCase(ActionTestCase):\r
64 def testRetireAction(self):\r
65 self.client.db.security.hasPermission = true\r
66 self.client.ok_message = []\r
67 RetireAction(self.client).handle()\r
68 self.assert_(len(self.client.ok_message) == 1)\r
69 \r
70 def testNoPermission(self):\r
71 self.assertRaises(Unauthorised, RetireAction(self.client).execute)\r
72 \r
73 def testDontRetireAdminOrAnonymous(self):\r
74 self.client.db.security.hasPermission=true\r
75 # look up the user class\r
76 self.client.classname = 'user'\r
77 # but always look up admin, regardless of nodeid\r
78 self.client.db.user.get = lambda a,b: 'admin'\r
79 self.assertRaises(ValueError, RetireAction(self.client).handle)\r
80 # .. or anonymous\r
81 self.client.db.user.get = lambda a,b: 'anonymous'\r
82 self.assertRaises(ValueError, RetireAction(self.client).handle)\r
83 \r
84 class SearchActionTestCase(ActionTestCase):\r
85 def setUp(self):\r
86 ActionTestCase.setUp(self)\r
87 self.action = SearchAction(self.client)\r
88 \r
89 class StandardSearchActionTestCase(SearchActionTestCase):\r
90 def testNoPermission(self):\r
91 self.assertRaises(Unauthorised, self.action.execute)\r
92 \r
93 def testQueryName(self):\r
94 self.assertEqual(self.action.getQueryName(), '')\r
95 \r
96 self.form.value.append(MiniFieldStorage('@queryname', 'foo'))\r
97 self.assertEqual(self.action.getQueryName(), 'foo')\r
98 \r
99 class FakeFilterVarsTestCase(SearchActionTestCase):\r
100 def setUp(self):\r
101 SearchActionTestCase.setUp(self)\r
102 self.client.db.classes.getprops = lambda: {'foo': hyperdb.Multilink('foo')}\r
103 \r
104 def assertFilterEquals(self, expected):\r
105 self.action.fakeFilterVars()\r
106 self.assertEqual(self.form.getvalue('@filter'), expected)\r
107 \r
108 def testEmptyMultilink(self):\r
109 self.form.value.append(MiniFieldStorage('foo', ''))\r
110 self.form.value.append(MiniFieldStorage('foo', ''))\r
111 \r
112 self.assertFilterEquals(None)\r
113 \r
114 def testNonEmptyMultilink(self):\r
115 self.form.value.append(MiniFieldStorage('foo', ''))\r
116 self.form.value.append(MiniFieldStorage('foo', '1'))\r
117 \r
118 self.assertFilterEquals('foo')\r
119 \r
120 def testEmptyKey(self):\r
121 self.form.value.append(MiniFieldStorage('foo', ''))\r
122 self.assertFilterEquals(None)\r
123 \r
124 def testStandardKey(self):\r
125 self.form.value.append(MiniFieldStorage('foo', '1'))\r
126 self.assertFilterEquals('foo')\r
127 \r
128 def testStringKey(self):\r
129 self.client.db.classes.getprops = lambda: {'foo': hyperdb.String()}\r
130 self.form.value.append(MiniFieldStorage('foo', 'hello'))\r
131 self.assertFilterEquals('foo')\r
132 \r
133 def testTokenizedStringKey(self):\r
134 self.client.db.classes.getprops = lambda: {'foo': hyperdb.String()}\r
135 self.form.value.append(MiniFieldStorage('foo', 'hello world'))\r
136 \r
137 self.assertFilterEquals('foo')\r
138 \r
139 # The single value gets replaced with the tokenized list.\r
140 self.assertEqual([x.value for x in self.form['foo']], ['hello', 'world'])\r
141 \r
142 class CollisionDetectionTestCase(ActionTestCase):\r
143 def setUp(self):\r
144 ActionTestCase.setUp(self)\r
145 self.action = EditItemAction(self.client)\r
146 self.now = Date('.')\r
147 \r
148 def testLastUserActivity(self):\r
149 self.assertEqual(self.action.lastUserActivity(), None)\r
150 \r
151 self.client.form.value.append(MiniFieldStorage('@lastactivity', str(self.now)))\r
152 self.assertEqual(self.action.lastUserActivity(), self.now)\r
153 \r
154 def testLastNodeActivity(self):\r
155 self.action.classname = 'issue'\r
156 self.action.nodeid = '1'\r
157 \r
158 def get(nodeid, propname):\r
159 self.assertEqual(nodeid, '1')\r
160 self.assertEqual(propname, 'activity')\r
161 return self.now\r
162 self.client.db.issue.get = get\r
163 \r
164 self.assertEqual(self.action.lastNodeActivity(), self.now)\r
165 \r
166 def testCollision(self):\r
167 self.failUnless(self.action.detectCollision(self.now, self.now + Interval("1d")))\r
168 self.failIf(self.action.detectCollision(self.now, self.now - Interval("1d")))\r
169 self.failIf(self.action.detectCollision(None, self.now))\r
170 \r
171 def test_suite():\r
172 suite = unittest.TestSuite()\r
173 suite.addTest(unittest.makeSuite(RetireActionTestCase))\r
174 suite.addTest(unittest.makeSuite(StandardSearchActionTestCase))\r
175 suite.addTest(unittest.makeSuite(FakeFilterVarsTestCase))\r
176 suite.addTest(unittest.makeSuite(ShowActionTestCase))\r
177 suite.addTest(unittest.makeSuite(CollisionDetectionTestCase))\r
178 return suite\r
179 \r
180 if __name__ == '__main__':\r
181 runner = unittest.TextTestRunner()\r
182 unittest.main(testRunner=runner)\r