Moonshark/tests/kv.lua

359 lines
9.5 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()
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()