Skip to content

Commit b6d147f

Browse files
authored
Add json serialize test (#182)
* WIP * add json-serialize-tests, and add two fields being not implemented * fix lint warning * add richMenu tests, and refactor * add tests for get_message_quota
1 parent 7e75ade commit b6d147f

File tree

10 files changed

+977
-4
lines changed

10 files changed

+977
-4
lines changed

linebot/models/events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
DeviceLink,
3737
ScenarioResult,
3838
)
39-
from linebot.models.things import Things # noqa
39+
from linebot.models.things import Things # noqa, backward compatibility
4040

4141

4242
class Event(with_metaclass(ABCMeta, Base)):

linebot/models/template.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class ButtonsTemplate(Template):
8181
def __init__(self, text=None, title=None, thumbnail_image_url=None,
8282
image_aspect_ratio=None,
8383
image_size=None, image_background_color=None,
84-
actions=None, **kwargs):
84+
actions=None, default_action=None, **kwargs):
8585
"""__init__ method.
8686
8787
:param str text: Message text.
@@ -105,6 +105,9 @@ def __init__(self, text=None, title=None, thumbnail_image_url=None,
105105
:param actions: Action when tapped.
106106
Max: 4
107107
:type actions: list[T <= :py:class:`linebot.models.actions.Action`]
108+
:param default_action: Action when image is tapped;
109+
set for the entire image, title, and text area
110+
:type default_action: T <= :py:class:`linebot.models.actions.Action`
108111
:param kwargs:
109112
"""
110113
super(ButtonsTemplate, self).__init__(**kwargs)
@@ -117,6 +120,7 @@ def __init__(self, text=None, title=None, thumbnail_image_url=None,
117120
self.image_size = image_size
118121
self.image_background_color = image_background_color
119122
self.actions = get_actions(actions)
123+
self.default_action = get_action(default_action)
120124

121125

122126
class ConfirmTemplate(Template):
@@ -214,8 +218,9 @@ class CarouselColumn(Base):
214218
https://developers.line.biz/en/reference/messaging-api/#column-object
215219
"""
216220

217-
def __init__(self, text=None, title=None, thumbnail_image_url=None,
218-
image_background_color=None, actions=None, **kwargs):
221+
def __init__(self, text=None, title=None,
222+
thumbnail_image_url=None, image_background_color=None,
223+
actions=None, default_action=None, **kwargs):
219224
"""__init__ method.
220225
221226
:param str text: Message text.
@@ -230,6 +235,9 @@ def __init__(self, text=None, title=None, thumbnail_image_url=None,
230235
:param actions: Action when tapped.
231236
Max: 3
232237
:type actions: list[T <= :py:class:`linebot.models.actions.Action`]
238+
:param default_action: Action when image is tapped;
239+
set for the entire image, title, and text area
240+
:type default_action: T <= :py:class:`linebot.models.actions.Action`
233241
:param kwargs:
234242
"""
235243
super(CarouselColumn, self).__init__(**kwargs)
@@ -239,6 +247,7 @@ def __init__(self, text=None, title=None, thumbnail_image_url=None,
239247
self.thumbnail_image_url = thumbnail_image_url
240248
self.image_background_color = image_background_color
241249
self.actions = get_actions(actions)
250+
self.default_action = get_action(default_action)
242251

243252

244253
class ImageCarouselColumn(Base):

tests/api/test_get_message_quota.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# -*- coding: utf-8 -*-
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# https://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, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
from __future__ import unicode_literals, absolute_import
16+
17+
import unittest
18+
19+
import responses
20+
21+
from linebot import (
22+
LineBotApi
23+
)
24+
25+
26+
class TestLineBotApi(unittest.TestCase):
27+
def setUp(self):
28+
self.tested = LineBotApi('channel_secret')
29+
30+
@responses.activate
31+
def test_get_message_quota(self):
32+
responses.add(
33+
responses.GET,
34+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/quota',
35+
json={
36+
'type': 'limited',
37+
'value': 1000
38+
},
39+
status=200
40+
)
41+
res = self.tested.get_message_quota()
42+
request = responses.calls[0].request
43+
self.assertEqual('GET', request.method)
44+
self.assertEqual('limited', res.type)
45+
self.assertEqual(1000, res.value)
46+
47+
@responses.activate
48+
def test_get_message_quota_2(self):
49+
responses.add(
50+
responses.GET,
51+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/quota',
52+
json={'type': 'none'},
53+
status=200
54+
)
55+
res = self.tested.get_message_quota()
56+
request = responses.calls[0].request
57+
self.assertEqual('GET', request.method)
58+
self.assertEqual('none', res.type)
59+
60+
@responses.activate
61+
def test_get_message_quota_consumption(self):
62+
responses.add(
63+
responses.GET,
64+
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/message/quota/consumption',
65+
json={'totalUsage': 500},
66+
status=200
67+
)
68+
res = self.tested.get_message_quota_consumption()
69+
request = responses.calls[0].request
70+
self.assertEqual('GET', request.method)
71+
self.assertEqual(500, res.total_usage)
72+
73+
74+
if __name__ == '__main__':
75+
unittest.main()

tests/api/test_rich_menu.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,56 @@ def test_cancel_default_rich_menu(self):
388388
LineBotApi.DEFAULT_API_ENDPOINT + '/v2/bot/user/all/richmenu'
389389
)
390390

391+
@responses.activate
392+
def test_get_rich_menu_image(self):
393+
rich_menu_id = '1234'
394+
body = b'hogieoidksk'
395+
responses.add(
396+
responses.GET,
397+
LineBotApi.DEFAULT_API_ENDPOINT +
398+
'/v2/bot/richmenu/{rich_menu_id}/content'.format(rich_menu_id=rich_menu_id),
399+
body=body, status=200
400+
)
401+
402+
res = self.tested.get_rich_menu_image(rich_menu_id)
403+
404+
request = responses.calls[0].request
405+
self.assertEqual(request.method, 'GET')
406+
self.assertEqual(
407+
request.url,
408+
LineBotApi.DEFAULT_API_ENDPOINT +
409+
'/v2/bot/richmenu/{rich_menu_id}/content'.format(rich_menu_id=rich_menu_id),
410+
)
411+
self.assertEqual(
412+
body,
413+
res.content
414+
)
415+
416+
@responses.activate
417+
def test_set_rich_menu_image(self):
418+
rich_menu_id = '1234'
419+
body = b'hogieoidksk'
420+
responses.add(
421+
responses.POST,
422+
LineBotApi.DEFAULT_API_ENDPOINT +
423+
'/v2/bot/richmenu/{rich_menu_id}/content'.format(rich_menu_id=rich_menu_id),
424+
json={}, status=200
425+
)
426+
427+
self.tested.set_rich_menu_image(
428+
rich_menu_id=rich_menu_id,
429+
content_type='image/jpeg',
430+
content=body
431+
)
432+
433+
request = responses.calls[0].request
434+
self.assertEqual('POST', request.method)
435+
self.assertEqual(
436+
LineBotApi.DEFAULT_API_ENDPOINT +
437+
'/v2/bot/richmenu/{rich_menu_id}/content'.format(rich_menu_id=rich_menu_id),
438+
request.url
439+
)
440+
391441

392442
if __name__ == '__main__':
393443
unittest.main()

tests/models/serialize_test_case.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# -*- coding: utf-8 -*-
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# https://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, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
from __future__ import unicode_literals, absolute_import
16+
17+
import sys
18+
import unittest
19+
from numbers import Number
20+
21+
from linebot.models import (
22+
Base,
23+
)
24+
from linebot.utils import to_camel_case
25+
26+
PY3 = sys.version_info[0] == 3
27+
28+
29+
class SerializeTestCase(unittest.TestCase):
30+
MESSAGE = 'message'
31+
STICKER = 'sticker'
32+
POSTBACK = 'postback'
33+
CAMERA = 'camera'
34+
CAMERA_ROLL = 'cameraRoll'
35+
DATETIMEPICKER = 'datetimepicker'
36+
URI = 'uri'
37+
LOCATION = 'location'
38+
FLEX = 'flex'
39+
SPACER = 'spacer'
40+
BUBBLE = 'bubble'
41+
CAROUSEL = 'carousel'
42+
BOX = 'box'
43+
BUTTON = 'button'
44+
FILLER = 'filler'
45+
ICON = 'icon'
46+
TEXT = 'text'
47+
IMAGE = 'image'
48+
VIDEO = 'video'
49+
AUDIO = 'audio'
50+
SEPARATOR = 'separator'
51+
IMAGEMAP = 'imagemap'
52+
ACTION = 'action'
53+
TEMPLATE = 'template'
54+
BUTTONS = 'buttons'
55+
CONFIRM = 'confirm'
56+
IMAGE_CAROUSEL = 'image_carousel'
57+
58+
def serialize_as_dict(self, obj, type=None):
59+
if isinstance(obj, Base):
60+
return obj.as_json_dict()
61+
elif isinstance(obj, dict):
62+
ret = {to_camel_case(k): self.serialize_as_dict(v) for k, v in obj.items()}
63+
if type is not None:
64+
ret['type'] = type
65+
return ret
66+
elif isinstance(obj, list):
67+
return [self.serialize_as_dict(elem) for elem in obj]
68+
else:
69+
if PY3:
70+
self.assertIsInstance(obj, (str, bool, Number))
71+
else:
72+
self.assertIsInstance(obj, (basestring, bool, Number)) # noqa
73+
return obj
74+
75+
class ConstError(TypeError):
76+
pass
77+
78+
def __setattr__(self, name, value):
79+
if name in SerializeTestCase.__dict__:
80+
raise self.ConstError("Can't rebind const (%s)" % name)
81+
self.__dict__[name] = value

tests/models/test_actions.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# -*- coding: utf-8 -*-
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# https://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, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
from __future__ import unicode_literals, absolute_import
16+
17+
import unittest
18+
19+
from linebot.models import (
20+
PostbackAction,
21+
MessageAction,
22+
CameraRollAction,
23+
CameraAction,
24+
URIAction,
25+
LocationAction,
26+
DatetimePickerAction,
27+
AltUri,
28+
)
29+
from tests.models.serialize_test_case import SerializeTestCase
30+
31+
32+
class TestActions(SerializeTestCase):
33+
def test_postback(self):
34+
arg = {
35+
'label': 'Buy',
36+
'data': 'action=buy&id=1',
37+
'display_text': 'buy'
38+
}
39+
self.assertEqual(
40+
self.serialize_as_dict(arg, type=self.POSTBACK),
41+
PostbackAction(**arg).as_json_dict()
42+
)
43+
44+
def test_message(self):
45+
arg = {
46+
'label': 'Yes',
47+
'text': 'yes'
48+
}
49+
self.assertEqual(
50+
self.serialize_as_dict(arg, type=self.MESSAGE),
51+
MessageAction(**arg).as_json_dict()
52+
)
53+
54+
def test_camera(self):
55+
arg = {
56+
'label': 'camera'
57+
}
58+
self.assertEqual(
59+
self.serialize_as_dict(arg, type=self.CAMERA),
60+
CameraAction(**arg).as_json_dict()
61+
)
62+
63+
def test_camera_roll(self):
64+
arg = {
65+
'label': 'camera roll'
66+
}
67+
self.assertEqual(
68+
self.serialize_as_dict(arg, type=self.CAMERA_ROLL),
69+
CameraRollAction(**arg).as_json_dict()
70+
)
71+
72+
def test_datetime_picker(self):
73+
arg = {
74+
'label': 'Select date',
75+
'data': 'storeId=12345',
76+
'mode': 'datetime',
77+
'initial': '2017-12-25t00:00',
78+
'max': '2018-01-24t23:59',
79+
'min': '2017-12-25t00:00'
80+
}
81+
self.assertEqual(
82+
self.serialize_as_dict(arg, type=self.DATETIMEPICKER),
83+
DatetimePickerAction(**arg).as_json_dict()
84+
)
85+
86+
def test_uri(self):
87+
arg = {
88+
'label': 'View detail',
89+
'uri': 'https://example.com',
90+
'alt_uri': AltUri(desktop='https://example.com')
91+
}
92+
self.assertEqual(
93+
self.serialize_as_dict(arg, type=self.URI),
94+
URIAction(**arg).as_json_dict()
95+
)
96+
97+
def test_location(self):
98+
arg = {
99+
'label': 'Location'
100+
}
101+
self.assertEqual(
102+
self.serialize_as_dict(arg, type=self.LOCATION),
103+
LocationAction(**arg).as_json_dict()
104+
)
105+
106+
107+
if __name__ == '__main__':
108+
unittest.main()

0 commit comments

Comments
 (0)