Coverage for jutil/tests.py : 97%

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
1import logging
2import os
3from datetime import datetime, timedelta, date
4from decimal import Decimal
5from os.path import join
6from urllib.parse import urlparse
7from django.utils import timezone
8from typing import List
9from django.utils.timezone import now
10from rest_framework.test import APIClient
11from jutil.drf_exceptions import transform_exception_to_drf
12from jutil.modelfields import SafeCharField, SafeTextField
13from jutil.middleware import logger as jutil_middleware_logger, ActivateUserProfileTimezoneMiddleware
14import pytz
15from django.conf import settings
16from django.contrib.admin.models import LogEntry
17from django.contrib.auth.models import User
18from django.core.exceptions import ValidationError
19from rest_framework.exceptions import ValidationError as DRFValidationError, ErrorDetail
20from django.core.management.base import CommandParser # type: ignore
21from django.db import models
22from django.http.response import HttpResponse
23from django.test import TestCase
24from django.test.client import RequestFactory, Client
25from django.utils.translation import override, gettext as _, gettext_lazy
26from rest_framework.exceptions import NotAuthenticated
27from jutil.admin import admin_log, admin_obj_url, admin_obj_link, ModelAdminBase, AdminLogEntryMixin
28from jutil.auth import AuthUserMixin, get_auth_user, get_auth_user_or_none
29from jutil.command import get_date_range_by_name, add_date_range_arguments, parse_date_range_arguments
30from jutil.email import make_email_recipient_list
31from jutil.middleware import EnsureOriginMiddleware, LogExceptionMiddleware, EnsureLanguageCookieMiddleware
32from jutil.model import (
33 is_model_field_changed,
34 clone_model,
35 get_model_field_label_and_value,
36 get_object_or_none,
37 wait_object_or_none,
38)
39from jutil.request import get_ip_info
40from jutil.responses import CsvResponse
41from jutil.testing import TestSetupMixin
42from jutil.urls import modify_url
43from jutil.xml import xml_to_dict, dict_to_element, _xml_filter_tag_name
44from jutil.dates import (
45 add_month,
46 per_delta,
47 per_month,
48 this_week,
49 next_month,
50 next_week,
51 this_month,
52 last_month,
53 last_year,
54 last_week,
55 yesterday,
56 end_of_month,
57 this_year,
58 get_time_steps,
59 TIME_STEP_DAILY,
60)
61from jutil.format import (
62 format_full_name,
63 format_xml,
64 format_xml_bytes,
65 format_timedelta,
66 dec1,
67 dec2,
68 dec3,
69 dec4,
70 dec5,
71 dec6,
72 format_table,
73 ucfirst_lazy,
74 strip_media_root,
75 get_media_full_path,
76 camel_case_to_underscore,
77 underscore_to_camel_case,
78 format_as_html_json,
79 format_dict_as_html,
80 choices_label,
81 is_media_full_path,
82)
83from jutil.parse import parse_datetime, parse_bool, parse_datetime_or_none
84from jutil.validators import (
85 fi_payment_reference_number,
86 se_ssn_validator,
87 se_ssn_filter,
88 fi_iban_validator,
89 se_iban_validator,
90 iban_filter_readable,
91 email_filter,
92 iban_validator,
93 iban_bank_info,
94 fi_company_org_id_validator,
95 email_validator,
96 fi_payment_reference_validator,
97 iso_payment_reference_validator,
98 fi_ssn_age,
99 se_clearing_code_bank_info,
100 ascii_filter,
101 ee_iban_validator,
102 be_iban_validator,
103 dk_iban_validator,
104 dk_iban_bank_info,
105 dk_clearing_code_bank_name,
106 country_code_sanitizer,
107 phone_sanitizer,
108 email_sanitizer,
109 fi_company_org_id_generator,
110 phone_validator,
111 passport_filter,
112 passport_validator,
113 passport_sanitizer,
114 country_code_validator,
115 validate_country_iban,
116 iban_bic,
117 validate_country_company_org_id,
118 fi_ssn_generator,
119 fi_ssn_validator,
120 bic_validator,
121 iban_generator,
122 bic_sanitizer,
123 filter_country_company_org_id,
124)
125from xml.etree.ElementTree import Element
126from xml.etree import ElementTree as ET
127from django.contrib import admin
130MY_CHOICE_1 = "1"
131MY_CHOICE_2 = "2"
132MY_CHOICES = (
133 (MY_CHOICE_1, "MY_CHOICE_1"),
134 (MY_CHOICE_2, "MY_CHOICE_2"),
135)
137request_factory = RequestFactory()
140class DummyLogHandler(logging.Handler):
141 msgs: List[str]
143 def __init__(self):
144 super().__init__()
145 self.msgs = []
147 def emit(self, record):
148 msg = self.format(record)
149 self.msgs.append(msg)
152def dummy_time_zone_response(obj) -> HttpResponse:
153 tz = timezone.get_current_timezone()
154 return HttpResponse(str(tz).encode())
157def dummy_admin_func_a(modeladmin, request, qs):
158 print("dummy_admin_func_a")
161def dummy_admin_func_b(modeladmin, request, qs):
162 print("dummy_admin_func_b")
165def dummy_middleware_get_response(obj) -> HttpResponse:
166 return HttpResponse(b"hello content")
169class DummyUserProfile:
170 timezone = "Europe/Helsinki"
173class MyCustomAdmin(ModelAdminBase):
174 max_history_length = 5
175 actions = (
176 dummy_admin_func_b,
177 dummy_admin_func_a,
178 )
180 def get_object(self, request, obj_id):
181 return self.model.objects.get(id=obj_id)
184class Tests(TestCase, TestSetupMixin):
185 def setUp(self):
186 self.user = user = self.add_test_user("test@example.com", "test1234")
187 assert isinstance(user, User)
188 user.is_superuser = True
189 user.is_staff = True
190 user.save()
191 self.client = Client()
193 def test_api_client(self):
194 api_client = self.create_api_client()
195 self.assertTrue(isinstance(api_client, APIClient))
197 def test_payment_reference(self):
198 self.assertEqual(fi_payment_reference_number("100"), "1009")
199 invalids = [
200 "89182932u",
201 "0000002",
202 ]
203 for invalid in invalids:
204 try:
205 fi_payment_reference_number(invalid)
206 self.fail("invalid number but passed: {}".format(invalid))
207 except ValidationError:
208 pass
210 def test_format_full_name(self):
211 samples = [
212 ("Short", "Full Name", "Short Full Name"),
213 ("Short Middle Name Is Quite Long", "Full Name", "Short Full Name"),
214 ("Short-Middle Name Is Quite Long", "Full Name", "Short Full Name"),
215 ("Olga Demi", "Serpuhovitinova-Miettinen", "Olga Serpuhovitinova"),
216 ("Olga-Anne Demi", "Serpuhovitinovatsko", "Olga S"),
217 ]
218 for v in samples:
219 limited = format_full_name(v[0], v[1], 20)
220 # print('{} {} -> {} (was: {})'.format(v[0], v[1], v[2], limited))
221 self.assertEqual(v[2], limited)
222 try:
223 long_name = "19280309812083091829038190823081208301280381092830182038018203810283021"
224 format_full_name(long_name, long_name)
225 self.fail("format_full_name failed with long name")
226 except Exception:
227 pass
229 def test_parse_datetime(self):
230 pairs = [
231 ("2016-06-12", "2016-06-12T00:00:00+00:00"),
232 ("2016-06-12T01:00:00", "2016-06-12T01:00:00+00:00"),
233 ("2016-06-12 01:00:00", "2016-06-12T01:00:00+00:00"),
234 ("2016-06-12T01:00:00+00:00", "2016-06-12T01:00:00+00:00"),
235 ("2016-06-12 01:00:00+00:00", "2016-06-12T01:00:00+00:00"),
236 ]
237 for t_str_input, t_ref_str in pairs:
238 # parse_datetime
239 t = parse_datetime(t_str_input)
240 self.assertTrue(isinstance(t, datetime))
241 assert isinstance(t, datetime)
242 self.assertEqual(t.isoformat(), t_ref_str)
243 # parse_datetime_or_none
244 t = parse_datetime_or_none(t_str_input)
245 self.assertTrue(isinstance(t, datetime))
246 assert isinstance(t, datetime)
247 self.assertEqual(t.isoformat(), t_ref_str)
249 invalids = [
250 "12312313ew",
251 "2016-13-05",
252 ]
253 for t_str_input in invalids:
254 # parse_datetime
255 try:
256 parse_datetime(t_str_input)
257 self.fail("{} is not valid input for parse_datetime()".format(t_str_input))
258 except Exception:
259 pass
260 # parse_datetime_or_none
261 t = parse_datetime_or_none(t_str_input)
262 assert t is None
264 def test_add_month(self):
265 t = parse_datetime("2016-06-12T01:00:00")
266 self.assertTrue(isinstance(t, datetime))
267 assert isinstance(t, datetime)
268 self.assertEqual(t.isoformat(), "2016-06-12T01:00:00+00:00")
269 t2 = add_month(t)
270 self.assertEqual(t2.isoformat(), "2016-07-12T01:00:00+00:00")
271 t3 = add_month(t, 7)
272 self.assertEqual(t3.isoformat(), "2017-01-12T01:00:00+00:00")
273 t4 = add_month(t, -1)
274 self.assertEqual(t4.isoformat(), "2016-05-12T01:00:00+00:00")
275 time_now = datetime(2020, 6, 30, 15, 47, 23, 818646)
276 self.assertEqual(add_month(time_now, -4).isoformat(), "2020-02-29T15:47:23.818646")
277 self.assertEqual(add_month(time_now, 8).isoformat(), "2021-02-28T15:47:23.818646")
278 self.assertEqual(add_month(time_now, 0).isoformat(), "2020-06-30T15:47:23.818646")
280 def test_se_ssn(self):
281 se_ssn_validator("811228-9874")
282 se_ssn_validator("670919-9530")
283 with self.assertRaises(ValidationError):
284 se_ssn_validator("811228-9873")
286 def test_phone_numbers(self):
287 try:
288 phone_validator("+358456343767")
289 except Exception:
290 self.fail('phone_validator("+358456343767") should not raise Exception')
291 with self.assertRaisesMessage(ValidationError, _("Invalid phone number")):
292 phone_validator("214")
293 self.assertEqual(phone_sanitizer("214"), "")
295 def test_passport(self):
296 self.assertEqual(passport_filter("?ADsd-12312dsds"), "ADSD-12312DSDS")
297 passport_validator("21412312312")
298 with self.assertRaisesMessage(ValidationError, _("Invalid passport number")):
299 passport_validator("214")
300 self.assertEqual(passport_sanitizer("214"), "")
301 self.assertEqual(passport_sanitizer("21412312312"), "21412312312")
303 def test_country_code(self):
304 for cc in ["FI", "DK", "ES", "SE", "VN"]:
305 country_code_validator(cc)
306 with self.assertRaisesMessage(ValidationError, _("Invalid country code")):
307 country_code_validator("Finland")
309 def test_bic(self):
310 bic = iban_bic("FI21 1234 5600 0007 85")
311 self.assertEqual(bic, "NDEAFIHH")
312 self.assertEqual(bic_sanitizer("NDEAFIHH"), "NDEAFIHH")
313 self.assertEqual(bic_sanitizer("NDEAFIH"), "")
315 def test_org_id(self):
316 try:
317 validate_country_company_org_id("FI", "2084069-9")
318 except Exception:
319 self.fail("2084069-9 is valid org id")
320 with self.assertRaisesMessage(ValidationError, _("Invalid company organization ID")):
321 validate_country_company_org_id("FI", "2084069-8")
323 def test_validate_country_iban(self):
324 with self.assertRaisesMessage(ValidationError, _("Invalid IBAN account number")):
325 validate_country_iban("FI15616515616156", "SE")
327 def test_fi_ssn_generator(self):
328 self.assertEqual(len(fi_ssn_generator()), 6 + 1 + 4)
329 for min_year, max_year in [(1800, 1900), (1900, 2000), (2000, 2050)]:
330 for n in range(10):
331 ssn = fi_ssn_generator(min_year, max_year)
332 try:
333 fi_ssn_age(ssn)
334 fi_ssn_validator(ssn)
335 except Exception:
336 self.fail("{} is valid SSN".format(ssn))
337 fi_ssn_validator("110305+283X")
338 for ssn in ["9999-123F", "271138-670X", "090228+256X"]:
339 with self.assertRaisesMessage(ValidationError, _("Invalid personal identification number")):
340 fi_ssn_validator(ssn)
341 with self.assertRaises(ValidationError):
342 fi_ssn_generator(1700, 1799)
343 with self.assertRaises(ValidationError):
344 fi_ssn_generator(2100, 2200)
346 def test_iban(self):
347 with self.assertRaisesMessage(ValidationError, _("Invalid IBAN account number")):
348 iban_validator("")
349 with self.assertRaisesMessage(ValidationError, _("Invalid country code")):
350 iban_validator("XX")
351 with self.assertRaisesMessage(ValidationError, _("Invalid IBAN account number")):
352 iban_validator("FI2112345600000786")
353 bic_validator("HELSFIHH")
354 bic_validator("HELSFIHHXXX")
355 with self.assertRaisesMessage(ValidationError, _("Invalid bank BIC/SWIFT code")):
356 bic_validator("HELSFIH")
357 with self.assertRaisesMessage(ValidationError, _("Invalid bank BIC/SWIFT code")):
358 bic_validator("")
359 with self.assertRaisesMessage(ValidationError, _("Invalid bank BIC/SWIFT code")):
360 bic_validator("XX123123123112")
361 iban_validator("FI2112345600000785")
362 iban_validator("SE4550000000058398257466")
363 fi_iban_validator("FI2112345600000785")
364 se_iban_validator("SE4550000000058398257466")
365 ee_iban_validator("EE38 2200 2210 2014 5685")
366 be_iban_validator("BE68 5390 0754 7034")
367 with self.assertRaises(ValidationError):
368 fi_iban_validator("FI2112345600000784")
369 with self.assertRaises(ValidationError):
370 se_iban_validator("SE4550000000058398257465")
371 iban = "FI8847304720017517"
372 self.assertEqual(iban_filter_readable(iban), "FI88 4730 4720 0175 17")
373 self.assertEqual(iban_filter_readable(""), "")
375 def test_urls(self):
376 url = "http://yle.fi/uutiset/3-8045550?a=123&b=456"
377 self.assertEqual(
378 modify_url("http://yle.fi/uutiset/3-8045550?a=123&b=456", {"a": "123", "b": "456"}),
379 "http://yle.fi/uutiset/3-8045550?a=123&b=456",
380 )
382 def test_email_filter_and_validation(self):
383 emails = [
384 (" Asdsa@a-a.com ", "asdsa@a-a.com", True),
385 ("1asdsa@a-a2.com", "1asdsa@a-a2.com", True),
386 (" Asdsa@a-a ", "asdsa@a-a", False),
387 (" @a-a2.com", "@a-a2.com", False),
388 (" a-a2.com", "a-a2.com", False),
389 ("ää-a2@ää-a2.com", "ää-a2@ää-a2.com", False),
390 ("aaa.bbbbb@ccc-ddd.fi", "aaa.bbbbb@ccc-ddd.fi", True),
391 ]
392 for i, o, is_valid in emails:
393 # print('email_filter({}) -> {}'.format(i, email_filter(i)))
394 self.assertEqual(email_filter(i), o)
395 if is_valid:
396 email_validator(o)
397 else:
398 fail = False
399 try:
400 email_validator(o)
401 except ValidationError:
402 fail = True
403 self.assertTrue(fail, "{} is not valid email but passed validation".format(o))
405 def test_ip_info(self):
406 ip, cc, host = get_ip_info("213.214.146.142")
407 self.assertEqual(ip, "213.214.146.142")
408 if cc: 408 ↛ 410line 408 didn't jump to line 410, because the condition on line 408 was never false
409 self.assertEqual(cc, "FI")
410 if host: 410 ↛ exitline 410 didn't return from function 'test_ip_info', because the condition on line 410 was never false
411 self.assertEqual(host, "213214146142.edelkey.net")
413 def test_parse_xml(self):
414 # finvoice_201_example1.xml
415 xml_bytes = open(join(settings.BASE_DIR, "data/fi/finvoice_201_example1.xml"), "rb").read()
416 data = xml_to_dict(xml_bytes, value_key="value", attribute_prefix="_")
417 # pprint(data)
418 self.assertEqual(data["_Version"], "2.01")
419 self.assertEqual(data["InvoiceRow"][0]["ArticleIdentifier"], "12345")
420 self.assertEqual(data["InvoiceRow"][0]["DeliveredQuantity"]["value"], "2")
421 self.assertEqual(data["InvoiceRow"][0]["DeliveredQuantity"]["_QuantityUnitCode"], "kpl")
422 self.assertEqual(data["InvoiceRow"][1]["ArticleIdentifier"], "123456")
424 # parse_xml1.xml
425 xml_str = open(join(settings.BASE_DIR, "data/parse_xml1.xml"), "rt").read()
426 data = xml_to_dict(xml_str.encode())
427 # pprint(data)
428 ref_data = {
429 "@version": "1.2",
430 "A": [
431 {"@class": "x", "B": {"@": "hello", "@class": "x2"}},
432 {"@class": "y", "B": {"@": "world", "@class": "y2"}},
433 ],
434 "C": "value node",
435 }
436 self.assertEqual(ref_data, data)
438 # parse_xml1.xml / no attributes
439 xml_str = open(join(settings.BASE_DIR, "data/parse_xml1.xml"), "rt").read()
440 data = xml_to_dict(xml_str.encode(), parse_attributes=False)
441 # pprint(data)
442 ref_data = {"A": [{"B": "hello"}, {"B": "world"}], "C": "value node"}
443 self.assertEqual(ref_data, data)
445 # parse_xml2.xml / no attributes
446 xml_str = open(join(settings.BASE_DIR, "data/parse_xml2.xml"), "rt").read()
447 data = xml_to_dict(xml_str.encode(), ["VastausLoki", "LuottoTietoMerkinnat"], parse_attributes=False)
448 # pprint(data)
449 ref_data = {
450 "VastausLoki": {
451 "KysyttyHenkiloTunnus": "020685-1234",
452 "PaluuKoodi": "Palveluvastaus onnistui",
453 "SyyKoodi": "1",
454 }
455 }
456 self.assertEqual(ref_data, data)
458 def test_dict_to_xml(self):
459 data = {
460 "Doc": {
461 "@version": "1.2",
462 "A": [
463 {"@class": "x", "B": {"@": "hello", "@class": "x2"}},
464 {"@class": "y", "B": {"@": "world", "@class": "y2"}},
465 ],
466 "C": "value node",
467 "D": 123,
468 "E": ["abc"],
469 }
470 }
471 el = dict_to_element(data)
472 assert isinstance(el, Element)
473 xml_str = ET.tostring(el, encoding="utf8", method="xml").decode()
474 # 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>
475 data2 = xml_to_dict(xml_str.encode(), document_tag=True, array_tags=["E"], int_tags=["D"])
476 # print('')
477 # pprint(data)
478 # pprint(data2)
479 self.assertEqual(data2, data)
481 def test_dict_to_xml2(self):
482 self.assertEqual(_xml_filter_tag_name("TagName[0]"), "TagName")
483 self.assertEqual(_xml_filter_tag_name("TagName[1]"), "TagName")
484 self.assertEqual(_xml_filter_tag_name("TagName"), "TagName")
485 data = {
486 "Doc": {
487 "@version": "1.2",
488 "A": [
489 {"@class": "x", "B": {"@": "hello", "@class": "x2"}},
490 {"@class": "y", "B": {"@": "world", "@class": "y2"}},
491 ],
492 "C": "value node",
493 "D": 123,
494 "E": ["abc"],
495 "F": ["line 1", "line 2"],
496 }
497 }
498 el = dict_to_element(data)
499 assert isinstance(el, Element)
500 xml_str = ET.tostring(el, encoding="utf8", method="xml").decode()
501 data2 = xml_to_dict(xml_str.encode(), document_tag=True, array_tags=["E", "F"], int_tags=["D"])
502 self.assertEqual(data2, data)
504 def test_xml_to_dict(self):
505 xml_str = """<?xml version="1.0" encoding="utf-8"?>
506<Document>
507 <TxsSummry>
508 <TtlNtries>
509 <NbOfNtries>12</NbOfNtries>
510 </TtlNtries>
511 <TtlCdtNtries>
512 <NbOfNtries>34</NbOfNtries>
513 <Sum>1234.56</Sum>
514 </TtlCdtNtries>
515 <TtlDbtNtries>
516 <NbOfNtries>0</NbOfNtries>
517 <Sum>0</Sum>
518 </TtlDbtNtries>
519 </TxsSummry>
520</Document>"""
521 data = xml_to_dict(xml_str.encode(), document_tag=True, array_tags=[], int_tags=["NbOfNtries"])
522 # print('')
523 # pprint(data)
524 self.assertEqual(data["Document"]["TxsSummry"]["TtlNtries"]["NbOfNtries"], 12)
525 self.assertEqual(data["Document"]["TxsSummry"]["TtlCdtNtries"]["NbOfNtries"], 34)
527 def test_per_delta(self):
528 begin = datetime(2017, 9, 17, 11, 42)
529 end = begin + timedelta(days=4)
530 ref = [
531 (datetime(2017, 9, 17, 11, 42), datetime(2017, 9, 18, 11, 42)),
532 (datetime(2017, 9, 18, 11, 42), datetime(2017, 9, 19, 11, 42)),
533 (datetime(2017, 9, 19, 11, 42), datetime(2017, 9, 20, 11, 42)),
534 (datetime(2017, 9, 20, 11, 42), datetime(2017, 9, 21, 11, 42)),
535 ]
536 res = per_delta(begin, end, timedelta(days=1))
537 self.assertEqual(list(res), ref)
539 def test_per_month(self):
540 begin = datetime(2017, 9, 1, 0, 0)
541 res = list(per_month(begin, begin + timedelta(days=32)))
542 ref = [
543 (datetime(2017, 9, 1, 0, 0), datetime(2017, 10, 1, 0, 0)),
544 (datetime(2017, 10, 1, 0, 0), datetime(2017, 11, 1, 0, 0)),
545 ]
546 self.assertEqual(list(res), ref)
548 def test_dates(self):
549 t = datetime(2018, 1, 30)
550 b, e = this_week(t)
551 self.assertEqual(b, pytz.utc.localize(datetime(2018, 1, 29)))
552 self.assertEqual(e, pytz.utc.localize(datetime(2018, 2, 5)))
553 b, e = this_month(t)
554 self.assertEqual(b, pytz.utc.localize(datetime(2018, 1, 1)))
555 self.assertEqual(e, pytz.utc.localize(datetime(2018, 2, 1)))
556 b, e = next_week(t)
557 self.assertEqual(b, pytz.utc.localize(datetime(2018, 2, 5)))
558 self.assertEqual(e, pytz.utc.localize(datetime(2018, 2, 12)))
560 def test_named_date_ranges(self):
561 t = datetime(2018, 5, 31)
562 t_tz = pytz.utc.localize(t)
563 named_ranges = [
564 ("last_year", last_year(t)),
565 ("last_month", last_month(t)),
566 ("last_week", last_week(t)),
567 ("this_year", this_year(t)),
568 ("this_month", this_month(t)),
569 ("this_week", this_week(t)),
570 ("yesterday", yesterday(t)),
571 ("today", yesterday(t + timedelta(hours=24))),
572 ]
573 day_ranges = [7, 15, 30, 60, 90]
574 for days in day_ranges:
575 named_ranges.append(
576 ("plus_minus_{}d".format(days), (t_tz - timedelta(days=days), t_tz + timedelta(days=days)))
577 )
578 named_ranges.append(("prev_{}d".format(days), (t_tz - timedelta(days=days), t_tz)))
579 named_ranges.append(("next_{}d".format(days), (t_tz, t_tz + timedelta(days=days))))
580 for name, res in named_ranges:
581 # print('testing', name)
582 self.assertEqual(get_date_range_by_name(name, t), res)
584 def test_time_steps(self):
585 t = parse_datetime("2020-08-24 23:28:36.503174")
586 this_week_daily = [
587 "2020-08-24T00:00:00+00:00 2020-08-25T00:00:00+00:00",
588 "2020-08-25T00:00:00+00:00 2020-08-26T00:00:00+00:00",
589 "2020-08-26T00:00:00+00:00 2020-08-27T00:00:00+00:00",
590 "2020-08-27T00:00:00+00:00 2020-08-28T00:00:00+00:00",
591 "2020-08-28T00:00:00+00:00 2020-08-29T00:00:00+00:00",
592 "2020-08-29T00:00:00+00:00 2020-08-30T00:00:00+00:00",
593 "2020-08-30T00:00:00+00:00 2020-08-31T00:00:00+00:00",
594 ]
595 ix = 0
596 for begin, end in get_time_steps(TIME_STEP_DAILY, *this_week(t)):
597 self.assertEqual("{} {}".format(begin.isoformat(), end.isoformat()), this_week_daily[ix])
598 ix += 1
600 def test_bank_info(self):
601 ac = "FI8847304720017517"
602 inf = iban_bank_info(ac)
603 self.assertEqual(inf[0], "POPFFI22")
604 self.assertEqual(inf[1], "POP-Pankki")
606 ac = ""
607 inf = iban_bank_info(ac)
608 self.assertEqual(inf[0], "")
609 self.assertEqual(inf[1], "")
611 ac = "BE75270187592710"
612 inf = iban_bank_info(ac)
613 self.assertEqual(inf[0], "GEBABEBB")
614 self.assertEqual(inf[1], "BNP Paribas Fortis")
615 ac = "BE58465045170210"
616 inf = iban_bank_info(ac)
617 self.assertEqual(inf[0], "KREDBEBB")
618 self.assertEqual(inf[1], "KBC Bank")
619 ac = "BE11000123456748"
620 inf = iban_bank_info(ac)
621 self.assertEqual(inf[0], "BPOTBEB1")
622 self.assertEqual(inf[1], "bpost bank")
624 def test_org_id_fi(self):
625 valids = [
626 "FI01098230",
627 "FI-01098230",
628 "0109823-0",
629 "2084069-9",
630 ]
631 invalids = [
632 "2084069-1",
633 "SE2084069-1",
634 ]
635 co_filtered = [
636 ("FI", "FI01098230", "0109823-0"),
637 ("FI", "FI-01098230", "0109823-0"),
638 ("FI", "0109823-0", "0109823-0"),
639 ("FI", "2084069-9", "2084069-9"),
640 ("SE", "01098230", "01098230"),
641 ("SE", "20840699", "20840699"),
642 ]
643 for cc, org, val in co_filtered:
644 self.assertEqual(filter_country_company_org_id(cc, org), val)
645 validate_country_company_org_id(cc, org)
646 for valid in valids:
647 fi_company_org_id_validator(valid)
648 for invalid in invalids:
649 try:
650 fi_company_org_id_validator(invalid)
651 self.fail("{} passed as valid FI-org".format(invalid))
652 except ValidationError:
653 # print('ok')
654 pass
655 for n in range(10):
656 v0 = fi_company_org_id_generator()
657 # print(v0)
658 fi_company_org_id_validator(v0)
660 def test_reference_number_validators(self):
661 valid_fi_refs = [
662 "302300",
663 "202196",
664 "302290",
665 ]
666 for ref_no in valid_fi_refs:
667 fi_payment_reference_validator(ref_no)
669 invalid_fi_refs = [
670 "302301",
671 "202195",
672 "302291",
673 ]
674 for ref_no in invalid_fi_refs:
675 try:
676 fi_payment_reference_validator(ref_no)
677 self.assertFalse(True, "{} should have failed validation".format(ref_no))
678 except ValidationError:
679 pass
681 valid_iso_refs = [
682 "RF92 1229",
683 "RF11 1232",
684 "RF48 1245",
685 ]
686 for ref_no in valid_iso_refs:
687 iso_payment_reference_validator(ref_no)
689 invalid_iso_refs = [
690 "RF92 1229}",
691 ]
692 for ref_no in invalid_iso_refs:
693 with self.assertRaisesMessage(ValidationError, "Invalid payment reference"):
694 iso_payment_reference_validator(ref_no)
696 def test_fi_ssn_age(self):
697 samples = [
698 (date(2018, 12, 20), "231298-965X", 19),
699 (date(2018, 12, 22), "231298-965X", 19),
700 (date(2018, 12, 23), "231298-965X", 20),
701 (date(2018, 12, 24), "231298-965X", 20),
702 ]
703 for date_now, ssn, age in samples:
704 self.assertEqual(
705 fi_ssn_age(ssn, date_now),
706 age,
707 msg="{} age is {} on {} but fi_ssn_age result was {}".format(
708 ssn, age, date_now, fi_ssn_age(ssn, date_now)
709 ),
710 )
712 def test_se_banks(self):
713 self.assertEqual(se_clearing_code_bank_info("6789"), ("Handelsbanken", 9))
714 se_iban_validator("SE45 5000 0000 0583 9825 7466")
715 with self.assertRaisesMessage(ValidationError, _("Invalid IBAN account number")):
716 se_iban_validator("")
717 with self.assertRaisesMessage(ValidationError, _("Invalid IBAN account number")):
718 se_iban_validator("XX45 5000 0000 0583 9825 7466")
719 with self.assertRaisesMessage(ValidationError, _("Invalid IBAN account number")):
720 se_iban_validator("SE45 5000 0000 0583 9825")
721 self.assertEqual(se_clearing_code_bank_info("9500"), ("Nordea AB", 10))
722 an = "957033025420"
723 bank_name, acc_digits = se_clearing_code_bank_info(an)
724 self.assertEqual(bank_name, "Sparbanken Syd")
725 self.assertGreaterEqual(len(an) - 4, acc_digits)
727 def test_dk_banks(self):
728 an = "DK50 0040 0440 1162 43"
729 dk_iban_validator(an)
730 bic, name = dk_iban_bank_info(an)
731 self.assertEqual(name, "Nordea")
732 an = "8114 0008874093"
733 name = dk_clearing_code_bank_name(an)
734 self.assertEqual(name, "Nykredit Bank")
735 an = "DK2520006893703029"
736 name = dk_clearing_code_bank_name(an)
737 self.assertEqual(name, "Nordea")
739 def test_ascii_filter(self):
740 pairs = [
741 ("Åke va Källe o Öring", "Ake va Kalle o Oring"),
742 ("Tôi đang đi mua sắm", "Toi ang i mua sam"),
743 ("HELÉN FRANZÉN", "HELEN FRANZEN"),
744 ]
745 for a, b in pairs:
746 self.assertEqual(ascii_filter(a), b, 'ascii_filter("{}") != "{}"'.format(b, ascii_filter(a)))
748 def test_l10n(self):
749 with override("fi"):
750 msg = _("“%(value)s” value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format.")
751 if "muoto ei kelpaa" not in msg: 751 ↛ 752line 751 didn't jump to line 752, because the condition on line 751 was never true
752 print(msg)
753 self.assertTrue("muoto ei kelpaa" in msg)
755 try:
756 parse_bool("hello")
757 except ValidationError as e:
758 self.assertEqual(str(e), "['hello ei ole yksi valittavissa olevista arvoista']")
760 def test_sanitizers(self):
761 self.assertEqual(country_code_sanitizer("kods"), "")
762 self.assertEqual(country_code_sanitizer("fi"), "FI")
763 self.assertEqual(phone_sanitizer("+13146094459"), "+13146094459")
764 self.assertEqual(phone_sanitizer("13146094459"), "13146094459")
765 self.assertEqual(phone_sanitizer("+13146094459A"), "+13146094459")
766 self.assertEqual(email_sanitizer("test@example.com"), "test@example.com")
767 self.assertEqual(email_sanitizer("testexample.com"), "")
769 def test_format_dict_as_html(self):
770 a = {"b": 1, "c": {"@testVariable": "123"}}
771 res = "<pre>B: 1\nC:\n Test variable: 123\n\n</pre>"
772 self.assertEqual(format_dict_as_html(a), res)
774 def test_format_xml(self):
775 assert settings.XMLLINT_PATH, 'add e.g. XMLLINT_PATH = "/usr/bin/xmllint" to settings.py'
776 src = "<ApplicationRequest> <CustomerId>1</CustomerId> <Command>DownloadFileList</Command><Timestamp>2019-11-27T04:32:18.613452+02:00</Timestamp><Environment>PRODUCTION</Environment></ApplicationRequest>"
777 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'
778 dst = format_xml(src)
779 self.assertEqual(dst, dst_ref)
780 dst = format_xml_bytes(src.encode())
781 self.assertEqual(dst, dst_ref.encode())
783 def test_parse_sftp(self):
784 test_cases = [
785 ("sftp://jani@kajala.com", ["jani", None, "kajala.com", ""]),
786 ("sftp://jani.kajala:1231!@kajala.com", ["jani.kajala", "1231!", "kajala.com", ""]),
787 ("sftp://jani:1231!@kajala.com/my/dir", ["jani", "1231!", "kajala.com", "/my/dir"]),
788 ("sftp://jani.kajala:1231!@kajala.com/my/dir", ["jani.kajala", "1231!", "kajala.com", "/my/dir"]),
789 ]
790 for connection, ref_res in test_cases:
791 res = urlparse(connection)
792 res_list = [res.username, res.password, res.hostname, res.path]
793 self.assertListEqual(res_list, ref_res, 'SFTP connection string "{}" parsed incorrectly'.format(connection))
795 def test_admin(self):
796 obj = self.user
797 admin_log([obj], "Hello, world")
798 admin_log([obj], "Hello, world", user=self.user, ip="127.0.0.1")
799 admin_log(obj, "Hello, world", user=self.user, ip="127.0.0.1")
800 e = LogEntry.objects.all().filter(object_id=obj.id).last()
801 self.assertIsNotNone(e)
802 assert isinstance(e, LogEntry)
803 self.assertEqual(e.change_message, "Hello, world")
804 self.assertEqual(admin_obj_url(obj, "admin:auth_user_change"), "/admin/auth/user/{}/change/".format(obj.id))
805 self.assertEqual(admin_obj_url(None, "admin:auth_user_change"), "")
806 self.assertEqual(admin_obj_link(None, "admin:auth_user_change"), "")
807 self.assertEqual(admin_obj_url(obj), "/admin/auth/user/{}/change/".format(obj.id))
808 self.assertEqual(admin_obj_url(e), "/admin/admin/logentry/{}/change/".format(e.id))
809 link = admin_obj_link(obj, "User", "admin:auth_user_change")
810 self.assertEqual(link, "<a href='/admin/auth/user/{}/change/'>User</a>".format(obj.id))
812 def test_cmd_parser(self):
813 parser = CommandParser()
814 add_date_range_arguments(parser)
815 argv = parser.parse_args(["--begin", "2019-06-25", "--end", "2020-02-01"])
816 options = argv.__dict__
817 begin, end, steps = parse_date_range_arguments(options)
818 self.assertEqual(begin, pytz.utc.localize(datetime(2019, 6, 25)))
819 self.assertEqual(end, pytz.utc.localize(datetime(2020, 2, 1)))
821 def test_format_timedelta(self):
822 self.assertEqual(format_timedelta(timedelta(seconds=90)), "1min30s")
823 self.assertEqual(format_timedelta(timedelta(seconds=3600 + 90)), "1h1min30s")
824 self.assertEqual(format_timedelta(timedelta(seconds=90), minutes_label="min ", seconds_label="s "), "1min 30s")
825 self.assertEqual(
826 format_timedelta(timedelta(seconds=3600 + 90), hours_label="h ", minutes_label="min ", seconds_label="s "),
827 "1h 1min 30s",
828 )
829 self.assertEqual(format_timedelta(timedelta(seconds=90), seconds_label=""), "1min")
830 self.assertEqual(format_timedelta(timedelta(seconds=0.090), seconds_label="s"), "0.090s")
832 def test_dec123456(self):
833 self.assertEqual(dec1(Decimal("1.2345678")), Decimal("1.2"))
834 self.assertEqual(dec2(Decimal("1.2345678")), Decimal("1.23"))
835 self.assertEqual(dec3(Decimal("1.2345678")), Decimal("1.235"))
836 self.assertEqual(dec4(Decimal("1.2345678")), Decimal("1.2346"))
837 self.assertEqual(dec5(Decimal("1.2345678")), Decimal("1.23457"))
838 self.assertEqual(dec6(Decimal("1.2345678")), Decimal("1.234568"))
840 def test_model_funcs(self):
841 admin_log([self.user], "test msg 1")
842 obj = LogEntry.objects.all().order_by("-pk").last()
843 assert isinstance(obj, LogEntry)
844 self.assertFalse(is_model_field_changed(obj, "change_message"))
845 obj.change_message = "hello world"
846 self.assertTrue(is_model_field_changed(obj, "change_message"))
847 obj.save()
848 self.assertFalse(is_model_field_changed(obj, "change_message"))
849 obj2 = clone_model(obj)
850 assert isinstance(obj2, LogEntry)
851 self.assertEqual(obj.change_message, obj2.change_message)
852 self.assertGreater(obj2.pk, obj.pk)
853 label, val = get_model_field_label_and_value(obj, "action_time")
854 self.assertEqual(label, _("action time"))
855 self.assertEqual(str(obj.action_time), val)
856 obj_b = get_object_or_none(obj.__class__, id=obj.id)
857 self.assertEqual(obj_b.id, obj.id)
858 obj_b = get_object_or_none(obj.__class__, id=-1)
859 self.assertIsNone(obj_b)
861 def test_format_table(self):
862 a = [
863 ["date", "description", "count", "unit price", "total price"],
864 [date(2019, 12, 15), "oranges", 1000, dec2("0.99"), dec2("990.00")],
865 [date(2020, 1, 3), "apples", 4, dec2("1.10"), dec2("4.40")],
866 [date(2020, 11, 3), "apples", 5, dec2("10.10"), dec2("50.50")],
867 ]
868 out = format_table(a, has_label_row=True, max_col=10)
869 out_ref = """
870---------------------------------------------------
871| date|descript..|count|unit price|total pr..|
872---------------------------------------------------
873|2019-12-15| oranges| 1000| 0.99| 990.00|
874|2020-01-03| apples| 4| 1.10| 4.40|
875|2020-11-03| apples| 5| 10.10| 50.50|
876---------------------------------------------------
877 """.strip()
878 self.assertEqual(out, out_ref)
880 out = format_table(a, has_label_row=True, max_col=20)
881 out_ref = """
882-----------------------------------------------------
883| date|description|count|unit price|total price|
884-----------------------------------------------------
885|2019-12-15| oranges| 1000| 0.99| 990.00|
886|2020-01-03| apples| 4| 1.10| 4.40|
887|2020-11-03| apples| 5| 10.10| 50.50|
888-----------------------------------------------------
889 """.strip()
890 self.assertEqual(out, out_ref)
892 out = format_table(a, has_label_row=True, max_col=20, col_sep=" | ")
893 out_ref = """
894-------------------------------------------------------------
895| date | description | count | unit price | total price|
896-------------------------------------------------------------
897|2019-12-15 | oranges | 1000 | 0.99 | 990.00|
898|2020-01-03 | apples | 4 | 1.10 | 4.40|
899|2020-11-03 | apples | 5 | 10.10 | 50.50|
900-------------------------------------------------------------
901 """.strip()
902 self.assertEqual(out, out_ref)
904 out = format_table(a, has_label_row=True, max_col=20, col_sep=" | ", left_align=[1])
905 out_ref = """
906-------------------------------------------------------------
907| date | description | count | unit price | total price|
908-------------------------------------------------------------
909|2019-12-15 | oranges | 1000 | 0.99 | 990.00|
910|2020-01-03 | apples | 4 | 1.10 | 4.40|
911|2020-11-03 | apples | 5 | 10.10 | 50.50|
912-------------------------------------------------------------
913 """.strip()
914 self.assertEqual(out, out_ref)
916 out = format_table(a, has_label_row=True, max_col=20, col_sep=" | ", left_align=[1], max_line=50)
917 out_ref = """
918-------------------------------------------------
919| date | description | count | unit price|..
920-------------------------------------------------
921|2019-12-15 | oranges | 1000 | 0.99|..
922|2020-01-03 | apples | 4 | 1.10|..
923|2020-11-03 | apples | 5 | 10.10|..
924-------------------------------------------------
925 """.strip()
926 self.assertEqual(out, out_ref)
928 out = format_table(a, left_align=[1], center_align=[0, 2, 3, 4], max_col=50)
929 out_ref = """
930-----------------------------------------------------
931| date |description|count|unit price|total price|
932|2019-12-15|oranges |1000 | 0.99 | 990.00 |
933|2020-01-03|apples | 4 | 1.10 | 4.40 |
934|2020-11-03|apples | 5 | 10.10 | 50.50 |
935-----------------------------------------------------
936 """.strip()
937 self.assertEqual(out, out_ref)
939 def test_ucfirst_lazy(self):
940 s = gettext_lazy(ucfirst_lazy("missing value"))
941 s_ref = gettext_lazy("Missing value")
942 s_en = "Missing value"
943 s_fi = "Puuttuva arvo"
944 with override("fi"):
945 self.assertEqual(s, s_fi)
946 self.assertEqual(s, s_ref)
947 with override("en"):
948 self.assertEqual(s, s_en)
949 self.assertEqual(s, s_ref)
951 def test_media_paths(self):
952 media_root1 = os.path.join(settings.MEDIA_ROOT, "path1/path2")
953 media_root2 = os.path.join(settings.MEDIA_ROOT, "path3") + "/"
954 test_paths = [
955 (True, os.path.join(media_root1, "test1.file"), "path1/path2/test1.file"),
956 (False, os.path.join("/diff/path", "test2.file"), "/diff/path/test2.file"),
957 (True, os.path.join(media_root2, "test3.file"), "path3/test3.file"),
958 ]
959 for is_media, src, dst in test_paths:
960 self.assertEqual(is_media_full_path(src), is_media)
961 if is_media:
962 self.assertEqual(strip_media_root(src), dst)
963 self.assertEqual(get_media_full_path(dst), src)
964 self.assertEqual(get_media_full_path(dst), get_media_full_path(get_media_full_path(dst)))
966 def test_end_of_month(self):
967 helsinki = pytz.timezone("Europe/Helsinki")
968 # 1
969 time_now = datetime(2020, 6, 5, 15, 47, 23, 818646)
970 eom = end_of_month(time_now, tz=helsinki)
971 eom_ref = helsinki.localize(datetime(2020, 6, 30, 23, 59, 59, 999999))
972 self.assertEqual(eom, eom_ref)
973 # 2
974 time_now = datetime(2020, 7, 5, 15, 47, 23, 818646)
975 eom = end_of_month(time_now, tz=helsinki)
976 eom_ref = helsinki.localize(datetime(2020, 7, 31, 23, 59, 59, 999999))
977 self.assertEqual(eom, eom_ref)
978 # 3
979 time_now = datetime(2020, 6, 5, 15, 47, 23, 818646)
980 eom = end_of_month(time_now, n=1, tz=helsinki)
981 eom_ref = helsinki.localize(datetime(2020, 7, 31, 23, 59, 59, 999999))
982 self.assertEqual(eom, eom_ref)
983 # 4
984 time_now = datetime(2020, 7, 5, 15, 47, 23, 818646)
985 eom = end_of_month(time_now, n=-2, tz=helsinki)
986 eom_ref = helsinki.localize(datetime(2020, 5, 31, 23, 59, 59, 999999))
987 self.assertEqual(eom, eom_ref)
989 def test_iban_generator_and_validator(self):
990 test_ibans = [
991 "MD7289912714638112731113",
992 "IS363252851674877586492113",
993 "HR5125000099152386224",
994 "CZ4750515755735423825528",
995 "FI3253811381259333",
996 "FR3212739000501869481882E94",
997 ]
998 for iban in test_ibans:
999 iban_validator(iban)
1000 for cc in ["", "FI", "SE"]:
1001 for n in range(100):
1002 acc = iban_generator(cc)
1003 try:
1004 iban_validator(acc)
1005 except Exception as e:
1006 print("iban_generator() returned", acc, "but iban_validator() raised exception", e)
1007 self.fail(
1008 "iban_validator(iban_generator()) should not raise Exception, account number was {}".format(acc)
1009 )
1010 with self.assertRaisesMessage(ValidationError, _("Invalid country code")):
1011 iban_generator("XX")
1012 with self.assertRaisesMessage(
1013 ValidationError, _("IBAN checksum generation does not support >26 character IBANs")
1014 ):
1015 iban_generator("AL")
1017 def test_make_email_recipient(self):
1018 email_tests = [
1019 {
1020 "list": [
1021 ("Jani Kajala", "kajala@example.com"),
1022 '"Jani Kajala" <kajala@example.com>',
1023 "<kajala@example.com>",
1024 "kajala@example.com",
1025 ],
1026 "result": [
1027 ("Jani Kajala", "kajala@example.com"),
1028 ("Jani Kajala", "kajala@example.com"),
1029 ("kajala@example.com", "kajala@example.com"),
1030 ("kajala@example.com", "kajala@example.com"),
1031 ],
1032 }
1033 ]
1034 for et in email_tests:
1035 res = make_email_recipient_list(et["list"])
1036 self.assertListEqual(res, et["result"])
1038 def test_choices(self):
1039 val = choices_label(MY_CHOICES, MY_CHOICE_1)
1040 self.assertEqual(val, "MY_CHOICE_1")
1042 def test_camel_case(self):
1043 pairs = [
1044 ("camelCaseWord", "camel_case_word"),
1045 ("camelCase", "camel_case"),
1046 ("camel", "camel"),
1047 ("camelCCase", "camel_c_case"),
1048 ]
1049 for cc, us in pairs:
1050 self.assertEqual(camel_case_to_underscore(cc), us)
1051 self.assertEqual(cc, underscore_to_camel_case(us))
1053 def create_dummy_request(self, path: str = "/admin/login/"):
1054 request = request_factory.get(path)
1055 request.user = self.user # type: ignore
1056 request.user.profile = DummyUserProfile() # type: ignore
1057 return request
1059 def test_model_admin_base(self):
1060 # test that actions sorting by name works
1061 request = self.create_dummy_request()
1062 user = self.user
1063 model_admin = MyCustomAdmin(LogEntry, admin.site)
1064 res = model_admin.get_actions(request)
1065 self.assertEqual(list(res.items())[0][0], "dummy_admin_func_a", "ModelAdminBase.get_actions sorting failed")
1066 self.assertEqual(list(res.items())[1][0], "dummy_admin_func_b", "ModelAdminBase.get_actions sorting failed")
1068 # create 10 LogEntry for test user, 5 with text "VisibleLogMessage" and 5 "InvisibleLogMessage"
1069 # then check that "VisibleLogMessage" log entries are not visible since max_history_length = 5
1070 LogEntry.objects.filter(object_id=user.id).delete()
1071 for n in range(5):
1072 admin_log([user], "InvisibleLogMessage")
1073 for n in range(5):
1074 admin_log([user], "VisibleLogMessage")
1075 self.assertEqual(LogEntry.objects.filter(object_id=user.id).count(), 10)
1076 history_url = "/admin/auth/user/{}/history/".format(user.id)
1077 c = self.client
1078 c.get(history_url, follow=True)
1079 c.post("/admin/login/", {"username": "test@example.com", "password": "test1234"})
1080 res = c.get(history_url)
1081 content = res.content.decode()
1082 assert isinstance(content, str)
1083 self.assertEqual(content.count("VisibleLogMessage"), 5)
1084 self.assertEqual(content.count("InvisibleLogMessage"), 0)
1086 def test_admin_log_entry_mixin(self):
1087 user = self.user
1088 AdminLogEntryMixin.fields_changed(user, ["username"], who=None)
1089 e = LogEntry.objects.filter(object_id=user.id).last()
1090 assert isinstance(e, LogEntry)
1091 self.assertEqual(e.change_message, 'username: "test@example.com"')
1093 def test_auth(self):
1094 req = self.create_dummy_request()
1095 get_auth_user(req) # type: ignore
1096 req.user = None
1097 self.assertIsNone(get_auth_user_or_none(req))
1098 try:
1099 get_auth_user(req) # type: ignore
1100 self.fail("get_auth_user fail")
1101 except NotAuthenticated:
1102 pass
1103 try:
1104 model_admin = AuthUserMixin()
1105 model_admin.request = req
1106 user = model_admin.auth_user
1107 self.fail("get_auth_user fail")
1108 except NotAuthenticated:
1109 pass
1111 def test_middleware(self):
1112 # EnsureOriginMiddleware
1113 request = self.create_dummy_request("/admin/login/")
1114 EnsureOriginMiddleware(dummy_middleware_get_response)(request)
1115 self.assertIn("HTTP_ORIGIN", request.META)
1116 self.assertEqual(request.META["HTTP_ORIGIN"], request.get_host())
1118 # LogExceptionMiddleware
1119 dummy_log = DummyLogHandler()
1120 jutil_middleware_logger.addHandler(dummy_log)
1121 try:
1122 raise Exception("Dummy exception, ignore this")
1123 except Exception as e:
1124 mw = LogExceptionMiddleware(dummy_middleware_get_response)
1125 mw.process_exception(request, e)
1126 msg = dummy_log.msgs.pop()
1127 self.assertIn("Exception: Dummy exception, ignore this", msg)
1128 self.assertIn("user=test@example.com", msg)
1129 jutil_middleware_logger.removeHandler(dummy_log)
1131 # EnsureLanguageCookieMiddleware
1132 lang_cookie_tests = [
1133 ("/admin/login/", settings.LANGUAGE_CODE),
1134 ("/admin/login/?django_language=fi", "fi"),
1135 ]
1136 for request_path, lang_code in lang_cookie_tests:
1137 request = self.create_dummy_request(request_path)
1138 mw = EnsureLanguageCookieMiddleware(dummy_middleware_get_response)
1139 res = mw(request)
1140 assert isinstance(res, HttpResponse)
1141 self.assertEqual(res.status_code, 200)
1142 self.assertIn("django_language", request.COOKIES)
1143 self.assertIn(request.COOKIES["django_language"], lang_code)
1144 self.assertIn("django_language", res.cookies)
1145 self.assertEqual(
1146 str(res.cookies["django_language"]), "Set-Cookie: django_language={}; Path=/".format(lang_code)
1147 )
1149 # ActivateUserProfileTimezoneMiddleware
1150 user = self.user
1151 self.assertTrue(user.is_authenticated)
1152 user.profile.timezone = "Europe/Helsinki"
1153 with timezone.override(pytz.timezone("America/Chicago")):
1154 request = self.create_dummy_request("/admin/login/")
1155 mw = ActivateUserProfileTimezoneMiddleware(dummy_time_zone_response)
1156 res = mw(request)
1157 content = res.content.decode()
1158 self.assertEqual(content, user.profile.timezone)
1160 def test_safe_fields(self):
1161 class TestModel(models.Model):
1162 cf = SafeCharField(max_length=256)
1163 tf = SafeTextField()
1165 obj = TestModel()
1166 data = 'hello world <script>alert("popup")<script>'
1167 data_ref = "hello world "
1168 for f in obj._meta.fields:
1169 if f.name in ["cf", "tf"]:
1170 f.save_form_data(obj, data)
1171 self.assertEqual(obj.cf, data_ref)
1172 self.assertEqual(obj.tf, data_ref)
1174 def test_responses(self):
1175 a = [
1176 ["date", "description", "count", "unit price", "total price"],
1177 [date(2019, 12, 15), "oranges", 1000, dec2("0.99"), dec2("990.00")],
1178 [date(2020, 1, 3), "apples", 4, dec2("1.10"), dec2("4.40")],
1179 [date(2020, 11, 3), "apples", 5, dec2("10.10"), dec2("50.50")],
1180 ]
1181 res = CsvResponse(a, "test.csv")
1182 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"
1183 self.assertEqual(content_ref, res.content)
1184 print(res.content.decode())
1186 def test_wait_object_or_none(self):
1187 admin_log([self.user], "Hello, world")
1188 e = LogEntry.objects.all().filter(object_id=self.user.id).last()
1189 assert isinstance(e, LogEntry)
1190 e_id = e.id
1191 obj = wait_object_or_none(LogEntry, id=e_id)
1192 self.assertIsNotNone(obj)
1193 self.assertEqual(obj.id, e_id)
1194 t0 = now()
1195 obj = wait_object_or_none(LogEntry, timeout=1.0, sleep_interval=0.1, id=e_id + 1)
1196 t1 = now()
1197 self.assertIsNone(obj)
1198 self.assertGreater(t1 - t0, timedelta(seconds=0.99))
1200 def test_format_as_html_json(self):
1201 pairs = [
1202 (None, "null"),
1203 ({"a": 1}, "{<br/> "a": 1<br/>}"),
1204 (
1205 {"script": "<script>window.alert()</script>"},
1206 "{<br/> "script": "<script>window.alert()</script>"<br/>}",
1207 ),
1208 ]
1209 for val, html in pairs:
1210 self.assertEqual(format_as_html_json(val), html)
1212 def test_parse_bool(self):
1213 refs_true = [
1214 True,
1215 "True",
1216 "1",
1217 1,
1218 "true",
1219 "yes",
1220 ]
1221 refs_false = [
1222 False,
1223 "False",
1224 "0",
1225 0,
1226 "false",
1227 "no",
1228 ]
1229 for ref in refs_true:
1230 self.assertTrue(parse_bool(ref))
1231 for ref in refs_false:
1232 self.assertFalse(parse_bool(ref))
1234 def test_exception_convert(self):
1235 e = transform_exception_to_drf(ValidationError({"hello": "world"}))
1236 assert isinstance(e, DRFValidationError)
1237 self.assertTrue(isinstance(e, DRFValidationError))
1238 self.assertIn("hello", e.detail) # type: ignore
1239 self.assertEqual(e.detail["hello"], [ErrorDetail(string="world", code="invalid")]) # type: ignore
1242dummy_admin_func_a.short_description = "A" # type: ignore
1243dummy_admin_func_b.short_description = "B" # type: ignore
1245admin.site.unregister(User)
1246admin.site.register(User, MyCustomAdmin)
1247admin.site.register(LogEntry, MyCustomAdmin)