From 74bcd5ec71a36bdd194a13eff40c9cc2f41de4fa Mon Sep 17 00:00:00 2001 From: retoor Date: Thu, 24 Jul 2025 04:05:38 +0200 Subject: [PATCH] Added tests. --- ads.py | 212 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) diff --git a/ads.py b/ads.py index 209ce71..0a6ab27 100644 --- a/ads.py +++ b/ads.py @@ -177,6 +177,7 @@ class AsyncDataSet: args: Dict[str, Any], where: Optional[Dict[str, Any]] = None, ) -> str | None: + args['updated_at'] = str(datetime.now()) affected = await self.update(table, args, where) if affected: rec = await self.get(table, where) @@ -248,6 +249,7 @@ class AsyncDataSet: except Exception: return default +from typing import Any, Dict, Iterable, List, Optional, AsyncGenerator class TestAsyncDataSet(unittest.IsolatedAsyncioTestCase): @@ -282,6 +284,7 @@ class TestAsyncDataSet(unittest.IsolatedAsyncioTestCase): async def test_upsert_update(self): uid = await self.connector.upsert("people", {"age": 22}, {"name": "Alice"}) + await asyncio.sleep(2) uid_same = await self.connector.upsert("people", {"age": 23}, {"name": "Alice"}) self.assertEqual(uid_same, uid) rec = await self.connector.get("people", {"uid": uid}) @@ -327,6 +330,215 @@ class TestAsyncDataSet(unittest.IsolatedAsyncioTestCase): await self.connector.insert("binaries", {"data": b"1234"}) print(await self.connector.get("binaries", {"data": b"1234"})) + async def asyncSetUp(self): + self.db_path = Path("temp_test.db") + if self.db_path.exists(): + self.db_path.unlink() + self.connector = AsyncDataSet(str(self.db_path)) + + async def asyncTearDown(self): + if self.db_path.exists(): + self.db_path.unlink() + + async def test_insert_and_get(self): + await self.connector.insert("people", {"name": "John Doe", "age": 30}) + rec = await self.connector.get("people", {"name": "John Doe"}) + self.assertIsNotNone(rec) + self.assertEqual(rec["name"], "John Doe") + self.assertEqual(rec["age"], 30) + self.assertIsNotNone(rec["uid"]) + self.assertIsNotNone(rec["created_at"]) + self.assertIsNotNone(rec["updated_at"]) + self.assertIsNone(rec["deleted_at"]) + + async def test_get_nonexistent(self): + result = await self.connector.get("people", {"name": "Jane Doe"}) + self.assertIsNone(result) + + async def test_update(self): + await self.connector.insert("people", {"name": "John Doe", "age": 30}) + await self.connector.update("people", {"age": 31}, {"name": "John Doe"}) + rec = await self.connector.get("people", {"name": "John Doe"}) + self.assertEqual(rec["age"], 31) + self.assertNotEqual(rec["created_at"], rec["updated_at"]) + + async def test_upsert_insert(self): + uid = await self.connector.upsert("people", {"age": 22}, {"name": "Alice"}) + rec = await self.connector.get("people", {"uid": uid}) + self.assertEqual(rec["name"], "Alice") + self.assertEqual(rec["age"], 22) + self.assertIsNotNone(rec["uid"]) + self.assertIsNotNone(rec["created_at"]) + + async def test_upsert_update(self): + uid = await self.connector.upsert("people", {"age": 22}, {"name": "Alice"}) + await asyncio.sleep(2) + uid_same = await self.connector.upsert("people", {"age": 23}, {"name": "Alice"}) + self.assertEqual(uid_same, uid) + rec = await self.connector.get("people", {"uid": uid}) + self.assertEqual(rec["age"], 23) + self.assertNotEqual(rec["created_at"], rec["updated_at"]) + + async def test_count_and_exists(self): + await self.connector.insert("people", {"name": "John Doe", "age": 30}) + await self.connector.insert("people", {"name": "Alice", "age": 23}) + total = await self.connector.count("people") + self.assertEqual(total, 2) + self.assertTrue(await self.connector.exists("people", {"name": "Alice"})) + self.assertFalse(await self.connector.exists("people", {"name": "Nobody"})) + + async def test_find_pagination(self): + await self.connector.insert("people", {"name": "John Doe", "age": 30}) + await self.connector.insert("people", {"name": "Alice", "age": 23}) + rows = await self.connector.find("people", limit=1, offset=1) + self.assertEqual(len(rows), 1) + self.assertIn(rows[0]["name"], {"John Doe", "Alice"}) + + async def test_kv_set_and_get(self): + await self.connector.kv_set("config:threshold", {"limit": 10, "mode": "fast"}) + cfg = await self.connector.kv_get("config:threshold") + self.assertEqual(cfg, {"limit": 10, "mode": "fast"}) + + async def test_delete(self): + await self.connector.insert("people", {"name": "John Doe", "age": 30}) + await self.connector.insert("people", {"name": "Alice", "age": 23}) + await self.connector.delete("people", {"name": "John Doe"}) + self.assertIsNone(await self.connector.get("people", {"name": "John Doe"})) + count = await self.connector.count("people") + self.assertEqual(count, 1) + + async def test_insert_binary(self): + await self.connector.insert("binaries", {"data": b"1234"}) + rec = await self.connector.get("binaries", {"data": b"1234"}) + self.assertIsNotNone(rec) + self.assertEqual(rec["data"], b"1234") + + async def test_insert_multiple_types(self): + data = { + "name": "Test", + "age": 25, + "is_active": True, + "score": 98.5, + "data": b"test", + "metadata": None + } + await self.connector.insert("mixed", data) + rec = await self.connector.get("mixed", {"name": "Test"}) + self.assertEqual(rec["name"], "Test") + self.assertEqual(rec["age"], 25) + self.assertEqual(rec["is_active"], 1) + self.assertEqual(rec["score"], 98.5) + self.assertEqual(rec["data"], b"test") + self.assertIsNone(rec["metadata"]) + + async def test_update_nonexistent(self): + result = await self.connector.update("people", {"age": 40}, {"name": "Nobody"}) + self.assertEqual(result, 0) + + async def test_delete_nonexistent(self): + result = await self.connector.delete("people", {"name": "Nobody"}) + self.assertEqual(result, 0) + + async def test_kv_get_default(self): + result = await self.connector.kv_get("nonexistent_key", default="default") + self.assertEqual(result, "default") + + async def test_kv_set_custom_table(self): + await self.connector.kv_set("test_key", "test_value", table="custom_kv") + result = await self.connector.kv_get("test_key", table="custom_kv") + self.assertEqual(result, "test_value") + + async def test_find_empty_table(self): + result = await self.connector.find("empty_table") + self.assertEqual(result, []) + + async def test_count_empty_table(self): + result = await self.connector.count("empty_table") + self.assertEqual(result, 0) + + async def test_exists_empty_table(self): + result = await self.connector.exists("empty_table", {"name": "Test"}) + self.assertFalse(result) + + async def test_insert_duplicate_column_handling(self): + await self.connector.insert("people", {"name": "John", "age": 30}) + await self.connector.insert("people", {"name": "Jane", "age": 25}) + rec = await self.connector.get("people", {"name": "John"}) + self.assertEqual(rec["age"], 30) + + async def test_upsert_no_where(self): + uid = await self.connector.upsert("people", {"name": "Bob", "age": 40}) + rec = await self.connector.get("people", {"uid": uid}) + self.assertEqual(rec["name"], "Bob") + self.assertEqual(rec["age"], 40) + + async def test_find_with_where(self): + await self.connector.insert("people", {"name": "John", "age": 30}) + await self.connector.insert("people", {"name": "Jane", "age": 25}) + await self.connector.insert("people", {"name": "Bob", "age": 30}) + result = await self.connector.find("people", {"age": 30}) + self.assertEqual(len(result), 2) + names = {row["name"] for row in result} + self.assertEqual(names, {"John", "Bob"}) + + async def test_update_multiple_columns(self): + await self.connector.insert("people", {"name": "John", "age": 30, "city": "NY"}) + await self.connector.update("people", {"age": 31, "city": "LA"}, {"name": "John"}) + rec = await self.connector.get("people", {"name": "John"}) + self.assertEqual(rec["age"], 31) + self.assertEqual(rec["city"], "LA") + + async def test_insert_invalid_column_name(self): + await self.connector.insert("people", {"invalid column": "value"}) + + async def test_kv_set_complex_object(self): + complex_data = { + "numbers": [1, 2, 3], + "nested": {"a": 1, "b": {"c": 2}}, + "bool": True, + "null": None + } + await self.connector.kv_set("complex", complex_data) + result = await self.connector.kv_get("complex") + self.assertEqual(result, complex_data) + + async def test_concurrent_operations(self): + async def insert_task(name, age): + await self.connector.insert("people", {"name": name, "age": age}) + + tasks = [ + insert_task(f"Person_{i}", 20 + i) for i in range(5) + ] + await asyncio.gather(*tasks) + count = await self.connector.count("people") + self.assertEqual(count, 5) + + async def test_column_type_preservation(self): + data = {"name": "Test", "number": 42, "float": 3.14, "bool": True} + await self.connector.insert("types", data) + rec = await self.connector.get("types", {"name": "Test"}) + self.assertIsInstance(rec["number"], int) + self.assertIsInstance(rec["float"], float) + self.assertIsInstance(rec["bool"], int) # SQLite stores bool as int + self.assertEqual(rec["bool"], 1) + + async def test_empty_update(self): + await self.connector.insert("people", {"name": "John", "age": 30}) + result = await self.connector.update("people", {}, {"name": "John"}) + self.assertEqual(result, 0) + + async def test_find_with_zero_limit(self): + await self.connector.insert("people", {"name": "John", "age": 30}) + result = await self.connector.find("people", limit=0) + self.assertEqual(len(result), 1) + + async def test_upsert_empty_args(self): + with self.assertRaises(ValueError): + await self.connector.upsert("people", {}, {"name": "John"}) + + async def test_invalid_table_name(self): + with self.assertRaises(aiosqlite.OperationalError): + await self.connector.insert("invalid table name", {"name": "John"}) if __name__ == "__main__": unittest.main()