2017-07-27 16:30:26 +01:00
|
|
|
import pytest
|
2018-02-20 11:22:17 +00:00
|
|
|
from freezegun import freeze_time
|
2017-05-04 09:30:55 +01:00
|
|
|
|
2018-03-21 16:01:26 +00:00
|
|
|
from app import format_datetime_relative
|
2021-01-06 12:12:01 +00:00
|
|
|
from app.formatters import email_safe, round_to_significant_figures
|
2017-01-13 11:37:14 +00:00
|
|
|
from app.utils import (
|
2018-02-20 11:22:17 +00:00
|
|
|
generate_next_dict,
|
2017-01-13 11:37:14 +00:00
|
|
|
generate_previous_dict,
|
2021-03-05 16:26:26 +00:00
|
|
|
get_current_financial_year,
|
2018-11-29 11:41:13 +00:00
|
|
|
get_logo_cdn_domain,
|
2020-09-29 13:17:12 +01:00
|
|
|
is_less_than_days_ago,
|
2020-08-13 12:38:12 +01:00
|
|
|
merge_jsonlike,
|
2017-01-13 11:37:14 +00:00
|
|
|
)
|
2017-04-20 14:55:14 +01:00
|
|
|
|
|
|
|
|
|
2016-10-27 17:31:13 +01:00
|
|
|
@pytest.mark.parametrize('service_name, safe_email', [
|
|
|
|
|
('name with spaces', 'name.with.spaces'),
|
|
|
|
|
('singleword', 'singleword'),
|
|
|
|
|
('UPPER CASE', 'upper.case'),
|
|
|
|
|
('Service - with dash', 'service.with.dash'),
|
|
|
|
|
('lots of spaces', 'lots.of.spaces'),
|
|
|
|
|
('name.with.dots', 'name.with.dots'),
|
|
|
|
|
('name-with-other-delimiters', 'namewithotherdelimiters'),
|
|
|
|
|
('.leading', 'leading'),
|
|
|
|
|
('trailing.', 'trailing'),
|
|
|
|
|
('üńïçödë wördś', 'unicode.words'),
|
|
|
|
|
])
|
|
|
|
|
def test_email_safe_return_dot_separated_email_domain(service_name, safe_email):
|
|
|
|
|
assert email_safe(service_name) == safe_email
|
2016-07-11 10:49:01 +01:00
|
|
|
|
|
|
|
|
|
2016-10-10 17:15:57 +01:00
|
|
|
def test_generate_previous_dict(client):
|
|
|
|
|
ret = generate_previous_dict('main.view_jobs', 'foo', 2, {})
|
|
|
|
|
assert 'page=1' in ret['url']
|
|
|
|
|
assert ret['title'] == 'Previous page'
|
|
|
|
|
assert ret['label'] == 'page 1'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_generate_next_dict(client):
|
|
|
|
|
ret = generate_next_dict('main.view_jobs', 'foo', 2, {})
|
|
|
|
|
assert 'page=3' in ret['url']
|
|
|
|
|
assert ret['title'] == 'Next page'
|
|
|
|
|
assert ret['label'] == 'page 3'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_generate_previous_next_dict_adds_other_url_args(client):
|
|
|
|
|
ret = generate_next_dict('main.view_notifications', 'foo', 2, {'message_type': 'blah'})
|
|
|
|
|
assert 'notifications/blah' in ret['url']
|
2016-10-26 15:44:24 +01:00
|
|
|
|
|
|
|
|
|
2017-07-24 15:20:40 +01:00
|
|
|
def test_get_cdn_domain_on_localhost(client, mocker):
|
|
|
|
|
mocker.patch.dict('app.current_app.config', values={'ADMIN_BASE_URL': 'http://localhost:6012'})
|
2018-11-29 11:41:13 +00:00
|
|
|
domain = get_logo_cdn_domain()
|
2017-07-24 15:20:40 +01:00
|
|
|
assert domain == 'static-logos.notify.tools'
|
|
|
|
|
|
|
|
|
|
|
2017-07-28 15:19:20 +01:00
|
|
|
def test_get_cdn_domain_on_non_localhost(client, mocker):
|
2017-07-24 15:20:40 +01:00
|
|
|
mocker.patch.dict('app.current_app.config', values={'ADMIN_BASE_URL': 'https://some.admintest.com'})
|
2018-11-29 11:41:13 +00:00
|
|
|
domain = get_logo_cdn_domain()
|
2017-07-24 15:20:40 +01:00
|
|
|
assert domain == 'static-logos.admintest.com'
|
2018-02-06 10:55:29 +00:00
|
|
|
|
|
|
|
|
|
2018-03-21 16:01:26 +00:00
|
|
|
@pytest.mark.parametrize('time, human_readable_datetime', [
|
|
|
|
|
('2018-03-14 09:00', '14 March at 9:00am'),
|
|
|
|
|
('2018-03-14 15:00', '14 March at 3:00pm'),
|
|
|
|
|
|
|
|
|
|
('2018-03-15 09:00', '15 March at 9:00am'),
|
|
|
|
|
('2018-03-15 15:00', '15 March at 3:00pm'),
|
|
|
|
|
|
|
|
|
|
('2018-03-19 09:00', '19 March at 9:00am'),
|
|
|
|
|
('2018-03-19 15:00', '19 March at 3:00pm'),
|
|
|
|
|
('2018-03-19 23:59', '19 March at 11:59pm'),
|
|
|
|
|
|
|
|
|
|
('2018-03-20 00:00', '19 March at midnight'), # we specifically refer to 00:00 as belonging to the day before.
|
|
|
|
|
('2018-03-20 00:01', 'yesterday at 12:01am'),
|
|
|
|
|
('2018-03-20 09:00', 'yesterday at 9:00am'),
|
|
|
|
|
('2018-03-20 15:00', 'yesterday at 3:00pm'),
|
|
|
|
|
('2018-03-20 23:59', 'yesterday at 11:59pm'),
|
|
|
|
|
|
|
|
|
|
('2018-03-21 00:00', 'yesterday at midnight'), # we specifically refer to 00:00 as belonging to the day before.
|
|
|
|
|
('2018-03-21 00:01', 'today at 12:01am'),
|
|
|
|
|
('2018-03-21 09:00', 'today at 9:00am'),
|
|
|
|
|
('2018-03-21 12:00', 'today at midday'),
|
|
|
|
|
('2018-03-21 15:00', 'today at 3:00pm'),
|
|
|
|
|
('2018-03-21 23:59', 'today at 11:59pm'),
|
|
|
|
|
|
|
|
|
|
('2018-03-22 00:00', 'today at midnight'), # we specifically refer to 00:00 as belonging to the day before.
|
|
|
|
|
('2018-03-22 00:01', 'tomorrow at 12:01am'),
|
|
|
|
|
('2018-03-22 09:00', 'tomorrow at 9:00am'),
|
|
|
|
|
('2018-03-22 15:00', 'tomorrow at 3:00pm'),
|
|
|
|
|
('2018-03-22 23:59', 'tomorrow at 11:59pm'),
|
|
|
|
|
|
|
|
|
|
('2018-03-23 00:01', '23 March at 12:01am'),
|
|
|
|
|
('2018-03-23 09:00', '23 March at 9:00am'),
|
|
|
|
|
('2018-03-23 15:00', '23 March at 3:00pm'),
|
|
|
|
|
|
|
|
|
|
])
|
|
|
|
|
def test_format_datetime_relative(time, human_readable_datetime):
|
|
|
|
|
with freeze_time('2018-03-21 12:00'):
|
|
|
|
|
assert format_datetime_relative(time) == human_readable_datetime
|
2018-11-27 16:49:01 +00:00
|
|
|
|
|
|
|
|
|
2020-02-03 14:27:30 +00:00
|
|
|
@pytest.mark.parametrize("date_from_db, expected_result", [
|
2020-02-04 16:57:22 +00:00
|
|
|
('2019-11-17T11:35:21.726132Z', True),
|
|
|
|
|
('2019-11-16T11:35:21.726132Z', False),
|
2020-09-29 13:17:12 +01:00
|
|
|
('2019-11-16T11:35:21+0000', False),
|
2020-02-03 14:27:30 +00:00
|
|
|
])
|
|
|
|
|
@freeze_time('2020-02-14T12:00:00')
|
2020-09-29 13:17:12 +01:00
|
|
|
def test_is_less_than_days_ago(date_from_db, expected_result):
|
|
|
|
|
assert is_less_than_days_ago(date_from_db, 90) == expected_result
|
2020-05-06 14:17:12 +01:00
|
|
|
|
|
|
|
|
|
2020-08-13 12:38:12 +01:00
|
|
|
@pytest.mark.parametrize("source_object, destination_object, expected_result", [
|
|
|
|
|
# simple dicts:
|
|
|
|
|
({"a": "b"}, {"c": "d"}, {"a": "b", "c": "d"}),
|
|
|
|
|
# dicts with nested dict, both under same key, additive behaviour:
|
|
|
|
|
({"a": {"b": "c"}}, {"a": {"e": "f"}}, {"a": {"b": "c", "e": "f"}}),
|
2021-01-21 16:49:12 +00:00
|
|
|
# same key in both dicts, value is a string, destination supercedes source:
|
2020-08-13 12:38:12 +01:00
|
|
|
({"a": "b"}, {"a": "c"}, {"a": "c"}),
|
2021-01-22 15:40:28 +00:00
|
|
|
# nested dict added to new key of dict, additive behaviour:
|
|
|
|
|
({"a": "b"}, {"c": {"d": "e"}}, {"a": "b", "c": {"d": "e"}}),
|
2021-01-21 16:49:12 +00:00
|
|
|
# lists with same length but different items, destination supercedes source:
|
|
|
|
|
(["b", "c", "d"], ["b", "e", "f"], ["b", "e", "f"]),
|
2020-08-13 12:38:12 +01:00
|
|
|
# lists in dicts behave as top level lists
|
2021-01-21 16:49:12 +00:00
|
|
|
({"a": ["b", "c", "d"]}, {"a": ["b", "e", "f"]}, {"a": ["b", "e", "f"]}),
|
|
|
|
|
# lists with same string in both, at different positions, result in duplicates keeping their positions
|
|
|
|
|
(["a", "b", "c", "d"], ["d", "e", "f"], ["d", "e", "f", "d"]),
|
2020-08-13 12:38:12 +01:00
|
|
|
# lists with same dict in both result in a list with one instance of that dict
|
|
|
|
|
([{"b": "c"}], [{"b": "c"}], [{"b": "c"}]),
|
|
|
|
|
# if dicts in lists have different values, they are not merged
|
2021-01-21 16:49:12 +00:00
|
|
|
([{"b": "c"}], [{"b": "e"}], [{"b": "e"}]),
|
2021-01-22 15:40:28 +00:00
|
|
|
# if nested dicts in lists have different keys, additive behaviour
|
|
|
|
|
([{"b": "c"}], [{"d": {"e": "f"}}], [{"b": "c", "d": {"e": "f"}}]),
|
2021-01-26 12:16:08 +00:00
|
|
|
# if dicts in destination list but not source, they just get added to end of source
|
|
|
|
|
([{"a": "b"}], [{"a": "b"}, {"a": "b"}, {"c": "d"}], [{"a": "b"}, {"a": "b"}, {"c": "d"}]),
|
2020-08-13 12:38:12 +01:00
|
|
|
# merge a dict with a null object returns that dict (does not work the other way round)
|
2021-01-22 15:40:28 +00:00
|
|
|
({"a": {"b": "c"}}, None, {"a": {"b": "c"}}),
|
|
|
|
|
# double nested dicts, new adds new Boolean key: value, additive behaviour
|
|
|
|
|
({"a": {"b": {"c": "d"}}}, {"a": {"b": {"e": True}}}, {"a": {"b": {"c": "d", "e": True}}}),
|
|
|
|
|
# double nested dicts, both have same key, different values, destination supercedes source
|
|
|
|
|
({"a": {"b": {"c": "d"}}}, {"a": {"b": {"c": "e"}}}, {"a": {"b": {"c": "e"}}})
|
2020-08-13 12:38:12 +01:00
|
|
|
])
|
|
|
|
|
def test_merge_jsonlike_merges_jsonlike_objects_correctly(source_object, destination_object, expected_result):
|
|
|
|
|
merge_jsonlike(source_object, destination_object)
|
|
|
|
|
assert source_object == expected_result
|
2020-09-17 11:08:36 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('value, significant_figures, expected_result', (
|
|
|
|
|
(0, 1, 0),
|
|
|
|
|
(0, 2, 0),
|
|
|
|
|
(12_345, 1, 10_000),
|
|
|
|
|
(12_345, 2, 12_000),
|
|
|
|
|
(12_345, 3, 12_300),
|
|
|
|
|
(12_345, 9, 12_345),
|
|
|
|
|
(12_345.6789, 1, 10_000),
|
|
|
|
|
(12_345.6789, 9, 12_345),
|
|
|
|
|
(-12_345, 1, -10_000),
|
|
|
|
|
))
|
|
|
|
|
def test_round_to_significant_figures(value, significant_figures, expected_result):
|
|
|
|
|
assert round_to_significant_figures(value, significant_figures) == expected_result
|
2021-03-05 16:26:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('datetime_string, financial_year', (
|
|
|
|
|
('2021-01-01T00:00:00+00:00', 2020), # Start of 2021
|
|
|
|
|
('2021-03-31T22:59:59+00:00', 2020), # One minute before midnight (BST)
|
|
|
|
|
('2021-03-31T23:00:00+00:00', 2021), # Midnight (BST)
|
|
|
|
|
('2021-12-12T12:12:12+01:00', 2021), # Later in the year
|
|
|
|
|
))
|
|
|
|
|
def test_get_financial_year(datetime_string, financial_year):
|
|
|
|
|
with freeze_time(datetime_string):
|
|
|
|
|
assert get_current_financial_year() == financial_year
|