mirror of
https://github.com/borgbase/vorta
synced 2024-12-23 08:17:08 +00:00
b015368fee
Move existing tests into subfolder `tests/unit`. Write integration tests that actually run the installed borg executable. Those tests can be found in `tests/integration`. Those pytest fixtures that are the same for both kinds of tests remain in `tests/conftest.py`. The others can be found in `tests/integration/conftest.py` or `tests/unit/conftest.py`. This adds nox to the project and configures it to run the tests with different borg versions. This also updates the ci workflow to run the integration tests using nox. * noxfile.py : Run pytest with a matrix of borg versions OR a specific borg version * Makefile : Run using nox. Add phonies `test-unit` and `test-integration`. * tests/conftest.py : Move some fixtures/functions to `tests/unit/conftest.py`. * tests/test_*.py --> tests/unit/ : Move unittests and assets into subfolder * tests/integration/ : Write integration tests. * requirements.d/dev.txt: Add `nox` and `pkgconfig`. The latter is needed for installing new borg versions. * .github/actions/setup/action.yml : Update to install pre-commit and nox when needed. The action now no longer installs Vorta. * .github/actions/install-dependencies/action.yml : Install system deps of borg with this new composite action. * .github/workflows/test.yml : Rename `test` ci to `test-unit` and update it for the new test setup. Implement `test-integration` ci. Signed-off-by: Chirag Aggarwal <thechiragaggarwal@gmail.com>
350 lines
11 KiB
Python
350 lines
11 KiB
Python
from pathlib import PurePath
|
|
|
|
import pytest
|
|
from PyQt6.QtCore import QModelIndex
|
|
from vorta.views.partials.treemodel import FileSystemItem, FileTreeModel
|
|
|
|
|
|
class TreeModelImp(FileTreeModel):
|
|
def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
|
|
return 1
|
|
|
|
def _make_filesystemitem(self, path, data):
|
|
return super()._make_filesystemitem(path, data)
|
|
|
|
def _merge_data(self, item, data):
|
|
return super()._merge_data(item, data)
|
|
|
|
|
|
class TestFileSystemItem:
|
|
def test_tuple(self):
|
|
item = FileSystemItem(PurePath('test').parts, 0)
|
|
|
|
assert item[0] == item.path
|
|
assert item[1] == item.data
|
|
|
|
def test_add(self):
|
|
item = FileSystemItem(PurePath('test').parts, 0)
|
|
|
|
assert len(item.children) == 0
|
|
|
|
child = FileSystemItem(PurePath('test/hello').parts, 4)
|
|
|
|
item.add(child)
|
|
|
|
assert len(item.children) == 1
|
|
assert item.children[0] == child
|
|
assert child.subpath == 'hello'
|
|
assert child._parent == item
|
|
|
|
child = FileSystemItem(PurePath('test/hello').parts, 8)
|
|
with pytest.raises(RuntimeError):
|
|
# may not add a child with the same subpath
|
|
item.add(child)
|
|
|
|
# not implemented due to performance reasons:
|
|
# child = FileSystemItem((), 8)
|
|
# with pytest.raises(ValueError):
|
|
# item.add(child) # may not add a child with an empty path
|
|
|
|
def test_remove(self):
|
|
item = FileSystemItem(PurePath('test').parts, 0)
|
|
child1 = FileSystemItem(PurePath('test/a').parts, 4)
|
|
child2 = FileSystemItem(PurePath('test/b').parts, 3)
|
|
child3 = FileSystemItem(PurePath('test/c').parts, 2)
|
|
|
|
item.add(child1)
|
|
item.add(child2)
|
|
item.add(child3)
|
|
|
|
assert len(item.children) == 3
|
|
|
|
# test remove subpath
|
|
item.remove('b')
|
|
assert len(item.children) == 2
|
|
assert child2 not in item.children
|
|
|
|
# test remove item
|
|
item.remove(child3)
|
|
assert len(item.children) == 1
|
|
assert child3 not in item.children
|
|
|
|
# test remove item not present
|
|
child = FileSystemItem(PurePath('notpresent').parts, 2)
|
|
with pytest.raises(ValueError):
|
|
item.remove(child)
|
|
child = FileSystemItem((), 2)
|
|
with pytest.raises(ValueError):
|
|
item.remove(child)
|
|
|
|
def test_get(self):
|
|
item = FileSystemItem(PurePath('test').parts, 0)
|
|
child1 = FileSystemItem(PurePath('test/a').parts, 4)
|
|
child2 = FileSystemItem(PurePath('test/b').parts, 3)
|
|
child3 = FileSystemItem(PurePath('test/c').parts, 2)
|
|
|
|
item.add(child1)
|
|
item.add(child2)
|
|
item.add(child3)
|
|
|
|
# test get inexistent subpath
|
|
assert item.get('unknown') is None
|
|
assert item.get('unknown', default='default') == 'default'
|
|
|
|
# get subpath
|
|
res = item.get('a')
|
|
assert res is not None
|
|
assert res[1] == child1
|
|
|
|
res = item.get('b')
|
|
assert res is not None
|
|
assert res[1] == child2
|
|
|
|
# get subpath of empty list
|
|
assert child1.get('a') is None
|
|
|
|
def test_get_subpath(self):
|
|
item = FileSystemItem(('test',), 0)
|
|
child1 = FileSystemItem(PurePath('test/a').parts, 4)
|
|
child2 = FileSystemItem(PurePath('test/b').parts, 3)
|
|
child3 = FileSystemItem(PurePath('test/c').parts, 2)
|
|
|
|
item.add(child1)
|
|
item.add(child2)
|
|
item.add(child3)
|
|
|
|
child11 = FileSystemItem(PurePath('test/a/aa').parts, 4)
|
|
child1.add(child11)
|
|
|
|
assert item.get_path(PurePath('a/aa').parts) is child11
|
|
assert item.get_path(('b',)) is child2
|
|
|
|
# test get empty path
|
|
assert item.get_path(()) is item
|
|
|
|
|
|
class TestFileTreeModel:
|
|
def test_basic_setup(self):
|
|
model = TreeModelImp()
|
|
|
|
assert model.rowCount() == 0
|
|
|
|
# test FileTreeModel.addItem
|
|
model.addItem((('test',), 0))
|
|
assert model.rowCount() == 1
|
|
|
|
item = model.getItem(('test',))
|
|
assert item is not None
|
|
assert item.subpath == 'test'
|
|
assert len(item.children) == 0
|
|
assert item.data == 0 # test id
|
|
|
|
model.addItem((PurePath('/hello'), 1))
|
|
model.addItem(FileSystemItem(PurePath('/hello/test').parts, 2))
|
|
|
|
assert model.rowCount() == 2
|
|
|
|
item = model.getItem(('/',))
|
|
assert item is not None
|
|
assert item.subpath == '/'
|
|
assert len(item.children) == 1
|
|
|
|
item = model.getItem(PurePath('/hello/test').parts)
|
|
assert item is not None and item.data == 2
|
|
|
|
# test adding Item to existing parent
|
|
model.addItem((PurePath('test/subtest'), 3))
|
|
assert model.rowCount() == 2
|
|
item = model.getItem(PurePath('test/subtest').parts)
|
|
assert item is not None and item.data == 3
|
|
|
|
# test parent
|
|
assert model.parent(model.indexPath(PurePath('test/subtest'))) == model.indexPath(PurePath('test'))
|
|
|
|
# test index
|
|
item1 = model.getItem(('test',))
|
|
item2 = model.getItem(PurePath('test/subtest'))
|
|
|
|
index1 = model.index(1, 0)
|
|
assert index1.internalPointer() == item1
|
|
assert index1 == model.indexPath(PurePath('test'))
|
|
index2 = model.index(0, 0, index1)
|
|
assert index2.internalPointer() == item2
|
|
assert index2 == model.indexPath(PurePath('test/subtest'))
|
|
|
|
# test rowCount
|
|
assert model.rowCount() == 2
|
|
assert model.rowCount(index1) == 1
|
|
|
|
# test remove
|
|
model.removeItem(('test',))
|
|
assert model.rowCount() == 1
|
|
assert item1 not in model.root.children
|
|
|
|
model.removeItem(PurePath('/hello/test').parts)
|
|
assert model.rowCount() == 1
|
|
assert model.getItem(PurePath('/hello/test')) is None
|
|
item3 = model.getItem(PurePath('/hello'))
|
|
assert len(item3.children) == 0
|
|
|
|
def test_empty_path(self):
|
|
model = TreeModelImp()
|
|
assert model.rowCount() == 0
|
|
|
|
model.addItem(((), None))
|
|
assert model.rowCount() == 0
|
|
|
|
model.addItem((PurePath('.'), None))
|
|
assert model.rowCount() == 0
|
|
|
|
def test_root(self):
|
|
model = TreeModelImp()
|
|
assert model.getItem(PurePath()) == model.root
|
|
|
|
def test_flat(self):
|
|
items = [
|
|
(PurePath('a'), 0),
|
|
(PurePath('a/a'), 1),
|
|
(PurePath('a/c'), 3),
|
|
(PurePath('a/b/a'), 4),
|
|
(PurePath('a/b/b'), 5),
|
|
(PurePath('a/b'), 2),
|
|
(PurePath('b'), 6),
|
|
(PurePath('b/a'), 7),
|
|
(PurePath('b/b'), 8),
|
|
]
|
|
|
|
model = TreeModelImp()
|
|
model.addItems(items)
|
|
|
|
# test flat representation
|
|
model.setMode(model.DisplayMode.FLAT)
|
|
|
|
assert model.rowCount() == len(items)
|
|
assert model.parent(model.index(4, 0)) == QModelIndex()
|
|
assert model.rowCount(model.index(3, 0)) == 0
|
|
|
|
item = model.getItem(PurePath('a/b/a'))
|
|
assert item is not None and item.data == 4
|
|
|
|
# test flat add
|
|
model.addItem((PurePath('a/a/a'), 10))
|
|
|
|
assert model.rowCount() == len(items) + 1
|
|
item = model.getItem(PurePath('a/a/a'))
|
|
assert item is not None and item.data == 10
|
|
|
|
# test flat remove
|
|
model.removeItem(PurePath('a/a/a'))
|
|
|
|
assert model.rowCount() == len(items)
|
|
assert item not in model._flattened
|
|
|
|
# test flat indexPath
|
|
index = model.indexPath(PurePath('a/b'))
|
|
assert index.internalPointer().data == 2
|
|
assert model._flattened[index.row()].data == 2
|
|
assert index.parent() == QModelIndex()
|
|
|
|
# test
|
|
model.setMode(model.DisplayMode.TREE)
|
|
|
|
assert model.rowCount() == 2
|
|
|
|
def test_simplified_tree(self):
|
|
items = [
|
|
(PurePath('a'), 0),
|
|
(PurePath('a/a'), 1),
|
|
(PurePath('a/c'), 3),
|
|
(PurePath('a/b/a'), 4),
|
|
(PurePath('a/b/b'), 5),
|
|
(PurePath('a/b'), 2),
|
|
(PurePath('b'), 6),
|
|
(PurePath('b/a'), 7),
|
|
(PurePath('b/b'), 8),
|
|
(PurePath('c'), 9),
|
|
(PurePath('c/a'), 10),
|
|
(PurePath('c/a/b'), 11),
|
|
(PurePath('c/a/b/c'), 12),
|
|
(PurePath('c/a/b/a'), 13),
|
|
(PurePath('c/a/b/a/b/c'), 14),
|
|
(PurePath('c/a/b/b/c/a'), 15),
|
|
]
|
|
|
|
model = TreeModelImp()
|
|
model.addItems(items)
|
|
|
|
# test tree representation
|
|
model.setMode(model.DisplayMode.SIMPLIFIED_TREE)
|
|
|
|
assert model.rowCount() == 3
|
|
|
|
a = model.index(0, 0)
|
|
assert model.rowCount(a) == 3
|
|
ab = model.index(1, 0, a)
|
|
assert model.rowCount(ab) == 2
|
|
assert model.parent(ab) == a
|
|
|
|
# test combined representation
|
|
|
|
cab = model.index(2, 0)
|
|
assert model.rowCount(cab) == 3
|
|
assert cab.internalPointer().data == 11
|
|
assert model.rowCount(cab) == 3
|
|
assert model.parent(cab) == QModelIndex()
|
|
cabc = model.index(2, 0, cab)
|
|
cababc = model.index(0, 0, cab)
|
|
cabbca = model.index(1, 0, cab)
|
|
assert cababc.internalPointer().data == 14
|
|
assert model.parent(cababc).internalId() == cab.internalId()
|
|
assert cabbca.internalPointer().data == 15
|
|
assert model.parent(cabbca).internalId() == cab.internalId()
|
|
assert cabc.internalPointer().data == 12
|
|
|
|
# test combined add
|
|
model.addItem((PurePath('a/a/a'), 30))
|
|
|
|
aaa = model.index(0, 0, a)
|
|
assert aaa.internalPointer().data == 30
|
|
assert model.rowCount(aaa) == 0
|
|
|
|
model.addItem((PurePath('c/a/a'), 31))
|
|
|
|
ca = model.index(2, 0)
|
|
assert ca.internalPointer().data == 10
|
|
assert ca.parent() == QModelIndex()
|
|
assert model.rowCount(ca) == 2
|
|
caa = model.index(0, 0, ca)
|
|
assert caa.internalPointer().data == 31
|
|
assert caa.parent().internalId() == ca.internalId()
|
|
|
|
# test combined remove
|
|
model.removeItem(PurePath('a/a/a').parts)
|
|
|
|
aa = model.index(0, 0, a)
|
|
assert aa.internalPointer().data == 1
|
|
assert model.rowCount(aa) == 0
|
|
|
|
model.removeItem(PurePath('c/a/a'))
|
|
|
|
cab = model.index(2, 0)
|
|
assert cab.internalPointer().data == 11
|
|
assert model.rowCount(cab) == 3
|
|
|
|
# test combined indexPath
|
|
index = model.indexPath(PurePath('a/b'))
|
|
assert index.internalPointer().data == 2
|
|
assert index.parent() == a
|
|
|
|
index = model.indexPath(PurePath('c/a/b'))
|
|
assert model.parent(index) == QModelIndex()
|
|
assert index.internalPointer().data == 11
|
|
assert model.rowCount(index) == 3
|
|
|
|
index = model.indexPath(PurePath('c/a'))
|
|
assert index == QModelIndex()
|
|
|
|
# test mode change
|
|
model.setMode(model.DisplayMode.TREE)
|
|
|
|
assert model.rowCount() == 3
|