Добавлены тесты для всех классов
This commit is contained in:
@@ -0,0 +1,72 @@
|
|||||||
|
import pytest
|
||||||
|
from ipars import CsvManager
|
||||||
|
|
||||||
|
|
||||||
|
def test_writerow_and_getrows(tmp_path):
|
||||||
|
cm = CsvManager()
|
||||||
|
filepath = str(tmp_path / 'data.csv')
|
||||||
|
row = ['Alice', '30', 'Engineer']
|
||||||
|
|
||||||
|
cm.writerow(filepath, 'w', row)
|
||||||
|
result = cm.getRows(filepath)
|
||||||
|
|
||||||
|
assert result == [row]
|
||||||
|
|
||||||
|
|
||||||
|
def test_writerows_and_getrows(tmp_path):
|
||||||
|
cm = CsvManager()
|
||||||
|
filepath = str(tmp_path / 'data.csv')
|
||||||
|
rows = [['Alice', '30'], ['Bob', '25'], ['Carol', '28']]
|
||||||
|
|
||||||
|
cm.writerows(filepath, 'w', rows)
|
||||||
|
result = cm.getRows(filepath)
|
||||||
|
|
||||||
|
assert result == rows
|
||||||
|
|
||||||
|
|
||||||
|
def test_append_mode(tmp_path):
|
||||||
|
cm = CsvManager()
|
||||||
|
filepath = str(tmp_path / 'data.csv')
|
||||||
|
|
||||||
|
cm.writerow(filepath, 'w', ['first'])
|
||||||
|
cm.writerow(filepath, 'a', ['second'])
|
||||||
|
result = cm.getRows(filepath)
|
||||||
|
|
||||||
|
assert result == [['first'], ['second']]
|
||||||
|
|
||||||
|
|
||||||
|
def test_custom_delimiter(tmp_path):
|
||||||
|
cm = CsvManager(delimiter=',')
|
||||||
|
filepath = str(tmp_path / 'data.csv')
|
||||||
|
row = ['one', 'two', 'three']
|
||||||
|
|
||||||
|
cm.writerow(filepath, 'w', row)
|
||||||
|
result = cm.getRows(filepath)
|
||||||
|
|
||||||
|
assert result == [row]
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_mode_raises(tmp_path):
|
||||||
|
cm = CsvManager()
|
||||||
|
filepath = str(tmp_path / 'data.csv')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
cm.writerow(filepath, 'x', ['data'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_row_type_raises(tmp_path):
|
||||||
|
cm = CsvManager()
|
||||||
|
filepath = str(tmp_path / 'data.csv')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
cm.writerow(filepath, 'w', 'not a list')
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_constructor_args():
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
CsvManager(delimiter=123)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pprint_does_not_raise(capsys):
|
||||||
|
cm = CsvManager()
|
||||||
|
cm.pprint([['a', 'b'], ['c', 'd']])
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert 'a' in captured.out
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import pytest
|
||||||
|
from ipars import JsonManager
|
||||||
|
|
||||||
|
|
||||||
|
def test_dump_and_load(tmp_path):
|
||||||
|
jm = JsonManager()
|
||||||
|
filepath = str(tmp_path / 'data.json')
|
||||||
|
data = {'name': 'ipars', 'version': 3, 'active': True}
|
||||||
|
|
||||||
|
jm.dump(filepath, data)
|
||||||
|
result = jm.load(filepath)
|
||||||
|
|
||||||
|
assert result == data
|
||||||
|
|
||||||
|
|
||||||
|
def test_dump_and_load_list(tmp_path):
|
||||||
|
jm = JsonManager()
|
||||||
|
filepath = str(tmp_path / 'list.json')
|
||||||
|
data = [1, 2, 3, 'hello']
|
||||||
|
|
||||||
|
jm.dump(filepath, data)
|
||||||
|
result = jm.load(filepath)
|
||||||
|
|
||||||
|
assert result == data
|
||||||
|
|
||||||
|
|
||||||
|
def test_dump_and_load_with_cyrillic(tmp_path):
|
||||||
|
jm = JsonManager()
|
||||||
|
filepath = str(tmp_path / 'cyrillic.json')
|
||||||
|
data = {'текст': 'привет'}
|
||||||
|
|
||||||
|
jm.dump(filepath, data)
|
||||||
|
result = jm.load(filepath)
|
||||||
|
|
||||||
|
assert result == data
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_nonexistent_file():
|
||||||
|
jm = JsonManager()
|
||||||
|
with pytest.raises(FileNotFoundError):
|
||||||
|
jm.load('nonexistent_file_xyz.json')
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_encoding_raises():
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
JsonManager(encoding=123)
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_invalid_path_type():
|
||||||
|
jm = JsonManager()
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
jm.load(123)
|
||||||
|
|
||||||
|
|
||||||
|
def test_dump_invalid_path_type(tmp_path):
|
||||||
|
jm = JsonManager()
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
jm.dump(123, {'key': 'value'})
|
||||||
|
|
||||||
|
|
||||||
|
def test_pprint_does_not_raise(capsys):
|
||||||
|
jm = JsonManager()
|
||||||
|
jm.pprint({'key': 'value'})
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert 'key' in captured.out
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
import pytest
|
||||||
|
from unittest.mock import patch, MagicMock
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from ipars import Pars
|
||||||
|
|
||||||
|
|
||||||
|
# --- exists ---
|
||||||
|
|
||||||
|
def test_exists_true(tmp_path):
|
||||||
|
p = Pars()
|
||||||
|
assert p.exists(str(tmp_path)) is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_exists_false():
|
||||||
|
p = Pars()
|
||||||
|
assert p.exists('this_path_does_not_exist_xyz') is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_exists_invalid_type():
|
||||||
|
p = Pars()
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
p.exists(123)
|
||||||
|
|
||||||
|
|
||||||
|
# --- listdir ---
|
||||||
|
|
||||||
|
def test_listdir_returns_list(tmp_path):
|
||||||
|
p = Pars()
|
||||||
|
(tmp_path / 'a.txt').write_text('a')
|
||||||
|
(tmp_path / 'b.txt').write_text('b')
|
||||||
|
result = p.listdir(str(tmp_path))
|
||||||
|
assert isinstance(result, list)
|
||||||
|
assert 'a.txt' in result
|
||||||
|
assert 'b.txt' in result
|
||||||
|
|
||||||
|
|
||||||
|
def test_listdir_invalid_type():
|
||||||
|
p = Pars()
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
p.listdir(42)
|
||||||
|
|
||||||
|
|
||||||
|
# --- mkdir ---
|
||||||
|
|
||||||
|
def test_mkdir_creates_directory(tmp_path):
|
||||||
|
p = Pars()
|
||||||
|
new_dir = str(tmp_path / 'new_folder')
|
||||||
|
p.mkdir(new_dir)
|
||||||
|
assert (tmp_path / 'new_folder').exists()
|
||||||
|
|
||||||
|
|
||||||
|
def test_mkdir_does_not_raise_if_exists(tmp_path):
|
||||||
|
p = Pars()
|
||||||
|
existing = str(tmp_path)
|
||||||
|
p.mkdir(existing) # не должен бросать ошибку
|
||||||
|
|
||||||
|
|
||||||
|
def test_mkdir_invalid_type():
|
||||||
|
p = Pars()
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
p.mkdir(99)
|
||||||
|
|
||||||
|
|
||||||
|
# --- returnBs4Object ---
|
||||||
|
|
||||||
|
def test_returnBs4Object(tmp_path):
|
||||||
|
p = Pars()
|
||||||
|
html_file = tmp_path / 'page.html'
|
||||||
|
html_file.write_text('<html><body><h1>Hello</h1></body></html>', encoding='utf-8')
|
||||||
|
|
||||||
|
soup = p.returnBs4Object(str(html_file))
|
||||||
|
|
||||||
|
assert soup.find('h1').text == 'Hello'
|
||||||
|
|
||||||
|
|
||||||
|
def test_returnBs4Object_returns_beautifulsoup(tmp_path):
|
||||||
|
p = Pars()
|
||||||
|
html_file = tmp_path / 'page.html'
|
||||||
|
html_file.write_text('<p>Test</p>', encoding='utf-8')
|
||||||
|
|
||||||
|
result = p.returnBs4Object(str(html_file))
|
||||||
|
|
||||||
|
assert isinstance(result, BeautifulSoup)
|
||||||
|
|
||||||
|
|
||||||
|
# --- getTexts ---
|
||||||
|
|
||||||
|
def _make_soup_elements(html: str) -> list:
|
||||||
|
soup = BeautifulSoup(html, 'lxml')
|
||||||
|
return soup.find_all('div')
|
||||||
|
|
||||||
|
|
||||||
|
def test_getTexts_basic():
|
||||||
|
p = Pars()
|
||||||
|
elements = _make_soup_elements('<div>Hello</div><div>World</div>')
|
||||||
|
result = p.getTexts(elements)
|
||||||
|
assert result == ['Hello', 'World']
|
||||||
|
|
||||||
|
|
||||||
|
def test_getTexts_needfix_strips_whitespace():
|
||||||
|
p = Pars()
|
||||||
|
elements = _make_soup_elements('<div> Hello \n </div><div>\t World\t</div>')
|
||||||
|
result = p.getTexts(elements, needFix=True)
|
||||||
|
assert result == ['Hello', 'World']
|
||||||
|
|
||||||
|
|
||||||
|
def test_getTexts_returns_none_when_empty():
|
||||||
|
p = Pars()
|
||||||
|
elements = _make_soup_elements('<div></div>')
|
||||||
|
result = p.getTexts(elements)
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_getTexts_invalid_type():
|
||||||
|
p = Pars()
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
p.getTexts('not a list')
|
||||||
|
|
||||||
|
|
||||||
|
# --- getAttributes ---
|
||||||
|
|
||||||
|
def test_getAttributes_basic():
|
||||||
|
p = Pars()
|
||||||
|
soup = BeautifulSoup('<a href="http://a.com">1</a><a href="http://b.com">2</a>', 'lxml')
|
||||||
|
elements = soup.find_all('a')
|
||||||
|
result = p.getAttributes(elements, 'href')
|
||||||
|
assert result == ['http://a.com', 'http://b.com']
|
||||||
|
|
||||||
|
|
||||||
|
def test_getAttributes_missing_attr():
|
||||||
|
p = Pars()
|
||||||
|
soup = BeautifulSoup('<div>no href</div>', 'lxml')
|
||||||
|
elements = soup.find_all('div')
|
||||||
|
result = p.getAttributes(elements, 'href')
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_getAttributes_invalid_type():
|
||||||
|
p = Pars()
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
p.getAttributes('not a list', 'href')
|
||||||
|
|
||||||
|
|
||||||
|
# --- pprint ---
|
||||||
|
|
||||||
|
def test_pprint_does_not_raise(capsys):
|
||||||
|
p = Pars()
|
||||||
|
p.pprint({'key': 'value', 'list': [1, 2, 3]})
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert 'key' in captured.out
|
||||||
|
|
||||||
|
|
||||||
|
# --- getStaticPage (с моком запроса) ---
|
||||||
|
|
||||||
|
def test_getStaticPage_saves_file(tmp_path):
|
||||||
|
p = Pars()
|
||||||
|
filepath = str(tmp_path / 'page.html')
|
||||||
|
|
||||||
|
mock_response = MagicMock()
|
||||||
|
mock_response.status_code = 200
|
||||||
|
mock_response.text = '<html><body>Mocked</body></html>'
|
||||||
|
|
||||||
|
with patch('requests.get', return_value=mock_response):
|
||||||
|
status = p.getStaticPage(filepath, 'http://example.com')
|
||||||
|
|
||||||
|
assert status == 200
|
||||||
|
assert (tmp_path / 'page.html').read_text(encoding='utf-8') == mock_response.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_getStaticPage_binary_mode(tmp_path):
|
||||||
|
p = Pars()
|
||||||
|
filepath = str(tmp_path / 'image.png')
|
||||||
|
|
||||||
|
mock_response = MagicMock()
|
||||||
|
mock_response.status_code = 200
|
||||||
|
mock_response.content = b'\x89PNG\r\n'
|
||||||
|
|
||||||
|
with patch('requests.get', return_value=mock_response):
|
||||||
|
status = p.getStaticPage(filepath, 'http://example.com/img.png', writeMethod='wb')
|
||||||
|
|
||||||
|
assert status == 200
|
||||||
|
assert (tmp_path / 'image.png').read_bytes() == mock_response.content
|
||||||
|
|
||||||
|
|
||||||
|
def test_getStaticPage_invalid_write_method(tmp_path):
|
||||||
|
p = Pars()
|
||||||
|
filepath = str(tmp_path / 'page.html')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
p.getStaticPage(filepath, 'http://example.com', writeMethod='r')
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
from ipars import ProgressBarManager
|
||||||
|
|
||||||
|
|
||||||
|
def test_full_cycle_does_not_raise():
|
||||||
|
bar = ProgressBarManager(max=3)
|
||||||
|
bar.next()
|
||||||
|
bar.next()
|
||||||
|
bar.next()
|
||||||
|
bar.finish()
|
||||||
|
|
||||||
|
|
||||||
|
def test_single_iteration():
|
||||||
|
bar = ProgressBarManager(max=1)
|
||||||
|
bar.next()
|
||||||
|
bar.finish()
|
||||||
|
|
||||||
|
|
||||||
|
def test_custom_message():
|
||||||
|
bar = ProgressBarManager(max=2, message='Загрузка')
|
||||||
|
bar.next()
|
||||||
|
bar.next()
|
||||||
|
bar.finish()
|
||||||
|
|
||||||
|
|
||||||
|
def test_custom_fill_and_width():
|
||||||
|
bar = ProgressBarManager(max=2, fill='=', width=20)
|
||||||
|
bar.next()
|
||||||
|
bar.next()
|
||||||
|
bar.finish()
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import time
|
||||||
|
import pytest
|
||||||
|
from ipars import TimerManager
|
||||||
|
|
||||||
|
|
||||||
|
def test_getWorkTime_seconds():
|
||||||
|
timer = TimerManager()
|
||||||
|
timer.start()
|
||||||
|
time.sleep(0.1)
|
||||||
|
timer.end()
|
||||||
|
result = timer.getWorkTime('seconds')
|
||||||
|
assert 0.05 < result < 0.5
|
||||||
|
|
||||||
|
|
||||||
|
def test_getWorkTime_minutes():
|
||||||
|
timer = TimerManager()
|
||||||
|
timer.start()
|
||||||
|
time.sleep(0.1)
|
||||||
|
timer.end()
|
||||||
|
result = timer.getWorkTime('minutes')
|
||||||
|
assert result < 0.01
|
||||||
|
|
||||||
|
|
||||||
|
def test_getWorkTime_hours():
|
||||||
|
timer = TimerManager()
|
||||||
|
timer.start()
|
||||||
|
time.sleep(0.1)
|
||||||
|
timer.end()
|
||||||
|
result = timer.getWorkTime('hours')
|
||||||
|
assert result < 0.001
|
||||||
|
|
||||||
|
|
||||||
|
def test_getWorkTime_ndigits():
|
||||||
|
timer = TimerManager()
|
||||||
|
timer.start()
|
||||||
|
time.sleep(0.1)
|
||||||
|
timer.end()
|
||||||
|
result = timer.getWorkTime('seconds', ndigits=2)
|
||||||
|
assert isinstance(result, float)
|
||||||
|
assert len(str(result).split('.')[-1]) <= 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_getWorkTime_returns_float():
|
||||||
|
timer = TimerManager()
|
||||||
|
timer.start()
|
||||||
|
timer.end()
|
||||||
|
result = timer.getWorkTime()
|
||||||
|
assert isinstance(result, float)
|
||||||
|
|
||||||
|
|
||||||
|
def test_raises_without_start():
|
||||||
|
timer = TimerManager()
|
||||||
|
with pytest.raises(ValueError, match='"start"'):
|
||||||
|
timer.getWorkTime()
|
||||||
|
|
||||||
|
|
||||||
|
def test_raises_without_end():
|
||||||
|
timer = TimerManager()
|
||||||
|
timer.start()
|
||||||
|
with pytest.raises(ValueError, match='"end"'):
|
||||||
|
timer.getWorkTime()
|
||||||
|
|
||||||
|
|
||||||
|
def test_raises_invalid_format():
|
||||||
|
timer = TimerManager()
|
||||||
|
timer.start()
|
||||||
|
timer.end()
|
||||||
|
with pytest.raises(ValueError, match='milliseconds'):
|
||||||
|
timer.getWorkTime('milliseconds')
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import zipfile
|
||||||
|
import pytest
|
||||||
|
from ipars import ZipManager
|
||||||
|
|
||||||
|
|
||||||
|
def test_zipfile_creates_archive(tmp_path):
|
||||||
|
zm = ZipManager()
|
||||||
|
source = tmp_path / 'hello.txt'
|
||||||
|
source.write_text('hello world')
|
||||||
|
zip_path = str(tmp_path / 'output.zip')
|
||||||
|
|
||||||
|
zm.zipFile(str(source), zip_path)
|
||||||
|
|
||||||
|
assert (tmp_path / 'output.zip').exists()
|
||||||
|
with zipfile.ZipFile(zip_path, 'r') as zf:
|
||||||
|
assert 'hello.txt' in zf.namelist()
|
||||||
|
|
||||||
|
|
||||||
|
def test_zipfile_content_is_correct(tmp_path):
|
||||||
|
zm = ZipManager()
|
||||||
|
source = tmp_path / 'data.txt'
|
||||||
|
source.write_text('test content')
|
||||||
|
zip_path = str(tmp_path / 'output.zip')
|
||||||
|
|
||||||
|
zm.zipFile(str(source), zip_path)
|
||||||
|
|
||||||
|
with zipfile.ZipFile(zip_path, 'r') as zf:
|
||||||
|
content = zf.read('data.txt').decode('utf-8')
|
||||||
|
assert content == 'test content'
|
||||||
|
|
||||||
|
|
||||||
|
def test_zipfolder_creates_archive(tmp_path):
|
||||||
|
zm = ZipManager()
|
||||||
|
folder = tmp_path / 'myfolder'
|
||||||
|
folder.mkdir()
|
||||||
|
(folder / 'a.txt').write_text('aaa')
|
||||||
|
(folder / 'b.txt').write_text('bbb')
|
||||||
|
zip_path = str(tmp_path / 'folder.zip')
|
||||||
|
|
||||||
|
zm.zipFolder(str(folder), zip_path)
|
||||||
|
|
||||||
|
assert (tmp_path / 'folder.zip').exists()
|
||||||
|
with zipfile.ZipFile(zip_path, 'r') as zf:
|
||||||
|
names = zf.namelist()
|
||||||
|
assert any('a.txt' in n for n in names)
|
||||||
|
assert any('b.txt' in n for n in names)
|
||||||
|
|
||||||
|
|
||||||
|
def test_zipfolder_nested(tmp_path):
|
||||||
|
zm = ZipManager()
|
||||||
|
folder = tmp_path / 'root'
|
||||||
|
folder.mkdir()
|
||||||
|
sub = folder / 'sub'
|
||||||
|
sub.mkdir()
|
||||||
|
(sub / 'deep.txt').write_text('deep')
|
||||||
|
zip_path = str(tmp_path / 'nested.zip')
|
||||||
|
|
||||||
|
zm.zipFolder(str(folder), zip_path)
|
||||||
|
|
||||||
|
with zipfile.ZipFile(zip_path, 'r') as zf:
|
||||||
|
names = zf.namelist()
|
||||||
|
assert any('deep.txt' in n for n in names)
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_compression_none():
|
||||||
|
zm = ZipManager('none')
|
||||||
|
assert zm.compression == zipfile.ZIP_STORED
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_compression_normal():
|
||||||
|
zm = ZipManager('normal')
|
||||||
|
assert zm.compression == zipfile.ZIP_DEFLATED
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_compression_hard():
|
||||||
|
zm = ZipManager('hard')
|
||||||
|
assert zm.compression == zipfile.ZIP_BZIP2
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_compression_maximum():
|
||||||
|
zm = ZipManager('maximum')
|
||||||
|
assert zm.compression == zipfile.ZIP_LZMA
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_compression_raises():
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
ZipManager('ultra')
|
||||||
Reference in New Issue
Block a user