Coverage for jutil/tests.py: 97%

# Coverage for jutil/tests.py : 97%

## 732 statements

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1 import logging

2 import os

3 from datetime import datetime, timedelta, date

4 from decimal import Decimal

5 from os.path import join

6 from urllib.parse import urlparse

7 from django.utils import timezone

8 from typing import List

9 from django.utils.timezone import now

10 from rest_framework.test import APIClient

11

12 from jutil.modelfields import SafeCharField, SafeTextField

13 from jutil.middleware import logger as jutil_middleware_logger, ActivateUserProfileTimezoneMiddleware

14 import pytz

15 from django.conf import settings

16 from django.contrib.admin.models import LogEntry

17 from django.contrib.auth.models import User

18 from django.core.exceptions import ValidationError

19 from django.core.management.base import CommandParser # type: ignore

20 from django.db import models

21 from django.http.response import HttpResponse

22 from django.test import TestCase

23 from django.test.client import RequestFactory, Client

24 from django.utils.translation import override, gettext as _, gettext_lazy

25 from rest_framework.exceptions import NotAuthenticated

26 from jutil.admin import admin_log, admin_obj_url, admin_obj_link, ModelAdminBase, AdminLogEntryMixin

27 from jutil.auth import AuthUserMixin, get_auth_user, get_auth_user_or_none

28 from jutil.command import get_date_range_by_name, add_date_range_arguments, parse_date_range_arguments

29 from jutil.email import make_email_recipient_list

30 from jutil.middleware import EnsureOriginMiddleware, LogExceptionMiddleware, EnsureLanguageCookieMiddleware

31 from jutil.model import is_model_field_changed, clone_model, get_model_field_label_and_value, get_object_or_none, \

32 wait_object_or_none

33 from jutil.request import get_ip_info

34 from jutil.responses import CsvResponse

35 from jutil.testing import TestSetupMixin

36 from jutil.urls import modify_url

37 from jutil.xml import xml_to_dict, dict_to_element, _xml_filter_tag_name

38 from jutil.dates import add_month, per_delta, per_month, this_week, next_month, next_week, this_month, last_month, \

39 last_year, last_week, yesterday, end_of_month, this_year, get_time_steps, TIME_STEP_DAILY

40 from jutil.format import format_full_name, format_xml, format_xml_bytes, format_timedelta, dec1, dec2, dec3, dec4, dec5, \

41 dec6, format_table, ucfirst_lazy, strip_media_root, get_media_full_path, camel_case_to_underscore, \

42 underscore_to_camel_case, format_as_html_json, format_dict_as_html, choices_label, is_media_full_path

43 from jutil.parse import parse_datetime, parse_bool, parse_datetime_or_none

44 from jutil.validators import fi_payment_reference_number, se_ssn_validator, se_ssn_filter, fi_iban_validator, \

45 se_iban_validator, iban_filter_readable, email_filter, iban_validator, iban_bank_info, fi_company_org_id_validator, \

46 email_validator, fi_payment_reference_validator, iso_payment_reference_validator, fi_ssn_age, \

47 se_clearing_code_bank_info, ascii_filter, ee_iban_validator, be_iban_validator, dk_iban_validator, \

48 dk_iban_bank_info, dk_clearing_code_bank_name, country_code_sanitizer, phone_sanitizer, email_sanitizer, \

49 fi_company_org_id_generator, phone_validator, passport_filter, passport_validator, passport_sanitizer, \

50 country_code_validator, validate_country_iban, iban_bic, validate_country_company_org_id, fi_ssn_generator, \

51 fi_ssn_validator, bic_validator, iban_generator, bic_sanitizer, filter_country_company_org_id

52 from xml.etree.ElementTree import Element

53 from xml.etree import ElementTree as ET

54 from django.contrib import admin

55

56

57 MY_CHOICE_1 = '1'

58 MY_CHOICE_2 = '2'

59 MY_CHOICES = (

60 (MY_CHOICE_1, 'MY_CHOICE_1'),

61 (MY_CHOICE_2, 'MY_CHOICE_2'),

62)

63

64 request_factory = RequestFactory()

65

66

67 class DummyLogHandler(logging.Handler):

68 msgs: List[str]

69

70 def __init__(self):

71 super().__init__()

72 self.msgs = []

73

74 def emit(self, record):

75 msg = self.format(record)

76 self.msgs.append(msg)

77

78

79 def dummy_time_zone_response(obj) -> HttpResponse:

80 tz = timezone.get_current_timezone()

81 return HttpResponse(str(tz).encode())

82

83

84 def dummy_admin_func_a(modeladmin, request, qs):

85 print('dummy_admin_func_a')

86

87

88 def dummy_admin_func_b(modeladmin, request, qs):

89 print('dummy_admin_func_b')

90

91

92 def dummy_middleware_get_response(obj) -> HttpResponse:

93 return HttpResponse(b'hello content')

94

95

96 class DummyUserProfile:

97 timezone = 'Europe/Helsinki'

98

99

100 class MyCustomAdmin(ModelAdminBase):

101 max_history_length = 5

102 actions = (

103 dummy_admin_func_b,

104 dummy_admin_func_a,

105 )

106

107 def get_object(self, request, obj_id):

108 return self.model.objects.get(id=obj_id)

109

110

111 class Tests(TestCase, TestSetupMixin):

112 def setUp(self):

113 self.user = user = self.add_test_user('test@example.com', 'test1234')

114 assert isinstance(user, User)

115 user.is_superuser = True

116 user.is_staff = True

117 user.save()

118 self.client = Client()

119

120 def test_api_client(self):

121 api_client = self.create_api_client()

122 self.assertTrue(isinstance(api_client, APIClient))

123

124 def test_payment_reference(self):

125 self.assertEqual(fi_payment_reference_number('100'), '1009')

126 invalids = [

127 '89182932u',

128 '0000002',

129 ]

130 for invalid in invalids:

131 try:

132 fi_payment_reference_number(invalid)

133 self.fail('invalid number but passed: {}'.format(invalid))

134 except ValidationError:

135 pass

136

137 def test_format_full_name(self):

138 samples = [

139 ('Short', 'Full Name', 'Short Full Name'),

140 ('Short Middle Name Is Quite Long', 'Full Name', 'Short Full Name'),

141 ('Short-Middle Name Is Quite Long', 'Full Name', 'Short Full Name'),

142 ('Olga Demi', 'Serpuhovitinova-Miettinen', 'Olga Serpuhovitinova'),

143 ('Olga-Anne Demi', 'Serpuhovitinovatsko', 'Olga S'),

144 ]

145 for v in samples:

146 limited = format_full_name(v[0], v[1], 20)

147 # print('{} {} -> {} (was: {})'.format(v[0], v[1], v[2], limited))

148 self.assertEqual(v[2], limited)

149 try:

150 long_name = '19280309812083091829038190823081208301280381092830182038018203810283021'

151 format_full_name(long_name, long_name)

152 self.fail('format_full_name failed with long name')

153 except Exception:

154 pass

155

156 def test_parse_datetime(self):

157 pairs = [

158 ('2016-06-12', '2016-06-12T00:00:00+00:00'),

159 ('2016-06-12T01:00:00', '2016-06-12T01:00:00+00:00'),

160 ('2016-06-12 01:00:00', '2016-06-12T01:00:00+00:00'),

161 ('2016-06-12T01:00:00+00:00', '2016-06-12T01:00:00+00:00'),

162 ('2016-06-12 01:00:00+00:00', '2016-06-12T01:00:00+00:00'),

163 ]

164 for t_str_input, t_ref_str in pairs:

165 # parse_datetime

166 t = parse_datetime(t_str_input)

167 self.assertTrue(isinstance(t, datetime))

168 assert isinstance(t, datetime)

169 self.assertEqual(t.isoformat(), t_ref_str)

170 # parse_datetime_or_none

171 t = parse_datetime_or_none(t_str_input)

172 self.assertTrue(isinstance(t, datetime))

173 assert isinstance(t, datetime)

174 self.assertEqual(t.isoformat(), t_ref_str)

175

176 invalids = [

177 '12312313ew',

178 '2016-13-05',

179 ]

180 for t_str_input in invalids:

181 # parse_datetime

182 try:

183 parse_datetime(t_str_input)

184 self.fail('{} is not valid input for parse_datetime()'.format(t_str_input))

185 except Exception:

186 pass

187 # parse_datetime_or_none

188 t = parse_datetime_or_none(t_str_input)

189 assert t is None

190

191 def test_add_month(self):

192 t = parse_datetime('2016-06-12T01:00:00')

193 self.assertTrue(isinstance(t, datetime))

194 assert isinstance(t, datetime)

195 self.assertEqual(t.isoformat(), '2016-06-12T01:00:00+00:00')

196 t2 = add_month(t)

197 self.assertEqual(t2.isoformat(), '2016-07-12T01:00:00+00:00')

198 t3 = add_month(t, 7)

199 self.assertEqual(t3.isoformat(), '2017-01-12T01:00:00+00:00')

200 t4 = add_month(t, -1)

201 self.assertEqual(t4.isoformat(), '2016-05-12T01:00:00+00:00')

202 time_now = datetime(2020, 6, 30, 15, 47, 23, 818646)

203 self.assertEqual(add_month(time_now, -4).isoformat(), '2020-02-29T15:47:23.818646')

204 self.assertEqual(add_month(time_now, 8).isoformat(), '2021-02-28T15:47:23.818646')

205 self.assertEqual(add_month(time_now, 0).isoformat(), '2020-06-30T15:47:23.818646')

206

207 def test_se_ssn(self):

208 se_ssn_validator('811228-9874')

209 se_ssn_validator('670919-9530')

210 with self.assertRaises(ValidationError):

211 se_ssn_validator('811228-9873')

212

213 def test_phone_numbers(self):

214 try:

215 phone_validator('+358456343767')

216 except Exception:

217 self.fail('phone_validator("+358456343767") should not raise Exception')

218 with self.assertRaisesMessage(ValidationError, _('Invalid phone number')):

219 phone_validator('214')

220 self.assertEqual(phone_sanitizer('214'), '')

221

222 def test_passport(self):

223 self.assertEqual(passport_filter('?ADsd-12312dsds'), 'ADSD-12312DSDS')

224 passport_validator('21412312312')

225 with self.assertRaisesMessage(ValidationError, _('Invalid passport number')):

226 passport_validator('214')

227 self.assertEqual(passport_sanitizer('214'), '')

228 self.assertEqual(passport_sanitizer('21412312312'), '21412312312')

229

230 def test_country_code(self):

231 for cc in ['FI', 'DK', 'ES', 'SE', 'VN']:

232 country_code_validator(cc)

233 with self.assertRaisesMessage(ValidationError, _('Invalid country code')):

234 country_code_validator('Finland')

235

236 def test_bic(self):

237 bic = iban_bic('FI21 1234 5600 0007 85')

238 self.assertEqual(bic, 'NDEAFIHH')

239 self.assertEqual(bic_sanitizer('NDEAFIHH'), 'NDEAFIHH')

240 self.assertEqual(bic_sanitizer('NDEAFIH'), '')

241

242 def test_org_id(self):

243 try:

244 validate_country_company_org_id('FI', '2084069-9')

245 except Exception:

246 self.fail('2084069-9 is valid org id')

247 with self.assertRaisesMessage(ValidationError, _('Invalid company organization ID')):

248 validate_country_company_org_id('FI', '2084069-8')

249

250 def test_validate_country_iban(self):

251 with self.assertRaisesMessage(ValidationError, _('Invalid IBAN account number')):

252 validate_country_iban('FI15616515616156', 'SE')

253

254 def test_fi_ssn_generator(self):

255 self.assertEqual(len(fi_ssn_generator()), 6 + 1 + 4)

256 for min_year, max_year in [(1800, 1900), (1900, 2000), (2000, 2050)]:

257 for n in range(10):

258 ssn = fi_ssn_generator(min_year, max_year)

259 try:

260 fi_ssn_age(ssn)

261 fi_ssn_validator(ssn)

262 except Exception:

263 self.fail('{} is valid SSN'.format(ssn))

264 fi_ssn_validator('110305+283X')

265 for ssn in ['9999-123F', '271138-670X', '090228+256X']:

266 with self.assertRaisesMessage(ValidationError, _('Invalid personal identification number')):

267 fi_ssn_validator(ssn)

268 with self.assertRaises(ValidationError):

269 fi_ssn_generator(1700, 1799)

270 with self.assertRaises(ValidationError):

271 fi_ssn_generator(2100, 2200)

272

273 def test_iban(self):

274 with self.assertRaisesMessage(ValidationError, _('Invalid IBAN account number')):

275 iban_validator('')

276 with self.assertRaisesMessage(ValidationError, _('Invalid country code')):

277 iban_validator('XX')

278 with self.assertRaisesMessage(ValidationError, _('Invalid IBAN account number')):

279 iban_validator('FI2112345600000786')

280 bic_validator('HELSFIHH')

281 bic_validator('HELSFIHHXXX')

282 with self.assertRaisesMessage(ValidationError, _('Invalid bank BIC/SWIFT code')):

283 bic_validator('HELSFIH')

284 with self.assertRaisesMessage(ValidationError, _('Invalid bank BIC/SWIFT code')):

285 bic_validator('')

286 with self.assertRaisesMessage(ValidationError, _('Invalid bank BIC/SWIFT code')):

287 bic_validator('XX123123123112')

288 iban_validator('FI2112345600000785')

289 iban_validator('SE4550000000058398257466')

290 fi_iban_validator('FI2112345600000785')

291 se_iban_validator('SE4550000000058398257466')

292 ee_iban_validator('EE38 2200 2210 2014 5685')

293 be_iban_validator('BE68 5390 0754 7034')

294 with self.assertRaises(ValidationError):

295 fi_iban_validator('FI2112345600000784')

296 with self.assertRaises(ValidationError):

297 se_iban_validator('SE4550000000058398257465')

298 iban = 'FI8847304720017517'

299 self.assertEqual(iban_filter_readable(iban), 'FI88 4730 4720 0175 17')

300 self.assertEqual(iban_filter_readable(''), '')

301

302 def test_urls(self):

303 url = 'http://yle.fi/uutiset/3-8045550?a=123&b=456'

304 self.assertEqual(modify_url('http://yle.fi/uutiset/3-8045550?a=123&b=456', {'a': '123', 'b': '456'}),

305 'http://yle.fi/uutiset/3-8045550?a=123&b=456')

306

307 def test_email_filter_and_validation(self):

308 emails = [

309 (' Asdsa@a-a.com ', 'asdsa@a-a.com', True),

310 ('1asdsa@a-a2.com', '1asdsa@a-a2.com', True),

311 (' Asdsa@a-a ', 'asdsa@a-a', False),

312 (' @a-a2.com', '@a-a2.com', False),

313 (' a-a2.com', 'a-a2.com', False),

314 ('ää-a2@ää-a2.com', 'ää-a2@ää-a2.com', False),

315 ('aaa.bbbbb@ccc-ddd.fi', 'aaa.bbbbb@ccc-ddd.fi', True),

316 ]

317 for i, o, is_valid in emails:

318 # print('email_filter({}) -> {}'.format(i, email_filter(i)))

319 self.assertEqual(email_filter(i), o)

320 if is_valid:

321 email_validator(o)

322 else:

323 fail = False

324 try:

325 email_validator(o)

326 except ValidationError:

327 fail = True

328 self.assertTrue(fail, '{} is not valid email but passed validation'.format(o))

329

330 def test_ip_info(self):

331 ip, cc, host = get_ip_info('213.214.146.142')

332 self.assertEqual(ip, '213.214.146.142')

333 if cc: 333 ↛ 335line 333 didn't jump to line 335, because the condition on line 333 was never false

334 self.assertEqual(cc, 'FI')

335 if host: 335 ↛ exitline 335 didn't return from function 'test_ip_info', because the condition on line 335 was never false

336 self.assertEqual(host, '213214146142.edelkey.net')

337

338 def test_parse_xml(self):

339 # finvoice_201_example1.xml

340 xml_bytes = open(join(settings.BASE_DIR, 'data/fi/finvoice_201_example1.xml'), 'rb').read()

341 data = xml_to_dict(xml_bytes, value_key='value', attribute_prefix='_')

342 # pprint(data)

343 self.assertEqual(data['_Version'], '2.01')

344 self.assertEqual(data['InvoiceRow'][0]['ArticleIdentifier'], '12345')

345 self.assertEqual(data['InvoiceRow'][0]['DeliveredQuantity']['value'], '2')

346 self.assertEqual(data['InvoiceRow'][0]['DeliveredQuantity']['_QuantityUnitCode'], 'kpl')

347 self.assertEqual(data['InvoiceRow'][1]['ArticleIdentifier'], '123456')

348

349 # parse_xml1.xml

350 xml_str = open(join(settings.BASE_DIR, 'data/parse_xml1.xml'), 'rt').read()

351 data = xml_to_dict(xml_str.encode())

352 # pprint(data)

353 ref_data = {'@version': '1.2',

354 'A': [{'@class': 'x', 'B': {'@': 'hello', '@class': 'x2'}},

355 {'@class': 'y', 'B': {'@': 'world', '@class': 'y2'}}],

356 'C': 'value node'}

357 self.assertEqual(ref_data, data)

358

359 # parse_xml1.xml / no attributes

360 xml_str = open(join(settings.BASE_DIR, 'data/parse_xml1.xml'), 'rt').read()

361 data = xml_to_dict(xml_str.encode(), parse_attributes=False)

362 # pprint(data)

363 ref_data = {'A': [{'B': 'hello'}, {'B': 'world'}], 'C': 'value node'}

364 self.assertEqual(ref_data, data)

365

366 # parse_xml2.xml / no attributes

367 xml_str = open(join(settings.BASE_DIR, 'data/parse_xml2.xml'), 'rt').read()

368 data = xml_to_dict(xml_str.encode(), ['VastausLoki', 'LuottoTietoMerkinnat'], parse_attributes=False)

369 # pprint(data)

370 ref_data = {'VastausLoki': {'KysyttyHenkiloTunnus': '020685-1234',

371 'PaluuKoodi': 'Palveluvastaus onnistui',

372 'SyyKoodi': '1'}}

373 self.assertEqual(ref_data, data)

374

375 def test_dict_to_xml(self):

376 data = {

377 'Doc': {

378 '@version': '1.2',

379 'A': [{'@class': 'x', 'B': {'@': 'hello', '@class': 'x2'}},

380 {'@class': 'y', 'B': {'@': 'world', '@class': 'y2'}}],

381 'C': 'value node',

382 'D': 123,

383 'E': ['abc'],

384 }

385 }

386 el = dict_to_element(data)

387 assert isinstance(el, Element)

388 xml_str = ET.tostring(el, encoding='utf8', method='xml').decode()

389 # print(xml_str) # <Doc version="1.2"><C>value node</C><A class="x"><B class="x2">hello</B></A><A class="y"><B class="y2">world</B></A></Doc>

390 data2 = xml_to_dict(xml_str.encode(), document_tag=True, array_tags=['E'], int_tags=['D'])

391 # print('')

392 # pprint(data)

393 # pprint(data2)

394 self.assertEqual(data2, data)

395

396 def test_dict_to_xml2(self):

397 self.assertEqual(_xml_filter_tag_name('TagName[0]'), 'TagName')

398 self.assertEqual(_xml_filter_tag_name('TagName[1]'), 'TagName')

399 self.assertEqual(_xml_filter_tag_name('TagName'), 'TagName')

400 data = {

401 'Doc': {

402 '@version': '1.2',

403 'A': [{'@class': 'x', 'B': {'@': 'hello', '@class': 'x2'}},

404 {'@class': 'y', 'B': {'@': 'world', '@class': 'y2'}}],

405 'C': 'value node',

406 'D': 123,

407 'E': ['abc'],

408 'F': ['line 1', 'line 2']

409 }

410 }

411 el = dict_to_element(data)

412 assert isinstance(el, Element)

413 xml_str = ET.tostring(el, encoding='utf8', method='xml').decode()

414 data2 = xml_to_dict(xml_str.encode(), document_tag=True, array_tags=['E', 'F'], int_tags=['D'])

415 self.assertEqual(data2, data)

416

417 def test_xml_to_dict(self):

418 xml_str = """<?xml version="1.0" encoding="utf-8"?>

419<Document>

420 <TxsSummry>

421 <TtlNtries>

422 <NbOfNtries>12</NbOfNtries>

423 </TtlNtries>

424 <TtlCdtNtries>

425 <NbOfNtries>34</NbOfNtries>

426 <Sum>1234.56</Sum>

427 </TtlCdtNtries>

428 <TtlDbtNtries>

429 <NbOfNtries>0</NbOfNtries>

430 <Sum>0</Sum>

431 </TtlDbtNtries>

432 </TxsSummry>

433</Document>"""

434 data = xml_to_dict(xml_str.encode(), document_tag=True, array_tags=[], int_tags=['NbOfNtries'])

435 # print('')

436 # pprint(data)

437 self.assertEqual(data['Document']['TxsSummry']['TtlNtries']['NbOfNtries'], 12)

438 self.assertEqual(data['Document']['TxsSummry']['TtlCdtNtries']['NbOfNtries'], 34)

439

440 def test_per_delta(self):

441 begin = datetime(2017, 9, 17, 11, 42)

442 end = begin + timedelta(days=4)

443 ref = [(datetime(2017, 9, 17, 11, 42), datetime(2017, 9, 18, 11, 42)),

444 (datetime(2017, 9, 18, 11, 42), datetime(2017, 9, 19, 11, 42)),

445 (datetime(2017, 9, 19, 11, 42), datetime(2017, 9, 20, 11, 42)),

446 (datetime(2017, 9, 20, 11, 42), datetime(2017, 9, 21, 11, 42))]

447 res = per_delta(begin, end, timedelta(days=1))

448 self.assertEqual(list(res), ref)

449

450 def test_per_month(self):

451 begin = datetime(2017, 9, 1, 0, 0)

452 res = list(per_month(begin, begin + timedelta(days=32)))

453 ref = [(datetime(2017, 9, 1, 0, 0), datetime(2017, 10, 1, 0, 0)),

454 (datetime(2017, 10, 1, 0, 0), datetime(2017, 11, 1, 0, 0))]

455 self.assertEqual(list(res), ref)

456

457 def test_dates(self):

458 t = datetime(2018, 1, 30)

459 b, e = this_week(t)

460 self.assertEqual(b, pytz.utc.localize(datetime(2018, 1, 29)))

461 self.assertEqual(e, pytz.utc.localize(datetime(2018, 2, 5)))

462 b, e = this_month(t)

463 self.assertEqual(b, pytz.utc.localize(datetime(2018, 1, 1)))

464 self.assertEqual(e, pytz.utc.localize(datetime(2018, 2, 1)))

465 b, e = next_week(t)

466 self.assertEqual(b, pytz.utc.localize(datetime(2018, 2, 5)))

467 self.assertEqual(e, pytz.utc.localize(datetime(2018, 2, 12)))

468

469 def test_named_date_ranges(self):

470 t = datetime(2018, 5, 31)

471 t_tz = pytz.utc.localize(t)

472 named_ranges = [

473 ('last_year', last_year(t)),

474 ('last_month', last_month(t)),

475 ('last_week', last_week(t)),

476 ('this_year', this_year(t)),

477 ('this_month', this_month(t)),

478 ('this_week', this_week(t)),

479 ('yesterday', yesterday(t)),

480 ('today', yesterday(t + timedelta(hours=24))),

481 ]

482 day_ranges = [7, 15, 30, 60, 90]

483 for days in day_ranges:

484 named_ranges.append(

485 ('plus_minus_{}d'.format(days), (t_tz - timedelta(days=days), t_tz + timedelta(days=days))))

486 named_ranges.append(('prev_{}d'.format(days), (t_tz - timedelta(days=days), t_tz)))

487 named_ranges.append(('next_{}d'.format(days), (t_tz, t_tz + timedelta(days=days))))

488 for name, res in named_ranges:

489 # print('testing', name)

490 self.assertEqual(get_date_range_by_name(name, t), res)

491

492 def test_time_steps(self):

493 t = parse_datetime('2020-08-24 23:28:36.503174')

494 this_week_daily = [

495 '2020-08-24T00:00:00+00:00 2020-08-25T00:00:00+00:00',

496 '2020-08-25T00:00:00+00:00 2020-08-26T00:00:00+00:00',

497 '2020-08-26T00:00:00+00:00 2020-08-27T00:00:00+00:00',

498 '2020-08-27T00:00:00+00:00 2020-08-28T00:00:00+00:00',

499 '2020-08-28T00:00:00+00:00 2020-08-29T00:00:00+00:00',

500 '2020-08-29T00:00:00+00:00 2020-08-30T00:00:00+00:00',

501 '2020-08-30T00:00:00+00:00 2020-08-31T00:00:00+00:00',

502 ]

503 ix = 0

504 for begin, end in get_time_steps(TIME_STEP_DAILY, *this_week(t)):

505 self.assertEqual('{} {}'.format(begin.isoformat(), end.isoformat()), this_week_daily[ix])

506 ix += 1

507

508 def test_bank_info(self):

509 ac = 'FI8847304720017517'

510 inf = iban_bank_info(ac)

511 self.assertEqual(inf[0], 'POPFFI22')

512 self.assertEqual(inf[1], 'POP-Pankki')

513

514 ac = ''

515 inf = iban_bank_info(ac)

516 self.assertEqual(inf[0], '')

517 self.assertEqual(inf[1], '')

518

519 ac = 'BE75270187592710'

520 inf = iban_bank_info(ac)

521 self.assertEqual(inf[0], 'GEBABEBB')

522 self.assertEqual(inf[1], 'BNP Paribas Fortis')

523 ac = 'BE58465045170210'

524 inf = iban_bank_info(ac)

525 self.assertEqual(inf[0], 'KREDBEBB')

526 self.assertEqual(inf[1], 'KBC Bank')

527 ac = 'BE11000123456748'

528 inf = iban_bank_info(ac)

529 self.assertEqual(inf[0], 'BPOTBEB1')

530 self.assertEqual(inf[1], 'bpost bank')

531

532 def test_org_id_fi(self):

533 valids = [

534 'FI01098230',

535 'FI-01098230',

536 '0109823-0',

537 '2084069-9',

538 ]

539 invalids = [

540 '2084069-1',

541 'SE2084069-1',

542 ]

543 co_filtered = [

544 ('FI', 'FI01098230', '0109823-0'),

545 ('FI', 'FI-01098230', '0109823-0'),

546 ('FI', '0109823-0', '0109823-0'),

547 ('FI', '2084069-9', '2084069-9'),

548 ('SE', '01098230', '01098230'),

549 ('SE', '20840699', '20840699'),

550 ]

551 for cc, org, val in co_filtered:

552 self.assertEqual(filter_country_company_org_id(cc, org), val)

553 validate_country_company_org_id(cc, org)

554 for valid in valids:

555 fi_company_org_id_validator(valid)

556 for invalid in invalids:

557 try:

558 fi_company_org_id_validator(invalid)

559 self.fail('{} passed as valid FI-org'.format(invalid))

560 except ValidationError:

561 # print('ok')

562 pass

563 for n in range(10):

564 v0 = fi_company_org_id_generator()

565 # print(v0)

566 fi_company_org_id_validator(v0)

567

568 def test_reference_number_validators(self):

569 valid_fi_refs = [

570 '302300',

571 '202196',

572 '302290',

573 ]

574 for ref_no in valid_fi_refs:

575 fi_payment_reference_validator(ref_no)

576

577 invalid_fi_refs = [

578 '302301',

579 '202195',

580 '302291',

581 ]

582 for ref_no in invalid_fi_refs:

583 try:

584 fi_payment_reference_validator(ref_no)

585 self.assertFalse(True, '{} should have failed validation'.format(ref_no))

586 except ValidationError:

587 pass

588

589 valid_iso_refs = [

590 'RF92 1229',

591 'RF11 1232',

592 'RF48 1245',

593 ]

594 for ref_no in valid_iso_refs:

595 iso_payment_reference_validator(ref_no)

596

597 invalid_iso_refs = [

598 'RF92 1229}',

599 ]

600 for ref_no in invalid_iso_refs:

601 with self.assertRaisesMessage(ValidationError, 'Invalid payment reference'):

602 iso_payment_reference_validator(ref_no)

603

604 def test_fi_ssn_age(self):

605 samples = [

606 (date(2018, 12, 20), '231298-965X', 19),

607 (date(2018, 12, 22), '231298-965X', 19),

608 (date(2018, 12, 23), '231298-965X', 20),

609 (date(2018, 12, 24), '231298-965X', 20),

610 ]

611 for date_now, ssn, age in samples:

612 self.assertEqual(fi_ssn_age(ssn, date_now), age,

613 msg='{} age is {} on {} but fi_ssn_age result was {}'.format(ssn, age, date_now,

614 fi_ssn_age(ssn, date_now)))

615

616 def test_se_banks(self):

617 self.assertEqual(se_clearing_code_bank_info('6789'), ('Handelsbanken', 9))

618 se_iban_validator('SE45 5000 0000 0583 9825 7466')

619 with self.assertRaisesMessage(ValidationError, _('Invalid IBAN account number')):

620 se_iban_validator('')

621 with self.assertRaisesMessage(ValidationError, _('Invalid IBAN account number')):

622 se_iban_validator('XX45 5000 0000 0583 9825 7466')

623 with self.assertRaisesMessage(ValidationError, _('Invalid IBAN account number')):

624 se_iban_validator('SE45 5000 0000 0583 9825')

625 self.assertEqual(se_clearing_code_bank_info('9500'), ('Nordea AB', 10))

626 an = '957033025420'

627 bank_name, acc_digits = se_clearing_code_bank_info(an)

628 self.assertEqual(bank_name, 'Sparbanken Syd')

629 self.assertGreaterEqual(len(an) - 4, acc_digits)

630

631 def test_dk_banks(self):

632 an = 'DK50 0040 0440 1162 43'

633 dk_iban_validator(an)

634 bic, name = dk_iban_bank_info(an)

635 self.assertEqual(name, 'Nordea')

636 an = '8114 0008874093'

637 name = dk_clearing_code_bank_name(an)

638 self.assertEqual(name, 'Nykredit Bank')

639 an = 'DK2520006893703029'

640 name = dk_clearing_code_bank_name(an)

641 self.assertEqual(name, 'Nordea')

642

643 def test_ascii_filter(self):

644 pairs = [

645 ('Åke va Källe o Öring', 'Ake va Kalle o Oring'),

646 ('Tôi đang đi mua sắm', 'Toi ang i mua sam'),

647 ('HELÉN FRANZÉN', 'HELEN FRANZEN'),

648 ]

649 for a, b in pairs:

650 self.assertEqual(ascii_filter(a), b, 'ascii_filter("{}") != "{}"'.format(b, ascii_filter(a)))

651

652 def test_l10n(self):

653 from rest_framework.exceptions import ValidationError

654

655 with override('fi'):

656 msg = _("“%(value)s” value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format.")

657 if 'muoto ei kelpaa' not in msg: 657 ↛ 658line 657 didn't jump to line 658, because the condition on line 657 was never true

658 print(msg)

659 self.assertTrue('muoto ei kelpaa' in msg)

660

661 try:

662 parse_bool('hello')

663 except ValidationError as e:

664 self.assertEqual(str(e),

665 "[ErrorDetail(string='hello ei ole yksi valittavissa olevista arvoista', code='invalid')]")

666

667 def test_sanitizers(self):

668 self.assertEqual(country_code_sanitizer('kods'), '')

669 self.assertEqual(country_code_sanitizer('fi'), 'FI')

670 self.assertEqual(phone_sanitizer('+13146094459'), '+13146094459')

671 self.assertEqual(phone_sanitizer('13146094459'), '13146094459')

672 self.assertEqual(phone_sanitizer('+13146094459A'), '+13146094459')

673 self.assertEqual(email_sanitizer('test@example.com'), 'test@example.com')

674 self.assertEqual(email_sanitizer('testexample.com'), '')

675

676 def test_format_dict_as_html(self):

677 a = {'b': 1, 'c': {'@testVariable': '123'}}

678 res = '<pre>B: 1\nC:\n Test variable: 123\n\n</pre>'

679 self.assertEqual(format_dict_as_html(a), res)

680

681 def test_format_xml(self):

682 assert settings.XMLLINT_PATH, 'add e.g. XMLLINT_PATH = "/usr/bin/xmllint" to settings.py'

683 src = '<ApplicationRequest> <CustomerId>1</CustomerId> <Command>DownloadFileList</Command><Timestamp>2019-11-27T04:32:18.613452+02:00</Timestamp><Environment>PRODUCTION</Environment></ApplicationRequest>'

684 dst_ref = '<?xml version="1.0"?>\n<ApplicationRequest>\n <CustomerId>1</CustomerId>\n <Command>DownloadFileList</Command>\n <Timestamp>2019-11-27T04:32:18.613452+02:00</Timestamp>\n <Environment>PRODUCTION</Environment>\n</ApplicationRequest>\n'

685 dst = format_xml(src)

686 self.assertEqual(dst, dst_ref)

687 dst = format_xml_bytes(src.encode())

688 self.assertEqual(dst, dst_ref.encode())

689

690 def test_parse_sftp(self):

691 test_cases = [

692 ('sftp://jani@kajala.com', ['jani', None, 'kajala.com', '']),

693 ('sftp://jani.kajala:1231!@kajala.com', ['jani.kajala', '1231!', 'kajala.com', '']),

694 ('sftp://jani:1231!@kajala.com/my/dir', ['jani', '1231!', 'kajala.com', '/my/dir']),

695 ('sftp://jani.kajala:1231!@kajala.com/my/dir', ['jani.kajala', '1231!', 'kajala.com', '/my/dir']),

696 ]

697 for connection, ref_res in test_cases:

698 res = urlparse(connection)

699 res_list = [res.username, res.password, res.hostname, res.path]

700 self.assertListEqual(res_list, ref_res,

701 'SFTP connection string "{}" parsed incorrectly'.format(connection))

702

703 def test_admin(self):

704 obj = self.user

705 admin_log([obj], 'Hello, world')

706 admin_log([obj], 'Hello, world', user=self.user, ip='127.0.0.1')

707 admin_log(obj, 'Hello, world', user=self.user, ip='127.0.0.1')

708 e = LogEntry.objects.all().filter(object_id=obj.id).last()

709 self.assertIsNotNone(e)

710 assert isinstance(e, LogEntry)

711 self.assertEqual(e.change_message, 'Hello, world')

712 self.assertEqual(admin_obj_url(obj, 'admin:auth_user_change'), '/admin/auth/user/{}/change/'.format(obj.id))

713 self.assertEqual(admin_obj_url(None, 'admin:auth_user_change'), '')

714 self.assertEqual(admin_obj_link(None, 'admin:auth_user_change'), '')

715 self.assertEqual(admin_obj_url(obj), '/admin/auth/user/{}/change/'.format(obj.id))

716 self.assertEqual(admin_obj_url(e), '/admin/admin/logentry/{}/change/'.format(e.id))

717 link = admin_obj_link(obj, 'User', 'admin:auth_user_change')

718 self.assertEqual(link, "<a href='/admin/auth/user/{}/change/'>User</a>".format(obj.id))

719

720 def test_cmd_parser(self):

721 parser = CommandParser()

722 add_date_range_arguments(parser)

723 argv = parser.parse_args(['--begin', '2019-06-25', '--end', '2020-02-01'])

724 options = argv.__dict__

725 begin, end, steps = parse_date_range_arguments(options)

726 self.assertEqual(begin, pytz.utc.localize(datetime(2019, 6, 25)))

727 self.assertEqual(end, pytz.utc.localize(datetime(2020, 2, 1)))

728

729 def test_format_timedelta(self):

730 self.assertEqual(format_timedelta(timedelta(seconds=90)), '1min30s')

731 self.assertEqual(format_timedelta(timedelta(seconds=3600 + 90)), '1h1min30s')

732 self.assertEqual(format_timedelta(timedelta(seconds=90), minutes_label='min ', seconds_label='s '), '1min 30s')

733 self.assertEqual(

734 format_timedelta(timedelta(seconds=3600 + 90), hours_label='h ', minutes_label='min ', seconds_label='s '),

735 '1h 1min 30s')

736 self.assertEqual(format_timedelta(timedelta(seconds=90), seconds_label=''), '1min')

737 self.assertEqual(format_timedelta(timedelta(seconds=0.090), seconds_label='s'), '0.090s')

738

739 def test_dec123456(self):

740 self.assertEqual(dec1(Decimal('1.2345678')), Decimal('1.2'))

741 self.assertEqual(dec2(Decimal('1.2345678')), Decimal('1.23'))

742 self.assertEqual(dec3(Decimal('1.2345678')), Decimal('1.235'))

743 self.assertEqual(dec4(Decimal('1.2345678')), Decimal('1.2346'))

744 self.assertEqual(dec5(Decimal('1.2345678')), Decimal('1.23457'))

745 self.assertEqual(dec6(Decimal('1.2345678')), Decimal('1.234568'))

746

747 def test_model_funcs(self):

748 admin_log([self.user], 'test msg 1')

749 obj = LogEntry.objects.all().order_by('-pk').last()

750 assert isinstance(obj, LogEntry)

751 self.assertFalse(is_model_field_changed(obj, 'change_message'))

752 obj.change_message = 'hello world'

753 self.assertTrue(is_model_field_changed(obj, 'change_message'))

754 obj.save()

755 self.assertFalse(is_model_field_changed(obj, 'change_message'))

756 obj2 = clone_model(obj)

757 assert isinstance(obj2, LogEntry)

758 self.assertEqual(obj.change_message, obj2.change_message)

759 self.assertGreater(obj2.pk, obj.pk)

760 label, val = get_model_field_label_and_value(obj, 'action_time')

761 self.assertEqual(label, _('action time'))

762 self.assertEqual(str(obj.action_time), val)

763 obj_b = get_object_or_none(obj.__class__, id=obj.id)

764 self.assertEqual(obj_b.id, obj.id)

765 obj_b = get_object_or_none(obj.__class__, id=-1)

766 self.assertIsNone(obj_b)

767

768 def test_format_table(self):

769 a = [

770 ['date', 'description', 'count', 'unit price', 'total price'],

771 [date(2019, 12, 15), 'oranges', 1000, dec2('0.99'), dec2('990.00')],

772 [date(2020, 1, 3), 'apples', 4, dec2('1.10'), dec2('4.40')],

773 [date(2020, 11, 3), 'apples', 5, dec2('10.10'), dec2('50.50')],

774 ]

775 out = format_table(a, has_label_row=True, max_col=10)

776 out_ref = """

777---------------------------------------------------

778| date|descript..|count|unit price|total pr..|

779---------------------------------------------------

780|2019-12-15| oranges| 1000| 0.99| 990.00|

781|2020-01-03| apples| 4| 1.10| 4.40|

782|2020-11-03| apples| 5| 10.10| 50.50|

783---------------------------------------------------

784 """.strip()

785 self.assertEqual(out, out_ref)

786

787 out = format_table(a, has_label_row=True, max_col=20)

788 out_ref = """

789-----------------------------------------------------

790| date|description|count|unit price|total price|

791-----------------------------------------------------

792|2019-12-15| oranges| 1000| 0.99| 990.00|

793|2020-01-03| apples| 4| 1.10| 4.40|

794|2020-11-03| apples| 5| 10.10| 50.50|

795-----------------------------------------------------

796 """.strip()

797 self.assertEqual(out, out_ref)

798

799 out = format_table(a, has_label_row=True, max_col=20, col_sep=' | ')

800 out_ref = """

801-------------------------------------------------------------

802| date | description | count | unit price | total price|

803-------------------------------------------------------------

804|2019-12-15 | oranges | 1000 | 0.99 | 990.00|

805|2020-01-03 | apples | 4 | 1.10 | 4.40|

806|2020-11-03 | apples | 5 | 10.10 | 50.50|

807-------------------------------------------------------------

808 """.strip()

809 self.assertEqual(out, out_ref)

810

811 out = format_table(a, has_label_row=True, max_col=20, col_sep=' | ', left_align=[1])

812 out_ref = """

813-------------------------------------------------------------

814| date | description | count | unit price | total price|

815-------------------------------------------------------------

816|2019-12-15 | oranges | 1000 | 0.99 | 990.00|

817|2020-01-03 | apples | 4 | 1.10 | 4.40|

818|2020-11-03 | apples | 5 | 10.10 | 50.50|

819-------------------------------------------------------------

820 """.strip()

821 self.assertEqual(out, out_ref)

822

823 out = format_table(a, has_label_row=True, max_col=20, col_sep=' | ', left_align=[1], max_line=50)

824 out_ref = """

825-------------------------------------------------

826| date | description | count | unit price|..

827-------------------------------------------------

828|2019-12-15 | oranges | 1000 | 0.99|..

829|2020-01-03 | apples | 4 | 1.10|..

830|2020-11-03 | apples | 5 | 10.10|..

831-------------------------------------------------

832 """.strip()

833 self.assertEqual(out, out_ref)

834

835 out = format_table(a, left_align=[1], center_align=[0, 2, 3, 4], max_col=50)

836 out_ref = """

837-----------------------------------------------------

838| date |description|count|unit price|total price|

839|2019-12-15|oranges |1000 | 0.99 | 990.00 |

840|2020-01-03|apples | 4 | 1.10 | 4.40 |

841|2020-11-03|apples | 5 | 10.10 | 50.50 |

842-----------------------------------------------------

843 """.strip()

844 self.assertEqual(out, out_ref)

845

846 def test_ucfirst_lazy(self):

847 s = gettext_lazy(ucfirst_lazy("missing value"))

848 s_ref = gettext_lazy("Missing value")

849 s_en = "Missing value"

850 s_fi = "Puuttuva arvo"

851 with override('fi'):

852 self.assertEqual(s, s_fi)

853 self.assertEqual(s, s_ref)

854 with override('en'):

855 self.assertEqual(s, s_en)

856 self.assertEqual(s, s_ref)

857

858 def test_media_paths(self):

859 media_root1 = os.path.join(settings.MEDIA_ROOT, 'path1/path2')

860 media_root2 = os.path.join(settings.MEDIA_ROOT, 'path3') + '/'

861 test_paths = [

862 (True, os.path.join(media_root1, 'test1.file'), 'path1/path2/test1.file'),

863 (False, os.path.join('/diff/path', 'test2.file'), '/diff/path/test2.file'),

864 (True, os.path.join(media_root2, 'test3.file'), 'path3/test3.file'),

865 ]

866 for is_media, src, dst in test_paths:

867 self.assertEqual(is_media_full_path(src), is_media)

868 if is_media:

869 self.assertEqual(strip_media_root(src), dst)

870 self.assertEqual(get_media_full_path(dst), src)

871 self.assertEqual(get_media_full_path(dst), get_media_full_path(get_media_full_path(dst)))

872

873 def test_end_of_month(self):

874 helsinki = pytz.timezone('Europe/Helsinki')

875 # 1

876 time_now = datetime(2020, 6, 5, 15, 47, 23, 818646)

877 eom = end_of_month(time_now, tz=helsinki)

878 eom_ref = helsinki.localize(datetime(2020, 6, 30, 23, 59, 59, 999999))

879 self.assertEqual(eom, eom_ref)

880 # 2

881 time_now = datetime(2020, 7, 5, 15, 47, 23, 818646)

882 eom = end_of_month(time_now, tz=helsinki)

883 eom_ref = helsinki.localize(datetime(2020, 7, 31, 23, 59, 59, 999999))

884 self.assertEqual(eom, eom_ref)

885 # 3

886 time_now = datetime(2020, 6, 5, 15, 47, 23, 818646)

887 eom = end_of_month(time_now, n=1, tz=helsinki)

888 eom_ref = helsinki.localize(datetime(2020, 7, 31, 23, 59, 59, 999999))

889 self.assertEqual(eom, eom_ref)

890 # 4

891 time_now = datetime(2020, 7, 5, 15, 47, 23, 818646)

892 eom = end_of_month(time_now, n=-2, tz=helsinki)

893 eom_ref = helsinki.localize(datetime(2020, 5, 31, 23, 59, 59, 999999))

894 self.assertEqual(eom, eom_ref)

895

896 def test_iban_generator_and_validator(self):

897 test_ibans = [

898 'MD7289912714638112731113',

899 'IS363252851674877586492113',

900 'HR5125000099152386224',

901 'CZ4750515755735423825528',

902 'FI3253811381259333',

903 'FR3212739000501869481882E94',

904 ]

905 for iban in test_ibans:

906 iban_validator(iban)

907 for cc in ['', 'FI', 'SE']:

908 for n in range(100):

909 acc = iban_generator(cc)

910 try:

911 iban_validator(acc)

912 except Exception as e:

913 print('iban_generator() returned', acc, 'but iban_validator() raised exception', e)

914 self.fail('iban_validator(iban_generator()) should not raise Exception, account number was {}'.format(acc))

915 with self.assertRaisesMessage(ValidationError, _('Invalid country code')):

916 iban_generator('XX')

917 with self.assertRaisesMessage(ValidationError, _('IBAN checksum generation does not support >26 character IBANs')):

918 iban_generator('AL')

919

920 def test_make_email_recipient(self):

921 email_tests = [

922 {

923 'list': [

924 ('Jani Kajala', 'kajala@example.com'),

925 '"Jani Kajala" <kajala@example.com>',

926 '<kajala@example.com>',

927 'kajala@example.com',

928 ],

929 'result': [

930 ('Jani Kajala', 'kajala@example.com'),

931 ('Jani Kajala', 'kajala@example.com'),

932 ('kajala@example.com', 'kajala@example.com'),

933 ('kajala@example.com', 'kajala@example.com'),

934 ]

935 }

936 ]

937 for et in email_tests:

938 res = make_email_recipient_list(et['list'])

939 self.assertListEqual(res, et['result'])

940

941 def test_choices(self):

942 val = choices_label(MY_CHOICES, MY_CHOICE_1)

943 self.assertEqual(val, 'MY_CHOICE_1')

944

945 def test_camel_case(self):

946 pairs = [

947 ('camelCaseWord', 'camel_case_word'),

948 ('camelCase', 'camel_case'),

949 ('camel', 'camel'),

950 ('camelCCase', 'camel_c_case'),

951 ]

952 for cc, us in pairs:

953 self.assertEqual(camel_case_to_underscore(cc), us)

954 self.assertEqual(cc, underscore_to_camel_case(us))

955

956 def create_dummy_request(self, path: str = '/admin/login/'):

957 request = request_factory.get(path)

958 request.user = self.user # type: ignore

959 request.user.profile = DummyUserProfile() # type: ignore

960 return request

961

962 def test_model_admin_base(self):

963 # test that actions sorting by name works

964 request = self.create_dummy_request()

965 user = self.user

966 model_admin = MyCustomAdmin(LogEntry, admin.site)

967 res = model_admin.get_actions(request)

968 self.assertEqual(list(res.items())[0][0], 'dummy_admin_func_a', 'ModelAdminBase.get_actions sorting failed')

969 self.assertEqual(list(res.items())[1][0], 'dummy_admin_func_b', 'ModelAdminBase.get_actions sorting failed')

970

971 # create 10 LogEntry for test user, 5 with text "VisibleLogMessage" and 5 "InvisibleLogMessage"

972 # then check that "VisibleLogMessage" log entries are not visible since max_history_length = 5

973 LogEntry.objects.filter(object_id=user.id).delete()

974 for n in range(5):

975 admin_log([user], 'InvisibleLogMessage')

976 for n in range(5):

977 admin_log([user], 'VisibleLogMessage')

978 self.assertEqual(LogEntry.objects.filter(object_id=user.id).count(), 10)

979 history_url = '/admin/auth/user/{}/history/'.format(user.id)

980 c = self.client

981 c.get(history_url, follow=True)

982 c.post('/admin/login/', {'username': 'test@example.com', 'password': 'test1234'})

983 res = c.get(history_url)

984 content = res.content.decode()

985 assert isinstance(content, str)

986 self.assertEqual(content.count('VisibleLogMessage'), 5)

987 self.assertEqual(content.count('InvisibleLogMessage'), 0)

988

989 def test_admin_log_entry_mixin(self):

990 user = self.user

991 AdminLogEntryMixin.fields_changed(user, ['username'], who=None)

992 e = LogEntry.objects.filter(object_id=user.id).last()

993 assert isinstance(e, LogEntry)

994 self.assertEqual(e.change_message, 'User id={}: username=test@example.com'.format(user.id))

995

996 def test_auth(self):

997 req = self.create_dummy_request()

998 get_auth_user(req) # type: ignore

999 req.user = None

1000 self.assertIsNone(get_auth_user_or_none(req))

1001 try:

1002 get_auth_user(req) # type: ignore

1003 self.fail('get_auth_user fail')

1004 except NotAuthenticated:

1005 pass

1006 try:

1007 model_admin = AuthUserMixin()

1008 model_admin.request = req

1009 user = model_admin.auth_user

1010 self.fail('get_auth_user fail')

1011 except NotAuthenticated:

1012 pass

1013

1014 def test_middleware(self):

1015 # EnsureOriginMiddleware

1016 request = self.create_dummy_request('/admin/login/')

1017 EnsureOriginMiddleware(dummy_middleware_get_response)(request)

1018 self.assertIn('HTTP_ORIGIN', request.META)

1019 self.assertEqual(request.META['HTTP_ORIGIN'], request.get_host())

1020

1021 # LogExceptionMiddleware

1022 dummy_log = DummyLogHandler()

1023 jutil_middleware_logger.addHandler(dummy_log)

1024 try:

1025 raise Exception('Dummy exception, ignore this')

1026 except Exception as e:

1027 mw = LogExceptionMiddleware(dummy_middleware_get_response)

1028 mw.process_exception(request, e)

1029 msg = dummy_log.msgs.pop()

1030 self.assertIn('Exception: Dummy exception, ignore this', msg)

1031 self.assertIn('user=test@example.com', msg)

1032 jutil_middleware_logger.removeHandler(dummy_log)

1033

1034 # EnsureLanguageCookieMiddleware

1035 lang_cookie_tests = [

1036 ('/admin/login/', settings.LANGUAGE_CODE),

1037 ('/admin/login/?django_language=fi', 'fi'),

1038 ]

1039 for request_path, lang_code in lang_cookie_tests:

1040 request = self.create_dummy_request(request_path)

1041 mw = EnsureLanguageCookieMiddleware(dummy_middleware_get_response)

1042 res = mw(request)

1043 assert isinstance(res, HttpResponse)

1044 self.assertEqual(res.status_code, 200)

1045 self.assertIn('django_language', request.COOKIES)

1046 self.assertIn(request.COOKIES['django_language'], lang_code)

1047 self.assertIn('django_language', res.cookies)

1048 self.assertEqual(str(res.cookies['django_language']), 'Set-Cookie: django_language={}; Path=/'.format(lang_code))

1049

1050 # ActivateUserProfileTimezoneMiddleware

1051 user = self.user

1052 self.assertTrue(user.is_authenticated)

1053 user.profile.timezone = 'Europe/Helsinki'

1054 with timezone.override(pytz.timezone('America/Chicago')):

1055 request = self.create_dummy_request('/admin/login/')

1056 mw = ActivateUserProfileTimezoneMiddleware(dummy_time_zone_response)

1057 res = mw(request)

1058 content = res.content.decode()

1059 self.assertEqual(content, user.profile.timezone)

1060

1061 def test_safe_fields(self):

1062 class TestModel(models.Model):

1063 cf = SafeCharField(max_length=256)

1064 tf = SafeTextField()

1065

1066 obj = TestModel()

1067 data = 'hello world <script>alert("popup")<script>'

1068 data_ref = 'hello world '

1069 for f in obj._meta.fields:

1070 if f.name in ['cf', 'tf']:

1071 f.save_form_data(obj, data)

1072 self.assertEqual(obj.cf, data_ref)

1073 self.assertEqual(obj.tf, data_ref)

1074

1075 def test_responses(self):

1076 a = [

1077 ['date', 'description', 'count', 'unit price', 'total price'],

1078 [date(2019, 12, 15), 'oranges', 1000, dec2('0.99'), dec2('990.00')],

1079 [date(2020, 1, 3), 'apples', 4, dec2('1.10'), dec2('4.40')],

1080 [date(2020, 11, 3), 'apples', 5, dec2('10.10'), dec2('50.50')],

1081 ]

1082 res = CsvResponse(a, 'test.csv')

1083 content_ref = b'date,description,count,unit price,total price\r\n2019-12-15,oranges,1000,0.99,990.00\r\n2020-01-03,apples,4,1.10,4.40\r\n2020-11-03,apples,5,10.10,50.50\r\n'

1084 self.assertEqual(content_ref, res.content)

1085 print(res.content.decode())

1086

1087 def test_wait_object_or_none(self):

1088 admin_log([self.user], 'Hello, world')

1089 e = LogEntry.objects.all().filter(object_id=self.user.id).last()

1090 assert isinstance(e, LogEntry)

1091 e_id = e.id

1092 obj = wait_object_or_none(LogEntry, id=e_id)

1093 self.assertIsNotNone(obj)

1094 self.assertEqual(obj.id, e_id)

1095 t0 = now()

1096 obj = wait_object_or_none(LogEntry, timeout=1.0, sleep_interval=0.1, id=e_id+1)

1097 t1 = now()

1098 self.assertIsNone(obj)

1099 self.assertGreater(t1-t0, timedelta(seconds=0.99))

1100

1101 def test_format_as_html_json(self):

1102 pairs = [

1103 (None, 'null'),

1104 ({'a': 1}, '{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&quot;a&quot;:&nbsp;1<br/>}'),

1105 ({"script": "<script>window.alert()</script>"},

1106 '{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&quot;script&quot;:&nbsp;&quot;&lt;script&gt;window.alert()&lt;/script&gt;&quot;<br/>}'),

1107 ]

1108 for val, html in pairs:

1109 self.assertEqual(format_as_html_json(val), html)

1110

1111 def test_parse_bool(self):

1112 refs_true = [

1113 True,

1114 'True',

1115 '1',

1116 1,

1117 'true',

1118 'yes',

1119 ]

1120 refs_false = [

1121 False,

1122 'False',

1123 '0',

1124 0,

1125 'false',

1126 'no',

1127 ]

1128 for ref in refs_true:

1129 self.assertTrue(parse_bool(ref))

1130 for ref in refs_false:

1131 self.assertFalse(parse_bool(ref))

1132

1133

1134 dummy_admin_func_a.short_description = 'A' # type: ignore

1135 dummy_admin_func_b.short_description = 'B' # type: ignore

1136

1137 admin.site.unregister(User)

1138 admin.site.register(User, MyCustomAdmin)

1139 admin.site.register(LogEntry, MyCustomAdmin)