diff options
author | chai <chaifix@163.com> | 2021-10-30 11:32:16 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-10-30 11:32:16 +0800 |
commit | 42ec7286b2d36a9ba22925f816a17cb1cc2aa5ce (patch) | |
tree | 24bc7009457a8d7500f264e89946dc20d069294f /Data/Libraries/Penlight/spec | |
parent | 164885fd98d48703bd771f802d79557b7db97431 (diff) |
+ Penlight
Diffstat (limited to 'Data/Libraries/Penlight/spec')
-rw-r--r-- | Data/Libraries/Penlight/spec/app_spec.lua | 27 | ||||
-rw-r--r-- | Data/Libraries/Penlight/spec/array2d_spec.lua | 557 | ||||
-rw-r--r-- | Data/Libraries/Penlight/spec/date_spec.lua | 48 | ||||
-rw-r--r-- | Data/Libraries/Penlight/spec/multimap_spec.lua | 14 | ||||
-rw-r--r-- | Data/Libraries/Penlight/spec/permute_spec.lua | 213 | ||||
-rw-r--r-- | Data/Libraries/Penlight/spec/pretty_spec.lua | 40 | ||||
-rw-r--r-- | Data/Libraries/Penlight/spec/set_spec.lua | 84 | ||||
-rw-r--r-- | Data/Libraries/Penlight/spec/text_spec.lua | 11 | ||||
-rw-r--r-- | Data/Libraries/Penlight/spec/utils-deprecate_spec.lua | 128 | ||||
-rw-r--r-- | Data/Libraries/Penlight/spec/utils-npairs_spec.lua | 105 |
10 files changed, 1227 insertions, 0 deletions
diff --git a/Data/Libraries/Penlight/spec/app_spec.lua b/Data/Libraries/Penlight/spec/app_spec.lua new file mode 100644 index 0000000..3b1f290 --- /dev/null +++ b/Data/Libraries/Penlight/spec/app_spec.lua @@ -0,0 +1,27 @@ +local app = require("pl.app") + +describe("pl.app.lua", function () + + local invocation = app.lua() + + it("should pick up the arguments used to run this test", function () + assert.is.truthy(invocation:match("lua.+package.+busted")) + end) + + it("should be reusable to invoke Lua", function () + assert.is.truthy(os.execute(app.lua()..' -e "n=1;os.exit(n-1)"')) + end) + +end) + +describe("pl.app.platform", function () + + -- TODO: Find a reliable alternate way to determine platform to check that + -- this is returning the right answer, not just any old answer. + it("should at least return a valid platform", function () + local platforms = { Linux = true, OSX = true, Windows = true } + local detected = app.platform() + assert.is.truthy(platforms[detected]) + end) + +end) diff --git a/Data/Libraries/Penlight/spec/array2d_spec.lua b/Data/Libraries/Penlight/spec/array2d_spec.lua new file mode 100644 index 0000000..3fd0085 --- /dev/null +++ b/Data/Libraries/Penlight/spec/array2d_spec.lua @@ -0,0 +1,557 @@ +local array2d = require("pl.array2d") + +describe("pl.array2d", function() + + describe("new()", function() + it("creates an empty 2d array", function() + assert.same({{},{},{}}, array2d.new(3,3,nil)) + end) + + it("creates a value-filled 2d array", function() + assert.same({{99,99,99}, + {99,99,99}, + {99,99,99}}, array2d.new(3,3,99)) + end) + + it("creates a function-filled 2d array", function() + assert.same({{2,3,4}, + {3,4,5}, + {4,5,6}}, array2d.new(3,3,function(i,j) return i+j end)) + end) + end) + + describe("size()", function() + it("returns array size", function() + local a = array2d.new(3,5,99) + assert.same({3,5}, {array2d.size(a)}) + end) + + it("returns 0 columns for nil arrays", function() + local a = array2d.new(3,5,nil) + assert.same({3,0}, {array2d.size(a)}) + end) + end) + + describe("column()", function() + it("returns a column copy", function() + local a = {{1,2}, + {3,4}, + {5,6}} + assert.same({1,3,5}, array2d.column(a,1)) + assert.same({2,4,6}, array2d.column(a,2)) + end) + end) + + describe("row()", function() + it("returns a row copy", function() + local a = {{1,2}, + {3,4}, + {5,6}} + assert.same({1,2}, array2d.row(a,1)) + -- next test: need to remove the metatable to prevent comparison by + -- metamethods in Lua 5.3 and 5.4 + assert.not_equal(a[1], setmetatable(array2d.row(a,1),nil)) + assert.same({3,4}, array2d.row(a,2)) + assert.same({5,6}, array2d.row(a,3)) + end) + end) + + describe("map()", function() + it("maps a function on an array", function() + local a1 = array2d.new(2,3,function(i,j) return i+j end) + local a2 = array2d.map(function(a,b) return a .. b end, a1, "x") + assert.same({{"2x","3x","4x"}, + {"3x","4x","5x"}}, a2) + end) + end) + + describe("reduce_rows()", function() + it("reduces rows", function() + local a = {{ 1, 2, 3, 4}, + { 10, 20, 30, 40}, + { 100, 200, 300, 400}, + {1000,2000,3000,4000}} + assert.same({10,100,1000,10000},array2d.reduce_rows('+',a)) + end) + end) + + describe("reduce_cols()", function() + it("reduces columns", function() + local a = {{ 1, 2, 3, 4}, + { 10, 20, 30, 40}, + { 100, 200, 300, 400}, + {1000,2000,3000,4000}} + assert.same({1111,2222,3333,4444},array2d.reduce_cols('+',a)) + end) + end) + + describe("reduce2()", function() + it("recuces array to scalar", function() + local a = {{1,10}, + {2,10}, + {3,10}} + assert.same(60, array2d.reduce2('+','*',a)) + end) + end) + + describe("map2()", function() + it("maps over 2 arrays", function() + local b = {{10,20}, + {30,40}} + local a = {{1,2}, + {3,4}} + -- 2 2d arrays + assert.same({{11,22},{33,44}}, array2d.map2('+',2,2,a,b)) + -- 1d, 2d + assert.same({{11,102},{13,104}}, array2d.map2('+',1,2,{10,100},a)) + -- 2d, 1d + assert.same({{1,-2},{3,-4}},array2d.map2('*',2,1,a,{1,-1})) + end) + end) + + describe("product()", function() + it("creates a product array", function() + local a = array2d.product('..',{1,2,3},{'a','b','c'}) + assert.same({{'1a','2a','3a'},{'1b','2b','3b'},{'1c','2c','3c'}}, a) + + local a = array2d.product('{}',{1,2},{'a','b','c'}) + assert.same({{{1,'a'},{2,'a'}},{{1,'b'},{2,'b'}},{{1,'c'},{2,'c'}}}, a) + end) + end) + + describe("flatten()", function() + it("flattens a 2darray", function() + local a = {{1,2}, + {3,4}, + {5,6}} + assert.same( {1,2,3,4,5,6}, array2d.flatten(a)) + end) + + it("keeps a nil-array 'square'", function() + local a = {{ 1,2}, + {nil,4}, + {nil,6}} + assert.same( {1,2,nil,4,nil,6}, array2d.flatten(a)) + end) + end) + + describe("reshape()", function() + it("reshapes array in new nr of rows", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}, + {10,11,12}} + local b = array2d.reshape(a, 2, false) + assert.same({{ 1, 2, 3, 4, 5, 6}, + { 7, 8, 9,10,11,12}}, b) + local c = array2d.reshape(b, 4, false) + assert.same(a, c) + end) + it("reshapes array in new nr of rows, column order", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}} + local b = array2d.reshape(a, 3, true) + assert.same({{ 1, 4, 7}, + { 2, 5, 8}, + { 3, 6, 9}}, b) + end) + end) + + describe("transpose()", function() + it("transposes a 2d array", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}} + local b = array2d.transpose(a) + assert.same({{ 1, 4, 7}, + { 2, 5, 8}, + { 3, 6, 9}}, b) + + local a = {{ 1, 2, 3, 4, 5}, + { 6, 7, 8, 9, 10}} + local b = array2d.transpose(a) + assert.same({{ 1, 6}, + { 2, 7}, + { 3, 8}, + { 4, 9}, + { 5,10}}, b) + end) + end) + + describe("swap_rows()", function() + it("swaps 2 rows, in-place", function() + local a = {{1,2}, + {3,4}, + {5,6}} + local b = array2d.swap_rows(a, 1, 3) + assert.same({{5,6}, + {3,4}, + {1,2}}, b) + assert.equal(a, b) + end) + end) + + describe("swap_cols()", function() + it("swaps 2 columns, in-place", function() + local a = {{1,2,3}, + {4,5,6}, + {7,8,9}} + local b = array2d.swap_cols(a, 1, 3) + assert.same({{3,2,1}, + {6,5,4}, + {9,8,7}}, b) + assert.equal(a, b) + end) + end) + + describe("extract_rows()", function() + it("extracts rows", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}, + {10,11,12}} + local b = array2d.extract_rows(a, {1, 3}) + assert.same({{1,2,3}, + {7,8,9}}, b) + end) + end) + + describe("extract_cols()", function() + it("extracts colums", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}, + {10,11,12}} + local b = array2d.extract_cols(a, {1, 2}) + assert.same({{ 1, 2}, + { 4, 5}, + { 7, 8}, + {10,11}}, b) + end) + end) + + describe("remove_row()", function() + it("removes a row", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}, + {10,11,12}} + array2d.remove_row(a, 2) + assert.same({{ 1, 2, 3}, + { 7, 8, 9}, + {10,11,12}}, a) + end) + end) + + describe("remove_col()", function() + it("removes a colum", function() + local a = {{ 1, 2, 3}, + { 4, 5, 6}, + { 7, 8, 9}, + {10,11,12}} + array2d.remove_col(a, 2) + assert.same({{ 1, 3}, + { 4, 6}, + { 7, 9}, + {10,12}}, a) + end) + end) + + describe("parse_range()", function() + it("parses A1:B2 format", function() + assert.same({4,11,7,12},{array2d.parse_range("K4:L7")}) + assert.same({4,28,7,54},{array2d.parse_range("AB4:BB7")}) + -- test Col R since it might be mixed up with RxCx format + assert.same({4,18,7,18},{array2d.parse_range("R4:R7")}) + end) + + it("parses A1 format", function() + assert.same({4,11},{array2d.parse_range("K4")}) + -- test Col R since it might be mixed up with RxCx format + assert.same({4,18},{array2d.parse_range("R4")}) + end) + + it("parses R1C1:R2C2 format", function() + assert.same({4,11,7,12},{array2d.parse_range("R4C11:R7C12")}) + end) + + it("parses R1C1 format", function() + assert.same({4,11},{array2d.parse_range("R4C11")}) + end) + end) + + describe("range()", function() + it("returns a range", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local b = array2d.range(a, "B3:C4") + assert.same({{ 8, 9}, + {11,12}}, b) + end) + end) + + describe("default_range()", function() + it("returns the default range", function() + local a = array2d.new(4,6,1) + assert.same({1,1,4,6}, {array2d.default_range(a, nil, nil, nil, nil)}) + end) + + it("accepts negative indices", function() + local a = array2d.new(4,6,1) + assert.same({2,2,3,5}, {array2d.default_range(a, -3, -5, -2, -2)}) + end) + + it("corrects out of bounds indices", function() + local a = array2d.new(4,6,1) + assert.same({1,1,4,6}, {array2d.default_range(a, -100, -100, 100, 100)}) + end) + end) + + describe("slice()", function() + it("returns a slice", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local b = array2d.slice(a,3,2,4,3) + assert.same({{ 8, 9}, + {11,12}}, b) + end) + + it("returns a single row if rows are equal", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local b = array2d.slice(a,4,1,4,3) + assert.same({10,11,12}, b) + end) + + it("returns a single column if columns are equal", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local b = array2d.slice(a,1,3,4,3) + assert.same({3,6,9,12}, b) + end) + + it("returns a single value if rows and columns are equal", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local b = array2d.slice(a,2,2,2,2) + assert.same(5, b) + end) + end) + + describe("set()", function() + it("sets a range to a value", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + array2d.set(a,0,2,2,3,3) + assert.same({{1 ,2 ,3}, + {4 ,0 ,0}, + {7 ,0 ,0}, + {10,11,12}}, a) + end) + + it("sets a range to a function value", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local x = 10 + local args = {} + local f = function(r,c) + args[#args+1] = {r,c} + x = x + 1 + return x + end + array2d.set(a,f,3,1,4,3) + assert.same({{1 ,2 ,3}, + {4 ,5 ,6}, + {11,12,13}, + {14,15,16}}, a) + -- validate args used to call the function + assert.same({{3,1},{3,2},{3,3},{4,1},{4,2},{4,3}}, args) + end) + end) + + describe("write()", function() + it("writes array to a file", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local f = setmetatable({}, { + __index = { + write = function(self,str) + self[#self+1] = str + end + } + }) + array2d.write(a,f,"(%s)") + f = table.concat(f) + assert.equal([[(1)(2)(3) +(4)(5)(6) +(7)(8)(9) +(10)(11)(12) +]],f) + end) + + it("writes partial array to a file", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local f = setmetatable({}, { + __index = { + write = function(self,str) + self[#self+1] = str + end + } + }) + array2d.write(a,f,"(%s)", 1,1,2,2) + f = table.concat(f) + assert.equal([[(1)(2) +(4)(5) +]],f) + end) + end) + + describe("forall()", function() + it("runs all value and row functions", function() + local r = {} + local t = 0 + local fval = function(row, j) t = t + row[j] end + local frow = function(i) r[#r+1] = t; t = 0 end + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + array2d.forall(a, fval, frow) + assert.same({6, 15, 24, 33}, r) + r = {} + array2d.forall(a, fval, frow, 2,2,4,3) + assert.same({11, 17, 23}, r) + end) + + end) + + describe("move()", function() + it("moves block to destination aray", function() + local a = array2d.new(4,4,0) + local b = array2d.new(3,3,1) + array2d.move(a,2,2,b) + assert.same({{0,0,0,0}, + {0,1,1,1}, + {0,1,1,1}, + {0,1,1,1}}, a) + end) + end) + + describe("iter()", function() + it("iterates all values", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + for v, i, j in array2d.iter(a) do + r[#r+1] = v + assert.is_nil(i) + assert.is_nil(j) + end + assert.same({1,2,3,4,5,6,7,8,9,10,11,12}, r) + end) + + it("iterates all values and indices", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + local ri = {} + local rj = {} + for i, j, v in array2d.iter(a,true) do + r[#r+1] = v + ri[#ri+1] = i + rj[#rj+1] = j + end + assert.same({1,2,3,4,5,6,7,8,9,10,11,12}, r) + assert.same({1,1,1,2,2,2,3,3,3,4,4,4}, ri) + assert.same({1,2,3,1,2,3,1,2,3,1,2,3}, rj) + end) + + it("iterates all values of a 2d array part", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + for v, i, j in array2d.iter(a,false,2,2,4,3) do + r[#r+1] = v + assert.is_nil(i) + assert.is_nil(j) + end + assert.same({5,6,8,9,11,12}, r) + end) + + it("iterates all values and indices of a 2d array part", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + local ri = {} + local rj = {} + for i, j, v in array2d.iter(a,true,2,2,4,3) do + r[#r+1] = v + ri[#ri+1] = i + rj[#rj+1] = j + end + assert.same({5,6,8,9,11,12}, r) + assert.same({2,2,3,3,4,4}, ri) + assert.same({2,3,2,3,2,3}, rj) + end) + end) + + describe("columns()", function() + it("iterates all columns", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + for col, idx in array2d.columns(a) do + r[#r+1] = col + col.idx = idx + end + assert.same({{1,4,7,10, idx=1},{2,5,8,11, idx=2},{3,6,9,12, idx=3}}, r) + end) + end) + + describe("rows()", function() + it("iterates all columns", function() + local a = {{1 ,2 ,3}, + {4 ,5 ,6}, + {7 ,8 ,9}, + {10,11,12}} + local r = {} + for row, idx in array2d.rows(a) do + r[#r+1] = row + row.idx = idx + end + assert.same({{1,2,3, idx=1},{4,5,6, idx=2}, + {7,8,9, idx=3},{10,11,12, idx=4}}, r) + end) + end) + +end) diff --git a/Data/Libraries/Penlight/spec/date_spec.lua b/Data/Libraries/Penlight/spec/date_spec.lua new file mode 100644 index 0000000..1032de2 --- /dev/null +++ b/Data/Libraries/Penlight/spec/date_spec.lua @@ -0,0 +1,48 @@ +local Date = require("pl.Date") + +describe("pl.Date", function () + + describe("function", function () + + describe("Format()", function () + + it("should output parsable inputs", function () + local function assert_date_format(expected, format) + local df = Date.Format(format) + local d = df:parse(expected) + assert.is.equal(expected, df:tostring(d)) + end + assert_date_format('02/04/10', 'dd/mm/yy') + assert_date_format('04/02/2010', 'mm/dd/yyyy') + assert_date_format('2011-02-20', 'yyyy-mm-dd') + assert_date_format('20070320', 'yyyymmdd') + assert_date_format('23:10', 'HH:MM') + end) + + it("should parse 'slack' fields", function () + local df = Date.Format("m/d/yy") + -- TODO: Re-enable when issue #359 fixed + -- assert.is.equal('01/05/99', df:tostring(df:parse('1/5/99'))) + assert.is.equal('01/05/01', df:tostring(df:parse('1/5/01'))) + assert.is.equal('01/05/32', df:tostring(df:parse('1/5/32'))) + end) + + end) + + end) + + describe("meta method", function () + + describe("__tostring()", function () + + it("should be suitable for serialization", function () + local df = Date.Format() + local du = df:parse("2008-07-05") + assert.is.equal(du, du:toUTC()) + end) + + end) + + end) + +end) diff --git a/Data/Libraries/Penlight/spec/multimap_spec.lua b/Data/Libraries/Penlight/spec/multimap_spec.lua new file mode 100644 index 0000000..a83d150 --- /dev/null +++ b/Data/Libraries/Penlight/spec/multimap_spec.lua @@ -0,0 +1,14 @@ +local MultiMap = require("pl.MultiMap") + +describe("pl.MultiMap", function () + + it("should hold multiple values per key", function () + local map = MultiMap() + map:set('foo', 1) + map:set('bar', 3) + map:set('foo', 2) + local expected = { foo = { 1, 2 }, bar = { 3 } } + assert.is.same(expected, map) + end) + +end) diff --git a/Data/Libraries/Penlight/spec/permute_spec.lua b/Data/Libraries/Penlight/spec/permute_spec.lua new file mode 100644 index 0000000..49143c0 --- /dev/null +++ b/Data/Libraries/Penlight/spec/permute_spec.lua @@ -0,0 +1,213 @@ +local permute = require("pl.permute") +local tcopy = require("pl.tablex").copy +local utils = require("pl.utils") + +describe("pl.permute", function() + + describe("order_iter", function() + + it("returns all order combinations", function() + local result = {} + for list in permute.order_iter({"one", "two", "three"}) do + result[#result+1] = tcopy(list) + end + assert.same({ + [1] = { + [1] = 'two', + [2] = 'three', + [3] = 'one' }, + [2] = { + [1] = 'three', + [2] = 'two', + [3] = 'one' }, + [3] = { + [1] = 'three', + [2] = 'one', + [3] = 'two' }, + [4] = { + [1] = 'one', + [2] = 'three', + [3] = 'two' }, + [5] = { + [1] = 'two', + [2] = 'one', + [3] = 'three' }, + [6] = { + [1] = 'one', + [2] = 'two', + [3] = 'three' } }, result) + end) + + + it("returns nil on empty list", function() + local result = {} + for list in permute.order_iter({}) do + result[#result+1] = tcopy(list) + end + assert.equal(0, #result) + end) + + end) + + + + describe("order_table", function() + + it("returns all order combinations", function() + local result = permute.order_table({"one", "two", "three"}) + assert.same({ + [1] = { + [1] = 'two', + [2] = 'three', + [3] = 'one' }, + [2] = { + [1] = 'three', + [2] = 'two', + [3] = 'one' }, + [3] = { + [1] = 'three', + [2] = 'one', + [3] = 'two' }, + [4] = { + [1] = 'one', + [2] = 'three', + [3] = 'two' }, + [5] = { + [1] = 'two', + [2] = 'one', + [3] = 'three' }, + [6] = { + [1] = 'one', + [2] = 'two', + [3] = 'three' } }, result) + end) + + + it("returns empty table on empty input list", function() + local result = permute.order_table({}) + assert.same({}, result) + end) + + end) + + + + describe("list_iter", function() + + it("returns all combinations from sub-lists", function() + local result = {} + local strs = {"one", "two", "three"} + local ints = { 1,2,3 } + local bools = { true, false } + for count, str, int, bool in permute.list_iter(strs, ints, bools) do + result[#result+1] = {count, str, int, bool} + end + assert.same({ + [1] = {1, 'one', 1, true }, + [2] = {2, 'two', 1, true }, + [3] = {3, 'three', 1, true }, + [4] = {4, 'one', 2, true }, + [5] = {5, 'two', 2, true }, + [6] = {6, 'three', 2, true }, + [7] = {7, 'one', 3, true }, + [8] = {8, 'two', 3, true }, + [9] = {9, 'three', 3, true }, + [10] = {10, 'one', 1, false }, + [11] = {11, 'two', 1, false }, + [12] = {12, 'three', 1, false }, + [13] = {13, 'one', 2, false }, + [14] = {14, 'two', 2, false }, + [15] = {15, 'three', 2, false }, + [16] = {16, 'one', 3, false }, + [17] = {17, 'two', 3, false }, + [18] = {18, 'three', 3, false }, + }, result) + end) + + + it("is nil-safe, given 'n' is set", function() + local result = {} + local bools = utils.pack(nil, true, false) + local strs = utils.pack("one", "two", nil) + for count, bool, str in permute.list_iter(bools, strs) do + result[#result+1] = {count, bool, str} + end + assert.same({ + [1] = {1, nil, 'one' }, + [2] = {2, true, 'one' }, + [3] = {3, false, 'one' }, + [4] = {4, nil, 'two' }, + [5] = {5, true, 'two' }, + [6] = {6, false, 'two' }, + [7] = {7, nil, nil }, + [8] = {8, true, nil }, + [9] = {9, false, nil }, + }, result) + end) + + + it("returns nil on empty list", function() + local count = 0 + for list in permute.list_iter({}) do + count = count + 1 + end + assert.equal(0, count) + end) + + end) + + + + describe("list_table", function() + + it("returns all combinations from sub-lists", function() + local strs = {"one", "two", "three"} + local ints = { 1,2,3 } + local bools = { true, false } + assert.same({ + [1] = {'one', 1, true, n = 3 }, + [2] = {'two', 1, true, n = 3 }, + [3] = {'three', 1, true, n = 3 }, + [4] = {'one', 2, true, n = 3 }, + [5] = {'two', 2, true, n = 3 }, + [6] = {'three', 2, true, n = 3 }, + [7] = {'one', 3, true, n = 3 }, + [8] = {'two', 3, true, n = 3 }, + [9] = {'three', 3, true, n = 3 }, + [10] = {'one', 1, false, n = 3 }, + [11] = {'two', 1, false, n = 3 }, + [12] = {'three', 1, false, n = 3 }, + [13] = {'one', 2, false, n = 3 }, + [14] = {'two', 2, false, n = 3 }, + [15] = {'three', 2, false, n = 3 }, + [16] = {'one', 3, false, n = 3 }, + [17] = {'two', 3, false, n = 3 }, + [18] = {'three', 3, false, n = 3 }, + }, permute.list_table(strs, ints, bools)) + end) + + + it("is nil-safe, given 'n' is set", function() + local bools = utils.pack(nil, true, false) + local strs = utils.pack("one", "two", nil) + assert.same({ + [1] = {nil, 'one', n = 2 }, + [2] = {true, 'one', n = 2 }, + [3] = {false, 'one', n = 2 }, + [4] = {nil, 'two', n = 2 }, + [5] = {true, 'two', n = 2 }, + [6] = {false, 'two', n = 2 }, + [7] = {nil, nil, n = 2 }, + [8] = {true, nil, n = 2 }, + [9] = {false, nil, n = 2 }, + }, permute.list_table(bools, strs)) + end) + + + it("returns nil on empty list", function() + assert.same({}, permute.list_table({})) + end) + + end) + +end) diff --git a/Data/Libraries/Penlight/spec/pretty_spec.lua b/Data/Libraries/Penlight/spec/pretty_spec.lua new file mode 100644 index 0000000..85e3770 --- /dev/null +++ b/Data/Libraries/Penlight/spec/pretty_spec.lua @@ -0,0 +1,40 @@ +local pretty = require("pl.pretty") + +describe("pl.pretty.number", function () + + it("should format memory", function () + local function assert_memory (expected, input) + assert.is.equal(expected, pretty.number(input, "M")) + end + assert_memory("123B", 123) + assert_memory("1.2KiB", 1234) + assert_memory("10.0KiB", 10*1024) + assert_memory("1.0MiB", 1024*1024) + assert_memory("1.0GiB", 1024*1024*1024) + end) + + it("should format postfixes", function () + local function assert_postfix(expected, input) + assert.is.equal(expected, pretty.number(input, "N", 2)) + end + assert_postfix("123", 123) + assert_postfix("1.23K", 1234) + assert_postfix("10.24K", 10*1024) + assert_postfix("1.05M", 1024*1024) + assert_postfix("1.07B", 1024*1024*1024) + end) + + it("should format postfixes", function () + local function assert_separator(expected, input) + assert.is.equal(expected, pretty.number(input, "T")) + end + assert_separator('123', 123) + assert_separator('1,234', 1234) + assert_separator('12,345', 12345) + assert_separator('123,456', 123456) + assert_separator('1,234,567', 1234567) + assert_separator('12,345,678', 12345678) + end) + + +end) diff --git a/Data/Libraries/Penlight/spec/set_spec.lua b/Data/Libraries/Penlight/spec/set_spec.lua new file mode 100644 index 0000000..02febca --- /dev/null +++ b/Data/Libraries/Penlight/spec/set_spec.lua @@ -0,0 +1,84 @@ +local Set = require("pl.Set") + +describe("pl.Set", function () + + local s = Set() + local s1_2 = Set({ 1, 2 }) + local s1_2_3 = Set({ 1, 2, 3 }) + local s1_3 = Set({ 1, 3 }) + local s2 = Set({ 2 }) + local s2_1 = Set({ 2, 1 }) + local s2_3 = Set({ 2, 3 }) + local s3 = Set({ 3 }) + local sm = Set({ "foo", "bar" }) + + it("should produce a set object", function () + assert.is.same({ true, true }, s1_2) + end) + + it("should produce identical sets for any ordered input", function () + assert.is.same(s1_2, s2_1) + end) + + describe("should have an operator for", function () + + it("union", function () + assert.is.same(s1_2_3, s1_2 + s3) + assert.is.same(s1_2_3, s1_2 + 3) + end) + + it("intersection", function () + assert.is.same(s2, s1_2 * s2_3) + end) + + it("difference", function () + assert.is.same(s2_1, s1_2_3 - s3) + assert.is.same(s2_3, s1_2_3 - 1) + end) + + it("symmetric difference", function () + assert.is.same(s1_3, s1_2 ^ s2_3) + end) + + it("tostring", function () + -- Cannot test multi-entry sets because of non-deterministic key order + assert.is.same('[2]', tostring(s2)) + end) + + end) + + describe("should provide functions", function () + + it("isempty", function () + assert.is.truthy(Set.isempty(s)) + assert.is.falsy(Set.isempty(s3)) + end) + + it("set", function () + local m = Set() + Set.set(m, 'foo', true) + m.bar = true + assert.is.same(m, sm) + assert.is_not.same(m, s1_2) + end) + + end) + + describe("should have a comparison operator for", function () + + it("supersets/subsets than", function () + assert.is.truthy(s1_2 > s2) + assert.is.falsy(s1_3 > s2) + assert.is.falsy(s1_2 > s2_3) + assert.is.truthy(s1_2 < s1_2_3) + assert.is.falsy(s1_2_3 < s1_2) + end) + + it("equality", function () + assert.is.truthy(s1_2 == s2_1) + assert.is.falsy(s1_2 == s2_3) + end) + + end) + +end) diff --git a/Data/Libraries/Penlight/spec/text_spec.lua b/Data/Libraries/Penlight/spec/text_spec.lua new file mode 100644 index 0000000..cd42f06 --- /dev/null +++ b/Data/Libraries/Penlight/spec/text_spec.lua @@ -0,0 +1,11 @@ +local text = require("pl.text") + +describe("pl.text.Template", function () + + it("replaces placeholders", function () + local tempalte = text.Template("${here} is the $answer") + local out = tempalte:substitute({ here = 'one', answer = 'two' }) + assert.is.equal('one is the two', out) + end) + +end) diff --git a/Data/Libraries/Penlight/spec/utils-deprecate_spec.lua b/Data/Libraries/Penlight/spec/utils-deprecate_spec.lua new file mode 100644 index 0000000..1a6e352 --- /dev/null +++ b/Data/Libraries/Penlight/spec/utils-deprecate_spec.lua @@ -0,0 +1,128 @@ +local utils = require("pl.utils") + +describe("pl.utils", function () + + local old_fn, last_msg, last_trace + + before_each(function() + old_fn = function() end + last_msg = nil + last_trace = nil + utils.set_deprecation_func(function(msg, trace) + last_msg = msg + last_trace = trace + end) + end) + + + after_each(function() + utils.deprecation_warning = old_fn + end) + + + + describe("set_deprecation_func", function () + + it("accepts nil as callback", function() + assert.has.no.error(function() + utils.set_deprecation_func() + end) + end) + + + it("accepts function as callback", function() + assert.has.no.error(function() + utils.set_deprecation_func(function() end) + end) + end) + + + it("fails on non-functions", function() + assert.has.error(function() + utils.set_deprecation_func("not a function") + end, "argument 1 expected a 'function', got a 'string'") + end) + + end) + + + + describe("raise_deprecation", function () + + it("requires the opts table", function() + assert.has.error(function() utils.raise_deprecation(nil) end, + "argument 1 expected a 'table', got a 'nil'") + end) + + + it("requires the opts.message field", function() + assert.has.error(function() utils.raise_deprecation({}) end, + "field 'message' of the options table must be a string") + end) + + + it("should output the message", function () + utils.raise_deprecation { + message = "hello world" + } + assert.equal("hello world", last_msg) + end) + + + it("should output the deprecated version", function () + utils.raise_deprecation { + message = "hello world", + deprecated_after = "2.0.0", + } + assert.equal("hello world (deprecated after 2.0.0)", last_msg) + end) + + + it("should output the removal version", function () + utils.raise_deprecation { + message = "hello world", + version_removed = "3.0.0", + } + assert.equal("hello world (scheduled for removal in 3.0.0)", last_msg) + end) + + + it("should output the deprecated and removal versions", function () + utils.raise_deprecation { + message = "hello world", + deprecated_after = "2.0.0", + version_removed = "3.0.0", + } + assert.equal("hello world (deprecated after 2.0.0, scheduled for removal in 3.0.0)", last_msg) + end) + + + it("should output the application/module name", function () + utils.raise_deprecation { + source = "MyApp 1.2.3", + message = "hello world", + deprecated_after = "2.0.0", + version_removed = "3.0.0", + } + assert.equal("[MyApp 1.2.3] hello world (deprecated after 2.0.0, scheduled for removal in 3.0.0)", last_msg) + end) + + + it("should add a stracktrace", function () + local function my_function_name() + utils.raise_deprecation { + source = "MyApp 1.2.3", + message = "hello world", + deprecated_after = "2.0.0", + version_removed = "3.0.0", + } + end + my_function_name() + + assert.Not.match("raise_deprecation", last_trace) + assert.match("my_function_name", last_trace) + end) + + end) + +end) diff --git a/Data/Libraries/Penlight/spec/utils-npairs_spec.lua b/Data/Libraries/Penlight/spec/utils-npairs_spec.lua new file mode 100644 index 0000000..7e3c5d4 --- /dev/null +++ b/Data/Libraries/Penlight/spec/utils-npairs_spec.lua @@ -0,0 +1,105 @@ +local utils = require("pl.utils") + +describe("pl.utils", function () + + describe("npairs", function () + local npairs = utils.npairs + + it("start index defaults to 1", function() + local t1 = { 1, 2, 3 } + local t2 = {} + for i, v in npairs(t1, nil, 2) do t2[i] = v end + assert.are.same({ 1, 2 }, t2) + end) + + + it("end index defaults to `t.n`", function() + local t1 = { n = 2, 1, 2, 3 } + local t2 = {} + for i, v in npairs(t1) do t2[i] = v end + assert.are.same({1, 2}, t2) + end) + + + it("step size defaults to 1", function() + local t1 = { 1, 2, 3 } + local t2 = {} + for i, v in npairs(t1) do t2[i] = v end + assert.are.same({1, 2, 3}, t2) + end) + + + it("step size cannot be 0", function() + local t1 = { 1, 2, 3 } + assert.has.error(function() + npairs(t1, nil, nil, 0) + end, "iterator step-size cannot be 0") + end) + + + it("end index defaults to `#t` if there is no `t.n`", function() + local t1 = { 1, 2, 3 } + local t2 = {} + for i, v in npairs(t1) do t2[i] = v end + assert.are.same({1, 2, 3}, t2) + end) + + + it("returns nothing if start index is beyond end index", function() + local t1 = { 1, 2, 3 } + local t2 = {} + for i, v in npairs(t1, 5, 3) do t2[i] = v end + assert.are.same({}, t2) + end) + + + it("returns nothing if start index is beyond end index, with negative step size", function() + local t1 = { 1, 2, 3 } + local t2 = {} + for i, v in npairs(t1, 3, 1, -1) do t2[#t2+1] = v end + assert.are.same({ 3, 2, 1}, t2) + end) + + + it("returns 1 key/value if end == start index", function() + local t1 = { 1, 2, 3 } + local t2 = {} + for i, v in npairs(t1, 2, 2) do t2[i] = v end + assert.are.same({ [2] = 2 }, t2) + end) + + + it("returns negative to positive ranges", function() + local t1 = { [-5] = -5, [-4] = -4, [-3] = -3, [-2] = -2, [-1] = -1, [0] = 0, 1, 2, 3 } + local t2 = {} + for i, v in npairs(t1, -4, 1) do t2[i] = v end + assert.are.same({ [-4] = -4, [-3] = -3, [-2] = -2, [-1] = -1, [0] = 0, 1 }, t2) + end) + + + it("returns nil values with the range", function() + local t1 = { n = 3 } + local t2 = {} + for i, v in npairs(t1) do t2[i] = tostring(v) end + assert.are.same({ "nil", "nil", "nil" }, t2) + end) + + + it("honours positive step size", function() + local t1 = { [-5] = -5, [-4] = -4, [-3] = -3, [-2] = -2, [-1] = -1, [0] = 0, 1, 2, 3 } + local t2 = {} + for i, v in npairs(t1, -4, 1, 2) do t2[#t2+1] = v end + assert.are.same({ -4, -2, 0}, t2) + end) + + + it("honours negative step size", function() + local t1 = { [-5] = -5, [-4] = -4, [-3] = -3, [-2] = -2, [-1] = -1, [0] = 0, 1, 2, 3 } + local t2 = {} + for i, v in npairs(t1, 0, -5, -2) do t2[#t2+1] = v end + assert.are.same({ 0, -2, -4 }, t2) + end) + + end) + +end) |