1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2005-2021 Edgewall Software
4# Copyright (C) 2005-2007 Christopher Lenz <cmlenz@gmx.de>
5# All rights reserved.
6#
7# This software is licensed as described in the file COPYING, which
8# you should have received as part of this distribution. The terms
9# are also available at https://trac.edgewall.org/wiki/TracLicense.
10#
11# This software consists of voluntary contributions made by many
12# individuals. For the exact contribution history, see the revision
13# history and logs, available at https://trac.edgewall.org/log/.
14
15import doctest
16import unittest
17
18from trac.util.text import jinja2template
19import trac.web.href
20
21
22class HrefTestCase(unittest.TestCase):
23    """Unit tests for Href URL builder."""
24
25    def test_non_empty_base(self):
26        """Build URLs with a non-empty base."""
27        href = trac.web.href.Href('/base')
28        self.assertEqual('/base', href())
29        self.assertEqual('/base', href('/'))
30        self.assertEqual('/base/sub', href('sub'))
31        self.assertEqual('/base/sub', href('/sub/'))
32        self.assertEqual('/base/sub/other', href('sub', 'other'))
33        self.assertEqual('/base/sub/other', href('sub', None, 'other'))
34        self.assertEqual('/base/sub/other', href('sub', '', 'other'))
35        self.assertEqual('/base/sub/other', href('sub', '', '', 'other'))
36        self.assertEqual('/base/sub/other', href('', 'sub', 'other'))
37        self.assertEqual('/base/sub/other/', href('sub', 'other', ''))
38        self.assertEqual('/base/with%20special%26chars',
39                         href('with special&chars'))
40        self.assertIn(href('page', param='value', other='other value', more=None), [
41            '/base/page?param=value&other=other+value',
42            '/base/page?other=other+value&param=value'])
43        self.assertEqual('/base/page?param=multiple&param=values',
44                         href('page', param=['multiple', 'values']))
45
46        self.assertEqual('/base/path/to/file/', href + '/path/to/file/')
47        self.assertEqual('/base/path/to/file', href + 'path/to/file')
48        self.assertEqual('/base', href + '')
49
50    def test_base_with_trailing_slash(self):
51        """Build URLs with a base with a trailing slash."""
52        href = trac.web.href.Href('/base/')
53        self.assertEqual('/base', href())
54        self.assertEqual('/base', href('/'))
55        self.assertEqual('/base/sub', href('sub'))
56        self.assertEqual('/base/sub', href('/sub/'))
57
58        self.assertEqual('/base/path/to/file/', href + '/path/to/file/')
59        self.assertEqual('/base/path/to/file', href + 'path/to/file')
60        self.assertEqual('/base', href + '')
61
62    def test_empty_base(self):
63        """Build URLs with an empty base."""
64        href = trac.web.href.Href('')
65        self.assertEqual('/', href())
66        self.assertEqual('/', href('/'))
67        self.assertEqual('/sub', href('sub'))
68        self.assertEqual('/sub', href('/sub/'))
69        self.assertEqual('/sub/other', href('sub', 'other'))
70        self.assertEqual('/sub/other', href('sub', None, 'other'))
71        self.assertEqual('/sub/other', href('sub', '', 'other'))
72        self.assertEqual('/sub/other', href('sub', '', '', 'other'))
73        self.assertEqual('/sub/other', href('', 'sub', 'other'))
74        self.assertEqual('/sub/other/', href('sub', 'other', ''))
75        self.assertEqual('/with%20special%26chars',
76                         href('with special&chars'))
77        self.assertIn(
78            href('page', param='value', other='other value', more=None),
79            ['/page?param=value&other=other+value',
80             '/page?other=other+value&param=value'])
81        self.assertEqual('/page?param=multiple&param=values',
82                         href('page', param=['multiple', 'values']))
83
84        self.assertEqual('/path/to/file/', href + '/path/to/file/')
85        self.assertEqual('/path/to/file', href + 'path/to/file')
86        self.assertEqual('/', href + '')
87        self.assertEqual('/?name=val', href + '?name=val')
88
89    def test_params_subclasses(self):
90        """Parameters passed using subclasses of dict, list and tuple."""
91        class MyDict(dict):
92            pass
93        class MyList(list):
94            pass
95        class MyTuple(tuple):
96            pass
97        href = trac.web.href.Href('/base')
98        self.assertEqual('/base?param=test&param=other',
99                         href(param=MyList(['test', 'other'])))
100        self.assertEqual('/base?param=test&param=other',
101                         href(param=MyTuple(['test', 'other'])))
102        self.assertIn(href(MyDict(param='value', other='other value')), [
103            '/base?param=value&other=other+value',
104            '/base?other=other+value&param=value'])
105        self.assertEqual('/base?param=value&other=other+value',
106                         href(MyList([('param', 'value'), ('other', 'other value')])))
107        self.assertEqual('/base?param=value&other=other+value',
108                         href(MyTuple([('param', 'value'), ('other', 'other value')])))
109
110    def test_add_unicode(self):
111        href = trac.web.href.Href('/base')
112        self.assertEqual('/base/p%C3%A4th/to/%20/file/',
113                         href + '/päth/to/ /file/')
114        self.assertEqual('/base/p%C3%A4th/to/%20/file',
115                         href + 'päth/to/ /file')
116        self.assertEqual('/base?type=def%C3%A9ct&or&type=abc%20def',
117                         href + '?type=deféct&or&type=abc def')
118        self.assertEqual('/base/p%C3%A4th/to/file/'
119                         '?type=def%C3%A9ct&or&type=abc%20def',
120                         href + '/päth/to/file/?type=deféct&or&type=abc def')
121        self.assertEqual('/base/p%C3%A4th/to/file'
122                         '?type=def%C3%A9ct&or&type=abc%20def',
123                         href + 'päth/to/file?type=deféct&or&type=abc def')
124
125    def test_jinja2(self):
126        # https://trac.edgewall.org/ticket/13244
127
128        data = {'href': trac.web.href.Href('http://localhost/base')}
129        self.assertEqual(
130            '<a href="http://localhost/base">anchor</a>',
131            self._render_template('<a href="${href()}">anchor</a>', data))
132        self.assertEqual(
133            'URL: http://localhost/base',
134            self._render_template('URL: ${href()}', data, text=True))
135
136    def _render_template(self, template, data, text=False):
137        t = jinja2template(template, text=text)
138        return t.render(**data)
139
140
141def test_suite():
142    suite = unittest.TestSuite()
143    suite.addTest(doctest.DocTestSuite(trac.web.href))
144    suite.addTest(unittest.makeSuite(HrefTestCase))
145    return suite
146
147if __name__ == '__main__':
148    unittest.main(defaultTest='test_suite')
149