Merge branch 'delirious-lettuce-test_onionshare_common'

This commit is contained in:
Micah Lee 2017-07-09 10:59:00 -07:00
commit 2a8a7fd634
No known key found for this signature in database
GPG Key ID: 403C2657CD994F73
10 changed files with 773 additions and 43 deletions

View File

@ -1,5 +1,5 @@
language: python language: python
sudo: required # sudo: required
dist: trusty dist: trusty
python: python:
- "3.4" - "3.4"
@ -9,7 +9,9 @@ python:
- "3.7-dev" - "3.7-dev"
- "nightly" - "nightly"
# command to install dependencies # command to install dependencies
before_install: "sudo apt-get update; sudo apt-get install -y python3-nose python3-flask python3-stem python3-pyqt5" install:
install: "" - pip install Flask==0.12 stem==1.5.4 pytest-cov coveralls
# command to run tests # command to run tests
script: nosetests3 script: pytest --cov=onionshare test/
after_success:
- coveralls

View File

@ -11,9 +11,9 @@ cd onionshare
Install the needed dependencies: Install the needed dependencies:
For Debian-like distros: `apt install -y build-essential fakeroot python3-all python3-stdeb dh-python python3-flask python3-stem python3-pyqt5 python-nautilus python3-nose tor` For Debian-like distros: `apt install -y build-essential fakeroot python3-all python3-stdeb dh-python python3-flask python3-stem python3-pyqt5 python-nautilus python3-pytest tor`
For Fedora-like distros: `dnf install -y rpm-build python3-flask python3-stem python3-qt5 nautilus-python tor` For Fedora-like distros: `dnf install -y rpm-build python3-flask python3-stem python3-qt5 python3-pytest nautilus-python tor`
After that you can try both the CLI and the GUI version of OnionShare: After that you can try both the CLI and the GUI version of OnionShare:
@ -126,10 +126,8 @@ This will prompt you to codesign three binaries and execute one unsigned binary.
## Tests ## Tests
OnionShare includes [nose](https://nose.readthedocs.org/en/latest/) unit tests. First, `sudo apt-get install python3-nose` or `sudo pip3 install nose`. OnionShare includes PyTest unit tests. To run the tests:
To run the tests:
```sh ```sh
nosetests3 test pytest test/
``` ```

View File

@ -2,5 +2,3 @@
# Pre-push hook. If you want to test with a different version of firefox, put # Pre-push hook. If you want to test with a different version of firefox, put
# the path in the CFX_FIREFOX environment variable. # the path in the CFX_FIREFOX environment variable.
nosetests test

View File

@ -1,6 +1,6 @@
[DEFAULT] [DEFAULT]
Package3: onionshare Package3: onionshare
Depends3: python3-flask, python3-stem, python3-pyqt5, python-nautilus, tor Depends3: python3-flask, python3-stem, python3-pyqt5, python-nautilus, tor
Build-Depends: python3-nose, python3-flask, python3-stem, python3-pyqt5 Build-Depends: python3-pytest, python3-flask, python3-stem, python3-pyqt5
Suite: xenial Suite: xenial
X-Python3-Version: >= 3.4 X-Python3-Version: >= 3.4

0
test/__init__.py Normal file
View File

157
test/conftest.py Normal file
View File

@ -0,0 +1,157 @@
import os
import shutil
import sys
import tempfile
import pytest
from onionshare import common
@pytest.fixture
def temp_dir_1024():
""" Create a temporary directory that has a single file of a
particular size (1024 bytes).
"""
tmp_dir = tempfile.mkdtemp()
tmp_file, tmp_file_path = tempfile.mkstemp(dir=tmp_dir)
with open(tmp_file, 'wb') as f:
f.write(b'*' * 1024)
return tmp_dir
# pytest > 2.9 only needs @pytest.fixture
@pytest.yield_fixture
def temp_dir_1024_delete():
""" Create a temporary directory that has a single file of a
particular size (1024 bytes). The temporary directory (including
the file inside) will be deleted after fixture usage.
"""
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_file, tmp_file_path = tempfile.mkstemp(dir=tmp_dir)
with open(tmp_file, 'wb') as f:
f.write(b'*' * 1024)
yield tmp_dir
@pytest.fixture
def temp_file_1024():
""" Create a temporary file of a particular size (1024 bytes). """
with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
tmp_file.write(b'*' * 1024)
return tmp_file.name
# pytest > 2.9 only needs @pytest.fixture
@pytest.yield_fixture
def temp_file_1024_delete():
"""
Create a temporary file of a particular size (1024 bytes).
The temporary file will be deleted after fixture usage.
"""
with tempfile.NamedTemporaryFile() as tmp_file:
tmp_file.write(b'*' * 1024)
tmp_file.flush()
yield tmp_file.name
# pytest > 2.9 only needs @pytest.fixture
@pytest.yield_fixture(scope='session')
def custom_zw():
zw = common.ZipWriter(
zip_filename=common.random_string(4, 6),
processed_size_callback=lambda _: 'custom_callback'
)
yield zw
zw.close()
os.remove(zw.zip_filename)
# pytest > 2.9 only needs @pytest.fixture
@pytest.yield_fixture(scope='session')
def default_zw():
zw = common.ZipWriter()
yield zw
zw.close()
tmp_dir = os.path.dirname(zw.zip_filename)
shutil.rmtree(tmp_dir)
@pytest.fixture
def locale_en(monkeypatch):
monkeypatch.setattr('locale.getdefaultlocale', lambda: ('en_US', 'UTF-8'))
@pytest.fixture
def locale_fr(monkeypatch):
monkeypatch.setattr('locale.getdefaultlocale', lambda: ('fr_FR', 'UTF-8'))
@pytest.fixture
def locale_invalid(monkeypatch):
monkeypatch.setattr('locale.getdefaultlocale', lambda: ('xx_XX', 'UTF-8'))
@pytest.fixture
def locale_ru(monkeypatch):
monkeypatch.setattr('locale.getdefaultlocale', lambda: ('ru_RU', 'UTF-8'))
@pytest.fixture
def platform_darwin(monkeypatch):
monkeypatch.setattr('platform.system', lambda: 'Darwin')
@pytest.fixture # (scope="session")
def platform_linux(monkeypatch):
monkeypatch.setattr('platform.system', lambda: 'Linux')
@pytest.fixture
def platform_windows(monkeypatch):
monkeypatch.setattr('platform.system', lambda: 'Windows')
@pytest.fixture
def set_debug_false(monkeypatch):
monkeypatch.setattr('onionshare.common.debug', False)
@pytest.fixture
def set_debug_true(monkeypatch):
monkeypatch.setattr('onionshare.common.debug', True)
@pytest.fixture
def sys_argv_sys_prefix(monkeypatch):
monkeypatch.setattr('sys.argv', [sys.prefix])
@pytest.fixture
def sys_frozen(monkeypatch):
monkeypatch.setattr('sys.frozen', True, raising=False)
@pytest.fixture
def sys_meipass(monkeypatch):
monkeypatch.setattr(
'sys._MEIPASS', os.path.expanduser('~'), raising=False)
@pytest.fixture # (scope="session")
def sys_onionshare_dev_mode(monkeypatch):
monkeypatch.setattr('sys.onionshare_dev_mode', True, raising=False)
@pytest.fixture
def time_time_100(monkeypatch):
monkeypatch.setattr('time.time', lambda: 100)
@pytest.fixture
def time_strftime(monkeypatch):
monkeypatch.setattr('time.strftime', lambda _: 'Jun 06 2013 11:05:00')

View File

@ -16,20 +16,341 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import contextlib
import inspect
import io
import os
import random
import re
import socket import socket
import sys
import zipfile
import pytest
from onionshare import common from onionshare import common
DEFAULT_ZW_FILENAME_REGEX = re.compile(r'^onionshare_[a-z2-7]{6}.zip$')
LOG_MSG_REGEX = re.compile(r"""
^\[Jun\ 06\ 2013\ 11:05:00\]
\ TestModule\.<function\ TestLog\.test_output\.<locals>\.dummy_func
\ at\ 0x[a-f0-9]+>(:\ TEST_MSG)?$""", re.VERBOSE)
RANDOM_STR_REGEX = re.compile(r'^[a-z2-7]+$')
SLUG_REGEX = re.compile(r'^([a-z]+)(-[a-z]+)?-([a-z]+)(-[a-z]+)?$')
def test_get_platform_returns_platform_system():
"""get_platform() returns platform.system() when ONIONSHARE_PLATFORM is not defined"""
p = common.platform.system
common.platform.system = lambda: 'Sega Saturn'
assert common.get_platform() == 'Sega Saturn'
common.platform.system = p
def test_get_available_port_returns_an_open_port(): class TestBuildSlug:
"""get_available_port() should return an open port within the range""" @pytest.mark.parametrize('test_input,expected', (
for i in range(100): # VALID, two lowercase words, separated by a hyphen
port = common.get_available_port(1024, 2048) ('syrup-enzyme', True),
assert 1024 <= port <= 2048 ('caution-friday', True),
socket.socket().bind(("127.0.0.1", port))
# 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_slug_regex(self, test_input, expected):
""" Test that `SLUG_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 slug patterns:
* word-word
* hyphenated-word-word
* word-hyphenated-word
* hyphenated-word-hyphenated-word
"""
assert bool(SLUG_REGEX.match(test_input)) == expected
def test_build_slug_unique(self, sys_onionshare_dev_mode):
assert common.build_slug() != common.build_slug()
class TestDirSize:
def test_temp_dir_size(self, temp_dir_1024_delete):
""" dir_size() should return the total size (in bytes) of all files
in a particular directory.
"""
assert common.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, test_input, expected, time_time_100):
assert common.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, test_input, time_time_100):
with pytest.raises(ZeroDivisionError):
common.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, test_input, expected):
assert common.format_seconds(test_input) == expected
# TODO: test negative numbers?
@pytest.mark.parametrize('test_input', (
'string', lambda: None, [], {}, set()
))
def test_invalid_input_types(self, test_input):
with pytest.raises(TypeError):
common.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, port_min, port_max):
""" get_available_port() should return an open port within the range """
port = common.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):
assert common.get_platform() == 'Darwin'
def test_linux(self, platform_linux):
assert common.get_platform() == 'Linux'
def test_windows(self, platform_windows):
assert common.get_platform() == 'Windows'
# TODO: double-check these tests
class TestGetResourcePath:
def test_onionshare_dev_mode(self, sys_onionshare_dev_mode):
prefix = os.path.join(
os.path.dirname(
os.path.dirname(
os.path.abspath(
inspect.getfile(
inspect.currentframe())))), 'share')
assert (
common.get_resource_path(os.path.join(prefix, 'test_filename')) ==
os.path.join(prefix, 'test_filename'))
def test_linux(self, platform_linux, sys_argv_sys_prefix):
prefix = os.path.join(sys.prefix, 'share/onionshare')
assert (
common.get_resource_path(os.path.join(prefix, 'test_filename')) ==
os.path.join(prefix, 'test_filename'))
def test_frozen_darwin(self, platform_darwin, sys_frozen, sys_meipass):
prefix = os.path.join(sys._MEIPASS, 'share')
assert (
common.get_resource_path(os.path.join(prefix, 'test_filename')) ==
os.path.join(prefix, 'test_filename'))
def test_frozen_windows(self, platform_windows, sys_frozen):
prefix = os.path.join(os.path.dirname(sys.executable), 'share')
assert (
common.get_resource_path(os.path.join(prefix, 'test_filename')) ==
os.path.join(prefix, 'test_filename'))
class TestGetTorPaths:
# @pytest.mark.skipif(sys.platform != 'Darwin', reason='requires MacOS') ?
def test_get_tor_paths_darwin(self, platform_darwin, sys_frozen, sys_meipass):
base_path = os.path.dirname(
os.path.dirname(
os.path.dirname(
common.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')
assert (common.get_tor_paths() ==
(tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path))
# @pytest.mark.skipif(sys.platform != 'Linux', reason='requires Linux') ?
def test_get_tor_paths_linux(self, platform_linux):
assert (common.get_tor_paths() ==
('/usr/bin/tor', '/usr/share/tor/geoip', '/usr/share/tor/geoip6'))
# @pytest.mark.skipif(sys.platform != 'Windows', reason='requires Windows') ?
def test_get_tor_paths_windows(self, platform_windows, sys_frozen):
base_path = os.path.join(
os.path.dirname(
os.path.dirname(
common.get_resource_path(''))), 'tor')
tor_path = os.path.join(
os.path.join(base_path, 'Tor'), "tor.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.get_tor_paths() ==
(tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path))
class TestGetVersion:
def test_get_version(self, sys_onionshare_dev_mode):
with open(common.get_resource_path('version.txt')) as f:
version = f.read().strip()
assert version == common.get_version()
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, test_input, expected):
assert common.human_readable_filesize(test_input) == expected
class TestLog:
@pytest.mark.parametrize('test_input', (
('[Jun 06 2013 11:05:00]'
' TestModule.<function TestLog.test_output.<locals>.dummy_func'
' at 0xdeadbeef>'),
('[Jun 06 2013 11:05:00]'
' TestModule.<function TestLog.test_output.<locals>.dummy_func'
' at 0xdeadbeef>: TEST_MSG')
))
def test_log_msg_regex(self, test_input):
assert bool(LOG_MSG_REGEX.match(test_input))
def test_output(self, set_debug_true, time_strftime):
def dummy_func():
pass
# From: https://stackoverflow.com/questions/1218933
with io.StringIO() as buf, contextlib.redirect_stdout(buf):
common.log('TestModule', dummy_func)
common.log('TestModule', dummy_func, 'TEST_MSG')
output = buf.getvalue()
line_one, line_two, _ = output.split('\n')
assert LOG_MSG_REGEX.match(line_one)
assert LOG_MSG_REGEX.match(line_two)
class TestSetDebug:
def test_debug_true(self, set_debug_false):
common.set_debug(True)
assert common.debug is True
def test_debug_false(self, set_debug_true):
common.set_debug(False)
assert common.debug is False
class TestZipWriterDefault:
@pytest.mark.parametrize('test_input', (
'onionshare_{}.zip'.format(''.join(
random.choice('abcdefghijklmnopqrstuvwxyz234567') for _ in range(6)
)) for _ in range(50)
))
def test_default_zw_filename_regex(self, test_input):
assert bool(DEFAULT_ZW_FILENAME_REGEX.match(test_input))
def test_zw_filename(self, default_zw):
zw_filename = os.path.basename(default_zw.zip_filename)
assert bool(DEFAULT_ZW_FILENAME_REGEX.match(zw_filename))
def test_zipfile_filename_matches_zipwriter_filename(self, default_zw):
assert default_zw.z.filename == default_zw.zip_filename
def test_zipfile_allow_zip64(self, default_zw):
assert default_zw.z._allowZip64 is True
def test_zipfile_mode(self, default_zw):
assert default_zw.z.mode == 'w'
def test_callback(self, default_zw):
assert default_zw.processed_size_callback(None) is None
def test_add_file(self, default_zw, temp_file_1024_delete):
default_zw.add_file(temp_file_1024_delete)
zipfile_info = default_zw.z.getinfo(
os.path.basename(temp_file_1024_delete))
assert zipfile_info.compress_type == zipfile.ZIP_DEFLATED
assert zipfile_info.file_size == 1024
def test_add_directory(self, temp_dir_1024_delete, default_zw):
previous_size = default_zw._size # size before adding directory
default_zw.add_dir(temp_dir_1024_delete)
assert default_zw._size == previous_size + 1024
class TestZipWriterCustom:
@pytest.mark.parametrize('test_input', (
common.random_string(
random.randint(2, 50),
random.choice((None, random.randint(2, 50)))
) for _ in range(50)
))
def test_random_string_regex(self, test_input):
assert bool(RANDOM_STR_REGEX.match(test_input))
def test_custom_filename(self, custom_zw):
assert bool(RANDOM_STR_REGEX.match(custom_zw.zip_filename))
def test_custom_callback(self, custom_zw):
assert custom_zw.processed_size_callback(None) == 'custom_callback'

View File

@ -0,0 +1,163 @@
"""
OnionShare | https://onionshare.org/
Copyright (C) 2017 Micah Lee <micah@micahflee.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import json
import os
import tempfile
import pytest
from onionshare import common, settings, strings
@pytest.fixture
def custom_version(monkeypatch):
monkeypatch.setattr(common, 'get_version', lambda: 'DUMMY_VERSION_1.2.3')
@pytest.fixture
def os_path_expanduser(monkeypatch):
monkeypatch.setattr('os.path.expanduser', lambda path: path)
@pytest.fixture
def settings_obj(custom_version, sys_onionshare_dev_mode, platform_linux):
return settings.Settings()
class TestSettings:
def test_init(self, settings_obj):
assert settings_obj._settings == settings_obj.default_settings == {
'version': 'DUMMY_VERSION_1.2.3',
'connection_type': 'bundled',
'control_port_address': '127.0.0.1',
'control_port_port': 9051,
'socks_address': '127.0.0.1',
'socks_port': 9050,
'socket_file_path': '/var/run/tor/control',
'auth_type': 'no_auth',
'auth_password': '',
'close_after_first_download': True,
'systray_notifications': True,
'use_stealth': False,
'use_autoupdate': True,
'autoupdate_timestamp': None
}
def test_fill_in_defaults(self, settings_obj):
del settings_obj._settings['version']
settings_obj.fill_in_defaults()
assert settings_obj._settings['version'] == 'DUMMY_VERSION_1.2.3'
def test_load(self, settings_obj):
custom_settings = {
'version': 'CUSTOM_VERSION',
'socks_port': 9999,
'use_stealth': True
}
tmp_file, tmp_file_path = tempfile.mkstemp()
with open(tmp_file, 'w') as f:
json.dump(custom_settings, f)
settings_obj.filename = tmp_file_path
settings_obj.load()
assert settings_obj._settings['version'] == 'CUSTOM_VERSION'
assert settings_obj._settings['socks_port'] == 9999
assert settings_obj._settings['use_stealth'] is True
os.remove(tmp_file_path)
assert os.path.exists(tmp_file_path) is False
def test_save(self, monkeypatch, settings_obj):
monkeypatch.setattr(strings, '_', lambda _: '')
settings_filename = 'default_settings.json'
tmp_dir = tempfile.gettempdir()
settings_path = os.path.join(tmp_dir, settings_filename)
settings_obj.filename = settings_path
settings_obj.save()
with open(settings_path, 'r') as f:
settings = json.load(f)
assert settings_obj._settings == settings
os.remove(settings_path)
assert os.path.exists(settings_path) is False
def test_get(self, settings_obj):
assert settings_obj.get('version') == 'DUMMY_VERSION_1.2.3'
assert settings_obj.get('connection_type') == 'bundled'
assert settings_obj.get('control_port_address') == '127.0.0.1'
assert settings_obj.get('control_port_port') == 9051
assert settings_obj.get('socks_address') == '127.0.0.1'
assert settings_obj.get('socks_port') == 9050
assert settings_obj.get('socket_file_path') == '/var/run/tor/control'
assert settings_obj.get('auth_type') == 'no_auth'
assert settings_obj.get('auth_password') == ''
assert settings_obj.get('close_after_first_download') is True
assert settings_obj.get('systray_notifications') is True
assert settings_obj.get('use_stealth') is False
assert settings_obj.get('use_autoupdate') is True
assert settings_obj.get('autoupdate_timestamp') is None
def test_set_version(self, settings_obj):
settings_obj.set('version', 'CUSTOM_VERSION')
assert settings_obj._settings['version'] == 'CUSTOM_VERSION'
def test_set_control_port_port(self, settings_obj):
settings_obj.set('control_port_port', 999)
assert settings_obj._settings['control_port_port'] == 999
settings_obj.set('control_port_port', 'NON_INTEGER')
assert settings_obj._settings['control_port_port'] == 9051
def test_set_socks_port(self, settings_obj):
settings_obj.set('socks_port', 888)
assert settings_obj._settings['socks_port'] == 888
settings_obj.set('socks_port', 'NON_INTEGER')
assert settings_obj._settings['socks_port'] == 9050
def test_filename_darwin(
self,
custom_version,
monkeypatch,
os_path_expanduser,
platform_darwin):
obj = settings.Settings()
assert (obj.filename ==
'~/Library/Application Support/OnionShare/onionshare.json')
def test_filename_linux(
self,
custom_version,
monkeypatch,
os_path_expanduser,
platform_linux):
obj = settings.Settings()
assert obj.filename == '~/.config/onionshare/onionshare.json'
def test_filename_windows(
self,
custom_version,
monkeypatch,
platform_windows):
monkeypatch.setenv('APPDATA', 'C:')
obj = settings.Settings()
assert obj.filename == 'C:\\OnionShare\\onionshare.json'

View File

@ -17,30 +17,55 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import locale, os
import types
import pytest
from onionshare import common, strings from onionshare import common, strings
# Stub get_resource_path so it finds the correct path while running tests
def get_resource_path(filename): # # Stub get_resource_path so it finds the correct path while running tests
resources_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'share') # def get_resource_path(filename):
path = os.path.join(resources_dir, filename) # resources_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'share')
return path # path = os.path.join(resources_dir, filename)
common.get_resource_path = get_resource_path # return path
# common.get_resource_path = get_resource_path
def test_starts_with_empty_strings(): def test_starts_with_empty_strings():
"""creates an empty strings dict by default""" """ Creates an empty strings dict by default """
assert strings.strings == {} assert strings.strings == {}
def test_load_strings_defaults_to_english(): def test_underscore_is_function():
"""load_strings() loads English by default""" assert callable(strings._) and isinstance(strings._, types.FunctionType)
locale.getdefaultlocale = lambda: ('en_US', 'UTF-8')
strings.load_strings(common)
assert strings._('wait_for_hs') == "Waiting for HS to be ready:"
def test_load_strings_loads_other_languages(): class TestLoadStrings:
"""load_strings() loads other languages in different locales""" def test_load_strings_defaults_to_english(
locale.getdefaultlocale = lambda: ('fr_FR', 'UTF-8') self, locale_en, sys_onionshare_dev_mode):
strings.load_strings(common, "fr") """ load_strings() loads English by default """
assert strings._('wait_for_hs') == "En attente du HS:" strings.load_strings(common)
assert strings._('wait_for_hs') == "Waiting for HS to be ready:"
def test_load_strings_loads_other_languages(
self, locale_fr, sys_onionshare_dev_mode):
""" load_strings() loads other languages in different locales """
strings.load_strings(common, "fr")
assert strings._('wait_for_hs') == "En attente du HS:"
def test_load_partial_strings(
self, locale_ru, sys_onionshare_dev_mode):
strings.load_strings(common)
assert strings._("give_this_url") == (
"Отправьте эту ссылку тому человеку, "
"которому вы хотите передать файл:")
assert strings._('wait_for_hs') == "Waiting for HS to be ready:"
def test_load_invalid_locale(
self, locale_invalid, sys_onionshare_dev_mode):
""" load_strings() raises a KeyError for an invalid locale """
with pytest.raises(KeyError):
strings.load_strings(common, 'XX')

View File

@ -16,3 +16,69 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import os
import pytest
from onionshare import OnionShare
class MyOnion:
def __init__(self, stealth=False):
self.auth_string = 'TestHidServAuth'
self.stealth = stealth
@staticmethod
def start_onion_service(_):
return 'test_service_id.onion'
@pytest.fixture
def onionshare_obj():
return OnionShare(MyOnion())
class TestOnionShare:
def test_init(self, onionshare_obj):
assert onionshare_obj.hidserv_dir is None
assert onionshare_obj.onion_host is None
assert onionshare_obj.stealth is None
assert onionshare_obj.cleanup_filenames == []
assert onionshare_obj.local_only is False
assert onionshare_obj.stay_open is False
def test_set_stealth_true(self, onionshare_obj):
onionshare_obj.set_stealth(True)
assert onionshare_obj.stealth is True
assert onionshare_obj.onion.stealth is True
def test_set_stealth_false(self, onionshare_obj):
onionshare_obj.set_stealth(False)
assert onionshare_obj.stealth is False
assert onionshare_obj.onion.stealth is False
def test_start_onion_service(self, onionshare_obj):
onionshare_obj.set_stealth(False)
onionshare_obj.start_onion_service()
assert 17600 <= onionshare_obj.port <= 17650
assert onionshare_obj.onion_host == 'test_service_id.onion'
def test_start_onion_service_stealth(self, onionshare_obj):
onionshare_obj.set_stealth(True)
onionshare_obj.start_onion_service()
assert onionshare_obj.auth_string == 'TestHidServAuth'
def test_start_onion_service_local_only(self, onionshare_obj):
onionshare_obj.local_only = True
onionshare_obj.start_onion_service()
assert onionshare_obj.onion_host == '127.0.0.1:{}'.format(
onionshare_obj.port)
def test_cleanup(self, onionshare_obj, temp_dir_1024, temp_file_1024):
onionshare_obj.cleanup_filenames = [temp_dir_1024, temp_file_1024]
onionshare_obj.cleanup()
assert os.path.exists(temp_dir_1024) is False
assert os.path.exists(temp_dir_1024) is False
assert onionshare_obj.cleanup_filenames == []