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

« back to all changes in this revision

Viewing changes to ivle/webapp/routing/test_router.py

  • Committer: Nick Chadwick
  • Date: 2009-03-03 01:48:48 UTC
  • mto: (1099.1.227 exercise-ui)
  • mto: This revision was merged to the branch mainline in revision 1162.
  • Revision ID: chadnickbok@gmail.com-20090303014848-dyurvmtmbneohd7f
Modified the setup script to include '.txt' files.

This allows the automatic inclusion of definitions.txt from the rst
code, as it is needed by all worksheets.

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