1# -*- coding: utf-8 -*-
2from io import StringIO
3
4from django.conf.urls import url
5from django.core.management import CommandError, call_command
6from django.http import HttpResponse
7from django.test import TestCase
8from django.test.utils import override_settings
9from django.views.generic.base import View
10
11from unittest.mock import Mock, patch
12
13
14def function_based_view(request):
15    pass
16
17
18class ClassView(View):
19    pass
20
21
22urlpatterns = [
23    url(r'lambda/view', lambda request: HttpResponse('OK')),
24    url(r'function/based/', function_based_view, name='function-based-view'),
25    url(r'class/based/', ClassView.as_view(), name='class-based-view'),
26]
27
28
29class ShowUrlsExceptionsTests(TestCase):
30    """Tests if show_urls command raises exceptions."""
31
32    def test_should_raise_CommandError_when_format_style_does_not_exists(self):
33        with self.assertRaisesRegex(CommandError, "Format style 'invalid_format' does not exist. Options: aligned, dense, json, pretty-json, table, verbose"):
34            call_command('show_urls', '--format=invalid_format')
35
36    def test_should_raise_CommandError_when_doesnt_have_urlconf_attr(self):
37        with self.assertRaisesRegex(CommandError, "Settings module <Settings \"tests.testapp.settings\"> does not have the attribute INVALID_URLCONF."):
38            call_command('show_urls', '--urlconf=INVALID_URLCONF')
39
40    @override_settings(INVALID_URLCONF='')
41    def test_should_raise_CommandError_when_doesnt_have_urlconf_attr_print_exc(self):
42        m_traceback = Mock()
43        with self.assertRaisesRegex(CommandError, 'Error occurred while trying to load : Empty module name'):
44            with patch.dict('sys.modules', traceback=m_traceback):
45                call_command('show_urls', '--urlconf=INVALID_URLCONF', '--traceback')
46
47        self.assertTrue(m_traceback.print_exc.called)
48
49
50@override_settings(ROOT_URLCONF='tests.management.commands.test_show_urls')
51class ShowUrlsTests(TestCase):
52
53    @patch('sys.stdout', new_callable=StringIO)
54    def test_should_show_urls_unsorted_but_same_order_as_found_in_url_patterns(self, m_stdout):
55        call_command('show_urls', '-u', verbosity=3)
56
57        lines = m_stdout.getvalue().splitlines()
58        self.assertIn('/lambda/view\ttests.management.commands.test_show_urls.<lambda>', lines[0])
59        self.assertIn('/function/based/\ttests.management.commands.test_show_urls.function_based_view\tfunction-based-view', lines[1])
60        self.assertIn('/class/based/\ttests.management.commands.test_show_urls.ClassView\tclass-based-view', lines[2])
61
62    @patch('sys.stdout', new_callable=StringIO)
63    def test_should_show_urls_sorted_alphabetically(self, m_stdout):
64        call_command('show_urls', verbosity=3)
65
66        lines = m_stdout.getvalue().splitlines()
67        self.assertEqual('/class/based/\ttests.management.commands.test_show_urls.ClassView\tclass-based-view', lines[0])
68        self.assertEqual('/function/based/\ttests.management.commands.test_show_urls.function_based_view\tfunction-based-view', lines[1])
69        self.assertEqual('/lambda/view\ttests.management.commands.test_show_urls.<lambda>', lines[2])
70
71    @patch('sys.stdout', new_callable=StringIO)
72    def test_should_show_urls_in_json_format(self, m_stdout):
73        call_command('show_urls', '--format=json')
74
75        self.assertJSONEqual(m_stdout.getvalue(), [
76            {"url": "/lambda/view", "module": "tests.management.commands.test_show_urls.<lambda>", "name": "", "decorators": ""},
77            {"url": "/function/based/", "module": "tests.management.commands.test_show_urls.function_based_view", "name": "function-based-view", "decorators": ""},
78            {"url": "/class/based/", "module": "tests.management.commands.test_show_urls.ClassView", "name": "class-based-view", "decorators": ""}
79        ])
80        self.assertEqual(len(m_stdout.getvalue().splitlines()), 1)
81
82    @patch('sys.stdout', new_callable=StringIO)
83    def test_should_show_urls_in_pretty_json_format(self, m_stdout):
84        call_command('show_urls', '--format=pretty-json')
85
86        self.assertJSONEqual(m_stdout.getvalue(), [
87            {"url": "/lambda/view", "module": "tests.management.commands.test_show_urls.<lambda>", "name": "", "decorators": ""},
88            {"url": "/function/based/", "module": "tests.management.commands.test_show_urls.function_based_view", "name": "function-based-view", "decorators": ""},
89            {"url": "/class/based/", "module": "tests.management.commands.test_show_urls.ClassView", "name": "class-based-view", "decorators": ""}
90        ])
91        self.assertEqual(len(m_stdout.getvalue().splitlines()), 20)
92
93    @patch('sys.stdout', new_callable=StringIO)
94    def test_should_show_urls_in_table_format(self, m_stdout):
95        call_command('show_urls', '--format=table')
96
97        self.assertIn('/class/based/    | tests.management.commands.test_show_urls.ClassView           | class-based-view    |', m_stdout.getvalue())
98        self.assertIn('/function/based/ | tests.management.commands.test_show_urls.function_based_view | function-based-view |', m_stdout.getvalue())
99        self.assertIn('/lambda/view     | tests.management.commands.test_show_urls.<lambda>            |                     |', m_stdout.getvalue())
100
101    @patch('sys.stdout', new_callable=StringIO)
102    def test_should_show_urls_in_aligned_format(self, m_stdout):
103        call_command('show_urls', '--format=aligned')
104
105        lines = m_stdout.getvalue().splitlines()
106        self.assertEqual('/class/based/      tests.management.commands.test_show_urls.ClassView             class-based-view      ', lines[0])
107        self.assertEqual('/function/based/   tests.management.commands.test_show_urls.function_based_view   function-based-view   ', lines[1])
108        self.assertEqual('/lambda/view       tests.management.commands.test_show_urls.<lambda>                                    ', lines[2])
109
110    @patch('sys.stdout', new_callable=StringIO)
111    def test_should_show_urls_with_no_color_option(self, m_stdout):
112        call_command('show_urls', '--no-color')
113
114        lines = m_stdout.getvalue().splitlines()
115        self.assertEqual('/class/based/\ttests.management.commands.test_show_urls.ClassView\tclass-based-view', lines[0])
116        self.assertEqual('/function/based/\ttests.management.commands.test_show_urls.function_based_view\tfunction-based-view', lines[1])
117        self.assertEqual('/lambda/view\ttests.management.commands.test_show_urls.<lambda>', lines[2])
118