summaryrefslogtreecommitdiff
path: root/Data/Libraries/Penlight/tests/test-tablex.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Data/Libraries/Penlight/tests/test-tablex.lua')
-rw-r--r--Data/Libraries/Penlight/tests/test-tablex.lua348
1 files changed, 348 insertions, 0 deletions
diff --git a/Data/Libraries/Penlight/tests/test-tablex.lua b/Data/Libraries/Penlight/tests/test-tablex.lua
new file mode 100644
index 0000000..c8bbf01
--- /dev/null
+++ b/Data/Libraries/Penlight/tests/test-tablex.lua
@@ -0,0 +1,348 @@
+local tablex = require 'pl.tablex'
+local utils = require ('pl.utils')
+local L = utils.string_lambda
+local test = require('pl.test')
+-- bring tablex funtions into global namespace
+utils.import(tablex)
+local asserteq = test.asserteq
+
+local cmp = deepcompare
+
+function asserteq_no_order (x,y)
+ if not compare_no_order(x,y) then
+ test.complain(x,y,"these lists contained different elements")
+ end
+end
+
+
+asserteq(
+ copy {10,20,30},
+ {10,20,30}
+)
+
+asserteq(
+ deepcopy {10,20,{30,40}},
+ {10,20,{30,40}}
+)
+
+local t = {
+ a = "hello",
+ b = {
+ c = "world"
+ }
+}
+t.b.d = t.b
+
+local tcopy = {
+ a = "hello",
+ b = {
+ c = "world"
+ }
+}
+tcopy.b.d = tcopy.b
+
+asserteq(
+ deepcopy(t),
+ tcopy
+)
+
+asserteq(
+ pairmap(function(i,v) return v end,{10,20,30}),
+ {10,20,30}
+)
+
+asserteq_no_order(
+ pairmap(L'_',{fred=10,bonzo=20}),
+ {'fred','bonzo'}
+)
+
+asserteq_no_order(
+ pairmap(function(k,v) return v end,{fred=10,bonzo=20}),
+ {10,20}
+)
+
+asserteq_no_order(
+ pairmap(function(i,v) return v,i end,{10,20,30}),
+ {10,20,30}
+)
+
+asserteq(
+ pairmap(function(k,v) return {k,v},k end,{one=1,two=2}),
+ {one={'one',1},two={'two',2}}
+)
+-- same as above, using string lambdas
+asserteq(
+ pairmap(L'|k,v|{k,v},k',{one=1,two=2}),
+ {one={'one',1},two={'two',2}}
+)
+
+
+asserteq(
+ map(function(v) return v*v end,{10,20,30}),
+ {100,400,900}
+)
+
+-- extra arguments to map() are passed to the function; can use
+-- the abbreviations provided by pl.operator
+asserteq(
+ map('+',{10,20,30},1),
+ {11,21,31}
+)
+
+asserteq(
+ map(L'_+1',{10,20,30}),
+ {11,21,31}
+)
+
+-- map2 generalizes for operations on two tables
+asserteq(
+ map2(math.max,{1,2,3},{0,4,2}),
+ {1,4,3}
+)
+
+-- mapn operates over an arbitrary number of input tables (but use map2 for n=2)
+asserteq(
+ mapn(function(x,y,z) return x+y+z end, {1,2,3},{10,20,30},{100,200,300}),
+ {111,222,333}
+)
+
+asserteq(
+ mapn(math.max, {1,20,300},{10,2,3},{100,200,100}),
+ {100,200,300}
+)
+
+asserteq(
+ count_map({"foo", "bar", "foo", "baz"}),
+ {foo = 2, bar = 1, baz = 1}
+)
+
+asserteq(
+ zip({10,20,30},{100,200,300}),
+ {{10,100},{20,200},{30,300}}
+)
+
+assert(compare_no_order({1,2,3,4},{2,1,4,3})==true)
+assert(compare_no_order({1,2,3,4},{2,1,4,4})==false)
+
+asserteq(range(10,9),{})
+asserteq(range(10,10),{10})
+asserteq(range(10,11),{10,11})
+
+-- update inserts key-value pairs from the second table
+t1 = {one=1,two=2}
+t2 = {three=3,two=20,four=4}
+asserteq(update(t1,t2),{one=1,three=3,two=20,four=4})
+
+-- the difference between move and icopy is that the second removes
+-- any extra elements in the destination after end of copy
+-- 3rd arg is the index to start in the destination, defaults to 1
+asserteq(move({1,2,3,4,5,6},{20,30}),{20,30,3,4,5,6})
+asserteq(move({1,2,3,4,5,6},{20,30},2),{1,20,30,4,5,6})
+asserteq(icopy({1,2,3,4,5,6},{20,30},2),{1,20,30})
+-- 5th arg determines how many elements to copy (default size of source)
+asserteq(icopy({1,2,3,4,5,6},{20,30},2,1,1),{1,20})
+-- 4th arg is where to stop copying from the source (default s to 1)
+asserteq(icopy({1,2,3,4,5,6},{20,30},2,2,1),{1,30})
+
+-- whereas insertvalues works like table.insert, but inserts a range of values
+-- from the given table.
+asserteq(insertvalues({1,2,3,4,5,6},2,{20,30}),{1,20,30,2,3,4,5,6})
+asserteq(insertvalues({1,2},{3,4}),{1,2,3,4})
+
+-- the 4th arg of move and icopy gives the start index in the source table
+asserteq(move({1,2,3,4,5,6},{20,30},2,2),{1,30,3,4,5,6})
+asserteq(icopy({1,2,3,4,5,6},{20,30},2,2),{1,30})
+
+t = {1,2,3,4,5,6}
+move(t,{20,30},2,1,1)
+asserteq(t,{1,20,3,4,5,6})
+set(t,0,2,3)
+asserteq(t,{1,0,0,4,5,6})
+insertvalues(t,1,{10,20})
+asserteq(t,{10,20,1,0,0,4,5,6})
+
+asserteq(merge({10,20,30},{nil, nil, 30, 40}), {[3]=30})
+asserteq(merge({10,20,30},{nil, nil, 30, 40}, true), {10,20,30,40})
+
+
+-- Function to check that the order of elements returned by the iterator
+-- match the order of the elements in the list.
+function assert_iter_order(iter,l)
+ local i = 0
+ for k,v in iter do
+ i = i + 1
+ asserteq(k,l[i][1])
+ asserteq(v,l[i][2])
+ end
+end
+
+local t = {a=10,b=9,c=8,d=7,e=6,f=5,g=4,h=3,i=2,j=1}
+
+assert_iter_order(
+ sort(t),
+ {{'a',10},{'b',9},{'c',8},{'d',7},{'e',6},{'f',5},{'g',4},{'h',3},{'i',2},{'j',1}})
+
+assert_iter_order(
+ sortv(t),
+ {{'j',1},{'i',2},{'h',3},{'g',4},{'f',5},{'e',6},{'d',7},{'c',8},{'b',9},{'a',10}})
+
+
+asserteq(difference({a = true, b = true},{a = true, b = true}),{})
+
+-- no longer confused by false values ;)
+asserteq(difference({v = false},{v = false}),{})
+
+asserteq(difference({a = true},{b = true}),{a=true})
+
+-- symmetric difference
+asserteq(difference({a = true},{b = true},true),{a=true,b=true})
+
+--basic index_map test
+asserteq(index_map({10,20,30}), {[10]=1,[20]=2,[30]=3})
+--test that repeated values return multiple indices
+asserteq(index_map({10,20,30,30,30}), {[10]=1,[20]=2,[30]={3,4,5}})
+
+-- Reduce
+asserteq(tablex.reduce('-', {}, 2), 2)
+asserteq(tablex.reduce('-', {}), nil)
+asserteq(tablex.reduce('-', {1,2,3,4,5}), -13)
+asserteq(tablex.reduce('-', {1,2,3,4,5}, 1), -14)
+
+
+-- tablex.compare
+do
+ asserteq(tablex.compare({},{}, "=="), true)
+ asserteq(tablex.compare({1,2,3}, {1,2,3}, "=="), true)
+ asserteq(tablex.compare({1,"hello",3}, {1,2,3}, "=="), false)
+ asserteq(tablex.compare(
+ {1,2,3, hello = "world"},
+ {1,2,3},
+ function(v1, v2) return v1 == v2 end),
+ true) -- only compares the list part
+end
+
+
+-- tablex.rfind
+do
+ local rfind = tablex.rfind
+ local lst = { "Rudolph", "the", "red-nose", "raindeer" }
+ asserteq(rfind(lst, "Santa"), nil)
+ asserteq(rfind(lst, "raindeer", -2), nil)
+ asserteq(rfind(lst, "raindeer"), 4)
+ asserteq(rfind(lst, "Rudolph"), 1)
+ asserteq(rfind(lst, "the", -3), 2)
+ asserteq(rfind(lst, "the", -30), nil)
+ asserteq(rfind({10,10,10},10), 3)
+end
+
+
+-- tablex.find_if
+do
+ local fi = tablex.find_if
+ local lst = { "Rudolph", true, false, 15 }
+ asserteq({fi(lst, "==", "Rudolph")}, {1, true})
+ asserteq({fi(lst, "==", true)}, {2, true})
+ asserteq({fi(lst, "==", false)}, {3, true})
+ asserteq({fi(lst, "==", 15)}, {4, true})
+
+ local cmp = function(v1, v2) return v1 == v2 and v2 end
+ asserteq({fi(lst, cmp, "Rudolph")}, {1, "Rudolph"})
+ asserteq({fi(lst, cmp, true)}, {2, true})
+ asserteq({fi(lst, cmp, false)}, {}) -- 'false' cannot be returned!
+ asserteq({fi(lst, cmp, 15)}, {4, 15})
+end
+
+
+-- tablex.map_named_method
+do
+ local Car = {}
+ Car.__index = Car
+ function Car.new(car)
+ return setmetatable(car or {}, Car)
+ end
+ Car.speed = 0
+ function Car:faster(increase)
+ self.speed = self.speed + (increase or 1)
+ return self.speed
+ end
+ function Car:slower(self, decrease)
+ self.speed = self.speed - (decrease or 1)
+ return self.speed
+ end
+
+ local ferrari = Car.new{ name = "Ferrari" }
+ local lamborghini = Car.new{ name = "Lamborghini", speed = 50 }
+ local cars = { ferrari, lamborghini }
+
+ asserteq(ferrari.speed, 0)
+ asserteq(lamborghini.speed, 50)
+ asserteq(tablex.map_named_method("faster", cars, 10), {10, 60})
+ asserteq(ferrari.speed, 10)
+ asserteq(lamborghini.speed, 60)
+
+end
+
+
+-- tablex.foreach
+do
+ local lst = { "one", "two", "three", hello = "world" }
+ tablex.foreach(lst, function(v, k, sep)
+ lst[k] = tostring(k) .. sep .. v
+ end, " = ")
+ asserteq(lst, {"1 = one", "2 = two", "3 = three", hello = "hello = world"})
+end
+
+
+-- tablex.foreachi
+do
+ local lst = { "one", "two", "three", hello = "world" }
+ tablex.foreachi(lst, function(v, k, sep)
+ lst[k] = tostring(k) .. sep .. v
+ end, " = ")
+ asserteq(lst, {"1 = one", "2 = two", "3 = three", hello = "world"})
+end
+
+
+-- tablex.new
+asserteq(tablex.new(3, "hi"), { "hi", "hi", "hi" })
+
+
+-- tablex.search
+do
+ local t = {
+ penlight = {
+ battery = {
+ type = "AA",
+ capacity = "1500mah",
+ },
+ },
+ hello = {
+ world = {
+ also = "AA"
+ }
+ }
+ }
+ asserteq(tablex.search(t, "1500mah"), "penlight.battery.capacity")
+ asserteq(tablex.search(t, "AA", {t.penlight} ), "hello.world.also")
+ asserteq(tablex.search(t, "xxx"), nil)
+end
+
+
+-- tablex.readonly
+do
+ local ro = tablex.readonly { 1,2,3, hello = "world" }
+ asserteq(pcall(function() ro.hello = "hi there" end), false)
+ asserteq(getmetatable(ro), false)
+
+ if not utils.lua51 then
+ asserteq(#ro, 3)
+
+ local r = {}
+ for k,v in pairs(ro) do r[k] = v end
+ asserteq(r, { 1,2,3, hello = "world" })
+
+ r = {}
+ for k,v in ipairs(ro) do r[k] = v end
+ asserteq(r, { 1,2,3 })
+ end
+end