~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/webapp/publisher/test_publisher.py

  • Committer: William Grant
  • Date: 2009-04-29 04:58:42 UTC
  • Revision ID: grantw@unimelb.edu.au-20090429045842-upijb1ybcbz1zg6u
Kill --nosvnrevno from setup.install - we don't use Subversion now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
from nose.tools import assert_equal, raises
2
 
 
3
 
from ivle.webapp.publisher import (INF, InsufficientPathSegments, NoPath,
4
 
                                   NotFound, RouteConflict, Publisher, ROOT)
5
 
 
6
 
class Root(object):
7
 
    def __init__(self):
8
 
        self.subjects = {}
9
 
        self.users = {}
10
 
 
11
 
    def add_subject(self, subject):
12
 
        self.subjects[subject.name] = subject
13
 
 
14
 
    def add_user(self, user):
15
 
        self.users[user.login] = user
16
 
 
17
 
class User(object):
18
 
    def __init__(self, login):
19
 
        self.login = login
20
 
 
21
 
class Subject(object):
22
 
    def __init__(self, name, code):
23
 
        self.name = name
24
 
        self.code = code
25
 
        self.offerings = {}
26
 
 
27
 
    def add_offering(self, offering):
28
 
        assert self.name == offering.subject.name
29
 
        self.offerings[(offering.year, offering.semester)] = offering
30
 
 
31
 
class Offering(object):
32
 
    def __init__(self, subject, year, semester):
33
 
        self.subject = subject
34
 
        self.year = year
35
 
        self.semester = semester
36
 
        self.projects = {}
37
 
 
38
 
    def add_project(self, project):
39
 
        assert project.offering is self
40
 
        self.projects[project.name] = project
41
 
 
42
 
class OfferingFiles(object):
43
 
    def __init__(self, offering):
44
 
        self.offering = offering
45
 
 
46
 
class OfferingFile(object):
47
 
    def __init__(self, offeringfiles, path):
48
 
        self.offering = offeringfiles.offering
49
 
        self.path = path
50
 
 
51
 
class Project(object):
52
 
    def __init__(self, offering, name):
53
 
        self.offering = offering
54
 
        self.name = name
55
 
 
56
 
 
57
 
class View(object):
58
 
    def __init__(self, context):
59
 
        self.context = context
60
 
 
61
 
class RootIndex(View):
62
 
    pass
63
 
 
64
 
class UserServeView(View):
65
 
    pass
66
 
 
67
 
class SubjectIndex(View):
68
 
    pass
69
 
 
70
 
class SubjectEdit(View):
71
 
    pass
72
 
 
73
 
class OfferingIndex(View):
74
 
    pass
75
 
 
76
 
class OfferingEdit(View):
77
 
    pass
78
 
 
79
 
class OfferingAPIIndex(View):
80
 
    pass
81
 
 
82
 
class OfferingFilesIndex(View):
83
 
    pass
84
 
 
85
 
class OfferingFileIndex(View):
86
 
    pass
87
 
 
88
 
class ProjectIndex(View):
89
 
    pass
90
 
 
91
 
class OfferingProjects(View):
92
 
    pass
93
 
 
94
 
class OfferingAddProject(View):
95
 
    pass
96
 
 
97
 
def root_to_subject_or_user(root, name):
98
 
    if name.startswith('~'):
99
 
        return root.users.get(name[1:])
100
 
    return root.subjects.get(name)
101
 
 
102
 
def subject_to_offering(subject, year, semester):
103
 
    return subject.offerings.get((int(year), int(semester)))
104
 
 
105
 
def offering_to_files(offering):
106
 
    return OfferingFiles(offering)
107
 
 
108
 
def offering_files_to_file(offeringfiles, *path):
109
 
    return OfferingFile(offeringfiles, path)
110
 
 
111
 
def offering_to_project(offering, name):
112
 
    return offering.projects.get(name)
113
 
 
114
 
def subject_url(subject):
115
 
    return (ROOT, subject.name)
116
 
 
117
 
def offering_url(offering):
118
 
    return (offering.subject, (str(offering.year), str(offering.semester)))
119
 
 
120
 
def offering_files_url(offeringfiles):
121
 
    return (offeringfiles.offering, '+files')
122
 
 
123
 
def project_url(project):
124
 
    return (project.offering, ('+projects', project.name))
125
 
 
126
 
class BaseTest(object):
127
 
    def setUp(self):
128
 
        r = Root()
129
 
        self.r = r
130
 
 
131
 
        # A user would be nice.
132
 
        r.add_user(User('jsmith'))
133
 
 
134
 
        # Give us some subjects...
135
 
        r.add_subject(Subject('info1', '600151'))
136
 
        r.add_subject(Subject('info2', '600152'))
137
 
        r.add_subject(Subject('info3', '600251'))
138
 
 
139
 
        # ... and some offerings.
140
 
        r.subjects['info1'].add_offering(Offering(self.r.subjects['info1'],
141
 
                                         2008, 1))
142
 
        r.subjects['info1'].add_offering(Offering(self.r.subjects['info1'],
143
 
                                         2008, 2))
144
 
        r.subjects['info1'].add_offering(Offering(self.r.subjects['info1'],
145
 
                                         2009, 1))
146
 
        r.subjects['info2'].add_offering(Offering(self.r.subjects['info2'],
147
 
                                         2008, 2))
148
 
        r.subjects['info2'].add_offering(Offering(self.r.subjects['info2'],
149
 
                                         2009, 1))
150
 
        r.subjects['info3'].add_offering(Offering(self.r.subjects['info3'],
151
 
                                         2009, 1))
152
 
 
153
 
        # A normal project...
154
 
        r.subjects['info1'].offerings[(2009, 1)].add_project(
155
 
            Project(r.subjects['info1'].offerings[(2009, 1)], 'p1')
156
 
            )
157
 
 
158
 
        # And one conflicting with a deep view, just to be nasty.
159
 
        r.subjects['info1'].offerings[(2009, 1)].add_project(
160
 
            Project(r.subjects['info1'].offerings[(2009, 1)], '+new')
161
 
            )
162
 
 
163
 
class TestResolution(BaseTest):
164
 
    def setUp(self):
165
 
        super(TestResolution, self).setUp()
166
 
        self.rtr = Publisher(root=self.r, viewset='browser')
167
 
        self.rtr.add_set_switch('api', 'api')
168
 
        self.rtr.add_forward(Root, None, root_to_subject_or_user, 1)
169
 
        self.rtr.add_forward(Subject, None, subject_to_offering, 2)
170
 
        self.rtr.add_forward(Offering, '+files', offering_to_files, 0)
171
 
        self.rtr.add_forward(OfferingFiles, None, offering_files_to_file, INF)
172
 
        self.rtr.add_forward(Offering, '+projects', offering_to_project, 1)
173
 
        self.rtr.add_view(User, None, UserServeView, viewset='browser')
174
 
        self.rtr.add_view(Subject, '+index', SubjectIndex, viewset='browser')
175
 
        self.rtr.add_view(Subject, '+edit', SubjectEdit, viewset='browser')
176
 
        self.rtr.add_view(Offering, '+index', OfferingIndex, viewset='browser')
177
 
        self.rtr.add_view(Offering, '+index', OfferingAPIIndex, viewset='api')
178
 
        self.rtr.add_view(OfferingFiles, '+index', OfferingFilesIndex,
179
 
                          viewset='browser')
180
 
        self.rtr.add_view(OfferingFile, '+index', OfferingFileIndex,
181
 
                          viewset='browser')
182
 
        self.rtr.add_view(Project, '+index', ProjectIndex, viewset='browser')
183
 
        self.rtr.add_view(Offering, ('+projects', '+new'), OfferingAddProject,
184
 
                          viewset='browser')
185
 
        self.rtr.add_view(Offering, ('+projects', '+index'), OfferingProjects,
186
 
                          viewset='browser')
187
 
 
188
 
    def testOneRoute(self):
189
 
        assert_equal(self.rtr.resolve('/info1'),
190
 
                     (self.r.subjects['info1'], SubjectIndex, ())
191
 
                     )
192
 
        assert_equal(self.rtr.resolve('/info3'),
193
 
                     (self.r.subjects['info3'], SubjectIndex, ())
194
 
                     )
195
 
 
196
 
    def testTwoRoutes(self):
197
 
        assert_equal(self.rtr.resolve('/info1/2009/1'),
198
 
             (self.r.subjects['info1'].offerings[(2009, 1)], OfferingIndex, ())
199
 
             )
200
 
        assert_equal(self.rtr.resolve('/info2/2008/2'),
201
 
             (self.r.subjects['info2'].offerings[(2008, 2)], OfferingIndex, ())
202
 
             )
203
 
 
204
 
    def testNamedRoute(self):
205
 
        assert_equal(type(self.rtr.resolve('/info1/2009/1/+files')[0]),
206
 
                     OfferingFiles
207
 
                    )
208
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+files')[0].offering,
209
 
                     self.r.subjects['info1'].offerings[(2009, 1)]
210
 
                    )
211
 
 
212
 
    def testNonDefaultView(self):
213
 
        assert_equal(self.rtr.resolve('/info1/+edit'),
214
 
                     (self.r.subjects['info1'], SubjectEdit, ())
215
 
                     )
216
 
 
217
 
    def testDefaultView(self):
218
 
        assert_equal(self.rtr.resolve('/info1'),
219
 
                     (self.r.subjects['info1'], SubjectIndex, ())
220
 
                     )
221
 
 
222
 
    def testViewWithSubpath(self):
223
 
        assert_equal(self.rtr.resolve('/info1/+edit/foo/bar'),
224
 
                     (self.r.subjects['info1'], SubjectEdit, ('foo', 'bar'))
225
 
                     )
226
 
 
227
 
    def testNoDefaultView(self):
228
 
        try:
229
 
            self.rtr.default = 'not+index'
230
 
            self.rtr.resolve('/info1')
231
 
        except NotFound, e:
232
 
            assert_equal(e.args, (self.r.subjects['info1'], '+index', ()))
233
 
        except:
234
 
            raise
235
 
        else:
236
 
            raise AssertionError('did not raise NotFound')
237
 
        finally:
238
 
            self.rtr.default = '+index'
239
 
 
240
 
    def testMissingView(self):
241
 
        try:
242
 
            self.rtr.resolve('/info1/+foo')
243
 
        except NotFound, e:
244
 
            assert_equal(e.args, (self.r.subjects['info1'], '+foo', ()))
245
 
        except:
246
 
            raise
247
 
        else:
248
 
            raise AssertionError('did not raise NotFound')
249
 
 
250
 
    def testViewSetSeparation(self):
251
 
        try:
252
 
            self.rtr.resolve('/api/info1/+edit')
253
 
        except NotFound, e:
254
 
            assert_equal(e.args, (self.r.subjects['info1'], '+edit', ()))
255
 
        except:
256
 
            raise
257
 
        else:
258
 
            raise AssertionError('did not raise NotFound')
259
 
 
260
 
    def testRouteReturningNone(self):
261
 
        try:
262
 
            self.rtr.resolve('/info9/+index')
263
 
        except NotFound, e:
264
 
            assert_equal(e.args, (self.r, 'info9', ('+index',)))
265
 
        except:
266
 
            raise
267
 
        else:
268
 
            raise AssertionError('did not raise NotFound')
269
 
 
270
 
    def testRouteWithInfinitelyManyArguments(self):
271
 
        o, v, sp = self.rtr.resolve('/info1/2009/1/+files/foo/bar/baz')
272
 
 
273
 
        assert_equal(type(o), OfferingFile)
274
 
        assert_equal(o.path, ('foo', 'bar', 'baz'))
275
 
        assert_equal(o.offering, self.r.subjects['info1'].offerings[(2009, 1)])
276
 
        assert_equal(v, OfferingFileIndex)
277
 
        assert_equal(sp, ())
278
 
 
279
 
    def testMissingRoute(self):
280
 
        try:
281
 
            self.rtr.resolve('/info1/2009/1/+foo')
282
 
        except NotFound, e:
283
 
            assert_equal(e.args, (
284
 
                self.r.subjects['info1'].offerings[(2009, 1)],
285
 
                '+foo',
286
 
                ()
287
 
                ))
288
 
        except:
289
 
            raise
290
 
        else:
291
 
            raise AssertionError('did not raise NotFound')
292
 
 
293
 
    def testAlternateViewSetWithDefault(self):
294
 
        assert_equal(self.rtr.resolve('/info1/2009/1'),
295
 
             (self.r.subjects['info1'].offerings[(2009, 1)], OfferingIndex, ())
296
 
             )
297
 
 
298
 
        assert_equal(self.rtr.resolve('/api/info1/2009/1'),
299
 
          (self.r.subjects['info1'].offerings[(2009, 1)], OfferingAPIIndex, ())
300
 
          )
301
 
 
302
 
    def testDeepView(self):
303
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+projects/+new'),
304
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
305
 
              OfferingAddProject, ())
306
 
             )
307
 
 
308
 
    def testDefaultDeepView(self):
309
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+projects'),
310
 
             (self.r.subjects['info1'].offerings[(2009, 1)],
311
 
              OfferingProjects, ())
312
 
             )
313
 
 
314
 
    def testNamedRouteWithDeepView(self):
315
 
        assert_equal(self.rtr.resolve('/info1/2009/1/+projects/p1'),
316
 
             (self.r.subjects['info1'].offerings[(2009, 1)].projects['p1'],
317
 
              ProjectIndex, ())
318
 
             )
319
 
 
320
 
    def testNullPathView(self):
321
 
        """Verify that views can be placed immediately under an object.
322
 
 
323
 
        There are some cases in which it is useful for a view with a
324
 
        subpath to exist immediately under an object, with no name.
325
 
        """
326
 
        assert_equal(self.rtr.resolve('/~jsmith/foo/bar'),
327
 
             (self.r.users['jsmith'], UserServeView, ('foo', 'bar')))
328
 
 
329
 
 
330
 
class TestGeneration(BaseTest):
331
 
    def setUp(self):
332
 
        super(TestGeneration, self).setUp()
333
 
        self.rtr = Publisher(root=self.r, viewset='browser')
334
 
        self.rtr.add_set_switch('api', 'api')
335
 
        self.rtr.add_reverse(Subject, subject_url)
336
 
        self.rtr.add_reverse(Offering, offering_url)
337
 
        self.rtr.add_reverse(OfferingFiles, offering_files_url)
338
 
        self.rtr.add_reverse(Project, project_url)
339
 
        self.rtr.add_view(Subject, '+index', SubjectIndex, viewset='browser')
340
 
        self.rtr.add_view(Subject, '+edit', SubjectEdit, viewset='browser')
341
 
        self.rtr.add_view(Offering, '+index', OfferingIndex, viewset='browser')
342
 
        self.rtr.add_view(Offering, '+index', OfferingAPIIndex, viewset='api')
343
 
        self.rtr.add_view(Project, '+index', ProjectIndex, viewset='browser')
344
 
        self.rtr.add_view(Offering, ('+projects', '+new'), OfferingAddProject,
345
 
                          viewset='browser')
346
 
        self.rtr.add_view(Offering, ('+projects', '+index'), OfferingProjects,
347
 
                          viewset='browser')
348
 
 
349
 
    def testOneLevel(self):
350
 
        assert_equal(self.rtr.generate(self.r.subjects['info1']), '/info1')
351
 
 
352
 
    def testTwoLevel(self):
353
 
        assert_equal(
354
 
            self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)]),
355
 
            '/info1/2009/1'
356
 
            )
357
 
        assert_equal(
358
 
            self.rtr.generate(self.r.subjects['info2'].offerings[(2008, 2)]),
359
 
            '/info2/2008/2'
360
 
            )
361
 
 
362
 
    def testNamedRoute(self):
363
 
        assert_equal(self.rtr.generate(
364
 
                OfferingFiles(self.r.subjects['info1'].offerings[(2009, 1)])),
365
 
                '/info1/2009/1/+files'
366
 
            )
367
 
 
368
 
    def testView(self):
369
 
        assert_equal(self.rtr.generate(self.r.subjects['info1'], SubjectEdit),
370
 
                     '/info1/+edit'
371
 
                     )
372
 
 
373
 
    def testDefaultView(self):
374
 
        assert_equal(
375
 
            self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)],
376
 
                              OfferingIndex
377
 
                              ),
378
 
            '/info1/2009/1'
379
 
            )
380
 
 
381
 
    def testViewWithSubpath(self):
382
 
        assert_equal(self.rtr.generate(self.r.subjects['info1'], SubjectEdit,
383
 
                                       ('foo', 'bar')),
384
 
                     '/info1/+edit/foo/bar'
385
 
                     )
386
 
 
387
 
    def testViewWithStringSubpath(self):
388
 
        assert_equal(self.rtr.generate(self.r.subjects['info1'], SubjectEdit,
389
 
                                       'foo/bar'),
390
 
                     '/info1/+edit/foo/bar'
391
 
                     )
392
 
 
393
 
    def testAlternateViewSetWithDefault(self):
394
 
        assert_equal(
395
 
            self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)],
396
 
                              OfferingAPIIndex
397
 
                              ),
398
 
            '/api/info1/2009/1'
399
 
            )
400
 
 
401
 
    def testDeepView(self):
402
 
        assert_equal(
403
 
            self.rtr.generate(
404
 
                self.r.subjects['info1'].offerings[(2009, 1)],
405
 
                OfferingAddProject
406
 
                ),
407
 
        '/info1/2009/1/+projects/+new'
408
 
        )
409
 
 
410
 
    def testDefaultDeepView(self):
411
 
        assert_equal(
412
 
            self.rtr.generate(
413
 
                self.r.subjects['info1'].offerings[(2009, 1)],
414
 
                OfferingProjects
415
 
                ),
416
 
        '/info1/2009/1/+projects'
417
 
        )
418
 
 
419
 
    def testDefaultDeepViewWithSubpath(self):
420
 
        assert_equal(
421
 
            self.rtr.generate(
422
 
                self.r.subjects['info1'].offerings[(2009, 1)],
423
 
                OfferingProjects, ('foo', 'bar')
424
 
                ),
425
 
        '/info1/2009/1/+projects/+index/foo/bar'
426
 
        )
427
 
 
428
 
    def testNamedRouteWithDeepView(self):
429
 
        assert_equal(
430
 
            self.rtr.generate(
431
 
                self.r.subjects['info1'].offerings[(2009, 1)].projects['p1'],
432
 
                ProjectIndex
433
 
                ),
434
 
        '/info1/2009/1/+projects/p1'
435
 
        )
436
 
 
437
 
    def testRoot(self):
438
 
        assert_equal(self.rtr.generate(self.r), '/')
439
 
 
440
 
 
441
 
class TestErrors(BaseTest):
442
 
    def setUp(self):
443
 
        super(TestErrors, self).setUp()
444
 
        self.rtr = Publisher(root=self.r)
445
 
        self.rtr.add_forward(Root, None, root_to_subject_or_user, 1)
446
 
        self.rtr.add_forward(Subject, '+foo', lambda s: s.name + 'foo', 0)
447
 
        self.rtr.add_forward(Subject, None, subject_to_offering, 2)
448
 
        self.rtr.add_reverse(Subject, subject_url)
449
 
        self.rtr.add_reverse(Offering, offering_url)
450
 
        self.rtr.add_view(Offering, '+index', OfferingIndex)
451
 
        self.rtr.add_view(Offering, '+index', OfferingAPIIndex, viewset='api')
452
 
        self.rtr.add_set_switch('rest', 'rest')
453
 
 
454
 
    @raises(RouteConflict)
455
 
    def testForwardConflict(self):
456
 
        self.rtr.add_forward(Subject, '+foo', object(), 2)
457
 
 
458
 
    @raises(RouteConflict)
459
 
    def testReverseConflict(self):
460
 
        self.rtr.add_reverse(Subject, object())
461
 
 
462
 
    @raises(RouteConflict)
463
 
    def testViewConflict(self):
464
 
        self.rtr.add_view(Offering, '+index', object())
465
 
 
466
 
    @raises(RouteConflict)
467
 
    def testSetSwitchForwardConflict(self):
468
 
        self.rtr.add_set_switch('rest', 'foo')
469
 
 
470
 
    @raises(RouteConflict)
471
 
    def testSetSwitchReverseConflict(self):
472
 
        self.rtr.add_set_switch('bar', 'rest')
473
 
 
474
 
    @raises(NoPath)
475
 
    def testNoPath(self):
476
 
        self.rtr.generate(object())
477
 
 
478
 
    @raises(NoPath)
479
 
    def testNoSetSwitch(self):
480
 
        self.rtr.generate(self.r.subjects['info1'].offerings[(2009, 1)],
481
 
                          OfferingAPIIndex)
482
 
 
483
 
    @raises(NoPath)
484
 
    def testUnregisteredView(self):
485
 
        self.rtr.generate(self.r.subjects['info1'], SubjectIndex)
486
 
 
487
 
    @raises(NotFound)
488
 
    def testNotFound(self):
489
 
        self.rtr.resolve('/bar')
490
 
 
491
 
    @raises(InsufficientPathSegments)
492
 
    def testInsufficientPathSegments(self):
493
 
        self.rtr.resolve('/info1/foo')