1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2004-2021 Edgewall Software
4# All rights reserved.
5#
6# This software is licensed as described in the file COPYING, which
7# you should have received as part of this distribution. The terms
8# are also available at https://trac.edgewall.org/wiki/TracLicense.
9#
10# This software consists of voluntary contributions made by many
11# individuals. For the exact contribution history, see the revision
12# history and logs, available at https://trac.edgewall.org/log/.
13
14import unittest
15
16import trac.ticket.admin
17from trac.admin.api import get_console_locale
18from trac.admin.console import TracAdmin
19from trac.admin.test import TracAdminTestCaseBase
20from trac.test import EnvironmentStub
21from trac.ticket.test import insert_ticket
22from trac.util.datefmt import get_datetime_format_hint
23
24
25class TracAdminTestCase(TracAdminTestCaseBase):
26
27    def setUp(self):
28        self.env = EnvironmentStub(default_data=True, enable=('trac.*',),
29                                   disable=('trac.tests.*',))
30        self.admin = TracAdmin()
31        self.admin.env_set('', self.env)
32        self._test_date = '2004-01-11'  # Set test date to 11th Jan 2004
33
34    def tearDown(self):
35        self.env = None
36
37    @property
38    def datetime_format_hint(self):
39        return get_datetime_format_hint(get_console_locale(self.env))
40
41    def test_component_help(self):
42        rv, output = self.execute('help component')
43        self.assertEqual(0, rv, output)
44        self.assertExpectedResult(output)
45
46    def test_component_list_ok(self):
47        """
48        Tests the 'component list' command in trac-admin.  Since this command
49        has no command arguments, it is hard to call it incorrectly.  As
50        a result, there is only this one test.
51        """
52        rv, output = self.execute('component list')
53        self.assertEqual(0, rv, output)
54        self.assertExpectedResult(output)
55
56    def test_component_add_ok(self):
57        """
58        Tests the 'component add' command in trac-admin.  This particular
59        test passes valid arguments and checks for success.
60        """
61        self.execute('component add new_component')
62        rv, output = self.execute('component list')
63        self.assertEqual(0, rv, output)
64        self.assertExpectedResult(output)
65
66    def test_component_add_optional_owner_ok(self):
67        """
68        Tests the 'component add' command in trac-admin with the optional
69        'owner' argument.  This particular test passes valid arguments and
70        checks for success.
71        """
72        self.execute('component add new_component new_user')
73        rv, output = self.execute('component list')
74        self.assertEqual(0, rv, output)
75        self.assertExpectedResult(output)
76
77    def test_component_add_complete_optional_owner_restrict_owner_false(self):
78        """Tests completion of the 'component add <component>' command with
79        [ticket] restrict_owner = false.
80        """
81        self.execute('config set ticket restrict_owner false')
82        self.execute('session add user1')
83        self.execute('session add user3')
84        self.execute('permission add user1 TICKET_MODIFY')
85        self.execute('permission add user2 TICKET_VIEW')
86        self.execute('permission add user3 TICKET_MODIFY')
87        output = self.complete_command('component', 'add',
88                                        'new_component', '')
89        self.assertEqual([], output)
90
91    def test_component_add_complete_optional_owner_restrict_owner_true(self):
92        """Tests completion of the 'component add <component>' command with
93        [ticket] restrict_owner = true.
94        """
95        self.execute('config set ticket restrict_owner true')
96        self.execute('session add user1')
97        self.execute('session add user3')
98        self.execute('permission add user1 TICKET_MODIFY')
99        self.execute('permission add user2 TICKET_VIEW')
100        self.execute('permission add user3 TICKET_MODIFY')
101        output = self.complete_command('component', 'add',
102                                        'new_component', '')
103        self.assertEqual(['user1', 'user3'], output)
104
105    def test_component_add_error_already_exists(self):
106        """
107        Tests the 'component add' command in trac-admin.  This particular
108        test passes a component name that already exists and checks for an
109        error message.
110        """
111        rv, output = self.execute('component add component1 new_user')
112        self.assertEqual(2, rv, output)
113        self.assertExpectedResult(output)
114
115    def test_component_rename_ok(self):
116        """
117        Tests the 'component rename' command in trac-admin.  This particular
118        test passes valid arguments and checks for success.
119        """
120        self.execute('component rename component1 changed_name')
121        rv, output = self.execute('component list')
122        self.assertEqual(0, rv, output)
123        self.assertExpectedResult(output)
124
125    def test_component_rename_error_bad_component(self):
126        """
127        Tests the 'component rename' command in trac-admin.  This particular
128        test tries to rename a component that does not exist.
129        """
130        rv, output = self.execute('component rename bad_component changed_name')
131        self.assertEqual(2, rv, output)
132        self.assertExpectedResult(output)
133
134    def test_component_rename_error_bad_new_name(self):
135        """
136        Tests the 'component rename' command in trac-admin.  This particular
137        test tries to rename a component to a name that already exists.
138        """
139        rv, output = self.execute('component rename component1 component2')
140        self.assertEqual(2, rv, output)
141        self.assertExpectedResult(output)
142
143    def test_component_chown_ok(self):
144        """
145        Tests the 'component chown' command in trac-admin.  This particular
146        test passes valid arguments and checks for success.
147        """
148        self.execute('component chown component2 changed_owner')
149        rv, output = self.execute('component list')
150        self.assertEqual(0, rv, output)
151        self.assertExpectedResult(output)
152
153    def test_component_chown_complete_component(self):
154        """Tests completion of the 'component chown' command.
155        """
156        output = self.complete_command('component', 'chown', '')
157        self.assertEqual(['component1', 'component2'], output)
158
159    def test_component_chown_complete_owner_restrict_owner_false(self):
160        """Tests completion of the 'component chown <component>' command with
161        [ticket] restrict_owner = false.
162        """
163        self.execute('config set ticket restrict_owner false')
164        self.execute('session add user1')
165        self.execute('session add user3')
166        self.execute('permission add user1 TICKET_MODIFY')
167        self.execute('permission add user2 TICKET_VIEW')
168        self.execute('permission add user3 TICKET_MODIFY')
169        output = self.complete_command('component', 'chown', 'component1', '')
170        self.assertEqual([], output)
171
172    def test_component_chown_complete_owner_restrict_owner_true(self):
173        """Tests completion of the 'component chown <component>' command with
174        [ticket] restrict_owner = true.
175        """
176        self.execute('config set ticket restrict_owner true')
177        self.execute('session add user1')
178        self.execute('session add user3')
179        self.execute('permission add user1 TICKET_MODIFY')
180        self.execute('permission add user2 TICKET_VIEW')
181        self.execute('permission add user3 TICKET_MODIFY')
182        output = self.complete_command('component', 'chown', 'component1', '')
183        self.assertEqual(['user1', 'user3'], output)
184
185    def test_component_chown_error_bad_component(self):
186        """
187        Tests the 'component chown' command in trac-admin.  This particular
188        test tries to change the owner of a component that does not
189        exist.
190        """
191        rv, output = self.execute('component chown bad_component changed_owner')
192        self.assertEqual(2, rv, output)
193        self.assertExpectedResult(output)
194
195    def test_component_remove_ok(self):
196        """
197        Tests the 'component remove' command in trac-admin.  This particular
198        test passes a valid argument and checks for success.
199        """
200        self.execute('component remove component1')
201        rv, output = self.execute('component list')
202        self.assertEqual(0, rv, output)
203        self.assertExpectedResult(output)
204
205    def test_component_remove_error_bad_component(self):
206        """
207        Tests the 'component remove' command in trac-admin.  This particular
208        test tries to remove a component that does not exist.
209        """
210        rv, output = self.execute('component remove bad_component')
211        self.assertEqual(2, rv, output)
212        self.assertExpectedResult(output)
213
214    def test_ticket_help(self):
215        rv, output = self.execute('help ticket')
216        self.assertEqual(0, rv, output)
217        self.assertExpectedResult(output)
218
219    def test_ticket_remove_ok(self):
220        """Ticket is successfully deleted."""
221        insert_ticket(self.env)
222        rv, output = self.execute('ticket remove 1')
223        self.assertEqual(0, rv, output)
224        self.assertExpectedResult(output)
225
226    def test_ticket_remove_error_no_ticket_argument(self):
227        """Error reported when ticket# argument is missing."""
228        rv, output = self.execute('ticket remove')
229        self.assertEqual(2, rv, output)
230        self.assertExpectedResult(output)
231
232    def test_ticket_remove_error_ticket_id_not_an_int(self):
233        """Error reported when ticket id is not an int."""
234        insert_ticket(self.env)
235        rv, output = self.execute('ticket remove a')
236        self.assertEqual(2, rv, output)
237        self.assertExpectedResult(output)
238
239    def test_ticket_remove_error_invalid_ticket_id(self):
240        """ResourceNotFound error reported when ticket does not exist."""
241        insert_ticket(self.env)
242        rv, output = self.execute('ticket remove 2')
243        self.assertEqual(2, rv, output)
244        self.assertExpectedResult(output)
245
246    def test_ticket_comment_remove_ok(self):
247        """Ticket comment is successfully deleted."""
248        ticket = insert_ticket(self.env)
249        ticket.save_changes('user1', 'the comment')
250        rv, output = self.execute('ticket remove_comment 1 1')
251        self.assertEqual(0, rv, output)
252        self.assertExpectedResult(output)
253
254    def test_ticket_comment_remove_error_no_ticket_argument(self):
255        """Error reported when ticket# argument is missing."""
256        rv, output = self.execute('ticket remove_comment')
257        self.assertEqual(2, rv, output)
258        self.assertExpectedResult(output)
259
260    def test_ticket_comment_remove_error_no_comment_argument(self):
261        """Error reported when comment# argument is missing."""
262        ticket = insert_ticket(self.env)
263        rv, output = self.execute('ticket remove_comment 1')
264        self.assertEqual(2, rv, output)
265        self.assertExpectedResult(output)
266
267    def test_ticket_comment_remove_error_ticket_id_not_an_int(self):
268        """ResourceNotFound error reported when comment does not exist."""
269        ticket = insert_ticket(self.env)
270        ticket.save_changes('user1', 'the comment')
271        rv, output = self.execute('ticket remove_comment a 1')
272        self.assertEqual(2, rv, output)
273        self.assertExpectedResult(output)
274
275    def test_ticket_comment_remove_error_comment_id_not_an_int(self):
276        """ResourceNotFound error reported when comment does not exist."""
277        ticket = insert_ticket(self.env)
278        ticket.save_changes('user1', 'the comment')
279        rv, output = self.execute('ticket remove_comment 1 a')
280        self.assertEqual(2, rv, output)
281        self.assertExpectedResult(output)
282
283    def test_ticket_comment_remove_error_invalid_ticket_id(self):
284        """ResourceNotFound error reported when ticket does not exist."""
285        ticket = insert_ticket(self.env)
286        ticket.save_changes('user1', 'the comment')
287        rv, output = self.execute('ticket remove_comment 2 1')
288        self.assertEqual(2, rv, output)
289        self.assertExpectedResult(output)
290
291    def test_ticket_comment_remove_error_invalid_comment_id(self):
292        """ResourceNotFound error reported when comment does not exist."""
293        ticket = insert_ticket(self.env)
294        ticket.save_changes('user1', 'the comment')
295        rv, output = self.execute('ticket remove_comment 1 2')
296        self.assertEqual(2, rv, output)
297        self.assertExpectedResult(output)
298
299    def test_ticket_type_list_ok(self):
300        """
301        Tests the 'ticket_type list' command in trac-admin.  Since this command
302        has no command arguments, it is hard to call it incorrectly.  As
303        a result, there is only this one test.
304        """
305        rv, output = self.execute('ticket_type list')
306        self.assertEqual(0, rv, output)
307        self.assertExpectedResult(output)
308
309    def test_ticket_type_add_ok(self):
310        """
311        Tests the 'ticket_type add' command in trac-admin.  This particular
312        test passes a valid argument and checks for success.
313        """
314        self.execute('ticket_type add new_type')
315        rv, output = self.execute('ticket_type list')
316        self.assertEqual(0, rv, output)
317        self.assertExpectedResult(output)
318
319    def test_ticket_type_add_error_already_exists(self):
320        """
321        Tests the 'ticket_type add' command in trac-admin.  This particular
322        test passes a ticket type that already exists and checks for an error
323        message.
324        """
325        rv, output = self.execute('ticket_type add defect')
326        self.assertEqual(2, rv, output)
327        self.assertExpectedResult(output)
328
329    def test_ticket_type_change_ok(self):
330        """
331        Tests the 'ticket_type change' command in trac-admin.  This particular
332        test passes valid arguments and checks for success.
333        """
334        self.execute('ticket_type change defect bug')
335        rv, output = self.execute('ticket_type list')
336        self.assertEqual(0, rv, output)
337        self.assertExpectedResult(output)
338
339    def test_ticket_type_change_error_bad_type(self):
340        """
341        Tests the 'ticket_type change' command in trac-admin.  This particular
342        test tries to change a priority that does not exist.
343        """
344        rv, output = self.execute('ticket_type change bad_type changed_type')
345        self.assertEqual(2, rv, output)
346        self.assertExpectedResult(output)
347
348    def test_ticket_type_change_error_bad_new_name(self):
349        """
350        Tests the 'ticket_type change' command in trac-admin.  This particular
351        test tries to change a ticket type to another type that already exists.
352        """
353        rv, output = self.execute('ticket_type change defect task')
354        self.assertEqual(2, rv, output)
355        self.assertExpectedResult(output)
356
357    def test_ticket_type_remove_ok(self):
358        """
359        Tests the 'ticket_type remove' command in trac-admin.  This particular
360        test passes a valid argument and checks for success.
361        """
362        self.execute('ticket_type remove task')
363        rv, output = self.execute('ticket_type list')
364        self.assertEqual(0, rv, output)
365        self.assertExpectedResult(output)
366
367    def test_ticket_type_remove_error_bad_type(self):
368        """
369        Tests the 'ticket_type remove' command in trac-admin.  This particular
370        test tries to remove a ticket type that does not exist.
371        """
372        rv, output = self.execute('ticket_type remove bad_type')
373        self.assertEqual(2, rv, output)
374        self.assertExpectedResult(output)
375
376    def test_ticket_type_order_down_ok(self):
377        """
378        Tests the 'ticket_type order' command in trac-admin.  This particular
379        test passes a valid argument and checks for success.
380        """
381        self.execute('ticket_type order defect down')
382        rv, output = self.execute('ticket_type list')
383        self.assertEqual(0, rv, output)
384        self.assertExpectedResult(output)
385
386    def test_ticket_type_order_up_ok(self):
387        """
388        Tests the 'ticket_type order' command in trac-admin.  This particular
389        test passes a valid argument and checks for success.
390        """
391        self.execute('ticket_type order enhancement up')
392        rv, output = self.execute('ticket_type list')
393        self.assertEqual(0, rv, output)
394        self.assertExpectedResult(output)
395
396    def test_ticket_type_order_error_bad_type(self):
397        """
398        Tests the 'priority order' command in trac-admin.  This particular
399        test tries to reorder a priority that does not exist.
400        """
401        rv, output = self.execute('ticket_type order bad_type up')
402        self.assertEqual(2, rv, output)
403        self.assertExpectedResult(output)
404
405    def test_priority_help(self):
406        rv, output = self.execute('help priority')
407        self.assertEqual(0, rv, output)
408        self.assertExpectedResult(output)
409
410    def test_priority_list_ok(self):
411        """
412        Tests the 'priority list' command in trac-admin.  Since this command
413        has no command arguments, it is hard to call it incorrectly.  As
414        a result, there is only this one test.
415        """
416        rv, output = self.execute('priority list')
417        self.assertEqual(0, rv, output)
418        self.assertExpectedResult(output)
419
420    def test_priority_add_ok(self):
421        """
422        Tests the 'priority add' command in trac-admin.  This particular
423        test passes a valid argument and checks for success.
424        """
425        self.execute('priority add new_priority')
426        rv, output = self.execute('priority list')
427        self.assertEqual(0, rv, output)
428        self.assertExpectedResult(output)
429
430    def test_priority_add_many_ok(self):
431        """
432        Tests adding more than 10 priority values.  This makes sure that
433        ordering is preserved when adding more than 10 values.
434        """
435        for i in range(11):
436            self.execute('priority add p%s' % i)
437        rv, output = self.execute('priority list')
438        self.assertEqual(0, rv, output)
439        self.assertExpectedResult(output)
440
441    def test_priority_add_error_already_exists(self):
442        """
443        Tests the 'priority add' command in trac-admin.  This particular
444        test passes a priority name that already exists and checks for an
445        error message.
446        """
447        rv, output = self.execute('priority add blocker')
448        self.assertEqual(2, rv, output)
449        self.assertExpectedResult(output)
450
451    def test_priority_change_ok(self):
452        """
453        Tests the 'priority change' command in trac-admin.  This particular
454        test passes valid arguments and checks for success.
455        """
456        self.execute('priority change major normal')
457        rv, output = self.execute('priority list')
458        self.assertEqual(0, rv, output)
459        self.assertExpectedResult(output)
460
461    def test_priority_change_error_bad_priority(self):
462        """
463        Tests the 'priority change' command in trac-admin.  This particular
464        test tries to change a priority that does not exist.
465        """
466        rv, output = self.execute('priority change bad_priority changed_name')
467        self.assertEqual(2, rv, output)
468        self.assertExpectedResult(output)
469
470    def test_priority_change_error_bad_new_name(self):
471        """
472        Tests the 'priority change' command in trac-admin.  This particular
473        test tries to change a priority to a name that already exists.
474        """
475        rv, output = self.execute('priority change major minor')
476        self.assertEqual(2, rv, output)
477        self.assertExpectedResult(output)
478
479    def test_priority_remove_ok(self):
480        """
481        Tests the 'priority remove' command in trac-admin.  This particular
482        test passes a valid argument and checks for success.
483        """
484        self.execute('priority remove major')
485        rv, output = self.execute('priority list')
486        self.assertEqual(0, rv, output)
487        self.assertExpectedResult(output)
488
489    def test_priority_remove_error_bad_priority(self):
490        """
491        Tests the 'priority remove' command in trac-admin.  This particular
492        test tries to remove a priority that does not exist.
493        """
494        rv, output = self.execute('priority remove bad_priority')
495        self.assertEqual(2, rv, output)
496        self.assertExpectedResult(output)
497
498    def test_priority_order_down_ok(self):
499        """
500        Tests the 'priority order' command in trac-admin.  This particular
501        test passes a valid argument and checks for success.
502        """
503        self.execute('priority order blocker down')
504        rv, output = self.execute('priority list')
505        self.assertEqual(0, rv, output)
506        self.assertExpectedResult(output)
507
508    def test_priority_order_up_ok(self):
509        """
510        Tests the 'priority order' command in trac-admin.  This particular
511        test passes a valid argument and checks for success.
512        """
513        self.execute('priority order critical up')
514        rv, output = self.execute('priority list')
515        self.assertEqual(0, rv, output)
516        self.assertExpectedResult(output)
517
518    def test_priority_order_error_bad_priority(self):
519        """
520        Tests the 'priority order' command in trac-admin.  This particular
521        test tries to reorder a priority that does not exist.
522        """
523        rv, output = self.execute('priority remove bad_priority')
524        self.assertEqual(2, rv, output)
525        self.assertExpectedResult(output)
526
527    def test_severity_help(self):
528        rv, output = self.execute('help severity')
529        self.assertEqual(0, rv, output)
530        self.assertExpectedResult(output)
531
532    def test_severity_list_ok(self):
533        """
534        Tests the 'severity list' command in trac-admin.  Since this command
535        has no command arguments, it is hard to call it incorrectly.  As
536        a result, there is only this one test.
537        """
538        rv, output = self.execute('severity list')
539        self.assertEqual(0, rv, output)
540        self.assertExpectedResult(output)
541
542    def test_severity_add_ok(self):
543        """
544        Tests the 'severity add' command in trac-admin.  This particular
545        test passes a valid argument and checks for success.
546        """
547        self.execute('severity add new_severity')
548        rv, output = self.execute('severity list')
549        self.assertEqual(0, rv, output)
550        self.assertExpectedResult(output)
551
552    def test_severity_add_error_already_exists(self):
553        """
554        Tests the 'severity add' command in trac-admin.  This particular
555        test passes a severity name that already exists and checks for an
556        error message.
557        """
558        self.execute('severity add blocker')
559        rv, output = self.execute('severity add blocker')
560        self.assertEqual(2, rv, output)
561        self.assertExpectedResult(output)
562
563    def test_severity_change_ok(self):
564        """
565        Tests the 'severity add' command in trac-admin.  This particular
566        test passes valid arguments and checks for success.
567        """
568        self.execute('severity add critical')
569        self.execute('severity change critical "end-of-the-world"')
570        rv, output = self.execute('severity list')
571        self.assertEqual(0, rv, output)
572        self.assertExpectedResult(output)
573
574    def test_severity_change_error_bad_severity(self):
575        """
576        Tests the 'severity change' command in trac-admin.  This particular
577        test tries to change a severity that does not exist.
578        """
579        rv, output = self.execute(
580            'severity change bad_severity changed_name')
581        self.assertEqual(2, rv, output)
582        self.assertExpectedResult(output)
583
584    def test_severity_change_error_bad_new_name(self):
585        """
586        Tests the 'severity change' command in trac-admin.  This particular
587        test tries to change a severity to a name that already exists.
588        """
589        self.execute('severity add major')
590        self.execute('severity add critical')
591        rv, output = self.execute('severity change critical major')
592        self.assertEqual(2, rv, output)
593        self.assertExpectedResult(output)
594
595    def test_severity_remove_ok(self):
596        """
597        Tests the 'severity add' command in trac-admin.  This particular
598        test passes a valid argument and checks for success.
599        """
600        self.execute('severity remove trivial')
601        rv, output = self.execute('severity list')
602        self.assertEqual(0, rv, output)
603        self.assertExpectedResult(output)
604
605    def test_severity_remove_error_bad_severity(self):
606        """
607        Tests the 'severity remove' command in trac-admin.  This particular
608        test tries to remove a severity that does not exist.
609        """
610        rv, output = self.execute('severity remove bad_severity')
611        self.assertEqual(2, rv, output)
612        self.assertExpectedResult(output)
613
614    def test_severity_order_down_ok(self):
615        """
616        Tests the 'severity order' command in trac-admin.  This particular
617        test passes a valid argument and checks for success.
618        """
619        self.execute('severity add foo')
620        self.execute('severity add bar')
621        self.execute('severity order foo down')
622        rv, output = self.execute('severity list')
623        self.assertEqual(0, rv, output)
624        self.assertExpectedResult(output)
625
626    def test_severity_order_up_ok(self):
627        """
628        Tests the 'severity order' command in trac-admin.  This particular
629        test passes a valid argument and checks for success.
630        """
631        self.execute('severity add foo')
632        self.execute('severity add bar')
633        self.execute('severity order bar up')
634        rv, output = self.execute('severity list')
635        self.assertEqual(0, rv, output)
636        self.assertExpectedResult(output)
637
638    def test_severity_order_error_bad_severity(self):
639        """
640        Tests the 'severity order' command in trac-admin.  This particular
641        test tries to reorder a priority that does not exist.
642        """
643        rv, output = self.execute('severity remove bad_severity')
644        self.assertEqual(2, rv, output)
645        self.assertExpectedResult(output)
646
647    def test_help_version_time(self):
648        doc = self.get_command_help('version', 'time')
649        self.assertIn(self.datetime_format_hint, doc)
650        self.assertIn('"YYYY-MM-DDThh:mm:ss±hh:mm"', doc)
651
652    def test_version_help(self):
653        rv, output = self.execute('help version')
654        self.assertEqual(0, rv, output)
655        self.assertExpectedResult(output)
656
657    def test_version_list_ok(self):
658        """
659        Tests the 'version list' command in trac-admin.  Since this command
660        has no command arguments, it is hard to call it incorrectly.  As
661        a result, there is only this one test.
662        """
663        rv, output = self.execute('version list')
664        self.assertEqual(0, rv, output)
665        self.assertExpectedResult(output)
666
667    def test_version_add_ok(self):
668        """
669        Tests the 'version add' command in trac-admin.  This particular
670        test passes valid arguments and checks for success.
671        """
672        self.execute('version add 9.9 "%s"' % self._test_date)
673        rv, output = self.execute('version list')
674        self.assertEqual(0, rv, output)
675        self.assertExpectedResult(output)
676
677    def test_version_add_too_many_arguments(self):
678        rv, output = self.execute('version add 7.7 8.8 9.9')
679        self.assertEqual(2, rv, output)
680        self.assertExpectedResult(output)
681
682    def test_version_add_error_already_exists(self):
683        """
684        Tests the 'version add' command in trac-admin.  This particular
685        test passes a version name that already exists and checks for an
686        error message.
687        """
688        rv, output = self.execute(
689            'version add 1.0 "%s"' % self._test_date)
690        self.assertEqual(2, rv, output)
691        self.assertExpectedResult(output)
692
693    def test_version_rename_ok(self):
694        """
695        Tests the 'version rename' command in trac-admin.  This particular
696        test passes valid arguments and checks for success.
697        """
698        self.execute('version rename 1.0 9.9')
699        rv, output = self.execute('version list')
700        self.assertEqual(0, rv, output)
701        self.assertExpectedResult(output)
702
703    def test_version_rename_error_bad_version(self):
704        """
705        Tests the 'version rename' command in trac-admin.  This particular
706        test tries to rename a version that does not exist.
707        """
708        rv, output = self.execute(
709            'version rename bad_version changed_name')
710        self.assertEqual(2, rv, output)
711        self.assertExpectedResult(output)
712
713    def test_version_rename_error_bad_new_name(self):
714        """
715        Tests the 'version rename' command in trac-admin.  This particular
716        test tries to rename a version to a name that already exists.
717        """
718        rv, output = self.execute('version rename 1.0 2.0')
719        self.assertEqual(2, rv, output)
720        self.assertExpectedResult(output)
721
722    def test_version_time_ok(self):
723        """
724        Tests the 'version time' command in trac-admin.  This particular
725        test passes valid arguments and checks for success.
726        """
727        self.execute('version time 2.0 "%s"' % self._test_date)
728        rv, output = self.execute('version list')
729        self.assertEqual(0, rv, output)
730        self.assertExpectedResult(output)
731
732    def test_version_time_unset_ok(self):
733        """
734        Tests the 'version time' command in trac-admin.  This particular
735        test passes valid arguments for unsetting the date.
736        """
737        self.execute('version time 2.0 "%s"' % self._test_date)
738        self.execute('version time 2.0 ""')
739        rv, output = self.execute('version list')
740        self.assertEqual(0, rv, output)
741        self.assertExpectedResult(output)
742
743    def test_version_time_error_bad_version(self):
744        """
745        Tests the 'version time' command in trac-admin.  This particular
746        test tries to change the time on a version that does not exist.
747        """
748        rv, output = self.execute('version time bad_version "%s"'
749                                  % self._test_date)
750        self.assertEqual(2, rv, output)
751        self.assertExpectedResult(output)
752
753    def test_version_remove_ok(self):
754        """
755        Tests the 'version remove' command in trac-admin.  This particular
756        test passes a valid argument and checks for success.
757        """
758        self.execute('version remove 1.0')
759        rv, output = self.execute('version list')
760        self.assertEqual(0, rv, output)
761        self.assertExpectedResult(output)
762
763    def test_version_remove_error_bad_version(self):
764        """
765        Tests the 'version remove' command in trac-admin.  This particular
766        test tries to remove a version that does not exist.
767        """
768        rv, output = self.execute('version remove bad_version')
769        self.assertEqual(2, rv, output)
770        self.assertExpectedResult(output)
771
772    def test_backslash_use_ok(self):
773        if self.admin.interactive:
774            self.execute('version add \\')
775        else:
776            self.execute(r"version add '\'")
777        rv, output = self.execute('version list')
778        self.assertEqual(0, rv, output)
779        self.assertExpectedResult(output)
780
781    def test_milestone_help(self):
782        rv, output = self.execute('help milestone')
783        self.assertEqual(0, rv, output)
784        self.assertExpectedResult(output)
785
786    def test_help_milestone_due(self):
787        doc = self.get_command_help('milestone', 'due')
788        self.assertIn(self.datetime_format_hint, doc)
789        self.assertIn('"YYYY-MM-DDThh:mm:ss±hh:mm"', doc)
790
791    def test_help_milestone_completed(self):
792        doc = self.get_command_help('milestone', 'completed')
793        self.assertIn(self.datetime_format_hint, doc)
794        self.assertIn('"YYYY-MM-DDThh:mm:ss±hh:mm"', doc)
795
796    def test_milestone_list_ok(self):
797        """
798        Tests the 'milestone list' command in trac-admin.  Since this command
799        has no command arguments, it is hard to call it incorrectly.  As
800        a result, there is only this one test.
801        """
802        rv, output = self.execute('milestone list')
803        self.assertEqual(0, rv, output)
804        self.assertExpectedResult(output)
805
806    def test_milestone_add_ok(self):
807        """
808        Tests the 'milestone add' command in trac-admin.  This particular
809        test passes valid arguments and checks for success.
810        """
811        self.execute('milestone add new_milestone "%s"' % self._test_date)
812        rv, output = self.execute('milestone list')
813        self.assertEqual(0, rv, output)
814        self.assertExpectedResult(output)
815
816    def test_milestone_add_utf8_ok(self):
817        """
818        Tests the 'milestone add' command in trac-admin.  This particular
819        test passes valid arguments and checks for success.
820        """
821        self.execute('milestone add \xa9tat_final "%s"'  # \xc2\xa9
822                     % self._test_date)
823        rv, output = self.execute('milestone list')
824        self.assertEqual(0, rv, output)
825        self.assertExpectedResult(output)
826
827    def test_milestone_add_error_already_exists(self):
828        """
829        Tests the 'milestone add' command in trac-admin.  This particular
830        test passes a milestone name that already exists and checks for an
831        error message.
832        """
833        rv, output = self.execute('milestone add milestone1 "%s"'
834                                  % self._test_date)
835        self.assertEqual(2, rv, output)
836        self.assertExpectedResult(output)
837
838    def test_milestone_add_invalid_date(self):
839        rv, output = self.execute('milestone add new_milestone <add>')
840        self.assertEqual(2, rv, output)
841        self.assertExpectedResult(output, {
842            'hint': self.datetime_format_hint,
843            'isohint': get_datetime_format_hint('iso8601')
844        })
845
846    def test_milestone_rename_ok(self):
847        """
848        Tests the 'milestone rename' command in trac-admin.  This particular
849        test passes valid arguments and checks for success.
850        """
851        self.execute('milestone rename milestone1 changed_milestone')
852        rv, output = self.execute('milestone list')
853        self.assertEqual(0, rv, output)
854        self.assertExpectedResult(output)
855
856    def test_milestone_rename_error_bad_milestone(self):
857        """
858        Tests the 'milestone rename' command in trac-admin.  This particular
859        test tries to rename a milestone that does not exist.
860        """
861        rv, output = self.execute(
862            'milestone rename bad_milestone changed_name')
863        self.assertEqual(2, rv, output)
864        self.assertExpectedResult(output)
865
866    def test_milestone_due_ok(self):
867        """
868        Tests the 'milestone due' command in trac-admin.  This particular
869        test passes valid arguments and checks for success.
870        """
871        self.execute('milestone due milestone2 "%s"' % self._test_date)
872        rv, output = self.execute('milestone list')
873        self.assertEqual(0, rv, output)
874        self.assertExpectedResult(output)
875
876    def test_milestone_due_unset_ok(self):
877        """
878        Tests the 'milestone due' command in trac-admin.  This particular
879        test passes valid arguments for unsetting the due date.
880        """
881        self.execute('milestone due milestone2 "%s"' % self._test_date)
882        self.execute('milestone due milestone2 ""')
883        rv, output = self.execute('milestone list')
884        self.assertEqual(0, rv, output)
885        self.assertExpectedResult(output)
886
887    def test_milestone_due_error_bad_milestone(self):
888        """
889        Tests the 'milestone due' command in trac-admin.  This particular
890        test tries to change the due date on a milestone that does not exist.
891        """
892        rv, output = self.execute('milestone due bad_milestone "%s"'
893                                  % self._test_date)
894        self.assertEqual(2, rv, output)
895        self.assertExpectedResult(output)
896
897    def test_milestone_due_invalid_date(self):
898        rv, output = self.execute('milestone due milestone1 <due>')
899        self.assertEqual(2, rv, output)
900        self.assertExpectedResult(output, {
901            'hint': self.datetime_format_hint,
902            'isohint': get_datetime_format_hint('iso8601')
903        })
904
905    def test_milestone_completed_ok(self):
906        """
907        Tests the 'milestone completed' command in trac-admin.  This particular
908        test passes valid arguments and checks for success.
909        """
910        self.execute(
911            'milestone completed milestone2 "%s"' % self._test_date)
912        rv, output = self.execute('milestone list')
913        self.assertEqual(0, rv, output)
914        self.assertExpectedResult(output)
915
916    def test_milestone_completed_error_bad_milestone(self):
917        """
918        Tests the 'milestone completed' command in trac-admin.  This particular
919        test tries to change the completed date on a milestone that does not
920        exist.
921        """
922        rv, output = self.execute('milestone completed bad_milestone "%s"'
923                                  % self._test_date)
924        self.assertEqual(2, rv, output)
925        self.assertExpectedResult(output)
926
927    def test_milestone_completed_invalid_date(self):
928        rv, output = self.execute('milestone completed milestone1 <com>')
929        self.assertEqual(2, rv, output)
930        self.assertExpectedResult(output, {
931            'hint': self.datetime_format_hint,
932            'isohint': get_datetime_format_hint('iso8601')
933        })
934
935    def test_milestone_remove_ok(self):
936        """
937        Tests the 'milestone remove' command in trac-admin.  This particular
938        test passes a valid argument and checks for success.
939        """
940        self.execute('milestone remove milestone3')
941        rv, output = self.execute('milestone list')
942        self.assertEqual(0, rv, output)
943        self.assertExpectedResult(output)
944
945    def test_milestone_remove_error_bad_milestone(self):
946        """
947        Tests the 'milestone remove' command in trac-admin.  This particular
948        test tries to remove a milestone that does not exist.
949        """
950        rv, output = self.execute('milestone remove bad_milestone')
951        self.assertEqual(2, rv, output)
952        self.assertExpectedResult(output)
953
954
955def test_suite():
956    suite = unittest.TestSuite()
957    suite.addTest(unittest.makeSuite(TracAdminTestCase))
958    return suite
959
960
961if __name__ == '__main__':
962    unittest.main(defaultTest='test_suite')
963