Moonshark/tests/table.lua
2025-07-25 09:43:57 -05:00

912 lines
28 KiB
Lua

require("tests")
-- Test data
local simple_array = {1, 2, 3, 4, 5}
local simple_table = {a = 1, b = 2, c = 3}
local mixed_table = {1, 2, a = "hello", b = "world"}
local nested_table = {
a = {x = 1, y = 2},
b = {x = 3, y = 4},
c = {1, 2, 3}
}
-- ======================================================================
-- BUILT-IN TABLE FUNCTIONS
-- ======================================================================
test("Table Insert Operations", function()
local t = {1, 2, 3}
table.insert(t, 4)
assert_equal(4, #t)
assert_equal(4, t[4])
table.insert(t, 2, "inserted")
assert_equal(5, #t)
assert_equal("inserted", t[2])
assert_equal(2, t[3])
end)
test("Table Remove Operations", function()
local t = {1, 2, 3, 4, 5}
local removed = table.remove(t)
assert_equal(5, removed)
assert_equal(4, #t)
removed = table.remove(t, 2)
assert_equal(2, removed)
assert_equal(3, #t)
assert_equal(3, t[2])
end)
test("Table Concat", function()
local t = {"hello", "world", "test"}
assert_equal("helloworldtest", table.concat(t))
assert_equal("hello,world,test", table.concat(t, ","))
assert_equal("world,test", table.concat(t, ",", 2))
assert_equal("world", table.concat(t, ",", 2, 2))
end)
test("Table Sort", function()
local t = {3, 1, 4, 1, 5}
table.sort(t)
assert_table_equal({1, 1, 3, 4, 5}, t)
local t2 = {"c", "a", "b"}
table.sort(t2)
assert_table_equal({"a", "b", "c"}, t2)
local t3 = {3, 1, 4, 1, 5}
table.sort(t3, function(a, b) return a > b end)
assert_table_equal({5, 4, 3, 1, 1}, t3)
end)
-- ======================================================================
-- BASIC TABLE OPERATIONS
-- ======================================================================
test("Table Length and Size", function()
assert_equal(5, table.length(simple_array))
assert_equal(0, table.length({}))
assert_equal(3, table.size(simple_table))
assert_equal(4, table.size(mixed_table))
assert_equal(0, table.size({}))
end)
test("Table Empty Check", function()
assert_equal(true, table.is_empty({}))
assert_equal(false, table.is_empty(simple_array))
assert_equal(false, table.is_empty(simple_table))
end)
test("Table Array Check", function()
assert_equal(true, table.is_array(simple_array))
assert_equal(true, table.is_array({}))
assert_equal(false, table.is_array(simple_table))
assert_equal(false, table.is_array(mixed_table))
assert_equal(true, table.is_array({1, 2, 3}))
assert_equal(false, table.is_array({1, 2, nil, 4}))
assert_equal(false, table.is_array({[0] = 1, [1] = 2}))
end)
test("Table Clear", function()
local t = table.clone(simple_table)
table.clear(t)
assert_equal(true, table.is_empty(t))
end)
test("Table Clone", function()
local cloned = table.clone(simple_table)
assert_table_equal(simple_table, cloned)
-- Modify original shouldn't affect clone
simple_table.new_key = "test"
assert_equal(nil, cloned.new_key)
simple_table.new_key = nil
end)
test("Table Deep Copy", function()
local copied = table.deep_copy(nested_table)
assert_table_equal(nested_table, copied)
-- Modify nested part shouldn't affect copy
nested_table.a.z = 99
assert_equal(nil, copied.a.z)
nested_table.a.z = nil
end)
-- ======================================================================
-- SEARCHING AND FINDING
-- ======================================================================
test("Table Contains", function()
assert_equal(true, table.contains(simple_array, 3))
assert_equal(false, table.contains(simple_array, 6))
assert_equal(true, table.contains(simple_table, 2))
assert_equal(false, table.contains(simple_table, "hello"))
end)
test("Table Index Of", function()
assert_equal(3, table.index_of(simple_array, 3))
assert_equal(nil, table.index_of(simple_array, 6))
assert_equal("b", table.index_of(simple_table, 2))
assert_equal(nil, table.index_of(simple_table, "hello"))
end)
test("Table Find", function()
local value, key = table.find(simple_array, function(v) return v > 3 end)
assert_equal(4, value)
assert_equal(4, key)
local value2, key2 = table.find(simple_table, function(v, k) return k == "b" end)
assert_equal(2, value2)
assert_equal("b", key2)
local value3 = table.find(simple_array, function(v) return v > 10 end)
assert_equal(nil, value3)
end)
test("Table Find Index", function()
local idx = table.find_index(simple_array, function(v) return v > 3 end)
assert_equal(4, idx)
local idx2 = table.find_index(simple_table, function(v, k) return k == "c" end)
assert_equal("c", idx2)
local idx3 = table.find_index(simple_array, function(v) return v > 10 end)
assert_equal(nil, idx3)
end)
test("Table Count", function()
local arr = {1, 2, 3, 2, 4, 2}
assert_equal(3, table.count(arr, 2))
assert_equal(0, table.count(arr, 5))
assert_equal(2, table.count(arr, function(v) return v > 2 end))
assert_equal(2, table.count(arr, function(v) return v == 1 or v == 4 end))
end)
-- ======================================================================
-- FILTERING AND MAPPING
-- ======================================================================
test("Table Filter", function()
local evens = table.filter(simple_array, function(v) return v % 2 == 0 end)
assert_table_equal({2, 4}, evens)
local filtered_table = table.filter(simple_table, function(v) return v > 1 end)
assert_equal(2, table.size(filtered_table))
assert_equal(2, filtered_table.b)
assert_equal(3, filtered_table.c)
end)
test("Table Reject", function()
local odds = table.reject(simple_array, function(v) return v % 2 == 0 end)
assert_table_equal({1, 3, 5}, odds)
end)
test("Table Map", function()
local doubled = table.map(simple_array, function(v) return v * 2 end)
assert_table_equal({2, 4, 6, 8, 10}, doubled)
local mapped_table = table.map(simple_table, function(v) return v + 10 end)
assert_equal(11, mapped_table.a)
assert_equal(12, mapped_table.b)
assert_equal(13, mapped_table.c)
end)
test("Table Map Values", function()
local incremented = table.map_values(simple_table, function(v) return v + 1 end)
assert_equal(2, incremented.a)
assert_equal(3, incremented.b)
assert_equal(4, incremented.c)
end)
test("Table Map Keys", function()
local prefixed = table.map_keys(simple_table, function(k) return "key_" .. k end)
assert_equal(1, prefixed.key_a)
assert_equal(2, prefixed.key_b)
assert_equal(3, prefixed.key_c)
assert_equal(nil, prefixed.a)
end)
-- ======================================================================
-- REDUCING AND AGGREGATING
-- ======================================================================
test("Table Reduce", function()
local sum = table.reduce(simple_array, function(acc, v) return acc + v end)
assert_equal(15, sum)
local sum_with_initial = table.reduce(simple_array, function(acc, v) return acc + v end, 10)
assert_equal(25, sum_with_initial)
local product = table.reduce({2, 3, 4}, function(acc, v) return acc * v end)
assert_equal(24, product)
end)
test("Table Fold", function()
local sum = table.fold(simple_array, function(acc, v) return acc + v end, 0)
assert_equal(15, sum)
local concatenated = table.fold({"a", "b", "c"}, function(acc, v) return acc .. v end, "")
assert_equal("abc", concatenated)
end)
test("Table Math Operations", function()
assert_equal(15, table.sum(simple_array))
assert_equal(120, table.product(simple_array))
assert_equal(1, table.min(simple_array))
assert_equal(5, table.max(simple_array))
assert_equal(3, table.average(simple_array))
local floats = {1.5, 2.5, 3.0}
assert_close(7.0, table.sum(floats))
assert_close(2.33333, table.average(floats), 0.001)
end)
-- ======================================================================
-- BOOLEAN OPERATIONS
-- ======================================================================
test("Table All", function()
assert_equal(true, table.all({true, true, true}))
assert_equal(false, table.all({true, false, true}))
assert_equal(true, table.all({}))
assert_equal(true, table.all(simple_array, function(v) return v > 0 end))
assert_equal(false, table.all(simple_array, function(v) return v > 3 end))
end)
test("Table Any", function()
assert_equal(true, table.any({false, true, false}))
assert_equal(false, table.any({false, false, false}))
assert_equal(false, table.any({}))
assert_equal(true, table.any(simple_array, function(v) return v > 3 end))
assert_equal(false, table.any(simple_array, function(v) return v > 10 end))
end)
test("Table None", function()
assert_equal(true, table.none({false, false, false}))
assert_equal(false, table.none({false, true, false}))
assert_equal(true, table.none({}))
assert_equal(false, table.none(simple_array, function(v) return v > 3 end))
assert_equal(true, table.none(simple_array, function(v) return v > 10 end))
end)
-- ======================================================================
-- SET OPERATIONS
-- ======================================================================
test("Table Unique", function()
local duplicates = {1, 2, 2, 3, 3, 3, 4}
local unique = table.unique(duplicates)
assert_table_equal({1, 2, 3, 4}, unique)
local empty_unique = table.unique({})
assert_table_equal({}, empty_unique)
end)
test("Table Intersection", function()
local arr1 = {1, 2, 3, 4}
local arr2 = {3, 4, 5, 6}
local intersect = table.intersection(arr1, arr2)
assert_equal(2, #intersect)
assert_equal(true, table.contains(intersect, 3))
assert_equal(true, table.contains(intersect, 4))
end)
test("Table Union", function()
local arr1 = {1, 2, 3}
local arr2 = {3, 4, 5}
local union = table.union(arr1, arr2)
assert_equal(5, #union)
for i = 1, 5 do
assert_equal(true, table.contains(union, i))
end
end)
test("Table Difference", function()
local arr1 = {1, 2, 3, 4, 5}
local arr2 = {3, 4}
local diff = table.difference(arr1, arr2)
assert_table_equal({1, 2, 5}, diff)
end)
-- ======================================================================
-- ARRAY OPERATIONS
-- ======================================================================
test("Table Reverse", function()
local reversed = table.reverse(simple_array)
assert_table_equal({5, 4, 3, 2, 1}, reversed)
local single = table.reverse({42})
assert_table_equal({42}, single)
local empty = table.reverse({})
assert_table_equal({}, empty)
end)
test("Table Shuffle", function()
local shuffled = table.shuffle(simple_array)
assert_equal(5, #shuffled)
-- All original elements should still be present
for _, v in ipairs(simple_array) do
assert_equal(true, table.contains(shuffled, v))
end
-- Should be same length
assert_equal(#simple_array, #shuffled)
end)
test("Table Rotate", function()
local arr = {1, 2, 3, 4, 5}
local rotated_right = table.rotate(arr, 2)
assert_table_equal({4, 5, 1, 2, 3}, rotated_right)
local rotated_left = table.rotate(arr, -2)
assert_table_equal({3, 4, 5, 1, 2}, rotated_left)
local no_rotation = table.rotate(arr, 0)
assert_table_equal(arr, no_rotation)
local full_rotation = table.rotate(arr, 5)
assert_table_equal(arr, full_rotation)
end)
test("Table Slice", function()
local sliced = table.slice(simple_array, 2, 4)
assert_table_equal({2, 3, 4}, sliced)
local from_start = table.slice(simple_array, 1, 3)
assert_table_equal({1, 2, 3}, from_start)
local to_end = table.slice(simple_array, 3)
assert_table_equal({3, 4, 5}, to_end)
local negative_indices = table.slice(simple_array, -3, -1)
assert_table_equal({3, 4, 5}, negative_indices)
end)
test("Table Splice", function()
local arr = {1, 2, 3, 4, 5}
-- Remove elements
local removed = table.splice(arr, 2, 2)
assert_table_equal({2, 3}, removed)
assert_table_equal({1, 4, 5}, arr)
-- Insert elements
arr = {1, 2, 3, 4, 5}
removed = table.splice(arr, 3, 0, "a", "b")
assert_table_equal({}, removed)
assert_table_equal({1, 2, "a", "b", 3, 4, 5}, arr)
-- Replace elements
arr = {1, 2, 3, 4, 5}
removed = table.splice(arr, 2, 2, "x", "y", "z")
assert_table_equal({2, 3}, removed)
assert_table_equal({1, "x", "y", "z", 4, 5}, arr)
end)
-- ======================================================================
-- SORTING HELPERS
-- ======================================================================
test("Table Sort By", function()
local people = {
{name = "Alice", age = 30},
{name = "Bob", age = 25},
{name = "Charlie", age = 35}
}
local sorted_by_age = table.sort_by(people, function(p) return p.age end)
assert_equal("Bob", sorted_by_age[1].name)
assert_equal("Charlie", sorted_by_age[3].name)
local sorted_by_name = table.sort_by(people, function(p) return p.name end)
assert_equal("Alice", sorted_by_name[1].name)
assert_equal("Charlie", sorted_by_name[3].name)
end)
test("Table Is Sorted", function()
assert_equal(true, table.is_sorted({1, 2, 3, 4, 5}))
assert_equal(false, table.is_sorted({1, 3, 2, 4, 5}))
assert_equal(true, table.is_sorted({}))
assert_equal(true, table.is_sorted({42}))
assert_equal(true, table.is_sorted({5, 4, 3, 2, 1}, function(a, b) return a > b end))
assert_equal(false, table.is_sorted({1, 2, 3, 4, 5}, function(a, b) return a > b end))
end)
-- ======================================================================
-- UTILITY FUNCTIONS
-- ======================================================================
test("Table Keys and Values", function()
local keys = table.keys(simple_table)
assert_equal(3, #keys)
assert_equal(true, table.contains(keys, "a"))
assert_equal(true, table.contains(keys, "b"))
assert_equal(true, table.contains(keys, "c"))
local values = table.values(simple_table)
assert_equal(3, #values)
assert_equal(true, table.contains(values, 1))
assert_equal(true, table.contains(values, 2))
assert_equal(true, table.contains(values, 3))
end)
test("Table Pairs", function()
local pairs_list = table.pairs({a = 1, b = 2})
assert_equal(2, #pairs_list)
-- Should contain key-value pairs
local found_a, found_b = false, false
for _, pair in ipairs(pairs_list) do
if pair[1] == "a" and pair[2] == 1 then found_a = true end
if pair[1] == "b" and pair[2] == 2 then found_b = true end
end
assert_equal(true, found_a)
assert_equal(true, found_b)
end)
test("Table Merge", function()
local t1 = {a = 1, b = 2}
local t2 = {c = 3, d = 4}
local t3 = {b = 20, e = 5}
local merged = table.merge(t1, t2, t3)
assert_equal(5, table.size(merged))
assert_equal(1, merged.a)
assert_equal(20, merged.b) -- Last one wins
assert_equal(3, merged.c)
assert_equal(4, merged.d)
assert_equal(5, merged.e)
end)
test("Table Extend", function()
local t1 = {a = 1, b = 2}
local t2 = {c = 3, d = 4}
local extended = table.extend(t1, t2)
assert_equal(t1, extended) -- Should return t1
assert_equal(4, table.size(t1))
assert_equal(3, t1.c)
assert_equal(4, t1.d)
end)
test("Table Invert", function()
local inverted = table.invert(simple_table)
assert_equal("a", inverted[1])
assert_equal("b", inverted[2])
assert_equal("c", inverted[3])
end)
test("Table Pick and Omit", function()
local big_table = {a = 1, b = 2, c = 3, d = 4, e = 5}
local picked = table.pick(big_table, "a", "c", "e")
assert_equal(3, table.size(picked))
assert_equal(1, picked.a)
assert_equal(3, picked.c)
assert_equal(5, picked.e)
assert_equal(nil, picked.b)
assert_equal(nil, picked.d)
local omitted = table.omit(big_table, "b", "d")
assert_equal(3, table.size(omitted))
assert_equal(1, omitted.a)
assert_equal(3, omitted.c)
assert_equal(5, omitted.e)
assert_equal(nil, omitted.b)
assert_equal(nil, omitted.d)
end)
-- ======================================================================
-- DEEP OPERATIONS
-- ======================================================================
test("Table Deep Equals", function()
local t1 = {a = {x = 1, y = 2}, b = {1, 2, 3}}
local t2 = {a = {x = 1, y = 2}, b = {1, 2, 3}}
local t3 = {a = {x = 1, y = 3}, b = {1, 2, 3}}
assert_equal(true, table.deep_equals(t1, t2))
assert_equal(false, table.deep_equals(t1, t3))
assert_equal(true, table.deep_equals({}, {}))
assert_equal(false, table.deep_equals({a = 1}, {a = 1, b = 2}))
end)
test("Table Flatten", function()
local nested = {{1, 2}, {3, 4}, {5, {6, 7}}}
local flattened = table.flatten(nested)
assert_table_equal({1, 2, 3, 4, 5, {6, 7}}, flattened)
local deep_flattened = table.flatten(nested, 2)
assert_table_equal({1, 2, 3, 4, 5, 6, 7}, deep_flattened)
local already_flat = table.flatten({1, 2, 3})
assert_table_equal({1, 2, 3}, already_flat)
end)
test("Table Deep Merge", function()
local t1 = {a = {x = 1}, b = 2}
local t2 = {a = {y = 3}, c = 4}
local merged = table.deep_merge(t1, t2)
assert_equal(1, merged.a.x)
assert_equal(3, merged.a.y)
assert_equal(2, merged.b)
assert_equal(4, merged.c)
-- Original tables should be unchanged
assert_equal(nil, t1.a.y)
assert_equal(nil, t1.c)
end)
-- ======================================================================
-- ADVANCED OPERATIONS
-- ======================================================================
test("Table Chunk", function()
local chunks = table.chunk({1, 2, 3, 4, 5, 6, 7}, 3)
assert_equal(3, #chunks)
assert_table_equal({1, 2, 3}, chunks[1])
assert_table_equal({4, 5, 6}, chunks[2])
assert_table_equal({7}, chunks[3])
local exact_chunks = table.chunk({1, 2, 3, 4}, 2)
assert_equal(2, #exact_chunks)
assert_table_equal({1, 2}, exact_chunks[1])
assert_table_equal({3, 4}, exact_chunks[2])
end)
test("Table Partition", function()
local evens, odds = table.partition(simple_array, function(v) return v % 2 == 0 end)
assert_table_equal({2, 4}, evens)
assert_table_equal({1, 3, 5}, odds)
local empty_true, all_false = table.partition({1, 3, 5}, function(v) return v % 2 == 0 end)
assert_table_equal({}, empty_true)
assert_table_equal({1, 3, 5}, all_false)
end)
test("Table Group By", function()
local people = {
{name = "Alice", department = "engineering"},
{name = "Bob", department = "sales"},
{name = "Charlie", department = "engineering"},
{name = "David", department = "sales"}
}
local by_dept = table.group_by(people, function(person) return person.department end)
assert_equal(2, table.size(by_dept))
assert_equal(2, #by_dept.engineering)
assert_equal(2, #by_dept.sales)
assert_equal("Alice", by_dept.engineering[1].name)
assert_equal("Bob", by_dept.sales[1].name)
end)
test("Table Zip", function()
local names = {"Alice", "Bob", "Charlie"}
local ages = {25, 30, 35}
local cities = {"NYC", "LA", "Chicago"}
local zipped = table.zip(names, ages, cities)
assert_equal(3, #zipped)
assert_table_equal({"Alice", 25, "NYC"}, zipped[1])
assert_table_equal({"Bob", 30, "LA"}, zipped[2])
assert_table_equal({"Charlie", 35, "Chicago"}, zipped[3])
-- Different lengths
local short_zip = table.zip({1, 2, 3}, {"a", "b"})
assert_equal(2, #short_zip)
assert_table_equal({1, "a"}, short_zip[1])
assert_table_equal({2, "b"}, short_zip[2])
end)
test("Table Compact", function()
local messy = {1, nil, false, 2, nil, 3, false}
local compacted = table.compact(messy)
assert_table_equal({1, 2, 3}, compacted)
local clean = {1, 2, 3}
local unchanged = table.compact(clean)
assert_table_equal(clean, unchanged)
end)
test("Table Sample", function()
local sample1 = table.sample(simple_array, 3)
assert_equal(3, #sample1)
-- All sampled elements should be from original
for _, v in ipairs(sample1) do
assert_equal(true, table.contains(simple_array, v))
end
local single_sample = table.sample(simple_array)
assert_equal(1, #single_sample)
assert_equal(true, table.contains(simple_array, single_sample[1]))
local oversample = table.sample({1, 2}, 5)
assert_equal(2, #oversample)
end)
-- ======================================================================
-- EDGE CASES AND ERROR HANDLING
-- ======================================================================
test("Empty Table Handling", function()
local empty = {}
assert_equal(true, table.is_empty(empty))
assert_equal(0, table.length(empty))
assert_equal(0, table.size(empty))
assert_equal(true, table.is_array(empty))
assert_table_equal({}, table.filter(empty, function() return true end))
assert_table_equal({}, table.map(empty, function(v) return v * 2 end))
assert_table_equal({}, table.keys(empty))
assert_table_equal({}, table.values(empty))
assert_equal(true, table.all(empty))
assert_equal(false, table.any(empty))
assert_equal(true, table.none(empty))
end)
test("Single Element Tables", function()
local single = {42}
assert_equal(1, table.length(single))
assert_equal(1, table.size(single))
assert_equal(true, table.is_array(single))
assert_equal(false, table.is_empty(single))
assert_equal(42, table.sum(single))
assert_equal(42, table.product(single))
assert_equal(42, table.min(single))
assert_equal(42, table.max(single))
assert_equal(42, table.average(single))
assert_table_equal({42}, table.reverse(single))
assert_table_equal({84}, table.map(single, function(v) return v * 2 end))
end)
test("Circular Reference Handling", function()
local t1 = {a = 1}
local t2 = {b = 2}
t1.ref = t2
t2.ref = t1
-- Deep copy should handle circular references
local copied = table.deep_copy(t1)
assert_equal(1, copied.a)
assert_equal(2, copied.ref.b)
assert_equal(copied, copied.ref.ref) -- Should maintain circular structure
end)
test("Large Table Performance", function()
local large = {}
for i = 1, 10000 do
large[i] = i
end
assert_equal(10000, table.length(large))
assert_equal(true, table.is_array(large))
assert_equal(50005000, table.sum(large)) -- Sum of 1 to 10000
local evens = table.filter(large, function(v) return v % 2 == 0 end)
assert_equal(5000, #evens)
local doubled = table.map(large, function(v) return v * 2 end)
assert_equal(10000, #doubled)
assert_equal(2, doubled[1])
assert_equal(20000, doubled[10000])
end)
test("Mixed Type Table Handling", function()
local mixed = {1, "hello", true, {a = 1}, function() end}
assert_equal(5, table.length(mixed))
assert_equal(true, table.is_array(mixed))
assert_equal(true, table.contains(mixed, "hello"))
assert_equal(true, table.contains(mixed, true))
local strings_only = table.filter(mixed, function(v) return type(v) == "string" end)
assert_equal(1, #strings_only)
assert_equal("hello", strings_only[1])
end)
-- ======================================================================
-- PERFORMANCE TESTS
-- ======================================================================
test("Performance Test", function()
local large_array = {}
for i = 1, 10000 do
large_array[i] = math.random(1, 1000)
end
local start = os.clock()
local filtered = table.filter(large_array, function(v) return v > 500 end)
local filter_time = os.clock() - start
start = os.clock()
local mapped = table.map(large_array, function(v) return v * 2 end)
local map_time = os.clock() - start
start = os.clock()
local sum = table.sum(large_array)
local sum_time = os.clock() - start
start = os.clock()
local sorted = table.sort_by(large_array, function(v) return v end)
local sort_time = os.clock() - start
start = os.clock()
local unique = table.unique(large_array)
local unique_time = os.clock() - start
print(string.format(" Filter %d elements: %.3fs", #filtered, filter_time))
print(string.format(" Map %d elements: %.3fs", #mapped, map_time))
print(string.format(" Sum %d elements: %.3fs", #large_array, sum_time))
print(string.format(" Sort %d elements: %.3fs", #sorted, sort_time))
print(string.format(" Unique from %d to %d: %.3fs", #large_array, #unique, unique_time))
assert(#filtered > 0, "should filter some elements")
assert_equal(#large_array, #mapped)
assert(sum > 0, "sum should be positive")
assert_equal(#large_array, #sorted)
assert(table.is_sorted(sorted), "should be sorted")
end)
-- ======================================================================
-- INTEGRATION TESTS
-- ======================================================================
test("Data Processing Pipeline", function()
local sales_data = {
{product = "laptop", price = 1000, quantity = 2, category = "electronics"},
{product = "mouse", price = 25, quantity = 10, category = "electronics"},
{product = "book", price = 15, quantity = 5, category = "books"},
{product = "phone", price = 800, quantity = 3, category = "electronics"},
{product = "magazine", price = 5, quantity = 20, category = "books"}
}
-- Calculate total revenue per item
local with_revenue = table.map(sales_data, function(item)
local new_item = table.clone(item)
new_item.revenue = item.price * item.quantity
return new_item
end)
-- Filter high-value items (revenue >= 100)
local high_value = table.filter(with_revenue, function(item)
return item.revenue >= 100
end)
-- Group by category
local by_category = table.group_by(high_value, function(item)
return item.category
end)
-- Calculate total revenue by category
local category_totals = table.map_values(by_category, function(items)
return table.sum(table.map(items, function(item) return item.revenue end))
end)
assert_equal(2, table.size(category_totals))
assert_equal(4650, category_totals.electronics) -- laptop: 2000, mouse: 250, phone: 2400
assert_equal(100, category_totals.books) -- magazine: 100
end)
test("Complex Data Transformation", function()
local users = {
{id = 1, name = "Alice", age = 25, skills = {"lua", "python"}},
{id = 2, name = "Bob", age = 30, skills = {"javascript", "lua"}},
{id = 3, name = "Charlie", age = 35, skills = {"python", "java"}},
{id = 4, name = "David", age = 28, skills = {"lua", "go"}}
}
-- Find Lua developers
local lua_devs = table.filter(users, function(user)
return table.contains(user.skills, "lua")
end)
-- Sort by age
local sorted_lua_devs = table.sort_by(lua_devs, function(user) return user.age end)
-- Extract just names and ages
local simplified = table.map(sorted_lua_devs, function(user)
return {name = user.name, age = user.age}
end)
assert_equal(3, #simplified)
assert_equal("Alice", simplified[1].name) -- Youngest
assert_equal("David", simplified[2].name)
assert_equal("Bob", simplified[3].name) -- Oldest
-- Group all users by age ranges
local age_groups = table.group_by(users, function(user)
if user.age < 30 then return "young"
else return "experienced" end
end)
assert_equal(2, #age_groups.young) -- Alice, David
assert_equal(2, #age_groups.experienced) -- Bob, Charlie
end)
test("Statistical Analysis", function()
local test_scores = {
{student = "Alice", scores = {85, 92, 78, 95, 88}},
{student = "Bob", scores = {72, 85, 90, 77, 82}},
{student = "Charlie", scores = {95, 88, 92, 90, 85}},
{student = "David", scores = {68, 75, 80, 72, 78}}
}
-- Calculate average score for each student
local with_averages = table.map(test_scores, function(student)
local avg = table.average(student.scores)
return {
student = student.student,
scores = student.scores,
average = avg,
max_score = table.max(student.scores),
min_score = table.min(student.scores)
}
end)
-- Find top performer
local top_student = table.reduce(with_averages, function(best, current)
return current.average > best.average and current or best
end)
-- Students above class average
local all_averages = table.map(with_averages, function(s) return s.average end)
local class_average = table.average(all_averages)
local above_average = table.filter(with_averages, function(s)
return s.average > class_average
end)
assert_equal("Charlie", top_student.student)
assert_equal(90, top_student.average)
assert_equal(2, #above_average) -- Charlie and Alice
assert_close(83.4, class_average, 0.1)
end)
test("Table Metatable Method Chaining", function()
local t = {1, 2, 3, 4, 5}
-- Check if methods are available directly on table instances
assert_equal("function", type(t.filter), "table should have filter method via metatable")
assert_equal("function", type(t.map), "table should have map method via metatable")
assert_equal("function", type(t.length), "table should have length method via metatable")
-- Test actual method chaining
local result = t:filter(function(v) return v > 2 end)
:map(function(v) return v * 2 end)
assert_table_equal({6, 8, 10}, result)
-- Test chaining with method calls
local nums = {1, 2, 3, 4, 5}
local sum = nums:sum()
assert_equal(15, sum)
local sizes = {a = 1, b = 2}
local size = sizes:size()
assert_equal(2, size)
end)
summary()
test_exit()