1import json
2
3import pytest
4import flask
5from click.testing import CliRunner
6
7from bukuserver import server
8from bukuserver.response import response_template
9from bukuserver.server import get_bool_from_env_var
10
11
12@pytest.mark.parametrize(
13    'args,word',
14    [
15        ('--help', 'bukuserver'),
16        ('--version', 'buku')
17    ]
18)
19def test_cli(args, word):
20    runner = CliRunner()
21    result = runner.invoke(server.cli, [args])
22    assert result.exit_code == 0
23    assert word in result.output
24
25
26@pytest.fixture
27def client(tmp_path):
28    test_db = tmp_path / 'test.db'
29    app = server.create_app(test_db.as_posix())
30    client = app.test_client()
31    return client
32
33
34def test_home(client):
35    rd = client.get('/')
36    assert rd.status_code == 200
37    assert not flask.g.bukudb.get_rec_all()
38
39
40@pytest.mark.parametrize(
41    'url, exp_res', [
42        ['/api/tags', {'tags': []}],
43        ['/api/bookmarks', {'bookmarks': []}],
44        ['/api/bookmarks/search', {'bookmarks': []}],
45        ['/api/bookmarks/refresh', response_template['failure']]
46    ]
47)
48def test_api_empty_db(client, url, exp_res):
49    if url == '/api/bookmarks/refresh':
50        rd = client.post(url)
51        assert rd.status_code == 400
52    else:
53        rd = client.get(url)
54        assert rd.status_code == 200
55    assert rd.get_json() == exp_res
56
57
58@pytest.mark.parametrize(
59    'url, exp_res, status_code, method', [
60        ['/api/tags/1', {'message': 'This resource does not exist.'}, 404, 'get'],
61        ['/api/tags/1', response_template['failure'], 400, 'put'],
62        ['/api/bookmarks/1', response_template['failure'], 400, 'get'],
63        ['/api/bookmarks/1', response_template['failure'], 400, 'put'],
64        ['/api/bookmarks/1', response_template['failure'], 400, 'delete'],
65        ['/api/bookmarks/1/refresh', response_template['failure'], 400, 'post'],
66        ['/api/bookmarks/1/tiny', response_template['failure'], 400, 'get'],
67        ['/api/bookmarks/1/2', response_template['failure'], 400, 'get'],
68        ['/api/bookmarks/1/2', response_template['failure'], 400, 'put'],
69        ['/api/bookmarks/1/2', response_template['failure'], 400, 'delete'],
70    ]
71)
72def test_invalid_id(client, url, exp_res, status_code, method):
73    rd = getattr(client, method)(url)
74    assert rd.status_code == status_code
75    assert rd.get_json() == exp_res
76
77
78def test_tag_api(client):
79    url = 'http://google.com'
80    rd = client.post('/api/bookmarks', data={'url': url, 'tags': 'tag1,tag2'})
81    assert rd.status_code == 200
82    assert rd.get_json() == response_template['success']
83    rd = client.get('/api/tags')
84    assert rd.status_code == 200
85    assert rd.get_json() == {'tags': ['tag1', 'tag2']}
86    rd = client.get('/api/tags/tag1')
87    assert rd.status_code == 200
88    assert rd.get_json() == {'name': 'tag1', 'usage_count': 1}
89    rd = client.put('/api/tags/tag1', data={'tags': 'tag3,tag4'})
90    assert rd.status_code == 200
91    assert rd.get_json() == response_template['success']
92    rd = client.get('/api/tags')
93    assert rd.status_code == 200
94    assert rd.get_json() == {'tags': ['tag2', 'tag3 tag4']}
95    rd = client.put('/api/tags/tag2', data={'tags': 'tag5'})
96    assert rd.status_code == 200
97    assert rd.get_json() == response_template['success']
98    rd = client.get('/api/tags')
99    assert rd.status_code == 200
100    assert rd.get_json() == {'tags': ['tag3 tag4', 'tag5']}
101    rd = client.get('/api/bookmarks/1')
102    assert rd.status_code == 200
103    assert rd.get_json() == {
104        'description': '', 'tags': ['tag3 tag4', 'tag5'], 'title': '',
105        'url': 'http://google.com'}
106
107
108def test_bookmark_api(client):
109    url = 'http://google.com'
110    rd = client.post('/api/bookmarks', data={'url': url})
111    assert rd.status_code == 200
112    assert rd.get_json() == response_template['success']
113    rd = client.post('/api/bookmarks', data={'url': url})
114    assert rd.status_code == 400
115    assert rd.get_json() == response_template['failure']
116    rd = client.get('/api/bookmarks')
117    assert rd.status_code == 200
118    assert rd.get_json() == {'bookmarks': [{
119        'description': '', 'tags': [], 'title': '', 'url': 'http://google.com'}]}
120    rd = client.get('/api/bookmarks/1')
121    assert rd.status_code == 200
122    assert rd.get_json() == {
123        'description': '', 'tags': [], 'title': '', 'url': 'http://google.com'}
124    rd = client.put('/api/bookmarks/1', data={'tags': [',tag1,tag2,']})
125    assert rd.status_code == 200
126    assert rd.get_json() == response_template['success']
127    rd = client.get('/api/bookmarks/1')
128    assert rd.status_code == 200
129    assert rd.get_json() == {
130        'description': '', 'tags': ['tag1', 'tag2'], 'title': '', 'url': 'http://google.com'}
131
132
133@pytest.mark.parametrize('d_url', ['/api/bookmarks', '/api/bookmarks/1'])
134def test_bookmark_api_delete(client, d_url):
135    url = 'http://google.com'
136    rd = client.post('/api/bookmarks', data={'url': url})
137    assert rd.status_code == 200
138    assert rd.get_json() == response_template['success']
139    rd = client.delete(d_url)
140    assert rd.status_code == 200
141    assert rd.get_json() == response_template['success']
142
143
144@pytest.mark.parametrize('api_url', ['/api/bookmarks/refresh', '/api/bookmarks/1/refresh'])
145def test_refresh_bookmark(client, api_url):
146    url = 'http://google.com'
147    rd = client.post('/api/bookmarks', data={'url': url})
148    assert rd.status_code == 200
149    assert rd.get_json() == response_template['success']
150    rd = client.post(api_url)
151    assert rd.status_code == 200
152    assert rd.get_json() == response_template['success']
153    rd = client.get('/api/bookmarks/1')
154    assert rd.status_code == 200
155    json_data = rd.get_json()
156    json_data.pop('description')
157    assert json_data == {'tags': [], 'title': 'Google', 'url': 'http://google.com'}
158
159
160@pytest.mark.parametrize(
161    'url, exp_res, status_code', [
162        ['http://google.com', {'url': 'http://tny.im/2'}, 200],
163        ['chrome://bookmarks/', response_template['failure'], 400],
164    ])
165def test_get_tiny_url(client, url, exp_res, status_code):
166    rd = client.post('/api/bookmarks', data={'url': url})
167    assert rd.status_code == 200
168    assert rd.get_json() == response_template['success']
169    rd = client.get('/api/bookmarks/1/tiny')
170    assert rd.status_code == status_code
171    assert rd.get_json() == exp_res
172
173
174@pytest.mark.parametrize('kwargs, status_code, exp_res', [
175    [
176        dict(data={'url': 'http://google.com'}),
177        200,
178        {
179            'bad url': 0, 'recognized mime': 0,
180            'tags': None, 'title': 'Google'}
181    ],
182    [{}, 400, response_template['failure']],
183    [
184        dict(data={'url': 'chrome://bookmarks/'}),
185        200,
186        {
187            'bad url': 1, 'recognized mime': 0,
188            'tags': None, 'title': None}
189    ],
190])
191def test_network_handle(client, kwargs, status_code, exp_res):
192    rd = client.post('/api/network_handle', **kwargs)
193    assert rd.status_code == status_code
194    rd_json = rd.get_json()
195    rd_json.pop('description', None)
196    assert rd_json == exp_res
197
198
199def test_bookmark_range_api(client):
200    status_code = 200
201    kwargs_list = [
202        dict(data={'url': 'http://google.com'}),
203        dict(data={'url': 'http://example.com'})]
204    for kwargs in kwargs_list:
205        rd = client.post('/api/bookmarks', **kwargs)
206        assert rd.status_code == status_code
207    rd = client.get('/api/bookmarks/1/2')
208    assert rd.status_code == status_code
209    assert rd.get_json() == {
210        'bookmarks': {
211            '1': {'description': '', 'tags': [], 'title': '', 'url': 'http://google.com'},
212            '2': {'description': '', 'tags': [], 'title': '', 'url': 'http://example.com'}}}
213    put_data = json.dumps({1: {'tags': 'tag1'}, 2: {'tags': 'tag2'}})
214    headers = {'content-type': 'application/json'}
215    rd = client.put('/api/bookmarks/1/2', data=put_data, headers=headers)
216    assert rd.status_code == status_code
217    assert rd.get_json() == response_template['success']
218    rd = client.delete('/api/bookmarks/1/2')
219    assert rd.status_code == status_code
220    assert rd.get_json() == response_template['success']
221    rd = client.get('/api/bookmarks')
222    assert rd.get_json() == {'bookmarks': []}
223
224
225def test_bookmark_search(client):
226    status_code = 200
227    rd = client.post('/api/bookmarks', data={'url': 'http://google.com'})
228    assert rd.status_code == status_code
229    assert rd.get_json() == response_template['success']
230    rd = client.get('/api/bookmarks/search', query_string={'keywords': ['google']})
231    assert rd.status_code == status_code
232    assert rd.get_json() == {'bookmarks': [
233        {'description': '', 'id': 1, 'tags': [], 'title': '', 'url': 'http://google.com'}]}
234    rd = client.delete('/api/bookmarks/search', data={'keywords': ['google']})
235    assert rd.status_code == status_code
236    assert rd.get_json() == response_template['success']
237    rd = client.get('/api/bookmarks')
238    assert rd.get_json() == {'bookmarks': []}
239
240
241@pytest.mark.parametrize('env_val, exp_val', [
242    ['true', True],
243    ['false', False],
244    ['0', False],
245    ['1', True],
246    [None, True],
247    ['random', True]
248])
249def test_get_bool_from_env_var(monkeypatch, env_val, exp_val):
250    key = 'BUKUSERVER_TEST'
251    if env_val is not None:
252        monkeypatch.setenv(key, env_val)
253    assert get_bool_from_env_var(key, True) == exp_val
254