363 lines
9.6 KiB
Lua
363 lines
9.6 KiB
Lua
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()
|
|
-- Ensure store is properly opened with filename
|
|
kv.close("test") -- Close if already open
|
|
assert(kv.open("test", "test_store.json"))
|
|
|
|
assert(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()
|