Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mikf
GitHub Repository: mikf/gallery-dl
Path: blob/master/test/test_util.py
5457 views
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
# Copyright 2015-2025 Mike Fährmann
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License version 2 as
8
# published by the Free Software Foundation.
9
10
import os
11
import sys
12
import unittest
13
from unittest.mock import patch
14
15
import io
16
import time
17
import random
18
import string
19
import datetime
20
import platform
21
import tempfile
22
import itertools
23
import http.cookiejar
24
25
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
26
from gallery_dl import util, text, exception # noqa E402
27
28
29
class TestRange(unittest.TestCase):
30
31
def setUp(self):
32
self.predicate = util.RangePredicate("")
33
34
def test_parse_empty(self):
35
f = self.predicate._parse
36
37
self.assertEqual(f(""), [])
38
self.assertEqual(f([]), [])
39
40
def test_parse_digit(self):
41
f = self.predicate._parse
42
43
self.assertEqual(f("2"), [range(2, 3)])
44
45
self.assertEqual(
46
f("2, 3, 4"),
47
[range(2, 3),
48
range(3, 4),
49
range(4, 5)],
50
)
51
52
def test_parse_range(self):
53
f = self.predicate._parse
54
55
self.assertEqual(f("1-2"), [range(1, 3)])
56
self.assertEqual(f("2-"), [range(2, sys.maxsize)])
57
self.assertEqual(f("-3"), [range(1, 4)])
58
self.assertEqual(f("-"), [range(1, sys.maxsize)])
59
60
self.assertEqual(
61
f("-2,4,6-8,10-"),
62
[range(1, 3),
63
range(4, 5),
64
range(6, 9),
65
range(10, sys.maxsize)],
66
)
67
self.assertEqual(
68
f(" - 3 , 4- 4, 2-6"),
69
[range(1, 4),
70
range(4, 5),
71
range(2, 7)],
72
)
73
74
def test_parse_slice(self):
75
f = self.predicate._parse
76
77
self.assertEqual(f("2:4") , [range(2, 4)])
78
self.assertEqual(f("3::") , [range(3, sys.maxsize)])
79
self.assertEqual(f(":4:") , [range(1, 4)])
80
self.assertEqual(f("::5") , [range(1, sys.maxsize, 5)])
81
self.assertEqual(f("::") , [range(1, sys.maxsize)])
82
self.assertEqual(f("2:3:4"), [range(2, 3, 4)])
83
84
self.assertEqual(
85
f("2:4, 4:, :4, :4:, ::4"),
86
[range(2, 4),
87
range(4, sys.maxsize),
88
range(1, 4),
89
range(1, 4),
90
range(1, sys.maxsize, 4)],
91
)
92
self.assertEqual(
93
f(" : 3 , 4: 4, 2:6"),
94
[range(1, 3),
95
range(4, 4),
96
range(2, 6)],
97
)
98
99
100
class TestPredicate(unittest.TestCase):
101
102
def test_range_predicate(self):
103
dummy = None
104
105
pred = util.RangePredicate(" - 3 , 4- 4, 2-6")
106
for i in range(6):
107
self.assertTrue(pred(dummy, dummy))
108
with self.assertRaises(exception.StopExtraction):
109
pred(dummy, dummy)
110
111
pred = util.RangePredicate("1, 3, 5")
112
self.assertTrue(pred(dummy, dummy))
113
self.assertFalse(pred(dummy, dummy))
114
self.assertTrue(pred(dummy, dummy))
115
self.assertFalse(pred(dummy, dummy))
116
self.assertTrue(pred(dummy, dummy))
117
with self.assertRaises(exception.StopExtraction):
118
pred(dummy, dummy)
119
120
pred = util.RangePredicate("")
121
with self.assertRaises(exception.StopExtraction):
122
pred(dummy, dummy)
123
124
def test_unique_predicate(self):
125
dummy = None
126
pred = util.UniquePredicate()
127
128
# no duplicates
129
self.assertTrue(pred("1", dummy))
130
self.assertTrue(pred("2", dummy))
131
self.assertFalse(pred("1", dummy))
132
self.assertFalse(pred("2", dummy))
133
self.assertTrue(pred("3", dummy))
134
self.assertFalse(pred("3", dummy))
135
136
# duplicates for "text:"
137
self.assertTrue(pred("text:123", dummy))
138
self.assertTrue(pred("text:123", dummy))
139
self.assertTrue(pred("text:123", dummy))
140
141
def test_filter_predicate(self):
142
url = ""
143
144
pred = util.FilterPredicate("a < 3")
145
self.assertTrue(pred(url, {"a": 2}))
146
self.assertFalse(pred(url, {"a": 3}))
147
148
with self.assertRaises(SyntaxError):
149
util.FilterPredicate("(")
150
151
self.assertFalse(
152
util.FilterPredicate("a > 1")(url, {"a": None}))
153
self.assertFalse(
154
util.FilterPredicate("b > 1")(url, {"a": 2}))
155
156
pred = util.FilterPredicate(["a < 3", "b < 4", "c < 5"])
157
self.assertTrue(pred(url, {"a": 2, "b": 3, "c": 4}))
158
self.assertFalse(pred(url, {"a": 3, "b": 3, "c": 4}))
159
self.assertFalse(pred(url, {"a": 2, "b": 4, "c": 4}))
160
self.assertFalse(pred(url, {"a": 2, "b": 3, "c": 5}))
161
162
self.assertFalse(pred(url, {"a": 2}))
163
164
pred = util.FilterPredicate("re.search(r'.+', url)")
165
self.assertTrue(pred(url, {"url": "https://example.org/"}))
166
self.assertFalse(pred(url, {"url": ""}))
167
168
def test_build_predicate(self):
169
pred = util.build_predicate([])
170
self.assertIsInstance(pred, type(lambda: True))
171
172
pred = util.build_predicate([util.UniquePredicate()])
173
self.assertIsInstance(pred, util.UniquePredicate)
174
175
pred = util.build_predicate([util.UniquePredicate(),
176
util.UniquePredicate()])
177
self.assertIs(pred.func, util.chain_predicates)
178
179
180
class TestISO639_1(unittest.TestCase):
181
182
def test_code_to_language(self):
183
d = "default"
184
self._run_test(util.code_to_language, {
185
("en",): "English",
186
("FR",): "French",
187
("ja",): "Japanese",
188
("xx",): None,
189
("" ,): None,
190
(None,): None,
191
("en", d): "English",
192
("FR", d): "French",
193
("xx", d): d,
194
("" , d): d,
195
(None, d): d,
196
})
197
198
def test_language_to_code(self):
199
d = "default"
200
self._run_test(util.language_to_code, {
201
("English",): "en",
202
("fRENch",): "fr",
203
("Japanese",): "ja",
204
("xx",): None,
205
("" ,): None,
206
(None,): None,
207
("English", d): "en",
208
("fRENch", d): "fr",
209
("xx", d): d,
210
("" , d): d,
211
(None, d): d,
212
})
213
214
def _run_test(self, func, tests):
215
for args, result in tests.items():
216
self.assertEqual(func(*args), result)
217
218
219
class TestCookiesTxt(unittest.TestCase):
220
221
def test_cookiestxt_load(self):
222
223
def _assert(content, expected):
224
cookies = util.cookiestxt_load(io.StringIO(content, None))
225
for c, e in zip(cookies, expected):
226
self.assertEqual(c.__dict__, e.__dict__)
227
228
_assert("", [])
229
_assert("\n\n\n", [])
230
_assert("$ Comment", [])
231
_assert("# Comment", [])
232
_assert(" # Comment \n\n $ Comment ", [])
233
_assert(
234
".example.org\tTRUE\t/\tTRUE\t0\tname\tvalue",
235
[self._cookie("name", "value", ".example.org")],
236
)
237
_assert(
238
".example.org\tTRUE\t/\tTRUE\t\tname\t",
239
[self._cookie("name", "", ".example.org")],
240
)
241
_assert(
242
"\tTRUE\t/\tTRUE\t\tname\t",
243
[self._cookie("name", "", "")],
244
)
245
_assert(
246
"# Netscape HTTP Cookie File\n"
247
"\n"
248
"# default\n"
249
".example.org TRUE / FALSE 0 n1 v1\n"
250
".example.org TRUE / TRUE 2145945600 n2 v2\n"
251
".example.org TRUE /path FALSE 0 n3\n"
252
"\n"
253
" # # extra # # \n"
254
"www.example.org FALSE / FALSE n4 \n"
255
"www.example.org FALSE /path FALSE 100 n5 v5\n",
256
[
257
self._cookie(
258
"n1", "v1", ".example.org", True, "/", False),
259
self._cookie(
260
"n2", "v2", ".example.org", True, "/", True, 2145945600),
261
self._cookie(
262
"n3", None, ".example.org", True, "/path", False),
263
self._cookie(
264
"n4", "" , "www.example.org", False, "/", False),
265
self._cookie(
266
"n5", "v5", "www.example.org", False, "/path", False, 100),
267
],
268
)
269
270
with self.assertRaises(ValueError):
271
util.cookiestxt_load("example.org\tTRUE\t/\tTRUE\t0\tname")
272
273
def test_cookiestxt_store(self):
274
275
def _assert(cookies, expected):
276
fp = io.StringIO(newline=None)
277
util.cookiestxt_store(fp, cookies)
278
self.assertMultiLineEqual(fp.getvalue(), expected)
279
280
_assert([], "# Netscape HTTP Cookie File\n\n")
281
_assert(
282
[self._cookie("name", "value", ".example.org")],
283
"# Netscape HTTP Cookie File\n\n"
284
".example.org\tTRUE\t/\tTRUE\t0\tname\tvalue\n",
285
)
286
_assert(
287
[
288
self._cookie(
289
"n1", "v1", ".example.org", True, "/", False),
290
self._cookie(
291
"n2", "v2", ".example.org", True, "/", True, 2145945600),
292
self._cookie(
293
"n3", None, ".example.org", True, "/path", False),
294
self._cookie(
295
"n4", "" , "www.example.org", False, "/", False),
296
self._cookie(
297
"n5", "v5", "www.example.org", False, "/path", False, 100),
298
self._cookie(
299
"n6", "v6", "", False),
300
],
301
"# Netscape HTTP Cookie File\n"
302
"\n"
303
".example.org TRUE / FALSE 0 n1 v1\n"
304
".example.org TRUE / TRUE 2145945600 n2 v2\n"
305
".example.org TRUE /path FALSE 0 n3\n"
306
"www.example.org FALSE / FALSE 0 n4 \n"
307
"www.example.org FALSE /path FALSE 100 n5 v5\n",
308
)
309
310
def _cookie(self, name, value, domain, domain_specified=True,
311
path="/", secure=True, expires=None):
312
return http.cookiejar.Cookie(
313
0, name, value, None, False,
314
domain, domain_specified, domain.startswith("."),
315
path, False, secure, expires, False, None, None, {},
316
)
317
318
319
class TestCompileExpression(unittest.TestCase):
320
321
def test_compile_expression(self):
322
expr = util.compile_expression("1 + 2 * 3")
323
self.assertEqual(expr(), 7)
324
self.assertEqual(expr({"a": 1, "b": 2, "c": 3}), 7)
325
self.assertEqual(expr({"a": 9, "b": 9, "c": 9}), 7)
326
327
expr = util.compile_expression("a + b * c")
328
self.assertEqual(expr({"a": 1, "b": 2, "c": 3}), 7)
329
self.assertEqual(expr({"a": 9, "b": 9, "c": 9}), 90)
330
331
with self.assertRaises(SyntaxError):
332
util.compile_expression("")
333
with self.assertRaises(SyntaxError):
334
util.compile_expression("x++")
335
336
expr = util.compile_expression("1 and abort()")
337
with self.assertRaises(exception.StopExtraction):
338
expr()
339
340
def test_compile_expression_raw(self):
341
expr = util.compile_expression_raw("a + b * c")
342
with self.assertRaises(NameError):
343
expr()
344
with self.assertRaises(NameError):
345
expr({"a": 2})
346
347
expr = util.compile_expression_raw("int.param")
348
with self.assertRaises(AttributeError):
349
expr({"a": 2})
350
351
def test_compile_expression_tryexcept(self):
352
expr = util.compile_expression_tryexcept("a + b * c")
353
self.assertIs(expr(), util.NONE)
354
self.assertIs(expr({"a": 2}), util.NONE)
355
356
expr = util.compile_expression_tryexcept("int.param")
357
self.assertIs(expr({"a": 2}), util.NONE)
358
359
def test_compile_expression_defaultdict(self):
360
expr = util.compile_expression_defaultdict("a + b * c")
361
self.assertIs(expr(), util.NONE)
362
self.assertIs(expr({"a": 2}), util.NONE)
363
364
expr = util.compile_expression_defaultdict("int.param")
365
with self.assertRaises(AttributeError):
366
expr({"a": 2})
367
368
def test_compile_filter(self):
369
expr = util.compile_filter("a + b * c")
370
self.assertEqual(expr({"a": 1, "b": 2, "c": 3}), 7)
371
self.assertEqual(expr({"a": 9, "b": 9, "c": 9}), 90)
372
373
expr = util.compile_filter(["a % 2 == 0", "b % 3 == 0", "c % 5 == 0"])
374
self.assertTrue(expr({"a": 4, "b": 6, "c": 10}))
375
self.assertFalse(expr({"a": 1, "b": 2, "c": 3}))
376
377
def test_custom_globals(self):
378
value = {"v": "foobar"}
379
result = "8843d7f92416211de9ebb963ff4ce28125932878"
380
381
expr = util.compile_expression("hash_sha1(v)")
382
self.assertEqual(expr(value), result)
383
384
expr = util.compile_expression("hs(v)", globals={"hs": util.sha1})
385
self.assertEqual(expr(value), result)
386
387
with tempfile.TemporaryDirectory() as path:
388
file = f"{path}/module_sha1.py"
389
with open(file, "w") as fp:
390
fp.write("""
391
import hashlib
392
def hash(value):
393
return hashlib.sha1(value.encode()).hexdigest()
394
""")
395
module = util.import_file(file)
396
397
expr = util.compile_expression("hash(v)", globals=module.__dict__)
398
self.assertEqual(expr(value), result)
399
400
GLOBALS_ORIG = util.GLOBALS
401
try:
402
util.GLOBALS = module.__dict__
403
expr = util.compile_expression("hash(v)")
404
finally:
405
util.GLOBALS = GLOBALS_ORIG
406
self.assertEqual(expr(value), result)
407
408
409
class TestDatetime(unittest.TestCase):
410
411
def test_to_datetime(self, f=util.to_datetime):
412
413
def _assert(value, expected):
414
result = f(value)
415
self.assertIsInstance(result, datetime.datetime)
416
self.assertEqual(result, expected, msg=repr(value))
417
418
dt = datetime.datetime(2010, 1, 1)
419
self.assertIs(f(dt), dt)
420
421
_assert(dt , dt)
422
_assert(1262304000 , dt)
423
_assert(1262304000.0 , dt)
424
_assert(1262304000.123, dt)
425
_assert("1262304000" , dt)
426
427
_assert("2010-01-01" , dt)
428
_assert("2010-01-01 00:00:00" , dt)
429
_assert("2010-01-01T00:00:00" , dt)
430
_assert("2010-01-01T00:00:00.123456" , dt)
431
_assert("2009-12-31T19:00:00-05:00" , dt)
432
_assert("2009-12-31T19:00:00.123456-05:00", dt)
433
_assert("2010-01-01T00:00:00Z" , dt)
434
_assert("2010-01-01T00:00:00.123456Z" , dt)
435
436
_assert(0 , util.EPOCH)
437
_assert("" , util.EPOCH)
438
_assert("foo", util.EPOCH)
439
_assert(None , util.EPOCH)
440
_assert(() , util.EPOCH)
441
_assert([] , util.EPOCH)
442
_assert({} , util.EPOCH)
443
_assert((1, 2, 3), util.EPOCH)
444
445
@unittest.skipIf(sys.hexversion < 0x30b0000,
446
"extended fromisoformat timezones")
447
def test_to_datetime_tz(self, f=util.to_datetime):
448
449
def _assert(value, expected):
450
result = f(value)
451
self.assertIsInstance(result, datetime.datetime)
452
self.assertEqual(result, expected, msg=repr(value))
453
454
dt = datetime.datetime(2010, 1, 1)
455
456
_assert("2009-12-31T19:00:00-05" , dt)
457
_assert("2009-12-31T19:00:00-0500" , dt)
458
_assert("2009-12-31T19:00:00.123456-05" , dt)
459
_assert("2009-12-31T19:00:00.123456-0500" , dt)
460
461
def test_datetime_to_timestamp(self, f=util.datetime_to_timestamp):
462
self.assertEqual(f(util.EPOCH), 0.0)
463
self.assertEqual(f(datetime.datetime(2010, 1, 1)), 1262304000.0)
464
self.assertEqual(f(datetime.datetime(2010, 1, 1, 0, 0, 0, 128000)),
465
1262304000.128000)
466
with self.assertRaises(TypeError):
467
f(None)
468
469
def test_datetime_to_timestamp_string(
470
self, f=util.datetime_to_timestamp_string):
471
self.assertEqual(f(util.EPOCH), "0")
472
self.assertEqual(f(datetime.datetime(2010, 1, 1)), "1262304000")
473
self.assertEqual(f(None), "")
474
475
def test_datetime_from_timestamp(
476
self, f=util.datetime_from_timestamp):
477
self.assertEqual(f(0.0), util.EPOCH)
478
self.assertEqual(f(1262304000.0), datetime.datetime(2010, 1, 1))
479
self.assertEqual(f(1262304000.128000).replace(microsecond=0),
480
datetime.datetime(2010, 1, 1, 0, 0, 0))
481
482
def test_datetime_utcfromtimestamp(
483
self, f=util.datetime_utcfromtimestamp):
484
self.assertEqual(f(0.0), util.EPOCH)
485
self.assertEqual(f(1262304000.0), datetime.datetime(2010, 1, 1))
486
487
def test_datetime_utcnow(
488
self, f=util.datetime_utcnow):
489
self.assertIsInstance(f(), datetime.datetime)
490
491
492
class TestOther(unittest.TestCase):
493
494
def test_bencode(self):
495
self.assertEqual(util.bencode(0), "")
496
self.assertEqual(util.bencode(123), "123")
497
self.assertEqual(util.bencode(123, "01"), "1111011")
498
self.assertEqual(util.bencode(123, "BA"), "AAAABAA")
499
500
def test_bdecode(self):
501
self.assertEqual(util.bdecode(""), 0)
502
self.assertEqual(util.bdecode("123"), 123)
503
self.assertEqual(util.bdecode("1111011", "01"), 123)
504
self.assertEqual(util.bdecode("AAAABAA", "BA"), 123)
505
506
def test_bencode_bdecode(self):
507
for _ in range(100):
508
value = random.randint(0, 1000000)
509
for alphabet in ("01", "0123456789", string.ascii_letters):
510
result = util.bdecode(util.bencode(value, alphabet), alphabet)
511
self.assertEqual(result, value)
512
513
def test_advance(self):
514
items = range(5)
515
516
self.assertCountEqual(
517
util.advance(items, 0), items)
518
self.assertCountEqual(
519
util.advance(items, 3), range(3, 5))
520
self.assertCountEqual(
521
util.advance(items, 9), [])
522
self.assertCountEqual(
523
util.advance(util.advance(items, 1), 2), range(3, 5))
524
525
def test_unique(self):
526
self.assertSequenceEqual(
527
list(util.unique("")), "")
528
self.assertSequenceEqual(
529
list(util.unique("AABBCC")), "ABC")
530
self.assertSequenceEqual(
531
list(util.unique("ABABABCAABBCC")), "ABC")
532
self.assertSequenceEqual(
533
list(util.unique([1, 2, 1, 3, 2, 1])), [1, 2, 3])
534
535
def test_unique_sequence(self):
536
self.assertSequenceEqual(
537
list(util.unique_sequence("")), "")
538
self.assertSequenceEqual(
539
list(util.unique_sequence("AABBCC")), "ABC")
540
self.assertSequenceEqual(
541
list(util.unique_sequence("ABABABCAABBCC")), "ABABABCABC")
542
self.assertSequenceEqual(
543
list(util.unique_sequence([1, 2, 1, 3, 2, 1])), [1, 2, 1, 3, 2, 1])
544
545
def test_contains(self):
546
c = [1, "2", 3, 4, "5", "foo"]
547
self.assertTrue(util.contains(c, 1))
548
self.assertTrue(util.contains(c, "foo"))
549
self.assertTrue(util.contains(c, [1, 3, "5"]))
550
self.assertTrue(util.contains(c, ["a", "b", "5"]))
551
self.assertFalse(util.contains(c, "bar"))
552
self.assertFalse(util.contains(c, [2, 5, "bar"]))
553
554
s = "1 2 3 asd qwe y(+)c f(+)(-) bar"
555
self.assertTrue(util.contains(s, "y(+)c"))
556
self.assertTrue(util.contains(s, ["asd", "qwe", "yxc"]))
557
self.assertTrue(util.contains(s, ["sdf", "dfg", "qwe"]))
558
self.assertFalse(util.contains(s, "tag1"))
559
self.assertFalse(util.contains(s, ["tag1", "tag2", "tag3"]))
560
561
self.assertTrue(util.contains(s, "(+)", ""))
562
self.assertTrue(util.contains(s, ["(-)", "(+)"], ""))
563
self.assertTrue(util.contains(s, "(+)", 0))
564
self.assertTrue(util.contains(s, "(+)", False))
565
566
self.assertFalse(util.contains(s, "(+)", None))
567
self.assertTrue(util.contains(s, "y(+)c", None))
568
self.assertTrue(util.contains(s, ["(-)", "(+)", "bar"], None))
569
570
s = "1, 2, 3, asd, qwe, y(+)c, f(+)(-), bar"
571
self.assertTrue(util.contains(s, "y(+)c", ", "))
572
self.assertTrue(util.contains(s, ["sdf", "dfg", "qwe"], ", "))
573
self.assertFalse(util.contains(s, "tag1", ", "))
574
575
def test_raises(self):
576
func = util.raises(Exception)
577
with self.assertRaises(Exception):
578
func()
579
580
func = util.raises(ValueError)
581
with self.assertRaises(ValueError):
582
func(1)
583
with self.assertRaises(ValueError):
584
func(2)
585
with self.assertRaises(ValueError):
586
func(3)
587
588
def test_identity(self):
589
for value in (123, "foo", [1, 2, 3], (1, 2, 3), {1: 2}, None):
590
self.assertIs(util.identity(value), value)
591
592
def test_noop(self):
593
self.assertEqual(util.noop(), None)
594
self.assertEqual(util.noop(...), None)
595
596
def test_md5(self):
597
self.assertEqual(util.md5(b""),
598
"d41d8cd98f00b204e9800998ecf8427e")
599
self.assertEqual(util.md5(b"hello"),
600
"5d41402abc4b2a76b9719d911017c592")
601
602
self.assertEqual(util.md5(""),
603
"d41d8cd98f00b204e9800998ecf8427e")
604
self.assertEqual(util.md5("hello"),
605
"5d41402abc4b2a76b9719d911017c592")
606
self.assertEqual(util.md5("ワルド"),
607
"051f29cd6c942cf110a0ccc5729871d2")
608
609
self.assertEqual(util.md5(0),
610
"d41d8cd98f00b204e9800998ecf8427e")
611
self.assertEqual(util.md5(()),
612
"d41d8cd98f00b204e9800998ecf8427e")
613
self.assertEqual(util.md5(None),
614
"d41d8cd98f00b204e9800998ecf8427e")
615
616
def test_sha1(self):
617
self.assertEqual(util.sha1(b""),
618
"da39a3ee5e6b4b0d3255bfef95601890afd80709")
619
self.assertEqual(util.sha1(b"hello"),
620
"aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d")
621
622
self.assertEqual(util.sha1(""),
623
"da39a3ee5e6b4b0d3255bfef95601890afd80709")
624
self.assertEqual(util.sha1("hello"),
625
"aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d")
626
self.assertEqual(util.sha1("ワルド"),
627
"0cbe319081aa0e9298448ec2bb16df8c494aa04e")
628
629
self.assertEqual(util.sha1(0),
630
"da39a3ee5e6b4b0d3255bfef95601890afd80709")
631
self.assertEqual(util.sha1(()),
632
"da39a3ee5e6b4b0d3255bfef95601890afd80709")
633
self.assertEqual(util.sha1(None),
634
"da39a3ee5e6b4b0d3255bfef95601890afd80709")
635
636
def test_import_file(self):
637
module = util.import_file("datetime")
638
self.assertIs(module, datetime)
639
640
with tempfile.TemporaryDirectory() as path:
641
file = f"{path}/module_test.py"
642
with open(file, "w") as fp:
643
fp.write("""
644
import datetime
645
key = "foobar"
646
value = 123
647
""")
648
module = util.import_file(file)
649
650
self.assertEqual(module.__name__, "module_test")
651
self.assertEqual(module.key, "foobar")
652
self.assertEqual(module.value, 123)
653
self.assertIs(module.datetime, datetime)
654
655
def test_build_selection_func(self, f=util.build_selection_func):
656
657
def test_single(df, v, type=None):
658
for _ in range(10):
659
self.assertEqual(df(), v)
660
if type is not None:
661
self.assertIsInstance(df(), type)
662
663
def test_range(df, lower, upper, type=None):
664
for __ in range(10):
665
v = df()
666
self.assertGreaterEqual(v, lower)
667
self.assertLessEqual(v, upper)
668
if type is not None:
669
self.assertIsInstance(v, type)
670
671
for v in (0, 0.0, "", None, (), []):
672
self.assertIsNone(f(v))
673
674
for v in (0, 0.0, "", None, (), []):
675
test_single(f(v, 1.0), 1.0)
676
677
test_single(f(3) , 3 , float)
678
test_single(f(3.0) , 3.0, float)
679
test_single(f("3") , 3 , float)
680
test_single(f("3.0-") , 3 , float)
681
test_single(f(" 3 -"), 3 , float)
682
683
test_range(f((2, 4)) , 2, 4, float)
684
test_range(f([2.0, 4.0]) , 2, 4, float)
685
test_range(f("2-4") , 2, 4, float)
686
test_range(f(" 2.0 - 4 "), 2, 4, float)
687
688
pb = text.parse_bytes
689
test_single(f("3", 0, pb) , 3, int)
690
test_single(f("3.0-", 0, pb) , 3, int)
691
test_single(f(" 3 -", 0, pb), 3, int)
692
693
test_range(f("2k-4k", 0, pb) , 2048, 4096, int)
694
test_range(f(" 2.0k - 4k ", 0, pb), 2048, 4096, int)
695
696
def test_extractor_filter(self):
697
# empty
698
func = util.build_extractor_filter("")
699
self.assertEqual(func(TestExtractor) , True)
700
self.assertEqual(func(TestExtractorParent), True)
701
self.assertEqual(func(TestExtractorAlt) , True)
702
703
# category
704
func = util.build_extractor_filter("test_category")
705
self.assertEqual(func(TestExtractor) , False)
706
self.assertEqual(func(TestExtractorParent), False)
707
self.assertEqual(func(TestExtractorAlt) , True)
708
709
# subcategory
710
func = util.build_extractor_filter("*:test_subcategory")
711
self.assertEqual(func(TestExtractor) , False)
712
self.assertEqual(func(TestExtractorParent), True)
713
self.assertEqual(func(TestExtractorAlt) , False)
714
715
# basecategory
716
func = util.build_extractor_filter("test_basecategory")
717
self.assertEqual(func(TestExtractor) , False)
718
self.assertEqual(func(TestExtractorParent), False)
719
self.assertEqual(func(TestExtractorAlt) , False)
720
721
# category-subcategory pair
722
func = util.build_extractor_filter("test_category:test_subcategory")
723
self.assertEqual(func(TestExtractor) , False)
724
self.assertEqual(func(TestExtractorParent), True)
725
self.assertEqual(func(TestExtractorAlt) , True)
726
727
# combination
728
func = util.build_extractor_filter(
729
["test_category", "*:test_subcategory"])
730
self.assertEqual(func(TestExtractor) , False)
731
self.assertEqual(func(TestExtractorParent), False)
732
self.assertEqual(func(TestExtractorAlt) , False)
733
734
# whitelist
735
func = util.build_extractor_filter(
736
"test_category:test_subcategory", negate=False)
737
self.assertEqual(func(TestExtractor) , True)
738
self.assertEqual(func(TestExtractorParent), False)
739
self.assertEqual(func(TestExtractorAlt) , False)
740
741
func = util.build_extractor_filter(
742
["test_category:test_subcategory", "*:test_subcategory_parent"],
743
negate=False)
744
self.assertEqual(func(TestExtractor) , True)
745
self.assertEqual(func(TestExtractorParent), True)
746
self.assertEqual(func(TestExtractorAlt) , False)
747
748
def test_generate_token(self):
749
tokens = set()
750
for _ in range(100):
751
token = util.generate_token()
752
tokens.add(token)
753
self.assertEqual(len(token), 16 * 2)
754
self.assertRegex(token, r"^[0-9a-f]+$")
755
self.assertGreaterEqual(len(tokens), 99)
756
757
token = util.generate_token(80)
758
self.assertEqual(len(token), 80 * 2)
759
self.assertRegex(token, r"^[0-9a-f]+$")
760
761
def test_format_value(self):
762
self.assertEqual(util.format_value(0) , "0")
763
self.assertEqual(util.format_value(1) , "1")
764
self.assertEqual(util.format_value(12) , "12")
765
self.assertEqual(util.format_value(123) , "123")
766
self.assertEqual(util.format_value(1234) , "1.23k")
767
self.assertEqual(util.format_value(12345) , "12.34k")
768
self.assertEqual(util.format_value(123456) , "123.45k")
769
self.assertEqual(util.format_value(1234567) , "1.23M")
770
self.assertEqual(util.format_value(12345678) , "12.34M")
771
self.assertEqual(util.format_value(123456789) , "123.45M")
772
self.assertEqual(util.format_value(1234567890), "1.23G")
773
774
def test_combine_dict(self):
775
self.assertEqual(
776
util.combine_dict({}, {}),
777
{})
778
self.assertEqual(
779
util.combine_dict({1: 1, 2: 2}, {2: 4, 4: 8}),
780
{1: 1, 2: 4, 4: 8})
781
self.assertEqual(
782
util.combine_dict(
783
{1: {11: 22, 12: 24}, 2: {13: 26, 14: 28}},
784
{1: {11: 33, 13: 39}, 2: "str"}),
785
{1: {11: 33, 12: 24, 13: 39}, 2: "str"})
786
self.assertEqual(
787
util.combine_dict(
788
{1: {2: {3: {4: {"1": "a", "2": "b"}}}}},
789
{1: {2: {3: {4: {"1": "A", "3": "C"}}}}}),
790
{1: {2: {3: {4: {"1": "A", "2": "b", "3": "C"}}}}})
791
792
def test_transform_dict(self):
793
d = {}
794
util.transform_dict(d, str)
795
self.assertEqual(d, {})
796
797
d = {1: 123, 2: "123", 3: True, 4: None}
798
util.transform_dict(d, str)
799
self.assertEqual(
800
d, {1: "123", 2: "123", 3: "True", 4: "None"})
801
802
d = {1: 123, 2: "123", 3: "foo", 4: {11: 321, 12: "321", 13: "bar"}}
803
util.transform_dict(d, text.parse_int)
804
self.assertEqual(
805
d, {1: 123, 2: 123, 3: 0, 4: {11: 321, 12: 321, 13: 0}})
806
807
def test_filter_dict(self):
808
d = {}
809
r = util.filter_dict(d)
810
self.assertEqual(r, d)
811
self.assertIsNot(r, d)
812
813
d = {"foo": 123, "bar": [], "baz": None}
814
r = util.filter_dict(d)
815
self.assertEqual(r, d)
816
self.assertIsNot(r, d)
817
818
d = {"foo": 123, "_bar": [], "__baz__": None}
819
r = util.filter_dict(d)
820
self.assertEqual(r, {"foo": 123})
821
822
def test_enumerate_reversed(self):
823
824
seq = [11, 22, 33]
825
result = [(3, 33), (2, 22), (1, 11)]
826
827
def gen():
828
for i in seq:
829
yield i
830
831
def gen_2():
832
yield from seq
833
834
def assertEqual(it1, it2):
835
ae = self.assertEqual
836
for i1, i2 in itertools.zip_longest(it1, it2):
837
ae(i1, i2)
838
839
assertEqual(
840
util.enumerate_reversed(seq), [(2, 33), (1, 22), (0, 11)])
841
assertEqual(
842
util.enumerate_reversed(seq, 1), result)
843
assertEqual(
844
util.enumerate_reversed(seq, 2), [(4, 33), (3, 22), (2, 11)])
845
846
assertEqual(
847
util.enumerate_reversed(gen(), 0, len(seq)),
848
[(2, 33), (1, 22), (0, 11)])
849
assertEqual(
850
util.enumerate_reversed(gen(), 1, len(seq)), result)
851
assertEqual(
852
util.enumerate_reversed(gen_2(), 1, len(seq)), result)
853
assertEqual(
854
util.enumerate_reversed(gen_2(), 2, len(seq)),
855
[(4, 33), (3, 22), (2, 11)])
856
857
def test_number_to_string(self, f=util.number_to_string):
858
self.assertEqual(f(1) , "1")
859
self.assertEqual(f(1.0) , "1.0")
860
self.assertEqual(f("1.0") , "1.0")
861
self.assertEqual(f([1]) , [1])
862
self.assertEqual(f({1: 2}), {1: 2})
863
self.assertEqual(f(True) , True)
864
self.assertEqual(f(None) , None)
865
866
def test_to_string(self, f=util.to_string):
867
self.assertEqual(f(1) , "1")
868
self.assertEqual(f(1.0) , "1.0")
869
self.assertEqual(f("1.0"), "1.0")
870
871
self.assertEqual(f("") , "")
872
self.assertEqual(f(None) , "")
873
self.assertEqual(f(0) , "")
874
875
self.assertEqual(f(["a"]), "a")
876
self.assertEqual(f([1]) , "1")
877
self.assertEqual(f(["a", "b", "c"]), "a, b, c")
878
self.assertEqual(f([1, 2, 3]), "1, 2, 3")
879
880
def test_universal_none(self):
881
obj = util.NONE
882
883
self.assertFalse(obj)
884
self.assertEqual(obj, obj)
885
self.assertEqual(obj, None)
886
self.assertNotEqual(obj, False)
887
self.assertNotEqual(obj, 0)
888
self.assertNotEqual(obj, "")
889
890
self.assertEqual(len(obj), 0)
891
self.assertEqual(int(obj), 0)
892
self.assertEqual(hash(obj), 0)
893
894
self.assertEqual(str(obj), str(None))
895
self.assertEqual(repr(obj), repr(None))
896
self.assertEqual(format(obj), str(None))
897
self.assertEqual(format(obj, "%F"), str(None))
898
899
self.assertIs(obj.attr, obj)
900
self.assertIs(obj["key"], obj)
901
self.assertIs(obj(), obj)
902
self.assertIs(obj(1, "a"), obj)
903
self.assertIs(obj(foo="bar"), obj)
904
self.assertIs(iter(obj), obj)
905
self.assertEqual(util.json_dumps(obj), "null")
906
907
self.assertLess(obj, "foo")
908
self.assertLessEqual(obj, None)
909
self.assertTrue(obj == obj)
910
self.assertFalse(obj == 0)
911
self.assertFalse(obj != obj)
912
self.assertGreater(123, obj)
913
self.assertGreaterEqual(1.23, obj)
914
915
self.assertEqual(obj + 123, obj)
916
self.assertEqual(obj - 123, obj)
917
self.assertEqual(obj * 123, obj)
918
# self.assertEqual(obj @ 123, obj)
919
self.assertEqual(obj / 123, obj)
920
self.assertEqual(obj // 123, obj)
921
self.assertEqual(obj % 123, obj)
922
923
self.assertEqual(123 + obj, obj)
924
self.assertEqual(123 - obj, obj)
925
self.assertEqual(123 * obj, obj)
926
# self.assertEqual(123 @ obj, obj)
927
self.assertEqual(123 / obj, obj)
928
self.assertEqual(123 // obj, obj)
929
self.assertEqual(123 % obj, obj)
930
931
self.assertEqual(obj << 123, obj)
932
self.assertEqual(obj >> 123, obj)
933
self.assertEqual(obj & 123, obj)
934
self.assertEqual(obj ^ 123, obj)
935
self.assertEqual(obj | 123, obj)
936
937
self.assertEqual(123 << obj, obj)
938
self.assertEqual(123 >> obj, obj)
939
self.assertEqual(123 & obj, obj)
940
self.assertEqual(123 ^ obj, obj)
941
self.assertEqual(123 | obj, obj)
942
943
self.assertEqual(-obj, obj)
944
self.assertEqual(+obj, obj)
945
self.assertEqual(~obj, obj)
946
self.assertEqual(abs(obj), obj)
947
948
mapping = {}
949
mapping[obj] = 123
950
self.assertIn(obj, mapping)
951
self.assertEqual(mapping[obj], 123)
952
953
array = [1, 2, 3]
954
self.assertEqual(array[obj], 1)
955
956
if platform.python_implementation().lower() == "cpython":
957
self.assertTrue(time.localtime(obj))
958
959
i = 0
960
for _ in obj:
961
i += 1
962
self.assertEqual(i, 0)
963
964
def test_HTTPBasicAuth(self, f=util.HTTPBasicAuth):
965
class Request:
966
headers = {}
967
request = Request()
968
969
auth = f("", "")
970
auth(request)
971
self.assertEqual(request.headers["Authorization"],
972
b"Basic Og==")
973
974
f("foo", "bar")(request)
975
self.assertEqual(request.headers["Authorization"],
976
b"Basic Zm9vOmJhcg==")
977
978
f("ewsxcvbhnjtr",
979
"RVXQ4i9Ju5ypi86VGJ8MqhDYpDKluS0sxiSRBAG7ymB3Imok")(request)
980
self.assertEqual(request.headers["Authorization"],
981
b"Basic ZXdzeGN2YmhuanRyOlJWWFE0aTlKdTV5cGk4NlZHSjhNc"
982
b"WhEWXBES2x1UzBzeGlTUkJBRzd5bUIzSW1vaw==")
983
984
def test_module_proxy(self):
985
proxy = util.ModuleProxy()
986
987
self.assertIs(proxy.os, os)
988
self.assertIs(proxy.os.path, os.path)
989
self.assertIs(proxy["os"], os)
990
self.assertIs(proxy["os.path"], os.path)
991
self.assertIs(proxy["os"].path, os.path)
992
993
self.assertIs(proxy.abcdefghi, util.NONE)
994
self.assertIs(proxy["abcdefghi"], util.NONE)
995
self.assertIs(proxy["abc.def.ghi"], util.NONE)
996
self.assertIs(proxy["os.path2"], util.NONE)
997
998
def test_lazy_prompt(self):
999
prompt = util.LazyPrompt()
1000
1001
with patch("getpass.getpass") as p:
1002
p.return_value = "***"
1003
result = str(prompt)
1004
1005
self.assertEqual(result, "***")
1006
p.assert_called_once_with()
1007
1008
def test_null_context(self):
1009
with util.NullContext():
1010
pass
1011
1012
with util.NullContext() as ctx:
1013
self.assertIs(ctx, None)
1014
1015
try:
1016
with util.NullContext() as ctx:
1017
exc_orig = ValueError()
1018
raise exc_orig
1019
except ValueError as exc:
1020
self.assertIs(exc, exc_orig)
1021
1022
def test_null_response(self):
1023
response = util.NullResponse("https://example.org")
1024
1025
self.assertEqual(response.url, "https://example.org")
1026
self.assertEqual(response.status_code, 900)
1027
self.assertEqual(response.reason, "")
1028
self.assertEqual(response.text, "")
1029
self.assertEqual(response.content, b"")
1030
self.assertEqual(response.json(), {})
1031
1032
self.assertFalse(response.ok)
1033
self.assertFalse(response.is_redirect)
1034
self.assertFalse(response.is_permanent_redirect)
1035
self.assertFalse(response.history)
1036
1037
self.assertEqual(response.encoding, "utf-8")
1038
self.assertEqual(response.apparent_encoding, "utf-8")
1039
self.assertEqual(response.cookies.get("foo"), None)
1040
self.assertEqual(response.headers.get("foo"), None)
1041
self.assertEqual(response.links.get("next"), None)
1042
self.assertEqual(response.close(), None)
1043
1044
1045
class TestExtractor():
1046
category = "test_category"
1047
subcategory = "test_subcategory"
1048
basecategory = "test_basecategory"
1049
1050
1051
class TestExtractorParent(TestExtractor):
1052
category = "test_category"
1053
subcategory = "test_subcategory_parent"
1054
1055
1056
class TestExtractorAlt(TestExtractor):
1057
category = "test_category_alt"
1058
subcategory = "test_subcategory"
1059
1060
1061
if __name__ == "__main__":
1062
unittest.main()
1063
1064