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