from pathlib import Path import pytest from pca.data.predicate import where from pca.data.errors import QueryError, QueryErrors from pca.integration.errors import ConfigError, IntegrationErrors from pca.integration.tinydb import TinyDbDao @pytest.fixture(scope="session", autouse=True) def tinydb(): return pytest.importorskip("tinydb") class TestConstruction: @pytest.fixture def path(self, tmpdir): return str(tmpdir.join('db.json')) @pytest.fixture def json_dao(self, mock_container, path): dao = TinyDbDao(mock_container, path=path, table_name='table_name') yield dao dao.clear_db_cache() def test_path(self, path, json_dao: TinyDbDao): assert json_dao._path == path assert Path(path).is_file() @pytest.mark.skip("TODO #73") def test_implicit_json_storage(self, json_dao, tinydb): assert isinstance(json_dao._table._storage._storage, tinydb.storages.JSONStorage) @pytest.mark.skip("TODO #73") def test_implicit_memory_storage(self, mock_container, tinydb): dao = TinyDbDao(mock_container, table_name='table_name') assert isinstance(dao._table._storage._storage, tinydb.storages.MemoryStorage) def test_db_cache(self, mock_container, path, json_dao: TinyDbDao): cache = TinyDbDao._db_cache assert cache.get(path) is json_dao._db second_dao = TinyDbDao(mock_container, path=path, table_name='another_table') assert second_dao._db is json_dao._db def test_no_table_name(self, mock_container): with pytest.raises(ConfigError) as error_info: TinyDbDao(mock_container) assert error_info.value == IntegrationErrors.NO_TABLE_NAME_PROVIDED pred_a = where('char') == 'a' pred_not_a = ~(where('char') == 'a') pred_c = where('char') == 'c' pred_z = where('char') == 'z' class TestApi: @pytest.fixture def dao(self, mock_container): """ In-memory table that has three documents pre-assigned: {'char': 'a', 'is_a': True}, {'char': 'b', 'is_a': False}, {'char': 'c', 'is_a': False} """ dao = TinyDbDao(mock_container, table_name='table_name') dao.batch_insert([ {'char': c, 'is_a': c == 'a'} for c in 'abc' ]) return dao # Dao.all def test_all(self, dao: TinyDbDao): assert list(dao.all()) == [ {'char': 'a', 'is_a': True}, {'char': 'b', 'is_a': False}, {'char': 'c', 'is_a': False}, ] # QueryChain.filter def test_multiple_filter_success(self, dao: TinyDbDao): assert list(dao.filter(pred_not_a).filter(pred_c)) == [ {'char': 'c', 'is_a': False} ] # QueryChain.filter_by def test_filter_by_success(self, dao: TinyDbDao): not_a = pred_not_a assert list(dao.filter(not_a).filter_by(id_=3)) == [{'char': 'c', 'is_a': False}] def test_filter_by_both_arguments_error(self, dao: TinyDbDao): with pytest.raises(QueryError) as error_info: assert dao.all().filter_by(id_=3, ids=[3, 5]) assert error_info.value == QueryErrors.CONFLICTING_QUERY_ARGUMENTS def test_filter_by_two_times_error(self, dao: TinyDbDao): with pytest.raises(QueryError) as error_info: assert dao.all().filter_by(id_=3).filter_by(id_=5) assert error_info.value == QueryErrors.CONFLICTING_QUERY_ARGUMENTS # QueryChain.get def test_get_success(self, dao: TinyDbDao): assert dao.get(1) == {'char': 'a', 'is_a': True} def test_get_fail(self, dao: TinyDbDao): assert dao.get(42) is None def test_filtered_get_success(self, dao: TinyDbDao): object_2 = dao.get(2) assert dao.filter(pred_not_a).get(2) == object_2 def test_filtered_get_fail(self, dao: TinyDbDao): assert dao.filter(pred_not_a).get(1) is None # QueryChain.exists def test_exists_all_success(self, dao: TinyDbDao): assert dao.all().exists() @pytest.mark.skip("TODO #73") def test_exists_empty_fail(self, dao: TinyDbDao): dao.clear() assert not dao.all().exists() def test_exists_filtered_success(self, dao: TinyDbDao): assert dao.filter(pred_c).exists() def test_exists_filtered_fail(self, dao: TinyDbDao): assert not dao.filter(pred_z).exists() # QueryChain.count def test_count_all(self, dao: TinyDbDao): assert dao.all().count() == 3 def test_filtered_count(self, dao: TinyDbDao): assert dao.filter(pred_not_a).count() == 2 # QueryChain.update def test_update_all(self, dao: TinyDbDao): ids = dao.all().update(char='z') assert ids == [1, 2, 3] assert list(dao.all()) == [ {'char': 'z', 'is_a': True}, {'char': 'z', 'is_a': False}, {'char': 'z', 'is_a': False}, ] def test_update_filtered(self, dao: TinyDbDao): ids = dao.filter(pred_not_a).update(char='z') assert ids == [2, 3] assert list(dao.all()) == [ {'char': 'a', 'is_a': True}, {'char': 'z', 'is_a': False}, {'char': 'z', 'is_a': False}, ] def test_update_filtered_by_id(self, dao: TinyDbDao): ids = dao.filter(pred_not_a).filter_by(id_=2).update(char='z') assert ids == [2] assert list(dao.all()) == [ {'char': 'a', 'is_a': True}, {'char': 'z', 'is_a': False}, {'char': 'c', 'is_a': False}, ] def test_update_none(self, dao: TinyDbDao): ids = dao.filter(pred_z).update(char='z') assert ids == [] assert list(dao.all()) == [ {'char': 'a', 'is_a': True}, {'char': 'b', 'is_a': False}, {'char': 'c', 'is_a': False}, ] # QueryChain.remove def test_remove_all_error(self, dao: TinyDbDao): with pytest.raises(QueryError) as error_info: dao.all().remove() assert error_info.value == QueryErrors.UNRESTRICTED_REMOVE def test_remove_filtered(self, dao: TinyDbDao): ids = dao.filter(pred_a).remove() assert ids == [1] assert list(dao.all()) == [ {'char': 'b', 'is_a': False}, {'char': 'c', 'is_a': False}, ] def test_remove_filtered_by_id(self, dao: TinyDbDao): ids = dao.filter(pred_not_a).filter_by(id_=2).remove() assert ids == [2] assert list(dao.all()) == [ {'char': 'a', 'is_a': True}, {'char': 'c', 'is_a': False}, ] def test_remove_none(self, dao: TinyDbDao): ids = dao.filter(pred_z).remove() assert ids == [] assert list(dao.all()) == [ {'char': 'a', 'is_a': True}, {'char': 'b', 'is_a': False}, {'char': 'c', 'is_a': False}, ] # Dao.filter_by def test_dao_filter_by_success(self, dao: TinyDbDao): assert list(dao.filter_by(id_=3)) == [{'char': 'c', 'is_a': False}] def test_dao_filter_by_both_arguments_error(self, dao: TinyDbDao): with pytest.raises(QueryError) as error_info: assert dao.filter_by(id_=3, ids=[3, 5]) assert error_info.value == QueryErrors.CONFLICTING_QUERY_ARGUMENTS def test_dao_filter_by_two_times_error(self, dao: TinyDbDao): with pytest.raises(QueryError) as error_info: assert dao.filter_by(id_=3).filter_by(id_=5) assert error_info.value == QueryErrors.CONFLICTING_QUERY_ARGUMENTS # Dao.insert def test_insert(self, dao: TinyDbDao): id_ = dao.insert(foo='bar') assert id_ == 4 # Dao.batch_insert def test_batch_insert(self, dao: TinyDbDao): batch = [{'foo': 'bar'}, {'foo': 'baz'}] result = dao.batch_insert(batch) assert result == (4, 5) assert list(dao.filter(where('foo').exists())) == batch # Dao.clear @pytest.mark.skip("TODO #73") def test_clear(self, dao: TinyDbDao): dao.clear() assert list(dao.all()) == []