diff options
Diffstat (limited to 'cli/tests/test_cli_common.py')
-rw-r--r-- | cli/tests/test_cli_common.py | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/cli/tests/test_cli_common.py b/cli/tests/test_cli_common.py new file mode 100644 index 00000000..e95ba03e --- /dev/null +++ b/cli/tests/test_cli_common.py @@ -0,0 +1,247 @@ +import contextlib +import inspect +import io +import os +import random +import re +import socket +import sys +import zipfile + +import pytest + +PASSWORD_REGEX = re.compile(r"^([a-z]+)(-[a-z]+)?-([a-z]+)(-[a-z]+)?$") + + +# TODO: Improve the Common tests to test it all as a single class + + +class TestBuildPassword: + @pytest.mark.parametrize( + "test_input,expected", + ( + # VALID, two lowercase words, separated by a hyphen + ("syrup-enzyme", True), + ("caution-friday", True), + # VALID, two lowercase words, with one hyphenated compound word + ("drop-down-thimble", True), + ("unmixed-yo-yo", True), + # VALID, two lowercase hyphenated compound words, separated by hyphen + ("yo-yo-drop-down", True), + ("felt-tip-t-shirt", True), + ("hello-world", True), + # INVALID + ("Upper-Case", False), + ("digits-123", False), + ("too-many-hyphens-", False), + ("symbols-!@#$%", False), + ), + ) + def test_build_password_regex(self, test_input, expected): + """Test that `PASSWORD_REGEX` accounts for the following patterns + + There are a few hyphenated words in `wordlist.txt`: + * drop-down + * felt-tip + * t-shirt + * yo-yo + + These words cause a few extra potential password patterns: + * word-word + * hyphenated-word-word + * word-hyphenated-word + * hyphenated-word-hyphenated-word + """ + + assert bool(PASSWORD_REGEX.match(test_input)) == expected + + def test_build_password_unique(self, common_obj, sys_onionshare_dev_mode): + assert common_obj.build_password() != common_obj.build_password() + + +class TestDirSize: + def test_temp_dir_size(self, common_obj, temp_dir_1024_delete): + """dir_size() should return the total size (in bytes) of all files + in a particular directory. + """ + + assert common_obj.dir_size(temp_dir_1024_delete) == 1024 + + +class TestEstimatedTimeRemaining: + @pytest.mark.parametrize( + "test_input,expected", + ( + ((2, 676, 12), "8h14m16s"), + ((14, 1049, 30), "1h26m15s"), + ((21, 450, 1), "33m42s"), + ((31, 1115, 80), "11m39s"), + ((336, 989, 32), "2m12s"), + ((603, 949, 38), "36s"), + ((971, 1009, 83), "1s"), + ), + ) + def test_estimated_time_remaining( + self, common_obj, test_input, expected, time_time_100 + ): + assert common_obj.estimated_time_remaining(*test_input) == expected + + @pytest.mark.parametrize( + "test_input", + ( + (10, 20, 100), # if `time_elapsed == 0` + (0, 37, 99), # if `download_rate == 0` + ), + ) + def test_raises_zero_division_error(self, common_obj, test_input, time_time_100): + with pytest.raises(ZeroDivisionError): + common_obj.estimated_time_remaining(*test_input) + + +class TestFormatSeconds: + @pytest.mark.parametrize( + "test_input,expected", + ( + (0, "0s"), + (26, "26s"), + (60, "1m"), + (947.35, "15m47s"), + (1847, "30m47s"), + (2193.94, "36m34s"), + (3600, "1h"), + (13426.83, "3h43m47s"), + (16293, "4h31m33s"), + (18392.14, "5h6m32s"), + (86400, "1d"), + (129674, "1d12h1m14s"), + (56404.12, "15h40m4s"), + ), + ) + def test_format_seconds(self, common_obj, test_input, expected): + assert common_obj.format_seconds(test_input) == expected + + # TODO: test negative numbers? + @pytest.mark.parametrize("test_input", ("string", lambda: None, [], {}, set())) + def test_invalid_input_types(self, common_obj, test_input): + with pytest.raises(TypeError): + common_obj.format_seconds(test_input) + + +class TestGetAvailablePort: + @pytest.mark.parametrize( + "port_min,port_max", + ((random.randint(1024, 1500), random.randint(1800, 2048)) for _ in range(50)), + ) + def test_returns_an_open_port(self, common_obj, port_min, port_max): + """ get_available_port() should return an open port within the range """ + + port = common_obj.get_available_port(port_min, port_max) + assert port_min <= port <= port_max + with socket.socket() as tmpsock: + tmpsock.bind(("127.0.0.1", port)) + + +class TestGetPlatform: + def test_darwin(self, platform_darwin, common_obj): + assert common_obj.platform == "Darwin" + + def test_linux(self, platform_linux, common_obj): + assert common_obj.platform == "Linux" + + def test_windows(self, platform_windows, common_obj): + assert common_obj.platform == "Windows" + + +class TestGetTorPaths: + @pytest.mark.skipif(sys.platform != "Darwin", reason="requires MacOS") + def test_get_tor_paths_darwin( + self, platform_darwin, common_obj, sys_frozen, sys_meipass + ): + base_path = os.path.dirname( + os.path.dirname(os.path.dirname(common_obj.get_resource_path(""))) + ) + tor_path = os.path.join(base_path, "Resources", "Tor", "tor") + tor_geo_ip_file_path = os.path.join(base_path, "Resources", "Tor", "geoip") + tor_geo_ipv6_file_path = os.path.join(base_path, "Resources", "Tor", "geoip6") + obfs4proxy_file_path = os.path.join(base_path, "Resources", "Tor", "obfs4proxy") + assert common_obj.get_tor_paths() == ( + tor_path, + tor_geo_ip_file_path, + tor_geo_ipv6_file_path, + obfs4proxy_file_path, + ) + + @pytest.mark.skipif(sys.platform != "Linux", reason="requires Linux") + def test_get_tor_paths_linux(self, platform_linux, common_obj): + ( + tor_path, + tor_geo_ip_file_path, + tor_geo_ipv6_file_path, + _, # obfs4proxy is optional + ) = common_obj.get_tor_paths() + + assert os.path.basename(tor_path) == "tor" + assert ( + tor_geo_ip_file_path == "/usr/share/tor/geoip" + or tor_geo_ip_file_path == "/usr/local/share/tor/geoip" + ) + assert ( + tor_geo_ipv6_file_path == "/usr/share/tor/geoip6" + or tor_geo_ipv6_file_path == "/usr/local/share/tor/geoip6" + ) + + @pytest.mark.skipif(sys.platform != "win32", reason="requires Windows") + def test_get_tor_paths_windows(self, platform_windows, common_obj, sys_frozen): + base_path = os.path.join( + os.path.dirname(os.path.dirname(common_obj.get_resource_path(""))), "tor" + ) + tor_path = os.path.join(os.path.join(base_path, "Tor"), "tor.exe") + obfs4proxy_file_path = os.path.join( + os.path.join(base_path, "Tor"), "obfs4proxy.exe" + ) + tor_geo_ip_file_path = os.path.join( + os.path.join(os.path.join(base_path, "Data"), "Tor"), "geoip" + ) + tor_geo_ipv6_file_path = os.path.join( + os.path.join(os.path.join(base_path, "Data"), "Tor"), "geoip6" + ) + assert common_obj.get_tor_paths() == ( + tor_path, + tor_geo_ip_file_path, + tor_geo_ipv6_file_path, + obfs4proxy_file_path, + ) + + +class TestHumanReadableFilesize: + @pytest.mark.parametrize( + "test_input,expected", + ( + (1024 ** 0, "1.0 B"), + (1024 ** 1, "1.0 KiB"), + (1024 ** 2, "1.0 MiB"), + (1024 ** 3, "1.0 GiB"), + (1024 ** 4, "1.0 TiB"), + (1024 ** 5, "1.0 PiB"), + (1024 ** 6, "1.0 EiB"), + (1024 ** 7, "1.0 ZiB"), + (1024 ** 8, "1.0 YiB"), + ), + ) + def test_human_readable_filesize(self, common_obj, test_input, expected): + assert common_obj.human_readable_filesize(test_input) == expected + + +class TestLog: + def test_output(self, common_obj, time_strftime): + common_obj.verbose = True + + # From: https://stackoverflow.com/questions/1218933 + with io.StringIO() as buf, contextlib.redirect_stdout(buf): + common_obj.log("TestModule", "dummy_func") + common_obj.log("TestModule", "dummy_func", "TEST_MSG") + output = buf.getvalue() + + line_one, line_two, _ = output.split("\n") + assert line_one == "[Jun 06 2013 11:05:00] TestModule.dummy_func" + assert line_two == "[Jun 06 2013 11:05:00] TestModule.dummy_func: TEST_MSG" |