require("tests") local kv = require("kv") -- Clean up any existing test files os.remove("test_store.json") os.remove("test_store.txt") os.remove("test_oop.json") os.remove("test_temp.json") -- ====================================================================== -- BASIC OPERATIONS -- ====================================================================== test("Store creation and opening", function() assert(kv.open("test", "test_store.json")) assert(kv.open("memory_only", "")) assert(not kv.open("", "test.json")) -- Empty name should fail end) test("Set and get operations", function() assert(kv.set("test", "key1", "value1")) assert_equal("value1", kv.get("test", "key1")) assert_equal("default", kv.get("test", "nonexistent", "default")) assert_equal(nil, kv.get("test", "nonexistent")) -- Test with special characters assert(kv.set("test", "special:key", "value with spaces & symbols!")) assert_equal("value with spaces & symbols!", kv.get("test", "special:key")) end) test("Key existence and deletion", function() kv.set("test", "temp_key", "temp_value") assert(kv.has("test", "temp_key")) assert(not kv.has("test", "missing_key")) assert(kv.delete("test", "temp_key")) assert(not kv.has("test", "temp_key")) assert(not kv.delete("test", "missing_key")) end) test("Store size tracking", function() kv.clear("test") assert_equal(0, kv.size("test")) kv.set("test", "k1", "v1") kv.set("test", "k2", "v2") kv.set("test", "k3", "v3") assert_equal(3, kv.size("test")) kv.delete("test", "k2") assert_equal(2, kv.size("test")) end) test("Keys and values retrieval", function() kv.clear("test") kv.set("test", "a", "apple") kv.set("test", "b", "banana") kv.set("test", "c", "cherry") local keys = kv.keys("test") local values = kv.values("test") assert_equal(3, #keys) assert_equal(3, #values) -- Check all keys exist local key_set = {} for _, k in ipairs(keys) do key_set[k] = true end assert(key_set["a"] and key_set["b"] and key_set["c"]) -- Check all values exist local value_set = {} for _, v in ipairs(values) do value_set[v] = true end assert(value_set["apple"] and value_set["banana"] and value_set["cherry"]) end) test("Clear store", function() kv.set("test", "temp1", "value1") kv.set("test", "temp2", "value2") assert(kv.size("test") > 0) assert(kv.clear("test")) assert_equal(0, kv.size("test")) assert(not kv.has("test", "temp1")) end) test("Save and close operations", function() kv.set("test", "persistent", "data") assert(kv.save("test")) assert(kv.close("test")) -- Reopen and verify data persists assert(kv.open("test", "test_store.json")) assert_equal("data", kv.get("test", "persistent")) end) test("Invalid store operations", function() assert(not kv.set("nonexistent", "key", "value")) assert_equal(nil, kv.get("nonexistent", "key")) assert(not kv.has("nonexistent", "key")) assert_equal(0, kv.size("nonexistent")) assert(not kv.delete("nonexistent", "key")) assert(not kv.clear("nonexistent")) assert(not kv.save("nonexistent")) assert(not kv.close("nonexistent")) end) -- ====================================================================== -- OBJECT-ORIENTED INTERFACE -- ====================================================================== test("OOP store creation", function() local store = kv.create("oop_test", "test_oop.json") assert_equal("oop_test", store.name) local memory_store = kv.create("memory_oop") assert_equal("memory_oop", memory_store.name) end) test("OOP basic operations", function() local store = kv.create("oop_basic") assert(store:set("foo", "bar")) assert_equal("bar", store:get("foo")) assert_equal("default", store:get("missing", "default")) assert(store:has("foo")) assert(not store:has("missing")) assert_equal(1, store:size()) assert(store:delete("foo")) assert(not store:has("foo")) assert_equal(0, store:size()) end) test("OOP collections", function() local store = kv.create("oop_collections") store:set("a", "apple") store:set("b", "banana") store:set("c", "cherry") local keys = store:keys() local values = store:values() assert_equal(3, #keys) assert_equal(3, #values) store:clear() assert_equal(0, store:size()) store:close() end) -- ====================================================================== -- UTILITY FUNCTIONS -- ====================================================================== test("Increment operations", function() kv.open("util_test") -- Increment non-existent key assert_equal(1, kv.increment("util_test", "counter")) assert_equal("1", kv.get("util_test", "counter")) -- Increment existing key assert_equal(6, kv.increment("util_test", "counter", 5)) assert_equal("6", kv.get("util_test", "counter")) -- Decrement assert_equal(4, kv.increment("util_test", "counter", -2)) kv.close("util_test") end) test("Append operations", function() kv.open("append_test") -- Append to non-existent key assert(kv.append("append_test", "list", "first")) assert_equal("first", kv.get("append_test", "list")) -- Append with separator assert(kv.append("append_test", "list", "second", ",")) assert_equal("first,second", kv.get("append_test", "list")) assert(kv.append("append_test", "list", "third", ",")) assert_equal("first,second,third", kv.get("append_test", "list")) kv.close("append_test") end) test("TTL and expiration", function() kv.open("ttl_test", "test_temp.json") kv.set("ttl_test", "temp_key", "temp_value") assert(kv.expire("ttl_test", "temp_key", 1)) -- 1 second TTL -- Key should still exist immediately assert(kv.has("ttl_test", "temp_key")) -- Wait for expiration os.execute("sleep 2") local expired = kv.cleanup_expired("ttl_test") assert(expired >= 1) -- Key should be gone assert(not kv.has("ttl_test", "temp_key")) kv.close("ttl_test") end) -- ====================================================================== -- FILE FORMAT TESTS -- ====================================================================== test("JSON file format", function() kv.open("json_test", "test.json") kv.set("json_test", "key1", "value1") kv.set("json_test", "key2", "value2") kv.save("json_test") kv.close("json_test") -- Verify file exists and reload assert(file_exists("test.json")) kv.open("json_test", "test.json") assert_equal("value1", kv.get("json_test", "key1")) assert_equal("value2", kv.get("json_test", "key2")) kv.close("json_test") os.remove("test.json") end) test("Text file format", function() kv.open("txt_test", "test.txt") kv.set("txt_test", "setting1", "value1") kv.set("txt_test", "setting2", "value2") kv.save("txt_test") kv.close("txt_test") -- Verify file exists and reload assert(file_exists("test.txt")) kv.open("txt_test", "test.txt") assert_equal("value1", kv.get("txt_test", "setting1")) assert_equal("value2", kv.get("txt_test", "setting2")) kv.close("txt_test") os.remove("test.txt") end) -- ====================================================================== -- EDGE CASES AND ERROR HANDLING -- ====================================================================== test("Empty values and keys", function() kv.open("edge_test") -- Empty value assert(kv.set("edge_test", "empty", "")) assert_equal("", kv.get("edge_test", "empty")) -- Unicode keys and values assert(kv.set("edge_test", "ключ", "значение")) assert_equal("значение", kv.get("edge_test", "ключ")) kv.close("edge_test") end) test("Special characters in data", function() kv.open("special_test") local special_value = 'Special chars: "quotes", \'apostrophes\', \n newlines, \t tabs, \\ backslashes' assert(kv.set("special_test", "special", special_value)) assert_equal(special_value, kv.get("special_test", "special")) kv.close("special_test") end) test("Large data handling", function() kv.open("large_test") -- Large value local large_value = string.rep("x", 10000) assert(kv.set("large_test", "large", large_value)) assert_equal(large_value, kv.get("large_test", "large")) -- Many keys for i = 1, 100 do kv.set("large_test", "key" .. i, "value" .. i) end assert_equal(101, kv.size("large_test")) -- 100 + 1 large value kv.close("large_test") end) -- ====================================================================== -- PERFORMANCE TESTS -- ====================================================================== test("Performance test", function() kv.open("perf_test") local start = os.clock() -- Bulk insert for i = 1, 1000 do kv.set("perf_test", "key" .. i, "value" .. i) end local insert_time = os.clock() - start -- Bulk read start = os.clock() for i = 1, 1000 do local value = kv.get("perf_test", "key" .. i) assert_equal("value" .. i, value) end local read_time = os.clock() - start -- Check final size assert_equal(1000, kv.size("perf_test")) print(string.format(" Insert 1000 items: %.3fs", insert_time)) print(string.format(" Read 1000 items: %.3fs", read_time)) kv.close("perf_test") end) -- ====================================================================== -- INTEGRATION TESTS -- ====================================================================== test("Multiple store integration", function() local users = kv.create("users_int") local cache = kv.create("cache_int") -- Simulate user data users:set("user:123", "john_doe") cache:set("user:123:last_seen", tostring(os.time())) -- Verify data in stores assert_equal("john_doe", users:get("user:123")) assert(cache:has("user:123:last_seen")) -- Clean up users:close() cache:close() end) -- Clean up test files --os.remove("test_store.json") --os.remove("test_oop.json") --os.remove("test_temp.json") summary() test_exit()