2019-09-10 00:54:28 +00:00
|
|
|
# Created By: Virgil Dupras
|
|
|
|
# Created On: 2011-01-11
|
|
|
|
# Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
|
|
#
|
|
|
|
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
|
|
# which should be included with this package. The terms are also available at
|
|
|
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
|
|
|
|
|
|
|
from io import StringIO
|
|
|
|
|
|
|
|
from pytest import raises
|
|
|
|
|
|
|
|
from ..testutil import eq_
|
2022-03-28 04:50:03 +00:00
|
|
|
from pathlib import Path
|
2020-06-27 06:08:12 +00:00
|
|
|
from ..util import (
|
|
|
|
nonone,
|
|
|
|
tryint,
|
|
|
|
minmax,
|
|
|
|
first,
|
|
|
|
flatten,
|
|
|
|
dedupe,
|
|
|
|
stripfalse,
|
|
|
|
extract,
|
|
|
|
allsame,
|
|
|
|
trailiter,
|
|
|
|
format_time,
|
|
|
|
format_time_decimal,
|
|
|
|
format_size,
|
|
|
|
remove_invalid_xml,
|
|
|
|
multi_replace,
|
|
|
|
delete_if_empty,
|
|
|
|
open_if_filename,
|
|
|
|
FileOrPath,
|
|
|
|
iterconsume,
|
|
|
|
escape,
|
|
|
|
get_file_ext,
|
|
|
|
rem_file_ext,
|
|
|
|
pluralize,
|
|
|
|
)
|
2019-09-10 00:54:28 +00:00
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_nonone():
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("foo", nonone("foo", "bar"))
|
|
|
|
eq_("bar", nonone(None, "bar"))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_tryint():
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(42, tryint("42"))
|
|
|
|
eq_(0, tryint("abc"))
|
|
|
|
eq_(0, tryint(None))
|
|
|
|
eq_(42, tryint(None, 42))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_minmax():
|
|
|
|
eq_(minmax(2, 1, 3), 2)
|
|
|
|
eq_(minmax(0, 1, 3), 1)
|
|
|
|
eq_(minmax(4, 1, 3), 3)
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
|
|
|
# --- Sequence
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_first():
|
|
|
|
eq_(first([3, 2, 1]), 3)
|
|
|
|
eq_(first(i for i in [3, 2, 1] if i < 3), 2)
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_flatten():
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_([1, 2, 3, 4], flatten([[1, 2], [3, 4]]))
|
|
|
|
eq_([], flatten([]))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_dedupe():
|
2020-01-01 02:16:27 +00:00
|
|
|
reflist = [0, 7, 1, 2, 3, 4, 4, 5, 6, 7, 1, 2, 3]
|
|
|
|
eq_(dedupe(reflist), [0, 7, 1, 2, 3, 4, 5, 6])
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_stripfalse():
|
|
|
|
eq_([1, 2, 3], stripfalse([None, 0, 1, 2, 3, None]))
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_extract():
|
|
|
|
wheat, shaft = extract(lambda n: n % 2 == 0, list(range(10)))
|
|
|
|
eq_(wheat, [0, 2, 4, 6, 8])
|
|
|
|
eq_(shaft, [1, 3, 5, 7, 9])
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_allsame():
|
|
|
|
assert allsame([42, 42, 42])
|
|
|
|
assert not allsame([42, 43, 42])
|
|
|
|
assert not allsame([43, 42, 42])
|
|
|
|
# Works on non-sequence as well
|
|
|
|
assert allsame(iter([42, 42, 42]))
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_trailiter():
|
|
|
|
eq_(list(trailiter([])), [])
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(list(trailiter(["foo"])), [(None, "foo")])
|
|
|
|
eq_(list(trailiter(["foo", "bar"])), [(None, "foo"), ("foo", "bar")])
|
|
|
|
eq_(list(trailiter(["foo", "bar"], skipfirst=True)), [("foo", "bar")])
|
|
|
|
eq_(list(trailiter([], skipfirst=True)), []) # no crash
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_iterconsume():
|
|
|
|
# We just want to make sure that we return *all* items and that we're not mistakenly skipping
|
|
|
|
# one.
|
|
|
|
eq_(list(range(2500)), list(iterconsume(list(range(2500)))))
|
2021-08-15 09:10:18 +00:00
|
|
|
eq_(list(reversed(range(2500))), list(iterconsume(list(range(2500)), reverse=False)))
|
2020-01-01 02:16:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
# --- String
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_escape():
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("f\\o\\ob\\ar", escape("foobar", "oa"))
|
|
|
|
eq_("f*o*ob*ar", escape("foobar", "oa", "*"))
|
|
|
|
eq_("f*o*ob*ar", escape("foobar", set("oa"), "*"))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_get_file_ext():
|
|
|
|
eq_(get_file_ext("foobar"), "")
|
|
|
|
eq_(get_file_ext("foo.bar"), "bar")
|
|
|
|
eq_(get_file_ext("foobar."), "")
|
|
|
|
eq_(get_file_ext(".foobar"), "foobar")
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_rem_file_ext():
|
|
|
|
eq_(rem_file_ext("foobar"), "foobar")
|
|
|
|
eq_(rem_file_ext("foo.bar"), "foo")
|
|
|
|
eq_(rem_file_ext("foobar."), "foobar")
|
|
|
|
eq_(rem_file_ext(".foobar"), "")
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_pluralize():
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("0 song", pluralize(0, "song"))
|
|
|
|
eq_("1 song", pluralize(1, "song"))
|
|
|
|
eq_("2 songs", pluralize(2, "song"))
|
|
|
|
eq_("1 song", pluralize(1.1, "song"))
|
|
|
|
eq_("2 songs", pluralize(1.5, "song"))
|
|
|
|
eq_("1.1 songs", pluralize(1.1, "song", 1))
|
|
|
|
eq_("1.5 songs", pluralize(1.5, "song", 1))
|
|
|
|
eq_("2 entries", pluralize(2, "entry", plural_word="entries"))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_format_time():
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(format_time(0), "00:00:00")
|
|
|
|
eq_(format_time(1), "00:00:01")
|
|
|
|
eq_(format_time(23), "00:00:23")
|
|
|
|
eq_(format_time(60), "00:01:00")
|
|
|
|
eq_(format_time(101), "00:01:41")
|
|
|
|
eq_(format_time(683), "00:11:23")
|
|
|
|
eq_(format_time(3600), "01:00:00")
|
|
|
|
eq_(format_time(3754), "01:02:34")
|
|
|
|
eq_(format_time(36000), "10:00:00")
|
|
|
|
eq_(format_time(366666), "101:51:06")
|
|
|
|
eq_(format_time(0, with_hours=False), "00:00")
|
|
|
|
eq_(format_time(1, with_hours=False), "00:01")
|
|
|
|
eq_(format_time(23, with_hours=False), "00:23")
|
|
|
|
eq_(format_time(60, with_hours=False), "01:00")
|
|
|
|
eq_(format_time(101, with_hours=False), "01:41")
|
|
|
|
eq_(format_time(683, with_hours=False), "11:23")
|
|
|
|
eq_(format_time(3600, with_hours=False), "60:00")
|
|
|
|
eq_(format_time(6036, with_hours=False), "100:36")
|
|
|
|
eq_(format_time(60360, with_hours=False), "1006:00")
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_format_time_decimal():
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(format_time_decimal(0), "0.0 second")
|
|
|
|
eq_(format_time_decimal(1), "1.0 second")
|
|
|
|
eq_(format_time_decimal(23), "23.0 seconds")
|
|
|
|
eq_(format_time_decimal(60), "1.0 minute")
|
|
|
|
eq_(format_time_decimal(101), "1.7 minutes")
|
|
|
|
eq_(format_time_decimal(683), "11.4 minutes")
|
|
|
|
eq_(format_time_decimal(3600), "1.0 hour")
|
|
|
|
eq_(format_time_decimal(6036), "1.7 hours")
|
|
|
|
eq_(format_time_decimal(86400), "1.0 day")
|
|
|
|
eq_(format_time_decimal(160360), "1.9 days")
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_format_size():
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(format_size(1024), "1 KB")
|
|
|
|
eq_(format_size(1024, 2), "1.00 KB")
|
|
|
|
eq_(format_size(1024, 0, 2), "1 MB")
|
|
|
|
eq_(format_size(1024, 2, 2), "0.01 MB")
|
|
|
|
eq_(format_size(1024, 3, 2), "0.001 MB")
|
|
|
|
eq_(format_size(1024, 3, 2, False), "0.001")
|
|
|
|
eq_(format_size(1023), "1023 B")
|
|
|
|
eq_(format_size(1023, 0, 1), "1 KB")
|
|
|
|
eq_(format_size(511, 0, 1), "1 KB")
|
|
|
|
eq_(format_size(9), "9 B")
|
|
|
|
eq_(format_size(99), "99 B")
|
|
|
|
eq_(format_size(999), "999 B")
|
|
|
|
eq_(format_size(9999), "10 KB")
|
|
|
|
eq_(format_size(99999), "98 KB")
|
|
|
|
eq_(format_size(999999), "977 KB")
|
|
|
|
eq_(format_size(9999999), "10 MB")
|
|
|
|
eq_(format_size(99999999), "96 MB")
|
|
|
|
eq_(format_size(999999999), "954 MB")
|
|
|
|
eq_(format_size(9999999999), "10 GB")
|
|
|
|
eq_(format_size(99999999999), "94 GB")
|
|
|
|
eq_(format_size(999999999999), "932 GB")
|
|
|
|
eq_(format_size(9999999999999), "10 TB")
|
|
|
|
eq_(format_size(99999999999999), "91 TB")
|
|
|
|
eq_(format_size(999999999999999), "910 TB")
|
|
|
|
eq_(format_size(9999999999999999), "9 PB")
|
|
|
|
eq_(format_size(99999999999999999), "89 PB")
|
|
|
|
eq_(format_size(999999999999999999), "889 PB")
|
|
|
|
eq_(format_size(9999999999999999999), "9 EB")
|
|
|
|
eq_(format_size(99999999999999999999), "87 EB")
|
|
|
|
eq_(format_size(999999999999999999999), "868 EB")
|
|
|
|
eq_(format_size(9999999999999999999999), "9 ZB")
|
|
|
|
eq_(format_size(99999999999999999999999), "85 ZB")
|
|
|
|
eq_(format_size(999999999999999999999999), "848 ZB")
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_remove_invalid_xml():
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(remove_invalid_xml("foo\0bar\x0bbaz"), "foo bar baz")
|
2019-09-10 00:54:28 +00:00
|
|
|
# surrogate blocks have to be replaced, but not the rest
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(remove_invalid_xml("foo\ud800bar\udfffbaz\ue000"), "foo bar baz\ue000")
|
2019-09-10 00:54:28 +00:00
|
|
|
# replace with something else
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(remove_invalid_xml("foo\0baz", replace_with="bar"), "foobarbaz")
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_multi_replace():
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("136", multi_replace("123456", ("2", "45")))
|
|
|
|
eq_("1 3 6", multi_replace("123456", ("2", "45"), " "))
|
|
|
|
eq_("1 3 6", multi_replace("123456", "245", " "))
|
|
|
|
eq_("173896", multi_replace("123456", "245", "789"))
|
|
|
|
eq_("173896", multi_replace("123456", "245", ("7", "8", "9")))
|
|
|
|
eq_("17386", multi_replace("123456", ("2", "45"), "78"))
|
|
|
|
eq_("17386", multi_replace("123456", ("2", "45"), ("7", "8")))
|
2019-09-10 00:54:28 +00:00
|
|
|
with raises(ValueError):
|
2020-01-01 02:16:27 +00:00
|
|
|
multi_replace("123456", ("2", "45"), ("7", "8", "9"))
|
|
|
|
eq_("17346", multi_replace("12346", ("2", "45"), "78"))
|
|
|
|
|
|
|
|
|
|
|
|
# --- Files
|
2019-09-10 00:54:28 +00:00
|
|
|
|
2021-08-21 21:25:33 +00:00
|
|
|
|
|
|
|
class TestCaseDeleteIfEmpty:
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_is_empty(self, tmpdir):
|
|
|
|
testpath = Path(str(tmpdir))
|
|
|
|
assert delete_if_empty(testpath)
|
|
|
|
assert not testpath.exists()
|
|
|
|
|
|
|
|
def test_not_empty(self, tmpdir):
|
|
|
|
testpath = Path(str(tmpdir))
|
2022-03-28 04:50:03 +00:00
|
|
|
testpath.joinpath("foo").mkdir()
|
2019-09-10 00:54:28 +00:00
|
|
|
assert not delete_if_empty(testpath)
|
|
|
|
assert testpath.exists()
|
|
|
|
|
|
|
|
def test_with_files_to_delete(self, tmpdir):
|
|
|
|
testpath = Path(str(tmpdir))
|
2022-03-28 04:50:03 +00:00
|
|
|
testpath.joinpath("foo").touch()
|
|
|
|
testpath.joinpath("bar").touch()
|
2020-01-01 02:16:27 +00:00
|
|
|
assert delete_if_empty(testpath, ["foo", "bar"])
|
2019-09-10 00:54:28 +00:00
|
|
|
assert not testpath.exists()
|
|
|
|
|
|
|
|
def test_directory_in_files_to_delete(self, tmpdir):
|
|
|
|
testpath = Path(str(tmpdir))
|
2022-03-28 04:50:03 +00:00
|
|
|
testpath.joinpath("foo").mkdir()
|
2020-01-01 02:16:27 +00:00
|
|
|
assert not delete_if_empty(testpath, ["foo"])
|
2019-09-10 00:54:28 +00:00
|
|
|
assert testpath.exists()
|
|
|
|
|
|
|
|
def test_delete_files_to_delete_only_if_dir_is_empty(self, tmpdir):
|
|
|
|
testpath = Path(str(tmpdir))
|
2022-03-28 04:50:03 +00:00
|
|
|
testpath.joinpath("foo").touch()
|
|
|
|
testpath.joinpath("bar").touch()
|
2020-01-01 02:16:27 +00:00
|
|
|
assert not delete_if_empty(testpath, ["foo"])
|
2019-09-10 00:54:28 +00:00
|
|
|
assert testpath.exists()
|
2022-03-28 04:50:03 +00:00
|
|
|
assert testpath.joinpath("foo").exists()
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_doesnt_exist(self):
|
|
|
|
# When the 'path' doesn't exist, just do nothing.
|
2020-01-01 02:16:27 +00:00
|
|
|
delete_if_empty(Path("does_not_exist")) # no crash
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_is_file(self, tmpdir):
|
|
|
|
# When 'path' is a file, do nothing.
|
2022-03-28 04:50:03 +00:00
|
|
|
p = Path(str(tmpdir)).joinpath("filename")
|
|
|
|
p.touch()
|
2020-01-01 02:16:27 +00:00
|
|
|
delete_if_empty(p) # no crash
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_ioerror(self, tmpdir, monkeypatch):
|
|
|
|
# if an IO error happens during the operation, ignore it.
|
|
|
|
def do_raise(*args, **kw):
|
|
|
|
raise OSError()
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
monkeypatch.setattr(Path, "rmdir", do_raise)
|
|
|
|
delete_if_empty(Path(str(tmpdir))) # no crash
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
|
2021-08-21 21:25:33 +00:00
|
|
|
class TestCaseOpenIfFilename:
|
2021-08-25 05:46:33 +00:00
|
|
|
FILE_NAME = "test.txt"
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_file_name(self, tmpdir):
|
2021-08-25 05:46:33 +00:00
|
|
|
filepath = str(tmpdir.join(self.FILE_NAME))
|
2020-01-01 02:16:27 +00:00
|
|
|
open(filepath, "wb").write(b"test_data")
|
2019-09-10 00:54:28 +00:00
|
|
|
file, close = open_if_filename(filepath)
|
|
|
|
assert close
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(b"test_data", file.read())
|
2019-09-10 00:54:28 +00:00
|
|
|
file.close()
|
|
|
|
|
|
|
|
def test_opened_file(self):
|
|
|
|
sio = StringIO()
|
2020-01-01 02:16:27 +00:00
|
|
|
sio.write("test_data")
|
2019-09-10 00:54:28 +00:00
|
|
|
sio.seek(0)
|
|
|
|
file, close = open_if_filename(sio)
|
|
|
|
assert not close
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("test_data", file.read())
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_mode_is_passed_to_open(self, tmpdir):
|
2021-08-25 05:46:33 +00:00
|
|
|
filepath = str(tmpdir.join(self.FILE_NAME))
|
2020-01-01 02:16:27 +00:00
|
|
|
open(filepath, "w").close()
|
|
|
|
file, close = open_if_filename(filepath, "a")
|
|
|
|
eq_("a", file.mode)
|
2019-09-10 00:54:28 +00:00
|
|
|
file.close()
|
|
|
|
|
|
|
|
|
2021-08-21 21:25:33 +00:00
|
|
|
class TestCaseFileOrPath:
|
2021-08-25 05:46:33 +00:00
|
|
|
FILE_NAME = "test.txt"
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_path(self, tmpdir):
|
2021-08-25 05:46:33 +00:00
|
|
|
filepath = str(tmpdir.join(self.FILE_NAME))
|
2020-01-01 02:16:27 +00:00
|
|
|
open(filepath, "wb").write(b"test_data")
|
2019-09-10 00:54:28 +00:00
|
|
|
with FileOrPath(filepath) as fp:
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(b"test_data", fp.read())
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_opened_file(self):
|
|
|
|
sio = StringIO()
|
2020-01-01 02:16:27 +00:00
|
|
|
sio.write("test_data")
|
2019-09-10 00:54:28 +00:00
|
|
|
sio.seek(0)
|
|
|
|
with FileOrPath(sio) as fp:
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("test_data", fp.read())
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_mode_is_passed_to_open(self, tmpdir):
|
2021-08-25 05:46:33 +00:00
|
|
|
filepath = str(tmpdir.join(self.FILE_NAME))
|
2020-01-01 02:16:27 +00:00
|
|
|
open(filepath, "w").close()
|
|
|
|
with FileOrPath(filepath, "a") as fp:
|
|
|
|
eq_("a", fp.mode)
|