aboutsummaryrefslogtreecommitdiffstats
path: root/tests/mason-core/functional/function_spec.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tests/mason-core/functional/function_spec.lua')
-rw-r--r--tests/mason-core/functional/function_spec.lua142
1 files changed, 142 insertions, 0 deletions
diff --git a/tests/mason-core/functional/function_spec.lua b/tests/mason-core/functional/function_spec.lua
new file mode 100644
index 00000000..8c4b41ef
--- /dev/null
+++ b/tests/mason-core/functional/function_spec.lua
@@ -0,0 +1,142 @@
+local spy = require "luassert.spy"
+local match = require "luassert.match"
+local _ = require "mason-core.functional"
+
+describe("functional: function", function()
+ it("curries functions", function()
+ local function sum(...)
+ local res = 0
+ for i = 1, select("#", ...) do
+ res = res + select(i, ...)
+ end
+ return res
+ end
+ local arity0 = _.curryN(sum, 0)
+ local arity1 = _.curryN(sum, 1)
+ local arity2 = _.curryN(sum, 2)
+ local arity3 = _.curryN(sum, 3)
+
+ assert.equals(0, arity0(42))
+ assert.equals(42, arity1(42))
+ assert.equals(3, arity2(1)(2))
+ assert.equals(3, arity2(1, 2))
+ assert.equals(6, arity3(1)(2)(3))
+ assert.equals(6, arity3(1, 2, 3))
+
+ -- should discard superfluous args
+ assert.equals(0, arity1(0, 10, 20, 30))
+ end)
+
+ it("coalesces first non-nil value", function()
+ assert.equal("Hello World!", _.coalesce(nil, nil, "Hello World!", ""))
+ end)
+
+ it("should compose functions", function()
+ local function add(x)
+ return function(y)
+ return y + x
+ end
+ end
+ local function subtract(x)
+ return function(y)
+ return y - x
+ end
+ end
+ local function multiply(x)
+ return function(y)
+ return y * x
+ end
+ end
+
+ local big_maths = _.compose(add(1), subtract(3), multiply(5))
+
+ assert.equals(23, big_maths(5))
+ end)
+
+ it("should not allow composing no functions", function()
+ local e = assert.error(function()
+ _.compose()
+ end)
+ assert.equals("compose requires at least one function", e)
+ end)
+
+ it("should partially apply functions", function()
+ local funcy = spy.new()
+ local partially_funcy = _.partial(funcy, "a", "b", "c")
+ partially_funcy("d", "e", "f")
+ assert.spy(funcy).was_called_with("a", "b", "c", "d", "e", "f")
+ end)
+
+ it("should partially apply functions with nil arguments", function()
+ local funcy = spy.new()
+ local partially_funcy = _.partial(funcy, "a", nil, "c")
+ partially_funcy("d", nil, "f")
+ assert.spy(funcy).was_called_with("a", nil, "c", "d", nil, "f")
+ end)
+
+ it("memoizes functions with default cache mechanism", function()
+ local expensive_function = spy.new(function(s)
+ return s
+ end)
+ local memoized_fn = _.memoize(expensive_function)
+ assert.equal("key", memoized_fn "key")
+ assert.equal("key", memoized_fn "key")
+ assert.equal("new_key", memoized_fn "new_key")
+ assert.spy(expensive_function).was_called(2)
+ end)
+
+ it("memoizes function with custom cache mechanism", function()
+ local expensive_function = spy.new(function(arg1, arg2)
+ return arg1 .. arg2
+ end)
+ local memoized_fn = _.memoize(expensive_function, function(arg1, arg2)
+ return arg1 .. arg2
+ end)
+ assert.equal("key1key2", memoized_fn("key1", "key2"))
+ assert.equal("key1key2", memoized_fn("key1", "key2"))
+ assert.equal("key1key3", memoized_fn("key1", "key3"))
+ assert.spy(expensive_function).was_called(2)
+ end)
+
+ it("should evaluate functions lazily", function()
+ local impl = spy.new(function()
+ return {}, {}
+ end)
+ local lazy_fn = _.lazy(impl)
+ assert.spy(impl).was_called(0)
+ local a, b = lazy_fn()
+ assert.spy(impl).was_called(1)
+ assert.is_true(match.is_table()(a))
+ assert.is_true(match.is_table()(b))
+ local new_a, new_b = lazy_fn()
+ assert.spy(impl).was_called(1)
+ assert.is_true(match.is_ref(a)(new_a))
+ assert.is_true(match.is_ref(b)(new_b))
+ end)
+
+ it("should support nil return values in lazy functions", function()
+ local lazy_fn = _.lazy(function()
+ return nil, 2
+ end)
+ local a, b = lazy_fn()
+ assert.is_nil(a)
+ assert.equal(2, b)
+ end)
+
+ it("should provide identity value", function()
+ local obj = {}
+ assert.equals(2, _.identity(2))
+ assert.equals(obj, _.identity(obj))
+ end)
+
+ it("should always return bound value", function()
+ local obj = {}
+ assert.equals(2, _.always(2)())
+ assert.equals(obj, _.always(obj)())
+ end)
+
+ it("true is true and false is false", function()
+ assert.is_true(_.T())
+ assert.is_false(_.F())
+ end)
+end)