Skip to content

Commit 3011c8a

Browse files
committed
Add test coverage for search hints
1 parent 1e9695f commit 3011c8a

3 files changed

Lines changed: 58 additions & 4 deletions

File tree

events/__init__.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from .errors import *
1717
from .subscribe import send_event_email, subscribe_to_event, validate_email
1818
from .access import validate_token, generate_access_url
19-
from .utils import get_event_component, increase_event_seq_number, get_event_components
19+
from .utils import get_event_component, increase_event_seq_number, get_event_components, expect_type
2020
from datetime import datetime, date, timedelta
2121
from tzlocal import get_localzone
2222
from flask_wtf.csrf import CSRFProtect
@@ -414,11 +414,22 @@ def search_api(collection):
414414
if body is None:
415415
raise HTTPException(400, 'Invalid request: empty body')
416416

417-
search_term = body.get('pattern', '').strip()
417+
search_term = body.get('pattern', '')
418+
expect_type(search_term, [str], 'pattern')
419+
420+
search_term = search_term.strip()
421+
418422
before = body.get('before', inf)
423+
expect_type(before, [int, float], 'before', allow_none=True)
424+
419425
after = body.get('after', 0)
426+
expect_type(after, [int, float], 'after', allow_none=True)
427+
420428
exact = body.get('exact', False)
429+
expect_type(exact, [bool], 'exact')
430+
421431
hint = body.get('hint', None)
432+
expect_type(hint, [str], 'hint', allow_none=True)
422433

423434
matched_collection = get_collection(collection)
424435

events/test_events.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,13 @@
146146

147147
redirect_map = {'redirect-uid': 'event_5.ics', 'redirect-uid-14': 'event_14.ics'}
148148

149+
uid_only_event = Event()
150+
uid_only_event.add('dtstart', date(2012, 10, 10))
151+
uid_only_event['summary'] = 'uid_only_title'
152+
uid_only_event.add('dtend', datetime(2012, 10, 10, 10, 0, 0))
153+
uid_only_event['uid'] = 'uid_only'
154+
155+
149156

150157
save_event_override = None
151158

@@ -178,7 +185,10 @@ def lookup_event_by_uid(self, uid: str):
178185
raise NotFoundException(f'event with UID: {uid} not found')
179186

180187
def get_event_impl(self, name: str):
181-
event = self.content.get(remove_ics(name))
188+
if name == 'uid_only':
189+
event = uid_only_event # To test that event are looked up by UID and not via the entire collection
190+
else:
191+
event = self.content.get(remove_ics(name))
182192

183193
if not event:
184194
return None
@@ -300,7 +310,7 @@ def test_search_api_without_admin(client):
300310
assert response.status_code == 404
301311

302312

303-
def search_api(client, pattern: str, before: int = None, after: int = None, exact: bool = None) -> list:
313+
def search_api(client, pattern: str, before: int = None, after: int = None, exact: bool = None, hint: str = None) -> list:
304314
body = {'pattern': pattern}
305315

306316
if before is not None:
@@ -312,6 +322,9 @@ def search_api(client, pattern: str, before: int = None, after: int = None, exac
312322
if exact is not None:
313323
body['exact'] = exact
314324

325+
if hint is not None:
326+
body['hint'] = hint
327+
315328
response = client.post(f'api/1/search', data=json.dumps(body), headers={'X-Admin': 'true', 'Content-Type': 'application/json'})
316329
assert response.status_code == 200
317330

@@ -411,7 +424,28 @@ def test_search_rrule_occurence(client):
411424
content = search_api(client, "yearly_repeating_event", before=before, after=after)
412425
assert [e['title'] for e in content] == ['yearly_repeating_event']
413426

427+
def test_search_api_hint_match(client):
428+
content = search_api(client, "uid_only", hint='uid_only')
429+
assert [e['title'] for e in content] == ['uid_only_title']
430+
431+
def test_search_api_hint_no_match(client):
432+
content = search_api(client, "event_12", hint='uid_only')
433+
assert [e['title'] for e in content] == ['event_12']
434+
435+
def test_search_api_test_bad_types(client):
436+
def expect(body):
437+
response = client.post(f'api/1/search', data=json.dumps(body), headers={'X-Admin': 'true', 'Content-Type': 'application/json'})
438+
assert response.status_code == 404
439+
440+
expect({'pattern': None})
441+
expect({'pattern': 12})
442+
expect({'pattern': '12', 'hint': 12})
443+
expect({'pattern': '12', 'hint': 12})
414444

445+
expect({'pattern': '12', 'after': 'True'})
446+
expect({'pattern': '12', 'before': 'foo'})
447+
expect({'pattern': '12', 'exact': 'yes'})
448+
expect({'pattern': '12', 'exact': None})
415449

416450
def test_view_event_admin(client):
417451
response = client.get('/1/event_1.ics', headers={'X-Admin': 'true'})

events/utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from .errors import SuspiciousRequest
2+
13
def get_event_components(event) -> list:
24
if 'summary' in event:
35
return [event]
@@ -25,3 +27,10 @@ def increase_event_seq_number(event):
2527

2628
component['sequence'] = sequence
2729
return event
30+
31+
def expect_type(value, types, name: str, allow_none=False):
32+
if value is None and allow_none:
33+
return
34+
35+
if not any(isinstance(value, e) for e in types):
36+
raise SuspiciousRequest(f"Unexpected type for '{name}': {type(value).__name__}")

0 commit comments

Comments
 (0)