1# Copyright 2015 Google Inc. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Unit tests for googleapiclient._helpers."""
16
17import unittest
18import urllib
19
20import mock
21from googleapiclient import _helpers
22
23
24class PositionalTests(unittest.TestCase):
25    def test_usage(self):
26        _helpers.positional_parameters_enforcement = _helpers.POSITIONAL_EXCEPTION
27
28        # 1 positional arg, 1 keyword-only arg.
29        @_helpers.positional(1)
30        def function(pos, kwonly=None):
31            return True
32
33        self.assertTrue(function(1))
34        self.assertTrue(function(1, kwonly=2))
35        with self.assertRaises(TypeError):
36            function(1, 2)
37
38        # No positional, but a required keyword arg.
39        @_helpers.positional(0)
40        def function2(required_kw):
41            return True
42
43        self.assertTrue(function2(required_kw=1))
44        with self.assertRaises(TypeError):
45            function2(1)
46
47        # Unspecified positional, should automatically figure out 1 positional
48        # 1 keyword-only (same as first case above).
49        @_helpers.positional
50        def function3(pos, kwonly=None):
51            return True
52
53        self.assertTrue(function3(1))
54        self.assertTrue(function3(1, kwonly=2))
55        with self.assertRaises(TypeError):
56            function3(1, 2)
57
58    @mock.patch("googleapiclient._helpers.logger")
59    def test_enforcement_warning(self, mock_logger):
60        _helpers.positional_parameters_enforcement = _helpers.POSITIONAL_WARNING
61
62        @_helpers.positional(1)
63        def function(pos, kwonly=None):
64            return True
65
66        self.assertTrue(function(1, 2))
67        self.assertTrue(mock_logger.warning.called)
68
69    @mock.patch("googleapiclient._helpers.logger")
70    def test_enforcement_ignore(self, mock_logger):
71        _helpers.positional_parameters_enforcement = _helpers.POSITIONAL_IGNORE
72
73        @_helpers.positional(1)
74        def function(pos, kwonly=None):
75            return True
76
77        self.assertTrue(function(1, 2))
78        self.assertFalse(mock_logger.warning.called)
79
80
81class AddQueryParameterTests(unittest.TestCase):
82    def test__add_query_parameter(self):
83        self.assertEqual(_helpers._add_query_parameter("/action", "a", None), "/action")
84        self.assertEqual(
85            _helpers._add_query_parameter("/action", "a", "b"), "/action?a=b"
86        )
87        self.assertEqual(
88            _helpers._add_query_parameter("/action?a=b", "a", "c"), "/action?a=c"
89        )
90        # Order is non-deterministic.
91        self.assertIn(
92            _helpers._add_query_parameter("/action?a=b", "c", "d"),
93            ["/action?a=b&c=d", "/action?c=d&a=b"],
94        )
95        self.assertEqual(
96            _helpers._add_query_parameter("/action", "a", " ="), "/action?a=+%3D"
97        )
98
99
100def assertUrisEqual(testcase, expected, actual):
101    """Test that URIs are the same, up to reordering of query parameters."""
102    expected = urllib.parse.urlparse(expected)
103    actual = urllib.parse.urlparse(actual)
104    testcase.assertEqual(expected.scheme, actual.scheme)
105    testcase.assertEqual(expected.netloc, actual.netloc)
106    testcase.assertEqual(expected.path, actual.path)
107    testcase.assertEqual(expected.params, actual.params)
108    testcase.assertEqual(expected.fragment, actual.fragment)
109    expected_query = urllib.parse.parse_qs(expected.query)
110    actual_query = urllib.parse.parse_qs(actual.query)
111    for name in expected_query.keys():
112        testcase.assertEqual(expected_query[name], actual_query[name])
113    for name in actual_query.keys():
114        testcase.assertEqual(expected_query[name], actual_query[name])
115
116
117class Test_update_query_params(unittest.TestCase):
118    def test_update_query_params_no_params(self):
119        uri = "http://www.google.com"
120        updated = _helpers.update_query_params(uri, {"a": "b"})
121        self.assertEqual(updated, uri + "?a=b")
122
123    def test_update_query_params_existing_params(self):
124        uri = "http://www.google.com?x=y"
125        updated = _helpers.update_query_params(uri, {"a": "b", "c": "d&"})
126        hardcoded_update = uri + "&a=b&c=d%26"
127        assertUrisEqual(self, updated, hardcoded_update)
128
129    def test_update_query_params_replace_param(self):
130        base_uri = "http://www.google.com"
131        uri = base_uri + "?x=a"
132        updated = _helpers.update_query_params(uri, {"x": "b", "y": "c"})
133        hardcoded_update = base_uri + "?x=b&y=c"
134        assertUrisEqual(self, updated, hardcoded_update)
135
136    def test_update_query_params_repeated_params(self):
137        uri = "http://www.google.com?x=a&x=b"
138        with self.assertRaises(ValueError):
139            _helpers.update_query_params(uri, {"a": "c"})
140
141
142class Test_parse_unique_urlencoded(unittest.TestCase):
143    def test_without_repeats(self):
144        content = "a=b&c=d"
145        result = _helpers.parse_unique_urlencoded(content)
146        self.assertEqual(result, {"a": "b", "c": "d"})
147
148    def test_with_repeats(self):
149        content = "a=b&a=d"
150        with self.assertRaises(ValueError):
151            _helpers.parse_unique_urlencoded(content)
152